diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000000..bc24682a97 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,142 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +tone_instructions: >- + Be respectful, concise, and educational. Assume physicist contributors. Prioritize correctness and + safety. Ignore purely stylistic issues and Minor/Trivial/Info items. +reviews: + high_level_summary_instructions: >- + Write a concise PR summary for a scientific collaboration. + + Include: + + - Motivation / context + + - Key changes (bullets) + + - Potential risk areas (IO format changes, reconstruction behavior changes, thread-safety, + performance) + + - Possible future improvements + + + Add an emphasis that AI can make mistakes and use best judgment when reading + estimate_code_review_effort: false + suggested_labels: false + suggested_reviewers: false + in_progress_fortune: false + poem: false + enable_prompt_for_ai_agents: false + path_filters: + - '!**/build/**' + - '!**/install/**' + - '!**/*.root' + - '!**/*.pdf' + - '!**/*.png' + - '!**/*.jpg' + - '!**/*.gif' + - '!**/*.zip' + - '!**/*.tar.gz' + - '!**/*.so' + - '!**/*.dylib' + - '!**/*.a' + - '!**/*.o' + path_instructions: + - path: '**/*.{h,hpp,hxx,hh}' + instructions: >- + Focus on API clarity/stability, ownership semantics (RAII), and avoiding raw new/delete. + + If interfaces change, ask for compatibility notes and any needed downstream updates. + + + Only raise Critical or Major findings. Do not post minor style, formatting, naming, or + “nice-to-have” refactors. + - path: '**/*.{cc,cpp,cxx,c}' + instructions: >- + Prioritize correctness, memory safety, error handling, and thread-safety. + + Flag hidden global state, non-const singletons, and unclear lifetime assumptions. + + + Only raise Critical or Major findings. Do not post minor style, formatting, naming, or + “nice-to-have” refactors. + - path: '**/*.C' + instructions: Do NOT review these files + - path: '**/CMakeLists.txt' + instructions: | + Check for modern CMake target usage, correct scoping, and avoiding global flags. + auto_review: + ignore_title_keywords: + - WIP + - DRAFT + - DO NOT MERGE + - RFC + finishing_touches: + unit_tests: + enabled: false + pre_merge_checks: + docstrings: + mode: 'off' + title: + mode: 'off' + description: + mode: 'off' + issue_assessment: + mode: 'off' + custom_checks: + - mode: 'off' + name: Test plan present + instructions: > + Check that the PR description includes a "Testing" or "Test Plan" section with at least + one bullet. + + Accept: unit test, integration test, or example macro/validation command. + - mode: 'off' + name: Physics/reco impact noted (if applicable) + instructions: > + If the PR changes reconstruction outputs, calibration constants, or simulation behavior, + + ensure the description states expected analysis impact and whether reprocessing is + required. + tools: + swiftlint: + enabled: false + phpstan: + enabled: false + phpmd: + enabled: false + golangci-lint: + enabled: false + detekt: + enabled: false + pmd: + enabled: false +chat: + art: false + integrations: + jira: + usage: disabled + linear: + usage: disabled +knowledge_base: + code_guidelines: + filePatterns: + - CONTRIBUTING.md + - docs/** + - .github/*.md + learnings: + scope: global + jira: + usage: disabled +code_generation: + docstrings: + path_instructions: + - path: '**/*.{h,hpp,hh,hxx,cc,cpp,cxx,C}' + instructions: >- + Use Doxygen-style documentation, Link to example caller function if available. ONLY add + docstrings where none exist. Do NOT modify, rewrite, or reformat any existing + docstrings/comments. If a function already has a docstring (even if incomplete), leave it + unchanged. +issue_enrichment: + planning: + enabled: false + auto_planning: + enabled: false diff --git a/.github/workflows/fix-eof-newline-coderabbit-docstrings.yml b/.github/workflows/fix-eof-newline-coderabbit-docstrings.yml new file mode 100644 index 0000000000..75d43e65e5 --- /dev/null +++ b/.github/workflows/fix-eof-newline-coderabbit-docstrings.yml @@ -0,0 +1,106 @@ +name: Fix missing final newline (CodeRabbit docstring PRs) + +on: + pull_request_target: + types: [opened, synchronize, reopened] + +permissions: + contents: write + pull-requests: read + +jobs: + fix_eof_newline: + runs-on: ubuntu-latest + steps: + - name: Guard - only CodeRabbit docstring PRs from same repo + id: guard + shell: bash + run: | + set -euo pipefail + + AUTHOR='${{ github.event.pull_request.user.login }}' + BASE_REPO='${{ github.event.pull_request.base.repo.full_name }}' + HEAD_REPO='${{ github.event.pull_request.head.repo.full_name }}' + TITLE='${{ github.event.pull_request.title }}' + + if [[ "$AUTHOR" != "coderabbitai[bot]" ]]; then + echo "run=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # Safety: only push to branches within the same repo + if [[ "$BASE_REPO" != "$HEAD_REPO" ]]; then + echo "run=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + # only run for docstring PRs + if ! echo "$TITLE" | grep -qi "docstring"; then + echo "run=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + echo "run=true" >> "$GITHUB_OUTPUT" + + - name: Checkout PR head + if: steps.guard.outputs.run == 'true' + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + fetch-depth: 0 + + - name: Append final newline when missing (changed files only) + if: steps.guard.outputs.run == 'true' + shell: bash + run: | + set -euo pipefail + + BASE_SHA="${{ github.event.pull_request.base.sha }}" + HEAD_SHA="${{ github.event.pull_request.head.sha }}" + + files=$(git diff --name-only "$BASE_SHA" "$HEAD_SHA" -- \ + '*.C' '*.c' '*.cc' '*.cpp' '*.cxx' '*.h' '*.hh' '*.hpp' '*.hxx' || true) + + if [[ -z "${files}" ]]; then + echo "No relevant files changed." + exit 0 + fi + + changed=0 + for f in $files; do + [[ -f "$f" ]] || continue + + # For non-empty files: ensure last byte is '\n' + if [[ -s "$f" ]]; then + last_byte="$(tail -c 1 "$f" || true)" + if [[ "$last_byte" != $'\n' ]]; then + printf '\n' >> "$f" + echo "Fixed EOF newline: $f" + changed=1 + fi + fi + done + + if [[ "$changed" -eq 0 ]]; then + echo "All files already end with a newline." + exit 0 + fi + + git status --porcelain + git add -A + + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + git commit -m "Fix missing final newline in docstring PR" + + - name: Push fix commit back to PR branch + if: steps.guard.outputs.run == 'true' + shell: bash + run: | + set -euo pipefail + # If no commit was created, pushing will fail; so only push if HEAD is ahead. + if git rev-parse HEAD~1 >/dev/null 2>&1; then + git push origin "HEAD:${{ github.event.pull_request.head.ref }}" + fi diff --git a/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc b/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc index 8528cd26ae..56df96e205 100644 --- a/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc +++ b/calibrations/calorimeter/calo_cdb/CaloCDB-FilterDatasets.cc @@ -1,6 +1,10 @@ -#include "filter-datasets.h" +#include "FilterDatasets.h" + +#include #include +#include +#include int main(int argc, const char* const argv[]) { @@ -17,7 +21,7 @@ int main(int argc, const char* const argv[]) const std::string& input_csv = args[1]; std::string output_dir_path = "."; - Bool_t debug = false; + bool debug = false; if (args.size() >= 3) { @@ -28,6 +32,9 @@ int main(int argc, const char* const argv[]) debug = std::stoi(args[3]); } + recoConsts* rc = recoConsts::instance(); + rc->set_StringFlag("CDB_GLOBALTAG", "newcdbtag"); + FilterDatasets filter(debug); filter.process(input_csv, output_dir_path); diff --git a/calibrations/calorimeter/calo_cdb/CaloCDB-GenStatus.cc b/calibrations/calorimeter/calo_cdb/CaloCDB-GenStatus.cc index 335563c295..49bf3e3c4f 100644 --- a/calibrations/calorimeter/calo_cdb/CaloCDB-GenStatus.cc +++ b/calibrations/calorimeter/calo_cdb/CaloCDB-GenStatus.cc @@ -1,6 +1,7 @@ -#include "genStatus.h" +#include "GenStatus.h" #include +#include #include int main(int argc, const char* const argv[]) diff --git a/calibrations/calorimeter/calo_cdb/filter-datasets.cc b/calibrations/calorimeter/calo_cdb/FilterDatasets.cc similarity index 90% rename from calibrations/calorimeter/calo_cdb/filter-datasets.cc rename to calibrations/calorimeter/calo_cdb/FilterDatasets.cc index 38ce957c4e..5ac745f0e8 100644 --- a/calibrations/calorimeter/calo_cdb/filter-datasets.cc +++ b/calibrations/calorimeter/calo_cdb/FilterDatasets.cc @@ -1,14 +1,18 @@ -#include "filter-datasets.h" +#include "FilterDatasets.h" // -- My Utils -- #include "myUtils.h" -// c++ includes -- +// sPHENIX includes -- +#include +#include + +#include #include #include -#include #include +#include FilterDatasets::FilterDatasets(Bool_t debug) : m_debug(debug) @@ -30,21 +34,12 @@ void FilterDatasets::readRunInfo(const std::string &line) std::string FilterDatasets::getCalibration(const std::string &pl_type, uint64_t iov) { - if (!uti) - { - uti = std::make_unique(); - } - return uti->getUrl(pl_type, iov); -} + recoConsts *rc = recoConsts::instance(); + // Update the global timestamp flag for the current run in the loop + rc->set_uint64Flag("TIMESTAMP", iov); -int FilterDatasets::setGlobalTag(const std::string &tagname) -{ - if (!uti) - { - uti = std::make_unique(); - } - int iret = uti->setGlobalTag(tagname); - return iret; + // Fetch the calibration URL via CDBInterface + return CDBInterface::instance()->getUrl(pl_type); } void FilterDatasets::analyze(const std::string &input, const std::string &outputDir) @@ -142,8 +137,6 @@ void FilterDatasets::process(const std::string &input, const std::string &output std::cout << "Debug: " << ((m_debug) ? "True" : "False") << std::endl; std::cout << "#############################" << std::endl; - setGlobalTag("newcdbtag"); - std::filesystem::path input_filepath_obj(input); if (!myUtils::readCSV(input_filepath_obj, [this](const std::string &line) { this->readRunInfo(line); })) diff --git a/calibrations/calorimeter/calo_cdb/filter-datasets.h b/calibrations/calorimeter/calo_cdb/FilterDatasets.h similarity index 75% rename from calibrations/calorimeter/calo_cdb/filter-datasets.h rename to calibrations/calorimeter/calo_cdb/FilterDatasets.h index c3af89f1de..c92485e75e 100644 --- a/calibrations/calorimeter/calo_cdb/filter-datasets.h +++ b/calibrations/calorimeter/calo_cdb/FilterDatasets.h @@ -1,23 +1,16 @@ #ifndef CALOCDB_FILTERDATASETS_H #define CALOCDB_FILTERDATASETS_H -// -- sPHENIX includes -- -#include - -// -- ROOT includes -- -#include - // -- c++ includes -- #include -#include +#include #include -#include #include class FilterDatasets { public: - explicit FilterDatasets(Bool_t debug = false); + explicit FilterDatasets(bool debug = false); void process(const std::string &input, const std::string &output = "."); @@ -26,7 +19,6 @@ class FilterDatasets void readRunInfo(const std::string &line); std::string getCalibration(const std::string &pl_type, uint64_t iov); - int setGlobalTag(const std::string &tagname); std::vector> m_runInfo; std::map m_ctr; @@ -36,9 +28,7 @@ class FilterDatasets , "CEMC_hotTowers_fracBadChi2", "HCALIN_hotTowers_fracBadChi2", "HCALOUT_hotTowers_fracBadChi2" , "CEMC_ZSCrossCalib", "HCALIN_ZSCrossCalib", "HCALOUT_ZSCrossCalib"}; - Bool_t m_debug; - - std::unique_ptr uti{nullptr}; + bool m_debug; }; #endif diff --git a/calibrations/calorimeter/calo_cdb/genStatus.cc b/calibrations/calorimeter/calo_cdb/GenStatus.cc similarity index 99% rename from calibrations/calorimeter/calo_cdb/genStatus.cc rename to calibrations/calorimeter/calo_cdb/GenStatus.cc index a49703127a..a5cdf538f6 100644 --- a/calibrations/calorimeter/calo_cdb/genStatus.cc +++ b/calibrations/calorimeter/calo_cdb/GenStatus.cc @@ -1,4 +1,4 @@ -#include "genStatus.h" +#include "GenStatus.h" #include "geometry_constants.h" @@ -15,7 +15,6 @@ // c++ includes -- #include #include -#include #include #include diff --git a/calibrations/calorimeter/calo_cdb/genStatus.h b/calibrations/calorimeter/calo_cdb/GenStatus.h similarity index 100% rename from calibrations/calorimeter/calo_cdb/genStatus.h rename to calibrations/calorimeter/calo_cdb/GenStatus.h diff --git a/calibrations/calorimeter/calo_cdb/Makefile.am b/calibrations/calorimeter/calo_cdb/Makefile.am index 9fbea67179..0107211521 100644 --- a/calibrations/calorimeter/calo_cdb/Makefile.am +++ b/calibrations/calorimeter/calo_cdb/Makefile.am @@ -15,18 +15,22 @@ AM_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib64 \ `root-config --libs` +# Headers installed for use in macros and by other packages pkginclude_HEADERS = \ - genStatus.h \ - filter-datasets.h \ - geometry_constants.h \ + GenStatus.h \ + geometry_constants.h + +# Headers used only for building this library and its binaries +noinst_HEADERS = \ + FilterDatasets.h \ myUtils.h lib_LTLIBRARIES = \ libcalo_cdb.la libcalo_cdb_la_SOURCES = \ - genStatus.cc \ - filter-datasets.cc \ + GenStatus.cc \ + FilterDatasets.cc \ myUtils.cc libcalo_cdb_la_LIBADD = \ @@ -35,6 +39,7 @@ libcalo_cdb_la_LIBADD = \ -lcalo_io \ -lcdbobjects \ -lsphenixnpc \ + -lffamodules \ -lemcNoisyTowerFinder CaloCDB_GenStatus_SOURCES = CaloCDB-GenStatus.cc diff --git a/calibrations/calorimeter/calo_cdb/myUtils.cc b/calibrations/calorimeter/calo_cdb/myUtils.cc index 21a37ed595..3f495a4e7d 100644 --- a/calibrations/calorimeter/calo_cdb/myUtils.cc +++ b/calibrations/calorimeter/calo_cdb/myUtils.cc @@ -4,9 +4,12 @@ // root includes -- #include #include +#include +#include // c++ includes -- #include +#include TFitResultPtr myUtils::doGausFit(TH1 *hist, Double_t start, Double_t end, const std::string &name) { diff --git a/calibrations/calorimeter/calo_cdb/myUtils.h b/calibrations/calorimeter/calo_cdb/myUtils.h index 2799ab808f..a44d61984e 100644 --- a/calibrations/calorimeter/calo_cdb/myUtils.h +++ b/calibrations/calorimeter/calo_cdb/myUtils.h @@ -2,18 +2,19 @@ #define CALOCDB_MYUTILS_H // ROOT includes -- +#include #include -#include // -- c++ includes -- #include #include #include -#include #include #include #include +class TH1; + template concept InvocableWithString = std::invocable; @@ -39,7 +40,7 @@ class myUtils * @return true if the file was successfully opened and read, false otherwise. */ template // Using the more general concept for wider applicability - static Bool_t readCSV(const std::filesystem::path& filePath, Callable lineHandler, Bool_t skipHeader = true) + static bool readCSV(const std::filesystem::path& filePath, Callable lineHandler, bool skipHeader = true) { std::ifstream file(filePath); diff --git a/calibrations/calorimeter/calo_emc_noisy_tower/emcNoisyTowerFinder.cc b/calibrations/calorimeter/calo_emc_noisy_tower/emcNoisyTowerFinder.cc index 19809fedbb..533089f431 100644 --- a/calibrations/calorimeter/calo_emc_noisy_tower/emcNoisyTowerFinder.cc +++ b/calibrations/calorimeter/calo_emc_noisy_tower/emcNoisyTowerFinder.cc @@ -270,6 +270,16 @@ void emcNoisyTowerFinder::FindHot(const std::string &infilename, const std::stri } int val = h_hot->GetBinContent(i + 1, j + 1); float sigma = h_heatSigma->GetBinContent(i + 1, j + 1); + // For HCal only flag DEAD towers + if (Neta == 24 && val > 1) + { + if (Verbosity() > 0) + { + std::cout << "WARNING: Skipping Flagging for " << m_caloName << " Tower (" << j << ", " << i << ") with status = " << val << " and sigma = " << sigma << std::endl; + } + val = 0; + sigma = 0; + } cdbttree_out->SetIntValue(key, m_fieldname_out, val); cdbttree_out->SetFloatValue(key, m_caloName + "_sigma", sigma); } diff --git a/calibrations/calorimeter/calo_tower_slope/LiteCaloEval.cc b/calibrations/calorimeter/calo_tower_slope/LiteCaloEval.cc index 588a27b024..acffcc948a 100644 --- a/calibrations/calorimeter/calo_tower_slope/LiteCaloEval.cc +++ b/calibrations/calorimeter/calo_tower_slope/LiteCaloEval.cc @@ -14,7 +14,7 @@ #include #include -#include // for Double_t +#include // for Double_t #include #include #include @@ -548,7 +548,7 @@ void LiteCaloEval::Get_Histos(const std::string &infile, const std::string &outf if (!heta_tempp && i == 0) { - std::cout << " warning hist " << hist_name_p.c_str() << " not found" << std::endl; + std::cout << " warning hist " << hist_name_p << " not found" << std::endl; } /// assign heta_tempp to array of tower histos diff --git a/calibrations/framework/oncal/OnCal.cc b/calibrations/framework/fun4cal/CalReco.cc similarity index 75% rename from calibrations/framework/oncal/OnCal.cc rename to calibrations/framework/fun4cal/CalReco.cc index ae652adbc8..46ad141654 100644 --- a/calibrations/framework/oncal/OnCal.cc +++ b/calibrations/framework/fun4cal/CalReco.cc @@ -1,4 +1,4 @@ -#include "OnCal.h" +#include "CalReco.h" #include // for SubsysReco @@ -6,18 +6,18 @@ #include -OnCal::OnCal(const std::string &Name) +CalReco::CalReco(const std::string &Name) : SubsysReco(Name) { } -int OnCal::process_event(PHCompositeNode * /*topNode*/) +int CalReco::process_event(PHCompositeNode * /*topNode*/) { std::cout << "process_event(PHCompositeNode *topNode) not implemented by daughter class: " << Name() << std::endl; return -1; } -int OnCal::End(PHCompositeNode * /*topNode*/) +int CalReco::End(PHCompositeNode * /*topNode*/) { std::cout << "EndOfAnalysis not implemented by subsystem!" << std::endl; std::cout << "Use this signal for computing your calibrations and commit." << std::endl; @@ -26,7 +26,7 @@ int OnCal::End(PHCompositeNode * /*topNode*/) return 0; } -void OnCal::AddComment(const std::string &adcom) +void CalReco::AddComment(const std::string &adcom) { if (m_Comment.empty()) { @@ -40,7 +40,7 @@ void OnCal::AddComment(const std::string &adcom) return; } -int OnCal::CopyTables(const int /*FromRun*/, const int /*ToRun*/, const int /*commit*/) const +int CalReco::CopyTables(const int /*FromRun*/, const int /*ToRun*/, const int /*commit*/) const { std::cout << PHWHERE << " CopyTables not implemented" << std::endl << "this calibrator cannot copy its own tables" << std::endl; diff --git a/calibrations/framework/oncal/OnCal.h b/calibrations/framework/fun4cal/CalReco.h similarity index 90% rename from calibrations/framework/oncal/OnCal.h rename to calibrations/framework/fun4cal/CalReco.h index 454e240aaa..e2ba725884 100644 --- a/calibrations/framework/oncal/OnCal.h +++ b/calibrations/framework/fun4cal/CalReco.h @@ -1,5 +1,5 @@ -#ifndef ONCAL_ONCAL_H -#define ONCAL_ONCAL_H +#ifndef FUN4CAL_CALRECO_H +#define FUN4CAL_CALRECO_H #include #include @@ -7,10 +7,10 @@ #include // for pair #include -class OnCal : public SubsysReco +class CalReco : public SubsysReco { public: - ~OnCal() override = default; + ~CalReco() override = default; // These might be overwritten by everyone... int process_event(PHCompositeNode *topNode) override; @@ -47,7 +47,7 @@ class OnCal : public SubsysReco virtual std::vector GetLocalFileList() const { return localfilelist; } protected: - OnCal(const std::string &Name); // so noone can call it from outside + CalReco(const std::string &Name); // so noone can call it from outside unsigned int alldone{0}; std::string m_Comment; std::vector pdbcaltables; @@ -56,4 +56,4 @@ class OnCal : public SubsysReco std::vector localfilelist; }; -#endif /* ONCAL_ONCAL_H */ +#endif /* CALRECO_CALRECO_H */ diff --git a/calibrations/framework/oncal/OnCalDBCodes.h b/calibrations/framework/fun4cal/Fun4CalDBCodes.h similarity index 65% rename from calibrations/framework/oncal/OnCalDBCodes.h rename to calibrations/framework/fun4cal/Fun4CalDBCodes.h index 707c72f859..7964f6679c 100644 --- a/calibrations/framework/oncal/OnCalDBCodes.h +++ b/calibrations/framework/fun4cal/Fun4CalDBCodes.h @@ -1,7 +1,7 @@ -#ifndef ONCALDBCODES_H__ -#define ONCALDBCODES_H__ +#ifndef FUN4CAL_FUN4CALDBCODES_H +#define FUN4CAL_FUN4CALDBCODES_H -namespace OnCalDBCodes +namespace Fun4CalDBCodes { enum { diff --git a/calibrations/framework/fun4cal/Fun4CalHistoBinDefs.h b/calibrations/framework/fun4cal/Fun4CalHistoBinDefs.h new file mode 100644 index 0000000000..36c62bd3ec --- /dev/null +++ b/calibrations/framework/fun4cal/Fun4CalHistoBinDefs.h @@ -0,0 +1,16 @@ +#ifndef FUN4CAL_FUN4CALHISTOBINDEFS_H +#define FUN4CAL_FUN4CALHISTOBINDEFS_H + +namespace Fun4CalHistoBinDefs +{ + enum + { + FIRSTRUNBIN = 1, + LASTRUNBIN, + BORTIMEBIN, + EORTIMEBIN, + LASTBINPLUSONE + }; +}; + +#endif /* FUN4CAL_FUN4CALHISTOBINDEFS_H */ diff --git a/calibrations/framework/oncal/OnCalServer.cc b/calibrations/framework/fun4cal/Fun4CalServer.cc similarity index 89% rename from calibrations/framework/oncal/OnCalServer.cc rename to calibrations/framework/fun4cal/Fun4CalServer.cc index 5593b84188..c3612641dc 100644 --- a/calibrations/framework/oncal/OnCalServer.cc +++ b/calibrations/framework/fun4cal/Fun4CalServer.cc @@ -1,7 +1,7 @@ -#include "OnCalServer.h" -#include "OnCal.h" -#include "OnCalDBCodes.h" -#include "OnCalHistoBinDefs.h" +#include "Fun4CalServer.h" +#include "CalReco.h" +#include "Fun4CalDBCodes.h" +#include "Fun4CalHistoBinDefs.h" #include #include @@ -17,7 +17,7 @@ #include -#include // for Stat_t +#include // for Stat_t #include // for TDirectoryAtomicAdapter #include #include @@ -53,33 +53,33 @@ namespace odbc::Connection *DBconnection{nullptr}; } // namespace -OnCalServer *OnCalServer::instance() +Fun4CalServer *Fun4CalServer::instance() { if (__instance) { - OnCalServer *oncal = dynamic_cast(__instance); + Fun4CalServer *oncal = dynamic_cast(__instance); return oncal; } - __instance = new OnCalServer(); - OnCalServer *oncal = dynamic_cast(__instance); + __instance = new Fun4CalServer(); + Fun4CalServer *oncal = dynamic_cast(__instance); return oncal; } //--------------------------------------------------------------------- -OnCalServer::OnCalServer(const std::string &name) +Fun4CalServer::Fun4CalServer(const std::string &name) : Fun4AllServer(name) - , OnCalServerVars(new TH1D("OnCalServerVars", "OnCalServerVars", OnCalHistoBinDefs::LASTBINPLUSONE, -0.5, (int) (OnCalHistoBinDefs::LASTBINPLUSONE) -0.5)) + , Fun4CalServerVars(new TH1D("Fun4CalServerVars", "Fun4CalServerVars", Fun4CalHistoBinDefs::LASTBINPLUSONE, -0.5, (int) (Fun4CalHistoBinDefs::LASTBINPLUSONE) -0.5)) { beginTimeStamp.setTics(0); endTimeStamp.setTics(0); - Fun4AllServer::registerHisto(OnCalServerVars); + Fun4AllServer::registerHisto(Fun4CalServerVars); return; } //--------------------------------------------------------------------- -OnCalServer::~OnCalServer() +Fun4CalServer::~Fun4CalServer() { delete DBconnection; return; @@ -87,7 +87,7 @@ OnCalServer::~OnCalServer() //--------------------------------------------------------------------- PHTimeStamp * -OnCalServer::GetEndValidityTS() +Fun4CalServer::GetEndValidityTS() { if (endTimeStamp.getTics()) { @@ -100,7 +100,7 @@ OnCalServer::GetEndValidityTS() } //--------------------------------------------------------------------- -PHTimeStamp *OnCalServer::GetBeginValidityTS() +PHTimeStamp *Fun4CalServer::GetBeginValidityTS() { if (beginTimeStamp.getTics()) { @@ -113,7 +113,7 @@ PHTimeStamp *OnCalServer::GetBeginValidityTS() } //--------------------------------------------------------------------- -void OnCalServer::dumpHistos() +void Fun4CalServer::dumpHistos() { std::ostringstream filename; std::string fileprefix = "./"; @@ -137,7 +137,7 @@ void OnCalServer::dumpHistos() << "_" << iter->first << ".root"; TFile *hfile = new TFile(filename.str().c_str(), "RECREATE", "Created by Online Calibrator", compress); - std::cout << "OnCalServer::dumpHistos() Output root file: " << filename.str() << std::endl; + std::cout << "Fun4CalServer::dumpHistos() Output root file: " << filename.str() << std::endl; for (siter = (iter->second).begin(); siter != (iter->second).end(); ++siter) { histo = dynamic_cast(getHisto(*siter)); @@ -159,7 +159,7 @@ void OnCalServer::dumpHistos() return; } -void OnCalServer::registerHisto(TH1 *h1d, OnCal *Calibrator, const int replace) +void Fun4CalServer::registerHisto(TH1 *h1d, CalReco *Calibrator, const int replace) { if (Calibrator) { @@ -174,7 +174,7 @@ void OnCalServer::registerHisto(TH1 *h1d, OnCal *Calibrator, const int replace) { std::set newset; newset.insert(h1d->GetName()); - newset.insert("OnCalServerVars"); + newset.insert("Fun4CalServerVars"); calibratorhistomap[calibratorname] = newset; } } @@ -182,13 +182,13 @@ void OnCalServer::registerHisto(TH1 *h1d, OnCal *Calibrator, const int replace) return; } -void OnCalServer::unregisterHisto(const std::string &calibratorname) +void Fun4CalServer::unregisterHisto(const std::string &calibratorname) { calibratorhistomap.erase(calibratorname); return; } -int OnCalServer::process_event() +int Fun4CalServer::process_event() { Fun4AllServer::process_event(); int i = 0; @@ -201,7 +201,7 @@ int OnCalServer::process_event() std::vector >::const_iterator iter; for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) { - OnCal *oncal = dynamic_cast(iter->first); + CalReco *oncal = dynamic_cast(iter->first); if (oncal) { ical++; @@ -220,7 +220,7 @@ int OnCalServer::process_event() return i; } -int OnCalServer::BeginRun(const int runno) +int Fun4CalServer::BeginRun(const int runno) { if (runno <= 0) { @@ -291,10 +291,10 @@ int OnCalServer::BeginRun(const int runno) << " - send e-mail to off-l with your macro" << std::endl; exit(1); } - OnCal *oncal = dynamic_cast((*iter).first); + CalReco *oncal = dynamic_cast((*iter).first); if (oncal) { - std::string table = "OnCal"; + std::string table = "CalReco"; table += (*iter).first->Name(); check_create_subsystable(table); insertRunNumInDB(table, runNum); @@ -312,7 +312,7 @@ int OnCalServer::BeginRun(const int runno) else { std::ostringstream stringarg; - stringarg << OnCalDBCodes::STARTED; + stringarg << Fun4CalDBCodes::STARTED; for (runiter = runlist.begin(); runiter != runlist.end(); ++runiter) { updateDB(successTable, calibname, stringarg.str(), *runiter); @@ -328,7 +328,7 @@ int OnCalServer::BeginRun(const int runno) else { rc->set_IntFlag("RUNNUMBER", oncalrun); - // rc->set_TimeStamp(OnCalBORTimeStamp); + // rc->set_TimeStamp(CalRecoBORTimeStamp); } if (!droplist.contains((*iter).first->Name())) { @@ -344,17 +344,17 @@ int OnCalServer::BeginRun(const int runno) gROOT->cd(currdir.c_str()); rc->set_IntFlag("RUNNUMBER", oncalrun); - // rc->set_TimeStamp(OnCalBORTimeStamp); - if (OnCalServerVars->GetBinContent(OnCalHistoBinDefs::FIRSTRUNBIN) == 0) + // rc->set_TimeStamp(CalRecoBORTimeStamp); + if (Fun4CalServerVars->GetBinContent(Fun4CalHistoBinDefs::FIRSTRUNBIN) == 0) { - OnCalServerVars->SetBinContent(OnCalHistoBinDefs::FIRSTRUNBIN, runno); - OnCalServerVars->SetBinContent(OnCalHistoBinDefs::BORTIMEBIN, (Stat_t) OnCalBORTimeStamp.getTics()); + Fun4CalServerVars->SetBinContent(Fun4CalHistoBinDefs::FIRSTRUNBIN, runno); + Fun4CalServerVars->SetBinContent(Fun4CalHistoBinDefs::BORTIMEBIN, (Stat_t) OnCalBORTimeStamp.getTics()); } - OnCalServerVars->SetBinContent(OnCalHistoBinDefs::LASTRUNBIN, (Stat_t) runno); + Fun4CalServerVars->SetBinContent(Fun4CalHistoBinDefs::LASTRUNBIN, (Stat_t) runno); ts = runTime->getEndTime(runno); if (ts) { - OnCalServerVars->SetBinContent(OnCalHistoBinDefs::EORTIMEBIN, (Stat_t) ts->getTics()); + Fun4CalServerVars->SetBinContent(Fun4CalHistoBinDefs::EORTIMEBIN, (Stat_t) ts->getTics()); delete ts; } @@ -367,7 +367,7 @@ int OnCalServer::BeginRun(const int runno) return i; } -int OnCalServer::End() +int Fun4CalServer::End() { if (nEvents == 0) { @@ -404,7 +404,7 @@ int OnCalServer::End() currdir = gDirectory->GetPath(); for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) { - OnCal *oncal = dynamic_cast((*iter).first); + CalReco *oncal = dynamic_cast((*iter).first); if (!oncal) { continue; @@ -427,17 +427,17 @@ int OnCalServer::End() // report success database the status of the calibration if (recordDB) { - std::string table = "OnCal"; + std::string table = "CalReco"; table += CalibratorName; std::ostringstream stringarg; - if (databasecommitstatus == OnCalDBCodes::SUCCESS) + if (databasecommitstatus == Fun4CalDBCodes::SUCCESS) { - stringarg << OnCalDBCodes::COVERED; + stringarg << Fun4CalDBCodes::COVERED; } else { - stringarg << OnCalDBCodes::FAILED; + stringarg << Fun4CalDBCodes::FAILED; } std::set::const_iterator runiter; for (runiter = runlist.begin(); runiter != runlist.end(); ++runiter) @@ -503,7 +503,7 @@ int OnCalServer::End() } //--------------------------------------------------------------------- -void OnCalServer::Print(const std::string &what) const +void Fun4CalServer::Print(const std::string &what) const { Fun4AllServer::Print(what); if (what == "ALL" || what == "CALIBRATOR") @@ -513,13 +513,13 @@ void OnCalServer::Print(const std::string &what) const std::cout << "--------------------------------------" << std::endl << std::endl; - std::cout << "List of Calibrators in OnCalServer:" << std::endl; + std::cout << "List of Calibrators in Fun4CalServer:" << std::endl; std::vector >::const_iterator miter; for (miter = Subsystems.begin(); miter != Subsystems.end(); ++miter) { - OnCal *oncal = dynamic_cast((*miter).first); + CalReco *oncal = dynamic_cast((*miter).first); if (oncal) { std::cout << oncal->Name() << std::endl; @@ -534,7 +534,7 @@ void OnCalServer::Print(const std::string &what) const std::cout << "--------------------------------------" << std::endl << std::endl; - std::cout << "List of required Calibrations in OnCalServer:" << std::endl; + std::cout << "List of required Calibrations in Fun4CalServer:" << std::endl; std::map >::const_iterator iter; std::set::const_iterator siter; @@ -553,7 +553,7 @@ void OnCalServer::Print(const std::string &what) const { std::cout << "--------------------------------------" << std::endl << std::endl; - std::cout << "List of PRDF Files in OnCalServer:" << std::endl; + std::cout << "List of PRDF Files in Fun4CalServer:" << std::endl; for (Fun4AllSyncManager *sync : SyncManagers) { for (Fun4AllInputManager *inmgr : sync->GetInputManagers()) @@ -569,7 +569,7 @@ void OnCalServer::Print(const std::string &what) const { std::cout << "--------------------------------------" << std::endl << std::endl; - std::cout << "List of Run Numbers in OnCalServer:" << std::endl; + std::cout << "List of Run Numbers in Fun4CalServer:" << std::endl; std::set::const_iterator liter; for (liter = runlist.begin(); liter != runlist.end(); ++liter) { @@ -580,7 +580,7 @@ void OnCalServer::Print(const std::string &what) const return; } -void OnCalServer::printStamps() +void Fun4CalServer::printStamps() { std::cout << std::endl << std::endl; @@ -605,7 +605,7 @@ void OnCalServer::printStamps() //--------------------------------------------------------------------- -void OnCalServer::RunNumber(const int runnum) +void Fun4CalServer::RunNumber(const int runnum) { runNum = runnum; SetBorTime(runnum); @@ -641,7 +641,7 @@ void OnCalServer::RunNumber(const int runnum) //--------------------------------------------------------------------- -bool OnCalServer::connectDB() +bool Fun4CalServer::connectDB() { if (DBconnection) { @@ -660,7 +660,7 @@ bool OnCalServer::connectDB() } catch (odbc::SQLException &e) { - std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << "Cannot connect to " << database << std::endl; std::cout << e.getMessage() << std::endl; std::cout << "countdown: " << countdown << std::endl; countdown--; @@ -673,12 +673,12 @@ bool OnCalServer::connectDB() std::cout << "could not connect to DB after 10 tries in 1000 secs, giving up" << std::endl; exit(-1); } - std::cout << "connected to " << database.c_str() << " database." << std::endl; + std::cout << "connected to " << database << " database." << std::endl; return true; } //--------------------------------------------------------------------- -int OnCalServer::DisconnectDB() +int Fun4CalServer::DisconnectDB() { delete DBconnection; DBconnection = nullptr; @@ -686,7 +686,7 @@ int OnCalServer::DisconnectDB() } //--------------------------------------------------------------------- -bool OnCalServer::insertRunNumInDB(const std::string &DBtable, const int runno) +bool Fun4CalServer::insertRunNumInDB(const std::string &DBtable, const int runno) { if (findRunNumInDB(DBtable, runno)) { @@ -705,7 +705,7 @@ bool OnCalServer::insertRunNumInDB(const std::string &DBtable, const int runno) if (Verbosity() == 1) { - std::cout << "in function OnCalServer::insertRunNumInDB() ... "; + std::cout << "in function Fun4CalServer::insertRunNumInDB() ... "; std::cout << "executing SQL statements ..." << std::endl; std::cout << cmd.str() << std::endl; } @@ -725,7 +725,7 @@ bool OnCalServer::insertRunNumInDB(const std::string &DBtable, const int runno) //--------------------------------------------------------------------- -bool OnCalServer::findRunNumInDB(const std::string &DBtable, const int runno) +bool Fun4CalServer::findRunNumInDB(const std::string &DBtable, const int runno) { if (!DBconnection) { @@ -743,7 +743,7 @@ bool OnCalServer::findRunNumInDB(const std::string &DBtable, const int runno) if (Verbosity() == 1) { - std::cout << "in function OnCalServer::findRunNumInDB() "; + std::cout << "in function Fun4CalServer::findRunNumInDB() "; std::cout << "executing SQL statement ..." << std::endl << cmd.str() << std::endl; } @@ -779,7 +779,7 @@ bool OnCalServer::findRunNumInDB(const std::string &DBtable, const int runno) return true; } -bool OnCalServer::updateDBRunRange(const std::string &table, const std::string &column, const int entry, const int firstrun, const int lastrun) +bool Fun4CalServer::updateDBRunRange(const std::string &table, const std::string &column, const int entry, const int firstrun, const int lastrun) { if (!DBconnection) { @@ -801,7 +801,7 @@ bool OnCalServer::updateDBRunRange(const std::string &table, const std::string & if (Verbosity() == 1) { - std::cout << "in function OnCalServer::updateDB() ... "; + std::cout << "in function Fun4CalServer::updateDB() ... "; std::cout << "executin SQL statement ... " << std::endl; std::cout << command << std::endl; } @@ -822,7 +822,7 @@ bool OnCalServer::updateDBRunRange(const std::string &table, const std::string & //--------------------------------------------------------------------- -bool OnCalServer::updateDB(const std::string &table, const std::string &column, int entry) +bool Fun4CalServer::updateDB(const std::string &table, const std::string &column, int entry) { if (!DBconnection) { @@ -842,7 +842,7 @@ bool OnCalServer::updateDB(const std::string &table, const std::string &column, if (Verbosity() == 1) { - std::cout << "in function OnCalServer::updateDB() ... "; + std::cout << "in function Fun4CalServer::updateDB() ... "; std::cout << "executin SQL statement ... " << std::endl; std::cout << command.Data() << std::endl; } @@ -862,7 +862,7 @@ bool OnCalServer::updateDB(const std::string &table, const std::string &column, } //--------------------------------------------------------------------- -bool OnCalServer::updateDB(const std::string &table, const std::string &column, bool entry) +bool Fun4CalServer::updateDB(const std::string &table, const std::string &column, bool entry) { if (!DBconnection) { @@ -881,7 +881,7 @@ bool OnCalServer::updateDB(const std::string &table, const std::string &column, if (Verbosity() == 1) { - std::cout << "in function OnCalServer::updateDB() ... "; + std::cout << "in function Fun4CalServer::updateDB() ... "; std::cout << "executin SQL statement ... " << std::endl; std::cout << command.Data() << std::endl; } @@ -902,7 +902,7 @@ bool OnCalServer::updateDB(const std::string &table, const std::string &column, //--------------------------------------------------------------------- -int OnCalServer::updateDB(const std::string &table, const std::string &column, +int Fun4CalServer::updateDB(const std::string &table, const std::string &column, const time_t ticks) { if (!DBconnection) @@ -924,7 +924,7 @@ int OnCalServer::updateDB(const std::string &table, const std::string &column, if (Verbosity() == 1) { - std::cout << "in function OnCalServer::updateDB() ... "; + std::cout << "in function Fun4CalServer::updateDB() ... "; std::cout << "executin SQL statement ... " << std::endl; std::cout << cmd.str() << std::endl; } @@ -942,7 +942,7 @@ int OnCalServer::updateDB(const std::string &table, const std::string &column, } //--------------------------------------------------------------------- -bool OnCalServer::updateDB(const std::string &table, const std::string &column, +bool Fun4CalServer::updateDB(const std::string &table, const std::string &column, const std::string &entry, const int runno, const bool append) { if (!DBconnection) @@ -971,7 +971,7 @@ bool OnCalServer::updateDB(const std::string &table, const std::string &column, } catch (odbc::SQLException &e) { - std::cout << "in function OnCalServer::updateDB() ... "; + std::cout << "in function Fun4CalServer::updateDB() ... "; std::cout << "run number " << runno << "not found in DB" << std::endl; std::cout << e.getMessage() << std::endl; } @@ -984,7 +984,7 @@ bool OnCalServer::updateDB(const std::string &table, const std::string &column, } catch (odbc::SQLException &e) { - std::cout << "in function OnCalServer::updateDB() ... " << std::endl; + std::cout << "in function Fun4CalServer::updateDB() ... " << std::endl; std::cout << "nothing to append." << std::endl; std::cout << e.getMessage() << std::endl; } @@ -1003,7 +1003,7 @@ bool OnCalServer::updateDB(const std::string &table, const std::string &column, if (Verbosity() == 1) { - std::cout << "in function OnCalServer::updateDB() ... "; + std::cout << "in function Fun4CalServer::updateDB() ... "; std::cout << "executin SQL statement ... " << std::endl; std::cout << cmd.str() << std::endl; } @@ -1023,7 +1023,7 @@ bool OnCalServer::updateDB(const std::string &table, const std::string &column, //--------------------------------------------------------------------- -int OnCalServer::check_create_subsystable(const std::string &tablename) +int Fun4CalServer::check_create_subsystable(const std::string &tablename) { if (!connectDB()) { @@ -1110,7 +1110,7 @@ int OnCalServer::check_create_subsystable(const std::string &tablename) return 0; } -int OnCalServer::add_calibrator_to_statustable(const std::string &calibratorname) +int Fun4CalServer::add_calibrator_to_statustable(const std::string &calibratorname) { if (!connectDB()) { @@ -1139,7 +1139,7 @@ int OnCalServer::add_calibrator_to_statustable(const std::string &calibratorname } cmd.str(""); cmd << "ALTER TABLE " << successTable << " ALTER COLUMN " - << calibname << " SET DEFAULT " << OnCalDBCodes::INIT; + << calibname << " SET DEFAULT " << Fun4CalDBCodes::INIT; try { stmt->executeUpdate(cmd.str()); @@ -1152,7 +1152,7 @@ int OnCalServer::add_calibrator_to_statustable(const std::string &calibratorname } cmd.str(""); cmd << "UPDATE " << successTable << " SET " - << calibname << " = " << OnCalDBCodes::INIT; + << calibname << " = " << Fun4CalDBCodes::INIT; try { stmt->executeUpdate(cmd.str()); @@ -1167,7 +1167,7 @@ int OnCalServer::add_calibrator_to_statustable(const std::string &calibratorname return 0; } -int OnCalServer::check_calibrator_in_statustable(const std::string &calibratorname) +int Fun4CalServer::check_calibrator_in_statustable(const std::string &calibratorname) { // replace this contraption by this sql command which returns 1 row if column exists // select * from information_schema.columns where table_name = 'oncal_status' and column_name = 'svxstripdeadmapcal'; @@ -1213,7 +1213,7 @@ int OnCalServer::check_calibrator_in_statustable(const std::string &calibratorna return -1; } -int OnCalServer::check_create_successtable(const std::string &tablename) +int Fun4CalServer::check_create_successtable(const std::string &tablename) { if (!connectDB()) { @@ -1257,7 +1257,7 @@ int OnCalServer::check_create_successtable(const std::string &tablename) return 0; } -void OnCalServer::recordDataBase(const bool bookkeep) +void Fun4CalServer::recordDataBase(const bool bookkeep) { recordDB = bookkeep; if (recordDB) @@ -1267,20 +1267,20 @@ void OnCalServer::recordDataBase(const bool bookkeep) return; } -void OnCalServer::BeginTimeStamp(const PHTimeStamp &TimeStp) +void Fun4CalServer::BeginTimeStamp(const PHTimeStamp &TimeStp) { beginTimeStamp = TimeStp; - std::cout << "OnCalServer::BeginTimeStamp: Setting BOR TimeStamp to " << beginTimeStamp << std::endl; + std::cout << "Fun4CalServer::BeginTimeStamp: Setting BOR TimeStamp to " << beginTimeStamp << std::endl; } -void OnCalServer::EndTimeStamp(const PHTimeStamp &TimeStp) +void Fun4CalServer::EndTimeStamp(const PHTimeStamp &TimeStp) { endTimeStamp = TimeStp; - std::cout << "OnCalServer::EndTimeStamp: Setting EOR TimeStamp to " << endTimeStamp << std::endl; + std::cout << "Fun4CalServer::EndTimeStamp: Setting EOR TimeStamp to " << endTimeStamp << std::endl; } PHTimeStamp * -OnCalServer::GetLastGoodRunTS(OnCal *calibrator, const int irun) +Fun4CalServer::GetLastGoodRunTS(CalReco *calibrator, const int irun) { PHTimeStamp *ts = nullptr; if (!connectDB()) @@ -1324,7 +1324,7 @@ OnCalServer::GetLastGoodRunTS(OnCal *calibrator, const int irun) return ts; } -int OnCalServer::SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const int commit) +int Fun4CalServer::SyncCalibTimeStampsToOnCal(const CalReco *calibrator, const int commit) { std::vector caltab; calibrator->GetPdbCalTables(caltab); @@ -1337,7 +1337,7 @@ int OnCalServer::SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const int c return 0; } -int OnCalServer::SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const std::string &table, const int commit) +int Fun4CalServer::SyncCalibTimeStampsToOnCal(const CalReco *calibrator, const std::string &table, const int commit) { std::string name = calibrator->Name(); odbc::Connection *con = nullptr; @@ -1349,7 +1349,7 @@ int OnCalServer::SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const std:: } catch (odbc::SQLException &e) { - std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << "Cannot connect to " << database << std::endl; std::cout << e.getMessage() << std::endl; return -1; } @@ -1500,7 +1500,7 @@ int OnCalServer::SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const std:: return 0; } -int OnCalServer::SyncOncalTimeStampsToRunDB(const int commit) +int Fun4CalServer::SyncOncalTimeStampsToRunDB(const int commit) { odbc::Connection *con = nullptr; RunToTime *rt = RunToTime::instance(); @@ -1511,7 +1511,7 @@ int OnCalServer::SyncOncalTimeStampsToRunDB(const int commit) } catch (odbc::SQLException &e) { - std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << "Cannot connect to " << database << std::endl; std::cout << e.getMessage() << std::endl; return -1; } @@ -1636,13 +1636,13 @@ int OnCalServer::SyncOncalTimeStampsToRunDB(const int commit) return 0; } -int OnCalServer::CopyTables(const OnCal *calibrator, const int FromRun, const int ToRun, const int commit) +int Fun4CalServer::CopyTables(const CalReco *calibrator, const int FromRun, const int ToRun, const int commit) { int iret = calibrator->CopyTables(FromRun, ToRun, commit); return iret; } -int OnCalServer::CreateCalibration(OnCal *calibrator, const int myrunnumber, const std::string &what, const int commit) +int Fun4CalServer::CreateCalibration(CalReco *calibrator, const int myrunnumber, const std::string &what, const int commit) { int iret = -1; runNum = myrunnumber; @@ -1703,7 +1703,7 @@ int OnCalServer::CreateCalibration(OnCal *calibrator, const int myrunnumber, con std::cout << "updating oncal status tables for " << runnumber << std::endl; if (commit) { - CreateCalibrationUpdateStatus(calibrator, table, tablecomment, OnCalDBCodes::SUBSYSTEM); + CreateCalibrationUpdateStatus(calibrator, table, tablecomment, Fun4CalDBCodes::SUBSYSTEM); } } else @@ -1711,7 +1711,7 @@ int OnCalServer::CreateCalibration(OnCal *calibrator, const int myrunnumber, con std::cout << "Calibratior " << calibrator->Name() << " for run " << runnumber << " failed" << std::endl; if (commit) { - CreateCalibrationUpdateStatus(calibrator, table, tablecomment, OnCalDBCodes::FAILED); + CreateCalibrationUpdateStatus(calibrator, table, tablecomment, Fun4CalDBCodes::FAILED); } } } @@ -1723,7 +1723,7 @@ int OnCalServer::CreateCalibration(OnCal *calibrator, const int myrunnumber, con return iret; } -void OnCalServer::CreateCalibrationUpdateStatus(OnCal *calibrator, const std::string &table, const std::string &tablecomment, const int dbcode) +void Fun4CalServer::CreateCalibrationUpdateStatus(CalReco *calibrator, const std::string &table, const std::string &tablecomment, const int dbcode) { updateDB(successTable, calibrator->Name(), dbcode); insertRunNumInDB(table, RunNumber()); @@ -1766,7 +1766,7 @@ void OnCalServer::CreateCalibrationUpdateStatus(OnCal *calibrator, const std::st return; } -int OnCalServer::ClosestGoodRun(OnCal *calibrator, const int irun, const int previous) +int Fun4CalServer::ClosestGoodRun(CalReco *calibrator, const int irun, const int previous) { RunToTime *rt = RunToTime::instance(); PHTimeStamp *ts = rt->getBeginTime(irun); @@ -1906,7 +1906,7 @@ int OnCalServer::ClosestGoodRun(OnCal *calibrator, const int irun, const int pre return closestrun; } -int OnCalServer::OverwriteCalibration(OnCal *calibrator, const int runno, const int commit, const int FromRun) +int Fun4CalServer::OverwriteCalibration(CalReco *calibrator, const int runno, const int commit, const int FromRun) { if (FromRun < 0) { @@ -1916,7 +1916,7 @@ int OnCalServer::OverwriteCalibration(OnCal *calibrator, const int runno, const return iret; } -int OnCalServer::FixMissingCalibration(OnCal *calibrator, const int runno, const int commit, const int fromrun) +int Fun4CalServer::FixMissingCalibration(CalReco *calibrator, const int runno, const int commit, const int fromrun) { int iret = -1; // find this run in oncal_status @@ -1987,11 +1987,11 @@ int OnCalServer::FixMissingCalibration(OnCal *calibrator, const int runno, const int newstatus = 0; if (FromRun < runno) { - newstatus = OnCalDBCodes::COPIEDPREVIOUS; + newstatus = Fun4CalDBCodes::COPIEDPREVIOUS; } else { - newstatus = OnCalDBCodes::COPIEDLATER; + newstatus = Fun4CalDBCodes::COPIEDLATER; } std::string table = "OnCal"; table += calibrator->Name(); @@ -2016,7 +2016,7 @@ int OnCalServer::FixMissingCalibration(OnCal *calibrator, const int runno, const return iret; } -int OnCalServer::SetBorTime(const int runno) +int Fun4CalServer::SetBorTime(const int runno) { // recoConsts *rc = recoConsts::instance(); RunToTime *runTime = RunToTime::instance(); @@ -2033,7 +2033,7 @@ int OnCalServer::SetBorTime(const int runno) // enter begin run timestamp into rc flags PHTimeStamp BeginRunTimeStamp(*BorTimeStp); // rc->set_TimeStamp(BeginRunTimeStamp); - std::cout << "OnCalServer::SetBorTime from RunToTime was found for run : " << runno << " to "; + std::cout << "Fun4CalServer::SetBorTime from RunToTime was found for run : " << runno << " to "; BeginRunTimeStamp.print(); std::cout << std::endl; @@ -2041,7 +2041,7 @@ int OnCalServer::SetBorTime(const int runno) return 0; } -int OnCalServer::SetEorTime(const int runno) +int Fun4CalServer::SetEorTime(const int runno) { // recoConsts *rc = recoConsts::instance(); RunToTime *runTime = RunToTime::instance(); @@ -2065,14 +2065,14 @@ int OnCalServer::SetEorTime(const int runno) EorTimeStp->setTics(eorticks); } EndTimeStamp(*EorTimeStp); - std::cout << "OnCalServer::SetEorTime: setting eor time to "; + std::cout << "Fun4CalServer::SetEorTime: setting eor time to "; EorTimeStp->print(); std::cout << std::endl; delete EorTimeStp; return 0; } -int OnCalServer::GetRunTimeTicks(const int runno, time_t &borticks, time_t &eorticks) +int Fun4CalServer::GetRunTimeTicks(const int runno, time_t &borticks, time_t &eorticks) { RunToTime *runTime = RunToTime::instance(); PHTimeStamp *TimeStp(runTime->getBeginTime(runno)); @@ -2102,7 +2102,7 @@ int OnCalServer::GetRunTimeTicks(const int runno, time_t &borticks, time_t &eort return 0; } -int OnCalServer::requiredCalibration(SubsysReco *reco, const std::string &calibratorname) +int Fun4CalServer::requiredCalibration(SubsysReco *reco, const std::string &calibratorname) { std::map >::iterator iter; if (check_calibrator_in_statustable(calibratorname)) @@ -2124,7 +2124,7 @@ int OnCalServer::requiredCalibration(SubsysReco *reco, const std::string &calibr return 0; } -int OnCalServer::FindClosestCalibratedRun(const int irun) +int Fun4CalServer::FindClosestCalibratedRun(const int irun) { RunToTime *rt = RunToTime::instance(); PHTimeStamp *ts = rt->getBeginTime(irun); @@ -2261,7 +2261,7 @@ int OnCalServer::FindClosestCalibratedRun(const int irun) return closestrun; } -int OnCalServer::FillRunListFromFileList() +int Fun4CalServer::FillRunListFromFileList() { for (Fun4AllSyncManager *sync : SyncManagers) { @@ -2277,7 +2277,7 @@ int OnCalServer::FillRunListFromFileList() return 0; } -int OnCalServer::AdjustRichTimeStampForMultipleRuns() +int Fun4CalServer::AdjustRichTimeStampForMultipleRuns() { int firstrun = *runlist.begin(); int lastrun = *runlist.rbegin(); @@ -2289,7 +2289,7 @@ int OnCalServer::AdjustRichTimeStampForMultipleRuns() GetRunTimeTicks(firstrun, beginticks, dummy); GetRunTimeTicks(lastrun, dummy, endticks); std::ostringstream stringarg; - stringarg << OnCalDBCodes::COVERED; + stringarg << Fun4CalDBCodes::COVERED; // std::set::const_iterator runiter; /* for (runiter = runlist.begin(); runiter != runlist.end(); runiter++) @@ -2297,7 +2297,7 @@ int OnCalServer::AdjustRichTimeStampForMultipleRuns() updateDB(successTable, "RichCal", stringarg.str(), *runiter); } stringarg.str(""); - stringarg << OnCalDBCodes::SUCCESS; + stringarg << Fun4CalDBCodes::SUCCESS; updateDB(successTable, "RichCal", stringarg.str(), firstrun); */ @@ -2322,7 +2322,7 @@ int OnCalServer::AdjustRichTimeStampForMultipleRuns() } catch (odbc::SQLException& e) { - std::cout << "Cannot connect to " << database.c_str() << std::endl; + std::cout << "Cannot connect to " << database << std::endl; std::cout << e.getMessage() << std::endl; return -1; } @@ -2378,7 +2378,7 @@ int OnCalServer::AdjustRichTimeStampForMultipleRuns() return 0; } -int OnCalServer::GetCalibStatus(const std::string &calibname, const int runno) +int Fun4CalServer::GetCalibStatus(const std::string &calibname, const int runno) { int iret = -3; if (!connectDB()) @@ -2417,7 +2417,7 @@ int OnCalServer::GetCalibStatus(const std::string &calibname, const int runno) return iret; } -void OnCalServer::TestMode(const int i) +void Fun4CalServer::TestMode(const int i) { const char *logname = getenv("LOGNAME"); if (logname) diff --git a/calibrations/framework/oncal/OnCalServer.h b/calibrations/framework/fun4cal/Fun4CalServer.h similarity index 77% rename from calibrations/framework/oncal/OnCalServer.h rename to calibrations/framework/fun4cal/Fun4CalServer.h index 890901207c..47e0777ab8 100644 --- a/calibrations/framework/oncal/OnCalServer.h +++ b/calibrations/framework/fun4cal/Fun4CalServer.h @@ -1,5 +1,5 @@ -#ifndef ONCAL_ONCALSERVER_H -#define ONCAL_ONCALSERVER_H +#ifndef FUN4CAL_FUN4CALSERVER_H +#define FUN4CAL_FUN4CALSERVER_H #include #include @@ -10,7 +10,7 @@ #include #include -class OnCal; +class CalReco; class SubsysReco; class TH1; @@ -23,13 +23,13 @@ namespace fetchrun }; }; -class OnCalServer : public Fun4AllServer +class Fun4CalServer : public Fun4AllServer { public: - static OnCalServer *instance(); - ~OnCalServer() override; + static Fun4CalServer *instance(); + ~Fun4CalServer() override; using Fun4AllServer::registerHisto; - void registerHisto(TH1 *h1d, OnCal *Calibrator, const int replace = 0); + void registerHisto(TH1 *h1d, CalReco *Calibrator, const int replace = 0); void unregisterHisto(const std::string &calibratorname); void Print(const std::string &what = "ALL") const override; @@ -43,7 +43,7 @@ class OnCalServer : public Fun4AllServer PHTimeStamp *GetBeginValidityTS(); void printStamps(); - PHTimeStamp *GetLastGoodRunTS(OnCal *calibrator, const int irun); + PHTimeStamp *GetLastGoodRunTS(CalReco *calibrator, const int irun); void recordDataBase(const bool bookkeep = false); @@ -60,13 +60,13 @@ class OnCalServer : public Fun4AllServer void BeginTimeStamp(const PHTimeStamp &TimeStp); void EndTimeStamp(const PHTimeStamp &TimeStp); - int SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const std::string &table, const int commit = 0); - int SyncCalibTimeStampsToOnCal(const OnCal *calibrator, const int commit = 0); + int SyncCalibTimeStampsToOnCal(const CalReco *calibrator, const std::string &table, const int commit = 0); + int SyncCalibTimeStampsToOnCal(const CalReco *calibrator, const int commit = 0); int SyncOncalTimeStampsToRunDB(const int commit = 0); - int ClosestGoodRun(OnCal *calibrator, const int irun, const int previous = fetchrun::CLOSEST); - static int CopyTables(const OnCal *calibrator, const int FromRun, const int ToRun, const int commit = 0); - static int OverwriteCalibration(OnCal *calibrator, const int runno, const int commit = 0, const int fromrun = -1); - int FixMissingCalibration(OnCal *calibrator, const int runno, const int commit = 0, const int fromrun = -1); + int ClosestGoodRun(CalReco *calibrator, const int irun, const int previous = fetchrun::CLOSEST); + static int CopyTables(const CalReco *calibrator, const int FromRun, const int ToRun, const int commit = 0); + static int OverwriteCalibration(CalReco *calibrator, const int runno, const int commit = 0, const int fromrun = -1); + int FixMissingCalibration(CalReco *calibrator, const int runno, const int commit = 0, const int fromrun = -1); int SetBorTime(const int runno); int SetEorTime(const int runno); @@ -74,7 +74,7 @@ class OnCalServer : public Fun4AllServer int FindClosestCalibratedRun(const int irun); int FillRunListFromFileList(); int AdjustRichTimeStampForMultipleRuns(); - int CreateCalibration(OnCal *calibrator, const int myrunnumber, const std::string &what, const int commit = 0); + int CreateCalibration(CalReco *calibrator, const int myrunnumber, const std::string &what, const int commit = 0); int GetCalibStatus(const std::string &calibname, const int runno); static int DisconnectDB(); void TestMode(const int i = 1); @@ -113,13 +113,13 @@ class OnCalServer : public Fun4AllServer int add_calibrator_to_statustable(const std::string &calibratorname); int check_calibrator_in_statustable(const std::string &calibratorname); static int GetRunTimeTicks(const int runno, time_t &borticks, time_t &eorticks); - void CreateCalibrationUpdateStatus(OnCal *calibrator, const std::string &table, const std::string &tablecomment, const int dbcode); - OnCalServer(const std::string &name = "OnCalServer"); + void CreateCalibrationUpdateStatus(CalReco *calibrator, const std::string &table, const std::string &tablecomment, const int dbcode); + Fun4CalServer(const std::string &name = "Fun4CalServer"); PHTimeStamp beginTimeStamp; // begin run timestamp of run analysing PHTimeStamp endTimeStamp; // end run timestamp of run analysing int testmode{0}; bool recordDB{false}; - TH1 *OnCalServerVars{nullptr}; + TH1 *Fun4CalServerVars{nullptr}; std::map Histo; std::map > calibratorhistomap; bool SetEndTimeStampByHand{false}; @@ -137,4 +137,4 @@ class OnCalServer : public Fun4AllServer std::set runlist; }; -#endif /* __ONCALSERVER_H */ +#endif /* __FUN4CALSERVER_H */ diff --git a/calibrations/framework/oncal/Makefile.am b/calibrations/framework/fun4cal/Makefile.am similarity index 76% rename from calibrations/framework/oncal/Makefile.am rename to calibrations/framework/fun4cal/Makefile.am index bb0b3674c1..02ad88ff18 100644 --- a/calibrations/framework/oncal/Makefile.am +++ b/calibrations/framework/fun4cal/Makefile.am @@ -7,9 +7,9 @@ AM_CPPFLAGS = \ -isystem$(ROOTSYS)/include lib_LTLIBRARIES = \ - liboncal.la + libfun4cal.la -liboncal_la_LIBADD = \ +libfun4cal_la_LIBADD = \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib \ -L$(OPT_SPHENIX)/lib \ @@ -19,14 +19,14 @@ liboncal_la_LIBADD = \ -lphool pkginclude_HEADERS = \ - OnCalDBCodes.h \ - OnCalHistoBinDefs.h \ - OnCal.h \ - OnCalServer.h + Fun4CalDBCodes.h \ + Fun4CalHistoBinDefs.h \ + CalReco.h \ + Fun4CalServer.h -liboncal_la_SOURCES = \ - OnCal.cc \ - OnCalServer.cc +libfun4cal_la_SOURCES = \ + CalReco.cc \ + Fun4CalServer.cc BUILT_SOURCES = \ testexternals.cc @@ -38,7 +38,7 @@ testexternals_SOURCES = \ testexternals.cc testexternals_LDADD = \ - liboncal.la + libfun4cal.la testexternals.cc: echo "//*** this is a generated file. Do not commit, do not edit" > $@ diff --git a/calibrations/framework/oncal/autogen.sh b/calibrations/framework/fun4cal/autogen.sh similarity index 100% rename from calibrations/framework/oncal/autogen.sh rename to calibrations/framework/fun4cal/autogen.sh diff --git a/calibrations/framework/oncal/configure.ac b/calibrations/framework/fun4cal/configure.ac similarity index 93% rename from calibrations/framework/oncal/configure.ac rename to calibrations/framework/fun4cal/configure.ac index e5467a38b0..a665c5357c 100644 --- a/calibrations/framework/oncal/configure.ac +++ b/calibrations/framework/fun4cal/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(oncal,[2.00]) +AC_INIT(fun4cal,[1.00]) AC_CONFIG_SRCDIR([configure.ac]) AM_INIT_AUTOMAKE diff --git a/calibrations/framework/oncal/OnCalHistoBinDefs.h b/calibrations/framework/oncal/OnCalHistoBinDefs.h deleted file mode 100644 index d030b6dce2..0000000000 --- a/calibrations/framework/oncal/OnCalHistoBinDefs.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __ONCALHISTOBINDEFS_H__ -#define __ONCALHISTOBINDEFS_H__ - -namespace OnCalHistoBinDefs -{ - enum - { - FIRSTRUNBIN = 1, - LASTRUNBIN, - BORTIMEBIN, - EORTIMEBIN, - LASTBINPLUSONE - }; -}; - -#endif /* __ONCALHISTOBINDEFS_H__ */ diff --git a/calibrations/mbd/Makefile.am b/calibrations/mbd/Makefile.am new file mode 100644 index 0000000000..850ee853d7 --- /dev/null +++ b/calibrations/mbd/Makefile.am @@ -0,0 +1,45 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +pkginclude_HEADERS = \ + MbdTrackVertex.h + +lib_LTLIBRARIES = \ + libmbdcalib.la + +libmbdcalib_la_SOURCES = \ + MbdTrackVertex.cc + +libmbdcalib_la_LIBADD = \ + -lphool \ + -lSubsysReco \ + -lglobalvertex_io \ + -lffarawobjects \ + -lffaobjects + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libmbdcalib.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/calibrations/mbd/MbdTrackVertex.cc b/calibrations/mbd/MbdTrackVertex.cc new file mode 100644 index 0000000000..9c73c2ea7a --- /dev/null +++ b/calibrations/mbd/MbdTrackVertex.cc @@ -0,0 +1,190 @@ +#include "MbdTrackVertex.h" + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +constexpr GlobalVertex::VTXTYPE trkType = GlobalVertex::SVTX; +constexpr GlobalVertex::VTXTYPE mbdType = GlobalVertex::MBD; +//____________________________________________________________________________.. +MbdTrackVertex::MbdTrackVertex(const std::string &name): + SubsysReco(name) +{ + std::cout << "MbdTrackVertex::MbdTrackVertex(const std::string &name) Calling ctor" << std::endl; +} + +//____________________________________________________________________________.. +MbdTrackVertex::~MbdTrackVertex() +{ + std::cout << "MbdTrackVertex::~MbdTrackVertex() Calling dtor" << std::endl; +} + +//____________________________________________________________________________.. +int MbdTrackVertex::Init(PHCompositeNode * /*topNode*/) +{ + outFile = new TFile(outFileName.c_str(), "RECREATE"); + if (_treeflag) + { + outTree = new TTree("mz", "MBD-TRK ZVTX"); + outTree->OptimizeBaskets(); + outTree->SetAutoSave(-5e6); + + outTree->Branch("evt", &_evt, "evt/I"); + outTree->Branch("mbdz", &_mbdVertex, "mbdz/F"); + outTree->Branch("trkz", &_trackerVertex, "trkz/F"); + outTree->Branch("ntrks", &_nTracks, "ntrks/i"); + outTree->Branch("nbz", &_nMBDVertex, "nbz/i"); + outTree->Branch("ntz", &_nTRKVertex, "ntz/i"); + } + + // h_mbdtrkz: dz = _mbdVertex - trackerVertex, range (-15,15) cm, 0.25 cm bins → 120 bins + h_mbdtrkz = new TH1F("h_mbdtrkz", "MBD - Tracker z-vertex;dz (cm);Counts", 120, -15., 15.); + h_bz = new TH1F("h_bz", "MBD z-vertex;z (cm);Counts", 400, -20., 20.); + h_trkz = new TH1F("h_trkz", "Tracker z-vertex;z (cm);Counts", 400, -20., 20.); + + // h2_mbdtrkz: THnSparseF, x = _trackerVertex, y = _mbdVertex, (-20,20) cm, 0.1 cm bins → 400 bins each + const int nbins2[2] = {400, 400}; + const double xmin2[2] = {-20., -20.}; + const double xmax2[2] = { 20., 20.}; + h2_mbdtrkz = new THnSparseF("h2_mbdtrkz", "MBD vs Tracker z-vertex", 2, nbins2, xmin2, xmax2); + h2_mbdtrkz->GetAxis(0)->SetTitle("Tracker z (cm)"); + h2_mbdtrkz->GetAxis(1)->SetTitle("MBD z (cm)"); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MbdTrackVertex::process_event(PHCompositeNode *topNode) +{ + EventHeader *eventheader = findNode::getClass(topNode, "EventHeader"); + _evt = eventheader ? eventheader->get_EvtSequence() : -1; + + if (_gl1_trigmask != 0) + { + Gl1Packet *gl1 = findNode::getClass(topNode, "GL1Packet"); + if (gl1) + { + if ((gl1->getScaledVector() & _gl1_trigmask) == 0) + { + return Fun4AllReturnCodes::DISCARDEVENT; + } + } + else + { + std::cout << PHWHERE << " GL1Packet node not found; discarding event because trigger masking was requested" << std::endl; + return Fun4AllReturnCodes::DISCARDEVENT; + } + } + + MbdVertexMap *m_dst_mbdvertexmap = findNode::getClass(topNode, "MbdVertexMap"); + SvtxVertexMap *m_dst_vertexmap = findNode::getClass(topNode, "SvtxVertexMap"); + + GlobalVertexMap *globalvertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + if (!m_dst_mbdvertexmap || !m_dst_vertexmap || !globalvertexmap) + { + std::cout << PHWHERE << " missing required vertex node(s)" << std::endl; + return Fun4AllReturnCodes::DISCARDEVENT; + } + + _mbdVertex = _trackerVertex = std::numeric_limits::quiet_NaN(); + _nTracks = _nMBDVertex = _nTRKVertex = std::numeric_limits::quiet_NaN(); + + _hasMBD = false; + _hasTRK = false; + + for (GlobalVertexMap::ConstIter iter = globalvertexmap->begin(); iter != globalvertexmap->end(); ++iter) + { + GlobalVertex *gvertex = iter->second; + + if (gvertex->count_vtxs(mbdType) != 0) + { + _hasMBD = true; + + auto mbditer = gvertex->find_vertexes(mbdType); + auto mbdvertexvector = mbditer->second; + + _nMBDVertex = mbdvertexvector.size(); + for (auto &vertex : mbdvertexvector) + { + MbdVertex *m_dst_vertex = m_dst_mbdvertexmap->find(vertex->get_id())->second; + _mbdVertex = m_dst_vertex->get_z(); + } + } + + if (gvertex->count_vtxs(trkType) != 0) + { + _hasTRK = true; + + auto trkiter = gvertex->find_vertexes(trkType); + auto trkvertexvector = trkiter->second; + + _nTRKVertex = trkvertexvector.size(); + for (auto &vertex : trkvertexvector) + { + SvtxVertex *m_dst_vertex = m_dst_vertexmap->find(vertex->get_id())->second; + if ( m_dst_vertex->get_beam_crossing() != 0 ) + { + continue; + } + if ( m_dst_vertex->size_tracks() > _nTracks) + { + _trackerVertex = m_dst_vertex->get_z(); + _nTracks = m_dst_vertex->size_tracks(); + } + if (_nTracks == 0) + { + _hasTRK = false; + } + } + } + } + + if (_hasMBD) + { + h_bz->Fill(_mbdVertex); + } + if (_hasTRK) + { + h_trkz->Fill(_trackerVertex); + } + + if (_hasMBD && _hasTRK) + { + h_mbdtrkz->Fill(_mbdVertex - _trackerVertex); + const double coords[2] = {_trackerVertex, _mbdVertex}; + h2_mbdtrkz->Fill(coords); + } + + if (_treeflag) + { + outTree->Fill(); + } + + ++_counter; + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MbdTrackVertex::End(PHCompositeNode * /*topNode*/) +{ + outFile->Write(); + outFile->Close(); + delete outFile; + + return Fun4AllReturnCodes::EVENT_OK; +} + diff --git a/calibrations/mbd/MbdTrackVertex.h b/calibrations/mbd/MbdTrackVertex.h new file mode 100644 index 0000000000..4a6b8a32be --- /dev/null +++ b/calibrations/mbd/MbdTrackVertex.h @@ -0,0 +1,68 @@ +#ifndef MBDTRACKVERTEX_H +#define MBDTRACKVERTEX_H + +#include + +#include +#include +#include +#include + +#include +#include + +class PHCompositeNode; + +class MbdTrackVertex : public SubsysReco +{ + public: + + MbdTrackVertex(const std::string &name = "MbdTrackVertex"); + + ~MbdTrackVertex() override; + + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + int Init(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode *topNode) override; + + /// Called at the end of all processing. + int End(PHCompositeNode *topNode) override; + + void setOutputName(const std::string& name) { outFileName = name; }; + void SetTreeFlag(bool flag) { _treeflag = flag; } + void SetTriggerMask(uint64_t mask) { _gl1_trigmask = mask; } + + private: + + TFile* outFile {nullptr}; + TTree* outTree {nullptr}; + TH1F* h_mbdtrkz {nullptr}; + TH1F* h_bz {nullptr}; + TH1F* h_trkz {nullptr}; + THnSparseF* h2_mbdtrkz {nullptr}; + std::string outFileName = "mbdtrk_vertex.root"; + + Float_t _mbdVertex {std::numeric_limits::quiet_NaN()}; + Float_t _trackerVertex {std::numeric_limits::quiet_NaN()}; + UInt_t _nTracks {std::numeric_limits::quiet_NaN()}; + UInt_t _nMBDVertex {std::numeric_limits::quiet_NaN()}; + UInt_t _nTRKVertex {std::numeric_limits::quiet_NaN()}; + + bool _hasMBD {false}; + bool _hasTRK {false}; + + bool _treeflag {true}; + uint64_t _gl1_trigmask {0}; + int _counter{0}; + int _evt{0}; +}; + +#endif // MBDTRACKVERTEX_H diff --git a/offline/framework/rawbcolumi/autogen.sh b/calibrations/mbd/autogen.sh similarity index 100% rename from offline/framework/rawbcolumi/autogen.sh rename to calibrations/mbd/autogen.sh diff --git a/calibrations/mbd/configure.ac b/calibrations/mbd/configure.ac new file mode 100644 index 0000000000..350d9c3996 --- /dev/null +++ b/calibrations/mbd/configure.ac @@ -0,0 +1,19 @@ +AC_INIT(mbdcalib,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wshadow -Werror" +fi + +CINTDEFS=" -noIncludePaths -inlineInputHeader " +AC_SUBST(CINTDEFS) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc new file mode 100644 index 0000000000..57c3fcfc58 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.cc @@ -0,0 +1,44 @@ +#include "EventPlaneData.h" + +#include + +EventPlaneData::EventPlaneData() +{ + sepd_charge.fill(0); +} + +void EventPlaneData::Reset() +{ + event_id = 0; + event_zvertex = std::numeric_limits::quiet_NaN(); + event_centrality = std::numeric_limits::quiet_NaN(); + sepd_totalcharge = std::numeric_limits::quiet_NaN(); + sepd_charge.fill(0); +} + +void EventPlaneData::identify(std::ostream& os) const +{ + os << "--- EventPlaneData Identify ---" << std::endl; + os << "Event ID: " << event_id << std::endl; + os << "Z-Vertex: " << event_zvertex << std::endl; + os << "Centrality: " << event_centrality << std::endl; + os << "sEPD Total Charge: " << sepd_totalcharge << std::endl; + os << "-------------------------------" << std::endl; +} + +int EventPlaneData::isValid() const +{ + // An object is considered invalid if the Z-vertex is still NaN + // or if the event ID hasn't been set (remains 0). + if (std::isnan(event_zvertex)) + { + return 0; + } + + if (event_id == 0) + { + return 0; + } + + return 1; +} diff --git a/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h new file mode 100644 index 0000000000..d9ffea19c9 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/EventPlaneData.h @@ -0,0 +1,51 @@ +#ifndef SEPD_EVENTPLANECALIB_EVENTPLANEDATA_H +#define SEPD_EVENTPLANECALIB_EVENTPLANEDATA_H + +#include "QVecDefs.h" + +#include + +#include +#include + +class EventPlaneData : public PHObject +{ + public: + EventPlaneData(); + ~EventPlaneData() override = default; + + EventPlaneData(const EventPlaneData&) = default; + EventPlaneData& operator=(const EventPlaneData&) = default; + EventPlaneData(EventPlaneData&&) = default; + EventPlaneData& operator=(EventPlaneData&&) = default; + + void Reset() override; + void set_event_id(int id) {event_id = id;} + int get_event_id() const {return event_id;} + + void set_event_zvertex(double vtx) {event_zvertex = vtx;} + double get_event_zvertex() const {return event_zvertex;} + + void set_sepd_totalcharge(double chg) {sepd_totalcharge = chg;} + double get_sepd_totalcharge() const {return sepd_totalcharge;} + + void set_sepd_charge(int channel, double chg) {sepd_charge[channel] = chg;} + double get_sepd_charge(int channel) const {return sepd_charge[channel];} + + void set_event_centrality(double cent) { event_centrality = cent; } + double get_event_centrality() const { return event_centrality; } + + void identify(std::ostream& os = std::cout) const override; + int isValid() const override; + + private: + int event_id {0}; + double event_zvertex {std::numeric_limits::quiet_NaN()}; + double event_centrality{std::numeric_limits::quiet_NaN()}; + double sepd_totalcharge{std::numeric_limits::quiet_NaN()}; + + std::array sepd_charge {}; + ClassDefOverride(EventPlaneData, 1); +}; + +#endif diff --git a/calibrations/sepd/sepd_eventplanecalib/EventPlaneDataLinkDef.h b/calibrations/sepd/sepd_eventplanecalib/EventPlaneDataLinkDef.h new file mode 100644 index 0000000000..9c56106475 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/EventPlaneDataLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class EventPlaneData + ; + +#endif /* __CINT__ */ diff --git a/calibrations/sepd/sepd_eventplanecalib/Makefile.am b/calibrations/sepd/sepd_eventplanecalib/Makefile.am new file mode 100644 index 0000000000..d17c56b4a0 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/Makefile.am @@ -0,0 +1,71 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -isystem$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 \ + `root-config --libs` + +pkginclude_HEADERS = \ + sEPD_TreeGen.h \ + QVecCalib.h \ + QVecDefs.h + +lib_LTLIBRARIES = \ + libsepd_eventplanecalib.la + +ROOTDICTS = \ + EventPlaneData_Dict.cc + +pcmdir = $(libdir) +# more elegant way to create pcm files (without listing them) +nobase_dist_pcm_DATA = $(ROOTDICTS:.cc=_rdict.pcm) + +# EventPlaneData is a locally used root i/o object - no need to create an io library +libsepd_eventplanecalib_la_SOURCES = \ + $(ROOTDICTS) \ + EventPlaneData.cc \ + sEPD_TreeGen.cc \ + QVecCalib.cc + +libsepd_eventplanecalib_la_LIBADD = \ + -lphool \ + -lSubsysReco \ + -lcentrality_io \ + -lfun4all \ + -lffamodules \ + -lglobalvertex_io \ + -lcalotrigger_io \ + -lcalotrigger \ + -lcdbobjects \ + -lepd_io + +# Rule for generating table CINT dictionaries. +%_Dict.cc: %.h %LinkDef.h + rootcint -f $@ @CINTDEFS@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ + +#just to get the dependency +%_Dict_rdict.pcm: %_Dict.cc ; + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libsepd_eventplanecalib.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc new file mode 100644 index 0000000000..747524bfb2 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.cc @@ -0,0 +1,1281 @@ +#include "QVecCalib.h" +#include "EventPlaneData.h" + +// ==================================================================== +// sPHENIX Includes +// ==================================================================== +#include + +// -- Fun4All +#include +#include + +// -- Nodes +#include +#include + +// -- sEPD +#include + +// -- Run +#include + +// -- CDBTTree +#include + +#include +#include +#include +#include + + +// ==================================================================== +// Standard C++ Includes +// ==================================================================== +#include +#include +#include + +//____________________________________________________________________________.. +QVecCalib::QVecCalib(const std::string &name): + SubsysReco(name) +{ + // std::cout << "QVecCalib::QVecCalib(const std::string &name) Calling ctor" << std::endl; +} + +//____________________________________________________________________________.. +int QVecCalib::Init([[maybe_unused]] PHCompositeNode *topNode) +{ + if (Verbosity() > 1) + { + std::cout << "QVecCalib::Init(PHCompositeNode *topNode) Initializing" << std::endl; + + Fun4AllServer *se = Fun4AllServer::instance(); + se->Print("NODETREE"); + } + + int ret = process_QA_hist(); + if (ret) + { + return ret; + } + + init_hists(); + + if (m_pass == Pass::ApplyRecentering || m_pass == Pass::ApplyFlattening) + { + ret = load_correction_data(); + if (ret) + { + return ret; + } + } + + prepare_hists(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +void QVecCalib::prepare_hists() +{ + if (m_pass == Pass::ComputeRecentering) + { + prepare_average_hists(); + } + else if (m_pass == Pass::ApplyRecentering) + { + prepare_recenter_hists(); + } + else if (m_pass == Pass::ApplyFlattening) + { + prepare_flattening_hists(); + } +} + +int QVecCalib::process_QA_hist() +{ + TH1::AddDirectory(kFALSE); + auto* file = TFile::Open(m_input_hist.c_str()); + + // Check if the file was opened successfully. + if (!file || file->IsZombie()) + { + std::cout << PHWHERE << "Error! Cannot not open file: " << m_input_hist << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + // Get sEPD Total Charge Bounds as function of centrality + int ret = process_sEPD_event_thresholds(file); + if (ret) + { + return ret; + } + + // cleanup + file->Close(); + delete file; + + return Fun4AllReturnCodes::EVENT_OK; +} + +int QVecCalib::process_sEPD_event_thresholds(TFile* file) +{ + Fun4AllServer *se = Fun4AllServer::instance(); + + std::string sepd_totalcharge_centrality = "h2SEPD_totalcharge_centrality"; + + TH2 *hist {nullptr}; + file->GetObject(sepd_totalcharge_centrality.c_str(),hist); + + // Check if the hist is stored in the file + if (hist == nullptr) + { + std::cout << PHWHERE << "Error! Cannot find hist: " << sepd_totalcharge_centrality << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + h2SEPD_Charge = static_cast(hist->Clone("h2SEPD_Charge")); + h2SEPD_Chargev2 = static_cast(hist->Clone("h2SEPD_Chargev2")); + + se->registerHisto(h2SEPD_Charge); + se->registerHisto(h2SEPD_Chargev2); + + auto* h2SEPD_Charge_py = h2SEPD_Charge->ProfileY("h2SEPD_Charge_py", 1, -1, "s"); + + int binsx = h2SEPD_Charge->GetNbinsX(); + int binsy = h2SEPD_Charge->GetNbinsY(); + double ymin = h2SEPD_Charge->GetYaxis()->GetXmin(); + double ymax = h2SEPD_Charge->GetYaxis()->GetXmax(); + + hSEPD_Charge_Min = new TProfile("hSEPD_Charge_Min", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax); + hSEPD_Charge_Max = new TProfile("hSEPD_Charge_Max", "; Centrality [%]; sEPD Total Charge", binsy, ymin, ymax); + + se->registerHisto(hSEPD_Charge_Min); + se->registerHisto(hSEPD_Charge_Max); + + for (int y = 1; y <= binsy; ++y) + { + double cent = h2SEPD_Charge_py->GetBinCenter(y); + double mean = h2SEPD_Charge_py->GetBinContent(y); + double sigma = h2SEPD_Charge_py->GetBinError(y); + + if (sigma == 0) + { + continue; + } + + double charge_low = mean - m_sEPD_sigma_threshold * sigma; + double charge_high = mean + m_sEPD_sigma_threshold * sigma; + + hSEPD_Charge_Min->Fill(cent, charge_low); + hSEPD_Charge_Max->Fill(cent, charge_high); + + for (int x = 1; x <= binsx; ++x) + { + double charge = h2SEPD_Charge->GetXaxis()->GetBinCenter(x); + double zscore = (charge - mean) / sigma; + + if (std::abs(zscore) > m_sEPD_sigma_threshold) + { + h2SEPD_Chargev2->SetBinContent(x, y, 0); + h2SEPD_Chargev2->SetBinError(x, y, 0); + } + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +void QVecCalib::init_hists() +{ + unsigned int bins_psi = 126; + double psi_low = -std::numbers::pi; + double psi_high = std::numbers::pi; + + Fun4AllServer *se = Fun4AllServer::instance(); + + hCentrality = new TH1F("hCentrality", "|z| < 10 cm and MB; Centrality [%]; Events", m_cent_bins, m_cent_low, m_cent_high); + se->registerHisto(hCentrality); + + std::string pass_suffix; + if (m_pass == Pass::ApplyRecentering) + { + pass_suffix = "_corr"; + } + else if (m_pass == Pass::ApplyFlattening) + { + pass_suffix = "_corr2"; + } + + // n = 2, 3, 4, etc. + for (int n : m_harmonics) + { + std::string name_S = std::format("h2_sEPD_Psi_S_{}{}", n, pass_suffix); + std::string name_N = std::format("h2_sEPD_Psi_N_{}{}", n, pass_suffix); + std::string name_NS = std::format("h2_sEPD_Psi_NS_{}{}", n, pass_suffix); + + std::string title_S = std::format("sEPD South #Psi (Order {0}); Centrality [%]; {0}#Psi^{{S}}_{{{0}}}", n); + std::string title_N = std::format("sEPD North #Psi (Order {0}); Centrality [%]; {0}#Psi^{{N}}_{{{0}}}", n); + std::string title_NS = std::format("sEPD North South #Psi (Order {0}); Centrality [%]; {0}#Psi^{{NS}}_{{{0}}}", n); + + m_hists2D[name_S] = new TH2F(name_S.c_str(), title_S.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); + m_hists2D[name_N] = new TH2F(name_N.c_str(), title_N.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); + m_hists2D[name_NS] = new TH2F(name_NS.c_str(), title_NS.c_str(), m_cent_bins, m_cent_low, m_cent_high, bins_psi, psi_low, psi_high); + + if (m_pass == Pass::ApplyFlattening) + { + std::string name_EP_res = std::format("hEP_res_{}", n); + std::string title_EP_res = std::format("; Centrality [%]; #LTRe(Q^{{S}}_{{{0}}} Q^{{N*}}_{{{0}}}) / (|Q^{{S}}_{{{0}}}||Q^{{N}}_{{{0}}}|)#GT", n); + + m_profiles[name_EP_res] = new TProfile(name_EP_res.c_str(), title_EP_res.c_str(), m_cent_bins, m_cent_low, m_cent_high); + } + + // South, North + for (auto det : m_subdetectors) + { + std::string det_str = (det == QVecShared::Subdetector::S) ? "S" : "N"; + std::string det_name = (det == QVecShared::Subdetector::S) ? "South" : "North"; + + std::string q_avg_sq_cross_name; + std::string q_avg_sq_cross_title = std::format("sEPD {0}; Centrality [%]; ", det_name, n); + + if (m_pass == Pass::ApplyRecentering) + { + q_avg_sq_cross_name = QVecShared::get_hist_name(det_str, "xy", n); + } + + if (m_pass == Pass::ApplyFlattening) + { + q_avg_sq_cross_name = QVecShared::get_hist_name(det_str, "xy", n, "_corr"); + } + + if (!q_avg_sq_cross_name.empty()) + { + m_profiles[q_avg_sq_cross_name] = new TProfile(q_avg_sq_cross_name.c_str(), q_avg_sq_cross_title.c_str(), + m_cent_bins, m_cent_low, m_cent_high); + } + + for (auto comp : m_components) + { + std::string comp_str = (comp == QVecShared::QComponent::X) ? "x" : "y"; + std::string name = QVecShared::get_hist_name(det_str, comp_str, n, pass_suffix); + + auto add_profile = [&](const std::string& prof_name, std::string_view label_suffix = "") + { + std::string title = std::format("sEPD {}; Centrality [%]; ", det_name, n, comp_str, label_suffix); + m_profiles[prof_name] = new TProfile(prof_name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); + }; + + add_profile(name); + + // 2. Only generate strings and profiles for the current pass + switch (m_pass) + { + case Pass::ComputeRecentering: + { + break; + } + + case Pass::ApplyRecentering: + { + std::string name_sq = QVecShared::get_hist_name(det_str, comp_str+comp_str, n); + add_profile(name_sq, "^{2}"); + break; + } + + case Pass::ApplyFlattening: + { + std::string name_sq_corr = QVecShared::get_hist_name(det_str, comp_str+comp_str, n, "_corr"); + add_profile(name_sq_corr, "^{2}"); + break; + } + } + } + } + + // Init for Combined NS Histograms + if (m_pass == Pass::ApplyRecentering || m_pass == Pass::ApplyFlattening) + { + std::string det_str = "NS"; + + // Initialize 2nd Moment Profiles for NS (needed to compute flattening) + for (const auto* comp : {"xx", "yy", "xy"}) + { + std::string name = QVecShared::get_hist_name(det_str, comp, n); + std::string title = std::format("sEPD NS; Centrality [%]; ", n, comp); + m_profiles[name] = new TProfile(name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); + } + + // Initialize Validation Profiles (Flattened NS) + if (m_pass == Pass::ApplyFlattening) + { + for (const auto* comp : {"xx", "yy", "xy"}) + { + std::string name = QVecShared::get_hist_name(det_str, comp, n, "_corr"); + std::string title = std::format("sEPD NS Corrected; Centrality [%]; ", n, comp); + m_profiles[name] = new TProfile(name.c_str(), title.c_str(), m_cent_bins, m_cent_low, m_cent_high); + } + } + } + } +} + +std::array, 2> QVecCalib::calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label) +{ + double D_arg = (xx * yy) - (xy * xy); + if (D_arg < 1e-12) + { + std::cout << "Warning: Near-zero determinant in bin " << cent_bin << ". Skipping matrix calc." << std::endl; + return std::array, 2>{{{1, 0}, {0, 1}}}; // Return Identity + } + double D = std::sqrt(D_arg); + + double N_term = D * (xx + yy + (2 * D)); + if (N_term <= 0) + { + std::cout << "Invalid N-term (" << N_term << ") for n=" << n << ", cent=" << cent_bin + << ", det=" << det_label << std::endl; + exit(1); + } + double inv_sqrt_N = 1.0 / std::sqrt(N_term); + + std::array, 2> mat{}; + mat[0][0] = inv_sqrt_N * (yy + D); + mat[0][1] = -inv_sqrt_N * xy; + mat[1][0] = mat[0][1]; + mat[1][1] = inv_sqrt_N * (xx + D); + return mat; +} + +template +T* QVecCalib::load_and_clone(TFile* file, const std::string& name) { + T *obj {nullptr}; + file->GetObject(name.c_str(),obj); + if (!obj) + { + std::cout << "Could not find histogram " << name << " in file " << file->GetName() << std::endl; + exit(1); + } + return static_cast(obj->Clone()); +} + +int QVecCalib::load_correction_data() +{ + Fun4AllServer *se = Fun4AllServer::instance(); + auto* file = TFile::Open(m_input_Q_calib.c_str()); + + if (!file || file->IsZombie()) + { + std::cout << PHWHERE << "Error! Cannot open: " << m_input_Q_calib << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + // Helper to load and register histograms automatically + auto load_reg = [&](const std::string& det, const std::string& var, const std::string& suffix = "") + { + std::string name = QVecShared::get_hist_name(det, var, n, suffix); + m_profiles[name] = load_and_clone(file, name); + se->registerHisto(m_profiles[name]); + return name; + }; + + // Load standard Recentering averages for S and N + std::string s_names[2][2]; // [det][comp] + for (int d = 0; d < 2; ++d) + { + std::string det_str = (d == 0) ? "S" : "N"; + s_names[d][0] = load_reg(det_str, "x"); + s_names[d][1] = load_reg(det_str, "y"); + } + + // Load Flattening (2nd moment) data if needed + if (m_pass == Pass::ApplyFlattening) + { + for (const auto& det_str : {"S", "N", "NS"}) + { + for (const auto& var : {"xx", "yy", "xy"}) + { + load_reg(det_str, var); + } + } + } + + // Populate the CorrectionData matrix + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) + { + int bin = static_cast(cent_bin) + 1; + + // Populate Recentering (S, N) + for (int d = 0; d < 2; ++d) + { + m_correction_data[cent_bin][h_idx][d].avg_Q = {m_profiles[s_names[d][0]]->GetBinContent(bin), m_profiles[s_names[d][1]]->GetBinContent(bin)}; + } + + if (m_pass == Pass::ApplyFlattening) + { + // Populate Flattening for S, N, and NS + for (int d = 0; d < (int) QVecShared::Subdetector::Count; ++d) + { + std::string det_str; + switch (d) + { + case 0: + det_str = "S"; + break; + case 1: + det_str = "N"; + break; + default: + det_str = "NS"; + break; + } + + double xx = m_profiles[QVecShared::get_hist_name(det_str, "xx", n)]->GetBinContent(bin); + double yy = m_profiles[QVecShared::get_hist_name(det_str, "yy", n)]->GetBinContent(bin); + double xy = m_profiles[QVecShared::get_hist_name(det_str, "xy", n)]->GetBinContent(bin); + + auto& data = m_correction_data[cent_bin][h_idx][d]; + data.X_matrix = calculate_flattening_matrix(xx, yy, xy, n, cent_bin, det_str); + data.avg_Q_xx = xx; + data.avg_Q_yy = yy; + data.avg_Q_xy = xy; + } + } + } + } + + file->Close(); + delete file; + return Fun4AllReturnCodes::EVENT_OK; +} + +void QVecCalib::prepare_average_hists() +{ + Fun4AllServer *se = Fun4AllServer::instance(); + + for (int n : m_harmonics) + { + std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n); + std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n); + std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); + std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); + + std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}", n); + std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}", n); + std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}", n); + + AverageHists h; + + h.S_x_avg = m_profiles.at(S_x_avg_name); + h.S_y_avg = m_profiles.at(S_y_avg_name); + h.N_x_avg = m_profiles.at(N_x_avg_name); + h.N_y_avg = m_profiles.at(N_y_avg_name); + + h.Psi_S = m_hists2D.at(psi_S_name); + h.Psi_N = m_hists2D.at(psi_N_name); + h.Psi_NS = m_hists2D.at(psi_NS_name); + + se->registerHisto(h.S_x_avg); + se->registerHisto(h.S_y_avg); + se->registerHisto(h.N_x_avg); + se->registerHisto(h.N_y_avg); + + se->registerHisto(h.Psi_S); + se->registerHisto(h.Psi_N); + se->registerHisto(h.Psi_NS); + + m_average_hists.push_back(h); + } +} + +void QVecCalib::prepare_recenter_hists() +{ + Fun4AllServer *se = Fun4AllServer::instance(); + + for (int n : m_harmonics) + { + std::string S_x_corr_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr"); + std::string S_y_corr_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr"); + std::string N_x_corr_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr"); + std::string N_y_corr_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr"); + + std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n); + std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n); + std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n); + std::string N_xx_avg_name = QVecShared::get_hist_name("N", "xx", n); + std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n); + std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n); + + std::string NS_xx_avg_name = QVecShared::get_hist_name("NS", "xx", n); + std::string NS_yy_avg_name = QVecShared::get_hist_name("NS", "yy", n); + std::string NS_xy_avg_name = QVecShared::get_hist_name("NS", "xy", n); + + std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}_corr", n); + std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr", n); + std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr", n); + + RecenterHists h; + + h.S_x_corr_avg = m_profiles.at(S_x_corr_avg_name); + h.S_y_corr_avg = m_profiles.at(S_y_corr_avg_name); + h.N_x_corr_avg = m_profiles.at(N_x_corr_avg_name); + h.N_y_corr_avg = m_profiles.at(N_y_corr_avg_name); + + h.S_xx_avg = m_profiles.at(S_xx_avg_name); + h.S_yy_avg = m_profiles.at(S_yy_avg_name); + h.S_xy_avg = m_profiles.at(S_xy_avg_name); + + h.N_xx_avg = m_profiles.at(N_xx_avg_name); + h.N_yy_avg = m_profiles.at(N_yy_avg_name); + h.N_xy_avg = m_profiles.at(N_xy_avg_name); + + h.NS_xx_avg = m_profiles.at(NS_xx_avg_name); + h.NS_yy_avg = m_profiles.at(NS_yy_avg_name); + h.NS_xy_avg = m_profiles.at(NS_xy_avg_name); + + h.Psi_S_corr = m_hists2D.at(psi_S_name); + h.Psi_N_corr = m_hists2D.at(psi_N_name); + h.Psi_NS_corr = m_hists2D.at(psi_NS_name); + + se->registerHisto(h.S_x_corr_avg); + se->registerHisto(h.S_y_corr_avg); + se->registerHisto(h.N_x_corr_avg); + se->registerHisto(h.N_y_corr_avg); + + se->registerHisto(h.S_xx_avg); + se->registerHisto(h.S_yy_avg); + se->registerHisto(h.S_xy_avg); + + se->registerHisto(h.N_xx_avg); + se->registerHisto(h.N_yy_avg); + se->registerHisto(h.N_xy_avg); + + se->registerHisto(h.NS_xx_avg); + se->registerHisto(h.NS_yy_avg); + se->registerHisto(h.NS_xy_avg); + + se->registerHisto(h.Psi_S_corr); + se->registerHisto(h.Psi_N_corr); + se->registerHisto(h.Psi_NS_corr); + + m_recenter_hists.push_back(h); + } +} + +void QVecCalib::prepare_flattening_hists() +{ + Fun4AllServer *se = Fun4AllServer::instance(); + + for (int n : m_harmonics) + { + std::string S_x_corr2_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr2"); + std::string S_y_corr2_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr2"); + std::string N_x_corr2_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr2"); + std::string N_y_corr2_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr2"); + + std::string S_xx_corr_avg_name = QVecShared::get_hist_name("S", "xx", n, "_corr"); + std::string S_yy_corr_avg_name = QVecShared::get_hist_name("S", "yy", n, "_corr"); + std::string S_xy_corr_avg_name = QVecShared::get_hist_name("S", "xy", n, "_corr"); + std::string N_xx_corr_avg_name = QVecShared::get_hist_name("N", "xx", n, "_corr"); + std::string N_yy_corr_avg_name = QVecShared::get_hist_name("N", "yy", n, "_corr"); + std::string N_xy_corr_avg_name = QVecShared::get_hist_name("N", "xy", n, "_corr"); + + std::string NS_xx_corr_avg_name = QVecShared::get_hist_name("NS", "xx", n, "_corr"); + std::string NS_yy_corr_avg_name = QVecShared::get_hist_name("NS", "yy", n, "_corr"); + std::string NS_xy_corr_avg_name = QVecShared::get_hist_name("NS", "xy", n, "_corr"); + + std::string psi_S_name = std::format("h2_sEPD_Psi_S_{}_corr2", n); + std::string psi_N_name = std::format("h2_sEPD_Psi_N_{}_corr2", n); + std::string psi_NS_name = std::format("h2_sEPD_Psi_NS_{}_corr2", n); + + std::string EP_res_name = std::format("hEP_res_{}", n); + + FlatteningHists h; + + h.S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name); + h.S_y_corr2_avg = m_profiles.at(S_y_corr2_avg_name); + h.N_x_corr2_avg = m_profiles.at(N_x_corr2_avg_name); + h.N_y_corr2_avg = m_profiles.at(N_y_corr2_avg_name); + + h.S_xx_corr_avg = m_profiles.at(S_xx_corr_avg_name); + h.S_yy_corr_avg = m_profiles.at(S_yy_corr_avg_name); + h.S_xy_corr_avg = m_profiles.at(S_xy_corr_avg_name); + + h.N_xx_corr_avg = m_profiles.at(N_xx_corr_avg_name); + h.N_yy_corr_avg = m_profiles.at(N_yy_corr_avg_name); + h.N_xy_corr_avg = m_profiles.at(N_xy_corr_avg_name); + + h.NS_xx_corr_avg = m_profiles.at(NS_xx_corr_avg_name); + h.NS_yy_corr_avg = m_profiles.at(NS_yy_corr_avg_name); + h.NS_xy_corr_avg = m_profiles.at(NS_xy_corr_avg_name); + + h.Psi_S_corr2 = m_hists2D.at(psi_S_name); + h.Psi_N_corr2 = m_hists2D.at(psi_N_name); + h.Psi_NS_corr2 = m_hists2D.at(psi_NS_name); + + h.EP_res = m_profiles.at(EP_res_name); + + se->registerHisto(h.S_x_corr2_avg); + se->registerHisto(h.S_y_corr2_avg); + se->registerHisto(h.N_x_corr2_avg); + se->registerHisto(h.N_y_corr2_avg); + + se->registerHisto(h.S_xx_corr_avg); + se->registerHisto(h.S_yy_corr_avg); + se->registerHisto(h.S_xy_corr_avg); + + se->registerHisto(h.N_xx_corr_avg); + se->registerHisto(h.N_yy_corr_avg); + se->registerHisto(h.N_xy_corr_avg); + + se->registerHisto(h.NS_xx_corr_avg); + se->registerHisto(h.NS_yy_corr_avg); + se->registerHisto(h.NS_xy_corr_avg); + + se->registerHisto(h.Psi_S_corr2); + se->registerHisto(h.Psi_N_corr2); + se->registerHisto(h.Psi_NS_corr2); + + se->registerHisto(h.EP_res); + + m_flattening_hists.push_back(h); + } +} + +int QVecCalib::InitRun(PHCompositeNode *topNode) +{ + RunHeader* run_header = findNode::getClass(topNode, "RunHeader"); + if (!run_header) + { + std::cout << PHWHERE << "RunHeader Node missing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_runnumber = run_header->get_RunNumber(); + + EpdGeom* epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); + if (!epdgeom) + { + std::cout << PHWHERE << "TOWERGEOM_EPD Node missing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_trig_cache.assign(m_harmonics.size(), std::vector>(QVecShared::SEPD_CHANNELS)); + + for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) + { + unsigned int key = TowerInfoDefs::encode_epd(channel); + double phi = epdgeom->get_phi(key); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + m_trig_cache[h_idx][channel] = {std::cos(n * phi), std::sin(n * phi)}; + } + } + + std::cout << "QVecCalib::InitRun - Trigonometry cache initialized for " + << QVecShared::SEPD_CHANNELS << " channels." << std::endl; + + return Fun4AllReturnCodes::EVENT_OK; +} + +void QVecCalib::process_averages(double cent, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const AverageHists& h) +{ + double psi_S = std::atan2(q_S.y, q_S.x); + double psi_N = std::atan2(q_N.y, q_N.x); + double psi_NS = std::atan2(q_S.y + q_N.y, q_S.x + q_N.x); + + h.S_x_avg->Fill(cent, q_S.x); + h.S_y_avg->Fill(cent, q_S.y); + h.N_x_avg->Fill(cent, q_N.x); + h.N_y_avg->Fill(cent, q_N.y); + + h.Psi_S->Fill(cent, psi_S); + h.Psi_N->Fill(cent, psi_N); + h.Psi_NS->Fill(cent, psi_NS); +} + +void QVecCalib::process_recentering(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const RecenterHists& h) +{ + int cent_bin = hCentrality->FindBin(cent) - 1; + + const auto& S = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::S]; + const auto& N = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::N]; + + double Q_S_x_avg = S.avg_Q.x; + double Q_S_y_avg = S.avg_Q.y; + double Q_N_x_avg = N.avg_Q.x; + double Q_N_y_avg = N.avg_Q.y; + + QVecShared::QVec q_S_corr = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; + QVecShared::QVec q_N_corr = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; + + // Construct Combined Recentered Vector + // We use the sum of the individually recentered vectors + QVecShared::QVec q_NS_corr = {q_S_corr.x + q_N_corr.x, q_S_corr.y + q_N_corr.y}; + + double psi_S_corr = std::atan2(q_S_corr.y, q_S_corr.x); + double psi_N_corr = std::atan2(q_N_corr.y, q_N_corr.x); + double psi_NS_corr = std::atan2(q_NS_corr.y, q_NS_corr.x); + + h.S_x_corr_avg->Fill(cent, q_S_corr.x); + h.S_y_corr_avg->Fill(cent, q_S_corr.y); + h.N_x_corr_avg->Fill(cent, q_N_corr.x); + h.N_y_corr_avg->Fill(cent, q_N_corr.y); + + h.S_xx_avg->Fill(cent, q_S_corr.x * q_S_corr.x); + h.S_yy_avg->Fill(cent, q_S_corr.y * q_S_corr.y); + h.S_xy_avg->Fill(cent, q_S_corr.x * q_S_corr.y); + h.N_xx_avg->Fill(cent, q_N_corr.x * q_N_corr.x); + h.N_yy_avg->Fill(cent, q_N_corr.y * q_N_corr.y); + h.N_xy_avg->Fill(cent, q_N_corr.x * q_N_corr.y); + + h.NS_xx_avg->Fill(cent, q_NS_corr.x * q_NS_corr.x); + h.NS_yy_avg->Fill(cent, q_NS_corr.y * q_NS_corr.y); + h.NS_xy_avg->Fill(cent, q_NS_corr.x * q_NS_corr.y); + + h.Psi_S_corr->Fill(cent, psi_S_corr); + h.Psi_N_corr->Fill(cent, psi_N_corr); + h.Psi_NS_corr->Fill(cent, psi_NS_corr); +} + +void QVecCalib::process_flattening(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const FlatteningHists& h) +{ + int cent_bin = hCentrality->FindBin(cent) - 1; + + const auto& S = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::S]; + const auto& N = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::N]; + const auto& NS = m_correction_data[cent_bin][h_idx][(size_t) QVecShared::Subdetector::NS]; + + double Q_S_x_avg = S.avg_Q.x; + double Q_S_y_avg = S.avg_Q.y; + double Q_N_x_avg = N.avg_Q.x; + double Q_N_y_avg = N.avg_Q.y; + + QVecShared::QVec q_S_corr = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; + QVecShared::QVec q_N_corr = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; + + // Construct Combined Recentered Vector + QVecShared::QVec q_NS_corr = {q_S_corr.x + q_N_corr.x, q_S_corr.y + q_N_corr.y}; + + const auto& X_S = S.X_matrix; + const auto& X_N = N.X_matrix; + const auto& X_NS = NS.X_matrix; + + double Q_S_x_corr2 = X_S[0][0] * q_S_corr.x + X_S[0][1] * q_S_corr.y; + double Q_S_y_corr2 = X_S[1][0] * q_S_corr.x + X_S[1][1] * q_S_corr.y; + double Q_N_x_corr2 = X_N[0][0] * q_N_corr.x + X_N[0][1] * q_N_corr.y; + double Q_N_y_corr2 = X_N[1][0] * q_N_corr.x + X_N[1][1] * q_N_corr.y; + + double Q_NS_x_corr2 = X_NS[0][0] * q_NS_corr.x + X_NS[0][1] * q_NS_corr.y; + double Q_NS_y_corr2 = X_NS[1][0] * q_NS_corr.x + X_NS[1][1] * q_NS_corr.y; + + QVecShared::QVec q_S_corr2 = {Q_S_x_corr2, Q_S_y_corr2}; + QVecShared::QVec q_N_corr2 = {Q_N_x_corr2, Q_N_y_corr2}; + QVecShared::QVec q_NS_corr2 = {Q_NS_x_corr2, Q_NS_y_corr2}; + + double psi_S = std::atan2(q_S_corr2.y, q_S_corr2.x); + double psi_N = std::atan2(q_N_corr2.y, q_N_corr2.x); + double psi_NS = std::atan2(q_NS_corr2.y, q_NS_corr2.x); + + double SP_QS_QN = q_S_corr2.x * q_N_corr2.x + q_S_corr2.y * q_N_corr2.y; + double norm_S = std::sqrt(q_S_corr2.x * q_S_corr2.x + q_S_corr2.y * q_S_corr2.y); + double norm_N = std::sqrt(q_N_corr2.x * q_N_corr2.x + q_N_corr2.y * q_N_corr2.y); + double EP_res = (norm_S && norm_N) ? SP_QS_QN / (norm_S * norm_N) : 0; + + h.S_x_corr2_avg->Fill(cent, q_S_corr2.x); + h.S_y_corr2_avg->Fill(cent, q_S_corr2.y); + h.N_x_corr2_avg->Fill(cent, q_N_corr2.x); + h.N_y_corr2_avg->Fill(cent, q_N_corr2.y); + + h.S_xx_corr_avg->Fill(cent, q_S_corr2.x * q_S_corr2.x); + h.S_yy_corr_avg->Fill(cent, q_S_corr2.y * q_S_corr2.y); + h.S_xy_corr_avg->Fill(cent, q_S_corr2.x * q_S_corr2.y); + h.N_xx_corr_avg->Fill(cent, q_N_corr2.x * q_N_corr2.x); + h.N_yy_corr_avg->Fill(cent, q_N_corr2.y * q_N_corr2.y); + h.N_xy_corr_avg->Fill(cent, q_N_corr2.x * q_N_corr2.y); + + h.NS_xx_corr_avg->Fill(cent, q_NS_corr2.x * q_NS_corr2.x); + h.NS_yy_corr_avg->Fill(cent, q_NS_corr2.y * q_NS_corr2.y); + h.NS_xy_corr_avg->Fill(cent, q_NS_corr2.x * q_NS_corr2.y); + + h.Psi_S_corr2->Fill(cent, psi_S); + h.Psi_N_corr2->Fill(cent, psi_N); + h.Psi_NS_corr2->Fill(cent, psi_NS); + + h.EP_res->Fill(cent, EP_res); +} + +bool QVecCalib::process_sEPD() +{ + double sepd_total_charge_south = 0; + double sepd_total_charge_north = 0; + + // Loop over all sEPD Channels + for (int channel = 0; channel < QVecShared::SEPD_CHANNELS; ++channel) + { + double charge = m_evtdata->get_sepd_charge(channel); + + // Skip Noise + if (charge <= m_sEPD_noise_threshold) + { + continue; + } + + // Clamp on high charge threshold + if (m_sEPD_charge_threshold > 0 && charge > m_sEPD_charge_threshold) + { + charge = m_sEPD_charge_threshold; + } + + unsigned int key = TowerInfoDefs::encode_epd(channel); + unsigned int arm = TowerInfoDefs::get_epd_arm(key); + int rbin = TowerInfoDefs::get_epd_rbin(key); + + // Skip Innermost Ring + if (rbin == 0) + { + continue; + } + + // arm = 0: South + // arm = 1: North + if (arm == 0) + { + sepd_total_charge_south += charge; + } + else + { + sepd_total_charge_north += charge; + } + + // Compute Raw Q vectors for each harmonic and respective arm + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + // Optimized lookup instead of std::cos/std::sin calls + const auto& [cached_cos, cached_sin] = m_trig_cache[h_idx][channel]; + + m_q_vectors[h_idx][arm].x += charge * cached_cos; + m_q_vectors[h_idx][arm].y += charge * cached_sin; + } + } + + // Skip Events with Zero sEPD Total Charge in either arm + if (sepd_total_charge_south == 0 || sepd_total_charge_north == 0) + { + return false; + } + + // Normalize the Q-vectors by total charge + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + for (auto det : m_subdetectors) + { + size_t det_idx = (det == QVecShared::Subdetector::S) ? 0 : 1; + double sepd_total_charge = (det_idx == 0) ? sepd_total_charge_south : sepd_total_charge_north; + m_q_vectors[h_idx][det_idx].x /= sepd_total_charge; + m_q_vectors[h_idx][det_idx].y /= sepd_total_charge; + } + } + + return true; +} + +bool QVecCalib::process_event_check() +{ + double cent = m_evtdata->get_event_centrality(); + int cent_bin = hSEPD_Charge_Min->FindBin(cent); + + double sepd_totalcharge = m_evtdata->get_sepd_totalcharge(); + + double sepd_totalcharge_min = hSEPD_Charge_Min->GetBinContent(cent_bin); + double sepd_totalcharge_max = hSEPD_Charge_Max->GetBinContent(cent_bin); + + return sepd_totalcharge > sepd_totalcharge_min && sepd_totalcharge < sepd_totalcharge_max; +} + +//____________________________________________________________________________.. +int QVecCalib::process_event(PHCompositeNode *topNode) +{ + m_evtdata = findNode::getClass(topNode, "EventPlaneData"); + if (!m_evtdata) + { + std::cout << PHWHERE << "EventPlaneData Node missing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + int event_id = m_evtdata->get_event_id(); + + if (Verbosity() && m_event % PROGRESS_REPORT_INTERVAL == 0) + { + std::cout << "Progress: " << m_event << ", Global: " << event_id << std::endl; + } + ++m_event; + + double cent = m_evtdata->get_event_centrality(); + + bool isGood = process_event_check(); + + // Skip Events with non correlation between centrality and sEPD + if (!isGood) + { + ++m_event_counters.bad_centrality_sepd_correlation; + return Fun4AllReturnCodes::ABORTEVENT; + } + + isGood = process_sEPD(); + + // Skip Events with Zero sEPD Total Charge in either arm + if (!isGood) + { + ++m_event_counters.zero_sepd_total_charge; + return Fun4AllReturnCodes::ABORTEVENT; + } + + hCentrality->Fill(cent); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + const auto& q_S = m_q_vectors[h_idx][0]; // 0 for South + const auto& q_N = m_q_vectors[h_idx][1]; // 1 for North + + // --- First Pass: Derive 1st Order --- + if (m_pass == Pass::ComputeRecentering) + { + process_averages(cent, q_S, q_N, m_average_hists[h_idx]); + } + + // --- Second Pass: Apply 1st Order, Derive 2nd Order --- + else if (m_pass == Pass::ApplyRecentering) + { + process_recentering(cent, h_idx, q_S, q_N, m_recenter_hists[h_idx]); + } + + // --- Third Pass: Apply 2nd Order, Validate --- + else if (m_pass == Pass::ApplyFlattening) + { + process_flattening(cent, h_idx, q_S, q_N, m_flattening_hists[h_idx]); + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int QVecCalib::ResetEvent(PHCompositeNode * /*topNode*/) +{ + m_q_vectors = {}; + + return Fun4AllReturnCodes::EVENT_OK; +} + +void QVecCalib::compute_averages(size_t cent_bin, int h_idx) +{ + int n = m_harmonics[h_idx]; + + std::string S_x_avg_name = QVecShared::get_hist_name("S", "x", n); + std::string S_y_avg_name = QVecShared::get_hist_name("S", "y", n); + std::string N_x_avg_name = QVecShared::get_hist_name("N", "x", n); + std::string N_y_avg_name = QVecShared::get_hist_name("N", "y", n); + + int bin = cent_bin + 1; + + double Q_S_x_avg = m_profiles[S_x_avg_name]->GetBinContent(bin); + double Q_S_y_avg = m_profiles[S_y_avg_name]->GetBinContent(bin); + double Q_N_x_avg = m_profiles[N_x_avg_name]->GetBinContent(bin); + double Q_N_y_avg = m_profiles[N_y_avg_name]->GetBinContent(bin); + + m_correction_data[cent_bin][h_idx][static_cast(QVecShared::Subdetector::S)].avg_Q = {Q_S_x_avg, Q_S_y_avg}; + m_correction_data[cent_bin][h_idx][static_cast(QVecShared::Subdetector::N)].avg_Q = {Q_N_x_avg, Q_N_y_avg}; + + std::cout << std::format( + "Centrality Bin: {}, " + "Harmonic: {}, " + "Q_S_x_avg: {:13.10f}, " + "Q_S_y_avg: {:13.10f}, " + "Q_N_x_avg: {:13.10f}, " + "Q_N_y_avg: {:13.10f}", + cent_bin, + n, + Q_S_x_avg, + Q_S_y_avg, + Q_N_x_avg, + Q_N_y_avg) << std::endl; +} + +void QVecCalib::compute_recentering(size_t cent_bin, int h_idx) +{ + int n = m_harmonics[h_idx]; + + std::string S_x_corr_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr"); + std::string S_y_corr_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr"); + std::string N_x_corr_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr"); + std::string N_y_corr_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr"); + + int bin = cent_bin + 1; + + double Q_S_x_corr_avg = m_profiles[S_x_corr_avg_name]->GetBinContent(bin); + double Q_S_y_corr_avg = m_profiles[S_y_corr_avg_name]->GetBinContent(bin); + double Q_N_x_corr_avg = m_profiles[N_x_corr_avg_name]->GetBinContent(bin); + double Q_N_y_corr_avg = m_profiles[N_y_corr_avg_name]->GetBinContent(bin); + + // -- Compute 2nd Order Correction -- + std::string S_xx_avg_name = QVecShared::get_hist_name("S", "xx", n); + std::string S_yy_avg_name = QVecShared::get_hist_name("S", "yy", n); + std::string S_xy_avg_name = QVecShared::get_hist_name("S", "xy", n); + std::string N_xx_avg_name = QVecShared::get_hist_name("N", "xx", n); + std::string N_yy_avg_name = QVecShared::get_hist_name("N", "yy", n); + std::string N_xy_avg_name = QVecShared::get_hist_name("N", "xy", n); + + double Q_S_xx_avg = m_profiles[S_xx_avg_name]->GetBinContent(bin); + double Q_S_yy_avg = m_profiles[S_yy_avg_name]->GetBinContent(bin); + double Q_S_xy_avg = m_profiles[S_xy_avg_name]->GetBinContent(bin); + double Q_N_xx_avg = m_profiles[N_xx_avg_name]->GetBinContent(bin); + double Q_N_yy_avg = m_profiles[N_yy_avg_name]->GetBinContent(bin); + double Q_N_xy_avg = m_profiles[N_xy_avg_name]->GetBinContent(bin); + + // -- Compute NS Matrix -- + std::string NS_xx_avg_name = QVecShared::get_hist_name("NS", "xx", n); + std::string NS_yy_avg_name = QVecShared::get_hist_name("NS", "yy", n); + std::string NS_xy_avg_name = QVecShared::get_hist_name("NS", "xy", n); + + double Q_NS_xx_avg = m_profiles[NS_xx_avg_name]->GetBinContent(bin); + double Q_NS_yy_avg = m_profiles[NS_yy_avg_name]->GetBinContent(bin); + double Q_NS_xy_avg = m_profiles[NS_xy_avg_name]->GetBinContent(bin); + + m_correction_data[cent_bin][h_idx][static_cast(QVecShared::Subdetector::NS)].X_matrix = calculate_flattening_matrix(Q_NS_xx_avg, Q_NS_yy_avg, Q_NS_xy_avg, n, cent_bin, "NS"); + + for (size_t det_idx = 0; det_idx < 2; ++det_idx) + { + double xx = (det_idx == 0) ? Q_S_xx_avg : Q_N_xx_avg; + double yy = (det_idx == 0) ? Q_S_yy_avg : Q_N_yy_avg; + double xy = (det_idx == 0) ? Q_S_xy_avg : Q_N_xy_avg; + + std::string label = (det_idx == 0) ? "S" : "N"; + + m_correction_data[cent_bin][h_idx][det_idx].X_matrix = calculate_flattening_matrix(xx, yy, xy, n, cent_bin, label); + } + + std::cout << std::format( + "Centrality Bin: {}, " + "Harmonic: {}, " + "Q_S_x_corr_avg: {:13.10f}, " + "Q_S_y_corr_avg: {:13.10f}, " + "Q_N_x_corr_avg: {:13.10f}, " + "Q_N_y_corr_avg: {:13.10f}, " + "Q_S_xx_avg / Q_S_yy_avg: {:13.10f}, " + "Q_N_xx_avg / Q_N_yy_avg: {:13.10f}, " + "Q_NS_xx_avg / Q_NS_yy_avg: {:13.10f}, " + "Q_S_xy_avg: {:13.10f}, " + "Q_N_xy_avg: {:13.10f}, " + "Q_NS_xy_avg: {:13.10f}", + cent_bin, + n, + Q_S_x_corr_avg, + Q_S_y_corr_avg, + Q_N_x_corr_avg, + Q_N_y_corr_avg, + Q_S_xx_avg / Q_S_yy_avg, + Q_N_xx_avg / Q_N_yy_avg, + Q_NS_xx_avg / Q_NS_yy_avg, + Q_S_xy_avg, + Q_N_xy_avg, + Q_NS_xy_avg) << std::endl; +} + +void QVecCalib::print_flattening(size_t cent_bin, int n) const +{ + std::string S_x_corr2_avg_name = QVecShared::get_hist_name("S", "x", n, "_corr2"); + std::string S_y_corr2_avg_name = QVecShared::get_hist_name("S", "y", n, "_corr2"); + std::string N_x_corr2_avg_name = QVecShared::get_hist_name("N", "x", n, "_corr2"); + std::string N_y_corr2_avg_name = QVecShared::get_hist_name("N", "y", n, "_corr2"); + + std::string S_xx_corr_avg_name = QVecShared::get_hist_name("S", "xx", n, "_corr"); + std::string S_yy_corr_avg_name = QVecShared::get_hist_name("S", "yy", n, "_corr"); + std::string S_xy_corr_avg_name = QVecShared::get_hist_name("S", "xy", n, "_corr"); + std::string N_xx_corr_avg_name = QVecShared::get_hist_name("N", "xx", n, "_corr"); + std::string N_yy_corr_avg_name = QVecShared::get_hist_name("N", "yy", n, "_corr"); + std::string N_xy_corr_avg_name = QVecShared::get_hist_name("N", "xy", n, "_corr"); + + std::string NS_xx_corr_avg_name = QVecShared::get_hist_name("NS", "xx", n, "_corr"); + std::string NS_yy_corr_avg_name = QVecShared::get_hist_name("NS", "yy", n, "_corr"); + std::string NS_xy_corr_avg_name = QVecShared::get_hist_name("NS", "xy", n, "_corr"); + + int bin = cent_bin + 1; + + double Q_S_x_corr2_avg = m_profiles.at(S_x_corr2_avg_name)->GetBinContent(bin); + double Q_S_y_corr2_avg = m_profiles.at(S_y_corr2_avg_name)->GetBinContent(bin); + double Q_N_x_corr2_avg = m_profiles.at(N_x_corr2_avg_name)->GetBinContent(bin); + double Q_N_y_corr2_avg = m_profiles.at(N_y_corr2_avg_name)->GetBinContent(bin); + + double Q_S_xx_corr_avg = m_profiles.at(S_xx_corr_avg_name)->GetBinContent(bin); + double Q_S_yy_corr_avg = m_profiles.at(S_yy_corr_avg_name)->GetBinContent(bin); + double Q_S_xy_corr_avg = m_profiles.at(S_xy_corr_avg_name)->GetBinContent(bin); + double Q_N_xx_corr_avg = m_profiles.at(N_xx_corr_avg_name)->GetBinContent(bin); + double Q_N_yy_corr_avg = m_profiles.at(N_yy_corr_avg_name)->GetBinContent(bin); + double Q_N_xy_corr_avg = m_profiles.at(N_xy_corr_avg_name)->GetBinContent(bin); + + double Q_NS_xx_corr_avg = m_profiles.at(NS_xx_corr_avg_name)->GetBinContent(bin); + double Q_NS_yy_corr_avg = m_profiles.at(NS_yy_corr_avg_name)->GetBinContent(bin); + double Q_NS_xy_corr_avg = m_profiles.at(NS_xy_corr_avg_name)->GetBinContent(bin); + + std::cout << std::format( + "Centrality Bin: {}, " + "Harmonic: {}, " + "Q_S_x_corr2_avg: {:13.10f}, " + "Q_S_y_corr2_avg: {:13.10f}, " + "Q_N_x_corr2_avg: {:13.10f}, " + "Q_N_y_corr2_avg: {:13.10f}, " + "Q_S_xx_corr_avg / Q_S_yy_corr_avg: {:13.10f}, " + "Q_N_xx_corr_avg / Q_N_yy_corr_avg: {:13.10f}, " + "Q_NS_xx_corr_avg / Q_NS_yy_corr_avg: {:13.10f}, " + "Q_S_xy_corr_avg: {:13.10f}, " + "Q_N_xy_corr_avg: {:13.10f}, " + "Q_NS_xy_corr_avg: {:13.10f}", + cent_bin, + n, + Q_S_x_corr2_avg, + Q_S_y_corr2_avg, + Q_N_x_corr2_avg, + Q_N_y_corr2_avg, + Q_S_xx_corr_avg / Q_S_yy_corr_avg, + Q_N_xx_corr_avg / Q_N_yy_corr_avg, + Q_NS_xx_corr_avg / Q_NS_yy_corr_avg, + Q_S_xy_corr_avg, + Q_N_xy_corr_avg, + Q_NS_xy_corr_avg) << std::endl; +} + +void QVecCalib::write_cdb() +{ + std::error_code ec; + if (std::filesystem::create_directories(m_cdb_output_dir, ec)) + { + std::cout << "Success: Directory " << m_cdb_output_dir << " created" << std::endl; + } + else if (ec) + { + std::cout << "Failed to create directory " << m_cdb_output_dir << ": " << ec.message() << std::endl; + exit(1); + } + else + { + std::cout << "Info: Directory " << m_cdb_output_dir << " already exists." << std::endl; + } + + write_cdb_EventPlane(); +} + +void QVecCalib::write_cdb_EventPlane() +{ + std::cout << "Writing Event Plane CDB" << std::endl; + + std::string payload = "SEPD_EventPlaneCalib"; + std::string output_file = std::format("{}/{}-{}-{}.root", m_cdb_output_dir, payload, m_dst_tag, m_runnumber); + + CDBTTree cdbttree(output_file); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + // Define lambdas to generate field names consistently + auto field = [&](const std::string& det, const std::string& var) + { + return std::format("Q_{}_{}_{}_avg", det, var, n); + }; + + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) + { + int key = cent_bin; + + // Iterate through all subdetectors (S, N, NS) using the Enum Count + for (size_t d = 0; d < static_cast(QVecShared::Subdetector::Count); ++d) + { + auto det_enum = static_cast(d); + + // Map enum to the string labels used in the CDB field names + std::string det_label; + switch (det_enum) + { + case QVecShared::Subdetector::S: + det_label = "S"; + break; + case QVecShared::Subdetector::N: + det_label = "N"; + break; + case QVecShared::Subdetector::NS: + det_label = "NS"; + break; + default: + continue; + } + + const auto& data = m_correction_data[cent_bin][h_idx][d]; + // 1st Order Moments (Recentering) - Skip for NS as it is a combined vector + if (det_enum != QVecShared::Subdetector::NS) + { + cdbttree.SetDoubleValue(key, field(det_label, "x"), data.avg_Q.x); + cdbttree.SetDoubleValue(key, field(det_label, "y"), data.avg_Q.y); + } + + // 2nd Order Moments (Flattening) - Applicable to S, N, and NS + cdbttree.SetDoubleValue(key, field(det_label, "xx"), data.avg_Q_xx); + cdbttree.SetDoubleValue(key, field(det_label, "yy"), data.avg_Q_yy); + cdbttree.SetDoubleValue(key, field(det_label, "xy"), data.avg_Q_xy); + } + } + } + + std::cout << "Saving CDB: " << payload << " to " << output_file << std::endl; + + cdbttree.Commit(); + cdbttree.WriteCDBTTree(); +} + +//____________________________________________________________________________.. +int QVecCalib::End(PHCompositeNode * /*topNode*/) +{ + std::cout << "QVecCalib::End(PHCompositeNode *topNode) This is the End..." << std::endl; + + std::cout << "\n--- Event Counter Summary ---" << std::endl; + std::cout << "Bad Centrality/sEPD corr: " << m_event_counters.bad_centrality_sepd_correlation << std::endl; + std::cout << "Zero sEPD Charge: " << m_event_counters.zero_sepd_total_charge << std::endl; + std::cout << "Total Events Seen: " << m_event << std::endl; + std::cout << "-----------------------------\n" << std::endl; + + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) + { + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + if (m_pass == Pass::ComputeRecentering) + { + compute_averages(cent_bin, h_idx); + } + + else if (m_pass == Pass::ApplyRecentering) + { + compute_recentering(cent_bin, h_idx); + } + + else if (m_pass == Pass::ApplyFlattening) + { + print_flattening(cent_bin, n); + } + } + } + + if (m_pass == Pass::ApplyFlattening) + { + write_cdb(); + } + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h new file mode 100644 index 0000000000..0613505794 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/QVecCalib.h @@ -0,0 +1,423 @@ +#ifndef SEPDEVENTPLANECALIB_QVECCALIB_H +#define SEPDEVENTPLANECALIB_QVECCALIB_H + +#include "QVecDefs.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +class PHCompositeNode; +class EventPlaneData; +class TFile; +class TH1; +class TH2; +class TProfile; + +/** + * @class QVecCalib + * @brief Orchestrates the multi-pass anisotropy calibration for the sEPD Q-vectors. + * + * This class implements a three-pass correction procedure designed to remove + * detector-induced biases from the sEPD event plane reconstruction: + * * 1. **ComputeRecentering**: Calculates the first-order vector offsets (re-centering) + * per centrality bin. + * 2. **ApplyRecentering**: Applies the first-order offsets and computes the + * second-order whitening/flattening matrix. + * 3. **ApplyFlattening**: Applies the full correction (re-centering + flattening) + * to produce final validated event planes. + * * The class manages event-level selections based on charge-centrality correlations + * and handles the exclusion of "bad" (hot/cold/dead) sEPD channels. + */ +class QVecCalib : public SubsysReco +{ + public: + explicit QVecCalib(const std::string& name = "QVecCalib"); + + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + int Init(PHCompositeNode* topNode) override; + + /** Called for first event when run number is known. + Typically this is where you may want to fetch data from + database, because you know the run number. + */ + int InitRun(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode* topNode) override; + + /// Clean up internals after each event. + int ResetEvent(PHCompositeNode* topNode) override; + + /// Called at the end of all processing. + int End(PHCompositeNode* topNode) override; + + enum class Pass + { + ComputeRecentering, + ApplyRecentering, + ApplyFlattening + }; + + void set_pass(int pass) + { + m_pass = validate_pass(pass); + } + + void set_input_hist(std::string_view file) + { + m_input_hist = file; + } + + void set_input_Q_calib(std::string_view file) + { + m_input_Q_calib = file; + } + + void set_dst_tag(std::string_view tag) + { + m_dst_tag = tag; + } + + void set_cdb_output_dir(std::string_view cdb_dir) + { + m_cdb_output_dir = cdb_dir; + } + + void set_charge_threshold(double threshold) + { + m_sEPD_charge_threshold = std::max(0.0, threshold); + } + + void set_noise_threshold(double threshold) + { + m_sEPD_noise_threshold = threshold; + } + + private: + static Pass validate_pass(int pass) + { + switch (pass) + { + case 0: + return Pass::ComputeRecentering; + case 1: + return Pass::ApplyRecentering; + case 2: + return Pass::ApplyFlattening; + default: + throw std::invalid_argument("Invalid pass value"); + } + } + + struct CorrectionData + { + QVecShared::QVec avg_Q{}; + + double avg_Q_xx{0.0}; + double avg_Q_yy{0.0}; + double avg_Q_xy{0.0}; + + std::array, 2> X_matrix{}; + }; + + static constexpr size_t m_cent_bins = QVecShared::CENT_BINS; + static constexpr auto m_harmonics = QVecShared::HARMONICS; + + static constexpr float SIGMA_HOT {6.0}; + static constexpr float SIGMA_COLD {-6.0}; + + double m_cent_low{-0.5}; + double m_cent_high{79.5}; + + std::string m_input_hist; + std::string m_input_Q_calib; + std::string m_dst_tag; + std::string m_cdb_output_dir{"."}; + Pass m_pass{Pass::ComputeRecentering}; + EventPlaneData* m_evtdata{nullptr}; + + int m_event{0}; + int m_runnumber{0}; + + struct EventCounters + { + int bad_centrality_sepd_correlation{0}; + int zero_sepd_total_charge{0}; + int total_processed{0}; + }; + + EventCounters m_event_counters; + + std::array, m_harmonics.size()> m_q_vectors{}; + + static constexpr int PROGRESS_REPORT_INTERVAL = 10000; + + // Holds all correction data + // key: [Cent][Harmonic][Subdetector] + // Harmonics {2,3,4} -> 3 elements + // Subdetectors {S,N,NS} -> 3 elements + std::array, m_harmonics.size()>, m_cent_bins> m_correction_data; + + // Store harmonic orders and subdetectors for easy iteration + static constexpr std::array m_subdetectors = {QVecShared::Subdetector::S, QVecShared::Subdetector::N}; + static constexpr std::array m_components = {QVecShared::QComponent::X, QVecShared::QComponent::Y}; + + // [Harmonic Index][Channel Index] -> {cos, sin} + std::vector>> m_trig_cache; + + struct AverageHists + { + TProfile* S_x_avg{nullptr}; + TProfile* S_y_avg{nullptr}; + TProfile* N_x_avg{nullptr}; + TProfile* N_y_avg{nullptr}; + + TH2* Psi_S{nullptr}; + TH2* Psi_N{nullptr}; + TH2* Psi_NS{nullptr}; + }; + + struct RecenterHists + { + TProfile* S_x_corr_avg{nullptr}; + TProfile* S_y_corr_avg{nullptr}; + TProfile* N_x_corr_avg{nullptr}; + TProfile* N_y_corr_avg{nullptr}; + + TProfile* S_xx_avg{nullptr}; + TProfile* S_yy_avg{nullptr}; + TProfile* S_xy_avg{nullptr}; + TProfile* N_xx_avg{nullptr}; + TProfile* N_yy_avg{nullptr}; + TProfile* N_xy_avg{nullptr}; + + TProfile* NS_xx_avg{nullptr}; + TProfile* NS_yy_avg{nullptr}; + TProfile* NS_xy_avg{nullptr}; + + TH2* Psi_S_corr{nullptr}; + TH2* Psi_N_corr{nullptr}; + TH2* Psi_NS_corr{nullptr}; + }; + + struct FlatteningHists + { + TProfile* S_x_corr2_avg{nullptr}; + TProfile* S_y_corr2_avg{nullptr}; + TProfile* N_x_corr2_avg{nullptr}; + TProfile* N_y_corr2_avg{nullptr}; + + TProfile* S_xx_corr_avg{nullptr}; + TProfile* S_yy_corr_avg{nullptr}; + TProfile* S_xy_corr_avg{nullptr}; + + TProfile* N_xx_corr_avg{nullptr}; + TProfile* N_yy_corr_avg{nullptr}; + TProfile* N_xy_corr_avg{nullptr}; + + TProfile* NS_xx_corr_avg{nullptr}; + TProfile* NS_yy_corr_avg{nullptr}; + TProfile* NS_xy_corr_avg{nullptr}; + + TProfile* EP_res{nullptr}; + + TH2* Psi_S_corr2{nullptr}; + TH2* Psi_N_corr2{nullptr}; + TH2* Psi_NS_corr2{nullptr}; + }; + + double m_sEPD_sigma_threshold{3}; + + double m_sEPD_charge_threshold{50}; + double m_sEPD_noise_threshold{0.5}; + + // Hists + TH1* hCentrality{nullptr}; + + TH2* h2SEPD_Charge{nullptr}; + TH2* h2SEPD_Chargev2{nullptr}; + + TProfile* hSEPD_Charge_Min{nullptr}; + TProfile* hSEPD_Charge_Max{nullptr}; + + std::map m_hists2D; + std::map m_profiles; + + std::vector m_average_hists; + std::vector m_recenter_hists; + std::vector m_flattening_hists; + + /** + * @brief Initializes all output histograms and profiles. + * * Dynamically generates histogram names using the shared naming helper based on + * the current calibration pass (e.g., adding "_corr" or "_corr2" suffixes). + */ + void init_hists(); + + /** + * @brief Safely retrieves a ROOT object from a file and returns a managed pointer. + * * Performs a dynamic_cast to verify the requested type T and Clones the object + * to ensure it remains valid after the source file is closed. + * * @tparam T The ROOT class type (e.g., TProfile). + * @param file Pointer to the source TFile. + * @param name The name of the object within the file. + * @return T* A managed pointer to the cloned object. + * @throws std::runtime_error If the object is not found or type mismatch occurs. + */ + template + T* load_and_clone(TFile* file, const std::string& name); + + /** + * @brief Loads the results of previous passes from a calibration file. + * * Populates the internal correction data structure with averages and/or + * matrices required for the current processing pass. + */ + int load_correction_data(); + + /** + * @brief Validates events based on sEPD total charge vs. centrality correlation. + * * Compares the current event's total charge against the 3-sigma bounds derived + * from the QA histograms to reject pile-up or background-dominated events. + * @return True if the event falls within the acceptable charge window. + */ + bool process_event_check(); + + /** + * @brief Performs the primary tower-by-tower Q-vector calculation and normalization. + * * Loops through sEPD channels, excludes bad channels, calculates the raw Q-vector + * for all harmonics, and normalizes the results by the total arm charge. + * @return True if both South and North arms have non-zero total charge. + */ + bool process_sEPD(); + + /** + * @brief Calculates and fills profiles for the initial Q-vector averages. + * @param cent The event centrality. + * @param q_S The South arm normalized Q-vector. + * @param q_N The North arm normalized Q-vector. + * @param h Reference to the cache of profiles for the first pass. + */ + static void process_averages(double cent, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const AverageHists& h); + + /** + * @brief Applies re-centering offsets and fills profiles for second-moment calculation. + * @param cent The event centrality. + * @param h_idx Harmonic index. + * @param q_S The South arm normalized Q-vector. + * @param q_N The North arm normalized Q-vector. + * @param h Reference to the cache of profiles for the second pass. + */ + void process_recentering(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const RecenterHists& h); + + /** + * @brief Applies the full correction (re-centering + flattening) for validation. + * @param cent The event centrality. + * @param h_idx Harmonic index. + * @param q_S The South arm normalized Q-vector. + * @param q_N The North arm normalized Q-vector. + * @param h Reference to the cache of profiles for the third pass. + */ + void process_flattening(double cent, size_t h_idx, const QVecShared::QVec& q_S, const QVecShared::QVec& q_N, const FlatteningHists& h); + + /** + * @brief Calculates the 2x2 anisotropy correction (whitening) matrix. + * * This matrix transforms the elliptical Q-vector distribution into a circularly + * symmetric (isotropic) distribution. It effectively corrects for detector + * acceptance effects and gain non-uniformities by normalizing the second-order + * moments of the Q-vector. + * * @param xx The second moment. + * @param yy The second moment. + * @param xy The cross-moment. + * @param n Harmonic order (used for error logging context). + * @param cent_bin Centrality bin (used for error logging context). + * @param det_label Detector label ("S" or "N"). + * @return std::array, 2> The 2x2 correction matrix. + */ + std::array, 2> calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label); + + /** + * @brief Computes 1st-order re-centering offsets for a specific centrality bin. + * * Extracts average Q-vector components from histograms and stores them in the + * correction data matrix for use in subsequent processing passes. + * * @param cent_bin The index of the centrality bin. + * @param h_idx The index of the harmonic order in the harmonics array. + */ + void compute_averages(size_t cent_bin, int h_idx); + + /** + * @brief Computes re-centering parameters and solves the flattening matrices. + * * Extracts the re-centered second moments from the profiles and populates the + * internal CorrectionData matrix with calculated flattening coefficients. + * @param cent_bin The centrality bin index. + * @param h_idx The harmonic index. + */ + void compute_recentering(size_t cent_bin, int h_idx); + + /** + * @brief Logs the final corrected moments to verify successful flattening. + * @param cent_bin The centrality bin index. + * @param n The harmonic order. + */ + void print_flattening(size_t cent_bin, int n) const; + + void prepare_hists(); + + /** + * @brief Prepares a vector of pointers to histograms used in the first pass. + * @return A vector of AverageHists structs, indexed by harmonic. + */ + void prepare_average_hists(); + + /** + * @brief Prepares a vector of pointers to histograms used in the second pass. + * @return A vector of RecenterHists structs, indexed by harmonic. + */ + void prepare_recenter_hists(); + + /** + * @brief Prepares a vector of pointers to histograms used in the third pass. + * @return A vector of FlatteningHists structs, indexed by harmonic. + */ + void prepare_flattening_hists(); + + /** + * @brief Top-level driver for processing Quality Assurance histograms. + * * Loads the reference histogram file to identify bad channels and establish + * event-level charge thresholds as a function of centrality. + */ + int process_QA_hist(); + + /** + * @brief Establishes sEPD charge-cut thresholds for event selection. + * * Uses the 2D total charge vs. centrality distribution to derive mean and + * sigma values, generating a 1D profile of the selection window. + * @param file Pointer to the open QA histogram file. + */ + int process_sEPD_event_thresholds(TFile* file); + + void write_cdb(); + + /** + * @brief Writes the Event Plane calibration constants to a CDB-formatted TTree. + * * Formats the re-centering and flattening moments into a CDBTTree payload + * indexed by centrality bin for sPHENIX database integration. + * * @param output_dir The filesystem directory where the .root payload will be saved. + */ + void write_cdb_EventPlane(); +}; + +#endif // SEPDEVENTPLANECALIB_QVECCALIB_H diff --git a/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h new file mode 100644 index 0000000000..656ec1dc8f --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/QVecDefs.h @@ -0,0 +1,58 @@ +#ifndef SEPDEVENTPLANECALIB_QVECDEFS_H +#define SEPDEVENTPLANECALIB_QVECDEFS_H + +#include +#include +#include +#include + +namespace QVecShared +{ + static constexpr size_t CENT_BINS = 80; + static constexpr std::array HARMONICS = {2, 3, 4}; + static constexpr int SEPD_CHANNELS = 744; + + enum class ChannelStatus : int + { + Good = 0, + Dead = 1, + Hot = 2, + Cold = 3 + }; + + enum class Subdetector : size_t + { + S = 0, + N = 1, + NS = 2, + Count = 3 + }; + + enum class QComponent + { + X, + Y + }; + + struct QVec + { + double x{0.0}; + double y{0.0}; + }; + + /** + * @brief Centralized helper to generate standard histogram names for the sEPD calibration. + * * Standardizes the naming convention: h_sEPD_Q_{det}_{var}_{n}{suffix}_avg + * * @param det The detector arm ("S" for South, "N" for North). + * @param var The physics variable or moment (e.g., "x", "y", "xx", "xy"). + * @param n The harmonic order (e.g., 2, 3, 4). + * @param suffix Optional pass-specific suffix (e.g., "_corr", "_corr2"). + * @return A formatted std::string representing the ROOT histogram name. + */ + inline std::string get_hist_name(const std::string& det, const std::string& var, int n, const std::string& suffix = "") + { + return std::format("h_sEPD_Q_{}_{}_{}{}_avg", det, var, n, suffix); + } +} // namespace QVecShared + +#endif // SEPDEVENTPLANECALIB_QVECDEFS_H diff --git a/calibrations/sepd/sepd_eventplanecalib/autogen.sh b/calibrations/sepd/sepd_eventplanecalib/autogen.sh new file mode 100755 index 0000000000..18aced5f8f --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd "$srcdir" || exit 1; aclocal -I "${OFFLINE_MAIN}/share" && +libtoolize --force && automake -a --add-missing && autoconf) + +$srcdir/configure "$@" diff --git a/calibrations/sepd/sepd_eventplanecalib/configure.ac b/calibrations/sepd/sepd_eventplanecalib/configure.ac new file mode 100644 index 0000000000..5fcb1af63a --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/configure.ac @@ -0,0 +1,19 @@ +AC_INIT(sepd_eventplanecalib,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wshadow -Wall -Wextra -Werror" +fi + +CINTDEFS=" -noIncludePaths -inlineInputHeader " +AC_SUBST(CINTDEFS) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc new file mode 100644 index 0000000000..b757561999 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.cc @@ -0,0 +1,343 @@ +#include "sEPD_TreeGen.h" +#include "QVecDefs.h" +#include "EventPlaneData.h" + +// -- Calo +#include +#include + +// -- Vtx +#include +#include + +// -- MB +#include + +#include + +// -- sEPD +#include + +// -- event +#include + +// -- Fun4All +#include +#include + +// -- Nodes +#include +#include +#include + +// -- ROOT +#include +#include + +// -- c++ +#include +#include + +//____________________________________________________________________________.. +sEPD_TreeGen::sEPD_TreeGen(const std::string &name) + : SubsysReco(name) +{ +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::Init(PHCompositeNode *topNode) +{ + Fun4AllServer *se = Fun4AllServer::instance(); + if (Verbosity() > 0) + { + se->Print("NODETREE"); + } + unsigned int bins_sepd_totalcharge{100}; + double sepd_totalcharge_low{0}; + double sepd_totalcharge_high{2e4}; + + unsigned int bins_centrality{80}; + double centrality_low{-0.5}; + double centrality_high{79.5}; + + hSEPD_Charge = new TProfile("hSEPD_Charge", "|z| < 10 cm and MB; Channel; Avg Charge", QVecShared::SEPD_CHANNELS, 0, QVecShared::SEPD_CHANNELS); + hSEPD_Charge->Sumw2(); + + h2SEPD_totalcharge_centrality = new TH2F("h2SEPD_totalcharge_centrality", + "|z| < 10 cm and MB; sEPD Total Charge; Centrality [%]", + bins_sepd_totalcharge, sepd_totalcharge_low, sepd_totalcharge_high, + bins_centrality, centrality_low, centrality_high); + + se->registerHisto(hSEPD_Charge); + se->registerHisto(h2SEPD_totalcharge_centrality); + + PHNodeIterator node_itr(topNode); + PHCompositeNode *dstNode = dynamic_cast(node_itr.findFirst("PHCompositeNode", "DST")); + + if (!dstNode) + { + std::cout << PHWHERE << "DST node missing, cannot attach EventPlaneData." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + EventPlaneData *evtdata = findNode::getClass(topNode, "EventPlaneData"); + if (!evtdata) + { + evtdata = new EventPlaneData(); + PHIODataNode *newNode = new PHIODataNode(evtdata, "EventPlaneData", "PHObject"); + dstNode->addNode(newNode); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::process_event_check(PHCompositeNode *topNode) +{ + GlobalVertexMap *vertexmap = findNode::getClass(topNode, "GlobalVertexMap"); + + if (!vertexmap) + { + std::cout << PHWHERE << "GlobalVertexMap Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + if (vertexmap->empty()) + { + if (Verbosity() > 1) + { + std::cout << PHWHERE << "GlobalVertexMap Empty, Skipping Event: " << m_data.event_id << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + GlobalVertex *vtx = vertexmap->begin()->second; + double zvtx = vtx->get_z(); + + MinimumBiasInfo *m_mb_info = findNode::getClass(topNode, "MinimumBiasInfo"); + if (!m_mb_info) + { + std::cout << PHWHERE << "MinimumBiasInfo Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + // skip event if not minimum bias + if (!m_mb_info->isAuAuMinimumBias()) + { + if (Verbosity() > 1) + { + std::cout << "Event: " << m_data.event_id << ", Not Min Bias, Skipping" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + // skip event if zvtx is too large + if (std::abs(zvtx) >= m_cuts.m_zvtx_max) + { + if (Verbosity() > 1) + { + std::cout << "Event: " << m_data.event_id << ", Z: " << zvtx << " cm, Skipping" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_evtdata->set_event_zvertex(zvtx); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::process_centrality(PHCompositeNode *topNode) +{ + CentralityInfo *centInfo = findNode::getClass(topNode, "CentralityInfo"); + if (!centInfo) + { + std::cout << PHWHERE << "CentralityInfo Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + double cent = centInfo->get_centile(CentralityInfo::PROP::mbd_NS) * 100; + + // skip event if centrality is bad or too peripheral + if (!std::isfinite(cent) || cent < 0 || cent >= m_cuts.m_cent_max) + { + if (Verbosity() > 1) + { + std::cout << "Event: " << m_data.event_id << ", Centrality: " << cent << ", Skipping" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_evtdata->set_event_centrality(cent); + m_data.event_centrality = cent; + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::process_sEPD(PHCompositeNode *topNode) +{ + TowerInfoContainer *towerinfosEPD = findNode::getClass(topNode, m_inputNode); + if (!towerinfosEPD) + { + std::cout << PHWHERE << m_inputNode << " Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + EpdGeom *epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); + if (!epdgeom) + { + std::cout << PHWHERE << "TOWERGEOM_EPD Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + // sepd + unsigned int sepd_channels = towerinfosEPD->size(); + + if(sepd_channels != QVecShared::SEPD_CHANNELS) + { + if (Verbosity() > 1) + { + std::cout << "Event: " << m_data.event_id << ", SEPD Channels = " << sepd_channels << " != " << QVecShared::SEPD_CHANNELS << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + double sepd_totalcharge = 0; + + for (unsigned int channel = 0; channel < sepd_channels; ++channel) + { + TowerInfo *tower = towerinfosEPD->get_tower_at_channel(channel); + + if (!tower) + { + if (Verbosity() > 1) + { + std::cout << PHWHERE << "Null SEPD tower at channel " << channel << std::endl; + } + continue; + } + + double charge = tower->get_energy(); + bool isZS = tower->get_isZS(); + + // exclude ZS + // exclude Nmips + if (isZS || charge < m_cuts.m_sepd_charge_min) + { + continue; + } + + m_evtdata->set_sepd_charge(channel, charge); + + sepd_totalcharge += charge; + + hSEPD_Charge->Fill(channel, charge); + } + + m_evtdata->set_sepd_totalcharge(sepd_totalcharge); + h2SEPD_totalcharge_centrality->Fill(sepd_totalcharge, m_data.event_centrality); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +void sEPD_TreeGen::Print([[maybe_unused]] const std::string &what) const +{ + // Only execute if Verbosity is high enough + if (Verbosity() <= 2) + { + return; + } + + std::cout << "\n============================================================" << std::endl; + std::cout << "sEPD_TreeGen::Print -> Event Data State" << std::endl; + + if (!m_evtdata) + { + std::cout << " [WARNING] m_evtdata is null." << std::endl; + return; + } + + // Verbosity > 2: Print basic scalars + std::cout << " Event ID: " << m_evtdata->get_event_id() << std::endl; + std::cout << " Z-Vertex: " << m_evtdata->get_event_zvertex() << " cm" << std::endl; + std::cout << " Centrality: " << m_evtdata->get_event_centrality() << " %" << std::endl; + std::cout << " sEPD Total Charge: " << m_evtdata->get_sepd_totalcharge() << std::endl; + + // Verbosity > 3: Print channel arrays + if (Verbosity() > 3) + { + std::cout << " Active Towers (Charge > 0):" << std::endl; + for (int i = 0; i < QVecShared::SEPD_CHANNELS; ++i) + { + double charge = m_evtdata->get_sepd_charge(i); + if (charge > 0) + { + std::cout << " Channel: " << std::setw(3) << i + << " | Charge: " << std::fixed << std::setprecision(4) << charge << std::endl; + } + } + } + std::cout << "============================================================\n" << std::endl; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::process_event(PHCompositeNode *topNode) +{ + EventHeader *eventInfo = findNode::getClass(topNode, "EventHeader"); + if (!eventInfo) + { + std::cout << PHWHERE << "EventHeader Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_data.event_id = eventInfo->get_EvtSequence(); + + if (Verbosity() && m_event % PROGRESS_PRINT_INTERVAL == 0) + { + std::cout << "Progress: " << m_event << ", Global: " << m_data.event_id << std::endl; + } + ++m_event; + + m_evtdata = findNode::getClass(topNode, "EventPlaneData"); + if (!m_evtdata) + { + std::cout << PHWHERE << "EventPlaneData Node missing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_evtdata->set_event_id(m_data.event_id); + + int ret = process_event_check(topNode); + if (ret) + { + return ret; + } + + ret = process_centrality(topNode); + if (ret) + { + return ret; + } + + ret = process_sEPD(topNode); + if (ret) + { + return ret; + } + + Print(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int sEPD_TreeGen::ResetEvent([[maybe_unused]] PHCompositeNode *topNode) +{ + // Event + m_data.event_id = -1; + m_data.event_centrality = 9999; + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h new file mode 100644 index 0000000000..c8d7222a32 --- /dev/null +++ b/calibrations/sepd/sepd_eventplanecalib/sEPD_TreeGen.h @@ -0,0 +1,145 @@ +#ifndef SEPDEVENTPLANECALIB_SEPDTREEGEN_H +#define SEPDEVENTPLANECALIB_SEPDTREEGEN_H + +// -- sPHENIX +#include + +// -- c++ +#include + +class EventPlaneData; +class PHCompositeNode; +class TH2; +class TProfile; + +/** + * @class sEPD_TreeGen + * @brief SubsysReco module to produce flat TTrees and QA histograms for sEPD calibration. + * + * This module extracts event-level info (vertex, centrality) and sEPD tower-level info + * (charge, phi, channel ID), applying basic event selections (Minimum Bias, Z-vertex) + * and tower-level cuts (charge threshold, zero-suppression). + */ +class sEPD_TreeGen : public SubsysReco +{ + public: + /** + * @brief Constructor for sEPD_TreeGen. + * @param name The name assigned to this SubsysReco module. + */ + explicit sEPD_TreeGen(const std::string &name = "sEPD_TreeGen"); + + /** + * @brief Initializes the module and creates the output TTree and QA histograms. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int Init(PHCompositeNode *topNode) override; + + /** + * @brief Main event-by-event processing method. + * @details Orchestrates event checks, centrality retrieval, sEPD tower processing, + * and fills the TTree for valid events. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int process_event(PHCompositeNode *topNode) override; + + /** + * @brief Resets event-level data structures before the next event. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int ResetEvent(PHCompositeNode *topNode) override; + + /** + * @brief Prints the current state of the EventPlaneData object. + * @param what Optional string to specify what to print (default "ALL"). + */ + void Print(const std::string &what = "ALL") const override; + + /** + * @brief Sets the maximum allowed Z-vertex position for event selection. + * @param zvtx_max Maximum vertex Z in cm. + */ + void set_zvtx_max(double zvtx_max) + { + m_cuts.m_zvtx_max = zvtx_max; + } + + /** + * @brief Sets the minimum charge threshold for individual sEPD towers. + * @param charge_min Minimum charge to include a tower in the TTree. + */ + void set_sepd_charge_threshold(double charge_min) + { + m_cuts.m_sepd_charge_min = charge_min; + } + + /** + * @brief Sets the maximum centrality centile allowed for processing. + * @param cent_max Maximum centile (e.g., 80 for 0-80%). + */ + void set_cent_max(double cent_max) + { + m_cuts.m_cent_max = cent_max; + } + + void set_inputNode(const std::string &inputNode) + { + m_inputNode = inputNode; + } + + private: + /** + * @brief Validates event-level conditions (GlobalVertex, Minimum Bias). + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int process_event_check(PHCompositeNode *topNode); + + /** + * @brief Processes individual sEPD towers and calculates total charge. + * @details Applies tower cuts, fills QA histograms, and stores tower data in vectors. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int process_sEPD(PHCompositeNode *topNode); + + /** + * @brief Retrieves and validates centrality information. + * @param topNode Pointer to the node tree. + * @return Fun4All return code. + */ + int process_centrality(PHCompositeNode *topNode); + + std::string m_inputNode{"TOWERINFO_CALIB_SEPD"}; + + int m_event{0}; + + static constexpr int PROGRESS_PRINT_INTERVAL = 20; + + // Cuts + struct Cuts + { + double m_zvtx_max{10}; /*cm*/ + double m_sepd_charge_min{0.2}; + double m_cent_max{80}; + }; + + Cuts m_cuts; + + struct EventData + { + int event_id{0}; + double event_centrality{9999}; + }; + + EventData m_data; + EventPlaneData* m_evtdata{nullptr}; + + TProfile *hSEPD_Charge{nullptr}; + TH2 *h2SEPD_totalcharge_centrality{nullptr}; +}; + +#endif // SEPDEVENTPLANECALIB_SEPDTREEGEN_H diff --git a/calibrations/tpc/TpcDVCalib/Makefile.am b/calibrations/tpc/TpcDVCalib/Makefile.am index 033929f967..6ae4411894 100644 --- a/calibrations/tpc/TpcDVCalib/Makefile.am +++ b/calibrations/tpc/TpcDVCalib/Makefile.am @@ -24,10 +24,6 @@ libTpcDVCalib_la_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib libTpcDVCalib_la_LIBADD = \ - -lActsCore \ - -lActsPluginTGeo \ - -lActsExamplesDetectorTGeo \ - -lActsExamplesFramework \ -lSubsysReco \ -ltrackbase_historic_io \ -ltrack_io \ diff --git a/calibrations/tpc/TpcDVCalib/TrackToCalo.cc b/calibrations/tpc/TpcDVCalib/TrackToCalo.cc index f9707e4862..0a6bf6117f 100644 --- a/calibrations/tpc/TpcDVCalib/TrackToCalo.cc +++ b/calibrations/tpc/TpcDVCalib/TrackToCalo.cc @@ -38,14 +38,7 @@ #include #include #include -#include - -#include -#include -#include -#include -#include -#include + #include #include diff --git a/calibrations/tpc/dEdx/GlobaldEdxFitter.cc b/calibrations/tpc/dEdx/GlobaldEdxFitter.cc new file mode 100644 index 0000000000..1cefa44dcd --- /dev/null +++ b/calibrations/tpc/dEdx/GlobaldEdxFitter.cc @@ -0,0 +1,346 @@ +#include "GlobaldEdxFitter.h" + +#include "bethe_bloch.h" +#include "TF1.h" +#include "TF2.h" +#include "TF3.h" +#include "TChain.h" +#include "TGraph.h" +#include "Math/Minimizer.h" +#include "Math/Functor.h" +#include "Math/Factory.h" + +void GlobaldEdxFitter::processResidualData(const std::string& infile, size_t ntracks, size_t skip) +{ + std::unique_ptr t = std::make_unique(); + t->Add((infile+"?#residualtree").c_str()); +// TFile* f = TFile::Open(infile.c_str()); +// TTree* t = (TTree*)f->Get("residualtree"); + + float px; + float py; + float pz; + float dedx; + float eta; + int nmaps; + int nintt; + int ntpc; + float dcaxy; + + t->SetBranchAddress("px",&px); + t->SetBranchAddress("py",&py); + t->SetBranchAddress("pz",&pz); + t->SetBranchAddress("dedx",&dedx); + t->SetBranchAddress("eta",&eta); + t->SetBranchAddress("nmaps",&nmaps); + t->SetBranchAddress("nintt",&nintt); + t->SetBranchAddress("ntpc",&ntpc); + t->SetBranchAddress("dcaxy",&dcaxy); + + size_t total_entries = t->GetEntriesFast(); + + for(size_t entry=skip; entry<(skip+ntracks); entry++) + { + if(entry==total_entries) + { + break; + } + if(entry % 1000 == 0) + { + std::cout << entry << std::endl; + } + t->GetEntry(entry); + if(nmaps>0 && nintt>0 && std::fabs(eta)<1. && dcaxy<0.5 && ntpc>30) + { + p.push_back(std::sqrt(px*px+py*py+pz*pz)); + dEdx.push_back(dedx); + } + } + std::cout << "number of good tracks: " << p.size() << std::endl; + //f->Close(); +} + +void GlobaldEdxFitter::addTrack(double trk_dEdx, double trk_p) +{ + dEdx.push_back(trk_dEdx); + p.push_back(trk_p); +} + +double GlobaldEdxFitter::get_fitquality_new(double A) +{ + //double chi2 = 0.; + //double ndf = -1.; + + double pi_chi2 = 0.; + double K_chi2 = 0.; + double p_chi2 = 0.; + double d_chi2 = 0.; + double pi_ndf = -1.; + double K_ndf = -1.; + double p_ndf = -1.; + double d_ndf = -1.; + + for(size_t i=0; i GlobaldEdxFitter::get_betagamma(double A) +{ + std::vector betagamma; + for(size_t i=0; iGetMinimumXYZ(minA,minB,minC); + delete f; + return std::make_tuple(minA,minB,minC); +*/ + ROOT::Math::Minimizer* minimizer = ROOT::Math::Factory::CreateMinimizer("Minuit2"); + minimizer->SetMaxFunctionCalls(1000000); + minimizer->SetMaxIterations(10000); + minimizer->SetTolerance(0.1); + minimizer->SetPrintLevel(1); + ROOT::Math::Functor f(this,&GlobaldEdxFitter::get_fitquality_functor,1); + double step[1] = {.01}; + double variable[1] = {20.}; + minimizer->SetFunction(f); + minimizer->SetVariable(0,"A",variable[0],step[0]); + minimizer->Minimize(); + const double *xs = minimizer->X(); + delete minimizer; + return xs[0]; +} + +double GlobaldEdxFitter::get_minimum() +{ + TF1* f = create_TF1("temp"); + f->SetNpx(1000); + double minX = f->GetMinimumX(); + delete f; + return minX; +} + +std::pair GlobaldEdxFitter::get_minimum_ZS() +{ + TF2* f = create_TF2("temp"); + double minX; + double minY; + f->GetMinimumXY(minX,minY); + delete f; + return std::make_pair(minX,minY); +} + +TGraph* GlobaldEdxFitter::graph_vsbetagamma(double A) +{ + std::vector betagamma = get_betagamma(A); + TGraph* g = new TGraph(dEdx.size(),betagamma.data(),dEdx.data()); + return g; +} + +TGraph* GlobaldEdxFitter::graph_vsp() +{ + TGraph* g = new TGraph(dEdx.size(),p.data(),dEdx.data()); + return g; +} diff --git a/calibrations/tpc/dEdx/GlobaldEdxFitter.h b/calibrations/tpc/dEdx/GlobaldEdxFitter.h new file mode 100644 index 0000000000..9d8dada662 --- /dev/null +++ b/calibrations/tpc/dEdx/GlobaldEdxFitter.h @@ -0,0 +1,69 @@ +#ifndef GLOBALDEDXFITTER_H +#define GLOBALDEDXFITTER_H + +#include "bethe_bloch.h" +#include "TF1.h" +#include "TF2.h" +#include "TF3.h" +#include "TChain.h" +#include "TGraph.h" +#include "Math/Minimizer.h" +#include "Math/Functor.h" +#include "Math/Factory.h" + +class GlobaldEdxFitter +{ + public: + explicit GlobaldEdxFitter(double xmin = 10., double xmax = 50.) + : min_norm(xmin), max_norm(xmax) + {}; + void processResidualData(const std::string& infile, + size_t ntracks = 200000, + size_t skip = 0); + void addTrack(double trk_dEdx, double trk_p); + size_t getNtracks() + { + return dEdx.size(); + } + + double get_fitquality(double norm, double ZS_loss = 0.); + double get_fitquality_new(double A); + TF1* create_TF1(const std::string& name); + TF2* create_TF2(const std::string& name); + TF3* create_TF3_new(const std::string& name); + double get_minimum(); + double get_minimum_new(); + std::pair get_minimum_ZS(); + void set_range(double xmin, double xmax, double ZSmin, double ZSmax) + { + min_norm = xmin; + max_norm = xmax; + min_ZS = ZSmin; + max_ZS = ZSmax; + } + void reset() + { + p.clear(); + dEdx.clear(); + } + std::vector get_betagamma(double A); + TGraph* graph_vsbetagamma(double A); + TGraph* graph_vsp(); + private: + std::vector p; + std::vector dEdx; + + double get_fitquality_functor(const double* x); + + double get_fitquality_wrapper(double* x, double* par); + double get_fitquality_wrapper_ZS(double* x, double* par); + double get_fitquality_wrapper_new(double* x, double* par); + double min_norm = 10.; + double max_norm = 50.; + double min_ZS = 0.; + double max_ZS = 200.; + double min_B = 8.; + double max_B = 12.; +}; + +#endif // GLOBALDEDXFITTER_H diff --git a/calibrations/tpc/dEdx/Makefile.am b/calibrations/tpc/dEdx/Makefile.am new file mode 100644 index 0000000000..d0eeaa9c5a --- /dev/null +++ b/calibrations/tpc/dEdx/Makefile.am @@ -0,0 +1,50 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -isystem$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +pkginclude_HEADERS = \ + dEdxFitter.h \ + GlobaldEdxFitter.h \ + bethe_bloch.h + +lib_LTLIBRARIES = \ + libdedxfitter.la + +libdedxfitter_la_SOURCES = \ + dEdxFitter.cc \ + GlobaldEdxFitter.cc + +libdedxfitter_la_LIBADD = \ + -lphool \ + -ltrack_io \ + -lg4detectors \ + -ltrackbase_historic \ + -ltrackbase_historic_io \ + -lglobalvertex \ + -lSubsysReco + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libdedxfitter.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/calibrations/tpc/dEdx/autogen.sh b/calibrations/tpc/dEdx/autogen.sh new file mode 100755 index 0000000000..dea267bbfd --- /dev/null +++ b/calibrations/tpc/dEdx/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/calibrations/tpc/dEdx/bethe_bloch.h b/calibrations/tpc/dEdx/bethe_bloch.h new file mode 100644 index 0000000000..a359a98294 --- /dev/null +++ b/calibrations/tpc/dEdx/bethe_bloch.h @@ -0,0 +1,208 @@ +#ifndef BETHE_BLOCH_H_ +#define BETHE_BLOCH_H_ + +#include + +namespace dedx_constants +{ + // hadron masses + constexpr double m_pi = 0.1396; // GeV + constexpr double m_K = 0.4937; // GeV + constexpr double m_p = 0.9382; // GeV + constexpr double m_d = 1.876; // GeV + + // electron mass [eV] + constexpr double m_e = 511e3; + + // TPC gas fractions + constexpr double ar_frac = 0.75; + constexpr double cf4_frac = 0.2; + constexpr double isobutane_frac = 0.05; + + // Mean excitation [src: W. Blum, W. Riegler, L. Rolandi, "Particle Detection with Drift Chambers"] + constexpr double ar_I = 188; // eV + constexpr double cf4_I = 115; // eV + constexpr double isobutane_I = 48.3; // eV + + // Mean excitation of mixture approximated using Bragg additivity rule + constexpr double sphenix_I = ar_frac*ar_I + cf4_frac*cf4_I + isobutane_frac*isobutane_I; +} + +// Bethe-Bloch fit function, vs. betagamma +// A = normalization constant, equal to (ADC conversion)*4pi*n*Z^2*e^4/(m_e*c^2*4pi*epsilon_0^2) +// B = A*(ln(2*m_e/I)-1) - (zero-suppression loss factor) +inline double bethe_bloch_new(const double betagamma, const double A, const double B, const double C) +{ + const double beta = betagamma/sqrt(1.+betagamma*betagamma); + + return A/(beta*beta)*TMath::Log(betagamma) + A/(beta*beta)*B - A - C; +} + +inline double bethe_bloch_new_2D(const double betagamma, const double A, const double B) +{ + const double beta = betagamma/sqrt(1.+betagamma*betagamma); + + return A/(beta*beta)*(2.*TMath::Log(2.*dedx_constants::m_e/dedx_constants::sphenix_I * betagamma) - beta*beta) - B; +} + +inline double bethe_bloch_new_1D(const double betagamma, const double A) +{ + const double beta = betagamma/sqrt(1.+betagamma*betagamma); + + return A/(beta*beta)*(2.*TMath::Log(2.*dedx_constants::m_e/dedx_constants::sphenix_I * betagamma) - beta*beta); +} + +// dE/dx for one gas species, up to normalization +inline double bethe_bloch_species(const double betagamma, const double I) +{ + const double m_e = 511e3; // eV + + const double beta = betagamma/sqrt(1.+betagamma*betagamma); + + return 1./(beta*beta)*(TMath::Log(2.*m_e/I*betagamma*betagamma)-beta*beta); +} + +// dE/dx for TPC gas mixture, up to normalization +inline double bethe_bloch_total(const double betagamma) +{ + return dedx_constants::ar_frac * bethe_bloch_species(betagamma,dedx_constants::ar_I) + + dedx_constants::cf4_frac * bethe_bloch_species(betagamma,dedx_constants::cf4_I) + + dedx_constants::isobutane_frac * bethe_bloch_species(betagamma,dedx_constants::isobutane_I); +} + +inline Double_t bethe_bloch_new_wrapper(const Double_t* const x, const Double_t* const par) +{ + Double_t betagamma = x[0]; + Double_t A = par[0]; + Double_t B = par[1]; + Double_t C = par[2]; + + return bethe_bloch_new(betagamma,A,B,C); +} + +inline Double_t bethe_bloch_new_2D_wrapper(const Double_t* const x, const Double_t* const par) +{ + Double_t betagamma = x[0]; + Double_t A = par[0]; + Double_t B = par[1]; + + return bethe_bloch_new_2D(betagamma,A,B); +} + +inline Double_t bethe_bloch_new_1D_wrapper(const Double_t* const x, const Double_t* const par) +{ + Double_t betagamma = x[0]; + Double_t A = par[0]; + + return bethe_bloch_new_1D(betagamma,A); +} + +// wrapper function for TF1 constructor, for fitting +inline Double_t bethe_bloch_wrapper(const Double_t* const ln_bg, const Double_t* const par) +{ + Double_t betagamma = exp(ln_bg[0]); + + Double_t norm = par[0]; + + return norm * bethe_bloch_total(betagamma); +} + +inline Double_t bethe_bloch_vs_p_wrapper(const Double_t* const x, const Double_t* const par) +{ + Double_t p = x[0]; + Double_t norm = par[0]; + Double_t m = par[1]; + + return norm * bethe_bloch_total(fabs(p)/m); +} + +inline Double_t bethe_bloch_vs_logp_wrapper(const Double_t* const x, const Double_t* const par) +{ + Double_t p = pow(10.,x[0]); + Double_t norm = par[0]; + Double_t m = par[1]; + + return norm * bethe_bloch_total(fabs(p)/m); +} + +inline Double_t bethe_bloch_vs_p_wrapper_ZS(const Double_t* const x, const Double_t* const par) +{ + Double_t p = x[0]; + Double_t norm = par[0]; + Double_t m = par[1]; + Double_t ZS_loss = par[2]; + + return norm * bethe_bloch_total(fabs(p)/m) - ZS_loss; +} + +inline Double_t bethe_bloch_vs_p_wrapper_new(const Double_t* const x, const Double_t* const par) +{ + Double_t p = x[0]; + Double_t A = par[0]; + Double_t B = par[1]; + Double_t C = par[2]; + Double_t m = par[3]; + + return bethe_bloch_new(fabs(p)/m,A,B,C); +} + +inline Double_t bethe_bloch_vs_p_wrapper_new_2D(const Double_t* const x, const Double_t* const par) +{ + Double_t p = x[0]; + Double_t A = par[0]; + Double_t B = par[1]; + Double_t m = par[2]; + + return bethe_bloch_new_2D(fabs(p)/m,A,B); +} + +inline Double_t bethe_bloch_vs_p_wrapper_new_1D(const Double_t* const x, const Double_t* const par) +{ + Double_t p = x[0]; + Double_t A = par[0]; + Double_t m = par[1]; + + return bethe_bloch_new_1D(fabs(p)/m,A); +} + +inline Double_t bethe_bloch_vs_logp_wrapper_ZS(const Double_t* const x, const Double_t* const par) +{ + Double_t p = pow(10.,x[0]); + Double_t norm = par[0]; + Double_t m = par[1]; + Double_t ZS_loss = par[2]; + + return norm * bethe_bloch_total(fabs(p)/m) - ZS_loss; +} + +inline Double_t bethe_bloch_vs_logp_wrapper_new(const Double_t* const x, const Double_t* const par) +{ + Double_t p = pow(10.,x[0]); + Double_t A = par[0]; + Double_t B = par[1]; + Double_t C = par[2]; + Double_t m = par[3]; + + return bethe_bloch_new(fabs(p)/m,A,B,C); +} + +inline Double_t bethe_bloch_vs_logp_wrapper_new_1D(const Double_t* const x, const Double_t* const par) +{ + Double_t p = pow(10.,x[0]); + Double_t A = par[0]; + Double_t m = par[1]; + + return bethe_bloch_new_1D(fabs(p)/m,A); +} + +// ratio of dE/dx between two particle species at the same momentum +// (useful for dE/dx peak fits) +inline double dedx_ratio(const double p, const double m1, const double m2) +{ + const double betagamma1 = fabs(p)/m1; + const double betagamma2 = fabs(p)/m2; + + return bethe_bloch_total(betagamma1)/bethe_bloch_total(betagamma2); +} + +#endif // BETHE_BLOCH_H_ diff --git a/calibrations/tpc/dEdx/configure.ac b/calibrations/tpc/dEdx/configure.ac new file mode 100644 index 0000000000..efef9411e9 --- /dev/null +++ b/calibrations/tpc/dEdx/configure.ac @@ -0,0 +1,16 @@ +AC_INIT( dEdxFitter,[1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE +AC_PROG_CXX(CC g++) + +LT_INIT([disable-static]) + +dnl enable more warnings and make them fatal +dnl this package needs openmp which requires -fopenmp for clang +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Wshadow -Wextra -Werror" +fi + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/calibrations/tpc/dEdx/dEdxFitter.cc b/calibrations/tpc/dEdx/dEdxFitter.cc new file mode 100644 index 0000000000..4277d3f059 --- /dev/null +++ b/calibrations/tpc/dEdx/dEdxFitter.cc @@ -0,0 +1,249 @@ +#include "dEdxFitter.h" + +#include +#include +#include +#include +#include +#include + +#include + +//____________________________________ +dEdxFitter::dEdxFitter(const std::string &name): + SubsysReco(name), + fitter(std::make_unique()) +{ + //initialize +} + +//___________________________________ +int dEdxFitter::InitRun(PHCompositeNode * /*topNode*/) +{ + std::cout << PHWHERE << " Opening file " << _outfile << std::endl; + outf = new TFile( _outfile.c_str(), "RECREATE"); + + return 0; +} + +//__________________________________ +//Call user instructions for every event +int dEdxFitter::process_event(PHCompositeNode *topNode) +{ + _event++; + if(_event%1000==0) + { + std::cout << PHWHERE << "Events processed: " << _event << std::endl; + } + + GetNodes(topNode); + + if(Verbosity()>1) + { + std::cout << "--------------------------------" << std::endl; + std::cout << "event " << _event << std::endl; + } + + process_tracks(); + + return 0; +} + +//_____________________________________ +void dEdxFitter::process_tracks() +{ + + for(const auto &[key, track] : *_trackmap) + { + if(!track) + { + continue; + } + + double trackID = track->get_id(); + if(Verbosity()>1) + { + std::cout << "track ID " << trackID << std::endl; + } + if(std::isnan(track->get_x()) || + std::isnan(track->get_y()) || + std::isnan(track->get_z()) || + std::isnan(track->get_px()) || + std::isnan(track->get_py()) || + std::isnan(track->get_pz())) + { + std::cout << "malformed track:" << std::endl; + track->identify(); + std::cout << "skipping..." << std::endl; + continue; + } + + // ignore TPC-only tracks + if(!track->get_silicon_seed()) + { + if(Verbosity()>1) + { + std::cout << "TPC-only track, skipping..." << std::endl; + } + continue; + } + + std::tuple nclus = get_nclus(track); + int nmaps = std::get<0>(nclus); + int nintt = std::get<1>(nclus); + int ntpc = std::get<2>(nclus); + + if(nmaps>=nmaps_cut && nintt>=nintt_cut && ntpc>=ntpc_cut && std::fabs(track->get_eta())addTrack(get_dedx(track),track->get_p()); + } + + if(fitter->getNtracks() > ntracks_to_fit) + { + minima.push_back(fitter->get_minimum()); + fitter->reset(); + } + } +} + +std::tuple dEdxFitter::get_nclus(SvtxTrack* track) +{ + int nmaps = 0; + int nintt = 0; + int ntpc = 0; + + if(track->get_silicon_seed()) + { + for(auto it = track->get_silicon_seed()->begin_cluster_keys(); it != track->get_silicon_seed()->end_cluster_keys(); ++it) + { + TrkrDefs::cluskey ckey = *it; + auto trkrid = TrkrDefs::getTrkrId(ckey); + if(trkrid == TrkrDefs::mvtxId) + { + nmaps++; + } + else if(trkrid == TrkrDefs::inttId) + { + nintt++; + } + } + } + if(track->get_tpc_seed()) + { + for(auto it = track->get_tpc_seed()->begin_cluster_keys(); it != track->get_tpc_seed()->end_cluster_keys(); ++it) + { + ntpc++; + } + } + + return std::make_tuple(nmaps,nintt,ntpc); +} + +double dEdxFitter::get_dedx(SvtxTrack* track) +{ + float layerThicknesses[4] = {0.0, 0.0, 0.0, 0.0}; + // These are randomly chosen layer thicknesses for the TPC, to get the + // correct region thicknesses in an easy to pass way to the helper fxn + layerThicknesses[0] = _tpcgeom->GetLayerCellGeom(7)->get_thickness(); + layerThicknesses[1] = _tpcgeom->GetLayerCellGeom(8)->get_thickness(); + layerThicknesses[2] = _tpcgeom->GetLayerCellGeom(27)->get_thickness(); + layerThicknesses[3] = _tpcgeom->GetLayerCellGeom(50)->get_thickness(); + + return TrackAnalysisUtils::calc_dedx(track->get_tpc_seed(), _clustermap, _geometry, layerThicknesses); +} + +double dEdxFitter::get_dcaxy(SvtxTrack* track) +{ + auto vertexit = _vertexmap->find(track->get_vertex_id()); + if(vertexit != _vertexmap->end()) + { + SvtxVertex* vtx = vertexit->second; + Acts::Vector3 vertex(vtx->get_x(),vtx->get_y(),vtx->get_z()); + auto dcapair = TrackAnalysisUtils::get_dca(track,vertex); + return dcapair.first.first; + } + // if no vertex found + return std::numeric_limits::quiet_NaN(); +} + +//___________________________________ +void dEdxFitter::GetNodes(PHCompositeNode *topNode) +{ + + _trackmap = findNode::getClass(topNode,"SvtxTrackMap"); + if(!_trackmap && _event<2) + { + std::cout << PHWHERE << " cannot find SvtxTrackMap" << std::endl; + } + + _clustermap = findNode::getClass(topNode,"TRKR_CLUSTER"); + if(!_clustermap && _event<2) + { + std::cout << PHWHERE << " cannot find TrkrClusterContainer TRKR_CLUSTER" << std::endl; + } + + _geometry = findNode::getClass(topNode,"ActsGeometry"); + if(!_geometry && _event<2) + { + std::cout << PHWHERE << " cannot find ActsGeometry" << std::endl; + } + + _tpcgeom = findNode::getClass(topNode,"TPCGEOMCONTAINER"); + if(!_tpcgeom && _event<2) + { + std::cout << PHWHERE << " cannot find PHG4TpcGeomContainer TPCGEOMCONTAINER" << std::endl; + } + + _vertexmap = findNode::getClass(topNode,"SvtxVertexMap"); + if(!_vertexmap && _event<2) + { + std::cout << PHWHERE << " cannot find SvtxVertexMap" << std::endl; + } +} + +//______________________________________ +int dEdxFitter::End(PHCompositeNode * /*topNode*/) +{ + if(minima.empty()) + { + minima.push_back(fitter->get_minimum()); + } + + double avg_minimum = 0.; + for(double m : minima) + { + avg_minimum += m; + } + avg_minimum /= (double)minima.size(); + + outf->cd(); + + TF1* pi_band = new TF1("pi_band","bethe_bloch_new_1D(fabs(x)/[1],[0])"); + pi_band->SetParameter(0,avg_minimum); + pi_band->SetParameter(1,dedx_constants::m_pi); + pi_band->Write(); + + TF1* K_band = new TF1("K_band","bethe_bloch_new_1D(fabs(x)/[1],[0])"); + K_band->SetParameter(0,avg_minimum); + K_band->SetParameter(1,dedx_constants::m_K); + K_band->Write(); + + TF1* p_band = new TF1("p_band","bethe_bloch_new_1D(fabs(x)/[1],[0])"); + p_band->SetParameter(0,avg_minimum); + p_band->SetParameter(1,dedx_constants::m_p); + p_band->Write(); + + TF1* d_band = new TF1("d_band","bethe_bloch_new_1D(fabs(x)/[1],[0])"); + d_band->SetParameter(0,avg_minimum); + d_band->SetParameter(1,dedx_constants::m_d); + d_band->Write(); + + if(Verbosity()>0) + { + std::cout << "dEdxFitter extracted minimum: " << avg_minimum << std::endl; + } + + outf->Close(); + + return 0; +} diff --git a/calibrations/tpc/dEdx/dEdxFitter.h b/calibrations/tpc/dEdx/dEdxFitter.h new file mode 100644 index 0000000000..dcec9d96f0 --- /dev/null +++ b/calibrations/tpc/dEdx/dEdxFitter.h @@ -0,0 +1,98 @@ +#ifndef DEDXFITTER_H_ +#define DEDXFITTER_H_ + +#include "GlobaldEdxFitter.h" + +#include +#include +#include + +#include + +#include + +#include + +#include + +//Forward declerations +class PHCompositeNode; +class TFile; + +// dEdx fit analysis module +class dEdxFitter: public SubsysReco +{ + public: + //Default constructor + explicit dEdxFitter(const std::string &name="dEdxFitter"); + + //Initialization, called for initialization + int InitRun(PHCompositeNode * /*topNode*/) override; + + //Process Event, called for each event + int process_event(PHCompositeNode *topNode) override; + + //End, write and close files + int End(PHCompositeNode * /*topNode*/) override; + + //Change output filename + void set_filename(const char* file) + { + if(file) + { + _outfile = file; + } + } + + void set_nmaps_cut(int nmaps) + { nmaps_cut = nmaps; } + + void set_nintt_cut(int nintt) + { nintt_cut = nintt; } + + void set_ntpc_cut(int ntpc) + { ntpc_cut = ntpc; } + + void set_eta_cut(float eta) + { eta_cut = eta; } + + void set_dcaxy_cut(float dcaxy) + { dcaxy_cut = dcaxy; } + + void set_ntracks_to_fit(size_t ntrk) + { ntracks_to_fit = ntrk; } + + private: + //Get all the nodes + void GetNodes(PHCompositeNode * /*topNode*/); + + void process_tracks(); + + //output filename + std::string _outfile {"dedx_outfile.root"}; + TFile* outf {nullptr}; + size_t _event {0}; + + SvtxTrackMap* _trackmap {nullptr}; + TrkrClusterContainer* _clustermap {nullptr}; + ActsGeometry* _geometry {nullptr}; + PHG4TpcGeomContainer* _tpcgeom {nullptr}; + SvtxVertexMap* _vertexmap {nullptr}; + + int nmaps_cut {1}; + int nintt_cut {1}; + int ntpc_cut {30}; + float eta_cut {1.}; + float dcaxy_cut {0.5}; + + size_t ntracks_to_fit {40000}; + std::vector minima; + std::unique_ptr fitter; + + std::tuple get_nclus(SvtxTrack* track); + double get_dedx(SvtxTrack* track); + double get_dcaxy(SvtxTrack* track); + +}; + +#endif //* DEDXFITTER_H_ *// diff --git a/calibrations/tpc/dEdx/test_sample_size.C b/calibrations/tpc/dEdx/test_sample_size.C new file mode 100644 index 0000000000..8464aba486 --- /dev/null +++ b/calibrations/tpc/dEdx/test_sample_size.C @@ -0,0 +1,200 @@ +#include "GlobaldEdxFitter.h" + +#include +#include +#include +#include +#include + +#include +#include + +void test_sample_size(const std::string& infile="/sphenix/tg/tg01/hf/mjpeters/run53877_tracks/track_output_53877_*.root") +{ + std::vector samplesizes = {1000,2000,5000,10000,20000};//,50000,100000,200000,500000,1000000};//,2000000,5000000}; + + const int n_samples = 20; + const float fluctuation_ymin = 5.; + const float fluctuation_ymax = 26.; + const int distribution_nbins = 30; + const float distribution_xmin = 5.; + const float distribution_xmax = 26.; + + std::vector> fitvalues_all; + std::vector fitvalues_avg; + std::vector fitvalues_stdev; + + std::vector fluctuations; + std::vector distributions; + + std::vector dist_h; + + std::vector> gfs; + + for(int i=0; i()); + + const std::string& fluctuation_canvasname = "fluctuations_"+std::to_string((int)floor(samplesizes[i])); + const std::string& distribution_canvasname = "distributions_"+std::to_string((int)floor(samplesizes[i])); + fluctuations.push_back(new TCanvas(fluctuation_canvasname.c_str(),fluctuation_canvasname.c_str(),600,600)); + distributions.push_back(new TCanvas(distribution_canvasname.c_str(),distribution_canvasname.c_str(),600,600)); + + for(int j=0;jprocessResidualData(infile,floor(samplesizes[i]),j*samplesizes[i]); + double min = gfs[i]->get_minimum(); + std::cout << "minimum: " << min << std::endl; + fitvalues_all[i].push_back(min); + if(jreset(); + } +/* + tf1s[i]->cd(); + TF1* tf1copy = gfs[i]->create_TF1(("ntrk_"+std::to_string(samplesizes[i])).c_str()); + tf1copy->SetLineColor(base_color); + tf1copy->GetYaxis()->SetRangeUser(1.,tf1copy->GetMaximum()); + if(i==0) tf1copy->Draw(); + else tf1copy->Draw("SAME"); +*/ + } + } + + std::vector sample_index(n_samples); + std::iota(sample_index.begin(),sample_index.end(),0.); + + for(int i=0; icd(); + TGraph* g = new TGraph(n_samples,sample_index.data(),fitvalues_all[i].data()); + g->GetYaxis()->SetRangeUser(fluctuation_ymin,fluctuation_ymax); + g->SetMarkerStyle(kFullCircle); + g->SetMarkerSize(1.); + g->Draw("APL"); + + distributions[i]->cd(); + std::string hname = "h_"+std::to_string(floor(samplesizes[i])); + std::string htitle = "Distribution of fit results for sample size "+std::to_string(floor(samplesizes[i])); +/* + auto bounds = std::minmax_element(fitvalues_all[i].begin(),fitvalues_all[i].end()); + float lowerbound = floor(*bounds.first); + float upperbound = ceil(*bounds.second); +*/ + TH1F* h = new TH1F(hname.c_str(),htitle.c_str(),distribution_nbins,distribution_xmin,distribution_xmax); + for(int j=0; jFill(fitvalues_all[i][j]); + } + h->Draw(); + } + + for(int i=0; i errx(n_samples,0.); + + TCanvas* cg = new TCanvas("cg","sizes",600,600); + TGraph* g = new TGraphErrors(samplesizes.size(),samplesizes.data(),fitvalues_avg.data(),errx.data(),fitvalues_stdev.data()); + g->SetMarkerStyle(kFullCircle); + g->SetMarkerSize(1); + g->Draw("APL"); + cg->SetLogx(); + + TCanvas* cbg = new TCanvas("vsbetagamma","vsbetagamma",600,600); + TGraph* gbg = gfs.back()->graph_vsbetagamma(fitvalues_avg.back()); + gbg->SetMarkerStyle(kFullCircle); + gbg->SetMarkerSize(0.2); + gbg->Draw("AP"); + cbg->SetLogx(); + + double best_A = fitvalues_avg.back(); + + TF1* bethe = new TF1("bethebloch_vslnbg",bethe_bloch_new_1D_wrapper,0.,100.,2,1); + bethe->SetParameter(0,best_A); + bethe->SetNpx(1000); + bethe->Draw("SAME"); + + TF1* bethe_directfit = new TF1("bethebloch_directfit",bethe_bloch_new_1D_wrapper,0.,10.,1,1); + bethe_directfit->SetParameter(0,best_A); + bethe_directfit->SetLineColor(kBlue); + gbg->Fit(bethe_directfit); + double newbest_A = bethe_directfit->GetParameter(0); + std::cout << "new best: " << newbest_A << std::endl; + + TCanvas* cbands = new TCanvas("bands","bands",600,600); + TGraph* gp = gfs.back()->graph_vsp(); + gp->SetMarkerStyle(kFullCircle); + gp->SetMarkerSize(0.1); + gp->Draw("AP"); + cbands->SetLogx(); + + for(double mass : {dedx_constants::m_pi, dedx_constants::m_K, dedx_constants::m_p, dedx_constants::m_d}) + { + TF1* band = new TF1(("band_"+std::to_string(mass)).c_str(),bethe_bloch_vs_p_wrapper_new_1D,0.,10.,2,1); + band->SetParameter(0,best_A); + band->SetParameter(1,mass); + band->SetNpx(1000); + band->Draw("SAME"); + + TF1* directband = new TF1(("directband_"+std::to_string(mass)).c_str(),bethe_bloch_vs_p_wrapper_new_1D,0.,10.,2,1); + directband->SetLineColor(kBlue); + directband->SetParameters(best_A,mass); + directband->SetNpx(1000); + directband->Draw("SAME"); + } + + TCanvas* cb = new TCanvas("fullbands","fullbands",600,600); + TFile* f_h = TFile::Open("/sphenix/tg/tg01/hf/mjpeters/run53877_tracks/dedx/merged_dedx.root"); + TH2F* dedx_h = (TH2F*)f_h->Get("dedx_log_30"); + dedx_h->Draw("COLZ"); + cb->SetLogz(); + + for(double mass : {dedx_constants::m_pi, dedx_constants::m_K, dedx_constants::m_p, dedx_constants::m_d}) + { + TF1* band = new TF1(("band_"+std::to_string(mass)).c_str(),bethe_bloch_vs_logp_wrapper_new_1D,-1.,5.,2,1); + band->SetParameter(0,best_A); + band->SetParameter(1,mass); + band->Draw("SAME"); + + TF1* directband = new TF1(("directband_"+std::to_string(mass)).c_str(),bethe_bloch_vs_logp_wrapper_new_1D,-1.,5.,2,1); + directband->SetLineColor(kBlue); + directband->SetParameters(newbest_A,mass); + directband->SetNpx(1000); + directband->Draw("SAME"); + } + + TFile* fout = new TFile("dedxfitvals.root","RECREATE"); + for(auto& c : fluctuations) + { + c->Write(); + } + for(auto& c : distributions) + { + c->Write(); + } + cg->Write(); + cbg->Write(); + cbands->Write(); + cb->Write(); + fout->Close(); +} diff --git a/calibrations/xingshift/Makefile.am b/calibrations/xingshift/Makefile.am index 81ea4dbca4..08c0220b6b 100644 --- a/calibrations/xingshift/Makefile.am +++ b/calibrations/xingshift/Makefile.am @@ -23,9 +23,9 @@ libXingShiftCal_la_SOURCES = \ libXingShiftCal_la_LIBADD = \ -lcdbobjects \ -lfun4all \ + -lfun4cal \ -lphool \ - -lSubsysReco \ - -loncal + -lSubsysReco BUILT_SOURCES = testexternals.cc diff --git a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc index 02ca208f25..506799c874 100644 --- a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc +++ b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.cc @@ -31,7 +31,6 @@ HepMCJetTrigger::HepMCJetTrigger(float trigger_thresh, int n_incom, bool up_lim, int HepMCJetTrigger::process_event(PHCompositeNode* topNode) { // std::cout << "HepMCJetTrigger::process_event(PHCompositeNode *topNode) Processing Event" << std::endl; - n_evts++; if (this->set_event_limit == true) { // needed to keep all HepMC output at the same number of events if (n_good >= this->goal_event_number) @@ -39,6 +38,7 @@ int HepMCJetTrigger::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } } + n_evts++; PHHepMCGenEventMap* phg = findNode::getClass(topNode, "PHHepMCGenEventMap"); if (!phg) { @@ -96,6 +96,11 @@ std::vector HepMCJetTrigger::findAllJets(HepMC::GenEvent* e1 if (!(*iter)->end_vertex() && (*iter)->status() == 1) { auto p = (*iter)->momentum(); + auto pd = std::abs((*iter)->pdg_id()); + if (pd >= 12 && pd <= 18) + { + continue; // keep jet in the expected behavioro + } fastjet::PseudoJet pj(p.px(), p.py(), p.pz(), p.e()); pj.set_user_index((*iter)->barcode()); input.push_back(pj); @@ -122,6 +127,10 @@ int HepMCJetTrigger::jetsAboveThreshold(const std::vector& j for (const auto& j : jets) { float const pt = j.pt(); + if (std::abs(j.eta()) > 1.1) + { + continue; + } if (pt > this->threshold) { n_good_jets++; diff --git a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h index 67a1a4fbe5..0917e42cdc 100644 --- a/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h +++ b/generators/Herwig/HepMCTrigger/HepMCJetTrigger.h @@ -47,6 +47,8 @@ class HepMCJetTrigger : public SubsysReco /// Called at the end of all processing. /// Reset + int getNevts(){return this->n_evts;} + int getNgood(){return this->n_good;} private: bool isGoodEvent(HepMC::GenEvent* e1); @@ -54,9 +56,9 @@ class HepMCJetTrigger : public SubsysReco int jetsAboveThreshold(const std::vector& jets) const; float threshold{0.}; int goal_event_number{1000}; + bool set_event_limit{false}; int n_evts{0}; int n_good{0}; - bool set_event_limit{false}; }; #endif // HEPMCJETTRIGGER_H diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc new file mode 100644 index 0000000000..eccb80ce6c --- /dev/null +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.cc @@ -0,0 +1,439 @@ +#include "HepMCParticleTrigger.h" + +#include +#include +#include + +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +//____________________________________________________________________________.. +// NOLINTNEXTLINE(bugprone-easily-swappable-parameters) +HepMCParticleTrigger::HepMCParticleTrigger(float trigger_thresh, int n_incom, bool up_lim, const std::string& name) + : SubsysReco(name) + , threshold(trigger_thresh) + , goal_event_number(n_incom) + , set_event_limit(up_lim) + , _theEtaHigh(1.1) + , _theEtaLow(-1.1) + , _thePtHigh(999.9) + , _thePtLow(0) + , _thePHigh(999.9) + , _thePLow(-999.9) + , _thePzHigh(999.9) + , _thePzLow(-999.9) + , + + _doEtaHighCut(true) + , _doEtaLowCut(true) + , _doBothEtaCut(true) + , + + _doAbsEtaHighCut(false) + , _doAbsEtaLowCut(false) + , _doBothAbsEtaCut(false) + , + + _doPtHighCut(false) + , _doPtLowCut(false) + , _doBothPtCut(false) + , + _doPHighCut(false) + , _doPLowCut(false) + , _doBothPCut(false) + , + + _doPzHighCut(false) + , _doPzLowCut(false) + , _doBothPzCut(false) +{ + if (threshold != 0) + { + _doPtLowCut = true; + _thePtLow = threshold; + } +} + +//____________________________________________________________________________.. +int HepMCParticleTrigger::process_event(PHCompositeNode* topNode) +{ + // std::cout << "HepMCParticleTrigger::process_event(PHCompositeNode *topNode) Processing Event" << std::endl; + if (this->set_event_limit == true) + { // needed to keep all HepMC output at the same number of events + if (n_good >= this->goal_event_number) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + } + n_evts++; + bool good_event{false}; + PHHepMCGenEventMap* phg = findNode::getClass(topNode, "PHHepMCGenEventMap"); + if (!phg) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + for (PHHepMCGenEventMap::ConstIter eventIter = phg->begin(); eventIter != phg->end(); ++eventIter) + { + PHHepMCGenEvent* hepev = eventIter->second; + if (!hepev) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + HepMC::GenEvent* ev = hepev->getEvent(); + if (!ev) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + good_event = isGoodEvent(ev); + if (!good_event) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + } + if (good_event) + { + n_good++; + } + return Fun4AllReturnCodes::EVENT_OK; +} +void HepMCParticleTrigger::AddParticle(int particlePid) +{ + _theParticles.push_back(particlePid); + return; +} +void HepMCParticleTrigger::AddParticles(const std::vector& particles) +{ + for (auto p : particles) + { + _theParticles.push_back(p); + } + return; +} + +void HepMCParticleTrigger::SetPtHigh(double pt) +{ + _thePtHigh = pt; + _doPtHighCut = true; + if (_doPtLowCut) + { + _doBothPtCut = true; + } + return; +} +void HepMCParticleTrigger::SetPtLow(double pt) +{ + _thePtLow = pt; + _doPtLowCut = true; + if (_doPtHighCut) + { + _doBothPtCut = true; + } + return; +} +void HepMCParticleTrigger::SetPtHighLow(double ptHigh, double ptLow) +{ + _thePtHigh = ptHigh; + _doPtHighCut = true; + _thePtLow = ptLow; + _doPtLowCut = true; + _doBothPtCut = true; + return; +} +void HepMCParticleTrigger::SetPHigh(double pt) +{ + _thePHigh = pt; + _doPHighCut = true; + if (_doPLowCut) + { + _doBothPCut = true; + } + return; +} +void HepMCParticleTrigger::SetPLow(double pt) +{ + _thePLow = pt; + _doPLowCut = true; + if (_doPHighCut) + { + _doBothPCut = true; + } + return; +} +void HepMCParticleTrigger::SetPHighLow(double ptHigh, double ptLow) +{ + _thePHigh = ptHigh; + _doPHighCut = true; + _thePLow = ptLow; + _doPLowCut = true; + _doBothPCut = true; + return; +} +void HepMCParticleTrigger::SetPzHigh(double pt) +{ + _thePzHigh = pt; + _doPzHighCut = true; + if (_doPzLowCut) + { + _doBothPzCut = true; + } + return; +} +void HepMCParticleTrigger::SetPzLow(double pt) +{ + _thePzLow = pt; + _doPzLowCut = true; + if (_doPzHighCut) + { + _doBothPzCut = true; + } + return; +} +void HepMCParticleTrigger::SetPzHighLow(double ptHigh, double ptLow) +{ + _thePzHigh = ptHigh; + _doPzHighCut = true; + _thePzLow = ptLow; + _doPzLowCut = true; + _doBothPzCut = true; + return; +} +void HepMCParticleTrigger::SetEtaHigh(double pt) +{ + _theEtaHigh = pt; + _doEtaHighCut = true; + if (_doEtaLowCut) + { + _doBothEtaCut = true; + } + return; +} +void HepMCParticleTrigger::SetEtaLow(double pt) +{ + _theEtaLow = pt; + _doEtaLowCut = true; + if (_doEtaHighCut) + { + _doBothEtaCut = true; + } + return; +} +void HepMCParticleTrigger::SetEtaHighLow(double ptHigh, double ptLow) +{ + _theEtaHigh = ptHigh; + _doEtaHighCut = true; + _theEtaLow = ptLow; + _doEtaLowCut = true; + _doBothEtaCut = true; + return; +} +void HepMCParticleTrigger::SetAbsEtaHigh(double pt) +{ + _theEtaHigh = pt; + _doAbsEtaHighCut = true; + if (_doAbsEtaLowCut) + { + _doBothAbsEtaCut = true; + } + return; +} +void HepMCParticleTrigger::SetAbsEtaLow(double pt) +{ + _theEtaLow = pt; + _doAbsEtaLowCut = true; + if (_doAbsEtaHighCut) + { + _doBothAbsEtaCut = true; + } + return; +} +void HepMCParticleTrigger::SetAbsEtaHighLow(double ptHigh, double ptLow) +{ + _theEtaHigh = ptHigh; + _doAbsEtaHighCut = true; + _theEtaLow = ptLow; + _doAbsEtaLowCut = true; + _doBothAbsEtaCut = true; + return; +} +bool HepMCParticleTrigger::isGoodEvent(HepMC::GenEvent* e1) +{ + std::vector n_trigger_particles = getParticles(e1); + for (auto ntp : n_trigger_particles) + { + if (ntp <= 0) + { + return false; // make sure all particles have at least 1 + } + } + return true; +} + +std::vector HepMCParticleTrigger::getParticles(HepMC::GenEvent* e1) +{ + std::vector n_trigger{}; + std::unordered_set particle_pids; + particle_pids.reserve(_theParticles.size()); + for (auto it : _theParticles) + { + particle_pids.insert(std::abs(it)); + } + std::unordered_map particle_types; + particle_types.reserve(particle_pids.size()); + + for (HepMC::GenEvent::particle_const_iterator iter = e1->particles_begin(); iter != e1->particles_end(); ++iter) + { + const HepMC::GenParticle *g = *iter; + if (m_doStableParticleOnly && (g->end_vertex() || g->status() != 1)) + { + continue; + } + + int pid = std::abs(g->pdg_id()); + auto ipidx = particle_pids.find(pid); + if(ipidx == particle_pids.end()) + { + continue; + } + + if (m_rejectFromHadronDecay) + { + if(IsFromHadronDecay(g)) + { + continue; + } + } + + auto p = g->momentum(); + float px = p.px(); + float py = p.py(); + float pz = p.pz(); + float p_M = std::sqrt(std::pow(px, 2) + std::pow(py, 2) + std::pow(pz, 2)); + float pt = std::sqrt(std::pow(px, 2) + std::pow(py, 2)); + double eta = p.eta(); + + if ((_doEtaHighCut || _doBothEtaCut) && eta > _theEtaHigh) + { + continue; + } + if ((_doEtaLowCut || _doBothEtaCut) && eta < _theEtaLow) + { + continue; + } + if ((_doAbsEtaHighCut || _doBothAbsEtaCut) && std::abs(eta) > _theEtaHigh) + { + continue; + } + if ((_doAbsEtaLowCut || _doBothAbsEtaCut) && std::abs(eta) < _theEtaLow) + { + continue; + } + if ((_doPtHighCut || _doBothPtCut) && pt > _thePtHigh) + { + continue; + } + if ((_doPtLowCut || _doBothPtCut) && pt < _thePtLow) + { + continue; + } + if ((_doPHighCut || _doBothPCut) && p_M > _thePHigh) + { + continue; + } + if ((_doPLowCut || _doBothPCut) && p_M < _thePLow) + { + continue; + } + if ((_doPzHighCut || _doBothPzCut) && pz > _thePzHigh) + { + continue; + } + if ((_doPzLowCut || _doBothPzCut) && pz < _thePzLow) + { + continue; + } + + particle_types[pid]++; + + if(particle_types.size() == particle_pids.size()) + { + break; + } + } + + n_trigger.reserve(_theParticles.size()); + + for (auto it : _theParticles) + { + auto ptid = particle_types.find(std::abs(it)); + n_trigger.push_back((ptid != particle_types.end()) ? ptid->second : 0); + } + return n_trigger; +} + +int HepMCParticleTrigger::particleAboveThreshold(const std::map& n_particles, int trigger_particle) +{ + // search through for the number of identified trigger particles passing cuts + auto it = n_particles.find(std::abs(trigger_particle)); + if (it != n_particles.end()) + { + return it->second; + } + return 0; +} + +bool HepMCParticleTrigger::IsFromHadronDecay(const HepMC::GenParticle* gp) +{ + if (!gp) + { + return false; + } + + const HepMC::GenVertex* vtx = gp->production_vertex(); + if (!vtx) + { + return false; + } + + for (auto it = vtx->particles_in_const_begin(); it != vtx->particles_in_const_end(); ++it) + { + const HepMC::GenParticle* mom = *it; + if (!mom) + { + continue; + } + + if (IsHadronPDG(mom->pdg_id())) + { + return true; + } + } + return false; +} + + +bool HepMCParticleTrigger::IsHadronPDG(int _pdg) +{ + if(IsIonPDG(_pdg)) + { + return false; + } + + if(std::abs(_pdg) < 100 ) + { + return false; + } + + return true; +} diff --git a/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h new file mode 100644 index 0000000000..22bcf241d4 --- /dev/null +++ b/generators/Herwig/HepMCTrigger/HepMCParticleTrigger.h @@ -0,0 +1,124 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef HEPMCPARTICLETRIGGER_H +#define HEPMCPARTICLETRIGGER_H + +#include + +#include + +#include +#include +#include +#include + +class PHCompositeNode; +namespace HepMC +{ + class GenEvent; + class GenParticle; +} + +class HepMCParticleTrigger : public SubsysReco +{ + public: + HepMCParticleTrigger(float trigger_thresh = 10., int n_incom = 1000, bool up_lim = false, const std::string& name = "HepMCParticleTrigger"); + + ~HepMCParticleTrigger() override = default; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode* topNode) override; + + /// Clean up internals after each event. + + /// Called at the end of each run. + + /// Called at the end of all processing. + + /// Reset + void AddParticles(const std::vector&); //exclusively take input in the form of a pdg_ids (22 for photon, primary use case) + void AddParticle(int); + + /* void AddParents(const std::string &parents); + void AddParents(int parent); + void AddParents(std::vector parents); + void AddParentspID(std::vector parents); + */ + void SetPtHigh(double); + void SetPtLow(double); + void SetPtHighLow(double, double); + + void SetPHigh(double); + void SetPLow(double); + void SetPHighLow(double, double); + + void SetEtaHigh(double); + void SetEtaLow(double); + void SetEtaHighLow(double, double); + + void SetAbsEtaHigh(double); + void SetAbsEtaLow(double); + void SetAbsEtaHighLow(double, double); + + void SetPzHigh(double); + void SetPzLow(double); + void SetPzHighLow(double, double); + + void SetRejectFromHadronDecay(bool b) {m_rejectFromHadronDecay = b;} + void SetStableParticleOnly(bool b) { m_doStableParticleOnly = b; } + + int getNevts(){return this->n_evts;} + int getNgood(){return this->n_good;} + + bool IsFromHadronDecay(const HepMC::GenParticle* gp); + bool IsIonPDG(int _pdg) { return (std::abs(_pdg) >= 1000000000); } + + private: + bool isGoodEvent(HepMC::GenEvent* e1); + std::vector getParticles(HepMC::GenEvent* e1); + int particleAboveThreshold(const std::map& n_particles, int particle); + // std::vector _theParentsi {}; + std::vector _theParticles{}; + bool m_doStableParticleOnly{true}; + bool m_rejectFromHadronDecay{true}; + float threshold{0.}; + int goal_event_number{1000}; + bool set_event_limit{false}; + int n_evts{0}; + int n_good{0}; + + float _theEtaHigh{2.0}; + float _theEtaLow{-2.0}; + float _thePtHigh{999.9}; + float _thePtLow{-999.9}; + float _thePHigh{999.9}; + float _thePLow{-999.9}; + float _thePzHigh{999.9}; + float _thePzLow{-999.9}; + + bool _doEtaHighCut{true}; + bool _doEtaLowCut{true}; + bool _doBothEtaCut{true}; + + bool _doAbsEtaHighCut{false}; + bool _doAbsEtaLowCut{false}; + bool _doBothAbsEtaCut{false}; + + bool _doPtHighCut{false}; + bool _doPtLowCut{false}; + bool _doBothPtCut{false}; + + bool _doPHighCut{false}; + bool _doPLowCut{false}; + bool _doBothPCut{false}; + + bool _doPzHighCut{false}; + bool _doPzLowCut{false}; + bool _doBothPzCut{false}; + + bool IsHadronPDG(int _pdg); +}; + +#endif // HEPMCPARTICLETRIGGER_H diff --git a/generators/Herwig/HepMCTrigger/Makefile.am b/generators/Herwig/HepMCTrigger/Makefile.am index 17ef6c4221..9807a9a78e 100644 --- a/generators/Herwig/HepMCTrigger/Makefile.am +++ b/generators/Herwig/HepMCTrigger/Makefile.am @@ -12,20 +12,31 @@ AM_LDFLAGS = \ `fastjet-config --libs` pkginclude_HEADERS = \ - HepMCJetTrigger.h + HepMCJetTrigger.h \ + HepMCParticleTrigger.h lib_LTLIBRARIES = \ - libHepMCJetTrigger.la + libHepMCJetTrigger.la \ + libHepMCParticleTrigger.la libHepMCJetTrigger_la_SOURCES = \ HepMCJetTrigger.cc +libHepMCParticleTrigger_la_SOURCES = \ + HepMCParticleTrigger.cc + libHepMCJetTrigger_la_LIBADD = \ -lphool \ -lSubsysReco \ -lfun4all \ -lphhepmc +libHepMCParticleTrigger_la_LIBADD = \ + -lphool \ + -lSubsysReco \ + -lfun4all \ + -lphhepmc + BUILT_SOURCES = testexternals.cc noinst_PROGRAMS = \ diff --git a/generators/PHPythia8/PHPythia8.cc b/generators/PHPythia8/PHPythia8.cc index 9aa14d4684..ab059542b4 100644 --- a/generators/PHPythia8/PHPythia8.cc +++ b/generators/PHPythia8/PHPythia8.cc @@ -33,6 +33,20 @@ #include #include // for operator<<, endl +/** + * @brief Construct a PHPythia8 generator instance and configure HepMC conversion. + * + * Initializes the Pythia8 engine using the path from the environment variable + * `PYTHIA8`, configures a HepMC::Pythia8ToHepMC converter to store process, + * PDF, and cross-section information, and sets the default embedding ID to 1. + * The constructor preserves and restores std::cout formatting around Pythia8 + * construction to avoid altering global stream state. + * + * If `PYTHIA8` is not set, an error message is printed and the Pythia8 instance + * remains uninitialized. + * + * @param name Name forwarded to the SubsysReco base class (module instance name). + */ PHPythia8::PHPythia8(const std::string &name) : SubsysReco(name) { @@ -45,8 +59,12 @@ PHPythia8::PHPythia8(const std::string &name) std::string thePath(charPath); thePath += "/xmldoc/"; + // the pythia8 ctor messes with the formatting, so we save the cout state here + // and restore it later + std::ios old_state(nullptr); + old_state.copyfmt(std::cout); m_Pythia8.reset(new Pythia8::Pythia(thePath)); - + std::cout.copyfmt(old_state); m_Pythia8ToHepMC.reset(new HepMC::Pythia8ToHepMC()); m_Pythia8ToHepMC->set_store_proc(true); m_Pythia8ToHepMC->set_store_pdf(true); @@ -55,6 +73,18 @@ PHPythia8::PHPythia8(const std::string &name) PHHepMCGenHelper::set_embedding_id(1); // default embedding ID to 1 } +/** + * @brief Initialize the Pythia8 generator, configure nodes, and seed the RNG. + * + * Performs module initialization: reads an optional configuration file and any + * queued Pythia command strings, creates the required node tree under the + * provided top-level node, sets Pythia's random seed (mapped from PHRandomSeed + * into Pythia's valid range) and prints it for reproducibility, then calls + * Pythia8::init(). + * + * @param topNode Top-level PHCompositeNode under which generator nodes are created. + * @return int Fun4All return code; returns Fun4AllReturnCodes::EVENT_OK on success. + */ int PHPythia8::Init(PHCompositeNode *topNode) { if (!m_ConfigFileName.empty()) @@ -92,8 +122,15 @@ int PHPythia8::Init(PHCompositeNode *topNode) // print out seed so we can make this is reproducible std::cout << "PHPythia8 random seed: " << seed << std::endl; + +// pythia again messes with the cout formatting + std::ios old_state(nullptr); + old_state.copyfmt(std::cout); // save current state + m_Pythia8->init(); + std::cout.copyfmt(old_state); // restore state to saved state + return Fun4AllReturnCodes::EVENT_OK; } @@ -139,7 +176,7 @@ int PHPythia8::read_config(const std::string &cfg_file) if (Verbosity() >= VERBOSITY_SOME) { - std::cout << "PHPythia8::read_config - Reading " << m_ConfigFileName << std::endl; + std::cout << Name() << " PHPythia8::read_config - Reading " << m_ConfigFileName << std::endl; } std::ifstream infile(m_ConfigFileName); @@ -164,12 +201,15 @@ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) { if (Verbosity() >= VERBOSITY_MORE) { - std::cout << "PHPythia8::process_event - event: " << m_EventCount << std::endl; + std::cout << Name() << " PHPythia8::process_event - event: " << m_EventCount << std::endl; } bool passedGen = false; bool passedTrigger = false; // int genCounter = 0; +// pythia again messes with the cout formatting in its event loop + std::ios old_state(nullptr); + old_state.copyfmt(std::cout); // save current state while (!passedTrigger) { @@ -208,7 +248,7 @@ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) andScoreKeeper &= trigResult; } - if (Verbosity() >= VERBOSITY_EVEN_MORE && !passedTrigger) + if (Verbosity() >= VERBOSITY_EVEN_MORE && !passedTrigger && !andScoreKeeper) { std::cout << "PHPythia8::process_event - failed trigger: " << m_RegisteredTrigger->GetName() << std::endl; @@ -245,6 +285,7 @@ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) if (!success) { std::cout << "PHPythia8::process_event - Failed to add event to HepMC record!" << std::endl; + std::cout.copyfmt(old_state); // restore state to saved state return Fun4AllReturnCodes::ABORTRUN; } @@ -265,6 +306,8 @@ int PHPythia8::process_event(PHCompositeNode * /*topNode*/) ++m_EventCount; + std::cout.copyfmt(old_state); // restore state to saved state + // save statistics if (m_IntegralNode) { diff --git a/generators/flowAfterburner/flowAfterburner.h b/generators/flowAfterburner/flowAfterburner.h index 8cac630401..6c3c77706c 100644 --- a/generators/flowAfterburner/flowAfterburner.h +++ b/generators/flowAfterburner/flowAfterburner.h @@ -1,11 +1,11 @@ #ifndef FLOWAFTERBURNER_FLOWAFTERBURNER_H #define FLOWAFTERBURNER_FLOWAFTERBURNER_H +#include "AfterburnerAlgo.h" + #include #include -#include "AfterburnerAlgo.h" - namespace CLHEP { class HepRandomEngine; @@ -63,18 +63,18 @@ class Afterburner private: - AfterburnerAlgo * m_algo = nullptr; - CLHEP::HepRandomEngine * m_engine = nullptr; - bool m_ownAlgo = false; - bool m_ownEngine = false; - float m_mineta = -5.0f; - float m_maxeta = 5.0f; - float m_minpt = 0.0f; - float m_maxpt = 100.0f; - double m_phishift = 0.0; // shift of the reaction plane angle in phi, used to align with the impact parameter + AfterburnerAlgo * m_algo {nullptr}; + CLHEP::HepRandomEngine * m_engine {nullptr}; + bool m_ownAlgo {false}; + bool m_ownEngine {false}; + float m_mineta {-5.0}; + float m_maxeta {5.0}; + float m_minpt {0.0}; + float m_maxpt {100.0}; + double m_phishift {0.0}; // shift of the reaction plane angle in phi, used to align with the impact parameter void setPsiN(unsigned int n, float psi); - float m_psi_n[6] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}; // reaction plane angles + float m_psi_n[6] {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; // reaction plane angles // Legacy arguments void readLegacyArguments( diff --git a/generators/phhepmc/PHHepMCGenEventv1.cc b/generators/phhepmc/PHHepMCGenEventv1.cc index bc8eef6f41..3aa7515365 100644 --- a/generators/phhepmc/PHHepMCGenEventv1.cc +++ b/generators/phhepmc/PHHepMCGenEventv1.cc @@ -9,6 +9,7 @@ #include #include // for cout +#include #include // for map #include #include // for swap @@ -109,6 +110,6 @@ float PHHepMCGenEventv1::get_flow_psi(unsigned int n) const return it->second; } - std::cout << "PHHepMCGenEventv1::get_flow_psi - Warning - requested reaction plane angle psi_n for n=" << n << " does not exist. Returning 0.0" << std::endl; - return 0.0F; + std::cout << "PHHepMCGenEventv1::get_flow_psi - Warning - requested reaction plane angle psi_n for n=" << n << " does not exist. Returning NAN" << std::endl; + return std::numeric_limits::quiet_NaN(); } diff --git a/generators/phhepmc/PHHepMCGenHelper.h b/generators/phhepmc/PHHepMCGenHelper.h index 4accf6b1d6..d60f6b862f 100644 --- a/generators/phhepmc/PHHepMCGenHelper.h +++ b/generators/phhepmc/PHHepMCGenHelper.h @@ -43,9 +43,9 @@ class PHHepMCGenHelper enum VTXFUNC { //! uniform distribution with half width set via set_vertex_distribution_width() - Uniform, + Uniform = 0, //! normal distribution with sigma width set via set_vertex_distribution_width() - Gaus + Gaus = 1 }; //! toss a new vertex according to a Uniform or Gaus distribution diff --git a/generators/sHijing/xml_test.cc b/generators/sHijing/xml_test.cc index 587fd0e957..a6c1ba75f2 100644 --- a/generators/sHijing/xml_test.cc +++ b/generators/sHijing/xml_test.cc @@ -3,6 +3,14 @@ // // Inspired by code from ATLAS. Thanks! // +#define f2cFortran +#define gFortran + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#include "cfortran.h" +#pragma GCC diagnostic pop + #include #include #include @@ -12,15 +20,6 @@ #include #include -#define f2cFortran -#define gFortran - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -#include "cfortran.h" -#pragma GCC diagnostic pop - -//using namespace boost; float atl_ran(int * /*unused*/) { diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index 2451672807..fe815df37f 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -84,7 +84,23 @@ int CaloValid::Init(PHCompositeNode* /*unused*/) return Fun4AllReturnCodes::EVENT_OK; } -// Note: InitRun cannot be made static as it modifies member variable m_species +/** + * @brief Determine the collision species for the current run and set m_species. + * + * Reads the RunHeader from the provided node tree, inspects the run number, and sets + * the member variable `m_species` to one of the recognized values ("pp", "AuAu", "OO"). + * If the run number does not match any known range or the RunHeader is missing, + * `m_species` remains unchanged (default behavior uses "pp" elsewhere) and a diagnostic + * message may be printed depending on verbosity. + * + * Recognized mappings: + * - RUN2PP_* -> "pp" + * - RUN2AUAU_* or RUN3AUAU_* -> "AuAu" + * - RUN3OO_* -> "OO" + * + * @param topNode Top-level node of the event tree used to locate the RunHeader. + * @return int EVENT_OK on success. + */ int CaloValid::InitRun(PHCompositeNode* topNode) { RunHeader* runhdr = findNode::getClass(topNode, "RunHeader"); @@ -117,6 +133,14 @@ int CaloValid::InitRun(PHCompositeNode* topNode) std::cout << "This run is from Run-3 Au+Au.\n"; } } + else if (runnumber >= RunnumberRange::RUN3OO_FIRST && runnumber <= RunnumberRange::RUN3OO_LAST) + { + m_species = "OO"; + if (Verbosity() > 0) + { + std::cout << "This run is from Run-3 O+O.\n"; + } + } else { if (Verbosity() > 0) @@ -142,6 +166,20 @@ int CaloValid::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Process event towers, triggers, MBD, and clusters to populate QA histograms. + * + * Reads event header, vertex, trigger (GL1), calibrated and raw tower containers for + * CEMC/HCAL (inner/outer), MBD PMTs, and CEMC clusters; computes per-detector totals, + * downscaled correlations, per-channel and per-tower QA, pi0 candidate invariant masses, + * and trigger/alignment summaries, then fills the corresponding histograms and profiles. + * + * @param topNode Top-level PHCompositeNode containing event data (towers, clusters, + * trigger/GL1 packets, vertex map, and MBD PMTs). + * @return Fun4AllReturnCodes::EVENT_OK on success; may return other Fun4All return codes + * or 0 on error conditions encountered while processing nodes. + * + */ int CaloValid::process_towers(PHCompositeNode* topNode) { //---------------------------Event header--------------------------------// @@ -176,7 +214,8 @@ int CaloValid::process_towers(PHCompositeNode* topNode) float ihcaldownscale; float ohcaldownscale; float mbddownscale; - float adc_threshold; + float adc_threshold_hcal; + float adc_threshold_emcal; float emcal_hit_threshold; float emcal_highhit_threshold; float ohcal_hit_threshold; @@ -190,7 +229,28 @@ int CaloValid::process_towers(PHCompositeNode* topNode) ihcaldownscale = 55000. / 300.; ohcaldownscale = 265000. / 600.; mbddownscale = 2800.0; - adc_threshold = 15.; + adc_threshold_hcal = 30; + adc_threshold_emcal = 70; + + emcal_hit_threshold = 0.5; // GeV + ohcal_hit_threshold = 0.5; + ihcal_hit_threshold = 0.25; + + emcal_highhit_threshold = 3.0; + ohcal_highhit_threshold = 3.0; + ihcal_highhit_threshold = 3.0; + } + else if (m_species == "OO") + { + // Scale by the ratio of nucleons: OO/AuAu + float scale_factor = 16. / 197.; + + emcaldownscale = (1350000. / 800.) * scale_factor; + ihcaldownscale = (55000. / 300.) * scale_factor; + ohcaldownscale = (265000. / 600.) * scale_factor; + mbddownscale = 2800.0 * scale_factor; + adc_threshold_hcal = 30; + adc_threshold_emcal = 70; emcal_hit_threshold = 0.5; // GeV ohcal_hit_threshold = 0.5; @@ -206,7 +266,8 @@ int CaloValid::process_towers(PHCompositeNode* topNode) ihcaldownscale = 4000. / 300.; ohcaldownscale = 25000. / 600.; mbddownscale = 200.0; - adc_threshold = 100.; + adc_threshold_hcal = 30; + adc_threshold_emcal = 70; emcal_hit_threshold = 0.5; // GeV ohcal_hit_threshold = 0.5; @@ -335,13 +396,16 @@ 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) { h_cemc_etaphi_time->Fill(ieta, iphi, _timef); h_cemc_etaphi->Fill(ieta, iphi); - if (isGood && (scaledBits[10] || scaledBits[11])) + if (isGood && (scaledBits[10] || scaledBits[12])) { h_cemc_etaphi_wQA->Fill(ieta, iphi, offlineenergy); } @@ -407,14 +471,17 @@ 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) { h_ihcal_etaphi->Fill(ieta, iphi); h_ihcal_etaphi_time->Fill(ieta, iphi, _timef); - if (isGood && (scaledBits[10] || scaledBits[11])) + if (isGood && (scaledBits[10] || scaledBits[12])) { h_ihcal_etaphi_wQA->Fill(ieta, iphi, offlineenergy); } @@ -472,14 +539,17 @@ 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) { h_ohcal_etaphi_time->Fill(ieta, iphi, _timef); h_ohcal_etaphi->Fill(ieta, iphi); - if (isGood && (scaledBits[10] || scaledBits[11])) + if (isGood && (scaledBits[10] || scaledBits[12])) { h_ohcal_etaphi_wQA->Fill(ieta, iphi, offlineenergy); } @@ -519,7 +589,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) } float raw_energy = tower->get_energy(); - if (raw_energy > adc_threshold) + if (raw_energy > adc_threshold_emcal) { h_cemc_etaphi_fracHitADC->Fill(ieta, iphi, 1); h_cemc_etaphi_time_raw->Fill(ieta, iphi, raw_time); @@ -549,7 +619,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) } float raw_energy = tower->get_energy(); - if (raw_energy > adc_threshold) + if (raw_energy > adc_threshold_hcal) { h_ohcal_etaphi_time_raw->Fill(ieta, iphi, raw_time); h_ohcal_etaphi_fracHitADC->Fill(ieta, iphi, 1); @@ -579,7 +649,7 @@ int CaloValid::process_towers(PHCompositeNode* topNode) } float raw_energy = tower->get_energy(); - if (raw_energy > adc_threshold) + if (raw_energy > adc_threshold_hcal) { h_ihcal_etaphi_time_raw->Fill(ieta, iphi, raw_time); h_ihcal_etaphi_fracHitADC->Fill(ieta, iphi, 1); diff --git a/offline/QA/Calorimeters/CaloValid.h b/offline/QA/Calorimeters/CaloValid.h index 2e2f9e278e..baaede0fe5 100644 --- a/offline/QA/Calorimeters/CaloValid.h +++ b/offline/QA/Calorimeters/CaloValid.h @@ -55,7 +55,7 @@ class CaloValid : public SubsysReco TriggerAnalyzer* trigAna{nullptr}; TH3* h_pi0_trigIB_mass{nullptr}; - std::vector triggerIndices{10, 28, 29, 30, 31}; // MBD NS>=1, Photon Triggers + std::vector triggerIndices{10, 12, 28, 29, 30, 31}; // MBD NS>=1, Photon Triggers TH1* h_cemc_channel_pedestal[128 * 192]{nullptr}; TH1* h_ihcal_channel_pedestal[32 * 48]{nullptr}; diff --git a/offline/QA/Jet/CaloStatusMapperDefs.h b/offline/QA/Jet/CaloStatusMapperDefs.h index c77d1b765c..08f8289fe0 100644 --- a/offline/QA/Jet/CaloStatusMapperDefs.h +++ b/offline/QA/Jet/CaloStatusMapperDefs.h @@ -59,7 +59,6 @@ namespace CaloStatusMapperDefs { Good, Hot, - BadTime, BadChi, NotInstr, NoCalib, @@ -74,7 +73,6 @@ namespace CaloStatusMapperDefs static std::map mapStatLabels = { {Stat::Good, "Good"}, {Stat::Hot, "Hot"}, - {Stat::BadTime, "BadTime"}, {Stat::BadChi, "BadChi"}, {Stat::NotInstr, "NotInstr"}, {Stat::NoCalib, "NoCalib"}, @@ -173,10 +171,6 @@ namespace CaloStatusMapperDefs { status = Stat::Hot; } - else if (tower->get_isBadTime()) - { - status = Stat::BadTime; - } else if (tower->get_isBadChi2()) { status = Stat::BadChi; @@ -204,7 +198,6 @@ namespace CaloStatusMapperDefs { bool skip = false; if ((label == "Hot") || - (label == "BadTime") || (label == "BadChi") || (label == "NoCalib") || (label == "NotInstr") || diff --git a/offline/QA/Jet/EMCalShowerShapes.cc b/offline/QA/Jet/EMCalShowerShapes.cc new file mode 100644 index 0000000000..88506fc4ce --- /dev/null +++ b/offline/QA/Jet/EMCalShowerShapes.cc @@ -0,0 +1,619 @@ +/////////////////////// +//EMCal Shower Shape QA +// +/////////////////////// +#include "EMCalShowerShapes.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace +{ + void shift_tower_index(int& ieta, int& iphi, int etadiv, int phidiv) + { + while (iphi < 0) + { + iphi += phidiv; + } + while (iphi >= phidiv) + { + iphi -= phidiv; + } + if (ieta < 0 || ieta >= etadiv) + { + ieta = -1; + } + } +} + +EMCalShowerShapes::EMCalShowerShapes(const std::string &modulename, const std::string &inputnode, const std::string &histtag) + : SubsysReco(modulename) + , m_modulename(modulename) + , m_inputnode(inputnode) + , m_histtag(histtag) + , m_trgToSelect(JetQADefs::GL1::MBDNSPhoton1) + , m_doTrgSelect(false) +{ +} + +EMCalShowerShapes::~EMCalShowerShapes() +{ + delete m_analyzer; +} + +int EMCalShowerShapes::Init(PHCompositeNode* /*topNode*/) +{ + delete m_analyzer; + m_analyzer = new TriggerAnalyzer(); + + m_manager = QAHistManagerDef::getHistoManager(); + if (!m_manager) + { + std::cerr << PHWHERE << "PANIC: couldn't grab histogram manager!" << std::endl; + gSystem->Exit(1); + } + + std::string smallModuleName = m_modulename; + std::transform(smallModuleName.begin(), smallModuleName.end(), smallModuleName.begin(), ::tolower); + + std::vector vecHistNames = { + "cluster_et", + "e11_to_e33", + "e33_to_e55", + "e55_to_e77", + "e32_to_e35", + "weta", + "wphi", + "weta_cogx", + "wphi_cogx", + "detamax", + "dphimax", + "mean_time", + "iso04_emcal", + "weta_vs_et", + "wphi_vs_et"}; + + for (auto &histName : vecHistNames) + { + histName.insert(0, "h_" + smallModuleName + "_"); + if (!m_histtag.empty()) + { + histName.append("_" + m_histtag); + } + } + + h_cluster_et = new TH1F(vecHistNames[0].data(), "", 120, 0, 30); + h_cluster_et->GetXaxis()->SetTitle("E_{T} [GeV]"); + + h_e11oe33 = new TH1F(vecHistNames[1].data(), "", 26, -0.02, 1.02); + h_e11oe33->GetXaxis()->SetTitle("e11/e33"); + + h_e33oe55 = new TH1F(vecHistNames[2].data(), "", 26, -0.02, 1.02); + h_e33oe55->GetXaxis()->SetTitle("e33/e55"); + + h_e55oe77 = new TH1F(vecHistNames[3].data(), "", 26, -0.02, 1.02); + h_e55oe77->GetXaxis()->SetTitle("e55/e77"); + + h_e32oe35 = new TH1F(vecHistNames[4].data(), "", 26, -0.02, 1.02); + h_e32oe35->GetXaxis()->SetTitle("e32/e35"); + + h_weta = new TH1F(vecHistNames[5].data(), "", 120, 0, 2); + h_weta->GetXaxis()->SetTitle("w#eta"); + + h_wphi = new TH1F(vecHistNames[6].data(), "", 120, 0, 2); + h_wphi->GetXaxis()->SetTitle("w#phi"); + + h_weta_cogx = new TH1F(vecHistNames[7].data(), "", 50, 0, 2); + h_weta_cogx->GetXaxis()->SetTitle("w#eta_cogx"); + + h_wphi_cogx = new TH1F(vecHistNames[8].data(), "", 50, 0, 2); + h_wphi_cogx->GetXaxis()->SetTitle("w#phi_cogx"); + + h_detamax = new TH1F(vecHistNames[9].data(), "", 10, -0.5, 9.5); + h_detamax->GetXaxis()->SetTitle("detamax"); + + h_dphimax = new TH1F(vecHistNames[10].data(), "", 20, -0.5, 19.5); + h_dphimax->GetXaxis()->SetTitle("dphimax"); + + h_mean_time = new TH1F(vecHistNames[11].data(), "", 200, -20, 20); + h_mean_time->GetXaxis()->SetTitle("cluster mean time"); + + h_iso04_emcal = new TH1F(vecHistNames[12].data(), "", 200, -10, 40); + h_iso04_emcal->GetXaxis()->SetTitle("iso_{0.4}^{EMCal} [GeV]"); + + h_weta_vs_et = new TH2F(vecHistNames[13].data(), "", 120, 0, 30, 120, 0, 6); + h_weta_vs_et->GetXaxis()->SetTitle("E_{T} [GeV]"); + h_weta_vs_et->GetYaxis()->SetTitle("w#eta"); + + h_wphi_vs_et = new TH2F(vecHistNames[14].data(), "", 120, 0, 30, 120, 0, 6); + h_wphi_vs_et->GetXaxis()->SetTitle("E_{T} [GeV]"); + h_wphi_vs_et->GetYaxis()->SetTitle("w#phi"); + + // Register histograms here to preserve them even if files are closedß + m_manager->registerHisto(h_cluster_et); + m_manager->registerHisto(h_e11oe33); + m_manager->registerHisto(h_e33oe55); + m_manager->registerHisto(h_e55oe77); + m_manager->registerHisto(h_e32oe35); + m_manager->registerHisto(h_weta); + m_manager->registerHisto(h_wphi); + m_manager->registerHisto(h_weta_cogx); + m_manager->registerHisto(h_wphi_cogx); + m_manager->registerHisto(h_detamax); + m_manager->registerHisto(h_dphimax); + m_manager->registerHisto(h_mean_time); + m_manager->registerHisto(h_iso04_emcal); + m_manager->registerHisto(h_weta_vs_et); + m_manager->registerHisto(h_wphi_vs_et); + + return Fun4AllReturnCodes::EVENT_OK; +} + +int EMCalShowerShapes::InitRun(PHCompositeNode* topNode) +{ + if (!LoadEMCalNodes(topNode)) + { + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; +} + +bool EMCalShowerShapes::LoadEMCalNodes(PHCompositeNode *topNode) +{ + m_emc_tower_container = findNode::getClass(topNode, "TOWERINFO_CALIB_CEMC"); + m_geomEM = findNode::getClass(topNode, "TOWERGEOM_CEMC"); + + const bool have_nodes = (m_emc_tower_container && m_geomEM); + if (!have_nodes && !m_reportedMissingCaloNodes) + { + std::cout << PHWHERE << "EMCalShowerShapes::LoadEMCalNodes - missing TOWERINFO_CALIB_CEMC or TOWERGEOM_CEMC" << std::endl; + m_reportedMissingCaloNodes = true; + } + return have_nodes; +} + +float EMCalShowerShapes::GetVertexZ(PHCompositeNode *topNode) const +{ + MbdVertexMap* vertexmap = findNode::getClass(topNode, "MbdVertexMap"); + if (!vertexmap || vertexmap->empty()) + { + return 0.0F; + } + + MbdVertex* vtx = vertexmap->begin()->second; + if (!vtx) + { + return 0.0F; + } + + return vtx->get_z(); +} + +int EMCalShowerShapes::process_event(PHCompositeNode *topNode) +{ + RawClusterContainer* clusterContainer = findNode::getClass(topNode, m_inputnode); + if (!clusterContainer) + { + if (!m_reportedMissingClusterNode) + { + std::cout << PHWHERE << "EMCalShowerShapes::process_event - missing node " << m_inputnode << std::endl; + m_reportedMissingClusterNode = true; + } + return Fun4AllReturnCodes::ABORTRUN; + } + + if (!LoadEMCalNodes(topNode)) + { + return Fun4AllReturnCodes::ABORTRUN; + } + + if (m_doTrgSelect) + { + m_analyzer->decodeTriggers(topNode); + if (!JetQADefs::DidTriggerFire(m_trgToSelect, m_analyzer)) + { + return Fun4AllReturnCodes::EVENT_OK; + } + } + + const float vertex_z = GetVertexZ(topNode); + if (m_doMbdZvtxCut && std::abs(vertex_z) >= m_mbdZvtxMax) + { + return Fun4AllReturnCodes::EVENT_OK; + } + + const CLHEP::Hep3Vector vertex_vec(0, 0, vertex_z); + + RawClusterContainer::ConstRange clusters = clusterContainer->getClusters(); + for (auto iter = clusters.first; iter != clusters.second; ++iter) + { + RawCluster* cluster = iter->second; + if (!cluster) + { + continue; + } + + const float eta = RawClusterUtility::GetPseudorapidity(*cluster, vertex_vec); + if (m_doClusterEtaCut && std::abs(eta) >= m_clusterEtaMax) + { + continue; + } + + const float phi = RawClusterUtility::GetAzimuthAngle(*cluster, vertex_vec); + const float et = cluster->get_energy() / std::cosh(eta); + if (m_doClusterETCut && et < m_clusterETMin) + { + continue; + } + + ShowerShapeData data; + if (!CalculateShowerShapes(cluster, eta, phi, et, vertex_z, data)) + { + continue; + } + + h_cluster_et->Fill(et); + if (data.e33 > 0) { + h_e11oe33->Fill(data.e11 / data.e33); + } + if (data.e55 > 0) { + h_e33oe55->Fill(data.e33 / data.e55); + } + if (data.e77 > 0) { + h_e55oe77->Fill(data.e55 / data.e77); + } + if (data.e35 > 0) { + h_e32oe35->Fill(data.e32 / data.e35); + } + h_weta->Fill(data.weta); + h_wphi->Fill(data.wphi); + h_weta_cogx->Fill(data.weta_cogx); + h_wphi_cogx->Fill(data.wphi_cogx); + h_detamax->Fill(data.detamax); + h_dphimax->Fill(data.dphimax); + h_mean_time->Fill(data.mean_time); + h_iso04_emcal->Fill(data.iso04_emcal); + h_weta_vs_et->Fill(et, data.weta); + h_wphi_vs_et->Fill(et, data.wphi); + + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +bool EMCalShowerShapes::CalculateShowerShapes(RawCluster* cluster, float cluster_eta, float cluster_phi, float cluster_et, float vertex_z, ShowerShapeData& data) const +{ + std::vector showershape = cluster->get_shower_shapes(m_shape_min_tower_E); + if (showershape.empty()) + { + return false; + } + + const std::pair leadtowerindex = cluster->get_lead_tower(); + const int lead_ieta = leadtowerindex.first; + const int lead_iphi = leadtowerindex.second; + + const float avg_eta = showershape[4] + 0.5F; + const float avg_phi = showershape[5] + 0.5F; + const int maxieta = std::floor(avg_eta); + const int maxiphi = std::floor(avg_phi); + + int detamax = 0; + int dphimax = 0; + float clusteravgtime = 0.0F; + float cluster_total_e = 0.0F; + const RawCluster::TowerMap& tower_map = cluster->get_towermap(); + std::set towers_in_cluster; + for (auto tower_iter : tower_map) + { + RawTowerDefs::keytype tower_key = tower_iter.first; + const int ieta = RawTowerDefs::decode_index1(tower_key); + const int iphi = RawTowerDefs::decode_index2(tower_key); + + const unsigned int towerinfokey = TowerInfoDefs::encode_emcal(ieta, iphi); + towers_in_cluster.insert(towerinfokey); + TowerInfo* towerinfo = m_emc_tower_container->get_tower_at_key(towerinfokey); + if (towerinfo) + { + clusteravgtime += towerinfo->get_time() * towerinfo->get_energy(); + cluster_total_e += towerinfo->get_energy(); + } + + int totalphibins = 256; + auto dphiwrap = [totalphibins](int towerphi, int maxiphi_arg) + { + int idphi = towerphi - maxiphi_arg; + if (idphi > totalphibins / 2) + { + idphi -= totalphibins; + } + if (idphi < -totalphibins / 2) + { + idphi += totalphibins; + } + return idphi; + }; + + const int deta = ieta - lead_ieta; + const int dphi_val = dphiwrap(iphi, lead_iphi); + detamax = std::max(std::abs(deta), detamax); + dphimax = std::max(std::abs(dphi_val), dphimax); + } + + if (cluster_total_e > 0) + { + clusteravgtime /= cluster_total_e; + } + else + { + std::cout << "cluster_total_e is 0(this should not happen!!!), setting clusteravgtime to NaN" << std::endl; + clusteravgtime = std::numeric_limits::quiet_NaN(); + } + + float E77[7][7] = {{0.0F}}; + int E77_ownership[7][7] = {{0}}; + + for (int ieta = maxieta - 3; ieta < maxieta + 4; ++ieta) + { + for (int iphi = maxiphi - 3; iphi < maxiphi + 4; ++iphi) + { + if (ieta < 0 || ieta > 95) + { + E77[ieta - maxieta + 3][iphi - maxiphi + 3] = 0.0F; + E77_ownership[ieta - maxieta + 3][iphi - maxiphi + 3] = 0; + continue; + } + + int temp_ieta = ieta; + int temp_iphi = iphi; + shift_tower_index(temp_ieta, temp_iphi, 96, 256); + if (temp_ieta < 0) + { + continue; + } + + const unsigned int towerinfokey = TowerInfoDefs::encode_emcal(temp_ieta, temp_iphi); + //if (towers_in_cluster.find(towerinfokey) != towers_in_cluster.end()) + if (towers_in_cluster.contains(towerinfokey)) + { + E77_ownership[ieta - maxieta + 3][iphi - maxiphi + 3] = 1; + } + + TowerInfo* towerinfo = m_emc_tower_container->get_tower_at_key(towerinfokey); + if (towerinfo && towerinfo->get_isGood()) + { + const float energy = towerinfo->get_energy(); + if (energy > m_shape_min_tower_E) + { + E77[ieta - maxieta + 3][iphi - maxiphi + 3] = energy; + } + } + } + } + + float e11 = E77[3][3]; + float e32 = 0.0F; + float e33 = 0.0F; + float e35 = 0.0F; + float e55 = 0.0F; + float e77 = 0.0F; + float weta = 0.0F; + float wphi = 0.0F; + float weta_cogx = 0.0F; + float wphi_cogx = 0.0F; + float Eetaphi = 0.0F; + + const float shift_eta = avg_eta - std::floor(avg_eta) - 0.5F; + const float shift_phi = avg_phi - std::floor(avg_phi) - 0.5F; + const float cog_eta = 3 + shift_eta; + const float cog_phi = 3 + shift_phi; + const int signphi = (avg_phi - std::floor(avg_phi)) > 0.5 ? 1 : -1; + + for (int i = 0; i < 7; ++i) + { + for (int j = 0; j < 7; ++j) + { + const int di = std::abs(i - 3); + const int dj = std::abs(j - 3); + const float di_float = i - cog_eta; + const float dj_float = j - cog_phi; + + if (E77_ownership[i][j] == 1) + { + weta += E77[i][j] * di * di; + wphi += E77[i][j] * dj * dj; + Eetaphi += E77[i][j]; + if (i != 3 || j != 3) + { + weta_cogx += E77[i][j] * di_float * di_float; + wphi_cogx += E77[i][j] * dj_float * dj_float; + } + } + + e77 += E77[i][j]; + if (di <= 1 && (dj == 0 || j == (3 + signphi))) + { + e32 += E77[i][j]; + } + if (di <= 1 && dj <= 1) + { + e33 += E77[i][j]; + } + if (di <= 1 && dj <= 2) + { + e35 += E77[i][j]; + } + if (di <= 2 && dj <= 2) + { + e55 += E77[i][j]; + } + } + } + + if (Eetaphi > 0) + { + weta /= Eetaphi; + wphi /= Eetaphi; + weta_cogx /= Eetaphi; + wphi_cogx /= Eetaphi; + } + /*else + { + weta = std::numeric_limits::quiet_NaN(); + wphi = std::numeric_limits::quiet_NaN(); + weta_cogx = std::numeric_limits::quiet_NaN(); + wphi_cogx = std::numeric_limits::quiet_NaN(); + }*/ + + data.e11 = e11; + data.e33 = e33; + data.e32 = e32; + data.e35 = e35; + data.e55 = e55; + data.e77 = e77; + data.weta = weta; + data.wphi = wphi; + data.weta_cogx = weta_cogx; + data.wphi_cogx = wphi_cogx; + data.detamax = detamax; + data.dphimax = dphimax; + data.mean_time = clusteravgtime; + data.iso04_emcal = CalculateLayerET(cluster_eta, cluster_phi, 0.4F, m_emc_tower_container, m_geomEM, vertex_z) - cluster_et; + + return true; +} + +double EMCalShowerShapes::GetTowerEta(RawTowerGeom* tower_geom, double vx, double vy, double vz) const +{ + if (!tower_geom) + { + return -9999; + } + if (vx == 0 && vy == 0 && vz == 0) + { + return tower_geom->get_eta(); + } + + const double radius = std::sqrt((tower_geom->get_center_x() - vx) * (tower_geom->get_center_x() - vx) + + (tower_geom->get_center_y() - vy) * (tower_geom->get_center_y() - vy)); + const double theta = std::atan2(radius, tower_geom->get_center_z() - vz); + return -std::log(std::tan(theta / 2.)); +} + +double EMCalShowerShapes::DeltaR(double eta1, double phi1, double eta2, double phi2) const +{ + double dphi = phi1 - phi2; + while (dphi > M_PI) + { + dphi -= 2 * M_PI; + } + while (dphi <= -M_PI) + { + dphi += 2 * M_PI; + } + return std::sqrt(std::pow(eta1 - eta2, 2) + std::pow(dphi, 2)); +} + +float EMCalShowerShapes::CalculateLayerET(float seed_eta, float seed_phi, float radius, TowerInfoContainer* towerContainer, RawTowerGeomContainer* geomContainer, float vertex_z) const +{ + if (!towerContainer || !geomContainer) + { + return std::numeric_limits::quiet_NaN(); + } + + float layer_et = 0.0F; + const unsigned int ntowers = towerContainer->size(); + for (unsigned int channel = 0; channel < ntowers; ++channel) + { + TowerInfo* tower = towerContainer->get_tower_at_channel(channel); + if (!tower || !tower->get_isGood()) + { + continue; + } + + const unsigned int towerkey = towerContainer->encode_key(channel); + const int ieta = towerContainer->getTowerEtaBin(towerkey); + const int iphi = towerContainer->getTowerPhiBin(towerkey); + + const RawTowerDefs::keytype geom_key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::CEMC, ieta, iphi); + RawTowerGeom* tower_geom = geomContainer->get_tower_geometry(geom_key); + if (!tower_geom) + { + continue; + } + + const double tower_eta = GetTowerEta(tower_geom, 0, 0, vertex_z); + const double tower_phi = tower_geom->get_phi(); + if (DeltaR(seed_eta, seed_phi, tower_eta, tower_phi) >= radius) + { + continue; + } + + const float energy = tower->get_energy(); + if (energy <= m_shape_min_tower_E) + { + continue; + } + + layer_et += energy / std::cosh(tower_eta); + } + + return layer_et; +} + +//int EMCalShowerShapes::ResetEvent(PHCompositeNode* /*topNode*/) +//{ +// return Fun4AllReturnCodes::EVENT_OK; +//} + +//int EMCalShowerShapes::EndRun(const int /*runnumber*/) +//{ +// return Fun4AllReturnCodes::EVENT_OK; +//} + +//int EMCalShowerShapes::End(PHCompositeNode* /*topNode*/) +//{ +// return Fun4AllReturnCodes::EVENT_OK; +//} + +//int EMCalShowerShapes::Reset(PHCompositeNode* /*topNode*/) +//{ +// return Fun4AllReturnCodes::EVENT_OK; +//} + +void EMCalShowerShapes::Print(const std::string &what) const +{ + std::cout << "EMCalShowerShapes::Print(" << what << ")" << std::endl; +} diff --git a/offline/QA/Jet/EMCalShowerShapes.h b/offline/QA/Jet/EMCalShowerShapes.h new file mode 100644 index 0000000000..b60d1153e8 --- /dev/null +++ b/offline/QA/Jet/EMCalShowerShapes.h @@ -0,0 +1,136 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef EMCALSHOWERSHAPES_H +#define EMCALSHOWERSHAPES_H + +#include "JetQADefs.h" + +#include + +#include +#include + +class Fun4AllHistoManager; +class PHCompositeNode; +class RawCluster; +class RawTowerGeom; +class RawTowerGeomContainer; +class TH1; +class TH2; +class TowerInfoContainer; +class TriggerAnalyzer; + +class EMCalShowerShapes : public SubsysReco +{ + public: + EMCalShowerShapes(const std::string &modulename = "EMCalShowerShapes", const std::string &inputnode = "CLUSTERINFO_CEMC", const std::string &histtag = ""); + ~EMCalShowerShapes() override; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + //int ResetEvent(PHCompositeNode *topNode) override; + //int EndRun(const int runnumber) override; + //int End(PHCompositeNode *topNode) override; + //int Reset(PHCompositeNode *topNode) override; + void Print(const std::string &what = "ALL") const override; + + void SetTrgToSelect(const uint32_t trig = JetQADefs::GL1::MBDNSPhoton1) + { + m_doTrgSelect = true; + m_trgToSelect = trig; + } + + void SetHistTag(const std::string& tag) + { + m_histtag = tag; + } + + void SetApplyMbdZvtxCut(const bool apply) + { + m_doMbdZvtxCut = apply; + } + + void SetMbdZvtxMax(const float maxz) + { + m_mbdZvtxMax = maxz; + } + + void SetApplyClusterEtaCut(const bool apply) + { + m_doClusterEtaCut = apply; + } + + void SetApplyClusterETCut(const bool apply) + { + m_doClusterETCut = apply; + } + + void SetClusterEtaMax(const float maxeta) + { + m_clusterEtaMax = maxeta; + } + + private: + struct ShowerShapeData + { + float e11 {std::numeric_limits::quiet_NaN()}; + float e33 {std::numeric_limits::quiet_NaN()}; + float e55 {std::numeric_limits::quiet_NaN()}; + float e77 {std::numeric_limits::quiet_NaN()}; + float e32 {std::numeric_limits::quiet_NaN()}; + float e35 {std::numeric_limits::quiet_NaN()}; + float weta {std::numeric_limits::quiet_NaN()}; + float wphi {std::numeric_limits::quiet_NaN()}; + float weta_cogx {std::numeric_limits::quiet_NaN()}; + float wphi_cogx {std::numeric_limits::quiet_NaN()}; + float detamax {std::numeric_limits::quiet_NaN()}; + float dphimax {std::numeric_limits::quiet_NaN()}; + float mean_time {std::numeric_limits::quiet_NaN()}; + float iso04_emcal {std::numeric_limits::quiet_NaN()}; + }; + + bool LoadEMCalNodes(PHCompositeNode *topNode); + float GetVertexZ(PHCompositeNode *topNode) const; + bool CalculateShowerShapes(RawCluster* cluster, float cluster_eta, float cluster_phi, float cluster_et, float vertex_z, ShowerShapeData& data) const; + double GetTowerEta(RawTowerGeom* tower_geom, double vx, double vy, double vz) const; + double DeltaR(double eta1, double phi1, double eta2, double phi2) const; + float CalculateLayerET(float seed_eta, float seed_phi, float radius, TowerInfoContainer* towerContainer, RawTowerGeomContainer* geomContainer, float vertex_z) const; + + TriggerAnalyzer* m_analyzer {nullptr}; + Fun4AllHistoManager* m_manager {nullptr}; + TowerInfoContainer* m_emc_tower_container {nullptr}; + RawTowerGeomContainer* m_geomEM {nullptr}; + std::string m_modulename; + std::string m_inputnode; + std::string m_histtag; + uint32_t m_trgToSelect; + bool m_doTrgSelect; + bool m_reportedMissingClusterNode {false}; + bool m_reportedMissingCaloNodes {false}; + float m_shape_min_tower_E {0.070F}; + bool m_doMbdZvtxCut {true}; + float m_mbdZvtxMax {60.0F}; + bool m_doClusterEtaCut {true}; + float m_clusterEtaMax {0.7F}; + bool m_doClusterETCut {true}; + float m_clusterETMin {5.0F}; + + TH1* h_cluster_et {nullptr}; + TH1* h_e11oe33 {nullptr}; + TH1* h_e33oe55 {nullptr}; + TH1* h_e55oe77 {nullptr}; + TH1* h_e32oe35 {nullptr}; + TH1* h_weta {nullptr}; + TH1* h_wphi {nullptr}; + TH1* h_weta_cogx {nullptr}; + TH1* h_wphi_cogx {nullptr}; + TH1* h_detamax {nullptr}; + TH1* h_dphimax {nullptr}; + TH1* h_mean_time {nullptr}; + TH1* h_iso04_emcal {nullptr}; + TH2* h_weta_vs_et {nullptr}; + TH2* h_wphi_vs_et {nullptr}; +}; + +#endif diff --git a/offline/QA/Jet/Makefile.am b/offline/QA/Jet/Makefile.am index 91b4292ad4..497c22458b 100644 --- a/offline/QA/Jet/Makefile.am +++ b/offline/QA/Jet/Makefile.am @@ -18,6 +18,7 @@ pkginclude_HEADERS = \ CaloStatusMapperDefs.h \ ConstituentsinJets.h \ DijetQA.h \ + EMCalShowerShapes.h \ EMClusterKinematics.h \ JetKinematicCheck.h \ JetQADefs.h \ @@ -43,6 +44,7 @@ libjetqa_la_SOURCES = \ CaloStatusMapper.cc \ ConstituentsinJets.cc \ DijetQA.cc \ + EMCalShowerShapes.cc \ EMClusterKinematics.cc \ JetKinematicCheck.cc \ JetSeedCount.cc \ diff --git a/offline/QA/KFParticle/QAKFParticle.h b/offline/QA/KFParticle/QAKFParticle.h index 60d47c158c..1123ac92d4 100644 --- a/offline/QA/KFParticle/QAKFParticle.h +++ b/offline/QA/KFParticle/QAKFParticle.h @@ -3,6 +3,8 @@ #ifndef QA_KFPARTICLE_QAKFPARTICLE_H #define QA_KFPARTICLE_QAKFPARTICLE_H +#include "QAKFParticleTrackPtAsymmetry.h" + #include #include @@ -15,7 +17,6 @@ #include -#include "QAKFParticleTrackPtAsymmetry.h" class KFParticle_Container; class PHCompositeNode; diff --git a/offline/QA/SimulationModules/QAG4SimulationKFParticle.cc b/offline/QA/SimulationModules/QAG4SimulationKFParticle.cc index b9be814a15..4c24fe241e 100644 --- a/offline/QA/SimulationModules/QAG4SimulationKFParticle.cc +++ b/offline/QA/SimulationModules/QAG4SimulationKFParticle.cc @@ -417,7 +417,7 @@ int QAG4SimulationKFParticle::load_nodes(PHCompositeNode *topNode) m_kfpContainer = findNode::getClass(topNode, m_mother_name + "_KFParticle_Container"); if (!m_kfpContainer) { - std::cout << m_mother_name.c_str() << "_KFParticle_Container - Fatal Error - " + std::cout << m_mother_name << "_KFParticle_Container - Fatal Error - " << "unable to find DST node " << "G4_QA" << std::endl; assert(m_kfpContainer); diff --git a/offline/QA/Tpc/Makefile.am b/offline/QA/Tpc/Makefile.am index 4025cd381a..71dd9bb00e 100644 --- a/offline/QA/Tpc/Makefile.am +++ b/offline/QA/Tpc/Makefile.am @@ -28,6 +28,7 @@ libtpcqa_la_SOURCES = \ libtpcqa_la_LIBADD = \ -lphool \ -lSubsysReco \ + -lg4detectors_io \ -lg4tpc \ -ltrack_io \ -ltrackbase_historic_io \ diff --git a/offline/QA/Tpc/TpcLaserQA.cc b/offline/QA/Tpc/TpcLaserQA.cc index 5fd399d05e..38058f018c 100644 --- a/offline/QA/Tpc/TpcLaserQA.cc +++ b/offline/QA/Tpc/TpcLaserQA.cc @@ -30,7 +30,7 @@ TpcLaserQA::TpcLaserQA(const std::string &name) { } -int TpcLaserQA::InitRun(PHCompositeNode * /*topNode*/) +int TpcLaserQA::InitRun(PHCompositeNode* topNode) { createHistos(); @@ -54,6 +54,9 @@ int TpcLaserQA::InitRun(PHCompositeNode * /*topNode*/) } } + m_laserClusterHelper.set_useZ(m_useZ); + m_laserClusterHelper.loadNodes(topNode); + return Fun4AllReturnCodes::EVENT_OK; } @@ -108,14 +111,27 @@ int TpcLaserQA::process_event(PHCompositeNode *topNode) nS++; } + const unsigned int nhits = cmclus->getNhits(); for (unsigned int i = 0; i < nhits; i++) - { - float layer = cmclus->getHitLayer(i); - float hitAdc = cmclus->getHitAdc(i); - float hitIT = cmclus->getHitIT(i); + { + LaserClusterHitInfo LCHI = cmclus->getHit(i); + + Acts::Vector3 hitGlobal = m_laserClusterHelper.getHitGlobalPosition(LCHI.hitsetkey, LCHI.hitkey); + if(hitGlobal.hasNaN()) + { + continue; + } + + float layer = 1.0*TrkrDefs::getLayer(LCHI.hitsetkey); + float hitAdc = 1.0*LCHI.adc; + float hitIT = 1.0*TpcDefs::getTBin(LCHI.hitkey); + + //float layer = cmclus->getHitLayer(i); + //float hitAdc = cmclus->getHitAdc(i); + //float hitIT = cmclus->getHitIT(i); - double phi = std::atan2(cmclus->getHitY(i), cmclus->getHitX(i)); + double phi = std::atan2(hitGlobal(1), hitGlobal(0)); if (phi < -M_PI / 12.) { phi += 2 * M_PI; } diff --git a/offline/QA/Tpc/TpcLaserQA.h b/offline/QA/Tpc/TpcLaserQA.h index 02e98bfc4d..ce17c62f32 100644 --- a/offline/QA/Tpc/TpcLaserQA.h +++ b/offline/QA/Tpc/TpcLaserQA.h @@ -3,6 +3,8 @@ #include +#include + #include class PHCompositeNode; @@ -19,6 +21,8 @@ class TpcLaserQA : public SubsysReco int InitRun(PHCompositeNode* topNode) override; int process_event(PHCompositeNode* topNode) override; + void set_useZ(bool use) { m_useZ = use; } + private: void createHistos(); std::string getHistoPrefix() const; @@ -34,6 +38,9 @@ class TpcLaserQA : public SubsysReco TH1* m_sample_R1[2][12]{{nullptr}}; TH1* m_sample_R2[2][12]{{nullptr}}; TH1* m_sample_R3[2][12]{{nullptr}}; + + LaserClusterHelper m_laserClusterHelper; + bool m_useZ{false}; }; #endif diff --git a/offline/QA/Tracking/CosmicTrackQA.cc b/offline/QA/Tracking/CosmicTrackQA.cc index 08f9cdadea..c3ae615158 100644 --- a/offline/QA/Tracking/CosmicTrackQA.cc +++ b/offline/QA/Tracking/CosmicTrackQA.cc @@ -149,7 +149,7 @@ int CosmicTrackQA::process_event(PHCompositeNode *topNode) } else { - Acts::Vector3 loc = surf->transform(geometry->geometry().getGeoContext()).inverse() * (intersection * Acts::UnitConstants::cm); + Acts::Vector3 loc = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse() * (intersection * Acts::UnitConstants::cm); loc /= Acts::UnitConstants::cm; statelx = loc(0); statelz = loc(1); @@ -191,7 +191,7 @@ int CosmicTrackQA::process_event(PHCompositeNode *topNode) } else { - Acts::Vector3 loc = surf->transform(geometry->geometry().getGeoContext()).inverse() * (stateglob * Acts::UnitConstants::cm); + Acts::Vector3 loc = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse() * (stateglob * Acts::UnitConstants::cm); loc /= Acts::UnitConstants::cm; statelx = loc(0); statelz = loc(1); diff --git a/offline/QA/Tracking/Makefile.am b/offline/QA/Tracking/Makefile.am index f5d87546f1..d2afc07c08 100644 --- a/offline/QA/Tracking/Makefile.am +++ b/offline/QA/Tracking/Makefile.am @@ -17,10 +17,13 @@ pkginclude_HEADERS = \ TpcSeedsQA.h \ TpcSiliconQA.h \ SiliconSeedsQA.h \ + StateClusterResidualsQA.h \ MicromegasClusterQA.h \ CosmicTrackQA.h \ TrackFittingQA.h \ - VertexQA.h + VertexQA.h \ + SiliconDriftQA.h \ + MicromegasDriftQA.h lib_LTLIBRARIES = \ libtrackingqa.la @@ -32,10 +35,13 @@ libtrackingqa_la_SOURCES = \ TpcSeedsQA.cc \ TpcSiliconQA.cc \ SiliconSeedsQA.cc \ + StateClusterResidualsQA.cc \ MicromegasClusterQA.cc \ CosmicTrackQA.cc \ TrackFittingQA.cc \ - VertexQA.cc + VertexQA.cc \ + SiliconDriftQA.cc \ + MicromegasDriftQA.cc libtrackingqa_la_LIBADD = \ -lphool \ @@ -47,6 +53,7 @@ libtrackingqa_la_LIBADD = \ -lmvtx_io \ -lintt_io \ -ltrack_io \ + -ltrack \ -ltrackbase_historic_io \ -ltrack_reco \ -lqautils diff --git a/offline/QA/Tracking/MicromegasClusterQA.cc b/offline/QA/Tracking/MicromegasClusterQA.cc index 41efeffaa7..6feb510c54 100644 --- a/offline/QA/Tracking/MicromegasClusterQA.cc +++ b/offline/QA/Tracking/MicromegasClusterQA.cc @@ -73,6 +73,9 @@ int MicromegasClusterQA::InitRun(PHCompositeNode* topNode) << (m_calibration_filename.empty() ? "unspecified" : m_calibration_filename) << std::endl; + std::cout << "MicromegasClusterQA::InitRun - m_sample_min: " << m_sample_min << std::endl; + std::cout << "MicromegasClusterQA::InitRun - m_sample_max: " << m_sample_max << std::endl; + // read calibrations if (!m_calibration_filename.empty()) { @@ -162,6 +165,13 @@ int MicromegasClusterQA::process_event(PHCompositeNode* topNode) // find associated hits const auto hit_range = m_cluster_hit_map->getHits(ckey); + // check hit samples + // if none of the associated hits' sample is within acceptable range, skip the cluster + if( std::none_of( hit_range.first, hit_range.second, + [this]( const TrkrClusterHitAssoc::Map::value_type& pair ) + { return MicromegasDefs::getSample( pair.second ) >= m_sample_min && MicromegasDefs::getSample( pair.second ) < m_sample_max; } ) ) + { continue; } + // store cluster size and fill cluster size histogram const int cluster_size = std::distance(hit_range.first, hit_range.second); m_h_cluster_size->Fill(detid, cluster_size); diff --git a/offline/QA/Tracking/MicromegasClusterQA.h b/offline/QA/Tracking/MicromegasClusterQA.h index 338e5302de..d6de8344c4 100644 --- a/offline/QA/Tracking/MicromegasClusterQA.h +++ b/offline/QA/Tracking/MicromegasClusterQA.h @@ -51,6 +51,13 @@ class MicromegasClusterQA : public SubsysReco m_calibration_filename = value; } + /// set min sample for signal hits + void set_sample_min(uint16_t value) { m_sample_min = value; } + + /// set max sample for signal hits + void set_sample_max(uint16_t value) { m_sample_max = value; } + + private: void create_histograms(); @@ -98,6 +105,12 @@ class MicromegasClusterQA : public SubsysReco /// keep track of detector names std::vector m_detector_names; + /// min sample for signal + uint16_t m_sample_min = 0; + + /// max sample for signal + uint16_t m_sample_max = 1024; + ///@name calibration filename //@{ diff --git a/offline/QA/Tracking/MicromegasDriftQA.cc b/offline/QA/Tracking/MicromegasDriftQA.cc new file mode 100644 index 0000000000..ab6ddc7f0d --- /dev/null +++ b/offline/QA/Tracking/MicromegasDriftQA.cc @@ -0,0 +1,618 @@ +#include "MicromegasDriftQA.h" + +#include + +#include +#include + +#include +#include +#include // for PHWHERE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + template + class range_adaptor + { + public: + explicit range_adaptor(const T& range) + : m_range(range) + { + } + const typename T::first_type& begin() { return m_range.first; } + const typename T::second_type& end() { return m_range.second; } + + private: + T m_range; + }; + + double normalize_angle(double phi) + { + while (phi < 0) + { + phi += 2 * M_PI; + } + while (phi >= 2 * M_PI) + { + phi -= 2 * M_PI; + } + return phi; + } + + bool phi_in_range(double phi, double min, double max) + { + phi = normalize_angle(phi); + min = normalize_angle(min); + max = normalize_angle(max); + return (min < max) ? (phi >= min && phi <= max) + : (phi >= min || phi <= max); + } + + //! helix-plane intersection via Newton-Raphson + // identical to the version in MicromegasTrackEvaluator_hp.cc + bool helix_plane_intersection( + double t_min, + double t_max, + double zmin, + double zmax, + double R, + double X0, + double Y0, + double intersect_rz, + double slope_rz, + const TVector3& ptile, + const TVector3& ntile, + TVector3& intersect) + { + // number of iterations and tolerance for Newton-Raphson method + const int max_iter = 10; + const double tol = 1e-6; + + // define C + const double C = ntile.X() * (X0 - ptile.X()) + ntile.Y() * (Y0 - ptile.Y()) + ntile.Z() * (intersect_rz - ptile.Z()); + + // define the function and the corresponding derivative used in the Newton-Raphson method + auto f = [&](double t) + { + const double xt = X0 + R * std::cos(t); + const double yt = Y0 + R * std::sin(t); + const double Rt = std::sqrt(xt * xt + yt * yt); + return ntile.X() * R * std::cos(t) + ntile.Y() * R * std::sin(t) + ntile.Z() * slope_rz * Rt + C; + }; + + auto df = [&](double t) + { + const double xt = X0 + R * std::cos(t); + const double yt = Y0 + R * std::sin(t); + const double Rt = std::sqrt(xt * xt + yt * yt); + return -ntile.X() * R * std::sin(t) + ntile.Y() * R * std::cos(t) + ntile.Z() * R * slope_rz * (Y0 * std::cos(t) - X0 * std::sin(t)) / Rt; + }; + + auto solve_from = [&](double t_seed, TVector3& result) -> bool + { + double t = t_seed; + for (int i = 0; i < max_iter; ++i) + { + const double ft = f(t); + const double dft = df(t); + if (std::abs(dft) < 1e-8) + { + return false; + } + const double t_new = t - ft / dft; + + const double x = X0 + R * std::cos(t_new); + const double y = Y0 + R * std::sin(t_new); + const double Rt_n = std::sqrt(x * x + y * y); + const double z = slope_rz * Rt_n + intersect_rz; + const double phi = std::atan2(y, x); + + const TVector3 cand(x, y, z); + const bool phi_ok = phi_in_range(phi, t_min - 1e-4, t_max + 1e-4); + const bool z_ok = (z >= zmin - 1e-4 && z <= zmax + 1e-4); + const bool proj_ok = (std::abs(ntile.Dot(cand - ptile)) <= 0.05); + + if (std::abs(t_new - t) < tol && proj_ok && phi_ok && z_ok) + { + result = cand; + return true; + } + t = t_new; + } + return false; + }; + + auto wrap = [&](double t) + { + while (t > t_max) + { + t -= 2 * M_PI; + } + while (t < t_min) + { + t += 2 * M_PI; + } + return t; + }; + + // the helix-plane equation can have more than one solution: + // look for a solution within the tile acceptance from three different phi seeds + std::vector t_seeds(3); + const double t_center = 0.5 * (t_min + t_max); + const double delta = 2.0 * M_PI / 3.0; + for (int i = 0; i < 3; ++i) + { + t_seeds[i]=wrap(t_center + i * delta); + } + + for (const double t_seed : t_seeds) + { + if (solve_from(t_seed, intersect)) + { + return true; + } + } + return false; + } + + //! piecewise fit function used for the drift velocity extraction + // par[0] = constrained slope, par[1..8] = per-tile offsets + double fit_function_2d(double* x, double* par) + { + const int itile = static_cast(std::floor(x[0])); + const double z = x[1]; + if (itile < 0 || itile >= 8) + { + TF2::RejectPoint(); + return 0.; + } + return par[itile + 1] + par[0] * z; + } + + //! z-view tile names + const std::array k_tile_names = + {"SCOZ", "SCIZ", "NCIZ", "NCOZ", "SEZ", "NEZ", "SWZ", "NWZ"}; + + //! number of z bins of the dz vs z histograms + constexpr int k_nzbins = 220; + + //! z_track range (cm) + constexpr double k_max_z = 110; + + //! dz range (cm) + constexpr double k_max_dz = 10; + +} // namespace + +//____________________________________________________________________________.. +MicromegasDriftQA::MicromegasDriftQA(const std::string& name) + : SubsysReco(name) +{ +} + +//____________________________________________________________________________.. +int MicromegasDriftQA::InitRun(PHCompositeNode* topNode) +{ + if (Verbosity()) + { + std::cout << Name() << "::InitRun" + << " drift_velocity=" << m_drift_velocity << " cm/ns" + << " min_tpc_layer=" << m_min_tpc_layer + << " max_tpc_layer=" << m_max_tpc_layer + << std::endl; + } + + const auto res = load_nodes(topNode); + if (res != Fun4AllReturnCodes::EVENT_OK) + { + return res; + } + + createHistos(); + + // reference histograms initialized in header file to histos in HistoManager + auto* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + for (int itile = 0; itile < 8; itile++) + { + h_ztrk_dz[itile] = dynamic_cast(hm->getHisto(std::format("{}ztrk_dz_{}", getHistoPrefix(), k_tile_names[itile]))); + } + h_dz = dynamic_cast(hm->getHisto(std::format("{}dz", getHistoPrefix()))); + h_tile = dynamic_cast(hm->getHisto(std::format("{}tile", getHistoPrefix()))); + h_ylocal = dynamic_cast(hm->getHisto(std::format("{}ylocal", getHistoPrefix()))); + h_ntracks = dynamic_cast(hm->getHisto(std::format("{}ntracks", getHistoPrefix()))); + h_driftSummary = dynamic_cast(hm->getHisto(std::format("{}driftSummary", getHistoPrefix()))); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MicromegasDriftQA::process_event(PHCompositeNode* topNode) +{ + const auto res = load_nodes(topNode); + if (res != Fun4AllReturnCodes::EVENT_OK) + { + return res; + } + + int nmatched = 0; + + for (const auto& [track_id, track] : *m_track_map) + { + // require valid beam-crossing + const auto crossing = track->get_crossing(); + if (crossing == SHRT_MAX) + { + continue; + } + + // collect distortion-corrected TPC cluster positions in the selected layer range + std::vector tpc_positions; + for (const auto* seed : {track->get_silicon_seed(), track->get_tpc_seed()}) + { + if (!seed) + { + continue; + } + for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) + { + const auto ckey = *it; + if (TrkrDefs::getTrkrId(ckey) != TrkrDefs::tpcId) + { + continue; + } + const auto layer = TrkrDefs::getLayer(ckey); + if (layer < m_min_tpc_layer || layer >= m_max_tpc_layer) + { + continue; + } + auto* cl = m_cluster_map->findCluster(ckey); + if (cl) + { + tpc_positions.push_back( + m_globalPositionWrapper.getGlobalPositionDistortionCorrected(ckey, cl, crossing)); + } + } + } + + // need at least 3 TPC clusters in range + if (tpc_positions.size() < 3) + { + continue; + } + + // helix fit: straight line in r-z, circle in x-y + const auto [slope_rz, intersect_rz] = TrackFitUtils::line_fit(tpc_positions); + const auto [R, X0, Y0] = TrackFitUtils::circle_fit_by_taubin(tpc_positions); + + // reject badly reconstructed / low-pT tracks + if (R < 40.0) + { + continue; + } + + // extrapolate to the TPOT z-view modules + const auto mm_range = m_micromegas_geomcontainer->get_begin_end(); + for (const auto& [mm_layer, base_layergeom] : range_adaptor(mm_range)) + { + const auto* layergeom = static_cast(base_layergeom); + assert(layergeom); + + // skip the phi layer; only the z-view layer matters here + if (layergeom->get_segmentation_type() != MicromegasDefs::SegmentationType::SEGMENTATION_Z) + { + continue; + } + + const double layer_radius = layergeom->get_radius(); + auto [xplus, yplus, xminus, yminus] = + TrackFitUtils::circle_circle_intersection(layer_radius, R, X0, Y0); + + if (!std::isfinite(xplus)) + { + continue; + } + + // pick the solution closest in phi to the last TPC cluster + const double last_phi = std::atan2(tpc_positions.back().y(), tpc_positions.back().x()); + const double phi_plus = std::atan2(yplus, xplus); + const double phi_minus = std::atan2(yminus, xminus); + const double phi = (std::abs(last_phi - phi_plus) < std::abs(last_phi - phi_minus)) ? phi_plus : phi_minus; + + const double r_cyl = layer_radius; + const double z_cyl = intersect_rz + slope_rz * r_cyl; + const TVector3 world_cyl(r_cyl * std::cos(phi), r_cyl * std::sin(phi), z_cyl); + + const int tileid = layergeom->find_tile_cylindrical(world_cyl); + if (tileid < 0) + { + continue; + } + + const auto tile_center = layergeom->get_world_from_local_coords(tileid, m_tGeometry, {0, 0}); + const TVector3 ptile(tile_center.x(), tile_center.y(), tile_center.z()); + + const auto tile_norm = layergeom->get_world_from_local_vect(tileid, m_tGeometry, {0, 0, 1}); + const TVector3 ntile(tile_norm.x(), tile_norm.y(), tile_norm.z()); + + const auto phi_range = layergeom->get_phi_range(tileid, m_tGeometry); + const double zmin = layergeom->get_zmin(); + const double zmax = layergeom->get_zmax(); + + TVector3 intersection; + if (!helix_plane_intersection(phi_range.first, phi_range.second, zmin, zmax, + R, X0, Y0, intersect_rz, slope_rz, ptile, ntile, intersection)) + { + continue; + } + + const auto local_intersection = layergeom->get_local_from_world_coords( + tileid, m_tGeometry, {intersection.x(), intersection.y(), intersection.z()}); + const double y_local = local_intersection.y(); + + // reject track states near the tile edge + if (std::abs(y_local) > m_y_local_cut) + { + continue; + } + + // find the nearest TPOT cluster on this tile + const auto hitsetkey = MicromegasDefs::genHitSetKey(mm_layer, MicromegasDefs::SegmentationType::SEGMENTATION_Z, tileid); + const auto clusrange = m_cluster_map->getClusters(hitsetkey); + + double dmin = -1; + double z_cluster = 0; + for (const auto& [ckey, cl] : range_adaptor(clusrange)) + { + const double cl_y_local = cl->getLocalY(); + const double d = std::abs(y_local - cl_y_local); + if (dmin < 0 || d < dmin) + { + dmin = d; + const auto gpos = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(ckey, cl, crossing); + z_cluster = gpos.z(); + } + } + + // require cluster within the z search window + if (dmin < 0 || dmin > m_z_search_win) + { + continue; + } + + // fill histograms + const double z_track = intersection.z(); + const double dz = z_track - z_cluster; + + h_ztrk_dz[tileid]->Fill(z_track, dz); + h_dz->Fill(dz); + h_tile->Fill(tileid); + h_ylocal->Fill(y_local); + + ++nmatched; + break; + } + } + + h_ntracks->Fill(nmatched); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MicromegasDriftQA::End(PHCompositeNode* /*topNode*/) +{ + if (!(h_ztrk_dz[0] && h_driftSummary)) + { + std::cout << PHWHERE << " histograms not found, skipping drift velocity fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + int nEntries = 0; + for (const auto* h : h_ztrk_dz) + { + nEntries += static_cast(h->GetEntries()); + } + if (Verbosity()) + { + std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; + } + + // record input drift velocity even if the fit is skipped + h_driftSummary->SetBinContent(3, m_drift_velocity); + + if (nEntries < 8 * m_min_slice_entries) + { + std::cout << Name() << "::End - not enough entries (" << nEntries << "), skipping drift velocity fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + // build mean-dz TH2 via FitSlicesY, one tile at a time + // x = tile [0,8), y = z_track (cm), content = mean dz (cm) + auto* h_fit = new TH2F("h_fit_micromegas", "", 8, 0, 8, k_nzbins, -k_max_z, k_max_z); + h_fit->SetDirectory(nullptr); + + for (int itile = 0; itile < 8; ++itile) + { + auto* h2d = h_ztrk_dz[itile]; + + // fit vertical slices; require a minimum of m_min_slice_entries per slice + TObjArray slices; + slices.SetOwner(kTRUE); + h2d->FitSlicesY(nullptr, 0, -1, m_min_slice_entries, "QNR", &slices); + auto* h_mean = dynamic_cast(slices.At(1)); + if (!h_mean) + { + continue; + } + + for (int iz = 1; iz <= h_mean->GetNbinsX(); ++iz) + { + const double entries = h2d->Integral(iz, iz, 1, h2d->GetNbinsY()); + if (entries > 0) + { + h_fit->SetBinContent(itile + 1, iz, h_mean->GetBinContent(iz)); + } + } + } + + // 2D piecewise fit: the eight tiles are fitted simultaneously with a shared + // slope and per-tile offsets. This eliminates the need for perfect + // translational TPOT alignment. + auto* fit2d = new TF2("fit2d_micromegas", fit_function_2d, 0, 8, -k_max_z, k_max_z, 9); + for (int i = 0; i < 9; ++i) + { + fit2d->SetParameter(i, 0.0); + } + h_fit->Fit(fit2d, "0RQ"); + + const double slope = fit2d->GetParameter(0); + const double slope_err = fit2d->GetParError(0); + const double new_drift = m_drift_velocity / (1.0 + slope); + const double drift_err = m_drift_velocity / std::pow(1.0 + slope, 2) * slope_err; + + std::cout << Name() << "::End" + << " slope=" << slope + << " input_drift=" << m_drift_velocity << " cm/ns" + << " new_drift=" << new_drift << " cm/ns +/- " << drift_err << " cm/ns" + << std::endl; + + // store fit results in the summary histogram + h_driftSummary->SetBinContent(1, slope); + h_driftSummary->SetBinContent(2, slope_err); + h_driftSummary->SetBinContent(4, new_drift); + h_driftSummary->SetBinContent(5, drift_err); + + delete fit2d; + delete h_fit; + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int MicromegasDriftQA::load_nodes(PHCompositeNode* topNode) +{ + m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); + if (!m_tGeometry) + { + std::cout << PHWHERE << " ActsGeometry node missing, abort." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_micromegas_geomcontainer = findNode::getClass(topNode, "CYLINDERGEOM_MICROMEGAS_FULL"); + if (!m_micromegas_geomcontainer) + { + std::cout << PHWHERE << " CYLINDERGEOM_MICROMEGAS_FULL node missing, abort." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_track_map = findNode::getClass(topNode, m_trackmapname); + if (!m_track_map) + { + std::cout << PHWHERE << " " << m_trackmapname << " node missing, abort." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + if (!m_cluster_map) + { + std::cout << PHWHERE << " TRKR_CLUSTER node missing, abort." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_globalPositionWrapper.loadNodes(topNode); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +std::string MicromegasDriftQA::getHistoPrefix() const +{ + // define prefix to all histos in HistoManager + return std::string("h_") + Name() + std::string("_"); +} + +//____________________________________________________________________________.. +void MicromegasDriftQA::createHistos() +{ + // initialize HistoManager + auto* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + // create and register histos in HistoManager + for (int itile = 0; itile < 8; itile++) + { + auto* h = new TH2F(std::format("{}ztrk_dz_{}", getHistoPrefix(), k_tile_names[itile]).c_str(), + std::format("{};z_{{track}} (cm);#Deltaz (track#minuscluster) (cm)", k_tile_names[itile]).c_str(), + k_nzbins, -k_max_z, k_max_z, 100, -k_max_dz, k_max_dz); + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}dz", getHistoPrefix()).c_str(), + ";#Deltaz (track#minuscluster) (cm);track states", 100, -k_max_dz, k_max_dz); + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}tile", getHistoPrefix()).c_str(), + ";tile;track states", 8, -0.5, 7.5); + for (int itile = 0; itile < 8; itile++) + { + h->GetXaxis()->SetBinLabel(itile + 1, k_tile_names[itile]); + } + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}ylocal", getHistoPrefix()).c_str(), + ";y_{local} (cm);track states", 100, -30, 30); + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}ntracks", getHistoPrefix()).c_str(), + ";matched track states per event;events", 20, -0.5, 19.5); + hm->registerHisto(h); + } + + { + // summary of the drift velocity fit performed in End() + auto* h = new TH1F(std::format("{}driftSummary", getHistoPrefix()).c_str(), + "drift velocity fit summary", 5, 0.5, 5.5); + h->GetXaxis()->SetBinLabel(1, "slope"); + h->GetXaxis()->SetBinLabel(2, "slope_err"); + h->GetXaxis()->SetBinLabel(3, "v_{in} (cm/ns)"); + h->GetXaxis()->SetBinLabel(4, "v_{new} (cm/ns)"); + h->GetXaxis()->SetBinLabel(5, "v_{new} err (cm/ns)"); + hm->registerHisto(h); + } +} \ No newline at end of file diff --git a/offline/QA/Tracking/MicromegasDriftQA.h b/offline/QA/Tracking/MicromegasDriftQA.h new file mode 100644 index 0000000000..c39176d774 --- /dev/null +++ b/offline/QA/Tracking/MicromegasDriftQA.h @@ -0,0 +1,118 @@ +#ifndef QA_TRACKING_MICROMEGASDRIFTQA_H +#define QA_TRACKING_MICROMEGASDRIFTQA_H + +/* + * Bade Sayki June 10th, 2026 -- LANL + * This QA module is created to monitor the calibration of the drift velocity in the TPC by fitting a helix to the clusters within a certain layer range, and projecting it to the TPOT z view module plane. The default layers in the TPC are set to be 39-55, which correspond to R3. + * This is heavily inspired by and distilled from Dr. Hugo Pereira Da Costa's MicromegasTrackEvaluator_hp module. It is meant to be a more lightweight and specialized version. + * If you have any questions, please feel free to message me on mattermost. + * Claude Code tool was used to format and debug this module + */ + +#include +#include + +#include + +class ActsGeometry; +class PHCompositeNode; +class PHG4CylinderGeomContainer; +class SvtxTrackMap; +class TrkrClusterContainer; +class TH1; +class TH2; + +class MicromegasDriftQA : public SubsysReco +{ + public: + explicit MicromegasDriftQA(const std::string& name = "MicromegasDriftQA"); + + ~MicromegasDriftQA() override = default; + + //! run initialization: load nodes, create and register histograms + int InitRun(PHCompositeNode* topNode) override; + + //! event processing: fill histograms + int process_event(PHCompositeNode* topNode) override; + + //! end of processing: fit accumulated distributions, fill summary histogram + int End(PHCompositeNode* topNode) override; + + //! track map name + void set_trackmapname(const std::string& value) { m_trackmapname = value; } + + //! initial drift velocity (cm/ns); starting point for the fit. Use the drift velocity used at reconstruction. + void set_drift_velocity(double value) { m_drift_velocity = value; } + + //! TPC layer range used for the helix fit (default: R3) + void set_min_tpc_layer(unsigned int value) { m_min_tpc_layer = value; } + void set_max_tpc_layer(unsigned int value) { m_max_tpc_layer = value; } + + //! reject track states near the tile edge (cm, local y) + void set_y_local_cut(double value) { m_y_local_cut = value; } + + //! search window to match a Micromegas cluster to the prediction (cm) + void set_z_search_window(double value) { m_z_search_win = value; } + + //! minimum entries per z slice required by FitSlicesY + void set_min_slice_entries(int value) { m_min_slice_entries = value; } + + private: + int load_nodes(PHCompositeNode* topNode); + + void createHistos(); + std::string getHistoPrefix() const; + + //!@name histograms (owned by the QA histogram manager) + //@{ + + //! z_track vs dz, one per z-view tile + TH2* h_ztrk_dz[8]{nullptr}; + + //! dz = z_track - z_cluster, all tiles + TH1* h_dz{nullptr}; + + //! matched track states per tile + TH1* h_tile{nullptr}; + + //! local y of the track state on the tile + TH1* h_ylocal{nullptr}; + + //! number of matched track states per event + TH1* h_ntracks{nullptr}; + + //! drift velocity fit summary, filled in End() + TH1* h_driftSummary{nullptr}; + + //@} + + //!@name nodes + //@{ + ActsGeometry* m_tGeometry{nullptr}; + TpcGlobalPositionWrapper m_globalPositionWrapper; + PHG4CylinderGeomContainer* m_micromegas_geomcontainer{nullptr}; + TrkrClusterContainer* m_cluster_map{nullptr}; + SvtxTrackMap* m_track_map{nullptr}; + //@} + + //! track map name + std::string m_trackmapname{"SvtxTrackMap"}; + + //! initial drift velocity (cm/ns) + double m_drift_velocity{0.00745}; + + //! TPC layer range used for the helix fit + unsigned int m_min_tpc_layer{39}; + unsigned int m_max_tpc_layer{55}; + + //! reject track states near the tile edge (cm) + double m_y_local_cut{22.0}; + + //! search window to match a Micromegas cluster to the prediction (cm) + double m_z_search_win{3.0}; + + //! minimum entries per z slice for FitSlicesY + int m_min_slice_entries{10}; +}; + +#endif // QA_TRACKING_MICROMEGASDRIFTQA_H diff --git a/offline/QA/Tracking/SiliconDriftQA.cc b/offline/QA/Tracking/SiliconDriftQA.cc new file mode 100644 index 0000000000..ab97edf4b1 --- /dev/null +++ b/offline/QA/Tracking/SiliconDriftQA.cc @@ -0,0 +1,338 @@ +#include "SiliconDriftQA.h" + +#include + +#include +#include + +#include +#include +#include // for PHWHERE + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace +{ + //! pt + template + T get_pt(const T& px, const T& py) + { + return std::sqrt(px * px + py * py); + } + + //! piecewise fit function used for the drift velocity extraction + // par[0] = constrained slope + // par[1] = offset for eta < 0 + // par[2] = offset for eta >= 0 + double fit_function_2d(double* x, double* par) + { + const int ieta = static_cast(std::floor(x[0])); + const double z = x[1]; + if (ieta < 0 || ieta > 1) + { + TF2::RejectPoint(); + return 0.; + } + return par[ieta + 1] + par[0] * z; + } + + //! suffixes used in histogram names for the two eta bins + const char* k_eta_suffix[2] = {"negeta", "poseta"}; + + //! number of z bins of the dz vs z histograms + constexpr int k_nzbins = 200; + +} // namespace + +//____________________________________________________________________________.. +SiliconDriftQA::SiliconDriftQA(const std::string& name) + : SubsysReco(name) +{ +} + +//____________________________________________________________________________.. +int SiliconDriftQA::InitRun(PHCompositeNode* /*topNode*/) +{ + createHistos(); + + // reference histograms initialized in header file to histos in HistoManager + auto* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + for (int ieta = 0; ieta < 2; ieta++) + { + h_zsi_dz[ieta] = dynamic_cast(hm->getHisto(std::format("{}zsi_dz_{}", getHistoPrefix(), k_eta_suffix[ieta]))); + } + h_dz = dynamic_cast(hm->getHisto(std::format("{}dz", getHistoPrefix()))); + h_ntracks = dynamic_cast(hm->getHisto(std::format("{}ntracks", getHistoPrefix()))); + h_driftSummary = dynamic_cast(hm->getHisto(std::format("{}driftSummary", getHistoPrefix()))); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int SiliconDriftQA::process_event(PHCompositeNode* topNode) +{ + auto* track_map = findNode::getClass(topNode, m_trackmapname); + if (!track_map) + { + std::cout << PHWHERE << " " << m_trackmapname << " node missing, abort." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + int naccepted = 0; + + for (const auto& [track_id, track] : *track_map) + { + // require valid beam-crossing + const auto crossing = track->get_crossing(); + if (crossing == SHRT_MAX) + { + if (Verbosity()) + { + std::cout << PHWHERE << " invalid crossing, track ignored." << std::endl; + } + continue; + } + + // require both seeds + const auto* si_seed = track->get_silicon_seed(); + const auto* tpc_seed = track->get_tpc_seed(); + if (!si_seed || !tpc_seed) + { + continue; + } + + // count clusters per subsystem + unsigned int n_tpc = 0; + unsigned int n_mvtx = 0; + unsigned int n_intt = 0; + + for (const auto* seed : {si_seed, tpc_seed}) + { + for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) + { + switch (TrkrDefs::getTrkrId(*it)) + { + case TrkrDefs::tpcId: + ++n_tpc; + break; + case TrkrDefs::mvtxId: + ++n_mvtx; + break; + case TrkrDefs::inttId: + ++n_intt; + break; + default: + break; + } + } + } + + // apply selection cuts + if (n_tpc < m_min_nclusters_tpc) + { + continue; + } + if (n_mvtx < m_min_nclusters_mvtx) + { + continue; + } + if (n_intt < m_min_nclusters_intt) + { + continue; + } + + const float eta = tpc_seed->get_eta(); + if (std::abs(eta) > m_max_eta) + { + continue; + } + + const float pt = get_pt(track->get_px(), track->get_py()); + if (pt < m_min_pt) + { + continue; + } + + // get seed z positions at POCA + const auto si_pos = TrackSeedHelper::get_xyz(si_seed); + const auto tpc_pos = TrackSeedHelper::get_xyz(tpc_seed); + + const float z_si = si_pos.z(); + const float z_tpc = tpc_pos.z(); + + // dz = (z_tpc + sign(eta)*crossing*crossing_interval*dv) - z_si + const double sign_eta = (eta >= 0) ? 1.0 : -1.0; + const float z_tpc_corr = z_tpc + sign_eta * crossing * m_crossing_interval * m_drift_velocity; + const float dz = z_tpc_corr - z_si; + + // fill histograms + const int ieta = (eta >= 0) ? 1 : 0; + h_zsi_dz[ieta]->Fill(z_si, dz); + h_dz->Fill(dz); + + ++naccepted; + } + + h_ntracks->Fill(naccepted); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int SiliconDriftQA::End(PHCompositeNode* /*topNode*/) +{ + if (!(h_zsi_dz[0] && h_zsi_dz[1] && h_driftSummary)) + { + std::cout << PHWHERE << " histograms not found, skipping drift velocity fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + const int nEntries = static_cast(h_zsi_dz[0]->GetEntries() + h_zsi_dz[1]->GetEntries()); + if (Verbosity()) + { + std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; + } + + // record input drift velocity even if the fit is skipped + h_driftSummary->SetBinContent(3, m_drift_velocity); + + if (nEntries < 2 * m_min_slice_entries) + { + std::cout << Name() << "::End - not enough entries (" << nEntries << "), skipping drift velocity fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + // build mean-dz TH2 via FitSlicesY, one eta bin at a time + // x = eta bin [0,2), y = z_si (cm), content = mean dz (cm) + auto* h_fit = new TH2F("h_fit_silicon", "", 2, 0, 2, k_nzbins, -m_max_z, m_max_z); + h_fit->SetDirectory(nullptr); + + for (int ieta = 0; ieta < 2; ++ieta) + { + auto* h2d = h_zsi_dz[ieta]; + + // fit vertical slices; require a minimum of m_min_slice_entries per slice + TObjArray slices; + slices.SetOwner(kTRUE); + h2d->FitSlicesY(nullptr, 0, -1, m_min_slice_entries, "QNR", &slices); + auto* h_mean = dynamic_cast(slices.At(1)); + if (!h_mean) + { + continue; + } + + for (int iz = 1; iz <= h_mean->GetNbinsX(); ++iz) + { + const double entries = h2d->Integral(iz, iz, 1, h2d->GetNbinsY()); + if (entries > 0) + { + h_fit->SetBinContent(ieta + 1, iz, h_mean->GetBinContent(iz)); + } + } + } + + // 2D piecewise fit: shared slope + per-eta offset + auto* fit2d = new TF2("fit2d_silicon", fit_function_2d, 0, 2, -m_max_z, m_max_z, 3); + for (int i = 0; i < 3; ++i) + { + fit2d->SetParameter(i, 0.0); + } + h_fit->Fit(fit2d, "0RQ"); + + const double slope = fit2d->GetParameter(0); + const double slope_err = fit2d->GetParError(0); + const double off_neg = fit2d->GetParameter(1); // ieta=0, eta<0 + const double off_pos = fit2d->GetParameter(2); // ieta=1, eta>=0 + + const double dv_new = m_drift_velocity / (1.0 + slope); + const double dv_err = m_drift_velocity / std::pow(1.0 + slope, 2) * slope_err; + const double t0_new = (off_pos - off_neg) / (2.0 * dv_new); + + std::cout << Name() << "::End" + << " slope=" << slope + << " dv_in=" << m_drift_velocity << " cm/ns" + << " dv_new=" << dv_new << " +/- " << dv_err << " cm/ns" + << " t0_new=" << t0_new << " ns" + << std::endl; + + // store fit results in the summary histogram + h_driftSummary->SetBinContent(1, slope); + h_driftSummary->SetBinContent(2, slope_err); + h_driftSummary->SetBinContent(4, dv_new); + h_driftSummary->SetBinContent(5, dv_err); + h_driftSummary->SetBinContent(6, t0_new); + + delete fit2d; + delete h_fit; + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +std::string SiliconDriftQA::getHistoPrefix() const +{ + // define prefix to all histos in HistoManager + return std::string("h_") + Name() + std::string("_"); +} + +//____________________________________________________________________________.. +void SiliconDriftQA::createHistos() +{ + // initialize HistoManager + auto* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + // create and register histos in HistoManager + for (int ieta = 0; ieta < 2; ieta++) + { + auto* h = new TH2F(std::format("{}zsi_dz_{}", getHistoPrefix(), k_eta_suffix[ieta]).c_str(), + std::format("{};z_{{silicon}} (cm);#Deltaz_{{TPC-silicon}} (cm)", + (ieta == 0 ? "#eta_{TPC} < 0" : "#eta_{TPC} #geq 0")) + .c_str(), + k_nzbins, -m_max_z, m_max_z, 200, -m_max_dz, m_max_dz); + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}dz", getHistoPrefix()).c_str(), + ";#Deltaz_{TPC-silicon} (cm);tracks", 200, -m_max_dz, m_max_dz); + hm->registerHisto(h); + } + + { + auto* h = new TH1F(std::format("{}ntracks", getHistoPrefix()).c_str(), + ";accepted tracks per event;events", 50, -0.5, 49.5); + hm->registerHisto(h); + } + + { + // summary of the drift velocity fit performed in End() + auto* h = new TH1F(std::format("{}driftSummary", getHistoPrefix()).c_str(), + "drift velocity fit summary", 6, 0.5, 6.5); + h->GetXaxis()->SetBinLabel(1, "slope"); + h->GetXaxis()->SetBinLabel(2, "slope_err"); + h->GetXaxis()->SetBinLabel(3, "v_{in} (cm/ns)"); + h->GetXaxis()->SetBinLabel(4, "v_{new} (cm/ns)"); + h->GetXaxis()->SetBinLabel(5, "v_{new} err (cm/ns)"); + h->GetXaxis()->SetBinLabel(6, "t_{0} (ns)"); + hm->registerHisto(h); + } +} \ No newline at end of file diff --git a/offline/QA/Tracking/SiliconDriftQA.h b/offline/QA/Tracking/SiliconDriftQA.h new file mode 100644 index 0000000000..ab851a2278 --- /dev/null +++ b/offline/QA/Tracking/SiliconDriftQA.h @@ -0,0 +1,119 @@ +#ifndef QA_TRACKING_SILICONDRIFTQA_H +#define QA_TRACKING_SILICONDRIFTQA_H + +/* + * QA version of SiliconDriftEvaluator (B. Sayki, LANL). + * + * Monitors the TPC drift velocity calibration by comparing the z position of + * the TPC seed and the silicon seed at the beam line, following the standard + * sPHENIX QA module conventions + * Claude code was used in formatting and debugging of this module + * v_new = v_in / (1 + slope) + * t0 = (offset_pos - offset_neg) / (2 v_new) + */ + +#include + +#include + +class PHCompositeNode; +class TH1; +class TH2; + +class SiliconDriftQA : public SubsysReco +{ + public: + explicit SiliconDriftQA(const std::string& name = "SiliconDriftQA"); + + ~SiliconDriftQA() override = default; + + //! run initialization: create and register histograms + int InitRun(PHCompositeNode* topNode) override; + + //! event processing: fill histograms + int process_event(PHCompositeNode* topNode) override; + + //! end of processing: fit accumulated distributions, fill summary histogram + int End(PHCompositeNode* topNode) override; + + //! track map name + void set_trackmapname(const std::string& value) { m_trackmapname = value; } + + //! initial drift velocity (cm/ns); starting point for the fit and used in the crossing correction + void set_drift_velocity(double value) { m_drift_velocity = value; } + + //! bunch-crossing interval in ns (default: 106.65237 ns) + void set_crossing_interval(double value) { m_crossing_interval = value; } + + //! minimum pT cut on tracks (GeV) + void set_min_pt(double value) { m_min_pt = value; } + + //! minimum number of TPC clusters required + void set_min_nclusters_tpc(unsigned int value) { m_min_nclusters_tpc = value; } + + //! minimum number of MVTX clusters required + void set_min_nclusters_mvtx(unsigned int value) { m_min_nclusters_mvtx = value; } + + //! minimum number of INTT clusters required + void set_min_nclusters_intt(unsigned int value) { m_min_nclusters_intt = value; } + + //! maximum abs(eta) of TPC seed accepted + void set_max_eta(double value) { m_max_eta = value; } + + //! half-range of the z_si histogram axis (cm) + void set_max_z(double value) { m_max_z = value; } + + //! half-range of the dz histogram axis (cm) + void set_max_dz(double value) { m_max_dz = value; } + + //! minimum entries per z slice required by FitSlicesY + void set_min_slice_entries(int value) { m_min_slice_entries = value; } + + private: + void createHistos(); + std::string getHistoPrefix() const; + + //!@name histograms (owned by the QA histogram manager) + //@{ + + //! z_si vs dz, one per eta bin (0: eta<0, 1: eta>=0) + TH2* h_zsi_dz[2]{nullptr, nullptr}; + + //! crossing-corrected dz = z_tpc_corr - z_si (cm) + TH1* h_dz{nullptr}; + + //! number of accepted tracks per event + TH1* h_ntracks{nullptr}; + + //! drift velocity fit summary, filled in End() + TH1* h_driftSummary{nullptr}; + + //@} + + //! track map name + std::string m_trackmapname{"SvtxTrackMap"}; + + //! initial drift velocity (cm/ns) + double m_drift_velocity{0.00749}; + + //! bunch-crossing interval (ns) + double m_crossing_interval{106.65237}; + + //!@name track selection cuts + //@{ + double m_min_pt{0.5}; + unsigned int m_min_nclusters_tpc{20}; + unsigned int m_min_nclusters_mvtx{3}; + unsigned int m_min_nclusters_intt{2}; + double m_max_eta{0.9}; + //@} + + //! histogram ranges + double m_max_z{20.0}; + double m_max_dz{10.0}; + + //! minimum entries per z slice for FitSlicesY + int m_min_slice_entries{10}; +}; + +#endif // QA_TRACKING_SILICONDRIFTQA_H \ No newline at end of file diff --git a/offline/QA/Tracking/SiliconSeedsQA.cc b/offline/QA/Tracking/SiliconSeedsQA.cc index 14a9feeaed..6f2ba5e91a 100644 --- a/offline/QA/Tracking/SiliconSeedsQA.cc +++ b/offline/QA/Tracking/SiliconSeedsQA.cc @@ -233,7 +233,7 @@ void SiliconSeedsQA::createHistos() } { - h_ntrack1d = new TH1F(std::string(getHistoPrefix() + "nrecotracks1d").c_str(), "Number of reconstructed tracks;Number of silicon tracklets;Entries", 50, 0, 200); + h_ntrack1d = new TH1F(std::string(getHistoPrefix() + "nrecotracks1d").c_str(), "Number of reconstructed tracks;Number of silicon tracklets;Entries", 500, 0, 2000); hm->registerHisto(h_ntrack1d); } @@ -248,7 +248,7 @@ void SiliconSeedsQA::createHistos() } { - h_trackcrossing = new TH1F(std::string(getHistoPrefix() + "trackcrossing").c_str(), "Track beam bunch crossing;Track crossing;Entries", 110, -10, 100); + h_trackcrossing = new TH1F(std::string(getHistoPrefix() + "trackcrossing").c_str(), "Track beam bunch crossing;Track crossing;Entries", 1000, -200, 800); hm->registerHisto(h_trackcrossing); } @@ -304,7 +304,7 @@ void SiliconSeedsQA::createHistos() // vertex { - h_nvertex = new TH1F(std::string(getHistoPrefix() + "nrecovertices").c_str(), "Num of reco vertices per event;Number of vertices;Entries", 20, 0, 20); + h_nvertex = new TH1F(std::string(getHistoPrefix() + "nrecovertices").c_str(), "Num of reco vertices per event;Number of vertices;Entries", 60, 0, 60); hm->registerHisto(h_nvertex); } diff --git a/offline/QA/Tracking/StateClusterResidualsQA.cc b/offline/QA/Tracking/StateClusterResidualsQA.cc new file mode 100644 index 0000000000..d2239ede5d --- /dev/null +++ b/offline/QA/Tracking/StateClusterResidualsQA.cc @@ -0,0 +1,400 @@ +#include "StateClusterResidualsQA.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +namespace +{ + template + inline T square (T const& t) { return t * t; } + + template + class range_adaptor + { + public: + explicit range_adaptor( + T const& begin, + T const& end) + : m_begin(begin) + , m_end(end) + { + } + T const& begin() { return m_begin; } + T const& end() { return m_end; } + + private: + T m_begin; + T m_end; + }; +} // namespace + +StateClusterResidualsQA::StateClusterResidualsQA(const std::string& name) + : SubsysReco(name) +{ +} + +int StateClusterResidualsQA::InitRun( + PHCompositeNode* top_node) +{ + createHistos(); + + // F4A will not actually ABORTRUN unless that return code is issued here + auto* track_map = findNode::getClass(top_node, m_track_map_node_name); + if (!track_map) + { + std::cout + << PHWHERE << "\n" + << "\tCould not get track map:\n" + << "\t\"" << m_track_map_node_name << "\"\n" + << "\tAborting\n" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + auto* cluster_map = findNode::getClass(top_node, m_clusterContainerName); + if (!cluster_map) + { + std::cout + << PHWHERE << "\n" + << "\tCould not get cluster map:\n" + << "\t\"" << m_clusterContainerName << "\"\n" + << "\tAborting\n" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + auto *geometry = findNode::getClass(top_node, "ActsGeometry"); + if (!geometry) + { + std::cout + << PHWHERE << "\n" + << "\tCould not get ActsGeometry:\n" + << "\t\"" << "ActsGeometry" << "\"\n" + << "\tAborting\n" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + auto* hm = QAHistManagerDef::getHistoManager(); + if (!hm) + { + std::cout + << PHWHERE << "\n" + << "\tCould not get QAHistManager\n" + << "\tAborting\n" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + for (const auto& cfg : m_pending) + { + if (m_use_local_coords) + { + m_histograms_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_rphi")))); + m_histograms_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_z")))); + m_histograms_layer_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_layer_rphi")))); + m_histograms_layer_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_layer_z")))); + m_histograms_phi_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_phi_rphi")))); + m_histograms_phi_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_phi_z")))); + m_histograms_eta_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_eta_rphi")))); + m_histograms_eta_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_local_eta_z")))); + } + else + { + m_histograms_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_x")))); + m_histograms_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_y")))); + m_histograms_z.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_z")))); + m_histograms_layer_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_layer_x")))); + m_histograms_layer_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_layer_y")))); + m_histograms_layer_z.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_layer_z")))); + m_histograms_phi_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_phi_x")))); + m_histograms_phi_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_phi_y")))); + m_histograms_phi_z.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_phi_z")))); + m_histograms_eta_x.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_eta_x")))); + m_histograms_eta_y.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_eta_y")))); + m_histograms_eta_z.push_back(dynamic_cast(hm->getHisto(std::string(cfg.name + "_eta_z")))); + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int StateClusterResidualsQA::process_event(PHCompositeNode* top_node) +{ + auto* track_map = findNode::getClass(top_node, m_track_map_node_name); + auto *cluster_map = findNode::getClass(top_node, m_clusterContainerName); + auto *geometry = findNode::getClass(top_node, "ActsGeometry"); + + for (auto const& [idkey, track] : *track_map) + { + if (!track) + { + continue; + } + + // count states + std::map counters = { + {TrkrDefs::mvtxId, 0}, + {TrkrDefs::inttId, 0}, + {TrkrDefs::tpcId, 0}, + {TrkrDefs::micromegasId, 0}, + }; + + for (auto const& [path_length, state] : range_adaptor(track->begin_states(), track->end_states())) + { + // There is an additional state representing the vertex at the beginning of the map, + // but getTrkrId will return 0 for its corresponding cluster + // Identify it as having path_length identically equal to 0 + if (path_length == 0) { continue; } + + auto trkr_id = static_cast(TrkrDefs::getTrkrId(state->get_cluskey())); + auto itr = counters.find(trkr_id); + if (itr == counters.end()) { continue; } + ++itr->second; + } + + float track_eta = track->get_eta(); + float track_phi = track->get_phi(); + float track_pt = track->get_pt(); + int h = 0; + for (const auto& cfg : m_pending) + { + if (cfg.charge != 0) + { + if ((cfg.charge < 0) && track->get_positive_charge()) + { + continue; + } + if ((cfg.charge > 0) && !(track->get_positive_charge())) + { + continue; + } + } + if (cfg.min_mvtx_clusters <= counters[TrkrDefs::mvtxId] && cfg.max_mvtx_clusters >= counters[TrkrDefs::mvtxId] + && cfg.min_intt_clusters <= counters[TrkrDefs::inttId] && cfg.max_intt_clusters >= counters[TrkrDefs::inttId] + && cfg.min_tpc_clusters <= counters[TrkrDefs::tpcId] && cfg.max_tpc_clusters >= counters[TrkrDefs::tpcId] + && cfg.phi_min <= track_phi && cfg.phi_max >= track_phi + && cfg.eta_min <= track_eta && cfg.eta_max >= track_eta + && cfg.pt_min <= track_pt && cfg.pt_max >= track_pt) + { + for (auto const& [path_length, state] : range_adaptor(track->begin_states(), track->end_states())) + { + if (path_length == 0) { continue; } + + auto *cluster = cluster_map->findCluster(state->get_cluskey()); + if (!cluster) + { + continue; + } + + float state_x; + float state_y; + float state_z; + float cluster_x; + float cluster_y; + float cluster_z; + if (m_use_local_coords == true) + { + state_x = state->get_localX(); + state_y = state->get_localY(); + Acts::Vector2 loc = geometry->getLocalCoords(state->get_cluskey(), cluster); + cluster_x = loc.x(); + cluster_y = loc.y(); + m_histograms_x[h]->Fill(state_x - cluster_x); + m_histograms_y[h]->Fill(state_y - cluster_y); + m_histograms_layer_x[h]->Fill(TrkrDefs::getLayer(state->get_cluskey()), state_x - cluster_x); + m_histograms_layer_y[h]->Fill(TrkrDefs::getLayer(state->get_cluskey()), state_y - cluster_y); + m_histograms_phi_x[h]->Fill(state->get_phi(), state_x - cluster_x); + m_histograms_phi_y[h]->Fill(state->get_phi(), state_y - cluster_y); + m_histograms_eta_x[h]->Fill(state->get_eta(), state_x - cluster_x); + m_histograms_eta_y[h]->Fill(state->get_eta(), state_y - cluster_y); + } + else + { + state_x = state->get_x(); + state_y = state->get_y(); + state_z = state->get_z(); + Acts::Vector3 glob = geometry->getGlobalPosition(state->get_cluskey(), cluster); + cluster_x = glob.x(); + cluster_y = glob.y(); + cluster_z = glob.z(); + m_histograms_x[h]->Fill(state_x - cluster_x); + m_histograms_y[h]->Fill(state_y - cluster_y); + m_histograms_z[h]->Fill(state_z - cluster_z); + m_histograms_layer_x[h]->Fill(TrkrDefs::getLayer(state->get_cluskey()), state_x - cluster_x); + m_histograms_layer_y[h]->Fill(TrkrDefs::getLayer(state->get_cluskey()), state_y - cluster_y); + m_histograms_layer_z[h]->Fill(TrkrDefs::getLayer(state->get_cluskey()), state_z - cluster_z); + m_histograms_phi_x[h]->Fill(state->get_phi(), state_x - cluster_x); + m_histograms_phi_y[h]->Fill(state->get_phi(), state_y - cluster_y); + m_histograms_phi_z[h]->Fill(state->get_phi(), state_z - cluster_z); + m_histograms_eta_x[h]->Fill(state->get_eta(), state_x - cluster_x); + m_histograms_eta_y[h]->Fill(state->get_eta(), state_y - cluster_y); + m_histograms_eta_z[h]->Fill(state->get_eta(), state_z - cluster_z); + } + } + } + ++h; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +void StateClusterResidualsQA::createHistos() +{ + auto *hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + for (const auto& cfg : m_pending) + { + if (m_use_local_coords) + { + TH1F* h_new_x = new TH1F( + (cfg.name + "_local_rphi").c_str(), + ";State-Cluster Local r#phi Residual [cm];Entries", + m_nBins, cfg.rphi_local_lower, cfg.rphi_local_upper); + h_new_x->SetMarkerColor(kBlue); + h_new_x->SetLineColor(kBlue); + hm->registerHisto(h_new_x); + TH1F* h_new_y = new TH1F( + (cfg.name + "_local_z").c_str(), + ";State-Cluster Local Z Residual [cm];Entries", + m_nBins, cfg.z_local_lower, cfg.z_local_upper); + h_new_y->SetMarkerColor(kBlue); + h_new_y->SetLineColor(kBlue); + hm->registerHisto(h_new_y); + TH2F* h_new_layer_x = new TH2F( + (cfg.name + "_local_layer_rphi").c_str(), + ";Layer Number;State-Cluster Local r#phi Residual [cm]", + 60, -0.5, 59.5, m_nBins, cfg.rphi_local_lower, cfg.rphi_local_upper); + hm->registerHisto(h_new_layer_x); + TH2F* h_new_layer_y = new TH2F( + (cfg.name + "_local_layer_z").c_str(), + ";Layer Number;State-Cluster Local Z Residual [cm]", + 60, -0.5, 59.5, m_nBins, cfg.z_local_lower, cfg.z_local_upper); + hm->registerHisto(h_new_layer_y); + TH2F* h_new_phi_x = new TH2F( + (cfg.name + "_local_phi_rphi").c_str(), + ";#phi [rad];State-Cluster Local r#phi Residual [cm]", + 50, -3.2, 3.2, m_nBins, cfg.rphi_local_lower, cfg.rphi_local_upper); + hm->registerHisto(h_new_phi_x); + TH2F* h_new_phi_y = new TH2F( + (cfg.name + "_local_phi_z").c_str(), + ";#phi [rad];State-Cluster Local Z Residual [cm]", + 50, -3.2, 3.2, m_nBins, cfg.z_local_lower, cfg.z_local_upper); + hm->registerHisto(h_new_phi_y); + TH2F* h_new_eta_x = new TH2F( + (cfg.name + "_local_eta_rphi").c_str(), + ";#eta;State-Cluster Local r#phi Residual [cm]", + 50, -1.1, 1.1, m_nBins, cfg.rphi_local_lower, cfg.rphi_local_upper); + hm->registerHisto(h_new_eta_x); + TH2F* h_new_eta_y = new TH2F( + (cfg.name + "_local_eta_z").c_str(), + ";#eta;State-Cluster Local Z Residual [cm]", + 50, -1.1, 1.1, m_nBins, cfg.z_local_lower, cfg.z_local_upper); + hm->registerHisto(h_new_eta_y); + } + else + { + TH1F* h_new_x = new TH1F( + (cfg.name + "_x").c_str(), + ";State-Cluster X Residual [cm];Entries", + m_nBins, cfg.x_lower, cfg.x_upper); + h_new_x->SetMarkerColor(kBlue); + h_new_x->SetLineColor(kBlue); + hm->registerHisto(h_new_x); + TH1F* h_new_y = new TH1F( + (cfg.name + "_y").c_str(), + ";State-Cluster Y Residual [cm];Entries", + m_nBins, cfg.y_lower, cfg.y_upper); + h_new_y->SetMarkerColor(kBlue); + h_new_y->SetLineColor(kBlue); + hm->registerHisto(h_new_y); + TH1F* h_new_z = new TH1F( + (cfg.name + "_z").c_str(), + ";State-Cluster Z Residual [cm];Entries", + m_nBins, cfg.z_lower, cfg.z_upper); + h_new_z->SetMarkerColor(kBlue); + h_new_z->SetLineColor(kBlue); + hm->registerHisto(h_new_z); + TH2F* h_new_layer_x = new TH2F( + (cfg.name + "_layer_x").c_str(), + ";Layer Number;State-Cluster Local X Residual [cm]", + 60, -0.5, 59.5, m_nBins, cfg.x_lower, cfg.x_upper); + hm->registerHisto(h_new_layer_x); + TH2F* h_new_layer_y = new TH2F( + (cfg.name + "_layer_y").c_str(), + ";Layer Number;State-Cluster Local Y Residual [cm]", + 60, -0.5, 59.5, m_nBins, cfg.y_lower, cfg.y_upper); + hm->registerHisto(h_new_layer_y); + TH2F* h_new_layer_z = new TH2F( + (cfg.name + "_layer_z").c_str(), + ";Layer Number;State-Cluster Local Z Residual [cm]", + 60, -0.5, 59.5, m_nBins, cfg.z_lower, cfg.z_upper); + hm->registerHisto(h_new_layer_z); + TH2F* h_new_phi_x = new TH2F( + (cfg.name + "_phi_x").c_str(), + ";#phi [rad];State-Cluster Local X Residual [cm]", + 50, -3.2, 3.2, m_nBins, cfg.x_lower, cfg.x_upper); + hm->registerHisto(h_new_phi_x); + TH2F* h_new_phi_y = new TH2F( + (cfg.name + "_phi_y").c_str(), + ";#phi [rad];State-Cluster Local Y Residual [cm]", + 50, -3.2, 3.2, m_nBins, cfg.y_lower, cfg.y_upper); + hm->registerHisto(h_new_phi_y); + TH2F* h_new_phi_z = new TH2F( + (cfg.name + "_phi_z").c_str(), + ";#phi [rad];State-Cluster Local Z Residual [cm]", + 50, -3.2, 3.2, m_nBins, cfg.z_lower, cfg.z_upper); + hm->registerHisto(h_new_phi_z); + TH2F* h_new_eta_x = new TH2F( + (cfg.name + "_eta_x").c_str(), + ";#eta;State-Cluster Local X Residual [cm]", + 50, -1.1, 1.1, m_nBins, cfg.x_lower, cfg.x_upper); + hm->registerHisto(h_new_eta_x); + TH2F* h_new_eta_y = new TH2F( + (cfg.name + "_eta_y").c_str(), + ";#eta;State-Cluster Local Y Residual [cm]", + 50, -1.1, 1.1, m_nBins, cfg.y_lower, cfg.y_upper); + hm->registerHisto(h_new_eta_y); + TH2F* h_new_eta_z = new TH2F( + (cfg.name + "_eta_z").c_str(), + ";#eta;State-Cluster Local Z Residual [cm]", + 50, -1.1, 1.1, m_nBins, cfg.z_lower, cfg.z_upper); + hm->registerHisto(h_new_eta_z); + } + } +} + +int StateClusterResidualsQA::EndRun(const int /*unused*/) +{ + auto *hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/QA/Tracking/StateClusterResidualsQA.h b/offline/QA/Tracking/StateClusterResidualsQA.h new file mode 100644 index 0000000000..587178ef9b --- /dev/null +++ b/offline/QA/Tracking/StateClusterResidualsQA.h @@ -0,0 +1,181 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef STATECLUSTERRESIDUALSQA_H +#define STATECLUSTERRESIDUALSQA_H + +#include + +#include +#include +#include +#include +#include + +class PHCompositeNode; +class TH1; +class TH2; + +struct ResidualHistConfig +{ + std::string name = "h_StateClusterResidualsQA_"; + std::string title = ";Residual [cm];Entries"; + + int min_mvtx_clusters = 0; + int max_mvtx_clusters = 3; + int min_intt_clusters = 0; + int max_intt_clusters = 4; + int min_tpc_clusters = 0; + int max_tpc_clusters = 48; + + float phi_min = -M_PI; + float phi_max = M_PI; + float eta_min = -1.1; + float eta_max = 1.1; + + float pt_min = 0.0; + float pt_max = FLT_MAX; + + int charge = 0; + + float rphi_local_lower = -0.5; + float rphi_local_upper = 0.5; + float z_local_lower = -0.5; + float z_local_upper = 0.5; + float x_lower = -0.5; + float x_upper = 0.5; + float y_lower = -0.5; + float y_upper = 0.5; + float z_lower = -0.5; + float z_upper = 0.5; +}; + +class StateClusterResidualsQA : public SubsysReco +{ + public: + StateClusterResidualsQA(const std::string& name = "StateClusterResidualsQA"); + ~StateClusterResidualsQA() override = default; + + /// sets the name of node to retrieve the track map from (default member value is "SvtxTrackMap") + void set_track_map_name(std::string const& track_map_node_name) { m_track_map_node_name = track_map_node_name; } + + StateClusterResidualsQA& addHistogram(const std::string& name) + { + ResidualHistConfig cfg; + cfg.name += name; + m_pending.push_back(cfg); + return *this; + } + StateClusterResidualsQA& setNMvtx(int min, int max) + { + m_pending.back().min_mvtx_clusters = min; + m_pending.back().max_mvtx_clusters = max; + return *this; + } + StateClusterResidualsQA& setNIntt(int min, int max) + { + m_pending.back().min_intt_clusters = min; + m_pending.back().max_intt_clusters = max; + return *this; + } + StateClusterResidualsQA& setNTpc(int min, int max) + { + m_pending.back().min_tpc_clusters = min; + m_pending.back().max_tpc_clusters = max; + return *this; + } + StateClusterResidualsQA& setPhiRange(float min, float max) + { + m_pending.back().phi_min = min; + m_pending.back().phi_max = max; + return *this; + } + StateClusterResidualsQA& setEtaRange(float min, float max) + { + m_pending.back().eta_min = min; + m_pending.back().eta_max = max; + return *this; + } + StateClusterResidualsQA& setPtRange(float min, float max) + { + m_pending.back().pt_min = min; + m_pending.back().pt_max = max; + return *this; + } + StateClusterResidualsQA& setXRange(float min, float max) + { + m_pending.back().x_lower = min; + m_pending.back().x_upper = max; + return *this; + } + StateClusterResidualsQA& setYRange(float min, float max) + { + m_pending.back().y_lower = min; + m_pending.back().y_upper = max; + return *this; + } + StateClusterResidualsQA& setZRange(float min, float max) + { + m_pending.back().z_lower = min; + m_pending.back().z_upper = max; + return *this; + } + StateClusterResidualsQA& setLocalRphiRange(float min, float max) + { + m_pending.back().rphi_local_lower = min; + m_pending.back().rphi_local_upper = max; + return *this; + } + StateClusterResidualsQA& setLocalZRange(float min, float max) + { + m_pending.back().z_local_lower = min; + m_pending.back().z_local_upper = max; + return *this; + } + StateClusterResidualsQA& setPositiveTracks() + { + m_pending.back().charge = 1; + return *this; + } + StateClusterResidualsQA& setNegativeTracks() + { + m_pending.back().charge = -1; + return *this; + } + + void setUseLocalCoords() + { + m_use_local_coords = true; + } + + void createHistos(); + + int InitRun(PHCompositeNode*) override; + + int process_event(PHCompositeNode*) override; + + int EndRun(const int runnumber) override; + + private: + std::vector m_pending; + + std::string m_track_map_node_name = "SvtxTrackMap"; + std::string m_clusterContainerName = "TRKR_CLUSTER"; + + int m_nBins = 50; + bool m_use_local_coords = false; + + std::vector m_histograms_x{}; + std::vector m_histograms_y{}; + std::vector m_histograms_z{}; + std::vector m_histograms_layer_x{}; + std::vector m_histograms_layer_y{}; + std::vector m_histograms_layer_z{}; + std::vector m_histograms_phi_x{}; + std::vector m_histograms_phi_y{}; + std::vector m_histograms_phi_z{}; + std::vector m_histograms_eta_x{}; + std::vector m_histograms_eta_y{}; + std::vector m_histograms_eta_z{}; +}; + +#endif // TRACKFITTINGQA_H diff --git a/offline/QA/Tracking/TpcSeedsQA.cc b/offline/QA/Tracking/TpcSeedsQA.cc index dc78d7d51c..3a23895c18 100644 --- a/offline/QA/Tracking/TpcSeedsQA.cc +++ b/offline/QA/Tracking/TpcSeedsQA.cc @@ -73,7 +73,7 @@ int TpcSeedsQA::InitRun(PHCompositeNode *topNode) // global position wrapper m_globalPositionWrapper.loadNodes(topNode); - m_clusterMover.initialize_geometry(g4geom); + m_clusterMover.initialize_geometry(g4geom, actsgeom); m_clusterMover.set_verbosity(0); auto *hm = QAHistManagerDef::getHistoManager(); diff --git a/offline/database/PHParameter/PHParameters.cc b/offline/database/PHParameter/PHParameters.cc index 1f8fea5f14..5357ce9c4c 100644 --- a/offline/database/PHParameter/PHParameters.cc +++ b/offline/database/PHParameter/PHParameters.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -384,7 +385,8 @@ int PHParameters::WriteToCDBFile(const std::string &filename) { PdbParameterMap *myparm = new PdbParameterMap(); CopyToPdbParameterMap(myparm); - TFile *f = TFile::Open(filename.c_str(), "recreate"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(filename); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); myparm->Write(); delete f; delete myparm; @@ -416,7 +418,8 @@ int PHParameters::WriteToFile(const std::string &extension, const std::string &d PdbParameterMap *myparm = new PdbParameterMap(); CopyToPdbParameterMap(myparm); - TFile *f = TFile::Open(fullpath.str().c_str(), "recreate"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(fullpath.str()); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); // force xml file writing to use extended precision shown experimentally // to not modify input parameters (.17g) std::string floatformat = TBufferXML::GetFloatFormat(); diff --git a/offline/database/PHParameter/PHParametersContainer.cc b/offline/database/PHParameter/PHParametersContainer.cc index dbe5e0f633..6899838380 100644 --- a/offline/database/PHParameter/PHParametersContainer.cc +++ b/offline/database/PHParameter/PHParametersContainer.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -148,7 +149,8 @@ int PHParametersContainer::WriteToFile(const std::string &extension, const std:: PdbParameterMapContainer *myparm = new PdbParameterMapContainer(); CopyToPdbParameterMapContainer(myparm); - TFile *f = TFile::Open(fullpath.str().c_str(), "recreate"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(fullpath.str()); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); // force xml file writing to use extended precision shown experimentally // to not modify input parameters (.15e) std::string floatformat = TBufferXML::GetFloatFormat(); diff --git a/offline/database/cdbobjects/CDBHistos.cc b/offline/database/cdbobjects/CDBHistos.cc index 2fcf5a1bad..0776fa0b47 100644 --- a/offline/database/cdbobjects/CDBHistos.cc +++ b/offline/database/cdbobjects/CDBHistos.cc @@ -1,5 +1,7 @@ #include "CDBHistos.h" +#include + #include // for TClass #include // for TIter #include // for TDirectoryAtomicAdapter, TDirectory, gDirec... @@ -36,7 +38,8 @@ void CDBHistos::WriteCDBHistos() return; } std::string currdir = gDirectory->GetPath(); - TFile *f = TFile::Open(m_Filename.c_str(), "RECREATE"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(m_Filename); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); for (auto &iter : m_HistoMap) { iter.second->Write(); diff --git a/offline/database/cdbobjects/CDBTF.cc b/offline/database/cdbobjects/CDBTF.cc index b80a63666f..6b80c825f3 100644 --- a/offline/database/cdbobjects/CDBTF.cc +++ b/offline/database/cdbobjects/CDBTF.cc @@ -1,5 +1,7 @@ #include "CDBTF.h" +#include + #include // for TClass #include // for TIter #include // for TDirectoryAtomicAdapter, TDirectory, gDirec... @@ -36,7 +38,8 @@ void CDBTF::WriteCDBTF() return; } std::string currdir = gDirectory->GetPath(); - TFile *f = TFile::Open(m_Filename.c_str(), "RECREATE"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(m_Filename); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); for (auto &iter : m_TFMap) { iter.second->Write(); diff --git a/offline/database/cdbobjects/CDBTTree.cc b/offline/database/cdbobjects/CDBTTree.cc index 6889dfacb1..20cd10f399 100644 --- a/offline/database/cdbobjects/CDBTTree.cc +++ b/offline/database/cdbobjects/CDBTTree.cc @@ -1,5 +1,6 @@ #include "CDBTTree.h" +#include #include #include // for TBranch @@ -230,7 +231,7 @@ void CDBTTree::WriteMultipleCDBTTree() void CDBTTree::SetSingleFloatValue(const std::string &name, float value) { std::string fieldname = "F" + name; -// if (!m_SingleFloatEntryMap.contains(fieldname)) + // if (!m_SingleFloatEntryMap.contains(fieldname)) // NOLINTNEXTLINE(readability-container-contains) if (m_SingleFloatEntryMap.find(fieldname) == m_SingleFloatEntryMap.end()) { @@ -249,7 +250,7 @@ void CDBTTree::SetSingleFloatValue(const std::string &name, float value) void CDBTTree::SetSingleDoubleValue(const std::string &name, double value) { std::string fieldname = "D" + name; -// if (!m_SingleDoubleEntryMap.contains(fieldname)) + // if (!m_SingleDoubleEntryMap.contains(fieldname)) // NOLINTNEXTLINE(readability-container-contains) if (m_SingleDoubleEntryMap.find(fieldname) == m_SingleDoubleEntryMap.end()) { @@ -268,7 +269,7 @@ void CDBTTree::SetSingleDoubleValue(const std::string &name, double value) void CDBTTree::SetSingleIntValue(const std::string &name, int value) { std::string fieldname = "I" + name; -// if (!m_SingleIntEntryMap.contains(fieldname)) + // if (!m_SingleIntEntryMap.contains(fieldname)) // NOLINTNEXTLINE(readability-container-contains) if (m_SingleIntEntryMap.find(fieldname) == m_SingleIntEntryMap.end()) { @@ -287,7 +288,7 @@ void CDBTTree::SetSingleIntValue(const std::string &name, int value) void CDBTTree::SetSingleUInt64Value(const std::string &name, uint64_t value) { std::string fieldname = "g" + name; -// if (m_SingleUInt64EntryMap.contains(fieldname)) + // if (!m_SingleUInt64EntryMap.contains(fieldname)) // NOLINTNEXTLINE(readability-container-contains) if (m_SingleUInt64EntryMap.find(fieldname) == m_SingleUInt64EntryMap.end()) { @@ -470,8 +471,8 @@ void CDBTTree::WriteCDBTTree() } std::string currdir = gDirectory->GetPath(); - - TFile *f = TFile::Open(m_Filename.c_str(), "RECREATE"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(m_Filename); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); if (!empty_single) { WriteSingleCDBTTree(); diff --git a/offline/database/cdbobjects/CDBTTree.h b/offline/database/cdbobjects/CDBTTree.h index 0db6719f71..bf04a83ea1 100644 --- a/offline/database/cdbobjects/CDBTTree.h +++ b/offline/database/cdbobjects/CDBTTree.h @@ -30,14 +30,22 @@ class CDBTTree void Print(); void SetFilename(const std::string &fname) { m_Filename = fname; } void LoadCalibrations(); + float GetSingleFloatValue(const std::string &name, int verbose = 0); float GetFloatValue(int channel, const std::string &name, int verbose = 0); + size_t GetFloatMapSize() const { return m_FloatEntryMap.size(); } + double GetSingleDoubleValue(const std::string &name, int verbose = 0); double GetDoubleValue(int channel, const std::string &name, int verbose = 0); + size_t GetDoubleMapSize() const { return m_DoubleEntryMap.size(); } + int GetSingleIntValue(const std::string &name, int verbose = 0); int GetIntValue(int channel, const std::string &name, int verbose = 0); + size_t GetIntMapSize() const { return m_IntEntryMap.size(); } + uint64_t GetSingleUInt64Value(const std::string &name, int verbose = 0); uint64_t GetUInt64Value(int channel, const std::string &name, int verbose = 0); + size_t GetUInt64MapSize() const { return m_UInt64EntryMap.size(); } const auto &GetFloatEntryMap() const { return m_FloatEntryMap; } const auto &GetDoubleEntryMap() const { return m_DoubleEntryMap; } diff --git a/offline/database/cdbobjects/Makefile.am b/offline/database/cdbobjects/Makefile.am index 5df1880ad3..d2922bbab0 100644 --- a/offline/database/cdbobjects/Makefile.am +++ b/offline/database/cdbobjects/Makefile.am @@ -15,6 +15,9 @@ libcdbobjects_la_SOURCES = \ CDBTTree.cc libcdbobjects_la_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -lphool \ `root-config --libs` ############################################## diff --git a/offline/database/pdbcal/base/PdbParameterMapContainer.cc b/offline/database/pdbcal/base/PdbParameterMapContainer.cc index 6d10797a60..abb4a2f7dc 100644 --- a/offline/database/pdbcal/base/PdbParameterMapContainer.cc +++ b/offline/database/pdbcal/base/PdbParameterMapContainer.cc @@ -3,6 +3,7 @@ #include "PdbParameterMap.h" #include +#include #include #include @@ -111,7 +112,8 @@ int PdbParameterMapContainer::WriteToFile(const std::string &detector_name, std::cout << "PdbParameterMapContainer::WriteToFile - save to " << fullpath.str() << std::endl; - TFile *f = TFile::Open(fullpath.str().c_str(), "recreate"); + std::string reproducible_TFile_name = PHUtils::CreateReproducibleTFileName(fullpath.str()); + TFile *f = TFile::Open(reproducible_TFile_name.c_str(), "RECREATE"); PdbParameterMapContainer *container = new PdbParameterMapContainer(); for (std::map::const_iterator it = diff --git a/offline/database/sphenixnpc/CDBUtils.cc b/offline/database/sphenixnpc/CDBUtils.cc index 080812b419..46737fe89a 100644 --- a/offline/database/sphenixnpc/CDBUtils.cc +++ b/offline/database/sphenixnpc/CDBUtils.cc @@ -12,12 +12,12 @@ #include // for pair, make_pair CDBUtils::CDBUtils() - : cdbclient(new SphenixClient()) + : cdbclient(std::make_unique()) { } CDBUtils::CDBUtils(const std::string &globaltag) - : cdbclient(new SphenixClient(globaltag)) + : cdbclient(std::make_unique(globaltag)) { } @@ -75,23 +75,39 @@ int CDBUtils::createPayloadType(const std::string &pt) return cdbclient->createDomain(pt); } -void CDBUtils::listPayloadIOVs(uint64_t iov) +std::map> CDBUtils::PayloadIOVs(uint64_t iov, const std::string &ptype) { + std::map> iovs; nlohmann::json resp = cdbclient->getPayloadIOVs(iov); if (resp["code"] != 0) { std::cout << resp["msg"] << std::endl; - return; + return iovs; } nlohmann::json payload_iovs = resp["msg"]; - std::map> iovs; - for (auto &[pt, val] : payload_iovs.items()) + for (const auto &[pt, val] : payload_iovs.items()) { std::string url = val["payload_url"]; uint64_t bts = val["minor_iov_start"]; uint64_t ets = val["minor_iov_end"]; - iovs.insert(std::make_pair(pt, std::make_tuple(url, bts, ets))); + if (ets > iov) + { + if (!ptype.empty()) + { + if (pt.find(ptype) == std::string::npos) + { + continue; + } + } + iovs.insert(std::make_pair(pt, std::make_tuple(url, bts, ets))); + } } + return iovs; +} + +void CDBUtils::listPayloadIOVs(uint64_t iov, const std::string &ptype) +{ + auto iovs = PayloadIOVs(iov, ptype); for (const auto &it : iovs) { std::cout << it.first << ": " << std::get<0>(it.second) @@ -107,7 +123,7 @@ int CDBUtils::cloneGlobalTag(const std::string &source, const std::string &targe nlohmann::json resp = cdbclient->getGlobalTags(); nlohmann::json msgcont = resp["msg"]; std::set gtset; - for (auto &it : msgcont.items()) + for (const auto &it : msgcont.items()) { std::string exist_gt = it.value().at("name"); gtset.insert(exist_gt); @@ -133,7 +149,7 @@ void CDBUtils::listGlobalTags() nlohmann::json resp = cdbclient->getGlobalTags(); nlohmann::json msgcont = resp["msg"]; std::set globaltags; - for (auto &it : msgcont.items()) + for (const auto &it : msgcont.items()) { std::string exist_gt = it.value().at("name"); globaltags.insert(exist_gt); @@ -150,7 +166,7 @@ void CDBUtils::listPayloadTypes() nlohmann::json resp = cdbclient->getPayloadTypes(); nlohmann::json msgcont = resp["msg"]; std::set payloadtypes; - for (auto &it : msgcont.items()) + for (const auto &it : msgcont.items()) { std::string exist_pl = it.value().at("name"); payloadtypes.insert(exist_pl); diff --git a/offline/database/sphenixnpc/CDBUtils.h b/offline/database/sphenixnpc/CDBUtils.h index 393036236c..067ccf295b 100644 --- a/offline/database/sphenixnpc/CDBUtils.h +++ b/offline/database/sphenixnpc/CDBUtils.h @@ -2,6 +2,8 @@ #define SPHENIXNPC_CDBUTILS_H #include // for uint64_t +#include +#include #include #include @@ -27,11 +29,9 @@ class CDBUtils int insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start); int insertPayload(const std::string &pl_type, const std::string &file_url, uint64_t iov_start, uint64_t iov_end); int cloneGlobalTag(const std::string &source, const std::string &target); - int deleteGlobalTag(const std::string &); void listGlobalTags(); void listPayloadTypes(); - void listPayloadIOVs(uint64_t iov); void clearCache(); bool isGlobalTagSet(); void Verbosity(int i); @@ -39,9 +39,12 @@ class CDBUtils int deletePayloadIOV(const std::string &pl_type, uint64_t iov_start); int deletePayloadIOV(const std::string &pl_type, uint64_t iov_start, uint64_t iov_end); + std::map> PayloadIOVs(uint64_t iov, const std::string &ptype = ""); + void listPayloadIOVs(uint64_t iov, const std::string &ptype = ""); + private: - int m_Verbosity = 0; - SphenixClient *cdbclient = nullptr; + int m_Verbosity{0}; + std::unique_ptr cdbclient; std::string m_CachedGlobalTag; std::set m_PayloadTypeCache; }; diff --git a/offline/database/sphenixnpc/SphenixClient.cc b/offline/database/sphenixnpc/SphenixClient.cc index 7de6ecd6ed..b20eea35e7 100644 --- a/offline/database/sphenixnpc/SphenixClient.cc +++ b/offline/database/sphenixnpc/SphenixClient.cc @@ -5,6 +5,7 @@ #include +#include #include #include @@ -60,7 +61,7 @@ nlohmann::json SphenixClient::getUrlDict(long long iov) } for (auto it = resp["msg"].begin(); it != resp["msg"].end();) { - if (it.value()["minor_iov_end"] < iov) + if (it.value()["minor_iov_end"] <= iov) { it = resp["msg"].erase(it); } @@ -69,13 +70,53 @@ nlohmann::json SphenixClient::getUrlDict(long long iov) ++it; } } - for (auto& piov : resp["msg"].items()) + for (const auto& piov : resp["msg"].items()) { piov.value() = piov.value()["payload_url"]; } return resp; } +void SphenixClient::DumpCalibrations(long long iov, const std::string& filename) +{ + nlohmann::json resp = getPayloadIOVs(iov); + if (resp["code"] != 0) + { + std::cout << "not writing " << filename << std::endl; + return; + } + for (auto it = resp["msg"].begin(); it != resp["msg"].end();) + { + if (it.value()["minor_iov_end"] <= iov) + { + it = resp["msg"].erase(it); + } + else + { + ++it; + } + } + std::ofstream dumpfile(filename); + if (dumpfile.is_open()) + { + for (const auto& piov : resp["msg"].items()) + { + std::string payload_url = piov.value()["payload_url"]; + if (!payload_url.empty() && payload_url.front() == '"' && payload_url.back() == '"') + { + payload_url = payload_url.substr(1, payload_url.size() - 2); + } + dumpfile << piov.key() << " " << payload_url << std::endl; + } + dumpfile.close(); + } + else + { + std::cout << "Could not open " << filename << std::endl; + } + return; +} + nlohmann::json SphenixClient::deletePayloadIOV(const std::string& pl_type, long long iov_start) { return nopayloadclient::NoPayloadClient::deletePayloadIOV(pl_type, 0, iov_start); @@ -162,7 +203,7 @@ int SphenixClient::cache_set_GlobalTag(const std::string& tagname) bool found_gt = false; nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); nlohmann::json msgcont = resp["msg"]; - for (auto& it : msgcont.items()) + for (const auto& it : msgcont.items()) { std::string exist_gt = it.value().at("name"); std::cout << "global tag: " << exist_gt << std::endl; @@ -196,7 +237,7 @@ int SphenixClient::createDomain(const std::string& domain) { resp = nopayloadclient::NoPayloadClient::getPayloadTypes(); nlohmann::json msgcont = resp["msg"]; - for (auto& it : msgcont.items()) + for (const auto& it : msgcont.items()) { std::string existent_domain = it.value().at("name"); m_DomainCache.insert(existent_domain); @@ -235,7 +276,7 @@ bool SphenixClient::existGlobalTag(const std::string& gt_name) } nlohmann::json resp = nopayloadclient::NoPayloadClient::getGlobalTags(); nlohmann::json msgcont = resp["msg"]; - for (auto& it : msgcont.items()) + for (const auto& it : msgcont.items()) { std::string exist_gt = it.value().at("name"); m_GlobalTagCache.insert(gt_name); diff --git a/offline/database/sphenixnpc/SphenixClient.h b/offline/database/sphenixnpc/SphenixClient.h index 95b3729e95..0dd6d9ff1c 100644 --- a/offline/database/sphenixnpc/SphenixClient.h +++ b/offline/database/sphenixnpc/SphenixClient.h @@ -39,9 +39,10 @@ class SphenixClient : public nopayloadclient::NoPayloadClient bool isGlobalTagSet(); void Verbosity(int i) { m_Verbosity = i; } int Verbosity() const { return m_Verbosity; } + void DumpCalibrations(long long iov, const std::string& filename); private: - int m_Verbosity = 0; + int m_Verbosity{0}; std::string m_CachedGlobalTag; std::set m_DomainCache; std::set m_GlobalTagCache; diff --git a/offline/framework/ffamodules/CDBInterface.cc b/offline/framework/ffamodules/CDBInterface.cc index 2b4feef203..dfe464e5e6 100644 --- a/offline/framework/ffamodules/CDBInterface.cc +++ b/offline/framework/ffamodules/CDBInterface.cc @@ -20,10 +20,13 @@ #include -#include // for uint64_t +#include // for uint64_t +#include +#include #include // for operator<<, basic_ostream, endl -#include // for pair -#include // for vector +#include +#include // for pair +#include // for vector CDBInterface *CDBInterface::__instance{nullptr}; @@ -55,7 +58,8 @@ CDBInterface::~CDBInterface() //____________________________________________________________________________.. int CDBInterface::End(PHCompositeNode *topNode) { - int iret = UpdateRunNode(topNode);PHNodeIterator iter(topNode); + int iret = UpdateRunNode(topNode); + PHNodeIterator iter(topNode); return iret; } @@ -127,6 +131,15 @@ std::string CDBInterface::getUrl(const std::string &domain, const std::string &f return ""; } std::string domain_noconst = domain; + if (m_Read_From_File_Flag) + { + if (m_Payload_Url_Cache.contains(domain_noconst)) + { + return m_Payload_Url_Cache[domain_noconst]; + } + std::cout << "calibration " << domain << " not found in local cache" << std::endl; + return ""; + } recoConsts *rc = recoConsts::instance(); if (!rc->FlagExist("CDB_GLOBALTAG")) { @@ -185,11 +198,85 @@ std::string CDBInterface::getUrl(const std::string &domain, const std::string &f std::cout << "... reply: " << return_url << std::endl; } } - auto pret = m_UrlVector.insert(make_tuple(domain_noconst, return_url, timestamp)); - if (!pret.second && Verbosity() > 1) + if (!return_url.empty()) { - std::cout << PHWHERE << "not adding again " << domain_noconst << ", url: " << return_url - << ", time stamp: " << timestamp << std::endl; + auto pret = m_UrlVector.insert(make_tuple(domain_noconst, return_url, timestamp)); + if (!pret.second && Verbosity() > 1) + { + std::cout << PHWHERE << "not adding again " << domain_noconst << ", url: " << return_url + << ", time stamp: " << timestamp << std::endl; + } } return return_url; } + +void CDBInterface::DumpCalibrations(const std::string &filename) +{ + recoConsts *rc = recoConsts::instance(); + if (!rc->FlagExist("CDB_GLOBALTAG")) + { + std::cout << PHWHERE << "CDB_GLOBALTAG flag needs to be set via" << std::endl; + std::cout << "rc->set_StringFlag(\"CDB_GLOBALTAG\",)" << std::endl; + gSystem->Exit(1); + } + if (!rc->FlagExist("TIMESTAMP")) + { + std::cout << PHWHERE << "TIMESTAMP flag needs to be set via" << std::endl; + std::cout << "rc->set_uint64Flag(\"TIMESTAMP\",<64 bit timestamp>)" << std::endl; + gSystem->Exit(1); + } + if (cdbclient == nullptr) + { + cdbclient = new SphenixClient(rc->get_StringFlag("CDB_GLOBALTAG")); + } + uint64_t timestamp = rc->get_uint64Flag("TIMESTAMP"); + cdbclient->DumpCalibrations(timestamp, filename); + return; +} + +void CDBInterface::ReadCalibrationsFromFile(const std::string &filename) +{ + std::filesystem::path filePath = filename; + if (!std::filesystem::exists(filePath)) + { + std::cout << PHWHERE << " cannot locate " << filename << std::endl; + gSystem->Exit(1); + } + if (!std::filesystem::is_regular_file(filePath)) + { + std::cout << PHWHERE << " not a regular file " << filename << std::endl; + gSystem->Exit(1); + } + std::ifstream calibsfile(filename); + if (calibsfile.is_open()) + { + std::string line; + while (std::getline(calibsfile, line)) + { + // Skip empty lines + if (line.empty()) + { + continue; + } + + // Skip comments + if (line[0] == '#') + { + continue; + } + std::istringstream iss(line); + std::string key; + std::string payload_url; + if (iss >> key >> payload_url) + { + m_Payload_Url_Cache.insert(std::make_pair(key, payload_url)); + } + } + m_Read_From_File_Flag = true; + } + else + { + std::cout << "could not open " << filename << std::endl; + } + return; +} diff --git a/offline/framework/ffamodules/CDBInterface.h b/offline/framework/ffamodules/CDBInterface.h index c88fae9dee..b4b0303239 100644 --- a/offline/framework/ffamodules/CDBInterface.h +++ b/offline/framework/ffamodules/CDBInterface.h @@ -6,11 +6,11 @@ #include #include // for uint64_t +#include #include #include #include // for tuple -class PHCompositeNode; class SphenixClient; class CDBInterface : public SubsysReco @@ -35,6 +35,9 @@ class CDBInterface : public SubsysReco std::string getUrl(const std::string &domain, const std::string &filename = ""); + void DumpCalibrations(const std::string &filename); + void ReadCalibrationsFromFile(const std::string &filename); + private: CDBInterface(const std::string &name = "CDBInterface"); @@ -42,6 +45,8 @@ class CDBInterface : public SubsysReco SphenixClient *cdbclient{nullptr}; bool disable{false}; bool disable_default{false}; + bool m_Read_From_File_Flag{false}; + std::map m_Payload_Url_Cache; std::set> m_UrlVector; }; diff --git a/offline/framework/ffamodules/FlagHandler.h b/offline/framework/ffamodules/FlagHandler.h index f5cc06bcdb..fd7e40cca3 100644 --- a/offline/framework/ffamodules/FlagHandler.h +++ b/offline/framework/ffamodules/FlagHandler.h @@ -7,14 +7,12 @@ #include -class PHCompositeNode; - class FlagHandler : public SubsysReco { public: FlagHandler(const std::string &name = "FlagHandler"); - ~FlagHandler() override {} + ~FlagHandler() override = default; /** Create the Flag Node if it does not exist, if it exists, read back flags and copy them into recoConsts diff --git a/offline/framework/ffamodules/HeadReco.cc b/offline/framework/ffamodules/HeadReco.cc index 75e879fdff..17214758c8 100644 --- a/offline/framework/ffamodules/HeadReco.cc +++ b/offline/framework/ffamodules/HeadReco.cc @@ -84,10 +84,13 @@ int HeadReco::process_event(PHCompositeNode *topNode) { evtheader->set_ImpactParameter(hi->impact_parameter()); evtheader->set_EventPlaneAngle(hi->event_plane_angle()); - for (unsigned int n = 1; n <= 6; ++n) - { - evtheader->set_FlowPsiN(n, genevt->get_flow_psi(n)); - } + if (! genevt->get_flow_psi_map().empty()) + { + for (unsigned int n = 1; n <= 6; ++n) + { + evtheader->set_FlowPsiN(n, genevt->get_flow_psi(n)); + } + } evtheader->set_eccentricity(hi->eccentricity()); evtheader->set_ncoll(hi->Ncoll()); evtheader->set_npart(hi->Npart_targ() + hi->Npart_proj()); diff --git a/offline/framework/ffamodules/HeadReco.h b/offline/framework/ffamodules/HeadReco.h index ca2f6cf34e..53fbc3c6c3 100644 --- a/offline/framework/ffamodules/HeadReco.h +++ b/offline/framework/ffamodules/HeadReco.h @@ -7,13 +7,11 @@ #include // for string -class PHCompositeNode; - class HeadReco : public SubsysReco { public: HeadReco(const std::string &name = "HeadReco"); - ~HeadReco() override {} + ~HeadReco() override = default; int Init(PHCompositeNode *topNode) override; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; diff --git a/offline/framework/ffamodules/SyncReco.h b/offline/framework/ffamodules/SyncReco.h index 0a490302a0..73d0954593 100644 --- a/offline/framework/ffamodules/SyncReco.h +++ b/offline/framework/ffamodules/SyncReco.h @@ -5,13 +5,11 @@ #include -class PHCompositeNode; - class SyncReco : public SubsysReco { public: SyncReco(const std::string &name = "SYNC"); - ~SyncReco() override {} + ~SyncReco() override = default; int Init(PHCompositeNode *topNode) override; int InitRun(PHCompositeNode *topNode) override; @@ -24,7 +22,7 @@ class SyncReco : public SubsysReco // just if we need to override the segment for e.g. embedding // where we want to reuse hijing files which normally set // the segment number - int forced_segment = -1; + int forced_segment {-1}; }; #endif /* FFAMODULES_SYNCRECO_H */ diff --git a/offline/framework/ffamodules/Timing.cc b/offline/framework/ffamodules/Timing.cc index f662ba1b33..16210e4f73 100644 --- a/offline/framework/ffamodules/Timing.cc +++ b/offline/framework/ffamodules/Timing.cc @@ -3,8 +3,6 @@ #include #include // for SubsysReco -#include - #include Timing::Timing(const std::string &name) diff --git a/offline/framework/ffamodules/Timing.h b/offline/framework/ffamodules/Timing.h index 01b95638e0..a9a5ccd39d 100644 --- a/offline/framework/ffamodules/Timing.h +++ b/offline/framework/ffamodules/Timing.h @@ -8,15 +8,13 @@ #include // for string #include -class PHCompositeNode; - class Timing : public SubsysReco { public: Timing(const std::string &name = "Timing"); - ~Timing() override {} - int InitRun(PHCompositeNode *topNode) override; - int process_event(PHCompositeNode *topNode) override; + ~Timing() override = default; + int InitRun(PHCompositeNode * /*topNode*/) override; + int process_event(PHCompositeNode * /*topNode*/) override; void SetCallCounter(unsigned int i) { calls = i; } private: diff --git a/offline/framework/ffarawobjects/MicromegasRawHitv3.cc b/offline/framework/ffarawobjects/MicromegasRawHitv3.cc index 15bdd93a50..3799bfa1ef 100644 --- a/offline/framework/ffarawobjects/MicromegasRawHitv3.cc +++ b/offline/framework/ffarawobjects/MicromegasRawHitv3.cc @@ -11,7 +11,7 @@ MicromegasRawHitv3::MicromegasRawHitv3(MicromegasRawHit *source) { once = false; std::cout << "MicromegasRawHitv3::MicromegasRawHitv3(MicromegasRawHit *tpchit) - " - << "WARNING: This moethod is slow and should be avoided as much as possible! Please use the move constructor." + << "WARNING: This method is slow and should be avoided as much as possible! Please use the move constructor." << std::endl; } diff --git a/offline/framework/ffarawobjects/MicromegasRawHitv3.h b/offline/framework/ffarawobjects/MicromegasRawHitv3.h index 3a369be542..929dc1f232 100644 --- a/offline/framework/ffarawobjects/MicromegasRawHitv3.h +++ b/offline/framework/ffarawobjects/MicromegasRawHitv3.h @@ -65,8 +65,13 @@ class MicromegasRawHitv3 : public MicromegasRawHit //! adc list using adc_list_t = std::vector; + using waveform_pair_t = std::pair; + + // get adc values + const std::vector& get_adc_waveforms() const + { return m_adcData; } - // set adc values + // set adc values (move operator) void move_adc_waveform(const uint16_t start_time, adc_list_t &&adc); private: @@ -83,7 +88,6 @@ class MicromegasRawHitv3 : public MicromegasRawHit //! list of waveforms /** each pair contains the start sample of the waveform and the constituting adc values */ - using waveform_pair_t = std::pair; std::vector m_adcData; ClassDefOverride(MicromegasRawHitv3, 1) diff --git a/offline/framework/ffarawobjects/TpcRawHitv3.h b/offline/framework/ffarawobjects/TpcRawHitv3.h index 755520c678..8d1994a8fc 100644 --- a/offline/framework/ffarawobjects/TpcRawHitv3.h +++ b/offline/framework/ffarawobjects/TpcRawHitv3.h @@ -73,7 +73,11 @@ class TpcRawHitv3 : public TpcRawHit // { // adcmap[sample] = val; // } + using AdcWaveform_t = std::pair >; + using AdcWaveformVector_t = std::vector; + void move_adc_waveform(const uint16_t start_time, std::vector &&adc); + const AdcWaveformVector_t &get_adc_waveforms() const { return m_adcData; } uint16_t get_type() const override { return type; } void set_type(const uint16_t i) override { type = i; } diff --git a/offline/framework/frog/CreateFileList.pl b/offline/framework/frog/CreateFileList.pl index cc59083d8c..903fa28236 100755 --- a/offline/framework/frog/CreateFileList.pl +++ b/offline/framework/frog/CreateFileList.pl @@ -41,7 +41,7 @@ my %proddesc = ( # "1" => "hijing (0-12fm) pileup 0-12fm DELETED", # "2" => "hijing (0-4.88fm) pileup 0-12fm DELETED", - "3" => "pythia8 pp MB", +# "3" => "pythia8 pp MB", "4" => "hijing (0-20fm) pileup 0-20fm", # "5" => "hijing (0-12fm) pileup 0-20fm DELETED", "6" => "hijing (0-4.88fm) pileup 0-20fm", @@ -49,36 +49,51 @@ "8" => "HF pythia8 Bottom", "9" => "HF pythia8 Charm D0", "10" => "HF pythia8 Bottom D0", - "11" => "JS pythia8 Jet ptmin = 30GeV", - "12" => "JS pythia8 Jet ptmin = 10GeV", + "11" => "JS pythia8 Jet ptmin = 30 GeV", + "12" => "JS pythia8 Jet ptmin = 10 GeV", "13" => "JS pythia8 Photon Jet", "14" => "Single Particles", "15" => "Special Productions", "16" => "HF pythia8 D0 Jets", - "17" => "HF pythia8 D0 pi-k Jets ptmin = 5GeV ", - "18" => "HF pythia8 D0 pi-k Jets ptmin = 12GeV", - "19" => "JS pythia8 Jet ptmin = 40GeV", + "17" => "HF pythia8 D0 pi-k Jets ptmin = 5 GeV ", + "18" => "HF pythia8 D0 pi-k Jets ptmin = 12 GeV", + "19" => "JS pythia8 Jet ptmin = 40 GeV", "20" => "hijing pAu (0-10fm) pileup 0-10fm", - "21" => "JS pythia8 Jet ptmin = 20GeV", + "21" => "JS pythia8 Jet ptmin = 20 GeV", "22" => "cosmic field on", "23" => "cosmic field off", "24" => "AMPT", "25" => "EPOS", - "26" => "JS pythia8 Detroit", - "27" => "JS pythia8 Photonjet ptmin = 5GeV", - "28" => "JS pythia8 Photonjet ptmin = 10GeV", - "29" => "JS pythia8 Photonjet ptmin = 20GeV", + "26" => "JS pythia8 Detroit (MB)", + "27" => "JS pythia8 Photonjet ptmin = 5 GeV", + "28" => "JS pythia8 Photonjet ptmin = 10 GeV", + "29" => "JS pythia8 Photonjet ptmin = 20 GeV", "30" => "Herwig MB", "31" => "Herwig Jet ptmin = 10 GeV", "32" => "Herwig Jet ptmin = 30 GeV", - "33" => "JS pythia8 Jet ptmin = 15GeV", - "34" => "JS pythia8 Jet ptmin = 50GeV", - "35" => "JS pythia8 Jet ptmin = 70GeV", - "36" => "JS pythia8 Jet ptmin = 5GeV" + "33" => "JS pythia8 Jet ptmin = 15 GeV", + "34" => "JS pythia8 Jet ptmin = 50 GeV", + "35" => "JS pythia8 Jet ptmin = 70 GeV", + "36" => "JS pythia8 Jet ptmin = 5 GeV", + "37" => "hijing O+O (0-15fm)", + "38" => "JS pythia8 Jet ptmin = 60 GeV", + "39" => "JS pythia8 Jet ptmin = 12 GeV", + "40" => "Herwig Jet ptmin = 5 GeV", + "41" => "Herwig Jet ptmin = 12 GeV", + "42" => "Herwig Jet ptmin = 20 GeV", + "43" => "Herwig Jet ptmin = 40 GeV", + "44" => "Herwig Jet ptmin = 50 GeV", + "45" => "Herwig Photonjet ptmin = 5 GeV", + "46" => "Herwig Photonjet ptmin = 10 GeV", + "47" => "Herwig Photonjet ptmin = 20 GeV", + "48" => "JS pythia8 Jet ptmin = 8 GeV", + "49" => "JS pythia8 Jet ptmin = 80 GeV", + "50" => "JS pythia8 Detroit eta ptmin = 3 GeV", + "51" => "JS pythia8 Detroit eta ptmin = 8 GeV" ); my %pileupdesc = ( - "1" => "50kHz for Au+Au, 3MHz for p+p (default)", + "1" => "50kHz for Au+Au, 3MHz for p+p, 220kHz for O+O (default)", "2" => "25kHz for Au+Au", "3" => "10kHz for Au+Au", "4" => "1MHz for pp 100us streaming", @@ -102,6 +117,7 @@ my $pmax; my $production; my $momentum; +my $double; # that should teach me a lesson to not give a flag an optional string value # just using embed:s leads to the next ARGV to be used as argument, even if it # is the next option. Sadly getopt swallows the - so parsing this becomes @@ -126,7 +142,7 @@ else { push(@newargs, $argument); - if ($ARGV[$iarg+1] ne "pau" && $ARGV[$iarg+1] ne "auau" && $ARGV[$iarg+1] ne "central") + if ($ARGV[$iarg+1] ne "pau" && $ARGV[$iarg+1] ne "auau" && $ARGV[$iarg+1] ne "central" && $ARGV[$iarg+1] ne "oo" ) { push(@newargs,"auau"); } @@ -139,7 +155,7 @@ $iarg++; } @ARGV=@newargs; -GetOptions('embed:s' => \$embed, 'l:i' => \$last_segment, 'momentum:s' => \$momentum, 'n:i' => \$nEvents, "nobkgpileup" => \$nobkgpileup, "nopileup" => \$nopileup, "particle:s" => \$particle, 'pileup:i' => \$pileup, "pmin:i" => \$pmin, "pmax:i"=>\$pmax, "production:s"=>\$production, 'rand' => \$randomize, 'run:i' => \$runnumber, 's:i' => \$start_segment, 'type:i' =>\$prodtype, "verbose" =>\$verbose); +GetOptions('double' => \$double, 'embed:s' => \$embed, 'l:i' => \$last_segment, 'momentum:s' => \$momentum, 'n:i' => \$nEvents, "nobkgpileup" => \$nobkgpileup, "nopileup" => \$nopileup, "particle:s" => \$particle, 'pileup:i' => \$pileup, "pmin:i" => \$pmin, "pmax:i"=>\$pmax, "production:s"=>\$production, 'rand' => \$randomize, 'run:i' => \$runnumber, 's:i' => \$start_segment, 'type:i' =>\$prodtype, "verbose" =>\$verbose); my $filenamestring; my %filetypes = (); my %notlike = (); @@ -147,6 +163,7 @@ my $AuAu_pileupstring; my $pp_pileupstring; my $pAu_pileupstring; +my $OO_pileupstring; my $pileupstring; if (! defined $runnumber && $#newargs >= 0) @@ -167,11 +184,13 @@ } my $pAu_bkgpileup = sprintf("_bkg_0_20fm"); my $AuAu_bkgpileup = sprintf("_bkg_0_10fm"); +my $OO_bkgpileup = sprintf("_bkg_0_15fm"); if ($pileup == 1) { $AuAu_pileupstring = sprintf("_50kHz%s",$AuAu_bkgpileup); $pp_pileupstring = sprintf("_3MHz"); $pAu_pileupstring = sprintf("_500kHz%s",$pAu_bkgpileup); + $OO_pileupstring = sprintf("_220kHz%s",$OO_bkgpileup); } elsif ($pileup == 2) { @@ -192,15 +211,18 @@ else { $pp_pileupstring = sprintf("_%dkHz",$pileup); - $AuAu_pileupstring = sprintf("_%dkHz%s",$AuAu_bkgpileup); + $AuAu_pileupstring = sprintf("_%dkHz%s",$pileup, $AuAu_bkgpileup); + $OO_pileupstring = sprintf("_%dkHz%s",$pileup,$OO_bkgpileup); } if (defined $nobkgpileup) { $pp_pileupstring = sprintf(""); $AuAu_pileupstring = sprintf(""); + $OO_pileupstring = sprintf(""); } my $embedok = 0; +my $doubleok = 0; if (defined $prodtype) { @@ -302,6 +324,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet30"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -314,6 +341,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -343,6 +374,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -497,6 +532,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet40"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -509,6 +549,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -540,6 +584,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet20"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -552,6 +601,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -611,6 +664,11 @@ { $embedok = 1; $filenamestring = "pythia8_Detroit"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -640,6 +698,11 @@ { $embedok = 1; $filenamestring = "pythia8_PhotonJet5"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -652,6 +715,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -669,6 +736,11 @@ { $embedok = 1; $filenamestring = "pythia8_PhotonJet10"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = "pythia8_PhotonJet10_pythia8_Detroit"; + } if (! defined $nopileup) { if (defined $embed) @@ -681,6 +753,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -698,6 +774,11 @@ { $embedok = 1; $filenamestring = "pythia8_PhotonJet20"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -710,6 +791,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -826,6 +911,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -843,6 +932,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet50"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -855,6 +949,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -884,6 +982,10 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -901,6 +1003,11 @@ { $embedok = 1; $filenamestring = "pythia8_Jet5"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } if (! defined $nopileup) { if (defined $embed) @@ -913,6 +1020,503 @@ { $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 37) + { + if (defined $nopileup) + { + $filenamestring = sprintf("sHijing_OO_0_15fm"); + } + else + { + $filenamestring = sprintf("sHijing_OO_0_15fm%s",$OO_pileupstring); + } + $notlike{$filenamestring} = ["pythia8" ,"single", "special"]; + $pileupstring = $AuAu_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 38) + { + $embedok = 1; + $filenamestring = "pythia8_Jet60"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 39) + { + $embedok = 1; + $filenamestring = "pythia8_Jet12"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 40) + { + $embedok = 1; + $filenamestring = "Herwig_Jet5"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 41) + { + $embedok = 1; + $filenamestring = "Herwig_Jet12"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 42) + { + $embedok = 1; + $filenamestring = "Herwig_Jet20"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 43) + { + $embedok = 1; + $filenamestring = "Herwig_Jet40"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 44) + { + $embedok = 1; + $filenamestring = "Herwig_Jet50"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 45) + { + $embedok = 1; + $filenamestring = "Herwig_PhotonJet5"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 45) + { + $embedok = 1; + $filenamestring = "Herwig_PhotonJet5"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 46) + { + $embedok = 1; + $filenamestring = "Herwig_PhotonJet10"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 47) + { + $embedok = 1; + $filenamestring = "Herwig_PhotonJet20"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 48) + { + $embedok = 1; + $filenamestring = "pythia8_Jet8"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 49) + { + $embedok = 1; + $filenamestring = "pythia8_Jet80"; + if (defined $double) + { + $doubleok = 1; + $filenamestring = sprintf("%s_pythia8_Detroit",$filenamestring); + } + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 50) + { + $embedok = 1; + $filenamestring = "pythia8_Eta3"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } + else + { + $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); + } + } + else + { + $filenamestring = sprintf("%s%s",$filenamestring,$pp_pileupstring); + } + } + $pileupstring = $pp_pileupstring; + &commonfiletypes(); + } + elsif ($prodtype == 51) + { + $embedok = 1; + $filenamestring = "pythia8_Eta8"; + if (! defined $nopileup) + { + if (defined $embed) + { + if ($embed eq "pau") + { + $filenamestring = sprintf("%s_sHijing_pAu_0_10fm%s",$filenamestring, $pAu_pileupstring); + } + elsif ($embed eq "central") + { + $filenamestring = sprintf("%s_sHijing_0_488fm%s",$filenamestring, $AuAu_pileupstring); + } + elsif ($embed eq "oo") + { + $filenamestring = sprintf("%s_sHijing_OO_0_15fm%s",$filenamestring, $OO_pileupstring); + } else { $filenamestring = sprintf("%s_sHijing_0_20fm%s",$filenamestring, $AuAu_pileupstring); @@ -926,7 +1530,6 @@ $pileupstring = $pp_pileupstring; &commonfiletypes(); } - else { print "no production type $prodtype\n"; @@ -940,6 +1543,11 @@ print "Embedding not implemented for type $prodtype\n"; exit(1); } +if (defined $double && ! $doubleok) +{ + print "Double interactions not implemented for type $prodtype\n"; + exit(1); +} my $filenamestring_with_runnumber = sprintf("%s\-%010d-",$filenamestring,$runnumber); if ($#ARGV < 0) @@ -948,6 +1556,7 @@ { print "usage: CreateFileLists.pl -type \n"; print "parameters:\n"; + print "-double : double interactions, pp of your type and Detroit pp\n"; print "-embed : pp embedded into MB AuAu hijing (only for pp types)\n"; print " -embed pau : embedded into pAu (only for pp types)\n"; print " -embed central : embedded into central AuAu\n"; @@ -1071,6 +1680,10 @@ } print "This Can Take a While (10 minutes depending on the amount of events and the number of file types you want)\n"; my $conds = sprintf("dsttype = ? and filename like \'\%%%s\%\'",$filenamestring_with_runnumber); +if (! defined $double) +{ + $conds = sprintf("%s and filename not like '\%%pythia8_\%_pythia8\%'",$conds); +} if (exists $notlike{$filenamestring}) { diff --git a/offline/framework/fun4all/CreateSubsysRecoModule.pl b/offline/framework/fun4all/CreateSubsysRecoModule.pl index 51f64ea25c..f46c37053d 100755 --- a/offline/framework/fun4all/CreateSubsysRecoModule.pl +++ b/offline/framework/fun4all/CreateSubsysRecoModule.pl @@ -138,6 +138,8 @@ () print F "// void $classname\:\:Print(const std::string &what) const\n"; print F "// Called from the command line - useful to print information when you need it\n"; print F "//\n"; + print F "// [[maybe_unused]] suppresses compiler warnings if topNode is not used in this method\n"; + print F "//\n"; print F "//____________________________________________________________________________..\n"; print F "\n"; @@ -166,7 +168,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:Init(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:Init([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:Init(PHCompositeNode *topNode) Initializing\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -174,7 +176,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:InitRun(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:InitRun([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:InitRun(PHCompositeNode *topNode) Initializing for Run XXX\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -182,7 +184,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:process_event(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:process_event([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:process_event(PHCompositeNode *topNode) Processing Event\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -190,7 +192,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:ResetEvent(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:ResetEvent([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:ResetEvent(PHCompositeNode *topNode) Resetting internal structures, prepare for next event\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -206,7 +208,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:End(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:End([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:End(PHCompositeNode *topNode) This is the End...\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -214,7 +216,7 @@ () print F "\n"; print F "//____________________________________________________________________________..\n"; - print F "int $classname\:\:Reset(PHCompositeNode *topNode)\n"; + print F "int $classname\:\:Reset([[maybe_unused]] PHCompositeNode *topNode)\n"; print F "{\n"; print F " std::cout << \"$classname\:\:Reset(PHCompositeNode *topNode) being Reset\" << std::endl;\n"; print F " return Fun4AllReturnCodes::EVENT_OK;\n"; @@ -331,7 +333,7 @@ () print F "dnl no point in suppressing warnings people should \n"; print F "dnl at least see them, so here we go for g++: -Wall\n"; print F "if test \$ac_cv_prog_gxx = yes; then\n"; - print F " CXXFLAGS=\"\$CXXFLAGS -Wall -Werror\"\n"; + print F " CXXFLAGS=\"\$CXXFLAGS -Wall -Wextra -Wshadow -Werror\"\n"; print F "fi\n"; print F "\n"; @@ -348,7 +350,7 @@ () print F "AM_CPPFLAGS = \\\n"; print F " -I\$(includedir) \\\n"; - print F " -I\$(OFFLINE_MAIN)/include \\\n"; + print F " -isystem\$(OFFLINE_MAIN)/include \\\n"; print F " -isystem\$(ROOTSYS)/include\n"; print F "\n"; diff --git a/offline/framework/fun4all/Fun4AllHistoManager.cc b/offline/framework/fun4all/Fun4AllHistoManager.cc index f88a59c3b9..0c05ce9b53 100644 --- a/offline/framework/fun4all/Fun4AllHistoManager.cc +++ b/offline/framework/fun4all/Fun4AllHistoManager.cc @@ -126,7 +126,7 @@ int Fun4AllHistoManager::dumpHistos(const std::string &filename, const std::stri TFile hfile(theoutfile.c_str(), openmode.c_str(), creator.c_str()); if (!hfile.IsOpen()) { - std::cout << PHWHERE << " Could not open output file" << theoutfile.c_str() << std::endl; + std::cout << PHWHERE << " Could not open output file" << theoutfile << std::endl; return -1; } hfile.SetCompressionSettings(compress); @@ -237,7 +237,11 @@ bool Fun4AllHistoManager::registerHisto(const std::string &hname, TNamed *h1d, c // For histograms, enforce error calculation and propagation if (h1d->InheritsFrom("TH1")) { - static_cast(h1d)->Sumw2();// NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + TH1 *h = static_cast(h1d); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) + if (h->GetSumw2N() == 0) + { + h->Sumw2(); + } } return true; diff --git a/offline/framework/fun4all/Fun4AllInputManager.h b/offline/framework/fun4all/Fun4AllInputManager.h index a198906c48..b3f66d5817 100644 --- a/offline/framework/fun4all/Fun4AllInputManager.h +++ b/offline/framework/fun4all/Fun4AllInputManager.h @@ -50,8 +50,9 @@ class Fun4AllInputManager : public Fun4AllBase, public InputFileHandler void InputNode(const std::string &innode) { m_InputNode = innode; } const std::string &TopNodeName() const { return m_TopNodeName; } void Verbosity(const uint64_t ival) override; - - protected: + virtual int NoRunTTree() {return -1;} + +protected: Fun4AllInputManager(const std::string &name = "DUMMY", const std::string &nodename = "DST", const std::string &topnodename = "TOP"); Fun4AllSyncManager *MySyncManager() { return m_MySyncManager; } void DisableReadCache() { m_disable_read_cache_flag = true; } diff --git a/offline/framework/fun4all/Fun4AllNoSyncDstInputManager.h b/offline/framework/fun4all/Fun4AllNoSyncDstInputManager.h index 13cdec2ba4..66ccebd165 100644 --- a/offline/framework/fun4all/Fun4AllNoSyncDstInputManager.h +++ b/offline/framework/fun4all/Fun4AllNoSyncDstInputManager.h @@ -28,7 +28,7 @@ class Fun4AllNoSyncDstInputManager : public Fun4AllDstInputManager int setSyncBranches(PHNodeIOManager* /*IManager*/) override { return 0; } // turn off reading of the runwise TTree to make run mixing for embedding possible - int NoRunTTree(); + int NoRunTTree() override; int SkipForThisManager(const int nevents) override { return PushBackEvents(nevents); } int HasSyncObject() const override { return 0; } diff --git a/offline/framework/fun4all/Fun4AllServer.cc b/offline/framework/fun4all/Fun4AllServer.cc index 9d8779204e..41e4dd6924 100644 --- a/offline/framework/fun4all/Fun4AllServer.cc +++ b/offline/framework/fun4all/Fun4AllServer.cc @@ -128,9 +128,9 @@ void Fun4AllServer::InitAll() { gSystem->IgnoreSignal((ESignals) i); } + m_saved_cout_state.copyfmt(std::cout); // save current state Fun4AllMonitoring::instance()->Snapshot("StartUp"); - std::string histomanagername; - histomanagername = Name() + "HISTOS"; + std::string histomanagername = Name() + "HISTOS"; ServerHistoManager = new Fun4AllHistoManager(histomanagername); registerHistoManager(ServerHistoManager); double uplim = NFRAMEWORKBINS - 0.5; @@ -245,6 +245,7 @@ int Fun4AllServer::registerSubsystem(SubsysReco *subsystem, const std::string &t << subsystem->Name() << std::endl; exit(1); } + std::cout.copyfmt(m_saved_cout_state); // restore cout to default formatting gROOT->cd(currdir.c_str()); if (iret) { @@ -576,6 +577,7 @@ int Fun4AllServer::process_event() ffamemtracker->Snapshot("Fun4AllServerProcessEvent"); #endif int retcode = Subsystem.first->process_event(Subsystem.second); + std::cout.copyfmt(m_saved_cout_state); // restore cout to default formatting #ifdef FFAMEMTRACKER ffamemtracker->Snapshot("Fun4AllServerProcessEvent"); #endif @@ -899,6 +901,7 @@ int Fun4AllServer::BeginRun(const int runno) for (iter = Subsystems.begin(); iter != Subsystems.end(); ++iter) { iret = BeginRunSubsystem(*iter); + std::cout.copyfmt(m_saved_cout_state); // restore cout to default formatting } for (; !NewSubsystems.empty(); NewSubsystems.pop_front()) { @@ -1092,6 +1095,7 @@ int Fun4AllServer::EndRun(const int runno) << (*iter).first->Name() << std::endl; exit(1); } + std::cout.copyfmt(m_saved_cout_state); // restore cout to default formatting } gROOT->cd(currdir.c_str()); @@ -1101,7 +1105,14 @@ int Fun4AllServer::EndRun(const int runno) int Fun4AllServer::End() { recoConsts *rc = recoConsts::instance(); - EndRun(rc->get_IntFlag("RUNNUMBER")); // call SubsysReco EndRun methods for current run + if (rc->FlagExist("RUNNUMBER")) + { + EndRun(rc->get_IntFlag("RUNNUMBER")); // call SubsysReco EndRun methods for current run + } + else + { + std::cout << PHWHERE << " No RUNNUMBER Int Flag set, not calling EndRun() for registered modules" << std::endl; + } int i = 0; std::vector>::iterator iter; gROOT->cd(default_Tdirectory.c_str()); @@ -1144,6 +1155,7 @@ int Fun4AllServer::End() << (*iter).first->Name() << std::endl; exit(1); } + std::cout.copyfmt(m_saved_cout_state); // restore cout to default formatting } gROOT->cd(currdir.c_str()); PHNodeIterator nodeiter(TopNode); diff --git a/offline/framework/fun4all/Fun4AllServer.h b/offline/framework/fun4all/Fun4AllServer.h index 0c7ea72c14..9f360b9502 100644 --- a/offline/framework/fun4all/Fun4AllServer.h +++ b/offline/framework/fun4all/Fun4AllServer.h @@ -143,7 +143,8 @@ class Fun4AllServer : public Fun4AllBase int eventnumber{0}; int eventcounter{0}; int keep_db_connected{0}; - + + std::ios m_saved_cout_state{nullptr}; std::vector ComplaintList; std::vector ResetNodeList {"DST"}; std::vector> Subsystems; diff --git a/offline/framework/fun4all/InputFileHandler.cc b/offline/framework/fun4all/InputFileHandler.cc index 8939b67568..0fdc858db8 100644 --- a/offline/framework/fun4all/InputFileHandler.cc +++ b/offline/framework/fun4all/InputFileHandler.cc @@ -3,10 +3,13 @@ #include +#include + #include #include #include #include +#include int InputFileHandler::AddFile(const std::string &filename) { @@ -89,6 +92,19 @@ int InputFileHandler::OpenNextFile() { std::cout << PHWHERE << " opening next file: " << *iter << std::endl; } + if (!GetOpeningScript().empty()) + { + std::vector stringvec; + stringvec.push_back(*iter); + if (!m_FileName.empty()) + { + stringvec.push_back(m_FileName); + } + if (RunBeforeOpening(stringvec)) + { + std::cout << PHWHERE << " RunBeforeOpening() failed" << std::endl; + } + } if (fileopen(*iter)) { std::cout << PHWHERE << " could not open file: " << *iter << std::endl; @@ -145,3 +161,40 @@ int InputFileHandler::fileopen(const std::string &fname) std::cout << "InputFileHandler::fileopen opening " << fname << std::endl; return 0; } + +int InputFileHandler::RunBeforeOpening(const std::vector &stringvec) +{ + if (m_RunBeforeOpeningScript.empty()) + { + return 0; + } + if (!std::filesystem::exists(m_RunBeforeOpeningScript)) + { + std::cout << PHWHERE << " script " << m_RunBeforeOpeningScript << " not found" + << std::endl; + return -1; + } + if (!((std::filesystem::status(m_RunBeforeOpeningScript).permissions() & std::filesystem::perms::owner_exec) == std::filesystem::perms::owner_exec)) + { + std::cout << PHWHERE << "RunBeforeOpeningScript script " + << m_RunBeforeOpeningScript << " is not owner executable" << std::endl; + return -1; + } + std::string fullcmd = m_RunBeforeOpeningScript + " " + m_OpeningArgs; + for (const auto& iter : stringvec) + { + fullcmd += " " + iter; + } + + if (m_Verbosity > 1) + { + std::cout << PHWHERE << " running " << fullcmd << std::endl; + } + unsigned int iret = gSystem->Exec(fullcmd.c_str()); + + if (iret) + { + iret = iret >> 8U; + } + return static_cast (iret); +} diff --git a/offline/framework/fun4all/InputFileHandler.h b/offline/framework/fun4all/InputFileHandler.h index 823ae33b38..49df4aa379 100644 --- a/offline/framework/fun4all/InputFileHandler.h +++ b/offline/framework/fun4all/InputFileHandler.h @@ -4,13 +4,14 @@ #include #include #include +#include class InputFileHandler { public: InputFileHandler() = default; virtual ~InputFileHandler() = default; - virtual int fileopen(const std::string & /*filename*/);// { return 0; } + virtual int fileopen(const std::string & /*filename*/); // { return 0; } virtual int fileclose() { return -1; } virtual int ResetFileList(); @@ -32,12 +33,19 @@ class InputFileHandler std::pair::const_iterator, std::list::const_iterator> FileOpenListBeginEnd() { return std::make_pair(m_FileListOpened.begin(), m_FileListOpened.end()); } const std::list &GetFileList() const { return m_FileListCopy; } const std::list &GetFileOpenedList() const { return m_FileListOpened; } + void SetOpeningScript(const std::string &script) { m_RunBeforeOpeningScript = script; } + const std::string &GetOpeningScript() const { return m_RunBeforeOpeningScript; } + void SetOpeningScriptArgs(const std::string &args) { m_OpeningArgs = args; } + const std::string &GetOpeningScriptArgs() const { return m_OpeningArgs; } + int RunBeforeOpening(const std::vector &stringvec); private: int m_IsOpen{0}; int m_Repeat{0}; uint64_t m_Verbosity{0}; std::string m_FileName; + std::string m_RunBeforeOpeningScript; + std::string m_OpeningArgs; std::list m_FileList; std::list m_FileListCopy; std::list m_FileListOpened; // all files which were opened during running diff --git a/offline/framework/fun4all/Makefile.am b/offline/framework/fun4all/Makefile.am index 8f9d9e2019..30ca180fcb 100644 --- a/offline/framework/fun4all/Makefile.am +++ b/offline/framework/fun4all/Makefile.am @@ -66,7 +66,6 @@ libfun4all_la_SOURCES = \ libfun4all_la_LIBADD = \ libSubsysReco.la \ libTDirectoryHelper.la \ - -lboost_filesystem \ -lFROG \ -lffaobjects \ -lphool \ diff --git a/offline/framework/fun4all/PHTFileServer.h b/offline/framework/fun4all/PHTFileServer.h index dc53700f90..31ed067341 100644 --- a/offline/framework/fun4all/PHTFileServer.h +++ b/offline/framework/fun4all/PHTFileServer.h @@ -13,6 +13,8 @@ #ifndef FUN4ALL_PHTFILESERVER_H #define FUN4ALL_PHTFILESERVER_H +#include + #include #include @@ -71,7 +73,7 @@ class PHTFileServer public: //! constructor SafeTFile(const std::string& filename, const std::string& type = "RECREATE") - : TFile(filename.c_str(), type.c_str()) + : TFile(PHUtils::CreateReproducibleTFileName(filename).c_str(), type.c_str()) , _filename(filename) , _counter(1) { diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index 78b3e3a365..aba54f36c2 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -45,6 +45,7 @@ #include #include #include // for operator<<, basic_ostream, endl +#include #include // for pair Fun4AllStreamingInputManager::Fun4AllStreamingInputManager(const std::string &name, const std::string &dstnodename, const std::string &topnodename) @@ -650,6 +651,28 @@ int Fun4AllStreamingInputManager::FillIntt() return iret; } + if (m_Intt_print_count == 0) + { + std::cout<<"Fun4AllStreamingInputManager::FillIntt(), Post first FillInttPool(), m_RefBCO: "<(m_topNode, "INTTRAWHIT"); @@ -710,6 +733,14 @@ int Fun4AllStreamingInputManager::FillIntt() } } + if (Verbosity() > 2 && m_Intt_print_count < 10){ + std::cout<<"Fun4AllStreamingInputManager::FillIntt(), Post GL1BCO matching, m_RefBCO (40-bit GL1BCO): "<Fill(refbcobitshift); } - while (m_InttRawHitMap.begin()->first <= select_crossings - m_intt_negative_bco) + + if (m_InttHitDuplication){ + m_InttRawHitCount_FEE.clear(); + + for (auto& [bco, hitinfo] : m_InttRawHitMap) + { + if (bco > select_crossings) + { + break; + } + + for (auto *intthititer : hitinfo.InttRawHitVector) + { + uint64_t bco_full = intthititer->get_bco(); + int FPHXbco = intthititer->get_FPHX_BCO(); + int server = intthititer->get_packetid(); // note : the felix server ID + int felix_ch = intthititer->get_fee(); // note : the felix channel ID 0 - 13 + + std::string hit_string = std::format("{}_{}_{}_{}", + bco_full, FPHXbco, server, felix_ch); + + // note: "BCOFULL_FPHXBCO_FELIX_FEE" + if (!m_InttRawHitCount_FEE.contains(hit_string)){ + m_InttRawHitCount_FEE[hit_string.c_str()] = 1; + } + else { + m_InttRawHitCount_FEE[hit_string.c_str()] += 1; + } + } + } + + if (Verbosity() > 2 && m_Intt_print_count < 10){ + for (auto &pair : m_InttRawHitCount_FEE){ + std::cout<<"m_InttRawHitCount_FEE key: "<second.InttRawHitVector) + if (bco > select_crossings) + { + break; + } + + for (auto *intthititer : hitinfo.InttRawHitVector) { if (Verbosity() > 1) { @@ -786,27 +862,102 @@ int Fun4AllStreamingInputManager::FillIntt() << intthititer->get_bco() << std::dec << std::endl; // intthititer->identify(); } + + int FPHXbco = intthititer->get_FPHX_BCO(); + if (m_IsRejectInttNoiseCrossings && m_IsInttStreaming && (FPHXbco < m_InttStreamingSignalCrossing.first || FPHXbco > m_InttStreamingSignalCrossing.second) ){ + + if (Verbosity() > 10){ + std::cout<<"Fun4AllStreamingInputManager::FillIntt(), hits with FPHX_BCO: "<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); + } + + if (m_InttHitDuplication){ + for (const auto& pair : m_InttRawHitCount_FEE){ + + uint64_t ThisStrobe_HL_bco_full = 0; + int ThisStrobe_HL_FPHXBCO = 0; + int ThisStrobe_HL_server = 0; + int ThisStrobe_HL_felix_ch = 0; + + char separator1 = 0; + char separator2 = 0; + char separator3 = 0; + + std::stringstream key_stream(pair.first); + if (!(key_stream >> ThisStrobe_HL_bco_full >> separator1 >> ThisStrobe_HL_FPHXBCO >> separator2 >> ThisStrobe_HL_server >> separator3 >> ThisStrobe_HL_felix_ch) || + separator1 != '_' || separator2 != '_' || separator3 != '_') + { + std::cerr << "Fun4AllStreamingInputManager::FillIntt(), Failed to parse hit key: " << pair.first.c_str() << std::endl; + gSystem->Exit(1); + exit(1); + } + + int ThisStrobe_HL_count_perFPHXBCO = pair.second; + + if (m_IsRejectInttNoiseCrossings && m_IsInttStreaming && (ThisStrobe_HL_FPHXBCO < m_InttStreamingSignalCrossing.first || ThisStrobe_HL_FPHXBCO > m_InttStreamingSignalCrossing.second) ){ + + if (Verbosity() > 10){ + std::cout<<"Fun4AllStreamingInputManager::FillIntt(), Doing hit duplication, half-ladder (BCOFULL_FPHXBCO_FELIXID_FELIXChannel): "<10){ + std::cout<<"Fun4AllStreamingInputManager::FillIntt(), don't see the future strobe, GL1_BCO: "<second.InttRawHitVector) + { + int server = source_hit->get_packetid(); // note : the felix server ID + int felix_ch = source_hit->get_fee(); // note : the felix channel ID 0 - 13 + int FPHXbco = source_hit->get_FPHX_BCO(); + uint64_t bco_full = source_hit->get_bco(); + + if (bco_full != future_strobe_bco_full){continue;} + if (server != ThisStrobe_HL_server){continue;} + if (felix_ch != ThisStrobe_HL_felix_ch){continue;} + + if ( + FPHXbco == ThisStrobe_HL_FPHXBCO || + (m_IsDuplicateInttFPHXBCOResetHit && std::find(m_InttResetFphxBcoVec.begin(),m_InttResetFphxBcoVec.end(), FPHXbco) != m_InttResetFphxBcoVec.end()) + ){ + auto *copied_hit = inttcont->AddHit(source_hit); + copied_hit->set_bco(ThisStrobe_HL_bco_full); + copied_hit->set_FPHX_BCO(ThisStrobe_HL_FPHXBCO); + } + } + + } + } - } - m_InttRawHitMap.begin()->second.InttRawHitVector.clear(); - m_InttRawHitMap.erase(m_InttRawHitMap.begin()); - if (m_InttRawHitMap.empty()) - { - break; - } } + return 0; } - int Fun4AllStreamingInputManager::FillMvtx() { int iret = FillMvtxPool(); @@ -846,7 +997,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 +1132,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); } } @@ -1357,6 +1460,11 @@ int Fun4AllStreamingInputManager::FillTpcPool() std::cout << "Fun4AllStreamingInputManager::FillTpcPool - fill pool for " << iter->Name() << std::endl; } iter->FillPool(ref_bco_minus_range); + const int fill_pool_status = iter->FillPoolStatus(); + if (fill_pool_status < 0) + { + return fill_pool_status; + } if (m_RunNumber == 0) { m_RunNumber = iter->RunNumber(); @@ -1386,13 +1494,20 @@ int Fun4AllStreamingInputManager::FillTpcPool() int Fun4AllStreamingInputManager::FillMicromegasPool() { + + uint64_t ref_bco_minus_range = 0; + if (m_RefBCO > m_micromegas_negative_bco) + { + ref_bco_minus_range = m_RefBCO - m_micromegas_negative_bco; + } + for (auto *iter : m_MicromegasInputVector) { if (Verbosity() > 0) { std::cout << "Fun4AllStreamingInputManager::FillMicromegasPool - fill pool for " << iter->Name() << std::endl; } - iter->FillPool(); + iter->FillPool(ref_bco_minus_range); if (m_RunNumber == 0) { m_RunNumber = iter->RunNumber(); @@ -1422,7 +1537,7 @@ int Fun4AllStreamingInputManager::FillMicromegasPool() 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) @@ -1570,3 +1685,26 @@ void Fun4AllStreamingInputManager::createQAHistos() h_tagBcoFelixAllFees_mvtx[i] = dynamic_cast(hm->getHisto((boost::format("h_MvtxPoolQA_TagBCOAllFees_Felix%i") % i).str())); } } + + +void Fun4AllStreamingInputManager::SetInttStreamingSignalCrossing(std::pair input_pair) { + + if (input_pair.first > input_pair.second) + { + std::cout << "In Fun4AllStreamingInputManager, Error: streaming signal crossing range is reversed: " + << input_pair.first << ", " << input_pair.second << std::endl; + std::exit(1); + } + + m_InttStreamingSignalCrossing = input_pair; +} + +void Fun4AllStreamingInputManager::InttHitCarryOverShiftMaxMultiple(const int i) { + if (i < 0) + { + std::cout << "In Fun4AllStreamingInputManagerm, Error: InttHitCarryOverShiftMaxMultiple must be non-negative" + << std::endl; + std::exit(1); + } + m_InttHitCarryOverShiftMaxMultiple = i; +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h index e51a59c549..86a951a8e3 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include class SingleStreamingInput; class Gl1Packet; @@ -69,6 +71,17 @@ class Fun4AllStreamingInputManager : public Fun4AllInputManager void runMvtxTriggered(bool b = true) { m_mvtx_is_triggered = b; } + // configuration for INTT hit carry-over issue mitigation (hit duplication) + void EnableInttHitDuplication(bool b = true) { m_InttHitDuplication = b; } + void SetIsRejectInttNoiseCrossings(bool b = true) {m_IsRejectInttNoiseCrossings = b;} + void SetIsInttStreaming(bool b = true) {m_IsInttStreaming = b;} + void SetIsDuplicateInttFPHXBCOResetHit(bool b = true) {m_IsDuplicateInttFPHXBCOResetHit = b;} + void SetInttResetFphxBcoVec(const std::vector& input_vec) {m_InttResetFphxBcoVec = input_vec;} + + void SetInttStreamingSignalCrossing(std::pair input_pair); + void InttHitCarryOverShiftMaxMultiple(const int i); + + private: struct MvtxRawHitInfo { @@ -159,6 +172,20 @@ class Fun4AllStreamingInputManager : public Fun4AllInputManager TH1 *h_taggedAllFees_intt[8]{nullptr}; TH1 *h_gl1taggedfee_intt[8][14]{{nullptr}}; TH2 *h_bcodiff_intt[8]{nullptr}; + + // for INTT hit carry-over issue mitigation (hit duplication) + bool m_InttHitDuplication{false}; // default to false; Should be set to true when running streaming data + const unsigned int m_InttHitCarryOverShift{120}; // 120 BCOs as the default shift. Fixed value + int m_InttHitCarryOverShiftMaxMultiple{4}; // the max multiple of the shift. For a max multiple of M, duplicate hits from N + [1..M] * shift BCOs to N + bool m_IsRejectInttNoiseCrossings{false}; // not allow hits in the abort-gap crossings being saved to the INTTRawHit container + bool m_IsInttStreaming{true}; // is INTT in the streaming readout mode + bool m_IsDuplicateInttFPHXBCOResetHit{true}; // Allow duplicating hits with FPHXBCO in the range given by std::vectorm_InttResetFphxBcoVec + + std::pair m_InttStreamingSignalCrossing{6,116}; + std::map m_InttRawHitCount_FEE; + int m_Intt_print_count{0}; + std::vector m_InttResetFphxBcoVec{0,1,2,3,4,5}; + }; #endif /* FUN4ALL_FUN4ALLSTREAMINGINPUTMANAGER_H */ diff --git a/offline/framework/fun4allraw/Makefile.am b/offline/framework/fun4allraw/Makefile.am index ef0c1b54a2..1cd5a80afa 100644 --- a/offline/framework/fun4allraw/Makefile.am +++ b/offline/framework/fun4allraw/Makefile.am @@ -37,7 +37,9 @@ pkginclude_HEADERS = \ SingleTpcPoolInput.h \ SingleTriggeredInput.h \ SingleTpcTimeFrameInput.h \ - TpcTimeFrameBuilder.h + TpcTimeFrameBuilder.h \ + TpcTimeFrameBuilderBase.h \ + TpcTimeFrameBuilderRun3.h decoderincludedir = $(includedir)/mvtx_decoder decoderinclude_HEADERS = \ @@ -92,7 +94,8 @@ libfun4allraw_la_SOURCES = \ SingleTpcPoolInput.cc \ SingleTriggeredInput.cc \ SingleTpcTimeFrameInput.cc \ - TpcTimeFrameBuilder.cc + TpcTimeFrameBuilder.cc \ + TpcTimeFrameBuilderRun3.cc libfun4allraw_la_LIBADD = \ libmvtx_decoder.la \ @@ -100,7 +103,9 @@ libfun4allraw_la_LIBADD = \ -lfun4all \ -lEvent \ -lphoolraw \ - -lqautils + -lqautils \ + -lffamodules \ + -lcdbobjects BUILT_SOURCES = testexternals.cc diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc index 31524e97f4..954ab59f18 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.cc @@ -19,8 +19,6 @@ namespace { - // streamer for lists - // streamer for lists template std::ostream& operator<<(std::ostream& o, const std::list& list) @@ -82,15 +80,8 @@ namespace return o; } - // get the difference between two BCO. - template - constexpr T get_bco_diff(const T& first, const T& second) - { - return first < second ? (second - first) : (first - second); - } - // define limit for matching two fee_bco - constexpr unsigned int m_max_fee_bco_diff = 10; + constexpr uint32_t m_max_fee_bco_diff = 10; // needed to avoid memory leak. Assumes that we will not be assembling more than 50 events at the same time constexpr unsigned int m_max_matching_data_size = 50; @@ -98,6 +89,19 @@ namespace //! copied from micromegas/MicromegasDefs.h, not available here constexpr int m_nchannels_fee = 256; + // gtm clock bits + /* used for rollover calculation */ + constexpr unsigned int m_GTM_CLOCK_BITS = 40U; + constexpr uint64_t m_GTM_CLOCK_MASK = (1ULL << m_GTM_CLOCK_BITS)-1; + constexpr int64_t m_GTM_CLOCK_RANGE = 1ULL << m_GTM_CLOCK_BITS; + constexpr int64_t m_GTM_CLOCK_HALF_RANGE = 1ULL << (m_GTM_CLOCK_BITS-1); + + // Fee clock bits + constexpr unsigned int m_FEE_CLOCK_BITS = 20U; + constexpr uint32_t m_FEE_CLOCK_MASK = (1UL << m_FEE_CLOCK_BITS)-1ULL; + constexpr int32_t m_FEE_CLOCK_RANGE = 1UL << m_FEE_CLOCK_BITS; + constexpr int32_t m_FEE_CLOCK_HALF_RANGE = 1UL << (m_FEE_CLOCK_BITS-1UL); + /* see: https://git.racf.bnl.gov/gitea/Instrumentation/sampa_data/src/branch/fmtv2/README.md */ enum SampaDataType { @@ -116,21 +120,65 @@ namespace BX_COUNTER_SYNC_T = 0b001, ELINK_HEARTBEAT_T = 0b010 }; + } // namespace -// this is the clock multiplier from lvl1 to fee clock +//! this is the clock multiplier from lvl1 to fee clock bool MicromegasBcoMatchingInformation_v2::m_multiplier_is_set = false; double MicromegasBcoMatchingInformation_v2::m_multiplier = 0; -// true if on-fly multiplier adjustment is enabled +//! true if on-fly multiplier adjustment is enabled bool MicromegasBcoMatchingInformation_v2::m_multiplier_adjustment_enabled = true; -// muliplier adjustment count +//! muliplier adjustment count /* controls how often the gtm multiplier is automatically adjusted */ unsigned int MicromegasBcoMatchingInformation_v2::m_max_multiplier_adjustment_count = 200; -// define limit for matching fee_bco to fee_bco_predicted -unsigned int MicromegasBcoMatchingInformation_v2::m_max_gtm_bco_diff = 100; +//! define limit for matching fee_bco to fee_bco_predicted +unsigned int MicromegasBcoMatchingInformation_v2::m_max_gtm_bco_diff = 60; + +//! Max time forward to ensure that a given +unsigned int MicromegasBcoMatchingInformation_v2::m_max_fee_sync_time = 1024 * 96; + +//___________________________________________________ +int64_t MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff(uint64_t first, uint64_t second) +{ + // calculate raw diff + int64_t diff = static_cast(first & m_GTM_CLOCK_MASK) - static_cast(second & m_GTM_CLOCK_MASK); + + // make sure result is within +/- m_GTM_CLOCK_HALF_RANGE + if (diff > m_GTM_CLOCK_HALF_RANGE) { diff -= m_GTM_CLOCK_RANGE; } + else if (diff < -m_GTM_CLOCK_HALF_RANGE) { diff += m_GTM_CLOCK_RANGE; } + + return diff; +} + +//___________________________________________________ +int32_t MicromegasBcoMatchingInformation_v2::get_signed_fee_bco_diff(uint32_t first, uint32_t second) +{ + // calculate raw diff + int32_t diff = static_cast(first & m_FEE_CLOCK_MASK) - static_cast(second & m_FEE_CLOCK_MASK); + + // make sure result is within +/- m_FEE_CLOCK_HALF_RANGE + if (diff > m_FEE_CLOCK_HALF_RANGE) { diff -= m_FEE_CLOCK_RANGE; } + else if (diff < -m_FEE_CLOCK_HALF_RANGE) { diff += m_FEE_CLOCK_RANGE; } + + return diff; +} + +//___________________________________________________ +uint64_t MicromegasBcoMatchingInformation_v2::get_unsigned_gtm_bco_diff(uint64_t first, uint64_t second) +{ + const auto diff = get_signed_gtm_bco_diff(first, second); + return uint64_t((diff<0) ? -diff:diff); +} + +//___________________________________________________ +uint32_t MicromegasBcoMatchingInformation_v2::get_unsigned_fee_bco_diff(uint32_t first, uint32_t second) +{ + const auto diff = get_signed_fee_bco_diff(first, second); + return uint32_t((diff<0) ? -diff:diff); +} //___________________________________________________ std::optional MicromegasBcoMatchingInformation_v2::get_predicted_fee_bco(uint64_t gtm_bco) const @@ -141,12 +189,12 @@ std::optional MicromegasBcoMatchingInformation_v2::get_predicted_fee_b return std::nullopt; } - // get gtm bco difference with proper rollover accounting - const uint64_t gtm_bco_difference = (gtm_bco >= m_gtm_bco_first) ? (gtm_bco - m_gtm_bco_first) : (gtm_bco + (1ULL << 40U) - m_gtm_bco_first); + // get gtm bco difference + const int64_t gtm_bco_difference = get_signed_gtm_bco_diff(gtm_bco, m_bco_reference.second); // convert to fee bco, and truncate to 20 bits - const uint64_t fee_bco_predicted = m_fee_bco_first + get_adjusted_multiplier() * gtm_bco_difference; - return uint32_t(fee_bco_predicted & 0xFFFFFU); + const int64_t fee_bco_predicted = m_bco_reference.first + get_adjusted_multiplier() * gtm_bco_difference; + return static_cast(fee_bco_predicted) & m_FEE_CLOCK_MASK; } //___________________________________________________ @@ -178,6 +226,34 @@ void MicromegasBcoMatchingInformation_v2::print_gtm_bco_information() const } } +//___________________________________________________ +bool MicromegasBcoMatchingInformation_v2::is_more_data_required( uint64_t gtm_bco ) const +{ + // check proper initialization + if( !is_verified() ) { return true; } + + // compare to reference + if( get_signed_gtm_bco_diff( m_bco_reference.second, gtm_bco ) > m_max_fee_sync_time ) + { return false; } + + // check against stored bco + if( !m_gtm_bco_list.empty() ) + { + if( get_signed_gtm_bco_diff( m_gtm_bco_list.back(), gtm_bco ) > m_max_fee_sync_time ) + { return false; } + } + + // check against matched BCOs + if( !m_bco_matching_list.empty() ) + { + if( get_signed_gtm_bco_diff( m_bco_matching_list.back().second, gtm_bco ) > m_max_fee_sync_time ) + { return false; } + } + + return true; +} + + //___________________________________________________ void MicromegasBcoMatchingInformation_v2::save_gtm_bco_information(int /*packet_id*/, const MicromegasBcoMatchingInformation_v2::gtm_payload& payload) { @@ -193,7 +269,7 @@ void MicromegasBcoMatchingInformation_v2::save_gtm_bco_information(int /*packet_ const auto& gtm_bco = payload.bco; // add to list if difference to last entry is big enough - if (m_gtm_bco_list.empty() || (gtm_bco - m_gtm_bco_list.back()) > 10) + if (m_gtm_bco_list.empty() || get_signed_gtm_bco_diff(gtm_bco,m_gtm_bco_list.back()) > 10) { m_gtm_bco_list.push_back(gtm_bco); } @@ -225,8 +301,7 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_modebits(const Mic // get BCO and assign const auto& gtm_bco = payload.bco; - m_gtm_bco_first = gtm_bco; - m_fee_bco_first = 0; + m_bco_reference = {0, gtm_bco}; m_verified_from_modebits = true; return true; } @@ -239,16 +314,15 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_pay { // store gtm bco and diff to previous in an array std::vector gtm_bco_list; - std::vector gtm_bco_diff_list; + std::vector fee_bco_diff_list; for (const auto& gtm_bco : m_gtm_bco_list) { if (!gtm_bco_list.empty()) { // add difference to last // get gtm bco difference with proper rollover accounting - const uint64_t gtm_bco_difference = (gtm_bco >= gtm_bco_list.back()) ? (gtm_bco - gtm_bco_list.back()) : (gtm_bco + (1ULL << 40U) - gtm_bco_list.back()); - - gtm_bco_diff_list.push_back(get_adjusted_multiplier() * gtm_bco_difference); + const int64_t gtm_bco_difference = get_signed_gtm_bco_diff( gtm_bco, gtm_bco_list.back() ); + fee_bco_diff_list.push_back(get_adjusted_multiplier() * gtm_bco_difference); } // append to list @@ -258,7 +332,7 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_pay // print all differences if (verbosity()) { - std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - gtm_bco_diff_list: " << gtm_bco_diff_list << std::endl; + std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - fee_bco_diff_list: " << fee_bco_diff_list << std::endl; } // skip hearbeat @@ -282,7 +356,7 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_pay } // calculate difference - const uint64_t fee_bco_diff = get_bco_diff(fee_bco, m_fee_bco_prev); + const uint32_t fee_bco_diff = get_unsigned_fee_bco_diff(fee_bco, m_fee_bco_prev); // discard identical fee_bco if (fee_bco_diff < m_max_fee_bco_diff) @@ -293,28 +367,27 @@ bool MicromegasBcoMatchingInformation_v2::find_reference_from_data(const fee_pay std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - fee_bco_diff: " << fee_bco_diff << std::endl; // look for matching diff in gtm_bco array - for (size_t i = 0; i < gtm_bco_diff_list.size(); ++i) + for (size_t i = 0; i < fee_bco_diff_list.size(); ++i) { - uint64_t sum = 0; - for (size_t j = i; j < gtm_bco_diff_list.size(); ++j) + uint32_t sum = 0; + for (size_t j = i; j < fee_bco_diff_list.size(); ++j) { - sum += gtm_bco_diff_list[j]; - if (get_bco_diff(sum, fee_bco_diff) < m_max_fee_bco_diff) + sum += fee_bco_diff_list[j]; + if (get_unsigned_fee_bco_diff(sum, fee_bco_diff) < m_max_fee_bco_diff) { m_verified_from_data = true; - m_gtm_bco_first = gtm_bco_list[i]; - m_fee_bco_first = m_fee_bco_prev; + m_bco_reference = { m_fee_bco_prev, gtm_bco_list[i] }; if (verbosity()) { std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data - matching is verified" << std::endl; std::cout << "MicromegasBcoMatchingInformation_v2::find_reference_from_data -" - << " m_gtm_bco_first: " << std::hex << m_gtm_bco_first << std::dec - << std::endl; - std::cout - << "MicromegasBcoMatchingInformation_v2::find_reference_from_data -" - << " m_fee_bco_first: " << std::hex << m_fee_bco_first << std::dec + << std::hex + << " m_bco_reference: ( 0x" + << m_bco_reference.first + << ", 0x" << m_bco_reference.second << ")" + << std::dec << std::endl; } return true; @@ -341,18 +414,19 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa m_bco_matching_list.begin(), m_bco_matching_list.end(), [fee_bco](const m_bco_matching_pair_t& pair) - { return get_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; }); + { return get_unsigned_fee_bco_diff(pair.first, fee_bco) < m_max_fee_bco_diff; }); if (bco_matching_iter != m_bco_matching_list.end()) { return bco_matching_iter->second; } + // find element for which predicted fee_bco matches fee_bco, within limit const auto iter = std::find_if( m_gtm_bco_list.begin(), m_gtm_bco_list.end(), [this, fee_bco](const uint64_t& gtm_bco) - { return get_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; }); + { return get_unsigned_fee_bco_diff(get_predicted_fee_bco(gtm_bco).value(), fee_bco) < m_max_gtm_bco_diff; }); // check if (iter != m_gtm_bco_list.end()) @@ -363,18 +437,18 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa if (auto opt_fee_bco = get_predicted_fee_bco(gtm_bco)) // check if optional exists { const auto fee_bco_predicted = *opt_fee_bco; // get_predicted_fee_bco(gtm_bco).value(); - const auto fee_bco_diff = get_bco_diff(fee_bco_predicted, fee_bco); + const auto fee_bco_diff = get_unsigned_fee_bco_diff(fee_bco_predicted, fee_bco); std::cout << "MicromegasBcoMatchingInformation_v2::find_gtm_bco -" - << " packet_id: " << packet_id - << " fee_id: " << fee_id - << std::hex - << " fee_bco: 0x" << fee_bco - << " predicted: 0x" << fee_bco_predicted - << " gtm_bco: 0x" << gtm_bco - << std::dec - << " difference: " << fee_bco_diff - << std::endl; + << " packet_id: " << packet_id + << " fee_id: " << fee_id + << std::hex + << " fee_bco: 0x" << fee_bco + << " predicted: 0x" << fee_bco_predicted + << " gtm_bco: 0x" << gtm_bco + << std::dec + << " difference: " << fee_bco_diff + << std::endl; } } // save fee_bco and gtm_bco matching in map @@ -401,9 +475,8 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa m_gtm_bco_list.begin(), m_gtm_bco_list.end(), [this, fee_bco](const uint64_t& first, const uint64_t& second) - { return get_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); }); + { return get_unsigned_fee_bco_diff(get_predicted_fee_bco(first).value(), fee_bco) < get_unsigned_fee_bco_diff(get_predicted_fee_bco(second).value(), fee_bco); }); - // const int fee_bco_diff = (iter2 != m_gtm_bco_list.end()) ? get_bco_diff(get_predicted_fee_bco(*iter2).value(), fee_bco) : -1; // compared to the previous statement, this checks if the optional int fee_bco_diff = -1; @@ -413,7 +486,7 @@ std::optional MicromegasBcoMatchingInformation_v2::find_gtm_bco(int pa if (predicted) { - fee_bco_diff = get_bco_diff(*predicted, fee_bco); + fee_bco_diff = get_unsigned_fee_bco_diff(*predicted, fee_bco); } } @@ -452,14 +525,13 @@ void MicromegasBcoMatchingInformation_v2::cleanup() void MicromegasBcoMatchingInformation_v2::cleanup(uint64_t ref_bco) { // erase all elements from bco_list that are less than or equal to ref_bco - m_gtm_bco_list.erase(std::remove_if(m_gtm_bco_list.begin(), m_gtm_bco_list.end(), [ref_bco](const uint64_t& bco) - { return bco <= ref_bco; }), - m_gtm_bco_list.end()); + m_gtm_bco_list.erase(std::remove_if(m_gtm_bco_list.begin(), m_gtm_bco_list.end(), + [ref_bco](const uint64_t& bco) { return get_signed_gtm_bco_diff( bco,ref_bco ) <= 0; }), m_gtm_bco_list.end()); // erase all elements from bco_list that are less than or equal to ref_bco - m_bco_matching_list.erase(std::remove_if(m_bco_matching_list.begin(), m_bco_matching_list.end(), [ref_bco](const m_bco_matching_pair_t& pair) - { return pair.second <= ref_bco; }), - m_bco_matching_list.end()); + m_bco_matching_list.erase(std::remove_if(m_bco_matching_list.begin(), m_bco_matching_list.end(), + [ref_bco](const m_bco_matching_pair_t& pair) { return get_signed_gtm_bco_diff( pair.second, ref_bco ) <= 0; }), + m_bco_matching_list.end()); // clear orphans m_orphans.clear(); @@ -481,7 +553,7 @@ void MicromegasBcoMatchingInformation_v2::update_multiplier_adjustment(uint64_t } // skip if trivial - if (gtm_bco == m_gtm_bco_first) + if (gtm_bco == m_bco_reference.second) { return; } @@ -494,12 +566,12 @@ void MicromegasBcoMatchingInformation_v2::update_multiplier_adjustment(uint64_t gSystem->Exit(1); exit(1); } - const uint32_t fee_bco_predicted = *predicted_opt; - const double delta_fee_bco = double(fee_bco) - double(fee_bco_predicted); - const double gtm_bco_difference = (gtm_bco >= m_gtm_bco_first) ? (gtm_bco - m_gtm_bco_first) : (gtm_bco + (1ULL << 40U) - m_gtm_bco_first); + const uint32_t fee_bco_predicted = predicted_opt.value(); + const double delta_fee_bco = get_signed_fee_bco_diff(fee_bco,fee_bco_predicted); + const double gtm_bco_difference = get_signed_gtm_bco_diff(gtm_bco,m_bco_reference.second); - m_multiplier_adjustment_numerator += gtm_bco_difference * delta_fee_bco; - m_multiplier_adjustment_denominator += gtm_bco_difference * gtm_bco_difference; + m_multiplier_adjustment_numerator += gtm_bco_difference*delta_fee_bco; + m_multiplier_adjustment_denominator += gtm_bco_difference*gtm_bco_difference; ++m_multiplier_adjustment_count; if (verbosity()) diff --git a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h index 1b25f8d8a8..643b56a7b9 100644 --- a/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h +++ b/offline/framework/fun4allraw/MicromegasBcoMatchingInformation_v2.h @@ -97,18 +97,19 @@ class MicromegasBcoMatchingInformation_v2 //! print gtm bco information void print_gtm_bco_information() const; - //! get first gtm bco - unsigned int get_fee_bco_first() const - { return m_fee_bco_first; } - - //! get first gtm bco - uint64_t get_gtm_bco_first() const - { return m_gtm_bco_first; } + //! get BCO matching reference + using m_bco_matching_pair_t = std::pair; + const m_bco_matching_pair_t& get_bco_matching_reference() const + { return m_bco_reference; } //! get last gtm bco uint64_t get_gtm_bco_last() const { return m_gtm_bco_list.empty() ? 0:*m_gtm_bco_list.rbegin(); } + //! returns true if more data needs to be fetched. + /** it is based on the latest BCO read from the data stream, from either tagger or heartbeat */ + bool is_more_data_required(uint64_t /*gtm_bco*/) const; + //@} //!@name modifiers @@ -144,6 +145,12 @@ class MicromegasBcoMatchingInformation_v2 m_max_gtm_bco_diff = value; } + //! max time in GTM BCO for FEE data to sync over to datastream + static void set_m_max_fee_sync_time( unsigned int value ) + { + m_max_fee_sync_time = value; + } + //! find reference from modebits bool find_reference_from_modebits(const gtm_payload&); @@ -168,6 +175,25 @@ class MicromegasBcoMatchingInformation_v2 //@} + //!@name utilities + //@{ + + //! get difference between two GTM BCO, properly accounting for 40bits rollover + /** based on Jin's code in TpcTimeFrameBuilder */ + static int64_t get_signed_gtm_bco_diff(uint64_t /*first*/, uint64_t /*second*/); + + //! get difference between two FEE BCO, properly accounting for 20bits rollover + /** based on Jin's code in TpcTimeFrameBuilder */ + static int32_t get_signed_fee_bco_diff(uint32_t /*first*/, uint32_t /*second*/); + + //! get difference between two GTM BCO, properly accounting for 40bits rollover + static uint64_t get_unsigned_gtm_bco_diff(uint64_t /*first*/, uint64_t /*second*/); + + //! get difference between two FEE BCO, properly accounting for 20bits rollover + static uint32_t get_unsigned_fee_bco_diff(uint32_t /*first*/, uint32_t /*second*/); + + //@} + private: //! update multiplier adjustment @@ -178,15 +204,8 @@ class MicromegasBcoMatchingInformation_v2 //! verified bool m_verified_from_modebits = false; - bool m_verified_from_data = false; - //! first lvl1 bco (40 bits) - uint64_t m_gtm_bco_first = 0; - - //! first fee bco (20 bits) - uint32_t m_fee_bco_first = 0; - //! last found fee_bco /** used to try finding bco reference from data */ uint32_t m_fee_bco_prev = 0; @@ -195,8 +214,10 @@ class MicromegasBcoMatchingInformation_v2 //! list of available bco std::list m_gtm_bco_list; + //! reference matching + m_bco_matching_pair_t m_bco_reference; + //! matching between fee bco and lvl1 bco - using m_bco_matching_pair_t = std::pair; std::list m_bco_matching_list; //! keep track or fee_bco for which no gtm_bco is found @@ -218,6 +239,9 @@ class MicromegasBcoMatchingInformation_v2 // define limit for matching fee_bco to fee_bco_predicted static unsigned int m_max_gtm_bco_diff; + //! max time in GTM BCO for FEE data to sync over to datastream + static unsigned int m_max_fee_sync_time; + //! adjustment to multiplier double m_multiplier_adjustment = 0; diff --git a/offline/framework/fun4allraw/SingleInttPoolInput.cc b/offline/framework/fun4allraw/SingleInttPoolInput.cc index 7bca9bc8b6..fd8effd719 100644 --- a/offline/framework/fun4allraw/SingleInttPoolInput.cc +++ b/offline/framework/fun4allraw/SingleInttPoolInput.cc @@ -466,7 +466,7 @@ bool SingleInttPoolInput::GetSomeMoreEvents(const uint64_t ibclk) std::set toerase; for (auto bcliter : m_FEEBclkMap) { - if (bcliter.second <= localbclk) + if (bcliter.second <= localbclk + 120 * 40) { uint64_t highest_bclk = m_InttRawHitMap.rbegin()->first; if ((highest_bclk - m_InttRawHitMap.begin()->first) < MaxBclkDiff()) diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 7500e3badf..6248c1a506 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -142,6 +142,8 @@ namespace } // namespace +using MicromegasRawHit_impl = MicromegasRawHitv3; + //______________________________________________________________ SingleMicromegasPoolInput_v2::SingleMicromegasPoolInput_v2(const std::string& name) : SingleStreamingInput(name) @@ -228,12 +230,11 @@ SingleMicromegasPoolInput_v2::~SingleMicromegasPoolInput_v2() } //______________________________________________________________ -void SingleMicromegasPoolInput_v2::FillPool(const unsigned int /*nbclks*/) +void SingleMicromegasPoolInput_v2::FillPool(const uint64_t target_bco) { + if (AllDone()) // no more files and all events read - { - return; - } + { return; } while (!GetEventiterator()) // at startup this is a null pointer { @@ -244,9 +245,8 @@ void SingleMicromegasPoolInput_v2::FillPool(const unsigned int /*nbclks*/) } } - while (GetSomeMoreEvents()) + while( is_more_data_required(target_bco) ) { - // std::cout << "SingleMicromegasPoolInput_v2::FillPool" << std::endl; std::unique_ptr evt(GetEventiterator()->getNextEvent()); while (!evt) { @@ -309,6 +309,13 @@ void SingleMicromegasPoolInput_v2::FillPool(const unsigned int /*nbclks*/) m_timer.stop(); } + + if( m_do_evaluation ) + { fill_evaluation_tree( target_bco ); } + + // recover truncated FEEs for target bco + if( m_recover_truncated_waveforms ) { recover_truncated_waveforms( target_bco ); } + } //______________________________________________________________ @@ -325,63 +332,38 @@ void SingleMicromegasPoolInput_v2::Print(const std::string& what) const } } } - - if (what == "ALL" || what == "FEEBCLK") - { - for (auto bcliter : m_FEEBclkMap) - { - std::cout << "FEE" << bcliter.first << " bclk: 0x" - << std::hex << bcliter.second << std::dec << std::endl; - } - } - - if (what == "ALL" || what == "STORAGE") - { - for (const auto& bcliter : m_MicromegasRawHitMap) - { - std::cout << "Beam clock 0x" << std::hex << bcliter.first << std::dec << std::endl; - for (auto* feeiter : bcliter.second) - { - std::cout - << "fee: " << feeiter->get_fee() - << " at " << std::hex << feeiter << std::dec - << std::endl; - } - } - } - - if (what == "ALL" || what == "STACK") - { - for (const auto& iter : m_BclkStack) - { - std::cout << "stacked bclk: 0x" << std::hex << iter << std::dec << std::endl; - } - } } //____________________________________________________________________________ void SingleMicromegasPoolInput_v2::CleanupUsedPackets(const uint64_t bclk, bool dropped) { // delete all raw hits associated to bco smaller than reference, and remove from map - for (auto iter = m_MicromegasRawHitMap.begin(); iter != m_MicromegasRawHitMap.end() && (iter->first <= bclk); iter = m_MicromegasRawHitMap.erase(iter)) + // loop over per-FEE maps + for( auto&& rawhitmap: m_MicromegasRawHitMap ) { - for (const auto& rawhit : iter->second) + // loop over rawhit lists for which gtm bco is below request + // delete hits in list and remove list from map + for (auto iter = rawhitmap.begin(); iter != rawhitmap.end() && (iter->first <= bclk); iter = rawhitmap.erase(iter)) { - if (dropped) + for (const auto& rawhit : iter->second) { - // increment dropped waveform counter and histogram - ++m_waveform_counters[rawhit->get_packetid()].dropped_pool; - ++m_fee_waveform_counters[rawhit->get_fee()].dropped_pool; - h_waveform_count_dropped_pool->Fill(std::to_string(rawhit->get_packetid()).c_str(), 1); - h_fee_waveform_count_dropped_pool->Fill(rawhit->get_fee(), 1); + // increment dropped waveform counters + if (dropped) + { + // increment dropped waveform counter and histogram + ++m_waveform_counters[rawhit->get_packetid()].dropped_pool; + ++m_fee_waveform_counters[rawhit->get_fee()].dropped_pool; + h_waveform_count_dropped_pool->Fill(std::to_string(rawhit->get_packetid()).c_str(), 1); + h_fee_waveform_count_dropped_pool->Fill(rawhit->get_fee(), 1); + } + + // delete raw hit + delete rawhit; } - delete rawhit; } } // cleanup bco stacks - /* it erases all elements for which the bco is no greater than the provided one */ - m_BclkStack.erase(m_BclkStack.begin(), m_BclkStack.upper_bound(bclk)); m_BeamClockFEE.erase(m_BeamClockFEE.begin(), m_BeamClockFEE.upper_bound(bclk)); m_BeamClockPacket.erase(m_BeamClockPacket.begin(), m_BeamClockPacket.upper_bound(bclk)); @@ -395,51 +377,26 @@ void SingleMicromegasPoolInput_v2::CleanupUsedPackets(const uint64_t bclk, bool //_______________________________________________________ void SingleMicromegasPoolInput_v2::ClearCurrentEvent() { - std::cout << "SingleMicromegasPoolInput_v2::ClearCurrentEvent." << std::endl; - uint64_t currentbclk = *m_BclkStack.begin(); - CleanupUsedPackets(currentbclk); - return; + std::cout << "SingleTpcTimeFrameInput::ClearCurrentEvent() - deprecated " << std::endl; } //_______________________________________________________ -bool SingleMicromegasPoolInput_v2::GetSomeMoreEvents() +bool SingleMicromegasPoolInput_v2::is_more_data_required(const uint64_t target_bco) const { if (AllDone()) { return false; } - // check minimum pool size - if (m_MicromegasRawHitMap.size() < m_BcoPoolSize) - { - return true; - } - - // make sure that the latest BCO received by each FEEs is past the current BCO - std::set toerase; - uint64_t lowest_bclk = m_MicromegasRawHitMap.begin()->first + m_BcoRange; - for (auto bcliter : m_FEEBclkMap) - { - if (bcliter.second <= lowest_bclk) - { - uint64_t highest_bclk = m_MicromegasRawHitMap.rbegin()->first; - if ((highest_bclk - m_MicromegasRawHitMap.begin()->first) < MaxBclkDiff()) - { - return true; - } + if( m_bco_matching_information_map.empty() ) + { return true; } - std::cout << PHWHERE << Name() << ": erasing FEE " << bcliter.first - << " with stuck bclk: " << std::hex << bcliter.second - << " current bco range: 0x" << m_MicromegasRawHitMap.begin()->first - << ", to: 0x" << highest_bclk << ", delta: " << std::dec - << (highest_bclk - m_MicromegasRawHitMap.begin()->first) - << std::dec << std::endl; - toerase.insert(bcliter.first); - } - } - for (const auto& fee : toerase) + // correct target_bco by negative BCO and Tagger offset + const uint64_t target_bco_corrected = target_bco + m_NegativeBco + m_TaggerBcoOffset; + for( const auto& [packet, bco_matching_information]:m_bco_matching_information_map ) { - m_FEEBclkMap.erase(fee); + if( bco_matching_information.is_more_data_required( target_bco_corrected ) ) + { return true; } } return false; @@ -502,10 +459,12 @@ void SingleMicromegasPoolInput_v2::FillBcoQA(uint64_t gtm_bco) } // waveforms - const auto wf_iter = m_MicromegasRawHitMap.find(gtm_bco_loc); - if (wf_iter != m_MicromegasRawHitMap.end()) + // loop over FEEs, find gtm bco and increment by number of rawhits in corresponding list + for( const auto& rawhitmap:m_MicromegasRawHitMap ) { - n_waveforms += wf_iter->second.size(); + const auto wf_iter = rawhitmap.find(gtm_bco_loc); + if (wf_iter != rawhitmap.end()) + { n_waveforms += wf_iter->second.size(); } } } @@ -524,6 +483,7 @@ void SingleMicromegasPoolInput_v2::FillBcoQA(uint64_t gtm_bco) // how many waveforms found for this BCO h_waveform->Fill(n_waveforms); } + //_______________________________________________________ void SingleMicromegasPoolInput_v2::createQAHistos() { @@ -606,19 +566,18 @@ 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("packet_id", &m_waveform.packet_id); m_evaluation_tree->Branch("fee_id", &m_waveform.fee_id); m_evaluation_tree->Branch("channel", &m_waveform.channel); m_evaluation_tree->Branch("gtm_bco_first", &m_waveform.gtm_bco_first); - m_evaluation_tree->Branch("gtm_bco", &m_waveform.gtm_bco); - m_evaluation_tree->Branch("gtm_bco_matched", &m_waveform.gtm_bco_matched); + m_evaluation_tree->Branch("gtm_bco_tagger", &m_waveform.gtm_bco_tagger); + m_evaluation_tree->Branch("gtm_bco_gl1", &m_waveform.gtm_bco_gl1); m_evaluation_tree->Branch("fee_bco_first", &m_waveform.fee_bco_first); m_evaluation_tree->Branch("fee_bco", &m_waveform.fee_bco); - m_evaluation_tree->Branch("fee_bco_predicted", &m_waveform.fee_bco_predicted); - m_evaluation_tree->Branch("fee_bco_predicted_matched", &m_waveform.fee_bco_predicted_matched); + m_evaluation_tree->Branch("fee_bco_predicted_tagger", &m_waveform.fee_bco_predicted_tagger); + m_evaluation_tree->Branch("fee_bco_predicted_gl1", &m_waveform.fee_bco_predicted_gl1); } } @@ -703,6 +662,10 @@ void SingleMicromegasPoolInput_v2::process_packet(Packet* packet) // populate fee buffer if (fee_id < MAX_FEECOUNT) { + + // update FEE packet ID + m_fee_packet[fee_id] = packet_id; + // NOLINTNEXTLINE(modernize-loop-convert) for (unsigned int i = 0; i < DAM_DMA_WORD_LENGTH - 1; i++) { @@ -711,6 +674,7 @@ void SingleMicromegasPoolInput_v2::process_packet(Packet* packet) // immediate fee buffer processing to reduce memory consuption process_fee_data(packet_id, fee_id); + } } } @@ -758,7 +722,6 @@ void SingleMicromegasPoolInput_v2::decode_gtm_data(int packet_id, const SingleMi { const auto& gtm_bco = payload.bco; m_BeamClockPacket[gtm_bco].insert(packet_id); - m_BclkStack.insert(gtm_bco); } // find reference from modebits, using BX_COUNTER_SYNC_T @@ -767,25 +730,6 @@ void SingleMicromegasPoolInput_v2::decode_gtm_data(int packet_id, const SingleMi * because any BX_COUNTER_SYNC_T event will break past references */ bco_matching_information.find_reference_from_modebits(payload); - - // store in running waveform - if (m_do_evaluation) - { - m_waveform.packet_id = packet_id; - m_waveform.gtm_bco_first = bco_matching_information.get_gtm_bco_first(); - m_waveform.gtm_bco = bco_matching_information.get_gtm_bco_last(); - - { - const auto predicted = bco_matching_information.get_predicted_fee_bco(m_waveform.gtm_bco); - ; - if (predicted) - { - m_waveform.fee_bco_predicted = predicted.value(); - } - } - - m_waveform.fee_bco_first = bco_matching_information.get_fee_bco_first(); - } } //____________________________________________________________________ @@ -920,9 +864,9 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int { // assign gtm bco gtm_bco = result.value(); - } - else - { + + } else { + // increment counter and histogram ++m_waveform_counters[packet_id].dropped_bco; ++m_fee_waveform_counters[fee_id].dropped_bco; @@ -939,26 +883,6 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int 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; - { - 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(); - } - // ignore heartbeat waveforms if (is_heartbeat) { @@ -976,12 +900,13 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int { if (Verbosity()) { - std::cout << "SingleMicromegasPoolInput_v2::process_fee_data -" - << " samples: " << samples - << " pos: " << pos - << " pkt_length: " << pkt_length - << " format error" - << std::endl; + std::cout + << "SingleMicromegasPoolInput_v2::process_fee_data -" + << " samples: " << samples + << " pos: " << pos + << " pkt_length: " << pkt_length + << " format error" + << std::endl; } break; } @@ -997,7 +922,7 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int } // create new hit - auto newhit = std::make_unique(); + auto newhit = std::make_unique(); newhit->set_bco(fee_bco); newhit->set_gtm_bco(gtm_bco); @@ -1015,13 +940,241 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int } m_BeamClockFEE[gtm_bco].insert(fee_id); - m_FEEBclkMap[fee_id] = gtm_bco; + // add hit to streaming input manager if (StreamingInputManager()) + { StreamingInputManager()->AddMicromegasRawHit(gtm_bco, newhit.get()); } + + // add to local map + m_MicromegasRawHitMap[fee_id][gtm_bco].emplace_back(newhit.release()); + } +} + +//____________________________________________________________________ +void SingleMicromegasPoolInput_v2::fill_evaluation_tree( const uint64_t target_bco ) +{ + + // loop over fees + for( size_t fee = 0; fee < MAX_FEECOUNT; ++fee ) + { + + // get local raw hitmap + auto&& rawhitmap = m_MicromegasRawHitMap[fee]; + if( rawhitmap.empty() ) { continue; } + + // get the relevant BCO matching information object + const auto& bco_matching_information = m_bco_matching_information_map.at( m_fee_packet[fee] ); + if( !bco_matching_information.is_verified() ) + { continue; } + + m_waveform.packet_id = m_fee_packet[fee]; + m_waveform.fee_id = fee; + m_waveform.gtm_bco_first = bco_matching_information.get_bco_matching_reference().second; + m_waveform.fee_bco_first = bco_matching_information.get_bco_matching_reference().first; + + // assign target bco and prediction + m_waveform.gtm_bco_gl1 = target_bco; + + // get prediction + const uint64_t target_bco_corrected = target_bco + m_NegativeBco + m_TaggerBcoOffset; + m_waveform.fee_bco_predicted_gl1 = bco_matching_information.get_predicted_fee_bco(target_bco_corrected).value(); + + // find matching bco if any and store raw hits + // list of raw hits (channel ordered) matching target BCO + for( auto&& [bco, rawhitlist]:rawhitmap ) { - StreamingInputManager()->AddMicromegasRawHit(gtm_bco, newhit.get()); + + // compare bco to target, within acceptable range + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco_corrected ); + if( bco_diff >= -(int64_t)m_NegativeBco && bco_diff < m_BcoRange ) + { + + // assign found bco and prediction + m_waveform.gtm_bco_tagger = bco; + m_waveform.fee_bco_predicted_tagger = bco_matching_information.get_predicted_fee_bco(bco).value(); + for( auto&& rawhit:rawhitlist ) + { + m_waveform.channel = rawhit->get_channel(); + m_waveform.fee_bco = rawhit->get_bco(); + m_evaluation_tree->Fill(); + } + break; + } } - m_MicromegasRawHitMap[gtm_bco].push_back(newhit.release()); - } + } // FEE loop +} + +//____________________________________________________________________ +void SingleMicromegasPoolInput_v2::recover_truncated_waveforms( const uint64_t target_bco ) +{ + + // TODO: consolidate everything (ahah) + + static constexpr int32_t kTruncatedWaveformWindow = 1024U; + static constexpr int32_t kFEEClockPerADCClock = 2U; + static constexpr int32_t kTruncatedWaveformFEEWindow = kTruncatedWaveformWindow*kFEEClockPerADCClock; + + // keep track of exact BCO + const uint64_t target_bco_corrected = target_bco + m_NegativeBco + m_TaggerBcoOffset; + uint64_t found_bco = target_bco_corrected; + + // loop over fees + for( size_t fee = 0; fee < MAX_FEECOUNT; ++fee ) + { + + // get local raw hitmap + using rawhit_array_t = std::array; + auto&& rawhitmap = m_MicromegasRawHitMap[fee]; + if( rawhitmap.empty() ) { continue; } + + // get the relevant BCO matching information object + const auto& bco_matching_information = m_bco_matching_information_map.at( m_fee_packet[fee] ); + + // do nothing if bco_matching_information is not verified + if( !bco_matching_information.is_verified() ) { continue; } + + const double truncatedWaveformGTMWindow = kTruncatedWaveformFEEWindow/bco_matching_information.get_adjusted_multiplier(); + + // find matching bco if any and store raw hits + // list of raw hits (channel ordered) matching target BCO + rawhit_array_t current_rawhits{}; + for( auto&& [bco, rawhitlist]:rawhitmap ) + { + + // compare bco to target, within acceptable range + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco_corrected ); + if( bco_diff >= -(int64_t)m_NegativeBco && bco_diff < m_BcoRange ) + { + found_bco = bco; + if( Verbosity() ) + { + std::cout << "SingleMicromegasPoolInput_v2::recover_truncated_waveforms -" + << " fee: " << fee + << " target_bco: " << target_bco + << " found_bco: " << found_bco + << std::endl; + } + + for( auto&& rawhit:rawhitlist ) + { + if( rawhit->get_channel() < MAX_FEECHANNELCOUNT ) + { current_rawhits[rawhit->get_channel()] = rawhit; } + } + + break; + } + } + + // keep track of newly created hits + using rawhit_impl_pointer_t = std::unique_ptr; // unique_ptr to raw hit implementation object + using rawhit_impl_array_t = std::array; // fixed size array of the above + rawhit_impl_array_t new_rawhits{}; + + // find candidate overlapping bco if any + for( auto&& [bco, rawhitlist]:rawhitmap ) + { + const auto bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_gtm_bco_diff( bco, target_bco_corrected ); + if( bco_diff >= m_BcoRange && bco_diff < truncatedWaveformGTMWindow ) + { + + if( Verbosity() ) + { + std::cout << "SingleMicromegasPoolInput_v2::recover_truncated_waveforms -" + << " fee: " << fee + << " target_bco: " << target_bco + << " found_bco: " << found_bco + << " overlaping bco: " << bco + << std::endl; + } + + // perform overlap restoration + for( auto* source:rawhitlist ) + { + + // cast to versioned raw hit + auto* source_impl = static_cast(source); + + // get channel and check + const auto channel = source->get_channel(); + if( channel >= MAX_FEECHANNELCOUNT ) { continue; } + + // keep track of target hit + MicromegasRawHit_impl* target = nullptr; + + // check if there is an existing raw hit in current BCO at the same channel + if( current_rawhits[channel] ) + { + + // cast to versioned raw hit + target = static_cast(current_rawhits[channel]); + + } else { + + // get FEE BCO from GTM + const auto target_fee_bco = bco_matching_information.get_predicted_fee_bco( target_bco_corrected ).value(); + + // create new hit with shifted waveform + target = new MicromegasRawHit_impl; + + // copy relevant members from source + target->set_bco(target_fee_bco); + target->set_gtm_bco(source->get_gtm_bco()); + target->set_packetid(source->get_packetid()); + target->set_fee(source->get_fee()); + target->set_channel(source->get_channel()); + target->set_sampaaddress(source->get_sampaaddress()); + target->set_sampachannel(source->get_sampachannel()); + + // store in new array + new_rawhits[target->get_channel()].reset(target); + + } + + // calculate waveform shift + // TODO: get proper diff with proper rollover + const int64_t fee_bco_diff = MicromegasBcoMatchingInformation_v2::get_signed_fee_bco_diff( source->get_bco(), target->get_bco() ); + const int16_t fee_clock_shift = static_cast(fee_bco_diff/kFEEClockPerADCClock); + + // get waveforms (copy) + auto waveformlist = source_impl->get_adc_waveforms(); + + // move copy to target hit, with properly shifted start time + for( auto&& [start_time,adc_list]:waveformlist) + { + + // make sure shifted start time is in acceptable window + if( start_time+fee_clock_shift >= kTruncatedWaveformWindow ) continue; + + // make sure all samples are in acceptable range + if( start_time+fee_clock_shift + adc_list.size() > kTruncatedWaveformWindow ) + { adc_list.resize( kTruncatedWaveformWindow - start_time - fee_clock_shift ); } + + target->move_adc_waveform( start_time+fee_clock_shift, std::move(adc_list) ); + + } + + } + + // found overlapping BCO. stop here + break; + } + } + + // copy new hits in internal storage and add to streaming manager + for( auto&& rawhit:new_rawhits ) + { + if( rawhit && !rawhit->get_adc_waveforms().empty() ) + { + // add hit to streaming input manager + if (StreamingInputManager()) + { StreamingInputManager()->AddMicromegasRawHit(found_bco, rawhit.get()); } + + // add hit to insternal storage + m_MicromegasRawHitMap[fee][found_bco].emplace_back(rawhit.release()); + } + } + + } // FEE loop + } diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index d8c3c1da62..ef7a63e00f 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -25,31 +25,57 @@ class TH1; class SingleMicromegasPoolInput_v2 : public SingleStreamingInput { public: + + /// constructor explicit SingleMicromegasPoolInput_v2(const std::string &name = "SingleMicromegasPoolInput_v2"); + + /// destructor ~SingleMicromegasPoolInput_v2() override; - void FillPool(const unsigned int nevents = 1) override; + /// pool filling + void FillPool(const uint64_t /*target_bco*/) override; + + /// cleanup void CleanupUsedPackets(const uint64_t bclk) override { CleanupUsedPackets(bclk, false); } - //! specialized verion of cleaning up packets, with an extra flag about wheter the cleanup hits are dropped or not + /// specialized verion of cleaning up packets, with an extra flag about wheter the cleanup hits are dropped or not void CleanupUsedPackets(const uint64_t /* bclk */, bool /*dropped */) override; + /// current event cleaning void ClearCurrentEvent() override; - bool GetSomeMoreEvents(); + + /// print void Print(const std::string &what = "ALL") const override; + + /// void CreateDSTNode(PHCompositeNode *topNode) override; + void SetRecoverTruncatedWaveforms( bool value ) { m_recover_truncated_waveforms = value; } + void SetBcoRange(const unsigned int value) { m_BcoRange = value; } + void ConfigureStreamingInputManager() override; - void SetNegativeBco(const unsigned int value) { m_NegativeBco = value; } - //! define minimum pool size in terms of how many BCO are stored - void SetBcoPoolSize(const unsigned int value) { m_BcoPoolSize = value; } + void SetNegativeBco(const unsigned int value) { m_NegativeBco = value; } - //! save some statistics for BCO QA + /// set the offset between FELIX tagger BCO (internal) and GL1 (external) BCO + /** + * explicitly taggerBCO = GL1 BCO + offset + * this is somewhat redundant with m_Negative BCO, unfortunately, but + * 1/ m_NegativeBco is also used upstream by Fun4AllStreamingInputManager + * 2/ m_NegativeBCO is unsigned int + */ + void SetTaggerBcoOffset( const int value ) { m_TaggerBcoOffset = value; } + + /// define minimum pool size in terms of how many BCO are stored + /** deprecated */ + void SetBcoPoolSize(const unsigned int /*value*/) + { std::cout << "SingleMicromegasPoolInput_v2::SetBcoPoolSize is deprecated" << std::endl; } + + /// save some statistics for BCO QA void FillBcoQA(uint64_t /*gtm_bco*/) override; // write the initial histograms for QA manager @@ -61,17 +87,24 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// output file name for evaluation histograms void set_evaluation_outputfile(const std::string &outputfile) { m_evaluation_filename = outputfile; } - private: - //!@name decoding constants + private: + + /// true if more data is to be processed for collecting that of a given bco + bool is_more_data_required(const uint64_t /*target_bco*/) const; + + ///@name decoding constants //@{ /// max number of FEE per OBDC static constexpr uint16_t MAX_FEECOUNT = 26; + /// max number of channels per FEE + static constexpr uint16_t MAX_FEECHANNELCOUNT = 256; + // Length for the 256-bit wide Round Robin Multiplexer for the data stream static constexpr size_t DAM_DMA_WORD_LENGTH = 16; //@} - //! DMA word structure + /// DMA word structure struct dma_word { uint16_t dma_header; @@ -82,10 +115,19 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput void decode_gtm_data(int /*packet_id*/, const dma_word &); void process_fee_data(int /*packet_id*/, unsigned int /*fee_id*/); - // fee data buffer - std::vector> m_feeData{MAX_FEECOUNT}; + /// fill evaluation tree + void fill_evaluation_tree( const uint64_t /*target_bco*/ ); - // list of packets from data stream + /// recover truncated waveforms for a given gtm bco + void recover_truncated_waveforms( const uint64_t /*target_bco*/ ); + + /// true to recover waveform truncated due to overlapping timeframes + bool m_recover_truncated_waveforms{true}; + + /// fee data buffer + std::array, MAX_FEECOUNT> m_feeData{}; + + /// list of packets from data stream std::array plist{}; /// keep track of number of non data events @@ -97,10 +139,10 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// bco adjustment for matching across subsystems unsigned int m_NegativeBco{0}; - //! minimum number of BCO required in Micromegas Pools - unsigned int m_BcoPoolSize{1}; + /// offset between FELIX tagger BCO (internal) and GL1 (external) BCO + int m_TaggerBcoOffset{3}; - //! store list of packets that have data for a given beam clock + /// store list of packets that have data for a given beam clock /** * all packets in taggers are stored, * disregarding whether there is data associated to it or not @@ -108,44 +150,42 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput */ std::map> m_BeamClockPacket; - //! store list of FEE that have data for a given beam clock + /// store list of FEE that have data for a given beam clock std::map> m_BeamClockFEE; - //! store list of raw hits matching a given bco - std::map> m_MicromegasRawHitMap; + /// list of raw hits + using rawhit_list_t = std::vector; - //! store current list of BCO on a per fee basis. - /** only packets for which a given FEE have data are stored */ - std::map m_FEEBclkMap; + /// maps list of raw hits on GTM BCO values + using rawhit_map_t = std::map; - //! store current list of BCO - /** - * all packets in taggers are stored, - * disregarding whether there is data associated to it or not - * this allows to keep track of dropped data, also in zero-suppression mode - */ - std::set m_BclkStack; + /// store list of raw hits matching a given GTM bco on a per FEE basis + std::array m_MicromegasRawHitMap{}; - //! map bco_information_t to packet id + /// map bco_information_t to packet id using bco_matching_information_map_t = std::map; - bco_matching_information_map_t m_bco_matching_information_map; + bco_matching_information_map_t m_bco_matching_information_map{}; + + /// map packet to FEE ID + /* it is filled on the fly. It allows to quickly retrieve BCO matching information from FEE index */ + std::array m_fee_packet{}; class counter_t { public: - //! total count + /// total count uint64_t total {0}; - //! drop count due to unmatched bco + /// drop count due to unmatched bco uint64_t dropped_bco {0}; - //! drop count due to pools + /// drop count due to pools uint64_t dropped_pool {0}; - //! dropped fraction (bco) + /// dropped fraction (bco) double dropped_fraction_bco() const { return double(dropped_bco) / total; } - //! dropped fraction (pool) + /// dropped fraction (pool) double dropped_fraction_pool() const { return double(dropped_pool) / total; } }; @@ -164,50 +204,50 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput // timer PHTimer m_timer{"SingleMicromegasPoolInput_v2"}; - //!@name QA histograms + ///@name QA histograms //@{ - //! keeps track of how often a given (or all) packets are found for a given BCO + /// keeps track of how often a given (or all) packets are found for a given BCO TH1 *h_packet_stat{nullptr}; - //! keep track of how many heartbeats are found per FEE sampa + /// keep track of how many heartbeats are found per FEE sampa TH1 *h_heartbeat_stat{nullptr}; - //! keeps track of how many packets are found for a given BCO + /// keeps track of how many packets are found for a given BCO TH1 *h_packet{nullptr}; - //! keeps track of how many waveforms are found for a given BCO + /// keeps track of how many waveforms are found for a given BCO TH1 *h_waveform{nullptr}; - //! total number of waveforms per packet + /// total number of waveforms per packet TH1 *h_waveform_count_total{nullptr}; - //! total number of dropped waveforms per packet due to bco mismatch + /// total number of dropped waveforms per packet due to bco mismatch /*! waveforms are dropped when their FEE-BCO cannot be associated to any global BCO */ TH1 *h_waveform_count_dropped_bco{nullptr}; - //! total number of dropped waveforms per packet due to fun4all pool mismatch + /// total number of dropped waveforms per packet due to fun4all pool mismatch TH1 *h_waveform_count_dropped_pool{nullptr}; - //! total number of waveforms per packet + /// total number of waveforms per packet TH1 *h_fee_waveform_count_total{nullptr}; - //! total number of dropped waveforms per fee due to bco mismatch + /// total number of dropped waveforms per fee due to bco mismatch /*! waveforms are dropped when their FEE-BCO cannot be associated to any global BCO */ TH1 *h_fee_waveform_count_dropped_bco{nullptr}; - //! total number of dropped waveforms per fee due to fun4all pool mismatch + /// total number of dropped waveforms per fee due to fun4all pool mismatch TH1 *h_fee_waveform_count_dropped_pool{nullptr}; //@} - //!@name evaluation + ///@name evaluation //@{ - //! evaluation + /// evaluation bool m_do_evaluation = false; - //! evaluation output filename + /// evaluation output filename std::string m_evaluation_filename = "SingleMicromegasPoolInput.root"; std::unique_ptr m_evaluation_file; @@ -227,17 +267,14 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// channel id unsigned short channel {0}; - /// true if measurement is hearbeat - bool is_heartbeat = false; - /// ll1 bco uint64_t gtm_bco_first {0}; - /// ll1 bco - uint64_t gtm_bco {0}; + /// bco + uint64_t gtm_bco_tagger {0}; - /// ll1 bco - uint64_t gtm_bco_matched {0}; + /// bco + uint64_t gtm_bco_gl1 {0}; /// fee bco unsigned int fee_bco_first {0}; @@ -245,16 +282,17 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// fee bco unsigned int fee_bco {0}; - /// fee bco predicted (from gtm) - unsigned int fee_bco_predicted {0}; + /// fee bco predicted (from gtm tagger) + unsigned int fee_bco_predicted_tagger {0}; + + /// fee bco predicted (from gtm gl1) + unsigned int fee_bco_predicted_gl1 {0}; - /// fee bco match (from gtm) - unsigned int fee_bco_predicted_matched {0}; }; Waveform m_waveform; - //! tree + /// tree TTree *m_evaluation_tree {nullptr}; //*} diff --git a/offline/framework/fun4allraw/SingleMvtxPoolInput.cc b/offline/framework/fun4allraw/SingleMvtxPoolInput.cc index de98a9936e..4ce498ee9e 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 @@ -29,7 +29,8 @@ #include SingleMvtxPoolInput::SingleMvtxPoolInput(const std::string &name) - : SingleStreamingInput(name), plist(new Packet *[2]) + : SingleStreamingInput(name) + , plist(new Packet *[2]) { m_rawHitContainerName = "MVTXRAWHIT"; @@ -161,7 +162,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 +207,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()) { @@ -462,7 +463,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 { diff --git a/offline/framework/fun4allraw/SingleStreamingInput.h b/offline/framework/fun4allraw/SingleStreamingInput.h index 082c1a079e..65220ec9fb 100644 --- a/offline/framework/fun4allraw/SingleStreamingInput.h +++ b/offline/framework/fun4allraw/SingleStreamingInput.h @@ -22,6 +22,7 @@ class SingleStreamingInput : public Fun4AllBase, public InputFileHandler virtual Eventiterator *GetEventIterator() { return m_EventIterator; } virtual void FillPool(const uint64_t) { return; } virtual void FillPool(const unsigned int = 1) { return; } + virtual int FillPoolStatus() const { return 0; } virtual void RunNumber(const int runno) { m_RunNumber = runno; } virtual int RunNumber() const { return m_RunNumber; } virtual int fileopen(const std::string &filename) override; diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc index 03e83f4cd0..f9cf309631 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.cc @@ -1,5 +1,6 @@ #include "SingleTpcTimeFrameInput.h" #include "TpcTimeFrameBuilder.h" +#include "TpcTimeFrameBuilderRun3.h" #include "Fun4AllStreamingInputManager.h" #include "InputManagerType.h" @@ -25,6 +26,8 @@ #include #include +#include +#include #include #include #include @@ -113,6 +116,7 @@ SingleTpcTimeFrameInput::TimeTracker::~TimeTracker() void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) { + m_FillPoolStatus = Fun4AllReturnCodes::EVENT_OK; { static bool first = true; if (first) @@ -177,6 +181,9 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) // std::set saved_beamclocks; while (true) { + // clean up cache to avoid memory over usage when trigger jumped by a long time + CleanupUsedPackets(targetBCO - kUsedPacketsCachingLimit); + if (m_TpcTimeFrameBuilderMap.empty()) { if (Verbosity() > 1) @@ -269,6 +276,18 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) auto &packet = plist[i]; assert(packet); + auto cleanup_remaining_packets = [&](const int first_index) + { + for (int j = first_index; j < npackets; ++j) + { + if (plist[j]) + { + delete plist[j]; + plist[j] = nullptr; + } + } + }; + // get packet id const auto packet_id = packet->getIdentifier(); @@ -284,19 +303,62 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) continue; } + const int hit_format = packet->getHitFormat(); + const auto builder_hit_format_iter = m_TpcTimeFrameBuilderHitFormatMap.find(packet_id); + if (builder_hit_format_iter != m_TpcTimeFrameBuilderHitFormatMap.end() && builder_hit_format_iter->second != hit_format) + { + std::cout << __PRETTY_FUNCTION__ << ": Error : packet id " << packet_id + << " changed TPC hit format from " << builder_hit_format_iter->second + << " to " << hit_format << ". Aborting run." << std::endl; + packet->identify(); + m_FillPoolStatus = Fun4AllReturnCodes::ABORTRUN; + cleanup_remaining_packets(i); + return; + } + if (!m_TpcTimeFrameBuilderMap.contains(packet_id)) { - if (Verbosity() >= 1) + TpcTimeFrameBuilderBase *builder = nullptr; + if (hit_format == IDTPCFEEV4) { - std::cout << __PRETTY_FUNCTION__ << ": Creating TpcTimeFrameBuilder for packet id: " << packet_id << std::endl; + if (Verbosity() >= 1) + { + std::cout << __PRETTY_FUNCTION__ << ": Creating TpcTimeFrameBuilder for packet id: " << packet_id + << " hit format " << hit_format << std::endl; + } + builder = new TpcTimeFrameBuilder(packet_id); + } + else if (hit_format == IDTPCFEEV5 || hit_format == IDTPCFEEV6) + { + if (Verbosity() >= 1) + { + std::cout << __PRETTY_FUNCTION__ << ": Creating TpcTimeFrameBuilderRun3 for packet id: " << packet_id + << " hit format " << hit_format << std::endl; + } + builder = new TpcTimeFrameBuilderRun3(packet_id); + } + else + { + std::cout << __PRETTY_FUNCTION__ << ": Error : unsupported TPC hit format " << hit_format + << " for packet id " << packet_id << ". Aborting run." << std::endl; + packet->identify(); + m_FillPoolStatus = Fun4AllReturnCodes::ABORTRUN; + cleanup_remaining_packets(i); + return; } - m_TpcTimeFrameBuilderMap[packet_id] = new TpcTimeFrameBuilder(packet_id); + m_TpcTimeFrameBuilderMap[packet_id] = builder; + m_TpcTimeFrameBuilderHitFormatMap[packet_id] = hit_format; m_TpcTimeFrameBuilderMap[packet_id]->setVerbosity(Verbosity()); + m_TpcTimeFrameBuilderMap[packet_id]->fillBadFeeMap(); if (!m_digitalCurrentDebugTTreeName.empty()) { m_TpcTimeFrameBuilderMap[packet_id]->SaveDigitalCurrentDebugTTree(m_digitalCurrentDebugTTreeName); } + if (!m_bxCounterSyncCDBTTreeName.empty()) + { + m_TpcTimeFrameBuilderMap[packet_id]->SaveBXCounterSyncCDBTTree(m_bxCounterSyncCDBTTreeName); + } } if (Verbosity() > 1) @@ -305,7 +367,15 @@ void SingleTpcTimeFrameInput::FillPool(const uint64_t targetBCO) } assert(m_TpcTimeFrameBuilderMap[packet_id]); - m_TpcTimeFrameBuilderMap[packet_id]->ProcessPacket(packet); + const int process_packet_status = m_TpcTimeFrameBuilderMap[packet_id]->ProcessPacket(packet); + if (process_packet_status < 0) + { + std::cout << __PRETTY_FUNCTION__ << ": Error : TPC packet builder returned " << process_packet_status + << " for packet id " << packet_id << ". Aborting run." << std::endl; + m_FillPoolStatus = process_packet_status; + cleanup_remaining_packets(i); + return; + } // require_more_data = require_more_data or m_TpcTimeFrameBuilderMap[packet_id]->isMoreDataRequired(targetBCO); delete packet; diff --git a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h index e1f9ded3dd..af22167e61 100644 --- a/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h +++ b/offline/framework/fun4allraw/SingleTpcTimeFrameInput.h @@ -12,7 +12,7 @@ class TpcRawHit; class Packet; -class TpcTimeFrameBuilder; +class TpcTimeFrameBuilderBase; class PHTimer; class TH1; class TH2; @@ -25,6 +25,7 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput explicit SingleTpcTimeFrameInput(const std::string &name); ~SingleTpcTimeFrameInput() override; void FillPool(const uint64_t targetBCO) override; + int FillPoolStatus() const override { return m_FillPoolStatus; } void CleanupUsedPackets(const uint64_t bclk) override; // bool CheckPoolDepth(const uint64_t bclk) override; void ClearCurrentEvent() override; @@ -42,18 +43,27 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput m_digitalCurrentDebugTTreeName = name; } + void setBXCounterSyncCDBTTreeName(const std::string &name) + { + m_bxCounterSyncCDBTTreeName = name; + } + private: const int NTPCPACKETS = 3; + // in BCO, limit caching to a quarter of FEE clock rollover or 7ms, to avoid memory over usage when trigger jumped by a long time + static constexpr uint64_t kUsedPacketsCachingLimit = (1<<20)/4/4; + Packet **plist{nullptr}; unsigned int m_NumSpecialEvents{0}; unsigned int m_BcoRange{0}; unsigned int m_NegativeBco{0}; //! packet ID -> TimeFrame builder - std::map m_TpcTimeFrameBuilderMap; + std::map m_TpcTimeFrameBuilderMap; + std::map m_TpcTimeFrameBuilderHitFormatMap; std::set m_SelectedPacketIDs; - + TH1 *m_hNorm = nullptr; PHTimer *m_FillPoolTimer = nullptr; @@ -63,20 +73,22 @@ class SingleTpcTimeFrameInput : public SingleStreamingInput // NOLINTNEXTLINE(hicpp-special-member-functions) class TimeTracker - { + { public: - TimeTracker(PHTimer * timer, const std::string & name, TH1* hout) ; - virtual ~TimeTracker() ; + TimeTracker(PHTimer *timer, const std::string &name, TH1 *hout); + virtual ~TimeTracker(); void stop(); private: - PHTimer * m_timer = nullptr; + PHTimer *m_timer = nullptr; std::string m_name; TH1 *m_hNorm = nullptr; bool stopped = false; }; + int m_FillPoolStatus{0}; std::string m_digitalCurrentDebugTTreeName; + std::string m_bxCounterSyncCDBTTreeName; }; #endif diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.cc b/offline/framework/fun4allraw/SingleTriggeredInput.cc index 3bb6b30a2b..434aaac876 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.cc +++ b/offline/framework/fun4allraw/SingleTriggeredInput.cc @@ -26,7 +26,7 @@ #include // for pair #include -SingleTriggeredInput::SingleTriggeredInput(const std::string &name) +SingleTriggeredInput::SingleTriggeredInput(const std::string& name) : Fun4AllBase(name) { m_bclkarray.fill(std::numeric_limits::max()); @@ -35,7 +35,7 @@ SingleTriggeredInput::SingleTriggeredInput(const std::string &name) SingleTriggeredInput::~SingleTriggeredInput() { - std::set evtset; + std::set evtset; for (auto& [pid, dq] : m_PacketEventDeque) { while (!dq.empty()) @@ -44,7 +44,7 @@ SingleTriggeredInput::~SingleTriggeredInput() dq.pop_front(); } } - for (auto *evt : evtset) + for (auto* evt : evtset) { delete evt; } @@ -64,7 +64,7 @@ bool SingleTriggeredInput::CheckFemDiffIdx(int pid, size_t index, const std::deq return false; } - Packet* pkt_prev = events[index-1]->getPacket(pid); + Packet* pkt_prev = events[index - 1]->getPacket(pid); Packet* pkt_curr = events[index]->getPacket(pid); if (!pkt_prev || !pkt_curr) { @@ -73,7 +73,8 @@ bool SingleTriggeredInput::CheckFemDiffIdx(int pid, size_t index, const std::deq return false; } - auto get_majority_femclk = [](Packet* pkt) -> uint16_t { + auto get_majority_femclk = [](Packet* pkt) -> uint16_t + { int nmod = pkt->iValue(0, "NRMODULES"); std::map counts; for (int j = 0; j < nmod; ++j) @@ -85,7 +86,9 @@ bool SingleTriggeredInput::CheckFemDiffIdx(int pid, size_t index, const std::deq { return std::numeric_limits::max(); } - return std::max_element(counts.begin(), counts.end(), [](const auto& a, const auto& b) { return a.second < b.second; })->first; + return std::max_element(counts.begin(), counts.end(), [](const auto& a, const auto& b) + { return a.second < b.second; }) + ->first; }; uint16_t clk_prev = get_majority_femclk(pkt_prev); @@ -108,38 +111,38 @@ bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array bad_diff_indices; for (size_t i = 0; i < n; ++i) { - if ( sebdiff[i] != gl1diff[i] ) + if (sebdiff[i] != gl1diff[i]) { - if ( !m_packetclk_copy_runs ) + if (!m_packetclk_copy_runs) { - //backup procedure to recover stuck 16bit XMIT clock - size_t idxcheck = i == 0 ? i+1 : i; + // backup procedure to recover stuck 16bit XMIT clock + size_t idxcheck = i == 0 ? i + 1 : i; bool passFemDiffCheckIdx = CheckFemDiffIdx(pid, idxcheck, m_PacketEventDeque[pid], gl1diff[idxcheck]); - if ( passFemDiffCheckIdx ) + if (passFemDiffCheckIdx) { m_OverrideWithRepClock.insert(pid); continue; } - } + } bad_diff_indices.push_back(i); } } if (bad_diff_indices.empty()) { - if ( Verbosity() > 0 ) + if (Verbosity() > 0) { std::cout << Name() << " recovered from bad XMIT clocks. Merging pool" << std::endl; } @@ -147,14 +150,14 @@ bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array=5) + if (bad_diff_indices.size() >= 5) { std::cout << std::endl; std::cout << "----------------- " << Name() << " -----------------" << std::endl; std::cout << "More than 5 diffs are bad.. try shifting algorithm" << std::endl; move_to_shift_algo = true; } - if(!move_to_shift_algo) + if (!move_to_shift_algo) { std::cout << std::endl; std::cout << "----------------- " << Name() << " -----------------" << std::endl; @@ -164,23 +167,23 @@ bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array=5) + if (length >= 5) { std::cout << Name() << ": length of bad diffs >=5 with bad_diff_indices.size() " << bad_diff_indices.size() << ". This should not have happened.. rejecting pool" << std::endl; return false; } - if(start==static_cast(pooldepth - 1)) + if (start == static_cast(pooldepth - 1)) { bad_indices.push_back(start); - CurrentPoolLastDiffBad= true; + CurrentPoolLastDiffBad = true; } - else if (start==0) + else if (start == 0) { if (PrevPoolLastDiffBad) { @@ -202,14 +205,14 @@ bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array(pooldepth - 1) && start >0) + else if (start < static_cast(pooldepth - 1) && start > 0) { - if(length==1) + if (length == 1) { std::cout << Name() << ": Isolated bad diff[" << start << "] - rejecting pool" << std::endl; return false; } - if(length>=2) + if (length >= 2) { for (int j = start; j < end; ++j) { @@ -219,7 +222,7 @@ bool SingleTriggeredInput::CheckPoolAlignment(int pid, const std::array::max()); - if ( representative_pid == -1 ) + static bool firstclockarray = true; + if (firstclockarray) + { + std::cout << "first clock call pid " << pid << " m_bclkarray_map[pid][0] : " << m_bclkarray_map[pid][0] << std::endl; + firstclockarray = false; + } + + if (representative_pid == -1) { representative_pid = pid; } } - if ( !allPacketEventDequeEmpty ) + if (!allPacketEventDequeEmpty) { return 0; } @@ -368,13 +378,18 @@ int SingleTriggeredInput::FillEventVector() while (i < pooldepth) { Event* evt{nullptr}; + bool skiptrace = false; if (this != Gl1Input()) { auto* gl1 = dynamic_cast(Gl1Input()); if (gl1) { int nskip = gl1->GetGl1SkipArray()[i]; - + if (nskip > 0) + { + skiptrace = true; + } + while (nskip > 0) { Event* skip_evt = GetEventIterator()->getNextEvent(); @@ -388,9 +403,10 @@ int SingleTriggeredInput::FillEventVector() } skip_evt = GetEventIterator()->getNextEvent(); } - + if (skip_evt->getEvtType() != DATAEVENT) { + delete skip_evt; continue; } @@ -412,14 +428,91 @@ int SingleTriggeredInput::FillEventVector() { if (Verbosity() > 0) { - std::cout << Name() << ": Early stop of SEB skip after " << (gl1->GetGl1SkipArray()[i] - nskip) << " from intial " << gl1->GetGl1SkipArray()[i] << " events." << std::endl; + std::cout << Name() << ": Early stop in pool " << i << " of SEB skip after " << (gl1->GetGl1SkipArray()[i] - nskip) << " from intial " << gl1->GetGl1SkipArray()[i] << " events. gl1diff vs sebdiff : " << gl1_diff << " vs " << seb_diff << std::endl; } evt = skip_evt; + skiptrace = false; break; } delete skip_evt; nskip--; } + + if (skiptrace) + { + evt = GetEventIterator()->getNextEvent(); + while (!evt) + { + fileclose(); + if (OpenNextFile() == InputFileHandlerReturnCodes::FAILURE) + { + FilesDone(1); + return -1; + } + evt = GetEventIterator()->getNextEvent(); + } + if (evt->getEvtType() != DATAEVENT) + { + if (Verbosity() > 0) + { + std::cout << Name() << " dropping non data event: " << evt->getEvtSequence() << std::endl; + } + delete evt; + continue; + } + + Packet* pkt = evt->getPacket(representative_pid); + if (!pkt) + { + std::cout << "representative packet invalid inside skiptrace.. continuing.." << std::endl; + continue; + } + FillPacketClock(evt, pkt, i); + uint64_t seb_diff = m_bclkdiffarray_map[representative_pid][i]; + int gl1pid = Gl1Input()->m_bclkdiffarray_map.begin()->first; + uint64_t gl1_diff = gl1->m_bclkdiffarray_map[gl1pid][i]; + + bool clockconsistency = true; + if (seb_diff != gl1_diff) + { + clockconsistency = false; + int clockconstcount = 0; + while (!clockconsistency && clockconstcount < 5) + { + std::cout << Name() << ": Still inconsistent clock diff after Gl1 drop. gl1diff vs sebdiff : " << gl1_diff << " vs " << seb_diff << std::endl; + delete pkt; + delete evt; + evt = GetEventIterator()->getNextEvent(); + while (!evt) + { + fileclose(); + if (OpenNextFile() == InputFileHandlerReturnCodes::FAILURE) + { + FilesDone(1); + return -1; + } + evt = GetEventIterator()->getNextEvent(); + } + pkt = evt->getPacket(representative_pid); + if (!pkt) + { + std::cout << "representative packet invalid inside skiptrace.. continuing.." << std::endl; + continue; + } + + FillPacketClock(evt, pkt, i); + uint64_t seb_diff_next = m_bclkdiffarray_map[representative_pid][i]; + uint64_t gl1_diff_next = gl1->m_bclkdiffarray_map[gl1pid][i]; + std::cout << "seb_diff_next : " << seb_diff_next << " , gl1_diff_next : " << gl1_diff_next << std::endl; + if (seb_diff_next == gl1_diff_next) + { + clockconsistency = true; + std::cout << Name() << " : recovered by additional skip in skiptrace" << std::endl; + } + clockconstcount++; + } + } + } } } @@ -447,22 +540,22 @@ int SingleTriggeredInput::FillEventVector() continue; } evt->convert(); - + if (firstcall) { std::cout << "Creating DSTs first call" << std::endl; CreateDSTNodes(evt); int run = evt->getRunNumber(); - m_packetclk_copy_runs = (run >= 44000 && run < 56079); + m_packetclk_copy_runs = (run >= 44000 && run < 56079); firstcall = false; } for (int pid : m_PacketSet) { - Event *thisevt = evt; + Event* thisevt = evt; if (m_PacketShiftOffset[pid] == 1) { - if (i==0) + if (i == 0) { thisevt = m_PacketEventBackup[pid]; m_ShiftedEvents[pid] = evt; @@ -471,13 +564,13 @@ int SingleTriggeredInput::FillEventVector() { thisevt = m_ShiftedEvents[pid]; m_ShiftedEvents[pid] = evt; - if (i == pooldepth -1) + if (i == pooldepth - 1) { m_PacketEventBackup[pid] = evt; } } } - + Packet* pkt = thisevt->getPacket(pid); if (!pkt) { @@ -485,14 +578,16 @@ int SingleTriggeredInput::FillEventVector() } FillPacketClock(thisevt, pkt, i); m_PacketEventDeque[pid].push_back(thisevt); + delete pkt; - + if (representative_pid == -1 && m_PacketShiftOffset[pid] == 0) { representative_pid = pid; } } i++; + eventcounter++; } size_t minSize = pooldepth; @@ -503,7 +598,7 @@ int SingleTriggeredInput::FillEventVector() return minSize; } -uint64_t SingleTriggeredInput::GetClock(Event *evt, int pid) +uint64_t SingleTriggeredInput::GetClock(Event* evt, int pid) { Packet* packet = evt->getPacket(pid); if (!packet) @@ -534,20 +629,19 @@ void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event auto& clkarray = m_bclkarray_map[pid]; auto& diffarray = m_bclkdiffarray_map[pid]; - // Special handling for FEM-copied clocks if (m_packetclk_copy_runs && m_CorrectCopiedClockPackets.contains(pid)) { if (event_index == 0) { - clkarray[event_index+1] = m_PreviousValidBCOMap[pid]; + clkarray[event_index + 1] = m_PreviousValidBCOMap[pid]; } - else if (event_index >=1) + else if (event_index >= 1) { Event* shifted_evt = m_PacketEventDeque[pid][event_index - 1]; - clkarray[event_index+1] = GetClock(shifted_evt, pid); + clkarray[event_index + 1] = GetClock(shifted_evt, pid); } - + uint64_t prev = clkarray[event_index]; uint64_t curr = clkarray[event_index + 1]; @@ -563,7 +657,6 @@ void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event return; } - uint64_t clk = GetClock(evt, pid); if (clk == std::numeric_limits::max()) { @@ -574,7 +667,7 @@ void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event clkarray[event_index + 1] = clk; uint64_t prev = clkarray[event_index]; - if(prev == std::numeric_limits::max()) + if (prev == std::numeric_limits::max()) { static std::unordered_set warned; @@ -598,7 +691,7 @@ void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event { int packet_number = pkt->iValue(0); gl1->SetPacketNumbers(gl1->GetCurrentPacketNumber(), packet_number); - if ( event_index < pooldepth ) + if (event_index < pooldepth) { gl1->SetGl1PacketNumber(event_index, packet_number); } @@ -606,7 +699,7 @@ void SingleTriggeredInput::FillPacketClock(Event* evt, Packet* pkt, size_t event int skip_count = 0; if (gl1->GetLastPacketNumber() != 0) { - int diff = gl1->GetCurrentPacketNumber() - gl1->GetLastPacketNumber() ; + int diff = gl1->GetCurrentPacketNumber() - gl1->GetLastPacketNumber(); skip_count = diff - 1; } @@ -624,7 +717,8 @@ void SingleTriggeredInput::FillPool() return; } - bool all_packets_bad = !m_PacketAlignmentProblem.empty() && std::all_of(m_PacketAlignmentProblem.begin(), m_PacketAlignmentProblem.end(), [](const std::pair &entry) -> bool { return entry.second;}); + bool all_packets_bad = !m_PacketAlignmentProblem.empty() && std::all_of(m_PacketAlignmentProblem.begin(), m_PacketAlignmentProblem.end(), [](const std::pair& entry) -> bool + { return entry.second; }); if (all_packets_bad) { std::cout << Name() << ": ALL packets are marked as bad. Stop combining for this SEB." << std::endl; @@ -635,6 +729,15 @@ void SingleTriggeredInput::FillPool() if (!FilesDone()) { int eventvectorsize = FillEventVector(); + // this seems a unique signature for raw data files which only contain the + // begin and end run event but no data events. FillEventVector() returns -1 + // and since no events were read the m_PacketEventDeque is empty + if (eventvectorsize < 0 && m_PacketEventDeque.empty()) + { + std::cout << Name() << ": No data Events in input file " << FileName() << std::endl; + AllDone(1); + return; + } if (eventvectorsize != 0) { if (Gl1Input()->m_bclkdiffarray_map.empty()) @@ -647,9 +750,8 @@ void SingleTriggeredInput::FillPool() int gl1pid = Gl1Input()->m_bclkdiffarray_map.begin()->first; const auto& gl1diff = Gl1Input()->m_bclkdiffarray_map.at(gl1pid); - bool allgl1max = std::all_of(gl1diff.begin(), gl1diff.end(), [](uint64_t val) { - return val == std::numeric_limits::max(); - }); + bool allgl1max = std::all_of(gl1diff.begin(), gl1diff.end(), [](uint64_t val) + { return val == std::numeric_limits::max(); }); if (allgl1max) { std::cout << Name() << " : GL1 clock diffs all filled with max 64 bit values for PID " << gl1pid << " return and try next pool" << std::endl; @@ -660,13 +762,13 @@ void SingleTriggeredInput::FillPool() for (const auto& [pid, sebdiff] : m_bclkdiffarray_map) { size_t packetpoolsize = m_PacketEventDeque[pid].size(); - if(packetpoolsize==0) + if (packetpoolsize == 0) { std::cout << Name() << ": packet pool size is zero.... something is wrong" << std::endl; return; } - if(m_PacketAlignmentProblem[pid]) + if (m_PacketAlignmentProblem[pid]) { continue; } @@ -677,22 +779,23 @@ void SingleTriggeredInput::FillPool() bool PrevPoolLastDiffBad = m_PrevPoolLastDiffBad[pid]; bool aligned = false; - if( packetpoolsize < pooldepth && FilesDone() ) + if (packetpoolsize < pooldepth && FilesDone()) { aligned = true; } - else + else { aligned = CheckPoolAlignment(pid, sebdiff, gl1diff, bad_indices, shift, CurrentPoolLastDiffBad, PrevPoolLastDiffBad); } - + if (aligned) { m_PrevPoolLastDiffBad[pid] = CurrentPoolLastDiffBad; if (!bad_indices.empty()) { std::cout << Name() << ": Packet " << pid << " has bad indices: "; - for (int bi : bad_indices){ + for (int bi : bad_indices) + { std::cout << bi << " "; m_DitchPackets[pid].insert(bi); } @@ -704,12 +807,13 @@ void SingleTriggeredInput::FillPool() uint64_t gl1_clk = Gl1Input()->m_bclkarray_map[gl1pid][i]; uint64_t seb_clk = m_bclkarray_map[pid][i]; std::cout << "pool index i " << i << ", gl1 / seb : " << gl1_clk << " / " << seb_clk; - if(im_bclkdiffarray_map[gl1pid][i]; uint64_t seb_diff = m_bclkdiffarray_map[pid][i]; std::cout << " -> diff of gl1 vs seb : " << gl1_diff << " " << seb_diff << std::endl; } - else if(i==pooldepth) + else if (i == pooldepth) { std::cout << std::endl; } @@ -719,11 +823,11 @@ void SingleTriggeredInput::FillPool() if (shift == -1) { std::cout << Name() << ": Packet " << pid << " shifted by -1 with dropping the first seb event" << std::endl; - if(m_PacketShiftOffset[pid] == -1) + if (m_PacketShiftOffset[pid] == -1) { std::cout << "Packet " << pid << " requires an additional shift -1. Lets not handle this for the moment.. stop combining" << std::endl; m_PacketAlignmentProblem[pid] = true; - } + } if (!m_PacketEventDeque[pid].empty()) { @@ -737,12 +841,12 @@ void SingleTriggeredInput::FillPool() for (size_t i = 0; i < packetpoolsize - 1; ++i) { - m_bclkarray_map[pid][i] = m_bclkarray_map[pid][i+1]; + m_bclkarray_map[pid][i] = m_bclkarray_map[pid][i + 1]; } for (size_t i = 0; i < packetpoolsize; ++i) { - m_bclkdiffarray_map[pid][i] = ComputeClockDiff(m_bclkarray_map[pid][i+1], m_bclkarray_map[pid][i]); + m_bclkdiffarray_map[pid][i] = ComputeClockDiff(m_bclkarray_map[pid][i + 1], m_bclkarray_map[pid][i]); } Event* evt = GetEventIterator()->getNextEvent(); if (evt) @@ -770,7 +874,7 @@ void SingleTriggeredInput::FillPool() else if (shift == 1) { std::cout << Name() << ": Packet " << pid << " requires shift +1 (insert dummy at front)" << std::endl; - + if (m_packetclk_copy_runs) { std::cout << Name() << " : runs where clocks are copied from the first XMIT. Checking FEM clock diff" << std::endl; @@ -788,7 +892,7 @@ void SingleTriggeredInput::FillPool() std::cout << Name() << " : Packet identified as misaligned also with FEMs. Do normal recovery process" << std::endl; } - if(m_PacketShiftOffset[pid] == 1) + if (m_PacketShiftOffset[pid] == 1) { std::cout << "Packet " << pid << " requires an additional shift +1. Lets not handle this for the moment.. stop combining" << std::endl; m_PacketAlignmentProblem[pid] = true; @@ -796,11 +900,11 @@ void SingleTriggeredInput::FillPool() for (size_t i = pooldepth; i > 0; --i) { - m_bclkarray_map[pid][i] = m_bclkarray_map[pid][i-1]; + m_bclkarray_map[pid][i] = m_bclkarray_map[pid][i - 1]; } - for (size_t i = 1 ; i < pooldepth; ++i) + for (size_t i = 1; i < pooldepth; ++i) { - m_bclkdiffarray_map[pid][i] = ComputeClockDiff(m_bclkarray_map[pid][i+1], m_bclkarray_map[pid][i]); + m_bclkdiffarray_map[pid][i] = ComputeClockDiff(m_bclkarray_map[pid][i + 1], m_bclkarray_map[pid][i]); } m_bclkarray_map[pid][0] = 0; @@ -810,7 +914,7 @@ void SingleTriggeredInput::FillPool() if (!m_PacketEventDeque[pid].empty()) { m_PacketEventBackup[pid] = m_PacketEventDeque[pid].back(); - Event* dummy_event = m_PacketEventDeque[pid][0]; + Event* dummy_event = m_PacketEventDeque[pid][0]; m_PacketEventDeque[pid].push_front(dummy_event); m_PacketEventDeque[pid].pop_back(); } @@ -833,12 +937,13 @@ void SingleTriggeredInput::FillPool() uint64_t gl1_clk = Gl1Input()->m_bclkarray_map[gl1pid][i]; uint64_t seb_clk = m_bclkarray_map[pid][i]; std::cout << "pool index i " << i << ", gl1 / seb : " << gl1_clk << " / " << seb_clk; - if(im_bclkdiffarray_map[gl1pid][i]; uint64_t seb_diff = m_bclkdiffarray_map[pid][i]; std::cout << " -- diff of gl1 vs seb : " << gl1_diff << " " << seb_diff << std::endl; } - else if(i==pooldepth) + else if (i == pooldepth) { std::cout << std::endl; } @@ -853,10 +958,10 @@ void SingleTriggeredInput::FillPool() if (m_PacketAlignmentFailCount[pid] >= m_max_alignment_retries) { std::cout << Name() << ": Max retries reached — permanently ditching packet " << pid << std::endl; - m_PacketAlignmentFailCount[pid] = 0; + m_PacketAlignmentFailCount[pid] = 0; m_PacketAlignmentProblem[pid] = true; } - + m_PrevPoolLastDiffBad[pid] = false; } } @@ -865,7 +970,7 @@ void SingleTriggeredInput::FillPool() return; } -void SingleTriggeredInput::CreateDSTNodes(Event *evt) +void SingleTriggeredInput::CreateDSTNodes(Event* evt) { std::string CompositeNodeName = "Packets"; if (KeepMyPackets()) @@ -873,31 +978,61 @@ void SingleTriggeredInput::CreateDSTNodes(Event *evt) CompositeNodeName = "PacketsKeep"; } PHNodeIterator iter(m_topNode); - PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + PHCompositeNode* dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); if (!dstNode) { dstNode = new PHCompositeNode("DST"); m_topNode->addNode(dstNode); } PHNodeIterator iterDst(dstNode); - PHCompositeNode *detNode = dynamic_cast(iterDst.findFirst("PHCompositeNode", CompositeNodeName)); - if (!detNode) + PHCompositeNode* detNode{nullptr}; + PHCompositeNode* detNodeKeep{nullptr}; + if (m_KeepPacketSet.empty()) + { + detNode = dynamic_cast(iterDst.findFirst("PHCompositeNode", CompositeNodeName)); + if (!detNode) + { + detNode = new PHCompositeNode(CompositeNodeName); + dstNode->addNode(detNode); + } + } + else { - detNode = new PHCompositeNode(CompositeNodeName); - dstNode->addNode(detNode); + // if we want to keep a few packets, we need two detNodes, Packet and PacketKeep + // this construct here allows for the KeepMyPackets flag to take effect, then both + // node pointers detNode and detNodeKeep point to the same (so KeepMyPackets has precedence) + detNode = dynamic_cast(iterDst.findFirst("PHCompositeNode", CompositeNodeName)); + if (!detNode) + { + detNode = new PHCompositeNode(CompositeNodeName); + dstNode->addNode(detNode); + } + detNodeKeep = dynamic_cast(iterDst.findFirst("PHCompositeNode", "PacketsKeep")); + if (!detNodeKeep) + { + detNodeKeep = new PHCompositeNode("PacketsKeep"); + dstNode->addNode(detNodeKeep); + } } - std::vector pktvec = evt->getPacketVector(); - for (auto *piter : pktvec) + + std::vector pktvec = evt->getPacketVector(); + for (auto* piter : pktvec) { int packet_id = piter->getIdentifier(); m_PacketSet.insert(packet_id); - std::string PacketNodeName = std::to_string(packet_id); - CaloPacket *calopacket = findNode::getClass(detNode, PacketNodeName); + CaloPacket* calopacket = findNode::getClass(detNode, packet_id); if (!calopacket) { calopacket = new CaloPacketv1(); - PHIODataNode *newNode = new PHIODataNode(calopacket, PacketNodeName, "PHObject"); - detNode->addNode(newNode); + PHIODataNode* newNode = new PHIODataNode(calopacket, packet_id, "PHObject"); + if (m_KeepPacketSet.contains(packet_id)) + { + detNodeKeep->addNode(newNode); + } + else + { + detNode->addNode(newNode); + } } m_PacketShiftOffset.try_emplace(packet_id, 0); delete piter; @@ -940,8 +1075,10 @@ bool SingleTriggeredInput::FemClockAlignment(int pid, const std::deque& } int majority_clk = std::max_element( - clk_count.begin(), clk_count.end(), - [](const auto& a, const auto& b) { return a.second < b.second; })->first; + clk_count.begin(), clk_count.end(), + [](const auto& a, const auto& b) + { return a.second < b.second; }) + ->first; if (clk_count[majority_clk] < 2) { @@ -949,7 +1086,6 @@ bool SingleTriggeredInput::FemClockAlignment(int pid, const std::deque& return false; } - if (i >= 1 && prev_clk != std::numeric_limits::max() && gl1diff[i] != std::numeric_limits::max()) { uint16_t fem_diff = static_cast(ComputeClockDiff(majority_clk, prev_clk) & 0xFFFFU); @@ -968,9 +1104,9 @@ bool SingleTriggeredInput::FemClockAlignment(int pid, const std::deque& return true; } -int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket *pkt) +int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket* pkt) { - CaloPacket *calopkt = dynamic_cast(pkt); + CaloPacket* calopkt = dynamic_cast(pkt); if (!calopkt) { return 0; @@ -1008,7 +1144,7 @@ int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket *pkt) } } } - else + else { for (int j = 0; j < nrModules; j++) { @@ -1056,7 +1192,7 @@ int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket *pkt) for (const auto iterA : ClockMap) { std::cout << "Clock : 0x" << std::hex << iterA.first << std::dec - << " shows up " << iterA.second << " times" << std::endl; + << " shows up " << iterA.second << " times" << std::endl; } } return -1; @@ -1067,8 +1203,8 @@ int SingleTriggeredInput::FemEventNrClockCheck(OfflinePacket *pkt) void SingleTriggeredInput::dumpdeque() { - const auto *iter1 = clkdiffbegin(); - const auto *iter2 = Gl1Input()->clkdiffbegin(); + const auto* iter1 = clkdiffbegin(); + const auto* iter2 = Gl1Input()->clkdiffbegin(); while (iter1 != clkdiffend()) { std::cout << Name() << " clk: 0x" << std::hex << *iter1 @@ -1099,12 +1235,11 @@ int SingleTriggeredInput::ReadEvent() size_t size = m_PacketEventDeque.begin()->second.size(); std::cout << "deque size: " << size << std::endl; } - - auto *ref_evt = m_PacketEventDeque.begin()->second.front(); + auto* ref_evt = m_PacketEventDeque.begin()->second.front(); RunNumber(ref_evt->getRunNumber()); uint64_t event_number = ref_evt->getEvtSequence(); - if(event_number % 10000==0) + if (event_number % 10000 == 0) { std::cout << "processed events : " << event_number << std::endl; } @@ -1113,19 +1248,19 @@ int SingleTriggeredInput::ReadEvent() bool all_packets_unshifted = std::all_of( m_PacketShiftOffset.begin(), m_PacketShiftOffset.end(), - [](const std::pair& p) { return p.second == 0; }); + [](const std::pair& p) + { return p.second == 0; }); std::set events_to_delete; - for (auto& [pid, dq] : m_PacketEventDeque) { - if(m_PacketAlignmentProblem[pid]) + if (m_PacketAlignmentProblem[pid]) { continue; } + Event* evt = dq.front(); Packet* packet = evt->getPacket(pid); - int packet_id = packet->getIdentifier(); if (packet_id != pid) { @@ -1135,9 +1270,8 @@ int SingleTriggeredInput::ReadEvent() return -1; } - CaloPacket *newhit = findNode::getClass(m_topNode, packet_id); + CaloPacket* newhit = findNode::getClass(m_topNode, packet_id); newhit->Reset(); - if (m_DitchPackets.contains(packet_id) && m_DitchPackets[packet_id].contains(0)) { newhit->setStatus(OfflinePacket::PACKET_DROPPED); @@ -1164,7 +1298,7 @@ int SingleTriggeredInput::ReadEvent() { uint64_t prev_packet_clock = m_PreviousValidBCOMap[packet_id]; newhit->setBCO(prev_packet_clock); - m_PreviousValidBCOMap[packet_id] = GetClock(evt,packet_id); + m_PreviousValidBCOMap[packet_id] = GetClock(evt, packet_id); } else { @@ -1203,7 +1337,7 @@ int SingleTriggeredInput::ReadEvent() int iret = FemEventNrClockCheck(newhit); if (iret < 0) { - std::cout << Name() <<" : failed on FemEventNrClockCheck reset calo packet " << std::endl; + std::cout << Name() << " : failed on FemEventNrClockCheck reset calo packet " << std::endl; newhit->Reset(); } @@ -1213,7 +1347,7 @@ int SingleTriggeredInput::ReadEvent() } } - for(Event *evtdelete : events_to_delete) + for (Event* evtdelete : events_to_delete) { delete evtdelete; } diff --git a/offline/framework/fun4allraw/SingleTriggeredInput.h b/offline/framework/fun4allraw/SingleTriggeredInput.h index 088be73bef..cad0d64bf0 100644 --- a/offline/framework/fun4allraw/SingleTriggeredInput.h +++ b/offline/framework/fun4allraw/SingleTriggeredInput.h @@ -17,6 +17,7 @@ #include #include #include +#include #include class Event; @@ -34,9 +35,6 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler virtual void FillPool(); virtual void RunNumber(const int runno) { m_RunNumber = runno; } virtual int RunNumber() const { return m_RunNumber; } - virtual void EventNumber(const int i) { m_EventNumber = i; } - virtual int EventNumber() const { return m_EventNumber; } - virtual int EventsInThisFile() const { return m_EventsThisFile; } virtual int fileopen(const std::string &filename) override; virtual int fileclose() override; virtual int AllDone() const { return m_AllDone; } @@ -45,6 +43,8 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler virtual void FilesDone(const int i) { m_FilesDone = i; } virtual void EventAlignmentProblem(const int i) { m_EventAlignmentProblem = i; } virtual int EventAlignmentProblem() const { return m_EventAlignmentProblem; } + virtual void EventNumber(const int i) { m_EventNumber = i; } + virtual int EventNumber() const { return m_EventNumber; } virtual void CreateDSTNodes(Event *evt); // these ones are used directly by the derived classes, maybe later // move to cleaner accessors @@ -59,15 +59,16 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler virtual std::array::const_iterator beginclock() { return m_bclkarray.begin(); } virtual void KeepPackets() { m_KeepPacketsFlag = true; } virtual bool KeepMyPackets() const { return m_KeepPacketsFlag; } + virtual void KeepPacket(const int packetnum) { m_KeepPacketSet.insert(packetnum); } void topNode(PHCompositeNode *topNode) { m_topNode = topNode; } PHCompositeNode *topNode() { return m_topNode; } virtual void FakeProblemEvent(const int ievent) { m_ProblemEvent = ievent; } virtual int FemEventNrClockCheck(OfflinePacket *calopkt); void dumpdeque(); int checkfirstsebevent(); - virtual bool CheckFemDiffIdx(int pid, size_t index, const std::deque& events, uint64_t gl1diffidx); - virtual bool CheckPoolAlignment(int pid, const std::array& sebdiff, const std::array& gl1diff, std::vector& bad_indices, int& shift, bool& CurrentPoolLastDiffBad, bool PrevPoolLastDiffBad); - virtual bool FemClockAlignment(int pid, const std::deque& events, const std::array& gl1diff); + virtual bool CheckFemDiffIdx(int pid, size_t index, const std::deque &events, uint64_t gl1diffidx); + virtual bool CheckPoolAlignment(int pid, const std::array &sebdiff, const std::array &gl1diff, std::vector &bad_indices, int &shift, bool &CurrentPoolLastDiffBad, bool PrevPoolLastDiffBad); + virtual bool FemClockAlignment(int pid, const std::deque &events, const std::array &gl1diff); protected: PHCompositeNode *m_topNode{nullptr}; @@ -77,24 +78,22 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler // the accompanying diff to the previous beam clock with this event, so any mismatch // gives us the event index in the deque which is off std::deque m_EventDeque; - std::map> m_PacketEventDeque; - std::map m_PacketEventBackup; + std::map> m_PacketEventDeque; + std::map m_PacketEventBackup; std::map m_PacketShiftOffset; std::array m_bclkarray{}; // keep the last bco from previous loop std::array m_bclkdiffarray{}; std::map> m_bclkarray_map; - std::map> m_bclkdiffarray_map; + std::map> m_bclkdiffarray_map; std::set m_PacketSet; static uint64_t ComputeClockDiff(uint64_t curr, uint64_t prev) { return (curr - prev) & 0xFFFFFFFF; } - private: Eventiterator *m_EventIterator{nullptr}; SingleTriggeredInput *m_Gl1Input{nullptr}; int m_AllDone{0}; uint64_t m_Event{0}; int m_EventNumber{0}; - int m_EventsThisFile{0}; int m_EventAlignmentProblem{0}; int m_FilesDone{0}; int m_LastEvent{std::numeric_limits::max()}; @@ -106,6 +105,7 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler bool firstclockcheck{true}; bool m_KeepPacketsFlag{false}; bool m_packetclk_copy_runs{false}; + int64_t eventcounter{0}; std::set m_CorrectCopiedClockPackets; std::map> m_DitchPackets; std::set m_FEMEventNrSet; @@ -114,6 +114,7 @@ class SingleTriggeredInput : public Fun4AllBase, public InputFileHandler std::map m_PacketAlignmentProblem; std::map m_PrevPoolLastDiffBad; std::map m_PreviousValidBCOMap; + std::unordered_set m_KeepPacketSet; }; #endif diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc index 8eeca60c88..21917c0cf3 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.cc @@ -8,6 +8,9 @@ #include #include +#include +#include + #include // for PHTimer #include @@ -596,6 +599,12 @@ int TpcTimeFrameBuilder::ProcessPacket(Packet* packet) { unsigned int fee_id = dma_word_data.dma_header & 0xffU; + // for packet id 4XYZ ebdc is XY, endpoint is Z + if (m_maskedFEEs[((m_packet_id / 10) % 100)].contains(fee_id)) + { + continue; + } + if (fee_id < MAX_FEECOUNT) { for (const uint16_t& i : dma_word_data.data) @@ -713,7 +722,7 @@ int TpcTimeFrameBuilder::process_fee_data(unsigned int fee) } // valid packet - const uint16_t& pkt_length = data_buffer[0]; // this is indeed the number of 10-bit words + 5 in this packet + const uint16_t pkt_length = data_buffer[0]; // this is indeed the number of 10-bit words + 5 in this packet if (pkt_length > MAX_PACKET_LENGTH) { if (m_verbosity > 1) @@ -1115,6 +1124,10 @@ void TpcTimeFrameBuilder::process_fee_data_digital_current(const unsigned int& f return; } +void TpcTimeFrameBuilder::SaveBXCounterSyncCDBTTree(const std::string& /*name*/) +{ +} + void TpcTimeFrameBuilder::SaveDigitalCurrentDebugTTree(const std::string& name) { if (m_verbosity >= 1) @@ -2056,3 +2069,27 @@ void TpcTimeFrameBuilder::BcoMatchingInformation::cleanup(uint64_t ref_bco) // clear orphans m_orphans.clear(); } + +void TpcTimeFrameBuilder::fillBadFeeMap() +{ + const std::string filename = CDBInterface::instance()->getUrl("TPC_DECODER_BAD_FEE"); + + if (filename.empty()) + { + if (m_verbosity > 0) + { + std::cout << "TpcTimeFrameBuilder::fillBadFeeMap - no file found for TPC_DECODER_BAD_FEE, not filling bad fee map" << std::endl; + } + return; + } + + CDBTTree cdbtree(filename); + cdbtree.LoadCalibrations(); + + const int nentries = cdbtree.GetSingleIntValue("N_MASKED_FEES"); + + for (int i = 0; i < nentries; i++) + { + m_maskedFEEs[cdbtree.GetIntValue(i, "EBDC")].insert(cdbtree.GetIntValue(i, "FEEID")); + } +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h index 553052b851..9d65baba5b 100644 --- a/offline/framework/fun4allraw/TpcTimeFrameBuilder.h +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilder.h @@ -1,6 +1,8 @@ #ifndef Fun4All_TpcTimeFrameBuilder_H #define Fun4All_TpcTimeFrameBuilder_H +#include "TpcTimeFrameBuilderBase.h" + #include #include #include @@ -24,25 +26,28 @@ class TH2; class TTree; // NOLINTNEXTLINE(hicpp-special-member-functions) -class TpcTimeFrameBuilder +class TpcTimeFrameBuilder : public TpcTimeFrameBuilderBase { public: explicit TpcTimeFrameBuilder(const int packet_id); - virtual ~TpcTimeFrameBuilder(); + ~TpcTimeFrameBuilder() override; - int ProcessPacket(Packet *); - bool isMoreDataRequired(const uint64_t >m_bco) const; - void CleanupUsedPackets(const uint64_t &bclk); - std::vector &getTimeFrame(const uint64_t >m_bco); + int ProcessPacket(Packet *) override; + bool isMoreDataRequired(const uint64_t >m_bco) const override; + void CleanupUsedPackets(const uint64_t &bclk) override; + std::vector &getTimeFrame(const uint64_t >m_bco) override; - void setVerbosity(const int i); + void setVerbosity(int i) override; void setFastBCOSkip(bool fastBCOSkip = true) { m_fastBCOSkip = fastBCOSkip; } + void fillBadFeeMap() override; + // enable saving of digital current debug TTree with file name `name` - void SaveDigitalCurrentDebugTTree(const std::string &name); + void SaveDigitalCurrentDebugTTree(const std::string &name) override; + void SaveBXCounterSyncCDBTTree(const std::string &name) override; protected: // Length for the 256-bit wide Round Robin Multiplexer for the data stream @@ -50,7 +55,7 @@ class TpcTimeFrameBuilder static const uint16_t FEE_PACKET_MAGIC_KEY_1 = 0xfe; static const uint16_t FEE_PACKET_MAGIC_KEY_2 = 0xed; - static const uint16_t FEE_PACKET_MAGIC_KEY_3_DC = 0xdcdc; // Digital Current word[3] + static const uint16_t FEE_PACKET_MAGIC_KEY_3_DC = 0xdcdc; // Digital Current word[3] static const uint16_t FEE_MAGIC_KEY = 0xba00; static const uint16_t GTM_MAGIC_KEY = 0xbb00; @@ -81,8 +86,8 @@ class TpcTimeFrameBuilder int decode_gtm_data(const dma_word >m_word); int process_fee_data(unsigned int fee_id); - void process_fee_data_waveform(const unsigned int & fee_id, std::deque& data_buffer); - void process_fee_data_digital_current(const unsigned int & fee_id, std::deque& data_buffer); + void process_fee_data_waveform(const unsigned int &fee_id, std::deque &data_buffer); + void process_fee_data_digital_current(const unsigned int &fee_id, std::deque &data_buffer); struct gtm_payload { @@ -112,7 +117,7 @@ class TpcTimeFrameBuilder uint16_t data_crc = 0; uint16_t calc_crc = 0; - + uint16_t data_parity = 0; uint16_t calc_parity = 0; @@ -123,18 +128,18 @@ class TpcTimeFrameBuilder { static const int MAX_CHANNELS = 8; - uint64_t gtm_bco {std::numeric_limits::max()}; - uint32_t bx_timestamp_predicted {std::numeric_limits::max()}; + uint64_t gtm_bco{std::numeric_limits::max()}; + uint32_t bx_timestamp_predicted{std::numeric_limits::max()}; - uint16_t fee {std::numeric_limits::max()}; - uint16_t pkt_length {std::numeric_limits::max()}; - uint16_t channel {std::numeric_limits::max()}; + uint16_t fee{std::numeric_limits::max()}; + uint16_t pkt_length{std::numeric_limits::max()}; + uint16_t channel{std::numeric_limits::max()}; // uint16_t sampa_max_channel {std::numeric_limits::max()}; - uint16_t sampa_address {std::numeric_limits::max()}; - uint32_t bx_timestamp {0}; - uint32_t current[MAX_CHANNELS] {0}; - uint32_t nsamples[MAX_CHANNELS] {0}; - uint16_t data_crc {std::numeric_limits::max()}; + uint16_t sampa_address{std::numeric_limits::max()}; + uint32_t bx_timestamp{0}; + uint32_t current[MAX_CHANNELS]{0}; + uint32_t nsamples[MAX_CHANNELS]{0}; + uint16_t data_crc{std::numeric_limits::max()}; uint16_t calc_crc = {std::numeric_limits::max()}; // uint16_t type {std::numeric_limits::max()}; }; @@ -153,7 +158,7 @@ class TpcTimeFrameBuilder std::string m_name; TTree *m_tDigitalCurrent = nullptr; }; - DigitalCurrentDebugTTree * m_digitalCurrentDebugTTree = nullptr; + DigitalCurrentDebugTTree *m_digitalCurrentDebugTTree = nullptr; // ------------------------- // GTM Matcher @@ -371,6 +376,8 @@ class TpcTimeFrameBuilder private: std::vector> m_feeData; + std::map> m_maskedFEEs; + int m_verbosity = 0; int m_packet_id = 0; diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h new file mode 100644 index 0000000000..e67c3b18a4 --- /dev/null +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderBase.h @@ -0,0 +1,27 @@ +#ifndef FUN4ALLRAW_TPCTIMEFRAMEBUILDERBASE_H +#define FUN4ALLRAW_TPCTIMEFRAMEBUILDERBASE_H + +#include +#include +#include + +class Packet; +class TpcRawHit; + +class TpcTimeFrameBuilderBase +{ + public: + virtual ~TpcTimeFrameBuilderBase() = default; + + virtual int ProcessPacket(Packet *) = 0; + virtual bool isMoreDataRequired(const uint64_t >m_bco) const = 0; + virtual void CleanupUsedPackets(const uint64_t &bclk) = 0; + virtual std::vector &getTimeFrame(const uint64_t >m_bco) = 0; + + virtual void setVerbosity(int i) = 0; + virtual void fillBadFeeMap() = 0; + virtual void SaveDigitalCurrentDebugTTree(const std::string &name) = 0; + virtual void SaveBXCounterSyncCDBTTree(const std::string &name) = 0; +}; + +#endif diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc new file mode 100644 index 0000000000..cab8c787b5 --- /dev/null +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.cc @@ -0,0 +1,2904 @@ +#include "TpcTimeFrameBuilderRun3.h" + +#include +#include + +#include + +#include +#include + +#include +#include + +#include // for PHTimer + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include // For std::tie + +TpcTimeFrameBuilderRun3::TpcTimeFrameBuilderRun3(const int packet_id) + : m_packet_id(packet_id) + , m_HistoPrefix("TpcTimeFrameBuilderRun3_Packet" + std::to_string(packet_id)) + , m_bxCounterSyncCDBTTreeName(m_HistoPrefix + "_BXCounterSyncCDBTTree.root") +{ + for (int fee = 0; fee < MAX_FEECOUNT; ++fee) + { + m_bcoMatchingInformation_vec.emplace_back( + std::string("BcoMatchingInformation_Packet") + std::to_string(packet_id) + "_FEE" + std::to_string(fee)); + } + + m_feeData.resize(MAX_FEECOUNT); + m_timeHitMap.resize(MAX_FEECOUNT); + + // cppcheck-suppress noCopyConstructor + // cppcheck-suppress noOperatorEq + m_packetTimer = new PHTimer("TpcTimeFrameBuilderRun3_Packet" + std::to_string(packet_id)); + + Fun4AllHistoManager* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + m_hNorm = new TH1D(TString(m_HistoPrefix.c_str()) + "_Normalization", // + TString(m_HistoPrefix.c_str()) + " Normalization;Items;Count", + kRun3NormalizationBinCount, .5, kRun3NormalizationBinCount + .5); + int i = 1; + m_hNorm->GetXaxis()->SetBinLabel(i++, "Packet"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Lv1-Taggers"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "EnDat-Taggers"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "ChannelPackets"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Waveforms"); + + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_GTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_FEE"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_FEE_INVALID"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_INVALID"); + + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_GTM_HEARTBEAT"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "DMA_WORD_GTM_DC_STOP_SEND"); + + m_hNorm->GetXaxis()->SetBinLabel(i++, "TimeFrameSizeLimitError"); + + m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Matched"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Unmatched"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Matched_Hit_Sum"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "GTM_TimeFrame_Dropped_Hit_Sum"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Run3_TimeFrame_Exact_Matched"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Run3_TimeFrame_FuzzyFallback"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Run3_TimeFrame_FuzzyFallback_Hit_Sum"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "Run3_TimeFrame_MatchFailed"); + + m_hNormTruncatedWaveformRecoveryFeeFirstBin = i; + for (uint16_t fee = 0; fee < MAX_FEECOUNT; ++fee) + { + m_hNorm->GetXaxis()->SetBinLabel(i++, ("Run3_TruncatedWaveformRecover_FEE" + std::to_string(fee)).c_str()); + } + + assert(i <= kRun3NormalizationBinCount + 1); + m_hNorm->GetXaxis()->LabelsOption("v"); + hm->registerHisto(m_hNorm); + + h_PacketLength = new TH1I(TString(m_HistoPrefix.c_str()) + "_PacketLength", // + TString(m_HistoPrefix.c_str()) + " PacketLength;PacketLength [32bit Words];Count", 1000, .5, 5e6); + hm->registerHisto(h_PacketLength); + + h_PacketLength_Residual = new TH1I(TString(m_HistoPrefix.c_str()) + "_PacketLength_Residual", // + TString(m_HistoPrefix.c_str()) + + " PacketLength that does not fit into DMA transfer;PacketLength [16bit Words];Count", + 16, -.5, 15.5); + hm->registerHisto(h_PacketLength_Residual); + + h_PacketLength_Padding = new TH1I(TString(m_HistoPrefix.c_str()) + "_PacketLength_Padding", // + TString(m_HistoPrefix.c_str()) + + " padding within PacketLength;PacketLength [32bit Words];Count", + 16, -.5, 15.5); + hm->registerHisto(h_PacketLength_Padding); + + m_hFEEDataStream = new TH2I(TString(m_HistoPrefix.c_str()) + "_FEE_DataStream_WordCount", // + TString(m_HistoPrefix.c_str()) + + " FEE Data Stream Word Count;FEE ID;Type;Count", + MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5, 25, .5, 25.5); + i = 1; + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "WordValid"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "WordSkipped"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "WordDigitalCurrentKeyWord"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "InvalidLength"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "RawHit"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitFormatErrorOverLength"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitFormatErrorMismatchedLength"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitCRCError"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "DigitalCurrent"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "DigitalCurrentFormatErrorMismatchedLength"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "DigitalCurrentCRCError"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "ParityError"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "HitUnusedBeforeCleanup"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeat"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeatClockSyncUnavailable"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeatClockSyncError"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketHeartBeatClockSyncOK"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketClockSyncUnavailable"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketClockSyncError"); + m_hFEEDataStream->GetYaxis()->SetBinLabel(i++, "PacketClockSyncOK"); + assert(i <= 25); + hm->registerHisto(m_hFEEDataStream); + + m_hFEEChannelPacketCount = new TH1I(TString(m_HistoPrefix.c_str()) + "_FEEChannelPacketCount", // + TString(m_HistoPrefix.c_str()) + + " Count of waveform packet per channel;FEE*256 + Channel;Count", + MAX_FEECOUNT * MAX_CHANNELS, -.5, MAX_FEECOUNT * MAX_CHANNELS - .5); + hm->registerHisto(m_hFEEChannelPacketCount); + + m_hFEESAMPAADC = new TH2I(TString(m_HistoPrefix.c_str()) + "_FEE_SAMPA_ADC", // + TString(m_HistoPrefix.c_str()) + + " ADC distribution in 2D;ADC Time Bin [0...1023];FEE*8+SAMPA;Sum ADC", + MAX_PACKET_LENGTH, -.5, MAX_PACKET_LENGTH - .5, + MAX_FEECOUNT * MAX_SAMPA, -.5, MAX_FEECOUNT * MAX_SAMPA - .5); + hm->registerHisto(m_hFEESAMPAADC); + + m_hFEESAMPAHeartBeatSync = new TH1I(TString(m_HistoPrefix.c_str()) + "_FEE_SAMPA_HEARTBEAT_SYNC", // + TString(m_HistoPrefix.c_str()) + + " FEE/SAMPA Sync Heartbeat Count;FEE*8+SAMPA;Sync Heartbeat Count", + MAX_FEECOUNT * MAX_SAMPA, -.5, MAX_FEECOUNT * MAX_SAMPA - .5); + hm->registerHisto(m_hFEESAMPAHeartBeatSync); + + h_GTMClockDiff_Matched = new TH1I(TString(m_HistoPrefix.c_str()) + "_GTMClockDiff_Matched", // + TString(m_HistoPrefix.c_str()) + + " GTM BCO Diff for Matched Time Frame;Trigger BCO Diff [BCO];Count", + 1024, -512 - .5, 512 - .5); + hm->registerHisto(h_GTMClockDiff_Matched); + h_GTMClockDiff_Unmatched = new TH1I(TString(m_HistoPrefix.c_str()) + "_GTMClockDiff_Unmatched", // + TString(m_HistoPrefix.c_str()) + + " GTM BCO Diff for Unmatched Time Frame;Trigger BCO Diff [BCO];Count", + 1024, -512 - .5, 512 - .5); + hm->registerHisto(h_GTMClockDiff_Unmatched); + h_GTMClockDiff_Dropped = new TH1I(TString(m_HistoPrefix.c_str()) + "_GTMClockDiff_Dropped", // + TString(m_HistoPrefix.c_str()) + + " GTM BCO Diff for Dropped Time Frame;Trigger BCO Diff [BCO];Count", + 16384, -16384 - .5, 0 - .5); + hm->registerHisto(h_GTMClockDiff_Dropped); + h_TimeFrame_Matched_Size = new TH1I(TString(m_HistoPrefix.c_str()) + "_TimeFrame_Matched_Size", // + TString(m_HistoPrefix.c_str()) + + " Time frame size for Matched Time Frame ;Size [TPC raw hits];Count", + 3328, -.5, 3328 - .5); + hm->registerHisto(h_TimeFrame_Matched_Size); + + h_Run3_FEE_GTMMatching_ClockDiff = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3_FEE_GTMMatching_ClockDiff", // + TString(m_HistoPrefix.c_str()) + + " Run3 FEE GTM matching clock diff by FEE;Clock Difference [FEE Clock Cycle];FEE;Matched hits", + 2048, -1024 - .5, 1024 - .5, + MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3_FEE_GTMMatching_ClockDiff); + + h_Run3TimeFrameExactHit_FEE = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3TimeFrameExactHit_FEE", // + TString(m_HistoPrefix.c_str()) + + " Run3 exact matched hit sum by FEE;FEE;Exact matched hits", + MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3TimeFrameExactHit_FEE); + + h_Run3TimeFrameFuzzyHit_FEE = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3TimeFrameFuzzyHit_FEE", // + TString(m_HistoPrefix.c_str()) + + " Run3 fuzzy fallback matched hit sum by FEE;FEE;Fuzzy fallback matched hits", + MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3TimeFrameFuzzyHit_FEE); + + static constexpr uint32_t kRun3TruncatedWaveformRecoveryWindowPlotingRange = 1200U; + h_Run3Waveform_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3Waveform_GL1Spacing", // + TString(m_HistoPrefix.c_str()) + + " Run3 matched waveform ADC sum before truncated waveform recovery vs GL1 spacing;ADC Time Bin [0...1199];Current - previous GL1 GTM BCO [BCO]", + kRun3TruncatedWaveformRecoveryWindowPlotingRange, -.5, static_cast(kRun3TruncatedWaveformRecoveryWindowPlotingRange) - .5, 1001, -.5, 1000.5); + hm->registerHisto(h_Run3Waveform_GL1Spacing); + + h_Run3WaveformRecovered_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3WaveformRecovered_GL1Spacing", // + TString(m_HistoPrefix.c_str()) + + " Run3 matched waveform ADC sum after truncated waveform recovery vs GL1 spacing;ADC Time Bin [0...1199];Current - previous GL1 GTM BCO [BCO]", + kRun3TruncatedWaveformRecoveryWindowPlotingRange, -.5, static_cast(kRun3TruncatedWaveformRecoveryWindowPlotingRange) - .5, 1001, -.5, 1000.5); + hm->registerHisto(h_Run3WaveformRecovered_GL1Spacing); + + h_Run3FEE_TimeFrameCount_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3FEE_TimeFrameCount_GL1Spacing", // + TString(m_HistoPrefix.c_str()) + + " Run3 exact timeframe count by FEE vs GL1 spacing;Current - previous GL1 GTM BCO [BCO];FEE", + 1001, -.5, 1000.5, MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3FEE_TimeFrameCount_GL1Spacing); + + h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3FEE_TimeFrameRecoveredCount_GL1Spacing", // + TString(m_HistoPrefix.c_str()) + + " Run3 timeframe count by FEE after truncated waveform recovery vs GL1 spacing;Current - previous GL1 GTM BCO [BCO];FEE", + 1001, -.5, 1000.5, MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing); + + h_Run3FEE_TriggerCount_GL1Spacing = new TH2I(TString(m_HistoPrefix.c_str()) + "_Run3FEE_TriggerCount_GL1Spacing", // + TString(m_HistoPrefix.c_str()) + + " Run3 GL1 trigger count by FEE vs GL1 spacing;Current - previous GL1 GTM BCO [BCO];FEE", + 1001, -.5, 1000.5, MAX_FEECOUNT, -.5, MAX_FEECOUNT - .5); + hm->registerHisto(h_Run3FEE_TriggerCount_GL1Spacing); + + h_Run3PreviousTimeFrameWaveformADC = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3PreviousTimeFrameWaveformADCCache", // + TString(m_HistoPrefix.c_str()) + + " Run3 previous matched waveform ADC cache;ADC Time Bin [0...1199];Sum ADC", + kRun3TruncatedWaveformRecoveryWindowPlotingRange, -.5, static_cast(kRun3TruncatedWaveformRecoveryWindowPlotingRange) - .5); + h_Run3PreviousTimeFrameWaveformADC->SetDirectory(nullptr); + + h_Run3PreviousTimeFrameRecoveredWaveformADC = new TH1I(TString(m_HistoPrefix.c_str()) + "_Run3PreviousTimeFrameRecoveredWaveformADCCache", // + TString(m_HistoPrefix.c_str()) + + " Run3 previous matched waveform ADC cache after truncated waveform recovery;ADC Time Bin [0...1199];Sum ADC", + kRun3TruncatedWaveformRecoveryWindowPlotingRange, -.5, static_cast(kRun3TruncatedWaveformRecoveryWindowPlotingRange) - .5); + h_Run3PreviousTimeFrameRecoveredWaveformADC->SetDirectory(nullptr); + + h_ProcessPacket_Time = new TH2I(TString(m_HistoPrefix.c_str()) + "_ProcessPacket_Time", // + TString(m_HistoPrefix.c_str()) + + " Time cost to run ProcessPacket();Call counts;Time elapsed per call [ms];Count", + 100, 0, 30e6, 100, 0, 10); + hm->registerHisto(h_ProcessPacket_Time); +} + +TpcTimeFrameBuilderRun3::~TpcTimeFrameBuilderRun3() +{ + for (auto& feeTimeHitMap : m_timeHitMap) + { + for (auto& timeHitEntry : feeTimeHitMap) + { + for (TpcRawHit* hit : timeHitEntry.second) + { + delete hit; + } + timeHitEntry.second.clear(); + } + } + + for (auto& timeFrameEntry : m_timeFrameMap) + { + while (!timeFrameEntry.second.empty()) + { + TpcRawHit* hit = timeFrameEntry.second.back(); + delete hit; + timeFrameEntry.second.pop_back(); + } + } + + write_bx_counter_sync_cdb_tree(); + + delete h_Run3PreviousTimeFrameWaveformADC; + delete h_Run3PreviousTimeFrameRecoveredWaveformADC; + + delete m_packetTimer; + + delete m_digitalCurrentDebugTTree; +} + +void TpcTimeFrameBuilderRun3::setVerbosity(const int i) +{ + m_verbosity = i; + + for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec) + { + bcoMatchingInformation.set_verbosity(i); + } +} + +void TpcTimeFrameBuilderRun3::write_bx_counter_sync_cdb_tree() const +{ + if (m_bxCounterSyncCDBTTreeName.empty()) + { + return; + } + + CDBTTree cdbtree(m_bxCounterSyncCDBTTreeName); + + int entry_count = 0; + for (size_t fee = 0; fee < m_bcoMatchingInformation_vec.size(); ++fee) + { + const BcoMatchingInformation& bco_info = m_bcoMatchingInformation_vec[fee]; + const size_t observation_count = std::min(bco_info.get_bx_counter_sync_observation_count(), + BcoMatchingInformation::kMaxBXCounterSyncObservations); + const auto& observations = bco_info.get_bx_counter_sync_observations(); + for (size_t observation_index = 0; observation_index < observation_count; ++observation_index) + { + const BcoMatchingInformation::BXCounterSyncObservation& observation = observations[observation_index]; + const int channel = static_cast(fee * BcoMatchingInformation::kMaxBXCounterSyncObservations + observation_index); + cdbtree.SetIntValue(channel, "packet_id", m_packet_id); + cdbtree.SetIntValue(channel, "fee", static_cast(fee)); + cdbtree.SetIntValue(channel, "observation", static_cast(observation_index)); + cdbtree.SetUInt64Value(channel, "bx_counter_sync_gtm_bco", observation.bx_counter_sync_gtm_bco); + cdbtree.SetUInt64Value(channel, "bco_reference_gtm_bco", observation.bco_reference_gtm_bco); + cdbtree.SetUInt64Value(channel, "m_bco_reference_gtm_bco", observation.m_bco_reference.first); + cdbtree.SetIntValue(channel, "m_bco_reference_fee_bco", static_cast(observation.m_bco_reference.second)); + ++entry_count; + } + } + + if (entry_count == 0) + { + return; + } + + cdbtree.SetSingleIntValue("packet_id", m_packet_id); + cdbtree.SetSingleIntValue("n_bx_counter_sync_observations", entry_count); + cdbtree.SetSingleIntValue("max_fee_count", MAX_FEECOUNT); + cdbtree.SetSingleIntValue("max_observations_per_fee", static_cast(BcoMatchingInformation::kMaxBXCounterSyncObservations)); + cdbtree.CommitSingle(); + cdbtree.Commit(); + cdbtree.WriteCDBTTree(); + + if (m_verbosity >= 0) + { + std::cout << __PRETTY_FUNCTION__ << " - saved " << entry_count + << " BX_COUNTER_SYNC_T observations to " << m_bxCounterSyncCDBTTreeName << std::endl; + } +} + +void TpcTimeFrameBuilderRun3::fill_waveform_gl1_spacing(TH1 *waveform_adc_cache, TH2 *waveform_gl1_spacing, uint64_t gtm_bco_spacing) const +{ + assert(waveform_adc_cache); + assert(waveform_gl1_spacing); + + const int waveform_ybin = waveform_gl1_spacing->GetYaxis()->FindFixBin(static_cast(gtm_bco_spacing)); + double waveform_entries = 0; + for (int xbin = 1; xbin <= waveform_adc_cache->GetNbinsX(); ++xbin) + { + const double adc_sum = waveform_adc_cache->GetBinContent(xbin); + if (adc_sum == 0) + { + continue; + } + + waveform_gl1_spacing->AddBinContent(waveform_gl1_spacing->GetBin(xbin, waveform_ybin), adc_sum); + ++waveform_entries; + } + waveform_gl1_spacing->SetEntries(waveform_gl1_spacing->GetEntries() + waveform_entries); +} + +void TpcTimeFrameBuilderRun3::flush_previous_timeframe_qa_cache(uint64_t current_gtm_bco) +{ + assert(h_Run3PreviousTimeFrameWaveformADC); + assert(h_Run3PreviousTimeFrameRecoveredWaveformADC); + assert(h_Run3Waveform_GL1Spacing); + assert(h_Run3WaveformRecovered_GL1Spacing); + assert(h_Run3FEE_TimeFrameCount_GL1Spacing); + assert(h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing); + assert(h_Run3FEE_TriggerCount_GL1Spacing); + + if (!m_previousTimeFrameGtmBco) + { + return; + } + + const uint64_t previous_gtm_bco = *m_previousTimeFrameGtmBco; + static constexpr uint64_t gtm_clock_range = uint64_t(1) << 40U; + const uint64_t current_gtm_bco_rollover_corrected = current_gtm_bco >= previous_gtm_bco + ? current_gtm_bco + : current_gtm_bco + gtm_clock_range; + const uint64_t gtm_bco_spacing = current_gtm_bco_rollover_corrected - previous_gtm_bco; + + fill_waveform_gl1_spacing(h_Run3PreviousTimeFrameWaveformADC, h_Run3Waveform_GL1Spacing, gtm_bco_spacing); + fill_waveform_gl1_spacing(h_Run3PreviousTimeFrameRecoveredWaveformADC, h_Run3WaveformRecovered_GL1Spacing, gtm_bco_spacing); + + const int fee_xbin = h_Run3FEE_TriggerCount_GL1Spacing->GetXaxis()->FindFixBin(static_cast(gtm_bco_spacing)); + double timeframe_entries = 0; + double recovered_timeframe_entries = 0; + for (uint16_t fee = 0; fee < MAX_FEECOUNT; ++fee) + { + const int fee_ybin = static_cast(fee) + 1; + h_Run3FEE_TriggerCount_GL1Spacing->AddBinContent(h_Run3FEE_TriggerCount_GL1Spacing->GetBin(fee_xbin, fee_ybin)); + + if (m_previousTimeFrameExactFees.test(fee)) + { + h_Run3FEE_TimeFrameCount_GL1Spacing->AddBinContent(h_Run3FEE_TimeFrameCount_GL1Spacing->GetBin(fee_xbin, fee_ybin)); + ++timeframe_entries; + } + + if (m_previousTimeFrameRecoveredFees.test(fee)) + { + h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing->AddBinContent(h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing->GetBin(fee_xbin, fee_ybin)); + ++recovered_timeframe_entries; + } + } + h_Run3FEE_TriggerCount_GL1Spacing->SetEntries(h_Run3FEE_TriggerCount_GL1Spacing->GetEntries() + MAX_FEECOUNT); + h_Run3FEE_TimeFrameCount_GL1Spacing->SetEntries(h_Run3FEE_TimeFrameCount_GL1Spacing->GetEntries() + timeframe_entries); + h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing->SetEntries(h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing->GetEntries() + recovered_timeframe_entries); + + h_Run3PreviousTimeFrameWaveformADC->Reset(); + h_Run3PreviousTimeFrameRecoveredWaveformADC->Reset(); + m_previousTimeFrameExactFees.reset(); + m_previousTimeFrameRecoveredFees.reset(); + m_previousTimeFrameGtmBco.reset(); +} + +void TpcTimeFrameBuilderRun3::cache_waveform_adc(TH1 *waveform_adc_cache, const std::vector& timeframe) const +{ + assert(waveform_adc_cache); + + waveform_adc_cache->Reset(); + for (const TpcRawHit* hit : timeframe) + { + if (!hit) + { + continue; + } + + std::unique_ptr adc_iter(hit->CreateAdcIterator()); + if (!adc_iter) + { + continue; + } + + for (adc_iter->First(); !adc_iter->IsDone(); adc_iter->Next()) + { + const uint16_t time_bin = adc_iter->CurrentTimeBin(); + const uint16_t adc = adc_iter->CurrentAdc(); + if (adc == 0 || time_bin >= kRun3TruncatedWaveformRecoveryWindow) + { + continue; + } + + waveform_adc_cache->AddBinContent(static_cast(time_bin) + 1, adc); + } + } +} + +void TpcTimeFrameBuilderRun3::cache_timeframe_qa(uint64_t gtm_bco, const std::vector& timeframe, const std::bitset& exact_matched_fees) +{ + cache_waveform_adc(h_Run3PreviousTimeFrameRecoveredWaveformADC, timeframe); + + m_previousTimeFrameExactFees = exact_matched_fees; + m_previousTimeFrameRecoveredFees.reset(); + for (const TpcRawHit* hit : timeframe) + { + if (!hit || hit->get_fee() >= MAX_FEECOUNT) + { + continue; + } + m_previousTimeFrameRecoveredFees.set(hit->get_fee()); + } + m_previousTimeFrameGtmBco = gtm_bco; +} + +int64_t TpcTimeFrameBuilderRun3::get_signed_fee_bco_diff(uint32_t first, uint32_t second) +{ + static constexpr int64_t fee_clock_range = static_cast(uint64_t{1} << 20U); + static constexpr int64_t fee_clock_half_range = static_cast(uint64_t{1} << 19U); + + int64_t diff = static_cast(first & kFEEClockMask) - static_cast(second & kFEEClockMask); + if (diff > fee_clock_half_range) + { + diff -= fee_clock_range; + } + else if (diff < -fee_clock_half_range) + { + diff += fee_clock_range; + } + return diff; +} + +uint32_t TpcTimeFrameBuilderRun3::get_fee_bco_diff(uint32_t first, uint32_t second) +{ + const int64_t diff = get_signed_fee_bco_diff(first, second); + return static_cast(diff < 0 ? -diff : diff); +} + +size_t TpcTimeFrameBuilderRun3::move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector& timeframe) +{ + if (fee >= m_timeHitMap.size()) + { + return 0; + } + + auto& fee_time_hits = m_timeHitMap[fee]; + auto it = fee_time_hits.find(fee_bco & kFEEClockMask); + if (it == fee_time_hits.end()) + { + return 0; + } + + std::vector& hits = it->second; + const size_t moved = hits.size(); + if (moved == 0) + { + fee_time_hits.erase(it); + return 0; + } + + timeframe.reserve(timeframe.size() + moved); + timeframe.insert(timeframe.end(), hits.begin(), hits.end()); + fee_time_hits.erase(it); + return moved; +} + +size_t TpcTimeFrameBuilderRun3::count_time_hits(uint32_t fee_bco, uint16_t fee) const +{ + if (fee >= m_timeHitMap.size()) + { + return 0; + } + + const auto& fee_time_hits = m_timeHitMap[fee]; + auto it = fee_time_hits.find(fee_bco & kFEEClockMask); + if (it == fee_time_hits.end()) + { + return 0; + } + + return it->second.size(); +} + +size_t TpcTimeFrameBuilderRun3::time_hit_bucket_count() const +{ + size_t count = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + count += fee_time_hits.size(); + } + return count; +} + +std::optional TpcTimeFrameBuilderRun3::find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const +{ + if (fee >= m_timeHitMap.size()) + { + return std::nullopt; + } + + const auto& fee_time_hits = m_timeHitMap[fee]; + if (fee_time_hits.empty()) + { + return std::nullopt; + } + + predicted_fee_bco &= kFEEClockMask; + uint32_t best_fee_bco = 0; + uint32_t best_diff = std::numeric_limits::max(); + bool found = false; + + auto consider_fee_bco = [&](uint32_t fee_bco, const std::vector& hits) + { + if (hits.empty()) + { + return; + } + + const uint32_t diff = get_fee_bco_diff(fee_bco, predicted_fee_bco); + if (diff <= kRun3FeeMatchWindow && (!found || diff < best_diff || (diff == best_diff && fee_bco < best_fee_bco))) + { + found = true; + best_diff = diff; + best_fee_bco = fee_bco; + } + }; + + auto scan_range = [&](uint32_t first_fee_bco, uint32_t last_fee_bco) + { + for (auto it = fee_time_hits.lower_bound(first_fee_bco); it != fee_time_hits.end() && it->first <= last_fee_bco; ++it) + { + consider_fee_bco(it->first, it->second); + } + }; + + const uint32_t lower_fee_bco = (predicted_fee_bco - kRun3FeeMatchWindow) & kFEEClockMask; + const uint32_t upper_fee_bco = (predicted_fee_bco + kRun3FeeMatchWindow) & kFEEClockMask; + if (lower_fee_bco <= upper_fee_bco) + { + scan_range(lower_fee_bco, upper_fee_bco); + } + else + { + scan_range(lower_fee_bco, kFEEClockMask); + scan_range(0, upper_fee_bco); + } + + if (found) + { + return best_fee_bco; + } + return std::nullopt; +} + +size_t TpcTimeFrameBuilderRun3::append_shifted_waveforms(TpcRawHitRun3_typ *target, const TpcRawHit &source, uint32_t fee_clock_shift) const +{ + if (!target || fee_clock_shift >= kRun3TruncatedWaveformRecoveryWindow) + { + return 0; + } + + const auto& source_run3 = static_cast(source); + const TpcRawHitRun3_typ::AdcWaveformVector_t& source_waveforms = source_run3.get_adc_waveforms(); + if (source_waveforms.empty()) + { + return 0; + } + + size_t appended_waveforms = 0; + std::vector adc_values; + uint16_t waveform_start = 0; + uint32_t expected_time_bin = std::numeric_limits::max(); + + auto flush_waveform = [&]() + { + if (adc_values.empty()) + { + return; + } + + std::vector waveform_adc; + waveform_adc.swap(adc_values); + target->move_adc_waveform(waveform_start, std::move(waveform_adc)); + expected_time_bin = std::numeric_limits::max(); + ++appended_waveforms; + }; + + for (const TpcRawHitRun3_typ::AdcWaveform_t& source_waveform : source_waveforms) + { + const std::vector& source_adc_values = source_waveform.second; + if (source_adc_values.empty()) + { + continue; + } + + const uint32_t shifted_waveform_start = static_cast(source_waveform.first) + fee_clock_shift; + if (shifted_waveform_start >= kRun3TruncatedWaveformRecoveryWindow) + { + flush_waveform(); + continue; + } + + for (size_t adc_index = 0; adc_index < source_adc_values.size(); ++adc_index) + { + const uint32_t shifted_time_bin = shifted_waveform_start + static_cast(adc_index); + if (shifted_time_bin >= kRun3TruncatedWaveformRecoveryWindow) + { + flush_waveform(); + break; + } + + if (adc_values.empty() || shifted_time_bin != expected_time_bin) + { + flush_waveform(); + waveform_start = static_cast(shifted_time_bin); + } + + adc_values.push_back(source_adc_values[adc_index]); + expected_time_bin = shifted_time_bin + 1U; + } + } + flush_waveform(); + + return appended_waveforms; +} + +size_t TpcTimeFrameBuilderRun3::recover_truncated_waveforms(uint32_t predicted_fee_bco, uint16_t fee, std::vector& timeframe) +{ + if (fee >= m_timeHitMap.size()) + { + return 0; + } + + predicted_fee_bco &= kFEEClockMask; + std::array current_hits{}; + std::array current_hit_diff{}; + current_hit_diff.fill(std::numeric_limits::max()); + + for (TpcRawHit* hit : timeframe) + { + if (!hit || hit->get_fee() != fee || hit->get_channel() >= MAX_CHANNELS) + { + continue; + } + + TpcRawHitRun3_typ* hit_v3 = dynamic_cast(hit); + if (!hit_v3) + { + continue; + } + + const uint16_t channel = hit_v3->get_channel(); + const int64_t signed_diff = get_signed_fee_bco_diff(static_cast(hit_v3->get_bco()), predicted_fee_bco); + const int64_t abs_diff = signed_diff < 0 ? -signed_diff : signed_diff; + if (abs_diff < current_hit_diff[channel]) + { + current_hit_diff[channel] = abs_diff; + current_hits[channel] = hit_v3; + } + } + + size_t recovered_hits = 0; + auto& fee_time_hits = m_timeHitMap[fee]; + if (fee_time_hits.empty()) + { + return 0; + } + + auto recover_from_bucket = [&](const std::pair>& bucket) + { + for (const TpcRawHit* source_hit : bucket.second) + { + if (!source_hit || source_hit->get_channel() >= MAX_CHANNELS) + { + continue; + } + + const uint16_t channel = source_hit->get_channel(); + TpcRawHitRun3_typ* target_hit = current_hits[channel]; + const uint32_t target_fee_bco = target_hit ? static_cast(target_hit->get_bco()) & kFEEClockMask : predicted_fee_bco; + const int64_t fee_bco_diff = get_signed_fee_bco_diff(static_cast(source_hit->get_bco()), target_fee_bco); + if (fee_bco_diff <= 0 || fee_bco_diff >= static_cast(kRun3TruncatedWaveformRecoveryFEEWindow)) + { + continue; + } + + const int64_t fee_clock_shift = fee_bco_diff / static_cast(kRun3FEEClockPerADCClock); + // FEE BCO is 2x ADC clock, so the waveform shift is half the FEE BCO difference. + if (fee_clock_shift <= 0) + { + continue; + } + + bool created_target = false; + if (!target_hit) + { + target_hit = new TpcRawHitRun3_typ(); + target_hit->set_bco(predicted_fee_bco); + target_hit->set_packetid(m_packet_id); + target_hit->set_fee(fee); + target_hit->set_channel(channel); + target_hit->set_type(source_hit->get_type()); + target_hit->set_checksumerror(source_hit->get_checksumerror()); + target_hit->set_parityerror(source_hit->get_parityerror()); + timeframe.push_back(target_hit); + current_hits[channel] = target_hit; + current_hit_diff[channel] = 0; + created_target = true; + } + + const size_t appended_waveforms = append_shifted_waveforms(target_hit, *source_hit, static_cast(fee_clock_shift)); + if (appended_waveforms == 0) + { + if (created_target) + { + current_hits[channel] = nullptr; + current_hit_diff[channel] = std::numeric_limits::max(); + assert(!timeframe.empty() && timeframe.back() == target_hit); + timeframe.pop_back(); + delete target_hit; + } + continue; + } + + target_hit->set_checksumerror(target_hit->get_checksumerror() || source_hit->get_checksumerror()); + target_hit->set_parityerror(target_hit->get_parityerror() || source_hit->get_parityerror()); + ++recovered_hits; + } + }; + + const uint32_t lower_fee_bco = (predicted_fee_bco + 1U) & kFEEClockMask; + const uint32_t upper_fee_bco = (predicted_fee_bco + kRun3TruncatedWaveformRecoveryFEEWindow - 1U) & kFEEClockMask; + auto scan_range = [&](uint32_t first_fee_bco, uint32_t last_fee_bco) + { + for (auto it = fee_time_hits.lower_bound(first_fee_bco); it != fee_time_hits.end() && it->first <= last_fee_bco; ++it) + { + recover_from_bucket(*it); + } + }; + + if (lower_fee_bco <= upper_fee_bco) + { + scan_range(lower_fee_bco, upper_fee_bco); + } + else + { + scan_range(lower_fee_bco, kFEEClockMask); + scan_range(0, upper_fee_bco); + } + + return recovered_hits; +} + + +void TpcTimeFrameBuilderRun3::cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window) +{ + assert(m_hFEEDataStream); + + const size_t nfees = std::min(m_timeHitMap.size(), m_bcoMatchingInformation_vec.size()); + for (size_t fee_index = 0; fee_index < nfees; ++fee_index) + { + const uint16_t fee = static_cast(fee_index); + auto& fee_time_hits = m_timeHitMap[fee_index]; + + const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee_index].get_predicted_fee_bco(bclk_rollover_corrected); + if (!predicted_fee_bco) + { + if (m_verbosity >= 2) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": WARNING: No predicted FEE BCO for fee index " << fee_index + << " with bclk_rollover_corrected: 0x" << std::hex << bclk_rollover_corrected << std::dec + << ". Clearing time hit map for this fee." << std::endl; + } + + for (auto map_it = fee_time_hits.begin(); map_it != fee_time_hits.end();) + { + for (TpcRawHit* hit : map_it->second) + { + m_hFEEDataStream->Fill(fee, "HitUnusedBeforeCleanup", 1); + delete hit; + } + map_it = fee_time_hits.erase(map_it); + } + + continue; + } + + for (auto map_it = fee_time_hits.begin(); map_it != fee_time_hits.end();) + { + const int64_t diff = get_signed_fee_bco_diff(map_it->first, *predicted_fee_bco); + if ((fee_clock_window == 0 && diff <= 0) || (fee_clock_window > 0 && diff < -static_cast(fee_clock_window))) + { + for (TpcRawHit* hit : map_it->second) + { + m_hFEEDataStream->Fill(fee, "HitUnusedBeforeCleanup", 1); + delete hit; + } + map_it = fee_time_hits.erase(map_it); + } + else + { + ++map_it; + } + } + } +} + +bool TpcTimeFrameBuilderRun3::isMoreDataRequired(const uint64_t& gtm_bco) const +{ + for (const BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec) + { + // if (not bcoMatchingInformation.is_verified()) + // { + // continue; + // } + + if (bcoMatchingInformation.isMoreDataRequired(gtm_bco)) + { + return true; + } + } + + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- packet " << m_packet_id + << ":PASS: All FEEs satisfied for gtm_bco: 0x" << std::hex << gtm_bco << std::dec << ". Return false." + << std::endl; + } + return false; +} + +std::vector& TpcTimeFrameBuilderRun3::getTimeFrame(const uint64_t& gtm_bco) +{ + assert(m_hNorm); + const uint64_t bclk_rollover_corrected = m_bcoMatchingInformation_vec[0].get_gtm_rollover_correction(gtm_bco); + + for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec) + { + bcoMatchingInformation.cleanup(bclk_rollover_corrected); + } + + cleanup_time_hit_map(bclk_rollover_corrected, kRun3FeeMatchWindow); + + if (auto cached = m_timeFrameMap.find(bclk_rollover_corrected); cached != m_timeFrameMap.end()) + { + return cached->second; + } + + flush_previous_timeframe_qa_cache(bclk_rollover_corrected); + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": getTimeFrame for gtm_bco: 0x" << std::hex << gtm_bco << std::dec + << ": bclk_rollover_corrected: 0x" << std::hex << bclk_rollover_corrected << std::dec + << std::endl; + } + + // Track initial buffer usage + if (m_verbosity >= 2) + { + size_t total_time_hits = 0; + size_t time_hit_map_buckets = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits += bucket.second.size(); + } + } + size_t total_gtm_bco_trig = 0; + size_t total_bco_heartbeat = 0; + size_t total_gtm_bco_trigger = 0; + size_t total_bco_matching = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig += bco_info.get_gtm_bco_trig_list_size(); + total_bco_heartbeat += bco_info.get_bco_heartbeat_list_size(); + total_gtm_bco_trigger += bco_info.get_gtm_bco_trigger_map_size(); + total_bco_matching += bco_info.get_bco_matching_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [INITIAL] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() + << " frames, m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_timeHitMap: " << time_hit_map_buckets << " FEE-BCO buckets, " + << total_time_hits << " total hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig + << ", bco_heartbeat: " << total_bco_heartbeat + << ", gtm_trigger_map: " << total_gtm_bco_trigger + << ", bco_matching: " << total_bco_matching + << std::endl; + } + + auto inserted_frame = m_timeFrameMap.emplace(bclk_rollover_corrected, std::vector{}); + auto frame_it = inserted_frame.first; + std::vector& timeframe = frame_it->second; + + size_t exact_hit_count = 0; + size_t fallback_hit_count = 0; + std::bitset exact_matched_fees; + std::array predicted_fee_bcos{}; + std::bitset predicted_fee_bco_available; + + for (size_t fee_index = 0; fee_index < std::min(m_bcoMatchingInformation_vec.size(), static_cast(MAX_FEECOUNT)); ++fee_index) + { + const uint16_t fee = static_cast(fee_index); + const std::optional predicted_fee_bco = m_bcoMatchingInformation_vec[fee_index].get_predicted_fee_bco(bclk_rollover_corrected); + if (!predicted_fee_bco) + { + continue; + } + predicted_fee_bcos[fee] = *predicted_fee_bco; + predicted_fee_bco_available.set(fee); + + size_t exact_hits = 0; + for (int32_t fee_clock_offset = -kRun3ExactMatchWindow; fee_clock_offset <= kRun3ExactMatchWindow; ++fee_clock_offset) + { + const uint32_t exact_fee_bco = static_cast(static_cast(static_cast(*predicted_fee_bco) + fee_clock_offset) & kFEEClockMask); + const size_t exact_hits_for_bco = move_time_hits(exact_fee_bco, fee, timeframe); + if (exact_hits_for_bco == 0) + { + continue; + } + + exact_hits += exact_hits_for_bco; + assert(h_Run3_FEE_GTMMatching_ClockDiff); + h_Run3_FEE_GTMMatching_ClockDiff->Fill(static_cast(get_signed_fee_bco_diff(exact_fee_bco, *predicted_fee_bco)), + static_cast(fee), + static_cast(exact_hits_for_bco)); + } + + exact_hit_count += exact_hits; + if (exact_hits > 0) + { + assert(h_Run3TimeFrameExactHit_FEE); + h_Run3TimeFrameExactHit_FEE->Fill(fee, exact_hits); + exact_matched_fees.set(fee); + continue; + } + + const std::optional fuzzy_fee_bco = find_fuzzy_fee_bco(*predicted_fee_bco, fee); + if (!fuzzy_fee_bco) + { + continue; + } + + + const size_t fuzzy_hits = count_time_hits(*fuzzy_fee_bco, fee); + if (fuzzy_hits == 0) + { + continue; + } + + fallback_hit_count += fuzzy_hits; + assert(h_Run3TimeFrameFuzzyHit_FEE); + h_Run3TimeFrameFuzzyHit_FEE->Fill(fee, fuzzy_hits); + assert(h_Run3_FEE_GTMMatching_ClockDiff); + h_Run3_FEE_GTMMatching_ClockDiff->Fill(static_cast(get_signed_fee_bco_diff(*fuzzy_fee_bco, *predicted_fee_bco)), + static_cast(fee), + static_cast(fuzzy_hits)); + + if (m_verbosity >= 2) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": Run3 fuzzy FEE-clock fallback for fee " << fee + << " predicted 0x" << std::hex << *predicted_fee_bco + << " matched 0x" << *fuzzy_fee_bco << std::dec + << " diff " << get_signed_fee_bco_diff(*fuzzy_fee_bco, *predicted_fee_bco) + << " hits " << fuzzy_hits << std::endl; + } + } + + if (fallback_hit_count > 0) + { + m_hNorm->Fill("Run3_TimeFrame_FuzzyFallback", 1); + m_hNorm->Fill("Run3_TimeFrame_FuzzyFallback_Hit_Sum", fallback_hit_count); + } + + cache_waveform_adc(h_Run3PreviousTimeFrameWaveformADC, timeframe); + + // Track buffer usage after exact and fuzzy hit processing + if (m_verbosity >= 2) + { + size_t total_time_hits_post_exact_fuzzy = 0; + size_t time_hit_map_buckets_post_exact_fuzzy = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_post_exact_fuzzy += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_post_exact_fuzzy += bucket.second.size(); + } + } + size_t total_gtm_bco_trig_post = 0; + size_t total_bco_heartbeat_post = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_post += bco_info.get_gtm_bco_trig_list_size(); + total_bco_heartbeat_post += bco_info.get_bco_heartbeat_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [AFTER EXACT/FUZZY] STL buffer usage - exact_hits: " << exact_hit_count + << ", fuzzy_hits: " << fallback_hit_count + << ", timeframe size: " << timeframe.size() + << ", m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_timeHitMap: " << time_hit_map_buckets_post_exact_fuzzy << " buckets, " + << total_time_hits_post_exact_fuzzy << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_post + << ", bco_heartbeat: " << total_bco_heartbeat_post << "]" + << std::endl; + } + + size_t recovered_hit_count = 0; + for (uint16_t fee = 0; fee < MAX_FEECOUNT; ++fee) + { + if (!predicted_fee_bco_available.test(fee)) + { + continue; + } + + const size_t recovered_hits = recover_truncated_waveforms(predicted_fee_bcos[fee], fee, timeframe); + if (recovered_hits == 0) + { + continue; + } + + recovered_hit_count += recovered_hits; + if (m_hNormTruncatedWaveformRecoveryFeeFirstBin > 0) + { + m_hNorm->Fill(static_cast(m_hNormTruncatedWaveformRecoveryFeeFirstBin + fee), static_cast(recovered_hits)); + } + } + + if (m_verbosity >= 2 && recovered_hit_count > 0) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": Run3 truncated waveform recovery appended " << recovered_hit_count + << " later hit segments for gtm_bco: 0x" << std::hex << gtm_bco << std::dec << std::endl; + } + + // Track buffer usage after recovery + if (m_verbosity >= 2) + { + size_t total_time_hits_post_recovery = 0; + size_t time_hit_map_buckets_post_recovery = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_post_recovery += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_post_recovery += bucket.second.size(); + } + } + size_t total_gtm_bco_trig_recovery = 0; + size_t total_bco_heartbeat_recovery = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_recovery += bco_info.get_gtm_bco_trig_list_size(); + total_bco_heartbeat_recovery += bco_info.get_bco_heartbeat_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [AFTER RECOVERY] STL buffer usage - timeframe size: " << timeframe.size() + << ", recovered_hits: " << recovered_hit_count + << ", m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_timeHitMap: " << time_hit_map_buckets_post_recovery << " buckets, " + << total_time_hits_post_recovery << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_recovery + << ", bco_heartbeat: " << total_bco_heartbeat_recovery << "]" + << std::endl; + } + + if (timeframe.empty()) + { + if (m_verbosity >= 1) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ":ERROR: Run3 FEE-clock match failed for gtm_bco: 0x" << std::hex << gtm_bco << std::dec + << " bclk_rollover_corrected 0x" << std::hex << bclk_rollover_corrected << std::dec + << ". m_timeHitMap size: " << time_hit_bucket_count() << std::endl; + } + + if (m_verbosity >= 2) + { + size_t total_time_hits_empty = 0; + size_t time_hit_map_buckets_empty = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_empty += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_empty += bucket.second.size(); + } + } + size_t total_gtm_bco_trig_empty = 0; + size_t total_bco_heartbeat_empty = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_empty += bco_info.get_gtm_bco_trig_list_size(); + total_bco_heartbeat_empty += bco_info.get_bco_heartbeat_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [EMPTY-FRAME ERROR] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_timeHitMap: " << time_hit_map_buckets_empty << " buckets, " + << total_time_hits_empty << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_empty + << ", bco_heartbeat: " << total_bco_heartbeat_empty << "]" + << std::endl; + } + + m_hNorm->Fill("Run3_TimeFrame_MatchFailed", 1); + m_hNorm->Fill("GTM_TimeFrame_Unmatched", 1); + cache_timeframe_qa(bclk_rollover_corrected, timeframe, exact_matched_fees); + m_timeFrameMap.erase(frame_it); + static std::vector empty; + return empty; + } + + if (exact_hit_count > 0) + { + m_hNorm->Fill("Run3_TimeFrame_Exact_Matched", 1); + } + m_hNorm->Fill("GTM_TimeFrame_Matched", 1); + assert(h_TimeFrame_Matched_Size); + h_TimeFrame_Matched_Size->Fill(timeframe.size()); + m_hNorm->Fill("GTM_TimeFrame_Matched_Hit_Sum", timeframe.size()); + cache_timeframe_qa(bclk_rollover_corrected, timeframe, exact_matched_fees); + m_UsedTimeFrameSet.push(bclk_rollover_corrected); + + // Track final buffer usage + if (m_verbosity >= 2) + { + size_t total_time_hits_final = 0; + size_t time_hit_map_buckets_final = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_final += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_final += bucket.second.size(); + } + } + size_t total_gtm_bco_trig_final = 0; + size_t total_bco_heartbeat_final = 0; + size_t total_gtm_bco_trigger_final = 0; + size_t total_bco_matching_final = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_final += bco_info.get_gtm_bco_trig_list_size(); + total_bco_heartbeat_final += bco_info.get_bco_heartbeat_list_size(); + total_gtm_bco_trigger_final += bco_info.get_gtm_bco_trigger_map_size(); + total_bco_matching_final += bco_info.get_bco_matching_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [FINAL] STL buffer usage - timeframe size: " << timeframe.size() + << ", exact_hits: " << exact_hit_count + << ", fuzzy_hits: " << fallback_hit_count + << ", recovered_hits: " << recovered_hit_count + << ", m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_timeHitMap: " << time_hit_map_buckets_final << " buckets, " + << total_time_hits_final << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_final + << ", bco_heartbeat: " << total_bco_heartbeat_final + << ", gtm_trigger_map: " << total_gtm_bco_trigger_final + << ", bco_matching: " << total_bco_matching_final + << std::endl; + } + + return timeframe; +} + +void TpcTimeFrameBuilderRun3::CleanupUsedPackets(const uint64_t& bclk) +{ + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id << ": cleaning up bcos < 0x" << std::hex + << bclk << std::dec + << " and m_UsedTimeFrameSet size: " << m_UsedTimeFrameSet.size() + << std::endl; + } + + while (!m_UsedTimeFrameSet.empty()) + { + const uint64_t bco_completed = m_UsedTimeFrameSet.front(); + m_UsedTimeFrameSet.pop(); + + auto it = m_timeFrameMap.find(bco_completed); + if (it != m_timeFrameMap.end()) + { + while (!it->second.empty()) + { + TpcRawHit* hit = it->second.back(); + delete hit; + it->second.pop_back(); + } + m_timeFrameMap.erase(it); + } + } + + const uint64_t bclk_rollover_corrected = m_bcoMatchingInformation_vec[0].get_gtm_rollover_correction(bclk); + cleanup_time_hit_map(bclk_rollover_corrected, 0); +} + +int TpcTimeFrameBuilderRun3::ProcessPacket(Packet* packet) +{ + static size_t call_count = 0; + ++call_count; + + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3::ProcessPacket: " << m_packet_id + << "\t- Entry " << std::endl; + } + + if (!packet) + { + std::cout << __PRETTY_FUNCTION__ << "\t- Error : Invalid packet, doing nothing" << std::endl; + assert(packet); + return 0; + } + + const int packet_hit_format = packet->getHitFormat(); + if (packet_hit_format != IDTPCFEEV5 && packet_hit_format != IDTPCFEEV6) + { + std::cout << __PRETTY_FUNCTION__ + << "\t- Error : TpcTimeFrameBuilderRun3 only supports packet formats " << IDTPCFEEV5 + << " or " << IDTPCFEEV6 + << " but received packet format " << packet_hit_format + << ". Aborting run." << std::endl; + packet->identify(); + return Fun4AllReturnCodes::ABORTRUN; + } + + if (m_hitFormat < 0) + { + m_hitFormat = packet_hit_format; + } + else if (packet_hit_format != m_hitFormat) + { + std::cout << __PRETTY_FUNCTION__ << "\t- Error : packet format changed for packet " << m_packet_id + << " from " << m_hitFormat << " to " << packet_hit_format + << ". Aborting run." << std::endl; + packet->identify(); + return Fun4AllReturnCodes::ABORTRUN; + } + assert((packet_hit_format == m_hitFormat)); + + + if (m_packet_id != packet->getIdentifier()) + { + std::cout << __PRETTY_FUNCTION__ << "\t- Error : mismatched packet with packet ID expectation of " << m_packet_id << ", but received"; + packet->identify(); + assert(m_packet_id == packet->getIdentifier()); + return 0; + } + + assert(m_packetTimer); + if ((m_verbosity == 1 && (call_count % 1000) == 0) || (m_verbosity > 1)) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : received packet "; + packet->identify(); + + m_packetTimer->print_stat(); + } + m_packetTimer->restart(); + + // Track initial buffer usage at start of ProcessPacket + if (m_verbosity >= 2) + { + size_t total_time_hits = 0; + size_t time_hit_map_buckets = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits += bucket.second.size(); + } + } + size_t total_fee_data = 0; + for (const auto& fee_data_deque : m_feeData) + { + total_fee_data += fee_data_deque.size(); + } + size_t total_gtm_bco_trig = 0; + size_t total_bco_heartbeat = 0; + size_t total_gtm_bco_trigger = 0; + size_t total_bco_matching = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig += bco_info.get_gtm_bco_trig_list_size(); + total_bco_heartbeat += bco_info.get_bco_heartbeat_list_size(); + total_gtm_bco_trigger += bco_info.get_gtm_bco_trigger_map_size(); + total_bco_matching += bco_info.get_bco_matching_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [INITIAL] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_feeData total: " << total_fee_data + << ", m_timeHitMap: " << time_hit_map_buckets << " buckets, " << total_time_hits << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig + << ", bco_heartbeat: " << total_bco_heartbeat + << ", gtm_trigger_map: " << total_gtm_bco_trigger + << ", bco_matching: " << total_bco_matching + << std::endl; + } + + // //remove after testing + // ; + // std::cout <<"packet->lValue(0, N_TAGGER) = "<lValue(0, "N_TAGGER")<lValue(0, NR_WF) = "<iValue(0, "NR_WF")<Fill("Packet", 1); + + int data_length = packet->getDataLength(); // 32bit length + assert(h_PacketLength); + h_PacketLength->Fill(data_length); + + int data_padding = packet->getPadding(); // 32bit padding + assert(h_PacketLength_Padding); + h_PacketLength_Padding->Fill(data_padding); + if (data_padding != 0) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Warning : suspecious padding " + << data_padding << "\t- in packet " << m_packet_id << ":" << std::endl; + packet->identify(); + // packet->dump(); + } + + size_t dma_words_buffer = static_cast(data_length) * 2 / DAM_DMA_WORD_LENGTH + 1; + std::vector buffer(dma_words_buffer); + + int l2 = 0; + packet->fillIntArray(reinterpret_cast(buffer.data()), data_length + DAM_DMA_WORD_LENGTH / 2, &l2, "DATA"); + + if (data_padding != 0) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : data_length = " << data_length + << "\t- data_padding = " << data_padding << "\t l2 = " << l2 << "\t- in packet " << m_packet_id << ":" << std::endl; + } + + assert(l2 <= data_length); + + if (l2 < data_padding) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : l2 from fillIntArray() is smaller than padding suggesting an invalid data: " << l2 + << "\t- in packet " << m_packet_id << ". Data length: " << data_length + << ", data padding: " << data_padding << ". Ignore this packet: " << std::endl; + packet->identify(); + return Fun4AllReturnCodes::DISCARDEVENT; + } + l2 -= data_padding; + + assert(l2 >= 0); + + size_t dma_words = static_cast(l2) * 2 / DAM_DMA_WORD_LENGTH; + size_t dma_residual = (static_cast(l2) * 2) % DAM_DMA_WORD_LENGTH; + assert(dma_words <= buffer.size()); + assert(h_PacketLength_Residual); + h_PacketLength_Residual->Fill(dma_residual); + if (dma_residual > 0) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Warning : mismatch of RCDAQ data to DMA transfer. Dropping mismatched data: " + << dma_residual << "\t- in packet " << m_packet_id << ". Dropping residual data : " << std::endl; + + assert(dma_words + 1 < buffer.size()); + const dma_word& last_dma_word_data = buffer[dma_words + 1]; + const uint16_t* last_dma_word = reinterpret_cast(&last_dma_word_data); + + for (size_t i = 0; i < dma_residual; ++i) + { + std::cout << "\t- 0x" << std::hex << last_dma_word[i] << std::dec; + } + std::cout << std::endl; + } + + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : packet" << m_packet_id << std::endl + << "\t- data_length = " << data_length << std::endl + << "\t- data_padding = " << data_padding << std::endl + << "\t- dma_words_buffer = " << dma_words_buffer << std::endl + << "\t- l2 = " << l2 << std::endl + << "\t- dma_words = " << dma_words << std::endl; + } + + // demultiplexer + for (size_t index = 0; index < dma_words; ++index) + { + const dma_word& dma_word_data = buffer[index]; + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : processing DMA word " + << index << "/" << dma_words << "\t- with header 0x" + << std::hex << dma_word_data.dma_header << std::dec << std::endl; + } + + if ((dma_word_data.dma_header & 0xFF00U) == FEE_MAGIC_KEY) + { + unsigned int fee_id = dma_word_data.dma_header & 0xffU; + + // for packet id 4XYZ ebdc is XY, endpoint is Z + if (m_maskedFEEs[((m_packet_id / 10) % 100)].contains(fee_id)) + { + continue; + } + + if (fee_id < MAX_FEECOUNT) + { + for (const uint16_t& i : dma_word_data.data) + { + m_feeData[fee_id].push_back(i); + } + m_hNorm->Fill("DMA_WORD_FEE", 1); + + // immediate fee buffer processing to reduce memory consuption + process_fee_data(fee_id); + } + else + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE ID " << fee_id << "\t- at position " << index << std::endl; + index += DAM_DMA_WORD_LENGTH - 1; + m_hNorm->Fill("DMA_WORD_FEE_INVALID", 1); + } + } + + else if ((dma_word_data.dma_header & 0xFF00U) == GTM_MAGIC_KEY) + { + decode_gtm_data(dma_word_data); + m_hNorm->Fill("DMA_WORD_GTM", 1); + } + else + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Unknown data type at position " << index << ": " + << std::hex << buffer[index].dma_header << std::dec << std::endl; + // not FEE data, e.g. GTM data or other stream, to be decoded + m_hNorm->Fill("DMA_WORD_INVALID", 1); + } + } + + // Track buffer usage after DMA word processing + if (m_verbosity >= 2) + { + size_t total_time_hits_post = 0; + size_t time_hit_map_buckets_post = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_post += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_post += bucket.second.size(); + } + } + size_t total_fee_data_post = 0; + for (const auto& fee_data_deque : m_feeData) + { + total_fee_data_post += fee_data_deque.size(); + } + size_t total_gtm_bco_trig_post = 0; + size_t total_bco_heartbeat_post = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_post += bco_info.get_gtm_bco_trig_list_size(); + total_bco_heartbeat_post += bco_info.get_bco_heartbeat_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [AFTER DMA PROCESSING] STL buffer usage - m_feeData total: " << total_fee_data_post + << ", m_timeHitMap: " << time_hit_map_buckets_post << " buckets, " << total_time_hits_post << " hits" + << ", m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_post + << ", bco_heartbeat: " << total_bco_heartbeat_post << "]" + << std::endl; + } + + // sanity check for the cached FEE-clock hit size + for (size_t fee = 0; fee < m_timeHitMap.size(); ++fee) + { + auto& fee_time_hits = m_timeHitMap[fee]; + for (auto timehit = fee_time_hits.begin(); timehit != fee_time_hits.end();) + { + if (timehit->second.size() > kMaxRawHitLimit) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Warning : impossible amount of hits for FEE " + << fee << " at FEE BCO " << timehit->first << "\t- : " << timehit->second.size() + << ", limit is " << kMaxRawHitLimit + << ". Dropping this FEE-clock cache!" + << std::endl; + m_hNorm->Fill("TimeFrameSizeLimitError", 1); + + for (TpcRawHit* hit : timehit->second) + { + delete hit; + } + timehit = fee_time_hits.erase(timehit); + } + else + { + ++timehit; + } + } + } + + m_packetTimer->stop(); + assert(h_ProcessPacket_Time); + h_ProcessPacket_Time->Fill(call_count, m_packetTimer->elapsed()); + + // Track final buffer usage at end of ProcessPacket + if (m_verbosity >= 1) + { + size_t total_time_hits_final = 0; + size_t time_hit_map_buckets_final = 0; + for (const auto& fee_time_hits : m_timeHitMap) + { + time_hit_map_buckets_final += fee_time_hits.size(); + for (const auto& bucket : fee_time_hits) + { + total_time_hits_final += bucket.second.size(); + } + } + size_t total_fee_data_final = 0; + for (const auto& fee_data_deque : m_feeData) + { + total_fee_data_final += fee_data_deque.size(); + } + size_t total_gtm_bco_trig_final = 0; + size_t total_bco_heartbeat_final = 0; + size_t total_gtm_bco_trigger_final = 0; + size_t total_bco_matching_final = 0; + for (const auto& bco_info : m_bcoMatchingInformation_vec) + { + total_gtm_bco_trig_final += bco_info.get_gtm_bco_trig_list_size(); + total_bco_heartbeat_final += bco_info.get_bco_heartbeat_list_size(); + total_gtm_bco_trigger_final += bco_info.get_gtm_bco_trigger_map_size(); + total_bco_matching_final += bco_info.get_bco_matching_list_size(); + } + std::cout << __PRETTY_FUNCTION__ << " - packet " << m_packet_id + << ": [FINAL] STL buffer usage - m_timeFrameMap: " << m_timeFrameMap.size() + << ", m_UsedTimeFrameSet: " << m_UsedTimeFrameSet.size() + << ", m_feeData total: " << total_fee_data_final + << ", m_timeHitMap: " << time_hit_map_buckets_final << " buckets, " << total_time_hits_final << " hits" + << ", BcoMatchingInfo[gtm_trig: " << total_gtm_bco_trig_final + << ", bco_heartbeat: " << total_bco_heartbeat_final + << ", gtm_trigger_map: " << total_gtm_bco_trigger_final + << ", bco_matching: " << total_bco_matching_final + << std::endl; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int TpcTimeFrameBuilderRun3::process_fee_data(unsigned int fee) +{ + assert(m_hFEEDataStream); + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : processing FEE " << fee << "\t- with " << m_feeData[fee].size() << "\t- words" << std::endl; + } + + assert(fee < m_feeData.size()); + std::deque& data_buffer = m_feeData[fee]; + + while (HEADER_LENGTH <= data_buffer.size()) + { + // packet loop + + bool is_digital_current = false; + // test if digital current packet + if (data_buffer[3] == FEE_PACKET_MAGIC_KEY_3_DC) + { + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ + << "\t- : processing FEE " << fee + << "\t- with digital packet" << std::endl; + } + + m_hFEEDataStream->Fill(fee, "WordDigitalCurrentKeyWord", 1); + is_digital_current = true; + } // if (data_buffer[3] == FEE_PACKET_MAGIC_KEY_3) + else + { + if (data_buffer[1] != FEE_PACKET_MAGIC_KEY_1) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE magic key at position 1 0x" << std::hex << data_buffer[1] << std::dec << std::endl; + } + m_hFEEDataStream->Fill(fee, "WordSkipped", 1); + data_buffer.pop_front(); + continue; + } + assert(data_buffer[1] == FEE_PACKET_MAGIC_KEY_1); + + if (data_buffer[2] != FEE_PACKET_MAGIC_KEY_2) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE magic key at position 2 0x" << std::hex << data_buffer[2] << std::dec << std::endl; + } + m_hFEEDataStream->Fill(fee, "WordSkipped", 1); + data_buffer.pop_front(); + continue; + } + assert(data_buffer[2] == FEE_PACKET_MAGIC_KEY_2); + } + + // valid packet + const uint16_t pkt_length = data_buffer[0]; // this is indeed the number of 10-bit words + 5 in this packet + if (pkt_length > MAX_PACKET_LENGTH) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE pkt_length " << pkt_length << std::endl; + } + m_hFEEDataStream->Fill(fee, "InvalidLength", 1); + data_buffer.pop_front(); + continue; + } + + if (pkt_length + 1U > data_buffer.size()) + { + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : packet over buffer boundary for now, skip decoding and wait for more data: " + " pkt_length = " + << pkt_length + << "\t- data_buffer.size() = " << data_buffer.size() + << std::endl; + } + break; + } + + if (is_digital_current) + { + process_fee_data_digital_current(fee, data_buffer); + } + else + { + process_fee_data_waveform(fee, data_buffer); + } + data_buffer.erase(data_buffer.begin(), data_buffer.begin() + pkt_length + 1); + m_hFEEDataStream->Fill(fee, "WordValid", pkt_length + 1); + + } // while (HEADER_LENGTH < data_buffer.size()) + + return Fun4AllReturnCodes::EVENT_OK; +} + +void TpcTimeFrameBuilderRun3::process_fee_data_waveform(const unsigned int& fee, std::deque& data_buffer) +{ + const uint16_t& pkt_length = data_buffer[0]; + + fee_payload payload; + // continue the decoding + payload.fee_id = fee; + payload.adc_length = data_buffer[0] - HEADER_LENGTH; // this is indeed the number of 10-bit words in this packet + payload.data_parity = data_buffer[4] >> 9U; + payload.sampa_address = static_cast(data_buffer[4] >> 5U) & 0xfU; + payload.sampa_channel = data_buffer[4] & 0x1fU; + payload.channel = data_buffer[4] & 0x1ffU; + payload.type = static_cast(data_buffer[3] >> 7U) & 0x7U; + payload.user_word = data_buffer[3] & 0x7fU; + payload.bx_timestamp = static_cast(static_cast(data_buffer[6] & 0x3ffU) << 10U) | (data_buffer[5] & 0x3ffU); + payload.data_crc = data_buffer[pkt_length]; + + if (!m_fastBCOSkip) + { + auto crc_parity = crc16_parity(fee, pkt_length); + payload.calc_crc = crc_parity.first; + payload.calc_parity = crc_parity.second; + + if (payload.data_crc != payload.calc_crc) + { + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : CRC error in FEE " + << fee << "\t- at position " << pkt_length - 1 + << ": data_crc = " << payload.data_crc + << "\t- calc_crc = " << payload.calc_crc << std::endl; + } + m_hFEEDataStream->Fill(fee, "HitCRCError", 1); + // continue; + } + + if (payload.data_parity != payload.calc_parity) + { + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : parity error in FEE " + << fee << "\t- at position " << pkt_length - 1 + << ": data_parity = " << payload.data_parity + << "\t- calc_parity = " << payload.calc_parity << std::endl; + } + m_hFEEDataStream->Fill(fee, "ParityError", 1); + // continue; + } + } // if (not m_fastBCOSkip) + + assert(fee < m_bcoMatchingInformation_vec.size()); + BcoMatchingInformation& m_bcoMatchingInformation = m_bcoMatchingInformation_vec[fee]; + // gtm_bco matching + if (payload.type == TpcTimeFrameBuilderRun3::BcoMatchingInformation::HEARTBEAT_T) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ + << "\t- : received heartbeat packet from FEE " << fee << std::endl; + } + + // if bco matching information is still not verified, drop the packet + if (!m_bcoMatchingInformation.is_verified()) + { + m_hFEEDataStream->Fill(fee, "PacketHeartBeatClockSyncUnavailable", 1); + + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3::process_fee_data - bco_matching not verified for heart beat, dropping packet" << std::endl; + m_bcoMatchingInformation.print_gtm_bco_information(); + } + } + else // if (not m_bcoMatchingInformation.is_verified()) + { + const std::optional result = m_bcoMatchingInformation.find_reference_heartbeat(payload); + m_hFEEDataStream->Fill(fee, "PacketHeartBeat", 1); + + if (result) + { + // assign gtm bco + payload.gtm_bco = result.value(); + payload.has_clock_sync = true; + m_hFEEDataStream->Fill(fee, "PacketHeartBeatClockSyncOK", 1); + + assert(m_hFEESAMPAHeartBeatSync); + m_hFEESAMPAHeartBeatSync->Fill(fee * MAX_SAMPA + payload.sampa_address, 1); + } + else + { + m_hFEEDataStream->Fill(fee, "PacketHeartBeatClockSyncError", 1); + + // skip the waverform + } + if (m_verbosity > 2) + { + m_bcoMatchingInformation.print_gtm_bco_information(); + } + } + } + else if (!m_fastBCOSkip) // if (payload.type == m_bcoMatchingInformation.HEARTBEAT_T) + { + m_hFEEChannelPacketCount->Fill(fee * MAX_CHANNELS + payload.channel, 1); + + // if bco matching information is still not verified, drop the packet + if (!m_bcoMatchingInformation.is_verified()) + { + m_hFEEDataStream->Fill(fee, "PacketClockSyncUnavailable", 1); + + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3::process_fee_data - bco_matching not verified, dropping packet" << std::endl; + m_bcoMatchingInformation.print_gtm_bco_information(); + } + } + else + { + payload.has_clock_sync = true; + m_hFEEDataStream->Fill(fee, "PacketClockSyncOK", 1); + } + } + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : received data packet " + << "\t- from FEE " << fee << std::endl + << "\t- pkt_length = " << pkt_length << std::endl + << "\t- type = " << payload.type << std::endl + << "\t- adc_length = " << payload.adc_length << std::endl + << "\t- sampa_address = " << payload.sampa_address << std::endl + << "\t- sampa_channel = " << payload.sampa_channel << std::endl + << "\t- channel = " << payload.channel << std::endl + << "\t- bx_timestamp = 0x" << std::hex << payload.bx_timestamp << std::dec << std::endl + << "\t- bco = 0x" << std::hex << payload.gtm_bco << std::dec << std::endl + << "\t- data_crc = 0x" << std::hex << payload.data_crc << std::dec << std::endl + << "\t- calc_crc = 0x" << std::hex << payload.calc_crc << std::dec << std::endl + << "\t- data_parity = 0x" << std::hex << payload.data_parity << std::dec << std::endl + << "\t- calc_parity = 0x" << std::hex << payload.calc_parity << std::dec << std::endl; + } + + if ((!m_fastBCOSkip) && payload.has_clock_sync) + { + m_hFEEDataStream->Fill(fee, "RawHit", 1); + + // Format is (N sample) (start time), (1st sample)... (Nth sample) + size_t pos = HEADER_LENGTH; + std::deque::const_iterator data_buffer_iterator = data_buffer.cbegin(); + std::advance(data_buffer_iterator, pos); + while (pos + 2 < pkt_length) + { + const uint16_t& nsamp = *data_buffer_iterator; + ++pos; + ++data_buffer_iterator; + const uint16_t& start_t = *data_buffer_iterator; + ++pos; + ++data_buffer_iterator; + if (m_verbosity > 3) + { + std::cout << __PRETTY_FUNCTION__ << ": nsamp: " << nsamp + << "+ pos: " << pos + << " pkt_length: " << pkt_length << " start_t:" << start_t << std::endl; + } + + if (pos + nsamp > pkt_length) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << ": WARNING : nsamp: " << nsamp + << "+ pos: " << pos + << " > pkt_length: " << pkt_length << ", format error over length: " << std::endl; + + for (int print_pos = 0; print_pos <= pkt_length; ++print_pos) + { + std::cout << "\t[" << print_pos << "]=0x" << std::hex << data_buffer[print_pos] << std::dec << "(" << data_buffer[print_pos] << ")"; + } + std::cout << std::endl; + } + m_hFEEDataStream->Fill(fee, "HitFormatErrorOverLength", 1); + + break; + } + + const unsigned int fee_sampa_address = fee * MAX_SAMPA + payload.sampa_address; + std::vector adc(nsamp); + for (int j = 0; j < nsamp; j++) + { + const uint16_t& adc_value = *data_buffer_iterator; + + adc[j] = adc_value; + m_hFEESAMPAADC->Fill(start_t + j, fee_sampa_address, adc_value); + + ++pos; + ++data_buffer_iterator; // data_buffer[pos++]; + } + payload.waveforms.emplace_back(start_t, std::move(adc)); + + // // an exception to deal with the last sample that is missing in the current hit format + // if (pos + 1 == pkt_length) break; + } + + if (pos != pkt_length) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << ": WARNING : residual data at the end of decoding:" + << " pos: " << pos + << " Fill(fee, "HitFormatErrorMismatchedLength", 1); + } + + // valid packet in the buffer, create a new hit + if (payload.type != TpcTimeFrameBuilderRun3::BcoMatchingInformation::HEARTBEAT_T) + { + if (fee >= m_timeHitMap.size()) + { + std::cout << __PRETTY_FUNCTION__ << ": ERROR : invalid FEE " << fee + << " for packet " << m_packet_id << ". Dropping waveform hit." << std::endl; + return; + } + + TpcRawHitRun3_typ* hit = new TpcRawHitRun3_typ(); + + hit->set_bco(payload.bx_timestamp); + hit->set_packetid(m_packet_id); + hit->set_fee(fee); + hit->set_channel(payload.channel); + hit->set_type(payload.type); + // hit->set_checksum(payload.data_crc); + hit->set_checksumerror(payload.data_crc != payload.calc_crc); + // hit->set_parity(payload.data_parity); + hit->set_parityerror(payload.data_parity != payload.calc_parity); + + for (std::pair>& waveform : payload.waveforms) + { + hit->move_adc_waveform(waveform.first, std::move(waveform.second)); + } + + m_timeHitMap[fee][payload.bx_timestamp & kFEEClockMask].push_back(hit); + } + } // if (not m_fastBCOSkip) + + return; +} + +void TpcTimeFrameBuilderRun3::process_fee_data_digital_current(const unsigned int& fee, std::deque& data_buffer) +{ + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : processing digital_current data " << std::endl; + } + m_hFEEDataStream->Fill(fee, "DigitalCurrent", 1); + const uint16_t& pkt_length = data_buffer[0]; + + if (pkt_length != HEADER_LENGTH + digital_current_payload::MAX_CHANNELS * 2 * 2) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Error : Invalid FEE pkt_length " << pkt_length + << ", expected at least " << HEADER_LENGTH + digital_current_payload::MAX_CHANNELS * 2 * 2 + << std::endl; + } + m_hFEEDataStream->Fill(fee, "DigitalCurrentFormatErrorMismatchedLength", 1); + return; + } + + digital_current_payload payload; + + payload.fee = fee; + payload.pkt_length = pkt_length; + payload.sampa_address = (data_buffer[4] >> 5U) & 0xfU; // NOLINT(hicpp-signed-bitwise) + // payload.sampa_max_channel = data_buffer[4] & 0x1fU; + payload.channel = data_buffer[4] & 0x1ffU; + // payload.type = data_buffer[3]; + payload.bx_timestamp = ((data_buffer[6] & 0x3ffU) << 10U) | (data_buffer[5] & 0x3ff); // NOLINT(hicpp-signed-bitwise) + + uint16_t pos = HEADER_LENGTH; + for (int ich = 0; ich < digital_current_payload::MAX_CHANNELS; ich++) + { + payload.current[ich] = ((unsigned int) data_buffer[pos]) << 16U | ((unsigned int) data_buffer[pos + 1U]); + pos++; + pos++; + payload.nsamples[ich] = ((unsigned int) data_buffer[pos]) << 16U | ((unsigned int) data_buffer[pos + 1U]); + pos++; + pos++; + } + + if (pos != pkt_length) + { + if (m_verbosity > 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Warning : residual data at the end of decoding:" + << " pos: " << pos + << " 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : CRC error in FEE " + << fee << "\t- at position " << pkt_length - 1 + << ": data_crc = " << payload.data_crc + << "\t- calc_crc = " << payload.calc_crc << std::endl; + } + m_hFEEDataStream->Fill(fee, "DigitalCurrentCRCError", 1); + // continue; + } + + assert(fee < m_bcoMatchingInformation_vec.size()); + BcoMatchingInformation& m_bcoMatchingInformation = m_bcoMatchingInformation_vec[fee]; + std::tie(payload.gtm_bco, payload.bx_timestamp_predicted) = m_bcoMatchingInformation.find_dc_read_bco(); + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : received digital current packet " + << "\t- from FEE " << fee << std::endl + << "\t- pkt_length = " << pkt_length << std::endl + << "\t- sampa_address = " << payload.sampa_address << std::endl + << "\t- channel = " << payload.channel << std::endl + << "\t- bx_timestamp = 0x" << std::hex << payload.bx_timestamp << std::dec << std::endl + << "\t- gtm_bco = 0x" << std::hex << payload.gtm_bco << std::dec << std::endl + << "\t- bx_timestamp_predicted = 0x" << std::hex << payload.bx_timestamp_predicted << std::dec << std::endl; + + std::cout << "\t- current:"; + for (int ich = 0; ich < digital_current_payload::MAX_CHANNELS; ich++) + { + std::cout << "\t[" << ich << "] = " << payload.current[ich]; + } + std::cout << std::endl; + std::cout << "\t- nsamples:"; + for (int ich = 0; ich < digital_current_payload::MAX_CHANNELS; ich++) + { + std::cout << "\t[" << ich << "] = " << payload.nsamples[ich]; + } + std::cout << std::endl; + std::cout << "\t- data_crc = 0x" << std::hex << payload.data_crc << std::dec << std::endl + << "\t- calc_crc = 0x" << std::hex << payload.calc_crc << std::dec << std::endl; + } + + if (m_digitalCurrentDebugTTree) + { + m_digitalCurrentDebugTTree->fill(payload); + } + + return; +} + +void TpcTimeFrameBuilderRun3::SaveBXCounterSyncCDBTTree(const std::string& name) +{ + m_bxCounterSyncCDBTTreeName = name; + + if (m_verbosity >= 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Saving BX counter sync CDB TTree to " << m_bxCounterSyncCDBTTreeName << std::endl; + } +} + +void TpcTimeFrameBuilderRun3::SaveDigitalCurrentDebugTTree(const std::string& name) +{ + if (m_verbosity >= 1) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : Saving digital current debug TTree to " << name << std::endl; + } + + m_digitalCurrentDebugTTree = new TpcTimeFrameBuilderRun3::DigitalCurrentDebugTTree(name); +} + +TpcTimeFrameBuilderRun3::DigitalCurrentDebugTTree::DigitalCurrentDebugTTree(const std::string& name) + : m_name(name) +{ + // open TFile + PHTFileServer::open(m_name, "RECREATE"); + + // cppcheck-suppress noCopyConstructor + // cppcheck-suppress noOperatorEq + m_tDigitalCurrent = new TTree("T_DigitalCurrent", "DigitalCurrent Debug TTree"); + assert(m_tDigitalCurrent); + + m_tDigitalCurrent->Branch("dc", &m_payload, + "gtm_bco/l:bx_timestamp_predicted/i:fee/s:pkt_length/s:channel/s:sampa_address/s:bx_timestamp/i:current[8]/i:nsamples[8]/i:data_crc/s:calc_crc/s"); +} + +TpcTimeFrameBuilderRun3::DigitalCurrentDebugTTree::~DigitalCurrentDebugTTree() +{ + // open TFile + PHTFileServer::write(m_name); +} + +void TpcTimeFrameBuilderRun3::DigitalCurrentDebugTTree::fill(const TpcTimeFrameBuilderRun3::digital_current_payload& payload) +{ + assert(m_tDigitalCurrent); + + m_payload = payload; + m_tDigitalCurrent->Fill(); +} + +int TpcTimeFrameBuilderRun3::decode_gtm_data(const TpcTimeFrameBuilderRun3::dma_word& gtm_word) +{ + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : processing GTM data " << std::endl; + } + + const uint8_t* gtm = reinterpret_cast(>m_word); + + gtm_payload payload; + + payload.pkt_type = gtm[0] | static_cast((unsigned short) gtm[1] << 8U); + // if (payload.pkt_type != GTM_LVL1_ACCEPT_MAGIC_KEY && payload.pkt_type != GTM_ENDAT_MAGIC_KEY) + if (payload.pkt_type != GTM_LVL1_ACCEPT_MAGIC_KEY && payload.pkt_type != GTM_ENDAT_MAGIC_KEY && payload.pkt_type != GTM_MODEBIT_MAGIC_KEY) + { + return -1; + } + + payload.is_lvl1 = payload.pkt_type == GTM_LVL1_ACCEPT_MAGIC_KEY; + payload.is_endat = payload.pkt_type == GTM_ENDAT_MAGIC_KEY; + payload.is_modebit = payload.pkt_type == GTM_MODEBIT_MAGIC_KEY; + + payload.bco = ((unsigned long long) gtm[2] << 0U) | ((unsigned long long) gtm[3] << 8U) | ((unsigned long long) gtm[4] << 16U) | ((unsigned long long) gtm[5] << 24U) | ((unsigned long long) gtm[6] << 32U) | (((unsigned long long) gtm[7]) << 40U); + payload.lvl1_count = ((unsigned int) gtm[8] << 0U) | ((unsigned int) gtm[9] << 8U) | ((unsigned int) gtm[10] << 16U) | ((unsigned int) gtm[11] << 24U); + payload.endat_count = ((unsigned int) gtm[12] << 0U) | ((unsigned int) gtm[13] << 8U) | ((unsigned int) gtm[14] << 16U) | ((unsigned int) gtm[15] << 24U); + payload.last_bco = ((unsigned long long) gtm[16] << 0U) | ((unsigned long long) gtm[17] << 8U) | ((unsigned long long) gtm[18] << 16U) | ((unsigned long long) gtm[19] << 24U) | ((unsigned long long) gtm[20] << 32U) | (((unsigned long long) gtm[21]) << 40U); + payload.modebits = gtm[22]; + payload.userbits = gtm[23]; + + if (m_verbosity >= 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- GTM data : " + << "\t- pkt_type = " << payload.pkt_type << std::endl + << "\t- is_lvl1 = " << payload.is_lvl1 << std::endl + << "\t- is_endat = " << payload.is_endat << std::endl + << "\t- is_modebit = " << payload.is_modebit << std::endl + << "\t- bco = 0x" << std::hex << payload.bco << std::dec << std::endl + << "\t- lvl1_count = " << payload.lvl1_count << std::endl + << "\t- endat_count = " << payload.endat_count << std::endl + << "\t- last_bco = 0x" << std::hex << payload.last_bco << std::dec << std::endl + << "\t- modebits = 0x" << std::hex << (int) payload.modebits << std::dec << std::endl + << "\t- userbits = 0x" << std::hex << (int) payload.userbits << std::dec << std::endl; + } + + if (payload.is_modebit) + { + if (payload.modebits == BcoMatchingInformation::ELINK_HEARTBEAT_T) + { + if (m_verbosity > 2) + { + std::cout << "\t- (Heartbeat modebit)" << std::endl; + } + assert(m_hNorm); + m_hNorm->Fill("DMA_WORD_GTM_HEARTBEAT", 1); + } + + if (payload.modebits == BcoMatchingInformation::DC_STOP_SEND_T) + { + if (m_verbosity > 2) + { + std::cout << "\t- (DC stop send modebit)" << std::endl; + } + assert(m_hNorm); + m_hNorm->Fill("DMA_WORD_GTM_DC_STOP_SEND", 1); + } + } + + if (!(m_fastBCOSkip && (payload.is_lvl1 || payload.is_endat))) + { + int fee = -1; + for (BcoMatchingInformation& bcoMatchingInformation : m_bcoMatchingInformation_vec) + { + ++fee; + + if (m_verbosity > 2) + { + std::cout << __PRETTY_FUNCTION__ << "\t- : processing GTM data for FEE " << fee << std::endl; + } + + bcoMatchingInformation.save_gtm_bco_information(payload); + + if (m_verbosity > 2) + { + bcoMatchingInformation.print_gtm_bco_information(); + } + } + } // if (not m_fastBCOSkip) + + return 0; +} + +uint16_t TpcTimeFrameBuilderRun3::reverseBits(const uint16_t x) const +{ + uint16_t n = x; + n = (static_cast(n >> 1U) & 0x55555555U) | (static_cast(n << 1U) & 0xaaaaaaaaU); + n = (static_cast(n >> 2U) & 0x33333333U) | (static_cast(n << 2U) & 0xccccccccU); + n = (static_cast(n >> 4U) & 0x0f0f0f0fU) | (static_cast(n << 4U) & 0xf0f0f0f0U); + n = (static_cast(n >> 8U) & 0x00ff00ffU) | (static_cast(n << 8U) & 0xff00ff00U); + // n = (n >> 16U) & 0x0000ffffU | (n << 16U) & 0xffff0000U; + return n; +} + +std::pair TpcTimeFrameBuilderRun3::crc16_parity(const uint32_t fee, const uint16_t l) const +{ + const std::deque& data_buffer = m_feeData[fee]; + assert(l < data_buffer.size()); + + std::deque::const_iterator it = data_buffer.begin(); + + uint16_t crc = 0xffffU; + uint16_t data_parity = 0U; + + for (int i = 0; i < l; ++i, ++it) + { + const uint16_t& x = *it; + + crc ^= reverseBits(x); + for (uint16_t k = 0; k < 16U; k++) + { + crc = crc & 1U ? static_cast(crc >> 1U) ^ 0xa001U : crc >> 1U; + } + + // parity on data payload only + if (i >= HEADER_LENGTH) + { + // fast parity + uint16_t word = x & uint16_t((1U << 10U) - 1U); + word = word ^ static_cast(word >> 1U); + word = word ^ static_cast(word >> 2U); + word = word ^ static_cast(word >> 4U); + word = word ^ static_cast(word >> 8U); + data_parity ^= word & 1U; + } + } + crc = reverseBits(crc); + return std::make_pair(crc, data_parity); +} + +namespace +{ + // streamer for lists + template + std::ostream& operator<<(std::ostream& o, const std::list& list) + { + if (list.empty()) + { + o << "{}"; + } + else + { + const bool is_hex = (o.flags() & std::ios_base::hex); + o << "{ "; + bool first = true; + for (const auto& value : list) + { + if (!first) + { + o << ", "; + } + if (is_hex) + { + o << "0x"; + } + o << value; + first = false; + } + o << "\t- }"; + } + return o; + } + + template + std::ostream& operator<<(std::ostream& o, const std::vector& list) + { + if (list.empty()) + { + o << "{}"; + } + else + { + const bool is_hex = (o.flags() & std::ios_base::hex); + o << "{ "; + bool first = true; + for (const auto& value : list) + { + if (!first) + { + o << ", "; + } + if (is_hex) + { + o << "0x"; + } + o << value; + first = false; + } + o << "\t- }"; + } + return o; + } + +} // namespace + +TpcTimeFrameBuilderRun3::BcoMatchingInformation::BcoMatchingInformation(const std::string& name) + : m_name(name) +{ + Fun4AllHistoManager* hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + // cppcheck-suppress noCopyConstructor + // cppcheck-suppress noOperatorEq + m_hNorm = new TH1D(TString(m_name.c_str()) + "_Normalization", // + TString(m_name.c_str()) + " Normalization;Items;Count", + 20, .5, 20.5); + int i = 1; + m_hNorm->GetXaxis()->SetBinLabel(i++, "SyncGTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "DC_STOP_SEND_GTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatGTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEE"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEEMatchedReference"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEEMatchedNew"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "HeartBeatFEEUnMatched"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "TriggerGTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "EnDATGTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "UnmatchedEnDATGTM"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCO"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCOMatchedExisting"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCOMatchedNew"); + m_hNorm->GetXaxis()->SetBinLabel(i++, "FindGTMBCOMatchedFailed"); + + assert(i <= 20); + m_hNorm->GetXaxis()->LabelsOption("v"); + hm->registerHisto(m_hNorm); + + m_hFEEClockAdjustment_MatchedReference = new TH1I(TString(m_name.c_str()) + "_FEEClockAdjustment_MatchedReference", // + TString(m_name.c_str()) + + " FEEClockAdjustment for Matched Reference;Clock Adjustment [FEE Clock Cycle];Count", + 512, -256 - .5, +256 - .5); + hm->registerHisto(m_hFEEClockAdjustment_MatchedReference); + m_hFEEClockAdjustment_MatchedNew = new TH1I(TString(m_name.c_str()) + "_FEEClockAdjustment_MatchedNew", // + TString(m_name.c_str()) + + " FEEClockAdjustment for Matched New;Clock Adjustment [FEE Clock Cycle];Count", + 512, -256 - .5, +256 - .5); + hm->registerHisto(m_hFEEClockAdjustment_MatchedNew); + + m_hFEEClockAdjustment_Unmatched = new TH1I(TString(m_name.c_str()) + "_FEEClockAdjustment_Unmatched", // + TString(m_name.c_str()) + + " FEEClock Diff for unmatched;Clock Adjustment [FEE Clock Cycle];Count", + 512, + -(1UL << m_FEE_CLOCK_BITS) - .5, + +(1UL << m_FEE_CLOCK_BITS) - .5); + hm->registerHisto(m_hFEEClockAdjustment_Unmatched); + + m_hGTMNewEventSpacing = new TH1I(TString(m_name.c_str()) + + "_GTM_NewEventSpacing", // + TString(m_name.c_str()) + + " Spacing between two events;Clock Diff [RHIC Clock Cycle];Count", + 1024, -.5, +1024 - .5); + hm->registerHisto(m_hGTMNewEventSpacing); + + // m_hFindGTMBCO_MatchedExisting_BCODiff = new TH1I(TString(m_name.c_str()) + "_FindGTMBCO_MatchedExisting_BCODiff", // + // TString(m_name.c_str()) + + // " find_gtm_bco matched to existing event clock diff;Clock Difference [FEE Clock Cycle];Count", + // 512, -256 - .5, +256 - .5); + // hm->registerHisto(m_hFindGTMBCO_MatchedExisting_BCODiff); + // m_hFindGTMBCO_MatchedNew_BCODiff = new TH1I(TString(m_name.c_str()) + "_FindGTMBCO_MatchedNew_BCODiff", // + // TString(m_name.c_str()) + + // " find_gtm_bco matched to new event clock diff;Clock Difference [FEE Clock Cycle];Count", + // 512, -256 - .5, +256 - .5); + // hm->registerHisto(m_hFindGTMBCO_MatchedNew_BCODiff); +} + +//! whether reference bco has moved pass the given gtm_bco +bool TpcTimeFrameBuilderRun3::BcoMatchingInformation::isMoreDataRequired(const uint64_t& gtm_bco) const +{ + const uint64_t bco_correction = get_gtm_rollover_correction(gtm_bco); + + if (m_verbosity >= 2) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired entry" + << " at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << " bco_correction = 0x" << std::hex << bco_correction << std::dec + << std::endl; + } + + if (m_bco_reference) + { + if (m_bco_reference.value().first > bco_correction + m_max_fee_sync_time) + { + if (m_verbosity >= 2) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" + << " at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << ". m_bco_reference.value().first = 0x" << std::hex << m_bco_reference.value().first << std::dec + << " bco_correction = 0x" << std::hex << bco_correction << std::dec + << ". satisified m_max_fee_sync_time = " << m_max_fee_sync_time + << std::endl; + } + + return false; + } + } + + if (!m_bco_heartbeat_list.empty()) + { + if (m_bco_heartbeat_list.back().first > bco_correction + m_max_fee_sync_time) + { + if (m_verbosity >= 2) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << ". m_bco_heartbeat_list.back().first = 0x" << std::hex << m_bco_heartbeat_list.back().first << std::dec + << " bco_correction = 0x" << std::hex << bco_correction << std::dec + << ". satisified m_max_fee_sync_time = " << m_max_fee_sync_time + << std::endl; + } + + return false; + } + + if (m_verbosity > 4) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << ". m_bco_heartbeat_list.back().first = 0x" << std::hex << m_bco_heartbeat_list.back().first << std::dec + << " bco_correction = 0x" << std::hex << bco_correction << std::dec + << ". not yet satisified m_max_fee_sync_time = " << m_max_fee_sync_time + << std::endl; + } + } + + if (m_verbosity > 3) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::isMoreDataRequired" + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << " bco_correction = 0x" << std::hex << bco_correction << std::dec << ": more data required" + << " as their is NO m_bco_reference nor m_bco_heartbeat_list" + << std::endl; + + std::cout << " m_gtm_bco_trigger_map:" << std::endl; + for (const auto& trig : m_gtm_bco_trigger_map) + { + std::cout << " - 0x" << std::hex << trig.first << std::dec << "(Diff = " << trig.first - bco_correction << ") " << std::endl; + } + + std::cout << " m_bco_matching_list:" << std::endl; + for (const auto& trig : m_bco_matching_list) + { + std::cout << " - 0x" << std::hex << trig.second << std::dec << "(Diff = " << trig.second - bco_correction << ") " << std::endl; + } + } + return true; +} + +//___________________________________________________ +std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::get_predicted_fee_bco(uint64_t gtm_bco) const +{ + // check proper initialization + if (!is_verified() || !m_bco_reference) + { + return std::nullopt; + } + + // check whether it is within the same FEE clock rollover window based on the reference candidate list + { + uint64_t latest_reference_bco = (*m_bco_reference).first; + if (! m_bco_heartbeat_list.empty()) + { + latest_reference_bco = m_bco_heartbeat_list.back().first; // get the latest heartbeat bco + } + + if (get_bco_diff(gtm_bco , latest_reference_bco)*m_clock_ratio_numerator + > ((1U << (m_FEE_CLOCK_BITS -1))) * m_clock_ratio_denominator) + { + if (m_verbosity >= 3) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::get_predicted_fee_bco -" + << " GTM bco 0x" << std::hex << gtm_bco << std::dec + << " is too far from the latest heartbeat bco 0x" << std::hex << latest_reference_bco << std::dec + << " get_bco_diff(gtm_bco , latest_reference_bco) =" << get_bco_diff(gtm_bco , latest_reference_bco) + << " > " << ((1U << (m_FEE_CLOCK_BITS -1))) * m_clock_ratio_denominator / m_clock_ratio_numerator + << ", cannot predict fee bco" << std::endl; + } + return std::nullopt; + } + } + + // get gtm bco difference with proper rollover accounting + const auto& bco_reference = *m_bco_reference; + const int64_t gtm_bco_difference = int64_t(gtm_bco) - int64_t(bco_reference.first); + + static_assert(m_clock_ratio_numerator > 0); + static_assert(m_clock_ratio_denominator > 0); + + // convert to fee bco with the exact Run3 30/8 ratio, and truncate to 20 bits + const int64_t fee_bco_predicted = int64_t(bco_reference.second) + + (gtm_bco_difference * m_clock_ratio_numerator) / m_clock_ratio_denominator; + return uint32_t(static_cast(fee_bco_predicted) & 0xFFFFFU); +} + +//___________________________________________________ +void TpcTimeFrameBuilderRun3::BcoMatchingInformation::print_gtm_bco_information() const +{ + if (!m_gtm_bco_trig_list.empty()) + { + std::cout + << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::print_gtm_bco_information -" + << "\t- m_gtm_bco_trig_list: " << std::hex << m_gtm_bco_trig_list << std::dec + << std::endl; + + // also print predicted fee bco + if (is_verified()) + { + std::list fee_bco_predicted_list; + std::transform( + m_gtm_bco_trig_list.begin(), + m_gtm_bco_trig_list.end(), + std::back_inserter(fee_bco_predicted_list), + [this](const uint64_t& gtm_bco) + { return get_predicted_fee_bco(gtm_bco).value(); }); + + std::cout + << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::print_gtm_bco_information -" + << "\t- m_gtm_bco_trig_list fee predicted: " << std::hex << fee_bco_predicted_list << std::dec + << std::endl; + } + } + + std::cout << "\t m_gtm_bco_dc_read = " << std::hex + << m_gtm_bco_dc_read.first << " -> 0x" << m_gtm_bco_dc_read.second + << std::dec << std::endl; +} + +uint64_t TpcTimeFrameBuilderRun3::BcoMatchingInformation:: + get_gtm_rollover_correction(const uint64_t& gtm_bco) const +{ + // start with 40bit clock, enforced + uint64_t gtm_bco_corrected = gtm_bco & ((uint64_t(1) << m_GTM_CLOCK_BITS) - 1); + + if (!m_bco_reference) + { + return gtm_bco_corrected; + } + + // get the last GTM clock roll over + const uint64_t& last_bco = m_bco_reference.value().first; + const uint64_t last_bco_rollover = last_bco & + (std::numeric_limits::max() << m_GTM_CLOCK_BITS); + + // use the roll over of the last GTM clock reading + gtm_bco_corrected += last_bco_rollover; + + // check if the rollover has advanced + if (gtm_bco_corrected + (uint64_t(1) << (m_GTM_CLOCK_BITS - 1)) < last_bco) + { + gtm_bco_corrected += uint64_t(1) << m_GTM_CLOCK_BITS; + } + + return gtm_bco_corrected; +} + +//___________________________________________________ +void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_bx_counter_sync_observation( + uint64_t bx_counter_sync_gtm_bco, + uint64_t bco_reference_gtm_bco, + const TpcTimeFrameBuilderRun3::BcoMatchingInformation::m_gtm_fee_bco_matching_pair_t& bco_reference) +{ + if (m_bx_counter_sync_observation_count >= kMaxBXCounterSyncObservations) + { + return; + } + + BXCounterSyncObservation& observation = m_bx_counter_sync_observations[m_bx_counter_sync_observation_count]; + observation.bx_counter_sync_gtm_bco = bx_counter_sync_gtm_bco; + observation.bco_reference_gtm_bco = bco_reference_gtm_bco; + observation.m_bco_reference = bco_reference; + ++m_bx_counter_sync_observation_count; +} + +void TpcTimeFrameBuilderRun3::BcoMatchingInformation::save_gtm_bco_information(const TpcTimeFrameBuilderRun3::gtm_payload& gtm_tagger) +{ + // append gtm_bco from taggers in this event to packet-specific list of available lv1_bco + + // save level1 trigger bco + const bool& is_lvl1 = gtm_tagger.is_lvl1; + const bool& is_endat = gtm_tagger.is_endat; + const bool& is_modebit = gtm_tagger.is_modebit; + const uint64_t gtm_bco = get_gtm_rollover_correction(gtm_tagger.bco); + + if (is_lvl1) + { + assert(m_hNorm); + m_hNorm->Fill("TriggerGTM", 1); + + assert(m_hGTMNewEventSpacing); + if (!m_gtm_bco_trig_list.empty()) + { + m_hGTMNewEventSpacing->Fill(gtm_bco - m_gtm_bco_trig_list.back()); + } + m_gtm_bco_trig_list.push_back(gtm_bco); + } + + // also save ENDDAT bco + else if (is_endat) + { + assert(m_hNorm); + m_hNorm->Fill("EnDATGTM", 1); + + // add to list if difference to last entry is big enough + if (m_gtm_bco_trig_list.empty() || (gtm_bco - m_gtm_bco_trig_list.back()) > m_max_lv1_endat_bco_diff) + { + assert(m_hNorm); + m_hNorm->Fill("UnmatchedEnDATGTM", 1); + + if (!m_gtm_bco_trig_list.empty()) + { + assert(m_hGTMNewEventSpacing); + m_hGTMNewEventSpacing->Fill(gtm_bco - m_gtm_bco_trig_list.back()); + } + m_gtm_bco_trig_list.push_back(gtm_bco); + } + } + + // also save hearbeat bco + else if (is_modebit) + { + // get modebits + const uint64_t& modebits = gtm_tagger.modebits; + if (modebits == ELINK_HEARTBEAT_T) + { + assert(m_hNorm); + m_hNorm->Fill("HeartBeatGTM", 1); + + auto predicted_fee_bco = get_predicted_fee_bco(gtm_bco); + if (predicted_fee_bco) + { + m_bco_heartbeat_list.emplace_back(gtm_bco, predicted_fee_bco.value()); + } + else + { + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::save_gtm_bco_information" + << "\t- Warning: predicted_fee_bco is not available for gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << ". Skipping heartbeat candidate." << std::endl; + } + } + + if (m_verbosity > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::save_gtm_bco_information" + << "\t- found heartbeat candidate " + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << ". Current m_bco_heartbeat_list:" + << std::endl; + + for (const m_gtm_fee_bco_matching_pair_t& bco : m_bco_heartbeat_list) + { + std::cout << "\t- gtm_bco = 0x" << std::hex << bco.first << std::dec + << "\t- fee_bco = 0x" << std::hex << bco.second << std::dec + << std::endl; + } + } + + while (m_bco_heartbeat_list.size() > m_max_bco_heartbeat_list_size) + { + if (m_verbosity > 1) + { + uint64_t bco = m_bco_heartbeat_list.begin()->first; + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_from_modebits" + << "Warning: m_bco_heartbeat_list is full" + << "\t- drop unprocessed heart beat in queue " + << "at gtm_bco = 0x" << std::hex << bco + << std::dec + << ". Unprocessed heartbeats in queue with size of " << m_bco_heartbeat_list.size() + << std::endl; + } + + m_bco_heartbeat_list.pop_front(); + } + + } // if (modebits & (1U << ELINK_HEARTBEAT_T)) + + if (modebits == BX_COUNTER_SYNC_T) // initiate synchronization of clock sync + { + assert(m_hNorm); + m_hNorm->Fill("SyncGTM", 1); + + // get BCO and assign + const uint64_t bco_reference_gtm_bco = gtm_bco + kBXCounterSyncGtmBcoOffset; + const m_gtm_fee_bco_matching_pair_t bx_counter_sync_reference = + std::make_pair(bco_reference_gtm_bco, static_cast(kBXCounterSyncFEEBcoOffset)); + m_verified_from_modebits = true; + m_bco_reference = bx_counter_sync_reference; + save_bx_counter_sync_observation(gtm_bco, bco_reference_gtm_bco, bx_counter_sync_reference); + m_bco_heartbeat_list.clear(); + + if (m_verbosity) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_from_modebits" + << "\t- found reference from modebits BX_COUNTER_SYNC_T " + << "at gtm_bco = 0x" << std::hex << gtm_bco + << " reference gtm_bco = 0x" << bco_reference_gtm_bco << std::dec + << " GTM sync offset = " << kBXCounterSyncGtmBcoOffset + << " FEE sync offset = " << kBXCounterSyncFEEBcoOffset + << std::endl; + } + } // if (modebits == BX_COUNTER_SYNC_T) // initiate synchronization of clock sync + + if (modebits == DC_STOP_SEND_T) + { + assert(m_hNorm); + m_hNorm->Fill("DC_STOP_SEND_GTM", 1); + + // save the gtm_bco for the digital current readout + m_gtm_bco_dc_read.first = gtm_bco; + if (is_verified()) + { + m_gtm_bco_dc_read.second = get_predicted_fee_bco(gtm_bco).value(); // NOLINT(bugprone-unchecked-optional-access) + } + else + { + m_gtm_bco_dc_read.second = 0; // not verified, so no reference clock sync available + } + + if (m_verbosity > 2) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::save_gtm_bco_information" + << "\t- found DC stop send modebit " + << "at gtm_bco = 0x" << std::hex << gtm_bco << std::dec + << std::endl; + } + } + } +} + +//___________________________________________________ +std::optional TpcTimeFrameBuilderRun3::BcoMatchingInformation::find_reference_heartbeat(const TpcTimeFrameBuilderRun3::fee_payload& HeartBeatPacket) +{ + assert(m_hNorm); + m_hNorm->Fill("HeartBeatFEE", 1); + + // make sure the bco matching is properly initialized and historical valid + if (!is_verified()) + { + return std::nullopt; + } + + assert(HeartBeatPacket.type == HEARTBEAT_T); + const uint32_t& fee_bco = HeartBeatPacket.bx_timestamp; + + if (m_bco_reference) + { + const uint64_t& gtm_bco = m_bco_reference.value().first; + const uint32_t& fee_bco_predicted = m_bco_reference.value().second; + // check if the predicted fee bco matches the actual fee bco + if (get_fee_bco_diff(fee_bco_predicted, fee_bco) < m_max_fee_bco_diff) + { + // Keep QA for matched heartbeat, but do not update clock reference from heartbeat. + if (verbosity() > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - found a matched reference heartbeat; clock reference update disabled: " + << std::hex + << "\t- fee_bco: 0x" << fee_bco + << "\t- predicted: 0x" << fee_bco_predicted + << "\t- gtm_bco: 0x" << gtm_bco + << std::dec + << std::endl; + } + + assert(m_hFEEClockAdjustment_MatchedReference); + m_hFEEClockAdjustment_MatchedReference->Fill(int64_t(fee_bco) - int64_t(fee_bco_predicted), 1); + + m_hNorm->Fill("HeartBeatFEEMatchedReference", 1); + + return gtm_bco; + } + } + + for (const m_gtm_fee_bco_matching_pair_t& bco : m_bco_heartbeat_list) + { + const uint64_t gtm_bco = bco.first; + const uint32_t fee_bco_predicted = bco.second; + + // check if the predicted fee bco matches the actual fee bco + if (get_fee_bco_diff(fee_bco_predicted, fee_bco) < m_max_fee_bco_diff) + { + if (verbosity() > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - found a new reference candidate heartbeat; clock reference update disabled: " + << std::hex + << "\t- fee_bco: 0x" << fee_bco + << "\t- predicted: 0x" << fee_bco_predicted + << "\t- gtm_bco: 0x" << gtm_bco + << "\t- previous reference gtm_bco: 0x" << m_bco_reference.value().first // NOLINT(bugprone-unchecked-optional-access) + << "\t- previous reference fee_bco: 0x" << m_bco_reference.value().second // NOLINT(bugprone-unchecked-optional-access) + << std::dec + << std::endl; + } + // Keep QA for matched candidate heartbeat, but do not replace the clock reference or trim candidates. + if (m_verbosity > 1) + { + std::cout << "\t- clock reference update from heartbeat is disabled; candidate list retained at size " + << m_bco_heartbeat_list.size() << std::endl; + } + + assert(m_hFEEClockAdjustment_MatchedNew); + m_hFEEClockAdjustment_MatchedNew->Fill(int64_t(fee_bco) - int64_t(fee_bco_predicted), 1); + + m_hNorm->Fill("HeartBeatFEEMatchedNew", 1); + return gtm_bco; + } + + if (verbosity() > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - unmatched heartbeat: " + << std::hex + << "\t- fee_bco: 0x" << fee_bco + << "\t- predicted: 0x" << fee_bco_predicted + << "\t- gtm_bco: 0x" << gtm_bco + << std::dec + << std::endl; + } + + assert(m_hFEEClockAdjustment_Unmatched); + m_hFEEClockAdjustment_Unmatched->Fill(int64_t(fee_bco) - int64_t(fee_bco_predicted), 1); + } // for (const auto& bco : m_bco_heartbeat_list) + + if (verbosity() > 1) + { + std::cout << "TpcTimeFrameBuilderRun3[" << m_name << "]::BcoMatchingInformation::find_reference_heartbeat - WARNING: failed match for fee_bco = 0x" << std::hex << fee_bco << std::dec << std::endl; + } + m_hNorm->Fill("HeartBeatFEEUnMatched", 1); + return std::nullopt; +} + +//___________________________________________________ +void TpcTimeFrameBuilderRun3::BcoMatchingInformation::cleanup() +{ + // remove old gtm_bco and matching + while (m_gtm_bco_trig_list.size() > m_max_matching_data_size) + { + m_gtm_bco_trig_list.pop_front(); + } + while (m_bco_matching_list.size() > m_max_matching_data_size) + { + m_bco_matching_list.pop_front(); + } +} + +//___________________________________________________ +void TpcTimeFrameBuilderRun3::BcoMatchingInformation::cleanup(uint64_t ref_bco) +{ + // erase all elements from bco_list that are less than or equal to ref_bco + m_gtm_bco_trig_list.erase(std::remove_if(m_gtm_bco_trig_list.begin(), m_gtm_bco_trig_list.end(), + [ref_bco](const uint64_t& bco) + { return bco <= ref_bco; }), + m_gtm_bco_trig_list.end()); + + // erase all elements from bco_list that are less than or equal to ref_bco + m_bco_matching_list.erase(std::remove_if(m_bco_matching_list.begin(), m_bco_matching_list.end(), + [ref_bco](const m_fee_gtm_bco_matching_pair_t& pair) + { + return pair.second <= ref_bco; + }), + m_bco_matching_list.end()); +} + +void TpcTimeFrameBuilderRun3::fillBadFeeMap() +{ + const std::string filename = CDBInterface::instance()->getUrl("TPC_DECODER_BAD_FEE"); + + if (filename.empty()) + { + if (m_verbosity > 0) + { + std::cout << "TpcTimeFrameBuilderRun3::fillBadFeeMap - no file found for TPC_DECODER_BAD_FEE, not filling bad fee map" << std::endl; + } + return; + } + + CDBTTree cdbtree(filename); + cdbtree.LoadCalibrations(); + + const int nentries = cdbtree.GetSingleIntValue("N_MASKED_FEES"); + + for (int i = 0; i < nentries; i++) + { + m_maskedFEEs[cdbtree.GetIntValue(i, "EBDC")].insert(cdbtree.GetIntValue(i, "FEEID")); + } +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h new file mode 100644 index 0000000000..ecbe213465 --- /dev/null +++ b/offline/framework/fun4allraw/TpcTimeFrameBuilderRun3.h @@ -0,0 +1,520 @@ +#ifndef Fun4All_TpcTimeFrameBuilderRun3_H +#define Fun4All_TpcTimeFrameBuilderRun3_H + +#include "TpcTimeFrameBuilderBase.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class Packet; +class TpcRawHit; +class TpcRawHitv3; +using TpcRawHitRun3_typ = TpcRawHitv3; +class PHTimer; +class TH1; +class TH2; +class TTree; + +// NOLINTNEXTLINE(hicpp-special-member-functions) +class TpcTimeFrameBuilderRun3 : public TpcTimeFrameBuilderBase +{ + public: + explicit TpcTimeFrameBuilderRun3(const int packet_id); + ~TpcTimeFrameBuilderRun3() override; + + // delete copy and move constructors and assignment operators to avoid unsafe copying + TpcTimeFrameBuilderRun3(const TpcTimeFrameBuilderRun3&) = delete; + TpcTimeFrameBuilderRun3& operator=(const TpcTimeFrameBuilderRun3&) = delete; + TpcTimeFrameBuilderRun3(TpcTimeFrameBuilderRun3&&) = delete; + TpcTimeFrameBuilderRun3& operator=(TpcTimeFrameBuilderRun3&&) = delete; + + int ProcessPacket(Packet *) override; + bool isMoreDataRequired(const uint64_t >m_bco) const override; + void CleanupUsedPackets(const uint64_t &bclk) override; + std::vector &getTimeFrame(const uint64_t >m_bco) override; + + void setVerbosity(int i) override; + void setFastBCOSkip(bool fastBCOSkip = true) + { + m_fastBCOSkip = fastBCOSkip; + } + + void fillBadFeeMap() override; + + // enable saving of digital current debug TTree with file name `name` + void SaveDigitalCurrentDebugTTree(const std::string &name) override; + void SaveBXCounterSyncCDBTTree(const std::string &name) override; + + protected: + // Length for the 256-bit wide Round Robin Multiplexer for the data stream + static const size_t DAM_DMA_WORD_LENGTH = 16; + + static const uint16_t FEE_PACKET_MAGIC_KEY_1 = 0xfe; + static const uint16_t FEE_PACKET_MAGIC_KEY_2 = 0xed; + static const uint16_t FEE_PACKET_MAGIC_KEY_3_DC = 0xdcdc; // Digital Current word[3] + + static const uint16_t FEE_MAGIC_KEY = 0xba00; + static const uint16_t GTM_MAGIC_KEY = 0xbb00; + static const uint16_t GTM_LVL1_ACCEPT_MAGIC_KEY = 0xbbf0; + static const uint16_t GTM_ENDAT_MAGIC_KEY = 0xbbf1; + static const uint16_t GTM_MODEBIT_MAGIC_KEY = 0xbbf2; + + static const uint16_t MAX_FEECOUNT = 26; // that many FEEs + static const uint16_t MAX_SAMPA = 8; // that many FEEs + static const uint16_t MAX_CHANNELS = MAX_SAMPA * 32; // that many channels per FEE + // static const uint16_t HEADER_LENGTH = 5; + static const uint16_t HEADER_LENGTH = 7; + static const uint16_t MAX_PACKET_LENGTH = 1025; + + static const uint16_t GL1_BCO_MATCH_WINDOW = 256; // BCOs + + int m_hitFormat = -1; + + uint16_t reverseBits(const uint16_t x) const; + std::pair crc16_parity(const uint32_t fee, const uint16_t l) const; + + //! DMA word structure + struct dma_word + { + uint16_t dma_header = 0; + uint16_t data[DAM_DMA_WORD_LENGTH - 1] = {0}; + }; + + int decode_gtm_data(const dma_word >m_word); + int process_fee_data(unsigned int fee_id); + void process_fee_data_waveform(const unsigned int &fee_id, std::deque &data_buffer); + void process_fee_data_digital_current(const unsigned int &fee_id, std::deque &data_buffer); + + struct gtm_payload + { + uint16_t pkt_type = 0; + bool is_endat = false; + bool is_lvl1 = false; + bool is_modebit = false; + uint64_t bco = 0; + uint32_t lvl1_count = 0; + uint32_t endat_count = 0; + uint64_t last_bco = 0; + uint8_t modebits = 0; + uint8_t userbits = 0; + }; + + struct fee_payload + { + uint16_t fee_id = 0; + uint16_t adc_length = 0; + uint16_t sampa_address = 0; + uint16_t sampa_channel = 0; + uint16_t channel = 0; + uint16_t type = 0; + uint16_t user_word = 0; + uint32_t bx_timestamp = 0; + uint64_t gtm_bco = 0; + bool has_clock_sync = false; + + uint16_t data_crc = 0; + uint16_t calc_crc = 0; + + uint16_t data_parity = 0; + uint16_t calc_parity = 0; + + std::vector>> waveforms; + }; + + struct digital_current_payload + { + static const int MAX_CHANNELS = 8; + + uint64_t gtm_bco{std::numeric_limits::max()}; + uint32_t bx_timestamp_predicted{std::numeric_limits::max()}; + + uint16_t fee{std::numeric_limits::max()}; + uint16_t pkt_length{std::numeric_limits::max()}; + uint16_t channel{std::numeric_limits::max()}; + // uint16_t sampa_max_channel {std::numeric_limits::max()}; + uint16_t sampa_address{std::numeric_limits::max()}; + uint32_t bx_timestamp{0}; + uint32_t current[MAX_CHANNELS]{0}; + uint32_t nsamples[MAX_CHANNELS]{0}; + uint16_t data_crc{std::numeric_limits::max()}; + uint16_t calc_crc = {std::numeric_limits::max()}; + // uint16_t type {std::numeric_limits::max()}; + }; + + class DigitalCurrentDebugTTree + { + public: + explicit DigitalCurrentDebugTTree(const std::string &name); + virtual ~DigitalCurrentDebugTTree(); + + void fill(const digital_current_payload &payload); + + private: + digital_current_payload m_payload; + + std::string m_name; + TTree *m_tDigitalCurrent = nullptr; + }; + DigitalCurrentDebugTTree *m_digitalCurrentDebugTTree = nullptr; + + // ------------------------- + // GTM Matcher + // Initially developped by Hugo Pereira Da Costa as `MicromegasBcoMatchingInformation` + // ------------------------- + class BcoMatchingInformation + { + public: + //! constructor + explicit BcoMatchingInformation(const std::string &name); + + //!@name accessor + //@{ + + //! verbosity + int verbosity() const + { + return m_verbosity; + } + + //! true if matching information is verified + /** + * matching information is verified if at least one match + * between gtm_bco and fee_bco is found + */ + bool is_verified() const + { + return m_verified_from_modebits || m_verified_from_data; + } + + //! matching between fee bco and lvl1 bco + using m_gtm_fee_bco_matching_pair_t = std::pair; + using m_fee_gtm_bco_matching_pair_t = std::pair; + struct BXCounterSyncObservation + { + uint64_t bx_counter_sync_gtm_bco = 0; + uint64_t bco_reference_gtm_bco = 0; + m_gtm_fee_bco_matching_pair_t m_bco_reference = {0, 0}; + }; + + //! expect two but tollerate up to four BX_COUNTER_SYNC_T observations to define the reference clock, depending on data quality. The first few observations will be saved in the CDB for future reference. + static constexpr size_t kMaxBXCounterSyncObservations = 4; + + //! get reference bco + const std::optional &get_reference_bco() const + { + return m_bco_reference; + } + + const std::array &get_bx_counter_sync_observations() const + { + return m_bx_counter_sync_observations; + } + + size_t get_bx_counter_sync_observation_count() const + { + return m_bx_counter_sync_observation_count; + } + + //! whether FEE data has moved pass the given gtm_bco + bool isMoreDataRequired(const uint64_t >m_bco) const; + + //! get predicted fee_bco from gtm_bco + std::optional get_predicted_fee_bco(uint64_t) const; + + //! print gtm bco information + void print_gtm_bco_information() const; + + //! get size of m_gtm_bco_trig_list + size_t get_gtm_bco_trig_list_size() const + { + return m_gtm_bco_trig_list.size(); + } + + //! get size of m_bco_heartbeat_list + size_t get_bco_heartbeat_list_size() const + { + return m_bco_heartbeat_list.size(); + } + + //! get size of m_gtm_bco_trigger_map + size_t get_gtm_bco_trigger_map_size() const + { + return m_gtm_bco_trigger_map.size(); + } + + //! get size of m_bco_matching_list + size_t get_bco_matching_list_size() const + { + return m_bco_matching_list.size(); + } + + //@} + + //!@name modifiers + //@{ + + //! verbosity + void set_verbosity(int value) + { + m_verbosity = value; + } + + /// set gtm clock with rollover correction + uint64_t get_gtm_rollover_correction(const uint64_t >m_bco) const; + + //! find reference from data + std::optional find_reference_heartbeat(const fee_payload &HeartBeatPacket); + + //! save all GTM BCO clocks from packet data + void save_gtm_bco_information(const gtm_payload >m_tagger); + + // //! find gtm bco matching a given fee + // std::optional find_gtm_bco(uint32_t /*fee_gtm*/); + + //! cleanup + void cleanup(); + + //! cleanup + void cleanup(uint64_t /*ref_bco*/); + + m_gtm_fee_bco_matching_pair_t find_dc_read_bco() const + { + return m_gtm_bco_dc_read; + } + //@} + + /* see: https://git.racf.bnl.gov/gitea/Instrumentation/sampa_data/src/branch/fmtv2/README.md */ + enum SampaDataType + { + HEARTBEAT_T = 0b000, + TRUNCATED_DATA_T = 0b001, + TRUNCATED_TRIG_EARLY_DATA_T = 0b011, + NORMAL_DATA_T = 0b100, + LARGE_DATA_T = 0b101, + TRIG_EARLY_DATA_T = 0b110, + TRIG_EARLY_LARGE_DATA_T = 0b111, + }; + + // Command | OLD Mode-Bit | New Mode-Number | Function + // ====================================================== + // NOP | 0b000 | 0x0 | No Operation + // BX_SYNC | 0b001 | 0x1 | SAMPA Beam-crossing sync + // H_BEAT | 0b010 | 0x2 | Generates Heartbeat frame + // TRIG | 0b100 | 0x3 | Trigger data when FEM user bit is 0b01, otherwise the level 1 accept is used when FEM user bit is 0b00 + // CLK_SYNC | N/A | 0x4 | Reset and align 40 MHz and 20 MHz clocks to SAMPA + // SAMPA_RST | N/A | 0x5 | Hard reset SAMPA + // DC_START | N/A | 0x6 | Start digital current reading + // DC_STOP | N/A | 0x7 | Stop and send digital current packet + enum ModeBitType + { + BX_COUNTER_SYNC_T = 0x1, + ELINK_HEARTBEAT_T = 0x2, + DC_STOP_SEND_T = 0x7 + // SAMPA_EVENT_TRIGGER_T = 2, + // CLEAR_LV1_LAST_T = 6, + // CLEAR_LV1_ENDAT_T = 7 + }; + + // get the difference between two BCO WITHOUT rollover corrections + template + inline static constexpr T get_bco_diff( + const T &first, const T &second) + { + return first < second ? (second - first) : (first - second); + } + + // get the difference between two BCO with rollover corrections + inline static constexpr uint32_t get_fee_bco_diff( + const uint32_t &first, const uint32_t &second) // NOLINT(misc-unused-parameters) + { + const uint32_t diff_raw = get_bco_diff(first, second); + const uint32_t half_range = 1U << (m_FEE_CLOCK_BITS - 1); + const uint32_t full_range = 1U << m_FEE_CLOCK_BITS; + return (diff_raw <= half_range) ? diff_raw : full_range - diff_raw; + } + + private: + void save_bx_counter_sync_observation(uint64_t bx_counter_sync_gtm_bco, + uint64_t bco_reference_gtm_bco, + const m_gtm_fee_bco_matching_pair_t &bco_reference); + + std::string m_name; + + //! verbosity + unsigned int m_verbosity = 0; + + //! verified + bool m_verified_from_modebits = false; + + bool m_verified_from_data = false; + + //! list of available bco, sorted in time with rollover corrected + std::list m_gtm_bco_trig_list; + + //! last digital current readout GTM BCO + m_gtm_fee_bco_matching_pair_t m_gtm_bco_dc_read = {0, 0}; + + //! list of available GTM -> FEE bco mapping for synchronization + std::optional m_bco_reference = std::nullopt; + + //! first BX_COUNTER_SYNC_T observations saved for future CDB reference studies + std::array m_bx_counter_sync_observations; + size_t m_bx_counter_sync_observation_count = 0; + + // std::optional< std::pair< uint64_t, uint32_t > > m_bco_reference_candidate = std::nullopt; + //! not yet matched heart beats + std::list m_bco_heartbeat_list; + static constexpr unsigned int m_max_bco_heartbeat_list_size = 16; + + // //! list of heart beat GTM BCO that is still to be matched + // std::queue m_heartbeat_gtm_bco_queue; + // static constexpr unsigned int m_max_heartbeat_queue_size = 16; + + //! list of available GTM -> FEE bco mapping for trigger association + std::map m_gtm_bco_trigger_map; + + std::list m_bco_matching_list; + + // define limit for matching two lvl1 and EnDAT tagger BCOs + static constexpr int m_max_lv1_endat_bco_diff = 16; + + // define limit for matching two fee_bco + static constexpr unsigned int m_max_fee_bco_diff = 64; + + // define limit for matching gtm_bco from lvl1 to enddat + + // define limit for matching fee_bco to fee_bco_predicted + static constexpr unsigned int m_max_gtm_bco_diff = 256; + + // // needed to avoid memory leak. Assumes that we will not be assembling more than 50 events at the same time + static constexpr unsigned int m_max_matching_data_size = 10; + + //! max time in GTM BCO for FEE data to sync over to datastream + static constexpr unsigned int m_max_fee_sync_time = 1024 * 8; + + //! fixed GTM BCO offset applied when BX_COUNTER_SYNC_T defines the reference clock + static constexpr uint64_t kBXCounterSyncGtmBcoOffset = 0; + //! fixed FEE BCO offset applied when BX_COUNTER_SYNC_T defines the reference clock + static constexpr uint64_t kBXCounterSyncFEEBcoOffset = 12; + + static constexpr unsigned int m_FEE_CLOCK_BITS = 20; + static constexpr unsigned int m_GTM_CLOCK_BITS = 40; + + //! Run3 FEE firmware + static constexpr int64_t m_clock_ratio_numerator = 30; + static constexpr int64_t m_clock_ratio_denominator = 8; + + TH1 *m_hNorm = nullptr; + TH1 *m_hFEEClockAdjustment_MatchedReference = nullptr; + TH1 *m_hFEEClockAdjustment_MatchedNew = nullptr; + TH1 *m_hFEEClockAdjustment_Unmatched = nullptr; + TH1 *m_hGTMNewEventSpacing = nullptr; + // TH1 *m_hFindGTMBCO_MatchedExisting_BCODiff = nullptr; + // TH1 *m_hFindGTMBCO_MatchedNew_BCODiff = nullptr; + + }; // class BcoMatchingInformation + + private: + std::vector> m_feeData; + + std::map> m_maskedFEEs; + + int m_verbosity = 0; + int m_packet_id = 0; + + //! common prefix for QA histograms + std::string m_HistoPrefix; + std::string m_bxCounterSyncCDBTTreeName; + + static constexpr uint32_t kFEEClockMask = (1U << 20U) - 1U; + static constexpr uint32_t kRun3FeeMatchWindow = (GL1_BCO_MATCH_WINDOW * 30U + 7U) / 8U; + static constexpr int32_t kRun3ExactMatchWindow = 6; // allow for 1BCO offset from different clock freq. + 1BCO for possible missing first sync + static constexpr uint32_t kRun3FEEClockPerADCClock = 2U; + static constexpr uint32_t kRun3TruncatedWaveformRecoveryWindow = 1024U; + static constexpr uint32_t kRun3TruncatedWaveformRecoveryFEEWindow = + kRun3TruncatedWaveformRecoveryWindow * kRun3FEEClockPerADCClock; + static constexpr int kRun3NormalizationBaseBinCount = 20; + static constexpr int kRun3NormalizationBinCount = kRun3NormalizationBaseBinCount + MAX_FEECOUNT; + + static int64_t get_signed_fee_bco_diff(uint32_t first, uint32_t second); + static uint32_t get_fee_bco_diff(uint32_t first, uint32_t second); + size_t move_time_hits(uint32_t fee_bco, uint16_t fee, std::vector &timeframe); + size_t count_time_hits(uint32_t fee_bco, uint16_t fee) const; + size_t time_hit_bucket_count() const; + std::optional find_fuzzy_fee_bco(uint32_t predicted_fee_bco, uint16_t fee) const; + size_t recover_truncated_waveforms(uint32_t predicted_fee_bco, uint16_t fee, std::vector &timeframe); + size_t append_shifted_waveforms(TpcRawHitRun3_typ *target, const TpcRawHit &source, uint32_t fee_clock_shift) const; + void cleanup_time_hit_map(uint64_t bclk_rollover_corrected, uint32_t fee_clock_window); + void flush_previous_timeframe_qa_cache(uint64_t current_gtm_bco); + void fill_waveform_gl1_spacing(TH1 *waveform_adc_cache, TH2 *waveform_gl1_spacing, uint64_t gtm_bco_spacing) const; + void cache_waveform_adc(TH1 *waveform_adc_cache, const std::vector &timeframe) const; + void cache_timeframe_qa(uint64_t gtm_bco, const std::vector &timeframe, const std::bitset &exact_matched_fees); + void write_bx_counter_sync_cdb_tree() const; + + //! FEE -> FEE BCO -> cached TpcRawHit for Run3 exact-ratio matching + std::vector>> m_timeHitMap; + + //! rollover-corrected GTM BCO -> matched TpcRawHit returned to the input manager + std::map> m_timeFrameMap; + + //! previous timeframe QA state, filled once the next GTM BCO defines the GL1 spacing + std::optional m_previousTimeFrameGtmBco; + std::bitset m_previousTimeFrameExactFees; + std::bitset m_previousTimeFrameRecoveredFees; + int m_hNormTruncatedWaveformRecoveryFeeFirstBin = 0; + static const size_t kMaxRawHitLimit = 10000; // 10k hits per event > 256ch/fee * 26fee + std::queue m_UsedTimeFrameSet; + + //! fast skip mode when searching for particular GL1 BCO over long segment of files + bool m_fastBCOSkip = false; + + //! map bco_information_t to packet id + std::vector m_bcoMatchingInformation_vec; + + //! QA area + + PHTimer *m_packetTimer = nullptr; + + TH1 *m_hNorm = nullptr; + TH2 *m_hFEEDataStream = nullptr; + TH1 *m_hFEEChannelPacketCount = nullptr; + TH2 *m_hFEESAMPAADC = nullptr; + TH1 *m_hFEESAMPAHeartBeatSync = nullptr; + + TH1 *h_PacketLength = nullptr; + TH1 *h_PacketLength_Padding = nullptr; + TH1 *h_PacketLength_Residual = nullptr; + + TH1 *h_GTMClockDiff_Matched = nullptr; + TH1 *h_GTMClockDiff_Unmatched = nullptr; + TH1 *h_GTMClockDiff_Dropped = nullptr; + TH1 *h_TimeFrame_Matched_Size = nullptr; + TH2 *h_Run3_FEE_GTMMatching_ClockDiff = nullptr; + TH1 *h_Run3TimeFrameExactHit_FEE = nullptr; + TH1 *h_Run3TimeFrameFuzzyHit_FEE = nullptr; + TH1 *h_Run3PreviousTimeFrameWaveformADC = nullptr; + TH1 *h_Run3PreviousTimeFrameRecoveredWaveformADC = nullptr; + TH2 *h_Run3Waveform_GL1Spacing = nullptr; + TH2 *h_Run3WaveformRecovered_GL1Spacing = nullptr; + TH2 *h_Run3FEE_TimeFrameCount_GL1Spacing = nullptr; + TH2 *h_Run3FEE_TimeFrameRecoveredCount_GL1Spacing = nullptr; + TH2 *h_Run3FEE_TriggerCount_GL1Spacing = nullptr; + + TH2 *h_ProcessPacket_Time = nullptr; +}; + +#endif diff --git a/offline/framework/fun4allraw/mvtx_decoder/GBTLink.h b/offline/framework/fun4allraw/mvtx_decoder/GBTLink.h index 4604e9944e..69fa1a9c83 100644 --- a/offline/framework/fun4allraw/mvtx_decoder/GBTLink.h +++ b/offline/framework/fun4allraw/mvtx_decoder/GBTLink.h @@ -330,7 +330,7 @@ inline GBTLink::CollectedDataStatus GBTLink::collectROFCableData(/*const Mapping ((gbtWord.activeLanes >> 6) & 0x7) == 0x7) ) { log_error << "Expected all active lanes for links, but " << gbtWord.activeLanes << "found in HBF " << hbfEntry << ", " \ - << gbtWord.asString().data() << std::endl; + << gbtWord.asString() << std::endl; } } else if (gbtWord.isTDH()) // TRIGGER DATA HEADER (TDH) diff --git a/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h b/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h index 10eeb80d5d..0c2060490f 100644 --- a/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h +++ b/offline/framework/fun4allraw/mvtx_decoder/GBTWord.h @@ -104,10 +104,9 @@ struct GBTWord { }; // DIAGNOSTIC IB LANE - uint8_t data8[GBTWordLength]; // 80 bits GBT word + uint8_t data8[GBTWordLength]{}; // 80 bits GBT word }; #pragma GCC diagnostic pop - GBTWord() = default; /// check if the GBT Header corresponds to GBT payload header diff --git a/offline/framework/fun4allraw/mvtx_decoder/PixelData.h b/offline/framework/fun4allraw/mvtx_decoder/PixelData.h index 475e7581e6..6e3d0a964a 100644 --- a/offline/framework/fun4allraw/mvtx_decoder/PixelData.h +++ b/offline/framework/fun4allraw/mvtx_decoder/PixelData.h @@ -40,7 +40,7 @@ class ChipPixelData ~ChipPixelData() = default; uint16_t getChipID() const { return mChipID; } const std::vector& getData() const { return mPixels; } - std::vector& getData() { return (std::vector&)mPixels; } + std::vector& getData() { return mPixels; } // void setROFlags(uint8_t f = 0) { mROFlags = f; } void setChipID(uint16_t id) { mChipID = id; } diff --git a/offline/framework/phool/Makefile.am b/offline/framework/phool/Makefile.am index 22cd13f65d..3af3c76ec8 100644 --- a/offline/framework/phool/Makefile.am +++ b/offline/framework/phool/Makefile.am @@ -60,6 +60,7 @@ libphool_la_SOURCES = \ PHTimer.cc \ PHTimeServer.cc \ PHTimeStamp.cc \ + PHUtils.cc \ recoConsts.cc pkginclude_HEADERS = \ @@ -87,6 +88,7 @@ pkginclude_HEADERS = \ PHTimeServer.h \ PHTimeStamp.h \ PHTypedNodeIterator.h \ + PHUtils.h \ recoConsts.h \ RunnumberRange.h \ sphenix_constants.h diff --git a/offline/framework/phool/PHIODataNode.h b/offline/framework/phool/PHIODataNode.h index 46be461793..3ee60a8e4c 100644 --- a/offline/framework/phool/PHIODataNode.h +++ b/offline/framework/phool/PHIODataNode.h @@ -23,6 +23,7 @@ class PHIODataNode : public PHDataNode T *operator*() { return this->getData(); } PHIODataNode(T *, const std::string &); PHIODataNode(T *, const std::string &, const std::string &); + PHIODataNode(T *, const int, const std::string &); virtual ~PHIODataNode() = default; typedef PHTypedNodeIterator iterator; void BufferSize(int size) { buffersize = size; } @@ -54,6 +55,16 @@ PHIODataNode::PHIODataNode(T *d, const std::string &n, this->objectclass = TO->GetName(); } +template +PHIODataNode::PHIODataNode(T *d, const int id, + const std::string &objtype) + : PHDataNode(d, std::to_string(id), objtype) +{ + this->type = "PHIODataNode"; + TObject *TO = static_cast(d); + this->objectclass = TO->GetName(); +} + template bool PHIODataNode::write(PHIOManager *IOManager, const std::string &path) { diff --git a/offline/framework/phool/PHUtils.cc b/offline/framework/phool/PHUtils.cc new file mode 100644 index 0000000000..34bd50f49f --- /dev/null +++ b/offline/framework/phool/PHUtils.cc @@ -0,0 +1,19 @@ +#include "PHUtils.h" + +#include + +#include +#include + +std::string PHUtils::CreateReproducibleTFileName(const std::string &filename) +{ + std::string outfilename = filename; + if (filename.empty()) + { + std::cout << PHWHERE << " called with empty filename string, returning empty string" << std::endl; + return outfilename; + } + std::filesystem::path p = filename; + outfilename = outfilename + std::string("?reproducible=") + std::string(p.filename()); + return outfilename; +} diff --git a/offline/framework/phool/PHUtils.h b/offline/framework/phool/PHUtils.h new file mode 100644 index 0000000000..5951f2ff16 --- /dev/null +++ b/offline/framework/phool/PHUtils.h @@ -0,0 +1,13 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef PHOOL_PHUTILS_H +#define PHOOL_PHUTILS_H + +#include + +namespace PHUtils +{ + std::string CreateReproducibleTFileName(const std::string &filename); +} + +#endif diff --git a/offline/framework/phool/RunnumberRange.h b/offline/framework/phool/RunnumberRange.h index a9a860e583..7aadfd7d72 100644 --- a/offline/framework/phool/RunnumberRange.h +++ b/offline/framework/phool/RunnumberRange.h @@ -1,18 +1,36 @@ #ifndef PHOOL_RUNNUMBERRANGE_H #define PHOOL_RUNNUMBERRANGE_H -// first and last physics run +/** + * Defines run-number range constants and special run markers used to identify physics data-taking periods. + * + * Each constant names the first or last run number (or a special marker) for a given data-taking period. + * + * @var RUN2PP_FIRST First Run 2 proton-proton physics run passing >=5m, >=100k evts. + * @var RUN2PP_LAST Last Run 2 proton-proton physics run. + * @var RUN2AUAU_FIRST First Run 2 Au+Au (heavy-ion) physics run. + * @var RUN2AUAU_LAST Last Run 2 Au+Au (heavy-ion) physics run. + * @var RUN3_TPCFW_CLOCK_CHANGE Run 3 marker for the TPC Forward clock change. + * @var RUN3AUAU_FIRST First Run 3 Au+Au (heavy-ion) physics run. + * @var RUN3AUAU_LAST Last Run 3 Au+Au (heavy-ion) physics run. + * @var RUN3PP_FIRST First Run 3 proton-proton (beam) physics run. + * @var RUN3PP_LAST Last Run 3 proton-proton physics run. + * @var RUN3OO_FIRST First Run 3 O+O physics run. + * @var RUN3OO_LAST Last Run 3 O+O physics run. + */ namespace RunnumberRange { - static const int RUN2PP_FIRST = 47286; - static const int RUN2PP_LAST = 53880; - static const int RUN2AUAU_FIRST = 54128; - static const int RUN2AUAU_LAST = 54974; - static const int RUN3_TPCFW_CLOCK_CHANGE = 58667; - static const int RUN3AUAU_FIRST = 66457; - static const int RUN3AUAU_LAST = 78954; - static const int RUN3PP_FIRST = 79146; // first beam data - static const int RUN3PP_LAST = 100000; + constexpr int RUN2PP_FIRST = 47287; + constexpr int RUN2PP_LAST = 53880; + constexpr int RUN2AUAU_FIRST = 54128; + constexpr int RUN2AUAU_LAST = 54974; + constexpr int RUN3_TPCFW_CLOCK_CHANGE = 58667; + constexpr int RUN3AUAU_FIRST = 66457; + constexpr int RUN3AUAU_LAST = 78954; + constexpr int RUN3PP_FIRST = 79146; // first beam data + constexpr int RUN3PP_LAST = 81668; + constexpr int RUN3OO_FIRST = 82388; // after trigger settled down (run 82374 excluded); + constexpr int RUN3OO_LAST = 82703; } #endif diff --git a/offline/framework/phool/sphenix_constants.h b/offline/framework/phool/sphenix_constants.h index b5e72a4699..e1d00ca4c9 100644 --- a/offline/framework/phool/sphenix_constants.h +++ b/offline/framework/phool/sphenix_constants.h @@ -12,5 +12,6 @@ namespace sphenix_constants //! time between RHIC crossings (ns) static constexpr double time_between_crossings = 106.65237; static constexpr double CF4_density = 3.86; // mg / cm3 Tom Hemmick + static constexpr double m_xsec_MBDNS = 24.07*1e9; //convert to pb from Vernier scan } // namespace sphenix_constants #endif diff --git a/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.cc b/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.cc deleted file mode 100644 index 754718cfc6..0000000000 --- a/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.cc +++ /dev/null @@ -1,593 +0,0 @@ -#include "Fun4AllStreamingLumiCountingInputManager.h" - -#include -#include "SingleStreamingInputv2.h" - -#include - -#include -#include // for Fun4AllInputManager -#include -#include -#include - -#include // for SyncObject -#include - -#include -#include -#include - -#include // for PHObject -#include -#include // for PHWHERE -#include - -#include -#include -#include -#include - -#include // for max -#include -#include // for uint64_t, uint16_t -#include -#include // for operator<<, basic_ostream, endl -#include // for pair - -Fun4AllStreamingLumiCountingInputManager::Fun4AllStreamingLumiCountingInputManager(const std::string &name, const std::string &dstnodename, const std::string &topnodename) - : Fun4AllInputManager(name, dstnodename, topnodename) - , m_SyncObject(new SyncObjectv1()) -{ - Fun4AllServer *se = Fun4AllServer::instance(); - m_topNode = se->topNode(TopNodeName()); - - createLuminosityHistos(); - return; -} - -Fun4AllStreamingLumiCountingInputManager::~Fun4AllStreamingLumiCountingInputManager() -{ - if (IsOpen()) - { - fileclose(); - } - // std::cout<<"----Write? files to output.root"<Write("", TObject::kOverwrite); - h_lumibco->Write("", TObject::kOverwrite); - h_bunchnumber->Write("", TObject::kOverwrite); - h_bunchnumber_occur->Write("", TObject::kOverwrite); - tfile->Close(); - delete tfile; - */ - return iret; -} - -void Fun4AllStreamingLumiCountingInputManager::SetOutputFileName(const std::string &fileName) -{ - m_outputFileName = fileName; // Update the filename -} - -int Fun4AllStreamingLumiCountingInputManager::fileclose() -{ - // std::cout<<"----fileclose()"<Name() << " reads run " - << iter->RunNumber() - << " from file " << iter->FileName() - << std::endl; - } - } - Fun4AllInputManager::Print(what); - return; -} - -int Fun4AllStreamingLumiCountingInputManager::ResetEvent() -{ - // zhiwan - // m_RefBCO = 0; - return 0; -} - -int Fun4AllStreamingLumiCountingInputManager::PushBackEvents(const int /*i*/) -{ - return 0; -} - -int Fun4AllStreamingLumiCountingInputManager::GetSyncObject(SyncObject **mastersync) -{ - // here we copy the sync object from the current file to the - // location pointed to by mastersync. If mastersync is a 0 pointer - // the syncobject is cloned. If mastersync allready exists the content - // of syncobject is copied - if (!(*mastersync)) - { - if (m_SyncObject) - { - *mastersync = dynamic_cast(m_SyncObject->CloneMe()); - assert(*mastersync); - } - } - else - { - *(*mastersync) = *m_SyncObject; // copy syncobject content - } - return Fun4AllReturnCodes::SYNC_OK; -} - -int Fun4AllStreamingLumiCountingInputManager::SyncIt(const SyncObject *mastersync) -{ - if (!mastersync) - { - std::cout << PHWHERE << Name() << " No MasterSync object, cannot perform synchronization" << std::endl; - std::cout << "Most likely your first file does not contain a SyncObject and the file" << std::endl; - std::cout << "opened by the Fun4AllDstInputManager with Name " << Name() << " has one" << std::endl; - std::cout << "Change your macro and use the file opened by this input manager as first input" << std::endl; - std::cout << "and you will be okay. Fun4All will not process the current configuration" << std::endl - << std::endl; - return Fun4AllReturnCodes::SYNC_FAIL; - } - int iret = m_SyncObject->Different(mastersync); - if (iret) - { - std::cout << "big problem" << std::endl; - exit(1); - } - return Fun4AllReturnCodes::SYNC_OK; -} - -std::string Fun4AllStreamingLumiCountingInputManager::GetString(const std::string &what) const -{ - std::cout << PHWHERE << " called with " << what << " , returning empty string" << std::endl; - return ""; -} - -void Fun4AllStreamingLumiCountingInputManager::registerStreamingInput(SingleStreamingInputv2 *evtin, InputManagerType::enu_subsystem system) -{ - evtin->StreamingLumiInputManager(this); - // if the streaming flag is set, we only want the first event from the GL1 to - // get the starting BCO of that run which enables us to dump all the junk which - // is taken before the run starts in the streaming systems. But we don't want the - // GL1 in the output, so we do not create its dst node if running in streaming - if (system == InputManagerType::GL1) - { - if (!m_StreamingFlag) - { - evtin->CreateDSTNode(m_topNode); - } - } - else - { - evtin->CreateDSTNode(m_topNode); - } - evtin->ConfigureStreamingInputManager(); - if (system == InputManagerType::GL1) - { - m_gl1_registered_flag = true; - m_Gl1InputVector.push_back(evtin); - } - else - { - std::cout << "invalid subsystem flag " << system << std::endl; - gSystem->Exit(1); - exit(1); - } - if (Verbosity() > 3) - { - std::cout << "registering " << evtin->Name() - << " number of registered inputs: " - << m_Gl1InputVector.size() - << std::endl; - } - std::cout << m_Gl1InputVector.size() << std::endl; -} - -void Fun4AllStreamingLumiCountingInputManager::AddGl1RawHit(uint64_t bclk, Gl1Packet *hit) -{ - m_Gl1RawHitMap[bclk].Gl1RawHitVector.push_back(hit); -} - -void Fun4AllStreamingLumiCountingInputManager::AddGl1Window(uint64_t bco_trim, int negative_window, int positive_window) -{ - m_BCOWindows[bco_trim] = std::make_pair(bco_trim - negative_window, bco_trim + positive_window); -} - -void Fun4AllStreamingLumiCountingInputManager::AddGl1BunchNumber(uint64_t bco_trim, int bunch_number) -{ - m_BCOBunchNumber[bco_trim] = bunch_number; -} - -int Fun4AllStreamingLumiCountingInputManager::FillGl1() -{ - // unsigned int alldone = 0; - for (auto *iter : m_Gl1InputVector) - { - if (Verbosity() > 0) - { - std::cout << "Fun4AllStreamingLumiCountingInputManager::FillGl1 - fill pool for " << iter->Name() << std::endl; - std::cout << "Run number " << iter->RunNumber() << std::endl; - } - iter->FillPool(); - - if (m_RunNumber == 0) - { - m_RunNumber = iter->RunNumber(); - SetRunNumber(m_RunNumber); - } - else - { - if (m_RunNumber != iter->RunNumber()) - { - std::cout << PHWHERE << " Run Number mismatch, run is " - << m_RunNumber << ", " << iter->Name() << " reads " - << iter->RunNumber() << std::endl; - std::cout << "You are likely reading files from different runs, do not do that" << std::endl; - Print("INPUTFILES"); - gSystem->Exit(1); - exit(1); - } - } - } - - if (Verbosity() > 0) - { - std::cout << "Here BCO " << m_BCOWindows.begin()->first << " left " << m_BCOWindows.begin()->second.first << " right " << m_BCOWindows.begin()->second.second << std::endl; - } - /* - for (const auto &entry : m_BCOWindows) { - uint64_t key = entry.first; - uint64_t valueFirst = entry.second.first; - uint64_t valueSecond = entry.second.second; - std::cout << "Key: " << key - << ", Value First: " << valueFirst - << ", Value Second: " << valueSecond - << std::endl; - } - - for (const auto& [bco_trim, bunch_number] : m_BCOBunchNumber) { - std::cout << "Here BCO " << bco_trim << " Bunch Number " << bunch_number << std::endl; - } - */ - // std::cout << "Here BCO " <first < 1) - { - auto first_element = m_BCOWindows.begin(); - auto second_element = std::next(m_BCOWindows.begin()); - // std::cout<<"Key 1: "<first<<" Value ( "<second.first<<" , "<second.second<first<<" Value ( "<second.first<<" , "<second.second<first - first_element->first<<" compared with window "<< m_negative_bco_window+m_positive_bco_window < 1099511000000, then switch them - m_diffBCO = second_element->first - first_element->first; - - if (second_element->first - first_element->first > 1099510000000) - { - flat_overflow = true; - // int temp_m_diffBCO=first_element->first+1099511627775+1-second_element->first; - bco_temp = first_element->first; - m_BCOWindows.erase(m_BCOWindows.begin()); - bco_temp += 1099511627775 + 1; - m_BCOWindows[bco_temp] = std::make_pair(bco_temp - m_negative_bco_window, bco_temp + m_positive_bco_window); - first_element = m_BCOWindows.begin(); - second_element = std::next(m_BCOWindows.begin()); - m_diffBCO = second_element->first - first_element->first; - std::cout << "overflow new diff " << m_diffBCO << " new first element " << first_element->first << " new second element " << second_element->first << std::endl; - } - h_diffbco->Fill(m_diffBCO); - if (m_diffBCO < static_cast(m_negative_bco_window + m_positive_bco_window)) - { - m_BCOWindows.begin()->second.second = second_element->second.first; - std::cout << "*** new Key 1 BCO " << m_BCOWindows.begin()->first << " left " << m_BCOWindows.begin()->second.first << " right " << m_BCOWindows.begin()->second.second << std::endl; - } - } - - m_bco_trim = m_BCOWindows.begin()->first; - m_lower_bound = m_BCOWindows.begin()->second.first; - m_upper_bound = m_BCOWindows.begin()->second.second; - m_bunch_number = m_BCOBunchNumber[m_BCOWindows.begin()->first]; - // ttree->Fill(); - h_bunchnumber->Fill(m_BCOBunchNumber[m_BCOWindows.begin()->first]); - h_lumibco->Fill(m_BCOWindows.begin()->second.second - m_BCOWindows.begin()->second.first); - - int lower = -1 * static_cast(m_bco_trim - m_lower_bound); - int upper = (m_upper_bound > m_bco_trim) ? static_cast(m_upper_bound - m_bco_trim) : -1 * static_cast(m_bco_trim - m_upper_bound); // it is possible that upper is <0 - // std::cout<<"lower="<first); - // m_BCOBunchNumber.erase(m_BCOBunchNumber.begin()); - } - if (!m_BCOWindows.empty()) - { - m_BCOWindows.erase(m_BCOWindows.begin()); - } - if (flat_overflow) - { - m_BCOWindows.erase(m_BCOWindows.begin()); - bco_temp -= 1099511627775 + 1; - m_BCOWindows[bco_temp] = std::make_pair(bco_temp - m_negative_bco_window, bco_temp + m_positive_bco_window); - std::cout << " Change back, new bco window map " << m_BCOBunchNumber.begin()->first << std::endl; - flat_overflow = false; - } - - // mow use new - - Gl1Packet *gl1packet = findNode::getClass(m_topNode, "GL1RAWHIT"); - for (auto *gl1hititer : m_Gl1RawHitMap.begin()->second.Gl1RawHitVector) - { - if (!m_StreamingFlag) // if streaming flag is set, the gl1packet is a nullptr - { - gl1packet->FillFrom(gl1hititer); - MySyncManager()->CurrentEvent(gl1packet->getEvtSequence()); - } - } - - // add for mbd p_gl1 - Gl1Packet *p_gl1 = findNode::getClass(m_topNode, "GL1RAWHIT"); //"GL1Packet"); - if (!p_gl1) - { - std::cout << "CAN not find this Gl1Packet" << std::endl; - } - else - { - int bunchnumber = p_gl1->getBunchNumber(); - // uint64_t evtBCO_gl1 = p_gl1->getBCO() & 0xFFFFFFFFFFU; - // for (int i = 0; i <9;i++)// int(GL1PScaler_raw_vec.size()); i++) - // { - if (p_gl1->lValue(0, "GL1PRAW")) // 0-8, 0 is MBDSN - { - // GL1PScaler_raw_vec[i][bunchnumber] = p_gl1->lValue(i, "GL1PRAW"); - // std::cout<<"evtBCO: "<lValue(0, "GL1PRAW"); - m_bunchnumber_MBDNS_live[bunchnumber] = p_gl1->lValue(0, "GL1PLIVE"); - m_bunchnumber_MBDNS_scaled[bunchnumber] = p_gl1->lValue(0, "GL1PSCALED"); - m_bunchnumber_ZDCCoin_raw[bunchnumber] = p_gl1->lValue(5, "GL1PRAW"); // zdc coincidence - // h_gl1p_MBDSN_bunchid->Fill(bunchnumber, p_gl1->lValue(0, "GL1PRAW")); - // std::cout<<" bunchnumber ="<lValue(0, 0)) - { - // m_bunchnumber_rawgl1scaler[bunchnumber] = p_gl1->lValue(0, 0); - // std::cout<<" bunchnumber ="< 0) - { - if (m_alldone_flag) - { - std::cout << "all done is true" << std::endl; - } - } - - if (m_alldone_flag) - { - std::cout << m_event_number << " Events -- Storing files to output.root" << std::endl; - std::string updatedFileName = m_outputFileName + "_" + std::to_string(m_event_number) + ".root"; - if (TFile::Open(updatedFileName.c_str(), "READ")) - { - updatedFileName = m_outputFileName + "_" + std::to_string(m_event_number + 1) + ".root"; - } - tfile = TFile::Open(updatedFileName.c_str(), "RECREATE", ""); - ttree->Write("", TObject::kOverwrite); - h_lumibco->Write("", TObject::kOverwrite); - h_bunchnumber->Write("", TObject::kOverwrite); - h_bunchnumber_occur->Write("", TObject::kOverwrite); - h_diffbco->Write("", TObject::kOverwrite); - h_gl1p_MBDSN_bunchid_raw->Write("", TObject::kOverwrite); - h_gl1p_MBDSN_bunchid_live->Write("", TObject::kOverwrite); - h_gl1p_MBDSN_bunchid_scaled->Write("", TObject::kOverwrite); - h_gl1p_rawgl1scaler->Write("", TObject::kOverwrite); - h_gl1p_ZDCCoin_bunchid_raw->Write("", TObject::kOverwrite); - tfile->Close(); - delete tfile; - - ttree->Reset(); - h_lumibco->Reset(); - h_bunchnumber->Reset(); - h_bunchnumber_occur->Reset(); - h_diffbco->Reset(); - h_gl1p_MBDSN_bunchid_raw->Reset(); - h_gl1p_MBDSN_bunchid_live->Reset(); - h_gl1p_MBDSN_bunchid_scaled->Reset(); - h_gl1p_rawgl1scaler->Reset(); - h_gl1p_ZDCCoin_bunchid_raw->Reset(); - } - - return 0; -} - -void Fun4AllStreamingLumiCountingInputManager::SetNegativeWindow(const unsigned int i) -{ - m_negative_bco_window = std::max(i, m_negative_bco_window); -} - -void Fun4AllStreamingLumiCountingInputManager::SetPositiveWindow(const unsigned int i) -{ - m_positive_bco_window = std::max(i, m_positive_bco_window); -} - -void Fun4AllStreamingLumiCountingInputManager::createLuminosityHistos() -{ - auto *hm = QAHistManagerDef::getHistoManager(); - assert(hm); - // zhiwan - { - auto *tr = new TTree("BCOWindowTree", "BCO Window Data"); - tr->Branch("bco_trim", &m_bco_trim); - tr->Branch("lower_bound", &m_lower_bound); - tr->Branch("upper_bound", &m_upper_bound); - tr->Branch("bunch_number", &m_bunch_number); - // tr->Branch("rawgl1scaler", &m_rawgl1scaler); - tr->SetAutoFlush(100000); - hm->registerHisto(tr); - } - - { - auto *h = new TH1I("h_LumiBCO", "Lumi BCO", 500, 0, 500); - h->GetXaxis()->SetTitle(" Lumi BCO per event"); - h->SetTitle("Number of BCO matched"); - hm->registerHisto(h); - } - { - auto *h = new TH1I("h_BunchNumber", "Bunch Number Lumi BCO", 121, -0.5, 120.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_BunchNumberOccurance", "Bunch Number Lumi BCO", 120, -0.5, 119.5); - h->GetXaxis()->SetTitle("Bunch Number per time window"); - h->SetTitle("Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1I("h_diffBCO", "gl1 bco 1-2", 3500, 0, 3500); - h->GetXaxis()->SetTitle("GL1 BCO difference"); - h->SetTitle("Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_MBDSNraw_BunchID", "Bunch Number Lumi BCO", 121, -0.5, 120.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("MBDSN Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_MBDSNlive_BunchID", "Bunch Number Lumi BCO", 121, -0.5, 120.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("MBDSN Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_MBDSNscaled_BunchID", "Bunch Number Lumi BCO", 121, -0.5, 120.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("MBDSN Number of crossing"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_rawgl1scalerBunchID", "Bunch Number Lumi BCO", 10, -0.5, 9.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("raw GL1 scaler"); - hm->registerHisto(h); - } - { - auto *h = new TH1D("h_gl1p_ZDCCoin_BunchID", "Bunch Number Lumi BCO", 121, -0.5, 120.5); - h->GetXaxis()->SetTitle("Bunch Number per event"); - h->SetTitle("raw GL1 scaler"); - hm->registerHisto(h); - } - // Get the global pointers - h_lumibco = dynamic_cast(hm->getHisto("h_LumiBCO")); - h_bunchnumber = dynamic_cast(hm->getHisto("h_BunchNumber")); - h_bunchnumber_occur = dynamic_cast(hm->getHisto("h_BunchNumberOccurance")); - ttree = dynamic_cast(hm->getHisto("BCOWindowTree")); - h_diffbco = dynamic_cast(hm->getHisto("h_diffBCO")); - h_gl1p_MBDSN_bunchid_raw = dynamic_cast(hm->getHisto("h_MBDSNraw_BunchID")); - h_gl1p_MBDSN_bunchid_live = dynamic_cast(hm->getHisto("h_MBDSNlive_BunchID")); - h_gl1p_MBDSN_bunchid_scaled = dynamic_cast(hm->getHisto("h_MBDSNscaled_BunchID")); - h_gl1p_rawgl1scaler = dynamic_cast(hm->getHisto("h_rawgl1scalerBunchID")); - h_gl1p_ZDCCoin_bunchid_raw = dynamic_cast(hm->getHisto("h_gl1p_ZDCCoin_BunchID")); -} diff --git a/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.h b/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.h deleted file mode 100644 index 3f1515bb23..0000000000 --- a/offline/framework/rawbcolumi/Fun4AllStreamingLumiCountingInputManager.h +++ /dev/null @@ -1,108 +0,0 @@ -// Tell emacs that this is a C++ source -// -*- C++ -*-. -#ifndef RAWBCOLUMI_FUN4ALLSTREAMINGLUMICOUNTINGINPUTMANAGER_H -#define RAWBCOLUMI_FUN4ALLSTREAMINGLUMICOUNTINGINPUTMANAGER_H - -#include -// #include -#include - -#include -#include -#include -#include -class SingleStreamingInputv2; -class Gl1Packet; -class PHCompositeNode; -class SyncObject; -class TH1; -class TTree; -class Fun4AllStreamingLumiCountingInputManager : public Fun4AllInputManager -{ - public: - Fun4AllStreamingLumiCountingInputManager(const std::string &name = "DUMMY", const std::string &dstnodename = "DST", const std::string &topnodename = "TOP"); - ~Fun4AllStreamingLumiCountingInputManager() override; - int fileopen(const std::string & /*filenam*/) override { return 0; } - // cppcheck-suppress virtualCallInConstructor - int fileclose() override; - int run(const int nevents = 0) override; - - void Print(const std::string &what = "ALL") const override; - int ResetEvent() override; - int PushBackEvents(const int i) override; - int GetSyncObject(SyncObject **mastersync) override; - int SyncIt(const SyncObject *mastersync) override; - int HasSyncObject() const override { return 1; } - std::string GetString(const std::string &what) const override; - void registerStreamingInput(SingleStreamingInputv2 *evtin, InputManagerType::enu_subsystem); - int FillGl1(); - void AddGl1RawHit(uint64_t bclk, Gl1Packet *hit); - void AddGl1Window(uint64_t bco_trim, int negative_window, int positive_window); - void AddGl1BunchNumber(uint64_t bco_trim, int bunch_number); - void SetNegativeWindow(const unsigned int i); - void SetPositiveWindow(const unsigned int i); - void Streaming(bool b = true) { m_StreamingFlag = b; } - void SetOutputFileName(const std::string &fileName); - void SetEndofEvent(bool flag = false, bool flag2 = false) - { - m_alldone_flag = flag; - m_lastevent_flag = flag2; - } - void SetEventNumber(int num) { m_event_number = num; } - - private: - struct Gl1RawHitInfo - { - std::vector Gl1RawHitVector; - unsigned int EventFoundCounter{0}; - }; - - void createLuminosityHistos(); - - SyncObject *m_SyncObject{nullptr}; - PHCompositeNode *m_topNode{nullptr}; - - int m_RunNumber{0}; - unsigned int m_negative_bco_window{0}; - unsigned int m_positive_bco_window{0}; - uint64_t m_rawgl1scaler{0}; - // std::string m_output_file="output.root"; - bool m_alldone_flag = {false}; - bool m_lastevent_flag = {false}; - int m_event_number{0}; - int m_diffBCO{0}; - bool m_gl1_registered_flag{false}; - bool m_StreamingFlag{false}; - bool flat_overflow{false}; - uint64_t bco_temp = 0; - - std::vector m_Gl1InputVector; - std::map m_Gl1RawHitMap; - std::map> m_BCOWindows; - std::map m_BCOBunchNumber; - std::map m_bunchnumber_MBDNS_raw; - std::map m_bunchnumber_MBDNS_live; - std::map m_bunchnumber_MBDNS_scaled; - std::map m_bunchnumber_ZDCCoin_raw; - // std::map m_bunchnumber_rawgl1scaler; - - // QA histos - TH1 *h_lumibco{nullptr}; - TH1 *h_bunchnumber{nullptr}; - TH1 *h_bunchnumber_occur{nullptr}; - TH1 *h_diffbco{nullptr}; - TH1 *h_gl1p_MBDSN_bunchid_raw{nullptr}; - TH1 *h_gl1p_MBDSN_bunchid_live{nullptr}; - TH1 *h_gl1p_MBDSN_bunchid_scaled{nullptr}; - TH1 *h_gl1p_rawgl1scaler{nullptr}; - TH1 *h_gl1p_ZDCCoin_bunchid_raw{nullptr}; - uint64_t m_bco_trim{}; - uint64_t m_lower_bound{}; - uint64_t m_upper_bound{}; - int m_bunch_number{}; - TTree *ttree = nullptr; - TFile *tfile = nullptr; - std::string m_outputFileName = "/sphenix/user/xuzhiwan/luminosity/streaming-macro/macro/output.root"; // Default value -}; - -#endif /* RAWBCOLUMI_FUN4ALLSTREAMINGLUMICOUNTINGINPUTMANAGER_H */ diff --git a/offline/framework/rawbcolumi/Makefile.am b/offline/framework/rawbcolumi/Makefile.am deleted file mode 100644 index b95b96ad16..0000000000 --- a/offline/framework/rawbcolumi/Makefile.am +++ /dev/null @@ -1,50 +0,0 @@ -AUTOMAKE_OPTIONS = foreign - -AM_CPPFLAGS = \ - -I$(includedir) \ - -isystem$(OFFLINE_MAIN)/include \ - -isystem$(ROOTSYS)/include \ - -isystem$(OPT_SPHENIX)/include - -AM_LDFLAGS = \ - -L$(libdir) \ - -L$(OFFLINE_MAIN)/lib - -pkginclude_HEADERS = \ - SingleGl1PoolInputv2.h \ - SingleStreamingInputv2.h \ - Fun4AllStreamingLumiCountingInputManager.h - -lib_LTLIBRARIES = \ - librawbcolumi.la - -# source for mvtx decoder library -librawbcolumi_la_SOURCES = \ - SingleGl1PoolInputv2.cc \ - SingleStreamingInputv2.cc \ - Fun4AllStreamingLumiCountingInputManager.cc - -librawbcolumi_la_LIBADD = \ - -lffarawobjects \ - -lfun4all \ - -lEvent \ - -lphoolraw \ - -lqautils - -BUILT_SOURCES = testexternals.cc - -noinst_PROGRAMS = \ - testexternals - -testexternals_SOURCES = testexternals.cc -testexternals_LDADD = librawbcolumi.la - -testexternals.cc: - echo "//*** this is a generated file. Do not commit, do not edit" > $@ - echo "int main()" >> $@ - echo "{" >> $@ - echo " return 0;" >> $@ - echo "}" >> $@ - -clean-local: - rm -f $(BUILT_SOURCES) diff --git a/offline/framework/rawbcolumi/SingleGl1PoolInputv2.cc b/offline/framework/rawbcolumi/SingleGl1PoolInputv2.cc deleted file mode 100644 index aa4193b7f9..0000000000 --- a/offline/framework/rawbcolumi/SingleGl1PoolInputv2.cc +++ /dev/null @@ -1,362 +0,0 @@ -#include "SingleGl1PoolInputv2.h" - -#include -#include -#include "Fun4AllStreamingLumiCountingInputManager.h" - -#include - -#include -#include // for PHIODataNode -#include // for PHNode -#include // for PHNodeIterator -#include // for PHObject -#include -#include - -#include -#include -#include -#include // for Packet - -#include // for uint64_t -#include // for operator<<, basic_ostream<... -#include // for reverse_iterator -#include // for numeric_limits -#include -#include -#include // for pair - -SingleGl1PoolInputv2::SingleGl1PoolInputv2(const std::string &name) - : SingleStreamingInputv2(name) -{ - SubsystemEnum(InputManagerType::GL1); -} - -SingleGl1PoolInputv2::~SingleGl1PoolInputv2() -{ - CleanupUsedPackets(std::numeric_limits::max()); -} - -void SingleGl1PoolInputv2::FillPool(const unsigned int /*nbclks*/) -{ - if (AllDone()) // no more files and all events read - { - return; - } - while (GetEventiterator() == nullptr) // at startup this is a null pointer - { - if (!OpenNextFile()) - { - AllDone(1); - return; - } - } - // std::set saved_beamclocks; - while (GetSomeMoreEvents()) - { - std::unique_ptr evt(GetEventiterator()->getNextEvent()); - while (!evt) - { - fileclose(); - if (!OpenNextFile()) - { - AllDone(1); - return; - } - evt.reset(GetEventiterator()->getNextEvent()); - } - if (Verbosity() > 2) - { - std::cout << PHWHERE << "Fetching next Event" << evt->getEvtSequence() << std::endl; - } - if ((m_total_event == 0 && evt->getEvtType() == ENDRUNEVENT) || - (m_total_event != 0 && evt->getEvtSequence() - 2 == m_total_event)) - { - m_alldone_flag = true; - m_lastevent_flag = true; - } - if (evt->getEvtSequence() % 5000 == 0) - { - m_alldone_flag = true; - m_lastevent_flag = true; - } - if (Verbosity() > 2) - { - if (m_alldone_flag) - { - std::cout << "gl1 all done is true" << std::endl; - } - // else{std::cout<<"gl1 all done is false"<getRunNumber()); - if (GetVerbosity() > 1) - { - evt->identify(); - } - if (evt->getEvtType() != DATAEVENT) - { - m_NumSpecialEvents++; - if (evt->getEvtType() == ENDRUNEVENT) - { - AllDone(1); - std::unique_ptr nextevt(GetEventiterator()->getNextEvent()); - if (nextevt) - { - std::cout << PHWHERE << " Found event after End Run Event " << std::endl; - std::cout << "End Run Event identify: " << std::endl; - evt->identify(); - std::cout << "Next event identify: " << std::endl; - nextevt->identify(); - } - return; - } - continue; - } - int EventSequence = evt->getEvtSequence(); - Packet *packet = evt->getPacket(14001); - if (!packet) - { - std::cout << PHWHERE << "Packet 14001 is null ptr" << std::endl; - evt->identify(); - m_alldone_flag = true; - m_lastevent_flag = true; - if (StreamingLumiInputManager()) - { - StreamingLumiInputManager()->SetEndofEvent(m_alldone_flag, m_lastevent_flag); - StreamingLumiInputManager()->SetEventNumber(EventSequence); - } - m_alldone_flag = false; - m_lastevent_flag = false; - continue; - } - if (Verbosity() > 1) - { - packet->identify(); - } - - Gl1Packet *newhit = new Gl1Packetv3(); - uint64_t gtm_bco = packet->lValue(0, "BCO"); - uint64_t bco_trim = gtm_bco & 0xFFFFFFFFFFU; - // std::cout<first<<" left "<second.first<<" right "<< m_BCOWindows.begin()->second.second<lValue(0, "BunchNumber"); - // std::cout<<"BCO "<AddGl1Window(bco_trim, m_negative_bco_window, m_positive_bco_window); - StreamingLumiInputManager()->AddGl1BunchNumber(bco_trim, m_BCOBunchNumber[bco_trim]); - StreamingLumiInputManager()->SetEndofEvent(m_alldone_flag, m_lastevent_flag); - StreamingLumiInputManager()->SetEventNumber(EventSequence); - StreamingLumiInputManager()->SetNegativeWindow(m_negative_bco_window); - StreamingLumiInputManager()->SetPositiveWindow(m_positive_bco_window); - } - if (evt->getEvtSequence() % 5000 == 0) - { - m_alldone_flag = false; - m_lastevent_flag = false; - } - - m_FEEBclkMap.insert(gtm_bco); - newhit->setBCO(packet->lValue(0, "BCO")); - newhit->setHitFormat(packet->getHitFormat()); - newhit->setIdentifier(packet->getIdentifier()); - newhit->setEvtSequence(EventSequence); - newhit->setPacketNumber(packet->iValue(0)); - newhit->setBunchNumber(packet->lValue(0, "BunchNumber")); - newhit->setTriggerInput(packet->lValue(0, "TriggerInput")); - newhit->setLiveVector(packet->lValue(0, "LiveVector")); - newhit->setScaledVector(packet->lValue(0, "ScaledVector")); - newhit->setGTMBusyVector(packet->lValue(0, "GTMBusyVector")); - newhit->setGTMAllBusyVector(packet->lValue(0, "GTMAllBusyVector")); - for (int i = 0; i < 64; i++) - { - for (int j = 0; j < 3; j++) - { - newhit->setScaler(i, j, packet->lValue(i, j)); - } - } - for (int i = 0; i < 12; i++) - { - newhit->setGl1pScaler(i, 0, packet->lValue(i, "GL1PRAW")); - newhit->setGl1pScaler(i, 1, packet->lValue(i, "GL1PLIVE")); - newhit->setGl1pScaler(i, 2, packet->lValue(i, "GL1PSCALED")); - } - if (Verbosity() > 2) - { - std::cout << PHWHERE << " Packet: " << packet->getIdentifier() - << " evtno: " << EventSequence - << ", bco: 0x" << std::hex << gtm_bco << std::dec - << ", bunch no: " << packet->lValue(0, "BunchNumber") - << std::endl; - std::cout << PHWHERE << " RB Packet: " << newhit->getIdentifier() - << " evtno: " << newhit->getEvtSequence() - << ", bco: 0x" << std::hex << newhit->getBCO() << std::dec - << ", bunch no: " << +newhit->getBunchNumber() - << std::endl; - } - if (Verbosity() > 2) - { - std::cout << PHWHERE << "evtno: " << EventSequence - << ", bco: 0x" << std::hex << gtm_bco << std::dec - << std::endl; - } - if (StreamingLumiInputManager()) - { - StreamingLumiInputManager()->AddGl1RawHit(gtm_bco, newhit); - } - - m_Gl1RawHitMap[gtm_bco].push_back(newhit); - m_BclkStack.insert(gtm_bco); - - delete packet; - } -} - -void SingleGl1PoolInputv2::Print(const std::string &what) const -{ - if (what == "ALL" || what == "FEEBCLK") - { - for (auto bcliter : m_FEEBclkMap) - { - std::cout << PHWHERE << " bclk: 0x" - << std::hex << bcliter << std::dec << std::endl; - } - } - if (what == "ALL" || what == "STORAGE") - { - for (const auto &bcliter : m_Gl1RawHitMap) - { - std::cout << PHWHERE << "Beam clock 0x" << std::hex << bcliter.first << std::dec << std::endl; - for (auto *feeiter : bcliter.second) - { - std::cout << PHWHERE << "fee: " << feeiter->getBCO() - << " at " << std::hex << feeiter << std::dec << std::endl; - } - } - } - if (what == "ALL" || what == "STACK") - { - for (auto iter : m_BclkStack) - { - std::cout << PHWHERE << "stacked bclk: 0x" << std::hex << iter << std::dec << std::endl; - } - } -} - -void SingleGl1PoolInputv2::CleanupUsedPackets(const uint64_t bclk) -{ - std::vector toclearbclk; - for (const auto &iter : m_Gl1RawHitMap) - { - if (iter.first <= bclk) - { - for (auto *pktiter : iter.second) - { - delete pktiter; - } - toclearbclk.push_back(iter.first); - } - else - { - break; - } - } - - for (auto iter : toclearbclk) - { - m_FEEBclkMap.erase(iter); - m_BclkStack.erase(iter); - m_Gl1RawHitMap.erase(iter); - } -} - -bool SingleGl1PoolInputv2::CheckPoolDepth(const uint64_t bclk) -{ - // if (m_FEEBclkMap.size() < 10) - // { - // std::cout << PHWHERE << "not all FEEs in map: " << m_FEEBclkMap.size() << std::endl; - // return true; - // } - for (auto iter : m_FEEBclkMap) - { - if (Verbosity() > 2) - { - std::cout << PHWHERE << "my bclk 0x" << std::hex << iter - << " req: 0x" << bclk << std::dec << std::endl; - } - if (iter < bclk) - { - if (Verbosity() > 1) - { - std::cout << PHWHERE << "FEE " << iter << " beamclock 0x" << std::hex << iter - << " smaller than req bclk: 0x" << bclk << std::dec << std::endl; - } - return false; - } - } - return true; -} - -void SingleGl1PoolInputv2::ClearCurrentEvent() -{ - // called interactively, to get rid of the current event - uint64_t currentbclk = *m_BclkStack.begin(); - // std::cout << PHWHERE << "clearing bclk 0x" << std::hex << currentbclk << std::dec << std::endl; - CleanupUsedPackets(currentbclk); - // m_BclkStack.erase(currentbclk); - return; -} - -bool SingleGl1PoolInputv2::GetSomeMoreEvents() -{ - if (AllDone()) - { - return false; - } - if (m_Gl1RawHitMap.empty()) - { - return true; - } - - uint64_t lowest_bclk = m_Gl1RawHitMap.begin()->first; - lowest_bclk += m_BcoRange; - uint64_t last_bclk = m_Gl1RawHitMap.rbegin()->first; - if (Verbosity() > 1) - { - std::cout << PHWHERE << "first bclk 0x" << std::hex << lowest_bclk - << " last bco: 0x" << last_bclk - << std::dec << std::endl; - } - if (lowest_bclk >= last_bclk) - { - return true; - } - return false; -} - -void SingleGl1PoolInputv2::CreateDSTNode(PHCompositeNode *topNode) -{ - PHNodeIterator iter(topNode); - PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - dstNode = new PHCompositeNode("DST"); - topNode->addNode(dstNode); - } - PHNodeIterator iterDst(dstNode); - PHCompositeNode *detNode = dynamic_cast(iterDst.findFirst("PHCompositeNode", "GL1")); - if (!detNode) - { - detNode = new PHCompositeNode("GL1"); - dstNode->addNode(detNode); - } - Gl1Packet *gl1hitcont = findNode::getClass(detNode, "GL1RAWHIT"); - if (!gl1hitcont) - { - gl1hitcont = new Gl1Packetv3(); - PHIODataNode *newNode = new PHIODataNode(gl1hitcont, "GL1RAWHIT", "PHObject"); - detNode->addNode(newNode); - } -} diff --git a/offline/framework/rawbcolumi/SingleGl1PoolInputv2.h b/offline/framework/rawbcolumi/SingleGl1PoolInputv2.h deleted file mode 100644 index f2252571f4..0000000000 --- a/offline/framework/rawbcolumi/SingleGl1PoolInputv2.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef RAWBCOLUMI_SINGLEGL1POOLINPUTV2_H -#define RAWBCOLUMI_SINGLEGL1POOLINPUTV2_H - -#include "SingleStreamingInputv2.h" - -#include -#include -#include -#include -#include -#include - -class Gl1Packet; -class PHCompositeNode; - -class SingleGl1PoolInputv2 : public SingleStreamingInputv2 -{ - public: - explicit SingleGl1PoolInputv2(const std::string &name); - ~SingleGl1PoolInputv2() override; - void FillPool(const unsigned int) override; - void CleanupUsedPackets(const uint64_t bclk) override; - bool CheckPoolDepth(const uint64_t bclk) override; - void ClearCurrentEvent() override; - bool GetSomeMoreEvents(); - void Print(const std::string &what = "ALL") const override; - void CreateDSTNode(PHCompositeNode *topNode) override; - void SetBcoRange(const unsigned int i) { m_BcoRange = i; } - // void ConfigureStreamingInputManager() override; - void SetNegativeWindow(const unsigned int value) { m_negative_bco_window = value; } - void SetPositiveWindow(const unsigned int value) { m_positive_bco_window = value; } - void SetTotalEvent(const int value) { m_total_event = value; } - - private: - unsigned int m_NumSpecialEvents{0}; - unsigned int m_BcoRange{0}; - - //! map bco to packet - std::map m_packet_bco; - - std::map> m_Gl1RawHitMap; - std::map> m_BCOWindows; - std::map m_BCOBunchNumber; - std::set m_FEEBclkMap; - std::set m_BclkStack; - - unsigned int m_negative_bco_window = 20; - unsigned int m_positive_bco_window = 325; - bool m_alldone_flag = {false}; - bool m_lastevent_flag = {false}; - int m_total_event = std::numeric_limits::max(); -}; - -#endif diff --git a/offline/framework/rawbcolumi/SingleStreamingInputv2.cc b/offline/framework/rawbcolumi/SingleStreamingInputv2.cc deleted file mode 100644 index c0c7aef409..0000000000 --- a/offline/framework/rawbcolumi/SingleStreamingInputv2.cc +++ /dev/null @@ -1,139 +0,0 @@ -#include "SingleStreamingInputv2.h" - -#include - -#include - -#include -#include - -#include // for uint64_t -#include // for operator<<, basic_ostream, endl -#include -#include // for pair - -SingleStreamingInputv2::SingleStreamingInputv2(const std::string &name) - : Fun4AllBase(name) -{ -} - -SingleStreamingInputv2::~SingleStreamingInputv2() -{ - delete m_EventIterator; -} - -int SingleStreamingInputv2::fileopen(const std::string &filenam) -{ - std::cout << PHWHERE << "trying to open " << filenam << std::endl; - if (IsOpen()) - { - std::cout << "Closing currently open file " - << FileName() - << " and opening " << filenam << std::endl; - fileclose(); - } - FileName(filenam); - FROG frog; - std::string fname = frog.location(FileName()); - if (Verbosity() > 0) - { - std::cout << Name() << ": opening file " << FileName() << std::endl; - } - int status = 0; - m_EventIterator = new fileEventiterator(fname.c_str(), status); - m_EventsThisFile = 0; - if (status) - { - delete m_EventIterator; - m_EventIterator = nullptr; - std::cout << PHWHERE << Name() << ": could not open file " << fname << std::endl; - return -1; - } - IsOpen(1); - AddToFileOpened(fname); // add file to the list of files which were opened - return 0; -} - -int SingleStreamingInputv2::fileclose() -{ - if (!IsOpen()) - { - std::cout << Name() << ": fileclose: No Input file open" << std::endl; - return -1; - } - delete m_EventIterator; - m_EventIterator = nullptr; - IsOpen(0); - // if we have a file list, move next entry to top of the list - // or repeat the same entry again - UpdateFileList(); - return 0; -} - -void SingleStreamingInputv2::Print(const std::string &what) const -{ - if (what == "ALL" || what == "FEE") - { - for (const auto &bcliter : m_BeamClockFEE) - { - std::cout << "Beam clock 0x" << std::hex << bcliter.first << std::dec << std::endl; - for (auto feeiter : bcliter.second) - { - std::cout << "FEM: " << feeiter << std::endl; - } - } - } - if (what == "ALL" || what == "FEEBCLK") - { - for (auto bcliter : m_FEEBclkMap) - { - std::cout << "FEE" << bcliter.first << " bclk: 0x" - << std::hex << bcliter.second << std::dec << std::endl; - } - } - if (what == "ALL" || what == "STACK") - { - for (auto iter : m_BclkStack) - { - std::cout << "stacked bclk: 0x" << std::hex << iter << std::dec << std::endl; - } - } -} - -bool SingleStreamingInputv2::CheckPoolDepth(const uint64_t bclk) -{ - // if (m_FEEBclkMap.size() < 10) - // { - // std::cout << "not all FEEs in map: " << m_FEEBclkMap.size() << std::endl; - // return true; - // } - for (auto iter : m_FEEBclkMap) - { - if (Verbosity() > 2) - { - std::cout << "my bclk 0x" << std::hex << iter.second - << " req: 0x" << bclk << std::dec << std::endl; - } - if (iter.second < bclk) - { - if (Verbosity() > 1) - { - std::cout << "FEE " << iter.first << " beamclock 0x" << std::hex << iter.second - << " smaller than req bclk: 0x" << bclk << std::dec << std::endl; - } - return true; - } - } - return false; -} - -void SingleStreamingInputv2::ClearCurrentEvent() -{ - // called interactively, to get rid of the current event - uint64_t currentbclk = *m_BclkStack.begin(); - std::cout << "clearing bclk 0x" << std::hex << currentbclk << std::dec << std::endl; - CleanupUsedPackets(currentbclk); - m_BclkStack.erase(currentbclk); - m_BeamClockFEE.erase(currentbclk); - return; -} diff --git a/offline/framework/rawbcolumi/SingleStreamingInputv2.h b/offline/framework/rawbcolumi/SingleStreamingInputv2.h deleted file mode 100644 index 184fe6923f..0000000000 --- a/offline/framework/rawbcolumi/SingleStreamingInputv2.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef RAWBCOLUMI_SINGLESTREAMINGINPUTV2_H -#define RAWBCOLUMI_SINGLESTREAMINGINPUTV2_H - -#include -#include - -#include // for uint64_t -#include -#include -#include - -class Eventiterator; -class Fun4AllEvtInputPoolManager; -class Fun4AllStreamingInputManager; -class Fun4AllStreamingLumiCountingInputManager; -class PHCompositeNode; - -class SingleStreamingInputv2 : public Fun4AllBase, public InputFileHandler -{ - public: - explicit SingleStreamingInputv2(const std::string &name); - ~SingleStreamingInputv2() override; - virtual Eventiterator *GetEventIterator() { return m_EventIterator; } - virtual void FillPool(const uint64_t) { return; } - virtual void FillPool(const unsigned int = 1) { return; } - virtual void RunNumber(const int runno) { m_RunNumber = runno; } - virtual int RunNumber() const { return m_RunNumber; } - virtual int fileopen(const std::string &filename) override; - virtual int fileclose() override; - virtual int AllDone() const { return m_AllDone; } - virtual void AllDone(const int i) { m_AllDone = i; } - virtual void EventNumberOffset(const int i) { m_EventNumberOffset = i; } - virtual void Print(const std::string &what = "ALL") const override; - virtual void CleanupUsedPackets(const uint64_t) { return; } - virtual bool CheckPoolDepth(const uint64_t bclk); - virtual void ClearCurrentEvent(); - virtual Eventiterator *GetEventiterator() const { return m_EventIterator; } - virtual Fun4AllStreamingInputManager *StreamingInputManager() { return m_StreamingInputMgr; } - virtual void StreamingInputManager(Fun4AllStreamingInputManager *in) { m_StreamingInputMgr = in; } - // virtual void StreamingInputManager(Fun4AllStreamingLumiCountingInputManager *in) { m_StreamingLumiInputMgr = in; } - virtual Fun4AllStreamingLumiCountingInputManager *StreamingLumiInputManager() { return m_StreamingLumiInputMgr; } - virtual void StreamingLumiInputManager(Fun4AllStreamingLumiCountingInputManager *in) { m_StreamingLumiInputMgr = in; } - virtual void CreateDSTNode(PHCompositeNode *) { return; } - virtual void ConfigureStreamingInputManager() { return; } - virtual void SubsystemEnum(const int id) { m_SubsystemEnum = id; } - virtual int SubsystemEnum() const { return m_SubsystemEnum; } - void MaxBclkDiff(uint64_t ui) { m_MaxBclkSpread = ui; } - uint64_t MaxBclkDiff() const { return m_MaxBclkSpread; } - virtual const std::map> &BclkStackMap() const { return m_BclkStackPacketMap; } - virtual const std::set &BclkStack() const { return m_BclkStack; } - virtual const std::map> &BeamClockFEE() const { return m_BeamClockFEE; } - void setHitContainerName(const std::string &name) { m_rawHitContainerName = name; } - const std::string &getHitContainerName() const { return m_rawHitContainerName; } - const std::map> &getFeeGTML1BCOMap() const { return m_FeeGTML1BCOMap; } - - void clearPacketBClkStackMap(const int &packetid, const uint64_t &bclk) - { - std::set to_erase; - auto set = m_BclkStackPacketMap.find(packetid)->second; - for (auto &bclk_to_erase : set) - { - if (bclk_to_erase <= bclk) - { - to_erase.insert(bclk_to_erase); - } - } - for (auto &bclk_to_erase : to_erase) - { - set.erase(bclk_to_erase); - } - } - - void clearFeeGTML1BCOMap(const uint64_t &bclk) - { - std::set toerase; - for (auto &[key, set] : m_FeeGTML1BCOMap) - { - for (auto &ll1bclk : set) - { - if (ll1bclk <= bclk) - { - // to avoid invalid reads - toerase.insert(ll1bclk); - } - } - for (auto &bclk_to_erase : toerase) - { - set.erase(bclk_to_erase); - } - } - } - - protected: - std::map> m_BclkStackPacketMap; - std::map> m_FeeGTML1BCOMap; - std::string m_rawHitContainerName = ""; - - private: - Eventiterator *m_EventIterator{nullptr}; - // Fun4AllEvtInputPoolManager *m_InputMgr {nullptr}; - Fun4AllStreamingInputManager *m_StreamingInputMgr{nullptr}; - Fun4AllStreamingLumiCountingInputManager *m_StreamingLumiInputMgr{nullptr}; - uint64_t m_MaxBclkSpread{1000000}; - unsigned int m_EventNumberOffset{1}; // packet event counters start at 0 but we start with event number 1 - int m_RunNumber{0}; - int m_EventsThisFile{0}; - int m_AllDone{0}; - int m_SubsystemEnum{0}; - std::map> m_BeamClockFEE; - std::map m_FEEBclkMap; - std::set m_BclkStack; -}; - -#endif diff --git a/offline/packages/CaloBase/Makefile.am b/offline/packages/CaloBase/Makefile.am index 124c62cb55..de70f081e1 100644 --- a/offline/packages/CaloBase/Makefile.am +++ b/offline/packages/CaloBase/Makefile.am @@ -59,15 +59,19 @@ pkginclude_HEADERS = \ TowerInfov2.h \ TowerInfov3.h \ TowerInfov4.h \ + TowerInfov5.h \ TowerInfoSimv1.h \ TowerInfoSimv2.h \ + TowerInfoSimv3.h \ TowerInfoContainer.h \ TowerInfoContainerv1.h \ TowerInfoContainerv2.h \ TowerInfoContainerv3.h \ TowerInfoContainerv4.h \ + TowerInfoContainerv5.h \ TowerInfoContainerSimv1.h \ - TowerInfoContainerSimv2.h + TowerInfoContainerSimv2.h \ + TowerInfoContainerSimv3.h ROOTDICTS = \ PhotonClusterv1_Dict.cc \ @@ -94,15 +98,19 @@ ROOTDICTS = \ TowerInfov2_Dict.cc \ TowerInfov3_Dict.cc \ TowerInfov4_Dict.cc \ + TowerInfov5_Dict.cc \ TowerInfoSimv1_Dict.cc \ TowerInfoSimv2_Dict.cc \ + TowerInfoSimv3_Dict.cc \ TowerInfoContainer_Dict.cc \ TowerInfoContainerv1_Dict.cc \ TowerInfoContainerv2_Dict.cc \ TowerInfoContainerv3_Dict.cc \ TowerInfoContainerv4_Dict.cc \ + TowerInfoContainerv5_Dict.cc \ TowerInfoContainerSimv1_Dict.cc \ - TowerInfoContainerSimv2_Dict.cc + TowerInfoContainerSimv2_Dict.cc \ + TowerInfoContainerSimv3_Dict.cc pcmdir = $(libdir) # more elegant way to create pcm files (without listing them) @@ -133,16 +141,20 @@ libcalo_io_la_SOURCES = \ TowerInfov2.cc \ TowerInfov3.cc \ TowerInfov4.cc \ + TowerInfov5.cc \ TowerInfoSimv1.cc \ TowerInfoSimv2.cc \ + TowerInfoSimv3.cc \ TowerInfoDefs.cc \ TowerInfoContainer.cc \ TowerInfoContainerv1.cc \ TowerInfoContainerv2.cc \ TowerInfoContainerv3.cc \ TowerInfoContainerv4.cc \ + TowerInfoContainerv5.cc \ TowerInfoContainerSimv1.cc \ - TowerInfoContainerSimv2.cc + TowerInfoContainerSimv2.cc \ + TowerInfoContainerSimv3.cc endif # Rule for generating table CINT dictionaries. diff --git a/offline/packages/CaloBase/PhotonClusterv1.cc b/offline/packages/CaloBase/PhotonClusterv1.cc index 19879e25ed..66984ad98a 100644 --- a/offline/packages/CaloBase/PhotonClusterv1.cc +++ b/offline/packages/CaloBase/PhotonClusterv1.cc @@ -1,5 +1,5 @@ #include "PhotonClusterv1.h" -#include + #include #include #include @@ -29,9 +29,6 @@ void PhotonClusterv1::reset_photon_properties() return; } - - - void PhotonClusterv1::identify(std::ostream& os) const { // @warning: Call base class identify first to maintain output order @@ -65,7 +62,6 @@ bool PhotonClusterv1::pass_photon_cuts() const // if (it_core->second > 0.3f) return false; //} - // @warning: Add more sophisticated photon ID cuts as needed // Consider using cluster properties like get_ecore(), get_prob(), etc. @@ -80,4 +76,4 @@ float PhotonClusterv1::get_shower_shape_parameter(const std::string& name) const return it->second; } return std::numeric_limits::quiet_NaN(); -} \ No newline at end of file +} diff --git a/offline/packages/CaloBase/PhotonClusterv1.h b/offline/packages/CaloBase/PhotonClusterv1.h index 4561805c59..1914fefea4 100644 --- a/offline/packages/CaloBase/PhotonClusterv1.h +++ b/offline/packages/CaloBase/PhotonClusterv1.h @@ -3,6 +3,7 @@ #include "RawClusterv1.h" +#include #include #include @@ -14,8 +15,7 @@ class PhotonClusterv1 : public RawClusterv1 ~PhotonClusterv1() override = default; - - explicit PhotonClusterv1(const RawCluster & rc); + explicit PhotonClusterv1(const RawCluster& rc); //! Copy constructor PhotonClusterv1(const PhotonClusterv1& other) = default; @@ -29,7 +29,6 @@ class PhotonClusterv1 : public RawClusterv1 bool pass_photon_cuts() const override; void identify_photon(std::ostream& os = std::cout) const override; - void reset_photon_properties() override; //! @name PhotonCluster Setter Implementations @@ -45,8 +44,8 @@ class PhotonClusterv1 : public RawClusterv1 private: //! @warning Photon-specific data members - memory managed only in this derived class // Photon energy and isolation energy now sourced from RawCluster - //float m_conversion_prob{0.0f}; //!< Probability of photon conversion - //bool m_is_converted{false}; //!< Conversion flag + // float m_conversion_prob{0.0f}; //!< Probability of photon conversion + // bool m_is_converted{false}; //!< Conversion flag std::map m_shower_shapes; //!< Named shower shape parameters ClassDefOverride(PhotonClusterv1, 1) //!< ROOT dictionary generation diff --git a/offline/packages/CaloBase/TowerInfo.h b/offline/packages/CaloBase/TowerInfo.h index 821da289d7..fbcce0b0bf 100644 --- a/offline/packages/CaloBase/TowerInfo.h +++ b/offline/packages/CaloBase/TowerInfo.h @@ -30,8 +30,8 @@ class TowerInfo : public PHObject virtual float get_pedestal() { return std::numeric_limits::quiet_NaN(); } virtual void set_isHot(bool /*isHot*/) { return; } virtual bool get_isHot() const { return false; } - virtual void set_isBadTime(bool /*isBadTime*/) { return; } - virtual bool get_isBadTime() const { return false; } + virtual void set_FitStatus(bool /*fitstatus*/) { return; } + virtual bool get_FitStatus() const { return false; } virtual void set_isBadChi2(bool /*isBadChi2*/) { return; } virtual bool get_isBadChi2() const { return false; } virtual void set_isNotInstr(bool /*isNotInstr*/) { return; } @@ -74,9 +74,11 @@ class TowerInfo : public PHObject } virtual void add_edep(const PHG4HitDefs::keytype /*g4hitid*/, const float /*edep*/) { return; } virtual void add_shower_edep(const int /*showerid*/, const float /*edep*/) { return; } + // methods in v5 and simv3 + virtual void set_nsample(int /*nsample*/) { return; } private: - ClassDefOverride(TowerInfo, 1); + ClassDefOverride(TowerInfo, 0); }; #endif diff --git a/offline/packages/CaloBase/TowerInfoContainer.cc b/offline/packages/CaloBase/TowerInfoContainer.cc index 45f25d6fae..af506f53b7 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.cc +++ b/offline/packages/CaloBase/TowerInfoContainer.cc @@ -1,8 +1,6 @@ #include "TowerInfoContainer.h" #include "TowerInfoDefs.h" -#include - void TowerInfoContainer::identify(std::ostream& os) const { os << "TowerInfoContainer Base Class " << std::endl; @@ -77,3 +75,82 @@ unsigned int TowerInfoContainer::getTowerEtaBin(unsigned int key) unsigned int etabin = TowerInfoDefs::getCaloTowerEtaBin(key); return etabin; } + +unsigned int TowerInfoContainer::encode_key(unsigned int towerIndex) +{ + unsigned int key = 0; + if (get_detectorid() == DETECTOR::EMCAL) + { + key = TowerInfoContainer::encode_emcal(towerIndex); + } + else if (get_detectorid() == DETECTOR::HCAL) + { + key = TowerInfoContainer::encode_hcal(towerIndex); + } + else if (get_detectorid() == DETECTOR::SEPD) + { + key = TowerInfoContainer::encode_epd(towerIndex); + } + else if (get_detectorid() == DETECTOR::MBD) + { + key = TowerInfoContainer::encode_mbd(towerIndex); + } + else if (get_detectorid() == DETECTOR::ZDC) + { + key = TowerInfoContainer::encode_zdc(towerIndex); + } + return key; +} + +unsigned int TowerInfoContainer::decode_key(unsigned int tower_key) +{ + unsigned int index = 0; + + if (get_detectorid() == DETECTOR::EMCAL) + { + index = TowerInfoContainer::decode_emcal(tower_key); + } + else if (get_detectorid() == DETECTOR::HCAL) + { + index = TowerInfoContainer::decode_hcal(tower_key); + } + else if (get_detectorid() == DETECTOR::SEPD) + { + index = TowerInfoContainer::decode_epd(tower_key); + } + else if (get_detectorid() == DETECTOR::MBD) + { + index = TowerInfoContainer::decode_mbd(tower_key); + } + else if (get_detectorid() == DETECTOR::ZDC) + { + index = TowerInfoContainer::decode_zdc(tower_key); + } + return index; +} + +int TowerInfoContainer::get_channels(DETECTOR detec) +{ + int nchannels = 744; + if (detec == DETECTOR::SEPD) + { + nchannels = 744; + } + else if (detec == DETECTOR::EMCAL) + { + nchannels = 24576; + } + else if (detec == DETECTOR::HCAL) + { + nchannels = 1536; + } + else if (detec == DETECTOR::MBD) + { + nchannels = 256; + } + else if (detec == DETECTOR::ZDC) + { + nchannels = 52; + } + return nchannels; +} diff --git a/offline/packages/CaloBase/TowerInfoContainer.h b/offline/packages/CaloBase/TowerInfoContainer.h index 63b763172c..5432528474 100644 --- a/offline/packages/CaloBase/TowerInfoContainer.h +++ b/offline/packages/CaloBase/TowerInfoContainer.h @@ -5,7 +5,6 @@ #include #include -#include #include class TowerInfo; @@ -36,8 +35,8 @@ class TowerInfoContainer : public PHObject virtual TowerInfo* get_tower_at_key(int /*key*/) { return nullptr; } virtual size_t size() const { return 0; } - virtual unsigned int encode_key(unsigned int /*towerIndex*/) { return std::numeric_limits::max(); } - virtual unsigned int decode_key(unsigned int /*towerIndex*/) { return std::numeric_limits::max(); } + virtual unsigned int encode_key(unsigned int towerIndex); + virtual unsigned int decode_key(unsigned int tower_key); virtual unsigned int encode_epd(unsigned int /*towerIndex*/); virtual unsigned int encode_hcal(unsigned int /*towerIndex*/); @@ -55,9 +54,10 @@ class TowerInfoContainer : public PHObject virtual unsigned int getTowerEtaBin(unsigned int /*towerIndex*/); virtual DETECTOR get_detectorid() const { return DETECTOR_INVALID; } + virtual int get_channels(DETECTOR detec); private: - ClassDefOverride(TowerInfoContainer, 1); + ClassDefOverride(TowerInfoContainer, 0); }; #endif diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc index 0c00f1b1b8..ba7ba0a661 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv1.cc @@ -2,36 +2,15 @@ #include "TowerInfoSimv1.h" #include +#include -#include +#include TowerInfoContainerSimv1::TowerInfoContainerSimv1(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfoSimv1", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerSimv1"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,13 +24,11 @@ TowerInfoContainerSimv1::TowerInfoContainerSimv1(const TowerInfoContainerSimv1& , _clones(new TClonesArray("TowerInfoSimv1", source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerSimv1"); for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } @@ -71,23 +48,19 @@ void TowerInfoContainerSimv1::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); + TowerInfo* twr = (TowerInfoSimv1*) _clones->UncheckedAt(i); - if (obj == nullptr) + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +74,3 @@ TowerInfoSimv1* TowerInfoContainerSimv1::get_tower_at_key(int pos) int index = decode_key(pos); return (TowerInfoSimv1*) _clones->At(index); } - -unsigned int TowerInfoContainerSimv1::encode_key(unsigned int towerIndex) -{ - int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerSimv1::decode_key(unsigned int tower_key) -{ - int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv1.h b/offline/packages/CaloBase/TowerInfoContainerSimv1.h index 0053a5c1c5..0df3f029d5 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv1.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv1.h @@ -6,6 +6,9 @@ #include +#include // for size_t +#include + class PHObject; class TowerInfoContainerSimv1 : public TowerInfoContainer @@ -26,15 +29,12 @@ class TowerInfoContainerSimv1 : public TowerInfoContainer TowerInfoSimv1 *get_tower_at_channel(int pos) override; TowerInfoSimv1 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones = nullptr; - DETECTOR _detector = DETECTOR_INVALID; + TClonesArray *_clones{nullptr}; + DETECTOR _detector{DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerSimv1, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc index 479d21d68a..e9eeff969c 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerSimv2.cc @@ -2,36 +2,15 @@ #include "TowerInfoSimv2.h" #include +#include -#include +#include TowerInfoContainerSimv2::TowerInfoContainerSimv2(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfoSimv2", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerSimv2"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,13 +24,11 @@ TowerInfoContainerSimv2::TowerInfoContainerSimv2(const TowerInfoContainerSimv2& , _clones(new TClonesArray("TowerInfoSimv2", (int) source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerSimv2"); for (int i = 0; i < (int) source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } @@ -71,23 +48,19 @@ void TowerInfoContainerSimv2::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); + TowerInfo* twr = (TowerInfoSimv2*) _clones->UncheckedAt(i); - if (obj == nullptr) + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +74,3 @@ TowerInfoSimv2* TowerInfoContainerSimv2::get_tower_at_key(int pos) int index = (int) decode_key(pos); return (TowerInfoSimv2*) _clones->At(index); } - -unsigned int TowerInfoContainerSimv2::encode_key(unsigned int towerIndex) -{ - unsigned int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerSimv2::decode_key(unsigned int tower_key) -{ - unsigned int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv2.h b/offline/packages/CaloBase/TowerInfoContainerSimv2.h index c5a467b3be..13849b9537 100644 --- a/offline/packages/CaloBase/TowerInfoContainerSimv2.h +++ b/offline/packages/CaloBase/TowerInfoContainerSimv2.h @@ -6,6 +6,9 @@ #include +#include // for size_t +#include + class PHObject; class TowerInfoContainerSimv2 : public TowerInfoContainer @@ -26,9 +29,6 @@ class TowerInfoContainerSimv2 : public TowerInfoContainer TowerInfoSimv2 *get_tower_at_channel(int pos) override; TowerInfoSimv2 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.cc b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc new file mode 100644 index 0000000000..fd1b4e9757 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.cc @@ -0,0 +1,78 @@ +#include "TowerInfoContainerSimv3.h" +#include "TowerInfoSimv3.h" + +#include +#include + +#include + +TowerInfoContainerSimv3::TowerInfoContainerSimv3(DETECTOR detec) + : _detector(detec) +{ + int nchannels = get_channels(detec); + _clones = new TClonesArray("TowerInfoSimv3", nchannels); + for (int i = 0; i < nchannels; ++i) + { + // as tower numbers are fixed per event + // construct towers once per run, and clear the towers for first use + _clones->ConstructedAt(i, "C"); + } +} + +TowerInfoContainerSimv3::TowerInfoContainerSimv3(const TowerInfoContainerSimv3& source) + : TowerInfoContainer(source) + , _clones(new TClonesArray("TowerInfoSimv3", (int) source.size())) + , _detector(source.get_detectorid()) +{ + for (int i = 0; i < (int) source.size(); ++i) + { + // as tower numbers are fixed per event + // construct towers once per run, and clear the towers for first use + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); + } +} + +TowerInfoContainerSimv3::~TowerInfoContainerSimv3() +{ + delete _clones; +} + +void TowerInfoContainerSimv3::identify(std::ostream& os) const +{ + os << "TowerInfoContainerSimv3 of size " << size() << std::endl; +} + +void TowerInfoContainerSimv3::Reset() +{ + // clear content of towers in the container for the next event + + for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) + { + TowerInfo* twr = (TowerInfoSimv3*) _clones->UncheckedAt(i); + + if (twr == nullptr) + { + std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" + << " _clones->GetSize() = " << _clones->GetSize() + << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() + << " i = " << i << std::endl; + _clones->Print(); + gSystem->Exit(1); + exit(1); + } + twr->Reset(); + } +} + +TowerInfoSimv3* TowerInfoContainerSimv3::get_tower_at_channel(int pos) +{ + return (TowerInfoSimv3*) _clones->At(pos); +} + +TowerInfoSimv3* TowerInfoContainerSimv3::get_tower_at_key(int pos) +{ + int index = (int) decode_key(pos); + return (TowerInfoSimv3*) _clones->At(index); +} diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3.h b/offline/packages/CaloBase/TowerInfoContainerSimv3.h new file mode 100644 index 0000000000..4e40d23281 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3.h @@ -0,0 +1,44 @@ +#ifndef TOWERINFOCONTAINERSIMV3_H +#define TOWERINFOCONTAINERSIMV3_H + +#include "TowerInfoContainer.h" +#include "TowerInfoSimv3.h" + +#include + +#include // for size_t +#include + +class PHObject; + +class TowerInfoContainerSimv3 : public TowerInfoContainer +{ + public: + TowerInfoContainerSimv3(DETECTOR detec); + + // default constructor for ROOT IO + TowerInfoContainerSimv3() = default; + PHObject *CloneMe() const override { return new TowerInfoContainerSimv3(*this); } + TowerInfoContainerSimv3(const TowerInfoContainerSimv3 &); + TowerInfoContainerSimv3 &operator=(const TowerInfoContainerSimv3 &) = delete; + + ~TowerInfoContainerSimv3() override; + + void identify(std::ostream &os = std::cout) const override; + + void Reset() override; + TowerInfoSimv3 *get_tower_at_channel(int pos) override; + TowerInfoSimv3 *get_tower_at_key(int pos) override; + + size_t size() const override { return _clones->GetEntries(); } + DETECTOR get_detectorid() const override { return _detector; } + + protected: + TClonesArray *_clones = nullptr; + DETECTOR _detector = DETECTOR_INVALID; + + private: + ClassDefOverride(TowerInfoContainerSimv3, 1); +}; + +#endif diff --git a/offline/packages/CaloBase/TowerInfoContainerSimv3LinkDef.h b/offline/packages/CaloBase/TowerInfoContainerSimv3LinkDef.h new file mode 100644 index 0000000000..17bb2e4780 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerSimv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TowerInfoContainerSimv3 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.cc b/offline/packages/CaloBase/TowerInfoContainerv1.cc index bfddca6e40..9b7755bc51 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv1.cc @@ -2,36 +2,13 @@ #include "TowerInfov1.h" #include - -#include +#include TowerInfoContainerv1::TowerInfoContainerv1(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfov1", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv1"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -50,13 +27,11 @@ TowerInfoContainerv1::TowerInfoContainerv1(const TowerInfoContainerv1& source) , _clones(new TClonesArray("TowerInfov1", source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv1"); for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } @@ -71,23 +46,19 @@ void TowerInfoContainerv1::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); + TowerInfo* twr = (TowerInfov1*) _clones->UncheckedAt(i); - if (obj == nullptr) + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +72,3 @@ TowerInfov1* TowerInfoContainerv1::get_tower_at_key(int pos) int index = decode_key(pos); return (TowerInfov1*) _clones->At(index); } - -unsigned int TowerInfoContainerv1::encode_key(unsigned int towerIndex) -{ - int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainerv1::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainerv1::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainerv1::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainerv1::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainerv1::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerv1::decode_key(unsigned int tower_key) -{ - int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainerv1::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainerv1::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainerv1::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainerv1::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainerv1::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerv1.h b/offline/packages/CaloBase/TowerInfoContainerv1.h index 7267482c18..795f06ba0e 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv1.h +++ b/offline/packages/CaloBase/TowerInfoContainerv1.h @@ -29,15 +29,12 @@ class TowerInfoContainerv1 : public TowerInfoContainer TowerInfov1 *get_tower_at_channel(int pos) override; TowerInfov1 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones = nullptr; - DETECTOR _detector = DETECTOR_INVALID; + TClonesArray *_clones{nullptr}; + DETECTOR _detector{DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerv1, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerv2.cc b/offline/packages/CaloBase/TowerInfoContainerv2.cc index 94d3378945..dfedb29906 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv2.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv2.cc @@ -2,36 +2,15 @@ #include "TowerInfov2.h" #include +#include -#include +#include TowerInfoContainerv2::TowerInfoContainerv2(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfov2", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv2"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,13 +24,11 @@ TowerInfoContainerv2::TowerInfoContainerv2(const TowerInfoContainerv2& source) , _clones(new TClonesArray("TowerInfov2", source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv2"); for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } @@ -71,23 +48,19 @@ void TowerInfoContainerv2::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); + TowerInfo* twr = (TowerInfov2*) _clones->UncheckedAt(i); - if (obj == nullptr) + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +74,3 @@ TowerInfov2* TowerInfoContainerv2::get_tower_at_key(int pos) int index = decode_key(pos); return (TowerInfov2*) _clones->At(index); } - -unsigned int TowerInfoContainerv2::encode_key(unsigned int towerIndex) -{ - int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerv2::decode_key(unsigned int tower_key) -{ - int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerv2.h b/offline/packages/CaloBase/TowerInfoContainerv2.h index 1c39159828..61fcaa240e 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv2.h +++ b/offline/packages/CaloBase/TowerInfoContainerv2.h @@ -30,9 +30,6 @@ class TowerInfoContainerv2 : public TowerInfoContainer TowerInfov2 *get_tower_at_channel(int pos) override; TowerInfov2 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } diff --git a/offline/packages/CaloBase/TowerInfoContainerv3.cc b/offline/packages/CaloBase/TowerInfoContainerv3.cc index 5397eecbb6..921e474871 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv3.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv3.cc @@ -2,36 +2,15 @@ #include "TowerInfov3.h" #include +#include -#include +#include TowerInfoContainerv3::TowerInfoContainerv3(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfov3", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv3"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,13 +24,11 @@ TowerInfoContainerv3::TowerInfoContainerv3(const TowerInfoContainerv3& source) , _clones(new TClonesArray("TowerInfov3", source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv3"); for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } @@ -71,23 +48,19 @@ void TowerInfoContainerv3::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); + TowerInfo* twr = (TowerInfov3*) _clones->UncheckedAt(i); - if (obj == nullptr) + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +74,3 @@ TowerInfov3* TowerInfoContainerv3::get_tower_at_key(int pos) int index = decode_key(pos); return (TowerInfov3*) _clones->At(index); } - -unsigned int TowerInfoContainerv3::encode_key(unsigned int towerIndex) -{ - int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerv3::decode_key(unsigned int tower_key) -{ - int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerv3.h b/offline/packages/CaloBase/TowerInfoContainerv3.h index c8d89670cd..aeb8388f81 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv3.h +++ b/offline/packages/CaloBase/TowerInfoContainerv3.h @@ -29,15 +29,12 @@ class TowerInfoContainerv3 : public TowerInfoContainer TowerInfov3 *get_tower_at_channel(int pos) override; TowerInfov3 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones = nullptr; - DETECTOR _detector = DETECTOR_INVALID; + TClonesArray *_clones{nullptr}; + DETECTOR _detector{DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerv3, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerv4.cc b/offline/packages/CaloBase/TowerInfoContainerv4.cc index b124ba27c7..ffa93bf98c 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv4.cc +++ b/offline/packages/CaloBase/TowerInfoContainerv4.cc @@ -2,36 +2,15 @@ #include "TowerInfov4.h" #include +#include -#include +#include TowerInfoContainerv4::TowerInfoContainerv4(DETECTOR detec) : _detector(detec) { - int nchannels = 744; - if (_detector == DETECTOR::SEPD) - { - nchannels = 744; - } - else if (_detector == DETECTOR::EMCAL) - { - nchannels = 24576; - } - else if (_detector == DETECTOR::HCAL) - { - nchannels = 1536; - } - else if (_detector == DETECTOR::MBD) - { - nchannels = 256; - } - else if (_detector == DETECTOR::ZDC) - { - nchannels = 52; - } + int nchannels = get_channels(detec); _clones = new TClonesArray("TowerInfov4", nchannels); - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv4"); for (int i = 0; i < nchannels; ++i) { // as tower numbers are fixed per event @@ -45,13 +24,11 @@ TowerInfoContainerv4::TowerInfoContainerv4(const TowerInfoContainerv4& source) , _clones(new TClonesArray("TowerInfov4", source.size())) , _detector(source.get_detectorid()) { - _clones->SetOwner(); - _clones->SetName("TowerInfoContainerv4"); for (unsigned int i = 0; i < source.size(); ++i) { - // as tower numbers are fixed per event - // construct towers once per run, and clear the towers for first use - _clones->ConstructedAt(i, "C"); + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); } } @@ -71,23 +48,19 @@ void TowerInfoContainerv4::Reset() for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) { - TObject* obj = _clones->UncheckedAt(i); + TowerInfo* twr = (TowerInfov4*) _clones->UncheckedAt(i); - if (obj == nullptr) + if (twr == nullptr) { std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" << " _clones->GetSize() = " << _clones->GetSize() << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() << " i = " << i << std::endl; _clones->Print(); + gSystem->Exit(1); + exit(1); } - - assert(obj); - // same as TClonesArray::Clear() but only clear but not to erase all towers - obj->Clear(); - obj->ResetBit(kHasUUID); - obj->ResetBit(kIsReferenced); - obj->SetUniqueID(0); + twr->Reset(); } } @@ -101,56 +74,3 @@ TowerInfov4* TowerInfoContainerv4::get_tower_at_key(int pos) int index = decode_key(pos); return (TowerInfov4*) _clones->At(index); } - -unsigned int TowerInfoContainerv4::encode_key(unsigned int towerIndex) -{ - int key = 0; - if (_detector == DETECTOR::EMCAL) - { - key = TowerInfoContainer::encode_emcal(towerIndex); - } - else if (_detector == DETECTOR::HCAL) - { - key = TowerInfoContainer::encode_hcal(towerIndex); - } - else if (_detector == DETECTOR::SEPD) - { - key = TowerInfoContainer::encode_epd(towerIndex); - } - else if (_detector == DETECTOR::MBD) - { - key = TowerInfoContainer::encode_mbd(towerIndex); - } - else if (_detector == DETECTOR::ZDC) - { - key = TowerInfoContainer::encode_zdc(towerIndex); - } - return key; -} - -unsigned int TowerInfoContainerv4::decode_key(unsigned int tower_key) -{ - int index = 0; - - if (_detector == DETECTOR::EMCAL) - { - index = TowerInfoContainer::decode_emcal(tower_key); - } - else if (_detector == DETECTOR::HCAL) - { - index = TowerInfoContainer::decode_hcal(tower_key); - } - else if (_detector == DETECTOR::SEPD) - { - index = TowerInfoContainer::decode_epd(tower_key); - } - else if (_detector == DETECTOR::MBD) - { - index = TowerInfoContainer::decode_mbd(tower_key); - } - else if (_detector == DETECTOR::ZDC) - { - index = TowerInfoContainer::decode_zdc(tower_key); - } - return index; -} diff --git a/offline/packages/CaloBase/TowerInfoContainerv4.h b/offline/packages/CaloBase/TowerInfoContainerv4.h index df7af1b974..3d26d258f8 100644 --- a/offline/packages/CaloBase/TowerInfoContainerv4.h +++ b/offline/packages/CaloBase/TowerInfoContainerv4.h @@ -30,15 +30,12 @@ class TowerInfoContainerv4 : public TowerInfoContainer TowerInfov4 *get_tower_at_channel(int pos) override; TowerInfov4 *get_tower_at_key(int pos) override; - unsigned int encode_key(unsigned int towerIndex) override; - unsigned int decode_key(unsigned int tower_key) override; - size_t size() const override { return _clones->GetEntries(); } DETECTOR get_detectorid() const override { return _detector; } protected: - TClonesArray *_clones = nullptr; - DETECTOR _detector = DETECTOR_INVALID; + TClonesArray *_clones{nullptr}; + DETECTOR _detector{DETECTOR_INVALID}; private: ClassDefOverride(TowerInfoContainerv4, 1); diff --git a/offline/packages/CaloBase/TowerInfoContainerv5.cc b/offline/packages/CaloBase/TowerInfoContainerv5.cc new file mode 100644 index 0000000000..010086b037 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerv5.cc @@ -0,0 +1,76 @@ +#include "TowerInfoContainerv5.h" +#include "TowerInfov5.h" + +#include +#include + +#include + +TowerInfoContainerv5::TowerInfoContainerv5(DETECTOR detec) + : _detector(detec) +{ + int nchannels = get_channels(detec); + _clones = new TClonesArray("TowerInfov5", nchannels); + for (int i = 0; i < nchannels; ++i) + { + // as tower numbers are fixed per event + // construct towers once per run, and clear the towers for first use + _clones->ConstructedAt(i, "C"); + } +} + +TowerInfoContainerv5::TowerInfoContainerv5(const TowerInfoContainerv5& source) + : TowerInfoContainer(source) + , _clones(new TClonesArray("TowerInfov5", source.size())) + , _detector(source.get_detectorid()) +{ + for (unsigned int i = 0; i < source.size(); ++i) + { + auto* tower = static_cast(_clones->ConstructedAt(i, "C")); + auto* source_tower = static_cast(source._clones->UncheckedAt(i)); + tower->copy_tower(source_tower); + } +} + +TowerInfoContainerv5::~TowerInfoContainerv5() +{ + delete _clones; +} + +void TowerInfoContainerv5::identify(std::ostream& os) const +{ + os << "TowerInfoContainerv5 of size " << size() << std::endl; +} + +void TowerInfoContainerv5::Reset() +{ + // clear content of towers in the container for the next event + + for (Int_t i = 0; i < _clones->GetEntriesFast(); ++i) + { + TowerInfo* twr = (TowerInfov5*) _clones->UncheckedAt(i); + + if (twr == nullptr) + { + std::cout << __PRETTY_FUNCTION__ << " Fatal access error:" + << " _clones->GetSize() = " << _clones->GetSize() + << " _clones->GetEntriesFast() = " << _clones->GetEntriesFast() + << " i = " << i << std::endl; + _clones->Print(); + gSystem->Exit(1); + exit(1); + } + twr->Reset(); + } +} + +TowerInfov5* TowerInfoContainerv5::get_tower_at_channel(int pos) +{ + return (TowerInfov5*) _clones->At(pos); +} + +TowerInfov5* TowerInfoContainerv5::get_tower_at_key(int pos) +{ + int index = decode_key(pos); + return (TowerInfov5*) _clones->At(index); +} diff --git a/offline/packages/CaloBase/TowerInfoContainerv5.h b/offline/packages/CaloBase/TowerInfoContainerv5.h new file mode 100644 index 0000000000..3bfbf77f60 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerv5.h @@ -0,0 +1,43 @@ +#ifndef TOWERINFOCONTAINERV5_H +#define TOWERINFOCONTAINERV5_H + +#include "TowerInfoContainer.h" +#include "TowerInfov5.h" + +#include + +#include +#include + +class PHObject; + +class TowerInfoContainerv5 : public TowerInfoContainer +{ + public: + TowerInfoContainerv5(DETECTOR detec); + + // default constructor for ROOT IO + TowerInfoContainerv5() = default; + PHObject *CloneMe() const override { return new TowerInfoContainerv5(*this); } + TowerInfoContainerv5(const TowerInfoContainerv5 &); + + ~TowerInfoContainerv5() override; + + void identify(std::ostream &os = std::cout) const override; + + void Reset() override; + TowerInfov5 *get_tower_at_channel(int pos) override; + TowerInfov5 *get_tower_at_key(int pos) override; + + size_t size() const override { return _clones->GetEntries(); } + DETECTOR get_detectorid() const override { return _detector; } + + protected: + TClonesArray *_clones{nullptr}; + DETECTOR _detector{DETECTOR_INVALID}; + + private: + ClassDefOverride(TowerInfoContainerv5, 1); +}; + +#endif diff --git a/offline/packages/CaloBase/TowerInfoContainerv5LinkDef.h b/offline/packages/CaloBase/TowerInfoContainerv5LinkDef.h new file mode 100644 index 0000000000..b50eef6f7b --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoContainerv5LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TowerInfoContainerv5 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/CaloBase/TowerInfoSimv1.cc b/offline/packages/CaloBase/TowerInfoSimv1.cc index bd6c09b02b..c43e325f69 100644 --- a/offline/packages/CaloBase/TowerInfoSimv1.cc +++ b/offline/packages/CaloBase/TowerInfoSimv1.cc @@ -10,14 +10,6 @@ void TowerInfoSimv1::Reset() return; } -void TowerInfoSimv1::Clear(Option_t* /*unused*/) -{ - TowerInfov2::Clear(); - _hitedeps.clear(); - _showeredeps.clear(); - return; -} - void TowerInfoSimv1::copy_tower(TowerInfo* tower) { TowerInfov2::copy_tower(tower); diff --git a/offline/packages/CaloBase/TowerInfoSimv1.h b/offline/packages/CaloBase/TowerInfoSimv1.h index 796e8c7c50..ac24439d74 100644 --- a/offline/packages/CaloBase/TowerInfoSimv1.h +++ b/offline/packages/CaloBase/TowerInfoSimv1.h @@ -3,6 +3,8 @@ #include "TowerInfov2.h" +#include + class TowerInfoSimv1 : public TowerInfov2 { public: @@ -10,7 +12,6 @@ class TowerInfoSimv1 : public TowerInfov2 ~TowerInfoSimv1() override = default; void Reset() override; - void Clear(Option_t* = "") override; void copy_tower(TowerInfo* tower) override; diff --git a/offline/packages/CaloBase/TowerInfoSimv2.cc b/offline/packages/CaloBase/TowerInfoSimv2.cc index e14e6686bf..d20944f354 100644 --- a/offline/packages/CaloBase/TowerInfoSimv2.cc +++ b/offline/packages/CaloBase/TowerInfoSimv2.cc @@ -11,15 +11,6 @@ void TowerInfoSimv2::Reset() } } -void TowerInfoSimv2::Clear(Option_t* /*unused*/) -{ - TowerInfoSimv1::Clear(); - for (short& i : _waveform) - { - i = 0; - } -} - int16_t TowerInfoSimv2::get_waveform_value(int index) const { if (index >= 0 && index < nsample) diff --git a/offline/packages/CaloBase/TowerInfoSimv2.h b/offline/packages/CaloBase/TowerInfoSimv2.h index 88492a0af4..07ab6025c4 100644 --- a/offline/packages/CaloBase/TowerInfoSimv2.h +++ b/offline/packages/CaloBase/TowerInfoSimv2.h @@ -12,7 +12,6 @@ class TowerInfoSimv2 : public TowerInfoSimv1 ~TowerInfoSimv2() override = default; void Reset() override; - void Clear(Option_t* = "") override; void copy_tower(TowerInfo* tower) override; diff --git a/offline/packages/CaloBase/TowerInfoSimv3.cc b/offline/packages/CaloBase/TowerInfoSimv3.cc new file mode 100644 index 0000000000..602bc3d655 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoSimv3.cc @@ -0,0 +1,64 @@ +#include "TowerInfoSimv3.h" + +#include "TowerInfo.h" + +#include + +#include + +#include +#include +#include + +void TowerInfoSimv3::Reset() +{ + TowerInfoSimv1::Reset(); + std::ranges::fill(_waveform, 0); +} + +void TowerInfoSimv3::set_nsample(int nsample) +{ + if (nsample > 0) + { + _waveform.resize(nsample, 0); + return; + } + std::cout << PHWHERE << " invalid number of samples: " << nsample << std::endl; + gSystem->Exit(1); + exit(1); +} + +int16_t TowerInfoSimv3::get_waveform_value(int index) const +{ + if (index >= 0 && index < get_nsample()) + { + return _waveform[index]; + } + return 0; +} + +void TowerInfoSimv3::set_waveform_value(int index, int16_t value) +{ + if (index >= 0 && index < get_nsample()) + { + _waveform[index] = value; + } + return; +} + +void TowerInfoSimv3::copy_tower(TowerInfo* tower) +{ + TowerInfoSimv1::copy_tower(tower); + const int nsamples = tower->get_nsample(); + if (nsamples <= 0) + { + _waveform.clear(); + return; + } + set_nsample(nsamples); + for (int i = 0; i < nsamples; ++i) + { + _waveform[i] = tower->get_waveform_value(i); + } + return; +} diff --git a/offline/packages/CaloBase/TowerInfoSimv3.h b/offline/packages/CaloBase/TowerInfoSimv3.h new file mode 100644 index 0000000000..a718a8e03e --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoSimv3.h @@ -0,0 +1,30 @@ +#ifndef TOWERINFOSIMV3_H +#define TOWERINFOSIMV3_H + +#include "TowerInfoSimv1.h" + +#include // For int16_t +#include + +class TowerInfoSimv3 : public TowerInfoSimv1 +{ + public: + TowerInfoSimv3() = default; + ~TowerInfoSimv3() override = default; + + void Reset() override; + + void copy_tower(TowerInfo* tower) override; + + void set_nsample(int nsample) override; + int get_nsample() const override { return _waveform.size(); } + int16_t get_waveform_value(int index) const override; + void set_waveform_value(int index, int16_t value) override; + + private: + std::vector _waveform; + + ClassDefOverride(TowerInfoSimv3, 1); +}; + +#endif diff --git a/offline/packages/CaloBase/TowerInfoSimv3LinkDef.h b/offline/packages/CaloBase/TowerInfoSimv3LinkDef.h new file mode 100644 index 0000000000..306617306f --- /dev/null +++ b/offline/packages/CaloBase/TowerInfoSimv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TowerInfoSimv3 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/CaloBase/TowerInfov1.cc b/offline/packages/CaloBase/TowerInfov1.cc index 0a88070bc2..92e399be9a 100644 --- a/offline/packages/CaloBase/TowerInfov1.cc +++ b/offline/packages/CaloBase/TowerInfov1.cc @@ -1,7 +1,5 @@ #include "TowerInfov1.h" -#include - TowerInfov1::TowerInfov1(TowerInfo& tower) : _time(tower.get_time()) , _energy(tower.get_energy()) @@ -9,12 +7,6 @@ TowerInfov1::TowerInfov1(TowerInfo& tower) } void TowerInfov1::Reset() -{ - _time = 0; - _energy = std::numeric_limits::quiet_NaN(); -} - -void TowerInfov1::Clear(Option_t* /*unused*/) { _time = 0; _energy = 0; diff --git a/offline/packages/CaloBase/TowerInfov1.h b/offline/packages/CaloBase/TowerInfov1.h index cab6dc539e..1d1ee792ea 100644 --- a/offline/packages/CaloBase/TowerInfov1.h +++ b/offline/packages/CaloBase/TowerInfov1.h @@ -11,9 +11,6 @@ class TowerInfov1 : public TowerInfo ~TowerInfov1() override = default; void Reset() override; - //! Clear is used by TClonesArray to reset the tower to initial state without calling destructor/constructor - void Clear(Option_t* = "") override; - void set_time(float t) override { _time = t * 1000; } float get_time() override { return _time / 1000.; } void set_time_short(short t) override { _time = t * 1000; } diff --git a/offline/packages/CaloBase/TowerInfov2.cc b/offline/packages/CaloBase/TowerInfov2.cc index ff21ed4957..149d59eac8 100644 --- a/offline/packages/CaloBase/TowerInfov2.cc +++ b/offline/packages/CaloBase/TowerInfov2.cc @@ -9,14 +9,6 @@ void TowerInfov2::Reset() _status = 0; } -void TowerInfov2::Clear(Option_t* /*unused*/) -{ - TowerInfov1::Clear(); - _chi2 = 0; - _pedestal = 0; - _status = 0; -} - void TowerInfov2::copy_tower(TowerInfo* tower) { TowerInfov1::copy_tower(tower); diff --git a/offline/packages/CaloBase/TowerInfov2.h b/offline/packages/CaloBase/TowerInfov2.h index 8d064d840f..983ecfa145 100644 --- a/offline/packages/CaloBase/TowerInfov2.h +++ b/offline/packages/CaloBase/TowerInfov2.h @@ -13,8 +13,6 @@ class TowerInfov2 : public TowerInfov1 ~TowerInfov2() override = default; void Reset() override; - void Clear(Option_t* = "") override; - void set_chi2(float chi2) override { _chi2 = chi2; } float get_chi2() override { return _chi2; } @@ -24,8 +22,8 @@ class TowerInfov2 : public TowerInfov1 void set_isHot(bool isHot) override { set_status_bit(0, isHot); } bool get_isHot() const override { return get_status_bit(0); } - void set_isBadTime(bool isBadTime) override { set_status_bit(1, isBadTime); } - bool get_isBadTime() const override { return get_status_bit(1); } + void set_FitStatus(bool fitstatus) override { set_status_bit(1, fitstatus); } + bool get_FitStatus() const override { return get_status_bit(1); } void set_isBadChi2(bool isBadChi2) override { set_status_bit(2, isBadChi2); } bool get_isBadChi2() const override { return get_status_bit(2); } @@ -45,7 +43,7 @@ class TowerInfov2 : public TowerInfov1 void set_isSaturated(bool isSaturated) override { set_status_bit(7, isSaturated); } bool get_isSaturated() const override { return get_status_bit(7); } - bool get_isGood() const override { return !(get_isHot() || get_isBadChi2() || get_isNoCalib()); } + bool get_isGood() const override { return !(get_isHot() || get_isBadChi2() || get_isNoCalib() || get_isNotInstr()); } uint8_t get_status() const override { return _status; } diff --git a/offline/packages/CaloBase/TowerInfov3.cc b/offline/packages/CaloBase/TowerInfov3.cc index 19fb5581e0..b95c786683 100644 --- a/offline/packages/CaloBase/TowerInfov3.cc +++ b/offline/packages/CaloBase/TowerInfov3.cc @@ -1,6 +1,8 @@ #include "TowerInfov3.h" #include "TowerInfo.h" +#include + void TowerInfov3::Reset() { TowerInfov2::Reset(); @@ -10,15 +12,6 @@ void TowerInfov3::Reset() } } -void TowerInfov3::Clear(Option_t* /*unused*/) -{ - TowerInfov2::Clear(); - for (short& i : _waveform) - { - i = 0; - } -} - int16_t TowerInfov3::get_waveform_value(int index) const { if (index >= 0 && index < nsample) @@ -46,3 +39,13 @@ void TowerInfov3::copy_tower(TowerInfo* tower) } return; } + +void TowerInfov3::identify(std::ostream& os) const +{ + os << "TowerInfov3" << std::endl; + for (int i = 0; i < nsample; ++i) + { + std::cout << "sample " << i << ": " << get_waveform_value(i) << std::endl; + } + return; +} diff --git a/offline/packages/CaloBase/TowerInfov3.h b/offline/packages/CaloBase/TowerInfov3.h index 8121ee3693..51a6d53455 100644 --- a/offline/packages/CaloBase/TowerInfov3.h +++ b/offline/packages/CaloBase/TowerInfov3.h @@ -12,7 +12,6 @@ class TowerInfov3 : public TowerInfov2 ~TowerInfov3() override = default; void Reset() override; - void Clear(Option_t* = "") override; // Getter and setter for waveform int get_nsample() const override { return nsample; } @@ -21,6 +20,8 @@ class TowerInfov3 : public TowerInfov2 void copy_tower(TowerInfo* tower) override; + void identify(std::ostream& os) const override; + private: static const int nsample = 31; int16_t _waveform[nsample] = {0}; // Initializes the entire array to zero diff --git a/offline/packages/CaloBase/TowerInfov4.cc b/offline/packages/CaloBase/TowerInfov4.cc index e1b95ba4f3..6b2e83b030 100644 --- a/offline/packages/CaloBase/TowerInfov4.cc +++ b/offline/packages/CaloBase/TowerInfov4.cc @@ -1,20 +1,10 @@ #include "TowerInfov4.h" #include "TowerInfo.h" -#include - void TowerInfov4::Reset() { - energy = std::numeric_limits::quiet_NaN(); - time = 0; - chi2 = 0; - status = 0; -} - -void TowerInfov4::Clear(Option_t* /*unused*/) -{ - time = 0; energy = 0; + time = 0; chi2 = 0; status = 0; } diff --git a/offline/packages/CaloBase/TowerInfov4.h b/offline/packages/CaloBase/TowerInfov4.h index 09bd986298..25a8e0ce75 100644 --- a/offline/packages/CaloBase/TowerInfov4.h +++ b/offline/packages/CaloBase/TowerInfov4.h @@ -15,7 +15,6 @@ class TowerInfov4 : public TowerInfo ~TowerInfov4() override = default; void Reset() override; - void Clear(Option_t* = "") override; void set_energy(float _energy) override { energy = _energy; } float get_energy() override { return energy; } @@ -25,7 +24,6 @@ class TowerInfov4 : public TowerInfo void set_time_short(short t) override { time = t * 1000; } short get_time_short() override { return short(time / 1000); } - void set_chi2(float _chi2) override { float lnChi2; @@ -58,8 +56,8 @@ class TowerInfov4 : public TowerInfo void set_isHot(bool isHot) override { set_status_bit(0, isHot); } bool get_isHot() const override { return get_status_bit(0); } - void set_isBadTime(bool isBadTime) override { set_status_bit(1, isBadTime); } - bool get_isBadTime() const override { return get_status_bit(1); } + void set_FitStatus(bool fitstatus) override { set_status_bit(1, fitstatus); } + bool get_FitStatus() const override { return get_status_bit(1); } void set_isBadChi2(bool isBadChi2) override { set_status_bit(2, isBadChi2); } bool get_isBadChi2() const override { return get_status_bit(2); } @@ -79,7 +77,7 @@ class TowerInfov4 : public TowerInfo void set_isSaturated(bool isSaturated) override { set_status_bit(7, isSaturated); } bool get_isSaturated() const override { return get_status_bit(7); } - bool get_isGood() const override { return !(get_isHot() || get_isBadChi2() || get_isNoCalib()); } + bool get_isGood() const override { return !(get_isHot() || get_isBadChi2() || get_isNoCalib() || get_isNotInstr()); } uint8_t get_status() const override { return status; } diff --git a/offline/packages/CaloBase/TowerInfov5.cc b/offline/packages/CaloBase/TowerInfov5.cc new file mode 100644 index 0000000000..dd9703a441 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfov5.cc @@ -0,0 +1,73 @@ +#include "TowerInfov5.h" +#include "TowerInfo.h" + +#include + +#include + +#include +#include +#include + +void TowerInfov5::Reset() +{ + TowerInfov2::Reset(); + std::ranges::fill(_waveform, 0); +} + +void TowerInfov5::set_nsample(int nsample) +{ + if (nsample > 0) + { + _waveform.resize(nsample, 0); + return; + } + std::cout << PHWHERE << " invalid number of samples: " << nsample << std::endl; + gSystem->Exit(1); + exit(1); +} + +int16_t TowerInfov5::get_waveform_value(int index) const +{ + if (index >= 0 && index < get_nsample()) + { + return _waveform[index]; + } + return 0; +} + +void TowerInfov5::set_waveform_value(int index, int16_t value) +{ + if (index >= 0 && index < get_nsample()) + { + _waveform[index] = value; + } + return; +} + +void TowerInfov5::copy_tower(TowerInfo* tower) +{ + TowerInfov2::copy_tower(tower); + const int nsamples = tower->get_nsample(); + if (nsamples <= 0) + { + _waveform.clear(); + return; + } + set_nsample(nsamples); + for (int i = 0; i < nsamples; ++i) + { + _waveform[i] = tower->get_waveform_value(i); + } + return; +} + +void TowerInfov5::identify(std::ostream& os) const +{ + os << "TowerInfov5" << std::endl; + for (int i = 0; i < get_nsample(); ++i) + { + os << "sample " << i << ": " << get_waveform_value(i) << std::endl; + } + return; +} diff --git a/offline/packages/CaloBase/TowerInfov5.h b/offline/packages/CaloBase/TowerInfov5.h new file mode 100644 index 0000000000..d7e419978b --- /dev/null +++ b/offline/packages/CaloBase/TowerInfov5.h @@ -0,0 +1,35 @@ +#ifndef TOWERINFOV5_H +#define TOWERINFOV5_H + +#include "TowerInfov2.h" + +#include // For int16_t +#include // for ostream +#include + +class TowerInfov5 : public TowerInfov2 +{ + public: + TowerInfov5() = default; + ~TowerInfov5() override = default; + + void Reset() override; + + void identify(std::ostream& os) const override; + + void copy_tower(TowerInfo* tower) override; + + // Getter and setter for waveform + void set_nsample(int nsample) override; + int get_nsample() const override { return _waveform.size(); } + int16_t get_waveform_value(int index) const override; + void set_waveform_value(int index, int16_t value) override; + + private: + std::vector _waveform; + + ClassDefOverride(TowerInfov5, 1); + // Inherit other methods and properties from TowerInfov2 +}; + +#endif diff --git a/offline/packages/CaloBase/TowerInfov5LinkDef.h b/offline/packages/CaloBase/TowerInfov5LinkDef.h new file mode 100644 index 0000000000..08368bf568 --- /dev/null +++ b/offline/packages/CaloBase/TowerInfov5LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TowerInfov5 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/CaloEmbedding/CombineTowerInfo.cc b/offline/packages/CaloEmbedding/CombineTowerInfo.cc new file mode 100644 index 0000000000..3e5150d194 --- /dev/null +++ b/offline/packages/CaloEmbedding/CombineTowerInfo.cc @@ -0,0 +1,99 @@ +#include "CombineTowerInfo.h" + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +//____________________________________________________________________________ +CombineTowerInfo::CombineTowerInfo(const std::string& name) + : SubsysReco(name) +{ +} + +//____________________________________________________________________________ +int CombineTowerInfo::InitRun(PHCompositeNode* topNode) +{ + if (m_inputNodeA.empty() || m_inputNodeB.empty() || m_outputNode.empty()) + { + throw std::runtime_error("CombineTowerInfo: input/output node names not set"); + } + + CreateNodes(topNode); + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________ +void CombineTowerInfo::CreateNodes(PHCompositeNode* topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode* dstNode = + dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + + if (!dstNode) + { + throw std::runtime_error("CombineTowerInfo: DST node not found"); + } + + PHCompositeNode *DetNode = dynamic_cast(iter.findFirst("PHCompositeNode", m_detector)); + + m_towersA = findNode::getClass(topNode, m_inputNodeA); + m_towersB = findNode::getClass(topNode, m_inputNodeB); + + if (!m_towersB) + { + std::cout << "CombineTowerInfo: " <(dstNode, m_outputNode); + if (!m_towersOut) + { + m_towersOut = + dynamic_cast(m_towersA->CloneMe()); + + auto* node = new PHIODataNode( + m_towersOut, m_outputNode, "PHObject"); + + DetNode->addNode(node); + } + + if (m_towersA->size() != m_towersB->size()) + { + throw std::runtime_error("CombineTowerInfo: input containers have different sizes"); + } +} + +//____________________________________________________________________________ +int CombineTowerInfo::process_event(PHCompositeNode* /*topNode*/) +{ + const unsigned int ntowers = m_towersA->size(); + + for (unsigned int ich = 0; ich < ntowers; ++ich) + { + TowerInfo* towerA = m_towersA->get_tower_at_channel(ich); + TowerInfo* towerB = m_towersB->get_tower_at_channel(ich); + TowerInfo* towerO = m_towersOut->get_tower_at_channel(ich); + + towerO->copy_tower(towerA); + + const float e_sum = towerA->get_energy() + towerB->get_energy(); + towerO->set_energy(e_sum); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + diff --git a/offline/packages/CaloEmbedding/CombineTowerInfo.h b/offline/packages/CaloEmbedding/CombineTowerInfo.h new file mode 100644 index 0000000000..ab96a918e6 --- /dev/null +++ b/offline/packages/CaloEmbedding/CombineTowerInfo.h @@ -0,0 +1,39 @@ +#ifndef COMBINETOWERINFO_H +#define COMBINETOWERINFO_H + +#include + +#include + +class PHCompositeNode; +class TowerInfoContainer; + +class CombineTowerInfo : public SubsysReco +{ + public: + explicit CombineTowerInfo(const std::string& name = "CombineTowerInfo"); + ~CombineTowerInfo() override = default; + + int InitRun(PHCompositeNode* topNode) override; + int process_event(PHCompositeNode* topNode) override; + + void set_inputNodeA(const std::string& name) { m_inputNodeA = name; } + void set_inputNodeB(const std::string& name) { m_inputNodeB = name; } + void set_outputNode(const std::string& name) { m_outputNode = name; } + void set_detector(const std::string& name) { m_detector = name; } + + private: + void CreateNodes(PHCompositeNode* topNode); + + std::string m_inputNodeA; + std::string m_inputNodeB; + std::string m_outputNode; + std::string m_detector; + + TowerInfoContainer* m_towersA{nullptr}; + TowerInfoContainer* m_towersB{nullptr}; + TowerInfoContainer* m_towersOut{nullptr}; +}; + +#endif + diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.cc b/offline/packages/CaloEmbedding/CopyIODataNodes.cc index 0d4d4536ff..c480ecc76f 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.cc +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.cc @@ -7,7 +7,13 @@ #include +#include +#include + #include +#include +#include +#include #include #include @@ -53,10 +59,18 @@ int CopyIODataNodes::InitRun(PHCompositeNode *topNode) { CreateMbdOut(topNode, se->topNode()); } + if (m_CopyMbdPmtContainerFlag) + { + CreateMbdPmtContainer(topNode, se->topNode()); + } if (m_CopySyncObjectFlag) { CreateSyncObject(topNode, se->topNode()); } + if (m_CopyTowerInfoFlag) + { + CreateTowerInfo(topNode, se->topNode()); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -85,10 +99,18 @@ int CopyIODataNodes::process_event(PHCompositeNode *topNode) { CopyMbdOut(topNode, se->topNode()); } + if (m_CopyMbdPmtContainerFlag) + { + CopyMbdPmtContainer(topNode, se->topNode()); + } if (m_CopySyncObjectFlag) { CopySyncObject(topNode, se->topNode()); } + if (m_CopyTowerInfoFlag) + { + CopyTowerInfo(topNode, se->topNode()); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -293,6 +315,29 @@ void CopyIODataNodes::CopyMinimumBiasInfo(PHCompositeNode *from_topNode, PHCompo return; } +void CopyIODataNodes::CopyTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) +{ + TowerInfoContainer *from_towerInfo = findNode::getClass(from_topNode, from_towerInfo_name); + TowerInfoContainer *to_towerInfo = findNode::getClass( to_topNode, to_towerInfo_name); + unsigned int ntowers = from_towerInfo->size(); + for (unsigned int ch = 0; ch < ntowers; ++ch) + { + TowerInfo *from_tow = from_towerInfo->get_tower_at_channel(ch); + to_towerInfo->get_tower_at_channel(ch)->copy_tower(from_tow); + } + + if (Verbosity() > 0) + { + std::cout << "From TowerInfoContainer identify()" << std::endl; + from_towerInfo->identify(); + std::cout << "To TowerInfoCOntainer identify()" << std::endl; + to_towerInfo->identify(); + } + + return; +} + + void CopyIODataNodes::CreateMbdOut(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) { @@ -330,6 +375,71 @@ void CopyIODataNodes::CreateMbdOut(PHCompositeNode *from_topNode, PHCompositeNod } +void CopyIODataNodes::CreateMbdPmtContainer(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) +{ + MbdPmtContainer *from_mbdpmtcontainer = findNode::getClass(from_topNode, "MbdPmtContainer"); + if (!from_mbdpmtcontainer) + { + std::cout << "Could not locate MbdPmtContainer on " << from_topNode->getName() << std::endl; + m_CopyMbdPmtContainerFlag = false; + return; + } + + MbdPmtContainer *to_mbdpmtcontainer = findNode::getClass(to_topNode, "MbdPmtContainer_data"); + if (!to_mbdpmtcontainer) + { + PHNodeIterator iter(to_topNode); + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + dstNode = new PHCompositeNode("DST"); + to_topNode->addNode(dstNode); + } + + PHNodeIterator dstiter(dstNode); + PHCompositeNode *mbdNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "MBD")); + if (!mbdNode) + { + mbdNode = new PHCompositeNode("MBD"); + dstNode->addNode(mbdNode); + } + + to_mbdpmtcontainer = new MbdPmtContainerV1(); + PHIODataNode *newNode = new PHIODataNode(to_mbdpmtcontainer, "MbdPmtContainer_data", "PHObject"); + mbdNode->addNode(newNode); + } +} + +void CopyIODataNodes::CreateTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) +{ + std::cout << "copying tower info" << std::endl; + TowerInfoContainer *from_towerInfo = findNode::getClass(from_topNode, from_towerInfo_name); + if (!from_towerInfo) + { + std::cout << "Could not locate TowerInfoContainer on " << from_topNode->getName() << std::endl; + m_CopyTowerInfoFlag = false; + return; + } + TowerInfoContainer *to_towerInfo = findNode::getClass(to_topNode, to_towerInfo_name); + if (!to_towerInfo) + { + PHNodeIterator iter(to_topNode); + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + dstNode = new PHCompositeNode("DST"); + to_topNode->addNode(dstNode); + } + to_towerInfo = dynamic_cast(from_towerInfo->CloneMe()); + PHIODataNode *newNode = new PHIODataNode(to_towerInfo, to_towerInfo_name, "PHObject"); + dstNode->addNode(newNode); + } + return; +} + + + + void CopyIODataNodes::CopyMbdOut(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) { MbdOut *from_mbdout = findNode::getClass(from_topNode, "MbdOut"); @@ -346,6 +456,35 @@ void CopyIODataNodes::CopyMbdOut(PHCompositeNode *from_topNode, PHCompositeNode return; } +void CopyIODataNodes::CopyMbdPmtContainer(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) +{ + MbdPmtContainer *from_mbdpmtcontainer = findNode::getClass(from_topNode, "MbdPmtContainer"); + MbdPmtContainer *to_mbdpmtcontainer = findNode::getClass(to_topNode, "MbdPmtContainer_data"); + if (!from_mbdpmtcontainer || !to_mbdpmtcontainer) + { + return; + } + + to_mbdpmtcontainer->Reset(); + const short nPMTs = from_mbdpmtcontainer->get_npmt(); + to_mbdpmtcontainer->set_npmt(nPMTs); + for (short i = 0; i < nPMTs; ++i) + { + MbdPmtHit *from_mbdpmt = from_mbdpmtcontainer->get_pmt(i); + MbdPmtHit *to_mbdpmt = to_mbdpmtcontainer->get_pmt(i); + to_mbdpmt->set_pmt(from_mbdpmt->get_pmt(), from_mbdpmt->get_q(), from_mbdpmt->get_tt(), from_mbdpmt->get_tq()); + } + + if (Verbosity() > 0) + { + std::cout << "From MbdPmtContainer identify()" << std::endl; + from_mbdpmtcontainer->identify(); + std::cout << "To MbdPmtContainer identify()" << std::endl; + to_mbdpmtcontainer->identify(); + } + return; +} + void CopyIODataNodes::CreateSyncObject(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode) { SyncObject *from_syncobject = findNode::getClass(from_topNode, "Sync"); diff --git a/offline/packages/CaloEmbedding/CopyIODataNodes.h b/offline/packages/CaloEmbedding/CopyIODataNodes.h index 08626bdafb..03ff2ca3bc 100644 --- a/offline/packages/CaloEmbedding/CopyIODataNodes.h +++ b/offline/packages/CaloEmbedding/CopyIODataNodes.h @@ -35,6 +35,14 @@ class CopyIODataNodes : public SubsysReco void CopyMbdOut(bool flag = true) { m_CopyMbdOutFlag = flag; } void CopyRunHeader(bool flag = true) { m_CopyRunHeaderFlag = flag; } void CopySyncObject(bool flag = true) { m_CopySyncObjectFlag = flag; } + void CopyMbdPmtContainer(bool flag = true) { m_CopyMbdPmtContainerFlag = flag; } + void set_CopyTowerInfo(const std::string& set_from_towerInfo_name,const std::string& set_to_towerInfo_name) + { + from_towerInfo_name = set_from_towerInfo_name; + to_towerInfo_name = set_to_towerInfo_name; + m_CopyTowerInfoFlag = true; + return; + } private: void CreateCentralityInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); @@ -56,6 +64,10 @@ class CopyIODataNodes : public SubsysReco void CreateSyncObject(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); void CopySyncObject(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); + void CopyTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); + void CreateTowerInfo(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); + void CreateMbdPmtContainer(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); + void CopyMbdPmtContainer(PHCompositeNode *from_topNode, PHCompositeNode *to_topNode); bool m_CopyCentralityInfoFlag = true; bool m_CopyEventHeaderFlag = true; @@ -64,6 +76,11 @@ class CopyIODataNodes : public SubsysReco bool m_CopyMbdOutFlag = true; bool m_CopyRunHeaderFlag = true; bool m_CopySyncObjectFlag = true; + bool m_CopyTowerInfoFlag = false; + bool m_CopyMbdPmtContainerFlag = false; + + std::string from_towerInfo_name = {}; + std::string to_towerInfo_name = {}; }; #endif // COPYIODATANODES_H diff --git a/offline/packages/CaloEmbedding/Makefile.am b/offline/packages/CaloEmbedding/Makefile.am index 9731b33cb8..f9dd1faa22 100644 --- a/offline/packages/CaloEmbedding/Makefile.am +++ b/offline/packages/CaloEmbedding/Makefile.am @@ -13,6 +13,7 @@ AM_LDFLAGS = \ pkginclude_HEADERS = \ caloTowerEmbed.h \ CopyIODataNodes.h \ + CombineTowerInfo.h \ HepMCCollisionVertex.h lib_LTLIBRARIES = \ @@ -21,6 +22,7 @@ lib_LTLIBRARIES = \ libCaloEmbedding_la_SOURCES = \ caloTowerEmbed.cc \ CopyIODataNodes.cc \ + CombineTowerInfo.cc \ HepMCCollisionVertex.cc libCaloEmbedding_la_LIBADD = \ diff --git a/offline/packages/CaloReco/CaloTowerBuilder.cc b/offline/packages/CaloReco/CaloTowerBuilder.cc index 632cd8161d..9d439e4c24 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.cc +++ b/offline/packages/CaloReco/CaloTowerBuilder.cc @@ -13,9 +13,12 @@ #include #include +#include // for CDBTTree + +#include + #include #include // for SubsysReco -#include #include #include // for PHIODataNode @@ -23,10 +26,7 @@ #include // for PHNodeIterator #include // for PHObject #include - -#include // for CDBTTree - -#include +#include #include #include @@ -58,6 +58,7 @@ CaloTowerBuilder::~CaloTowerBuilder() { delete cdbttree; delete cdbttree_tbt_zs; + delete cdbttree_sepd_map; delete WaveformProcessing; } @@ -75,6 +76,14 @@ int CaloTowerBuilder::InitRun(PHCompositeNode *topNode) WaveformProcessing->set_bitFlipRecovery(m_dobitfliprecovery); } + // Set functional fit parameters + if (_processingtype == CaloWaveformProcessing::FUNCFIT) + { + WaveformProcessing->set_funcfit_type(m_funcfit_type); + WaveformProcessing->set_powerlaw_params(m_powerlaw_power, m_powerlaw_decay); + WaveformProcessing->set_doubleexp_params(m_doubleexp_power, m_doubleexp_peaktime1, m_doubleexp_peaktime2, m_doubleexp_ratio); + } + if (m_dettype == CaloTowerDefs::CEMC) { m_detector = "CEMC"; @@ -232,6 +241,7 @@ int CaloTowerBuilder::process_sim() { towerinfo->set_isRecovered(true); } + towerinfo->set_FitStatus(static_cast(processed_waveforms.at(i).at(5))); int n_samples = waveforms.at(i).size(); if (n_samples == m_nzerosuppsamples || SZS) { @@ -299,6 +309,25 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vectoriValue(0, "CHANNELS"); unsigned int adc_skip_mask = 0; + if (nchannels == 0) // push back -1 and return for empty packets + { + for (int channel = 0; channel < m_nchannels; channel++) + { + if (skipChannel(channel, pid)) + { + continue; + } + std::vector waveform; + waveform.reserve(m_nzerosuppsamples); + for (int samp = 0; samp < m_nzerosuppsamples; samp++) + { + waveform.push_back(-1); + } + waveforms.push_back(waveform); + } + return Fun4AllReturnCodes::EVENT_OK; + } + if (m_dettype == CaloTowerDefs::CEMC) { adc_skip_mask = cdbttree->GetIntValue(pid, m_fieldname); @@ -398,7 +427,7 @@ int CaloTowerBuilder::process_data(PHCompositeNode *topNode, std::vectorset_pedestal(processed_waveforms.at(idx).at(2)); towerinfo->set_chi2(processed_waveforms.at(idx).at(3)); bool SZS = isSZS(processed_waveforms.at(idx).at(1), processed_waveforms.at(idx).at(3)); + if (processed_waveforms.at(idx).at(4) == 0) { towerinfo->set_isRecovered(false); @@ -484,10 +514,11 @@ int CaloTowerBuilder::process_event(PHCompositeNode *topNode) { towerinfo->set_isRecovered(true); } + towerinfo->set_FitStatus(static_cast(processed_waveforms.at(idx).at(5))); int n_samples = waveforms.at(idx).size(); if (n_samples == m_nzerosuppsamples || SZS) { - if (waveforms.at(idx).at(0) == 0) + if (waveforms.at(idx).at(0) == -1) { towerinfo->set_isNotInstr(true); } diff --git a/offline/packages/CaloReco/CaloTowerBuilder.h b/offline/packages/CaloReco/CaloTowerBuilder.h index cb22806903..c3b0bd2e8c 100644 --- a/offline/packages/CaloReco/CaloTowerBuilder.h +++ b/offline/packages/CaloReco/CaloTowerBuilder.h @@ -20,7 +20,7 @@ class TowerInfoContainerv3; class CaloTowerBuilder : public SubsysReco { - public: +public: explicit CaloTowerBuilder(const std::string &name = "CaloTowerBuilder"); ~CaloTowerBuilder() override; @@ -94,6 +94,26 @@ class CaloTowerBuilder : public SubsysReco m_dobitfliprecovery = dobitfliprecovery; } + // Functional fit options: 0 = PowerLawExp, 1 = PowerLawDoubleExp + void set_funcfit_type(int type) + { + m_funcfit_type = type; + } + + void set_powerlaw_params(double power, double decay) + { + m_powerlaw_power = power; + m_powerlaw_decay = decay; + } + + void set_doubleexp_params(double power, double peaktime1, double peaktime2, double ratio) + { + m_doubleexp_power = power; + m_doubleexp_peaktime1 = peaktime1; + m_doubleexp_peaktime2 = peaktime2; + m_doubleexp_ratio = ratio; + } + void set_tbt_softwarezerosuppression(const std::string &url) { m_zsURL = url; @@ -109,7 +129,7 @@ class CaloTowerBuilder : public SubsysReco CaloWaveformProcessing *get_WaveformProcessing() { return WaveformProcessing; } - private: +private: int process_sim(); bool skipChannel(int ich, int pid); static bool isSZS(float time, float chi2); @@ -150,6 +170,15 @@ class CaloTowerBuilder : public SubsysReco std::string m_directURL; std::string m_zsURL; std::string m_zs_fieldname{"zs_threshold"}; + + // Functional fit parameters + int m_funcfit_type{1}; // 0 = PowerLawExp, 1 = PowerLawDoubleExp + double m_powerlaw_power{4.0}; + double m_powerlaw_decay{1.5}; + double m_doubleexp_power{2.0}; + double m_doubleexp_peaktime1{5.0}; + double m_doubleexp_peaktime2{5.0}; + double m_doubleexp_ratio{0.3}; }; #endif // CALOTOWERBUILDER_H diff --git a/offline/packages/CaloReco/CaloTowerCalib.cc b/offline/packages/CaloReco/CaloTowerCalib.cc index cbd13ce4ed..ecc7da5157 100644 --- a/offline/packages/CaloReco/CaloTowerCalib.cc +++ b/offline/packages/CaloReco/CaloTowerCalib.cc @@ -114,6 +114,12 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) } else { + if (m_doAbortNoEnergyCalib) + { + std::cout << "CaloTowerCalib::InitRun: No energy calibration found for " << m_calibName << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } + calibdir = CDBInterface::instance()->getUrl(default_time_independent_calib); if (calibdir.empty()) @@ -151,6 +157,11 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) } else { + if (m_doAbortNoTimeCalib) + { + std::cout << "CaloTowerCalib::InitRun: No time calibration found for " << m_calibName_time << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } m_dotimecalib = false; if (Verbosity() > 0) { @@ -185,6 +196,11 @@ int CaloTowerCalib::InitRun(PHCompositeNode *topNode) } else { + if (m_doAbortNoZSCalib) + { + std::cout << "CaloTowerCalib::InitRun: No ZS cross calibration found for " << m_calibName_ZScrosscalib << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } m_doZScrosscalib = false; if (Verbosity() > 0) { diff --git a/offline/packages/CaloReco/CaloTowerCalib.h b/offline/packages/CaloReco/CaloTowerCalib.h index 06ae6148a1..10a3f2771f 100644 --- a/offline/packages/CaloReco/CaloTowerCalib.h +++ b/offline/packages/CaloReco/CaloTowerCalib.h @@ -92,6 +92,32 @@ class CaloTowerCalib : public SubsysReco } } + void set_doAbortNoEnergyCalib(bool doAbort = true) + { + m_doAbortNoEnergyCalib = doAbort; + return; + } + + void set_doAbortNoTimeCalib(bool doAbort = true) + { + m_doAbortNoTimeCalib = doAbort; + return; + } + + void set_doAbortNoZSCalib(bool doAbort = true) + { + m_doAbortNoZSCalib = doAbort; + return; + } + + void set_doAbortMissingCalib(bool doAbort = true) + { + m_doAbortNoEnergyCalib = doAbort; + m_doAbortNoTimeCalib = doAbort; + m_doAbortNoZSCalib = doAbort; + return; + } + void set_use_TowerInfov2(bool use) { m_use_TowerInfov2 = use; } private: @@ -125,6 +151,10 @@ class CaloTowerCalib : public SubsysReco std::string m_directURL_ZScrosscalib = ""; bool m_doZScrosscalib = true; + bool m_doAbortNoEnergyCalib{false}; + bool m_doAbortNoTimeCalib{false}; + bool m_doAbortNoZSCalib{false}; + CDBTTree *cdbttree = nullptr; CDBTTree *cdbttree_time = nullptr; CDBTTree *cdbttree_ZScrosscalib = nullptr; diff --git a/offline/packages/CaloReco/CaloTowerStatus.cc b/offline/packages/CaloReco/CaloTowerStatus.cc index c5401edb33..d50a792adf 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.cc +++ b/offline/packages/CaloReco/CaloTowerStatus.cc @@ -3,36 +3,22 @@ #include // for TowerInfo #include -#include -#include -#include -#include #include // for CDBTTree #include -#include - #include #include // for SubsysReco #include -#include // for PHIODataNode -#include // for PHNode -#include // for PHNodeIterator -#include // for PHObject #include -#include -#include #include +#include #include -#include // for exit -#include // for exception -#include // for operator<<, basic_ostream -#include // for runtime_error +#include // for operator<<, basic_ostream //____________________________________________________________________________.. CaloTowerStatus::CaloTowerStatus(const std::string &name) @@ -44,23 +30,9 @@ CaloTowerStatus::CaloTowerStatus(const std::string &name) } } -//____________________________________________________________________________.. -CaloTowerStatus::~CaloTowerStatus() -{ - if (Verbosity() > 0) - { - std::cout << "CaloTowerStatus::~CaloTowerStatus() Calling dtor" << std::endl; - } - delete m_cdbttree_chi2; - delete m_cdbttree_time; - delete m_cdbttree_hotMap; -} - //____________________________________________________________________________.. int CaloTowerStatus::InitRun(PHCompositeNode *topNode) { - PHNodeIterator nodeIter(topNode); - if (m_dettype == CaloTowerDefs::CEMC) { m_detector = "CEMC"; @@ -83,132 +55,93 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) m_detector = "SEPD"; } + CreateNodeTree(topNode); + + CDBTTree *cdbttree_chi2{nullptr}; + m_calibName_chi2 = m_detector + "_hotTowers_fracBadChi2"; m_fieldname_chi2 = "fraction"; - std::string calibdir = CDBInterface::instance()->getUrl(m_calibName_chi2); - if (!calibdir.empty()) + if (!m_directURL_chi2.empty()) { - m_cdbttree_chi2 = new CDBTTree(calibdir); - if (Verbosity() > 0) - { - std::cout << "CaloTowerStatus::InitRun Found " << m_calibName_chi2 << " Doing isHot for frac bad chi2" << std::endl; - } + std::cout << "CaloTowerStatus::InitRun: Using direct URL override for chi2: " << m_directURL_chi2 << std::endl; + cdbttree_chi2 = new CDBTTree(m_directURL_chi2); } else { - if (use_directURL_chi2) + std::string calibdir_chi2 = CDBInterface::instance()->getUrl(m_calibName_chi2); + if (!calibdir_chi2.empty()) { - calibdir = m_directURL_chi2; - std::cout << "CaloTowerStatus::InitRun: Using default hotBadChi2" << calibdir << std::endl; - m_cdbttree_chi2 = new CDBTTree(calibdir); - } - else - { - m_doHotChi2 = false; + cdbttree_chi2 = new CDBTTree(calibdir_chi2); if (Verbosity() > 0) { - std::cout << "CaloTowerStatus::InitRun No masking file for domain " << m_calibName_chi2 << " found, not doing isHot from isBadChi2" << std::endl; + std::cout << "CaloTowerStatus::InitRun Found " << m_calibName_chi2 << " Doing isHot for frac bad chi2" << std::endl; } } - } - - m_calibName_time = m_detector + "_meanTime"; - m_fieldname_time = "time"; - - calibdir = CDBInterface::instance()->getUrl(m_calibName_time); - if (!calibdir.empty()) - { - m_cdbttree_time = new CDBTTree(calibdir); - if (Verbosity() > 0) - { - std::cout << "CaloTowerStatus::InitRun Found " << m_calibName_time << " not Doing isBadTime" << std::endl; - } - } - else - { - if (use_directURL_time) - { - calibdir = m_directURL_time; - std::cout << "CaloTowerStatus::InitRun: Using default time " << calibdir << std::endl; - m_cdbttree_time = new CDBTTree(calibdir); - } else { - m_doTime = false; - if (Verbosity() > 1) + if (m_doAbortNoChi2) + { + std::cout << "CaloTowerStatus::InitRun: No chi2 calibration found for " << m_calibName_chi2 << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } + m_doHotChi2 = false; + if (Verbosity() > 0) { - std::cout << "CaloTowerStatus::InitRun no timing info, " << m_calibName_time << " not found, not doing isBadTime" << std::endl; + std::cout << "CaloTowerStatus::InitRun No masking file for domain " << m_calibName_chi2 << " found, not doing isHot from isBadChi2" << std::endl; } } } - m_calibName_hotMap = m_detector + "nome"; - if (m_dettype == CaloTowerDefs::CEMC) - { - m_calibName_hotMap = m_detector + "_BadTowerMap"; - } + CDBTTree *cdbttree_hotMap = nullptr; + + m_calibName_hotMap = m_detector + "_BadTowerMap"; m_fieldname_hotMap = "status"; m_fieldname_z_score = m_detector + "_sigma"; - calibdir = CDBInterface::instance()->getUrl(m_calibName_hotMap); - if (!calibdir.empty()) + std::string calibdir_hotMap; + if (!m_directURL_hotMap.empty()) { - m_cdbttree_hotMap = new CDBTTree(calibdir); - if (Verbosity() > 1) - { - std::cout << "CaloTowerStatus::Init " << m_detector << " hot map found " << m_calibName_hotMap << " Ddoing isHot" << std::endl; - } + calibdir_hotMap = m_directURL_hotMap; + std::cout << "CaloTowerStatus::InitRun: Using direct URL override for hot map: " << calibdir_hotMap << std::endl; + cdbttree_hotMap = new CDBTTree(calibdir_hotMap); } else { - if (m_doAbortNoHotMap) + calibdir_hotMap = CDBInterface::instance()->getUrl(m_calibName_hotMap); + if (!calibdir_hotMap.empty()) { - std::cout << "CaloTowerStatus::InitRun: No hot map.. exiting" << std::endl; - gSystem->Exit(1); - } - if (use_directURL_hotMap) - { - calibdir = m_directURL_hotMap; - std::cout << "CaloTowerStatus::InitRun: Using default map " << calibdir << std::endl; - m_cdbttree_hotMap = new CDBTTree(calibdir); + cdbttree_hotMap = new CDBTTree(calibdir_hotMap); + if (Verbosity() > 1) + { + std::cout << "CaloTowerStatus::Init " << m_detector << " hot map found " << m_calibName_hotMap << " Doing isHot" << std::endl; + } } else { + if (m_doAbortNoHotMap) + { + std::cout << "CaloTowerStatus::InitRun: No hot map found for " << m_calibName_hotMap << " and abort mode is set. Exiting." << std::endl; + gSystem->Exit(1); + } m_doHotMap = false; if (Verbosity() > 1) { std::cout << "CaloTowerStatus::InitRun hot map info, " << m_calibName_hotMap << " not found, not doing isHot" << std::endl; } - } + } } if (Verbosity() > 0) { - std::cout << "CaloTowerStatus::Init " << m_detector << " doing time status =" << std::boolalpha << m_doTime << " doing hotBadChi2=" << std::boolalpha << m_doHotChi2 << " doing hot map=" << std::boolalpha << m_doHotMap << std::endl; + std::cout << "CaloTowerStatus::Init " << m_detector << " doing hotBadChi2=" << std::boolalpha << m_doHotChi2 << " doing hot map=" << std::boolalpha << m_doHotMap << std::endl; } - PHNodeIterator iter(topNode); + LoadCalib(cdbttree_chi2, cdbttree_hotMap); + + delete cdbttree_chi2; + delete cdbttree_hotMap; - // Looking for the DST node - PHCompositeNode *dstNode; - dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) - { - std::cout << Name() << "::" << m_detector << "::" << __PRETTY_FUNCTION__ - << "DST Node missing, doing nothing." << std::endl; - exit(1); - } - try - { - CreateNodeTree(topNode); - LoadCalib(); - } - catch (std::exception &e) - { - std::cout << e.what() << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } if (Verbosity() > 0) { topNode->print(); @@ -216,7 +149,7 @@ int CaloTowerStatus::InitRun(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -void CaloTowerStatus::LoadCalib() +void CaloTowerStatus::LoadCalib(CDBTTree *cdbttree_chi2, CDBTTree *cdbttree_hotMap) { unsigned int ntowers = m_raw_towers->size(); m_cdbInfo_vec.resize(ntowers); @@ -225,18 +158,19 @@ void CaloTowerStatus::LoadCalib() { unsigned int key = m_raw_towers->encode_key(channel); - if (m_doHotChi2) + if (m_doHotChi2 && cdbttree_chi2) { - m_cdbInfo_vec[channel].fraction_badChi2 = m_cdbttree_chi2->GetFloatValue(key, m_fieldname_chi2); + m_cdbInfo_vec[channel].fraction_badChi2 = cdbttree_chi2->GetFloatValue(key, m_fieldname_chi2); } - if (m_doTime) + if (m_doHotMap && cdbttree_hotMap) { - m_cdbInfo_vec[channel].mean_time = m_cdbttree_time->GetFloatValue(key, m_fieldname_time); - } - if (m_doHotMap) - { - m_cdbInfo_vec[channel].hotMap_val = m_cdbttree_hotMap->GetIntValue(key, m_fieldname_hotMap); - m_cdbInfo_vec[channel].z_score = m_cdbttree_hotMap->GetFloatValue(key, m_fieldname_z_score); + m_cdbInfo_vec[channel].hotMap_val = cdbttree_hotMap->GetIntValue(key, m_fieldname_hotMap); + + // Only fetch the z_score field if the custom threshold requires it + if (z_score_threshold != z_score_threshold_default) + { + m_cdbInfo_vec[channel].z_score = cdbttree_hotMap->GetFloatValue(key, m_fieldname_z_score); + } } } } @@ -246,49 +180,56 @@ int CaloTowerStatus::process_event(PHCompositeNode * /*topNode*/) { unsigned int ntowers = m_raw_towers->size(); float fraction_badChi2 = 0; - float mean_time = 0; int hotMap_val = 0; float z_score = 0; for (unsigned int channel = 0; channel < ntowers; channel++) { // only reset what we will set m_raw_towers->get_tower_at_channel(channel)->set_isHot(false); - m_raw_towers->get_tower_at_channel(channel)->set_isBadTime(false); m_raw_towers->get_tower_at_channel(channel)->set_isBadChi2(false); if (m_doHotChi2) { fraction_badChi2 = m_cdbInfo_vec[channel].fraction_badChi2; } - if (m_doTime) - { - mean_time = m_cdbInfo_vec[channel].mean_time; - } if (m_doHotMap) { hotMap_val = m_cdbInfo_vec[channel].hotMap_val; z_score = m_cdbInfo_vec[channel].z_score; } float chi2 = m_raw_towers->get_tower_at_channel(channel)->get_chi2(); - float time = m_raw_towers->get_tower_at_channel(channel)->get_time(); float adc = m_raw_towers->get_tower_at_channel(channel)->get_energy(); if (fraction_badChi2 > fraction_badChi2_threshold && m_doHotChi2) { m_raw_towers->get_tower_at_channel(channel)->set_isHot(true); } - if (!m_raw_towers->get_tower_at_channel(channel)->get_isZS() && std::fabs(time - mean_time) > time_cut && m_doTime) - { - m_raw_towers->get_tower_at_channel(channel)->set_isBadTime(true); - } - if (( hotMap_val == 1 || // dead - std::fabs(z_score) > z_score_threshold || // hot or cold - (hotMap_val == 3 && z_score >= -1 * z_score_threshold_default)) // cold part 2 - && m_doHotMap) + if (m_doHotMap) { - m_raw_towers->get_tower_at_channel(channel)->set_isHot(true); + bool is_hot_tower = false; + + // 1. Default behavior: rely on valid positive hotMap status codes only + if (z_score_threshold == z_score_threshold_default) + { + is_hot_tower = (hotMap_val > 0); + } + // 2. Custom behavior: evaluate based on the custom z_score threshold + else + { + bool is_dead = (hotMap_val == 1); + bool exceeds_zscore_limit = (std::abs(z_score) > z_score_threshold); // Captures both hot and cold by sigma + bool is_low_yield_cold = (hotMap_val == 3 && z_score >= -1 * z_score_threshold_default); // Captures the mean-based cold towers + + is_hot_tower = (is_dead || exceeds_zscore_limit || is_low_yield_cold); + } + + // Apply the result + if (is_hot_tower) + { + m_raw_towers->get_tower_at_channel(channel)->set_isHot(true); + } } - if (chi2 > std::min(std::max(badChi2_treshold_const, adc * adc * badChi2_treshold_quadratic),badChi2_treshold_max)) + if (chi2 > std::min(std::max(badChi2_treshold_const, adc * adc * badChi2_treshold_quadratic), badChi2_treshold_max)) { m_raw_towers->get_tower_at_channel(channel)->set_isBadChi2(true); } @@ -299,14 +240,17 @@ int CaloTowerStatus::process_event(PHCompositeNode * /*topNode*/) void CaloTowerStatus::CreateNodeTree(PHCompositeNode *topNode) { std::string RawTowerNodeName = m_inputNodePrefix + m_detector; + if (!m_inputNode.empty()) + { + RawTowerNodeName = m_inputNode; + } m_raw_towers = findNode::getClass(topNode, RawTowerNodeName); if (!m_raw_towers) { - std::cout << Name() << "::" << m_detector.c_str() << "::" << __PRETTY_FUNCTION__ - << " " << RawTowerNodeName << " Node missing, doing bail out!" + std::cout << Name() << "::" << m_detector << "::" << __PRETTY_FUNCTION__ + << " " << RawTowerNodeName << " Node missing, exiting!" << std::endl; - throw std::runtime_error( - "Failed to find " + RawTowerNodeName + " node in CaloTowerStatus::CreateNodes"); + gSystem->Exit(1); } return; diff --git a/offline/packages/CaloReco/CaloTowerStatus.h b/offline/packages/CaloReco/CaloTowerStatus.h index 8c6f20ecf6..21cb652634 100644 --- a/offline/packages/CaloReco/CaloTowerStatus.h +++ b/offline/packages/CaloReco/CaloTowerStatus.h @@ -5,11 +5,8 @@ #include "CaloTowerDefs.h" -#include // for TowerInfoContainer, TowerIn... - #include -#include #include #include @@ -22,7 +19,7 @@ class CaloTowerStatus : public SubsysReco public: CaloTowerStatus(const std::string &name = "CaloTowerStatus"); - ~CaloTowerStatus() override; + ~CaloTowerStatus() override = default; int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; @@ -38,6 +35,11 @@ class CaloTowerStatus : public SubsysReco m_inputNodePrefix = name; return; } + void set_inputNode(const std::string &name) + { + m_inputNode = name; + return; + } void set_badChi2_const_threshold(float threshold) { badChi2_treshold_const = threshold; @@ -63,80 +65,67 @@ class CaloTowerStatus : public SubsysReco z_score_threshold = threshold; return; } - void set_time_cut(float threshold) + void set_directURL_hotMap(const std::string &str) { - time_cut = threshold; + m_directURL_hotMap = str; return; } - void set_directURL_hotMap(const std::string &str) + void set_directURL_chi2(const std::string &str) { - m_directURL_hotMap = str; - use_directURL_hotMap = true; + m_directURL_chi2 = str; return; } - void set_directURL_time(const std::string &str) + void set_doAbortNoHotMap(bool status = true) { - m_directURL_time = str; - use_directURL_time = true; + m_doAbortNoHotMap = status; return; } - void set_directURL_chi2(const std::string &str) + void set_doAbortNoChi2(bool status = true) { - m_directURL_chi2 = str; - use_directURL_chi2 = true; + m_doAbortNoChi2 = status; return; } - void set_doAbortNoHotMap(bool status = true) + void set_doAbortMissingCalib(bool status = true) { m_doAbortNoHotMap = status; + m_doAbortNoChi2 = status; return; } private: TowerInfoContainer *m_raw_towers{nullptr}; - CDBTTree *m_cdbttree_chi2{nullptr}; - CDBTTree *m_cdbttree_time{nullptr}; - CDBTTree *m_cdbttree_hotMap{nullptr}; - bool m_doHotChi2{true}; - bool m_doTime{true}; bool m_doHotMap{true}; bool m_doAbortNoHotMap{false}; + bool m_doAbortNoChi2{false}; CaloTowerDefs::DetectorSystem m_dettype{CaloTowerDefs::DETECTOR_INVALID}; std::string m_detector; - std::string m_fieldname_time; - std::string m_calibName_time; std::string m_fieldname_chi2; std::string m_calibName_chi2; std::string m_fieldname_hotMap; std::string m_fieldname_z_score; std::string m_calibName_hotMap; std::string m_inputNodePrefix{"TOWERS_"}; + std::string m_inputNode; - std::string m_directURL_time; std::string m_directURL_hotMap; std::string m_directURL_chi2; - bool use_directURL_time{false}; - bool use_directURL_hotMap{false}; - bool use_directURL_chi2{false}; float badChi2_treshold_const = {1e4}; - float badChi2_treshold_quadratic = {1./100}; + float badChi2_treshold_quadratic = {1. / 100}; float badChi2_treshold_max = {1e8}; float fraction_badChi2_threshold = {0.01}; float z_score_threshold = {5}; float z_score_threshold_default = {5}; - float time_cut = 2; // number of samples from the mean time for the channel in the run - void LoadCalib(); + void LoadCalib(CDBTTree *cdbttree_chi2, CDBTTree *cdbttree_hotMap); struct CDBInfo { float fraction_badChi2{0}; - float mean_time{0}; float z_score{0}; int hotMap_val{0}; }; diff --git a/offline/packages/CaloReco/CaloWaveformFitting.cc b/offline/packages/CaloReco/CaloWaveformFitting.cc index f5163275a0..341860c754 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.cc +++ b/offline/packages/CaloReco/CaloWaveformFitting.cc @@ -2,8 +2,10 @@ #include #include +#include #include #include +#include #include #include @@ -21,7 +23,7 @@ #include #include -static ROOT::TThreadExecutor *t = new ROOT::TThreadExecutor(1);// NOLINT(misc-use-anonymous-namespace) +static ROOT::TThreadExecutor *t = new ROOT::TThreadExecutor(1); // NOLINT(misc-use-anonymous-namespace) double CaloWaveformFitting::template_function(double *x, double *par) { Double_t v1 = (par[0] * h_template->Interpolate(x[0] - par[1])) + par[2]; @@ -77,6 +79,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit v.push_back(std::numeric_limits::quiet_NaN()); } v.push_back(0); + v.push_back(0); } else { @@ -118,6 +121,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit v.push_back(std::numeric_limits::quiet_NaN()); } v.push_back(0); + v.push_back(0); } else { @@ -164,16 +168,17 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit } fitter->FitFCN(*EPChi2, nullptr, data.Size(), true); ROOT::Fit::FitResult fitres = fitter->Result(); - // get the result status + // get the fit status code (0 means successful fit) + int validfit = fitres.Status(); /* - bool validfit = fitres.IsValid(); - if(!validfit) + if(validfit != 0) { - std::cout<<"invalid fit"<> CaloWaveformFitting::calo_processing_templatefit recoverFitter->Config().ParSettings(1).SetLimits(-1 * m_peakTimeTemp, size1 - m_peakTimeTemp); // set lim on time par recoverFitter->FitFCN(*recoverEPChi2, nullptr, recoverData.Size(), true); ROOT::Fit::FitResult recover_fitres = recoverFitter->Result(); + int recover_validfit = recover_fitres.Status(); double recover_chi2min = recover_fitres.MinFcnValue(); recover_chi2min /= size1 - 3; // divide by the number of dof if (recover_chi2min < _chi2lowthreshold && recover_f->GetParameter(2) < _bfr_highpedestalthreshold && recover_f->GetParameter(2) > _bfr_lowpedestalthreshold) @@ -253,6 +259,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit } v.push_back(recover_chi2min); v.push_back(1); + v.push_back(recover_validfit); } else { @@ -262,6 +269,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit } v.push_back(chi2min); v.push_back(0); + v.push_back(validfit); } recover_f->Delete(); delete recoverFitFunction; @@ -276,6 +284,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit } v.push_back(chi2min); v.push_back(0); + v.push_back(validfit); } h->Delete(); f->Delete(); @@ -294,7 +303,7 @@ std::vector> CaloWaveformFitting::calo_processing_templatefit { const std::vector &tv = chnlvector.at(i); int size2 = tv.size(); - for (int q = 5; q > 0; q--) + for (int q = 6; q > 0; q--) { fit_params_tmp.push_back(tv.at(size2 - q)); } @@ -433,7 +442,7 @@ std::vector> CaloWaveformFitting::calo_processing_fast(const } } amp -= ped; - std::vector val = {amp, time, ped, chi2, 0}; + std::vector val = {amp, time, ped, chi2, 0, 0}; fit_values.push_back(val); val.clear(); } @@ -456,7 +465,7 @@ std::vector> CaloWaveformFitting::calo_processing_nyquist(con { chi2 = 1000000; } - fit_values.push_back({v.at(1) - v.at(0), std::numeric_limits::quiet_NaN(), v.at(0), chi2, 0}); + fit_values.push_back({v.at(1) - v.at(0), std::numeric_limits::quiet_NaN(), v.at(0), chi2, 0, 0}); continue; } @@ -531,7 +540,7 @@ std::vector CaloWaveformFitting::NyquistInterpolation(std::vector float diff = vec_signal_samples[i] - template_function(xval, par); chi2 += diff * diff; } - std::vector val = {max - pedestal, maxpos, pedestal, chi2, 0}; + std::vector val = {max - pedestal, maxpos, pedestal, chi2, 0, 0}; return val; } @@ -619,3 +628,331 @@ float CaloWaveformFitting::psinc(float time, std::vector &vec_signal_samp return sum; } + +double CaloWaveformFitting::SignalShape_PowerLawExp(double *x, double *par) +{ + // par[0]: Amplitude + // par[1]: Sample Start (t0) + // par[2]: Power + // par[3]: Decay + // par[4]: Pedestal + double pedestal = par[4]; + if (x[0] < par[1]) + { + return pedestal; + } + double signal = par[0] * pow((x[0] - par[1]), par[2]) * exp(-(x[0] - par[1]) * par[3]); + return pedestal + signal; +} + +double CaloWaveformFitting::SignalShape_PowerLawDoubleExp(double *x, double *par) +{ + // par[0]: Amplitude + // par[1]: Sample Start (t0) + // par[2]: Power + // par[3]: Peak Time 1 + // par[4]: Pedestal + // par[5]: Amplitude ratio + // par[6]: Peak Time 2 + double pedestal = par[4]; + if (x[0] < par[1]) + { + return pedestal; + } + double signal = par[0] * pow((x[0] - par[1]), par[2]) * + (((1.0 - par[5]) / pow(par[3], par[2]) * exp(par[2])) * + exp(-(x[0] - par[1]) * (par[2] / par[3])) + + (par[5] / pow(par[6], par[2]) * exp(par[2])) * + exp(-(x[0] - par[1]) * (par[2] / par[6]))); + return pedestal + signal; +} + +// chp: needs to be verified, but I can vaguely recall that making the args const fails in root +double CaloWaveformFitting::SignalShape_FermiExp(double *x, double *par) //NOLINT(readability-non-const-parameter) +{ + // par[0]: Amplitude + // par[1]: Midpoint (t0) + // par[2]: Rise width (w) + // par[3]: Decay time (tau) + // par[4]: Pedestal + + double tt = x[0]; + double A = par[0]; + double t0 = par[1]; + double w = par[2]; + double tau = par[3]; + double ped = par[4]; + + if (w <= 0 || tau <= 0) + { + return ped; + } + + double fermi = 1.0 / (1.0 + exp(-(tt - t0) / w)); + + double expo = exp(-(tt - t0) / tau); + + if (tt < t0) + { + expo = 1.0; + } + + double signal = A * fermi * expo; + + return ped + signal; +} + + +std::vector> CaloWaveformFitting::calo_processing_funcfit(const std::vector> &chnlvector) +{ + std::vector> fit_values; + int nchnls = chnlvector.size(); + + for (int m = 0; m < nchnls; m++) + { + const std::vector &v = chnlvector.at(m); + int nsamples = v.size(); + + float amp = 0; + float time = 0; + float ped = 0; + float chi2 = std::numeric_limits::quiet_NaN(); + + // Handle zero-suppressed samples (2-sample case) + if (nsamples == _nzerosuppresssamples) + { + amp = v.at(1) - v.at(0); + time = std::numeric_limits::quiet_NaN(); + ped = v.at(0); + if (v.at(0) != 0 && v.at(1) == 0) + { + chi2 = 1000000; + } + fit_values.push_back({amp, time, ped, chi2, 0, 0}); + continue; + } + + // Find peak position and estimate pedestal + float maxheight = 0; + int maxbin = 0; + for (int i = 0; i < nsamples; i++) + { + if (v.at(i) > maxheight) + { + maxheight = v.at(i); + maxbin = i; + } + } + + float pedestal = 1500; + if (maxbin > 4) + { + pedestal = 0.5 * (v.at(maxbin - 4) + v.at(maxbin - 5)); + } + else if (maxbin > 3) + { + pedestal = v.at(maxbin - 4); + } + else + { + pedestal = 0.5 * (v.at(nsamples - 3) + v.at(nsamples - 2)); + } + + // Software zero suppression check + if ((_bdosoftwarezerosuppression && v.at(6) - v.at(0) < _nsoftwarezerosuppression) || + (_maxsoftwarezerosuppression && maxheight - pedestal < _nsoftwarezerosuppression)) + { + amp = v.at(6) - v.at(0); + time = std::numeric_limits::quiet_NaN(); + ped = v.at(0); + if (v.at(0) != 0 && v.at(1) == 0) + { + chi2 = 1000000; + } + fit_values.push_back({amp, time, ped, chi2, 0, 0}); + continue; + } + + // Create histogram for fitting + TH1F h("h_funcfit", "", nsamples, -0.5, nsamples - 0.5); + int ndata = 0; + for (int i = 0; i < nsamples; ++i) + { + if ((v.at(i) == 16383) && _handleSaturation) + { + continue; + } + h.SetBinContent(i + 1, v.at(i)); + h.SetBinError(i + 1, 1); + ndata++; + } + + // If too many saturated, use all data + if (ndata < (nsamples - 4)) + { + ndata = nsamples; + for (int i = 0; i < nsamples; ++i) + { + h.SetBinContent(i + 1, v.at(i)); + h.SetBinError(i + 1, 1); + } + } + + double fit_amp = 0; + double fit_time = 0; + double fit_ped = 0; + double chi2val = 0; + int validfit = 0; + int npar = 0; + + if (m_funcfit_type == POWERLAWEXP) + { + // Create fit function with 5 parameters + TF1 f("f_powerlaw", SignalShape_PowerLawExp, 0, nsamples, 5); + npar = 5; + + // Set initial parameters + double risetime = m_powerlaw_power / m_powerlaw_decay; + double par[5]; + par[0] = maxheight - pedestal; // Amplitude + par[1] = maxbin - risetime; // t0 + par[1] = std::max(par[1], 0); + par[2] = m_powerlaw_power; // Power + par[3] = m_powerlaw_decay; // Decay + par[4] = pedestal; // Pedestal + + f.SetParameters(par); + f.SetParLimits(0, (maxheight - pedestal) * 0.5, (maxheight - pedestal) * 10); + f.SetParLimits(1, 0, nsamples); + f.SetParLimits(2, 0, 10.0); + f.SetParLimits(3, 0, 10.0); + f.SetParLimits(4, pedestal - std::abs(maxheight - pedestal), pedestal + std::abs(maxheight - pedestal)); + + // Perform fit + TFitResultPtr fitres = h.Fit(&f, "SQRN0W", "", 0, nsamples); + + // Calculate peak amplitude and time from fit parameters + // Peak height is (p0 * Power(p2/p3, p2)) / exp(p2) + fit_amp = (f.GetParameter(0) * pow(f.GetParameter(2) / f.GetParameter(3), f.GetParameter(2))) / exp(f.GetParameter(2)); + // Peak time is t0 + power/decay + fit_time = f.GetParameter(1) + f.GetParameter(2) / f.GetParameter(3); + fit_ped = f.GetParameter(4); + + // Calculate chi2 + for (int i = 0; i < nsamples; i++) + { + if (h.GetBinContent(i + 1) > 0) + { + double diff = h.GetBinContent(i + 1) - f.Eval(i); + chi2val += diff * diff; + } + } + if (fitres.Get()) { validfit = fitres.Get()->Status(); } + } + else if(m_funcfit_type == POWERLAWDOUBLEEXP) + { + // Create fit function with 7 parameters + TF1 f("f_doubleexp", SignalShape_PowerLawDoubleExp, 0, nsamples, 7); + npar = 7; + + // Set initial parameters + double risetime = 2.0; + double par[7]; + par[0] = (maxheight - pedestal) * 0.7; // Amplitude + par[1] = maxbin - risetime; // t0 + par[1] = std::max(par[1], 0); + par[2] = m_doubleexp_power; // Power + par[3] = m_doubleexp_peaktime1; // Peak Time 1 + par[4] = pedestal; // Pedestal + par[5] = m_doubleexp_ratio; // Amplitude ratio + par[6] = m_doubleexp_peaktime2; // Peak Time 2 + + f.SetParameters(par); + f.SetParLimits(0, (maxheight - pedestal) * -1.5, (maxheight - pedestal) * 1.5); + f.SetParLimits(1, maxbin - 3 * risetime, maxbin + risetime); + f.SetParLimits(2, 1, 5.0); + f.SetParLimits(3, risetime * 0.5, risetime * 4); + f.SetParLimits(4, pedestal - std::abs(maxheight - pedestal), pedestal + std::abs(maxheight - pedestal)); + f.SetParLimits(5, 0, 1); + f.SetParLimits(6, risetime * 0.5, risetime * 4); + + // Perform fit + TFitResultPtr fitres = h.Fit(&f, "SQRN0W", "", 0, nsamples); + + // Find peak by evaluating the function + double peakpos1 = f.GetParameter(3); + double peakpos2 = f.GetParameter(6); + double max_peakpos = f.GetParameter(1) + (peakpos1 > peakpos2 ? peakpos1 : peakpos2); + max_peakpos = std::min(max_peakpos, nsamples - 1); + + fit_time = f.GetMaximumX(f.GetParameter(1), max_peakpos); + fit_amp = f.Eval(fit_time) - f.GetParameter(4); + fit_ped = f.GetParameter(4); + + // Calculate chi2 + for (int i = 0; i < nsamples; i++) + { + if (h.GetBinContent(i + 1) > 0) + { + double diff = h.GetBinContent(i + 1) - f.Eval(i); + chi2val += diff * diff; + } + } + if (fitres.Get()) { validfit = fitres.Get()->Status(); } + } + else if(m_funcfit_type == FERMIEXP) + { + TF1 f("f_fermiexp", SignalShape_FermiExp, 0, nsamples, 5); + npar = 5; + + // Set initial parameters + double par[5]; + par[0] = maxheight - pedestal; // Amplitude + par[1] = maxbin ; // t0 + par[2] = 1.0; // width + par[3] = 2.0; // Peak Time 1 + par[4] = pedestal; // Pedestal + + f.SetParameters(par); + f.SetParLimits(0, maxheight-pedestal, 3*(maxheight-pedestal)); + f.SetParLimits(1, maxbin-1, maxbin); + f.SetParLimits(2, 0.025, 2.0); + f.SetParLimits(3, 0.5, 4.0); + f.SetParLimits(4, pedestal-500, pedestal+500); + + f.FixParameter(2, 0.1); + + TFitResultPtr fitres = h.Fit(&f, "SQRN0W", "", 0, nsamples); + + fit_time = f.GetParameter(1); + fit_amp = f.GetParameter(0); + fit_ped = f.GetParameter(4); + + // Calculate chi2 + for (int i = 0; i < nsamples; i++) + { + if (h.GetBinContent(i + 1) > 0) + { + double diff = h.GetBinContent(i + 1) - f.Eval(i); + chi2val += diff * diff; + } + } + if (fitres.Get()) { validfit = fitres.Get()->Status(); } + } + + int ndf = ndata - npar; + if (ndf > 0) + { + chi2val /= ndf; + } + else + { + chi2val = std::numeric_limits::quiet_NaN(); + } + + fit_values.push_back({static_cast(fit_amp), static_cast(fit_time), + static_cast(fit_ped), static_cast(chi2val), 0, static_cast(validfit)}); + } + + return fit_values; +} diff --git a/offline/packages/CaloReco/CaloWaveformFitting.h b/offline/packages/CaloReco/CaloWaveformFitting.h index 1a9f887305..1064dcd68e 100644 --- a/offline/packages/CaloReco/CaloWaveformFitting.h +++ b/offline/packages/CaloReco/CaloWaveformFitting.h @@ -9,6 +9,13 @@ class TProfile; class CaloWaveformFitting { public: + enum FuncFitType + { + POWERLAWEXP = 0, + POWERLAWDOUBLEEXP = 1, + FERMIEXP = 2, + }; + CaloWaveformFitting() = default; ~CaloWaveformFitting(); @@ -61,9 +68,35 @@ class CaloWaveformFitting std::vector> calo_processing_templatefit(std::vector> chnlvector); static std::vector> calo_processing_fast(const std::vector> &chnlvector); std::vector> calo_processing_nyquist(const std::vector> &chnlvector); + std::vector> calo_processing_funcfit(const std::vector> &chnlvector); void initialize_processing(const std::string &templatefile); + // Power-law fit function: amplitude * (x-t0)^power * exp(-(x-t0)*decay) + pedestal + static double SignalShape_PowerLawExp(double *x, double *par); + // Double exponential power-law fit function + static double SignalShape_PowerLawDoubleExp(double *x, double *par); + static double SignalShape_FermiExp(double *x, double *par); + + void set_funcfit_type(FuncFitType type) + { + m_funcfit_type = type; + } + + void set_powerlaw_params(double power, double decay) + { + m_powerlaw_power = power; + m_powerlaw_decay = decay; + } + + void set_doubleexp_params(double power, double peaktime1, double peaktime2, double ratio) + { + m_doubleexp_power = power; + m_doubleexp_peaktime1 = peaktime1; + m_doubleexp_peaktime2 = peaktime2; + m_doubleexp_ratio = ratio; + } + private: static void FastMax(float x0, float x1, float x2, float y0, float y1, float y2, float &xmax, float &ymax); std::vector NyquistInterpolation(std::vector &vec_signal_samples); @@ -97,5 +130,18 @@ class CaloWaveformFitting std::string url_template; std::string url_onnx; std::string m_model_name; + + // Functional fit type selector + FuncFitType m_funcfit_type{POWERLAWDOUBLEEXP}; + + // Power-law fit parameters + double m_powerlaw_power{4.0}; + double m_powerlaw_decay{1.5}; + + // Double exponential fit parameters + double m_doubleexp_power{2.0}; + double m_doubleexp_peaktime1{5.0}; + double m_doubleexp_peaktime2{5.0}; + double m_doubleexp_ratio{0.3}; }; #endif diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.cc b/offline/packages/CaloReco/CaloWaveformProcessing.cc index 4e51f71f45..ad4993aca4 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.cc +++ b/offline/packages/CaloReco/CaloWaveformProcessing.cc @@ -65,6 +65,19 @@ void CaloWaveformProcessing::initialize_processing() m_Fitter = new CaloWaveformFitting(); m_Fitter->initialize_processing(url_template); } + else if (m_processingtype == CaloWaveformProcessing::FUNCFIT) + { + m_Fitter = new CaloWaveformFitting(); + // Set functional fit type and parameters + m_Fitter->set_funcfit_type(static_cast(_funcfit_type)); + m_Fitter->set_powerlaw_params(_powerlaw_power, _powerlaw_decay); + m_Fitter->set_doubleexp_params(_doubleexp_power, _doubleexp_peaktime1, _doubleexp_peaktime2, _doubleexp_ratio); + if (_bdosoftwarezerosuppression) + { + m_Fitter->set_softwarezerosuppression(_bdosoftwarezerosuppression, _nsoftwarezerosuppression); + } + m_Fitter->set_handleSaturation(true); + } } std::vector> CaloWaveformProcessing::process_waveform(std::vector> waveformvector) @@ -91,6 +104,10 @@ std::vector> CaloWaveformProcessing::process_waveform(std::ve { fitresults = m_Fitter->calo_processing_nyquist(waveformvector); } + if (m_processingtype == CaloWaveformProcessing::FUNCFIT) + { + fitresults = m_Fitter->calo_processing_funcfit(waveformvector); + } return fitresults; } @@ -118,6 +135,7 @@ std::vector> CaloWaveformProcessing::calo_processing_ONNX(con val.push_back(std::numeric_limits::quiet_NaN()); } val.push_back(0); + val.push_back(0); fit_values.push_back(val); } else @@ -160,6 +178,7 @@ std::vector> CaloWaveformProcessing::calo_processing_ONNX(con val.push_back(std::numeric_limits::quiet_NaN()); } val.push_back(0); + val.push_back(0); fit_values.push_back(val); } else @@ -169,7 +188,7 @@ std::vector> CaloWaveformProcessing::calo_processing_ONNX(con { // downstream onnx does not have a static input vector API, // so we need to make a copy - std::vector vtmp(v); //NOLINT(performance-unnecessary-copy-initialization) + std::vector vtmp(v); // NOLINT(performance-unnecessary-copy-initialization) val = onnxInference(onnxmodule, vtmp, 1, onnxlib::n_input, onnxlib::n_output); unsigned int nvals = val.size(); for (unsigned int i = 0; i < nvals; i++) @@ -178,12 +197,13 @@ std::vector> CaloWaveformProcessing::calo_processing_ONNX(con } val.push_back(2000); val.push_back(0); + val.push_back(0); fit_values.push_back(val); } else { float v_diff = v[1] - v[0]; - std::vector val1{v_diff, std::numeric_limits::quiet_NaN(), v[1], std::numeric_limits::quiet_NaN(), 0}; + std::vector val1{v_diff, std::numeric_limits::quiet_NaN(), v[1], std::numeric_limits::quiet_NaN(), 0, 0}; fit_values.push_back(val1); } } diff --git a/offline/packages/CaloReco/CaloWaveformProcessing.h b/offline/packages/CaloReco/CaloWaveformProcessing.h index 8a5a5bbbe6..b657459d6c 100644 --- a/offline/packages/CaloReco/CaloWaveformProcessing.h +++ b/offline/packages/CaloReco/CaloWaveformProcessing.h @@ -20,6 +20,7 @@ class CaloWaveformProcessing : public SubsysReco FAST = 3, NYQUIST = 4, TEMPLATE_NOSAT = 5, + FUNCFIT = 6, }; CaloWaveformProcessing() = default; @@ -75,6 +76,26 @@ class CaloWaveformProcessing : public SubsysReco _dobitfliprecovery = dobitfliprecovery; } + // Functional fit options: 0 = PowerLawExp, 1 = PowerLawDoubleExp + void set_funcfit_type(int type) + { + _funcfit_type = type; + } + + void set_powerlaw_params(double power, double decay) + { + _powerlaw_power = power; + _powerlaw_decay = decay; + } + + void set_doubleexp_params(double power, double peaktime1, double peaktime2, double ratio) + { + _doubleexp_power = power; + _doubleexp_peaktime1 = peaktime1; + _doubleexp_peaktime2 = peaktime2; + _doubleexp_ratio = ratio; + } + std::vector> process_waveform(std::vector> waveformvector); std::vector> calo_processing_ONNX(const std::vector> &chnlvector); @@ -108,6 +129,15 @@ class CaloWaveformProcessing : public SubsysReco std::string m_model_name{"CEMC_ONNX"}; std::array m_Onnx_factor{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; std::array m_Onnx_offset{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + + // Functional fit parameters + int _funcfit_type{1}; // 0 = PowerLawExp, 1 = PowerLawDoubleExp + double _powerlaw_power{4.0}; + double _powerlaw_decay{1.5}; + double _doubleexp_power{2.0}; + double _doubleexp_peaktime1{5.0}; + double _doubleexp_peaktime2{5.0}; + double _doubleexp_ratio{0.3}; }; #endif diff --git a/offline/packages/CaloReco/ClusterCDFCalculator.cc b/offline/packages/CaloReco/ClusterCDFCalculator.cc index 80b908b2b6..df1d8fe6f6 100644 --- a/offline/packages/CaloReco/ClusterCDFCalculator.cc +++ b/offline/packages/CaloReco/ClusterCDFCalculator.cc @@ -5,9 +5,8 @@ #include #include -#include - #include +#include ClusterCDFCalculator::~ClusterCDFCalculator() { @@ -94,9 +93,9 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() for (int binidx = 0; binidx < nBins; ++binidx) { // photon hist - std::string hD2_3x3_name_photon = (boost::format("h_photon_hD2_3x3_en%d") % binidx).str(); - std::string hD2_5x5_name_photon = (boost::format("h_photon_hD2_5x5_en%d") % binidx).str(); - std::string hD2_7x7_name_photon = (boost::format("h_photon_hD2_7x7_en%d") % binidx).str(); + std::string hD2_3x3_name_photon = std::format("h_photon_hD2_3x3_en{}", binidx); + std::string hD2_5x5_name_photon = std::format("h_photon_hD2_5x5_en{}", binidx); + std::string hD2_7x7_name_photon = std::format("h_photon_hD2_7x7_en{}", binidx); file->GetObject(hD2_3x3_name_photon.c_str(), hD2_3x3_photon[binidx]); file->GetObject(hD2_5x5_name_photon.c_str(), hD2_5x5_photon[binidx]); @@ -109,11 +108,11 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() } TH1 *hD2mean3_photon{nullptr}; - file->GetObject((boost::format("h_photon_hD2mean3_en%d") % binidx).str().c_str(), hD2mean3_photon); + file->GetObject(std::format("h_photon_hD2mean3_en{}", binidx).c_str(), hD2mean3_photon); TH1 *hD2mean5_photon{nullptr}; - file->GetObject((boost::format("h_photon_hD2mean5_en%d") % binidx).str().c_str(), hD2mean5_photon); + file->GetObject(std::format("h_photon_hD2mean5_en{}", binidx).c_str(), hD2mean5_photon); TH1 *hD2mean7_photon{nullptr}; - file->GetObject((boost::format("h_photon_hD2mean7_en%d") % binidx).str().c_str(), hD2mean7_photon); + file->GetObject(std::format("h_photon_hD2mean7_en{}", binidx).c_str(), hD2mean7_photon); if (!hD2mean3_photon || !hD2mean5_photon || !hD2mean7_photon) { @@ -126,40 +125,40 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() for (int i = 0; i < NMATRIX_3x3; ++i) { - std::string histName = (boost::format("h_photon_heratio_3x3_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_photon_heratio_3x3_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_3x3_photon[binidx][i]); if (!ratioHistograms_3x3_photon[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName << " is missing." << std::endl; return; } } for (int i = 0; i < NMATRIX_5x5; ++i) { - std::string histName = (boost::format("h_photon_heratio_5x5_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_photon_heratio_5x5_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_5x5_photon[binidx][i]); if (!ratioHistograms_5x5_photon[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName << " is missing." << std::endl; return; } } for (int i = 0; i < NMATRIX_7x7; ++i) { - std::string histName = (boost::format("h_photon_heratio_7x7_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_photon_heratio_7x7_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_7x7_photon[binidx][i]); if (!ratioHistograms_7x7_photon[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: photon hist " << histName << " is missing." << std::endl; return; } } TH2 *hCovMatrix3x3_photon{nullptr}; - file->GetObject((boost::format("h_photon_hCovMatrix3_en%d") % binidx).str().c_str(), hCovMatrix3x3_photon); + file->GetObject(std::format("h_photon_hCovMatrix3_en{}", binidx).c_str(), hCovMatrix3x3_photon); TH2 *hCovMatrix5x5_photon{nullptr}; - file->GetObject((boost::format("h_photon_hCovMatrix5_en%d") % binidx).str().c_str(), hCovMatrix5x5_photon); + file->GetObject(std::format("h_photon_hCovMatrix5_en{}", binidx).c_str(), hCovMatrix5x5_photon); TH2 *hCovMatrix7x7_photon{nullptr}; - file->GetObject((boost::format("h_photon_hCovMatrix7_en%d") % binidx).str().c_str(), hCovMatrix7x7_photon); + file->GetObject(std::format("h_photon_hCovMatrix7_en{}", binidx).c_str(), hCovMatrix7x7_photon); if (!hCovMatrix3x3_photon || !hCovMatrix5x5_photon || !hCovMatrix7x7_photon) { @@ -200,9 +199,9 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() } // pi0 hist - std::string hD2_3x3_name_pi0 = (boost::format("h_pi0_hD2_3x3_en%d") % binidx).str(); - std::string hD2_5x5_name_pi0 = (boost::format("h_pi0_hD2_5x5_en%d") % binidx).str(); - std::string hD2_7x7_name_pi0 = (boost::format("h_pi0_hD2_7x7_en%d") % binidx).str(); + std::string hD2_3x3_name_pi0 = std::format("h_pi0_hD2_3x3_en{}", binidx); + std::string hD2_5x5_name_pi0 = std::format("h_pi0_hD2_5x5_en{}", binidx); + std::string hD2_7x7_name_pi0 = std::format("h_pi0_hD2_7x7_en{}", binidx); file->GetObject(hD2_3x3_name_pi0.c_str(), hD2_3x3_pi0[binidx]); file->GetObject(hD2_5x5_name_pi0.c_str(), hD2_5x5_pi0[binidx]); @@ -215,11 +214,11 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() } TH1 *hD2mean3_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hD2mean3_en%d") % binidx).str().c_str(), hD2mean3_pi0); + file->GetObject(std::format("h_pi0_hD2mean3_en{}", binidx).c_str(), hD2mean3_pi0); TH1 *hD2mean5_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hD2mean5_en%d") % binidx).str().c_str(), hD2mean5_pi0); + file->GetObject(std::format("h_pi0_hD2mean5_en{}", binidx).c_str(), hD2mean5_pi0); TH1 *hD2mean7_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hD2mean7_en%d") % binidx).str().c_str(), hD2mean7_pi0); + file->GetObject(std::format("h_pi0_hD2mean7_en{}", binidx).c_str(), hD2mean7_pi0); if (!hD2mean3_pi0 || !hD2mean5_pi0 || !hD2mean7_pi0) { @@ -232,40 +231,40 @@ void ClusterCDFCalculator::LoadHistogramsAndMatrices() for (int i = 0; i < NMATRIX_3x3; ++i) { - std::string histName = (boost::format("h_pi0_heratio_3x3_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_pi0_heratio_3x3_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_3x3_pi0[binidx][i]); if (!ratioHistograms_3x3_pi0[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName << " is missing." << std::endl; return; } } for (int i = 0; i < NMATRIX_5x5; ++i) { - std::string histName = (boost::format("h_pi0_heratio_5x5_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_pi0_heratio_5x5_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_5x5_pi0[binidx][i]); if (!ratioHistograms_5x5_pi0[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName << " is missing." << std::endl; return; } } for (int i = 0; i < NMATRIX_7x7; ++i) { - std::string histName = (boost::format("h_pi0_heratio_7x7_en%d_%d") % binidx % i).str(); + std::string histName = std::format("h_pi0_heratio_7x7_en{}_{}", binidx, i); file->GetObject(histName.c_str(), ratioHistograms_7x7_pi0[binidx][i]); if (!ratioHistograms_7x7_pi0[binidx][i]) { - std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName.c_str() << " is missing." << std::endl; + std::cout << "ClusterCDFCalculator::LoadHistogramsAndMatrices() error: pi0 hist " << histName << " is missing." << std::endl; return; } } TH2 *hCovMatrix3x3_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hCovMatrix3_en%d") % binidx).str().c_str(), hCovMatrix3x3_pi0); + file->GetObject(std::format("h_pi0_hCovMatrix3_en{}", binidx).c_str(), hCovMatrix3x3_pi0); TH2 *hCovMatrix5x5_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hCovMatrix5_en%d") % binidx).str().c_str(), hCovMatrix5x5_pi0); + file->GetObject(std::format("h_pi0_hCovMatrix5_en{}", binidx).c_str(), hCovMatrix5x5_pi0); TH2 *hCovMatrix7x7_pi0{nullptr}; - file->GetObject((boost::format("h_pi0_hCovMatrix7_en%d") % binidx).str().c_str(), hCovMatrix7x7_pi0); + file->GetObject(std::format("h_pi0_hCovMatrix7_en{}", binidx).c_str(), hCovMatrix7x7_pi0); if (!hCovMatrix3x3_pi0 || !hCovMatrix5x5_pi0 || !hCovMatrix7x7_pi0) { diff --git a/offline/packages/CaloReco/PhotonClusterBuilder.cc b/offline/packages/CaloReco/PhotonClusterBuilder.cc index 263ae04ef0..8171c2cbce 100644 --- a/offline/packages/CaloReco/PhotonClusterBuilder.cc +++ b/offline/packages/CaloReco/PhotonClusterBuilder.cc @@ -117,6 +117,19 @@ int PhotonClusterBuilder::InitRun(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTRUN; } + if (m_do_subtracted_iso) + { + m_emc_sub1_tower_container = findNode::getClass(topNode, "TOWERINFO_CALIB_CEMC_RETOWER_SUB1"); + m_ihcal_sub1_tower_container = findNode::getClass(topNode, "TOWERINFO_CALIB_HCALIN_SUB1"); + m_ohcal_sub1_tower_container = findNode::getClass(topNode, "TOWERINFO_CALIB_HCALOUT_SUB1"); + + if (!m_emc_sub1_tower_container || !m_ihcal_sub1_tower_container || !m_ohcal_sub1_tower_container) + { + std::cout << Name() << ": subtracted isolation enabled but one or more SUB1 tower nodes are missing; " + << "iso_sub_* values will remain at " << m_subtracted_iso_defval << std::endl; + } + } + CreateNodes(topNode); return Fun4AllReturnCodes::EVENT_OK; } @@ -323,7 +336,7 @@ void PhotonClusterBuilder::calculate_shower_shapes(RawCluster* rc, PhotonCluster nsaturated++; } } - + int totalphibins = 256; auto dphiwrap = [totalphibins](int towerphi, int maxiphi_arg) { @@ -435,7 +448,7 @@ void PhotonClusterBuilder::calculate_shower_shapes(RawCluster* rc, PhotonCluster float e72 = 0; float detacog = std::abs(maxieta - avg_eta); float dphicog = std::abs(maxiphi - avg_phi); - float drad = std::sqrt(dphicog*dphicog + detacog*detacog); + float drad = std::sqrt(dphicog * dphicog + detacog * detacog); int signphi = (avg_phi - std::floor(avg_phi)) > 0.5 ? 1 : -1; @@ -566,6 +579,7 @@ void PhotonClusterBuilder::calculate_shower_shapes(RawCluster* rc, PhotonCluster photon->set_shower_shape_parameter("et3", showershape[2]); photon->set_shower_shape_parameter("et4", showershape[3]); photon->set_shower_shape_parameter("e11", e11); + photon->set_shower_shape_parameter("e22", showershape[8] + showershape[9] + showershape[10] + showershape[11]); photon->set_shower_shape_parameter("e33", e33); photon->set_shower_shape_parameter("e55", e55); photon->set_shower_shape_parameter("e77", e77); @@ -766,6 +780,41 @@ void PhotonClusterBuilder::calculate_shower_shapes(RawCluster* rc, PhotonCluster photon->set_shower_shape_parameter("iso_02_emcal", emcal_et_02 - ET); photon->set_shower_shape_parameter("iso_01_emcal", emcal_et_01 - ET); photon->set_shower_shape_parameter("iso_005_emcal", emcal_et_005 - ET); + + photon->set_shower_shape_parameter("iso_sub_04_emcal", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_04_hcalin", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_04_hcalout", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_03_emcal", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_03_hcalin", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_03_hcalout", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_02_emcal", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_01_emcal", m_subtracted_iso_defval); + photon->set_shower_shape_parameter("iso_sub_005_emcal", m_subtracted_iso_defval); + + if (m_do_subtracted_iso && m_emc_sub1_tower_container && m_ihcal_sub1_tower_container && m_ohcal_sub1_tower_container) + { + const float sub_emcal_et_04 = calculate_layer_et(cluster_eta, cluster_phi, 0.4, m_emc_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_ihcal_et_04 = calculate_layer_et(cluster_eta, cluster_phi, 0.4, m_ihcal_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_ohcal_et_04 = calculate_layer_et(cluster_eta, cluster_phi, 0.4, m_ohcal_sub1_tower_container, m_geomOH, RawTowerDefs::CalorimeterId::HCALOUT, m_vertex); + + const float sub_emcal_et_03 = calculate_layer_et(cluster_eta, cluster_phi, 0.3, m_emc_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_ihcal_et_03 = calculate_layer_et(cluster_eta, cluster_phi, 0.3, m_ihcal_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_ohcal_et_03 = calculate_layer_et(cluster_eta, cluster_phi, 0.3, m_ohcal_sub1_tower_container, m_geomOH, RawTowerDefs::CalorimeterId::HCALOUT, m_vertex); + + const float sub_emcal_et_02 = calculate_layer_et(cluster_eta, cluster_phi, 0.2, m_emc_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_emcal_et_01 = calculate_layer_et(cluster_eta, cluster_phi, 0.1, m_emc_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + const float sub_emcal_et_005 = calculate_layer_et(cluster_eta, cluster_phi, 0.05, m_emc_sub1_tower_container, m_geomIH, RawTowerDefs::CalorimeterId::HCALIN, m_vertex); + + photon->set_shower_shape_parameter("iso_sub_04_emcal", sub_emcal_et_04 - ET); + photon->set_shower_shape_parameter("iso_sub_04_hcalin", sub_ihcal_et_04); + photon->set_shower_shape_parameter("iso_sub_04_hcalout", sub_ohcal_et_04); + photon->set_shower_shape_parameter("iso_sub_03_emcal", sub_emcal_et_03 - ET); + photon->set_shower_shape_parameter("iso_sub_03_hcalin", sub_ihcal_et_03); + photon->set_shower_shape_parameter("iso_sub_03_hcalout", sub_ohcal_et_03); + photon->set_shower_shape_parameter("iso_sub_02_emcal", sub_emcal_et_02 - ET); + photon->set_shower_shape_parameter("iso_sub_01_emcal", sub_emcal_et_01 - ET); + photon->set_shower_shape_parameter("iso_sub_005_emcal", sub_emcal_et_005 - ET); + } } double PhotonClusterBuilder::getTowerEta(RawTowerGeom* tower_geom, double vx, double vy, double vz) diff --git a/offline/packages/CaloReco/PhotonClusterBuilder.h b/offline/packages/CaloReco/PhotonClusterBuilder.h index 1c987f9849..b9a9baed50 100644 --- a/offline/packages/CaloReco/PhotonClusterBuilder.h +++ b/offline/packages/CaloReco/PhotonClusterBuilder.h @@ -42,6 +42,7 @@ class PhotonClusterBuilder : public SubsysReco void set_bdt_model_file(const std::string& path) { m_bdt_model_file = path; } void set_bdt_feature_list(const std::vector& features) { m_bdt_feature_list = features; } void set_do_bdt(bool do_bdt) { m_do_bdt = do_bdt; } + void set_do_subtracted_iso(bool do_subtracted_iso) { m_do_subtracted_iso = do_subtracted_iso; } const std::vector& get_bdt_feature_list() const { return m_bdt_feature_list; } private: @@ -53,6 +54,7 @@ class PhotonClusterBuilder : public SubsysReco double deltaR(double eta1, double phi1, double eta2, double phi2); float calculate_layer_et(float seed_eta, float seed_phi, float radius, TowerInfoContainer* towerContainer, RawTowerGeomContainer* geomContainer, RawTowerDefs::CalorimeterId calo_id, float vertex_z); bool m_do_bdt{false}; + bool m_do_subtracted_iso{false}; std::string m_input_cluster_node{"CLUSTERINFO_CEMC"}; std::string m_output_photon_node{"PHOTONCLUSTER_CEMC"}; @@ -61,6 +63,7 @@ class PhotonClusterBuilder : public SubsysReco std::string m_bdt_model_file{"myBDT_5.root"}; std::vector m_bdt_feature_list; float m_vertex{std::numeric_limits::quiet_NaN()}; + float m_subtracted_iso_defval{-999}; RawClusterContainer* m_rawclusters{nullptr}; RawClusterContainer* m_photon_container{nullptr}; @@ -70,6 +73,9 @@ class PhotonClusterBuilder : public SubsysReco RawTowerGeomContainer* m_geomIH{nullptr}; TowerInfoContainer* m_ohcal_tower_container{nullptr}; RawTowerGeomContainer* m_geomOH{nullptr}; + TowerInfoContainer* m_emc_sub1_tower_container{nullptr}; + TowerInfoContainer* m_ihcal_sub1_tower_container{nullptr}; + TowerInfoContainer* m_ohcal_sub1_tower_container{nullptr}; std::unique_ptr m_bdt; }; diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc index 01975c66f4..23ab068663 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.cc @@ -38,6 +38,7 @@ #include #include + //____________________________________________________________________________.. HFTrackEfficiency::HFTrackEfficiency(const std::string &name) : SubsysReco(name) @@ -113,21 +114,12 @@ int HFTrackEfficiency::process_event(PHCompositeNode *topNode) } } - m_dst_truth_reco_map = findNode::getClass(topNode, "PHG4ParticleSvtxMap"); - if (m_dst_truth_reco_map) + if (!m_svtx_evalstack) { - if (Verbosity() >= VERBOSITY_MORE) - { - std::cout << __FILE__ << ": PHG4ParticleSvtxMap found, truth matching will be more accurate" << std::endl; - } - } - else - { - if (Verbosity() >= VERBOSITY_MORE) - { - std::cout << __FILE__ << ": PHG4ParticleSvtxMap not found, reverting to true matching by momentum relations. Truth matching will be less accurate" << std::endl; - } + m_svtx_evalstack = new SvtxEvalStack(topNode); + trackeval = m_svtx_evalstack->get_track_eval(); } + m_svtx_evalstack->next_event(topNode); if (m_decay_descriptor.empty() && !m_decayMap->empty()) { @@ -213,20 +205,42 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_true_mother_pT = mother->momentum().perp(); m_true_mother_p = std::sqrt(std::pow(mother->momentum().px(), 2) + std::pow(mother->momentum().py(), 2) + std::pow(mother->momentum().pz(), 2)); // Must have an old HepMC build, no mag function m_true_mother_eta = mother->momentum().eta(); + m_true_mother_phi = mother->momentum().phi(); + if (mother->momentum().e() > std::fabs(mother->momentum().pz())) + { + m_true_mother_rapidity = 0.5 * log((mother->momentum().e() + mother->momentum().pz())/(mother->momentum().e() - mother->momentum().pz())); + } + else + { + m_true_mother_rapidity = -999.; + } HepMC::GenVertex *thisVtx = mother->production_vertex(); m_primary_vtx_x = thisVtx->point3d().x(); m_primary_vtx_y = thisVtx->point3d().y(); m_primary_vtx_z = thisVtx->point3d().z(); + + constexpr float epsilon = 1e-6F; + if (std::abs(m_primary_vtx_x) < epsilon && + std::abs(m_primary_vtx_y) < epsilon && + std::abs(m_primary_vtx_z) < epsilon) + { + m_is_primary = true; + } } + int index = -1; + PHG4Particle *daughterG4 {nullptr}; + for (unsigned int i = 1; i < decay.size(); ++i) { m_dst_track = nullptr; - int truth_ID = -1; + if (std::find(std::begin(trackableParticles), std::end(trackableParticles), std::abs(decay[i].second)) != std::end(trackableParticles)) { + ++index; + if (theEvent && decay[i].first.second > -1) { HepMC::GenParticle *daughterHepMC = theEvent->barcode_to_particle(decay[i].first.second); @@ -238,7 +252,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) daughterTrueLV->setVectM(CLHEP::Hep3Vector(daughterHepMC->momentum().px(), daughterHepMC->momentum().py(), daughterHepMC->momentum().pz()), getParticleMass(decay[i].second)); daughterSumTrueLV += *daughterTrueLV; - m_true_track_PID[i - 1] = daughterHepMC->pdg_id(); + m_true_track_PID[index] = daughterHepMC->pdg_id(); // Now get the decay vertex position HepMC::GenVertex *thisVtx = daughterHepMC->production_vertex(); @@ -247,21 +261,17 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_secondary_vtx_z = thisVtx->point3d().z(); // We need the G4 ID, not the HepMC ID to use the truth/reco map - if (m_dst_truth_reco_map) + PHG4TruthInfoContainer::ConstRange range = m_truthInfo->GetParticleRange(); + + for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) { - PHG4TruthInfoContainer::ConstRange range = m_truthInfo->GetParticleRange(); + daughterG4 = iter->second; - for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) + if (std::abs(daughterG4->get_px() - daughterTrueLV->x()) <= 5e-3 && + std::abs(daughterG4->get_py() - daughterTrueLV->y()) <= 5e-3 && + std::abs(daughterG4->get_pz() - daughterTrueLV->z()) <= 5e-3 && daughterG4->get_pid() == decay[i].second) { - PHG4Particle *daughterG4 = iter->second; - - if (std::abs(daughterG4->get_px() - daughterTrueLV->x()) <= 5e-3 && - std::abs(daughterG4->get_py() - daughterTrueLV->y()) <= 5e-3 && - std::abs(daughterG4->get_pz() - daughterTrueLV->z()) <= 5e-3 && daughterG4->get_pid() == decay[i].second) - { - truth_ID = daughterG4->get_track_id(); - break; - } + break; } } } @@ -271,7 +281,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) { - PHG4Particle *daughterG4 = iter->second; + daughterG4 = iter->second; PHG4Particle *motherG4 = nullptr; if (daughterG4->get_parent_id() != 0) @@ -283,18 +293,88 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) continue; } - if (motherG4->get_pid() == decay[0].second && motherG4->get_barcode() == decay[0].first.second && daughterG4->get_pid() == decay[i].second && daughterG4->get_barcode() == decay[i].first.second) + if (motherG4->get_pid() == decay[0].second && motherG4->get_barcode() == decay[0].first.second && daughterG4->get_pid() == decay[i].second && daughterG4->get_barcode() == decay[i].first.second && m_nDaughters == 2) { + if (Verbosity() >= VERBOSITY_MORE || true) // fix later + { + daughterG4->identify(); + } + + m_is_primary = m_truthInfo->is_sPHENIX_primary(motherG4); + + CLHEP::Hep3Vector *mother3Vector = new CLHEP::Hep3Vector(motherG4->get_px(), motherG4->get_py(), motherG4->get_pz()); + motherTrueLV->setVectM((*mother3Vector), getParticleMass(decay[0].second)); + m_true_mother_pT = motherTrueLV->perp(); + m_true_mother_p = mother3Vector->mag(); + m_true_mother_eta = motherTrueLV->pseudoRapidity(); + m_true_mother_phi = motherTrueLV->phi(); + m_true_mother_rapidity = motherTrueLV->rapidity(); + + PHG4VtxPoint *thisVtx = m_truthInfo->GetVtx(motherG4->get_vtx_id()); + m_primary_vtx_x = thisVtx->get_x(); + m_primary_vtx_y = thisVtx->get_y(); + m_primary_vtx_z = thisVtx->get_z(); + + daughterTrueLV->setVectM(CLHEP::Hep3Vector(daughterG4->get_px(), daughterG4->get_py(), daughterG4->get_pz()), getParticleMass(decay[i].second)); + daughterSumTrueLV += *daughterTrueLV; + + // Now get the decay vertex position + thisVtx = m_truthInfo->GetVtx(daughterG4->get_vtx_id()); + m_secondary_vtx_x = thisVtx->get_x(); + m_secondary_vtx_y = thisVtx->get_y(); + m_secondary_vtx_z = thisVtx->get_z(); + + m_true_track_PID[index] = daughterG4->get_pid(); + + delete mother3Vector; + } + else if (m_nDaughters == 3) + { + if (i != 4 && motherG4->get_pid() == decay[3].second && motherG4->get_barcode() == decay[3].first.second && daughterG4->get_pid() == decay[i].second && daughterG4->get_barcode() == decay[i].first.second) + { + PHG4Particle *motherG4_temp = nullptr; + if (motherG4->get_parent_id() != 0) + { + motherG4_temp = m_truthInfo->GetParticle(motherG4->get_parent_id()); + } + else + { + continue; + } + + if (motherG4_temp->get_pid() == decay[0].second && motherG4_temp->get_barcode() == decay[0].first.second) + { + motherG4 = motherG4_temp; + } + else + { + continue; + } + } + else if (i != 4) + { + continue; + } + + if (i==4 && !(motherG4->get_pid() == decay[0].second && motherG4->get_barcode() == decay[0].first.second && daughterG4->get_pid() == decay[i].second && daughterG4->get_barcode() == decay[i].first.second)) + { + continue; + } + if (Verbosity() >= VERBOSITY_MORE) { daughterG4->identify(); } + m_is_primary = m_truthInfo->is_sPHENIX_primary(motherG4); + CLHEP::Hep3Vector *mother3Vector = new CLHEP::Hep3Vector(motherG4->get_px(), motherG4->get_py(), motherG4->get_pz()); motherTrueLV->setVectM((*mother3Vector), getParticleMass(decay[0].second)); m_true_mother_pT = motherTrueLV->perp(); m_true_mother_p = mother3Vector->mag(); m_true_mother_eta = motherTrueLV->pseudoRapidity(); + m_true_mother_phi = motherTrueLV->phi(); + m_true_mother_rapidity = motherTrueLV->rapidity(); PHG4VtxPoint *thisVtx = m_truthInfo->GetVtx(motherG4->get_vtx_id()); m_primary_vtx_x = thisVtx->get_x(); @@ -310,36 +390,27 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) m_secondary_vtx_y = thisVtx->get_y(); m_secondary_vtx_z = thisVtx->get_z(); - m_true_track_PID[i - 1] = daughterG4->get_pid(); - truth_ID = daughterG4->get_track_id(); + m_true_track_PID[index] = daughterG4->get_pid(); delete mother3Vector; + break; } } } - m_true_track_pT[i - 1] = (float) daughterTrueLV->perp(); - m_true_track_eta[i - 1] = (float) daughterTrueLV->pseudoRapidity(); - m_min_true_track_pT = std::min(m_true_track_pT[i - 1], m_min_true_track_pT); - m_max_true_track_pT = std::max(m_true_track_pT[i - 1], m_max_true_track_pT); + m_true_track_pT[index] = (float) daughterTrueLV->perp(); + m_true_track_eta[index] = (float) daughterTrueLV->pseudoRapidity(); + m_true_track_rapidity[index] = (float) daughterTrueLV->rapidity(); + m_true_track_phi[index] = (float) daughterTrueLV->phi(); + m_min_true_track_pT = std::min(m_true_track_pT[index], m_min_true_track_pT); + m_max_true_track_pT = std::max(m_true_track_pT[index], m_max_true_track_pT); - if (m_dst_truth_reco_map && truth_ID >= 0) + if (trackeval && daughterG4) { - std::map> reco_set = m_dst_truth_reco_map->get(truth_ID); - if (reco_set.empty()) - { - continue; - } - const auto &best_weight = reco_set.rbegin(); - if (best_weight->second.empty()) - { - continue; - } - unsigned int best_reco_id = *best_weight->second.rbegin(); - m_dst_track = m_input_trackMap->get(best_reco_id); + m_dst_track = trackeval->best_track_from(daughterG4); if (m_dst_track) { - m_used_truth_reco_map[i - 1] = true; + m_used_truth_reco_map[index] = true; recoTrackFound = true; } } @@ -367,24 +438,49 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) { m_dst_track->identify(); } - m_reco_track_exists[i - 1] = true; - m_reco_track_pT[i - 1] = m_dst_track->get_pt(); - m_reco_track_eta[i - 1] = m_dst_track->get_eta(); - m_reco_track_chi2nDoF[i - 1] = m_dst_track->get_chisq() / m_dst_track->get_ndf(); - if (m_dst_track->get_silicon_seed()) + m_reco_track_exists[index] = true; + m_reco_track_pT[index] = m_dst_track->get_pt(); + m_reco_track_eta[index] = m_dst_track->get_eta(); + m_reco_track_phi[index] = m_dst_track->get_phi(); + m_reco_track_chi2nDoF[index] = m_dst_track->get_chisq() / m_dst_track->get_ndf(); + m_reco_track_silicon_seeds[index] = 0; + m_reco_track_tpc_seeds[index] = 0; + + for (auto state_iter = m_dst_track->begin_states(); + state_iter != m_dst_track->end_states(); + ++state_iter) { - m_reco_track_silicon_seeds[i - 1] = static_cast(m_dst_track->get_silicon_seed()->size_cluster_keys()); - } - else - { - m_reco_track_silicon_seeds[i - 1] = 0; + SvtxTrackState *tstate = state_iter->second; + if (tstate->get_pathlength() != 0) // The first track state is an extrapolation so has no cluster + { + auto stateckey = tstate->get_cluskey(); + if (stateckey == TrkrDefs::CLUSKEYMAX) + { + continue; + } + uint8_t id = TrkrDefs::getTrkrId(stateckey); + + switch (id) + { + case TrkrDefs::mvtxId: + [[fallthrough]]; + case TrkrDefs::inttId: + ++m_reco_track_silicon_seeds[index]; + break; + case TrkrDefs::tpcId: + ++m_reco_track_tpc_seeds[index]; + break; + default: + break; + } + } } - m_reco_track_tpc_seeds[i - 1] = static_cast(m_dst_track->get_tpc_seed()->size_cluster_keys()); - m_min_reco_track_pT = std::min(m_reco_track_pT[i - 1], m_min_reco_track_pT); - m_max_reco_track_pT = std::max(m_reco_track_pT[i - 1], m_max_reco_track_pT); + + m_min_reco_track_pT = std::min(m_reco_track_pT[index], m_min_reco_track_pT); + m_max_reco_track_pT = std::max(m_reco_track_pT[index], m_max_reco_track_pT); CLHEP::HepLorentzVector *daughterRecoLV = new CLHEP::HepLorentzVector(); - daughterRecoLV->setVectM(CLHEP::Hep3Vector(m_dst_track->get_px(), m_dst_track->get_py(), m_dst_track->get_pz()), getParticleMass(m_true_track_PID[i - 1])); + daughterRecoLV->setVectM(CLHEP::Hep3Vector(m_dst_track->get_px(), m_dst_track->get_py(), m_dst_track->get_pz()), getParticleMass(m_true_track_PID[index])); motherRecoLV += *daughterRecoLV; delete daughterRecoLV; @@ -399,6 +495,7 @@ bool HFTrackEfficiency::findTracks(PHCompositeNode *topNode, Decay decay) if (selectedTracks.size() == m_nDaughters) { m_reco_mother_mass = motherRecoLV.m(); + m_reco_mother_pT = motherRecoLV.perp(); if (m_write_track_map) { m_output_trackMap = findNode::getClass(topNode, outputNodeName); @@ -429,11 +526,15 @@ void HFTrackEfficiency::initializeBranches() m_tree->SetAutoSave(-5e6); // Save the output file every 5MB m_tree->Branch("all_tracks_reconstructed", &m_all_tracks_reconstructed, "all_tracks_reconstructed/O"); + m_tree->Branch("is_primary", &m_is_primary, "is_primary/O"); m_tree->Branch("true_mother_mass", &m_true_mother_mass, "true_mother_mass/F"); m_tree->Branch("reco_mother_mass", &m_reco_mother_mass, "reco_mother_mass/F"); m_tree->Branch("true_mother_pT", &m_true_mother_pT, "true_mother_pT/F"); + m_tree->Branch("reco_mother_pT", &m_reco_mother_pT, "reco_mother_pT/F"); m_tree->Branch("true_mother_p", &m_true_mother_p, "true_mother_p/F"); m_tree->Branch("true_mother_eta", &m_true_mother_eta, "true_mother_eta/F"); + m_tree->Branch("true_mother_rapidity", &m_true_mother_rapidity, "true_mother_rapidity/F"); + m_tree->Branch("true_mother_phi", &m_true_mother_phi, "true_mother_phi/F"); m_tree->Branch("min_true_track_pT", &m_min_true_track_pT, "min_true_track_pT/F"); m_tree->Branch("min_reco_track_pT", &m_min_reco_track_pT, "min_reco_track_pT/F"); m_tree->Branch("max_true_track_pT", &m_max_true_track_pT, "max_true_track_pT/F"); @@ -448,6 +549,9 @@ void HFTrackEfficiency::initializeBranches() m_tree->Branch("reco_" + TString(daughter_number) + "_pT", &m_reco_track_pT[iTrack], "reco_" + TString(daughter_number) + "_pT/F"); m_tree->Branch("true_" + TString(daughter_number) + "_eta", &m_true_track_eta[iTrack], "true_" + TString(daughter_number) + "_eta/F"); m_tree->Branch("reco_" + TString(daughter_number) + "_eta", &m_reco_track_eta[iTrack], "reco_" + TString(daughter_number) + "_eta/F"); + m_tree->Branch("true_" + TString(daughter_number) + "_rapidity", &m_true_track_rapidity[iTrack], "true_" + TString(daughter_number) + "_rapidity/F"); + m_tree->Branch("true_" + TString(daughter_number) + "_phi", &m_true_track_phi[iTrack], "true_" + TString(daughter_number) + "_phi/F"); + m_tree->Branch("reco_" + TString(daughter_number) + "_phi", &m_reco_track_phi[iTrack], "reco_" + TString(daughter_number) + "_phi/F"); m_tree->Branch("true_" + TString(daughter_number) + "_PID", &m_true_track_PID[iTrack], "true_" + TString(daughter_number) + "_PID/F"); m_tree->Branch("reco_" + TString(daughter_number) + "_chi2nDoF", &m_reco_track_chi2nDoF[iTrack], "reco_" + TString(daughter_number) + "_chi2nDoF/F"); m_tree->Branch("reco_" + TString(daughter_number) + "_silicon_seeds", &m_reco_track_silicon_seeds[iTrack], "reco_" + TString(daughter_number) + "_silicon_seeds/I"); @@ -465,11 +569,14 @@ void HFTrackEfficiency::initializeBranches() void HFTrackEfficiency::resetBranches() { m_all_tracks_reconstructed = false; + m_is_primary = false; m_true_mother_mass = std::numeric_limits::quiet_NaN(); m_reco_mother_mass = std::numeric_limits::quiet_NaN(); m_true_mother_pT = std::numeric_limits::quiet_NaN(); + m_reco_mother_pT = std::numeric_limits::quiet_NaN(); m_true_mother_p = std::numeric_limits::quiet_NaN(); m_true_mother_eta = std::numeric_limits::quiet_NaN(); + m_true_mother_rapidity = std::numeric_limits::quiet_NaN(); m_min_true_track_pT = std::numeric_limits::max(); m_min_reco_track_pT = std::numeric_limits::max(); m_max_true_track_pT = -1 * std::numeric_limits::max(); @@ -482,10 +589,13 @@ void HFTrackEfficiency::resetBranches() m_reco_track_pT[iTrack] = std::numeric_limits::quiet_NaN(); m_true_track_eta[iTrack] = std::numeric_limits::quiet_NaN(); m_reco_track_eta[iTrack] = std::numeric_limits::quiet_NaN(); + m_true_track_rapidity[iTrack] = std::numeric_limits::quiet_NaN(); + m_true_track_phi[iTrack] = std::numeric_limits::quiet_NaN(); + m_reco_track_phi[iTrack] = std::numeric_limits::quiet_NaN(); m_true_track_PID[iTrack] = std::numeric_limits::quiet_NaN(); m_reco_track_chi2nDoF[iTrack] = std::numeric_limits::quiet_NaN(); - m_reco_track_silicon_seeds[iTrack] = 0; - m_reco_track_tpc_seeds[iTrack] = 0; + m_reco_track_silicon_seeds[iTrack] = -1; + m_reco_track_tpc_seeds[iTrack] = -1; } m_primary_vtx_x = std::numeric_limits::quiet_NaN(); diff --git a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h index ddd346c7a4..ee5c0969f8 100644 --- a/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h +++ b/offline/packages/HFTrackEfficiency/HFTrackEfficiency.h @@ -4,6 +4,8 @@ #define HFTRACKEFFICIENCY_H #include +#include +#include #include #include @@ -54,7 +56,9 @@ class HFTrackEfficiency : public SubsysReco PHHepMCGenEventMap *m_geneventmap{nullptr}; PHHepMCGenEvent *m_genevt{nullptr}; - PHG4ParticleSvtxMap *m_dst_truth_reco_map{nullptr}; + SvtxEvalStack *m_svtx_evalstack{nullptr}; + SvtxTrackEval *trackeval{nullptr}; + //PHG4ParticleSvtxMap *m_dst_truth_reco_map{nullptr}; DecayFinderContainerBase *m_decayMap{nullptr}; std::string m_df_module_name; @@ -89,11 +93,15 @@ class HFTrackEfficiency : public SubsysReco static const int m_maxTracks{5}; bool m_all_tracks_reconstructed{false}; + bool m_is_primary{false}; float m_true_mother_mass{std::numeric_limits::quiet_NaN()}; float m_reco_mother_mass{std::numeric_limits::quiet_NaN()}; float m_true_mother_pT{std::numeric_limits::quiet_NaN()}; + float m_reco_mother_pT{std::numeric_limits::quiet_NaN()}; float m_true_mother_p{std::numeric_limits::quiet_NaN()}; float m_true_mother_eta{std::numeric_limits::quiet_NaN()}; + float m_true_mother_rapidity{std::numeric_limits::quiet_NaN()}; + float m_true_mother_phi{std::numeric_limits::quiet_NaN()}; float m_min_true_track_pT{std::numeric_limits::max()}; float m_min_reco_track_pT{std::numeric_limits::max()}; float m_max_true_track_pT{std::numeric_limits::min()}; // Apparently min() is still a +ve value @@ -104,6 +112,9 @@ class HFTrackEfficiency : public SubsysReco float m_reco_track_pT[m_maxTracks]{std::numeric_limits::quiet_NaN()}; float m_true_track_eta[m_maxTracks]{std::numeric_limits::quiet_NaN()}; float m_reco_track_eta[m_maxTracks]{std::numeric_limits::quiet_NaN()}; + float m_true_track_rapidity[m_maxTracks]{std::numeric_limits::quiet_NaN()}; + float m_true_track_phi[m_maxTracks]{std::numeric_limits::quiet_NaN()}; + float m_reco_track_phi[m_maxTracks]{std::numeric_limits::quiet_NaN()}; float m_true_track_PID[m_maxTracks]{std::numeric_limits::quiet_NaN()}; float m_reco_track_chi2nDoF[m_maxTracks]{std::numeric_limits::quiet_NaN()}; int m_reco_track_silicon_seeds[m_maxTracks]{0}; diff --git a/offline/packages/HFTrackEfficiency/Makefile.am b/offline/packages/HFTrackEfficiency/Makefile.am index ed47b011eb..7b53aed68f 100644 --- a/offline/packages/HFTrackEfficiency/Makefile.am +++ b/offline/packages/HFTrackEfficiency/Makefile.am @@ -24,7 +24,8 @@ libhftrackefficiency_la_LIBADD = \ -ldecayfinder_io \ -ltrackbase_historic_io \ -lphg4hit \ - -lphhepmc + -lphhepmc \ + -lg4eval ################################################ # linking tests diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc index b319af5b56..f62e79f313 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.cc @@ -26,6 +26,7 @@ /*****************/ #include "KFParticle_Tools.h" +#include "KFParticle_truthAndDetTools.h" #include #include @@ -55,8 +56,6 @@ #include #include #include -#include "KFParticle_truthAndDetTools.h" - #include #include // for TMatrixD #include // for TMatrixT, operator* @@ -68,27 +67,26 @@ #include // for abs, NULL #include // for operator<<, basic_ostream #include // for end +#include #include // for _Rb_tree_iterator, map #include // for allocator_traits<>::va... -KFParticle_truthAndDetTools toolSet; - /// KFParticle constructor KFParticle_Tools::KFParticle_Tools() : m_has_intermediates(false) , m_min_mass(0) , m_max_mass(0) - , m_min_decayTime(-1 * FLT_MAX) - , m_max_decayTime(FLT_MAX) - , m_min_decayLength(-1 * FLT_MAX) - , m_max_decayLength(FLT_MAX) + , m_min_decayTime(-1 * std::numeric_limits::max()) + , m_max_decayTime(std::numeric_limits::max()) + , m_min_decayLength(-1 * std::numeric_limits::max()) + , m_max_decayLength(std::numeric_limits::max()) , m_track_min_pt(0.) , m_track_max_pt(5e3) - , m_track_ptchi2(FLT_MAX) - , m_track_ip_xy(-100.) - , m_track_ipchi2_xy(-1) - , m_track_ip(-1.) - , m_track_ipchi2(-1) + , m_track_ptchi2(std::numeric_limits::max()) + , m_track_PV_dca_xy(-100.) + , m_track_PV_dca_stddev_xy(-1) + , m_track_PV_dca(-1.) + , m_track_PV_dca_stddev(-1) , m_track_chi2ndof(100.) , m_nMVTXStates(3) , m_nINTTStates(1) @@ -101,7 +99,7 @@ KFParticle_Tools::KFParticle_Tools() , m_dira_min(-1.01) , m_dira_max(1.01) , m_mother_pt(0.) - , m_mother_ipchi2(FLT_MAX) + , m_mother_PV_dca_stddev(std::numeric_limits::max()) , m_get_charge_conjugate(false) , m_extrapolateTracksToSV(true) , m_vtx_map_node_name("SvtxVertexMap") @@ -327,6 +325,14 @@ std::vector KFParticle_Tools::makeAllDaughterParticles(PHCompositeNo } } + if (m_verbosity > 100) + { + printSelectionCheck("MVTX states", m_nMVTXStates, MVTX_states, 5); + printSelectionCheck("INTT states", m_nINTTStates, INTT_states, 5); + printSelectionCheck("TPC states", m_nTPCStates, TPC_states, 100); + printSelectionCheck("TPOT states", m_nTPOTStates, TPOT_states, 5); + } + if (MVTX_states < m_nMVTXStates) { continue; @@ -436,10 +442,10 @@ int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, const KFPart { bool goodTrack = false; - float min_ip = 0; - float min_ipchi2 = 0; - float min_ip_xy = 0; - float min_ipchi2_xy = 0; + float min_PV_dca = 0; + float min_PV_dca_stddev = 0; + float min_PV_dca_xy = 0; + float min_PV_dca_stddev_xy = 0; float pt = 0; float pterr = 0; @@ -453,59 +459,74 @@ int KFParticle_Tools::getTracksFromVertex(PHCompositeNode *topNode, const KFPart float ptchi2 = pow(pterr / pt, 2); float trackchi2ndof = particle.GetChi2() / particle.GetNDF(); - calcMinIP(particle, primaryVertices, min_ip, min_ipchi2); - calcMinIP(particle, primaryVertices, min_ip_xy, min_ipchi2_xy, false); + calcMinPV_DCA(particle, primaryVertices, min_PV_dca, min_PV_dca_stddev); + calcMinPV_DCA(particle, primaryVertices, min_PV_dca_xy, min_PV_dca_stddev_xy, false); - if (isInRange(m_track_min_pt, pt, m_track_max_pt) && ptchi2 <= m_track_ptchi2 && min_ip >= m_track_ip && min_ipchi2 >= m_track_ipchi2 && min_ip_xy >= m_track_ip_xy && min_ipchi2_xy >= m_track_ipchi2_xy && trackchi2ndof <= m_track_chi2ndof) + if (isInRange(m_track_min_pt, pt, m_track_max_pt) && ptchi2 <= m_track_ptchi2 && min_PV_dca >= m_track_PV_dca && min_PV_dca_stddev >= m_track_PV_dca_stddev && min_PV_dca_xy >= m_track_PV_dca_xy && min_PV_dca_stddev_xy >= m_track_PV_dca_stddev_xy && trackchi2ndof <= m_track_chi2ndof) { goodTrack = true; } + + + if (m_verbosity >= 10) + { + printSelectionCheck("This track", "passed", "failed", "the selection", goodTrack); + if (m_verbosity >= 11) + { + printSelectionCheck("Track pT", m_track_min_pt, pt, m_track_max_pt); + printSelectionCheck("Track pT chi^2", 0, ptchi2, m_track_ptchi2); + printSelectionCheck("PV DCA", m_track_PV_dca, min_PV_dca, std::numeric_limits::max()); + printSelectionCheck("PV DCA Std. Dev.", m_track_PV_dca_stddev, min_PV_dca_stddev, std::numeric_limits::max()); + printSelectionCheck("PV DCA xy", m_track_PV_dca_xy, min_PV_dca_xy, std::numeric_limits::max()); + printSelectionCheck("PV DCA xy Std. Dev.", m_track_PV_dca_stddev_xy, min_PV_dca_stddev_xy, std::numeric_limits::max()); + printSelectionCheck("Track chi^2/nDoF", 0, trackchi2ndof, m_track_chi2ndof); + } + } + return goodTrack; } -int KFParticle_Tools::calcMinIP(const KFParticle &track, const std::vector &PVs, - float &minimumIP, float &minimumIPchi2, bool do3D) +int KFParticle_Tools::calcMinPV_DCA(const KFParticle &track, const std::vector &PVs, + float &minimumPV_DCA, float &minimumPV_DCA_stddev, bool do3D) { std::vector ip; - std::vector ipchi2; + std::vector ip_significance; for (const auto &PV : PVs) { - float thisIPchi2 = 0; + float thisPV_DCA_stddev = 0; if (do3D) { ip.push_back(track.GetDistanceFromVertex(PV)); - track.GetDeviationFromVertex(PV); + thisPV_DCA_stddev = track.GetDeviationFromVertex(PV); } else { ip.push_back(abs(track.GetDistanceFromVertexXY(PV))); - track.GetDeviationFromVertexXY(PV); + thisPV_DCA_stddev = track.GetDeviationFromVertexXY(PV); } - thisIPchi2 = std::max(thisIPchi2, 0.F); - ipchi2.push_back(thisIPchi2); // Τhere are times where the IPchi2 calc fails + thisPV_DCA_stddev = std::max(thisPV_DCA_stddev, 0.F); + ip_significance.push_back(thisPV_DCA_stddev); // Τhere are times where the PV_DCA_stddev calc fails } - auto minmax_ip = minmax_element(ip.begin(), ip.end()); // Order the IP from small to large - minimumIP = *minmax_ip.first; - auto minmax_ipchi2 = minmax_element(ipchi2.begin(), ipchi2.end()); // Order the IP chi2 from small to large - minimumIPchi2 = *minmax_ipchi2.first; + auto minmax_PV_dca = minmax_element(ip.begin(), ip.end()); // Order the PV_DCA from small to large + minimumPV_DCA = *minmax_PV_dca.first; + auto minmax_PV_dca_stddev = minmax_element(ip_significance.begin(), ip_significance.end()); // Order the PV_DCA chi2 from small to large + minimumPV_DCA_stddev = *minmax_PV_dca_stddev.first; return 0; } -std::vector KFParticle_Tools::findAllGoodTracks(const std::vector &daughterParticles, const std::vector &primaryVertices) +std::vector KFParticle_Tools::findAllGoodTracks(const std::vector &daughterParticles)//, const std::vector &primaryVertices) { std::vector goodTrackIndex; + goodTrackIndex.reserve(daughterParticles.size()); for (unsigned int i_parts = 0; i_parts < daughterParticles.size(); ++i_parts) { - if (isGoodTrack(daughterParticles[i_parts], primaryVertices)) - { - goodTrackIndex.push_back(i_parts); - } + goodTrackIndex.push_back(i_parts); } removeDuplicates(goodTrackIndex); @@ -513,7 +534,7 @@ std::vector KFParticle_Tools::findAllGoodTracks(const std::vector> KFParticle_Tools::findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks) const +std::vector> KFParticle_Tools::findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks, const std::vector &primaryVertices) { std::vector> goodTracksThatMeet; @@ -523,26 +544,101 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector dummy_tracks = {daughterParticles[*i_it], daughterParticles[*j_it]}; + if (m_require_bunch_crossing_match) + { + std::vector crossings; + crossings.reserve(dummy_tracks.size()); + for (const auto &track : dummy_tracks) + { + SvtxTrack *thisTrack = KFParticle_truthAndDetTools::getTrack(track.Id(), m_dst_trackmap); + if (thisTrack) + { + crossings.push_back(thisTrack->get_crossing()); + } + } + + removeDuplicates(crossings); + + if (crossings.size() !=1) + { + continue; + } + } + + KFParticle dummy_mother; + dummy_mother.SetConstructMethod(2); + + for (auto &track : dummy_tracks) + { + dummy_mother.AddDaughter(track); + } + for (auto &track : dummy_tracks) + { + track.SetProductionVertex(dummy_mother); + } + + float dca = dummy_tracks[0].GetDistanceFromParticle(dummy_tracks[1]); + float dca_xy = std::abs(dummy_tracks[0].GetDistanceFromParticleXY(dummy_tracks[1])); + + if (m_verbosity >= 10) + { + printSelectionCheck("This track pair", "passed", "failed", "the DCA selection", (dca <= m_comb_DCA) && (dca_xy <= m_comb_DCA_xy)); + if (m_verbosity >= 11) + { + printSelectionCheck("Pair DCA", 0., dca, m_comb_DCA); + printSelectionCheck("Pair DCA xy", 0., dca_xy, m_comb_DCA_xy); + } + } if (dca <= m_comb_DCA && dca_xy <= m_comb_DCA_xy) { KFVertex twoParticleVertex; - twoParticleVertex += daughterParticles[*i_it]; - twoParticleVertex += daughterParticles[*j_it]; + twoParticleVertex += dummy_tracks[0]; + twoParticleVertex += dummy_tracks[1]; float vertexchi2ndof = twoParticleVertex.GetChi2() / twoParticleVertex.GetNDF(); float sv_radial_position = sqrt(pow(twoParticleVertex.GetX(), 2) + pow(twoParticleVertex.GetY(), 2)); std::vector combination = {*i_it, *j_it}; - if (nTracks == 2 && vertexchi2ndof > m_vertex_chi2ndof) + if (nTracks == 2 && m_verbosity >= 10) { - continue; + printSelectionCheck("This track pair", "passed", "failed", "the quality and radius selection", (vertexchi2ndof <= m_vertex_chi2ndof) && (sv_radial_position >= m_min_radial_SV)); + if (m_verbosity >= 11) + { + printSelectionCheck("SV chi^2/nDoF", 0., vertexchi2ndof, m_vertex_chi2ndof); + printSelectionCheck("SV radius", m_min_radial_SV, sv_radial_position, std::numeric_limits::max()); + } } - if (nTracks == 2 && sv_radial_position < m_min_radial_SV) + //Now check if tracks are good as we need full reco to make DCA calc make sense + if (nTracks == 2) { - continue; + if (vertexchi2ndof > m_vertex_chi2ndof) + { + continue; + } + + if (sv_radial_position < m_min_radial_SV) + { + continue; + } + + bool rejectComboDueToTrack = false; + + for (auto &track : dummy_tracks) + { + bool trackPassesCuts = isGoodTrack(track, primaryVertices); + if (!trackPassesCuts) + { + rejectComboDueToTrack = true; + } + } + + if (rejectComboDueToTrack) + { + continue; + } + } goodTracksThatMeet.push_back(combination); @@ -554,10 +650,10 @@ std::vector> KFParticle_Tools::findTwoProngs(std::vector> KFParticle_Tools::findNProngs(std::vector daughterParticles, +std::vector> KFParticle_Tools::findNProngs(const std::vector &daughterParticles, const std::vector &goodTrackIndex, std::vector> goodTracksThatMeet, - int nRequiredTracks, unsigned int nProngs) + int nRequiredTracks, unsigned int nProngs, const std::vector &primaryVertices) { unsigned int nGoodProngs = goodTracksThatMeet.size(); @@ -576,10 +672,50 @@ std::vector> KFParticle_Tools::findNProngs(std::vector combination; + combination.push_back(i_it); for (unsigned int i = 0; i < nProngs - 1; ++i) { - float dca = daughterParticles[i_it].GetDistanceFromParticle(daughterParticles[goodTracksThatMeet[i_prongs][i]]); - float dca_xy = abs(daughterParticles[i_it].GetDistanceFromParticleXY(daughterParticles[goodTracksThatMeet[i_prongs][i]])); + particleVertex += daughterParticles[goodTracksThatMeet[i_prongs][i]]; + combination.push_back(goodTracksThatMeet[i_prongs][i]); + } + + KFParticle dummy_mother; + std::vector dummy_tracks; + dummy_tracks.reserve(combination.size()); + for (auto &id : combination) + { + dummy_tracks.push_back(daughterParticles[id]); + } + dummy_mother.SetConstructMethod(2); + + for (auto &track : dummy_tracks) + { + dummy_mother.AddDaughter(track); + } + for (auto &track : dummy_tracks) + { + track.SetProductionVertex(dummy_mother); + } + + for (unsigned int i = 1; i < combination.size(); ++i) + { + float dca = dummy_tracks[0].GetDistanceFromParticle(dummy_tracks[i]); + float dca_xy = dummy_tracks[0].GetDistanceFromParticleXY(dummy_tracks[i]); + + if (m_verbosity >= 10) + { + printSelectionCheck("This track", "combined", "did not combine", "with a SV set", (dca <= m_comb_DCA) && (dca_xy <= m_comb_DCA_xy)); + if (m_verbosity >= 11) + { + printSelectionCheck("Pair DCA", 0., dca, m_comb_DCA); + printSelectionCheck("Pair DCA xy", 0., dca_xy, m_comb_DCA_xy); + } + } if (dca > m_comb_DCA || dca_xy > m_comb_DCA_xy) { @@ -589,26 +725,46 @@ std::vector> KFParticle_Tools::findNProngs(std::vector combination; - combination.push_back(i_it); - for (unsigned int i = 0; i < nProngs - 1; ++i) - { - particleVertex += daughterParticles[goodTracksThatMeet[i_prongs][i]]; - combination.push_back(goodTracksThatMeet[i_prongs][i]); - } float vertexchi2ndof = particleVertex.GetChi2() / particleVertex.GetNDF(); float sv_radial_position = sqrt(pow(particleVertex.GetX(), 2) + pow(particleVertex.GetY(), 2)); - if ((unsigned int) nRequiredTracks == nProngs && vertexchi2ndof > m_vertex_chi2ndof) + if ((unsigned int) nRequiredTracks == nProngs && m_verbosity >= 10) { - continue; + printSelectionCheck("This SV combination", "passed", "failed", "the quality and radius selection", (vertexchi2ndof <= m_vertex_chi2ndof) && (sv_radial_position >= m_min_radial_SV)); + if (m_verbosity >= 11) + { + printSelectionCheck("SV chi^2/nDoF", 0., vertexchi2ndof, m_vertex_chi2ndof); + printSelectionCheck("SV radius", m_min_radial_SV, sv_radial_position, std::numeric_limits::max()); + } } - if ((unsigned int) nRequiredTracks == nProngs && sv_radial_position < m_min_radial_SV) + if ((unsigned int) nRequiredTracks == nProngs) { - continue; + if (vertexchi2ndof > m_vertex_chi2ndof) + { + continue; + } + + if (sv_radial_position < m_min_radial_SV) + { + continue; + } + + bool rejectComboDueToTrack = false; + + for (auto &track : dummy_tracks) + { + bool trackPassesCuts = isGoodTrack(track, primaryVertices); + if (!trackPassesCuts) + { + rejectComboDueToTrack = true; + } + } + + if (rejectComboDueToTrack) + { + continue; + } } goodTracksThatMeet.push_back(combination); @@ -627,7 +783,7 @@ std::vector> KFParticle_Tools::findNProngs(std::vector> KFParticle_Tools::appendTracksToIntermediates(KFParticle intermediateResonances[], const std::vector &daughterParticles, const std::vector &goodTrackIndex, int num_remaining_tracks) +std::vector> KFParticle_Tools::appendTracksToIntermediates(KFParticle intermediateResonances[], const std::vector &daughterParticles, const std::vector &goodTrackIndex, int num_remaining_tracks, const std::vector &primaryVertices) { std::vector> goodTracksThatMeet; std::vector> goodTracksThatMeetIntermediates; //, vectorOfGoodTracks; @@ -644,14 +800,14 @@ std::vector> KFParticle_Tools::appendTracksToIntermediates(KFPa { dummyTrackID.push_back(k); } - dummyTrackList = findTwoProngs(v_intermediateResonances, dummyTrackID, (int) v_intermediateResonances.size()); + dummyTrackList = findTwoProngs(v_intermediateResonances, dummyTrackID, (int) v_intermediateResonances.size(), primaryVertices); if (v_intermediateResonances.size() > 2) { for (unsigned int p = 3; p <= v_intermediateResonances.size(); ++p) { dummyTrackList = findNProngs(v_intermediateResonances, dummyTrackID, dummyTrackList, - (int) v_intermediateResonances.size(), (int) p); + (int) v_intermediateResonances.size(), (int) p, primaryVertices); } } @@ -664,11 +820,11 @@ std::vector> KFParticle_Tools::appendTracksToIntermediates(KFPa } else { - goodTracksThatMeet = findTwoProngs(daughterParticles, goodTrackIndex, num_remaining_tracks); + goodTracksThatMeet = findTwoProngs(daughterParticles, goodTrackIndex, num_remaining_tracks, primaryVertices); for (int p = 3; p <= num_remaining_tracks; ++p) { - goodTracksThatMeet = findNProngs(daughterParticles, goodTrackIndex, goodTracksThatMeet, num_remaining_tracks, p); + goodTracksThatMeet = findNProngs(daughterParticles, goodTrackIndex, goodTracksThatMeet, num_remaining_tracks, p, primaryVertices); } for (auto &i : goodTracksThatMeet) @@ -678,17 +834,18 @@ std::vector> KFParticle_Tools::appendTracksToIntermediates(KFPa std::vector dummyTrackID; // I already have the track ids stored in goodTracksThatMeet[i] for (int j : i) { - v_intermediateResonances.push_back(daughterParticles[i[j]]); + v_intermediateResonances.push_back(daughterParticles[j]); + //v_intermediateResonances.push_back(daughterParticles[i[j]]); } dummyTrackID.reserve(v_intermediateResonances.size()); for (unsigned int k = 0; k < v_intermediateResonances.size(); ++k) { dummyTrackID.push_back(k); } - dummyTrackList = findTwoProngs(v_intermediateResonances, dummyTrackID, (int) v_intermediateResonances.size()); + dummyTrackList = findTwoProngs(v_intermediateResonances, dummyTrackID, (int) v_intermediateResonances.size(), primaryVertices); for (unsigned int p = 3; p <= v_intermediateResonances.size(); ++p) { - dummyTrackList = findNProngs(v_intermediateResonances, dummyTrackID, dummyTrackList, (int) v_intermediateResonances.size(), (int) p); + dummyTrackList = findNProngs(v_intermediateResonances, dummyTrackID, dummyTrackList, (int) v_intermediateResonances.size(), (int) p, primaryVertices); } if (!dummyTrackList.empty()) @@ -825,6 +982,12 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters float calculated_dEdx_value = get_dEdx(topNode, vDaughters[i]); double expected_dEdx_value = get_dEdx_fitValue((Int_t) vDaughters[i].GetQ() * vDaughters[i].GetP(), track_PDG_ID); bool accept_dEdx = isInRange((1 - m_dEdx_band_width) * expected_dEdx_value, calculated_dEdx_value, (1 + m_dEdx_band_width) * expected_dEdx_value); + + if (m_verbosity >= 11) + { + printSelectionCheck("dE/dx check", (1 - m_dEdx_band_width) * expected_dEdx_value, calculated_dEdx_value, (1 + m_dEdx_band_width) * expected_dEdx_value); + } + if (!accept_dEdx) { delete[] inputTracks; @@ -875,7 +1038,9 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters float calculated_mass; float calculated_mass_err; mother.GetMass(calculated_mass, calculated_mass_err); - float calculated_pt = mother.GetPt(); + float calculated_pt; + float calculated_pt_err; + mother.GetPt(calculated_pt, calculated_pt_err); float min_mass = isIntermediate ? m_intermediate_mass_range[intermediateNumber].first : m_min_mass; float max_mass = isIntermediate ? m_intermediate_mass_range[intermediateNumber].second : m_max_mass; @@ -909,6 +1074,12 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters { goodCandidate = false; } + + if (m_verbosity >= 11) + { + bool accept = crossings.size() == 1; + printSelectionCheck("", "All tracks are from the same BC", "Tracks are from different BC", "", accept); + } } // Check the requirements of an intermediate states against this mother and re-do goodCandidate @@ -923,6 +1094,28 @@ std::tuple KFParticle_Tools::buildMother(KFParticle vDaughters { goodCandidate = false; } + + if (m_verbosity >= 10) + { + printSelectionCheck("", "Accepted", "Rejected", "the intermediate selection", goodCandidate); + if (m_verbosity >= 11) + { + printSelectionCheck("Intermediate DIRA", m_intermediate_min_dira[k], intermediate_DIRA, std::numeric_limits::max()); + printSelectionCheck("Intermediate FD chi^2", m_intermediate_min_fdchi2[k], intermediate_FDchi2, std::numeric_limits::max()); + } + } + } + } + + if (m_verbosity >= 10) + { + printSelectionCheck("", "Accepted", "Rejected", "the mother selection", goodCandidate); + if (m_verbosity >= 11) + { + printSelectionCheck("Vertex charge is", "right", "wrong", "", chargeCheck); + printSelectionCheck("Invariant Mass", min_mass, calculated_mass, max_mass); + printSelectionCheck("Mother pT", min_pt, calculated_pt, std::numeric_limits::max()); + printSelectionCheck("Mother SV volume", 0., calculateEllipsoidVolume(mother), max_vertex_volume); } } delete[] inputTracks; @@ -950,11 +1143,11 @@ void KFParticle_Tools::constrainToVertex(KFParticle &particle, bool &goodCandida float calculated_fdchi2 = flightDistanceChi2(particle, vertex); - float calculated_ip_xy = abs(particle.GetDistanceFromVertexXY(vertex)); - float calculated_ipchi2_xy = particle.GetDeviationFromVertexXY(vertex); + float calculated_PV_dca_xy = abs(particle.GetDistanceFromVertexXY(vertex)); + float calculated_PV_dca_stddev_xy = particle.GetDeviationFromVertexXY(vertex); float calculated_dira_xy = eventDIRA(particle, vertex, false); - float calculated_ip = particle.GetDistanceFromVertex(vertex); - float calculated_ipchi2 = particle.GetDeviationFromVertex(vertex); + float calculated_PV_dca = particle.GetDistanceFromVertex(vertex); + float calculated_PV_dca_stddev = particle.GetDeviationFromVertex(vertex); float calculated_dira = eventDIRA(particle, vertex); float calculated_decay_time_significance = calculated_decayTime / calculated_decayTimeErr; @@ -966,10 +1159,32 @@ void KFParticle_Tools::constrainToVertex(KFParticle &particle, bool &goodCandida const float speed = 2.99792458e-2; calculated_decayTime /= speed; - if (calculated_fdchi2 >= m_fdchi2 && calculated_ip <= m_mother_ip && calculated_ipchi2 <= m_mother_ipchi2 && calculated_ip_xy <= m_mother_ip_xy && calculated_ipchi2_xy <= m_mother_ipchi2_xy && calculated_decay_time_significance >= m_mother_min_decay_time_significance && calculated_decay_length_significance >= m_mother_min_decay_length_significance && calculated_decay_length_xy_significance >= m_mother_min_decay_length_xy_significance && isInRange(m_dira_min, calculated_dira, m_dira_max) && isInRange(m_dira_xy_min, calculated_dira_xy, m_dira_xy_max) && isInRange(m_min_decayTime, calculated_decayTime, m_max_decayTime) && isInRange(m_min_decayTime_xy, calculated_decayTime_xy, m_max_decayTime_xy) && isInRange(m_min_decayLength, calculated_decayLength, m_max_decayLength) && isInRange(m_min_decayLength_xy, calculated_decayLength_xy, m_max_decayLength_xy)) + if (calculated_fdchi2 >= m_fdchi2 && calculated_PV_dca <= m_mother_PV_dca && calculated_PV_dca_stddev <= m_mother_PV_dca_stddev && calculated_PV_dca_xy <= m_mother_PV_dca_xy && calculated_PV_dca_stddev_xy <= m_mother_PV_dca_stddev_xy && calculated_decay_time_significance >= m_mother_min_decay_time_significance && calculated_decay_length_significance >= m_mother_min_decay_length_significance && calculated_decay_length_xy_significance >= m_mother_min_decay_length_xy_significance && isInRange(m_dira_min, calculated_dira, m_dira_max) && isInRange(m_dira_xy_min, calculated_dira_xy, m_dira_xy_max) && isInRange(m_min_decayTime, calculated_decayTime, m_max_decayTime) && isInRange(m_min_decayTime_xy, calculated_decayTime_xy, m_max_decayTime_xy) && isInRange(m_min_decayLength, calculated_decayLength, m_max_decayLength) && isInRange(m_min_decayLength_xy, calculated_decayLength_xy, m_max_decayLength_xy)) { goodCandidate = true; } + + if (m_verbosity >= 10) + { + printSelectionCheck("", "Passed", "Failed", "the PV constraint", goodCandidate); + if (m_verbosity >= 11) + { + printSelectionCheck("Mother DIRA", m_dira_min, calculated_dira, m_dira_max); + printSelectionCheck("Mother DIRA xy", m_dira_xy_min, calculated_dira_xy, m_dira_xy_max); + printSelectionCheck("Mother FD chi^2", m_fdchi2, calculated_fdchi2, std::numeric_limits::max()); + printSelectionCheck("Mother PV DCA", 0, calculated_PV_dca, m_mother_PV_dca); + printSelectionCheck("Mother PV DCA Std. Dev.", 0., calculated_PV_dca_stddev, m_mother_PV_dca_stddev); + printSelectionCheck("Mother PV DCA xy", 0., calculated_PV_dca_xy, m_mother_PV_dca_xy); + printSelectionCheck("Mother PV DCA xy Std. Dev.", 0., calculated_PV_dca_stddev_xy, m_mother_PV_dca_stddev_xy); + printSelectionCheck("Mother Decay Time", m_min_decayTime, calculated_decayTime, m_max_decayTime); + printSelectionCheck("Mother Decay Time Significance", m_mother_min_decay_time_significance, calculated_decay_time_significance, std::numeric_limits::max()); + printSelectionCheck("Mother Decay Time xy", m_min_decayTime_xy, calculated_decayTime_xy, m_max_decayTime_xy); + printSelectionCheck("Mother Decay Length", m_min_decayLength, calculated_decayLength, m_max_decayLength); + printSelectionCheck("Mother Decay Length Significance", m_mother_min_decay_length_significance, calculated_decay_length_significance, std::numeric_limits::max()); + printSelectionCheck("Mother Decay Length xy", m_min_decayLength_xy, calculated_decayLength_xy, m_max_decayLength_xy); + printSelectionCheck("Mother Decay Length xy Significance", m_mother_min_decay_length_xy_significance, calculated_decay_length_xy_significance, std::numeric_limits::max()); + } + } } std::tuple KFParticle_Tools::getCombination(KFParticle vDaughters[], int daughterOrder[], KFParticle vertex, bool constrain_to_vertex, bool isIntermediate, int intermediateNumber, int nTracks, bool constrainMass, float required_vertexID, PHCompositeNode *topNode) @@ -1162,6 +1377,10 @@ float KFParticle_Tools::get_dEdx(PHCompositeNode *topNode, const KFParticle &dau { m_dst_trackmap = findNode::getClass(topNode, m_trk_map_node_name); m_cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + if (!m_cluster_map) + { + m_cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER_SEED"); + } m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); auto *geometry = findNode::getClass(topNode, "ActsGeometry"); if (!m_cluster_map || !m_geom_container || !geometry) @@ -1184,7 +1403,18 @@ float KFParticle_Tools::get_dEdx(PHCompositeNode *topNode, const KFParticle &dau void KFParticle_Tools::init_dEdx_fits() { - std::string dedx_fitparams = CDBInterface::instance()->getUrl("TPC_DEDX_FITPARAM"); + std::string dedx_fitparams; + if (m_use_local_PID_file) + { + dedx_fitparams = m_local_PID_filename; + } + else + { + dedx_fitparams = CDBInterface::instance()->getUrl("TPC_DEDX_FITPARAM"); + } + + std::cout << PHWHERE << " opening " << dedx_fitparams << std::endl; + TFile *filefit = TFile::Open(dedx_fitparams.c_str()); if (!filefit->IsOpen()) @@ -1193,12 +1423,29 @@ void KFParticle_Tools::init_dEdx_fits() return; } - filefit->GetObject("f_piband", f_pion_plus); - filefit->GetObject("f_Kband", f_kaon_plus); - filefit->GetObject("f_pband", f_proton_plus); - filefit->GetObject("f_piminus_band", f_pion_minus); - filefit->GetObject("f_Kminus_band", f_kaon_minus); - filefit->GetObject("f_pbar_band", f_proton_minus); + if (m_use_local_PID_file) + { + if (m_verbosity > 4) + { + std::cout << PHWHERE << " using local file " << m_local_PID_filename << std::endl; + } + // new method is independent of charge + filefit->GetObject("pi_band",f_pion_plus); + filefit->GetObject("K_band",f_kaon_plus); + filefit->GetObject("p_band",f_proton_plus); + filefit->GetObject("pi_band",f_pion_minus); + filefit->GetObject("K_band",f_kaon_minus); + filefit->GetObject("p_band",f_proton_minus); + } + else + { + filefit->GetObject("f_piband", f_pion_plus); + filefit->GetObject("f_Kband", f_kaon_plus); + filefit->GetObject("f_pband", f_proton_plus); + filefit->GetObject("f_piminus_band", f_pion_minus); + filefit->GetObject("f_Kminus_band", f_kaon_minus); + filefit->GetObject("f_pbar_band", f_proton_minus); + } pidMap.insert(std::pair(-11, f_pion_plus)); pidMap.insert(std::pair(211, f_pion_plus)); @@ -1270,3 +1517,25 @@ bool KFParticle_Tools::checkTrackAndVertexMatch(KFParticle vDaughters[], int nTr return vertexAndTrackMatch; } + +void KFParticle_Tools::printSelectionCheck(const std::string ¶meter, float min, float val, float max) +{ + std::string trailer = "the " + parameter + " requirement\033[0m"; + std::string passOrFail = isInRange(min, val, max) ? "\033[1;" + accept_colour + "mPassed " + trailer + : "\033[1;" + reject_colour + "mFailed " + trailer; + std::cout << passOrFail << ". Lower bound = " << min << ", measured value = " << val << ", upper bound = " << max << std::endl; +} + +void KFParticle_Tools::printSelectionCheck(const std::string &start, const std::string &accept, const std::string &reject, const std::string &end, bool equality) +{ + std::string decision = equality ? accept : reject; + std::string colour = equality ? accept_colour : reject_colour; + std::string spacing = start.empty() ? "" : " "; + std::cout << "\033[1;" << colour << "m" << start << spacing << decision << " " << end << "\033[0m" << std::endl; +} + +void KFParticle_Tools::printSelectionCheck(const std::string &info, unsigned int value) +{ + std::string colour = value > 0 ? accept_colour : reject_colour; + std::cout << info << " = \033[1;" << colour << "m" << value << "\033[0m" << std::endl; +} diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h index 4e722a15db..478701533a 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_Tools.h @@ -27,6 +27,8 @@ #include #include +#include // included here so inline functions are defined on user end + #include #include @@ -69,18 +71,18 @@ class KFParticle_Tools : protected KFParticle_MVA /*const*/ bool isGoodTrack(const KFParticle &particle, const std::vector &primaryVertices); - int calcMinIP(const KFParticle &track, const std::vector &PVs, float &minimumIP, float &minimumIPchi2, bool do3D = true); + int calcMinPV_DCA(const KFParticle &track, const std::vector &PVs, float &minimumPV_DCA, float &minimumPV_DCA_stddev, bool do3D = true); - std::vector findAllGoodTracks(const std::vector &daughterParticles, const std::vector &primaryVertices); + std::vector findAllGoodTracks(const std::vector &daughterParticles);//, const std::vector &primaryVertices); - std::vector> findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks) const; + std::vector> findTwoProngs(std::vector daughterParticles, std::vector goodTrackIndex, int nTracks, const std::vector &primaryVertices); - std::vector> findNProngs(std::vector daughterParticles, + std::vector> findNProngs(const std::vector &daughterParticles, const std::vector &goodTrackIndex, std::vector> goodTracksThatMeet, - int nRequiredTracks, unsigned int nProngs); + int nRequiredTracks, unsigned int nProngs, const std::vector &primaryVertices); - std::vector> appendTracksToIntermediates(KFParticle intermediateResonances[], const std::vector &daughterParticles, const std::vector &goodTrackIndex, int num_remaining_tracks); + std::vector> appendTracksToIntermediates(KFParticle intermediateResonances[], const std::vector &daughterParticles, const std::vector &goodTrackIndex, int num_remaining_tracks, const std::vector &primaryVertices); /// Calculates the cosine of the angle betweent the flight direction and momentum float eventDIRA(const KFParticle &particle, const KFParticle &vertex, bool do3D = true); @@ -124,6 +126,8 @@ class KFParticle_Tools : protected KFParticle_MVA void set_dont_use_global_vertex(bool set_variable) { m_dont_use_global_vertex = set_variable; } protected: + int m_verbosity = 0; + std::string m_mother_name_Tools; int m_num_intermediate_states{-1}; std::vector m_num_tracks_from_intermediate; @@ -138,17 +142,19 @@ class KFParticle_Tools : protected KFParticle_MVA std::vector m_intermediate_min_pt; std::vector m_intermediate_min_dira; std::vector m_intermediate_min_fdchi2; - std::vector m_intermediate_min_ip_xy; - std::vector m_intermediate_max_ip_xy; - std::vector m_intermediate_min_ipchi2_xy; - std::vector m_intermediate_max_ipchi2_xy; - std::vector m_intermediate_min_ip; - std::vector m_intermediate_max_ip; - std::vector m_intermediate_min_ipchi2; - std::vector m_intermediate_max_ipchi2; + std::vector m_intermediate_min_PV_dca_xy; + std::vector m_intermediate_max_PV_dca_xy; + std::vector m_intermediate_min_PV_dca_stddev_xy; + std::vector m_intermediate_max_PV_dca_stddev_xy; + std::vector m_intermediate_min_PV_dca; + std::vector m_intermediate_max_PV_dca; + std::vector m_intermediate_min_PV_dca_stddev; + std::vector m_intermediate_max_PV_dca_stddev; std::vector m_intermediate_vertex_volume; bool m_use_PID{false}; + bool m_use_local_PID_file{false}; + std::string m_local_PID_filename = ""; float m_dEdx_band_width{0.2}; // Fraction of expected dE/dx TF1 *f_pion_plus{nullptr}; @@ -192,13 +198,13 @@ class KFParticle_Tools : protected KFParticle_MVA float m_track_ptchi2{std::numeric_limits::max()}; - float m_track_ip_xy{-100}; + float m_track_PV_dca_xy{-100}; - float m_track_ipchi2_xy{-1000}; + float m_track_PV_dca_stddev_xy{-1000}; - float m_track_ip{-1}; + float m_track_PV_dca{-1}; - float m_track_ipchi2{-1}; + float m_track_PV_dca_stddev{-1}; float m_track_chi2ndof{std::numeric_limits::max()}; @@ -228,13 +234,13 @@ class KFParticle_Tools : protected KFParticle_MVA float m_mother_pt{-1}; - float m_mother_ip{std::numeric_limits::max()}; + float m_mother_PV_dca{std::numeric_limits::max()}; - float m_mother_ipchi2{std::numeric_limits::max()}; + float m_mother_PV_dca_stddev{std::numeric_limits::max()}; - float m_mother_ip_xy{std::numeric_limits::max()}; + float m_mother_PV_dca_xy{std::numeric_limits::max()}; - float m_mother_ipchi2_xy{std::numeric_limits::max()}; + float m_mother_PV_dca_stddev_xy{std::numeric_limits::max()}; float m_mother_vertex_volume{std::numeric_limits::max()}; @@ -277,6 +283,12 @@ class KFParticle_Tools : protected KFParticle_MVA void removeDuplicates(std::vector &v); void removeDuplicates(std::vector> &v); void removeDuplicates(std::vector> &v); + + void printSelectionCheck(const std::string ¶meter, float min, float val, float max); + void printSelectionCheck(const std::string &start, const std::string &accept, const std::string &reject, const std::string &end, bool equality); + void printSelectionCheck(const std::string &info, unsigned int value); + std::string accept_colour = "32"; + std::string reject_colour = "31"; }; #endif // KFPARTICLESPHENIX_KFPARTICLETOOLS_H diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc index 64d6b932fa..47a4db156c 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_eventReconstruction.cc @@ -74,7 +74,14 @@ void KFParticle_eventReconstruction::createDecay(PHCompositeNode* topNode, std:: nPVs = primaryVertices.size(); - std::vector goodTrackIndex = findAllGoodTracks(daughterParticles, primaryVertices); + std::vector goodTrackIndex = findAllGoodTracks(daughterParticles);//, primaryVertices); + + if (m_verbosity >= 10) + { + printSelectionCheck("Number of daughters passing state selection", daughterParticles.size()); + printSelectionCheck("Number of daughters passing track selection", goodTrackIndex.size()); + printSelectionCheck("Number of PVs passing selection", primaryVertices.size()); + } if (!m_has_intermediates) { @@ -96,10 +103,15 @@ void KFParticle_eventReconstruction::buildBasicChain(std::vector& se const std::vector& goodTrackIndexBasic, const std::vector& primaryVerticesBasic, PHCompositeNode* topNode) { - std::vector> goodTracksThatMeet = findTwoProngs(daughterParticlesBasic, goodTrackIndexBasic, m_num_tracks); + std::vector> goodTracksThatMeet = findTwoProngs(daughterParticlesBasic, goodTrackIndexBasic, m_num_tracks, primaryVerticesBasic); for (int p = 3; p < m_num_tracks + 1; ++p) { - goodTracksThatMeet = findNProngs(daughterParticlesBasic, goodTrackIndexBasic, goodTracksThatMeet, m_num_tracks, p); + goodTracksThatMeet = findNProngs(daughterParticlesBasic, goodTrackIndexBasic, goodTracksThatMeet, m_num_tracks, p, primaryVerticesBasic); + } + + if (m_verbosity >= 10) + { + printSelectionCheck("Number of SVs passing selection", goodTracksThatMeet.size()); } getCandidateDecay(selectedMotherBasic, selectedVertexBasic, selectedDaughtersBasic, daughterParticlesBasic, @@ -128,18 +140,32 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte for (int i = 0; i < m_num_intermediate_states; ++i) { std::vector vertices; - std::vector> goodTracksThatMeet = findTwoProngs(daughterParticlesAdv, goodTrackIndexAdv, m_num_tracks_from_intermediate[i]); + std::vector> goodTracksThatMeet = findTwoProngs(daughterParticlesAdv, goodTrackIndexAdv, m_num_tracks_from_intermediate[i], primaryVerticesAdv); for (int p = 3; p <= m_num_tracks_from_intermediate[i]; ++p) { goodTracksThatMeet = findNProngs(daughterParticlesAdv, goodTrackIndexAdv, goodTracksThatMeet, - m_num_tracks_from_intermediate[i], p); + m_num_tracks_from_intermediate[i], p, primaryVerticesAdv); + } + + if (m_verbosity >= 10) + { + printSelectionCheck("Number of SVs passing selection", goodTracksThatMeet.size()); } + getCandidateDecay(potentialIntermediates[i], vertices, potentialDaughters[i], daughterParticlesAdv, goodTracksThatMeet, primaryVerticesAdv, track_start, track_stop, true, i, m_constrain_int_mass, topNode); - track_start += track_stop; + if (i + 1 >= m_num_intermediate_states) + { + break; + } + track_start = track_stop; track_stop += m_num_tracks_from_intermediate[i + 1]; + if (track_stop > m_num_tracks) + { + break; + } } int num_tracks_used_by_intermediates = 0; for (int i = 0; i < m_num_intermediate_states; ++i) @@ -242,7 +268,7 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte uniqueCombinations = findUniqueDaughterCombinations(num_tracks_used_by_intermediates, m_num_tracks); // Unique comb of remaining trackIDs - listOfTracksToAppend = appendTracksToIntermediates(motherDecayProducts, daughterParticlesAdv, goodTrackIndexAdv_withoutIntermediates, num_remaining_tracks); + listOfTracksToAppend = appendTracksToIntermediates(motherDecayProducts, daughterParticlesAdv, goodTrackIndexAdv_withoutIntermediates, num_remaining_tracks, primaryVerticesAdv); for (auto& uniqueCombination : uniqueCombinations) { @@ -281,7 +307,8 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte m_constrain_to_vertex, false, 0, num_mother_decay_products, m_constrain_int_mass, required_unique_vertexID, topNode); if (isGood) { - + /* + * Moving this to SV calculation for speed if (m_require_bunch_crossing_match) { KFParticle_truthAndDetTools toolSet; @@ -312,6 +339,7 @@ void KFParticle_eventReconstruction::buildChain(std::vector& selecte continue; } } + */ goodCandidates.push_back(candidate); if (m_constrain_to_vertex) @@ -450,16 +478,16 @@ void KFParticle_eventReconstruction::getCandidateDecay(std::vector& isIntermediate, intermediateNumber, nTracks, constrainMass, required_unique_vertexID, topNode); if (isIntermediate && isGood) { - float min_ip = 0; - float min_ipchi2 = 0; - float min_ip_xy = 0; - float min_ipchi2_xy = 0; - calcMinIP(candidate, primaryVerticesCand, min_ip, min_ipchi2); - calcMinIP(candidate, primaryVerticesCand, min_ip_xy , min_ipchi2_xy, false); - if (!isInRange(m_intermediate_min_ip[intermediateNumber], min_ip, m_intermediate_max_ip[intermediateNumber]) - || !isInRange(m_intermediate_min_ipchi2[intermediateNumber], min_ipchi2, m_intermediate_max_ipchi2[intermediateNumber]) - || !isInRange(m_intermediate_min_ip_xy[intermediateNumber], min_ip_xy, m_intermediate_max_ip_xy[intermediateNumber]) - || !isInRange(m_intermediate_min_ipchi2_xy[intermediateNumber], min_ipchi2_xy, m_intermediate_max_ipchi2_xy[intermediateNumber])) + float min_PV_dca = 0; + float min_PV_dca_stddev = 0; + float min_PV_dca_xy = 0; + float min_PV_dca_stddev_xy = 0; + calcMinPV_DCA(candidate, primaryVerticesCand, min_PV_dca, min_PV_dca_stddev); + calcMinPV_DCA(candidate, primaryVerticesCand, min_PV_dca_xy , min_PV_dca_stddev_xy, false); + if (!isInRange(m_intermediate_min_PV_dca[intermediateNumber], min_PV_dca, m_intermediate_max_PV_dca[intermediateNumber]) + || !isInRange(m_intermediate_min_PV_dca_stddev[intermediateNumber], min_PV_dca_stddev, m_intermediate_max_PV_dca_stddev[intermediateNumber]) + || !isInRange(m_intermediate_min_PV_dca_xy[intermediateNumber], min_PV_dca_xy, m_intermediate_max_PV_dca_xy[intermediateNumber]) + || !isInRange(m_intermediate_min_PV_dca_stddev_xy[intermediateNumber], min_PV_dca_stddev_xy, m_intermediate_max_PV_dca_stddev_xy[intermediateNumber])) { isGood = false; } @@ -553,21 +581,21 @@ int KFParticle_eventReconstruction::selectBestCombination(bool PVconstraint, boo } else { - float current_IPchi2 = 0; - float best_IPchi2 = 0; + float current_PV_DCAchi2 = 0; + float best_PV_DCAchi2 = 0; if (m_use_2D_matching_tools) { - current_IPchi2 = possibleCandidates[i].GetDeviationFromVertexXY(possibleVertex[i]); - best_IPchi2 = smallestMassError.GetDeviationFromVertexXY(possibleVertex[bestCombinationIndex]); + current_PV_DCAchi2 = possibleCandidates[i].GetDeviationFromVertexXY(possibleVertex[i]); + best_PV_DCAchi2 = smallestMassError.GetDeviationFromVertexXY(possibleVertex[bestCombinationIndex]); } else { - current_IPchi2 = possibleCandidates[i].GetDeviationFromVertex(possibleVertex[i]); - best_IPchi2 = smallestMassError.GetDeviationFromVertex(possibleVertex[bestCombinationIndex]); + current_PV_DCAchi2 = possibleCandidates[i].GetDeviationFromVertex(possibleVertex[i]); + best_PV_DCAchi2 = smallestMassError.GetDeviationFromVertex(possibleVertex[bestCombinationIndex]); } - if (current_IPchi2 < best_IPchi2) + if (current_PV_DCAchi2 < best_PV_DCAchi2) { smallestMassError = possibleCandidates[i]; bestCombinationIndex = i; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc index 1770870bb3..8053b515ca 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.cc @@ -84,15 +84,15 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) m_tree->Branch(TString(mother_name) + "_DIRA", &m_calculated_mother_dira, TString(mother_name) + "_DIRA/F"); m_tree->Branch(TString(mother_name) + "_DIRA_xy", &m_calculated_mother_dira_xy, TString(mother_name) + "_DIRA_xy/F"); m_tree->Branch(TString(mother_name) + "_FDchi2", &m_calculated_mother_fdchi2, TString(mother_name) + "_FDchi2/F"); - m_tree->Branch(TString(mother_name) + "_IP", &m_calculated_mother_ip, TString(mother_name) + "_IP/F"); - m_tree->Branch(TString(mother_name) + "_IPchi2", &m_calculated_mother_ipchi2, TString(mother_name) + "_IPchi2/F"); - m_tree->Branch(TString(mother_name) + "_IPErr", &m_calculated_mother_ip_err, TString(mother_name) + "_IPErr/F"); - m_tree->Branch(TString(mother_name) + "_IP_xy", &m_calculated_mother_ip_xy, TString(mother_name) + "_IP_xy/F"); + m_tree->Branch(TString(mother_name) + "_PV_DCA", &m_calculated_mother_PV_dca, TString(mother_name) + "_PV_DCA/F"); + m_tree->Branch(TString(mother_name) + "_PV_DCA_StdDev", &m_calculated_mother_PV_dca_sig, TString(mother_name) + "_PV_DCA_StdDev/F"); + m_tree->Branch(TString(mother_name) + "_PV_DCA_Err", &m_calculated_mother_PV_dca_err, TString(mother_name) + "_PV_DCA_Err/F"); + m_tree->Branch(TString(mother_name) + "_PV_DCA_xy", &m_calculated_mother_PV_dca_xy, TString(mother_name) + "_PV_DCA_xy/F"); } if (m_get_all_PVs) { - m_tree->Branch(TString(mother_name) + "_IP_allPV", &allPV_mother_IP); - m_tree->Branch(TString(mother_name) + "_IPchi2_allPV", &allPV_mother_IPchi2); + m_tree->Branch(TString(mother_name) + "_PV_DCA_allPV", &allPV_mother_PV_DCA); + m_tree->Branch(TString(mother_name) + "_PV_DCA_StdDev_allPV", &allPV_mother_PV_DCA_StdDev); } m_tree->Branch(TString(mother_name) + "_x", &m_calculated_mother_x, TString(mother_name) + "_x/F"); m_tree->Branch(TString(mother_name) + "_y", &m_calculated_mother_y, TString(mother_name) + "_y/F"); @@ -144,15 +144,15 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) m_tree->Branch(TString(intermediate_name) + "_FDchi2", &m_calculated_intermediate_fdchi2[i], TString(intermediate_name) + "_FDchi2/F"); if (m_constrain_to_vertex_nTuple) { - m_tree->Branch(TString(intermediate_name) + "_IP", &m_calculated_intermediate_ip[i], TString(intermediate_name) + "_IP/F"); - m_tree->Branch(TString(intermediate_name) + "_IPchi2", &m_calculated_intermediate_ipchi2[i], TString(intermediate_name) + "_IPchi2/F"); - m_tree->Branch(TString(intermediate_name) + "_IPErr", &m_calculated_intermediate_ip_err[i], TString(intermediate_name) + "_IPErr/F"); - m_tree->Branch(TString(intermediate_name) + "_IP_xy", &m_calculated_intermediate_ip_xy[i], TString(intermediate_name) + "_IP_xy/F"); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA", &m_calculated_intermediate_PV_dca[i], TString(intermediate_name) + "_PV_DCA/F"); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA_StdDev", &m_calculated_intermediate_PV_dca_sig[i], TString(intermediate_name) + "_PV_DCA_StdDev/F"); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA_Err", &m_calculated_intermediate_PV_dca_err[i], TString(intermediate_name) + "_PV_DCA_Err/F"); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA_xy", &m_calculated_intermediate_PV_dca_xy[i], TString(intermediate_name) + "_PV_DCA_xy/F"); } if (m_get_all_PVs) { - m_tree->Branch(TString(intermediate_name) + "_IP_allPV", &allPV_intermediates_IP[i]); - m_tree->Branch(TString(intermediate_name) + "_IPchi2_allPV", &allPV_intermediates_IPchi2[i]); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA_allPV", &allPV_intermediates_PV_DCA[i]); + m_tree->Branch(TString(intermediate_name) + "_PV_DCA_StdDev_allPV", &allPV_intermediates_PV_DCA_StdDev[i]); } m_tree->Branch(TString(intermediate_name) + "_x", &m_calculated_intermediate_x[i], TString(intermediate_name) + "_x/F"); m_tree->Branch(TString(intermediate_name) + "_y", &m_calculated_intermediate_y[i], TString(intermediate_name) + "_y/F"); @@ -201,15 +201,16 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) m_tree->Branch(TString(daughter_number) + "_mass", &m_calculated_daughter_mass[i], TString(daughter_number) + "_mass/F"); if (m_constrain_to_vertex_nTuple) { - m_tree->Branch(TString(daughter_number) + "_IP", &m_calculated_daughter_ip[i], TString(daughter_number) + "_IP/F"); - m_tree->Branch(TString(daughter_number) + "_IPchi2", &m_calculated_daughter_ipchi2[i], TString(daughter_number) + "_IPchi2/F"); - m_tree->Branch(TString(daughter_number) + "_IPErr", &m_calculated_daughter_ip_err[i], TString(daughter_number) + "_IPErr/F"); - m_tree->Branch(TString(daughter_number) + "_IP_xy", &m_calculated_daughter_ip_xy[i], TString(daughter_number) + "_IP_xy/F"); + m_tree->Branch(TString(daughter_number) + "_PV_DCA", &m_calculated_daughter_PV_dca[i], TString(daughter_number) + "_PV_DCA/F"); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_Err", &m_calculated_daughter_PV_dca_err[i], TString(daughter_number) + "_PV_DCA_Err/F"); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_xy", &m_calculated_daughter_PV_dca_xy[i], TString(daughter_number) + "_PV_DCA_xy/F"); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_sig", &m_calculated_daughter_PV_dca_sig[i], TString(daughter_number) + "_PV_DCA_sig/F"); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_sig_xy", &m_calculated_daughter_PV_dca_xy_sig[i], TString(daughter_number) + "_PV_DCA_sig_xy/F"); } if (m_get_all_PVs) { - m_tree->Branch(TString(daughter_number) + "_IP_allPV", &allPV_daughter_IP[i]); - m_tree->Branch(TString(daughter_number) + "_IPchi2_allPV", &allPV_daughter_IPchi2[i]); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_allPV", &allPV_daughter_PV_DCA[i]); + m_tree->Branch(TString(daughter_number) + "_PV_DCA_StdDev_allPV", &allPV_daughter_PV_DCA_StdDev[i]); } m_tree->Branch(TString(daughter_number) + "_x", &m_calculated_daughter_x[i], TString(daughter_number) + "_x/F"); m_tree->Branch(TString(daughter_number) + "_y", &m_calculated_daughter_y[i], TString(daughter_number) + "_y/F"); @@ -270,6 +271,14 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) std::string dca_branch_name_xy = dca_branch_name + "_xy"; std::string dca_leaf_name_xy = dca_branch_name_xy + "/F"; m_tree->Branch(dca_branch_name_xy.c_str(), &m_daughter_dca_xy[iter], dca_leaf_name_xy.c_str()); + + std::string dca_sig_branch_name = "track_" + std::to_string(i + 1) + "_track_" + std::to_string(j + 1) + "_DCA_sig"; + std::string dca_sig_leaf_name = dca_sig_branch_name + "/F"; + m_tree->Branch(dca_sig_branch_name.c_str(), &m_daughter_dca_sig[iter], dca_sig_leaf_name.c_str()); + + std::string dca_sig_branch_name_xy = dca_sig_branch_name + "_xy"; + std::string dca_sig_leaf_name_xy = dca_sig_branch_name_xy + "/F"; + m_tree->Branch(dca_sig_branch_name_xy.c_str(), &m_daughter_dca_sig_xy[iter], dca_sig_leaf_name_xy.c_str()); ++iter; } @@ -303,7 +312,9 @@ void KFParticle_nTuple::initializeBranches(PHCompositeNode* topNode) m_tree->Branch("runNumber", &m_runNumber, "runNumber/I"); m_tree->Branch("eventNumber", &m_evtNumber, "eventNumber/I"); - m_tree->Branch("BCO", &m_bco, "BCO/L"); + m_tree->Branch("Collision_BCO", &m_bco, "Collision_BCO/L"); //already there, this is shifted BCO + m_tree->Branch("GL1_BCO", &m_event_bco, "GL1_BCO/L"); //adding for the current event BCO, not shifted + m_tree->Branch("last_GL1_BCO", &m_last_event_bco, "last_GL1_BCO/L"); //BCO for the last event if (m_get_trigger_info) { @@ -400,10 +411,10 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, m_calculated_mother_dira = kfpTupleTools.eventDIRA(motherParticle, vertex_fillbranch); m_calculated_mother_dira_xy = kfpTupleTools.eventDIRA(motherParticle, vertex_fillbranch, false); m_calculated_mother_fdchi2 = kfpTupleTools.flightDistanceChi2(motherParticle, vertex_fillbranch); - m_calculated_mother_ip = motherParticle.GetDistanceFromVertex(vertex_fillbranch); - m_calculated_mother_ipchi2 = motherParticle.GetDeviationFromVertex(vertex_fillbranch); - m_calculated_mother_ip_err = m_calculated_mother_ip / std::sqrt(m_calculated_mother_ipchi2); - m_calculated_mother_ip_xy = motherParticle.GetDistanceFromVertexXY(vertex_fillbranch); + m_calculated_mother_PV_dca = motherParticle.GetDistanceFromVertex(vertex_fillbranch); + m_calculated_mother_PV_dca_sig = motherParticle.GetDeviationFromVertex(vertex_fillbranch); + m_calculated_mother_PV_dca_err = m_calculated_mother_PV_dca / std::sqrt(m_calculated_mother_PV_dca_sig); + m_calculated_mother_PV_dca_xy = motherParticle.GetDistanceFromVertexXY(vertex_fillbranch); } m_calculated_mother_x = motherParticle.GetX(); m_calculated_mother_y = motherParticle.GetY(); @@ -442,10 +453,10 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, m_calculated_intermediate_fdchi2[i] = kfpTupleTools.flightDistanceChi2(intermediateArray[i], motherParticle); if (m_constrain_to_vertex_nTuple) { - m_calculated_intermediate_ip[i] = intermediateArray[i].GetDistanceFromVertex(vertex_fillbranch); - m_calculated_intermediate_ipchi2[i] = intermediateArray[i].GetDeviationFromVertex(vertex_fillbranch); - m_calculated_intermediate_ip_err[i] = m_calculated_intermediate_ip[i] / std::sqrt(m_calculated_intermediate_ipchi2[i]); - m_calculated_intermediate_ip_xy[i] = intermediateArray[i].GetDistanceFromVertexXY(vertex_fillbranch); + m_calculated_intermediate_PV_dca[i] = intermediateArray[i].GetDistanceFromVertex(vertex_fillbranch); + m_calculated_intermediate_PV_dca_sig[i] = intermediateArray[i].GetDeviationFromVertex(vertex_fillbranch); + m_calculated_intermediate_PV_dca_err[i] = m_calculated_intermediate_PV_dca[i] / std::sqrt(m_calculated_intermediate_PV_dca_sig[i]); + m_calculated_intermediate_PV_dca_xy[i] = intermediateArray[i].GetDistanceFromVertexXY(vertex_fillbranch); } m_calculated_intermediate_x[i] = intermediateArray[i].GetX(); m_calculated_intermediate_y[i] = intermediateArray[i].GetY(); @@ -490,10 +501,12 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, m_calculated_daughter_mass[i] = daughterArray[i].GetMass(); if (m_constrain_to_vertex_nTuple) { - m_calculated_daughter_ip[i] = daughterArray[i].GetDistanceFromVertex(vertex_fillbranch); - m_calculated_daughter_ipchi2[i] = daughterArray[i].GetDeviationFromVertex(vertex_fillbranch); - m_calculated_daughter_ip_err[i] = m_calculated_daughter_ip[i] / std::sqrt(m_calculated_daughter_ipchi2[i]); - m_calculated_daughter_ip_xy[i] = daughterArray[i].GetDistanceFromVertexXY(vertex_fillbranch); + m_calculated_daughter_PV_dca[i] = daughterArray[i].GetDistanceFromVertex(vertex_fillbranch); + m_calculated_daughter_PV_dca_sig[i] = daughterArray[i].GetDeviationFromVertex(vertex_fillbranch); + m_calculated_daughter_PV_dca_err[i] = m_calculated_daughter_PV_dca[i] / std::sqrt(m_calculated_daughter_PV_dca_sig[i]); + m_calculated_daughter_PV_dca_xy[i] = daughterArray[i].GetDistanceFromVertexXY(vertex_fillbranch); + m_calculated_daughter_PV_dca_sig[i] = daughterArray[i].GetDeviationFromVertex(vertex_fillbranch); + m_calculated_daughter_PV_dca_xy_sig[i] = daughterArray[i].GetDeviationFromVertexXY(vertex_fillbranch); } m_calculated_daughter_x[i] = daughterArray[i].GetX(); m_calculated_daughter_y[i] = daughterArray[i].GetY(); @@ -594,6 +607,8 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, { m_daughter_dca[iter] = daughterArray[i].GetDistanceFromParticle(daughterArray[j]); m_daughter_dca_xy[iter] = daughterArray[i].GetDistanceFromParticleXY(daughterArray[j]); + m_daughter_dca_sig[iter] = daughterArray[i].GetDeviationFromParticle(daughterArray[j]); + m_daughter_dca_sig_xy[iter] = daughterArray[i].GetDeviationFromParticleXY(daughterArray[j]); ++iter; } } @@ -663,20 +678,38 @@ void KFParticle_nTuple::fillBranch(PHCompositeNode* topNode, if (evtNode) { - EventHeader* evtHeader = findNode::getClass(topNode, "EventHeader"); - m_runNumber = evtHeader->get_RunNumber(); - m_evtNumber = evtHeader->get_EvtSequence(); - - auto* gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); - if (!gl1packet) - { - gl1packet = findNode::getClass(topNode, "GL1Packet"); - } - m_bco = m_trigger_info_available ? gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0] : 0; + EventHeader* evtHeader = findNode::getClass(topNode, "EventHeader"); + if (evtHeader) + { + m_runNumber = evtHeader->get_RunNumber(); + m_evtNumber = evtHeader->get_EvtSequence(); + } + else + { + m_runNumber = -1; + m_evtNumber = -1; + } + + auto* gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); + if (!gl1packet) + { + gl1packet = findNode::getClass(topNode, "GL1Packet"); + } + + if (gl1packet) + { + m_bco = gl1packet->lValue(0, "BCO") + m_calculated_daughter_bunch_crossing[0]; + } + else + { + m_bco = -1; + } } else { - m_runNumber = m_evtNumber = m_bco = -1; + m_runNumber = -1; + m_evtNumber = -1; + m_bco = -1; } if (m_trigger_info_available) @@ -741,4 +774,4 @@ bool KFParticle_nTuple::fillConditionMet() const // if requiring track-calo matching, the match result is returned return isTrackEMCalmatch; -} \ No newline at end of file +} diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h index 4798e24942..cc84bf22c2 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_nTuple.h @@ -9,6 +9,7 @@ #include #include // for string #include +#include // fixed width integer types used for BCO counters class PHCompositeNode; class TTree; @@ -35,6 +36,13 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ std::vector daughters, std::vector intermediates); + // pass event-level BCO values from KFParticle_sPHENIX + void set_event_bcos(const int64_t this_bco, const int64_t last_bco) + { + m_event_bco = this_bco; + m_last_event_bco = last_bco; + } + float calc_secondary_vertex_mass_noPID(std::vector kfp_daughters); bool fillConditionMet() const; @@ -97,10 +105,10 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ float m_calculated_mother_dira{-1}; float m_calculated_mother_dira_xy{-1}; float m_calculated_mother_fdchi2{-1}; - float m_calculated_mother_ip{-1}; - float m_calculated_mother_ip_xy{-1}; - float m_calculated_mother_ipchi2{-1}; - float m_calculated_mother_ip_err{-1}; + float m_calculated_mother_PV_dca{-1}; + float m_calculated_mother_PV_dca_xy{-1}; + float m_calculated_mother_PV_dca_sig{-1}; + float m_calculated_mother_PV_dca_err{-1}; float m_calculated_mother_x{-1}; float m_calculated_mother_y{-1}; float m_calculated_mother_z{-1}; @@ -135,10 +143,10 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ float m_calculated_intermediate_decaylength_xy_err[max_intermediates]{0}; float m_calculated_intermediate_dira[max_intermediates]{0}; float m_calculated_intermediate_fdchi2[max_intermediates]{0}; - float m_calculated_intermediate_ip[max_intermediates]{0}; - float m_calculated_intermediate_ip_xy[max_intermediates]{0}; - float m_calculated_intermediate_ipchi2[max_intermediates]{0}; - float m_calculated_intermediate_ip_err[max_intermediates]{0}; + float m_calculated_intermediate_PV_dca[max_intermediates]{0}; + float m_calculated_intermediate_PV_dca_xy[max_intermediates]{0}; + float m_calculated_intermediate_PV_dca_sig[max_intermediates]{0}; + float m_calculated_intermediate_PV_dca_err[max_intermediates]{0}; float m_calculated_intermediate_x[max_intermediates]{0}; float m_calculated_intermediate_y[max_intermediates]{0}; float m_calculated_intermediate_z[max_intermediates]{0}; @@ -164,10 +172,11 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ // static const int max_tracks {20}; float m_calculated_daughter_mass[max_tracks]{0}; - float m_calculated_daughter_ip[max_tracks]{0}; - float m_calculated_daughter_ip_xy[max_tracks]{0}; - float m_calculated_daughter_ipchi2[max_tracks]{0}; - float m_calculated_daughter_ip_err[max_tracks]{0}; + float m_calculated_daughter_PV_dca[max_tracks]{0}; + float m_calculated_daughter_PV_dca_err[max_tracks]{0}; + float m_calculated_daughter_PV_dca_sig[max_tracks]{0}; + float m_calculated_daughter_PV_dca_xy[max_tracks]{0}; + float m_calculated_daughter_PV_dca_xy_sig[max_tracks]{0}; float m_calculated_daughter_x[max_tracks]{0}; float m_calculated_daughter_y[max_tracks]{0}; float m_calculated_daughter_z[max_tracks]{0}; @@ -199,6 +208,8 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ float m_daughter_dca[99]{0}; float m_daughter_dca_xy[99]{0}; + float m_daughter_dca_sig[99]{0}; + float m_daughter_dca_sig_xy[99]{0}; float m_calculated_vertex_x{-1}; float m_calculated_vertex_y{-1}; @@ -219,6 +230,8 @@ class KFParticle_nTuple : public KFParticle_truthAndDetTools, public KFParticle_ int m_runNumber{-1}; int m_evtNumber{-1}; int64_t m_bco{-1}; + uint64_t m_event_bco{0};//current event BCO + uint64_t m_last_event_bco{0}; //only keeping this, BCO for the last event bool m_trigger_info_available{false}; }; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc index 38b60d55ba..1b597afcef 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.cc @@ -29,6 +29,8 @@ #include #include +#include +#include #include #include @@ -86,6 +88,7 @@ KFParticle_sPHENIX::KFParticle_sPHENIX(const std::string &name) int KFParticle_sPHENIX::Init(PHCompositeNode *topNode) { + m_verbosity = Verbosity(); if (m_save_output && Verbosity() >= VERBOSITY_SOME) { @@ -133,53 +136,113 @@ int KFParticle_sPHENIX::InitRun(PHCompositeNode *topNode) } int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) -{ - - std::vector mother, vertex_kfparticle; - std::vector> daughters, intermediates; - int nPVs, multiplicity; +{ + std::vector mother; + std::vector vertex_kfparticle; + std::vector> daughters; + std::vector> intermediates; + int nPVs; + int multiplicity; + + // Adding BCO Matching + auto* evtHeader = findNode::getClass(topNode, "EventHeader"); // event header node + auto* gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); // gl1 packet node + + if (!gl1packet) + { + gl1packet = findNode::getClass(topNode, "GL1Packet"); + } + + if (evtHeader && gl1packet) + { + const int64_t run = evtHeader->get_RunNumber(); + const int64_t evn = evtHeader->get_EvtSequence(); + m_this_event_bco = static_cast(gl1packet->lValue(0, "BCO")); + + if (Verbosity() >= VERBOSITY_A_LOT) + { + std::cout << "Event start | run: " << run << " event: " << evn << " this_event_bco: " << m_this_event_bco << std::endl; + } + + if (run != m_prev_runNumber || evn != m_prev_eventNumber) + { + + if (Verbosity() >= VERBOSITY_A_LOT) + { + std::cout << "New event detected" << std::endl; + std::cout << "Previous event BCO: " << m_prev_event_bco << std::endl; + } + + m_last_event_bco = (run == m_prev_runNumber) ? m_prev_event_bco : -1; + m_prev_event_bco = m_this_event_bco; + + m_prev_runNumber = run; + m_prev_eventNumber = evn; + + if (Verbosity() >= VERBOSITY_A_LOT) + { + std::cout << "Updated values | last_event_bco: " << m_last_event_bco + << " stored_prev_event_bco: " << m_prev_event_bco + << std::endl; + } + } + } + else + { + + if (Verbosity() >= VERBOSITY_MORE) + { + std::cout << "KFParticle: EventHeader or GL1 packet not found" << std::endl; + } + m_this_event_bco = 0; + m_last_event_bco = 0; + m_prev_event_bco = 0; + m_prev_runNumber = 0; + m_prev_eventNumber = 0; + } + // End BCO matching here SvtxTrackMap *check_trackmap = findNode::getClass(topNode, m_trk_map_node_name); - multiplicity = check_trackmap->size(); - if (check_trackmap->size() == 0) + if (!check_trackmap || check_trackmap->empty()) { if (Verbosity() >= VERBOSITY_SOME) { std::cout << "KFParticle: Event skipped as there are no tracks" << std::endl; } - return Fun4AllReturnCodes::ABORTEVENT; + return Fun4AllReturnCodes::EVENT_OK; } + multiplicity = check_trackmap->size(); if (!m_use_fake_pv) { if (m_use_mbd_vertex) { MbdVertexMap* check_vertexmap = findNode::getClass(topNode, "MbdVertexMap"); - if (check_vertexmap->size() == 0) + if (check_vertexmap->empty()) { if (Verbosity() >= VERBOSITY_SOME) { std::cout << "KFParticle: Event skipped as there are no vertices" << std::endl; } - return Fun4AllReturnCodes::ABORTEVENT; + return Fun4AllReturnCodes::EVENT_OK; } } else { SvtxVertexMap* check_vertexmap = findNode::getClass(topNode, m_vtx_map_node_name); - if (check_vertexmap->size() == 0) + if (check_vertexmap->empty()) { if (Verbosity() >= VERBOSITY_SOME) { std::cout << "KFParticle: Event skipped as there are no vertices" << std::endl; } - return Fun4AllReturnCodes::ABORTEVENT; + return Fun4AllReturnCodes::EVENT_OK; } } - } + createDecay(topNode, mother, vertex_kfparticle, daughters, intermediates, nPVs); if (!m_has_intermediates_sPHENIX) { @@ -190,7 +253,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) vertex_kfparticle = mother; } - if (mother.size() != 0) + if (!mother.empty()) { for (unsigned int i = 0; i < mother.size(); ++i) { @@ -206,6 +269,7 @@ int KFParticle_sPHENIX::process_event(PHCompositeNode *topNode) if (m_save_output) { + set_event_bcos(m_this_event_bco, m_last_event_bco); //filling nTuple for BCO Matching fillBranch(topNode, mother[i], vertex_kfparticle[i], daughters[i], intermediates[i]); } if (m_save_dst) @@ -479,7 +543,7 @@ int KFParticle_sPHENIX::parseDecayDescriptor() setNumberOfTracks(nTracks); setDaughters(daughter_list); - if (intermediates_name.size() > 0) + if (!intermediates_name.empty()) { hasIntermediateStates(); setIntermediateStates(intermediate_list); @@ -495,15 +559,14 @@ int KFParticle_sPHENIX::parseDecayDescriptor() } return 0; } - else + + if (Verbosity() >= VERBOSITY_SOME) { - if (Verbosity() >= VERBOSITY_SOME) - { - std::cout << "KFParticle: Your decay descriptor, " << Name() << " cannot be parsed" - << "\nExiting!" << std::endl; - } - return Fun4AllReturnCodes::ABORTRUN; + std::cout << "KFParticle: Your decay descriptor, " << Name() << " cannot be parsed" + << "\nExiting!" << std::endl; } + return Fun4AllReturnCodes::ABORTRUN; + } void KFParticle_sPHENIX::getField() diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h index 64fc3f37bb..47809ca4e4 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_sPHENIX.h @@ -44,6 +44,8 @@ #include #include // for pair #include // for vector +#include //include for new member added +#include // fixed width integer types used for BCO counters class PHCompositeNode; class TFile; @@ -184,13 +186,13 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void setMaximumTrackPTchi2(float ptchi2) { m_track_ptchi2 = ptchi2; } - void setMinimumTrackIP_XY(float ip) { m_track_ip_xy = ip; } + void setMinimumTrackPV_DCA_XY(float ip) { m_track_PV_dca_xy = ip; } - void setMinimumTrackIPchi2_XY(float ipchi2) { m_track_ipchi2_xy = ipchi2; } + void setMinimumTrackPV_DCA_StdDev_XY(float ip_significance) { m_track_PV_dca_stddev_xy = ip_significance; } - void setMinimumTrackIP(float ip) { m_track_ip = ip; } + void setMinimumTrackPV_DCA(float ip) { m_track_PV_dca = ip; } - void setMinimumTrackIPchi2(float ipchi2) { m_track_ipchi2 = ipchi2; } + void setMinimumTrackPV_DCA_StdDev(float ip_significance) { m_track_PV_dca_stddev = ip_significance; } void setMaximumTrackchi2nDOF(float trackchi2ndof) { m_track_chi2ndof = trackchi2ndof; } @@ -200,7 +202,7 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void setMinTPChits(int nHits) { m_nTPCStates = nHits; } //Actually state counting but use this for backwards compatibility! - void setMinTPOThits(int nHits) { m_nTPCStates = nHits; } //Actually state counting but use this for backwards compatibility! + void setMinTPOThits(int nHits) { m_nTPOTStates = nHits; } //Actually state counting but use this for backwards compatibility! void setMaximumDaughterDCA_XY(float dca) { m_comb_DCA_xy = dca; } @@ -222,13 +224,13 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void setMotherPT(float mother_pt) { m_mother_pt = mother_pt; } - void setMotherIP(float mother_ip) { m_mother_ip = mother_ip; } + void setMotherPV_DCA(float mother_PV_dca) { m_mother_PV_dca = mother_PV_dca; } - void setMotherIP_XY(float mother_ip) { m_mother_ip_xy = mother_ip; } + void setMotherPV_DCA_XY(float mother_PV_dca) { m_mother_PV_dca_xy = mother_PV_dca; } - void setMotherIPchi2(float mother_ipchi2) { m_mother_ipchi2 = mother_ipchi2; } + void setMotherPV_DCA_StdDev(float mother_PV_dca_stddev) { m_mother_PV_dca_stddev = mother_PV_dca_stddev; } - void setMotherIPchi2_XY(float mother_ipchi2) { m_mother_ipchi2_xy = mother_ipchi2; } + void setMotherPV_DCA_StdDev_XY(float mother_PV_dca_stddev) { m_mother_PV_dca_stddev_xy = mother_PV_dca_stddev; } void setMaximumMotherVertexVolume(float vertexvol) { m_mother_vertex_volume = vertexvol; } @@ -273,59 +275,59 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K m_intermediate_min_pt = intermediate_min_pt; } - void setIntermediateMinIP_XY(const std::vector &intermediate_min_IP) + void setIntermediateMinPV_DCA_XY(const std::vector &intermediate_min_PV_DCA) { - for (unsigned int i = 0; i < intermediate_min_IP.size(); ++i) m_intermediate_min_ip_xy.push_back(intermediate_min_IP[i]); + for (unsigned int i = 0; i < intermediate_min_PV_DCA.size(); ++i) m_intermediate_min_PV_dca_xy.push_back(intermediate_min_PV_DCA[i]); } - void setIntermediateIPRange_XY(const std::vector /*unused*/> &intermediate_IP_range) + void setIntermediatePV_DCARange_XY(const std::vector /*unused*/> &intermediate_PV_DCA_range) { - for (unsigned int i = 0; i < intermediate_IP_range.size(); ++i) + for (unsigned int i = 0; i < intermediate_PV_DCA_range.size(); ++i) { - m_intermediate_min_ip_xy.push_back(intermediate_IP_range[i].first); - m_intermediate_max_ip_xy.push_back(intermediate_IP_range[i].second); + m_intermediate_min_PV_dca_xy.push_back(intermediate_PV_DCA_range[i].first); + m_intermediate_max_PV_dca_xy.push_back(intermediate_PV_DCA_range[i].second); } } - void setIntermediateMinIP(const std::vector &intermediate_min_IP) + void setIntermediateMinPV_DCA(const std::vector &intermediate_min_PV_DCA) { - for (unsigned int i = 0; i < intermediate_min_IP.size(); ++i) m_intermediate_min_ip.push_back(intermediate_min_IP[i]); + for (unsigned int i = 0; i < intermediate_min_PV_DCA.size(); ++i) m_intermediate_min_PV_dca.push_back(intermediate_min_PV_DCA[i]); } - void setIntermediateIPRange(const std::vector /*unused*/> &intermediate_IP_range) + void setIntermediatePV_DCARange(const std::vector /*unused*/> &intermediate_PV_DCA_range) { - for (unsigned int i = 0; i < intermediate_IP_range.size(); ++i) + for (unsigned int i = 0; i < intermediate_PV_DCA_range.size(); ++i) { - m_intermediate_min_ip.push_back(intermediate_IP_range[i].first); - m_intermediate_max_ip.push_back(intermediate_IP_range[i].second); + m_intermediate_min_PV_dca.push_back(intermediate_PV_DCA_range[i].first); + m_intermediate_max_PV_dca.push_back(intermediate_PV_DCA_range[i].second); } } - void setIntermediateMinIPchi2_XY(const std::vector &intermediate_min_IPchi2) + void setIntermediateMinPV_DCA_StdDev_XY(const std::vector &intermediate_min_PV_DCA_StdDev) { - for (unsigned int i = 0; i < intermediate_min_IPchi2.size(); ++i) m_intermediate_min_ipchi2_xy.push_back(intermediate_min_IPchi2[i]); + for (unsigned int i = 0; i < intermediate_min_PV_DCA_StdDev.size(); ++i) m_intermediate_min_PV_dca_stddev_xy.push_back(intermediate_min_PV_DCA_StdDev[i]); } - void setIntermediateIPchi2Range_XY(const std::vector /*unused*/> &intermediate_IPchi2_range) + void setIntermediatePV_DCA_StdDevRange_XY(const std::vector /*unused*/> &intermediate_PV_DCA_StdDev_range) { - for (unsigned int i = 0; i < intermediate_IPchi2_range.size(); ++i) + for (unsigned int i = 0; i < intermediate_PV_DCA_StdDev_range.size(); ++i) { - m_intermediate_min_ipchi2_xy.push_back(intermediate_IPchi2_range[i].first); - m_intermediate_max_ipchi2_xy.push_back(intermediate_IPchi2_range[i].second); + m_intermediate_min_PV_dca_stddev_xy.push_back(intermediate_PV_DCA_StdDev_range[i].first); + m_intermediate_max_PV_dca_stddev_xy.push_back(intermediate_PV_DCA_StdDev_range[i].second); } } - void setIntermediateMinIPchi2(const std::vector &intermediate_min_IPchi2) + void setIntermediateMinPV_DCA_StdDev(const std::vector &intermediate_min_PV_DCA_StdDev) { - for (unsigned int i = 0; i < intermediate_min_IPchi2.size(); ++i) m_intermediate_min_ipchi2.push_back(intermediate_min_IPchi2[i]); + for (unsigned int i = 0; i < intermediate_min_PV_DCA_StdDev.size(); ++i) m_intermediate_min_PV_dca_stddev.push_back(intermediate_min_PV_DCA_StdDev[i]); } - void setIntermediateIPchi2Range(const std::vector /*unused*/> &intermediate_IPchi2_range) + void setIntermediatePV_DCA_StdDevRange(const std::vector /*unused*/> &intermediate_PV_DCA_StdDev_range) { - for (unsigned int i = 0; i < intermediate_IPchi2_range.size(); ++i) + for (unsigned int i = 0; i < intermediate_PV_DCA_StdDev_range.size(); ++i) { - m_intermediate_min_ipchi2.push_back(intermediate_IPchi2_range[i].first); - m_intermediate_max_ipchi2.push_back(intermediate_IPchi2_range[i].second); + m_intermediate_min_PV_dca_stddev.push_back(intermediate_PV_DCA_StdDev_range[i].first); + m_intermediate_max_PV_dca_stddev.push_back(intermediate_PV_DCA_StdDev_range[i].second); } } @@ -394,6 +396,10 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K void selectMotherByMassError(bool select = true) { m_select_by_mass_error = select; } void usePID(bool use = true){ m_use_PID = use; } + + void useLocalPIDFile(bool use = true){ m_use_local_PID_file = use; } + + void setLocalPIDFilename(const std::string &filename){ m_local_PID_filename = filename; } void setPIDacceptFraction(float frac = 0.2){ m_dEdx_band_width = frac; } @@ -418,6 +424,12 @@ class KFParticle_sPHENIX : public SubsysReco, public KFParticle_nTuple, public K bool m_save_dst; bool m_save_output; int candidateCounter = 0; + //Adding member variables for BCO matching + uint64_t m_this_event_bco{0}; + uint64_t m_last_event_bco{0}; + uint64_t m_prev_event_bco{0}; + int64_t m_prev_runNumber{-1}; + int64_t m_prev_eventNumber{-1}; //till here std::string m_outfile_name; TFile *m_outfile; std::string m_decayDescriptor; diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc index f8373c9e6f..28a102150e 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.cc @@ -146,8 +146,8 @@ void KFParticle_truthAndDetTools::initializeTruthBranches(TTree *m_tree, int dau m_tree->Branch((daughter_number + "_true_ID").c_str(), &m_true_daughter_id[daughter_id], (daughter_number + "_true_ID/I").c_str()); if (m_constrain_to_vertex_truthMatch) { - m_tree->Branch((daughter_number + "_true_IP").c_str(), &m_true_daughter_ip[daughter_id], (daughter_number + "_true_IP/F").c_str()); - m_tree->Branch((daughter_number + "_true_IP_xy").c_str(), &m_true_daughter_ip_xy[daughter_id], (daughter_number + "_true_IP_xy/F").c_str()); + m_tree->Branch((daughter_number + "_true_PV_DCA").c_str(), &m_true_daughter_ip[daughter_id], (daughter_number + "_true_PV_DCA/F").c_str()); + m_tree->Branch((daughter_number + "_true_PV_DCA_xy").c_str(), &m_true_daughter_ip_xy[daughter_id], (daughter_number + "_true_PV_DCA_xy/F").c_str()); } m_tree->Branch((daughter_number + "_true_px").c_str(), &m_true_daughter_px[daughter_id], (daughter_number + "_true_px/F").c_str()); m_tree->Branch((daughter_number + "_true_py").c_str(), &m_true_daughter_py[daughter_id], (daughter_number + "_true_py/F").c_str()); @@ -289,8 +289,7 @@ void KFParticle_truthAndDetTools::fillTruthBranch(PHCompositeNode *topNode, TTre if (truePoint == nullptr && isParticleValid) { - // PHG4Particle *g4mother = m_truthinfo->GetParticle(g4particle->get_parent_id()); - PHG4Particle *g4mother = m_truthinfo->GetPrimaryParticle(g4particle->get_parent_id()); + PHG4Particle *g4mother = trutheval->get_parent_particle(g4particle); if (!g4mother) { std::cout << "KFParticle truth matching: True mother not found!\n"; @@ -299,7 +298,7 @@ void KFParticle_truthAndDetTools::fillTruthBranch(PHCompositeNode *topNode, TTre } else { - truePoint = m_truthinfo->GetVtx(g4mother->get_vtx_id()); // Note, this may not be the PV for a decay with tertiaries + truePoint = trutheval->get_vertex(g4mother); } } @@ -352,7 +351,6 @@ void KFParticle_truthAndDetTools::fillTruthBranch(PHCompositeNode *topNode, TTre void KFParticle_truthAndDetTools::fillGeant4Branch(PHG4Particle *particle, int daughter_id) { Float_t pT = sqrt(pow(particle->get_px(), 2) + pow(particle->get_py(), 2)); - m_true_daughter_track_history_PDG_ID[daughter_id].push_back(particle->get_pid()); m_true_daughter_track_history_PDG_mass[daughter_id].push_back(0); m_true_daughter_track_history_px[daughter_id].push_back((Float_t) particle->get_px()); @@ -1299,7 +1297,11 @@ void KFParticle_truthAndDetTools::fillDetectorBranch(PHCompositeNode *topNode, dst_clustermap = findNode::getClass(topNode, "TRKR_CLUSTER"); if (!dst_clustermap) { - std::cout << "KFParticle detector info: TRKR_CLUSTER does not exist" << std::endl; + dst_clustermap = findNode::getClass(topNode, "TRKR_CLUSTER_SEED"); + if (!dst_clustermap) + { + std::cout << "KFParticle detector info: TRKR_CLUSTER does not exist" << std::endl; + } } track = getTrack(daughter.Id(), dst_trackmap); @@ -1498,19 +1500,19 @@ void KFParticle_truthAndDetTools::allPVInfo(PHCompositeNode *topNode, allPV_y.push_back(primaryVertice.GetY()); allPV_z.push_back(primaryVertice.GetZ()); - allPV_mother_IP.push_back(motherParticle.GetDistanceFromVertex(primaryVertice)); - allPV_mother_IPchi2.push_back(motherParticle.GetDeviationFromVertex(primaryVertice)); + allPV_mother_PV_DCA.push_back(motherParticle.GetDistanceFromVertex(primaryVertice)); + allPV_mother_PV_DCA_StdDev.push_back(motherParticle.GetDeviationFromVertex(primaryVertice)); for (unsigned int j = 0; j < daughters.size(); ++j) { - allPV_daughter_IP[j].push_back(daughters[j].GetDistanceFromVertex(primaryVertice)); - allPV_daughter_IPchi2[j].push_back(daughters[j].GetDeviationFromVertex(primaryVertice)); + allPV_daughter_PV_DCA[j].push_back(daughters[j].GetDistanceFromVertex(primaryVertice)); + allPV_daughter_PV_DCA_StdDev[j].push_back(daughters[j].GetDeviationFromVertex(primaryVertice)); } for (unsigned int j = 0; j < intermediates.size(); ++j) { - allPV_intermediates_IP[j].push_back(intermediates[j].GetDistanceFromVertex(primaryVertice)); - allPV_intermediates_IPchi2[j].push_back(intermediates[j].GetDeviationFromVertex(primaryVertice)); + allPV_intermediates_PV_DCA[j].push_back(intermediates[j].GetDistanceFromVertex(primaryVertice)); + allPV_intermediates_PV_DCA_StdDev[j].push_back(intermediates[j].GetDeviationFromVertex(primaryVertice)); } } } @@ -1546,8 +1548,8 @@ void KFParticle_truthAndDetTools::clearVectors() detector_nStates_TPOT[i] = 0; // PV vectors - allPV_daughter_IP[i].clear(); - allPV_daughter_IPchi2[i].clear(); + allPV_daughter_PV_DCA[i].clear(); + allPV_daughter_PV_DCA_StdDev[i].clear(); // Detailed Calo if (m_get_detailed_calorimetry) @@ -1563,12 +1565,12 @@ void KFParticle_truthAndDetTools::clearVectors() allPV_z.clear(); allPV_z.clear(); - allPV_mother_IP.clear(); - allPV_mother_IPchi2.clear(); + allPV_mother_PV_DCA.clear(); + allPV_mother_PV_DCA_StdDev.clear(); for (int i = 0; i < m_num_intermediate_states_nTuple; ++i) { - allPV_intermediates_IP[i].clear(); - allPV_intermediates_IPchi2[i].clear(); + allPV_intermediates_PV_DCA[i].clear(); + allPV_intermediates_PV_DCA_StdDev[i].clear(); } } diff --git a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h index 0dc0dff847..28c755b902 100644 --- a/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h +++ b/offline/packages/KFParticle_sPHENIX/KFParticle_truthAndDetTools.h @@ -63,8 +63,8 @@ class KFParticle_truthAndDetTools void fillHepMCBranch(HepMC::GenParticle *particle, int daughter_id); int getHepMCInfo(PHCompositeNode *topNode, TTree *m_tree, const KFParticle &daughter, int daughter_id); - void initializeCaloBranches(TTree *m_tree, int daughter_id, const std::string &daughter_number); - void fillCaloBranch(PHCompositeNode *topNode, TTree *m_tree, const KFParticle &daughter, int daughter_id, bool &isTrackEMCalmatch, const KFParticle &vertex); + virtual void initializeCaloBranches(TTree *m_tree, int daughter_id, const std::string &daughter_number); + virtual void fillCaloBranch(PHCompositeNode *topNode, TTree *m_tree, const KFParticle &daughter, int daughter_id, bool &isTrackEMCalmatch, const KFParticle &vertex); void Get5x5CellInfo(RawClusterDefs::keytype key_in, int daughter_id); void initializeDetectorBranches(TTree *m_tree, int daughter_id, const std::string &daughter_number); @@ -226,12 +226,12 @@ class KFParticle_truthAndDetTools std::vector allPV_x; std::vector allPV_y; std::vector allPV_z; - std::vector allPV_mother_IP; - std::vector allPV_mother_IPchi2; - std::vector allPV_daughter_IP[max_tracks]; - std::vector allPV_daughter_IPchi2[max_tracks]; - std::vector allPV_intermediates_IP[max_tracks]; - std::vector allPV_intermediates_IPchi2[max_tracks]; + std::vector allPV_mother_PV_DCA; + std::vector allPV_mother_PV_DCA_StdDev; + std::vector allPV_daughter_PV_DCA[max_tracks]; + std::vector allPV_daughter_PV_DCA_StdDev[max_tracks]; + std::vector allPV_intermediates_PV_DCA[max_tracks]; + std::vector allPV_intermediates_PV_DCA_StdDev[max_tracks]; PHG4TruthInfoContainer *m_truthinfo{nullptr}; PHHepMCGenEventMap *m_geneventmap{nullptr}; diff --git a/offline/packages/NodeDump/DumpTowerInfoContainer.cc b/offline/packages/NodeDump/DumpTowerInfoContainer.cc index 21f8c99c19..7ae0ae0230 100644 --- a/offline/packages/NodeDump/DumpTowerInfoContainer.cc +++ b/offline/packages/NodeDump/DumpTowerInfoContainer.cc @@ -41,7 +41,6 @@ int DumpTowerInfoContainer::process_Node(PHNode *myNode) *fout << "chi2: " << rawtwr->get_chi2() << std::endl; *fout << "pedestal: " << rawtwr->get_pedestal() << std::endl; *fout << "isHot: " << rawtwr->get_isHot() << std::endl; - *fout << "isBadTime: " << rawtwr->get_isBadTime() << std::endl; *fout << "isNotInstr: " << rawtwr->get_isNotInstr() << std::endl; *fout << "isGood: " << rawtwr->get_isGood() << std::endl; *fout << "status: " << static_cast(rawtwr->get_status()) << std::endl; diff --git a/offline/packages/PHGarfield/GasModel.cc b/offline/packages/PHGarfield/GasModel.cc new file mode 100644 index 0000000000..d64f9970ad --- /dev/null +++ b/offline/packages/PHGarfield/GasModel.cc @@ -0,0 +1,75 @@ +#include +#include +#include + +#include + +//------------------------------------------------------------ +// This standalone executable makes gas calculations for +// whatever mixture you specify and range of electric, +// magnetic, and angle between values that you select. +// TKH 5/27/2026 +// +// +//------------------------------------------------------------ + +int main(int argc, char* argv[]) +{ + if (argc != 11) + { + std::cerr + << "Usage:\n" + << argv[0] + << " Emin Emax nE Bmin Bmax nB Amin Amax nA output_file_name\n\n" + << "Units:\n" + << " E: V/cm\n" + << " B: Tesla\n" + << " angle: radians\n"; + return 1; + } + + const double Emin = std::atof(argv[1]); + const double Emax = std::atof(argv[2]); + const int nE = std::atoi(argv[3]); + + const double Bmin = std::atof(argv[4]); + const double Bmax = std::atof(argv[5]); + const int nB = std::atoi(argv[6]); + + const double Amin = std::atof(argv[7]); + const double Amax = std::atof(argv[8]); + const int nA = std::atoi(argv[9]); + + const std::string output_file(argv[10]); + + std::cout << "E grid: " + << Emin << " -> " << Emax + << " with " << nE << " points\n"; + + std::cout << "B grid: " + << Bmin << " -> " << Bmax + << " with " << nB << " points\n"; + + std::cout << "Angle grid: " + << Amin << " -> " << Amax + << " with " << nA << " points\n"; + + std::cout << "Output File: " << output_file << std::endl; + + // ------------------------------------------------------------ + // Gas: Ar/CF4/isobutane = 75/20/5. + // ------------------------------------------------------------ + Garfield::MediumMagboltz gas; + gas.SetComposition("ar", 75., "cf4", 20., "isobutane", 5.); + gas.SetTemperature(301.65); // K from Grafana + gas.SetPressure(762.); // Torr from Grafana + + // Try to load an existing gas table. + bool LogGrid = false; + gas.SetFieldGrid(Emin, Emax, nE, LogGrid, + Bmin, Bmax, nB, + Amin, Amax, nA); + + gas.GenerateGasTable(10); + gas.WriteGasFile(output_file); +} diff --git a/offline/packages/PHGarfield/Makefile.am b/offline/packages/PHGarfield/Makefile.am new file mode 100644 index 0000000000..6037ac8d1c --- /dev/null +++ b/offline/packages/PHGarfield/Makefile.am @@ -0,0 +1,65 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -isystem$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 \ + `root-config --libs` + +pkginclude_HEADERS = \ + PHGarfield.h + +lib_LTLIBRARIES = \ + libPHGarfield.la + +libPHGarfield_la_LIBADD = \ + -lffamodules \ + -lffarawobjects \ + -lcdbobjects \ + -lEvent \ + -lphool \ + -lphfield \ + -lGarfield \ + -lSubsysReco + +libPHGarfield_la_SOURCES = \ + PHGarfield.cc + +bin_PROGRAMS = \ + GasModel \ + MergeGasFiles + +MergeGasFiles_SOURCES = MergeGasFiles.cc + +MergeGasFiles_LDADD = \ + -lGarfield \ + -lphool + +GasModel_SOURCES = GasModel.cc + +GasModel_LDADD = \ + -lGarfield + +################################################ +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libPHGarfield.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/offline/packages/PHGarfield/MergeGasFiles.cc b/offline/packages/PHGarfield/MergeGasFiles.cc new file mode 100644 index 0000000000..8007c5060d --- /dev/null +++ b/offline/packages/PHGarfield/MergeGasFiles.cc @@ -0,0 +1,212 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace fs = std::filesystem; +std::string mergedName(const std::string& path, unsigned int eindex); + +bool searchAndUnpackDirectory( + const std::string& directoryPath, + std::set& Eindices, + std::set& Bindices, + std::map, std::string>& FileList); + +int main(int argc, char* argv[]) +{ + try + { + if (argc != 3) + { + std::cerr << "Usage:\n" + << argv[0] + << " path_to_gasfiles name_of_output_file\n"; + return 1; + } + + const std::string path = argv[1]; + const std::string output = path + "/" + argv[2]; + + std::set Eindices; + std::set Bindices; + std::map, std::string> FileList; + + if (!searchAndUnpackDirectory(path, Eindices, Bindices, FileList)) + { + std::cerr << PHWHERE << " Imperfect directory." << std::endl; + return 1; + } + + Garfield::MediumMagboltz gas; + + for (const auto Eindex : Eindices) + { + bool firstB = true; + + for (const auto Bindex : Bindices) + { + const auto it = FileList.find({Eindex, Bindex}); + if (it == FileList.end()) + { + std::cerr << PHWHERE << " Missing file for E=" << Eindex + << " B=" << Bindex << std::endl; + return 1; + } + + const std::string& nextfile = it->second; + + if (firstB) + { + gas.LoadGasFile(nextfile); + firstB = false; + } + else + { + gas.MergeGasFile(nextfile, true); + } + } + + const std::string mergedFile = mergedName(path, Eindex); + + std::cout << "Writing " << mergedFile << std::endl; + gas.WriteGasFile(mergedFile); + + std::vector nE; + std::vector nB; + std::vector nA; + gas.GetFieldGrid(nE, nB, nA); + + std::cout << "Merged Gas File created: "<< mergedFile + << " with Grid Dimensions: " + << nE.size() << " E-fields, " + << nB.size() << " B-fields, " + << nA.size() << " Angles." << std::endl; + } + + bool firstE = true; + + for (const auto Eindex : Eindices) + { + //if (Eindex > 10) {break;} + const std::string mergedFile = mergedName(path, Eindex); + + if (!fs::exists(mergedFile)) + { + std::cerr << PHWHERE << " Missing merged file " << mergedFile << std::endl; + return 1; + } + + if (firstE) + { + gas.LoadGasFile(mergedFile); + firstE = false; + } + else + { + gas.MergeGasFile(mergedFile, true); + } + } + + std::cout << "Writing final file " << output << std::endl; + gas.WriteGasFile(output); + + std::vector nE; + std::vector nB; + std::vector nA; + gas.GetFieldGrid(nE, nB, nA); + + std::cout << "Final Gas File created: "<< output + << " with Grid Dimensions: " + << nE.size() << " E-fields, " + << nB.size() << " B-fields, " + << nA.size() << " Angles." << std::endl; + + return 0; + } + + catch (const std::exception& e) + { + std::cerr << PHWHERE << " Exception: " << e.what() << std::endl; + return 1; + } + catch (...) + { + std::cerr << PHWHERE << " Unknown exception." << std::endl; + return 1; + } +} + +bool searchAndUnpackDirectory(const std::string& directoryPath, std::set &Eindices, std::set &Bindices, std::map, std::string> &FileList) +{ + // Check if the directory exists and is valid + if (!fs::exists(directoryPath) || !fs::is_directory(directoryPath)) + { + std::cerr << "Error: Invalid directory path." << std::endl; + return false; + } + + std::regex filePattern(R"(^E([0-9]{3})_B([0-9]{3})\.gas$)"); + std::smatch matchResults; + + // Iterate through all items in the directory + for (const auto& entry : fs::directory_iterator(directoryPath)) + { + // Only process regular files + if (entry.is_regular_file()) + { + std::string filename = entry.path().filename().string(); + + // Check if the filename matches our target pattern + if (std::regex_match(filename, matchResults, filePattern)) + { + // matchResults[1] contains the string after 'E' + // matchResults[2] contains the string after 'B' + // std::stoul automatically handles leading zeros + unsigned int eValue = std::stoul(matchResults[1].str()); + unsigned int bValue = std::stoul(matchResults[2].str()); + Eindices.insert(eValue); + Bindices.insert(bValue); + FileList[{eValue, bValue}] = entry.path().string(); + } + } + } + + // Validate the results. + if (Eindices.empty()) { return false; } + if (Bindices.empty()) { return false; } + + unsigned int maxE = *Eindices.rbegin(); + unsigned int maxB = *Bindices.rbegin(); + for (unsigned int i=0; i<=maxE; i++) + { + for (unsigned int j=0; j<=maxB; j++) + { + if ( !FileList.contains({i,j}) ) { return false; } + } + } + + std::cout << " *** Gas File List Valid ***" << std::endl; + std::cout << "Electric field indices 0 --> " << maxE << std::endl; + std::cout << "Magnetic field indices 0 --> " << maxB << std::endl; + + return true; +} + +std::string mergedName(const std::string& path, unsigned int eindex) +{ + std::ostringstream name; + name << path << "/MERGED_E" + << std::setw(3) << std::setfill('0') << eindex + << ".gas"; + return name.str(); +} diff --git a/offline/packages/PHGarfield/PHGarfield.cc b/offline/packages/PHGarfield/PHGarfield.cc new file mode 100644 index 0000000000..259c8803dc --- /dev/null +++ b/offline/packages/PHGarfield/PHGarfield.cc @@ -0,0 +1,408 @@ +#include "PHGarfield.h" +#include +#include + +#include + +#include + +#include + +#include + +#include + +#include +#include + +#include +#include +#include +#include // for basic_ostream, operat... +#include +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; + +PHGarfield::PHGarfield(const std::string& name) + : SubsysReco(name), + //m_defaultGasfile("/sphenix/user/hemmick/gasfiles_20260624/Ar75_CF20_iso5.gas") + m_defaultGasfile("/sphenix/user/hemmick/gasfiles_20260624") +{ +} + +PHGarfield::~PHGarfield() +{ + // Housekeeping. + delete m_field; + delete m_cdbTPCMAPttree; + delete m_component; + delete m_gas; +} + +int PHGarfield::InitRun(PHCompositeNode* /*topNode*/) +{ + if (Verbosity() > 1) + { + std::cout << "PHGarfield::InitRun(PHCompositeNode *topNode) Initializing" << std::endl; + } + CDBInterface* m_cdb = CDBInterface::instance(); + + // Here we use the CDBInterface to set up the magnetic field map: + std::string url = m_cdb->getUrl("FIELDMAP_TRACKING"); + m_field = new PHField3DCartesian(url, 1.0); + + // Here we use the CDBInterface to set up the channel making of the TPC: + std::string text = m_cdb->getUrl("TPC_FEE_CHANNEL_MAP"); + m_cdbTPCMAPttree = new CDBTTree(text); + m_cdbTPCMAPttree->LoadCalibrations(); + + // Make the Garfield Component and register the methods that will interface to our fields... + m_component = new Garfield::ComponentUser(); + m_component->SetMagneticField([this](double x, double y, double z, double& bx, double& by, double& bz) + { GetMagneticFieldTesla(x, y, z, bx, by, bz); }); + m_component->SetElectricField([this](double x, double y, double z, double& ex, double& ey, double& ez) + { GetElectricFieldVcm(x, y, z, ex, ey, ez); }); + + // Here we fetch the gas from the CDB + std::string gasfile = m_cdb->getUrl("PHGARFIELD_GAS"); + if (gasfile.empty() || !fs::exists(gasfile)) + { + std::cerr << PHWHERE << " Missing CDB gasfile: " << gasfile << std::endl; + std::cerr << PHWHERE << " Using default gasfile: " << m_defaultGasfile << std::endl; + gasfile = m_defaultGasfile; + } + InitializeGas(gasfile); + + // Diagnostic during code development... + FillRadii(); + if (Verbosity() > 1) + { + PrintMaps(); + } + return Fun4AllReturnCodes::EVENT_OK; +} + +void PHGarfield::FillRadii() +{ + // Unload the pad map to get the radii in a handy location: + for (unsigned int side = 0; side < 2; side++) + { + for (unsigned int sector = 0; sector < 12; sector++) + { + for (unsigned int fee = 0; fee < 26; fee++) + { + for (unsigned int channel = 0; channel < 256; channel++) + { + unsigned int key = (256 * (fee)) + channel; + int layer = m_cdbTPCMAPttree->GetIntValue(key, "layer"); + double r = m_cdbTPCMAPttree->GetDoubleValue(key, "R") / CLHEP::cm; + if (layer > 6) + { + radii[layer - 7] = r; + } + } + } + } + } +} + +void PHGarfield::PrintGarfield(double x, double y, double z) const +{ + double ex; + double ey; + double ez; + double bx; + double by; + double bz; + double vx; + double vy; + double vz; + GetElectricFieldVcm(x, y, z, ex, ey, ez); + GetMagneticFieldTesla(x, y, z, bx, by, bz); + m_gas->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); + std::cout << " x:" << x + << " y:" << y + << " z:" << z + << " ex:" << ex + << " ey:" << ey + << " ez:" << ez + << " bx:" << bx + << " by:" << by + << " bz:" << bz + << " vx:" << vx + << " vy:" << vy + << " vz:" << vz + << std::endl; +} + +void PHGarfield::PrintGasSummary() const +{ + if (!m_GasFilesLoaded) + { + std::cerr << PHWHERE << "No Gas File(s) have been successfully loaded." << std::endl; + return; + } + + std::vector nE; + std::vector nB; + std::vector nA; + m_gas->GetFieldGrid(nE, nB, nA); + + std::cout << "Gas File Grid Dimensions: " << std::endl; + std::cout << nE.size() << " E-fields ranging from " << nE.front() << " to " << nE.back() << std::endl; + std::cout << nB.size() << " B-fields ranging from " << nB.front() << " to " << nB.back() << std::endl; + std::cout << nA.size() << " Angles ranging from " << nA.front() << " to " << nA.back() << std::endl; +} + +void PHGarfield::PrintMaps() const +{ + // Print out a few test points of the Garfield information + PrintGarfield(0.0, 0.0, 0.1); + PrintGarfield(0.0, 0.0, 100.0); + PrintGarfield(0.0, 40.0, 100.1); + PrintGarfield(0.0, 78.0, 010.1); + + // Print out the pad coordinate map: + int MAX = 10; + int prints = 0; + for (unsigned int side = 0; side < 2; side++) + { + for (unsigned int sector = 0; sector < 12; sector++) + { + for (unsigned int fee = 0; fee < 26; fee++) + { + for (unsigned int channel = 0; channel < 256; channel++) + { + unsigned int key = (256 * (fee)) + channel; + int layer = m_cdbTPCMAPttree->GetIntValue(key, "layer"); + double phi = ((side == 1 ? 1 : -1) * (m_cdbTPCMAPttree->GetDoubleValue(key, "phi") - std::numbers::pi / 2.)) + ((sector % 12) * std::numbers::pi / 6); + double r = m_cdbTPCMAPttree->GetDoubleValue(key, "R") / CLHEP::cm; + + phi = bounder(phi, PHI_MIN); + + if (layer > 6) + { + if (prints < MAX) + { + prints++; + std::cout << " side: " << side; + std::cout << " sector: " << sector; + std::cout << " fee: " << fee; + std::cout << " channel: " << channel; + std::cout << " layer: " << layer; + std::cout << " phi: " << phi; + std::cout << " r: " << r; + std::cout << std::endl; + } + } + } + } + } + } +} + +void PHGarfield::GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double& bx_t, double& by_t, double& bz_t) const +{ + // NOTE: Garfield uses cm, V/cm, and Tesla. + // CLHEP uses mm, V/mm, and kiloTesla + // PHField3DCartesian follows the CLHEP conventions for magnetic fields. + + double point[4] = + { + x_cm * CLHEP::cm, + y_cm * CLHEP::cm, + z_cm * CLHEP::cm, + //(z_cm-20.0) * CLHEP::cm, + 0.0}; + + double bfield[3] = {0.0, 0.0, 0.0}; + + // Get the magnetic field via the PHField3DCartesian object constructed usinf the CDB url reference. + m_field->GetFieldValue(point, bfield); + + bx_t = bfield[0] / CLHEP::tesla; + by_t = bfield[1] / CLHEP::tesla; + bz_t = bfield[2] / CLHEP::tesla; +} + +void PHGarfield::GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double& ex_vcm, double& ey_vcm, double& ez_vcm) const +{ + // NOTE: Garfield uses cm, V/cm, and Tesla. + (void) x_cm; + (void) y_cm; + + ex_vcm = 0.0; + ey_vcm = 0.0; + ez_vcm = z_cm > 0 ? -400.0 : 400.0; +} + +void PHGarfield::InitializeGas(const std::string &name) +{ + // Create and fill the gas object so that we can trace particles through the gas... + m_gas = new Garfield::MediumMagboltz(); + + if (!std::filesystem::exists(name)) + { + std::cerr << "Missing gas file or gas directory: " << name << std::endl; + return; + } + + if (fs::is_regular_file(name)) + { + std::cout << "Loading Garfield gas from file: " << name << std::endl; + if (!m_gas->LoadGasFile(name)) + { + std::cerr << "Failed to load " << name << std::endl; + return; + } + m_GasFilesLoaded = true; + } + else if (fs::is_directory(name)) + { + std::cout << "Loading Garfield gas from directory: " << name << std::endl; + std::regex filePattern(R"(^MERGED_E([0-9]{3})\.gas$)"); + std::smatch matchResults; + + // Iterate through all items in the directory + // NOTE: Map assures that files are properly ordered when merged... + std::map FilesToMerge; + for (const auto& entry : fs::directory_iterator(name)) + { + // Only process regular files + if (entry.is_regular_file()) + { + std::string filepath = entry.path().string(); + std::string filename = entry.path().filename().string(); + + // Check if the filename matches our target pattern + if (std::regex_match(filename, matchResults, filePattern)) + { + //std::cout << "matchResults: " << matchResults[1].str() << std::endl; + FilesToMerge[std::stoul( matchResults[1].str() )]=filepath; + } + } + } + bool firstE = true; + for (const auto& [key, filepath] : FilesToMerge) + { + if (firstE) + { + m_gas->LoadGasFile(filepath); + firstE = false; + m_GasFilesLoaded = true; + } + else + { + m_gas->MergeGasFile(filepath, true); + m_GasFilesLoaded = true; + } + } + } + + PrintGasSummary(); +} + +int PHGarfield::process_event(PHCompositeNode* topNode) +{ + // Initial implementation doesn't do anything event-by-event. + // Nonetheless, a future user might want do do something here... + (void) topNode; + return Fun4AllReturnCodes::EVENT_OK; +} + +double PHGarfield::bounder(double phi, double phi_min) +{ + double phi_max = phi_min + 2.0 * std::numbers::pi; + while (phi < phi_min) + { + phi = phi + 2.0 * std::numbers::pi; + } + while (phi >= phi_max) + { + phi = phi - 2.0 * std::numbers::pi; + } + + return phi; +} + +TPolyLine3D* PHGarfield::ReverseDrift(double x, double y, double z, double step_ns) +{ + std::vector xlist; + std::vector ylist; + std::vector zlist; + + xlist.push_back(x); + ylist.push_back(y); + zlist.push_back(z); + + double ex; + double ey; + double ez; + double bx; + double by; + double bz; + double vx; + double vy; + double vz; + + double zPrevious = z; + while (!StopHere(x, y, z, zPrevious)) + { + zPrevious = z; + GetMagneticFieldTesla(x, y, z, bx, by, bz); + GetElectricFieldVcm(x, y, z, ex, ey, ez); + m_gas->ElectronVelocity(ex, ey, ez, bx, by, bz, vx, vy, vz); + + x = x - vx * step_ns; + y = y - vy * step_ns; + z = z - vz * step_ns; + + xlist.push_back(x); + ylist.push_back(y); + zlist.push_back(z); + } + + TPolyLine3D* poly = new TPolyLine3D(xlist.size() - 1); + for (unsigned int i = 0; i < xlist.size() - 1; i++) + { + poly->SetPoint(i, xlist[i], ylist[i], zlist[i]); + } + + return poly; +} + +bool PHGarfield::StopHere(const double x, const double y, const double z, + const double zPrevious) +{ + const double r = std::hypot(x, y); + + if (r < 18.0) + { + return true; + } + if (r > 82.0) + { + return true; + } + if (z > 120.0) + { + return true; + } + if (z < -120.0) + { + return true; + } + + // z crossed the central membrane. + if (z * zPrevious < 0.0) + { + return true; + } + + return false; +} diff --git a/offline/packages/PHGarfield/PHGarfield.h b/offline/packages/PHGarfield/PHGarfield.h new file mode 100644 index 0000000000..ff2d8bb957 --- /dev/null +++ b/offline/packages/PHGarfield/PHGarfield.h @@ -0,0 +1,62 @@ +#ifndef PHGARFIELD__H +#define PHGARFIELD__H + +#include + +#include +#include +#include + +class CDBTTree; +class PHField3DCartesian; +class TPolyLine3D; + +namespace Garfield +{ + class ComponentUser; + class MediumMagboltz; +} // namespace Garfield + +class PHGarfield : public SubsysReco +{ + public: + PHGarfield(const std::string &name = "PHGarfield"); + ~PHGarfield() override; + + int InitRun(PHCompositeNode *) override; + int process_event(PHCompositeNode * topNode) override; + + bool StopHere(const double x, const double y, const double z, const double zPrevious); + + void PrintMaps() const; + void PrintGarfield(double x, double y, double z) const; + void PrintGasSummary() const; + + // These are left in public namespace for easy plotting macros... + // The user is encouraged to add more routine to fit their analysis goals... + TPolyLine3D *ReverseDrift(double x_cm, double y_cm, double z_cm, double step_ns = 50.0); // Drifts electrons from some initial point until they hit a detector boundary... + + double GetRadius(size_t index) const {return radii.at(index);} + + private: + void GetMagneticFieldTesla(double x_cm, double y_cm, double z_cm, double &bx_t, double &by_t, double &bz_t) const; // Feeds magnetic field to Garfield + void GetElectricFieldVcm(double x_cm, double y_cm, double z_cm, double &ex_vcm, double &ey_vcm, double &ez_vcm) const; // Feeds electric field to Garfield + void InitializeGas(const std::string &name); // Acepts a file or a directory + void FillRadii(); + static double bounder(double phi, double phi_min); + + CDBTTree *m_cdbTPCMAPttree{nullptr}; // Locations of the pads from CDB... + PHField3DCartesian *m_field{nullptr}; // The standard sPHENIX field holding container. + Garfield::ComponentUser *m_component{nullptr}; // This handles the interface of the electric and magnetic fields as handed to Garfield + Garfield::MediumMagboltz *m_gas{nullptr}; // This is the pre-tabulated gas properties required by Garfield... + std::string m_defaultGasfile; + bool m_GasFilesLoaded{false}; + + // These are utilities for a spot check of the overall routine: + // std::string calibdir; + // std::string m_DiodeContainerName; + double PHI_MIN{-std::numbers::pi}; + std::array radii{}; // Radius on each layer just for test purposes...need to be cm! +}; + +#endif diff --git a/offline/packages/PHGarfield/autogen.sh b/offline/packages/PHGarfield/autogen.sh new file mode 100755 index 0000000000..333dd3b499 --- /dev/null +++ b/offline/packages/PHGarfield/autogen.sh @@ -0,0 +1,9 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" + diff --git a/offline/packages/PHGarfield/configure.ac b/offline/packages/PHGarfield/configure.ac new file mode 100644 index 0000000000..b2b598e585 --- /dev/null +++ b/offline/packages/PHGarfield/configure.ac @@ -0,0 +1,14 @@ +AC_INIT(PHGarfield, [1.00]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE + +AC_PROG_CXX(CC g++) +LT_INIT([disable-static]) + +dnl leaving this here in case we want to play with different compiler +dnl specific flags +CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wshadow -Werror" + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc index 8fe89b5019..aeb01dee62 100644 --- a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc +++ b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.cc @@ -51,9 +51,9 @@ namespace PHGenFit const std::string& /*track_rep_choice*/, const bool doEventDisplay) : verbosity(1000) + , _tgeo_manager(new TGeoManager("Default", "Geane geometry")) , _doEventDisplay(doEventDisplay) { - _tgeo_manager = new TGeoManager("Default", "Geane geometry"); TGeoManager::Import(tgeo_file_name.data()); assert(field); @@ -73,26 +73,24 @@ namespace PHGenFit } // init fitter - if (fitter_choice.compare("KalmanFitterRefTrack") == 0) + if (fitter_choice == "KalmanFitterRefTrack") { _fitter = new genfit::KalmanFitterRefTrack(); } - else if (fitter_choice.compare("KalmanFitter") == 0) -// NOLINTNEXTLINE(bugprone-branch-clone) - { + else if (fitter_choice == "KalmanFitter") + { // NOLINT(bugprone-branch-clone) _fitter = new genfit::KalmanFitter(); } - else if (fitter_choice.compare("DafSimple") == 0) + else if (fitter_choice == "DafSimple") { _fitter = new genfit::DAF(false); } - else if (fitter_choice.compare("DafRef") == 0) + else if (fitter_choice == "DafRef") { _fitter = new genfit::DAF(true); } else -// NOLINTNEXTLINE(bugprone-branch-clone) - { + { // NOLINT(bugprone-branch-clone) _fitter = new genfit::KalmanFitter(); } @@ -235,7 +233,7 @@ namespace PHGenFit { _fitter = new genfit::KalmanFitterRefTrack(); } - if (fitter_choice == PHGenFit::Fitter::DafSimple) + else if (fitter_choice == PHGenFit::Fitter::DafSimple) { _fitter = new genfit::DAF(false); } @@ -289,19 +287,19 @@ namespace PHGenFit } // init fitter - if (fitter_choice.compare("KalmanFitterRefTrack") == 0) + if (fitter_choice == "KalmanFitterRefTrack") { _fitter = new genfit::KalmanFitterRefTrack(); } - else if (fitter_choice.compare("KalmanFitter") == 0) + else if (fitter_choice == "KalmanFitter") { _fitter = new genfit::KalmanFitter(); } - else if (fitter_choice.compare("DafSimple") == 0) + else if (fitter_choice == "DafSimple") { _fitter = new genfit::DAF(false); } - else if (fitter_choice.compare("DafRef") == 0) + else if (fitter_choice == "DafRef") { _fitter = new genfit::DAF(true); } diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.h b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.h index 7f2ec1f761..958baa62aa 100644 --- a/offline/packages/PHGenFitPkg/PHGenFit/Fitter.h +++ b/offline/packages/PHGenFitPkg/PHGenFit/Fitter.h @@ -13,7 +13,7 @@ #include #include -#include "GenFit/Exception.h" +#include #include diff --git a/offline/packages/PHGenFitPkg/PHGenFit/Track.cc b/offline/packages/PHGenFitPkg/PHGenFit/Track.cc index b1643e8cd0..0e06f15984 100644 --- a/offline/packages/PHGenFitPkg/PHGenFit/Track.cc +++ b/offline/packages/PHGenFitPkg/PHGenFit/Track.cc @@ -48,8 +48,8 @@ #define WILD_DOUBLE (-999999) -//#define _DEBUG_ -//#define _PRINT_MATRIX_ +// #define _DEBUG_ +// #define _PRINT_MATRIX_ #ifdef _DEBUG_ #include @@ -60,11 +60,10 @@ ofstream fout_matrix("matrix.txt"); namespace PHGenFit { Track::Track(genfit::AbsTrackRep* rep, const TVector3& seed_pos, const TVector3& seed_mom, const TMatrixDSym& seed_cov, const int v) + : verbosity(v) { // TODO Add input param check - verbosity = v; - genfit::MeasuredStateOnPlane seedMSoP(rep); seedMSoP.setPosMomCov(seed_pos, seed_mom, seed_cov); // const genfit::StateOnPlane seedSoP(seedMSoP); @@ -78,12 +77,12 @@ namespace PHGenFit } Track::Track(const PHGenFit::Track& t) + : verbosity(t.verbosity) + , _track(new genfit::Track(*(t.getGenFitTrack()))) + , _clusterIDs(t.get_cluster_IDs()) + , _clusterkeys(t.get_cluster_keys()) + , _vertex_id(t.get_vertex_id()) { - _track = new genfit::Track(*(t.getGenFitTrack())); - verbosity = t.verbosity; - _clusterIDs = t.get_cluster_IDs(); - _clusterkeys = t.get_cluster_keys(); - _vertex_id = t.get_vertex_id(); } int Track::addMeasurement(PHGenFit::Measurement* measurement) @@ -191,10 +190,8 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + + return state; } double Track::extrapolateToLine(genfit::MeasuredStateOnPlane& state, const TVector3& line_point, const TVector3& line_direction, const int tr_point_id) const @@ -240,10 +237,8 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + + return state; } double Track::extrapolateToCylinder(genfit::MeasuredStateOnPlane& state, double radius, const TVector3& line_point, const TVector3& line_direction, const int tr_point_id, const int direction) const @@ -361,10 +356,8 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + + return state; } int Track::updateOneMeasurementKalman( @@ -385,7 +378,7 @@ namespace PHGenFit << std::endl; #endif - if (measurements.size() == 0) + if (measurements.empty()) { return -1; } @@ -437,11 +430,11 @@ namespace PHGenFit #endif continue; } - //#ifdef _DEBUG_ + // #ifdef _DEBUG_ // std::cout << __LINE__ << "\n ###################################################################"<Print(); // std::cout << __LINE__ << "\n ###################################################################"<getFittedState(true)); @@ -579,7 +572,7 @@ namespace PHGenFit // std::cout << err_phi << "\t" << err_z << "\t"; } #endif - for (auto rawMeasurement : rawMeasurements) + for (auto* rawMeasurement : rawMeasurements) { fi->addMeasurementsOnPlane( rawMeasurement->constructMeasurementsOnPlane(*state)); @@ -598,7 +591,7 @@ namespace PHGenFit << ": size of fi's MeasurementsOnPlane: " << measurements_on_plane.size() << std::endl; #endif - for (auto it : measurements_on_plane) + for (auto* it : measurements_on_plane) { const genfit::MeasurementOnPlane& mOnPlane = *it; // const double weight = mOnPlane.getWeight(); @@ -769,10 +762,7 @@ namespace PHGenFit delete state; return nullptr; } - else - { - return state; - } + return state; } double Track::get_chi2() const diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc new file mode 100644 index 0000000000..d146ccc9e6 --- /dev/null +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.cc @@ -0,0 +1,279 @@ +#include "CaloStatusSkimmer.h" + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include + +//____________________________________________________________________________.. +CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) + : SubsysReco(name) +{ + // std::cout << "CaloStatusSkimmer::CaloStatusSkimmer(const std::string &name) ""Calling ctor" << std::endl; +} + +//____________________________________________________________________________.. +int CaloStatusSkimmer::Init([[maybe_unused]] PHCompositeNode *topNode) +{ + // std::cout << "CaloStatusSkimmer::Init(PHCompositeNode *topNode) This is Init..." << std::endl; + + if (b_produce_QA_histograms) + { + auto *hm = QAHistManagerDef::getHistoManager(); + assert(hm); + + h_EMC_nTowers_notinstr = new TH1F("h_EMC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in EMCal; nNotInstrTowers; Counts", 24577, -0.5, 24576.5); + h_EMC_nTowers_notinstr->SetDirectory(nullptr); + h_HCal_nTowers_notinstr = new TH1F("h_HCal_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in HCal; nNotInstrTowers; Counts", 1537, -0.5, 1536.5); + h_HCal_nTowers_notinstr->SetDirectory(nullptr); + h_sEPD_nTowers_notinstr = new TH1F("h_sEPD_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in sEPD; nNotInstrTowers; Counts", 745, -0.5, 744.5); + h_sEPD_nTowers_notinstr->SetDirectory(nullptr); + h_ZDC_nTowers_notinstr = new TH1F("h_ZDC_nTowers_notinstr", "Number of not-instrumented(empty/missing pckt) towers in ZDC; nNotInstrTowers; Counts", 53, -0.5, 52.5); + h_ZDC_nTowers_notinstr->SetDirectory(nullptr); + + h_calo_nEvents = new TH1F("h_calo_nEvents", "Number of events", 6, 0.5, 6.5); + h_calo_nEvents->GetXaxis()->SetBinLabel(1, "Total events processed"); + h_calo_nEvents->GetXaxis()->SetBinLabel(2, "Total events skimmed"); + h_calo_nEvents->GetXaxis()->SetBinLabel(3, "EMCal above not-instr threshold"); + h_calo_nEvents->GetXaxis()->SetBinLabel(4, "HCal above not-instr threshold"); + h_calo_nEvents->GetXaxis()->SetBinLabel(5, "sEPD above not-instr threshold"); + h_calo_nEvents->GetXaxis()->SetBinLabel(6, "ZDC above not-instr threshold"); + h_calo_nEvents->SetDirectory(nullptr); + + hm->registerHisto(h_calo_nEvents); + + hm->registerHisto(h_EMC_nTowers_notinstr); + hm->registerHisto(h_HCal_nTowers_notinstr); + hm->registerHisto(h_sEPD_nTowers_notinstr); + hm->registerHisto(h_ZDC_nTowers_notinstr); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int CaloStatusSkimmer::process_event(PHCompositeNode *topNode) +{ + n_eventcounter++; + uint16_t notinstr_EMC = 0; + uint16_t notinstr_HCalin = 0; + uint16_t notinstr_HCalout = 0; + uint16_t notinstr_sEPD = 0; + uint16_t notinstr_ZDC = 0; + + if (m_EMC_skim_threshold > 0) + { + TowerInfoContainer *towers = findNode::getClass(topNode, "TOWERS_CEMC"); + if (!towers) + { + if (Verbosity() > 0) + { + std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_CEMC" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + const uint32_t ntowers = towers->size(); + for (uint32_t ch = 0; ch < ntowers; ++ch) + { + TowerInfo *tower = towers->get_tower_at_channel(ch); + if (tower->get_isNotInstr()) + { + ++notinstr_EMC; + } + } + if (Verbosity() > 9) + { + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in EMCal = " << ntowers << ", not-instrumented(empty/missing pckt) towers in EMCal = " << notinstr_EMC << std::endl; + } + + if (b_produce_QA_histograms) + { + h_EMC_nTowers_notinstr->Fill(notinstr_EMC); + } + + if (notinstr_EMC >= m_EMC_skim_threshold) + { + EMC_skim_count++; + } + } + + if (m_HCal_skim_threshold > 0) + { + TowerInfoContainer *hcalin_towers = findNode::getClass(topNode, "TOWERS_HCALIN"); + TowerInfoContainer *hcalout_towers = findNode::getClass(topNode, "TOWERS_HCALOUT"); + if (!hcalin_towers || !hcalout_towers) + { + if (Verbosity() > 0) + { + std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_HCALIN or TOWERS_HCALOUT" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + const uint32_t ntowers_hcalin = hcalin_towers->size(); + for (uint32_t ch = 0; ch < ntowers_hcalin; ++ch) + { + TowerInfo *tower_in = hcalin_towers->get_tower_at_channel(ch); + if (tower_in->get_isNotInstr()) + { + ++notinstr_HCalin; + } + } + + const uint32_t ntowers_hcalout = hcalout_towers->size(); + for (uint32_t ch = 0; ch < ntowers_hcalout; ++ch) + { + TowerInfo *tower_out = hcalout_towers->get_tower_at_channel(ch); + if (tower_out->get_isNotInstr()) + { + ++notinstr_HCalout; + } + } + + if (Verbosity() > 9) + { + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in HCalIn = " << ntowers_hcalin << ", not-instrumented(empty/missing pckt) towers in HCalIn = " << notinstr_HCalin << ", ntowers in HCalOut = " << ntowers_hcalout << ", not-instrumented(empty/missing pckt) towers in HCalOut = " << notinstr_HCalout << std::endl; + } + + if (b_produce_QA_histograms) + { + h_HCal_nTowers_notinstr->Fill(notinstr_HCalin); + h_HCal_nTowers_notinstr->Fill(notinstr_HCalout); + } + + if (notinstr_HCalin >= m_HCal_skim_threshold || + notinstr_HCalout >= m_HCal_skim_threshold) + { + HCal_skim_count++; + } + } + + // special handling of the sEPD and ZDC because of DST format changes. + + if (m_sEPD_skim_threshold > 0) + { + TowerInfoContainer *sepd_towers = findNode::getClass(topNode, "TOWERS_SEPD"); + + if (!sepd_towers) + { + if (Verbosity() > 0 && !b_printed_missing_sEPD_towers) + { + b_printed_missing_sEPD_towers = true; + std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_SEPD. Further warnings will be suppressed." << std::endl; + } + // Temporarily turned off the event abort because the sEPD towers were removed from calofitting dsts. + // return Fun4AllReturnCodes::ABORTEVENT; + } + if (sepd_towers) + { + const uint32_t ntowers = sepd_towers->size(); + for (uint32_t ch = 0; ch < ntowers; ++ch) + { + TowerInfo *tower = sepd_towers->get_tower_at_channel(ch); + if (tower->get_isNotInstr()) + { + ++notinstr_sEPD; + } + } + + if (Verbosity() > 9) + { + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in sEPD = " << ntowers << ", not-instrumented(empty/missing pckt) towers in sEPD = " << notinstr_sEPD << std::endl; + } + + if (b_produce_QA_histograms) + { + h_sEPD_nTowers_notinstr->Fill(notinstr_sEPD); + } + + if (notinstr_sEPD >= m_sEPD_skim_threshold) + { + sEPD_skim_count++; + } + } + } + + if (m_ZDC_skim_threshold > 0) + { + TowerInfoContainer *zdc_towers = findNode::getClass(topNode, "TOWERS_ZDC"); + if (!zdc_towers) + { + if (Verbosity() > 0 && !b_printed_missing_ZDC_towers) + { + b_printed_missing_ZDC_towers = true; + std::cout << PHWHERE << "CaloStatusSkimmer::process_event: missing TOWERS_ZDC. Further warnings will be suppressed." << std::endl; + } + // Temporarily turned off the event abort because the ZDC towers were removed from calofitting dsts. + // return Fun4AllReturnCodes::ABORTEVENT; + } + if (zdc_towers) + { + const uint32_t ntowers = zdc_towers->size(); + for (uint32_t ch = 0; ch < ntowers; ++ch) + { + TowerInfo *tower = zdc_towers->get_tower_at_channel(ch); + if (tower->get_isNotInstr()) + { + ++notinstr_ZDC; + } + } + + if (Verbosity() > 9) + { + std::cout << "CaloStatusSkimmer::process_event: event " << n_eventcounter << ", ntowers in ZDC = " << ntowers << ", not-instrumented(empty/missing pckt) towers in ZDC = " << notinstr_ZDC << std::endl; + } + + if (b_produce_QA_histograms) + { + h_ZDC_nTowers_notinstr->Fill(notinstr_ZDC); + } + + if (notinstr_ZDC >= m_ZDC_skim_threshold) + { + ZDC_skim_count++; + } + } + } + + // If any of the enabled skimming conditions are met, then increment the skim counter and return ABORTEVENT to skip the event + if ((m_EMC_skim_threshold > 0 && notinstr_EMC >= m_EMC_skim_threshold) || (m_HCal_skim_threshold > 0 && (notinstr_HCalin >= m_HCal_skim_threshold || notinstr_HCalout >= m_HCal_skim_threshold)) || (m_sEPD_skim_threshold > 0 && notinstr_sEPD >= m_sEPD_skim_threshold) || (m_ZDC_skim_threshold > 0 && notinstr_ZDC >= m_ZDC_skim_threshold)) + { + n_skimcounter++; + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int CaloStatusSkimmer::End([[maybe_unused]] PHCompositeNode *topNode) +{ + std::cout << "CaloStatusSkimmer::End(PHCompositeNode *topNode) This is the End..." << std::endl; + std::cout << "CaloStatusSkimmer::End Total events processed: " << n_eventcounter << std::endl; + std::cout << "CaloStatusSkimmer::End Total events skimmed: " << n_skimcounter << std::endl; + + if (b_produce_QA_histograms) + { + h_calo_nEvents->SetBinContent(1, n_eventcounter); + h_calo_nEvents->SetBinContent(2, n_skimcounter); + h_calo_nEvents->SetBinContent(3, EMC_skim_count); + h_calo_nEvents->SetBinContent(4, HCal_skim_count); + h_calo_nEvents->SetBinContent(5, sEPD_skim_count); + h_calo_nEvents->SetBinContent(6, ZDC_skim_count); + } + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h new file mode 100644 index 0000000000..305da1c47a --- /dev/null +++ b/offline/packages/Skimmers/CaloStatusSkimmer/CaloStatusSkimmer.h @@ -0,0 +1,97 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef CALOSTATUSSKIMMER_H +#define CALOSTATUSSKIMMER_H + +#include + +#include +#include +#include +#include + +class PHCompositeNode; +class TH1; + +class CaloStatusSkimmer : public SubsysReco { +public: + CaloStatusSkimmer(const std::string &name = "CaloStatusSkimmer"); + + ~CaloStatusSkimmer() override = default; + + int Init(PHCompositeNode* topNode) override; + + /** Called for each event. + This is where you do the real work. + */ + int process_event(PHCompositeNode *topNode) override; + + /// Called at the end of all processing. + int End(PHCompositeNode *topNode) override; + + void do_skim_EMCal( uint16_t threshold) + { + m_EMC_skim_threshold = threshold; + } + + void do_skim_HCal( uint16_t threshold) + { + m_HCal_skim_threshold = threshold; + } + + void do_skim_sEPD( uint16_t threshold) + { + m_sEPD_skim_threshold = threshold; + } + + void do_skim_ZDC( uint16_t threshold) + { + m_ZDC_skim_threshold = threshold; + } + + void produce_QA_histograms(bool produce) + { + b_produce_QA_histograms = produce; + } + +private: + uint32_t n_eventcounter{0}; + uint32_t n_skimcounter{0}; + + bool b_produce_QA_histograms{false}; + + // If the threshold is set to 0, then the skimming for that subsystem is disabled. If threshold is > 0, then the event is skimmed if nchannels >= threshold not-instrumented (empty/missing packet) channels in that subsystem. + + uint16_t m_EMC_skim_threshold{193}; + // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in EMCal. For the EMCal in particular we want to skim if greater than 1 packet's worth of channels are not-instrumented, which corresponds to 193 channels (since each packet has 192 channels) + + uint16_t m_HCal_skim_threshold{192}; + // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in HCal. Corresponds to 1 packet's worth of channels in HCal, which has 192 channels per packet + + uint16_t m_sEPD_skim_threshold{1}; + // skim if nchannels >= this many not-instrumented (empty/missing packet) channels in sEPD. + + uint16_t m_ZDC_skim_threshold{0}; + // skim if nchannels > this many not-instrumented (empty/missing packet) channels in ZDC. Some issue in the ZDC right now so skimming is turned off by now by default. + + // Counters for number of events skimmed per subsystem + uint32_t EMC_skim_count = 0; + uint32_t HCal_skim_count = 0; + uint32_t sEPD_skim_count = 0; + uint32_t ZDC_skim_count = 0; + + //Per-calo tower counter histograms + TH1* h_EMC_nTowers_notinstr = nullptr; + TH1* h_HCal_nTowers_notinstr = nullptr; + TH1* h_sEPD_nTowers_notinstr = nullptr; + TH1* h_ZDC_nTowers_notinstr = nullptr; + + //Event counter histograms + TH1* h_calo_nEvents = nullptr; + + // print out the missing sEPD and ZDC towers only Once. + bool b_printed_missing_sEPD_towers = false; + bool b_printed_missing_ZDC_towers = false; +}; + +#endif // CALOSTATUSSKIMMER_H diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am b/offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am new file mode 100644 index 0000000000..6ec5fc7af2 --- /dev/null +++ b/offline/packages/Skimmers/CaloStatusSkimmer/Makefile.am @@ -0,0 +1,44 @@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = \ + -I$(includedir) \ + -I$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +pkginclude_HEADERS = \ + CaloStatusSkimmer.h + +lib_LTLIBRARIES = \ + libCaloStatusSkimmer.la + +libCaloStatusSkimmer_la_SOURCES = \ + CaloStatusSkimmer.cc + +libCaloStatusSkimmer_la_LIBADD = \ + -lphool \ + -lSubsysReco \ + -lcalo_io \ + -lqautils + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals + +testexternals_SOURCES = testexternals.cc +testexternals_LDADD = libCaloStatusSkimmer.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/offline/packages/Skimmers/CaloStatusSkimmer/autogen.sh b/offline/packages/Skimmers/CaloStatusSkimmer/autogen.sh new file mode 100755 index 0000000000..dea267bbfd --- /dev/null +++ b/offline/packages/Skimmers/CaloStatusSkimmer/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/offline/framework/rawbcolumi/configure.ac b/offline/packages/Skimmers/CaloStatusSkimmer/configure.ac similarity index 90% rename from offline/framework/rawbcolumi/configure.ac rename to offline/packages/Skimmers/CaloStatusSkimmer/configure.ac index 301b8f12e5..d31173586b 100644 --- a/offline/framework/rawbcolumi/configure.ac +++ b/offline/packages/Skimmers/CaloStatusSkimmer/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(rawbcolumi,[2.00]) +AC_INIT(calostatusskimmer,[1.00]) AC_CONFIG_SRCDIR([configure.ac]) AM_INIT_AUTOMAKE @@ -12,6 +12,5 @@ if test $ac_cv_prog_gxx = yes; then CXXFLAGS="$CXXFLAGS -Wall -Wextra -Wshadow -Werror" fi - AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc index b519fd472e..224d172a24 100644 --- a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc +++ b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.cc @@ -20,6 +20,12 @@ TriggerDSTSkimmer::TriggerDSTSkimmer(const std::string &name) //____________________________________________________________________________.. int TriggerDSTSkimmer::process_event(PHCompositeNode *topNode) { + + if ((accepted_events >= max_accept) && use_max_accept) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + if (Verbosity() > 0) { if (ievent % 1000 == 0) @@ -45,7 +51,7 @@ int TriggerDSTSkimmer::process_event(PHCompositeNode *topNode) if (n_trigger_index != 0) { bool trigger_fired = false; - Gl1Packet *_gl1PacketInfo = findNode::getClass(topNode, "GL1Packet"); + Gl1Packet *_gl1PacketInfo = findNode::getClass(topNode, 14001); int gl1_trigger_vector_scaled[64] = {0}; if (_gl1PacketInfo) { @@ -61,6 +67,7 @@ int TriggerDSTSkimmer::process_event(PHCompositeNode *topNode) std::cout << "TriggerDSTSkimmer::process_event - Error - Can't find Trigger Node Gl1Packet therefore no selection can be made" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } + for (int it = 0; it < n_trigger_index; ++it) { if (gl1_trigger_vector_scaled[m_trigger_index[it]] == 1) @@ -74,5 +81,8 @@ int TriggerDSTSkimmer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } } + + accepted_events++; + return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h index dfb2c47a7c..9919df06b7 100644 --- a/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h +++ b/offline/packages/Skimmers/Trigger/TriggerDSTSkimmer.h @@ -22,10 +22,22 @@ class TriggerDSTSkimmer : public SubsysReco void SetTrigger(std::vector &trigger_vector) {m_trigger_index = trigger_vector;} + void set_accept_max(int max_events) + { + use_max_accept = true; + max_accept = max_events; + return; + } + private: std::vector m_trigger_index{10}; int ievent{0}; + + int accepted_events{0}; + int max_accept{0}; + bool use_max_accept{false}; + }; #endif // JETDSTSKIMMER_H diff --git a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc index e50a41a3f6..8331a8b491 100644 --- a/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc +++ b/offline/packages/TrackerMillepedeAlignment/HelicalFitter.cc @@ -594,8 +594,8 @@ int HelicalFitter::process_event(PHCompositeNode* /*unused*/) // fitpoint is the point where the helical fit intersects the plane of the surface // Now transform the helix fitpoint to local coordinates to compare with cluster local coordinates - Acts::Vector3 fitpoint_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint * Acts::UnitConstants::cm); - Acts::Vector3 fitpoint_mvtx_half_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_mvtx_half * Acts::UnitConstants::cm); + Acts::Vector3 fitpoint_local = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint * Acts::UnitConstants::cm); + Acts::Vector3 fitpoint_mvtx_half_local = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_mvtx_half * Acts::UnitConstants::cm); fitpoint_local /= Acts::UnitConstants::cm; fitpoint_mvtx_half_local /= Acts::UnitConstants::cm; @@ -634,7 +634,7 @@ int HelicalFitter::process_event(PHCompositeNode* /*unused*/) if (Verbosity() > 1) { - Acts::Vector3 loc_check = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm); + Acts::Vector3 loc_check = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm); loc_check /= Acts::UnitConstants::cm; std::cout << " layer " << layer << std::endl << " cluster global " << global(0) << " " << global(1) << " " << global(2) << std::endl @@ -647,10 +647,10 @@ int HelicalFitter::process_event(PHCompositeNode* /*unused*/) if (Verbosity() > 1) { - Acts::Transform3 transform = surf->transform(_tGeometry->geometry().getGeoContext()); + Acts::Transform3 transform = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()); std::cout << "Transform is:" << std::endl; std::cout << transform.matrix() << std::endl; - Acts::Vector3 loc_check = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm); + Acts::Vector3 loc_check = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm); loc_check /= Acts::UnitConstants::cm; unsigned int const sector = TpcDefs::getSectorId(cluskey_vec[ivec]); unsigned int const side = TpcDefs::getSide(cluskey_vec[ivec]); @@ -779,7 +779,7 @@ int HelicalFitter::process_event(PHCompositeNode* /*unused*/) Acts::Vector3 ideal_center = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1; Acts::Vector3 ideal_norm = -surf->normal(_tGeometry->geometry().getGeoContext(),Acts::Vector3(1,1,1), Acts::Vector3(1,1,1)); Acts::Vector3 const ideal_local(xloc, zloc, 0.0); // cm - Acts::Vector3 ideal_glob = surf->transform(_tGeometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); + Acts::Vector3 ideal_glob = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); ideal_glob /= Acts::UnitConstants::cm; alignmentTransformationContainer::use_alignment = true; @@ -1953,10 +1953,10 @@ void HelicalFitter::get_projectionXY(const Surface& surf, const std::pairtransform(_tGeometry->geometry().getGeoContext()) * (xloc * Acts::UnitConstants::cm); + Acts::Vector3 xglob = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()) * (xloc * Acts::UnitConstants::cm); xglob /= Acts::UnitConstants::cm; Acts::Vector3 const yloc(0.0, 1.0, 0.0); - Acts::Vector3 yglob = surf->transform(_tGeometry->geometry().getGeoContext()) * (yloc * Acts::UnitConstants::cm); + Acts::Vector3 yglob = surf->localToGlobalTransform(_tGeometry->geometry().getGeoContext()) * (yloc * Acts::UnitConstants::cm); yglob /= Acts::UnitConstants::cm; // These are the local frame unit vectors transformed to the global frame Acts::Vector3 const X = (xglob - sensorCenter) / (xglob - sensorCenter).norm(); diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc index c894542990..cb50fd55f0 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.cc @@ -297,23 +297,22 @@ bool MakeMilleFiles::getLocalVtxDerivativesXY(SvtxTrack* track, const Acts::Vector3& vertex, float lclvtx_derivative[SvtxAlignmentState::NRES][SvtxAlignmentState::NLOC]) { + //! Get the first track state beyond the vertex, which will be the //! innermost track state and propagate it to the vertex surface to //! get the jacobian at the vertex - SvtxTrackState* firststate = (*std::next(track->begin_states(), 1)).second; - - TrkrDefs::cluskey ckey = firststate->get_cluskey(); - auto cluster = _cluster_map->findCluster(ckey); - auto surf = _tGeometry->maps().getSurface(ckey, cluster); + auto* firststate = (*std::next(track->begin_states(), 1)).second; - auto param = propagator.makeTrackParams(firststate, track->get_charge(), surf).value(); - auto perigee = propagator.makeVertexSurface(vertex); - auto actspropagator = propagator.makePropagator(); + const auto ckey = firststate->get_cluskey(); + const auto cluster = _cluster_map->findCluster(ckey); + const auto surf = _tGeometry->maps().getSurface(ckey, cluster); - Acts::PropagatorOptions<> options(_tGeometry->geometry().getGeoContext(), - _tGeometry->geometry().magFieldContext); + const auto param = propagator.makeTrackParams(firststate, track->get_charge(), surf).value(); + const auto perigee = propagator.makeVertexSurface(vertex); + const auto actspropagator = propagator.makePropagator(); + const ActsPropagator::SphenixPropagator::Options options(_tGeometry->geometry().getGeoContext(), _tGeometry->geometry().magFieldContext); - auto result = actspropagator.propagate(param, *perigee, options); + const auto result = actspropagator.propagate(param, *perigee, options); if (result.ok()) { diff --git a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h index 25a8963987..0733e22bb6 100644 --- a/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h +++ b/offline/packages/TrackerMillepedeAlignment/MakeMilleFiles.h @@ -23,6 +23,7 @@ #include +#include #include #include diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc index f92bfc9581..6efbebf100 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.cc +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.cc @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -24,6 +25,7 @@ #include #pragma GCC diagnostic pop +#include #include #include #include @@ -56,11 +58,57 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) m_runNumber = m_evtNumber = -1; } + //Truth matching setup. Setting IDs and getting nodes + if (m_truth_match) + { + if (m_used_string) + { + m_mother_id = getMotherPDG(); + } + + m_truthinfo = findNode::getClass(topNode, "G4TruthInfo"); + + if (!m_truthinfo) //Missing truth info container. Disable truth matching + { + m_truth_match = false; + } + + } + + // Loop over tracks and check for close DCA match with all other tracks for (auto tr1_it = m_svtxTrackMap->begin(); tr1_it != m_svtxTrackMap->end(); ++tr1_it) { + auto id1 = tr1_it->first; auto *tr1 = tr1_it->second; + + //Truth matching. Let's see if this track came from the right mother + if (m_truth_match) + { + truth_particle_1 = getTruthTrack(tr1, topNode); + + if (truth_particle_1 == nullptr) + { + continue; + } + + int parent_id = truth_particle_1->get_parent_id(); + if (parent_id == 0) //Particle is primary. Trying to access its parent returns nullptr + { + continue; + } + + PHG4Particle *g4mother = m_truthinfo->GetParticle(parent_id); + + if (g4mother == nullptr || (abs(g4mother->get_pid()) != abs(m_mother_id))) //PID check + { + continue; + } + + truth_mother_id_particle_1 = g4mother->get_barcode(); + } + if (tr1->get_quality() > _qual_cut) { continue; @@ -92,8 +140,6 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) std::vector nstates1 = getTrackStates(tr1); unsigned int track1_mvtx_state_size = nstates1[0]; unsigned int track1_intt_state_size = nstates1[1]; - // unsigned int track1_tpc_state_size = nstates1[2]; - // unsigned int track1_mms_state_size = nstates1[3]; unsigned int track1_silicon_cluster_size = std::numeric_limits::quiet_NaN(); if (siliconseed) @@ -125,20 +171,56 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) Acts::Vector3 pos1(tr1->get_x(), tr1->get_y(), tr1->get_z()); Acts::Vector3 mom1(tr1->get_px(), tr1->get_py(), tr1->get_pz()); Acts::Vector3 dcaVals1 = calculateDca(tr1, mom1, pos1); - // first dca cuts if (fabs(dcaVals1(0)) < this_dca_cut || fabs(dcaVals1(1)) < this_dca_cut) - { - continue; - } - + { + // std::cout << " tr1 failed dca cuts " << std::endl; + continue; + } // look for close DCA matches with all other such tracks for (auto tr2_it = std::next(tr1_it); tr2_it != m_svtxTrackMap->end(); ++tr2_it) { auto id2 = tr2_it->first; auto *tr2 = tr2_it->second; + + //Truth matching. Let's see if this track came from the right mother + if (m_truth_match) + { + truth_particle_2 = getTruthTrack(tr2, topNode); + + if (truth_particle_2 == nullptr) + { + continue; + } + + int parent_id = truth_particle_2->get_parent_id(); + if (parent_id == 0) //Particle is primary. Trying to access its parent returns nullptr + { + continue; + } + PHG4Particle *g4mother = m_truthinfo->GetParticle(parent_id); + + if (g4mother == nullptr || (abs(g4mother->get_pid()) != abs(m_mother_id))) //PID check + { + continue; + } + + truth_mother_id_particle_2 = g4mother->get_barcode(); + + //Check that the two tracks came from the same mother + if (truth_mother_id_particle_1 != truth_mother_id_particle_2) + { + continue; + } + } + + // dca xy and dca z cut here compare to track dca cut + Acts::Vector3 pos2(tr2->get_x(), tr2->get_y(), tr2->get_z()); + Acts::Vector3 mom2(tr2->get_px(), tr2->get_py(), tr2->get_pz()); + Acts::Vector3 dcaVals2 = calculateDca(tr2, mom2, pos2); + if (tr2->get_quality() > _qual_cut) { - continue; + continue; } if (tr2->get_pt() < track_pt_cut) { @@ -161,15 +243,13 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) } if (_require_mvtx) { - continue; - } + continue; + } } std::vector nstates2 = getTrackStates(tr2); unsigned int track2_mvtx_state_size = nstates2[0]; unsigned int track2_intt_state_size = nstates2[1]; - // unsigned int track2_tpc_state_size = nstates2[2]; - // unsigned int track2_mms_state_size = nstates2[3]; unsigned int track2_silicon_cluster_size = std::numeric_limits::quiet_NaN(); if (siliconseed2) @@ -198,20 +278,16 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) } } - // dca xy and dca z cut here compare to track dca cut - Acts::Vector3 pos2(tr2->get_x(), tr2->get_y(), tr2->get_z()); - Acts::Vector3 mom2(tr2->get_px(), tr2->get_py(), tr2->get_pz()); - Acts::Vector3 dcaVals2 = calculateDca(tr2, mom2, pos2); - + if (fabs(dcaVals2(0)) < this_dca_cut2 || fabs(dcaVals2(1)) < this_dca_cut2) { continue; } - // find DCA of these two tracks + // find pair DCA of these two tracks if (Verbosity() > 3) { - std::cout << "Check DCA for tracks " << id1 << " and " << id2 << std::endl; + std::cout << "Check pair DCA for tracks " << id1 << " and " << id2 << std::endl; } if (tr1->get_charge() == tr2->get_charge()) @@ -233,7 +309,6 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) // This presently assumes straight line tracks to get a rough answer // Should update to use circles instead? findPcaTwoTracks(pos1, pos2, mom1, mom2, pca_rel1, pca_rel2, pair_dca); - // tracks with small relative pca are k short candidates if (abs(pair_dca) < pair_dca_cut) { @@ -260,36 +335,57 @@ int KshortReconstruction::process_event(PHCompositeNode* topNode) // if(pair_dca_proj > pair_dca_cut) continue; - // invariant mass is calculated in this method - fillHistogram(projected_mom1, projected_mom2, recomass, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity); - fillNtp(tr1, tr2, dcaVals1, dcaVals2, pca_rel1, pca_rel2, pair_dca, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity, projected_pos1, projected_pos2, projected_mom1, projected_mom2, pca_rel1_proj, pca_rel2_proj, pair_dca_proj, track1_silicon_cluster_size, track2_silicon_cluster_size, track1_mvtx_cluster_size, track1_mvtx_state_size, track1_intt_cluster_size, track1_intt_state_size, track2_mvtx_cluster_size, track2_mvtx_state_size, track2_intt_cluster_size, track2_intt_state_size, m_runNumber, m_evtNumber); - - if (Verbosity() > 1) - { - std::cout << " Accepted Track Pair" << std::endl; - std::cout << " id1 " << id1 << " id2 " << id2 << std::endl; - std::cout << " crossing1 " << crossing1 << " crossing2 " << crossing2 << std::endl; - std::cout << " invariant mass: " << invariantMass << std::endl; - std::cout << " track1 dca_cut: " << this_dca_cut << " track2 dca_cut: " << this_dca_cut2 << std::endl; - std::cout << " dca3dxy1,dca3dz1,phi1: " << dcaVals1 << std::endl; - std::cout << " dca3dxy2,dca3dz2,phi2: " << dcaVals2 << std::endl; - std::cout << "Initial: pca_rel1: " << pca_rel1 << " pca_rel2: " << pca_rel2 << std::endl; - std::cout << " Initial: mom1: " << mom1 << " mom2: " << mom2 << std::endl; - std::cout << "Proj_pca_rel: proj_pos1: " << projected_pos1 << " proj_pos2: " << projected_pos2 << " proj_mom1: " << projected_mom1 << " proj_mom2: " << projected_mom2 << std::endl; - std::cout << " Relative PCA = " << abs(pair_dca) << " pca_cut = " << pair_dca_cut << std::endl; - std::cout << " charge 1: " << tr1->get_charge() << " charge2: " << tr2->get_charge() << std::endl; - std::cout << "found viable projection" << std::endl; - std::cout << "Final: pca_rel1_proj: " << pca_rel1_proj << " pca_rel2_proj: " << pca_rel2_proj << " mom1: " << projected_mom1 << " mom2: " << projected_mom2 << std::endl - << std::endl; - } - + // calculate both ways if decaymass1 and decaymass2 are different + int ncombinations = 1; + if(decaymass1 != decaymass2) + { + ncombinations = 2; + } + for(int icomb=0;icomb < ncombinations; ++icomb) + { + float decaymassa = decaymass1; + float decaymassb = decaymass2; + if(icomb == 1) + { + decaymassa = decaymass2; + decaymassb = decaymass1; + } + + // invariant mass is calculated in this method + fillHistogram(projected_mom1, projected_mom2, recomass, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity,decaymassa, decaymassb); + fillNtp(tr1, tr2, decaymassa, decaymassb, dcaVals1, dcaVals2, pca_rel1, pca_rel2, pair_dca, invariantMass, invariantPt, invariantPhi, rapidity, pseudorapidity, projected_pos1, projected_pos2, projected_mom1, projected_mom2, pca_rel1_proj, pca_rel2_proj, pair_dca_proj, track1_silicon_cluster_size, track2_silicon_cluster_size, track1_mvtx_cluster_size, track1_mvtx_state_size, track1_intt_cluster_size, track1_intt_state_size, track2_mvtx_cluster_size, track2_mvtx_state_size, track2_intt_cluster_size, track2_intt_state_size, m_runNumber, m_evtNumber); + + if (Verbosity() > 1) + { + std::cout << "Accepted Track Pair" << " id1 " << id1 << " id2 " << id2 << " crossing1 " << crossing1 << " crossing2 " << crossing2 << std::endl; + std::cout << " invariant mass: " << invariantMass << " decaymassa " << decaymassa << " decaymassb " << decaymassb << std::endl; + std::cout << " track1 dca_cut: " << this_dca_cut << " track2 dca_cut: " << this_dca_cut2 << std::endl; + std::cout << " dca3dxy1,dca3dz1,phi1: " << dcaVals1(0) << " " << dcaVals1(1) << " " << dcaVals1(2) << std::endl; + std::cout << " dca3dxy2,dca3dz2,phi2: " << dcaVals2(0) << " " << dcaVals2(1) << " " << dcaVals2(2) << std::endl; + std::cout << " Initial: pca_rel1: " << pca_rel1(0) << " " << pca_rel1(1) << " " << pca_rel1(2) << std::endl; + std::cout << " Initial: pca_rel2: " << pca_rel2(0) << " " << pca_rel2(1) << " " << pca_rel2(2) << std::endl; + std::cout << " Initial: mom1: " << mom1(0) << " " << mom1(1) << " " << mom1(2) << std::endl; + std::cout << " Initial: mom2: " << mom2(0) << " " << mom2(1) << " " << mom2(2) << std::endl; + std::cout << " Proj_pca_rel: proj_pos1: " << projected_pos1(0) << " " << projected_pos1(1) << " " << projected_pos1(2) << std::endl; + std::cout << " Proj_pca_rel: proj_pos2: " << projected_pos2(0) << " " << projected_pos2(1) << " " << projected_pos2(2) << std::endl; + std::cout << " proj_mom1: " << projected_mom1(0) << " " << projected_mom1(1) << " " << projected_mom1(2) << std::endl; + std::cout << " proj_mom2: " << projected_mom2(0) << " " << projected_mom2(1) << " " << projected_mom2(2) << std::endl; + std::cout << " Relative PCA = " << abs(pair_dca) << " pca_cut = " << pair_dca_cut << std::endl; + std::cout << " charge 1: " << tr1->get_charge() << " charge2: " << tr2->get_charge() << std::endl; + std::cout << " found viable projection" << std::endl; + std::cout << " Final: pca_rel1_proj: " << pca_rel1_proj(0) << " " << pca_rel1_proj(1) << " " << pca_rel1_proj(2) << std::endl; + std::cout << " Final: pca_rel2_proj: " << pca_rel2_proj(0) << " " << pca_rel2_proj(1) << " " << pca_rel2_proj(2) << std::endl; + std::cout << " Final: mom1: " << projected_mom1(0) << " " << projected_mom1(1) << " " << projected_mom1(2) << std::endl; + std::cout << " Final: mom2: " << projected_mom2(0) << " " << projected_mom2(1) << " " << projected_mom2(2) << std::endl; + } + } if (m_save_tracks) - { - m_output_trackMap = findNode::getClass(topNode, m_output_trackMap_node_name); - m_output_trackMap->insertWithKey(tr1, tr1->get_id()); - m_output_trackMap->insertWithKey(tr2, tr2->get_id()); - } - + { + m_output_trackMap = findNode::getClass(topNode, m_output_trackMap_node_name); + m_output_trackMap->insertWithKey(tr1, tr1->get_id()); + m_output_trackMap->insertWithKey(tr2, tr2->get_id()); + } + } } } @@ -327,9 +423,7 @@ std::vector KshortReconstruction::getTrackStates(SvtxTrack *track) nmmsstate++; break; default: - std::cout << PHWHERE << " unknown key " << stateckey << std::endl; - gSystem->Exit(1); - exit(1); + break; } } nstates.push_back(nmapsstate); @@ -340,6 +434,53 @@ std::vector KshortReconstruction::getTrackStates(SvtxTrack *track) return nstates; } +void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, float mass1, float mass2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj, unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber) +{ + double px1 = track1->get_px(); + double py1 = track1->get_py(); + double pz1 = track1->get_pz(); + auto *tpcSeed1 = track1->get_tpc_seed(); + size_t tpcClusters1 = tpcSeed1->size_cluster_keys(); + double eta1 = asinh(pz1 / sqrt(pow(px1, 2) + pow(py1, 2))); + + double px2 = track2->get_px(); + double py2 = track2->get_py(); + double pz2 = track2->get_pz(); + auto *tpcSeed2 = track2->get_tpc_seed(); + size_t tpcClusters2 = tpcSeed2->size_cluster_keys(); + double eta2 = asinh(pz2 / sqrt(pow(px2, 2) + pow(py2, 2))); + + auto vtxid = track1->get_vertex_id(); + + int ntracks_vertex = 0; + Acts::Vector3 vertex(0, 0, track1->get_z()); // fake primary vertex + auto *svtxVertex = m_vertexMap->get(vtxid); + if (svtxVertex) + { + vertex(0) = svtxVertex->get_x(); + vertex(1) = svtxVertex->get_y(); + vertex(2) = svtxVertex->get_z(); + ntracks_vertex = svtxVertex->size_tracks(); + } + + Acts::Vector3 pathLength = (pca_rel1 + pca_rel2) * 0.5 - vertex; + Acts::Vector3 pathLength_proj = (pca_rel1_proj + pca_rel2_proj) * 0.5 - vertex; + + float mag_pathLength = sqrt(pow(pathLength(0), 2) + pow(pathLength(1), 2) + pow(pathLength(2), 2)); + float mag_pathLength_proj = sqrt(pow(pathLength_proj(0), 2) + pow(pathLength_proj(1), 2) + pow(pathLength_proj(2), 2)); + + Acts::Vector3 projected_momentum = projected_mom1 + projected_mom2; + float cos_theta_reco = pathLength_proj.dot(projected_momentum) / (projected_momentum.norm() * pathLength_proj.norm()); + + + float reco_info[] = {(float) track1->get_id(), mass1, (float) track1->get_crossing(), track1->get_x(), track1->get_y(), track1->get_z(), track1->get_px(), track1->get_py(), track1->get_pz(), (float) dcavals1(0), (float) dcavals1(1), (float) dcavals1(2), (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2), (float) eta1, (float) track1->get_charge(), (float) tpcClusters1, (float) track2->get_id(), mass2, (float) track2->get_crossing(), track2->get_x(), track2->get_y(), track2->get_z(), track2->get_px(), track2->get_py(), track2->get_pz(), (float) dcavals2(0), (float) dcavals2(1), (float) dcavals2(2), (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2), (float) eta2, (float) track2->get_charge(), (float) tpcClusters2, (float) ntracks_vertex, (float) vertex(0), (float) vertex(1), (float) vertex(2), (float) pair_dca, (float) invariantMass, (float) invariantPt, invariantPhi, (float) pathLength(0), (float) pathLength(1), (float) pathLength(2), mag_pathLength, rapidity, pseudorapidity, (float) projected_pos1(0), (float) projected_pos1(1), (float) projected_pos1(2), (float) projected_pos2(0), (float) projected_pos2(1), (float) projected_pos2(2), (float) projected_mom1(0), (float) projected_mom1(1), (float) projected_mom1(2), (float) projected_mom2(0), (float) projected_mom2(1), (float) projected_mom2(2), (float) pca_rel1_proj(0), (float) pca_rel1_proj(1), (float) pca_rel1_proj(2), (float) pca_rel2_proj(0), (float) pca_rel2_proj(1), (float) pca_rel2_proj(2), (float) pair_dca_proj, (float) pathLength_proj(0), (float) pathLength_proj(1), (float) pathLength_proj(2), mag_pathLength_proj, track1->get_quality(), track2->get_quality(), cos_theta_reco, (float) track1_silicon_cluster_size, (float) track2_silicon_cluster_size, (float) track1_mvtx_cluster_size, (float) track1_mvtx_state_size, (float) track1_intt_cluster_size, (float) track1_intt_state_size, (float) track2_mvtx_cluster_size, (float) track2_mvtx_state_size, (float) track2_intt_cluster_size, (float) track2_intt_state_size, (float) runNumber, (float) eventNumber}; + + ntp_reco_info->Fill(reco_info); +} + + + +/* void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj, unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber) { double px1 = track1->get_px(); @@ -381,36 +522,37 @@ void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::V ntp_reco_info->Fill(reco_info); } +*/ -void KshortReconstruction::fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity) +void KshortReconstruction::fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity, float &decaymassa, float &decaymassb) { - double E1 = sqrt(pow(mom1(0), 2) + pow(mom1(1), 2) + pow(mom1(2), 2) + pow(decaymass, 2)); - double E2 = sqrt(pow(mom2(0), 2) + pow(mom2(1), 2) + pow(mom2(2), 2) + pow(decaymass, 2)); - + double E1 = sqrt(pow(mom1(0), 2) + pow(mom1(1), 2) + pow(mom1(2), 2) + pow(decaymassa, 2)); + double E2 = sqrt(pow(mom2(0), 2) + pow(mom2(1), 2) + pow(mom2(2), 2) + pow(decaymassb, 2)); + TLorentzVector v1(mom1(0), mom1(1), mom1(2), E1); TLorentzVector v2(mom2(0), mom2(1), mom2(2), E2); - + TLorentzVector tsum; tsum = v1 + v2; - + rapidity = tsum.Rapidity(); pseudorapidity = tsum.Eta(); invariantMass = tsum.M(); invariantPt = tsum.Pt(); invariantPhi = tsum.Phi(); - - if (Verbosity() > 2) - { - std::cout << "px1: " << mom1(0) << " py1: " << mom1(1) << " pz1: " << mom1(2) << " E1: " << E1 << std::endl; - std::cout << "px2: " << mom2(0) << " py2: " << mom2(1) << " pz2: " << mom2(2) << " E2: " << E2 << std::endl; - std::cout << "tsum: " << tsum(0) << " " << tsum(1) << " " << tsum(2) << " " << tsum(3) << std::endl; - std::cout << "invariant mass: " << invariantMass << " invariant Pt: " << invariantPt << " invariantPhi: " << invariantPhi << std::endl; - } - + + if (Verbosity() > 1) + { + std::cout << "px1: " << mom1(0) << " py1: " << mom1(1) << " pz1: " << mom1(2) << " mass " << decaymassa << " E1: " << E1 << std::endl; + std::cout << "px2: " << mom2(0) << " py2: " << mom2(1) << " pz2: " << mom2(2) << " mass2 " << decaymassb << " E2: " << E2 << std::endl; + std::cout << "tsum: " << tsum(0) << " " << tsum(1) << " " << tsum(2) << " " << tsum(3) << std::endl; + std::cout << "invariant mass: " << invariantMass << " invariant Pt: " << invariantPt << " invariantPhi: " << invariantPhi << std::endl; + } + if (invariantPt > invariant_pt_cut) - { - massreco->Fill(invariantMass); - } + { + massreco->Fill(invariantMass); + } } bool KshortReconstruction::projectTrackToPoint(SvtxTrack* track, Eigen::Vector3d PCA, Eigen::Vector3d& pos, Eigen::Vector3d& mom) @@ -529,6 +671,72 @@ Acts::Vector3 KshortReconstruction::getVertex(SvtxTrack* track) return vertex; } +void KshortReconstruction::findPcaTwoTracks(const Acts::Vector3& pos1, const Acts::Vector3& pos2, Acts::Vector3 mom1, Acts::Vector3 mom2, Acts::Vector3& pca1, Acts::Vector3& pca2, double& dca) const +{ + TLorentzVector v1; + TLorentzVector v2; + + double px1 = mom1(0); + double py1 = mom1(1); + double pz1 = mom1(2); + double px2 = mom2(0); + double py2 = mom2(1); + double pz2 = mom2(2); + + // calculate lorentz vector + const Eigen::Vector3d& a1 = pos1; + const Eigen::Vector3d& a2 = pos2; + + Eigen::Vector3d b1(px1, py1, pz1); + Eigen::Vector3d b2(px2, py2, pz2); + + // The shortest distance between two skew lines described by + // a1 + c * b1 + // a2 + d * b2 + // where a1, a2, are vectors representing points on the lines, b1, b2 are direction vectors, and c and d are scalars + // dca = (b1 x b2) .(a2-a1) / |b1 x b2| + + // bcrossb/mag_bcrossb is a unit vector perpendicular to both direction vectors b1 and b2 + auto bcrossb = b1.cross(b2); + auto mag_bcrossb = bcrossb.norm(); + // a2-a1 is the vector joining any arbitrary points on the two lines + auto aminusa = a2 - a1; + + // The DCA of these two lines is the projection of a2-a1 along the direction of the perpendicular to both + // remember that a2-a1 is longer than (or equal to) the dca by definition + dca = 999; + if (mag_bcrossb != 0) + { + dca = bcrossb.dot(aminusa) / mag_bcrossb; + } + else + { + return; // same track, skip combination + } + + // get the points at which the normal to the lines intersect the lines, where the lines are perpendicular + + // coderabbit suggestion + const double b1b1 = b1.dot(b1); + const double b2b2 = b2.dot(b2); + const double b1b2 = b1.dot(b2); + const double denom = b1b1 * b2b2 - b1b2 * b1b2; + if (std::abs(denom) < 1e-12) + { + return; + } + const Eigen::Vector3d w0 = a1 - a2; + const double c = (b1b2 * b2.dot(w0) - b2b2 * b1.dot(w0)) / denom; + const double d = (b1b1 * b2.dot(w0) - b1b2 * b1.dot(w0)) / denom; + + // then the points of closest approach are: + pca1 = a1 + c * b1; + pca2 = a2 + d * b2; + + return; +} + +/* void KshortReconstruction::findPcaTwoTracks(const Acts::Vector3& pos1, const Acts::Vector3& pos2, Acts::Vector3 mom1, Acts::Vector3 mom2, Acts::Vector3& pca1, Acts::Vector3& pca2, double& dca) const { TLorentzVector v1; @@ -593,6 +801,7 @@ void KshortReconstruction::findPcaTwoTracks(const Acts::Vector3& pos1, const Act return; } +*/ KshortReconstruction::KshortReconstruction(const std::string& name) : SubsysReco(name) @@ -603,7 +812,7 @@ Acts::Vector3 KshortReconstruction::calculateDca(SvtxTrack* track, const Acts::V { // For the purposes of this module, we set default values to prevent this track from being rejected if the dca calc fails Acts::Vector3 r = momentum.cross(Acts::Vector3(0., 0., 1.)); - float phi = atan2(r(1), r(0)); + float phi = std::atan2(r(1), r(0)); Acts::Vector3 outVals(track_dca_cut*1.1, track_dca_cut*1.1, phi); auto vtxid = track->get_vertex_id(); if (!m_vertexMap) @@ -638,7 +847,7 @@ Acts::Vector3 KshortReconstruction::calculateDca(SvtxTrack* track, const Acts::V outVals(0) = abs(dca3dxy); outVals(1) = abs(dca3dz); outVals(2) = phi; - + if (Verbosity() > 4) { std::cout << " pre-position: " << position << std::endl; @@ -653,7 +862,8 @@ int KshortReconstruction::InitRun(PHCompositeNode* topNode) { const char* cfilepath = filepath.c_str(); fout = new TFile(cfilepath, "recreate"); - ntp_reco_info = new TNtuple("ntp_reco_info", "decay_pairs", "id1:crossing1:x1:y1:z1:px1:py1:pz1:dca3dxy1:dca3dz1:phi1:pca_rel1_x:pca_rel1_y:pca_rel1_z:eta1:charge1:tpcClusters_1:id2:crossing2:x2:y2:z2:px2:py2:pz2:dca3dxy2:dca3dz2:phi2:pca_rel2_x:pca_rel2_y:pca_rel2_z:eta2:charge2:tpcClusters_2:vertex_x:vertex_y:vertex_z:pair_dca:invariant_mass:invariant_pt:invariantPhi:pathlength_x:pathlength_y:pathlength_z:pathlength:rapidity:pseudorapidity:projected_pos1_x:projected_pos1_y:projected_pos1_z:projected_pos2_x:projected_pos2_y:projected_pos2_z:projected_mom1_x:projected_mom1_y:projected_mom1_z:projected_mom2_x:projected_mom2_y:projected_mom2_z:projected_pca_rel1_x:projected_pca_rel1_y:projected_pca_rel1_z:projected_pca_rel2_x:projected_pca_rel2_y:projected_pca_rel2_z:projected_pair_dca:projected_pathlength_x:projected_pathlength_y:projected_pathlength_z:projected_pathlength:quality1:quality2:cosThetaReco:track1_silicon_clusters:track2_silicon_clusters:track1_mvtx_clusters:track1_mvtx_states:track1_intt_clusters:track1_intt_states:track2_mvtx_clusters:track2_mvtx_states:track2_intt_clusters:track2_intt_states:runNumber:eventNumber"); + +ntp_reco_info = new TNtuple("ntp_reco_info", "decay_pairs", "id1:mass1:crossing1:x1:y1:z1:px1:py1:pz1:dca3dxy1:dca3dz1:phi1:pca_rel1_x:pca_rel1_y:pca_rel1_z:eta1:charge1:tpcClusters_1:id2:mass2:crossing2:x2:y2:z2:px2:py2:pz2:dca3dxy2:dca3dz2:phi2:pca_rel2_x:pca_rel2_y:pca_rel2_z:eta2:charge2:tpcClusters_2:ntracks_vertex:vertex_x:vertex_y:vertex_z:pair_dca:invariant_mass:invariant_pt:invariantPhi:pathlength_x:pathlength_y:pathlength_z:pathlength:rapidity:pseudorapidity:projected_pos1_x:projected_pos1_y:projected_pos1_z:projected_pos2_x:projected_pos2_y:projected_pos2_z:projected_mom1_x:projected_mom1_y:projected_mom1_z:projected_mom2_x:projected_mom2_y:projected_mom2_z:projected_pca_rel1_x:projected_pca_rel1_y:projected_pca_rel1_z:projected_pca_rel2_x:projected_pca_rel2_y:projected_pca_rel2_z:projected_pair_dca:projected_pathlength_x:projected_pathlength_y:projected_pathlength_z:projected_pathlength:quality1:quality2:cosThetaReco:track1_silicon_clusters:track2_silicon_clusters:track1_mvtx_clusters:track1_mvtx_states:track1_intt_clusters:track1_intt_states:track2_mvtx_clusters:track2_mvtx_states:track2_intt_clusters:track2_intt_states:runNumber:eventNumber"); getNodes(topNode); @@ -716,3 +926,55 @@ int KshortReconstruction::getNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } + +int KshortReconstruction::getMotherPDG() +{ + TParticlePDG* particle = TDatabasePDG::Instance()->GetParticle(m_mother_name.c_str()); + if (!particle) + { + if (Verbosity() > 2) + { + std::cout << "Error: Unknown particle name '" << m_mother_name << "'" << std::endl; + } + return -1; // or throw exception + } + return particle->PdgCode(); +} + +PHG4Particle *KshortReconstruction::getTruthTrack(SvtxTrack *thisTrack, PHCompositeNode *topNode) +{ + /* + * There are two methods for getting the truth rack from the reco track + * 1. (recommended) Use the reco -> truth tables (requires SvtxPHG4ParticleMap). Introduced Summer of 2022 + * 2. Get truth track via nClusters. Older method and will work with older DSTs + */ + + PHG4Particle *particle = nullptr; + + SvtxPHG4ParticleMap *dst_reco_truth_map = findNode::getClass(topNode, "SvtxPHG4ParticleMap"); + if (dst_reco_truth_map && dst_reco_truth_map->processed()) + { + std::map> truth_set = dst_reco_truth_map->get(thisTrack->get_id()); + if (!truth_set.empty()) + { + std::pair> best_weight = *truth_set.rbegin(); + int best_truth_id = *best_weight.second.rbegin(); + particle = m_truthinfo->GetParticle(best_truth_id); + } + } + else + { + if (!m_svtx_evalstack) + { + m_svtx_evalstack = new SvtxEvalStack(topNode); + trackeval = m_svtx_evalstack->get_track_eval(); + //trutheval = m_svtx_evalstack->get_truth_eval(); + //vertexeval = m_svtx_evalstack->get_vertex_eval(); + } + + m_svtx_evalstack->next_event(topNode); + + particle = trackeval->max_truth_particle_by_nclusters(thisTrack); + } + return particle; +} diff --git a/offline/packages/TrackingDiagnostics/KshortReconstruction.h b/offline/packages/TrackingDiagnostics/KshortReconstruction.h index 3ff1ae3501..27d6e3f601 100644 --- a/offline/packages/TrackingDiagnostics/KshortReconstruction.h +++ b/offline/packages/TrackingDiagnostics/KshortReconstruction.h @@ -5,6 +5,11 @@ #include +#include +#include +#include +#include + #include class TFile; @@ -33,14 +38,25 @@ class KshortReconstruction : public SubsysReco void setPairDCACut(double cut) { pair_dca_cut = cut; } void setTrackDCACut(double cut) { track_dca_cut = cut; } void setRequireMVTX(bool set) { _require_mvtx = set; } - void setDecayMass(float decayMassSet) { decaymass = decayMassSet; } //(muons decaymass = 0.1057) (pions = 0.13957) (electron = 0.000511) + void setDecayMass1(float decayMassSet) { decaymass1 = decayMassSet; } //(muons decaymass = 0.1057) (pions = 0.13957) (electron = 0.000511) + void setDecayMass2(float decayMassSet) { decaymass2 = decayMassSet; } //(muons decaymass = 0.1057) (pions = 0.13957) (electron = 0.000511) + // void setDecayMass(float decayMassSet) { decaymass = decayMassSet; } //(muons decaymass = 0.1057) (pions = 0.13957) (electron = 0.000511) void set_output_file(const std::string& outputfile) { filepath = outputfile; } void save_tracks(bool save = true) { m_save_tracks = save; } + //Truth matching code + void truthMatch(bool match = true) { m_truth_match = match; } + void setMotherID(const std::string &id = "K_S0") { m_mother_name = id; m_used_string = true; } + void setMotherID(int id = 310) { m_mother_id = id; m_used_string = false; } + private: - void fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj,unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber); + void fillNtp(SvtxTrack* track1, SvtxTrack* track2, float mass1, float mass2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj,unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber); - void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity); + // void fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float invariantPhi, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj,unsigned int track1_silicon_cluster_size, unsigned int track2_silicon_cluster_size, unsigned int track1_mvtx_cluster_size, unsigned int track1_mvtx_state_size, unsigned int track1_intt_cluster_size, unsigned int track1_intt_state_size, unsigned int track2_mvtx_cluster_size, unsigned int track2_mvtx_state_size, unsigned int track2_intt_cluster_size, unsigned int track2_intt_state_size, int runNumber, int eventNumber); + + void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity, float& decaymassa, float& decaymassb); + + // void fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1* massreco, double& invariantMass, double& invariantPt, float& invariantPhi, float& rapidity, float& pseudorapidity); // void findPcaTwoTracks(SvtxTrack *track1, SvtxTrack *track2, Acts::Vector3& pca1, Acts::Vector3& pca2, double& dca); void findPcaTwoTracks(const Acts::Vector3& pos1, const Acts::Vector3& pos2, Acts::Vector3 mom1, Acts::Vector3 mom2, Acts::Vector3& pca1, Acts::Vector3& pca2, double& dca) const; @@ -61,7 +77,10 @@ class KshortReconstruction : public SubsysReco SvtxVertexMap* m_vertexMap {nullptr}; std::string filepath {""}; - float decaymass {0.13957}; // pion decay mass + float decaymass1 = 0.13957; // pion decay mass + float decaymass2 = 0.13957; // pion decay mass + + //float decaymass {0.13957}; // pion decay mass bool _require_mvtx {true}; double _qual_cut {1000.0}; double pair_dca_cut {0.05}; // kshort relative cut 500 microns @@ -74,6 +93,25 @@ class KshortReconstruction : public SubsysReco bool m_save_tracks {false}; SvtxTrackMap *m_output_trackMap {nullptr}; std::string m_output_trackMap_node_name {"KshortReconstruction_SvtxTrackMap"}; + + //Truth matching code + bool m_truth_match {false}; + bool m_used_string {false}; + std::string m_mother_name {"K_S0"}; + int m_mother_id {310}; + + PHG4Particle *truth_particle_1 {nullptr}; + PHG4Particle *truth_particle_2 {nullptr}; + int truth_mother_id_particle_1 {0}; + int truth_mother_id_particle_2 {0}; + + PHG4TruthInfoContainer *m_truthinfo {nullptr}; + SvtxEvalStack *m_svtx_evalstack {nullptr}; + SvtxTrackEval *trackeval {nullptr}; + + int getMotherPDG(); + PHG4Particle *getTruthTrack(SvtxTrack *thisTrack, PHCompositeNode *topNode); + }; #endif // KSHORTRECONSTRUCTION_H diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.cc b/offline/packages/TrackingDiagnostics/TrackResiduals.cc index 894dfb4d3c..bd12b6b877 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.cc +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.cc @@ -46,6 +46,8 @@ #include #include +#include + #include #include #include @@ -57,6 +59,7 @@ #include #include #include +#include #include @@ -115,7 +118,9 @@ int TrackResiduals::InitRun(PHCompositeNode* topNode) m_globalPositionWrapper.set_suppressCrossing(m_convertSeeds); // clusterMover needs the correct radii of the TPC layers auto *tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); - m_clusterMover.initialize_geometry(tpccellgeo); + + auto *geometry = findNode::getClass(topNode, "ActsGeometry"); + m_clusterMover.initialize_geometry(tpccellgeo, geometry); m_clusterMover.set_verbosity(0); auto *se = Fun4AllServer::instance(); @@ -126,6 +131,7 @@ int TrackResiduals::InitRun(PHCompositeNode* topNode) void TrackResiduals::clearClusterStateVectors() { m_cluskeys.clear(); + m_clussize.clear(); m_clusphisize.clear(); m_cluszsize.clear(); m_idealsurfcenterx.clear(); @@ -183,7 +189,23 @@ void TrackResiduals::clearClusterStateVectors() m_statelzlocderivqop.clear(); m_clusedge.clear(); + m_clussledge.clear(); + m_clussredge.clear(); + m_clustledge.clear(); + m_clustredge.clear(); + m_clusdledge.clear(); + m_clusdredge.clear(); + m_clushledge.clear(); + m_clushredge.clear(); + m_clusslmix.clear(); + m_clussrmix.clear(); + m_clustlmix.clear(); + m_clustrmix.clear(); m_clusoverlap.clear(); + m_clusPadCen.clear(); + m_clusTBinCen.clear(); + m_clusPadMax.clear(); + m_clusTBinMax.clear(); m_cluslx.clear(); m_cluslz.clear(); m_cluselx.clear(); @@ -197,7 +219,14 @@ void TrackResiduals::clearClusterStateVectors() m_clusgzunmoved.clear(); m_clusAdc.clear(); m_clusMaxAdc.clear(); + m_clusCenAdc.clear(); m_cluslayer.clear(); + m_clusphibinlo.clear(); + m_clusphibinhi.clear(); + m_clustbinlo.clear(); + m_clustbinhi.clear(); + m_cluspadphase.clear(); + m_clustbinphase.clear(); m_statelx.clear(); m_statelz.clear(); @@ -301,6 +330,21 @@ int TrackResiduals::process_event(PHCompositeNode* topNode) } } + EventHeader* eventheader = findNode::getClass(topNode, "EventHeader"); + + if(eventheader) + { + m_evt_id = eventheader->get_EvtSequence(); + } + else + { + m_evt_id = -1; + } + + auto *rcs = recoConsts::instance(); + m_runnumber = rcs->get_IntFlag("RUNNUMBER"); + m_segment = rcs->get_IntFlag("RUNSEGMENT"); + m_ntpcclus = 0; if (Verbosity() > 1) { @@ -662,11 +706,37 @@ void TrackResiduals::fillClusterTree(TrkrClusterContainer* clusters, m_scluseta = acos(glob.z() / std::sqrt(square(glob.x()) + square(glob.y()) + square(glob.z()))); m_adc = cluster->getAdc(); m_clusmaxadc = cluster->getMaxAdc(); + m_cluscenadc = cluster->getCenAdc(); + m_padcen = cluster->getPadCen(); + m_tbincen = cluster->getTBinCen(); + m_padmax = cluster->getPadMax(); + m_tbinmax = cluster->getTBinMax(); m_scluslx = cluster->getLocalX(); m_scluslz = cluster->getLocalY(); + m_phibinlo = cluster->getPhiBinLo(); + m_phibinhi = cluster->getPhiBinHi(); + m_tbinlo = cluster->getTBinLo(); + m_tbinhi = cluster->getTBinHi(); + m_padphase = cluster->getPadPhase(); + m_tbinphase = cluster->getTBinPhase(); auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, m_sclusgr, key); + m_size = cluster->getRSize(); m_phisize = cluster->getPhiSize(); m_zsize = cluster->getZSize(); + m_overlap = cluster->getOverlap(); + m_nedge = cluster->getEdge(); + m_sledge = cluster->getSLEdge(); + m_sredge = cluster->getSREdge(); + m_tledge = cluster->getTLEdge(); + m_tredge = cluster->getTREdge(); + m_dledge = cluster->getDLEdge(); + m_dredge = cluster->getDREdge(); + m_hledge = cluster->getHLEdge(); + m_hredge = cluster->getHREdge(); + m_slmix = cluster->getSLMix(); + m_srmix = cluster->getSRMix(); + m_tlmix = cluster->getTLMix(); + m_trmix = cluster->getTRMix(); m_scluselx = std::sqrt(para_errors.first); m_scluselz = std::sqrt(para_errors.second); @@ -1087,7 +1157,19 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr //! have cluster and state, fill vectors m_clusedge.push_back(cluster->getEdge()); + m_clussledge.push_back(cluster->getSLEdge()); + m_clussredge.push_back(cluster->getSREdge()); + m_clustledge.push_back(cluster->getTLEdge()); + m_clustredge.push_back(cluster->getTREdge()); + m_clusdledge.push_back(cluster->getDLEdge()); + m_clusdredge.push_back(cluster->getDREdge()); + m_clushledge.push_back(cluster->getHLEdge()); + m_clushredge.push_back(cluster->getHREdge()); m_clusoverlap.push_back(cluster->getOverlap()); + m_clusslmix.push_back(cluster->getSLMix()); + m_clussrmix.push_back(cluster->getSRMix()); + m_clustlmix.push_back(cluster->getTLMix()); + m_clustrmix.push_back(cluster->getTRMix()); // get new local coords from moved cluster Surface surf = geometry->maps().getSurface(ckey, cluster); @@ -1128,7 +1210,7 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr { // otherwise take the manual calculation for the TPC // doing it this way just avoids the bounds check that occurs in the surface class method - Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * clusglob_moved; // global is in mm + Acts::Vector3 loct = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse() * clusglob_moved; // global is in mm loct /= Acts::UnitConstants::cm; loc(0) = loct(0); @@ -1160,13 +1242,25 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr m_clusgzunmoved.push_back(clusglob.z()); m_clusAdc.push_back(cluster->getAdc()); m_clusMaxAdc.push_back(cluster->getMaxAdc()); + m_clusCenAdc.push_back(cluster->getCenAdc()); + m_clusPadCen.push_back(cluster->getPadCen()); + m_clusTBinCen.push_back(cluster->getTBinCen()); + m_clusPadMax.push_back(cluster->getPadMax()); + m_clusTBinMax.push_back(cluster->getTBinMax()); m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); + m_clussize.push_back(cluster->getRSize()); m_clusphisize.push_back(cluster->getPhiSize()); m_cluszsize.push_back(cluster->getZSize()); + m_clusphibinlo.push_back(cluster->getPhiBinLo()); + m_clusphibinhi.push_back(cluster->getPhiBinHi()); + m_clustbinlo.push_back(cluster->getTBinLo()); + m_clustbinhi.push_back(cluster->getTBinHi()); + m_cluspadphase.push_back(cluster->getPadPhase()); + m_clustbinphase.push_back(cluster->getTBinPhase()); auto misaligncenter = surf->center(geometry->geometry().getGeoContext()); auto misalignnorm = -1 * surf->normal(geometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); - auto misrot = surf->transform(geometry->geometry().getGeoContext()).rotation(); + auto misrot = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).rotation(); float mgamma = atan2(-misrot(1, 0), misrot(0, 0)); float mbeta = -asin(misrot(0, 1)); @@ -1183,11 +1277,11 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr std::cout << "resids: layer " << layer << " ideal center z " << idealcenter.z() << " mm " << std::endl; std::cout << " surface bounds " << surfbounds[0] << " " << surfbounds[1] << " mm " << std::endl; alignmentTransformationContainer::use_alignment = false; - Acts::Transform3 transform = surf_ideal->transform(geometry->geometry().getGeoContext()); + Acts::Transform3 transform = surf_ideal->localToGlobalTransform(geometry->geometry().getGeoContext()); std::cout << "Ideal transform is:" << std::endl; std::cout << transform.matrix() << std::endl; alignmentTransformationContainer::use_alignment = true; - Acts::Transform3 transform1 = surf_ideal->transform(geometry->geometry().getGeoContext()); + Acts::Transform3 transform1 = surf_ideal->localToGlobalTransform(geometry->geometry().getGeoContext()); std::cout << "Alignment transform is:" << std::endl; std::cout << transform1.matrix() << std::endl; @@ -1199,8 +1293,8 @@ void TrackResiduals::fillClusterBranchesKF(TrkrDefs::cluskey ckey, SvtxTrack* tr // Acts::Vector3 ideal_local(loc.x(), loc.y(), 0.0); auto nominal_loc = geometry->getLocalCoords(ckey, cluster); Acts::Vector3 ideal_local(nominal_loc.x(), nominal_loc.y(), 0.0); - Acts::Vector3 ideal_glob = surf_ideal->transform(geometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); - auto idealrot = surf_ideal->transform(geometry->geometry().getGeoContext()).rotation(); + Acts::Vector3 ideal_glob = surf_ideal->localToGlobalTransform(geometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); + auto idealrot = surf_ideal->localToGlobalTransform(geometry->geometry().getGeoContext()).rotation(); //! These calculations are taken from the wikipedia page for Euler angles, //! under the Tait-Bryan angle explanation. Formulas for the angles @@ -1416,6 +1510,18 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr //! have cluster and state, fill vectors m_clusedge.push_back(cluster->getEdge()); + m_clussledge.push_back(cluster->getSLEdge()); + m_clussredge.push_back(cluster->getSREdge()); + m_clustledge.push_back(cluster->getTLEdge()); + m_clustredge.push_back(cluster->getTREdge()); + m_clusdledge.push_back(cluster->getDLEdge()); + m_clusdredge.push_back(cluster->getDREdge()); + m_clushledge.push_back(cluster->getHLEdge()); + m_clushredge.push_back(cluster->getHREdge()); + m_clusslmix.push_back(cluster->getSLMix()); + m_clussrmix.push_back(cluster->getSRMix()); + m_clustlmix.push_back(cluster->getTLMix()); + m_clustrmix.push_back(cluster->getTRMix()); m_clusoverlap.push_back(cluster->getOverlap()); // This is the nominal position of the cluster in local coords, completely uncorrected - is that what we want? @@ -1438,9 +1544,21 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr m_clusgzunmoved.push_back(clusglob.z()); m_clusAdc.push_back(cluster->getAdc()); m_clusMaxAdc.push_back(cluster->getMaxAdc()); + m_clusCenAdc.push_back(cluster->getCenAdc()); + m_clusPadCen.push_back(cluster->getPadCen()); + m_clusTBinCen.push_back(cluster->getTBinCen()); + m_clusPadMax.push_back(cluster->getPadMax()); + m_clusTBinMax.push_back(cluster->getTBinMax()); m_cluslayer.push_back(TrkrDefs::getLayer(ckey)); + m_clussize.push_back(cluster->getRSize()); m_clusphisize.push_back(cluster->getPhiSize()); m_cluszsize.push_back(cluster->getZSize()); + m_clusphibinlo.push_back(cluster->getPhiBinLo()); + m_clusphibinhi.push_back(cluster->getPhiBinHi()); + m_clustbinlo.push_back(cluster->getTBinLo()); + m_clustbinhi.push_back(cluster->getTBinHi()); + m_cluspadphase.push_back(cluster->getPadPhase()); + m_clustbinphase.push_back(cluster->getTBinPhase()); if (Verbosity() > 1) { @@ -1453,7 +1571,7 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr auto misaligncenter = surf->center(geometry->geometry().getGeoContext()); auto misalignnorm = -1 * surf->normal(geometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); - auto misrot = surf->transform(geometry->geometry().getGeoContext()).rotation(); + auto misrot = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).rotation(); float mgamma = atan2(-misrot(1, 0), misrot(0, 0)); float mbeta = -asin(misrot(0, 1)); @@ -1464,8 +1582,8 @@ void TrackResiduals::fillClusterBranchesSeeds(TrkrDefs::cluskey ckey, // SvtxTr auto idealcenter = surf->center(geometry->geometry().getGeoContext()); auto idealnorm = -1 * surf->normal(geometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); Acts::Vector3 ideal_local(loc.x(), loc.y(), 0.0); - Acts::Vector3 ideal_glob = surf->transform(geometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); - auto idealrot = surf->transform(geometry->geometry().getGeoContext()).rotation(); + Acts::Vector3 ideal_glob = surf->localToGlobalTransform(geometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm); + auto idealrot = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).rotation(); //! These calculations are taken from the wikipedia page for Euler angles, //! under the Tait-Bryan angle explanation. Formulas for the angles @@ -1552,7 +1670,7 @@ void TrackResiduals::fillStatesWithCircleFit(const TrkrDefs::cluskey& key, } else { - auto local = (surf->transform(geometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); + auto local = (surf->localToGlobalTransform(geometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); local /= Acts::UnitConstants::cm; m_statelx.push_back(local.x()); m_statelz.push_back(local.y()); @@ -1579,7 +1697,7 @@ void TrackResiduals::fillStatesWithLineFit(const TrkrDefs::cluskey& key, } else { - Acts::Vector3 loct = surf->transform(geometry->geometry().getGeoContext()).inverse() * (intersection * Acts::UnitConstants::cm); + Acts::Vector3 loct = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse() * (intersection * Acts::UnitConstants::cm); loct /= Acts::UnitConstants::cm; m_statelx.push_back(loct(0)); m_statelz.push_back(loct(1)); @@ -1607,6 +1725,7 @@ void TrackResiduals::createBranches() m_eventtree->Branch("run", &m_runnumber, "m_runnumber/I"); m_eventtree->Branch("segment", &m_segment, "m_segment/I"); m_eventtree->Branch("event", &m_event, "m_event/I"); + m_eventtree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_eventtree->Branch("gl1bco", &m_bco, "m_bco/I"); m_eventtree->Branch("nmvtx", &m_nmvtx_all, "m_nmvtx_all/I"); m_eventtree->Branch("nintt", &m_nintt_all, "m_nintt_all/I"); @@ -1627,6 +1746,7 @@ void TrackResiduals::createBranches() m_failedfits->Branch("segment", &m_segment, "m_segment/I"); m_failedfits->Branch("trackid", &m_trackid, "m_trackid/I"); m_failedfits->Branch("event", &m_event, "m_event/I"); + m_failedfits->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_failedfits->Branch("silseedx", &m_silseedx, "m_silseedx/F"); m_failedfits->Branch("silseedy", &m_silseedy, "m_silseedy/F"); m_failedfits->Branch("silseedz", &m_silseedz, "m_silseedz/F"); @@ -1653,6 +1773,7 @@ void TrackResiduals::createBranches() m_vertextree->Branch("run", &m_runnumber, "m_runnumber/I"); m_vertextree->Branch("segment", &m_segment, "m_segment/I"); m_vertextree->Branch("event", &m_event, "m_event/I"); + m_vertextree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_vertextree->Branch("firedTriggers", &m_firedTriggers); m_vertextree->Branch("gl1BunchCrossing", &m_gl1BunchCrossing, "m_gl1BunchCrossing/l"); m_vertextree->Branch("gl1bco", &m_bco, "m_bco/l"); @@ -1675,6 +1796,7 @@ void TrackResiduals::createBranches() m_hittree->Branch("run", &m_runnumber, "m_runnumber/I"); m_hittree->Branch("segment", &m_segment, "m_segment/I"); m_hittree->Branch("event", &m_event, "m_event/I"); + m_hittree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_hittree->Branch("gl1bco", &m_bco, "m_bco/l"); m_hittree->Branch("hitsetkey", &m_hitsetkey, "m_hitsetkey/i"); m_hittree->Branch("gx", &m_hitgx, "m_hitgx/F"); @@ -1704,6 +1826,7 @@ void TrackResiduals::createBranches() m_clustree->Branch("run", &m_runnumber, "m_runnumber/I"); m_clustree->Branch("segment", &m_segment, "m_segment/I"); m_clustree->Branch("event", &m_event, "m_event/I"); + m_clustree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_clustree->Branch("gl1bco", &m_bco, "m_bco/l"); m_clustree->Branch("lx", &m_scluslx, "m_scluslx/F"); m_clustree->Branch("lz", &m_scluslz, "m_scluslz/F"); @@ -1713,11 +1836,37 @@ void TrackResiduals::createBranches() m_clustree->Branch("phi", &m_sclusphi, "m_sclusphi/F"); m_clustree->Branch("eta", &m_scluseta, "m_scluseta/F"); m_clustree->Branch("adc", &m_adc, "m_adc/F"); + m_clustree->Branch("size", &m_size, "m_size/I"); m_clustree->Branch("phisize", &m_phisize, "m_phisize/I"); m_clustree->Branch("zsize", &m_zsize, "m_zsize/I"); + m_clustree->Branch("phibinlo", &m_phibinlo, "m_phibinlo/F"); + m_clustree->Branch("phibinhi", &m_phibinhi, "m_phibinhi/F"); + m_clustree->Branch("tbinlo", &m_tbinlo, "m_tbinlo/F"); + m_clustree->Branch("tbinhi", &m_tbinhi, "m_tbinhi/F"); + m_clustree->Branch("padphase", &m_padphase, "m_padphase/F"); + m_clustree->Branch("tbinphase", &m_tbinphase, "m_tbinphase/F"); + m_clustree->Branch("overlap", &m_overlap, "m_overlap/B"); + m_clustree->Branch("nedge", &m_nedge, "m_nedge/B"); + m_clustree->Branch("sledge", &m_sledge, "m_sledge/B"); + m_clustree->Branch("sredge", &m_sredge, "m_sredge/B"); + m_clustree->Branch("tledge", &m_tledge, "m_tledge/B"); + m_clustree->Branch("tredge", &m_tredge, "m_tredge/B"); + m_clustree->Branch("dledge", &m_dledge, "m_dledge/B"); + m_clustree->Branch("dredge", &m_dredge, "m_dredge/B"); + m_clustree->Branch("hledge", &m_hledge, "m_hledge/B"); + m_clustree->Branch("hredge", &m_hredge, "m_hredge/B"); + m_clustree->Branch("slmix", &m_slmix, "m_slmix/B"); + m_clustree->Branch("srmix", &m_srmix, "m_srmix/B"); + m_clustree->Branch("tlmix", &m_tlmix, "m_tlmix/B"); + m_clustree->Branch("trmix", &m_trmix, "m_trmix/B"); m_clustree->Branch("erphi", &m_scluselx, "m_scluselx/F"); m_clustree->Branch("ez", &m_scluselz, "m_scluselz/F"); m_clustree->Branch("maxadc", &m_clusmaxadc, "m_clusmaxadc/F"); + m_clustree->Branch("cenadc", &m_cluscenadc, "m_cluscenadc/F"); + m_clustree->Branch("padcen", &m_padcen, "m_padcen/F"); + m_clustree->Branch("tbincen", &m_tbincen, "m_tbincen/F"); + m_clustree->Branch("padmax", &m_padmax, "m_padmax/F"); + m_clustree->Branch("tbinmax", &m_tbinmax, "m_tbinmax/F"); m_clustree->Branch("sector", &m_clussector, "m_clussector/I"); m_clustree->Branch("side", &m_side, "m_side/I"); m_clustree->Branch("stave", &m_staveid, "m_staveid/I"); @@ -1728,11 +1877,13 @@ void TrackResiduals::createBranches() m_clustree->Branch("timebucket", &m_timebucket, "m_timebucket/I"); m_clustree->Branch("segtype", &m_segtype, "m_segtype/I"); m_clustree->Branch("tile", &m_tileid, "m_tileid/I"); + m_clustree->Branch("layer", &m_scluslayer, "m_scluslayer/I"); m_tree = new TTree("residualtree", "A tree with track, cluster, and state info"); m_tree->Branch("run", &m_runnumber, "m_runnumber/I"); m_tree->Branch("segment", &m_segment, "m_segment/I"); m_tree->Branch("event", &m_event, "m_event/I"); + m_tree->Branch("evt_id", &m_evt_id, "m_evt_id/I"); m_tree->Branch("mbdcharge",&m_totalmbd, "m_totalmbd/F"); m_tree->Branch("mbdzvtx", &m_mbdvtxz, "m_mbdvtxz/F"); m_tree->Branch("firedTriggers", &m_firedTriggers); @@ -1814,7 +1965,27 @@ void TrackResiduals::createBranches() m_tree->Branch("clusside", &m_clside); m_tree->Branch("cluskeys", &m_cluskeys); m_tree->Branch("clusedge", &m_clusedge); + m_tree->Branch("clussledge", &m_clussledge); + m_tree->Branch("clussredge", &m_clussredge); + m_tree->Branch("clustledge", &m_clustledge); + m_tree->Branch("clustredge", &m_clustredge); + m_tree->Branch("clusdledge", &m_clusdledge); + m_tree->Branch("clusdredge", &m_clusdredge); + m_tree->Branch("clushledge", &m_clushledge); + m_tree->Branch("clushredge", &m_clushredge); + m_tree->Branch("clusslmix", &m_clusslmix); + m_tree->Branch("clussrmix", &m_clussrmix); + m_tree->Branch("clustlmix", &m_clustlmix); + m_tree->Branch("clustrmix", &m_clustrmix); m_tree->Branch("clusoverlap", &m_clusoverlap); + m_tree->Branch("clusphibinlo", &m_clusphibinlo); + m_tree->Branch("clusphibinhi", &m_clusphibinhi); + m_tree->Branch("clustbinlo", &m_clustbinlo); + m_tree->Branch("clustbinhi", &m_clustbinhi); + m_tree->Branch("clusPadCen", &m_clusPadCen); + m_tree->Branch("clusTBinCen", &m_clusTBinCen); + m_tree->Branch("clusPadMax", &m_clusPadMax); + m_tree->Branch("clusTBinMax", &m_clusTBinMax); m_tree->Branch("cluslx", &m_cluslx); m_tree->Branch("cluslz", &m_cluslz); m_tree->Branch("cluselx", &m_cluselx); @@ -1823,6 +1994,8 @@ void TrackResiduals::createBranches() m_tree->Branch("clusgy", &m_clusgy); m_tree->Branch("clusgz", &m_clusgz); m_tree->Branch("clusgr", &m_clusgr); + m_tree->Branch("cluspadphase", &m_cluspadphase); + m_tree->Branch("clustbinphase", &m_clustbinphase); if (m_doAlignment) { m_tree->Branch("clusgxunmoved", &m_clusgxunmoved); @@ -1831,6 +2004,8 @@ void TrackResiduals::createBranches() } m_tree->Branch("clusAdc", &m_clusAdc); m_tree->Branch("clusMaxAdc", &m_clusMaxAdc); + m_tree->Branch("clusCenAdc", &m_clusCenAdc); + m_tree->Branch("clussize", &m_clussize); m_tree->Branch("clusphisize", &m_clusphisize); m_tree->Branch("cluszsize", &m_cluszsize); @@ -2234,6 +2409,7 @@ void TrackResiduals::fillEventTree(PHCompositeNode* topNode) if (Verbosity() > 1) { std::cout << " m_event:" << m_event << std::endl; + std::cout << " m_evt_id:" << m_evt_id << std::endl; std::cout << " m_ntpc_clus0:" << m_ntpc_clus0 << std::endl; std::cout << " m_ntpc_clus1: " << m_ntpc_clus1 << std::endl; std::cout << " m_nmvtx_all:" << m_nmvtx_all << std::endl; diff --git a/offline/packages/TrackingDiagnostics/TrackResiduals.h b/offline/packages/TrackingDiagnostics/TrackResiduals.h index 7e789faba5..2fb8b6f648 100644 --- a/offline/packages/TrackingDiagnostics/TrackResiduals.h +++ b/offline/packages/TrackingDiagnostics/TrackResiduals.h @@ -128,6 +128,7 @@ class TrackResiduals : public SubsysReco bool m_doMicromegasOnly = false; int m_event = 0; + int m_evt_id = -1; int m_segment = std::numeric_limits::quiet_NaN(); int m_runnumber = std::numeric_limits::quiet_NaN(); int m_ntpcclus = std::numeric_limits::quiet_NaN(); @@ -246,8 +247,34 @@ class TrackResiduals : public SubsysReco float m_scluseta = std::numeric_limits::quiet_NaN(); float m_adc = std::numeric_limits::quiet_NaN(); float m_clusmaxadc = std::numeric_limits::quiet_NaN(); + float m_cluscenadc = std::numeric_limits::quiet_NaN(); + int m_size = std::numeric_limits::quiet_NaN(); int m_phisize = std::numeric_limits::quiet_NaN(); int m_zsize = std::numeric_limits::quiet_NaN(); + char m_overlap = std::numeric_limits::max(); + char m_nedge = std::numeric_limits::max(); + char m_sledge = std::numeric_limits::max(); + char m_sredge = std::numeric_limits::max(); + char m_tledge = std::numeric_limits::max(); + char m_tredge = std::numeric_limits::max(); + char m_dledge = std::numeric_limits::max(); + char m_dredge = std::numeric_limits::max(); + char m_hledge = std::numeric_limits::max(); + char m_hredge = std::numeric_limits::max(); + char m_slmix = std::numeric_limits::max(); + char m_srmix = std::numeric_limits::max(); + char m_tlmix = std::numeric_limits::max(); + char m_trmix = std::numeric_limits::max(); + float m_phibinlo = std::numeric_limits::quiet_NaN(); + float m_phibinhi = std::numeric_limits::quiet_NaN(); + float m_tbinlo = std::numeric_limits::quiet_NaN(); + float m_tbinhi = std::numeric_limits::quiet_NaN(); + float m_padphase = std::numeric_limits::quiet_NaN(); + float m_tbinphase = std::numeric_limits::quiet_NaN(); + float m_padcen = std::numeric_limits::quiet_NaN(); + float m_tbincen = std::numeric_limits::quiet_NaN(); + float m_padmax = std::numeric_limits::quiet_NaN(); + float m_tbinmax = std::numeric_limits::quiet_NaN(); float m_scluslx = std::numeric_limits::quiet_NaN(); float m_scluslz = std::numeric_limits::quiet_NaN(); float m_sclusgx = std::numeric_limits::quiet_NaN(); @@ -270,6 +297,11 @@ class TrackResiduals : public SubsysReco //! clusters on track information std::vector m_clusAdc; std::vector m_clusMaxAdc; + std::vector m_clusCenAdc; + std::vector m_clusPadCen; + std::vector m_clusTBinCen; + std::vector m_clusPadMax; + std::vector m_clusTBinMax; std::vector m_cluslx; std::vector m_cluslz; std::vector m_cluselx; @@ -288,10 +320,29 @@ class TrackResiduals : public SubsysReco std::vector m_clsector; std::vector m_clside; std::vector m_cluslayer; + std::vector m_clussize; std::vector m_clusphisize; std::vector m_cluszsize; - std::vector m_clusedge; std::vector m_clusoverlap; + std::vector m_clusedge; + std::vector m_clussledge; + std::vector m_clussredge; + std::vector m_clustledge; + std::vector m_clustredge; + std::vector m_clusdledge; + std::vector m_clusdredge; + std::vector m_clushledge; + std::vector m_clushredge; + std::vector m_clusslmix; + std::vector m_clussrmix; + std::vector m_clustlmix; + std::vector m_clustrmix; + std::vector m_clusphibinlo; + std::vector m_clusphibinhi; + std::vector m_clustbinlo; + std::vector m_clustbinhi; + std::vector m_cluspadphase; + std::vector m_clustbinphase; std::vector m_cluskeys; std::vector m_idealsurfcenterx; std::vector m_idealsurfcentery; diff --git a/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.cc b/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.cc index 02a10baea3..969e746c82 100644 --- a/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.cc +++ b/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.cc @@ -588,10 +588,11 @@ int TrackSeedTrackMapConverter::getNodes(PHCompositeNode* topNode) std::cout << PHWHERE << "WARNING, TrackSeedTrackMapConverter may seg fault depending on what seeding algorithm this is run after" << std::endl; } - m_clusters = findNode::getClass(topNode, "TRKR_CLUSTER"); + m_clusters = findNode::getClass(topNode, m_clusterMapName); if (!m_clusters) { - std::cout << PHWHERE << " Can't find cluster container, can't continue." + std::cout << PHWHERE << " Can't find cluster container " << m_clusterMapName + << ", can't continue." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } diff --git a/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.h b/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.h index 1cff3281d7..ef9c48766e 100644 --- a/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.h +++ b/offline/packages/TrackingDiagnostics/TrackSeedTrackMapConverter.h @@ -29,6 +29,7 @@ class TrackSeedTrackMapConverter : public SubsysReco void setFieldMap(const std::string &name) { m_fieldMap = name; } void setTrackMapName(const std::string &name) { m_trackMapName = name; } void setTrackSeedName(const std::string &name) { m_trackSeedName = name; } + void setClusterMapName(const std::string& name) {m_clusterMapName = name; } void cosmics() { m_cosmics = true; } void constField() { m_ConstField = true; } @@ -56,6 +57,7 @@ class TrackSeedTrackMapConverter : public SubsysReco std::string m_fieldMap; std::string m_trackMapName{"SvtxTrackMap"}; std::string m_trackSeedName{"TpcTrackSeedContainer"}; + std::string m_clusterMapName{"TRKR_CLUSTER"}; }; #endif // TRACKSEEDTRACKMAPCONVERTER_H diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc index 6ee6d35395..1c90c4688c 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.cc @@ -31,10 +31,15 @@ #include #include +#include + +#include + #include #include #include +#include #include @@ -158,6 +163,7 @@ enum n_hit // NOLINT(readability-enum-initial-value, performance-enum-size) nhitcellID, nhitecell, nhitphibin, + nhitzbin, nhittbin, nhitphi, nhitr, @@ -283,6 +289,11 @@ enum n_cluster // NOLINT(readability-enum-initial-value, performance-enum-size) nclue, ncluadc, nclumaxadc, + nclucenadc, + nclupadcen, + nclutbincen, + nclupadmax, + nclutbinmax, ncluthick, ncluafac, nclubfac, @@ -295,7 +306,25 @@ enum n_cluster // NOLINT(readability-enum-initial-value, performance-enum-size) ncluzsize, nclupedge, ncluredge, + nclusledge, + nclusredge, + nclutledge, + nclutredge, + ncludledge, + ncludredge, + ncluhledge, + ncluhredge, + ncluslmix, + nclusrmix, + nclutlmix, + nclutrmix, ncluovlp, + ncluphibinlo, + ncluphibinhi, + nclutbinlo, + nclutbinhi, + nclupadphase, + nclutbinphase, nclutrackID, ncluniter, clusize = ncluniter + 1 @@ -330,8 +359,8 @@ int TrkrNtuplizer::Init(PHCompositeNode* /*unused*/) std::string str_vertex = {"vertexID:vx:vy:vz:ntracks:chi2:ndof"}; std::string str_event = {"event:seed:run:seg:job"}; - std::string str_hit = {"hitID:e:adc:layer:phielem:zelem:cellID:ecell:phibin:tbin:phi:r:x:y:z"}; - std::string str_cluster = {"locx:locy:x:y:z:r:phi:eta:theta:phibin:tbin:fee:chan:sampa:ex:ey:ez:ephi:pez:pephi:e:adc:maxadc:thick:afac:bfac:dcal:layer:phielem:zelem:size:phisize:zsize:pedge:redge:ovlp:trackID:niter"}; + std::string str_hit = {"hitID:e:adc:layer:phielem:zelem:cellID:ecell:phibin:zbin:tbin:phi:r:x:y:z"}; + std::string str_cluster = {"locx:locy:x:y:z:r:phi:eta:theta:phibin:tbin:fee:chan:sampa:ex:ey:ez:ephi:pez:pephi:e:adc:maxadc:cenadc:padcen:tbincen:padmax:tbinmax:thick:afac:bfac:dcal:layer:phielem:zelem:size:phisize:zsize:pedge:redge:sledge:sredge:tledge:tredge:dledge:dredge:hledge:hredge:slmix:srmix:tlmix:trmix:ovlp:phibinlo:phibinhi:tbinlo:tbinhi:padphase:tbinphase:trackID:niter"}; std::string str_seed = {"seedID:siter:spt:sptot:seta:sphi:syxint:srzint:sxyslope:srzslope:sX0:sY0:sdZ0:sR0:scharge:sdedx:spidedx:skdedx:sprdedx:sn1pix:snsil:sntpc:snhits"}; std::string str_residual = {"alpha:beta:resphio:resphi:resz"}; std::string str_track = {"trackID:crossing:px:py:pz:pt:eta:phi:deltapt:deltaeta:deltaphi:charge:quality:chisq:ndf:nhits:nmaps:nintt:ntpc:nmms:ntpc1:ntpc11:ntpc2:ntpc3:dedx:pidedx:kdedx:prdedx:vertexID:vx:vy:vz:dca2d:dca2dsigma:dca3dxy:dca3dxysigma:dca3dz:dca3dzsigma:pcax:pcay:pcaz:hlxpt:hlxeta:hlxphi:hlxX0:hlxY0:hlxZ0:hlxcharge"}; @@ -560,6 +589,13 @@ int TrkrNtuplizer::InitRun(PHCompositeNode* topNode) } AdcClockPeriod = geom->GetFirstLayerCellGeom()->get_zstep(); + _inttGeom = findNode::getClass(topNode, "CYLINDERGEOM_INTT"); + if (_do_hit_eval && !_inttGeom) + { + std::cout << PHWHERE << "ERROR: Can't find node CYLINDERGEOM_INTT" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + // Create Fee Map auto* geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); { @@ -1373,7 +1409,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } //----------------------- - // fill the Vertex NTuple + // fill the Vertex NTuple and fixed NaN placeholders //----------------------- bool doit = true; if (_ntp_vertex && doit) @@ -1384,35 +1420,56 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) std::cout << "start vertex time: " << _timer->get_accumulated_time() / 1000. << " sec" << std::endl; _timer->restart(); } - float fx_vertex[n_vertex::vtxsize]; - for (float& i : fx_vertex) + + SvtxVertexMap* vertexmap = findNode::getClass(topNode, "SvtxVertexMapActs"); + + if (!vertexmap) { - i = 0; + std::cout << PHWHERE << " WARNING: SvtxVertexMapActs not found. Writing no vertex entries for this event." << std::endl; } + else + { + for (auto & iter : *vertexmap) + { + SvtxVertex* vertex = iter.second; + if (!vertex) { continue; } - // SvtxVertexMap* vertexmap = nullptr; + float fx_vertex[n_vertex::vtxsize]; + for (float& i : fx_vertex) + { + i = std::numeric_limits::quiet_NaN(); + } - // vertexmap = findNode::getClass(topNode, "SvtxVertexMapActs"); // Acts vertices + fx_vertex[vtxnvertexID] = static_cast(vertex->get_id()); + fx_vertex[vtxnvx] = vertex->get_x(); + fx_vertex[vtxnvy] = vertex->get_y(); + fx_vertex[vtxnvz] = vertex->get_z(); + fx_vertex[vtxnntracks] = static_cast(vertex->size_tracks()); + fx_vertex[vtxnchi2] = vertex->get_chisq(); + fx_vertex[vtxnndof] = vertex->get_ndof(); - float vx = std::numeric_limits::quiet_NaN(); - float vy = std::numeric_limits::quiet_NaN(); - float vz = std::numeric_limits::quiet_NaN(); - float ntracks = std::numeric_limits::quiet_NaN(); - fx_vertex[vtxnvx] = vx; - fx_vertex[vtxnvy] = vy; - fx_vertex[vtxnvz] = vz; - fx_vertex[vtxnntracks] = ntracks; - if (Verbosity() > 1) - { - std::cout << " adding vertex data " << std::endl; + if (Verbosity() > 1) + { + std::cout << " adding vertex data " + << " id = " << vertex->get_id() + << " vx = " << vertex->get_x() + << " vy = " << vertex->get_y() + << " vz = " << vertex->get_z() + << " ntracks = " << vertex->size_tracks() + << std::endl; + } + + float* vertex_data = new float[((int) (n_info::infosize)) + n_event::evsize + n_vertex::vtxsize]; + std::copy(fx_event, fx_event + n_event::evsize, vertex_data); + std::copy(fx_vertex, fx_vertex + n_vertex::vtxsize, vertex_data + n_event::evsize); + std::copy(fx_info, fx_info + ((int) (n_info::infosize)), vertex_data + n_event::evsize + n_vertex::vtxsize); + + _ntp_vertex->Fill(vertex_data); + delete[] vertex_data; + } } - float* vertex_data = new float[((int) (n_info::infosize)) + n_event::evsize + n_vertex::vtxsize]; - std::copy(fx_event, fx_event + n_event::evsize, vertex_data); - std::copy(fx_vertex, fx_vertex + n_vertex::vtxsize, vertex_data + n_event::evsize); - std::copy(fx_info, fx_info + ((int) (n_info::infosize)), vertex_data + n_event::evsize + n_vertex::vtxsize); - _ntp_vertex->Fill(vertex_data); - delete[] vertex_data; } + if (Verbosity() > 1) { _timer->stop(); @@ -1464,6 +1521,11 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) fx_hit[n_hit::nhitphielem] = -666; fx_hit[n_hit::nhitzelem] = -666; + if (layer_local < 3) + { + fx_hit[n_hit::nhitphielem] = MvtxDefs::getStaveId(hitset_key); + fx_hit[n_hit::nhitzelem] = MvtxDefs::getChipId(hitset_key); + } if (layer_local >= 3 && layer_local < 7) { fx_hit[n_hit::nhitphielem] = InttDefs::getLadderPhiId(hitset_key); @@ -1485,18 +1547,65 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } } */ - fx_hit[n_hit::nhitphielem] = TpcDefs::getSectorId(hitset_key); - fx_hit[n_hit::nhitzelem] = TpcDefs::getSide(hitset_key); + //fx_hit[n_hit::nhitphielem] = TpcDefs::getSectorId(hitset_key); + //fx_hit[n_hit::nhitzelem] = TpcDefs::getSide(hitset_key); fx_hit[n_hit::nhitcellID] = 0; fx_hit[n_hit::nhitecell] = hit->getAdc(); fx_hit[n_hit::nhitphibin] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhittbin] = std::numeric_limits::quiet_NaN(); + fx_hit[n_hit::nhitzbin] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhitphi] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhitr] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhitx] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhity] = std::numeric_limits::quiet_NaN(); fx_hit[n_hit::nhitz] = std::numeric_limits::quiet_NaN(); + if (layer_local < _nlayers_maps) + { + int row = MvtxDefs::getRow(hit_key); + int col = MvtxDefs::getCol(hit_key); + + float localX = std::numeric_limits::quiet_NaN(); + float localZ = std::numeric_limits::quiet_NaN(); + SegmentationAlpide::detectorToLocal(row,col,localX,localZ); + Acts::Vector2 local(localX * Acts::UnitConstants::cm, localZ * Acts::UnitConstants::cm); + + const auto& surface = m_tGeometry->maps().getSiliconSurface(hitset_key); + auto glob = surface->localToGlobal(m_tGeometry->geometry().getGeoContext(), local, Acts::Vector3()); + + fx_hit[n_hit::nhitphibin] = row; + fx_hit[n_hit::nhitzbin] = col; + fx_hit[n_hit::nhittbin] = MvtxDefs::getStrobeId(hitset_key); + fx_hit[n_hit::nhitx] = glob.x() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhity] = glob.y() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitz] = glob.z() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitr] = sqrt(glob.x()*glob.x()+glob.y()*glob.y()) / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitphi] = atan2(glob.y(),glob.x()); + } + + if (layer_local >= _nlayers_maps && layer_local < _nlayers_intt) + { + int row = InttDefs::getRow(hit_key); + int col = InttDefs::getCol(hit_key); + + CylinderGeomIntt* intt_cylinder = dynamic_cast(_inttGeom->GetLayerGeom(layer_local)); + double localcoords[3]; + intt_cylinder->find_strip_center_localcoords(InttDefs::getLadderZId(hitset_key),row,col,localcoords); + + Acts::Vector2 local(localcoords[1]*Acts::UnitConstants::cm,localcoords[2]*Acts::UnitConstants::cm); + const auto& surface = m_tGeometry->maps().getSiliconSurface(hitset_key); + auto glob = surface->localToGlobal(m_tGeometry->geometry().getGeoContext(), local, Acts::Vector3()); + + fx_hit[n_hit::nhitphibin] = row; + fx_hit[n_hit::nhitzbin] = col; + fx_hit[n_hit::nhittbin] = InttDefs::getTimeBucketId(hitset_key); + fx_hit[n_hit::nhitx] = glob.x() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhity] = glob.y() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitz] = glob.z() / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitr] = sqrt(glob.x()*glob.x()+glob.y()*glob.y()) / Acts::UnitConstants::cm; + fx_hit[n_hit::nhitphi] = atan2(glob.y(),glob.x()); + } + if (layer_local >= _nlayers_maps + _nlayers_intt && layer_local < _nlayers_maps + _nlayers_intt + _nlayers_tpc) { PHG4TpcGeom* GeoLayer_local = _geom_container->GetLayerCellGeom(layer_local); @@ -1618,7 +1727,7 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } TrackSeedContainer* _tpc_seeds = findNode::getClass(topNode, "TpcTrackSeedContainer"); - if (!_tpc_seeds) + if (!_tpc_seeds && _do_tpcseed_eval) { std::cout << PHWHERE << " ERROR: Can't find " << "TpcTrackSeedContainer" << std::endl; @@ -1737,9 +1846,9 @@ void TrkrNtuplizer::fillOutputNtuples(PHCompositeNode* topNode) } else { - pidedx = f_pion_minus->Eval(tptot); - kdedx = f_kaon_minus->Eval(tptot); - prdedx = f_proton_plus->Eval(tptot); + pidedx = f_pion_minus->Eval(-tptot); + kdedx = f_kaon_minus->Eval(-tptot); + prdedx = f_proton_minus->Eval(-tptot); } float n1pix = get_n1pix(tpcseed); float fx_seed[n_seed::seedsize] = {(float) trackID, 0, tpt, tptot, teta, tphi, xyint, rzint, xyslope, rzslope, tX0, tY0, tZ0, R0, charge, dedx, pidedx, kdedx, prdedx, n1pix, nsil_local, ntpc_local, nhits_local}; @@ -1933,9 +2042,9 @@ void TrkrNtuplizer::FillTrack(float fX[50], SvtxTrack* track, GlobalVertexMap* v } else { - fX[n_track::ntrknpidedx] = f_pion_minus->Eval(trptot); - fX[n_track::ntrknkdedx] = f_kaon_minus->Eval(trptot); - fX[n_track::ntrknprdedx] = f_proton_minus->Eval(trptot); + fX[n_track::ntrknpidedx] = f_pion_minus->Eval(-trptot); + fX[n_track::ntrknkdedx] = f_kaon_minus->Eval(-trptot); + fX[n_track::ntrknprdedx] = f_proton_minus->Eval(-trptot); } for (SvtxTrack::ConstClusterKeyIter iter_local = tpcseed->begin_cluster_keys(); @@ -2195,6 +2304,11 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c fXcluster[n_cluster::nclue] = cluster->getAdc(); fXcluster[n_cluster::ncluadc] = cluster->getAdc(); fXcluster[n_cluster::nclumaxadc] = cluster->getMaxAdc(); + fXcluster[n_cluster::nclucenadc] = cluster->getCenAdc(); + fXcluster[n_cluster::nclupadcen] = cluster->getPadCen(); + fXcluster[n_cluster::nclutbincen] = cluster->getTBinCen(); + fXcluster[n_cluster::nclupadmax] = cluster->getPadMax(); + fXcluster[n_cluster::nclutbinmax] = cluster->getTBinMax(); fXcluster[n_cluster::nclulayer] = layer_local; if (layer_local < 3) @@ -2222,7 +2336,7 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c } } */ - fXcluster[n_cluster::nclusize] = cluster->getSize(); + fXcluster[n_cluster::nclusize] = cluster->getRSize(); fXcluster[n_cluster::ncluphisize] = cluster->getPhiSize(); fXcluster[n_cluster::ncluzsize] = cluster->getZSize(); fXcluster[n_cluster::nclupedge] = cluster->getEdge(); @@ -2232,8 +2346,25 @@ void TrkrNtuplizer::FillCluster(float fXcluster[n_cluster::clusize], TrkrDefs::c { fXcluster[n_cluster::ncluredge] = 1; } - - fXcluster[n_cluster::ncluovlp] = 3; // cluster->getOvlp(); + fXcluster[n_cluster::nclusledge] = cluster->getSLEdge(); + fXcluster[n_cluster::nclusredge] = cluster->getSREdge(); + fXcluster[n_cluster::nclutledge] = cluster->getTLEdge(); + fXcluster[n_cluster::nclutredge] = cluster->getTREdge(); + fXcluster[n_cluster::ncludledge] = cluster->getDLEdge(); + fXcluster[n_cluster::ncludredge] = cluster->getDREdge(); + fXcluster[n_cluster::ncluhledge] = cluster->getHLEdge(); + fXcluster[n_cluster::ncluhredge] = cluster->getHREdge(); + fXcluster[n_cluster::ncluslmix] = cluster->getSLMix(); + fXcluster[n_cluster::nclusrmix] = cluster->getSRMix(); + fXcluster[n_cluster::nclutlmix] = cluster->getTLMix(); + fXcluster[n_cluster::nclutrmix] = cluster->getTRMix(); + fXcluster[n_cluster::ncluovlp] = cluster->getOverlap(); + fXcluster[n_cluster::ncluphibinlo] = cluster->getPhiBinLo(); + fXcluster[n_cluster::ncluphibinhi] = cluster->getPhiBinHi(); + fXcluster[n_cluster::nclutbinlo] = cluster->getTBinLo(); + fXcluster[n_cluster::nclutbinhi] = cluster->getTBinHi(); + fXcluster[n_cluster::nclupadphase] = cluster->getPadPhase(); + fXcluster[n_cluster::nclutbinphase] = cluster->getTBinPhase(); fXcluster[n_cluster::nclutrackID] = std::numeric_limits::quiet_NaN(); fXcluster[n_cluster::ncluniter] = 0; diff --git a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.h b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.h index 4e9df30628..ac341f1a45 100644 --- a/offline/packages/TrackingDiagnostics/TrkrNtuplizer.h +++ b/offline/packages/TrackingDiagnostics/TrkrNtuplizer.h @@ -35,6 +35,7 @@ class SvtxVertexMap; class TrkrClusterContainer; class ActsGeometry; class PHG4TpcGeomContainer; +class PHG4CylinderGeomContainer; class GlobalVertexMap; // class ClusterErrorPara; @@ -157,6 +158,7 @@ class TrkrNtuplizer : public SubsysReco SvtxTrackMap *_trackmap{nullptr}; ActsGeometry *_tgeometry{nullptr}; PHG4TpcGeomContainer *_geom_container{nullptr}; + PHG4CylinderGeomContainer *_inttGeom{nullptr}; float m_ZDC_coincidence{0}; float m_mbd_rate{0}; float m_rawzdc{0}; diff --git a/offline/packages/TruthNeutralMesonFinder/TruthNeutralMesonv1.h b/offline/packages/TruthNeutralMesonFinder/TruthNeutralMesonv1.h index 6386ebea67..2203ac6e57 100644 --- a/offline/packages/TruthNeutralMesonFinder/TruthNeutralMesonv1.h +++ b/offline/packages/TruthNeutralMesonFinder/TruthNeutralMesonv1.h @@ -1,9 +1,10 @@ #ifndef TRUTHNEUTRALMESONV1_H #define TRUTHNEUTRALMESONV1_H -#include #include "TruthNeutralMeson.h" +#include + class TruthNeutralMesonv1 : public TruthNeutralMeson { public: diff --git a/offline/packages/bcolumicount/BcoInfo.cc b/offline/packages/bcolumicount/BcoInfo.cc new file mode 100644 index 0000000000..3fc672a599 --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfo.cc @@ -0,0 +1,23 @@ +#include "BcoInfo.h" + +#include + +#include + +void BcoInfo::Reset() +{ + std::cout << PHWHERE << "ERROR Reset() not implemented by daughter class" << std::endl; + return; +} + +void BcoInfo::identify(std::ostream& os) const +{ + os << "identify yourself: virtual BcoInfo Object" << std::endl; + return; +} + +int BcoInfo::isValid() const +{ + std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; + return 0; +} diff --git a/offline/packages/bcolumicount/BcoInfo.h b/offline/packages/bcolumicount/BcoInfo.h new file mode 100644 index 0000000000..46548d48f4 --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfo.h @@ -0,0 +1,50 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLLUMICOUNT_BCOINFO_H +#define BCOLLUMICOUNT_BCOINFO_H + +#include + +#include +#include + +/// +class BcoInfo : public PHObject +{ + public: + /// ctor - daughter class copy ctor needs this + BcoInfo() = default; + /// dtor + ~BcoInfo() override = default; + /// Clear Sync + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& os = std::cout) const override; + + /// isValid returns non zero if object contains valid data + int isValid() const override; + + virtual uint64_t get_previous_bco() const { return 0; } + virtual uint64_t get_current_bco() const { return 0; } + virtual uint64_t get_future_bco() const { return 0; } + + virtual void set_previous_bco(uint64_t /*val*/) { return; } + virtual void set_current_bco(uint64_t /*val*/) { return; } + virtual void set_future_bco(uint64_t /*val*/) { return; } + + virtual int get_previous_evtno() const { return 0; } + virtual int get_current_evtno() const { return 0; } + virtual int get_future_evtno() const { return 0; } + + virtual void set_previous_evtno(int /*val*/) { return; } + virtual void set_current_evtno(int /*val*/) { return; } + virtual void set_future_evtno(int /*val*/) { return; } + + private: + ClassDefOverride(BcoInfo, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/BcoInfoLinkDef.h b/offline/packages/bcolumicount/BcoInfoLinkDef.h new file mode 100644 index 0000000000..54907ed5fe --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfoLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BcoInfo + ; + +#endif diff --git a/offline/packages/bcolumicount/BcoInfov1.cc b/offline/packages/bcolumicount/BcoInfov1.cc new file mode 100644 index 0000000000..28e206413f --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfov1.cc @@ -0,0 +1,28 @@ +#include "BcoInfov1.h" + +void BcoInfov1::Reset() +{ + bco.fill(0); + evtno.fill(0); + return; +} + +void BcoInfov1::identify(std::ostream& out) const +{ + out << "identify yourself: I am an BcoInfov1 Object\n"; + out << "previous event: " << get_previous_evtno() << std::hex + << " bco: 0x" << get_previous_bco() << "\n" + << std::dec + << "current event: " << get_current_evtno() << std::hex + << " bco: 0x" << get_current_bco() << "\n" + << std::dec + << "future event: " << get_future_evtno() << std::hex + << " bco: 0x" << get_future_bco() << std::dec + << std::endl; + return; +} + +int BcoInfov1::isValid() const +{ + return (bco[2] ? 1 : 0); // return 1 if future bco is not zero +} diff --git a/offline/packages/bcolumicount/BcoInfov1.h b/offline/packages/bcolumicount/BcoInfov1.h new file mode 100644 index 0000000000..78b2a3f348 --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfov1.h @@ -0,0 +1,54 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLUMICOUNT_BCOINFOV1_H +#define BCOLUMICOUNT_BCOINFOV1_H + +#include "BcoInfo.h" + +#include +#include + +class BcoInfov1 : public BcoInfo +{ + public: + /// ctor + BcoInfov1() = default; + + /// dtor + ~BcoInfov1() override = default; + + /// Clear Event + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& out = std::cout) const override; + + /// isValid returns non zero if object contains valid data + int isValid() const override; + + uint64_t get_previous_bco() const override { return bco[0]; } + uint64_t get_current_bco() const override { return bco[1]; } + uint64_t get_future_bco() const override { return bco[2]; } + + void set_previous_bco(uint64_t val) override { bco[0] = val; } + void set_current_bco(uint64_t val) override { bco[1] = val; } + void set_future_bco(uint64_t val) override { bco[2] = val; } + + int get_previous_evtno() const override { return evtno[0]; } + int get_current_evtno() const override { return evtno[1]; } + int get_future_evtno() const override { return evtno[2]; } + + void set_previous_evtno(int val) override { evtno[0] = val; } + void set_current_evtno(int val) override { evtno[1] = val; } + void set_future_evtno(int val) override { evtno[2] = val; } + + private: + std::array bco{0}; + std::array evtno{0}; + + ClassDefOverride(BcoInfov1, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/BcoInfov1LinkDef.h b/offline/packages/bcolumicount/BcoInfov1LinkDef.h new file mode 100644 index 0000000000..41672f57b9 --- /dev/null +++ b/offline/packages/bcolumicount/BcoInfov1LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class BcoInfov1 + ; + +#endif diff --git a/offline/packages/bcolumicount/BcoLumiReco.cc b/offline/packages/bcolumicount/BcoLumiReco.cc new file mode 100644 index 0000000000..eb5b3dd8b7 --- /dev/null +++ b/offline/packages/bcolumicount/BcoLumiReco.cc @@ -0,0 +1,153 @@ +#include "BcoLumiReco.h" + +#include "BcoInfo.h" +#include "BcoInfov1.h" + +#include +#include + +#include +#include // for SubsysReco + +#include +#include +#include // for PHNode +#include // for PHNodeIterator +#include // for PHObject +#include +#include // for PHWHERE + +#include +#include +#include // for Packet +# +#include + +BcoLumiReco::BcoLumiReco(const std::string &name) + : SubsysReco(name) +{ + return; +} + +BcoLumiReco::~BcoLumiReco() +{ + delete m_synccopy; + delete m_tmpsync; +} + +int BcoLumiReco::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + return iret; +} + +int BcoLumiReco::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); + if (!bcoinfo) + { + bcoinfo = new BcoInfov1(); + PHIODataNode *newnode = new PHIODataNode(bcoinfo, "BCOINFO", "PHObject"); + dstNode->addNode(newnode); + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int BcoLumiReco::process_event(PHCompositeNode *topNode) +{ + static bool ifirst = true; + SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); + Event *evt = findNode::getClass(topNode, "PRDF"); + if (evt) + { + if (Verbosity() > 1) + { + evt->identify(); + } + if (evt->getEvtType() != DATAEVENT) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + Packet *packet = evt->getPacket(14001); + if (!packet) + { + if (Verbosity() > 0) + { + std::cout << "no gl1 packet 14001" << std::endl; + evt->identify(); + } + return Fun4AllReturnCodes::ABORTEVENT; + } + uint64_t gtm_bco = packet->lValue(0, "BCO"); + if (Verbosity() > 1) + { + std::cout << std::hex << "packet ival: 0x" << packet->lValue(0, "BCO") + << " uint64_t: 0x" << gtm_bco << std::dec << std::endl; + } + push_bco(gtm_bco); + delete packet; + } + if (syncobject) + { + push_evtno(syncobject->EventNumber()); + } + if (ifirst) // abort first event since it does not have a previous bco + { + ifirst = false; + return Fun4AllReturnCodes::ABORTEVENT; + } + if (!m_synccopy) + { + m_synccopy = dynamic_cast(syncobject->CloneMe()); // clone for second event + m_tmpsync = dynamic_cast(m_synccopy->CloneMe()); // just to create this object + return Fun4AllReturnCodes::ABORTEVENT; // and abort + } + BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); + + if (Verbosity() > 0) + { + std::cout << "current event is: " << syncobject->EventNumber() << "\n"; + std::cout << "saving as event: " << m_synccopy->EventNumber() << "\n"; + } + // here we store the current sync object and overwrite its content with the cached copy + *m_tmpsync = *syncobject; // save current version in tmp + *syncobject = *m_synccopy; // copy previously cached version + *m_synccopy = *m_tmpsync; // cache current version + if (Verbosity() > 0) + { + std::cout << std::hex; + std::cout << "previous bco: " << get_previous_bco() << "\n"; + std::cout << "current bco: " << get_current_bco() << "\n"; + std::cout << "future bco: " << get_future_bco() << std::endl; + std::cout << std::dec; + } + bcoinfo->set_previous_bco(get_previous_bco()); + bcoinfo->set_current_bco(get_current_bco()); + bcoinfo->set_future_bco(get_future_bco()); + bcoinfo->set_previous_evtno(get_previous_evtno()); + bcoinfo->set_current_evtno(get_current_evtno()); + bcoinfo->set_future_evtno(get_future_evtno()); + return Fun4AllReturnCodes::EVENT_OK; +} + +void BcoLumiReco::push_bco(uint64_t value) +{ + m_bco[0] = m_bco[1]; + m_bco[1] = m_bco[2]; + m_bco[2] = value; +} + +void BcoLumiReco::push_evtno(int value) +{ + m_evtno[0] = m_evtno[1]; + m_evtno[1] = m_evtno[2]; + m_evtno[2] = value; +} diff --git a/offline/packages/bcolumicount/BcoLumiReco.h b/offline/packages/bcolumicount/BcoLumiReco.h new file mode 100644 index 0000000000..c0c0ab6a3a --- /dev/null +++ b/offline/packages/bcolumicount/BcoLumiReco.h @@ -0,0 +1,40 @@ +#ifndef BCOLUMICOUNT_BCOLUMIRECO_H +#define BCOLUMICOUNT_BCOLUMIRECO_H + +#include + +#include +#include +#include + +class PHCompositeNode; +class SyncObject; + +class BcoLumiReco : public SubsysReco +{ + public: + BcoLumiReco(const std::string &name = "BCOLUMIRECO"); + ~BcoLumiReco() override; + + int Init(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + + void push_bco(uint64_t value); + uint64_t get_previous_bco() { return m_bco[0]; } + uint64_t get_current_bco() const { return m_bco[1]; } + uint64_t get_future_bco() const { return m_bco[2]; } + + void push_evtno(int value); + int get_previous_evtno() { return m_evtno[0]; } + int get_current_evtno() const { return m_evtno[1]; } + int get_future_evtno() const { return m_evtno[2]; } + + private: + static int CreateNodeTree(PHCompositeNode *topNode); + SyncObject *m_synccopy{nullptr}; + SyncObject *m_tmpsync{nullptr}; + std::array m_bco{0}; + std::array m_evtno{0}; +}; + +#endif // BCOLUMICOUNT_BCOLUMIRECO_H diff --git a/offline/packages/bcolumicount/Makefile.am b/offline/packages/bcolumicount/Makefile.am new file mode 100644 index 0000000000..297fc5f840 --- /dev/null +++ b/offline/packages/bcolumicount/Makefile.am @@ -0,0 +1,101 @@ +AUTOMAKE_OPTIONS = foreign + +lib_LTLIBRARIES = \ + libbcolumicount_io.la \ + libbcolumicount.la + +AM_CPPFLAGS = \ + -I$(includedir) \ + -isystem$(OFFLINE_MAIN)/include \ + -isystem$(ROOTSYS)/include + +AM_LDFLAGS = \ + -L$(libdir) \ + -L$(OFFLINE_MAIN)/lib \ + -L$(OFFLINE_MAIN)/lib64 + +libbcolumicount_io_la_LIBADD = \ + -lphool + +libbcolumicount_la_LIBADD = \ + libbcolumicount_io.la \ + -lffaobjects \ + -lffarawobjects \ + -lSubsysReco \ + -lfun4all + +ROOTDICTS = \ + BcoInfo_Dict.cc \ + BcoInfov1_Dict.cc \ + StreamingBcoInfo_Dict.cc \ + StreamingBcoInfov1_Dict.cc \ + StreamingLumiInfo_Dict.cc \ + StreamingLumiInfov1_Dict.cc + +pcmdir = $(libdir) +# more elegant way to create pcm files (without listing them) +nobase_dist_pcm_DATA = $(ROOTDICTS:.cc=_rdict.pcm) + +pkginclude_HEADERS = \ + BcoInfo.h \ + BcoInfov1.h \ + BcoLumiReco.h \ + StreamingBcoInfo.h \ + StreamingBcoInfov1.h \ + StreamingLumiInfo.h \ + StreamingLumiInfov1.h \ + StreamingBcoReco.h \ + StreamingBcoCheck.h \ + StreamingLumiReco.h \ + StreamingLumiCheck.h + + +libbcolumicount_io_la_SOURCES = \ + $(ROOTDICTS) \ + BcoInfo.cc \ + BcoInfov1.cc \ + StreamingBcoInfo.cc \ + StreamingBcoInfov1.cc \ + StreamingLumiInfo.cc \ + StreamingLumiInfov1.cc + +libbcolumicount_la_SOURCES = \ + BcoLumiReco.cc \ + StreamingBcoReco.cc \ + StreamingBcoCheck.cc \ + StreamingLumiReco.cc \ + StreamingLumiCheck.cc + +BUILT_SOURCES = testexternals.cc + +noinst_PROGRAMS = \ + testexternals \ + testexternals_io + +testexternals_SOURCES = \ + testexternals.cc + +testexternals_LDADD = \ + libbcolumicount.la + +testexternals_io_SOURCES = \ + testexternals.cc + +testexternals_io_LDADD = \ + libbcolumicount_io.la + +testexternals.cc: + echo "//*** this is a generated file. Do not commit, do not edit" > $@ + echo "int main()" >> $@ + echo "{" >> $@ + echo " return 0;" >> $@ + echo "}" >> $@ + +%_Dict.cc: %.h %LinkDef.h + rootcint -f $@ @CINTDEFS@ $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $^ + +#just to get the dependency +%_Dict_rdict.pcm: %_Dict.cc ; + +clean-local: + rm -f $(BUILT_SOURCES) diff --git a/offline/packages/bcolumicount/StreamingBcoCheck.cc b/offline/packages/bcolumicount/StreamingBcoCheck.cc new file mode 100644 index 0000000000..e18dfb7333 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoCheck.cc @@ -0,0 +1,69 @@ +#include "StreamingBcoCheck.h" + +//#include "BcoInfo.h" +#include "StreamingBcoInfo.h" +#include "StreamingLumiInfo.h" +//#include "BcoStreamingLumiInfov1.h" + + +#include +#include + +#include + +#include +#include // for SubsysReco +#include +#include + + +#include +#include // for PHNode +#include // for PHNodeIterator +#include +#include // for PHWHERE + + +#include + +StreamingBcoCheck::StreamingBcoCheck(const std::string &name) + : SubsysReco(name) +{ + return; +} + +int StreamingBcoCheck::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + + return iret; +} + +int StreamingBcoCheck::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingBcoCheck::process_event(PHCompositeNode *topNode) +{ + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + if (streaming_bco_info) + { + if (Verbosity() > 1) + { + std::cout << "bco : " << streaming_bco_info->get_bco() << std::endl; + std::cout << "usable bco tag : " << streaming_bco_info->get_usable_bco_tag() << std::endl; + std::cout << "bco streaming window : (" << streaming_bco_info->get_bco_streaming_window().first << ", " << streaming_bco_info->get_bco_streaming_window().second << ")" << std::endl; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} \ No newline at end of file diff --git a/offline/packages/bcolumicount/StreamingBcoCheck.h b/offline/packages/bcolumicount/StreamingBcoCheck.h new file mode 100644 index 0000000000..5def0f329c --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoCheck.h @@ -0,0 +1,25 @@ +#ifndef BCOLUMICOUNT_STREAMINGBCOCHECK_H +#define BCOLUMICOUNT_STREAMINGBCOCHECK_H + +#include +#include + +#include + +#include + + +class StreamingBcoCheck : public SubsysReco +{ + public: + StreamingBcoCheck(const std::string &name = "BCOCHECKSTREAMINGOUTPUT"); + ~StreamingBcoCheck() override = default; + + int Init(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + + private: + static int CreateNodeTree(PHCompositeNode *topNode); +}; + +#endif // BCOLUMICOUNT_STREAMINGBCOCHECK_H diff --git a/offline/packages/bcolumicount/StreamingBcoInfo.cc b/offline/packages/bcolumicount/StreamingBcoInfo.cc new file mode 100644 index 0000000000..1519f90368 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfo.cc @@ -0,0 +1,23 @@ +#include "StreamingBcoInfo.h" + +#include + +#include + +void StreamingBcoInfo::Reset() +{ + std::cout << PHWHERE << "ERROR Reset() not implemented by daughter class" << std::endl; + return; +} + +void StreamingBcoInfo::identify(std::ostream& os) const +{ + os << "identify yourself: virtual StreamingBcoInfo Object" << std::endl; + return; +} + +//int BcoStreamingLumiInfo::isValid() const +//{ +// std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; +// return 0; +//} diff --git a/offline/packages/bcolumicount/StreamingBcoInfo.h b/offline/packages/bcolumicount/StreamingBcoInfo.h new file mode 100644 index 0000000000..5b8fe2b943 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfo.h @@ -0,0 +1,53 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLLUMICOUNT_STREAMINGBCOINFO_H +#define BCOLLUMICOUNT_STREAMINGBCOINFO_H + +#include + +#include +#include +#include + + +/// +class StreamingBcoInfo : public PHObject +{ + public: + /// ctor - daughter class copy ctor needs this + StreamingBcoInfo() = default; + /// dtor + ~StreamingBcoInfo() override = default; + /// Clear Sync + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& os = std::cout) const override; + + /// isValid returns non zero if object contains valid data + //int isValid() const override; + + virtual uint64_t get_bco() const { return 0; } + + virtual void set_bco(uint64_t /*val*/) { return; } + + virtual int get_evtno() const { return 0; } + + virtual void set_evtno(int /*val*/) { return; } + + virtual bool get_usable_bco_tag() const { return 0; } + + virtual void set_usable_bco_tag(bool /*val*/) { return; } + + virtual std::pair get_bco_streaming_window() const { return std::make_pair(0, 0); } + + virtual void set_bco_streaming_window(std::pair /*val*/) { return; } + + + private: + ClassDefOverride(StreamingBcoInfo, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/StreamingBcoInfoLinkDef.h b/offline/packages/bcolumicount/StreamingBcoInfoLinkDef.h new file mode 100644 index 0000000000..d01df73556 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfoLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class StreamingBcoInfo + ; + +#endif diff --git a/offline/packages/bcolumicount/StreamingBcoInfov1.cc b/offline/packages/bcolumicount/StreamingBcoInfov1.cc new file mode 100644 index 0000000000..73eb9f56b3 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfov1.cc @@ -0,0 +1,25 @@ +#include "StreamingBcoInfov1.h" + +#include + +#include + +void StreamingBcoInfov1::Reset() +{ + set_bco(0); + set_evtno(0); + set_usable_bco_tag(false); + set_bco_streaming_window(std::make_pair(0, 0)); + return; +} + +void StreamingBcoInfov1::identify(std::ostream& os) const +{ + os << "identify yourself: I am a StreamingBcoInfov1 Object\n"; return; +} + +//int StreamingBcoInfov1::isValid() const +//{ +// std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; +// return 0; +//} diff --git a/offline/packages/bcolumicount/StreamingBcoInfov1.h b/offline/packages/bcolumicount/StreamingBcoInfov1.h new file mode 100644 index 0000000000..ebbcadd123 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfov1.h @@ -0,0 +1,55 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLLUMICOUNT_STREAMINGBCOINFOV1_H +#define BCOLLUMICOUNT_STREAMINGBCOINFOV1_H + +#include "StreamingBcoInfo.h" + + +#include +#include +#include + + +/// +class StreamingBcoInfov1 : public StreamingBcoInfo +{ + public: + /// ctor - daughter class copy ctor needs this + StreamingBcoInfov1() = default; + /// dtor + ~StreamingBcoInfov1() override = default; + /// Clear Sync + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& os = std::cout) const override; + + /// isValid returns non zero if object contains valid data + //int isValid() const override; + + virtual uint64_t get_bco() const override { return m_bco; } + virtual void set_bco(uint64_t val) override { m_bco = val; } + + virtual int get_evtno() const override { return m_evtno; } + virtual void set_evtno(int val) override { m_evtno = val; } + + virtual bool get_usable_bco_tag() const override { return m_usable_bco_tag; } + virtual void set_usable_bco_tag(bool val) override { m_usable_bco_tag = val; } + + virtual std::pair get_bco_streaming_window() const override { return m_bco_streaming_window; } + virtual void set_bco_streaming_window(std::pair val) override { m_bco_streaming_window = val; } + + + private: + uint64_t m_bco{0}; + int m_evtno{0}; + bool m_usable_bco_tag{false}; + std::pair m_bco_streaming_window; + + ClassDefOverride(StreamingBcoInfov1, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/StreamingBcoInfov1LinkDef.h b/offline/packages/bcolumicount/StreamingBcoInfov1LinkDef.h new file mode 100644 index 0000000000..dc98f8629e --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoInfov1LinkDef.h @@ -0,0 +1,6 @@ +#ifdef __CINT__ + +#pragma link C++ class StreamingBcoInfov1 + ; +#pragma link C++ class std::pair + ; + +#endif diff --git a/offline/packages/bcolumicount/StreamingBcoReco.cc b/offline/packages/bcolumicount/StreamingBcoReco.cc new file mode 100644 index 0000000000..ca60549b8b --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoReco.cc @@ -0,0 +1,162 @@ +#include "StreamingBcoReco.h" + +#include "BcoInfo.h" +#include "StreamingBcoInfo.h" +#include "StreamingBcoInfov1.h" + + +#include +#include + +#include + +#include +#include // for SubsysReco +#include +#include + + +#include +#include // for PHNode +#include // for PHNodeIterator +#include +#include // for PHWHERE + +#include +#include +#include // for Packet + +#include + +#include + +StreamingBcoReco::StreamingBcoReco(const std::string &name) + : SubsysReco(name) +{ + hm = new Fun4AllHistoManager("bco_histos"); + Fun4AllServer *se = Fun4AllServer::instance(); + se->registerHistoManager(hm); + return; +} + +int StreamingBcoReco::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + h_bco_diff = new TH1I("h_bco_diff", ";bco diff;", 3500, 0, 3500); + //std::string hist_name = "h_bco_diff_bit"; + //for (int bit=0; bitregisterHisto(h_bco_diff_trigbits[bit]); + //} + h_bco_tag = new TH1I("h_bco_tag", ";usable bco tag;", 2, -0.5, 1.5); + hm->registerHisto(h_bco_diff); + hm->registerHisto(h_bco_tag); + + return iret; +} + +int StreamingBcoReco::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + if (!streaming_bco_info) + { + streaming_bco_info = new StreamingBcoInfov1(); + PHIODataNode *bconode = new PHIODataNode(streaming_bco_info, "STREAMINGBCOINFO", "PHObject"); + dstNode->addNode(bconode); + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingBcoReco::process_event(PHCompositeNode *topNode) +{ + BcoInfo *bcoinfo = findNode::getClass(topNode, "BCOINFO"); + SyncObject *syncobject = findNode::getClass(topNode, syncdefs::SYNCNODENAME); + if (Verbosity() > 2) + { + if (!syncobject) + { + std::cout << PHWHERE << " SyncObject missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + std::cout << "Event No: " << syncobject->EventNumber() << std::endl; + } + if (bcoinfo) + { + if (Verbosity() > 2) + { + std::cout << "prev event: " << bcoinfo->get_previous_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_previous_bco() << std::dec << std::endl; + std::cout << "curr event: " << bcoinfo->get_current_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_current_bco() << std::dec << std::endl; + std::cout << "futu event: " << bcoinfo->get_future_evtno() /*<< std::hex*/ + << " bco: " << bcoinfo->get_future_bco() << std::dec << std::endl; + } + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + if (!streaming_bco_info) + { + std::cout << PHWHERE << " STREAMINGBCOINFO node missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + m_bco = bcoinfo->get_current_bco(); + // No longer reading in the raw data for this check, but it should not be necessary + //if (gtm_bco != m_bco) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " m_bco " << m_bco << std::endl;} + uint64_t bco_prev = bcoinfo->get_previous_bco(); + uint64_t bco_futu = bcoinfo->get_future_bco(); + uint64_t bco_diff_prev = m_bco - bco_prev; + uint64_t bco_diff_futu = bco_futu - m_bco; + + // special case if BCO is within 20 of previous BCO? + if (bco_diff_prev < m_default_positive_window_length) + { + m_usable_bco_tag = true; + } + else + { + m_usable_bco_tag = false; + } + if (bco_diff_futu < m_default_positive_window_length) + { + // double check boundaries for overlap!! + m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, bco_futu - m_default_negative_window_length + 1); + } + else + { + m_bco_streaming_window = std::make_pair(get_bco() - m_default_negative_window_length, get_bco() + m_default_positive_window_length); + } + if (Verbosity() > 2) + { + std::cout << "bco_diff_prev : " << bco_diff_prev << std::endl; + std::cout << "bco_diff_futu : " << bco_diff_futu << std::endl; + } + h_bco_diff->Fill(bco_diff_prev); + h_bco_tag->Fill(m_usable_bco_tag); + // There is no longer a need to read in the .evt file here, so we won't have access to this info. If we wish to access it we can in a different module + //for (int bit=0; bit> static_cast(bit)) & 0x1U) == 0x1U; + // if (trigger_fired) + // { + // h_bco_diff_trigbits[bit]->Fill(bco_diff_prev); + // } + //} + + streaming_bco_info->set_bco(get_bco()); + streaming_bco_info->set_usable_bco_tag(get_usable_bco_tag()); + streaming_bco_info->set_bco_streaming_window(get_bco_streaming_window()); + if (syncobject) + { + streaming_bco_info->set_evtno(syncobject->EventNumber()); + } + } + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/bcolumicount/StreamingBcoReco.h b/offline/packages/bcolumicount/StreamingBcoReco.h new file mode 100644 index 0000000000..e54ef36dc6 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingBcoReco.h @@ -0,0 +1,51 @@ +#ifndef BCOLUMICOUNT_STREAMINGBCORECO_H +#define BCOLUMICOUNT_STREAMINGBCORECO_H + +#include +#include + +#include +#include +#include + +class TH1; + +class StreamingBcoReco : public SubsysReco +{ + public: + StreamingBcoReco(const std::string &name = "STREAMINGBCOLUMIRECO"); + ~StreamingBcoReco() override = default; + + int Init(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + + virtual int get_evtno() const { return m_evtno; } + + virtual uint64_t get_bco() const { return m_bco; } + + virtual bool get_usable_bco_tag() const { return m_usable_bco_tag; } + + virtual std::pair get_bco_streaming_window() const { return m_bco_streaming_window; } + + virtual void set_default_positive_window_length(int val) { m_default_positive_window_length = val; } + virtual void set_default_negative_window_length(int val) { m_default_negative_window_length = val; } + + + + private: + static int CreateNodeTree(PHCompositeNode *topNode); + //const int trigbits = 40; + Fun4AllHistoManager *hm = nullptr; + TH1 *h_bco_diff = nullptr; + //TH1 *h_bco_diff_trigbits[40] = {nullptr}; + TH1 *h_bco_tag = nullptr; + + uint64_t m_bco{0}; + int m_evtno{0}; + bool m_usable_bco_tag = false; + std::pair m_bco_streaming_window; + unsigned int m_default_positive_window_length{340}; + unsigned int m_default_negative_window_length{20}; +}; + +#endif // BCOLUMICOUNT_STREAMINGBCORECO_H diff --git a/offline/packages/bcolumicount/StreamingLumiCheck.cc b/offline/packages/bcolumicount/StreamingLumiCheck.cc new file mode 100644 index 0000000000..b2527bb24d --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiCheck.cc @@ -0,0 +1,82 @@ +#include "StreamingLumiCheck.h" + +//#include "BcoInfo.h" +#include "StreamingBcoInfo.h" +#include "StreamingLumiInfo.h" +//#include "BcoStreamingLumiInfov1.h" + + +#include +#include + +#include + +#include +#include // for SubsysReco +#include +#include + + +#include +#include // for PHNode +#include // for PHNodeIterator +#include +#include // for PHWHERE + + +#include + +StreamingLumiCheck::StreamingLumiCheck(const std::string &name) + : SubsysReco(name) +{ + return; +} + +int StreamingLumiCheck::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + + return iret; +} + +int StreamingLumiCheck::InitRun(PHCompositeNode *topNode) +{ + StreamingLumiInfo *streaming_lumi_info = findNode::getClass(topNode, "STREAMINGLUMIINFO"); + if (streaming_lumi_info) + { + std::cout << " raw lumi : " << streaming_lumi_info->get_lumi_raw() << std::endl; + std::cout << " live lumi : " << streaming_lumi_info->get_lumi_live() << std::endl; + std::cout << " scaled lumi : " << streaming_lumi_info->get_lumi_scaled() << std::endl; + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingLumiCheck::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; +} +/* +int StreamingLumiCheck::process_event(PHCompositeNode *topNode) +{ + StreamingBcoInfo *streaming_bco_info = findNode::getClass(topNode, "STREAMINGBCOINFO"); + if (streaming_bco_info) + { + if (Verbosity() > 1) + { + std::cout << "bco : " << streaming_bco_info->get_bco() << std::endl; + std::cout << "usable bco tag : " << streaming_bco_info->get_usable_bco_tag() << std::endl; + std::cout << "bco streaming window : (" << streaming_bco_info->get_bco_streaming_window().first << ", " << streaming_bco_info->get_bco_streaming_window().second << ")" << std::endl; + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} +*/ \ No newline at end of file diff --git a/offline/packages/bcolumicount/StreamingLumiCheck.h b/offline/packages/bcolumicount/StreamingLumiCheck.h new file mode 100644 index 0000000000..8fc89ff5e9 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiCheck.h @@ -0,0 +1,26 @@ +#ifndef BCOLUMICOUNT_STREAMINGLUMICHECK_H +#define BCOLUMICOUNT_STREAMINGLUMICHECK_H + +#include +#include + +#include + +#include + + +class StreamingLumiCheck : public SubsysReco +{ + public: + StreamingLumiCheck(const std::string &name = "LUMICHECKSTREAMINGOUTPUT"); + ~StreamingLumiCheck() override = default; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + //int process_event(PHCompositeNode *topNode) override; + + private: + static int CreateNodeTree(PHCompositeNode *topNode); +}; + +#endif // BCOLUMICOUNT_STREAMINGLUMICHECK_H diff --git a/offline/packages/bcolumicount/StreamingLumiInfo.cc b/offline/packages/bcolumicount/StreamingLumiInfo.cc new file mode 100644 index 0000000000..f7f2afebc2 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfo.cc @@ -0,0 +1,17 @@ +#include "StreamingLumiInfo.h" + +#include + +#include + +void StreamingLumiInfo::identify(std::ostream& os) const +{ + os << "identify yourself: virtual StreamingLumiInfo Object" << std::endl; + return; +} + +//int StreamingLumiInfo::isValid() const +//{ +// std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; +// return 0; +//} diff --git a/offline/packages/bcolumicount/StreamingLumiInfo.h b/offline/packages/bcolumicount/StreamingLumiInfo.h new file mode 100644 index 0000000000..9bea6a3dff --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfo.h @@ -0,0 +1,54 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLLUMICOUNT_STREAMINGLUMIINFO_H +#define BCOLLUMICOUNT_STREAMINGLUMIINFO_H + +#include + +#include +#include +#include +#include + + +/// +class StreamingLumiInfo : public PHObject +{ + public: + /// ctor - daughter class copy ctor needs this + StreamingLumiInfo() = default; + /// dtor + ~StreamingLumiInfo() override = default; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& os = std::cout) const override; + + /// isValid returns non zero if object contains valid data + //int isValid() const override; + + virtual const std::array get_bunchnumber_lumi_raw() const { return std::array{}; } + virtual void set_bunchnumber_lumi_raw(const std::array& /*vals*/) { return; } + + virtual const std::array get_bunchnumber_lumi_live() const { return std::array{}; } + virtual void set_bunchnumber_lumi_live(const std::array& /*vals*/) { return; } + + virtual const std::array get_bunchnumber_lumi_scaled() const { return std::array{}; } + virtual void set_bunchnumber_lumi_scaled(const std::array& /*vals*/) { return; } + + virtual double get_lumi_raw() const { return 0; } + virtual void set_lumi_raw(double /*val*/) { return; } + + virtual double get_lumi_live() const { return 0; } + virtual void set_lumi_live(double /*val*/) { return; } + + virtual double get_lumi_scaled() const { return 0; } + virtual void set_lumi_scaled(double /*val*/) { return; } + + + private: + ClassDefOverride(StreamingLumiInfo, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/StreamingLumiInfoLinkDef.h b/offline/packages/bcolumicount/StreamingLumiInfoLinkDef.h new file mode 100644 index 0000000000..098d7b8de3 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfoLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class StreamingLumiInfo + ; + +#endif diff --git a/offline/packages/bcolumicount/StreamingLumiInfov1.cc b/offline/packages/bcolumicount/StreamingLumiInfov1.cc new file mode 100644 index 0000000000..691259d784 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfov1.cc @@ -0,0 +1,16 @@ +#include "StreamingLumiInfov1.h" + +#include + +#include + +void StreamingLumiInfov1::identify(std::ostream& os) const +{ + os << "identify yourself: I am a StreamingLumiInfov1 Object\n"; return; +} + +//int StreamingLumiInfov1::isValid() const +//{ +// std::cout << PHWHERE << "isValid not implemented by daughter class" << std::endl; +// return 0; +//} diff --git a/offline/packages/bcolumicount/StreamingLumiInfov1.h b/offline/packages/bcolumicount/StreamingLumiInfov1.h new file mode 100644 index 0000000000..b8993c1f8d --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfov1.h @@ -0,0 +1,63 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef BCOLLUMICOUNT_STREAMINGLUMIINFOV1_H +#define BCOLLUMICOUNT_STREAMINGLUMIINFOV1_H + +#include "StreamingLumiInfo.h" + + +#include +#include +#include + + +/// +class StreamingLumiInfov1 : public StreamingLumiInfo +{ + public: + /// ctor - daughter class copy ctor needs this + StreamingLumiInfov1() = default; + /// dtor + ~StreamingLumiInfov1() override = default; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream& os = std::cout) const override; + + /// isValid returns non zero if object contains valid data + //int isValid() const override; + + virtual const std::array get_bunchnumber_lumi_raw() const override { return m_bunchnumber_lumi_raw; } + virtual void set_bunchnumber_lumi_raw(const std::array& vals) override { m_bunchnumber_lumi_raw = vals; } + + virtual const std::array get_bunchnumber_lumi_live() const override { return m_bunchnumber_lumi_live; } + virtual void set_bunchnumber_lumi_live(const std::array& vals) override { m_bunchnumber_lumi_live = vals; } + + virtual const std::array get_bunchnumber_lumi_scaled() const override { return m_bunchnumber_lumi_scaled; } + virtual void set_bunchnumber_lumi_scaled(const std::array& vals) override { m_bunchnumber_lumi_scaled = vals; } + + virtual double get_lumi_raw() const override { return m_lumi_raw; } + virtual void set_lumi_raw(double val) override { m_lumi_raw = val; } + + virtual double get_lumi_live() const override { return m_lumi_live; } + virtual void set_lumi_live(double val) override { m_lumi_live = val; } + + virtual double get_lumi_scaled() const override { return m_lumi_scaled; } + virtual void set_lumi_scaled(double val) override { m_lumi_scaled = val; } + + + private: + std::array m_bunchnumber_lumi_raw{0.}; + std::array m_bunchnumber_lumi_live{0.}; + std::array m_bunchnumber_lumi_scaled{0.}; + + double m_lumi_raw{0.}; + double m_lumi_live{0.}; + double m_lumi_scaled{0.}; + + + ClassDefOverride(StreamingLumiInfov1, 1) +}; + +#endif diff --git a/offline/packages/bcolumicount/StreamingLumiInfov1LinkDef.h b/offline/packages/bcolumicount/StreamingLumiInfov1LinkDef.h new file mode 100644 index 0000000000..7f59d1e0d1 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiInfov1LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class StreamingLumiInfov1 + ; + +#endif diff --git a/offline/packages/bcolumicount/StreamingLumiReco.cc b/offline/packages/bcolumicount/StreamingLumiReco.cc new file mode 100644 index 0000000000..0d72b47ec2 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiReco.cc @@ -0,0 +1,192 @@ +#include "StreamingLumiReco.h" + +#include "StreamingBcoInfo.h" +#include "StreamingLumiInfo.h" +#include "StreamingLumiInfov1.h" + + +#include +#include + +#include + +#include +#include // for SubsysReco +#include +#include + + +#include +#include // for PHNode +#include // for PHNodeIterator +#include +#include // for PHWHERE +#include // for MDB_NS_xsec + +#include + +#include + +StreamingLumiReco::StreamingLumiReco(const std::string &name) + : SubsysReco(name) +{ + return; +} + +int StreamingLumiReco::Init(PHCompositeNode *topNode) +{ + int iret = CreateNodeTree(topNode); + return iret; +} + +int StreamingLumiReco::InitRun(PHCompositeNode * topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *runNode; + runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); + if (!runNode) + { + std::cout << PHWHERE << " Run Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + m_streaming_lumi_info = findNode::getClass(topNode, "STREAMINGLUMIINFO"); + if (!m_streaming_lumi_info) + { + m_streaming_lumi_info = new StreamingLumiInfov1(); + PHIODataNode *luminode = new PHIODataNode(m_streaming_lumi_info, "STREAMINGLUMIINFO", "PHObject"); + runNode->addNode(luminode); + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingLumiReco::CreateNodeTree(PHCompositeNode *topNode) +{ + PHNodeIterator iter(topNode); + PHCompositeNode *dstNode; + dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << " DST Node is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingLumiReco::process_event(PHCompositeNode *topNode) +{ + StreamingBcoInfo *streaming_bcoinfo = findNode::getClass(topNode, "STREAMINGBCOINFO"); + Gl1Packet *gl1packet = findNode::getClass(topNode, "GL1RAWHIT"); + if (!gl1packet) + { + if (Verbosity() > 0) + { + std::cout << "no gl1 packet 14001" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + uint64_t gtm_bco = gl1packet->lValue(0, "BCO"); + + int bunchno = gl1packet->lValue(0,"BunchNumber"); + if (bunchno < 0 || bunchno >= m_bunches) + { + if (Verbosity() > 0) + { + std::cout << PHWHERE << " invalid bunch number: " << bunchno << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; + } + + // SYNTAX TAKEN FROM ZHIWANS CODE, why = and not +=? If this is correct it seems like a waste to call it for every event (would just need it for the last event in a particular crossing?) + m_bunchnumber_MBDNS_raw[bunchno] = gl1packet->lValue(0, "GL1PRAW"); + m_bunchnumber_MBDNS_live[bunchno] = gl1packet->lValue(0, "GL1PLIVE"); + m_bunchnumber_MBDNS_scaled[bunchno] = gl1packet->lValue(0, "GL1PSCALED"); + + + if(gl1packet->lValue(0, 0)) + { + m_rawgl1scaler = gl1packet->lValue(0, 0); + } + + if (streaming_bcoinfo) + { + if (gtm_bco != streaming_bcoinfo->get_bco()) { std::cout << "BCO MISMATCH!!! : gtm_bco : " << gtm_bco << " bco " << streaming_bcoinfo->get_bco() << std::endl;} + + // Double check Zhiwan's logic for assigning the adjusted bunch! + int lower = streaming_bcoinfo->get_bco_streaming_window().first - streaming_bcoinfo->get_bco(); + int upper = streaming_bcoinfo->get_bco_streaming_window().second - streaming_bcoinfo->get_bco(); + for(int i = lower; i< upper;i++) + { + int adjusted_bunch = bunchno + i; + while (adjusted_bunch < 0) + { + adjusted_bunch += 120; + } + while (adjusted_bunch > 119) + { + adjusted_bunch -= 120; + } + // ABORT GAP! + if (adjusted_bunch>110) { continue; } + + // Make sure this is the correct way to count crossings! Need to zero out for each run! + if(i!=0 || streaming_bcoinfo->get_usable_bco_tag()) + { + m_bunchnumber_crossings[adjusted_bunch] += 1; + } + } + } + return Fun4AllReturnCodes::EVENT_OK; +} + +int StreamingLumiReco::EndRun(int /*runnumber*/) +{ + uint64_t rawgl1scalers_per_bunch = m_rawgl1scaler/120.; + for (int i=0; i 1) + { + std::cout << "bunchno : " << i << " lumi_raw : " << m_bunchnumber_lumi_raw[i] << std::endl; + } + } + if (!m_streaming_lumi_info) + { + std::cout << PHWHERE << " STREAMINGLUMIINFO node missing in EndRun" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_streaming_lumi_info->set_bunchnumber_lumi_raw(get_bunchnumber_lumi_raw()); + m_streaming_lumi_info->set_bunchnumber_lumi_live(get_bunchnumber_lumi_live()); + m_streaming_lumi_info->set_bunchnumber_lumi_scaled(get_bunchnumber_lumi_scaled()); + + m_streaming_lumi_info->set_lumi_raw(get_lumi_raw()); + m_streaming_lumi_info->set_lumi_live(get_lumi_live()); + m_streaming_lumi_info->set_lumi_scaled(get_lumi_scaled()); + + if (Verbosity() > 1) + { + std::cout << "MBD xsec : " << sphenix_constants::m_xsec_MBDNS << std::endl; + std::cout << "total lumi (raw) : " << m_lumi_raw << std::endl; + } + + m_bunchnumber_lumi_raw.fill(0); + m_bunchnumber_lumi_live.fill(0); + m_bunchnumber_lumi_scaled.fill(0); + m_bunchnumber_crossings.fill(0); + m_bunchnumber_MBDNS_raw.fill(0); + m_bunchnumber_MBDNS_live.fill(0); + m_bunchnumber_MBDNS_scaled.fill(0); + m_lumi_raw = 0.; + m_lumi_live = 0.; + m_lumi_scaled = 0.; + m_rawgl1scaler = 0; + + return Fun4AllReturnCodes::EVENT_OK; +} diff --git a/offline/packages/bcolumicount/StreamingLumiReco.h b/offline/packages/bcolumicount/StreamingLumiReco.h new file mode 100644 index 0000000000..7f74a30367 --- /dev/null +++ b/offline/packages/bcolumicount/StreamingLumiReco.h @@ -0,0 +1,67 @@ +#ifndef BCOLUMICOUNT_STREAMINGLUMIRECO_H +#define BCOLUMICOUNT_STREAMINGLUMIRECO_H + +#include "StreamingLumiInfo.h" + +#include +#include + +#include +#include +#include + +class TH1; + +class StreamingLumiReco : public SubsysReco +{ + public: + StreamingLumiReco(const std::string &name = "STREAMINGBCOLUMIRECO"); + ~StreamingLumiReco() override = default; + + int Init(PHCompositeNode *topNode) override; + int InitRun(PHCompositeNode *topNode) override; + int process_event(PHCompositeNode *topNode) override; + int EndRun(const int runnumber) override; + + virtual const std::array get_bunchnumber_lumi_raw() const { return m_bunchnumber_lumi_raw; } + virtual const std::array get_bunchnumber_lumi_live() const { return m_bunchnumber_lumi_live; } + virtual const std::array get_bunchnumber_lumi_scaled() const { return m_bunchnumber_lumi_scaled; } + + virtual double get_lumi_raw() const { return m_lumi_raw; } + virtual double get_lumi_live() const { return m_lumi_live; } + virtual double get_lumi_scaled() const { return m_lumi_scaled; } + + virtual void set_default_positive_window_length(int val) { m_default_positive_window_length = val; } + virtual void set_default_negative_window_length(int val) { m_default_negative_window_length = val; } + + + private: + static int CreateNodeTree(PHCompositeNode *topNode); + + int m_bunches = 120; + unsigned int m_default_positive_window_length{340}; + unsigned int m_default_negative_window_length{20}; + + //double m_xsec_MBDNS = 24.07*1e9; //convert to pb from Vernier scan DOUBLE CHECK VALUE! + + uint64_t m_rawgl1scaler{0}; + + std::array m_bunchnumber_MBDNS_raw{0}; + std::array m_bunchnumber_MBDNS_live{0}; + std::array m_bunchnumber_MBDNS_scaled{0}; + + std::array m_bunchnumber_crossings{0}; + + std::array m_bunchnumber_lumi_raw{0.}; + std::array m_bunchnumber_lumi_live{0.}; + std::array m_bunchnumber_lumi_scaled{0.}; + + double m_lumi_raw{0.}; + double m_lumi_live{0.}; + double m_lumi_scaled{0.}; + + StreamingLumiInfo *m_streaming_lumi_info = nullptr; + +}; + +#endif // BCOLUMICOUNT_STREAMINGLUMIRECO_H diff --git a/offline/packages/bcolumicount/autogen.sh b/offline/packages/bcolumicount/autogen.sh new file mode 100755 index 0000000000..dea267bbfd --- /dev/null +++ b/offline/packages/bcolumicount/autogen.sh @@ -0,0 +1,8 @@ +#!/bin/sh +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +(cd $srcdir; aclocal -I ${OFFLINE_MAIN}/share;\ +libtoolize --force; automake -a --add-missing; autoconf) + +$srcdir/configure "$@" diff --git a/offline/packages/bcolumicount/configure.ac b/offline/packages/bcolumicount/configure.ac new file mode 100644 index 0000000000..ea3c13cc92 --- /dev/null +++ b/offline/packages/bcolumicount/configure.ac @@ -0,0 +1,20 @@ +AC_INIT(bcolumicount,[1.0]) +AC_CONFIG_SRCDIR([configure.ac]) + +AM_INIT_AUTOMAKE + +LT_INIT([disable-static]) + +AC_PROG_CXX(CC g++) + +dnl no point in suppressing warnings people should +dnl at least see them, so here we go for g++: -Wall +if test $ac_cv_prog_gxx = yes; then + CXXFLAGS="$CXXFLAGS -Wall -Werror -Wextra -Wshadow" +fi + +CINTDEFS=" -noIncludePaths -inlineInputHeader " +AC_SUBST(CINTDEFS) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/offline/packages/centrality/CentralityInfov2.cc b/offline/packages/centrality/CentralityInfov2.cc index 5704518fa0..d13c0f3ea2 100644 --- a/offline/packages/centrality/CentralityInfov2.cc +++ b/offline/packages/centrality/CentralityInfov2.cc @@ -11,6 +11,12 @@ void CentralityInfov2::identify(std::ostream &os) const return; } +void CentralityInfov2::Reset() +{ + CentralityInfov1::Reset(); + _centrality_bin_map.clear(); +} + bool CentralityInfov2::has_centrality_bin(const PROP prop_id) const { return _centrality_bin_map.contains(prop_id); diff --git a/offline/packages/centrality/CentralityInfov2.h b/offline/packages/centrality/CentralityInfov2.h index 91362b5e85..05072f47a6 100644 --- a/offline/packages/centrality/CentralityInfov2.h +++ b/offline/packages/centrality/CentralityInfov2.h @@ -13,7 +13,7 @@ class CentralityInfov2 : public CentralityInfov1 ~CentralityInfov2() override = default; void identify(std::ostream &os = std::cout) const override; - void Reset() override {} + void Reset() override; PHObject* CloneMe() const override { return new CentralityInfov2(*this); } void CopyTo(CentralityInfo *info) override; diff --git a/offline/packages/centrality/CentralityReco.cc b/offline/packages/centrality/CentralityReco.cc index 0a45ecb2c1..d77064ecc7 100644 --- a/offline/packages/centrality/CentralityReco.cc +++ b/offline/packages/centrality/CentralityReco.cc @@ -8,11 +8,9 @@ #include -#include -#include +#include #include -#include #include @@ -32,43 +30,54 @@ CentralityReco::CentralityReco(const std::string &name) : SubsysReco(name) { - } int CentralityReco::InitRun(PHCompositeNode *topNode) { CDBInterface *m_cdb = CDBInterface::instance(); - std::string centdiv_url = m_cdb->getUrl("Centrality"); - if (m_overwrite_divs) - { - centdiv_url = m_overwrite_url_divs; - std::cout << " Overwriting Divs to " << m_overwrite_url_divs << std::endl; - } + std::string centdiv_url; + if (!m_overwrite_url_divs.empty()) + { + centdiv_url = m_overwrite_url_divs; + std::cout << " Overwriting Divs to " << m_overwrite_url_divs << std::endl; + } + else + { + centdiv_url = m_cdb->getUrl("Centrality"); + } if (Download_centralityDivisions(centdiv_url)) { return Fun4AllReturnCodes::ABORTRUN; } - std::string centscale_url = m_cdb->getUrl("CentralityScale"); - if (m_overwrite_scale) - { - centscale_url = m_overwrite_url_scale; - std::cout << " Overwriting Scale to " << m_overwrite_url_scale << std::endl; - } + std::string centscale_url; + if (!m_overwrite_url_scale.empty()) + { + centscale_url = m_overwrite_url_scale; + std::cout << " Overwriting Scale to " << m_overwrite_url_scale << std::endl; + } + else + { + centscale_url = m_cdb->getUrl("CentralityScale"); + } if (Download_centralityScale(centscale_url)) { return Fun4AllReturnCodes::ABORTRUN; } - std::string vertexscale_url = m_cdb->getUrl("CentralityVertexScale"); - if (m_overwrite_vtx) - { - vertexscale_url = m_overwrite_url_vtx; - std::cout << " Overwriting Vtx to " << m_overwrite_url_vtx << std::endl; - } + std::string vertexscale_url; + if (!m_overwrite_url_vtx.empty()) + { + vertexscale_url = m_overwrite_url_vtx; + std::cout << " Overwriting Vtx to " << m_overwrite_url_vtx << std::endl; + } + else + { + vertexscale_url = m_cdb->getUrl("CentralityVertexScale"); + } if (Download_centralityVertexScales(vertexscale_url)) { @@ -115,9 +124,9 @@ int CentralityReco::Download_centralityDivisions(const std::string &dbfile) CDBTTree *cdbttree = new CDBTTree(dbase_file); cdbttree->LoadCalibrations(); if (Verbosity()) - { - cdbttree->Print(); - } + { + cdbttree->Print(); + } for (int idiv = 0; idiv < NDIVS; idiv++) { m_centrality_map[idiv] = cdbttree->GetFloatValue(idiv, "centralitydiv"); @@ -138,7 +147,6 @@ int CentralityReco::Download_centralityDivisions(const std::string &dbfile) } int CentralityReco::Download_centralityVertexScales(const std::string &dbfile) { - std::filesystem::path dbase_file = dbfile; if (dbase_file.extension() == ".root") @@ -146,18 +154,17 @@ int CentralityReco::Download_centralityVertexScales(const std::string &dbfile) CDBTTree *cdbttree = new CDBTTree(dbase_file); cdbttree->LoadCalibrations(); if (Verbosity()) - { - cdbttree->Print(); - } + { + cdbttree->Print(); + } int nvertexbins = cdbttree->GetIntValue(0, "nvertexbins"); - for (int iv = 0; iv < nvertexbins; iv++) { float scale = cdbttree->GetDoubleValue(iv, "scale"); float lowvertex = cdbttree->GetDoubleValue(iv, "low_vertex"); - float highvertex = cdbttree->GetDoubleValue(iv, "high_vertex"); + float highvertex = cdbttree->GetDoubleValue(iv, "high_vertex"); m_vertex_scales.emplace_back(std::make_pair(lowvertex, highvertex), scale); } @@ -186,30 +193,27 @@ int CentralityReco::FillVars() std::cout << __FILE__ << " :: " << __FUNCTION__ << std::endl; } - float scale_factor = getVertexScale(); if (Verbosity()) - { - std::cout << scale_factor << "*" << m_centrality_scale << std::endl; - } + { + std::cout << scale_factor << "*" << m_centrality_scale << std::endl; + } for (int i = 0; i < 128; i++) + { + m_mbd_hit = m_mbd_container->get_pmt(i); + + if ((m_mbd_hit->get_q()) < mbd_charge_cut) { - - m_mbd_hit = m_mbd_container->get_pmt(i); - - if ((m_mbd_hit->get_q()) < mbd_charge_cut) - { - continue; - } - if (fabs(m_mbd_hit->get_time()) > mbd_time_cut) - { - continue; - } - m_mbd_total_charge += m_mbd_hit->get_q()*scale_factor*m_centrality_scale; + continue; } - + if (fabs(m_mbd_hit->get_time()) > mbd_time_cut) + { + continue; + } + m_mbd_total_charge += m_mbd_hit->get_q() * scale_factor * m_centrality_scale; + } return Fun4AllReturnCodes::EVENT_OK; } @@ -230,15 +234,15 @@ int CentralityReco::FillCentralityInfo() if (m_centrality_map[i] < m_mbd_total_charge) { binvalue = i + 1; - value = static_cast(i + 1)/static_cast(NDIVS); + value = static_cast(i + 1) / static_cast(NDIVS); break; } } - if (Verbosity()) - { - std::cout << " Centile : " << value << std::endl; - std::cout << " Charge : " << m_mbd_total_charge << std::endl; - } + if (Verbosity()) + { + std::cout << " Centile : " << value << std::endl; + std::cout << " Charge : " << m_mbd_total_charge << std::endl; + } m_central->set_centile(CentralityInfo::PROP::mbd_NS, value); m_central->set_centrality_bin(CentralityInfo::PROP::mbd_NS, binvalue); @@ -254,16 +258,16 @@ int CentralityReco::process_event(PHCompositeNode *topNode) } // Get Nodes from the Tree - if (GetNodes(topNode)) + int ret = GetNodes(topNode); + if (ret != Fun4AllReturnCodes::EVENT_OK) { - return Fun4AllReturnCodes::ABORTRUN; + return ret; } if (!m_mb_info->isAuAuMinimumBias()) - { - return Fun4AllReturnCodes::EVENT_OK; - } - + { + return Fun4AllReturnCodes::EVENT_OK; + } // Fill Arrays if (FillVars()) @@ -291,7 +295,7 @@ int CentralityReco::GetNodes(PHCompositeNode *topNode) std::cout << __FILE__ << " :: " << __FUNCTION__ << " :: " << __LINE__ << std::endl; } - m_mb_info = findNode::getClass(topNode, "MinimumBiasInfo"); + m_mb_info = findNode::getClass(topNode, m_mb_info_nodename); if (!m_mb_info) { @@ -299,15 +303,7 @@ int CentralityReco::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - m_global_vertex_map = findNode::getClass(topNode, "GlobalVertexMap"); - - if (!m_global_vertex_map) - { - std::cout << "no vertex map node " << std::endl; - return Fun4AllReturnCodes::EVENT_OK; - } - - m_central = findNode::getClass(topNode, "CentralityInfo"); + m_central = findNode::getClass(topNode, m_centrality_nodename); if (!m_central) { @@ -315,7 +311,7 @@ int CentralityReco::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - m_mbd_container = findNode::getClass(topNode, "MbdPmtContainer"); + m_mbd_container = findNode::getClass(topNode, m_mbd_pmt_nodename); if (!m_mbd_container) { @@ -323,18 +319,17 @@ int CentralityReco::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - - m_mbd_out = findNode::getClass(topNode, "MbdOut"); + m_mbd_out = findNode::getClass(topNode, m_mbd_out_nodename); if (Verbosity()) - { - std::cout << "Getting MBD Out" << std::endl; - } + { + std::cout << "Getting MBD Out" << std::endl; + } if (!m_mbd_out) - { - std::cout << "no MBD out node " << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } + { + std::cout << "no MBD out node " << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } return Fun4AllReturnCodes::EVENT_OK; } @@ -365,7 +360,7 @@ void CentralityReco::CreateNodes(PHCompositeNode *topNode) CentralityInfo *central = new CentralityInfov2(); - PHIODataNode *centralityNode = new PHIODataNode(central, "CentralityInfo", "PHObject"); + PHIODataNode *centralityNode = new PHIODataNode(central, m_centrality_nodename, "PHObject"); detNode->addNode(centralityNode); return; @@ -373,23 +368,19 @@ void CentralityReco::CreateNodes(PHCompositeNode *topNode) float CentralityReco::getVertexScale() { - - float mbd_vertex = m_mbd_out->get_zvtx(); - for (auto v_range_scale : m_vertex_scales) + { + auto v_range = v_range_scale.first; + if (Verbosity()) { - auto v_range = v_range_scale.first; - if (Verbosity()) - { - std::cout << "vertexrange : "< v_range.first && mbd_vertex <= v_range.second) - { - return v_range_scale.second; - } + std::cout << "vertexrange : " << v_range.first << "-" << v_range.second << std::endl; } + + if (mbd_vertex > v_range.first && mbd_vertex <= v_range.second) + { + return v_range_scale.second; + } + } return 0; } - diff --git a/offline/packages/centrality/CentralityReco.h b/offline/packages/centrality/CentralityReco.h index bc0483d57d..46d8d54bd1 100644 --- a/offline/packages/centrality/CentralityReco.h +++ b/offline/packages/centrality/CentralityReco.h @@ -2,16 +2,18 @@ #define CENTRALITY_CENTRALITYRECO_H #include + #include -#include #include #include // for string, allocator +#include +#include // Forward declarations + class CentralityInfo; class MinimumBiasInfo; class PHCompositeNode; -class GlobalVertexMap; class MbdOut; class MbdPmtContainer; class MbdPmtHit; @@ -44,52 +46,66 @@ class CentralityReco : public SubsysReco void setOverwriteDivs(const std::string &url) { m_overwrite_url_divs = url; - m_overwrite_divs = true; } void setOverwriteScale(const std::string &url) { m_overwrite_url_scale = url; - m_overwrite_scale = true; } + void setOverwriteVtx(const std::string &url) { m_overwrite_url_vtx = url; - m_overwrite_vtx = true; } - private: + void set_minbiasNodeName(const std::string &name) + { + m_mb_info_nodename = name; + } + void set_mbdOutNodeName(const std::string &name) + { + m_mbd_out_nodename = name; + } + void set_centralityNodeName(const std::string &name) + { + m_centrality_nodename = name; + } + void set_mbdPmtNodeName(const std::string &name) + { + m_mbd_pmt_nodename = name; + } + private: float getVertexScale(); - std::string m_dbfilename; - - bool m_overwrite_divs{false}; - bool m_overwrite_scale{false}; - bool m_overwrite_vtx{false}; - std::string m_overwrite_url_divs{""}; - std::string m_overwrite_url_scale{""}; - std::string m_overwrite_url_vtx{""}; - - const int NDIVS{100}; - const float mbd_charge_cut{0.5}; - const float mbd_time_cut{25}; - - GlobalVertexMap *m_global_vertex_map{nullptr}; MbdOut *m_mbd_out{nullptr}; MbdPmtContainer *m_mbd_container{nullptr}; MbdPmtHit *m_mbd_hit{nullptr}; MinimumBiasInfo *m_mb_info{nullptr}; CentralityInfo *m_central{nullptr}; - unsigned int m_key{std::numeric_limits::max()}; + static constexpr int NDIVS{100}; - float m_mbd_total_charge{0.}; // init to zero for use in first event + static constexpr float mbd_charge_cut{0.5}; + static constexpr float mbd_time_cut{25}; + + unsigned int m_key{std::numeric_limits::max()}; double m_centrality_scale{std::numeric_limits::quiet_NaN()}; - std::vector, float>> m_vertex_scales{}; - std::array m_centrality_map{}; + + float m_mbd_total_charge{0.}; // init to zero for use in first event + std::string m_mb_info_nodename{"MinimumBiasInfo"}; + std::string m_mbd_out_nodename{"MbdOut"}; + std::string m_centrality_nodename{"CentralityInfo"}; + std::string m_mbd_pmt_nodename{"MbdPmtContainer"}; + + std::string m_overwrite_url_divs; + std::string m_overwrite_url_scale; + std::string m_overwrite_url_vtx; + + std::vector, float>> m_vertex_scales{}; + std::array m_centrality_map{}; }; #endif diff --git a/offline/packages/decayfinder/DecayFinder.cc b/offline/packages/decayfinder/DecayFinder.cc index 1593387592..596cce9c63 100644 --- a/offline/packages/decayfinder/DecayFinder.cc +++ b/offline/packages/decayfinder/DecayFinder.cc @@ -93,14 +93,14 @@ int DecayFinder::Init(PHCompositeNode* topNode) int DecayFinder::process_event(PHCompositeNode* topNode) { - bool decayFound = findDecay(topNode); + int decayFound = findDecay(topNode); - if (decayFound && m_save_dst && Verbosity() >= VERBOSITY_MORE) + if (decayFound > 0 && m_save_dst && Verbosity() >= VERBOSITY_MORE) { printNode(topNode); } - if (m_triggerOnDecay && !decayFound) + if (m_triggerOnDecay && decayFound < 1) { if (Verbosity() >= VERBOSITY_MORE) { @@ -317,10 +317,10 @@ int DecayFinder::parseDecayDescriptor() * as decays wont enter the HepMC record * need a switch to go to Geant4 record */ -bool DecayFinder::findDecay(PHCompositeNode* topNode) +int DecayFinder::findDecay(PHCompositeNode* topNode) { bool decayWasFound = false; - bool reconstructableDecayWasFound = false; + int reconstructableDecayWasFound = 0; bool aTrackFailedPT = false; bool aTrackFailedETA = false; bool aMotherHasPhoton = false; @@ -361,6 +361,9 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) exit(1); } + // correct mother PID to search for match + const int mother_id_to_match = m_getChargeConjugate ? std::abs(m_mother_ID) : m_mother_ID; + if (m_truthinfo && !m_geneventmap) // This should use the truth info container if we have no HepMC record { if (Verbosity() >= VERBOSITY_SOME) @@ -374,13 +377,18 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) { PHG4Particle* g4particle = iter->second; int this_pid = m_getChargeConjugate ? abs(g4particle->get_pid()) : g4particle->get_pid(); - if (this_pid == m_mother_ID) + if (this_pid == mother_id_to_match) { if (Verbosity() >= VERBOSITY_MAX) { std::cout << "parent->pdg_id(): " << g4particle->get_pid() << std::endl; } + aTrackFailedPT = false; + aTrackFailedETA = false; + aMotherHasPhoton = false; + aMotherHasPi0 = false; + bool breakOut = false; correctMotherProducts.clear(); decayChain.clear(); @@ -413,7 +421,7 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) else { m_nCandReconstructable += 1; - reconstructableDecayWasFound = true; + ++reconstructableDecayWasFound; if (m_save_dst) { fillDecayNode(topNode, decayChain); @@ -447,7 +455,7 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) if (!m_genevt) { std::cout << "DecayFinder: Missing node PHHepMCGenEvent" << std::endl; - return false; + continue; } HepMC::GenEvent* theEvent = m_genevt->getEvent(); @@ -455,13 +463,18 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) for (HepMC::GenEvent::particle_const_iterator p = theEvent->particles_begin(); p != theEvent->particles_end(); ++p) { int this_pid = m_getChargeConjugate ? abs((*p)->pdg_id()) : (*p)->pdg_id(); - if (this_pid == m_mother_ID) + if (this_pid == mother_id_to_match) { if (Verbosity() >= VERBOSITY_MAX) { std::cout << "parent->pdg_id(): " << (*p)->pdg_id() << std::endl; } + aTrackFailedPT = false; + aTrackFailedETA = false; + aMotherHasPhoton = false; + aMotherHasPi0 = false; + bool breakOut = false; correctMotherProducts.clear(); decayChain.clear(); @@ -502,7 +515,7 @@ bool DecayFinder::findDecay(PHCompositeNode* topNode) else { m_nCandReconstructable += 1; - reconstructableDecayWasFound = true; + ++reconstructableDecayWasFound; if (m_save_dst) { fillDecayNode(topNode, decayChain); diff --git a/offline/packages/decayfinder/DecayFinder.h b/offline/packages/decayfinder/DecayFinder.h index bd893546a1..3605733e9f 100644 --- a/offline/packages/decayfinder/DecayFinder.h +++ b/offline/packages/decayfinder/DecayFinder.h @@ -42,7 +42,7 @@ class DecayFinder : public SubsysReco int parseDecayDescriptor(); - bool findDecay(PHCompositeNode *topNode); + int findDecay(PHCompositeNode *topNode); bool findParticle(const std::string &particle); diff --git a/offline/packages/eventplaneinfo/EventPlaneCalibration.cc b/offline/packages/eventplaneinfo/EventPlaneCalibration.cc deleted file mode 100644 index 5e5fb01264..0000000000 --- a/offline/packages/eventplaneinfo/EventPlaneCalibration.cc +++ /dev/null @@ -1,840 +0,0 @@ -#include "EventPlaneCalibration.h" - -#include "Eventplaneinfo.h" -#include "EventplaneinfoMap.h" -#include "EventplaneinfoMapv1.h" -#include "Eventplaneinfov1.h" - -#include -#include -#include - -//#include - -//#include - -#include - -#include -#include -#include - -#include -#include - -#include -#include - -#include - -#include -#include // for SubsysReco - -#include -#include -#include // for PHNode -#include -#include // for PHObject -#include -#include // for PHWHERE -#include - -#include -#include - -#include -#include -#include -#include // for exit -#include -#include -#include // for _Rb_tree_const_iterator -#include // for pair -#include // for vector - -EventPlaneCalibration::EventPlaneCalibration(const std::string &name) : SubsysReco(name) { - south_q.resize(m_MaxOrder); - north_q.resize(m_MaxOrder); - northsouth_q.resize(m_MaxOrder); - south_q_subtract.resize(m_MaxOrder); - north_q_subtract.resize(m_MaxOrder); - northsouth_q_subtract.resize(m_MaxOrder); - shift_north.resize(m_MaxOrder); - shift_south.resize(m_MaxOrder); - shift_northsouth.resize(m_MaxOrder); - tmp_south_psi.resize(m_MaxOrder); - tmp_north_psi.resize(m_MaxOrder); - tmp_northsouth_psi.resize(m_MaxOrder); - - for (auto &vec : south_q) { - vec.resize(2); - } - - for (auto &vec : north_q) { - vec.resize(2); - } - - for (auto &vec : northsouth_q) { - vec.resize(2); - } - - for (auto &vec : south_q_subtract) { - vec.resize(2); - } - - for (auto &vec : north_q_subtract) { - vec.resize(2); - } - - for (auto &vec : northsouth_q_subtract) { - vec.resize(2); - } -} - -int EventPlaneCalibration::InitRun(PHCompositeNode *topNode) { - - if (_isSim) { - m_runNo = 0; - } - if (!_default_calib) { - recoConsts *rc = recoConsts::instance(); - m_runNo = rc->get_IntFlag("RUNNUMBER"); - } - - if (Verbosity() > 0) { - std::cout << "======================= EventPlaneCalibration:InitRun() " - "=======================" - << std::endl; - std::cout << PHWHERE << "RUNNUMBER " << m_runNo << std::endl; - } - - if (OutFileName.empty()) - { - OutFileName = std::format("eventplane_correction_histograms_run_{}.root",m_runNo); - } - cdbhistosOut = new CDBHistos(OutFileName); - - //-----------------------------------load calibration - //histograms-----------------------------------------// - // Create and register recentering histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - - tprof_mean_cos_south_epd[order] = new TProfile2D( - std::format("tprof_mean_cos_south_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_mean_sin_south_epd[order] = new TProfile2D( - std::format("tprof_mean_sin_south_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_mean_cos_north_epd[order] = new TProfile2D( - std::format("tprof_mean_cos_north_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_mean_sin_north_epd[order] = new TProfile2D( - std::format("tprof_mean_sin_north_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - - tprof_mean_cos_northsouth_epd[order] = new TProfile2D( - std::format("tprof_mean_cos_northsouth_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_mean_sin_northsouth_epd[order] = new TProfile2D( - std::format("tprof_mean_sin_northsouth_epd_order_{}", order).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - - cdbhistosOut->registerHisto(tprof_mean_cos_south_epd[order]); - cdbhistosOut->registerHisto(tprof_mean_sin_south_epd[order]); - cdbhistosOut->registerHisto(tprof_mean_cos_north_epd[order]); - cdbhistosOut->registerHisto(tprof_mean_sin_north_epd[order]); - cdbhistosOut->registerHisto(tprof_mean_cos_northsouth_epd[order]); - cdbhistosOut->registerHisto(tprof_mean_sin_northsouth_epd[order]); - } - - CDBHistos *cdbhistosIn = new CDBHistos(OutFileName); - cdbhistosIn->LoadCalibrations(); - - // Create and register shifting histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - for (int p = 0; p < _imax; p++) { - tprof_cos_north_epd_shift[order][p] = new TProfile2D( - std::format("tprof_cos_north_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_sin_north_epd_shift[order][p] = new TProfile2D( - std::format("tprof_sin_north_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_cos_south_epd_shift[order][p] = new TProfile2D( - std::format("tprof_cos_south_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_sin_south_epd_shift[order][p] = new TProfile2D( - std::format("tprof_sin_south_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - - tprof_cos_northsouth_epd_shift[order][p] = new TProfile2D( - std::format("tprof_cos_northsouth_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - tprof_sin_northsouth_epd_shift[order][p] = new TProfile2D( - std::format("tprof_sin_northsouth_epd_shift_order_{}_{}", order, p).c_str(), - "", 125 * 40, 0, 25000, 20, -100, 100, -1e10, 1e10); - - cdbhistosOut->registerHisto(tprof_cos_north_epd_shift[order][p]); - cdbhistosOut->registerHisto(tprof_sin_north_epd_shift[order][p]); - cdbhistosOut->registerHisto(tprof_cos_south_epd_shift[order][p]); - cdbhistosOut->registerHisto(tprof_sin_south_epd_shift[order][p]); - cdbhistosOut->registerHisto(tprof_cos_northsouth_epd_shift[order][p]); - cdbhistosOut->registerHisto(tprof_sin_northsouth_epd_shift[order][p]); - } - } - - // Get recentering histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - tprof_mean_cos_south_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_south_epd_order_{}", order), false)); - tprof_mean_sin_south_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_south_epd_order_{}", order), false)); - tprof_mean_cos_north_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_north_epd_order_{}", order), false)); - tprof_mean_sin_north_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_north_epd_order_{}", order), false)); - tprof_mean_cos_northsouth_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_northsouth_epd_order_{}", order), - false)); - tprof_mean_sin_northsouth_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_northsouth_epd_order_{}", order), - false)); - } - - // Get shifting histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - for (int p = 0; p < _imax; p++) { - tprof_cos_north_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_north_epd_shift_order_{}_{}", order, p), - false)); - tprof_sin_north_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_north_epd_shift_order_{}_{}", order, p), - false)); - tprof_cos_south_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_south_epd_shift_order_{}_{}", order, p), - false)); - tprof_sin_south_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_south_epd_shift_order_{}_{}", order, p), - false)); - tprof_cos_northsouth_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_northsouth_epd_shift_order_{}_{}", order, - p), - false)); - tprof_sin_northsouth_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_northsouth_epd_shift_order_{}_{}", order, - p), - false)); - } - } - - cdbhistosIn->Print(); - - return CreateNodes(topNode); -} - -int EventPlaneCalibration::process_event(PHCompositeNode *topNode) { - if (Verbosity() > 1) { - std::cout << "EventPlaneCalibration::process_event -- entered" << std::endl; - } - - //--------------------------------- - // Get Objects off of the Node Tree - //--------------------------------- - - MbdVertexMap *mbdvtxmap = - findNode::getClass(topNode, "MbdVertexMap"); - if (!mbdvtxmap) { - std::cout << PHWHERE << "::ERROR - cannot find MbdVertexMap" << std::endl; - exit(-1); - } - - MbdVertex *mvertex = nullptr; - if (mbdvtxmap) { - for (MbdVertexMap::ConstIter mbditer = mbdvtxmap->begin(); - mbditer != mbdvtxmap->end(); ++mbditer) { - mvertex = mbditer->second; - } - if (mvertex) { - _mbdvtx = mvertex->get_z(); - } - } - - EventplaneinfoMap *epmap = - findNode::getClass(topNode, "EventplaneinfoMap"); - if (!epmap) { - std::cout << PHWHERE << "::ERROR - cannot find EventplaneinfoMap" - << std::endl; - exit(-1); - } - - Gl1Packet *gl1PacketInfo = findNode::getClass(topNode, 14001); - if (!gl1PacketInfo) { - std::cout << PHWHERE << "GlobalQA::process_event: GL1Packet node is missing" - << std::endl; - } - - uint64_t triggervec = 0; - if (gl1PacketInfo) { - triggervec = gl1PacketInfo->getScaledVector(); - } - - if (_sepdEpReco) { - - TowerInfoContainer *epd_towerinfo = - findNode::getClass(topNode, "TOWERINFO_CALIB_SEPD"); - if (!epd_towerinfo) { - epd_towerinfo = findNode::getClass( - topNode, "TOWERINFO_CALIB_EPD"); - if (!epd_towerinfo) { - std::cout << PHWHERE - << "::ERROR - cannot find sEPD Calibrated TowerInfoContainer" - << std::endl; - exit(-1); - } - } - - EpdGeom *_epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); - if (!_epdgeom) { - std::cout << PHWHERE << "::ERROR - cannot find TOWERGEOM_EPD" - << std::endl; - exit(-1); - } - - ResetMe(); - - if ((triggervec >> 0xAU) & 0x1U) { - - if ((std::fabs(_mbdvtx) < _mbd_vertex_cut)) { - - unsigned int ntowers = epd_towerinfo->size(); - for (unsigned int ch = 0; ch < ntowers; ch++) { - TowerInfo *_tower = epd_towerinfo->get_tower_at_channel(ch); - float epd_e = _tower->get_energy(); - bool isZS = _tower->get_isZS(); - if (!isZS) // exclude ZS - { - unsigned int key = TowerInfoDefs::encode_epd(ch); - int arm = TowerInfoDefs::get_epd_arm(key); - if (arm == 0) { - _ssum += epd_e; - } else if (arm == 1) { - _nsum += epd_e; - } - } - } - - if (_ssum > _epd_charge_min && _nsum > _epd_charge_min && - _ssum < _epd_charge_max && _nsum < _epd_charge_max) { - _do_ep = true; - } - - if (_do_ep) { - for (unsigned int ch = 0; ch < ntowers; ch++) { - TowerInfo *_tower = epd_towerinfo->get_tower_at_channel(ch); - float epd_e = _tower->get_energy(); - bool isZS = _tower->get_isZS(); - if (!isZS) // exclude ZS - { - if (epd_e < 0.2) // expecting Nmips - { - continue; - } - unsigned int key = TowerInfoDefs::encode_epd(ch); - float tile_phi = _epdgeom->get_phi(key); - int arm = TowerInfoDefs::get_epd_arm(key); - float truncated_e = - (epd_e < _epd_e) ? epd_e : _epd_e; // set cutoff at _epd_e - if (arm == 0) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(tile_phi * (double)(order + 1)); - double Sine = sin(tile_phi * (double)(order + 1)); - south_q[order][0] += truncated_e * Cosine; // south Qn,x - south_q[order][1] += truncated_e * Sine; // south Qn,y - } - } else if (arm == 1) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(tile_phi * (double)(order + 1)); - double Sine = sin(tile_phi * (double)(order + 1)); - north_q[order][0] += truncated_e * Cosine; // north Qn,x - north_q[order][1] += truncated_e * Sine; // north Qn,y - } - } - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(tile_phi * (double)(order + 1)); - double Sine = sin(tile_phi * (double)(order + 1)); - northsouth_q[order][0] += - truncated_e * Cosine; // northsouth Qn,x - northsouth_q[order][1] += truncated_e * Sine; // northsouth Qn,y - } - } - } - - _totalcharge = _nsum + _ssum; - - // Filled during first run - for (unsigned int order = 0; order < m_MaxOrder; order++) { - // Fill recentering histograms by order - tprof_mean_cos_south_epd[order]->Fill(_ssum, _mbdvtx, - south_q[order][0] / _ssum); - tprof_mean_sin_south_epd[order]->Fill(_ssum, _mbdvtx, - south_q[order][1] / _ssum); - tprof_mean_cos_north_epd[order]->Fill(_nsum, _mbdvtx, - north_q[order][0] / _nsum); - tprof_mean_sin_north_epd[order]->Fill(_nsum, _mbdvtx, - north_q[order][1] / _nsum); - tprof_mean_cos_northsouth_epd[order]->Fill( - _totalcharge, _mbdvtx, northsouth_q[order][0] / _totalcharge); - tprof_mean_sin_northsouth_epd[order]->Fill( - _totalcharge, _mbdvtx, northsouth_q[order][1] / _totalcharge); - } - - // Get recentering histograms and do recentering - // Recentering: subtract Qn,x and Qn,y values averaged over all events - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_mean_cos_south_epd_input[order]) // check if recentering - // histograms exist - { - - // south - TAxis *south_xaxis = - tprof_mean_cos_south_epd_input[order]->GetXaxis(); - TAxis *south_yaxis = - tprof_mean_cos_south_epd_input[order]->GetYaxis(); - int xbin_south = south_xaxis->FindBin(_ssum); - int ybin_south = south_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_south = - tprof_mean_cos_south_epd_input[order]->GetBinContent( - xbin_south, ybin_south); - double event_ave_sin_south = - tprof_mean_sin_south_epd_input[order]->GetBinContent( - xbin_south, ybin_south); - south_q_subtract[order][0] = _ssum * event_ave_cos_south; - south_q_subtract[order][1] = _ssum * event_ave_sin_south; - south_q[order][0] -= south_q_subtract[order][0]; - south_q[order][1] -= south_q_subtract[order][1]; - - // north - TAxis *north_xaxis = - tprof_mean_cos_north_epd_input[order]->GetXaxis(); - TAxis *north_yaxis = - tprof_mean_cos_north_epd_input[order]->GetYaxis(); - int xbin_north = north_xaxis->FindBin(_nsum); - int ybin_north = north_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_north = - tprof_mean_cos_north_epd_input[order]->GetBinContent( - xbin_north, ybin_north); - double event_ave_sin_north = - tprof_mean_sin_north_epd_input[order]->GetBinContent( - xbin_north, ybin_north); - north_q_subtract[order][0] = _nsum * event_ave_cos_north; - north_q_subtract[order][1] = _nsum * event_ave_sin_north; - north_q[order][0] -= north_q_subtract[order][0]; - north_q[order][1] -= north_q_subtract[order][1]; - - // northsouth - TAxis *northsouth_xaxis = - tprof_mean_cos_northsouth_epd_input[order]->GetXaxis(); - TAxis *northsouth_yaxis = - tprof_mean_cos_northsouth_epd_input[order]->GetYaxis(); - int xbin_northsouth = northsouth_xaxis->FindBin(_totalcharge); - int ybin_northsouth = northsouth_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_northsouth = - tprof_mean_cos_northsouth_epd_input[order]->GetBinContent( - xbin_northsouth, ybin_northsouth); - double event_ave_sin_northsouth = - tprof_mean_sin_northsouth_epd_input[order]->GetBinContent( - xbin_northsouth, ybin_northsouth); - northsouth_q_subtract[order][0] = - _totalcharge * event_ave_cos_northsouth; - northsouth_q_subtract[order][1] = - _totalcharge * event_ave_sin_northsouth; - northsouth_q[order][0] -= northsouth_q_subtract[order][0]; - northsouth_q[order][1] -= northsouth_q_subtract[order][1]; - } - } - - // Get recentered psi_n - Eventplaneinfo *epinfo = new Eventplaneinfov1(); - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double n = order + 1.0; - if (tprof_mean_cos_south_epd_input[order]) // if present, Qs are - // recentered - { - tmp_south_psi[order] = - epinfo->GetPsi(south_q[order][0], south_q[order][1], n); - tmp_north_psi[order] = - epinfo->GetPsi(north_q[order][0], north_q[order][1], n); - tmp_northsouth_psi[order] = epinfo->GetPsi( - northsouth_q[order][0], northsouth_q[order][1], n); - } else { - tmp_south_psi[order] = NAN; - tmp_north_psi[order] = NAN; - tmp_northsouth_psi[order] = NAN; - } - } - - // Filled during second run - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_mean_cos_south_epd_input[order]) // if present, Qs are - // recentered - { - // Fill shifting histograms by order and terms - for (int p = 0; p < _imax; p++) { - double terms = p + 1.0; - double n = order + 1.0; - double tmp = (n * terms); - - tprof_cos_south_epd_shift[order][p]->Fill( - _ssum, _mbdvtx, - cos(tmp * tmp_south_psi[order])); // south - tprof_sin_south_epd_shift[order][p]->Fill( - _ssum, _mbdvtx, - sin(tmp * tmp_south_psi[order])); // south - tprof_cos_north_epd_shift[order][p]->Fill( - _nsum, _mbdvtx, - cos(tmp * tmp_north_psi[order])); // north - tprof_sin_north_epd_shift[order][p]->Fill( - _nsum, _mbdvtx, - sin(tmp * tmp_north_psi[order])); // north - tprof_cos_northsouth_epd_shift[order][p]->Fill( - _totalcharge, _mbdvtx, - cos(tmp * tmp_northsouth_psi[order])); // northsouth - // - tprof_sin_northsouth_epd_shift[order][p]->Fill( - _totalcharge, _mbdvtx, - sin(tmp * tmp_northsouth_psi[order])); // northsouth - // - } - } - } - - // Get shifting histograms and calculate shift - for (unsigned int order = 0; order < m_MaxOrder; order++) { - for (int p = 0; p < _imax; p++) { - if (tprof_cos_south_epd_shift_input[order] - [p]) // check if shifting - // histograms exist - { - double terms = p + 1.0; - double n = order + 1.0; - double tmp = (n * terms); - double prefactor = 2.0 / terms; - - // south - TAxis *south_xaxis = - tprof_cos_south_epd_shift_input[order][p]->GetXaxis(); - TAxis *south_yaxis = - tprof_cos_south_epd_shift_input[order][p]->GetYaxis(); - int xbin_south = south_xaxis->FindBin(_ssum); - int ybin_south = south_yaxis->FindBin(_mbdvtx); - - // north - TAxis *north_xaxis = - tprof_cos_north_epd_shift_input[order][p]->GetXaxis(); - TAxis *north_yaxis = - tprof_cos_north_epd_shift_input[order][p]->GetYaxis(); - int xbin_north = north_xaxis->FindBin(_nsum); - int ybin_north = north_yaxis->FindBin(_mbdvtx); - - // // northsouth - TAxis *northsouth_xaxis = - tprof_cos_northsouth_epd_shift_input[order][p]->GetXaxis(); - TAxis *northsouth_yaxis = - tprof_cos_northsouth_epd_shift_input[order][p]->GetYaxis(); - int xbin_northsouth = northsouth_xaxis->FindBin(_totalcharge); - int ybin_northsouth = northsouth_yaxis->FindBin(_mbdvtx); - - // Equation (6) of arxiv:nucl-ex/9805001 - // i = terms; n = order; i*n = tmp - // (2 / i ) * * - // sin(i*n*psi_n) - * - // cos(i*n*psi_n) - - // north - shift_north[order] += - prefactor * - (tprof_cos_north_epd_shift_input[order][p]->GetBinContent( - xbin_north, ybin_north) * - sin(tmp * tmp_north_psi[order]) - - tprof_sin_north_epd_shift_input[order][p]->GetBinContent( - xbin_north, ybin_north) * - cos(tmp * tmp_north_psi[order])); - - // south - shift_south[order] += - prefactor * - (tprof_cos_south_epd_shift_input[order][p]->GetBinContent( - xbin_south, ybin_south) * - sin(tmp * tmp_south_psi[order]) - - tprof_sin_south_epd_shift_input[order][p]->GetBinContent( - xbin_south, ybin_south) * - cos(tmp * tmp_south_psi[order])); - - // // northsouth - shift_northsouth[order] += - prefactor * - (tprof_cos_northsouth_epd_shift_input[order][p] - ->GetBinContent(xbin_northsouth, ybin_northsouth) * - sin(tmp * tmp_northsouth_psi[order]) - - tprof_sin_northsouth_epd_shift_input[order][p] - ->GetBinContent(xbin_northsouth, ybin_northsouth) * - cos(tmp * tmp_northsouth_psi[order])); - } - } - } - - // n * deltapsi_n = (2 / i ) * * sin(i*n*psi_n) - - // * cos(i*n*psi_n) Divide out n - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double n = order + 1.0; - shift_north[order] /= n; - shift_south[order] /= n; - shift_northsouth[order] /= n; - } - - // Now add shift to psi_n to flatten it - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_cos_north_epd_shift_input[0][0]) { - tmp_south_psi[order] += shift_south[order]; - tmp_north_psi[order] += shift_north[order]; - tmp_northsouth_psi[order] += shift_northsouth[order]; - } - } - - // Now enforce the range - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_cos_north_epd_shift_input[0][0]) { - double range = M_PI / (double)(order + 1); - if (tmp_south_psi[order] < -1.0 * range) { - tmp_south_psi[order] += 2.0 * range; - } - if (tmp_south_psi[order] > range) { - tmp_south_psi[order] -= 2.0 * range; - } - if (tmp_north_psi[order] < -1.0 * range) { - tmp_north_psi[order] += 2.0 * range; - } - if (tmp_north_psi[order] > range) { - tmp_north_psi[order] -= 2.0 * range; - } - if (tmp_northsouth_psi[order] < -1.0 * range) { - tmp_northsouth_psi[order] += 2.0 * range; - } - if (tmp_northsouth_psi[order] > range) { - tmp_northsouth_psi[order] -= 2.0 * range; - } - } - } - - for (unsigned int order = 0; order < m_MaxOrder; order++) { - south_Qvec.emplace_back(south_q[order][0], south_q[order][1]); - north_Qvec.emplace_back(north_q[order][0], north_q[order][1]); - northsouth_Qvec.emplace_back(northsouth_q[order][0], - northsouth_q[order][1]); - } - - if (epd_towerinfo) { - Eventplaneinfo *sepds = new Eventplaneinfov1(); - sepds->set_qvector(south_Qvec); - sepds->set_shifted_psi(tmp_south_psi); - epmap->insert(sepds, EventplaneinfoMap::sEPDS); - - Eventplaneinfo *sepdn = new Eventplaneinfov1(); - sepdn->set_qvector(north_Qvec); - sepdn->set_shifted_psi(tmp_north_psi); - epmap->insert(sepdn, EventplaneinfoMap::sEPDN); - - Eventplaneinfo *sepdns = new Eventplaneinfov1(); - sepdns->set_qvector(northsouth_Qvec); - sepdns->set_shifted_psi(tmp_northsouth_psi); - epmap->insert(sepdns, EventplaneinfoMap::sEPDNS); - - if (Verbosity() > 1) { - sepds->identify(); - sepdn->identify(); - sepdns->identify(); - } - } - } - } - } - } - - if (_mbdEpReco) { - ResetMe(); - - MbdPmtContainer *mbdpmts = - findNode::getClass(topNode, "MbdPmtContainer"); - if (!mbdpmts) { - std::cout << PHWHERE << "::ERROR - cannot find MbdPmtContainer" - << std::endl; - exit(-1); - } - - MbdGeom *mbdgeom = findNode::getClass(topNode, "MbdGeom"); - if (!mbdgeom) { - std::cout << PHWHERE << "::ERROR - cannot find MbdGeom" << std::endl; - exit(-1); - } - - if (mbdpmts) { - if (Verbosity()) { - std::cout << "EventPlaneCalibration::process_event - mbdpmts" << std::endl; - } - - for (int ipmt = 0; ipmt < mbdpmts->get_npmt(); ipmt++) { - float mbd_q = mbdpmts->get_pmt(ipmt)->get_q(); - _mbdQ += mbd_q; - } - - for (int ipmt = 0; ipmt < mbdpmts->get_npmt(); ipmt++) { - float mbd_q = mbdpmts->get_pmt(ipmt)->get_q(); - float phi = mbdgeom->get_phi(ipmt); - int arm = mbdgeom->get_arm(ipmt); - - if (_mbdQ < _mbd_e) { - continue; - } - - if (arm == 0) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(phi * (double)(order + 1)); - double Sine = sin(phi * (double)(order + 1)); - south_q[order][0] += mbd_q * Cosine; // south Qn,x - south_q[order][1] += mbd_q * Sine; // south Qn,y - } - } else if (arm == 1) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(phi * (double)(order + 1)); - double Sine = sin(phi * (double)(order + 1)); - north_q[order][0] += mbd_q * Cosine; // north Qn,x - north_q[order][1] += mbd_q * Sine; // north Qn,y - } - } - } - } - - for (unsigned int order = 0; order < m_MaxOrder; order++) { - south_Qvec.emplace_back(south_q[order][0], south_q[order][1]); - north_Qvec.emplace_back(north_q[order][0], north_q[order][1]); - } - - if (mbdpmts) { - Eventplaneinfo *mbds = new Eventplaneinfov1(); - mbds->set_qvector(south_Qvec); - epmap->insert(mbds, EventplaneinfoMap::MBDS); - - Eventplaneinfo *mbdn = new Eventplaneinfov1(); - mbdn->set_qvector(north_Qvec); - epmap->insert(mbdn, EventplaneinfoMap::MBDN); - - if (Verbosity() > 1) { - mbds->identify(); - mbdn->identify(); - } - } - - ResetMe(); - } - - if (Verbosity()) { - epmap->identify(); - } - - return Fun4AllReturnCodes::EVENT_OK; -} - -int EventPlaneCalibration::CreateNodes(PHCompositeNode *topNode) { - PHNodeIterator iter(topNode); - - PHCompositeNode *dstNode = - dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) { - std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } - - PHCompositeNode *globalNode = dynamic_cast( - iter.findFirst("PHCompositeNode", "GLOBAL")); - if (!globalNode) { - globalNode = new PHCompositeNode("GLOBAL"); - dstNode->addNode(globalNode); - } - - EventplaneinfoMap *eps = - findNode::getClass(topNode, "EventplaneinfoMap"); - if (!eps) { - eps = new EventplaneinfoMapv1(); - PHIODataNode *EpMapNode = - new PHIODataNode(eps, "EventplaneinfoMap", "PHObject"); - globalNode->addNode(EpMapNode); - } - return Fun4AllReturnCodes::EVENT_OK; -} - -void EventPlaneCalibration::ResetMe() { - for (auto &vec : south_q) { - std::fill(vec.begin(), vec.end(), 0.); - } - - for (auto &vec : north_q) { - std::fill(vec.begin(), vec.end(), 0.); - } - - for (auto &vec : northsouth_q) { - std::fill(vec.begin(), vec.end(), 0.); - } - - south_Qvec.clear(); - north_Qvec.clear(); - northsouth_Qvec.clear(); - - for (auto &vec : south_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); - } - - for (auto &vec : north_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); - } - - for (auto &vec : northsouth_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); - } - - std::fill(shift_north.begin(), shift_north.end(), 0.); - std::fill(shift_south.begin(), shift_south.end(), 0.); - std::fill(shift_northsouth.begin(), shift_northsouth.end(), 0.); - - std::fill(tmp_south_psi.begin(), tmp_south_psi.end(), NAN); - std::fill(tmp_north_psi.begin(), tmp_north_psi.end(), NAN); - std::fill(tmp_northsouth_psi.begin(), tmp_northsouth_psi.end(), NAN); - - _nsum = 0.; - _ssum = 0.; - _do_ep = false; - _mbdQ = 0.; - _totalcharge = 0.; -} - -int EventPlaneCalibration::End(PHCompositeNode * /*topNode*/) { - - cdbhistosOut->WriteCDBHistos(); - delete cdbhistosOut; - - std::cout << " EventPlaneCalibration::End() " << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} diff --git a/offline/packages/eventplaneinfo/EventPlaneCalibration.h b/offline/packages/eventplaneinfo/EventPlaneCalibration.h deleted file mode 100644 index 94875c08d2..0000000000 --- a/offline/packages/eventplaneinfo/EventPlaneCalibration.h +++ /dev/null @@ -1,121 +0,0 @@ -// Tell emacs that this is a C++ source -// -*- C++ -*-. -#ifndef EVENTPLANEINFO_EVENTPLANECALIBRATION_H -#define EVENTPLANEINFO_EVENTPLANECALIBRATION_H - -//=========================================================== -/// \author Ejiro Umaka -//=========================================================== - -#include - -#include // for string -#include // for vector - -class CDBHistos; -class TProfile2D; - -class PHCompositeNode; - -class EventPlaneCalibration : public SubsysReco { -public: - EventPlaneCalibration(const std::string &name = "EventPlaneCalibration"); - ~EventPlaneCalibration() override = default; - int InitRun(PHCompositeNode *topNode) override; - int process_event(PHCompositeNode *topNode) override; - int End(PHCompositeNode * /*topNode*/) override; - - void ResetMe(); - void set_sepd_epreco(bool sepdEpReco) { _sepdEpReco = sepdEpReco; } - void set_default_calibfile(bool default_calib) { - _default_calib = default_calib; - } - void set_mbd_epreco(bool mbdEpReco) { _mbdEpReco = mbdEpReco; } - void set_isSim(bool isSim) { _isSim = isSim; } - void set_sEPD_Mip_cut(const float e) { _epd_e = e; } - void set_sEPD_Charge_cut(const float c) { _epd_charge_min = c; } - void set_MBD_Min_Qcut(const float f) { _mbd_e = f; } - void set_MBD_Vetex_cut(const float v) { _mbd_vertex_cut = v; } - void set_Ep_orders(const unsigned int n) { m_MaxOrder = n; } - void set_outfilename(const std::string &name) {OutFileName = name;} - -private: - int CreateNodes(PHCompositeNode *topNode); - unsigned int m_MaxOrder{3}; - int m_runNo{0}; - std::string OutFileName; - CDBHistos *cdbhistosOut{nullptr}; - - std::vector> south_q; - std::vector> north_q; - std::vector> northsouth_q; - - std::vector> south_Qvec; - std::vector> north_Qvec; - std::vector> northsouth_Qvec; - - // recentering utility - std::vector> south_q_subtract; - std::vector> north_q_subtract; - std::vector> northsouth_q_subtract; - - // shifting utility - std::vector shift_north; - std::vector shift_south; - std::vector shift_northsouth; - std::vector tmp_south_psi; - std::vector tmp_north_psi; - std::vector tmp_northsouth_psi; - - // recentering histograms - - TProfile2D *tprof_mean_cos_north_epd[6]{}; - TProfile2D *tprof_mean_sin_north_epd[6]{}; - TProfile2D *tprof_mean_cos_south_epd[6]{}; - TProfile2D *tprof_mean_sin_south_epd[6]{}; - TProfile2D *tprof_mean_cos_northsouth_epd[6]{}; - TProfile2D *tprof_mean_sin_northsouth_epd[6]{}; - - TProfile2D *tprof_mean_cos_north_epd_input[6]{}; - TProfile2D *tprof_mean_sin_north_epd_input[6]{}; - TProfile2D *tprof_mean_cos_south_epd_input[6]{}; - TProfile2D *tprof_mean_sin_south_epd_input[6]{}; - TProfile2D *tprof_mean_cos_northsouth_epd_input[6]{}; - TProfile2D *tprof_mean_sin_northsouth_epd_input[6]{}; - - // shifting histograms - const int _imax{12}; - - TProfile2D *tprof_cos_north_epd_shift[6][12]{}; - TProfile2D *tprof_sin_north_epd_shift[6][12]{}; - TProfile2D *tprof_cos_south_epd_shift[6][12]{}; - TProfile2D *tprof_sin_south_epd_shift[6][12]{}; - TProfile2D *tprof_cos_northsouth_epd_shift[6][12]{}; - TProfile2D *tprof_sin_northsouth_epd_shift[6][12]{}; - - TProfile2D *tprof_cos_north_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_north_epd_shift_input[6][12]{}; - TProfile2D *tprof_cos_south_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_south_epd_shift_input[6][12]{}; - TProfile2D *tprof_cos_northsouth_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_northsouth_epd_shift_input[6][12]{}; - - bool _mbdEpReco{false}; - bool _sepdEpReco{false}; - bool _isSim{false}; - bool _do_ep{false}; - bool _default_calib{false}; - - float _nsum{0.0}; - float _ssum{0.0}; - float _mbdvtx{999.0}; - float _epd_charge_min{5.0}; - float _epd_charge_max{10000.0}; - float _epd_e{10.0}; - float _mbd_e{10.0}; - float _mbdQ{0.0}; - double _totalcharge{0.0}; - float _mbd_vertex_cut{60.0}; -}; - -#endif // EVENTPLANEINFO_EVENTPLANECALIBRATION_H diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.cc b/offline/packages/eventplaneinfo/EventPlaneReco.cc index f0c9f73dd4..bfd68cb4ca 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.cc +++ b/offline/packages/eventplaneinfo/EventPlaneReco.cc @@ -1,803 +1,683 @@ #include "EventPlaneReco.h" -#include "Eventplaneinfo.h" -#include "EventplaneinfoMap.h" #include "EventplaneinfoMapv1.h" -#include "Eventplaneinfov1.h" +#include "Eventplaneinfov2.h" #include #include #include +// -- Centrality +#include + +// -- sEPD #include -#include -#include -#include -#include +#include // for CDBTTree -#include -#include -#include -#include +// -- event +#include -#include -#include #include #include -#include // for SubsysReco -#include -#include -#include // for PHNode -#include -#include // for PHObject #include -#include // for PHWHERE -#include - -#include +#include +#include -#include // for array -#include -#include -#include // for exit -#include +// c++ includes -- #include -#include // for _Rb_tree_const_iterator -#include // for pair -#include // for vector - -EventPlaneReco::EventPlaneReco(const std::string &name) : SubsysReco(name) { - - south_q.resize(m_MaxOrder); - north_q.resize(m_MaxOrder); - northsouth_q.resize(m_MaxOrder); +#include +#include +#include - south_q_subtract.resize(m_MaxOrder); - north_q_subtract.resize(m_MaxOrder); - northsouth_q_subtract.resize(m_MaxOrder); +//____________________________________________________________________________.. +EventPlaneReco::EventPlaneReco(const std::string &name): + SubsysReco(name) +{ +} - shift_north.resize(m_MaxOrder); - shift_south.resize(m_MaxOrder); - shift_northsouth.resize(m_MaxOrder); - tmp_south_psi.resize(m_MaxOrder); - tmp_north_psi.resize(m_MaxOrder); - tmp_northsouth_psi.resize(m_MaxOrder); +//____________________________________________________________________________.. +int EventPlaneReco::Init(PHCompositeNode *topNode) +{ + std::string calibdir = CDBInterface::instance()->getUrl(m_calibName); - for (auto &vec : south_q) { - vec.resize(2); + if (!m_directURL_EventPlaneCalib.empty()) + { + m_cdbttree = new CDBTTree(m_directURL_EventPlaneCalib); + std::cout << PHWHERE << " Custom Event Plane Calib Found: " << m_directURL_EventPlaneCalib << std::endl; } - - for (auto &vec : north_q) { - vec.resize(2); + else if (!calibdir.empty()) + { + m_cdbttree = new CDBTTree(calibdir); + std::cout << PHWHERE << " Event Plane Calib Found: " << calibdir << std::endl; } - - for (auto &vec : northsouth_q) { - vec.resize(2); + else if (m_doAbortNoEventPlaneCalib) + { + std::cout << PHWHERE << " Error: No Event Plane Calib Found and m_doAbortNoEventPlaneCalib is true. Aborting." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + else + { + std::cout << PHWHERE << " Error: No Event Plane Calib Found. Skipping Event Plane Calibrations." << std::endl; + m_doNotCalib = true; } - for (auto &vec : south_q_subtract) { - vec.resize(2); + if (!m_doNotCalib) + { + LoadCalib(); } - for (auto &vec : north_q_subtract) { - vec.resize(2); + if (Verbosity() > 0) + { + print_correction_data(); } - for (auto &vec : northsouth_q_subtract) { - vec.resize(2); + return CreateNodes(topNode); +} + +int EventPlaneReco::InitRun(PHCompositeNode* topNode) +{ + EpdGeom* epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); + if (!epdgeom) + { + std::cout << PHWHERE << " Error: TOWERGEOM_EPD is missing. Cannot build trig cache." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; } - ring_q_north.resize(nRings); - ring_q_south.resize(nRings); + m_trig_cache.assign(m_harmonics.size(), std::vector>(SEPD_CHANNELS)); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + for (int channel = 0; channel < SEPD_CHANNELS; ++channel) + { + unsigned int key = TowerInfoDefs::encode_epd(channel); + double phi = epdgeom->get_phi(key); - for (auto &rq : ring_q_north) { - rq.resize(m_MaxOrder, std::vector(2, 0.0)); + m_trig_cache[h_idx][channel] = {std::cos(n * phi), std::sin(n * phi)}; + } } - for (auto &rq : ring_q_south) { - rq.resize(m_MaxOrder, std::vector(2, 0.0)); + + if (Verbosity() > 0) + { + std::cout << PHWHERE << " Trigonometry cache initialized for " << SEPD_CHANNELS << " sEPD channels." << std::endl; } - all_ring_Qvecs_north.assign( - nRings, std::vector>(m_MaxOrder, {0.0, 0.0})); + return Fun4AllReturnCodes::EVENT_OK; +} - all_ring_Qvecs_south.assign( - nRings, std::vector>(m_MaxOrder, {0.0, 0.0})); +std::array, 2> EventPlaneReco::calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label) +{ + std::array, 2> mat{}; + + double D_arg = (xx * yy) - (xy * xy); + if (D_arg <= 0) + { + std::cout << PHWHERE << "Invalid D-term " << D_arg << " for n=" << n << ", cent bin=" << cent_bin << ", det=" << det_label << std::endl; + // Return Identity Matrix to preserve Recentered vector + mat[0][0] = 1.0; + mat[1][1] = 1.0; + return mat; + } + double D = std::sqrt(D_arg); + + double N_term = D * (xx + yy + (2 * D)); + if (N_term <= 0) + { + std::cout << PHWHERE << "Invalid N-term " << N_term << " for n=" << n << ", cent bin=" << cent_bin << ", det=" << det_label << std::endl; + // Return Identity Matrix to preserve Recentered vector + mat[0][0] = 1.0; + mat[1][1] = 1.0; + return mat; + } + double inv_sqrt_N = 1.0 / std::sqrt(N_term); + + mat[0][0] = inv_sqrt_N * (yy + D); + mat[0][1] = -inv_sqrt_N * xy; + mat[1][0] = mat[0][1]; + mat[1][1] = inv_sqrt_N * (xx + D); + return mat; } -int EventPlaneReco::InitRun(PHCompositeNode *topNode) { +//____________________________________________________________________________.. +void EventPlaneReco::LoadCalib() +{ + size_t south_idx = static_cast(Subdetector::S); + size_t north_idx = static_cast(Subdetector::N); + size_t ns_idx = static_cast(Subdetector::NS); - FileName = "EVENTPLANE_CORRECTION"; - if (_isSim) { - FileName = "EVENTPLANE_CORRECTION_SIM"; - } + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; - std::string calibdir = CDBInterface::instance()->getUrl(FileName); + std::string S_x_avg_name = std::format("Q_S_x_{}_avg", n); + std::string S_y_avg_name = std::format("Q_S_y_{}_avg", n); + std::string N_x_avg_name = std::format("Q_N_x_{}_avg", n); + std::string N_y_avg_name = std::format("Q_N_y_{}_avg", n); - if (calibdir.empty()) { - std::cout << PHWHERE << "No Eventplane calibration file for domain " - << FileName << " found" << std::endl; - std::cout << PHWHERE - << "Will only produce raw Q vectors and event plane angles " - << std::endl; - } - - CDBHistos *cdbhistosIn = new CDBHistos(calibdir); - cdbhistosIn->LoadCalibrations(); - - // Get phiweights - h_phi_weight_south_input = - dynamic_cast(cdbhistosIn->getHisto("h_phi_weight_south", false)); - h_phi_weight_north_input = - dynamic_cast(cdbhistosIn->getHisto("h_phi_weight_north", false)); - - // Get recentering histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - tprof_mean_cos_south_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_south_epd_order_{}", order), false)); - tprof_mean_sin_south_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_south_epd_order_{}", order), false)); - tprof_mean_cos_north_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_north_epd_order_{}", order), false)); - tprof_mean_sin_north_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_north_epd_order_{}", order), false)); - tprof_mean_cos_northsouth_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_cos_northsouth_epd_order_{}", order), - false)); - tprof_mean_sin_northsouth_epd_input[order] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_mean_sin_northsouth_epd_order_{}", order), - false)); - } - - // Get shifting histograms - for (unsigned int order = 0; order < m_MaxOrder; order++) { - for (int p = 0; p < _imax; p++) { - tprof_cos_north_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_north_epd_shift_order_{}_{}", order, p), - false)); - tprof_sin_north_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_north_epd_shift_order_{}_{}", order, p), - false)); - tprof_cos_south_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_south_epd_shift_order_{}_{}", order, p), - false)); - tprof_sin_south_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_south_epd_shift_order_{}_{}", order, p), - false)); - tprof_cos_northsouth_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_cos_northsouth_epd_shift_order_{}_{}", order, - p), - false)); - tprof_sin_northsouth_epd_shift_input[order][p] = - dynamic_cast(cdbhistosIn->getHisto( - std::format("tprof_sin_northsouth_epd_shift_order_{}_{}", order, - p), - false)); - } - } + std::string S_xx_avg_name = std::format("Q_S_xx_{}_avg", n); + std::string S_yy_avg_name = std::format("Q_S_yy_{}_avg", n); + std::string S_xy_avg_name = std::format("Q_S_xy_{}_avg", n); + std::string N_xx_avg_name = std::format("Q_N_xx_{}_avg", n); + std::string N_yy_avg_name = std::format("Q_N_yy_{}_avg", n); + std::string N_xy_avg_name = std::format("Q_N_xy_{}_avg", n); - if (Verbosity() > 1) { - cdbhistosIn->Print(); - } + std::string NS_xx_avg_name = std::format("Q_NS_xx_{}_avg", n); + std::string NS_yy_avg_name = std::format("Q_NS_yy_{}_avg", n); + std::string NS_xy_avg_name = std::format("Q_NS_xy_{}_avg", n); - return CreateNodes(topNode); -} + for (size_t cent_bin = 0; cent_bin < m_cent_bins; ++cent_bin) + { + int key = cent_bin; -int EventPlaneReco::process_event(PHCompositeNode *topNode) { - if (Verbosity() > 1) { - std::cout << "EventPlaneReco::process_event -- entered" << std::endl; - } + // South + auto& dataS = m_correction_data[h_idx][cent_bin][south_idx]; + dataS.avg_Q.x = m_cdbttree->GetDoubleValue(key, S_x_avg_name); + dataS.avg_Q.y = m_cdbttree->GetDoubleValue(key, S_y_avg_name); - //--------------------------------- - // Get Objects off of the Node Tree - //--------------------------------- + dataS.avg_Q_xx = m_cdbttree->GetDoubleValue(key, S_xx_avg_name); + dataS.avg_Q_yy = m_cdbttree->GetDoubleValue(key, S_yy_avg_name); + dataS.avg_Q_xy = m_cdbttree->GetDoubleValue(key, S_xy_avg_name); - if (_isSim) { - // Use GlobalVertexMap for simulation - GlobalVertexMap *vertexmap = - findNode::getClass(topNode, "GlobalVertexMap"); - if (!vertexmap) { - std::cout << PHWHERE << "::ERROR - cannot find GlobalVertexMap" - << std::endl; - exit(-1); - } + dataS.X_matrix = calculate_flattening_matrix(dataS.avg_Q_xx, dataS.avg_Q_yy, dataS.avg_Q_xy, n, cent_bin, "South"); - if (!vertexmap->empty()) { - GlobalVertex *vtx = vertexmap->begin()->second; - if (vtx) { - _mbdvtx = vtx->get_z(); - } - } - } else { - // Use MbdVertexMap for data - MbdVertexMap *mbdvtxmap = - findNode::getClass(topNode, "MbdVertexMap"); - if (!mbdvtxmap) { - std::cout << PHWHERE << "::ERROR - cannot find MbdVertexMap" << std::endl; - exit(-1); - } + // North + auto& dataN = m_correction_data[h_idx][cent_bin][north_idx]; + dataN.avg_Q.x = m_cdbttree->GetDoubleValue(key, N_x_avg_name); + dataN.avg_Q.y = m_cdbttree->GetDoubleValue(key, N_y_avg_name); - MbdVertex *mvertex = nullptr; - if (mbdvtxmap) { - for (MbdVertexMap::ConstIter mbditer = mbdvtxmap->begin(); - mbditer != mbdvtxmap->end(); ++mbditer) { - mvertex = mbditer->second; - } - if (mvertex) { - _mbdvtx = mvertex->get_z(); - } - } - } + dataN.avg_Q_xx = m_cdbttree->GetDoubleValue(key, N_xx_avg_name); + dataN.avg_Q_yy = m_cdbttree->GetDoubleValue(key, N_yy_avg_name); + dataN.avg_Q_xy = m_cdbttree->GetDoubleValue(key, N_xy_avg_name); - EventplaneinfoMap *epmap = - findNode::getClass(topNode, "EventplaneinfoMap"); - if (!epmap) { - std::cout << PHWHERE << "::ERROR - cannot find EventplaneinfoMap" - << std::endl; - exit(-1); - } + dataN.X_matrix = calculate_flattening_matrix(dataN.avg_Q_xx, dataN.avg_Q_yy, dataN.avg_Q_xy, n, cent_bin, "North"); - if (_sepdEpReco) { + // North South + // Note: We do NOT load avg_Q (x,y) for NS because NS is recentered by summing the recentered S and N vectors. + auto& dataNS = m_correction_data[h_idx][cent_bin][ns_idx]; - TowerInfoContainer *epd_towerinfo = - findNode::getClass(topNode, "TOWERINFO_CALIB_SEPD"); - if (!epd_towerinfo) { - epd_towerinfo = findNode::getClass( - topNode, "TOWERINFO_CALIB_EPD"); - if (!epd_towerinfo) { - std::cout << PHWHERE - << "::ERROR - cannot find sEPD Calibrated TowerInfoContainer" - << std::endl; - exit(-1); - } - } + dataNS.avg_Q_xx = m_cdbttree->GetDoubleValue(key, NS_xx_avg_name); + dataNS.avg_Q_yy = m_cdbttree->GetDoubleValue(key, NS_yy_avg_name); + dataNS.avg_Q_xy = m_cdbttree->GetDoubleValue(key, NS_xy_avg_name); - EpdGeom *_epdgeom = findNode::getClass(topNode, "TOWERGEOM_EPD"); - if (!_epdgeom) { - std::cout << PHWHERE << "::ERROR - cannot find TOWERGEOM_EPD" - << std::endl; - exit(-1); + dataNS.X_matrix = calculate_flattening_matrix(dataNS.avg_Q_xx, dataNS.avg_Q_yy, dataNS.avg_Q_xy, n, cent_bin, "NorthSouth"); } + } + delete m_cdbttree; + m_cdbttree = nullptr; +} - ResetMe(); - - if ((std::fabs(_mbdvtx) < _mbd_vertex_cut)) { - - unsigned int ntowers = epd_towerinfo->size(); - for (unsigned int ch = 0; ch < ntowers; ch++) { - TowerInfo *_tower = epd_towerinfo->get_tower_at_channel(ch); - float epd_e = _tower->get_energy(); - bool isZS = _tower->get_isZS(); - if (!isZS) // exclude ZS +//____________________________________________________________________________.. +void EventPlaneReco::print_correction_data() +{ + std::cout << std::format("\n{:=>60}\n", ""); + std::cout << std::format("{:^60}\n", "EVENT PLANE CORRECTION DATA SUMMARY"); + std::cout << std::format("{:=>60}\n", ""); + + // Iterate through harmonics {2, 3, 4} + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + std::cout << std::format("\n>>> HARMONIC n = {} <<<\n", n); + + // Iterate through Centrality Bins (0-79) + for (size_t cent = 0; cent < m_cent_bins; ++cent) + { + std::cout << std::format("\n Centrality Bin: {}\n", cent); + std::cout << std::format(" {:->30}\n", ""); + + // Header with fixed column widths + std::cout << std::format(" {:<12} {:>10} {:>10} {:>10} {:>10} {:>10}\n", + "Detector", "Avg Qx", "Avg Qy", "Avg Qxx", "Avg Qyy", "Avg Qxy"); + + // Iterate through Subdetectors {S, N} + for (size_t det_idx = 0; det_idx < 3; ++det_idx) + { + std::string det_name; + if (det_idx == 0) { - unsigned int key = TowerInfoDefs::encode_epd(ch); - int arm = TowerInfoDefs::get_epd_arm(key); - if (arm == 0) { - _ssum += epd_e; - } else if (arm == 1) { - _nsum += epd_e; - } + det_name = "South"; + } + else if (det_idx == 1) + { + det_name = "North"; + } + else + { + det_name = "NorthSouth"; } - } - if (_ssum > _epd_charge_min && _nsum > _epd_charge_min && - _ssum < _epd_charge_max && _nsum < _epd_charge_max) { - _do_ep = true; - } + const auto& data = m_correction_data[h_idx][cent][det_idx]; - if (_do_ep) { - - // Apply phi weights in builiding ring Q-vectors - for (unsigned int ch = 0; ch < ntowers; ch++) { - TowerInfo *_tower = epd_towerinfo->get_tower_at_channel(ch); - float epd_e = _tower->get_energy(); - bool isZS = _tower->get_isZS(); - if (!isZS) // exclude ZS - { - if (epd_e < 0.2) // expecting Nmips - { - continue; - } - unsigned int key = TowerInfoDefs::encode_epd(ch); - float tile_phi = _epdgeom->get_phi(key); - int arm = TowerInfoDefs::get_epd_arm(key); - int rbin = TowerInfoDefs::get_epd_rbin(key); - int phibin = TowerInfoDefs::get_epd_phibin(key); - - float truncated_e = - (epd_e < _epd_e) ? epd_e : _epd_e; // set cutoff at _epd_e - - float TileWeight = truncated_e; // default - - if (h_phi_weight_south_input && h_phi_weight_north_input) { - if (arm == 0) { - TileWeight = - truncated_e * h_phi_weight_south_input->GetBinContent( - phibin + 1); // scale by 1/ - } else if (arm == 1) { - TileWeight = - truncated_e * h_phi_weight_north_input->GetBinContent( - phibin + 1); // scale by 1/ - } - } - - for (unsigned int order = 0; order < m_MaxOrder; ++order) { - double Cosine = cos(tile_phi * (double)(order + 1)); - double Sine = sin(tile_phi * (double)(order + 1)); - - // Arm-specific Q-vectors - if (arm == 0) { - south_q[order][0] += truncated_e * Cosine; - south_q[order][1] += truncated_e * Sine; - ring_q_south[rbin][order][0] += TileWeight * Cosine; - ring_q_south[rbin][order][1] += TileWeight * Sine; - - } else if (arm == 1) { - north_q[order][0] += truncated_e * Cosine; - north_q[order][1] += truncated_e * Sine; - ring_q_north[rbin][order][0] += TileWeight * Cosine; - ring_q_north[rbin][order][1] += TileWeight * Sine; - } - - // Combined Q-vectors - northsouth_q[order][0] += truncated_e * Cosine; - northsouth_q[order][1] += truncated_e * Sine; - } - } - } + // For NS, Avg Qx/Qy will be 0.0 because they are not loaded from CDB. + // This is expected behavior. + std::cout << std::format(" {:<12} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f} {:>10.6f}\n", + det_name, + data.avg_Q.x, data.avg_Q.y, + data.avg_Q_xx, data.avg_Q_yy, data.avg_Q_xy); - _totalcharge = _nsum + _ssum; - - // Get recentering histograms and do recentering - // Recentering: subtract Qn,x and Qn,y values averaged over all events - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_mean_cos_south_epd_input[order]) // check if recentering - // histograms exist - { - // south - TAxis *south_xaxis = - tprof_mean_cos_south_epd_input[order]->GetXaxis(); - TAxis *south_yaxis = - tprof_mean_cos_south_epd_input[order]->GetYaxis(); - int xbin_south = south_xaxis->FindBin(_ssum); - int ybin_south = south_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_south = - tprof_mean_cos_south_epd_input[order]->GetBinContent( - xbin_south, ybin_south); - double event_ave_sin_south = - tprof_mean_sin_south_epd_input[order]->GetBinContent( - xbin_south, ybin_south); - south_q_subtract[order][0] = _ssum * event_ave_cos_south; - south_q_subtract[order][1] = _ssum * event_ave_sin_south; - south_q[order][0] -= south_q_subtract[order][0]; - south_q[order][1] -= south_q_subtract[order][1]; - - // north - TAxis *north_xaxis = - tprof_mean_cos_north_epd_input[order]->GetXaxis(); - TAxis *north_yaxis = - tprof_mean_cos_north_epd_input[order]->GetYaxis(); - int xbin_north = north_xaxis->FindBin(_nsum); - int ybin_north = north_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_north = - tprof_mean_cos_north_epd_input[order]->GetBinContent( - xbin_north, ybin_north); - double event_ave_sin_north = - tprof_mean_sin_north_epd_input[order]->GetBinContent( - xbin_north, ybin_north); - north_q_subtract[order][0] = _nsum * event_ave_cos_north; - north_q_subtract[order][1] = _nsum * event_ave_sin_north; - north_q[order][0] -= north_q_subtract[order][0]; - north_q[order][1] -= north_q_subtract[order][1]; - - // northsouth - TAxis *northsouth_xaxis = - tprof_mean_cos_northsouth_epd_input[order]->GetXaxis(); - TAxis *northsouth_yaxis = - tprof_mean_cos_northsouth_epd_input[order]->GetYaxis(); - int xbin_northsouth = northsouth_xaxis->FindBin(_totalcharge); - int ybin_northsouth = northsouth_yaxis->FindBin(_mbdvtx); - - double event_ave_cos_northsouth = - tprof_mean_cos_northsouth_epd_input[order]->GetBinContent( - xbin_northsouth, ybin_northsouth); - double event_ave_sin_northsouth = - tprof_mean_sin_northsouth_epd_input[order]->GetBinContent( - xbin_northsouth, ybin_northsouth); - northsouth_q_subtract[order][0] = - _totalcharge * event_ave_cos_northsouth; - northsouth_q_subtract[order][1] = - _totalcharge * event_ave_sin_northsouth; - northsouth_q[order][0] -= northsouth_q_subtract[order][0]; - northsouth_q[order][1] -= northsouth_q_subtract[order][1]; - } - } + // Print X-Matrix in a bracketed layout + std::cout << std::format(" X-Matrix: [ {:>8.6f}, {:>8.6f} ]\n", + data.X_matrix[0][0], data.X_matrix[0][1]); + std::cout << std::format(" [ {:>8.6f}, {:>8.6f} ]\n", + data.X_matrix[1][0], data.X_matrix[1][1]); + } + } + } + std::cout << std::format("\n{:=>60}\n", ""); +} - // Get recentered psi_n - Eventplaneinfo *epinfo = new Eventplaneinfov1(); - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double n = order + 1.0; - if (tprof_mean_cos_south_epd_input[order]) // if present, Qs are - // recentered - { - tmp_south_psi[order] = - epinfo->GetPsi(south_q[order][0], south_q[order][1], n); - tmp_north_psi[order] = - epinfo->GetPsi(north_q[order][0], north_q[order][1], n); - tmp_northsouth_psi[order] = epinfo->GetPsi( - northsouth_q[order][0], northsouth_q[order][1], n); - } else { - tmp_south_psi[order] = NAN; - tmp_north_psi[order] = NAN; - tmp_northsouth_psi[order] = NAN; - } - } +int EventPlaneReco::CreateNodes(PHCompositeNode *topNode) { + PHNodeIterator iter(topNode); - // Get shifting histograms and calculate shift - for (unsigned int order = 0; order < m_MaxOrder; order++) { - for (int p = 0; p < _imax; p++) { - if (tprof_cos_south_epd_shift_input[order][p]) // check if shifting - // histograms exist - { - double terms = p + 1.0; - double n = order + 1.0; - double tmp = n * terms; - double prefactor = 2.0 / terms; - - // south - TAxis *south_xaxis = - tprof_cos_south_epd_shift_input[order][p]->GetXaxis(); - TAxis *south_yaxis = - tprof_cos_south_epd_shift_input[order][p]->GetYaxis(); - int xbin_south = south_xaxis->FindBin(_ssum); - int ybin_south = south_yaxis->FindBin(_mbdvtx); - - // north - TAxis *north_xaxis = - tprof_cos_north_epd_shift_input[order][p]->GetXaxis(); - TAxis *north_yaxis = - tprof_cos_north_epd_shift_input[order][p]->GetYaxis(); - int xbin_north = north_xaxis->FindBin(_nsum); - int ybin_north = north_yaxis->FindBin(_mbdvtx); - - // // northsouth - TAxis *northsouth_xaxis = - tprof_cos_northsouth_epd_shift_input[order][p]->GetXaxis(); - TAxis *northsouth_yaxis = - tprof_cos_northsouth_epd_shift_input[order][p]->GetYaxis(); - int xbin_northsouth = northsouth_xaxis->FindBin(_totalcharge); - int ybin_northsouth = northsouth_yaxis->FindBin(_mbdvtx); - - // Equation (6) of arxiv:nucl-ex/9805001 - // i = terms; n = order; i*n = tmp - // (2 / i ) * * sin(i*n*psi_n) - // - * cos(i*n*psi_n) - - // north - shift_north[order] += - prefactor * - (tprof_cos_north_epd_shift_input[order][p]->GetBinContent( - xbin_north, ybin_north) * - sin(tmp * tmp_north_psi[order]) - - tprof_sin_north_epd_shift_input[order][p]->GetBinContent( - xbin_north, ybin_north) * - cos(tmp * tmp_north_psi[order])); - - // south - shift_south[order] += - prefactor * - (tprof_cos_south_epd_shift_input[order][p]->GetBinContent( - xbin_south, ybin_south) * - sin(tmp * tmp_south_psi[order]) - - tprof_sin_south_epd_shift_input[order][p]->GetBinContent( - xbin_south, ybin_south) * - cos(tmp * tmp_south_psi[order])); - - // // northsouth - shift_northsouth[order] += - prefactor * - (tprof_cos_northsouth_epd_shift_input[order][p] - ->GetBinContent(xbin_northsouth, ybin_northsouth) * - sin(tmp * tmp_northsouth_psi[order]) - - tprof_sin_northsouth_epd_shift_input[order][p] - ->GetBinContent(xbin_northsouth, ybin_northsouth) * - cos(tmp * tmp_northsouth_psi[order])); - } - } - } + PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } - // n * deltapsi_n = (2 / i ) * * sin(i*n*psi_n) - - // * cos(i*n*psi_n) Divide out n - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double n = order + 1.0; - shift_north[order] /= n; - shift_south[order] /= n; - shift_northsouth[order] /= n; - } + PHCompositeNode *globalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "GLOBAL")); + if (!globalNode) + { + globalNode = new PHCompositeNode("GLOBAL"); + dstNode->addNode(globalNode); + } - // Now add shift to psi_n to flatten it - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_cos_north_epd_shift_input[0][0]) { - tmp_south_psi[order] += shift_south[order]; - tmp_north_psi[order] += shift_north[order]; - tmp_northsouth_psi[order] += shift_northsouth[order]; - } - } + EventplaneinfoMap *eps = findNode::getClass(topNode, m_EventPlaneInfoNodeName); + if (!eps) + { + eps = new EventplaneinfoMapv1(); + PHIODataNode *newNode = new PHIODataNode(eps , m_EventPlaneInfoNodeName, "PHObject"); + globalNode->addNode(newNode); + } - // Now enforce the range - for (unsigned int order = 0; order < m_MaxOrder; order++) { - if (tprof_cos_north_epd_shift_input[0][0]) { - double range = M_PI / (double)(order + 1); - if (tmp_south_psi[order] < -1.0 * range) { - tmp_south_psi[order] += 2.0 * range; - } - if (tmp_south_psi[order] > range) { - tmp_south_psi[order] -= 2.0 * range; - } - if (tmp_north_psi[order] < -1.0 * range) { - tmp_north_psi[order] += 2.0 * range; - } - if (tmp_north_psi[order] > range) { - tmp_north_psi[order] -= 2.0 * range; - } - if (tmp_northsouth_psi[order] < -1.0 * range) { - tmp_northsouth_psi[order] += 2.0 * range; - } - if (tmp_northsouth_psi[order] > range) { - tmp_northsouth_psi[order] -= 2.0 * range; - } - } - } + return Fun4AllReturnCodes::EVENT_OK; +} - for (unsigned int order = 0; order < m_MaxOrder; order++) { - south_Qvec.emplace_back(south_q[order][0], south_q[order][1]); - north_Qvec.emplace_back(north_q[order][0], north_q[order][1]); - northsouth_Qvec.emplace_back(northsouth_q[order][0], - northsouth_q[order][1]); - } +//____________________________________________________________________________.. +int EventPlaneReco::process_centrality(PHCompositeNode *topNode) +{ + CentralityInfo* centInfo = findNode::getClass(topNode, "CentralityInfo"); + if (!centInfo) + { + std::cout << PHWHERE << " CentralityInfo is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } - for (int rbin = 0; rbin < nRings; ++rbin) { - for (unsigned int order = 0; order < m_MaxOrder; ++order) { - all_ring_Qvecs_north[rbin][order] = std::make_pair( - ring_q_north[rbin][order][0], ring_q_north[rbin][order][1]); - all_ring_Qvecs_south[rbin][order] = std::make_pair( - ring_q_south[rbin][order][0], ring_q_south[rbin][order][1]); - } - } + m_cent = centInfo->get_centile(CentralityInfo::PROP::mbd_NS) * 100; - if (epd_towerinfo) { - Eventplaneinfo *sepds = new Eventplaneinfov1(); - sepds->set_qvector(south_Qvec); - sepds->set_shifted_psi(tmp_south_psi); - epmap->insert(sepds, EventplaneinfoMap::sEPDS); - - Eventplaneinfo *sepdn = new Eventplaneinfov1(); - sepdn->set_qvector(north_Qvec); - sepdn->set_shifted_psi(tmp_north_psi); - epmap->insert(sepdn, EventplaneinfoMap::sEPDN); - - Eventplaneinfo *sepdns = new Eventplaneinfov1(); - sepdns->set_qvector(northsouth_Qvec); - sepdns->set_shifted_psi(tmp_northsouth_psi); - epmap->insert(sepdns, EventplaneinfoMap::sEPDNS); - - Eventplaneinfo *epring_south = new Eventplaneinfov1(); - epring_south->set_ring_qvector(all_ring_Qvecs_south); - epmap->insert(epring_south, EventplaneinfoMap::sEPDRING_SOUTH); - - Eventplaneinfo *epring_north = new Eventplaneinfov1(); - epring_north->set_ring_qvector(all_ring_Qvecs_north); - epmap->insert(epring_north, EventplaneinfoMap::sEPDRING_NORTH); - - if (Verbosity() > 1) { - sepds->identify(); - sepdn->identify(); - sepdns->identify(); - epring_south->identify(); - epring_north->identify(); - } - } - } + if (!std::isfinite(m_cent) || m_cent < 0) + { + if (Verbosity() > 1) + { + std::cout << PHWHERE << " Warning Centrality is out of range. Cent: " << m_cent << ". Cannot calibrate Q vector for this event." << std::endl; } + m_doNotCalibEvent = true; } - if (_mbdEpReco) { - ResetMe(); + return Fun4AllReturnCodes::EVENT_OK; +} - MbdPmtContainer *mbdpmts = - findNode::getClass(topNode, "MbdPmtContainer"); - if (!mbdpmts) { - std::cout << PHWHERE << "::ERROR - cannot find MbdPmtContainer" - << std::endl; - exit(-1); - } +//____________________________________________________________________________.. +int EventPlaneReco::process_sEPD(PHCompositeNode* topNode) +{ + TowerInfoContainer* towerinfosEPD = findNode::getClass(topNode, m_inputNode); + if (!towerinfosEPD) + { + std::cout << PHWHERE << " TOWERINFO_CALIB_SEPD is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } - MbdGeom *mbdgeom = findNode::getClass(topNode, "MbdGeom"); - if (!mbdgeom) { - std::cout << PHWHERE << "::ERROR - cannot find MbdGeom" << std::endl; - exit(-1); - } + // sepd + const unsigned int nchannels_epd = towerinfosEPD->size(); + const unsigned int channel_limit = std::min(nchannels_epd, static_cast(SEPD_CHANNELS)); - if (mbdpmts) { - if (Verbosity()) { - std::cout << "EventPlaneReco::process_event - mbdpmts" << std::endl; - } + if (nchannels_epd != channel_limit && Verbosity() > 1) + { + std::cout << PHWHERE + << " Warning: sEPD channel count (" << nchannels_epd + << ") exceeds trig cache size (" << SEPD_CHANNELS + << "); truncating iteration." << std::endl; + } - for (int ipmt = 0; ipmt < mbdpmts->get_npmt(); ipmt++) { - float mbd_q = mbdpmts->get_pmt(ipmt)->get_q(); - _mbdQ += mbd_q; - } + double sepd_total_charge_south = 0; + double sepd_total_charge_north = 0; - for (int ipmt = 0; ipmt < mbdpmts->get_npmt(); ipmt++) { - float mbd_q = mbdpmts->get_pmt(ipmt)->get_q(); - float phi = mbdgeom->get_phi(ipmt); - int arm = mbdgeom->get_arm(ipmt); + for (unsigned int channel = 0; channel < channel_limit; ++channel) + { + TowerInfo* tower = towerinfosEPD->get_tower_at_channel(channel); - if (_mbdQ < _mbd_e) { - continue; - } + unsigned int key = TowerInfoDefs::encode_epd(channel); + int rbin = TowerInfoDefs::get_epd_rbin(key); + double charge = tower->get_energy(); - if (arm == 0) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(phi * (double)(order + 1)); - double Sine = sin(phi * (double)(order + 1)); - south_q[order][0] += mbd_q * Cosine; // south Qn,x - south_q[order][1] += mbd_q * Sine; // south Qn,y - } - } else if (arm == 1) { - for (unsigned int order = 0; order < m_MaxOrder; order++) { - double Cosine = cos(phi * (double)(order + 1)); - double Sine = sin(phi * (double)(order + 1)); - north_q[order][0] += mbd_q * Cosine; // north Qn,x - north_q[order][1] += mbd_q * Sine; // north Qn,y - } - } - } + // Skip Innermost Ring + if (m_skipRing0 && rbin == 0) + { + continue; + } + + // Skip Noise + if (charge <= m_sepd_min_channel_charge) + { + continue; } - for (unsigned int order = 0; order < m_MaxOrder; order++) { - south_Qvec.emplace_back(south_q[order][0], south_q[order][1]); - north_Qvec.emplace_back(north_q[order][0], north_q[order][1]); + // Clamp on high charge threshold + if (m_sEPD_charge_threshold > 0 && charge > m_sEPD_charge_threshold) + { + charge = m_sEPD_charge_threshold; } - if (mbdpmts) { - Eventplaneinfo *mbds = new Eventplaneinfov1(); - mbds->set_qvector(south_Qvec); - epmap->insert(mbds, EventplaneinfoMap::MBDS); + // arm = 0: South + // arm = 1: North + unsigned int arm = TowerInfoDefs::get_epd_arm(key); - Eventplaneinfo *mbdn = new Eventplaneinfov1(); - mbdn->set_qvector(north_Qvec); - epmap->insert(mbdn, EventplaneinfoMap::MBDN); + // sepd charge sums + double& sepd_total_charge = (arm == 0) ? sepd_total_charge_south : sepd_total_charge_north; - if (Verbosity() > 1) { - mbds->identify(); - mbdn->identify(); - } + // Compute total charge for the respective sEPD arm + sepd_total_charge += charge; + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + const auto& [cached_cos, cached_sin] = m_trig_cache[h_idx][channel]; + + m_Q_raw[h_idx][arm].x += charge * cached_cos; + m_Q_raw[h_idx][arm].y += charge * cached_sin; + } + } + + // ensure both total charges are nonzero + if (sepd_total_charge_south == 0 || sepd_total_charge_north == 0) + { + if (Verbosity() > 1) + { + std::cout << PHWHERE << " Error: Total sEPD Charge is Zero: " + << "South = " << sepd_total_charge_south + << ", North = " << sepd_total_charge_north << std::endl; } - ResetMe(); + // ensure raw Q vec is reset + m_Q_raw = {}; + m_doNotCalibEvent = true; + return Fun4AllReturnCodes::EVENT_OK; } - if (Verbosity()) { - epmap->identify(); + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + m_Q_raw[h_idx][0].x /= sepd_total_charge_south; + m_Q_raw[h_idx][0].y /= sepd_total_charge_south; + + m_Q_raw[h_idx][1].x /= sepd_total_charge_north; + m_Q_raw[h_idx][1].y /= sepd_total_charge_north; + + // NEW: Calculate Raw NS (Sum of Raw S + Raw N) + m_Q_raw[h_idx][2].x = m_Q_raw[h_idx][0].x + m_Q_raw[h_idx][1].x; + m_Q_raw[h_idx][2].y = m_Q_raw[h_idx][0].y + m_Q_raw[h_idx][1].y; } return Fun4AllReturnCodes::EVENT_OK; } -int EventPlaneReco::CreateNodes(PHCompositeNode *topNode) { - PHNodeIterator iter(topNode); +void EventPlaneReco::correct_QVecs() +{ + size_t cent_bin = static_cast(m_cent); + + // Skip calibration for out-of-range centrality + if (cent_bin >= m_cent_bins) + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << " Warning: Centrality " << m_cent + << "% exceeds calibration range (0-" << m_cent_bins - 1 + << "). Using raw Q-vectors." << std::endl; + } - PHCompositeNode *dstNode = - dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); - if (!dstNode) { - std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl; - return Fun4AllReturnCodes::ABORTRUN; + m_doNotCalibEvent = true; + return; } - PHCompositeNode *globalNode = dynamic_cast( - iter.findFirst("PHCompositeNode", "GLOBAL")); - if (!globalNode) { - globalNode = new PHCompositeNode("GLOBAL"); - dstNode->addNode(globalNode); - } + size_t south_idx = static_cast(Subdetector::S); + size_t north_idx = static_cast(Subdetector::N); + size_t ns_idx = static_cast(Subdetector::NS); - EventplaneinfoMap *eps = - findNode::getClass(topNode, "EventplaneinfoMap"); - if (!eps) { - eps = new EventplaneinfoMapv1(); - PHIODataNode *EpMapNode = - new PHIODataNode(eps, "EventplaneinfoMap", "PHObject"); - globalNode->addNode(EpMapNode); + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + auto& dataS = m_correction_data[h_idx][cent_bin][south_idx]; + auto& dataN = m_correction_data[h_idx][cent_bin][north_idx]; + auto& dataNS = m_correction_data[h_idx][cent_bin][ns_idx]; + + double Q_S_x_avg = dataS.avg_Q.x; + double Q_S_y_avg = dataS.avg_Q.y; + double Q_N_x_avg = dataN.avg_Q.x; + double Q_N_y_avg = dataN.avg_Q.y; + + QVec q_S = m_Q_raw[h_idx][south_idx]; + QVec q_N = m_Q_raw[h_idx][north_idx]; + + // Apply Recentering + QVec q_S_recenter = {q_S.x - Q_S_x_avg, q_S.y - Q_S_y_avg}; + QVec q_N_recenter = {q_N.x - Q_N_x_avg, q_N.y - Q_N_y_avg}; + QVec q_NS_recenter = {q_S_recenter.x + q_N_recenter.x, q_S_recenter.y + q_N_recenter.y}; + + m_Q_recentered[h_idx][south_idx] = q_S_recenter; + m_Q_recentered[h_idx][north_idx] = q_N_recenter; + m_Q_recentered[h_idx][ns_idx] = q_NS_recenter; + + // Flattening Matrix + const auto &X_S = dataS.X_matrix; + const auto &X_N = dataN.X_matrix; + const auto &X_NS = dataNS.X_matrix; + + // Apply Flattening + double Q_S_x_flat = X_S[0][0] * q_S_recenter.x + X_S[0][1] * q_S_recenter.y; + double Q_S_y_flat = X_S[1][0] * q_S_recenter.x + X_S[1][1] * q_S_recenter.y; + double Q_N_x_flat = X_N[0][0] * q_N_recenter.x + X_N[0][1] * q_N_recenter.y; + double Q_N_y_flat = X_N[1][0] * q_N_recenter.x + X_N[1][1] * q_N_recenter.y; + + double Q_NS_x_flat = X_NS[0][0] * q_NS_recenter.x + X_NS[0][1] * q_NS_recenter.y; + double Q_NS_y_flat = X_NS[1][0] * q_NS_recenter.x + X_NS[1][1] * q_NS_recenter.y; + + QVec q_S_flat = {Q_S_x_flat, Q_S_y_flat}; + QVec q_N_flat = {Q_N_x_flat, Q_N_y_flat}; + QVec q_NS_flat = {Q_NS_x_flat, Q_NS_y_flat}; + + m_Q_flat[h_idx][south_idx] = q_S_flat; + m_Q_flat[h_idx][north_idx] = q_N_flat; + m_Q_flat[h_idx][ns_idx] = q_NS_flat; } - return Fun4AllReturnCodes::EVENT_OK; } -void EventPlaneReco::ResetMe() { - for (auto &vec : south_q) { - std::fill(vec.begin(), vec.end(), 0.); - } +void EventPlaneReco::print_QVectors() +{ + std::string header_text = std::format("EVENT Q-VECTOR SUMMARY (Event: {}, CENTRALITY: {:.0f}%)", m_globalEvent, m_cent); + + std::cout << std::format("\n{:*>100}\n", ""); + std::cout << std::format("{:^100}\n", header_text); + std::cout << std::format("{:*>100}\n", ""); + + // Table Header + std::cout << std::format(" {:<10} {:<10} | {:>21} | {:>21} | {:>21}\n", + "Harmonic", "Detector", "Raw (x, y)", "Recentered (x, y)", "Flattened (x, y)"); + std::cout << std::format(" {:-<100}\n", ""); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + + for (size_t det_idx = 0; det_idx < 3; ++det_idx) + { + std::string det_name; + if (det_idx == 0) + { + det_name = "South"; + } + else if (det_idx == 1) + { + det_name = "North"; + } + else + { + det_name = "NorthSouth"; + } - for (auto &vec : north_q) { - std::fill(vec.begin(), vec.end(), 0.); - } + const auto& raw = m_Q_raw[h_idx][det_idx]; + const auto& rec = m_Q_recentered[h_idx][det_idx]; + const auto& flat = m_Q_flat[h_idx][det_idx]; - for (auto &vec : northsouth_q) { - std::fill(vec.begin(), vec.end(), 0.); - } + std::string h_label = (det_idx == 0) ? std::format("n={}", n) : ""; + + // Groups x and y into (val, val) pairs for better scannability + std::string raw_str = std::format("({:>8.5f}, {:>8.5f})", raw.x, raw.y); + std::string rec_str = std::format("({:>8.5f}, {:>8.5f})", rec.x, rec.y); + std::string flat_str = std::format("({:>8.5f}, {:>8.5f})", flat.x, flat.y); - for (auto &order_vec : ring_q_north) { - for (auto &xy_vec : order_vec) { - std::fill(xy_vec.begin(), xy_vec.end(), 0.0); + std::cout << std::format(" {:<10} {:<10} | {:<21} | {:<21} | {:10}\n", + h_label, det_name, raw_str, rec_str, flat_str); + } + if (h_idx < m_harmonics.size() - 1) + { + std::cout << std::format(" {:.>100}\n", ""); } } + std::cout << std::format("{:*>100}\n\n", ""); +} - for (auto &order_vec : ring_q_south) { - for (auto &xy_vec : order_vec) { - std::fill(xy_vec.begin(), xy_vec.end(), 0.0); - } +int EventPlaneReco::FillNode(PHCompositeNode *topNode) +{ + EventplaneinfoMap *epmap = findNode::getClass(topNode, m_EventPlaneInfoNodeName); + if (!epmap) + { + std::cout << PHWHERE << " EventplaneinfoMap is missing doing nothing" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; } - south_Qvec.clear(); - north_Qvec.clear(); - northsouth_Qvec.clear(); + size_t vec_size = static_cast(*std::ranges::max_element(m_harmonics)); - for (auto &ring : all_ring_Qvecs_north) { - for (auto &q : ring) { - q = {0.0, 0.0}; - } + std::vector> south_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> south_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> south_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + + std::vector> north_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> north_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> north_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + + std::vector> northsouth_Qvec_raw(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> northsouth_Qvec_recentered(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + std::vector> northsouth_Qvec(vec_size, {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}); + + for (size_t h_idx = 0; h_idx < m_harmonics.size(); ++h_idx) + { + int n = m_harmonics[h_idx]; + int idx = n - 1; + + // Fallback logic: Use raw if calibration failed or centrality is out of range + const auto& Q_S = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][0] : m_Q_flat[h_idx][0]; + const auto& Q_N = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][1] : m_Q_flat[h_idx][1]; + const auto& Q_NS = (m_doNotCalib || m_doNotCalibEvent) ? m_Q_raw[h_idx][2] : m_Q_flat[h_idx][2]; + + const auto& Q_S_raw = m_Q_raw[h_idx][0]; + const auto& Q_S_recentered = m_Q_recentered[h_idx][0]; + + const auto& Q_N_raw = m_Q_raw[h_idx][1]; + const auto& Q_N_recentered = m_Q_recentered[h_idx][1]; + + const auto& Q_NS_raw = m_Q_raw[h_idx][2]; + const auto& Q_NS_recentered = m_Q_recentered[h_idx][2]; + + // South + south_Qvec_raw[idx] = {Q_S_raw.x, Q_S_raw.y}; + south_Qvec_recentered[idx] = {Q_S_recentered.x, Q_S_recentered.y}; + south_Qvec[idx] = {Q_S.x, Q_S.y}; + + // North + north_Qvec_raw[idx] = {Q_N_raw.x, Q_N_raw.y}; + north_Qvec_recentered[idx] = {Q_N_recentered.x, Q_N_recentered.y}; + north_Qvec[idx] = {Q_N.x, Q_N.y}; + + // Combined (North + South) + northsouth_Qvec_raw[idx] = {Q_NS_raw.x, Q_NS_raw.y}; + northsouth_Qvec_recentered[idx] = {Q_NS_recentered.x, Q_NS_recentered.y}; + northsouth_Qvec[idx] = {Q_NS.x, Q_NS.y}; } - for (auto &ring : all_ring_Qvecs_south) { - for (auto &q : ring) { - q = {0.0, 0.0}; - } + // Helper lambda to fill nodes using the class's GetPsi method + auto create_and_fill = [&](const std::vector>& qvecs_raw, const std::vector>& qvecs_recentered, const std::vector>& qvecs) { + auto node = std::make_unique(); + node->set_qvector_raw(qvecs_raw); + node->set_qvector_recentered(qvecs_recentered); + node->set_qvector(qvecs); + + std::vector psi_vec(vec_size, std::numeric_limits::quiet_NaN()); + for (int n : m_harmonics) { + psi_vec[n-1] = node->GetPsi(qvecs[n-1].first, qvecs[n-1].second, n); + } + node->set_shifted_psi(psi_vec); + return node; + }; + + epmap->insert(create_and_fill(south_Qvec_raw, south_Qvec_recentered, south_Qvec).release(), EventplaneinfoMap::sEPDS); + epmap->insert(create_and_fill(north_Qvec_raw, north_Qvec_recentered, north_Qvec).release(), EventplaneinfoMap::sEPDN); + epmap->insert(create_and_fill(northsouth_Qvec_raw, northsouth_Qvec_recentered, northsouth_Qvec).release(), EventplaneinfoMap::sEPDNS); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________.. +int EventPlaneReco::process_event(PHCompositeNode *topNode) +{ + EventHeader *eventInfo = findNode::getClass(topNode, "EventHeader"); + if (!eventInfo) + { + return Fun4AllReturnCodes::ABORTRUN; } - for (auto &vec : south_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); + m_globalEvent = eventInfo->get_EvtSequence(); + + int ret = process_centrality(topNode); + if (ret) + { + return ret; } - for (auto &vec : north_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); + ret = process_sEPD(topNode); + if (ret) + { + return ret; } - for (auto &vec : northsouth_q_subtract) { - std::fill(vec.begin(), vec.end(), 0.); + // Calibrate Q Vectors + if (!m_doNotCalib && !m_doNotCalibEvent) + { + correct_QVecs(); } - std::fill(shift_north.begin(), shift_north.end(), 0.); - std::fill(shift_south.begin(), shift_south.end(), 0.); - std::fill(shift_northsouth.begin(), shift_northsouth.end(), 0.); + ret = FillNode(topNode); + if (ret) + { + return ret; + } - std::fill(tmp_south_psi.begin(), tmp_south_psi.end(), NAN); - std::fill(tmp_north_psi.begin(), tmp_north_psi.end(), NAN); - std::fill(tmp_northsouth_psi.begin(), tmp_northsouth_psi.end(), NAN); + if (Verbosity() > 1) + { + print_QVectors(); + } - _nsum = 0.; - _ssum = 0.; - _do_ep = false; - _mbdQ = 0.; - _totalcharge = 0.; + return Fun4AllReturnCodes::EVENT_OK; } -int EventPlaneReco::End(PHCompositeNode * /*topNode*/) { +//____________________________________________________________________________.. +int EventPlaneReco::ResetEvent(PHCompositeNode */*topNode*/) +{ + m_doNotCalibEvent = false; + + m_Q_raw = {}; + m_Q_recentered = {}; + m_Q_flat = {}; - std::cout << " EventPlaneReco::End() " << std::endl; return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/eventplaneinfo/EventPlaneReco.h b/offline/packages/eventplaneinfo/EventPlaneReco.h index ce4259c95e..167e7b698a 100644 --- a/offline/packages/eventplaneinfo/EventPlaneReco.h +++ b/offline/packages/eventplaneinfo/EventPlaneReco.h @@ -1,107 +1,163 @@ -// Tell emacs that this is a C++ source -// -*- C++ -*-. #ifndef EVENTPLANEINFO_EVENTPLANERECO_H #define EVENTPLANEINFO_EVENTPLANERECO_H -//=========================================================== -/// \author Ejiro Umaka -//=========================================================== - #include -#include // for string -#include // for vector -class TProfile2D; -class TH1; +#include +#include +#include +class CDBTTree; class PHCompositeNode; -class EventPlaneReco : public SubsysReco { -public: - EventPlaneReco(const std::string &name = "EventPlaneReco"); +class EventPlaneReco : public SubsysReco +{ + public: + + explicit EventPlaneReco(const std::string &name = "EventPlaneReco"); ~EventPlaneReco() override = default; + + // Explicitly disable copying and moving + EventPlaneReco(const EventPlaneReco&) = delete; + EventPlaneReco& operator=(const EventPlaneReco&) = delete; + EventPlaneReco(EventPlaneReco&&) = delete; + EventPlaneReco& operator=(EventPlaneReco&&) = delete; + + /** Called during initialization. + Typically this is where you can book histograms, and e.g. + register them to Fun4AllServer (so they can be output to file + using Fun4AllServer::dumpHistos() method). + */ + int Init(PHCompositeNode *topNode) override; + + /** Called during initialization. + * geometry is available + */ int InitRun(PHCompositeNode *topNode) override; + + /** Called for each event. + This is where you do the real work. + */ int process_event(PHCompositeNode *topNode) override; - int End(PHCompositeNode * /*topNode*/) override; - - void ResetMe(); - void set_sepd_epreco(bool sepdEpReco) { _sepdEpReco = sepdEpReco; } - void set_mbd_epreco(bool mbdEpReco) { _mbdEpReco = mbdEpReco; } - void set_isSim(bool isSim) { _isSim = isSim; } - void set_sEPD_Mip_cut(const float e) { _epd_e = e; } - void set_sEPD_Charge_cut(const float c) { _epd_charge_min = c; } - void set_MBD_Min_Qcut(const float f) { _mbd_e = f; } - void set_MBD_Vertex_cut(const float v) { _mbd_vertex_cut = v; } - void set_Ep_orders(const unsigned int n) { m_MaxOrder = n; } - -private: - int CreateNodes(PHCompositeNode *topNode); - unsigned int m_MaxOrder{3}; - static const int nRings {16}; - - std::string FileName; - - std::vector> south_q; - std::vector> north_q; - std::vector> northsouth_q; - std::vector>> ring_q_north; - std::vector>> ring_q_south; - std::vector> south_Qvec; - std::vector> north_Qvec; - std::vector> northsouth_Qvec; - std::vector>> all_ring_Qvecs_north; - std::vector>> all_ring_Qvecs_south; - - // const int phibins{24}; - TH1* h_phi_weight_south_input{nullptr}; - TH1* h_phi_weight_north_input{nullptr}; - - // recentering utility - std::vector> south_q_subtract; - std::vector> north_q_subtract; - std::vector> northsouth_q_subtract; - - // shifting utility - std::vector shift_north; - std::vector shift_south; - std::vector shift_northsouth; - std::vector tmp_south_psi; - std::vector tmp_north_psi; - std::vector tmp_northsouth_psi; - - // recentering histograms - TProfile2D *tprof_mean_cos_north_epd_input[6]{}; - TProfile2D *tprof_mean_sin_north_epd_input[6]{}; - TProfile2D *tprof_mean_cos_south_epd_input[6]{}; - TProfile2D *tprof_mean_sin_south_epd_input[6]{}; - TProfile2D *tprof_mean_cos_northsouth_epd_input[6]{}; - TProfile2D *tprof_mean_sin_northsouth_epd_input[6]{}; - - // shifting histograms - const int _imax{12}; - TProfile2D *tprof_cos_north_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_north_epd_shift_input[6][12]{}; - TProfile2D *tprof_cos_south_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_south_epd_shift_input[6][12]{}; - TProfile2D *tprof_cos_northsouth_epd_shift_input[6][12]{}; - TProfile2D *tprof_sin_northsouth_epd_shift_input[6][12]{}; - - bool _mbdEpReco{false}; - bool _sepdEpReco{false}; - bool _isSim{false}; - bool _do_ep{false}; - - float _nsum{0.0}; - float _ssum{0.0}; - float _mbdvtx{999.0}; - float _epd_charge_min{5.0}; - float _epd_charge_max{10000.0}; - float _epd_e{10.0}; - float _mbd_e{10.0}; - float _mbdQ{0.0}; - double _totalcharge{0.0}; - float _mbd_vertex_cut{60.0}; -}; -#endif // EVENTPLANEINFO_EVENTPLANERECO_H + /// Clean up internals after each event. + int ResetEvent(PHCompositeNode *topNode) override; + + + void set_inputNode(const std::string &inputNode) + { + m_inputNode = inputNode; + } + + void set_directURL_EventPlaneCalib(const std::string &directURL_EventPlaneCalib) + { + m_directURL_EventPlaneCalib = directURL_EventPlaneCalib; + } + + void set_doAbortNoEventPlaneCalib(bool status = true) + { + m_doAbortNoEventPlaneCalib = status; + } + + void set_sepd_min_channel_charge(double sepd_min_channel_charge) + { + m_sepd_min_channel_charge = sepd_min_channel_charge; + } + + void set_charge_threshold(double threshold) + { + m_sEPD_charge_threshold = std::max(0.0, threshold); + } + + void set_skipRing0(bool skip) + { + m_skipRing0 = skip; + } + + void set_EventPlaneInfoNodeName(const std::string &name) + { + m_EventPlaneInfoNodeName = name; + } + + private: + + int CreateNodes(PHCompositeNode *topNode); + + std::array, 2> calculate_flattening_matrix(double xx, double yy, double xy, int n, int cent_bin, const std::string& det_label); + void LoadCalib(); + + void print_correction_data(); + void print_QVectors(); + + int process_centrality(PHCompositeNode *topNode); + int process_sEPD(PHCompositeNode *topNode); + void correct_QVecs(); + + int FillNode(PHCompositeNode *topNode); + + std::string m_directURL_EventPlaneCalib; + bool m_doAbortNoEventPlaneCalib{false}; + bool m_doNotCalib{false}; + bool m_doNotCalibEvent{false}; + + bool m_skipRing0{true}; + + double m_cent{0.0}; + double m_globalEvent{0}; + double m_sepd_min_channel_charge{0.5}; + double m_sEPD_charge_threshold{50}; + + std::string m_calibName{"SEPD_EventPlaneCalib"}; + std::string m_inputNode{"TOWERINFO_CALIB_SEPD"}; + std::string m_EventPlaneInfoNodeName{"EventplaneinfoMap"}; + + CDBTTree *m_cdbttree {nullptr}; + + enum class Subdetector + { + S, + N, + NS + }; + + struct QVec + { + double x{0.0}; + double y{0.0}; + }; + + struct CorrectionData + { + // Averages of Qx, Qy, Qx^2, Qy^2, Qxy + QVec avg_Q{}; + double avg_Q_xx{0.0}; + double avg_Q_yy{0.0}; + double avg_Q_xy{0.0}; + + // Correction matrix + std::array, 2> X_matrix{}; + }; + + static constexpr size_t m_cent_bins {80}; + static constexpr std::array m_harmonics = {2, 3, 4}; + + // Holds all correction data + // key: [Harmonic][Cent][Subdetector] + // Harmonics {2,3,4} -> 3 elements + // Subdetectors {S,N,NS} -> 3 elements + std::array, m_cent_bins>, m_harmonics.size()> m_correction_data; + + // sEPD Q Vectors + // key: [Harmonic][Subdetector] + // Subdetectors {S,N,NS} -> 3 elements + std::array, m_harmonics.size()> m_Q_raw{}; + std::array, m_harmonics.size()> m_Q_recentered{}; + std::array, m_harmonics.size()> m_Q_flat{}; + + // [Harmonic Index][Channel Index] -> {cos, sin} + std::vector>> m_trig_cache; + + static constexpr int SEPD_CHANNELS = 744; +}; +#endif diff --git a/offline/packages/eventplaneinfo/Eventplaneinfo.h b/offline/packages/eventplaneinfo/Eventplaneinfo.h index 1ad2665881..04b085a393 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfo.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfo.h @@ -1,19 +1,19 @@ // Tell emacs that this is a C++ source // -*- C++ -*-. -#ifndef EVENTPLANEINFO_H -#define EVENTPLANEINFO_H +#ifndef EVENTPLANEINFO_EVENTPLANEINFO_H +#define EVENTPLANEINFO_EVENTPLANEINFO_H #include -#include #include +#include #include #include class Eventplaneinfo : public PHObject { public: - ~Eventplaneinfo() override {} + ~Eventplaneinfo() override = default; void identify(std::ostream& os = std::cout) const override { @@ -22,18 +22,29 @@ class Eventplaneinfo : public PHObject PHObject* CloneMe() const override { return nullptr; } - virtual void set_qvector(std::vector> /*Qvec*/) { return; } - virtual void set_shifted_psi(std::vector /*Psi_Shifted*/) { return; } - virtual std::pair get_qvector(int /*order*/) const { return std::make_pair(NAN, NAN); } - virtual double get_psi(int /*order*/) const { return NAN; } - virtual double get_shifted_psi(int /*order*/) const { return NAN; } - virtual double GetPsi(const double /*Qx*/, const double /*Qy*/, const unsigned int /*order*/) const { return NAN; } - virtual void set_ring_qvector(std::vector>> /*RingQvecs*/) { return; } - virtual std::pair get_ring_qvector(int /*rbin*/, int /*order*/) const { return std::make_pair(NAN, NAN); } - virtual double get_ring_psi(int /*rbin*/, int /*order*/) const { return NAN; } + virtual void set_qvector(const std::vector>& /*Qvec*/) { return; } + virtual void set_qvector_raw(const std::vector>& /*Qvec*/) { return; } + virtual void set_qvector_recentered(const std::vector>& /*Qvec*/) { return; } + virtual void set_shifted_psi(const std::vector& /*Psi_Shifted*/) { return; } + virtual std::pair get_qvector(unsigned int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual std::pair get_qvector_raw(unsigned int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual std::pair get_qvector_recentered(unsigned int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual double get_psi(unsigned int /*order*/) const { return std::numeric_limits::quiet_NaN(); } + virtual double get_shifted_psi(unsigned int /*order*/) const { return std::numeric_limits::quiet_NaN(); } + virtual double GetPsi(const double /*Qx*/, const double /*Qy*/, const unsigned int /*order*/) const { return std::numeric_limits::quiet_NaN(); } + virtual void set_ring_qvector(const std::vector>>& /*RingQvecs*/) { return; } + virtual std::pair get_ring_qvector(int /*rbin*/, unsigned int /*order*/) const { return std::make_pair(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); } + virtual double get_ring_psi(int /*rbin*/, unsigned int /*order*/) const { return std::numeric_limits::quiet_NaN(); } protected: - Eventplaneinfo() {} + Eventplaneinfo() = default; + + // Rule of Five: Protected allows derived classes to copy/move, + // but prevents "slicing" at the base class level. + Eventplaneinfo(const Eventplaneinfo&) = default; + Eventplaneinfo& operator=(const Eventplaneinfo&) = default; + Eventplaneinfo(Eventplaneinfo&&) = default; + Eventplaneinfo& operator=(Eventplaneinfo&&) = default; private: ClassDefOverride(Eventplaneinfo, 1); diff --git a/offline/packages/eventplaneinfo/EventplaneinfoMap.h b/offline/packages/eventplaneinfo/EventplaneinfoMap.h index 247a62a1f6..ee16720cff 100644 --- a/offline/packages/eventplaneinfo/EventplaneinfoMap.h +++ b/offline/packages/eventplaneinfo/EventplaneinfoMap.h @@ -25,10 +25,10 @@ class EventplaneinfoMap : public PHObject sEPDRING_NORTH = 200 }; - typedef std::map::const_iterator ConstIter; - typedef std::map::iterator Iter; + using ConstIter = std::map::const_iterator; + using Iter = std::map::iterator; - ~EventplaneinfoMap() override {} + ~EventplaneinfoMap() override = default; void identify(std::ostream& os = std::cout) const override { os << "EventplaneinfoMap base class" << std::endl; } virtual bool empty() const {return true;} @@ -47,7 +47,13 @@ class EventplaneinfoMap : public PHObject virtual Iter end(); protected: - EventplaneinfoMap() {} + EventplaneinfoMap() = default; + + // Rule of Five: Protected to support derived classes + EventplaneinfoMap(const EventplaneinfoMap&) = default; + EventplaneinfoMap& operator=(const EventplaneinfoMap&) = default; + EventplaneinfoMap(EventplaneinfoMap&&) = default; + EventplaneinfoMap& operator=(EventplaneinfoMap&&) = default; private: ClassDefOverride(EventplaneinfoMap, 1); diff --git a/offline/packages/eventplaneinfo/EventplaneinfoMapv1.cc b/offline/packages/eventplaneinfo/EventplaneinfoMapv1.cc index a0888d4d18..4aeffdd8c9 100644 --- a/offline/packages/eventplaneinfo/EventplaneinfoMapv1.cc +++ b/offline/packages/eventplaneinfo/EventplaneinfoMapv1.cc @@ -3,7 +3,6 @@ #include "Eventplaneinfo.h" #include "EventplaneinfoMap.h" -#include // for reverse_iterator #include // for pair, make_pair EventplaneinfoMapv1::~EventplaneinfoMapv1() diff --git a/offline/packages/eventplaneinfo/EventplaneinfoMapv1.h b/offline/packages/eventplaneinfo/EventplaneinfoMapv1.h index 5aac01a4ce..b4f10f3bed 100644 --- a/offline/packages/eventplaneinfo/EventplaneinfoMapv1.h +++ b/offline/packages/eventplaneinfo/EventplaneinfoMapv1.h @@ -16,6 +16,12 @@ class EventplaneinfoMapv1 : public EventplaneinfoMap EventplaneinfoMapv1() = default; ~EventplaneinfoMapv1() override; + // Rule of Five: Explicitly delete to prevent shallow copy/double free + EventplaneinfoMapv1(const EventplaneinfoMapv1&) = delete; + EventplaneinfoMapv1& operator=(const EventplaneinfoMapv1&) = delete; + EventplaneinfoMapv1(EventplaneinfoMapv1&&) = delete; + EventplaneinfoMapv1& operator=(EventplaneinfoMapv1&&) = delete; + void identify(std::ostream& os = std::cout) const override; void Reset() override { clear(); } // cppcheck-suppress [virtualCallInConstructor] diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov1.h b/offline/packages/eventplaneinfo/Eventplaneinfov1.h index 571997b63b..2b027323ea 100644 --- a/offline/packages/eventplaneinfo/Eventplaneinfov1.h +++ b/offline/packages/eventplaneinfo/Eventplaneinfov1.h @@ -11,27 +11,30 @@ #include // for pair, make_pair #include -class PHObject; - class Eventplaneinfov1 : public Eventplaneinfo { public: Eventplaneinfov1() = default; ~Eventplaneinfov1() override = default; + Eventplaneinfov1(const Eventplaneinfov1&) = default; + Eventplaneinfov1& operator=(const Eventplaneinfov1&) = default; + Eventplaneinfov1(Eventplaneinfov1&&) = default; + Eventplaneinfov1& operator=(Eventplaneinfov1&&) = default; + void identify(std::ostream& os = std::cout) const override; void Reset() override { *this = Eventplaneinfov1(); } PHObject* CloneMe() const override { return new Eventplaneinfov1(*this); } - void set_qvector(std::vector> Qvec) override { mQvec = Qvec; } - void set_shifted_psi(std::vector Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } - std::pair get_qvector(int order) const override { return std::make_pair(mQvec[order - 1].first, mQvec[order - 1].second); } - void set_ring_qvector(std::vector>> Qvec) override { ring_Qvec = Qvec; } - std::pair get_ring_qvector(int ring_index, int order) const override { return ring_Qvec[ring_index][order - 1]; } - double get_ring_psi(int ring_index, int order) const override {return GetPsi(ring_Qvec[ring_index][order - 1].first,ring_Qvec[ring_index][order - 1].second,order);} - double GetPsi(const double Qx, const double Qy, const unsigned int order) const override; - double get_psi(int order) const override { return GetPsi(mQvec[order - 1].first, mQvec[order - 1].second, order);} - double get_shifted_psi(int order) const override { return mPsi_Shifted[order - 1]; } + void set_qvector(const std::vector>& Qvec) override { mQvec = Qvec; } + void set_shifted_psi(const std::vector& Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } + std::pair get_qvector(unsigned int order) const override { return std::make_pair(mQvec[order - 1].first, mQvec[order - 1].second); } + void set_ring_qvector(const std::vector>>& Qvec) override { ring_Qvec = Qvec; } + std::pair get_ring_qvector(int ring_index, unsigned int order) const override { return ring_Qvec[ring_index][order - 1]; } + double get_ring_psi(int ring_index, unsigned int order) const override {return GetPsi(ring_Qvec[ring_index][order - 1].first,ring_Qvec[ring_index][order - 1].second,order);} + double GetPsi(double Qx, double Qy, unsigned int order) const override; + double get_psi(unsigned int order) const override { return GetPsi(mQvec[order - 1].first, mQvec[order - 1].second, order);} + double get_shifted_psi(unsigned int order) const override { return mPsi_Shifted[order - 1]; } private: std::vector> mQvec; diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.cc b/offline/packages/eventplaneinfo/Eventplaneinfov2.cc new file mode 100644 index 0000000000..7331117a17 --- /dev/null +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.cc @@ -0,0 +1,23 @@ +#include "Eventplaneinfov2.h" + +#include +#include + +void Eventplaneinfov2::identify(std::ostream& os) const +{ + os << "---------Eventplaneinfov2------------------" << std::endl; + return; +} + +double Eventplaneinfov2::GetPsi(const double Qx, const double Qy, const unsigned int order) const +{ + if (order == 0) + { + return std::numeric_limits::quiet_NaN(); + } + if ((Qx == 0.0) && (Qy == 0.0)) + { + return std::numeric_limits::quiet_NaN(); + } + return std::atan2(Qy, Qx) / order; +} diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2.h b/offline/packages/eventplaneinfo/Eventplaneinfov2.h new file mode 100644 index 0000000000..5ad62fe979 --- /dev/null +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2.h @@ -0,0 +1,86 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef EVENTPLANEINFO_EVENTPLANEINFOV2_H +#define EVENTPLANEINFO_EVENTPLANEINFOV2_H + +#include "Eventplaneinfo.h" + +#include // for size_t +#include +#include +#include // for pair, make_pair +#include + +class PHObject; + +class Eventplaneinfov2 : public Eventplaneinfo +{ + public: + Eventplaneinfov2() = default; + ~Eventplaneinfov2() override = default; + + Eventplaneinfov2(const Eventplaneinfov2&) = default; + Eventplaneinfov2& operator=(const Eventplaneinfov2&) = default; + Eventplaneinfov2(Eventplaneinfov2&&) = default; + Eventplaneinfov2& operator=(Eventplaneinfov2&&) = default; + + void identify(std::ostream& os = std::cout) const override; + void Reset() override { *this = Eventplaneinfov2(); } + PHObject* CloneMe() const override { return new Eventplaneinfov2(*this); } + + void set_qvector(const std::vector>& Qvec) override { mQvec = Qvec; } + void set_qvector_raw(const std::vector>& Qvec) override { mQvec_raw = Qvec; } + void set_qvector_recentered(const std::vector>& Qvec) override { mQvec_recentered = Qvec; } + void set_shifted_psi(const std::vector& Psi_Shifted) override { mPsi_Shifted = Psi_Shifted; } + std::pair get_qvector(unsigned int order) const override { return safe_qvec(mQvec, order); } + std::pair get_qvector_raw(unsigned int order) const override { return safe_qvec(mQvec_raw, order); } + std::pair get_qvector_recentered(unsigned int order) const override { return safe_qvec(mQvec_recentered, order); } + void set_ring_qvector(const std::vector>>& Qvec) override { ring_Qvec = Qvec; } + std::pair get_ring_qvector(int ring_index, unsigned int order) const override + { + if (ring_index < 0 || static_cast(ring_index) >= ring_Qvec.size()) + { + return {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + } + return safe_qvec(ring_Qvec[ring_index], order); + } + double get_ring_psi(int ring_index, unsigned int order) const override + { + auto q = get_ring_qvector(ring_index, order); + return GetPsi(q.first, q.second, order); + } + + double GetPsi(double Qx, double Qy, unsigned int order) const override; + double get_psi(unsigned int order) const override + { + auto q = get_qvector(order); + return GetPsi(q.first, q.second, order); + } + double get_shifted_psi(unsigned int order) const override + { + if (order <= 0 || order > mPsi_Shifted.size()) + { + return std::numeric_limits::quiet_NaN(); + } + return mPsi_Shifted[order - 1]; + } + + private: + static std::pair safe_qvec(const std::vector>& v, unsigned int order) + { + if (order <= 0 || order > v.size()) + { + return {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + } + return v[order - 1]; + } + + std::vector> mQvec; + std::vector> mQvec_raw; + std::vector> mQvec_recentered; + std::vector mPsi_Shifted; + std::vector>> ring_Qvec; + ClassDefOverride(Eventplaneinfov2, 1); +}; + +#endif diff --git a/offline/packages/eventplaneinfo/Eventplaneinfov2LinkDef.h b/offline/packages/eventplaneinfo/Eventplaneinfov2LinkDef.h new file mode 100644 index 0000000000..961c0446cf --- /dev/null +++ b/offline/packages/eventplaneinfo/Eventplaneinfov2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class Eventplaneinfov2 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/eventplaneinfo/Makefile.am b/offline/packages/eventplaneinfo/Makefile.am index 3a1192095d..188447cd06 100644 --- a/offline/packages/eventplaneinfo/Makefile.am +++ b/offline/packages/eventplaneinfo/Makefile.am @@ -14,8 +14,7 @@ AM_LDFLAGS = \ -L$(OFFLINE_MAIN)/lib libeventplaneinfo_io_la_LIBADD = \ - -lphool \ - -lcentrality_io + -lphool libeventplaneinfo_la_LIBADD = \ libeventplaneinfo_io.la \ @@ -24,14 +23,15 @@ libeventplaneinfo_la_LIBADD = \ -lfun4all \ -lffamodules \ -lcalotrigger_io \ + -lcentrality_io \ -lffarawobjects \ -lcdbobjects \ -lglobalvertex_io pkginclude_HEADERS = \ - EventPlaneCalibration.h \ Eventplaneinfo.h \ Eventplaneinfov1.h \ + Eventplaneinfov2.h \ EventplaneinfoMap.h \ EventplaneinfoMapv1.h \ EventPlaneReco.h @@ -39,6 +39,7 @@ pkginclude_HEADERS = \ ROOTDICTS = \ Eventplaneinfo_Dict.cc \ Eventplaneinfov1_Dict.cc \ + Eventplaneinfov2_Dict.cc \ EventplaneinfoMap_Dict.cc \ EventplaneinfoMapv1_Dict.cc @@ -50,11 +51,11 @@ libeventplaneinfo_io_la_SOURCES = \ $(ROOTDICTS) \ Eventplaneinfo.cc \ Eventplaneinfov1.cc \ + Eventplaneinfov2.cc \ EventplaneinfoMap.cc \ EventplaneinfoMapv1.cc libeventplaneinfo_la_SOURCES = \ - EventPlaneCalibration.cc \ EventPlaneReco.cc # Rule for generating table CINT dictionaries. diff --git a/offline/packages/globalvertex/GlobalVertex.h b/offline/packages/globalvertex/GlobalVertex.h index 2a42abbba6..3124cea282 100644 --- a/offline/packages/globalvertex/GlobalVertex.h +++ b/offline/packages/globalvertex/GlobalVertex.h @@ -78,8 +78,8 @@ class GlobalVertex : public PHObject virtual float get_error(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual void set_error(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) { return; } - virtual unsigned int get_beam_crossing() const { return std::numeric_limits::max(); } - virtual void set_beam_crossing(unsigned int) { return; } + virtual short int get_beam_crossing() const { return std::numeric_limits::max(); } + virtual void set_beam_crossing(short int) { return; } virtual bool empty_vtxs() const { return true; } virtual size_t size_vtxs() const { return 0; } diff --git a/offline/packages/globalvertex/GlobalVertexMap.h b/offline/packages/globalvertex/GlobalVertexMap.h index 7ee70fa284..2ba8f6b0c6 100644 --- a/offline/packages/globalvertex/GlobalVertexMap.h +++ b/offline/packages/globalvertex/GlobalVertexMap.h @@ -3,9 +3,11 @@ #ifndef GLOBALVERTEX_GLOBALVERTEXMAP_H #define GLOBALVERTEX_GLOBALVERTEXMAP_H -#include #include "Vertex.h" #include "GlobalVertex.h" + +#include + #include #include @@ -15,7 +17,7 @@ class GlobalVertexMap : public PHObject typedef std::map::const_iterator ConstIter; typedef std::map::iterator Iter; - ~GlobalVertexMap() override {} + ~GlobalVertexMap() override = default; void identify(std::ostream& os = std::cout) const override { os << "GlobalVertexMap base class" << std::endl; } int isValid() const override { return 0; } @@ -42,7 +44,7 @@ class GlobalVertexMap : public PHObject virtual Iter end(); protected: - GlobalVertexMap() {} + GlobalVertexMap() = default; private: ClassDefOverride(GlobalVertexMap, 1); diff --git a/offline/packages/globalvertex/GlobalVertexReco.cc b/offline/packages/globalvertex/GlobalVertexReco.cc index 4f50bbc1b6..73681759cc 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.cc +++ b/offline/packages/globalvertex/GlobalVertexReco.cc @@ -3,7 +3,7 @@ //#include "GlobalVertex.h" // for GlobalVertex, GlobalVe... #include "GlobalVertexMap.h" // for GlobalVertexMap #include "GlobalVertexMapv1.h" -#include "GlobalVertexv2.h" +#include "GlobalVertexv3.h" #include "MbdVertex.h" #include "MbdVertexMap.h" #include "CaloVertex.h" @@ -140,7 +140,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } // we have a matching pair - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); vertex->clone_insert_vtx(GlobalVertex::SVTX, svtx); @@ -193,7 +193,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } // we have a standalone SVTX vertex - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); @@ -243,7 +243,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) continue; } - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); vertex->clone_insert_vtx(GlobalVertex::MBD, mbd); @@ -282,7 +282,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) continue; } - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); vertex->clone_insert_vtx(GlobalVertex::CALO, calo); @@ -337,7 +337,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) continue; } - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); vertex->clone_insert_vtx(GlobalVertex::CALO, calo); @@ -354,7 +354,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) } else { - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->set_id(globalmap->size()); vertex->clone_insert_vtx(GlobalVertex::MBD, mbd); @@ -393,7 +393,7 @@ int GlobalVertexReco::process_event(PHCompositeNode *topNode) tvertex->set_t(0); tvertex->set_t_err(0); // 0.1 - GlobalVertex *vertex = new GlobalVertexv2(); + GlobalVertex *vertex = new GlobalVertexv3(); vertex->clone_insert_vtx(GlobalVertex::TRUTH, tvertex); globalmap->insert(vertex); if (truthmap) diff --git a/offline/packages/globalvertex/GlobalVertexReco.h b/offline/packages/globalvertex/GlobalVertexReco.h index 1149a17220..34240cf32b 100644 --- a/offline/packages/globalvertex/GlobalVertexReco.h +++ b/offline/packages/globalvertex/GlobalVertexReco.h @@ -10,9 +10,10 @@ /// \author Mike McCumber //=========================================================== -#include #include "GlobalVertex.h" +#include + #include // for string class PHCompositeNode; diff --git a/offline/packages/globalvertex/GlobalVertexv2.h b/offline/packages/globalvertex/GlobalVertexv2.h index 06a4d637f0..4c7a077df7 100644 --- a/offline/packages/globalvertex/GlobalVertexv2.h +++ b/offline/packages/globalvertex/GlobalVertexv2.h @@ -29,8 +29,22 @@ class GlobalVertexv2 : public GlobalVertex unsigned int get_id() const override { return _id; } void set_id(unsigned int id) override { _id = id; } - unsigned int get_beam_crossing() const override { return _bco; } - void set_beam_crossing(unsigned int bco) override { _bco = bco; } + short int get_beam_crossing() const override + { + return rollover_from_unsignedint(_bco); + } + + void set_beam_crossing(short int bco) override + { + if (bco == short_int_max) + { + _bco = std::numeric_limits::max(); + return; + } + + const short int bco_ro = rollover_short(bco); + _bco = static_cast(bco_ro); + } float get_t() const override; float get_t_err() const override; @@ -65,6 +79,25 @@ class GlobalVertexv2 : public GlobalVertex GlobalVertex::VertexIter end_vertexes() override { return _vtxs.end(); } private: + static constexpr short int short_int_max = std::numeric_limits::max(); + + static short int rollover_short(short int bco) + { + if (bco == short_int_max) return short_int_max; + if (bco >= 0) return bco; + return static_cast(static_cast(short_int_max) + static_cast(bco)); + } + + static short int rollover_from_unsignedint(unsigned int bco) + { + if (bco == std::numeric_limits::max()) return short_int_max; + if (bco <= static_cast(short_int_max)) return static_cast(bco); + + const short int bco_ro = static_cast(static_cast(bco)); + if (bco_ro >= 0) return bco_ro; + return rollover_short(bco_ro); + } + unsigned int _id{std::numeric_limits::max()}; unsigned int _bco{std::numeric_limits::max()}; //< global bco std::map _vtxs; //< list of vtxs diff --git a/offline/packages/globalvertex/GlobalVertexv3.cc b/offline/packages/globalvertex/GlobalVertexv3.cc new file mode 100644 index 0000000000..4eca34c62c --- /dev/null +++ b/offline/packages/globalvertex/GlobalVertexv3.cc @@ -0,0 +1,236 @@ +#include "GlobalVertexv3.h" + +#include + +GlobalVertexv3::GlobalVertexv3(const unsigned int id) + : _id(id) +{ +} + +GlobalVertexv3::~GlobalVertexv3() +{ + GlobalVertexv3::Reset(); +} + +void GlobalVertexv3::Reset() +{ + for (auto& _vtx : _vtxs) + { + for (const auto* vertex : _vtx.second) + { + delete vertex; + } + } + _vtxs.clear(); +} + +void GlobalVertexv3::identify(std::ostream& os) const +{ + os << "---GlobalVertexv3-----------------------" << std::endl; + + os << " list of vtx ids: " << std::endl; + for (ConstVertexIter iter = begin_vertexes(); iter != end_vertexes(); ++iter) + { + os << " Vertex type " << iter->first << " has " << iter->second.size() + << " vertices associated to it" << std::endl; + for (const auto& vertex : iter->second) + { + vertex->identify(); + } + } + + os << "-----------------------------------------------" << std::endl; +} + +int GlobalVertexv3::isValid() const +{ + if (_vtxs.empty()) + { + return 0; + } + return 1; +} + +void GlobalVertexv3::insert_vtx(GlobalVertex::VTXTYPE type, const Vertex* vertex) +{ + auto it = _vtxs.find(type); + if (it == _vtxs.end()) + { + VertexVector vector; + vector.push_back(vertex); + _vtxs.insert(std::make_pair(type, vector)); + return; + } + + it->second.push_back(vertex); +} + +void GlobalVertexv3::clone_insert_vtx(GlobalVertex::VTXTYPE type, const Vertex* vertex) +{ + auto it = _vtxs.find(type); + Vertex* clone = dynamic_cast(vertex->CloneMe()); + if (it == _vtxs.end()) + { + VertexVector vector; + vector.push_back(clone); + _vtxs.insert(std::make_pair(type, vector)); + return; + } + + it->second.push_back(clone); +} + +size_t GlobalVertexv3::count_vtxs(GlobalVertex::VTXTYPE type) const +{ + auto it = _vtxs.find(type); + if (it == _vtxs.end()) + { + return 0; + } + + return it->second.size(); +} + +float GlobalVertexv3::get_t() const +{ + auto it = _vtxs.find(GlobalVertex::VTXTYPE::MBD); + if (it == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + + return it->second[0]->get_t(); +} + +float GlobalVertexv3::get_t_err() const +{ + auto it = _vtxs.find(GlobalVertex::VTXTYPE::MBD); + if (it == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + + return it->second[0]->get_t_err(); +} + +float GlobalVertexv3::get_x() const { return get_position(0); } +float GlobalVertexv3::get_y() const { return get_position(1); } +float GlobalVertexv3::get_z() const { return get_position(2); } + +float GlobalVertexv3::get_position(unsigned int coor) const +{ + auto svtxit = _vtxs.find(GlobalVertex::VTXTYPE::SVTX); + if (svtxit == _vtxs.end()) + { + auto mbdit = _vtxs.find(GlobalVertex::VTXTYPE::MBD); + if (mbdit == _vtxs.end()) + { + auto caloit = _vtxs.find(GlobalVertex::VTXTYPE::CALO); + if (caloit == _vtxs.end()) + { + auto truthit = _vtxs.find(GlobalVertex::VTXTYPE::TRUTH); + if (truthit == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + return truthit->second[0]->get_position(coor); + } + return caloit->second[0]->get_position(coor); + } + return mbdit->second[0]->get_position(coor); + } + + GlobalVertex::VertexVector trackvertices = svtxit->second; + size_t mosttracks = 0; + float pos = std::numeric_limits::quiet_NaN(); + for (const auto* vertex : trackvertices) + { + if (vertex->size_tracks() > mosttracks) + { + mosttracks = vertex->size_tracks(); + pos = vertex->get_position(coor); + } + } + + return pos; +} + +float GlobalVertexv3::get_chisq() const +{ + auto svtxit = _vtxs.find(GlobalVertex::VTXTYPE::SVTX); + if (svtxit == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + + GlobalVertex::VertexVector trackvertices = svtxit->second; + size_t mosttracks = 0; + float chisq = std::numeric_limits::quiet_NaN(); + for (const auto* vertex : trackvertices) + { + if (vertex->size_tracks() > mosttracks) + { + mosttracks = vertex->size_tracks(); + chisq = vertex->get_chisq(); + } + } + + return chisq; +} + +unsigned int GlobalVertexv3::get_ndof() const +{ + auto svtxit = _vtxs.find(GlobalVertex::VTXTYPE::SVTX); + if (svtxit == _vtxs.end()) + { + return std::numeric_limits::max(); + } + + GlobalVertex::VertexVector trackvertices = svtxit->second; + size_t mosttracks = 0; + unsigned int ndf = std::numeric_limits::max(); + for (const auto* vertex : trackvertices) + { + if (vertex->size_tracks() > mosttracks) + { + mosttracks = vertex->size_tracks(); + ndf = vertex->get_ndof(); + } + } + + return ndf; +} + +float GlobalVertexv3::get_error(unsigned int i, unsigned int j) const +{ + auto svtxit = _vtxs.find(GlobalVertex::VTXTYPE::SVTX); + if (svtxit == _vtxs.end()) + { + auto mbdit = _vtxs.find(GlobalVertex::VTXTYPE::MBD); + if (mbdit == _vtxs.end()) + { + return std::numeric_limits::quiet_NaN(); + } + // MBD only has z error defined + if (i == 2 && j == 2) + { + return mbdit->second[0]->get_z_err(); + } + + return std::numeric_limits::quiet_NaN(); + } + + GlobalVertex::VertexVector trackvertices = svtxit->second; + size_t mosttracks = 0; + float err = std::numeric_limits::quiet_NaN(); + for (const auto* vertex : trackvertices) + { + if (vertex->size_tracks() > mosttracks) + { + mosttracks = vertex->size_tracks(); + err = vertex->get_error(i, j); + } + } + + return err; +} diff --git a/offline/packages/globalvertex/GlobalVertexv3.h b/offline/packages/globalvertex/GlobalVertexv3.h new file mode 100644 index 0000000000..c89e51e5c9 --- /dev/null +++ b/offline/packages/globalvertex/GlobalVertexv3.h @@ -0,0 +1,73 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef GLOBALVERTEX_GLOBALVERTEXV3_H +#define GLOBALVERTEX_GLOBALVERTEXV3_H + +#include "GlobalVertex.h" + +#include // for size_t +#include +#include +#include + +class PHObject; + +class GlobalVertexv3 : public GlobalVertex +{ + public: + GlobalVertexv3() = default; + GlobalVertexv3(const unsigned int id); + ~GlobalVertexv3() override; + + // PHObject virtual overloads + void identify(std::ostream& os = std::cout) const override; + void Reset() override; + int isValid() const override; + PHObject* CloneMe() const override { return new GlobalVertexv3(*this); } + + unsigned int get_id() const override { return _id; } + void set_id(unsigned int id) override { _id = id; } + + short int get_beam_crossing() const override { return _bco; } + void set_beam_crossing(short int bco) override { _bco = bco; } + + float get_t() const override; + float get_t_err() const override; + float get_x() const override; + float get_y() const override; + float get_z() const override; + float get_chisq() const override; + unsigned int get_ndof() const override; + float get_position(unsigned int coor) const override; + float get_error(unsigned int i, unsigned int j) const override; + + // + // associated vertex methods + // + bool empty_vtxs() const override { return _vtxs.empty(); } + size_t size_vtxs() const override { return _vtxs.size(); } + size_t count_vtxs(GlobalVertex::VTXTYPE type) const override; + + void clear_vtxs() override { _vtxs.clear(); } + void insert_vtx(GlobalVertex::VTXTYPE type, const Vertex* vertex) override; + void clone_insert_vtx(GlobalVertex::VTXTYPE type, const Vertex* vertex) override; + size_t erase_vtxs(GlobalVertex::VTXTYPE type) override { return _vtxs.erase(type); } + void erase_vtxs(GlobalVertex::VertexIter iter) override { _vtxs.erase(iter); } + + GlobalVertex::ConstVertexIter begin_vertexes() const override { return _vtxs.begin(); } + GlobalVertex::ConstVertexIter find_vertexes(GlobalVertex::VTXTYPE type) const override { return _vtxs.find(type); } + GlobalVertex::ConstVertexIter end_vertexes() const override { return _vtxs.end(); } + + GlobalVertex::VertexIter begin_vertexes() override { return _vtxs.begin(); } + GlobalVertex::VertexIter find_vertexes(GlobalVertex::VTXTYPE type) override { return _vtxs.find(type); } + GlobalVertex::VertexIter end_vertexes() override { return _vtxs.end(); } + + private: + unsigned int _id{std::numeric_limits::max()}; + short int _bco{std::numeric_limits::max()}; //< global bco (signed short) + std::map _vtxs; //< list of vtxs + + ClassDefOverride(GlobalVertexv3, 3); +}; + +#endif diff --git a/offline/packages/globalvertex/GlobalVertexv3LinkDef.h b/offline/packages/globalvertex/GlobalVertexv3LinkDef.h new file mode 100644 index 0000000000..8cd2f1abf7 --- /dev/null +++ b/offline/packages/globalvertex/GlobalVertexv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class GlobalVertexv3 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/globalvertex/Makefile.am b/offline/packages/globalvertex/Makefile.am index 5cedef884d..0ff0587389 100644 --- a/offline/packages/globalvertex/Makefile.am +++ b/offline/packages/globalvertex/Makefile.am @@ -30,17 +30,20 @@ pkginclude_HEADERS = \ GlobalVertex.h \ GlobalVertexv1.h \ GlobalVertexv2.h \ + GlobalVertexv3.h \ GlobalVertexMap.h \ GlobalVertexMapv1.h \ GlobalVertexReco.h \ MbdVertex.h \ MbdVertexv1.h \ MbdVertexv2.h \ + MbdVertexv3.h \ MbdVertexMap.h \ MbdVertexMapv1.h \ SvtxVertex.h \ SvtxVertex_v1.h \ SvtxVertex_v2.h \ + SvtxVertex_v3.h \ SvtxVertexMap.h \ SvtxVertexMap_v1.h \ TruthVertex.h \ @@ -57,16 +60,19 @@ ROOTDICTS = \ GlobalVertex_Dict.cc \ GlobalVertexv1_Dict.cc \ GlobalVertexv2_Dict.cc \ + GlobalVertexv3_Dict.cc \ GlobalVertexMap_Dict.cc \ GlobalVertexMapv1_Dict.cc \ MbdVertex_Dict.cc \ MbdVertexv1_Dict.cc \ MbdVertexv2_Dict.cc \ + MbdVertexv3_Dict.cc \ MbdVertexMap_Dict.cc \ MbdVertexMapv1_Dict.cc \ SvtxVertex_Dict.cc \ SvtxVertex_v1_Dict.cc \ SvtxVertex_v2_Dict.cc \ + SvtxVertex_v3_Dict.cc \ SvtxVertexMap_Dict.cc \ SvtxVertexMap_v1_Dict.cc \ TruthVertex_Dict.cc \ @@ -87,15 +93,18 @@ libglobalvertex_io_la_SOURCES = \ GlobalVertex.cc \ GlobalVertexv1.cc \ GlobalVertexv2.cc \ + GlobalVertexv3.cc \ GlobalVertexMap.cc \ GlobalVertexMapv1.cc \ MbdVertexv1.cc \ MbdVertexv2.cc \ + MbdVertexv3.cc \ MbdVertexMap.cc \ MbdVertexMapv1.cc \ SvtxVertex.cc \ SvtxVertex_v1.cc \ SvtxVertex_v2.cc \ + SvtxVertex_v3.cc \ SvtxVertexMap.cc \ SvtxVertexMap_v1.cc \ TruthVertex.cc \ diff --git a/offline/packages/globalvertex/MbdVertex.h b/offline/packages/globalvertex/MbdVertex.h index 6d0900b768..ed8d18e1d8 100644 --- a/offline/packages/globalvertex/MbdVertex.h +++ b/offline/packages/globalvertex/MbdVertex.h @@ -36,8 +36,12 @@ class MbdVertex : public Vertex virtual float get_z_err() const override { return std::numeric_limits::quiet_NaN(); } virtual void set_z_err(float) override {} - virtual unsigned int get_beam_crossing() const override { return std::numeric_limits::max(); } - virtual void set_beam_crossing(unsigned int) override {} + virtual short int get_beam_crossing() const override + { + return std::numeric_limits::max(); + } + virtual void set_beam_crossing(short int) override {} + virtual void set_bbc_ns(int, int, float, float) override {} virtual int get_bbc_npmt(int) const override { return std::numeric_limits::max(); } diff --git a/offline/packages/globalvertex/MbdVertexv2.h b/offline/packages/globalvertex/MbdVertexv2.h index bee34059e4..3b3482ed4f 100644 --- a/offline/packages/globalvertex/MbdVertexv2.h +++ b/offline/packages/globalvertex/MbdVertexv2.h @@ -44,12 +44,56 @@ class MbdVertexv2 : public MbdVertex float get_position(unsigned int coor) const override; - unsigned int get_beam_crossing() const override { return _bco; } - void set_beam_crossing(unsigned int bco) override { _bco = bco; } + short int get_beam_crossing() const override + { + return rollover_from_unsignedint(_bco); + } + void set_beam_crossing(short int bco) override + { + if (bco == short_int_max) + { + _bco = std::numeric_limits::max(); + return; + } + + const short int bco_ro = rollover_short(bco); + _bco = static_cast(bco_ro); + } private: + static constexpr short int short_int_max = std::numeric_limits::max(); // 32767 + + static short int rollover_short(short int bco) + { + if (bco == short_int_max) return short_int_max; + if (bco >= 0) return bco; + + const int bco_ro = static_cast(short_int_max) + static_cast(bco); // bco negative + return static_cast(bco_ro); + } + + static short int rollover_from_unsignedint(unsigned int bco) + { + // if unsigned int max, return short int max + if (bco == std::numeric_limits::max()) + { + return short_int_max; + } + + // common case: [0, 32767] + if (bco <= static_cast(short_int_max)) + { + return static_cast(bco); + } + + const short int bco_ro = static_cast(static_cast(bco)); + if (bco_ro >= 0) return bco_ro; + + return rollover_short(bco_ro); + } + unsigned int _id{std::numeric_limits::max()}; //< unique identifier within container - unsigned int _bco{std::numeric_limits::max()}; //< global bco + unsigned int _bco{std::numeric_limits::max()}; //< global bco (legacy storage) float _t{std::numeric_limits::quiet_NaN()}; //< collision time float _t_err{std::numeric_limits::quiet_NaN()}; //< collision time uncertainty float _z{std::numeric_limits::quiet_NaN()}; //< collision position z diff --git a/offline/packages/globalvertex/MbdVertexv3.cc b/offline/packages/globalvertex/MbdVertexv3.cc new file mode 100644 index 0000000000..9c76f521a3 --- /dev/null +++ b/offline/packages/globalvertex/MbdVertexv3.cc @@ -0,0 +1,60 @@ +#include "MbdVertexv3.h" + +#include +#include + +void MbdVertexv3::identify(std::ostream& os) const +{ + os << "---MbdVertexv3--------------------------------" << std::endl; + os << "vertexid: " << get_id() << std::endl; + os << " t = " << get_t() << " +/- " << get_t_err() << std::endl; + os << " z = " << get_z() << " +/- " << get_z_err() << std::endl; + os << " bco = " << get_beam_crossing() << std::endl; + os << "-----------------------------------------------" << std::endl; + + return; +} + +int MbdVertexv3::isValid() const +{ + if (_id == std::numeric_limits::max()) + { + return 0; + } + if (std::isnan(_t)) + { + return 0; + } + if (std::isnan(_t_err)) + { + return 0; + } + if (std::isnan(_z)) + { + return 0; + } + if (std::isnan(_z_err)) + { + return 0; + } + + return 1; +} + +float MbdVertexv3::get_position(unsigned int coor) const +{ + if (coor == 0) + { + return get_x(); + } + if (coor == 1) + { + return get_y(); + } + if (coor == 2) + { + return get_z(); + } + + return std::numeric_limits::quiet_NaN(); +} diff --git a/offline/packages/globalvertex/MbdVertexv3.h b/offline/packages/globalvertex/MbdVertexv3.h new file mode 100644 index 0000000000..7d59c82d79 --- /dev/null +++ b/offline/packages/globalvertex/MbdVertexv3.h @@ -0,0 +1,60 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef GLOBALVERTEX_MBDVERTEXV3_H +#define GLOBALVERTEX_MBDVERTEXV3_H + +#include "MbdVertex.h" + +#include +#include + +class MbdVertexv3 : public MbdVertex +{ + public: + MbdVertexv3() = default; + ~MbdVertexv3() override = default; + + // PHObject virtual overloads + void identify(std::ostream& os = std::cout) const override; + void Reset() override { *this = MbdVertexv3(); } + int isValid() const override; + PHObject* CloneMe() const override { return new MbdVertexv3(*this); } + + // vertex info + unsigned int get_id() const override { return _id; } + void set_id(unsigned int id) override { _id = id; } + + float get_t() const override { return _t; } + void set_t(float t) override { _t = t; } + + float get_t_err() const override { return _t_err; } + void set_t_err(float t_err) override { _t_err = t_err; } + + // Return 0 for now, can implement beam spot + float get_x() const override { return 0; } + float get_y() const override { return 0; } + + float get_z() const override { return _z; } + void set_z(float z) override { _z = z; } + + float get_z_err() const override { return _z_err; } + void set_z_err(float z_err) override { _z_err = z_err; } + + float get_position(unsigned int coor) const override; + + // beam crossing methods (v3: native signed short storage) + short int get_beam_crossing() const override { return _bco; } + void set_beam_crossing(short int bco) override { _bco = bco; } + + private: + unsigned int _id{std::numeric_limits::max()}; //< unique identifier within container + short int _bco{std::numeric_limits::max()}; //< global bco (signed short) + float _t{std::numeric_limits::quiet_NaN()}; //< collision time + float _t_err{std::numeric_limits::quiet_NaN()}; //< collision time uncertainty + float _z{std::numeric_limits::quiet_NaN()}; //< collision position z + float _z_err{std::numeric_limits::quiet_NaN()}; //< collision position z uncertainty + + ClassDefOverride(MbdVertexv3, 1); +}; + +#endif diff --git a/offline/packages/globalvertex/MbdVertexv3LinkDef.h b/offline/packages/globalvertex/MbdVertexv3LinkDef.h new file mode 100644 index 0000000000..b55e4bf42d --- /dev/null +++ b/offline/packages/globalvertex/MbdVertexv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class MbdVertexv3 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/globalvertex/SvtxVertex_v2.h b/offline/packages/globalvertex/SvtxVertex_v2.h index 24ccbfc0ca..32d19eda66 100644 --- a/offline/packages/globalvertex/SvtxVertex_v2.h +++ b/offline/packages/globalvertex/SvtxVertex_v2.h @@ -54,8 +54,21 @@ class SvtxVertex_v2 : public SvtxVertex float get_error(unsigned int i, unsigned int j) const override; //< get vertex error covar void set_error(unsigned int i, unsigned int j, float value) override; //< set vertex error covar - unsigned int get_beam_crossing() const override { return _beamcrossing; } - void set_beam_crossing(unsigned int cross) override { _beamcrossing = cross; } + short int get_beam_crossing() const override + { + return rollover_from_unsignedint(_beamcrossing); + } + void set_beam_crossing(short int cross) override + { + if (cross == short_int_max) + { + _beamcrossing = std::numeric_limits::max(); + return; + } + + const short int cross_ro = rollover_short(cross); + _beamcrossing = static_cast(cross_ro); + } // // associated track ids methods @@ -73,6 +86,37 @@ class SvtxVertex_v2 : public SvtxVertex TrackIter end_tracks() override { return _track_ids.end(); } private: + static constexpr short int short_int_max = std::numeric_limits::max(); // 32767 + // for unsigned int to short int conversion (rollover) + static short int rollover_short(short int cross) + { + if (cross == short_int_max) return short_int_max; + if (cross >= 0) return cross; + + const int cross_ro = static_cast(short_int_max) + static_cast(cross); // cross negative + return static_cast(cross_ro); + } + + static short int rollover_from_unsignedint(unsigned int cross) + { + // if unsigned int max, return short int max + if (cross == std::numeric_limits::max()) + { + return short_int_max; + } + + // Common case: [0, 32767] + if (cross <= static_cast(short_int_max)) + { + return static_cast(cross); + } + + const short int cross_ro = static_cast(static_cast(cross)); + if (cross_ro >= 0) return cross_ro; + + return rollover_short(cross_ro); + } + unsigned int covar_index(unsigned int i, unsigned int j) const; unsigned int _id{std::numeric_limits::max()}; //< unique identifier within container diff --git a/offline/packages/globalvertex/SvtxVertex_v3.cc b/offline/packages/globalvertex/SvtxVertex_v3.cc new file mode 100644 index 0000000000..731a2c841f --- /dev/null +++ b/offline/packages/globalvertex/SvtxVertex_v3.cc @@ -0,0 +1,113 @@ +#include "SvtxVertex_v3.h" + +#include +#include +#include +#include // for swap + +SvtxVertex_v3::SvtxVertex_v3() +{ + std::fill(std::begin(_pos), std::end(_pos), std::numeric_limits::quiet_NaN()); + std::fill(std::begin(_err), std::end(_err), std::numeric_limits::quiet_NaN()); +} + +void SvtxVertex_v3::identify(std::ostream& os) const +{ + os << "---SvtxVertex_v3--------------------" << std::endl; + os << "vertexid: " << get_id() << std::endl; + + os << " t0 = " << get_t() << std::endl; + os << " beam crossing = " << get_beam_crossing() << std::endl; + os << " (x,y,z) = (" << get_position(0); + os << ", " << get_position(1) << ", "; + os << get_position(2) << ") cm" << std::endl; + + os << " chisq = " << get_chisq() << ", "; + os << " ndof = " << get_ndof() << std::endl; + + os << " ( "; + os << get_error(0, 0) << " , "; + os << get_error(0, 1) << " , "; + os << get_error(0, 2) << " )" << std::endl; + os << " err = ( "; + os << get_error(1, 0) << " , "; + os << get_error(1, 1) << " , "; + os << get_error(1, 2) << " )" << std::endl; + os << " ( "; + os << get_error(2, 0) << " , "; + os << get_error(2, 1) << " , "; + os << get_error(2, 2) << " )" << std::endl; + + os << " list of tracks ids: "; + for (ConstTrackIter iter = begin_tracks(); iter != end_tracks(); ++iter) + { + os << *iter << " "; + } + os << std::endl; + os << "-----------------------------------------------" << std::endl; + + return; +} + +int SvtxVertex_v3::isValid() const +{ + if (_id == std::numeric_limits::max()) + { + return 0; + } + if (std::isnan(_t0)) + { + return 0; + } + if (std::isnan(_chisq)) + { + return 0; + } + if (_ndof == std::numeric_limits::max()) + { + return 0; + } + + for (float _po : _pos) + { + if (std::isnan(_po)) + { + return 0; + } + } + for (int j = 0; j < 3; ++j) + { + for (int i = j; i < 3; ++i) + { + if (std::isnan(get_error(i, j))) + { + return 0; + } + } + } + if (_track_ids.empty()) + { + return 0; + } + return 1; +} + +void SvtxVertex_v3::set_error(unsigned int i, unsigned int j, float value) +{ + _err[covar_index(i, j)] = value; + return; +} + +float SvtxVertex_v3::get_error(unsigned int i, unsigned int j) const +{ + return _err[covar_index(i, j)]; +} + +unsigned int SvtxVertex_v3::covar_index(unsigned int i, unsigned int j) const +{ + if (i > j) + { + std::swap(i, j); + } + return i + 1 + (j + 1) * (j) / 2 - 1; +} diff --git a/offline/packages/globalvertex/SvtxVertex_v3.h b/offline/packages/globalvertex/SvtxVertex_v3.h new file mode 100644 index 0000000000..74a75d90ea --- /dev/null +++ b/offline/packages/globalvertex/SvtxVertex_v3.h @@ -0,0 +1,89 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef GLOBALVERTEX_SVTXVERTEXV3_H +#define GLOBALVERTEX_SVTXVERTEXV3_H + +#include "SvtxVertex.h" + +#include // for size_t +#include +#include +#include + +class PHObject; + +class SvtxVertex_v3 : public SvtxVertex +{ + public: + SvtxVertex_v3(); + ~SvtxVertex_v3() override {} + + // PHObject virtual overloads + void identify(std::ostream& os = std::cout) const override; + void Reset() override { *this = SvtxVertex_v3(); } + int isValid() const override; + PHObject* CloneMe() const override { return new SvtxVertex_v3(*this); } + + // vertex info + unsigned int get_id() const override { return _id; } + void set_id(unsigned int id) override { _id = id; } + + float get_t() const override { return _t0; } + void set_t(float t0) override { _t0 = t0; } + + float get_x() const override { return _pos[0]; } + void set_x(float x) override { _pos[0] = x; } + + float get_y() const override { return _pos[1]; } + void set_y(float y) override { _pos[1] = y; } + + float get_z() const override { return _pos[2]; } + void set_z(float z) override { _pos[2] = z; } + + float get_chisq() const override { return _chisq; } + void set_chisq(float chisq) override { _chisq = chisq; } + + unsigned int get_ndof() const override { return _ndof; } + void set_ndof(unsigned int ndof) override { _ndof = ndof; } + + float get_position(unsigned int coor) const override { return _pos[coor]; } + void set_position(unsigned int coor, float xi) override { _pos[coor] = xi; } + + float get_error(unsigned int i, unsigned int j) const override; //< get vertex error covar + void set_error(unsigned int i, unsigned int j, float value) override; //< set vertex error covar + + // v3 uses signed short + short int get_beam_crossing() const override { return _beamcrossing; } + void set_beam_crossing(short int cross) override { _beamcrossing = cross; } + + // + // associated track ids methods + // + void clear_tracks() override { _track_ids.clear(); } + bool empty_tracks() override { return _track_ids.empty(); } + size_t size_tracks() const override { return _track_ids.size(); } + void insert_track(unsigned int trackid) override { _track_ids.insert(trackid); } + size_t erase_track(unsigned int trackid) override { return _track_ids.erase(trackid); } + ConstTrackIter begin_tracks() const override { return _track_ids.begin(); } + ConstTrackIter find_track(unsigned int trackid) const override { return _track_ids.find(trackid); } + ConstTrackIter end_tracks() const override { return _track_ids.end(); } + TrackIter begin_tracks() override { return _track_ids.begin(); } + TrackIter find_track(unsigned int trackid) override { return _track_ids.find(trackid); } + TrackIter end_tracks() override { return _track_ids.end(); } + + private: + unsigned int covar_index(unsigned int i, unsigned int j) const; + + unsigned int _id{std::numeric_limits::max()}; //< unique identifier within container + float _t0{std::numeric_limits::quiet_NaN()}; //< collision time + float _pos[3]{}; //< collision position x,y,z + float _chisq{std::numeric_limits::quiet_NaN()}; //< vertex fit chisq + unsigned int _ndof{std::numeric_limits::max()}; //< degrees of freedom + float _err[6]{}; //< error covariance matrix (packed storage) (+/- cm^2) + std::set _track_ids; //< list of track ids + short int _beamcrossing{std::numeric_limits::max()}; + + ClassDefOverride(SvtxVertex_v3, 3); +}; + +#endif diff --git a/offline/packages/globalvertex/SvtxVertex_v3LinkDef.h b/offline/packages/globalvertex/SvtxVertex_v3LinkDef.h new file mode 100644 index 0000000000..7b6506845d --- /dev/null +++ b/offline/packages/globalvertex/SvtxVertex_v3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class SvtxVertex_v3 + ; + +#endif /* __CINT__ */ diff --git a/offline/packages/globalvertex/TruthVertex_v1.cc b/offline/packages/globalvertex/TruthVertex_v1.cc index 38e9b2a61b..1c1ad39f4d 100644 --- a/offline/packages/globalvertex/TruthVertex_v1.cc +++ b/offline/packages/globalvertex/TruthVertex_v1.cc @@ -15,3 +15,21 @@ int TruthVertex_v1::isValid() const { return std::isfinite(_z) && std::isfinite(_t); } + +float TruthVertex_v1::get_position(unsigned int coor) const +{ + if (coor == 0) + { + return get_x(); + } + if (coor == 1) + { + return get_y(); + } + if (coor == 2) + { + return get_z(); + } + + return std::numeric_limits::quiet_NaN(); +} \ No newline at end of file diff --git a/offline/packages/globalvertex/TruthVertex_v1.h b/offline/packages/globalvertex/TruthVertex_v1.h index 42b48d9903..e5148387af 100644 --- a/offline/packages/globalvertex/TruthVertex_v1.h +++ b/offline/packages/globalvertex/TruthVertex_v1.h @@ -46,6 +46,7 @@ class TruthVertex_v1 : public TruthVertex float get_y_err() const override { return _y_err; } void set_y_err(float y_err) override { _y_err = y_err; } + float get_position(unsigned int coor) const override; private: unsigned int _id{std::numeric_limits::max()}; float _t{std::numeric_limits::quiet_NaN()}; diff --git a/offline/packages/globalvertex/Vertex.h b/offline/packages/globalvertex/Vertex.h index 7bbfa5f381..e475bfb95d 100644 --- a/offline/packages/globalvertex/Vertex.h +++ b/offline/packages/globalvertex/Vertex.h @@ -62,8 +62,8 @@ class Vertex : public PHObject virtual void set_error(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} // beam crossing methods - virtual unsigned int get_beam_crossing() const { return std::numeric_limits::max(); } - virtual void set_beam_crossing(unsigned int) {} + virtual short int get_beam_crossing() const { return std::numeric_limits::max(); } + virtual void set_beam_crossing(short int) {} // bbcvertex methods virtual void set_bbc_ns(int, int, float, float) {} diff --git a/offline/packages/intt/CylinderGeomInttHelper.cc b/offline/packages/intt/CylinderGeomInttHelper.cc index 952002c7ba..979ee6d0d7 100644 --- a/offline/packages/intt/CylinderGeomInttHelper.cc +++ b/offline/packages/intt/CylinderGeomInttHelper.cc @@ -18,7 +18,7 @@ TVector3 CylinderGeomInttHelper::get_world_from_local_coords(const Surface& surf Acts::Vector3 loc(local.x(), local.y(), local.z()); loc *= Acts::UnitConstants::cm; - Acts::Vector3 glob = surface->transform(tGeometry->geometry().getGeoContext()) * loc; + Acts::Vector3 glob = surface->localToGlobalTransform(tGeometry->geometry().getGeoContext()) * loc; glob /= Acts::UnitConstants::cm; return TVector3(glob(0), glob(1), glob(2)); } @@ -53,7 +53,7 @@ TVector3 CylinderGeomInttHelper::get_local_from_world_coords(const Surface& surf global(2) = world[2]; global *= Acts::UnitConstants::cm; - Acts::Vector3 local = surface->transform(tGeometry->geometry().getGeoContext()).inverse() * global; + Acts::Vector3 local = surface->localToGlobalTransform(tGeometry->geometry().getGeoContext()).inverse() * global; local /= Acts::UnitConstants::cm; diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.cc b/offline/packages/intt/InttCombinedRawDataDecoder.cc index 18db00ef01..de20509f1c 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.cc +++ b/offline/packages/intt/InttCombinedRawDataDecoder.cc @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -18,7 +18,12 @@ #include #include +#include +#include +#include + +#include #include #include // for PHIODataNode #include @@ -35,8 +40,9 @@ InttCombinedRawDataDecoder::InttCombinedRawDataDecoder(std::string const& name) : SubsysReco(name) - , m_calibinfoDAC({"INTT_DACMAP", CDB}) + // , m_calibinfoDAC({"INTT_DACMAP", CDB}) , m_calibinfoBCO({"INTT_BCOMAP", CDB}) + , m_intt_dac_values(0) { // Do nothing // Consider calling LoadHotChannelMapRemote() @@ -128,17 +134,60 @@ int InttCombinedRawDataDecoder::InitRun(PHCompositeNode* topNode) } /////////////////////////////////////// - std::cout << "calibinfo DAC : " << m_calibinfoDAC.first << " " << (m_calibinfoDAC.second == CDB ? "CDB" : "FILE") << std::endl; - m_dacmap.Verbosity(Verbosity()); - if (m_calibinfoDAC.second == CDB) - { - m_dacmap.LoadFromCDB(m_calibinfoDAC.first); - } - else + recoConsts *rc = recoConsts::instance(); + int run_number = rc->get_IntFlag("RUNNUMBER"); + + odbc::Statement* statement = DBInterface::instance()->getStatement("daq"); + if (!statement) { - m_dacmap.LoadFromFile(m_calibinfoDAC.first); + std::cerr << PHWHERE << "\n" + << "\tCould not get ODBC statement for 'daq' database\n" + << "\tExiting\n" + << std::flush; + exit(1); + gSystem->Exit(1); } + if (DACValue_set_count == 0){ + std::cout<< PHWHERE << ", " << "No manual setting for DAC values. Querying INTT DAC values from intt_setting table for run number " << run_number << std::endl; + int error_count = InttCombinedRawDataDecoder::QueryAllDACValues(statement, run_number); + + int count_minus = 0; + for (const auto& dac_value : m_intt_dac_values) + { + if (dac_value <= 0) {count_minus++;} + } + + if (error_count != 0 || m_intt_dac_values.size() != 8 || count_minus != 0) + { + std::cerr << PHWHERE << "\n" + << "\tError retrieving DAC values. error_count: " << error_count + << ", size of m_intt_dac_values: " << m_intt_dac_values.size() << std::endl; + std:: cout << "In the dac map: "; + for (size_t i = 0; i < m_intt_dac_values.size(); ++i) + { + std::cout << "dac" << i << ": " << m_intt_dac_values[i] << ", "; + } + std::cout << std::endl; + std::cout<< " The DAC values should be 8 integers and all should be positive. Exiting."<< std::endl; + std::cout<< " Please contact the INTT group if the run you analyzed doesn't appear in the intt_setting table."<< std::endl; + + exit(1); + gSystem->Exit(1); + } + } + + // std::cout << "calibinfo DAC : " << m_calibinfoDAC.first << " " << (m_calibinfoDAC.second == CDB ? "CDB" : "FILE") << std::endl; + // m_dacmap.Verbosity(Verbosity()); + // if (m_calibinfoDAC.second == CDB) + // { + // m_dacmap.LoadFromCDB(m_calibinfoDAC.first); + // } + // else + // { + // m_dacmap.LoadFromFile(m_calibinfoDAC.first); + // } + /////////////////////////////////////// std::cout << "calibinfo BCO : " << m_calibinfoBCO.first << " " << (m_calibinfoBCO.second == CDB ? "CDB" : "FILE") << std::endl; m_bcomap.Verbosity(Verbosity()); @@ -302,6 +351,19 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) continue; } + if (std::find(permanant_mask_chip.begin(), permanant_mask_chip.end(), std::format("{}_{}_{}", raw.felix_server, raw.felix_channel, raw.chip)) != permanant_mask_chip.end()) + { + if (1 < Verbosity()) + { + std::cout + << PHWHERE << "\n" + << "\tMasking permanant bad chip due to timing issues:\n" + << "\t" << raw.felix_server << " " << raw.felix_channel << " " << raw.chip << " " << raw.channel << "\n" + << std::endl; + } + continue; + } + //////////////////////// // bco filter if (m_bcomap.IsBad(raw, bco_full, bco) && m_bcoFilter) @@ -429,11 +491,19 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) //////////////////////// // dac conversion - int dac = m_dacmap.GetDAC(raw, adc); + // int dac = m_dacmap.GetDAC(raw, adc); + int dac = (adc >= 0 && adc <= 7) ? m_intt_dac_values[adc] : -1; + + if (Verbosity() > 100000){ + std::cout<< PHWHERE << "\n" << "ADC value: " << adc << ", converted DAC value: " << dac << std::endl; + } + - hit = new TrkrHitv2; + hit = new TrkrHitv3; //--hit->setAdc(adc); hit->setAdc(dac); + hit->setFPHXBCO(intthit->get_FPHX_BCO()); + hit->setBCO(intthit->get_bco()); hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } @@ -441,3 +511,70 @@ int InttCombinedRawDataDecoder::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } + + +void InttCombinedRawDataDecoder::set_DACValues(const std::vector& input_dac_vec) +{ + m_intt_dac_values = input_dac_vec; + DACValue_set_count = 1; + int count_minus = 0; + std::cout<Exit(1); + } +} + +int InttCombinedRawDataDecoder::QueryAllDACValues(odbc::Statement *statement, int runnumber) +{ + + std::unique_ptr result_set; + m_intt_dac_values.clear(); + + try + { + std::string sql = "SELECT dac0, dac1, dac2, dac3, dac4, dac5, dac6, dac7 From intt_setting WHERE runnumber = " + std::to_string(runnumber) + ";"; + result_set = std::unique_ptr(statement->executeQuery(sql)); + + if (!(result_set && result_set->next())) + { + std::cerr << PHWHERE << "\n" + << "\tNo DAC row found in intt_setting for run " << runnumber << std::endl; + return 1; + } + for (int i = 0; i < 8; i++) + { + std::string column_name = "dac" + std::to_string(i); + int DAC_value = -1; + DAC_value = result_set->getInt(column_name); + m_intt_dac_values.push_back(DAC_value); + std::cout << PHWHERE << ", retrieved DAC value for " << column_name << ": " << DAC_value << std::endl; + } + } + catch (odbc::SQLException& e) + { + std::cerr << PHWHERE << "\n" + << "\tSQL Exception:\n" + << "\t" << e.getMessage() << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/offline/packages/intt/InttCombinedRawDataDecoder.h b/offline/packages/intt/InttCombinedRawDataDecoder.h index 1ebb71200e..642f2edafa 100644 --- a/offline/packages/intt/InttCombinedRawDataDecoder.h +++ b/offline/packages/intt/InttCombinedRawDataDecoder.h @@ -3,12 +3,13 @@ #include "InttBadChannelMap.h" #include "InttBCOMap.h" -#include "InttDacMap.h" +// #include "InttDacMap.h" #include #include #include +#include #include #include #include @@ -17,6 +18,11 @@ class PHCompositeNode; class InttEventInfo; +namespace odbc +{ + class Statement; +} // namespace odbc + class InttCombinedRawDataDecoder : public SubsysReco { public: @@ -40,10 +46,10 @@ class InttCombinedRawDataDecoder : public SubsysReco /// Depreciated; use LoadHotChannelMap(const std::string&); int LoadHotChannelMapRemote(std::string const& s = "INTT_HotChannelMap") {return LoadBadChannelMap(s);} - void SetCalibDAC(std::string const& calibname = "INTT_DACMAP", const CalibRef& calibref = CDB) - { - m_calibinfoDAC = std::pair(calibname, calibref); - } + // void SetCalibDAC(std::string const& calibname = "INTT_DACMAP", const CalibRef& calibref = CDB) + // { + // m_calibinfoDAC = std::pair(calibname, calibref); + // } void SetCalibBCO(std::string const& calibname = "INTT_BCOMAP", const CalibRef& calibref = CDB) { @@ -60,21 +66,27 @@ class InttCombinedRawDataDecoder : public SubsysReco void set_bcoFilter(bool flag) {m_bcoFilter = flag; } void set_SaturatedChipRejection(bool flag){m_SaturatedChipRejection = flag;} // note : this is for removing a fraction of the saturated chips void set_HighChipMultiplicityCut(int cut){HighChipMultiplicityCut = cut;} + void set_DACValues(const std::vector& input_dac_vec); private: + int QueryAllDACValues(odbc::Statement *statement, int runnumber); + InttEventInfo* intt_event_header = nullptr; std::string m_InttRawNodeName = "INTTRAWHIT"; bool m_runStandAlone = false; bool m_writeInttEventHeader = false; bool m_bcoFilter = false; bool m_SaturatedChipRejection = true; // note : true as default - std::pair m_calibinfoDAC; + // std::pair m_calibinfoDAC; std::pair m_calibinfoBCO; InttBadChannelMap m_badmap; - InttDacMap m_dacmap; + // InttDacMap m_dacmap; InttBCOMap m_bcomap; + std::vector m_intt_dac_values; + int DACValue_set_count = 0; + int m_inttFeeOffset = 23; //23 is the offset for INTT in streaming mode bool m_outputBcoDiff = false; bool m_triggeredMode = false; @@ -83,6 +95,10 @@ class InttCombinedRawDataDecoder : public SubsysReco std::map evt_ChipHit_count_map; int HighChipMultiplicityCut = 71; + std::vector permanant_mask_chip = { + "2_9_15" // note : FELIX 2, FELIX channel 9, chip 15 (chip ID range: 0 to 25) + }; + }; #endif // INTT_COMBINEDRAWDATADECODER_H diff --git a/offline/packages/jetbackground/DetermineTowerBackground.cc b/offline/packages/jetbackground/DetermineTowerBackground.cc index 9823d337f6..64ffd50835 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.cc +++ b/offline/packages/jetbackground/DetermineTowerBackground.cc @@ -14,6 +14,10 @@ #include #include +#include +#include +#include + #include #include @@ -52,9 +56,57 @@ DetermineTowerBackground::DetermineTowerBackground(const std::string &name) int DetermineTowerBackground::InitRun(PHCompositeNode *topNode) { + if (_do_flow == 4) + { + if (Verbosity()) + { + std::cout << "Loading the average calo v2" << std::endl; + } + if (LoadCalibrations()) + { + std::cout << "Load calibrations failed." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + } + return CreateNode(topNode); } +int DetermineTowerBackground::LoadCalibrations() +{ + + CDBTTree *cdbtree_calo_v2 = nullptr; + + std::string calibdir = CDBInterface::instance()->getUrl(m_calibName); + if (m_overwrite_average_calo_v2) + { + calibdir = m_overwrite_average_calo_v2_path; + } + + if (calibdir.empty()) + { + std::cout << "Could not find filename for calo average v2, exiting" << std::endl; + exit(-1); + } + + cdbtree_calo_v2 = new CDBTTree(calibdir); + + + cdbtree_calo_v2->LoadCalibrations(); + + _CENTRALITY_V2.assign(100,0); + + for (int icent = 0; icent < 100; icent++) + { + _CENTRALITY_V2[icent] = cdbtree_calo_v2->GetFloatValue(icent, "jet_calo_v2"); + } + + delete cdbtree_calo_v2; + + return Fun4AllReturnCodes::EVENT_OK; +} + int DetermineTowerBackground::process_event(PHCompositeNode *topNode) { @@ -226,7 +278,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, comp_ieta, comp_iphi); tower_geom = geomIH->get_tower_geometry(key); comp_ET = towerinfo->get_energy() / cosh(tower_geom->get_eta()); - comp_isBad = towerinfo->get_isHot() || towerinfo->get_isNoCalib() || towerinfo->get_isNotInstr() || towerinfo->get_isBadChi2(); + comp_isBad = !towerinfo->get_isGood(); } else if (comp.first == 7 || comp.first == 27) { @@ -237,7 +289,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALOUT, comp_ieta, comp_iphi); tower_geom = geomOH->get_tower_geometry(key); comp_ET = towerinfo->get_energy() / cosh(tower_geom->get_eta()); - comp_isBad = towerinfo->get_isHot() || towerinfo->get_isNoCalib() || towerinfo->get_isNotInstr() || towerinfo->get_isBadChi2(); + comp_isBad = !towerinfo->get_isGood(); } else if (comp.first == 13 || comp.first == 28) { @@ -248,7 +300,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(RawTowerDefs::CalorimeterId::HCALIN, comp_ieta, comp_iphi); tower_geom = geomIH->get_tower_geometry(key); comp_ET = towerinfo->get_energy() / cosh(tower_geom->get_eta()); - comp_isBad = towerinfo->get_isHot() || towerinfo->get_isNoCalib() || towerinfo->get_isNotInstr() || towerinfo->get_isBadChi2(); + comp_isBad = !towerinfo->get_isGood(); } @@ -415,7 +467,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) int this_phibin = towerinfosEM3->getTowerPhiBin(key); TowerInfo *tower = towerinfosEM3->get_tower_at_channel(channel); float this_E = tower->get_energy(); - int this_isBad = tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2(); + int this_isBad = !tower->get_isGood(); _EMCAL_ISBAD[this_etabin][this_phibin] = this_isBad; if (!this_isBad) { // just in case since all energy is summed @@ -433,7 +485,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) int this_phibin = towerinfosIH3->getTowerPhiBin(key); TowerInfo *tower = towerinfosIH3->get_tower_at_channel(channel); float this_E = tower->get_energy(); - int this_isBad = tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2(); + int this_isBad = !tower->get_isGood(); _IHCAL_ISBAD[this_etabin][this_phibin] = this_isBad; if (!this_isBad) { // just in case since all energy is summed @@ -451,7 +503,7 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) int this_phibin = towerinfosOH3->getTowerPhiBin(key); TowerInfo *tower = towerinfosOH3->get_tower_at_channel(channel); float this_E = tower->get_energy(); - int this_isBad = tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2(); + int this_isBad = !tower->get_isGood(); _OHCAL_ISBAD[this_etabin][this_phibin] = this_isBad; if (!this_isBad) { // just in case since all energy is summed @@ -481,7 +533,103 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) } } - if ( _do_flow >= 1 ) + + // Get psi + if (_do_flow == 2) + { // HIJING truth flow extraction + PHG4TruthInfoContainer *truthinfo = findNode::getClass(topNode, "G4TruthInfo"); + + if (!truthinfo) + { + std::cout << "DetermineTowerBackground::process_event: FATAL , G4TruthInfo does not exist , cannot extract truth flow with do_flow = " << _do_flow << std::endl; + return -1; + } + + PHG4TruthInfoContainer::Range range = truthinfo->GetPrimaryParticleRange(); + + float Hijing_Qx = 0; + float Hijing_Qy = 0; + + for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) + { + PHG4Particle *g4particle = iter->second; + + if (truthinfo->isEmbeded(g4particle->get_track_id()) != 0) + { + continue; + } + + TLorentzVector t; + t.SetPxPyPzE(g4particle->get_px(), g4particle->get_py(), g4particle->get_pz(), g4particle->get_e()); + + float truth_pt = t.Pt(); + if (truth_pt < 0.4) + { + continue; + } + float truth_eta = t.Eta(); + if (std::fabs(truth_eta) > 1.1) + { + continue; + } + float truth_phi = t.Phi(); + int truth_pid = g4particle->get_pid(); + + if (Verbosity() > 10) + { + std::cout << "DetermineTowerBackground::process_event: determining truth flow, using particle w/ pt / eta / phi " << truth_pt << " / " << truth_eta << " / " << truth_phi << " , embed / PID = " << truthinfo->isEmbeded(g4particle->get_track_id()) << " / " << truth_pid << std::endl; + } + + Hijing_Qx += truth_pt * std::cos(2 * truth_phi); + Hijing_Qy += truth_pt * std::sin(2 * truth_phi); + } + + _Psi2 = std::atan2(Hijing_Qy, Hijing_Qx) / 2.0; + + if (Verbosity() > 0) + { + std::cout << "DetermineTowerBackground::process_event: flow extracted from Hijing truth particles, setting Psi2 = " << _Psi2 << " ( " << _Psi2 / M_PI << " * pi ) " << std::endl; + } + } + else if (_do_flow == 3 || _do_flow == 4) + { // sEPD event plane extraction + // get event plane map + EventplaneinfoMap *epmap = findNode::getClass(topNode, "EventplaneinfoMap"); + if (!epmap) + { + std::cout << "DetermineTowerBackground::process_event: FATAL, EventplaneinfoMap does not exist, cannot extract sEPD flow with do_flow = " << _do_flow << std::endl; + exit(-1); + } + if (!(epmap->empty())) + { + auto *EPDNS = epmap->get(EventplaneinfoMap::sEPDNS); + _Psi2 = EPDNS->get_shifted_psi(2); + } + else + { + _is_flow_failure = true; + _Psi2 = 0; + } + + // Safety check + if (!std::isfinite(_Psi2)) + { + if (Verbosity() > 0) + { + std::cout << "DetermineTowerBackground::process_event: WARNING Psi2 is non-finite (NaN or Inf), setting Psi2 = 0." << std::endl; + } + _is_flow_failure = true; + _Psi2 = 0; + } + + if (Verbosity() > 0) + { + std::cout << "DetermineTowerBackground::process_event: flow extracted from sEPD, setting Psi2 = " << _Psi2 << " ( " << _Psi2 / M_PI << " * pi ) " << std::endl; + } + + } + + if ( _do_flow >= 1 && _do_flow < 4) { if (Verbosity() > 0) @@ -754,88 +902,6 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) { // Calo event plane _Psi2 = std::atan2(Q_y, Q_x) / 2.0; } - else if (_do_flow == 2) - { // HIJING truth flow extraction - PHG4TruthInfoContainer *truthinfo = findNode::getClass(topNode, "G4TruthInfo"); - - if (!truthinfo) - { - std::cout << "DetermineTowerBackground::process_event: FATAL , G4TruthInfo does not exist , cannot extract truth flow with do_flow = " << _do_flow << std::endl; - return -1; - } - - PHG4TruthInfoContainer::Range range = truthinfo->GetPrimaryParticleRange(); - - float Hijing_Qx = 0; - float Hijing_Qy = 0; - - for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) - { - PHG4Particle *g4particle = iter->second; - - if (truthinfo->isEmbeded(g4particle->get_track_id()) != 0) - { - continue; - } - - TLorentzVector t; - t.SetPxPyPzE(g4particle->get_px(), g4particle->get_py(), g4particle->get_pz(), g4particle->get_e()); - - float truth_pt = t.Pt(); - if (truth_pt < 0.4) - { - continue; - } - float truth_eta = t.Eta(); - if (std::fabs(truth_eta) > 1.1) - { - continue; - } - float truth_phi = t.Phi(); - int truth_pid = g4particle->get_pid(); - - if (Verbosity() > 10) - { - std::cout << "DetermineTowerBackground::process_event: determining truth flow, using particle w/ pt / eta / phi " << truth_pt << " / " << truth_eta << " / " << truth_phi << " , embed / PID = " << truthinfo->isEmbeded(g4particle->get_track_id()) << " / " << truth_pid << std::endl; - } - - Hijing_Qx += truth_pt * std::cos(2 * truth_phi); - Hijing_Qy += truth_pt * std::sin(2 * truth_phi); - } - - _Psi2 = std::atan2(Hijing_Qy, Hijing_Qx) / 2.0; - - if (Verbosity() > 0) - { - std::cout << "DetermineTowerBackground::process_event: flow extracted from Hijing truth particles, setting Psi2 = " << _Psi2 << " ( " << _Psi2 / M_PI << " * pi ) " << std::endl; - } - } - else if (_do_flow == 3) - { // sEPD event plane extraction - // get event plane map - EventplaneinfoMap *epmap = findNode::getClass(topNode, "EventplaneinfoMap"); - if (!epmap) - { - std::cout << "DetermineTowerBackground::process_event: FATAL, EventplaneinfoMap does not exist, cannot extract sEPD flow with do_flow = " << _do_flow << std::endl; - exit(-1); - } - if (!(epmap->empty())) - { - auto *EPDNS = epmap->get(EventplaneinfoMap::sEPDNS); - _Psi2 = EPDNS->get_shifted_psi(2); - } - else - { - _is_flow_failure = true; - _Psi2 = 0; - } - - if (Verbosity() > 0) - { - std::cout << "DetermineTowerBackground::process_event: flow extracted from sEPD, setting Psi2 = " << _Psi2 << " ( " << _Psi2 / M_PI << " * pi ) " << std::endl; - } - - } if (std::isnan(_Psi2) || std::isinf(_Psi2)) { @@ -890,7 +956,30 @@ int DetermineTowerBackground::process_event(PHCompositeNode *topNode) std::cout << "DetermineTowerBackground::process_event: flow extraction successful, Psi2 = " << _Psi2 << " ( " << _Psi2 / M_PI << " * pi ) , v2 = " << _v2 << std::endl; } } // if do flow + else if (_do_flow == 4) + { + CentralityInfo *centinfo = findNode::getClass(topNode, "CentralityInfo"); + + if (!centinfo) + { + std::cout << "DetermineTowerBackground::process_event: FATAL, CentralityInfo does not exist, cannot extract centrality with do_flow = " << _do_flow << std::endl; + exit(-1); + } + + int centrality_bin = centinfo->get_centrality_bin(CentralityInfo::PROP::mbd_NS); + + if (centrality_bin > 0 && centrality_bin < 95) + { + _v2 = _CENTRALITY_V2[centrality_bin]; + } + else + { + _v2 = 0; + _is_flow_failure = true; + _Psi2 = 0; + } + } // now calculate energy densities... _nTowers = 0; // store how many towers were used to determine bkg diff --git a/offline/packages/jetbackground/DetermineTowerBackground.h b/offline/packages/jetbackground/DetermineTowerBackground.h index a8a6d0209c..ed9e34bf9a 100644 --- a/offline/packages/jetbackground/DetermineTowerBackground.h +++ b/offline/packages/jetbackground/DetermineTowerBackground.h @@ -13,6 +13,7 @@ #include #include #include +#include // forward declarations class PHCompositeNode; @@ -37,7 +38,11 @@ class DetermineTowerBackground : public SubsysReco void SetBackgroundOutputName(const std::string &name) { _backgroundName = name; } void SetSeedType(int seed_type) { _seed_type = seed_type; } void SetFlow(int do_flow) { _do_flow = do_flow; }; - + void SetOverwriteCaloV2(std::string &url) + { + m_overwrite_average_calo_v2 = true; + m_overwrite_average_calo_v2_path = url; + } void SetSeedJetD(float D) { _seed_jet_D = D; }; void SetSeedJetPt(float pt) { _seed_jet_pt = pt; }; void SetSeedMaxConst(float max_const) { _seed_max_const = max_const; }; @@ -55,6 +60,13 @@ class DetermineTowerBackground : public SubsysReco int CreateNode(PHCompositeNode *topNode); void FillNode(PHCompositeNode *topNode); + int LoadCalibrations(); + + std::vector _CENTRALITY_V2; + std::string m_calibName = "JET_AVERAGE_CALO_V2_SEPD_PSI2"; + bool m_overwrite_average_calo_v2{false}; + std::string m_overwrite_average_calo_v2_path; + int _do_flow{0}; float _v2{0}; float _Psi2{0}; diff --git a/offline/packages/jetbackground/Makefile.am b/offline/packages/jetbackground/Makefile.am index 6fe9740a4e..ad45676fbe 100644 --- a/offline/packages/jetbackground/Makefile.am +++ b/offline/packages/jetbackground/Makefile.am @@ -24,6 +24,8 @@ libjetbackground_la_LDFLAGS = \ libjetbackground_la_LIBADD = \ libjetbackground_io.la \ -lcalo_io \ + -lcentrality_io \ + -lcdbobjects \ -lConstituentSubtractor \ -leventplaneinfo_io \ -lglobalvertex \ @@ -33,6 +35,7 @@ libjetbackground_la_LIBADD = \ -lphg4hit \ -lphparameter \ -lqautils \ + -lffamodules \ -lSubsysReco pkginclude_HEADERS = \ diff --git a/offline/packages/jetbackground/RetowerCEMC.cc b/offline/packages/jetbackground/RetowerCEMC.cc index 6125052a23..9543f0e75b 100644 --- a/offline/packages/jetbackground/RetowerCEMC.cc +++ b/offline/packages/jetbackground/RetowerCEMC.cc @@ -86,7 +86,7 @@ int RetowerCEMC::process_event(PHCompositeNode *topNode) int iphi = towerinfosEM3->getTowerPhiBin(channelkey); rawtower_e[ieta][iphi] = tower->get_energy(); rawtower_time[ieta][iphi] = tower->get_time(); - rawtower_status[ieta][iphi] = tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2(); + rawtower_status[ieta][iphi] = !tower->get_isGood(); } EMRetowerName = m_towerNodePrefix + "_CEMC_RETOWER"; TowerInfoContainer *emcal_retower = findNode::getClass(topNode, EMRetowerName); @@ -145,7 +145,15 @@ int RetowerCEMC::process_event(PHCompositeNode *topNode) } else { - towerinfo->set_energy(retower_e_temp / (double) (1 - scalefactor)); + if (_do_rescale) + { + towerinfo->set_energy(retower_e_temp / (double) (1 - scalefactor)); + } + else + { + towerinfo->set_energy(retower_e_temp); + } + if (retower_e_temp == 0) { towerinfo->set_time(0); @@ -154,8 +162,8 @@ int RetowerCEMC::process_event(PHCompositeNode *topNode) { towerinfo->set_time((retower_time_temp / retower_e_temp)); } - towerinfo->set_chi2(scalefactor); } + towerinfo->set_chi2(scalefactor); // store the fraction of bad towers as the chi2 } } } diff --git a/offline/packages/jetbackground/RetowerCEMC.h b/offline/packages/jetbackground/RetowerCEMC.h index 3edb6fd112..3c48a057ce 100644 --- a/offline/packages/jetbackground/RetowerCEMC.h +++ b/offline/packages/jetbackground/RetowerCEMC.h @@ -18,6 +18,7 @@ class RetowerCEMC : public SubsysReco void SetEnergyDistribution(int val) { _weighted_energy_distribution = val; } void set_frac_cut(double frac_cut) { _frac_cut = frac_cut; } + void set_do_rescale(bool do_rescale) { _do_rescale = do_rescale; } void set_towerinfo(bool use_towerinfo) { m_use_towerinfo = use_towerinfo; } void set_towerNodePrefix(const std::string &prefix) { @@ -32,25 +33,26 @@ class RetowerCEMC : public SubsysReco void get_weighted_fraction(PHCompositeNode *topNode); int _weighted_energy_distribution{1}; - double _frac_cut{0.5}; + double _frac_cut{1}; + bool _do_rescale{false}; bool m_use_towerinfo{false}; std::string m_towerNodePrefix{"TOWERINFO_CALIB"}; - static const int neta_ihcal = 24; - static const int neta_emcal = 96; - static const int nphi_ihcal = 64; - static const int nphi_emcal = 256; + static const int neta_ihcal{24}; + static const int neta_emcal{96}; + static const int nphi_ihcal{64}; + static const int nphi_emcal{256}; - int retower_lowerbound_originaltower_ieta[neta_ihcal] = {0}; - int retower_upperbound_originaltower_ieta[neta_ihcal] = {0}; - double retower_lowerbound_originaltower_fraction[neta_ihcal] = {0.0}; - double retower_upperbound_originaltower_fraction[neta_ihcal] = {0.0}; - double retower_totalarea[neta_ihcal] = {0.0}; + int retower_lowerbound_originaltower_ieta[neta_ihcal]{0}; + int retower_upperbound_originaltower_ieta[neta_ihcal]{0}; + double retower_lowerbound_originaltower_fraction[neta_ihcal]{0.0}; + double retower_upperbound_originaltower_fraction[neta_ihcal]{0.0}; + double retower_totalarea[neta_ihcal]{0.0}; int retower_first_lowerbound_originaltower_iphi{-1}; - double rawtower_e[neta_emcal][nphi_emcal] = {{0.0}}; - double rawtower_time[neta_emcal][nphi_emcal] = {{0.0}}; - int rawtower_status[neta_emcal][nphi_emcal] = {{0}}; + double rawtower_e[neta_emcal][nphi_emcal]{{0.0}}; + double rawtower_time[neta_emcal][nphi_emcal]{{0.0}}; + int rawtower_status[neta_emcal][nphi_emcal]{{0}}; std::string EMTowerName; std::string IHTowerName; diff --git a/offline/packages/jetbackground/SubtractTowers.cc b/offline/packages/jetbackground/SubtractTowers.cc index 3d0ee5532e..1c6c51a0db 100644 --- a/offline/packages/jetbackground/SubtractTowers.cc +++ b/offline/packages/jetbackground/SubtractTowers.cc @@ -166,7 +166,7 @@ int SubtractTowers::process_event(PHCompositeNode *topNode) } float new_energy = raw_energy - UE; // if a tower is masked, leave it at zero - if (tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2()) + if (!tower->get_isGood()) { new_energy = 0; } @@ -259,7 +259,7 @@ int SubtractTowers::process_event(PHCompositeNode *topNode) } float new_energy = raw_energy - UE; // if a tower is masked, leave it at zero - if (tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2()) + if (!tower->get_isGood()) { new_energy = 0; } @@ -348,7 +348,7 @@ int SubtractTowers::process_event(PHCompositeNode *topNode) } float new_energy = raw_energy - UE; // if a tower is masked, leave it at zero - if (tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2()) + if (!tower->get_isGood()) { new_energy = 0; } diff --git a/offline/packages/jetbackground/TimingCut.cc b/offline/packages/jetbackground/TimingCut.cc index 69ab008124..41d8dc571d 100644 --- a/offline/packages/jetbackground/TimingCut.cc +++ b/offline/packages/jetbackground/TimingCut.cc @@ -12,21 +12,36 @@ #include #include +#include // for CDBTF1 + +#include +#include +#include #include #include // for basic_ostream, operator<< #include // for _Rb_tree_iterator, opera... #include // for pair #include // for vector //____________________________________________________________________________.. -TimingCut::TimingCut(const std::string &jetNodeName, const std::string &name, const bool doAbort) +TimingCut::TimingCut(const std::string &jetNodeName, const std::string &name, const bool doAbort, const std::string &ohTowerName) : SubsysReco(name) , _doAbort(doAbort) , _jetNodeName(jetNodeName) + , _ohTowerName(ohTowerName) , _cutParams(name) { SetDefaultParams(); } +TimingCut::~TimingCut() +{ + if(_fitFunc) + { + delete _fitFunc; + _fitFunc = nullptr; + } +} + //____________________________________________________________________________.. int TimingCut::Init(PHCompositeNode *topNode) { @@ -35,6 +50,26 @@ int TimingCut::Init(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } + std::string fitUrl = CDBInterface::instance()->getUrl("OHCAL_JET_TIME_FRACTION"); + if(!fitUrl.empty()) + { + CDBTF* fitFile = new CDBTF(fitUrl); + fitFile->LoadCalibrations(); + TF1* tmp = fitFile->getTF("JET_TIMING_CALO_FRACTION_CALIB_fullrange"); + if(!tmp) + { + std::cout << "ERROR: NO CALIBRATION TF1 FOUND FOR TIMING CUT OHCAL FRACTION CORRECTION! This should never happen. ABORT RUN!" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + _fitFunc = (TF1*)tmp->Clone(); + delete fitFile; + } + else + { + std::cout << "ERROR: NO CALIBRATION FILE FOUND FOR TIMING CUT OHCAL FRACTION CORRECTION! ABORT RUN!" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + return Fun4AllReturnCodes::EVENT_OK; } @@ -57,11 +92,12 @@ int TimingCut::CreateNodeTree(PHCompositeNode *topNode) int TimingCut::process_event(PHCompositeNode *topNode) { JetContainer *jets = findNode::getClass(topNode, _jetNodeName); - if (!jets) + TowerInfoContainer* towersOH = findNode::getClass(topNode, _ohTowerName); + if (!jets || !towersOH) { if (Verbosity() > 0 && !_missingInfoWarningPrinted) { - std::cout << "Missing jets; abort event. Further warnings will be suppressed." << std::endl; + std::cout << "Missing jets or OHCal towers; abort event. Further warnings will be suppressed." << std::endl; } _missingInfoWarningPrinted = true; return Fun4AllReturnCodes::ABORTEVENT; @@ -69,6 +105,8 @@ int TimingCut::process_event(PHCompositeNode *topNode) float maxJetpT = 0; float subJetpT = 0; + float maxJetOHFrac = std::numeric_limits::quiet_NaN(); + float subJetOHFrac = std::numeric_limits::quiet_NaN(); float maxJett = std::numeric_limits::quiet_NaN(); float subJett = std::numeric_limits::quiet_NaN(); float maxJetPhi = std::numeric_limits::quiet_NaN(); @@ -86,12 +124,36 @@ int TimingCut::process_event(PHCompositeNode *topNode) float jetpT = 0; float jett = std::numeric_limits::quiet_NaN(); float jetPhi = std::numeric_limits::quiet_NaN(); + float jetOHFrac = 0; Jet *jet = jets->get_jet(i); if (jet) { jetpT = jet->get_pt(); jett = jet->get_property(Jet::PROPERTY::prop_t); jetPhi = jet->get_phi(); + for(auto comp: jet->get_comp_vec()) + { + if(comp.first == 7 || comp.first == 27) + { + unsigned int channel = comp.second; + TowerInfo* tower = towersOH->get_tower_at_channel(channel); + if(!tower) + { + std::cout << "Component tower missing! This should not happen (something is wrong, check your inputs). Abort event!" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + jetOHFrac += tower->get_energy(); + } + } + float jetE = jet->get_e(); + if(jetE == 0) + { + jetOHFrac = std::numeric_limits::quiet_NaN(); + } + else + { + jetOHFrac /= jetE; + } } else { @@ -104,16 +166,19 @@ int TimingCut::process_event(PHCompositeNode *topNode) subJetpT = maxJetpT; subJett = maxJett; subJetPhi = maxJetPhi; + subJetOHFrac = maxJetOHFrac; } maxJetpT = jetpT; maxJett = jett; maxJetPhi = jetPhi; + maxJetOHFrac = jetOHFrac; } else if (jetpT > subJetpT) { subJetpT = jetpT; subJett = jett; subJetPhi = jetPhi; + subJetOHFrac = jetOHFrac; } } } @@ -126,8 +191,23 @@ int TimingCut::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTEVENT; } - bool passDeltat = Pass_Delta_t(maxJett, subJett, maxJetPhi, subJetPhi); - bool passLeadt = Pass_Lead_t(maxJett); + if(!std::isfinite(maxJetOHFrac) || !std::isfinite(subJetOHFrac)) + { + if(Verbosity() > 1) + { + std::cout << "Warning: bad OH fraction for leading or subleading jet; this event will automatically fail cuts." << std::endl; + } + maxJetOHFrac = std::numeric_limits::quiet_NaN(); + subJetOHFrac = std::numeric_limits::quiet_NaN(); + } + + float corrMaxJett = Correct_Time_Ohfrac(maxJett, maxJetOHFrac); //likewise, intentional NaNs here. + float corrSubJett = Correct_Time_Ohfrac(subJett, subJetOHFrac); + + + + bool passDeltat = Pass_Delta_t(corrMaxJett, corrSubJett, maxJetPhi, subJetPhi); + bool passLeadt = Pass_Lead_t(corrMaxJett); MbdOut * mbdout = static_cast(findNode::getClass(topNode,"MbdOut")); float m_mbd_t0 = std::numeric_limits::quiet_NaN(); @@ -157,10 +237,10 @@ int TimingCut::process_event(PHCompositeNode *topNode) bool passMbdt = false; if(!std::isnan(mbd_time)) { - passMbdt = Pass_Mbd_dt(maxJett, mbd_time); + passMbdt = Pass_Mbd_dt(corrMaxJett, mbd_time); } - bool failAnyCut = !passDeltat || !passLeadt || !passMbdt; + bool failAnyCut = !passDeltat || !passLeadt || (!passMbdt && _abortFailMbd); if (failAnyCut && _doAbort) { @@ -174,7 +254,11 @@ int TimingCut::process_event(PHCompositeNode *topNode) _cutParams.set_int_param("failAnyTimeCut", failAnyCut); _cutParams.set_double_param("maxJett",maxJett); _cutParams.set_double_param("subJett",subJett); + _cutParams.set_double_param("corrMaxJett",corrMaxJett); + _cutParams.set_double_param("corrSubJett",corrSubJett); _cutParams.set_double_param("mbd_time",mbd_time); + _cutParams.set_double_param("leadOhFrac",maxJetOHFrac); + _cutParams.set_double_param("subOhFrac",subJetOHFrac); _cutParams.set_double_param("dPhi",calc_dphi(maxJetPhi, subJetPhi)); _cutParams.UpdateNodeTree(parNode, "TimingCutParams"); diff --git a/offline/packages/jetbackground/TimingCut.h b/offline/packages/jetbackground/TimingCut.h index 2e426a82da..a6c56433e8 100644 --- a/offline/packages/jetbackground/TimingCut.h +++ b/offline/packages/jetbackground/TimingCut.h @@ -7,40 +7,22 @@ #include + +#include +#include #include #include +#include +class CDBTF; class PHCompositeNode; class TimingCut : public SubsysReco { public: - explicit TimingCut(const std::string &jetNodeName, const std::string &name = "TimingCutModule", bool doAbort = false); - - ~TimingCut() override = default; + explicit TimingCut(const std::string &jetNodeName, const std::string &name = "TimingCutModule", bool doAbort = false, const std::string &ohTowerName = "TOWERINFO_CALIB_HCALOUT"); - float calc_dphi(float maxJetPhi, float subJetPhi) - { - float dPhi = std::abs(maxJetPhi - subJetPhi); - if(dPhi>M_PI) dPhi -= M_PI; - return dPhi; - } - - bool Pass_Delta_t(float lead_time, float sub_time, float maxJetPhi, float subJetPhi) - { - float dPhi = calc_dphi(maxJetPhi, subJetPhi); - return (std::abs(lead_time - sub_time) < _dt_width && dPhi > _min_dphi); - } - - bool Pass_Lead_t(float lead_time) - { - return std::abs(lead_time + _t_shift) < _t_width; - } - - bool Pass_Mbd_dt(float lead_time, float mbd_time) - { - return std::abs(lead_time - mbd_time) < _mbd_dt_width; - } + ~TimingCut() override; void set_t_shift(float new_shift) { _t_shift = new_shift; } float get_t_shift() { return _t_shift; } @@ -57,6 +39,9 @@ class TimingCut : public SubsysReco void set_min_dphi(float new_min_dphi) { _min_dphi = new_min_dphi; } float get_min_dphi() { return _min_dphi; } + void set_abortFailMbd(bool abortFailMbd) { _abortFailMbd = abortFailMbd; } + bool get_abortFailMbd() { return _abortFailMbd; } + int Init(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; @@ -76,23 +61,69 @@ class TimingCut : public SubsysReco _cutParams.set_int_param("passLeadtCut", 0); _cutParams.set_int_param("passDeltatCut", 0); _cutParams.set_int_param("passMbdDtCut", 0); - _cutParams.set_int_param("failAnyTimeCut",0); + _cutParams.set_int_param("failAnyTimeCut",1); _cutParams.set_double_param("maxJett",9999); _cutParams.set_double_param("subJett",9999); _cutParams.set_double_param("mbd_time",9999); _cutParams.set_double_param("dPhi",9999); + _cutParams.set_double_param("leadOhFrac",-1); + _cutParams.set_double_param("subOhFrac",-1); + _cutParams.set_double_param("corrMaxJett",9999); + _cutParams.set_double_param("corrSubJett",9999); + } private: + + float Correct_Time_Ohfrac(float t, float ohfrac) + { + if(!_fitFunc) + { + if(Verbosity() > 0) + { + std::cout << "ERROR: mising fit function. All events will fail!" << std::endl; + } + return std::numeric_limits::quiet_NaN(); + } + float corrt = t - _fitFunc->Eval(ohfrac); + return corrt; + } + + float calc_dphi(float maxJetPhi, float subJetPhi) + { + float dPhi = std::abs(maxJetPhi - subJetPhi); + if(dPhi>M_PI) dPhi = 2*M_PI - dPhi; + return dPhi; + } + + bool Pass_Delta_t(float lead_time, float sub_time, float maxJetPhi, float subJetPhi) + { + float dPhi = calc_dphi(maxJetPhi, subJetPhi); + return (std::abs(lead_time - sub_time) < _dt_width && dPhi > _min_dphi); + } + + bool Pass_Lead_t(float lead_time) + { + return std::abs(lead_time + _t_shift) < _t_width; + } + + bool Pass_Mbd_dt(float lead_time, float mbd_time) + { + return std::abs(lead_time - mbd_time) < _mbd_dt_width; + } + bool _doAbort; + bool _abortFailMbd = false; bool _missingInfoWarningPrinted = false; std::string _jetNodeName; + std::string _ohTowerName; PHParameters _cutParams; float _t_width{6.0}; float _dt_width{3.0}; - float _t_shift{2.0}; + float _t_shift{0.0}; float _mbd_dt_width{3.0}; float _min_dphi{3*M_PI/4}; + TF1* _fitFunc{nullptr}; }; #endif diff --git a/offline/packages/jetbase/JetCalib.cc b/offline/packages/jetbase/JetCalib.cc index cc2fdd11b9..a6c9b8cf4d 100644 --- a/offline/packages/jetbase/JetCalib.cc +++ b/offline/packages/jetbase/JetCalib.cc @@ -244,6 +244,7 @@ int JetCalib::process_event(PHCompositeNode *topNode) calib_jet->set_py(calib_pt * std::sin(phi)); calib_jet->set_pz(calib_pt * std::sinh(eta)); calib_jet->set_id(ijet); + calib_jet->insert_comp(jet->get_comp_vec(), true); calib_jet->set_isCalib(1); ijet++; } diff --git a/offline/packages/jetbase/JetProbeMaker.cc b/offline/packages/jetbase/JetProbeMaker.cc index ea8e6b891e..21617c915f 100644 --- a/offline/packages/jetbase/JetProbeMaker.cc +++ b/offline/packages/jetbase/JetProbeMaker.cc @@ -5,6 +5,7 @@ #include "Jetv2.h" #include + #include #include #include // for PHNode @@ -15,6 +16,7 @@ #include // for PHWHERE #include + #include int JetProbeMaker::process_event(PHCompositeNode * /*topNode*/) @@ -29,7 +31,7 @@ int JetProbeMaker::process_event(PHCompositeNode * /*topNode*/) fastjet::PseudoJet fjet{}; fjet.reset_PtYPhiM(pt, eta, phi); - Jetv2 *jet = (Jetv2 *) _jets->add_jet(); + Jetv2 *jet = static_cast (_jets->add_jet()); jet->set_px(fjet.px()); jet->set_py(fjet.py()); jet->set_pz(fjet.pz()); diff --git a/offline/packages/jetbase/JetProbeMaker.h b/offline/packages/jetbase/JetProbeMaker.h index b319ff1198..86cfe54842 100644 --- a/offline/packages/jetbase/JetProbeMaker.h +++ b/offline/packages/jetbase/JetProbeMaker.h @@ -19,7 +19,7 @@ class JetProbeMaker : public SubsysReco { public: JetProbeMaker(const std::string &name = "JetProbeMaker"); - ~JetProbeMaker() override{}; + ~JetProbeMaker() override = default; int process_event(PHCompositeNode * /*topNode*/) override; int InitRun(PHCompositeNode *topNode) override; diff --git a/offline/packages/jetbase/TowerJetInput.cc b/offline/packages/jetbase/TowerJetInput.cc index f58249ad04..ca2af6ba3d 100644 --- a/offline/packages/jetbase/TowerJetInput.cc +++ b/offline/packages/jetbase/TowerJetInput.cc @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include @@ -471,7 +471,7 @@ std::vector TowerJetInput::get_input(PHCompositeNode *topNode) int iphi = towerinfos->getTowerPhiBin(calokey); const RawTowerDefs::keytype key = RawTowerDefs::encode_towerid(geocaloid, ieta, iphi); // skip masked towers - if (tower->get_isHot() || tower->get_isNoCalib() || tower->get_isNotInstr() || tower->get_isBadChi2()) + if (!tower->get_isGood()) { continue; } diff --git a/offline/packages/mbd/Makefile.am b/offline/packages/mbd/Makefile.am index 111f9b31df..af9a9d2598 100644 --- a/offline/packages/mbd/Makefile.am +++ b/offline/packages/mbd/Makefile.am @@ -49,8 +49,10 @@ pkginclude_HEADERS = \ MbdPmtHitV1.h \ MbdRawContainer.h \ MbdRawContainerV1.h \ + MbdRawContainerV2.h \ MbdRawHit.h \ MbdRawHitV1.h \ + MbdRawHitV2.h \ MbdReturnCodes.h \ MbdRunningStats.h \ MbdCalib.h \ @@ -68,10 +70,13 @@ pkginclude_HEADERS = \ MbdPmtHit.h \ MbdPmtHitV1.h \ MbdPmtSimHitV1.h \ + MbdCalibReco.h \ MbdRawContainer.h \ MbdRawContainerV1.h \ + MbdRawContainerV2.h \ MbdRawHit.h \ MbdRawHitV1.h \ + MbdRawHitV2.h \ MbdRunningStats.h \ MbdSig.h \ MbdEvent.h \ @@ -97,8 +102,10 @@ ROOTDICTS = \ MbdPmtHitV1_Dict.cc \ MbdRawContainer_Dict.cc \ MbdRawContainerV1_Dict.cc \ + MbdRawContainerV2_Dict.cc \ MbdRawHit_Dict.cc \ - MbdRawHitV1_Dict.cc + MbdRawHitV1_Dict.cc \ + MbdRawHitV2_Dict.cc else ROOTDICTS = \ @@ -116,8 +123,10 @@ ROOTDICTS = \ MbdPmtSimContainerV1_Dict.cc \ MbdRawHit_Dict.cc \ MbdRawHitV1_Dict.cc \ + MbdRawHitV2_Dict.cc \ MbdRawContainer_Dict.cc \ - MbdRawContainerV1_Dict.cc + MbdRawContainerV1_Dict.cc \ + MbdRawContainerV2_Dict.cc endif pcmdir = $(libdir) @@ -138,8 +147,10 @@ libmbd_io_la_SOURCES = \ MbdPmtContainerV1.cc \ MbdRawHit.cc \ MbdRawHitV1.cc \ + MbdRawHitV2.cc \ MbdRawContainer.cc \ MbdRawContainerV1.cc \ + MbdRawContainerV2.cc \ MbdRunningStats.cc \ MbdCalib.cc \ MbdSig.cc @@ -160,12 +171,15 @@ libmbd_io_la_SOURCES = \ MbdPmtSimContainerV1.cc \ MbdRawHit.cc \ MbdRawHitV1.cc \ + MbdRawHitV2.cc \ MbdRawContainer.cc \ MbdRawContainerV1.cc \ + MbdRawContainerV2.cc \ MbdRunningStats.cc \ MbdSig.cc libmbd_la_SOURCES = \ + MbdCalibReco.cc \ MbdEvent.cc \ MbdCalib.cc \ MbdReco.cc \ diff --git a/offline/packages/mbd/MbdCalib.cc b/offline/packages/mbd/MbdCalib.cc index 22b1e9930d..358bb6f0ce 100644 --- a/offline/packages/mbd/MbdCalib.cc +++ b/offline/packages/mbd/MbdCalib.cc @@ -7,6 +7,7 @@ #ifndef ONLINE #include #include +#include #endif #include @@ -79,91 +80,113 @@ int MbdCalib::Download_All() // if rc flag MBD_CALDIR does not exist, we create it and set it to an empty string if (!_rc->FlagExist("MBD_CALDIR")) { - std::string sampmax_url = _cdb->getUrl("MBD_SAMPMAX"); + // Always load Status + _cdb_urls["MBD_STATUS"] = _cdb->getUrl("MBD_STATUS"); + if ( !_cdb_urls["MBD_STATUS"].empty() ) + { + // if this doesn't exist, the status is assumed to be all good + Download_Status(_cdb_urls["MBD_STATUS"]); + } if (Verbosity() > 0) { - std::cout << "sampmax_url " << sampmax_url << std::endl; + std::cout << "MBD_STATUS url " << _cdb_urls["MBD_STATUS"] << std::endl; } - Download_SampMax(sampmax_url); + + // note: sampmax and ped will be calculated on the fly if calibs don't exist + _cdb_urls["MBD_SAMPMAX"] = _cdb->getUrl("MBD_SAMPMAX"); + if (Verbosity() > 0) + { + std::cout << "MBD_SAMPMAX url " << _cdb_urls["MBD_SAMPMAX"] << std::endl; + } + Download_SampMax(_cdb_urls["MBD_SAMPMAX"]); if ( !_rawdstflag ) { - std::string ped_url = _cdb->getUrl("MBD_PED"); + _cdb_urls["MBD_PED"] = _cdb->getUrl("MBD_PED"); if (Verbosity() > 0) { - std::cout << "ped_url " << ped_url << std::endl; + std::cout << "MBD_PED url " << _cdb_urls["MBD_PED"] << std::endl; } - Download_Ped(ped_url); + Download_Ped(_cdb_urls["MBD_PED"]); - - std::string pileup_url = _cdb->getUrl("MBD_PILEUP"); + _cdb_urls["MBD_PILEUP"] = _cdb->getUrl("MBD_PILEUP"); + if ( _cdb_urls["MBD_PILEUP"].empty() ) + { + std::cerr << "ERROR, MBD_PILEUP missing" << std::endl; + return -1; + } if (Verbosity() > 0) { - std::cout << "pileup_url " << pileup_url << std::endl; + std::cout << "MBD_PILEUP url " << _cdb_urls["MBD_PILEUP"] << std::endl; } - Download_Pileup(pileup_url); + Download_Pileup(_cdb_urls["MBD_PILEUP"]); if (do_templatefit) { - std::string shape_url = _cdb->getUrl("MBD_SHAPES"); + _cdb_urls["MBD_SHAPES"] = _cdb->getUrl("MBD_SHAPES"); + if ( _cdb_urls["MBD_SHAPES"].empty() ) + { + std::cerr << "ERROR, MBD_SHAPES missing" << std::endl; + return -1; + } if (Verbosity() > 0) { - std::cout << "shape_url " << shape_url << std::endl; + std::cout << "MBD_SHAPES url " << _cdb_urls["MBD_SHAPES"] << std::endl; } - Download_Shapes(shape_url); + Download_Shapes(_cdb_urls["MBD_SHAPES"]); } } - std::string qfit_url = _cdb->getUrl("MBD_QFIT"); - if (Verbosity() > 0) + if ( !_fitsonly ) { - std::cout << "qfit_url " << qfit_url << std::endl; - } - Download_Gains(qfit_url); + _cdb_urls["MBD_QFIT"] = _cdb->getUrl("MBD_QFIT"); + if (Verbosity() > 0) + { + std::cout << "MBD_QFIT url " << _cdb_urls["MBD_QFIT"] << std::endl; + } + Download_Gains(_cdb_urls["MBD_QFIT"]); - std::string tt_t0_url = _cdb->getUrl("MBD_TT_T0"); - if ( Verbosity() > 0 ) - { - std::cout << "tt_t0_url " << tt_t0_url << std::endl; - } - Download_TTT0(tt_t0_url); + _cdb_urls["MBD_TT_T0"] = _cdb->getUrl("MBD_TT_T0"); + if ( Verbosity() > 0 ) + { + std::cout << "MBD_TT_T0 url " << _cdb_urls["MBD_TT_T0"] << std::endl; + } + Download_TTT0(_cdb_urls["MBD_TT_T0"]); - std::string tq_t0_url = _cdb->getUrl("MBD_TQ_T0"); - if (Verbosity() > 0) - { - std::cout << "tq_t0_url " << tq_t0_url << std::endl; - } - Download_TQT0(tq_t0_url); + _cdb_urls["MBD_TQ_T0"] = _cdb->getUrl("MBD_TQ_T0"); + if (Verbosity() > 0) + { + std::cout << "MBD_TQ_T0 url " << _cdb_urls["MBD_TQ_T0"] << std::endl; + } + Download_TQT0(_cdb_urls["MBD_TQ_T0"]); - if ( !_fitsonly ) - { - std::string t0corr_url = _cdb->getUrl("MBD_T0CORR"); + _cdb_urls["MBD_T0CORR"] = _cdb->getUrl("MBD_T0CORR"); if ( Verbosity() > 0 ) { - std::cout << "t0corr_url " << t0corr_url << std::endl; + std::cout << "MBD_T0CORR url " << _cdb_urls["MBD_T0CORR"] << std::endl; } - Download_T0Corr(t0corr_url); + Download_T0Corr(_cdb_urls["MBD_T0CORR"]); - std::string timecorr_url = _cdb->getUrl("MBD_TIMECORR"); + _cdb_urls["MBD_TIMECORR"] = _cdb->getUrl("MBD_TIMECORR"); if ( Verbosity() > 0 ) { - std::cout << "timecorr_url " << timecorr_url << std::endl; + std::cout << "MBD_TIMECORR url " << _cdb_urls["MBD_TIMECORR"] << std::endl; } - Download_TimeCorr(timecorr_url); + Download_TimeCorr(_cdb_urls["MBD_TIMECORR"]); - std::string slew_url = _cdb->getUrl("MBD_SLEWCORR"); + _cdb_urls["MBD_SLEWCORR"] = _cdb->getUrl("MBD_SLEWCORR"); if ( Verbosity() > 0 ) { - std::cout << "slew_url " << slew_url << std::endl; + std::cout << "MBD_SLEWCORR url " << _cdb_urls["MBD_SLEWCORR"] << std::endl; } - Download_SlewCorr(slew_url); + Download_SlewCorr(_cdb_urls["MBD_SLEWCORR"]); - std::string trms_url = _cdb->getUrl("MBD_TIMERMS"); + _cdb_urls["MBD_TIMERMS"] = _cdb->getUrl("MBD_TIMERMS"); if ( Verbosity() > 0 ) { - std::cout << "trms_url " << trms_url << std::endl; + std::cout << "MBD_TIMERMS url " << _cdb_urls["MBD_TIMERMS"] << std::endl; } - Download_TimeRMS(trms_url); + Download_TimeRMS(_cdb_urls["MBD_TIMERMS"]); } Verbosity(0); @@ -176,6 +199,9 @@ int MbdCalib::Download_All() std::string sampmax_file = bbc_caldir + "/mbd_sampmax.calib"; Download_SampMax(sampmax_file); + std::string status_file = bbc_caldir + "/mbd_status.calib"; + Download_Status(status_file); + if ( !_rawdstflag ) { std::string ped_file = bbc_caldir + "/mbd_ped.calib"; @@ -617,8 +643,6 @@ int MbdCalib::Download_Ped(const std::string& dbase_location) if ( std::isnan(_pedmean[0]) ) { std::cout << PHWHERE << ", WARNING, ped calib missing, " << dbase_location << std::endl; - _status = -1; - return _status; } return 1; @@ -681,6 +705,74 @@ int MbdCalib::Download_SampMax(const std::string& dbase_location) if ( _sampmax[0] == -1 ) { std::cout << PHWHERE << ", WARNING, sampmax calib missing, " << dbase_location << std::endl; + } + + return 1; +} + +int MbdCalib::Download_Status(const std::string& dbase_location) +{ + // Reset All Values + _mbdstatus.fill(-1); + + TString dbase_file = dbase_location; + +#ifndef ONLINE + if (dbase_file.EndsWith(".root")) // read from database + { + CDBTTree* cdbttree = new CDBTTree(dbase_location); + cdbttree->LoadCalibrations(); + + for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) + { + _mbdstatus[ifeech] = cdbttree->GetIntValue(ifeech, "status"); + if (Verbosity() > 0) + { + if (ifeech < 5 || ifeech >= MbdDefs::MBD_N_FEECH - 5) + { + std::cout << ifeech << "\t" << _mbdstatus[ifeech] << std::endl; + } + } + } + delete cdbttree; + } +#endif + + if (dbase_file.EndsWith(".calib")) // read from text file + { + std::ifstream infile(dbase_location); + if (!infile.is_open()) + { + std::cout << PHWHERE << "unable to open " << dbase_location << std::endl; + _status = -3; + return _status; + } + + int feech = -1; + while (infile >> feech) + { + if (feech < 0 || feech >= MbdDefs::MBD_N_FEECH) + { + std::cout << "ERROR, invalid FEECH " << feech << " in MBD status calibration" << std::endl; + _status = -4; + return _status; + } + infile >> _mbdstatus[feech]; + if (Verbosity() > 0) + { + if (feech < 5 || feech >= MbdDefs::MBD_N_FEECH - 5) + { + std::cout << "status\t" << feech << "\t" << _mbdstatus[feech] << std::endl; + } + } + } + infile.close(); + } + + + if ( _mbdstatus[0] == -1 ) + { + std::cout << PHWHERE << ", WARNING, status calib seems bad, " << dbase_location << std::endl; _status = -1; return _status; // file not found } @@ -881,6 +973,19 @@ int MbdCalib::Download_Shapes(const std::string& dbase_location) return 1; } +void MbdCalib::get_tcorr_range(const int ifeech, int& min, int& max, int& step) +{ + min = static_cast( _tcorr_minrange[ifeech] ); + max = static_cast( _tcorr_maxrange[ifeech] ); + if ( _tcorr_npts[ifeech] > 1 ) + { + step = (_tcorr_maxrange[ifeech] - _tcorr_minrange[ifeech]) / (_tcorr_npts[ifeech]-1); + } + else + { + step = 0; + } +} int MbdCalib::Download_TimeCorr(const std::string& dbase_location) { @@ -1225,7 +1330,6 @@ int MbdCalib::Download_TimeRMS(const std::string& dbase_location) trms.clear(); } std::fill(_trms_npts.begin(), _trms_npts.end(), 0); - TString dbase_file = dbase_location; #ifndef ONLINE @@ -1331,9 +1435,10 @@ int MbdCalib::Download_TimeRMS(const std::string& dbase_location) if ( _trms_y[0].empty() ) { - std::cout << PHWHERE << ", ERROR, unknown file type, " << dbase_location << std::endl; - _status = -1; - return _status; // file not found + std::cout << PHWHERE << ", WARNING, trms calib missing " << dbase_location << std::endl; +// _status = -1; +// return _status; // file not found + return 0; } // Now we interpolate the trms @@ -1450,7 +1555,7 @@ int MbdCalib::Download_Pileup(const std::string& dbase_location) if (Verbosity() > 0) { - if (feech < 2 || feech >= MbdDefs::MBD_N_PMT - 2) + if (feech < 2 || feech >= MbdDefs::MBD_N_FEECH - 2) { std::cout << feech << "\t" << _pileup_p0[feech] << "\t" << _pileup_p0err[feech] << "\t" << _pileup_p1[feech] << "\t" << _pileup_p1err[feech] @@ -1591,6 +1696,52 @@ int MbdCalib::Write_SampMax(const std::string& dbfile) return 1; } +#ifndef ONLINE +int MbdCalib::Write_CDB_Status(const std::string& dbfile) +{ + CDBTTree* cdbttree{ nullptr }; + + std::cout << "Creating " << dbfile << std::endl; + cdbttree = new CDBTTree( dbfile ); + cdbttree->SetSingleIntValue("version", 1); + cdbttree->CommitSingle(); + + std::cout << "STATUS" << std::endl; + for (size_t ifeech = 0; ifeech < _mbdstatus.size(); ifeech++) + { + // store in a CDBTree + cdbttree->SetIntValue(ifeech, "status", _mbdstatus[ifeech]); + + if (ifeech < 12 || ifeech >= MbdDefs::MBD_N_FEECH - 5) + { + std::cout << ifeech << "\t" << cdbttree->GetIntValue(ifeech, "status") << std::endl; + } + } + + cdbttree->Commit(); + // cdbttree->Print(); + + // for now we create the tree after reading it + cdbttree->WriteCDBTTree(); + delete cdbttree; + + return 1; +} +#endif + +int MbdCalib::Write_Status(const std::string& dbfile) +{ + std::ofstream cal_file; + cal_file.open(dbfile); + for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) + { + cal_file << ifeech << "\t" << _mbdstatus[ifeech] << std::endl; + } + cal_file.close(); + + return 1; +} + #ifndef ONLINE int MbdCalib::Write_CDB_TTT0(const std::string& dbfile) { @@ -1930,6 +2081,40 @@ int MbdCalib::Write_CDB_TimeCorr(const std::string& dbfile) } #endif +int MbdCalib::Write_TimeCorr(const std::string& dbfile) +{ + std::ofstream cal_timecorr_file; + cal_timecorr_file.open(dbfile); + if (!cal_timecorr_file.is_open()) + { + std::cout << PHWHERE << "unable to open " << dbfile << std::endl; + return -1; + } + for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) + { + if ( _mbdgeom->get_type(ifeech) == 1 ) + { + continue; // skip q-channels + } + cal_timecorr_file << ifeech << "\t" << _tcorr_npts[ifeech] << "\t" << _tcorr_minrange[ifeech] << "\t" << _tcorr_maxrange[ifeech] << std::endl; + for (int ipt=0; ipt<_tcorr_npts[ifeech]; ipt++) + { + cal_timecorr_file << _tcorr_y[ifeech][ipt]; + if ( ipt%10 == 9 ) + { + cal_timecorr_file << std::endl; + } + else + { + cal_timecorr_file << " "; + } + } + } + cal_timecorr_file.close(); + + return 1; +} + #ifndef ONLINE int MbdCalib::Write_CDB_SlewCorr(const std::string& dbfile) { @@ -1991,6 +2176,40 @@ int MbdCalib::Write_CDB_SlewCorr(const std::string& dbfile) } #endif +int MbdCalib::Write_SlewCorr(const std::string& dbfile) +{ + std::ofstream cal_slewcorr_file; + cal_slewcorr_file.open(dbfile); + if (!cal_slewcorr_file.is_open()) + { + std::cout << PHWHERE << "unable to open " << dbfile << std::endl; + return -1; + } + for (int ifeech = 0; ifeech < MbdDefs::MBD_N_FEECH; ifeech++) + { + if ( _mbdgeom->get_type(ifeech) == 1 ) + { + continue; // skip q-channels + } + cal_slewcorr_file << ifeech << "\t" << _scorr_npts[ifeech] << "\t" << _scorr_minrange[ifeech] << "\t" << _scorr_maxrange[ifeech] << std::endl; + for (int ipt=0; ipt<_scorr_npts[ifeech]; ipt++) + { + cal_slewcorr_file << _scorr_y[ifeech][ipt]; + if ( ipt%10 == 9 ) + { + cal_slewcorr_file << std::endl; + } + else + { + cal_slewcorr_file << " "; + } + } + } + cal_slewcorr_file.close(); + + return 1; +} + #ifndef ONLINE int MbdCalib::Write_CDB_TimeRMS(const std::string& dbfile) { @@ -2220,10 +2439,114 @@ int MbdCalib::Write_Thresholds(const std::string& dbfile) #ifndef ONLINE int MbdCalib::Write_CDB_All() { - return 1; + int status = 1; + + if ( Write_CDB_Shapes("mbd_shape.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_TimeCorr("mbd_timecorr.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_SlewCorr("mbd_slewcorr.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_Pileup("mbd_pileup.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_SampMax("mbd_sampmax.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_Ped("mbd_ped.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_Status("mbd_status.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_TTT0("mbd_tt_t0.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_TQT0("mbd_tq_t0.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_T0Corr("mbd_t0corr.root") != 1 ) + { + status = 0; + } + if ( Write_CDB_Gains("mbd_qfit.root") != 1 ) + { + status = 0; + } + //Write_CDB_TimeRMS("mbd_trms.root"); + //Write_CDB_Thresholds("mbd_thresh.root"); + + return status; } #endif +int MbdCalib::Write_All() +{ + int status = 1; + /* + if ( Write_Shapes("mbd_shape.calib") != 1 ) + { + status = 0; + } + */ + if ( Write_TimeCorr("mbd_timecorr.calib") != 1 ) + { + status = 0; + } + if ( Write_SlewCorr("mbd_slewcorr.calib") != 1 ) + { + status = 0; + } + if ( Write_Pileup("mbd_pileup.calib") != 1 ) + { + status = 0; + } + if ( Write_SampMax("mbd_sampmax.calib") != 1 ) + { + status = 0; + } + if ( Write_Ped("mbd_ped.calib") != 1 ) + { + status = 0; + } + if ( Write_Status("mbd_status.calib") != 1 ) + { + status = 0; + } + if ( Write_TTT0("mbd_tt_t0.calib") != 1 ) + { + status = 0; + } + if ( Write_TQT0("mbd_tq_t0.calib") != 1 ) + { + status = 0; + } + if ( Write_T0Corr("mbd_t0corr.calib") != 1 ) + { + status = 0; + } + if ( Write_Gains("mbd_qfit.calib") != 1 ) + { + status = 0; + } + //Write_TimeRMS("mbd_trms.calib"); + //Write_Thresholds("mbd_thresh.calib"); + + return status; +} + // dz is what we need to move the MBD z by // dt is what we change the MBD t0 by void MbdCalib::Update_TQT0(const float dz, const float dt) @@ -2327,7 +2650,7 @@ void MbdCalib::Reset_Pileup() _pileup_p0err.fill(std::numeric_limits::quiet_NaN()); _pileup_p1err.fill(std::numeric_limits::quiet_NaN()); _pileup_p2err.fill(std::numeric_limits::quiet_NaN()); - _qfit_chi2ndf.fill(std::numeric_limits::quiet_NaN()); + _pileup_chi2ndf.fill(std::numeric_limits::quiet_NaN()); } void MbdCalib::Reset_Thresholds() @@ -2342,6 +2665,17 @@ void MbdCalib::Reset_Thresholds() _thresh_chi2ndf.fill(std::numeric_limits::quiet_NaN()); } +#ifndef ONLINE +void MbdCalib::Save_CDB_URL() +{ + for (const auto &kv : _cdb_urls) + { + auto named = std::make_unique(kv.first.c_str(), kv.second.c_str()); + named->Write(); + } +} +#endif + void MbdCalib::Reset() { Reset_TTT0(); @@ -2353,6 +2687,7 @@ void MbdCalib::Reset() Reset_Thresholds(); _sampmax.fill(-1); + _mbdstatus.fill(0); } void MbdCalib::set_ped(const int ifeech, const float m, const float merr, const float s, const float serr) @@ -2419,3 +2754,31 @@ TGraph *MbdCalib::get_lut_graph(const int pmtch, std::string_view type) return g; } + +void MbdCalib::set_pileup(const int ifeech, const int ipar, const float pval) +{ + int chtype = (ifeech / 8) % 2; // 0=T-ch, 1=Q-ch + + if (ipar==0) + { + _pileup_p0[ifeech] = pval; + } + else if (ipar==1) + { + _pileup_p1[ifeech] = pval; + } + else if (ipar==2) + { + _pileup_p2[ifeech] = pval; + } + else if (ipar==3 && chtype==0) + { + _pileup_p1err[ifeech] = pval; + } + else if (ipar==4 && chtype==0) + { + _pileup_p2err[ifeech] = pval; + } +} + + diff --git a/offline/packages/mbd/MbdCalib.h b/offline/packages/mbd/MbdCalib.h index 6d7208f631..53b8a6f187 100644 --- a/offline/packages/mbd/MbdCalib.h +++ b/offline/packages/mbd/MbdCalib.h @@ -12,12 +12,14 @@ #include #include +#include #include #include #include class TTree; class TGraph; +class TNamed; class CDBInterface; class MbdCalib @@ -35,8 +37,42 @@ class MbdCalib float get_tq0(const int ipmt) const { return _tqfit_t0mean[ipmt]; } float get_t0corr() const { return _t0corrmean; } float get_ped(const int ifeech) const { return _pedmean[ifeech]; } + float get_pederr(const int ifeech) const { return _pedmeanerr[ifeech]; } float get_pedrms(const int ifeech) const { return _pedsigma[ifeech]; } + float get_pedrmserr(const int ifeech) const { return _pedsigmaerr[ifeech]; } int get_sampmax(const int ifeech) const { return _sampmax[ifeech]; } + int get_status(const int ifeech) const { return _mbdstatus[ifeech]; } + + float get_pileup(const int ifeech, const int ipar) const + { + int chtype = (ifeech / 8) % 2; // 0=T-ch, 1=Q-ch + + if (ipar==0) + { + return _pileup_p0[ifeech]; + } + else if (ipar==1) + { + return _pileup_p1[ifeech]; + } + else if (ipar==2) + { + return _pileup_p2[ifeech]; + } + else if (ipar==3 && chtype==0) + { + return _pileup_p1err[ifeech]; + } + else if (ipar==4 && chtype==0) + { + return _pileup_p2err[ifeech]; + } + + return std::numeric_limits::quiet_NaN(); + } + + void get_tcorr_range(const int ifeech, int& min, int& max, int& step); + float get_tcorr(const int ifeech, const int tdc) const { if (tdc<0) { @@ -85,30 +121,14 @@ class MbdCalib std::vector get_shape(const int ifeech) const { return _shape_y[ifeech]; } std::vector get_sherr(const int ifeech) const { return _sherr_yerr[ifeech]; } - float get_pileup(const int ifeech, const int ipar) const { - - if (ipar==0) - { - return _pileup_p0[ifeech]; - } - else if (ipar==1) - { - return _pileup_p1[ifeech]; - } - else if (ipar==2) - { - return _pileup_p2[ifeech]; - } - - return std::numeric_limits::quiet_NaN(); - } - float get_threshold(const int pmtch, const int rel_or_abs = 0); TGraph *get_lut_graph(const int pmtch, std::string_view type); void set_sampmax(const int ifeech, const int val) { _sampmax[ifeech] = val; } + void set_status(const int ifeech, const int val) { _mbdstatus[ifeech] = val; } void set_ped(const int ifeech, const float m, const float merr, const float s, const float serr); + void set_pileup(const int ifeech, const int ipar, const float val); void set_tt0(const int ipmt, const float t0) { _ttfit_t0mean[ipmt] = t0; } void set_tq0(const int ipmt, const float t0) { _tqfit_t0mean[ipmt] = t0; } @@ -118,6 +138,7 @@ class MbdCalib int Download_T0Corr(const std::string& dbase_location); int Download_Ped(const std::string& dbase_location); int Download_SampMax(const std::string& dbase_location); + int Download_Status(const std::string& dbase_location); int Download_Shapes(const std::string& dbase_location); int Download_TimeCorr(const std::string& dbase_location); int Download_SlewCorr(const std::string& dbase_location); @@ -128,6 +149,7 @@ class MbdCalib #ifndef ONLINE int Write_CDB_SampMax(const std::string& dbfile); + int Write_CDB_Status(const std::string& dbfile); int Write_CDB_TTT0(const std::string& dbfile); int Write_CDB_TQT0(const std::string& dbfile); int Write_CDB_T0Corr(const std::string& dbfile); @@ -139,17 +161,21 @@ class MbdCalib int Write_CDB_Gains(const std::string& dbfile); int Write_CDB_Pileup(const std::string& dbfile); int Write_CDB_Thresholds(const std::string& dbfile); - static int Write_CDB_All(); + int Write_CDB_All(); #endif int Write_SampMax(const std::string& dbfile); + int Write_Status(const std::string& dbfile); int Write_TQT0(const std::string& dbfile); int Write_TTT0(const std::string& dbfile); int Write_T0Corr(const std::string& dbfile); int Write_Ped(const std::string& dbfile); + int Write_TimeCorr(const std::string& dbfile); + int Write_SlewCorr(const std::string& dbfile); int Write_Gains(const std::string& dbfile); int Write_Pileup(const std::string& dbfile); int Write_Thresholds(const std::string& dbfile); + int Write_All(); void Reset_TQT0(); void Reset_TTT0(); @@ -164,6 +190,10 @@ class MbdCalib // void Dump_to_file(const std::string& what = "ALL"); +#ifndef ONLINE + void Save_CDB_URL(); +#endif + void SetRawDstFlag(const int r) { _rawdstflag = r; } void SetFitsOnly(const int f) { _fitsonly = f; } @@ -177,6 +207,7 @@ class MbdCalib #ifndef ONLINE CDBInterface* _cdb{nullptr}; recoConsts* _rc{nullptr}; + std::map _cdb_urls; #endif std::unique_ptr _mbdgeom{nullptr}; @@ -231,6 +262,9 @@ class MbdCalib // SampMax (Peak of waveform) std::array _sampmax{}; + // Status (MBD Channel Status) + std::array _mbdstatus{}; + // Pileup waveform correction std::array _pileup_p0{}; std::array _pileup_p0err{}; diff --git a/offline/packages/mbd/MbdCalibReco.cc b/offline/packages/mbd/MbdCalibReco.cc new file mode 100644 index 0000000000..3b64e0f63e --- /dev/null +++ b/offline/packages/mbd/MbdCalibReco.cc @@ -0,0 +1,418 @@ +#include "MbdCalibReco.h" +#include "MbdCalib.h" +#include "MbdDefs.h" +#include "MbdPmtContainer.h" +#include "MbdPmtHit.h" +#include "MbdOut.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MbdCalibReco::MbdCalibReco(const std::string &name) + : SubsysReco(name) +{ +} + +int MbdCalibReco::Init(PHCompositeNode * /*topNode*/) +{ + _mbdcal = std::make_unique(); + _mbdcal->Verbosity( Verbosity() ); + return Fun4AllReturnCodes::EVENT_OK; +} + +int MbdCalibReco::InitRun(PHCompositeNode *topNode) +{ + _runheader = findNode::getClass(topNode, "RunHeader"); + if (!_runheader) + { + std::cout << PHWHERE << " RunHeader node not found, will use run number 0" << std::endl; + } + + _runnumber = _runheader ? _runheader->get_RunNumber() : 0; + + getNodes(topNode); + + // Build run directory path and create it + std::ostringstream oss; + oss << _caldir << "/" << _runnumber; + _rundir = oss.str(); + gSystem->Exec(("mkdir -p " + _rundir).c_str()); + + if (!_cdbtag.empty()) + { + // Download baseline calibrations from CDB + recoConsts::instance()->set_StringFlag("CDB_GLOBALTAG", _cdbtag); + CDBInterface* cdb = CDBInterface::instance(); + std::string url; + + url = cdb->getUrl("MBD_SAMPMAX"); + if (!url.empty()) { _mbdcal->Download_SampMax(url); } + + url = cdb->getUrl("MBD_PED"); + if (!url.empty()) { _mbdcal->Download_Ped(url); } + + url = cdb->getUrl("MBD_TIMECORR"); + if (!url.empty()) { _mbdcal->Download_TimeCorr(url); } + + url = cdb->getUrl("MBD_SLEWCORR"); + if (!url.empty()) { _mbdcal->Download_SlewCorr(url); } + + std::cout << Name() << ": loaded calibrations from CDB tag " << _cdbtag << std::endl; + } + else + { + // Load baseline calibrations from local files if they exist + std::string calfile = _rundir + "/mbd_sampmax.calib"; + if (gSystem->AccessPathName(calfile.c_str()) == 0) + { + _mbdcal->Download_SampMax(calfile); + } + calfile = _rundir + "/mbd_ped.calib"; + if (gSystem->AccessPathName(calfile.c_str()) == 0) + { + _mbdcal->Download_Ped(calfile); + } + + // Load slew correction for subpass >= 2 + if (_subpass >= 2) + { + calfile = _rundir + "/mbd_slewcorr.calib"; + if (gSystem->AccessPathName(calfile.c_str()) == 0) + { + _mbdcal->Download_SlewCorr(calfile); + std::cout << Name() << ": loaded " << calfile << std::endl; + } + else + { + std::cout << Name() << ": WARNING: " << calfile << " not found" << std::endl; + } + } + } + + // Load t0 offsets for subpass >= 1 (always from local files — outputs of previous subpass) + if (_subpass >= 1) + { + std::string prevpass = "pass" + std::to_string(_subpass - 1) + "_"; + + std::string calfile = _rundir + "/" + prevpass + "mbd_tq_t0.calib"; + if (gSystem->AccessPathName(calfile.c_str()) == 0) + { + _mbdcal->Download_TQT0(calfile); + std::cout << Name() << ": loaded " << calfile << std::endl; + } + else + { + std::cout << Name() << ": WARNING: " << calfile << " not found" << std::endl; + } + + calfile = _rundir + "/" + prevpass + "mbd_tt_t0.calib"; + if (gSystem->AccessPathName(calfile.c_str()) == 0) + { + _mbdcal->Download_TTT0(calfile); + std::cout << Name() << ": loaded " << calfile << std::endl; + } + else + { + std::cout << Name() << ": WARNING: " << calfile << " not found" << std::endl; + } + } + + // Build bitmask of scaled triggers whose names begin with "MBD N&S" + _mbias_trigger_mask = 0xfc00; + + // Open output ROOT file + TDirectory *origdir = gDirectory; + + std::string outfname = _rundir + "/calmbdpass2." + std::to_string(_subpass); + if (_subpass == 0) + { + outfname += "_time-" + std::to_string(_runnumber) + ".root"; + } + else if (_subpass == 1 || _subpass == 2) + { + outfname += "_slew-" + std::to_string(_runnumber) + ".root"; + } + else + { + outfname += "_q-" + std::to_string(_runnumber) + ".root"; + } + _outfile = std::make_unique(outfname.c_str(), "RECREATE"); + if (!_outfile || _outfile->IsZombie()) + { + std::cerr << PHWHERE << " ERROR: cannot open output file " << outfname << std::endl; + _outfile.reset(); + return Fun4AllReturnCodes::ABORTRUN; + } + std::cout << Name() << ": output file " << outfname << std::endl; + + BookHistograms(); + + origdir->cd(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +int MbdCalibReco::getNodes(PHCompositeNode *topNode) +{ + _evtheader = findNode::getClass(topNode, "EventHeader"); + if (!_evtheader) + { + std::cout << PHWHERE << " EvtHeader not found, will use run number 0" << std::endl; + } + + _gl1packet = findNode::getClass(topNode,14001); + if (!_gl1packet) + { + _gl1packet = findNode::getClass(topNode, "GL1Packet"); + static int counter = 0; + if ( counter<4 ) + { + std::cout << PHWHERE << " GL1Packet not found" << std::endl; + } + } + + _mbdpmts = findNode::getClass(topNode, "MbdPmtContainer"); + if (!_mbdpmts) + { + static int counter = 0; + if ( counter<4 ) + { + std::cout << PHWHERE << " MbdPmtContainer not found" << std::endl; + } + } + + _mbdout = findNode::getClass(topNode, "MbdOut"); + if (!_mbdout) + { + static int counter = 0; + if ( counter<4 ) + { + std::cout << PHWHERE << " MbdOut not found" << std::endl; + } + } + + _mbdgeom = findNode::getClass(topNode, "MbdGeom"); + if (!_mbdgeom) + { + static int counter = 0; + if ( counter<4 ) + { + std::cout << PHWHERE << " MbdGeom not found" << std::endl; + } + } + + if ( !_mbdgeom || !_mbdout || !_mbdpmts || !_gl1packet || !_evtheader ) + { + return Fun4AllReturnCodes::ABORTRUN; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +void MbdCalibReco::BookHistograms() +{ + // Delete histograms if they have already have been booked. + if ( h2_tt ) + { + DeleteHistograms(); + return; + } + + for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) + { + std::string sn = std::to_string(ipmt); + + h_tt[ipmt] = new TH1F(("h_tt" + sn).c_str(), ("tt" + sn).c_str(), 7000, -30., 30.); + h_tt[ipmt]->SetXTitle("ns"); + + h_tq[ipmt] = new TH1F(("h_tq" + sn).c_str(), ("tq" + sn).c_str(), 7000, -150., 31. * 17.7623); + h_tq[ipmt]->SetXTitle("ns"); + + h_qp[ipmt] = new TH1F(("h_q" + sn).c_str(), ("q" + sn).c_str(), 3000, -100., 14900.); + h_qp[ipmt]->SetXTitle("ADC"); + + if (_subpass >= 1) + { + const int nbins[2] = {4000, 1100}; + const double xmin[2] = {-0.5, -5.}; + const double xmax[2] = {16000. - 0.5, 6.}; + h2_slew[ipmt] = new THnSparseF(("h2_slew" + sn).c_str(), ("slew curve, ch " + sn).c_str(), 2, nbins, xmin, xmax); + h2_slew[ipmt]->GetAxis(0)->SetTitle("ADC"); + h2_slew[ipmt]->GetAxis(1)->SetTitle("#Delta T (ns)"); + } + else + { + h2_slew[ipmt] = nullptr; + } + } + + h2_tt = new TH2F("h2_tt", "ch vs tt", 900, -150., 150., MbdDefs::MBD_N_PMT, -0.5, MbdDefs::MBD_N_PMT - 0.5); + h2_tt->SetXTitle("tt [ns]"); + h2_tt->SetYTitle("pmt ch"); + + h2_tq = new TH2F("h2_tq", "ch vs tq", 900, -150., 150., MbdDefs::MBD_N_PMT, -0.5, MbdDefs::MBD_N_PMT - 0.5); + h2_tq->SetXTitle("tq [ns]"); + h2_tq->SetYTitle("pmt ch"); +} + +void MbdCalibReco::DeleteHistograms() +{ + for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) + { + if ( h_tt[ipmt] ) + { + delete h_tt[ipmt]; + } + if ( h_tq[ipmt] ) + { + delete h_tq[ipmt]; + } + if ( h_qp[ipmt] ) + { + delete h_qp[ipmt]; + } + if ( h2_slew[ipmt] ) + { + delete h2_slew[ipmt]; + } + } + + delete h2_tt; + delete h2_tq; +} + +int MbdCalibReco::process_event(PHCompositeNode * /*topNode*/) +{ + // Require a scaled "MBD N&S" trigger + if (_mbias_trigger_mask != 0) + { + uint64_t strig = _gl1packet->getScaledVector(); // scaled trigger only + if ( (strig&_mbias_trigger_mask)==0 ) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + } + + std::array armtime{}; + armtime.fill(0); + std::array nhit{}; + nhit.fill(0); + + Float_t zvtx = _mbdout->get_zvtx(); + // Vertex cut for subpass >= 1 + if ( _subpass >= 1 ) + { + if (std::abs(zvtx) > 60.) + { + return Fun4AllReturnCodes::EVENT_OK; + } + } + + for (int iarm=0; iarm<2; iarm++) + { + armtime[iarm] = _mbdout->get_time(iarm); + nhit[iarm] = _mbdout->get_npmt(iarm); + } + + for (int ipmt=0; ipmt < _mbdpmts->get_npmt(); ipmt++) + { + MbdPmtHit *pmt = _mbdpmts->get_pmt(ipmt); + if ( !pmt ) + { + continue; + } + + Short_t pmtno = pmt->get_pmt(); + if ( pmtno<0 || pmtno>=MbdDefs::MBD_N_PMT ) + { + static int counter = 0; + if ( counter<10 ) + { + std::cerr << PHWHERE << " invalide pmt no " << pmtno << std::endl; + counter++; + } + continue; + } + + Float_t q = pmt->get_q(); + Float_t tt = pmt->get_tt(); + Float_t tq = pmt->get_tq(); + + h_tt[pmtno]->Fill( tt ); + h2_tt->Fill( tt, pmtno ); + h_tq[pmtno]->Fill( tq ); + h2_tq->Fill( tq, pmtno ); + + // Fill charge histogram for in-time hits + if ( std::abs(tt)<26.0 && q > 0.) + { + h_qp[pmtno]->Fill( q ); + } + + int arm = _mbdgeom->get_arm( pmtno ); + + // Fill slew histogram for subpass >= 1 + if (_subpass >= 1 && h2_slew[pmtno]) + { + if (nhit[arm] >= 2. && q > 0.) + { + float dt = tt - armtime[arm]; + const double coords[2] = {q, dt}; + h2_slew[pmtno]->Fill(coords); + } + } + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int MbdCalibReco::EndRun(const int /*runnumber*/) +{ + if (!_outfile) + { + return Fun4AllReturnCodes::EVENT_OK; + } + + // Write histograms to output file + _outfile->cd(); + h2_tt->Write(); + h2_tq->Write(); + for (int ipmt = 0; ipmt < MbdDefs::MBD_N_PMT; ipmt++) + { + h_tt[ipmt]->Write(); + h_tq[ipmt]->Write(); + h_qp[ipmt]->Write(); + if (h2_slew[ipmt]) + { + h2_slew[ipmt]->Write(); + } + } + + _outfile->Close(); + + return Fun4AllReturnCodes::EVENT_OK; +} + diff --git a/offline/packages/mbd/MbdCalibReco.h b/offline/packages/mbd/MbdCalibReco.h new file mode 100644 index 0000000000..eed96688cd --- /dev/null +++ b/offline/packages/mbd/MbdCalibReco.h @@ -0,0 +1,73 @@ +#ifndef MBD_MBDCALIBRECO_H +#define MBD_MBDCALIBRECO_H + +#include "MbdDefs.h" + +#include + +#include +#include +#include +#include +#include + +class PHCompositeNode; +class MbdCalib; +class MbdPmtContainer; +class MbdOut; +class MbdGeom; +class Gl1Packet; +class EventHeader; +class RunHeader; +class TH1; +class TH2; +class TFile; +class TGraphErrors; + +class MbdCalibReco : public SubsysReco +{ + public: + MbdCalibReco(const std::string& name = "MbdCalibReco"); + ~MbdCalibReco() override = default; + + int Init(PHCompositeNode* topNode) override; + int InitRun(PHCompositeNode* topNode) override; + int process_event(PHCompositeNode* topNode) override; + int EndRun(const int runnumber) override; + + void SetSubPass(const int s) { _subpass = s; } + void SetCalDir(const std::string& d) { _caldir = d; } + void SetCDBTag(const std::string& t) { _cdbtag = t; } + + private: + int getNodes(PHCompositeNode* topNode); + void BookHistograms(); + void DeleteHistograms(); + + uint64_t _mbias_trigger_mask{0}; + + int _subpass{0}; + int _runnumber{0}; + std::string _caldir{"results"}; + std::string _rundir; // _caldir// + std::string _cdbtag{}; // non-empty → download from CDB instead of local files + + std::unique_ptr _mbdcal; + MbdPmtContainer* _mbdpmts{nullptr}; + MbdOut* _mbdout{nullptr}; + MbdGeom* _mbdgeom{nullptr}; + EventHeader* _evtheader{nullptr}; + RunHeader* _runheader{nullptr}; + Gl1Packet* _gl1packet{nullptr}; + + std::array h_tt{}; + std::array h_tq{}; + std::array h_qp{}; + std::array h2_slew{}; + TH2* h2_tt{nullptr}; + TH2* h2_tq{nullptr}; + + std::unique_ptr _outfile{nullptr}; +}; + +#endif // MBD_MBDCALIBRECO_H diff --git a/offline/packages/mbd/MbdEvent.cc b/offline/packages/mbd/MbdEvent.cc index d8c72b4395..f768dfa16d 100644 --- a/offline/packages/mbd/MbdEvent.cc +++ b/offline/packages/mbd/MbdEvent.cc @@ -33,8 +33,10 @@ #include #include #include +#include #include #include +#include MbdEvent::MbdEvent(const int cal_pass, const bool proc_charge) : _nsamples(MbdDefs::MAX_SAMPLES), @@ -150,60 +152,81 @@ int MbdEvent::InitRun() _mbdcal->SetRawDstFlag( _rawdstflag ); _mbdcal->SetFitsOnly( _fitsonly ); - _mbdcal->Download_All(); if ( _simflag == 0 ) // do following for real data { + // Download calibrations + int status = _mbdcal->Download_All(); + if ( status < 0 && _calpass==0 && _fitsonly ) // only abort for production waveform pass + { + return Fun4AllReturnCodes::ABORTRUN; + } + // load pass1 calibs from local file for calpass2+ if ( _calpass>1 ) { std::string calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_sampmax.calib"; - std::cout << "Loading local sampmax, " << calfname << std::endl; - _mbdcal->Download_SampMax( calfname ); + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local sampmax, " << calfname << std::endl; + _mbdcal->Download_SampMax( calfname ); + } + else + { + std::cout << PHWHERE << "local sampmax not found, skipping: " << calfname << std::endl; + } calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_ped.calib"; - std::cout << "Loading local ped, " << calfname << std::endl; - _mbdcal->Download_Ped( calfname ); + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local ped, " << calfname << std::endl; + _mbdcal->Download_Ped( calfname ); + } + else + { + std::cout << PHWHERE << "local ped not found, skipping: " << calfname << std::endl; + } } // check if sampmax and ped calibs exist int scheck = _mbdcal->get_sampmax(0); - if ( (scheck<0 || _is_online) && _calpass!=1 ) + if ( (scheck<0 || _is_online) && _calpass==0 ) { _no_sampmax = 1000; // num events for on the fly calculation _calib_done = 0; std::cout << PHWHERE << ",no sampmax calib, determining it on the fly using first " << _no_sampmax << " evts." << std::endl; } - } - - // Init parameters of the signal processing - for (int ifeech = 0; ifeech < MbdDefs::BBC_N_FEECH; ifeech++) - { - _mbdsig[ifeech].SetCalib(_mbdcal); - // Do evt-by-evt pedestal using sample range below - if ( _calpass==1 || _is_online || _no_sampmax>0 ) - { - _mbdsig[ifeech].SetEventPed0Range(0,1); - } - else + // Init parameters of the signal processing + for (int ifeech = 0; ifeech < MbdDefs::BBC_N_FEECH; ifeech++) { - const int presamp = 5; // start from 5 samples before sampmax - const int nsamps = -1; // use all to sample 0 - _mbdsig[ifeech].SetEventPed0PreSamp(presamp, nsamps, _mbdcal->get_sampmax(ifeech)); - } + _mbdsig[ifeech].SetCalib(_mbdcal); - // Read in template if specified - if ( do_templatefit && _mbdgeom->get_type(ifeech)==1 ) - { - // std::cout << PHWHERE << "Reading template " << ifeech << std::endl; - // std::cout << "SIZES0 " << _mbdcal->get_shape(ifeech).size() << std::endl; - // Should set template size automatically here - _mbdsig[ifeech].SetTemplate(_mbdcal->get_shape(ifeech), _mbdcal->get_sherr(ifeech)); - _mbdsig[ifeech].SetMinMaxFitTime(_mbdcal->get_sampmax(ifeech) - 2 - 3, _mbdcal->get_sampmax(ifeech) - 2 + 3); - //_mbdsig[ifeech].SetMinMaxFitTime( 0, 31 ); + // Do evt-by-evt pedestal using sample range below + if ( _calpass==1 || _is_online || _no_sampmax>0 ) + { + _mbdsig[ifeech].SetEventPed0Range(0,1); + } + else + { + const int presamp = 5; // start from 5 samples before sampmax + const int nsamps = -1; // use all to sample 0 + _mbdsig[ifeech].SetEventPed0PreSamp(presamp, nsamps, _mbdcal->get_sampmax(ifeech)); + } + + // Read in template if specified + if ( do_templatefit && _mbdgeom->get_type(ifeech)==1 ) + { + // std::cout << PHWHERE << "Reading template " << ifeech << std::endl; + // std::cout << "SIZES0 " << _mbdcal->get_shape(ifeech).size() << std::endl; + // Should set template size automatically here + _mbdsig[ifeech].SetTemplate(_mbdcal->get_shape(ifeech), _mbdcal->get_sherr(ifeech)); + _mbdsig[ifeech].SetMinMaxFitTime(_mbdcal->get_sampmax(ifeech) - 2 - 3, _mbdcal->get_sampmax(ifeech) - 2 + 3); + //_mbdsig[ifeech].SetMinMaxFitTime( 0, 31 ); + } } + } if ( _calpass > 0 ) @@ -273,11 +296,46 @@ int MbdEvent::InitRun() if ( _calpass == 2 ) { - // zero out the tt_t0, tq_t0, and gains to produce uncalibrated time and charge std::cout << "MBD Cal Pass 2" << std::endl; - _mbdcal->Reset_TTT0(); - _mbdcal->Reset_TQT0(); - _mbdcal->Reset_Gains(); + + // zero out the tt_t0, tq_t0, and gains to produce uncalibrated time and charge + // or load pass2 calibs from local file for calpass2+, if local files exist + std::string calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_tt_t0.calib"; + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local mbd_tt_t0, " << calfname << std::endl; + _mbdcal->Download_TTT0( calfname ); + } + else + { + _mbdcal->Reset_TTT0(); + std::cout << PHWHERE << "local mbd_tt_t0 not found, reset to 0: " << calfname << std::endl; + } + + calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_tq_t0.calib"; + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local mbd_tq_t0, " << calfname << std::endl; + _mbdcal->Download_TQT0( calfname ); + } + else + { + _mbdcal->Reset_TQT0(); + std::cout << PHWHERE << "local mbd_tq_t0 not found, reset to 0: " << calfname << std::endl; + } + + calfname = "results/"; calfname += std::to_string(_runnum); calfname += "/mbd_qfit.calib"; + if ( std::filesystem::exists(calfname) ) + { + std::cout << "Loading local mbd_qfit, " << calfname << std::endl; + _mbdcal->Download_Gains( calfname ); + } + else + { + _mbdcal->Reset_Gains(); + std::cout << PHWHERE << "local mbd_gains not found, reset to 1: " << calfname << std::endl; + } + TDirectory *orig_dir = gDirectory; @@ -361,6 +419,24 @@ int MbdEvent::End() orig_dir->cd(); } + // Write out MbdSig eval histograms + if ( _doeval ) + { + TDirectory *orig_dir = gDirectory; + + // _doeval is overloaded with segment_number+1 + std::string savefname = std::format("mbdfiteval_{:08}-{:05}.root",_runnum,_doeval-1); + _evalfile = std::make_unique(savefname.c_str(),"RECREATE"); + + for (auto & sig : _mbdsig) + { + sig.WritePedvsEvent(); + sig.WriteChi2Hist(); + } + + orig_dir->cd(); + } + return 1; } @@ -397,7 +473,13 @@ void MbdEvent::Clear() bool MbdEvent::isbadtch(const int ipmtch) { - return std::fabs(_mbdcal->get_tt0(ipmtch))>100.; + int feech = _mbdgeom->get_feech(ipmtch,0); + if ( _mbdcal->get_status(feech) > 0 ) + { + return true; + } + + return false; } @@ -412,13 +494,18 @@ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbc return Fun4AllReturnCodes::DISCARDEVENT; } + int evtseq = 0; + if ( gl1raw != nullptr ) + { + evtseq = gl1raw->getEvtSequence(); + } + // Only use MBDNS triggered events for MBD calibrations if ( _calpass>0 && gl1raw != nullptr ) { const uint64_t MBDTRIGS = 0x7c00; // MBDNS trigger bits //uint64_t trigvec = gl1raw->getTriggerVector(); // raw trigger only (obsolete, was only available in run1) uint64_t strig = gl1raw->getScaledVector(); // scaled trigger only - int evtseq = gl1raw->getEvtSequence(); if ( Verbosity() ) { static int counter = 0; @@ -451,6 +538,7 @@ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbc if (dstp[ipkt]) { _nsamples = dstp[ipkt]->iValue(0, "SAMPLES"); + { static bool printcount{true}; if ( printcount && Verbosity() > 0) @@ -460,6 +548,13 @@ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbc } } + // skip empty packets, corrupt event + if ( _nsamples == 0 ) + { + std::cout << PHWHERE << " ERROR, evt " << m_evt << " no samples in Packet " << pktid << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + m_xmitclocks[ipkt] = static_cast(dstp[ipkt]->iValue(0, "CLOCK")); m_femclocks[ipkt][0] = static_cast(dstp[ipkt]->iValue(0, "FEMCLOCK")); @@ -484,9 +579,18 @@ int MbdEvent::SetRawData(std::array< CaloPacket *,2> &dstp, MbdRawContainer *bbc } _mbdsig[feech].SetNSamples( _nsamples ); - _mbdsig[feech].SetXY(m_samp[feech], m_adc[feech]); - + + if ( _nsamples > 0 && _nsamples <= 30 ) + { + _mbdsig[feech].SetXY(m_samp[feech], m_adc[feech]); + _mbdsig[feech].SetEvtNum( evtseq ); + } /* + else + { + std::cout << PHWHERE << " empty feech " << feech << std::endl; + } + std::cout << "feech " << feech << std::endl; _mbdsig[feech].Print(); */ @@ -565,6 +669,7 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer if (p[ipkt]) { _nsamples = p[ipkt]->iValue(0, "SAMPLES"); + { static int counter = 0; if ( counter<1 ) @@ -574,6 +679,15 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer counter++; } + // If packets are missing, stop processing event + if ( _nsamples == 0 ) + { + std::cout << PHWHERE << " ERROR, skipping evt " << m_evt << " nsamples = 0 " << pktid << std::endl; + delete p[ipkt]; + p[ipkt] = nullptr; + return Fun4AllReturnCodes::ABORTEVENT; + } + m_xmitclocks[ipkt] = static_cast(p[ipkt]->iValue(0, "CLOCK")); m_femclocks[ipkt][0] = static_cast(p[ipkt]->iValue(0, "FEMCLOCK")); @@ -600,6 +714,7 @@ int MbdEvent::SetRawData(Event *event, MbdRawContainer *bbcraws, MbdPmtContainer _mbdsig[feech].SetNSamples( _nsamples ); _mbdsig[feech].SetXY(m_samp[feech], m_adc[feech]); + _mbdsig[feech].SetEvtNum( m_evt ); //_mbdsig[feech].Print(); } @@ -637,8 +752,9 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) // Do a quick sanity check that all fem counters agree if (m_xmitclocks[0] != m_xmitclocks[1]) { - std::cout << __FILE__ << ":" << __LINE__ << " ERROR, xmitclocks don't agree" << std::endl; + std::cout << __FILE__ << ":" << __LINE__ << " ERROR, xmitclocks don't agree, evt " << m_evt << std::endl; } + /* // format changed in run2024, need to update check for (auto &femclock : femclocks) @@ -673,20 +789,24 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) int pmtch = _mbdgeom->get_pmt(ifeech); int type = _mbdgeom->get_type(ifeech); // 0 = T-channel, 1 = Q-channel + if ( _mbdsig[ifeech].GetNSamples()==0 ) + { + continue; + } + // time channel if (type == 0) { m_ttdc[pmtch] = _mbdsig[ifeech].MBDTDC(_mbdcal->get_sampmax(ifeech)); - if ( m_ttdc[pmtch] < 40. || std::isnan(m_ttdc[pmtch]) || isbadtch(pmtch) ) + if ( m_ttdc[pmtch] < 40. || std::isnan(m_ttdc[pmtch]) ) { m_ttdc[pmtch] = std::numeric_limits::quiet_NaN(); // no hit } } - else if ( type == 1 && (!std::isnan(m_ttdc[pmtch]) || isbadtch(pmtch) || _always_process_charge ) ) + else if ( type == 1 && (!std::isnan(m_ttdc[pmtch]) || _always_process_charge ) ) { // we process charge channels which have good time hit - // or have time channels marked as bad // or have always_process_charge set to 1 (useful for threshold studies) // Use dCFD method to seed time in charge channels (or as primary if not fitting template) @@ -697,24 +817,21 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) m_ampl[ifeech] = _mbdsig[ifeech].GetAmpl(); // in adc units if (do_templatefit) { - //std::cout << "fittemplate" << std::endl; + //std::cout << "fittemplate " << ifeech << std::endl; _mbdsig[ifeech].FitTemplate( _mbdcal->get_sampmax(ifeech) ); + /* if ( _verbose ) { std::cout << "tt " << ifeech << " " << pmtch << " " << m_pmttt[pmtch] << std::endl; } + */ m_qtdc[pmtch] = _mbdsig[ifeech].GetTime(); // in units of sample number m_ampl[ifeech] = _mbdsig[ifeech].GetAmpl(); // in units of adc } // calpass 2, uncal_mbd. template fit. make sure qgain = 1, tq_t0 = 0 - // In Run 1 (runs before 40000), we didn't set hardware thresholds, and instead set a software threshold of 0.25 - if ( ((m_ampl[ifeech] < (_mbdcal->get_qgain(pmtch) * 0.25)) && (_runnum < 40000)) || std::fabs(_mbdcal->get_tq0(pmtch))>100. ) - { - m_qtdc[pmtch] = std::numeric_limits::quiet_NaN(); - } } } @@ -724,6 +841,8 @@ int MbdEvent::ProcessPackets(MbdRawContainer *bbcraws) { int feech = _mbdgeom->get_feech(ipmt); bbcraws->get_pmt(ipmt)->set_pmt(ipmt, m_ampl[feech], m_ttdc[ipmt], m_qtdc[ipmt]); + bbcraws->get_pmt(ipmt)->set_chi2ndf( _mbdsig[feech].GetChi2NDF() ); + bbcraws->get_pmt(ipmt)->set_fitinfo( _mbdsig[feech].GetFitInfo() ); } bbcraws->set_npmt(MbdDefs::BBC_N_PMT); // this would need to be changed if we zero-suppressed bbcraws->set_clocks(m_evt, m_clk, m_femclk); @@ -739,11 +858,17 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc int pmtch = _mbdgeom->get_pmt(ifeech); int type = _mbdgeom->get_type(ifeech); // 0 = T-channel, 1 = Q-channel + if ( _mbdsig[ifeech].GetNSamples()==0 ) + { + continue; + } + // time channel if (type == 0) { if ( std::isnan(bbcraws->get_pmt(pmtch)->get_ttdc()) || isbadtch(pmtch) ) { + // time channel has no hit or is marked as bad m_pmttt[pmtch] = std::numeric_limits::quiet_NaN(); // no hit } else @@ -754,6 +879,16 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc m_pmttt[pmtch] -= _mbdcal->get_tt0(pmtch); } + /* + if ( !std::isnan(m_pmttt[pmtch]) ) + { + std::cout << "pmttt " << m_evt << "\t" << pmtch << "\t" << m_pmttt[pmtch] << "\t" + << bbcraws->get_pmt(pmtch)->get_ttdc() << "\t" + << _mbdcal->get_tcorr(ifeech,bbcraws->get_pmt(pmtch)->get_ttdc()) << "\t" + << _mbdcal->get_tt0(pmtch) << std::endl; + } + */ + } else if ( type == 1 && (!std::isnan(bbcraws->get_pmt(pmtch)->get_ttdc()) || isbadtch(pmtch) || _always_process_charge ) ) { @@ -761,7 +896,15 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc // or have time channels marked as bad // or have always_process_charge set to 1 (useful for threshold studies) - m_pmttq[pmtch] = bbcraws->get_pmt(pmtch)->get_qtdc(); + // In Run 1 (runs before 40000), we didn't set hardware thresholds, and instead set a software threshold of 0.25 + if ( ((bbcraws->get_pmt(pmtch)->get_adc() < (_mbdcal->get_qgain(pmtch) * 0.25)) && (_runnum < 40000)) || std::fabs(_mbdcal->get_tq0(pmtch))>100. ) + { + m_pmttq[pmtch] = std::numeric_limits::quiet_NaN(); + } + else + { + m_pmttq[pmtch] = bbcraws->get_pmt(pmtch)->get_qtdc(); + } if ( !std::isnan(m_pmttq[pmtch]) ) { @@ -770,17 +913,15 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc m_pmttq[pmtch] = m_pmttq[pmtch] - _mbdcal->get_tq0(pmtch); // if ( m_pmttq[pmtch]<-50. && ifeech==255 ) std::cout << "hit_times " << ifeech << "\t" << m_pmttq[pmtch] << std::endl; - // if ( arm==1 ) std::cout << "hit_times " << ifeech << "\t" << setw(10) << m_pmttq[pmtch] << "\t" << board << "\t" << TRIG_SAMP[board] << std::endl; // if tt is bad, use tq - if ( std::fabs(_mbdcal->get_tt0(pmtch))>100. ) + if ( _mbdcal->get_status(ifeech-8)>0 ) { m_pmttt[pmtch] = m_pmttq[pmtch]; } else { // we have a good tt ch. correct for slew if there is a hit - //if ( ifeech==0 ) std::cout << "applying scorr" << std::endl; if ( !std::isnan(m_pmttt[pmtch]) ) { m_pmttt[pmtch] -= _mbdcal->get_scorr(ifeech-8,bbcraws->get_pmt(pmtch)->get_adc()); @@ -819,7 +960,10 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc // Copy to output for (int ipmt = 0; ipmt < MbdDefs::BBC_N_PMT; ipmt++) { + int feech = _mbdgeom->get_feech(ipmt); bbcpmts->get_pmt(ipmt)->set_pmt(ipmt, m_pmtq[ipmt], m_pmttt[ipmt], m_pmttq[ipmt]); + bbcraws->get_pmt(ipmt)->set_chi2ndf( _mbdsig[feech].GetChi2NDF() ); + bbcraws->get_pmt(ipmt)->set_fitinfo( _mbdsig[feech].GetFitInfo() ); } bbcpmts->set_npmt(MbdDefs::BBC_N_PMT); @@ -854,8 +998,14 @@ int MbdEvent::ProcessRawContainer(MbdRawContainer *bbcraws, MbdPmtContainer *bbc */ TGraphErrors *gsubpulse = _mbdsig[ifeech].GetGraph(); - Double_t *y = gsubpulse->GetY(); - h2_trange->Fill( y[samp_max], pmtch ); // fill ped-subtracted tdc + if ( gsubpulse ) + { + Double_t *y = gsubpulse->GetY(); + if ( y ) + { + h2_trange->Fill( y[samp_max], pmtch ); // fill ped-subtracted tdc + } + } } } @@ -1040,11 +1190,6 @@ int MbdEvent::Calculate(MbdPmtContainer *bbcpmts, MbdOut *bbcout, PHCompositeNod gausfit[iarm]->SetRange(hevt_bbct[iarm]->GetMean() - 5, hevt_bbct[iarm]->GetMean() + 5); */ - if ( hevt_bbct[iarm]->GetEntries()==0 )//chiu - { - std::cout << PHWHERE << " hevt_bbct EMPTY" << std::endl; - } - hevt_bbct[iarm]->Fit(gausfit[iarm], "BNQLR"); // m_bbct[iarm] = m_bbct[iarm] / m_bbcn[iarm]; @@ -1286,7 +1431,7 @@ int MbdEvent::FillSampMaxCalib() // _no_sampmax keeps track of how many events to use for on-the-fly calibration _no_sampmax--; - if ( _no_sampmax==0 && _calpass != 1 ) + if ( _no_sampmax==0 && _calpass==0 ) { CalcSampMaxCalib(); _calib_done = 1; @@ -1375,10 +1520,6 @@ int MbdEvent::CalcPedCalib() pedgaus->SetParameters(ampl,mean,sigma); pedgaus->SetRange(mean-(4*sigma), mean+(4*sigma)); - if ( hped0->GetEntries()==0 ) //chiu - { - std::cout << "HPED0 EMPTY" << std::endl; - } hped0->Fit(pedgaus,"RNQ"); mean = pedgaus->GetParameter(1); diff --git a/offline/packages/mbd/MbdEvent.h b/offline/packages/mbd/MbdEvent.h index ede1670171..31d22303f6 100644 --- a/offline/packages/mbd/MbdEvent.h +++ b/offline/packages/mbd/MbdEvent.h @@ -74,6 +74,7 @@ class MbdEvent void set_EventNumber(int ievt) { m_evt = ievt; } void set_debug(const int d) { _debug = d; } + void set_doeval(const int d) { _doeval = d; } MbdSig *GetSig(const int ipmt) { return &_mbdsig[ipmt]; } @@ -123,7 +124,7 @@ class MbdEvent int _verbose{0}; int _runnum{0}; int _simflag{0}; - int _rawdstflag{0}; // dst with raw container + int _rawdstflag{0}; // reading from dst with raw container int _fitsonly{0}; // stop reco after waveform fits (for DST_CALOFIT pass) int _nsamples{31}; int _calib_done{0}; @@ -196,12 +197,14 @@ class MbdEvent // debug stuff TCanvas *ac{nullptr}; // for plots used during debugging void PlotDebug(); + int _doeval{0}; + std::unique_ptr _evalfile{nullptr}; std::unique_ptr _synctfile{nullptr}; TTree *_syncttree{nullptr}; Double_t _refz{ std::numeric_limits::quiet_NaN() }; - std::vector bbevt; + std::vector bbevt; std::vector bbclk; - std::vector mybbz; + std::vector mybbz; std::vector bco; std::vector intz; std::vector bbz; diff --git a/offline/packages/mbd/MbdRawContainerV2.cc b/offline/packages/mbd/MbdRawContainerV2.cc new file mode 100644 index 0000000000..9b7236de4a --- /dev/null +++ b/offline/packages/mbd/MbdRawContainerV2.cc @@ -0,0 +1,64 @@ +#include "MbdRawContainerV2.h" +#include "MbdRawHitV2.h" +#include "MbdReturnCodes.h" +#include "MbdDefs.h" + +#include + +#include + +MbdRawContainerV2::MbdRawContainerV2() : MbdRawHits(new TClonesArray("MbdRawHitV2", MbdDefs::MBD_N_PMT)) +{ + // MbdRawHit is class for single hit (members: pmt,adc,ttdc,qtdc), do not mix + // with TClonesArray *MbdRawHits + +} + +MbdRawContainerV2::~MbdRawContainerV2() +{ + delete MbdRawHits; +} + +int MbdRawContainerV2::isValid() const +{ + if (npmt <= 0) + { + return 0; + } + return 1; +} + +void MbdRawContainerV2::Reset() +{ + MbdRawHits->Clear(); + npmt = 0; +} + +void MbdRawContainerV2::identify(std::ostream &out) const +{ + out << "identify yourself: I am a MbdRawContainerV2 object" << std::endl; +} + +//______________________________________ +void MbdRawContainerV2::set_clocks(const Int_t ievt, const UShort_t iclk, const UShort_t ifemclk) +{ + evt = ievt; + clk = iclk; + femclk = ifemclk; +} + +Int_t MbdRawContainerV2::get_evt() const +{ + return evt; +} + +UShort_t MbdRawContainerV2::get_clock() const +{ + return clk; +} + +UShort_t MbdRawContainerV2::get_femclock() const +{ + return femclk; +} + diff --git a/offline/packages/mbd/MbdRawContainerV2.h b/offline/packages/mbd/MbdRawContainerV2.h new file mode 100644 index 0000000000..199ab4cc73 --- /dev/null +++ b/offline/packages/mbd/MbdRawContainerV2.h @@ -0,0 +1,84 @@ +#ifndef MBD_MBDRAWCONTAINERV2_H__ +#define MBD_MBDRAWCONTAINERV2_H__ + +#include "MbdRawContainer.h" + +#include + +#include + +/// +class MbdRawContainerV2 : public MbdRawContainer +{ +public: + /// ctor + MbdRawContainerV2(); + + /// dtor + virtual ~MbdRawContainerV2(); + + /// Clear Event + void Reset() override; + + /** identify Function from PHObject + @param os Output Stream + */ + void identify(std::ostream &out = std::cout) const override; + + /// isValid returns non zero if object contains vailid data + int isValid() const override; + + /** Add Mbd data containing evt, clk, and femclk + @param ievt Event number + @param iclk XMIT clock + @param ifemclk FEM clock + */ + virtual void set_clocks(const Int_t ievt, const UShort_t iclk, const UShort_t ifemclk) override; + + /** get Event Number + */ + virtual Int_t get_evt() const override; + + /** get XMIT Clock Counter + */ + virtual UShort_t get_clock() const override; + + /** get FEM Clock Counter + */ + virtual UShort_t get_femclock() const override; + + /** set number of pmts for Mbd + @param ival Number of Mbd Pmt's + */ + void set_npmt(const Short_t ival) override + { + if ( ival != MbdRawHits->GetEntries() ) + { + std::cout << "ERROR, " << ival << " differs from " << MbdRawHits->GetEntries() << std::endl; + std::cout << " Setting npmt to " << MbdRawHits->GetEntries() << std::endl; + } + npmt = MbdRawHits->GetEntries(); + return; + } + + /// get Number of Mbd Pmt's + Short_t get_npmt() const override { return MbdRawHits->GetEntries(); } + + /** get MbdRawPmt of Pmt iPmt in TClonesArray + @param iPmt no of Pmt in TClonesArray + */ + MbdRawHit *get_pmt(const int iPmt) const override { return (MbdRawHit*)MbdRawHits->ConstructedAt(iPmt); } + +private: + TClonesArray *GetMbdRawHits() const { return MbdRawHits; } + + Int_t evt{-1}; + UShort_t clk{0}; + UShort_t femclk{0}; + Short_t npmt = 0; + TClonesArray *MbdRawHits = nullptr; + + ClassDefOverride(MbdRawContainerV2, 1) +}; + +#endif diff --git a/offline/packages/mbd/MbdRawContainerV2LinkDef.h b/offline/packages/mbd/MbdRawContainerV2LinkDef.h new file mode 100644 index 0000000000..2c3bf0df5d --- /dev/null +++ b/offline/packages/mbd/MbdRawContainerV2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class MbdRawContainerV2 + ; + +#endif diff --git a/offline/packages/mbd/MbdRawHit.h b/offline/packages/mbd/MbdRawHit.h index 45bd089d5b..862194352b 100644 --- a/offline/packages/mbd/MbdRawHit.h +++ b/offline/packages/mbd/MbdRawHit.h @@ -40,11 +40,53 @@ class MbdRawHit : public PHObject return MbdReturnCodes::MBD_INVALID_FLOAT; } + virtual Float_t get_chi2ndf() const + { + static int ctr = 0; + if ( ctr<3 ) + { + PHOOL_VIRTUAL_WARNING; + ctr++; + } + return MbdReturnCodes::MBD_INVALID_FLOAT; + } + + virtual UShort_t get_fitinfo() const + { + static int ctr = 0; + if ( ctr<3 ) + { + PHOOL_VIRTUAL_WARNING; + ctr++; + } + return 0; + } + virtual void set_pmt(const Short_t /*pmt*/, const Float_t /*adc*/, const Float_t /*ttdc*/, const Float_t /*qtdc*/) { PHOOL_VIRTUAL_WARNING; } + virtual void set_chi2ndf(const Double_t /*chi2ndf*/) + { + static int ctr = 0; + if ( ctr<3 ) + { + PHOOL_VIRTUAL_WARNING; + ctr++; + } + } + + virtual void set_fitinfo(const UShort_t /*fitinfo*/) + { + static int ctr = 0; + if ( ctr<3 ) + { + PHOOL_VIRTUAL_WARNING; + ctr++; + } + } + virtual void identify(std::ostream& out = std::cout) const override; virtual int isValid() const override { return 0; } diff --git a/offline/packages/mbd/MbdRawHitV1.cc b/offline/packages/mbd/MbdRawHitV1.cc index 6f4eec2001..2ea6b34c01 100644 --- a/offline/packages/mbd/MbdRawHitV1.cc +++ b/offline/packages/mbd/MbdRawHitV1.cc @@ -7,7 +7,7 @@ void MbdRawHitV1::Reset() void MbdRawHitV1::Clear(Option_t* /*unused*/) { - std::cout << "clearing " << bpmt << std::endl; + //std::cout << "clearing " << bpmt << std::endl; bpmt = -1; badc = std::numeric_limits::quiet_NaN(); bttdc = std::numeric_limits::quiet_NaN(); diff --git a/offline/packages/mbd/MbdRawHitV1.h b/offline/packages/mbd/MbdRawHitV1.h index ddb5e593e7..3b33d62e2c 100644 --- a/offline/packages/mbd/MbdRawHitV1.h +++ b/offline/packages/mbd/MbdRawHitV1.h @@ -39,6 +39,18 @@ class MbdRawHitV1 : public MbdRawHit bqtdc = tq; } + //! dummy method, only exists in V2 + void set_chi2ndf(const Double_t /*chi2ndf*/) override + { + return; + } + + //! dummy method, only exists in V2 + void set_fitinfo(const UShort_t /*fitinfo*/) override + { + return; + } + //! Prints out exact identity of object void identify(std::ostream& out = std::cout) const override; diff --git a/offline/packages/mbd/MbdRawHitV2.cc b/offline/packages/mbd/MbdRawHitV2.cc new file mode 100644 index 0000000000..695003cfb1 --- /dev/null +++ b/offline/packages/mbd/MbdRawHitV2.cc @@ -0,0 +1,23 @@ +#include "MbdRawHitV2.h" + +void MbdRawHitV2::Reset() +{ + Clear(); +} + +void MbdRawHitV2::Clear(Option_t* /*unused*/) +{ + //std::cout << "clearing " << bpmt << std::endl; + bpmt = -1; + fitstat = 0; + badc = std::numeric_limits::quiet_NaN(); + bttdc = std::numeric_limits::quiet_NaN(); + bqtdc = std::numeric_limits::quiet_NaN(); +} + +void MbdRawHitV2::identify(std::ostream& out) const +{ + out << "identify yourself: I am a MbdRawHitV2 object" << std::endl; + out << "Pmt: " << bpmt << ", adc: " << badc << ", ttdc: " + << bttdc << ", bqtdc: " << bqtdc << std::endl; +} diff --git a/offline/packages/mbd/MbdRawHitV2.h b/offline/packages/mbd/MbdRawHitV2.h new file mode 100644 index 0000000000..4bc88f871d --- /dev/null +++ b/offline/packages/mbd/MbdRawHitV2.h @@ -0,0 +1,89 @@ +#ifndef __MBD_MBDRAWHITV2_H__ +#define __MBD_MBDRAWHITV2_H__ + +#include "MbdRawHit.h" + +#include +#include +#include + +class MbdRawHitV2 : public MbdRawHit +{ + public: + MbdRawHitV2() = default; + ~MbdRawHitV2() override = default; + + //! Just does a clear + void Reset() override; + + //! Clear is used by TClonesArray to reset the tower to initial state without calling destructor/constructor + void Clear(Option_t* = "") override; + + //! PMT number + Short_t get_pmt() const override { return bpmt; } + + //! ADC + Float_t get_adc() const override { return badc; } + + //! TDC from time channel + Float_t get_ttdc() const override { return bttdc; } + + //! TDC from charge channel + Float_t get_qtdc() const override { return bqtdc; } + + //! Chi2/NDF from charge channel waveform fit + Float_t get_chi2ndf() const override { return (fitstat&0xfff)/100.; } + + //! Info about charge channel waveform fit + UShort_t get_fitinfo() const override { return (fitstat>>12); } + + //! Set PMT data values + void set_pmt(const Short_t pmt, const Float_t a, const Float_t tt, const Float_t tq) override + { + bpmt = pmt; + badc = a; + bttdc = tt; + bqtdc = tq; + } + + //! Store chi2/ndf (encoded in fitstat) + void set_chi2ndf(const Double_t chi2ndf) override + { + UShort_t us_chi2ndf = 0; + if (std::isfinite(chi2ndf) && chi2ndf > 0.) + { + const Double_t clipped = (chi2ndf > 40.95) ? 40.95 : chi2ndf; + us_chi2ndf = static_cast(clipped * 100.); + } + fitstat &= 0xf000; + fitstat |= us_chi2ndf; + } + + //! Store fitinfo (encoded in fitstat) + void set_fitinfo(const UShort_t fitinfo) override + { + fitstat &= 0xfff; + fitstat |= (fitinfo<<12); + } + + //! Prints out exact identity of object + void identify(std::ostream& out = std::cout) const override; + + //! isValid returns non zero if object contains valid data + virtual int isValid() const override + { + if (std::isnan(get_ttdc())) return 0; + return 1; + } + + private: + Short_t bpmt; + UShort_t fitstat; //waveform fit status + Float_t badc; + Float_t bttdc; + Float_t bqtdc; + + ClassDefOverride(MbdRawHitV2, 1) +}; + +#endif diff --git a/offline/packages/mbd/MbdRawHitV2LinkDef.h b/offline/packages/mbd/MbdRawHitV2LinkDef.h new file mode 100644 index 0000000000..8936852bfe --- /dev/null +++ b/offline/packages/mbd/MbdRawHitV2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class MbdRawHitV2 + ; + +#endif diff --git a/offline/packages/mbd/MbdReco.cc b/offline/packages/mbd/MbdReco.cc index c19ed37ba9..e705a671d1 100644 --- a/offline/packages/mbd/MbdReco.cc +++ b/offline/packages/mbd/MbdReco.cc @@ -2,12 +2,12 @@ #include "MbdEvent.h" #include "MbdGeomV1.h" #include "MbdOutV2.h" -#include "MbdRawContainerV1.h" +#include "MbdRawContainerV2.h" #include "MbdPmtContainerV1.h" #include "MbdPmtSimContainerV1.h" #include -#include +#include #include @@ -61,11 +61,17 @@ int MbdReco::InitRun(PHCompositeNode *topNode) } int ret = getNodes(topNode); + if ( ret != Fun4AllReturnCodes::EVENT_OK ) + { + return ret; + } m_mbdevent->SetSim(_simflag); m_mbdevent->SetRawDstFlag(_rawdstflag); m_mbdevent->SetFitsOnly(_fitsonly); - m_mbdevent->InitRun(); + m_mbdevent->set_doeval(_fiteval); + + ret = m_mbdevent->InitRun(); return ret; } @@ -103,7 +109,8 @@ int MbdReco::process_event(PHCompositeNode *topNode) int status = Fun4AllReturnCodes::EVENT_OK; if ( m_evtheader!=nullptr ) { - m_mbdevent->set_EventNumber( m_evtheader->get_EvtSequence() ); + _evtnum = m_evtheader->get_EvtSequence(); + m_mbdevent->set_EventNumber( _evtnum ); } if ( m_event!=nullptr ) @@ -125,7 +132,7 @@ int MbdReco::process_event(PHCompositeNode *topNode) static int counter = 0; if ( counter<3 ) { - std::cout << PHWHERE << " Warning, MBD discarding event " << std::endl; + std::cout << PHWHERE << " Warning, MBD discarding event " << _evtnum << std::endl; counter++; } return Fun4AllReturnCodes::DISCARDEVENT; @@ -135,7 +142,7 @@ int MbdReco::process_event(PHCompositeNode *topNode) static int counter = 0; if ( counter<3 ) { - std::cout << PHWHERE << " Warning, MBD aborting event " << std::endl; + std::cout << PHWHERE << " Warning, MBD aborting event " << _evtnum << std::endl; counter++; } return Fun4AllReturnCodes::ABORTEVENT; @@ -169,19 +176,16 @@ int MbdReco::process_event(PHCompositeNode *topNode) m_mbdevent->Calculate(m_mbdpmts, m_mbdout, topNode); // For multiple global vertex - if (m_mbdevent->get_bbcn(0) > 0 && m_mbdevent->get_bbcn(1) > 0 && _calpass==0 ) + if ( m_mbdevent->get_bbcn(0) > 0 && m_mbdevent->get_bbcn(1) > 0 && !_fitsonly && _calpass!=1 ) { - auto *vertex = new MbdVertexv2(); + auto *vertex = new MbdVertexv3(); vertex->set_t(m_mbdevent->get_bbct0()); vertex->set_z(m_mbdevent->get_bbcz()); vertex->set_z_err(0.6); vertex->set_t_err(m_tres); vertex->set_beam_crossing(0); - if ( !_fitsonly ) - { - m_mbdvtxmap->insert(vertex); - } + m_mbdvtxmap->insert(vertex); } if (Verbosity() > 0) @@ -255,7 +259,7 @@ int MbdReco::createNodes(PHCompositeNode *topNode) if (!m_mbdraws) { std::cout << "Creating MbdRawContainer Node " << std::endl; - m_mbdraws = new MbdRawContainerV1(); + m_mbdraws = new MbdRawContainerV2(); PHIODataNode *MbdRawContainerNode = new PHIODataNode(m_mbdraws, "MbdRawContainer", "PHObject"); bbcNode->addNode(MbdRawContainerNode); } diff --git a/offline/packages/mbd/MbdReco.h b/offline/packages/mbd/MbdReco.h index 0dfc7d7cbc..d824a81930 100644 --- a/offline/packages/mbd/MbdReco.h +++ b/offline/packages/mbd/MbdReco.h @@ -34,10 +34,13 @@ class MbdReco : public SubsysReco int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; - void DoOnlyFits() { _fitsonly = 1; } - void SetCalPass(const int calpass) { _calpass = calpass; } + void DoOnlyFits() { _fitsonly = 1; } + void DoFitEval(const int s) { _fiteval = s; } + void SetCalPass(const int calpass) { _calpass = calpass; if (calpass==1) DoOnlyFits(); } void SetProcChargeCh(const bool s) { _always_process_charge = s; } - void SetMbdTrigOnly(const int m) { _mbdonly = m; } + void SetMbdTrigOnly(const int m) { _mbdonly = m; } + + MbdEvent* GetMbdEvent() { return m_mbdevent.get(); } private: int createNodes(PHCompositeNode *topNode); @@ -48,10 +51,13 @@ class MbdReco : public SubsysReco int _mbdonly{0}; // only use mbd triggers int _rawdstflag{0}; // dst with raw container int _fitsonly{0}; // stop reco after waveform fits (for DST_CALOFIT pass) + int _fiteval{0}; // overload with segment+1 float m_tres = 0.05; std::unique_ptr m_gaussian = nullptr; + int _evtnum{-1}; + std::unique_ptr m_mbdevent{nullptr}; Event *m_event{nullptr}; std::arraym_mbdpacket{nullptr}; diff --git a/offline/packages/mbd/MbdReturnCodes.h b/offline/packages/mbd/MbdReturnCodes.h index c9b1aea40e..ee808346fa 100644 --- a/offline/packages/mbd/MbdReturnCodes.h +++ b/offline/packages/mbd/MbdReturnCodes.h @@ -8,8 +8,9 @@ namespace MbdReturnCodes { - const short MBD_INVALID_SHORT = std::numeric_limits::min(); //-9999; - const int MBD_INVALID_INT = std::numeric_limits::min(); //-9999; + const short MBD_INVALID_SHORT = std::numeric_limits::min(); + const unsigned short MBD_INVALID_USHORT = std::numeric_limits::min(); + const int MBD_INVALID_INT = std::numeric_limits::min(); const float MBD_INVALID_FLOAT = std::numeric_limits::quiet_NaN(); } // namespace MbdReturnCodes diff --git a/offline/packages/mbd/MbdSig.cc b/offline/packages/mbd/MbdSig.cc index ae1f821a4e..8c65012756 100644 --- a/offline/packages/mbd/MbdSig.cc +++ b/offline/packages/mbd/MbdSig.cc @@ -6,12 +6,15 @@ #include #include #include +#include +#include #include #include #include #include #include #include +#include #include #include @@ -49,12 +52,13 @@ void MbdSig::Init() gSubPulse->SetName(name); gSubPulse->GetHistogram()->SetXTitle("sample"); gSubPulse->GetHistogram()->SetYTitle("ADC"); + gSubPulse->GetHistogram()->SetTitle(name); hpulse = hRawPulse; // hpulse,gpulse point to raw by default gpulse = gRawPulse; // we switch to sub for default if ped is applied - //ped0stats = std::make_unique(100); // use the last 100 events for running pedestal - ped0stats = new MbdRunningStats(100); // use the last 100 events for running pedestal + ped0stats = new MbdRunningStats(8); // use the last 8 samples for running pedestal + name = "hPed0_"; name += _ch; hPed0 = new TH1F(name, name, 3000, -0.5, 2999.5); @@ -62,6 +66,15 @@ void MbdSig::Init() name = "hPedEvt_"; name += _ch; hPedEvt = new TH1F(name, name, 3000, -0.5, 2999.5); + if ( _pedstudyflag ) + { + gPedvsEvent = new TGraphErrors(); + name = "gpedvsevent"; + name += _ch; + gPedvsEvent->SetName(name); + gPedvsEvent->GetHistogram()->SetXTitle("evtnum"); + gPedvsEvent->GetHistogram()->SetYTitle("ped"); + } SetTemplateSize(900, 1000, -10., 20.); // SetTemplateSize(300,300,0.,15.); @@ -70,14 +83,13 @@ void MbdSig::Init() ped_fcn = new TF1("ped_fcn","[0]",0,2); ped_fcn->SetLineColor(3); - // Set tail function - ped_tail = new TF1("ped_tail","[0]+[1]*exp(-[2]*x)",0,2); - ped_tail->SetLineColor(2); + name = "h_chi2ndf"; name += _ch; + h_chi2ndf = new TH1F(name,name,2000,0,100); - // uncomment this to write out waveforms from events that have pileup from prev. crossing + // uncomment this to write out waveforms from events that have pileup from prev. crossing or next crossing /* name = "mbdsig"; name += _ch; name += ".txt"; - _pileupfile = new ofstream(name); + _pileupfile = new std::ofstream(name); */ } @@ -130,20 +142,28 @@ MbdSig::~MbdSig() { _pileupfile->close(); } + // ROOT keeps the current fitter as a process-wide cache after Fit(). + TVirtualFitter::SetFitter(nullptr, 0); delete hRawPulse; delete hSubPulse; delete gRawPulse; delete gSubPulse; - delete hPed0; delete ped0stats; - // h2Template->Write(); + delete hPed0; + delete hPedEvt; delete h2Template; delete h2Residuals; delete hAmpl; delete hTime; delete template_fcn; + delete twotemplate_fcn; delete ped_fcn; - delete ped_tail; + delete fit_pileup; + delete h_chi2ndf; + if ( _pedstudyflag ) + { + delete gPedvsEvent; + } } void MbdSig::SetEventPed0PreSamp(const Int_t presample, const Int_t nsamps, const int max_samp) @@ -218,8 +238,6 @@ void MbdSig::SetY(const Float_t* y, const int invert) Remove_Pileup(); } } - - _evt_counter++; } void MbdSig::SetXY(const Float_t* x, const Float_t* y, const int invert) @@ -251,6 +269,7 @@ void MbdSig::SetXY(const Float_t* x, const Float_t* y, const int invert) { gRawPulse->Draw("ap"); gRawPulse->GetHistogram()->SetTitle(gRawPulse->GetName()); + gPad->SetGridx(1); gPad->SetGridy(1); PadUpdate(); } @@ -291,25 +310,26 @@ void MbdSig::SetXY(const Float_t* x, const Float_t* y, const int invert) Remove_Pileup(); } + /* if ( _verbose && _ch==9 ) { std::cout << "SetXY: ch " << _ch << std::endl; gSubPulse->Print("ALL"); } + */ } - _evt_counter++; _verbose = 0; } void MbdSig::Remove_Pileup() { - //_verbose = 100; _verbose = 0; /* - if ( (_ch==238&&_evt_counter==7104) || (_ch==255&&_evt_counter==7762) ) + if ( _ch==46 && (_evt_counter>200910 && _evt_counter<200920)) { + std::cout << PHWHERE << "\t" << _evt_counter << "\t" << _ch << std::endl; _verbose = 100; } */ @@ -321,54 +341,135 @@ void MbdSig::Remove_Pileup() if ( (_ch/8)%2 == 0 ) // time ch { - float offset = _pileup_p0*gSubPulse->GetPointY(0); + double x_at_max = TMath::LocMax( 5, gSubPulse->GetY() ); - for (int isamp = 0; isamp < _nsamples; isamp++) + if ( x_at_max != 0 ) { - double x = gSubPulse->GetPointX(isamp); - double y = gSubPulse->GetPointY(isamp); + // time hit in prev crossing + if ( fit_pileup == nullptr ) + { + TString name = "fit_pileup"; name += _ch; + fit_pileup = new TF1(name,"pol3",0,16000); + fit_pileup->SetLineColor(7); + for (int ipar=0; ipar<4; ipar++) + { + fit_pileup->SetParameter( ipar, _mbdcal->get_pileup(_ch,ipar+1) ); + } + } + + int sampmax = _mbdcal->get_sampmax(_ch); + if ( (sampmax-6) > 0 ) + { + double x_sampmax = gSubPulse->GetPointX(sampmax); + double y_sampmax = gSubPulse->GetPointY(sampmax); + double y_min6 = gSubPulse->GetPointY(sampmax-6); - hSubPulse->SetBinContent( isamp + 1, y - offset ); - gSubPulse->SetPoint( isamp, x, y - offset ); + double offset = y_min6*fit_pileup->Eval(y_min6); + + hSubPulse->SetBinContent( sampmax + 1, y_sampmax - offset ); + gSubPulse->SetPoint( sampmax, x_sampmax, y_sampmax - offset ); + } + else + { + static int ctr = 0; + if ( ctr<10 ) + { + std::cout << PHWHERE << " WARNING, sampmax too early for time pileup corr" << std::endl; + ctr++; + } + } } - } - else - { - if ( fit_pileup == nullptr ) + else { - TString name = "fit_pileup"; name += _ch; - fit_pileup = new TF1(name,"gaus",-0.1,4.1); - fit_pileup->SetLineColor(2); - } + // time hit in 2 crossings before + float offset = _pileup_p0*gSubPulse->GetPointY(0); - fit_pileup->SetRange(-0.1,4.1); - fit_pileup->SetParameters( _pileup_p0*gSubPulse->GetPointY(0), _pileup_p1, _pileup_p2 ); - - // fix par limits - double plow{0.}; - double phigh{0.}; - fit_pileup->GetParLimits(2,plow,phigh); - if ( phigh < _pileup_p2 ) - { - phigh = 2*_pileup_p2; - fit_pileup->SetParLimits(2,plow,phigh); + for (int isamp = 0; isamp < _nsamples; isamp++) + { + double x = gSubPulse->GetPointX(isamp); + double y = gSubPulse->GetPointY(isamp); + + hSubPulse->SetBinContent( isamp + 1, y - offset ); + gSubPulse->SetPoint( isamp, x, y - offset ); + } } + } + else // charge ch + { + double ymax = TMath::MaxElement( 5, gSubPulse->GetY() ); + double x_at_max = TMath::LocMax( 5, gSubPulse->GetY() ); - if ( _verbose ) + if ( x_at_max != 0 ) { - gSubPulse->Fit( fit_pileup, "R" ); - gSubPulse->Draw("ap"); - PadUpdate(); + // Fit a pulse in prev crossing + template_fcn->SetParameters(ymax, x_at_max); + template_fcn->SetRange(0, x_at_max+2.1); + + if (_verbose == 0) + { + //std::cout << PHWHERE << std::endl; + gSubPulse->Fit(template_fcn, "RNQ"); + } + else + { + std::cout << "pre-pileup " << _ch << "\t" << x_at_max << "\t" << ymax << std::endl; + gSubPulse->Fit(template_fcn, "R"); + gSubPulse->Draw("ap"); + gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); + gPad->SetGridy(1); + PadUpdate(); + //gSubPulse->Print("ALL"); + } } else { - gSubPulse->Fit( fit_pileup, "RNQ" ); + // Fit the tail + if ( fit_pileup == nullptr ) + { + TString name = "fit_pileup"; name += _ch; + //fit_pileup = new TF1(name,"gaus",-0.1,4.1); + fit_pileup = new TF1(name, this, &MbdSig::SignalTail, -0.1, 4.1, 3, "MbdSig", "SignalTail"); + fit_pileup->SetLineColor(6); + } + + fit_pileup->SetRange(-0.1,4.1); + fit_pileup->SetParameters( _pileup_p0*gSubPulse->GetPointY(0), _pileup_p1, _pileup_p2 ); + + // fix par limits + double plow{0.}; + double phigh{0.}; + fit_pileup->GetParLimits(2,plow,phigh); + if ( phigh < _pileup_p2 ) + { + phigh = 2*_pileup_p2; + fit_pileup->SetParLimits(2,plow,phigh); + } + + if ( _verbose ) + { + gSubPulse->Fit( fit_pileup, "R" ); + gSubPulse->Draw("ap"); + PadUpdate(); + } + else + { + gSubPulse->Fit( fit_pileup, "RNQ" ); + } } + // subtract pre-pulse for (int isamp = 0; isamp < _nsamples; isamp++) { - double bkg = fit_pileup->Eval(isamp); + double bkg = 0.; + if ( x_at_max != 0 ) + { + bkg = template_fcn->Eval(isamp); + } + else + { + bkg = fit_pileup->Eval(isamp); + } double x = gSubPulse->GetPointX(isamp); double y = gSubPulse->GetPointY(isamp); @@ -382,6 +483,7 @@ void MbdSig::Remove_Pileup() if ( _verbose ) { + std::cout << "pileup sub " << _ch << std::endl; gSubPulse->Draw("ap"); PadUpdate(); } @@ -412,11 +514,24 @@ Double_t MbdSig::GetSplineAmpl() return f_ampl; } +void MbdSig::WriteChi2Hist() +{ + h_chi2ndf->Write(); +} + void MbdSig::WritePedHist() { hPed0->Write(); } +void MbdSig::WritePedvsEvent() +{ + if ( _pedstudyflag ) + { + gPedvsEvent->Write(); + } +} + void MbdSig::FillPed0(const Int_t sampmin, const Int_t sampmax) { Double_t x; @@ -427,13 +542,6 @@ void MbdSig::FillPed0(const Int_t sampmin, const Int_t sampmax) // gRawPulse->Print("all"); hPed0->Fill(y); - /* - // chiu taken out - ped0stats->Push( y ); - ped0 = ped0stats->Mean(); - ped0rms = ped0stats->RMS(); - */ - // std::cout << "ped0 " << _ch << " " << n << "\t" << ped0 << std::endl; // std::cout << "ped0 " << _ch << "\t" << ped0 << std::endl; } @@ -452,10 +560,10 @@ void MbdSig::FillPed0(const Double_t begin, const Double_t end) hPed0->Fill(y); /* - ped0stats->Push( y ); - ped0 = ped0stats->Mean(); - ped0rms = ped0stats->RMS(); - */ + ped0stats->Push( y ); + ped0 = ped0stats->Mean(); + ped0rms = ped0stats->RMS(); + */ // std::cout << "ped0 " << _ch << " " << n << "\t" << x << "\t" << y << std::endl; } @@ -537,9 +645,7 @@ void MbdSig::CalcEventPed0(const Double_t minpedx, const Double_t maxpedx) // If a prev event pileup is detected, return 1, otherwise, return 0 int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) { - //std::cout << PHWHERE << std::endl; //chiu //_verbose = 100; - //ped0stats->Clear(); int status = 0; // assume no pileup @@ -597,10 +703,16 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) ped_fcn->SetRange(minsamp-0.1,maxsamp+0.1); ped_fcn->SetParameter(0,1500.); - if ( gRawPulse->GetN()==0 )//chiu + gRawPulse->Fit( ped_fcn, "RNQ" ); + double chi2 = ped_fcn->GetChisquare(); + double ndf = ped_fcn->GetNDF(); + + /* + if ( chi2/ndf>4 ) { - std::cout << PHWHERE << " gRawPulse 0" << std::endl; + _verbose=100; } + */ if ( _verbose ) { @@ -614,25 +726,6 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) PadUpdate(); } } - else - { - //std::cout << PHWHERE << std::endl; - gRawPulse->Fit( ped_fcn, "RNQ" ); - - double chi2ndf = ped_fcn->GetChisquare()/ped_fcn->GetNDF(); - if ( _pileupfile != nullptr && chi2ndf > 4.0 ) - { - *_pileupfile << "ped " << _ch << " mean " << mean << "\t"; - for ( int i=0; iGetN(); i++) - { - *_pileupfile << std::setw(6) << gRawPulse->GetPointY(i); - } - *_pileupfile << std::endl; - } - } - - double chi2 = ped_fcn->GetChisquare(); - double ndf = ped_fcn->GetNDF(); if ( chi2/ndf < 4.0 ) { @@ -657,6 +750,28 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) << "isamp " << isamp << "\t" << x << "\t" << y << std::endl; } } + + // study pedestal vs event + if ( _pedstudyflag ) + { + // running pedestal (replace with mean and meanerr for evt-by-evt) + double ped_evtnum = _evt_counter; + double ped_mean = ped0stats->Mean(); + double ped_meanerr = rms; + if ( ped0stats->Size()>1 ) + { + ped_meanerr = ped0stats->RMS()/std::sqrt(ped0stats->Size()); + } + else + { + ped_meanerr = _mbdcal->get_pedrms(_ch); + } + + int n = gPedvsEvent->GetN(); + gPedvsEvent->SetPoint(n,ped_evtnum,ped_mean); + gPedvsEvent->SetPointError(n,0,ped_meanerr); + } + } else { @@ -687,11 +802,18 @@ int MbdSig::CalcEventPed0_PreSamp(const int presample, const int nsamps) } } - // use straight mean for pedestal - // Could consider using fit to hPed0 to remove outliers - //rms = ped0stats->RMS(); - //Double_t mean = hPed0->GetMean(); - //Double_t rms = hPed0->GetRMS(); + // uncomment this to write out file with pileup waveforms + /* + if ( _pileupfile != nullptr ) + { + *_pileupfile << "ped " << _ch << " mean " << mean << "\t"; + for ( int i=0; iGetN(); i++) + { + *_pileupfile << std::setw(6) << gRawPulse->GetPointY(i); + } + *_pileupfile << std::endl; + } + */ } SetPed0(mean, rms); @@ -969,9 +1091,10 @@ void MbdSig::PadUpdate() const std::cout << PHWHERE << " PadUpdate\t_verbose = " << _verbose << std::endl; if ( _verbose>5 ) { + gPad->SetGridy(1); gPad->Modified(); gPad->Update(); - std::cout << _ch << " ? "; + std::cout << _evt_counter << ": " << _ch << " ? "; if ( _verbose>10 ) { std::string junk; @@ -988,6 +1111,27 @@ void MbdSig::PadUpdate() const } } +Double_t MbdSig::SignalTail(const Double_t* x, const Double_t* par) +{ + // par[0] is the amplitude (relative to the spline amplitude) + // par[1] is the time + // x[0] units are in sample number + Double_t xx = x[0]-par[1]; + if ( xx<0. ) + { + return par[0]; + } + Double_t f = par[0]*TMath::Gaus(x[0],par[1],par[2]); + + return f; +} + +Double_t MbdSig::TwoTemplateFcn(const Double_t* x, const Double_t* par) +{ + Double_t f = TemplateFcn(x,par) + TemplateFcn(x,par+2); + return f; +} + Double_t MbdSig::TemplateFcn(const Double_t* x, const Double_t* par) { // par[0] is the amplitude (relative to the spline amplitude) @@ -1081,11 +1225,13 @@ Double_t MbdSig::TemplateFcn(const Double_t* x, const Double_t* par) } // reject points with very bad rms in shape + /* if (template_yrms[ilow] >= 1.0 || template_yrms[ihigh] >= 1.0) { TF1::RejectPoint(); // return f; } + */ // Reject points where ADC saturates int samp_point = static_cast(x[0]); @@ -1103,11 +1249,29 @@ Double_t MbdSig::TemplateFcn(const Double_t* x, const Double_t* par) } // sampmax>0 means fit to the peak near sampmax +// fitmode: +// 0 - no info or no fit +// 1 - regular template fit (shortened) +// 2 - two template fit +// 3 - two template fit, neg ampl 2nd template +// 4 - saturated template fit +// 5 - saturated and shortened template fit int MbdSig::FitTemplate( const Int_t sampmax ) { - //std::cout << PHWHERE << std::endl; //chiu - //_verbose = 100; // uncomment to see fits - //_verbose = 12; // don't see pedestal fits + //_verbose = 100; + //std::cout << PHWHERE << std::endl; + /* + if ( _evt_counter==2142 && _ch==92 ) + { + _verbose = 100; // uncomment to see fits + //_verbose = 12; // don't see pedestal fits + } + */ + + // Reset Fit Quality Parameters + f_chi2 = 0.; + f_ndf = 0.; + f_fitmode = 0; // Check if channel is empty if (gSubPulse->GetN() == 0) @@ -1124,31 +1288,44 @@ int MbdSig::FitTemplate( const Int_t sampmax ) int nsaturated = 0; for (int ipt=0; ipt 16370. ) + if ( rawsamps[ipt] > 16370. ) // don't trust adc near edge { nsaturated++; } } + /* - if ( nsaturated>2 && _ch==185 ) + if ( nsaturated>0 ) { _verbose = 12; } */ - if (_verbose > 0) { - std::cout << "Fitting ch " << _ch << std::endl; + std::cout << "Fitting ch sampmax " << _ch << "\t" << sampmax << std::endl; } // Get x and y of maximum Double_t x_at_max{-1.}; Double_t ymax{0.}; - if ( sampmax>=0 ) + if ( sampmax>0 ) { - gSubPulse->GetPoint(sampmax, x_at_max, ymax); - if ( nsaturated<=3 ) + for (int isamp=sampmax-1; isamp<=sampmax+1; isamp++) + { + if ( (isamp>=gSubPulse->GetN()) ) + { + continue; + } + double adcval = gSubPulse->GetPointY(isamp); + if ( adcval>ymax ) + { + ymax = adcval; + x_at_max = isamp; + } + } + + if ( nsaturated==0 ) { x_at_max -= 2.0; } @@ -1176,6 +1353,7 @@ int MbdSig::FitTemplate( const Int_t sampmax ) gSubPulse->Draw("ap"); gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); gPad->SetGridy(1); + gPad->SetGridx(1); PadUpdate(); } @@ -1183,22 +1361,17 @@ int MbdSig::FitTemplate( const Int_t sampmax ) return 1; } + // Start with fit over early part of waveform to reduce pileup and afterpulse effects template_fcn->SetParameters(ymax, x_at_max); - // template_fcn->SetParLimits(1, fit_min_time, fit_max_time); - // template_fcn->SetParLimits(1, 3, 15); - // template_fcn->SetRange(template_min_xrange,template_max_xrange); - if ( nsaturated<=3 ) + if ( nsaturated==0 ) { - template_fcn->SetRange(0, _nsamples); + template_fcn->SetRange(0, x_at_max+4.2); + f_fitmode = 1; } else { - template_fcn->SetRange(0, sampmax + nsaturated - 0.5); - } - - if ( gSubPulse->GetN()==0 )//chiu - { - std::cout << PHWHERE << " gSubPulse 0" << std::endl; + template_fcn->SetRange(0, sampmax + nsaturated + 0.5); + f_fitmode = 4; } if (_verbose == 0) @@ -1214,48 +1387,133 @@ int MbdSig::FitTemplate( const Int_t sampmax ) gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); gPad->SetGridy(1); PadUpdate(); - //std::cout << "doing fit2 " << _verbose << std::endl; - //std::cout << "doing fit3 " << _verbose << std::endl; //gSubPulse->Print("ALL"); } // Get fit parameters f_ampl = template_fcn->GetParameter(0); f_time = template_fcn->GetParameter(1); - if ( f_time<0. || f_time>_nsamples ) + f_chi2 = template_fcn->GetChisquare(); + f_ndf = template_fcn->GetNDF(); + Double_t chi2ndf = 1e9; + if ( f_ndf>0. ) { - f_time = _nsamples*0.5; // bad fit last time + chi2ndf = f_chi2/f_ndf; } - // refit with new range to exclude after-pulses - template_fcn->SetParameters( f_ampl, f_time ); - if ( nsaturated<=3 ) + // Good fit + if ( f_ndf>6. && chi2ndf<5. ) { - template_fcn->SetRange( 0., f_time+4.0 ); + h_chi2ndf->Fill( chi2ndf ); + + _verbose = 0; + return 1; } - else + + /* + _verbose = 100; + if ( _verbose ) { - template_fcn->SetRange( 0., f_time+nsaturated+0.8 ); + PrintResiduals(gSubPulse,template_fcn); } + */ - if (_verbose == 0) + // fit was bad, refit with two templates + if ( nsaturated==0 ) { - //std::cout << PHWHERE << std::endl; - int fit_status = gSubPulse->Fit(template_fcn, "RNQ"); - if ( fit_status<0 ) + //_verbose = 100; + f_fitmode = 2; + + if ( _verbose ) { - std::cout << PHWHERE << "\t" << fit_status << std::endl; - gSubPulse->Print("ALL"); + std::cout << "BADFIT " << _evt_counter << "\t" << _ch << "\t" << sampmax << "\t" << f_ampl << "\t" << f_time + << "\t" << chi2ndf << std::endl; gSubPulse->Draw("ap"); - gSubPulse->Fit(template_fcn, "R"); - std::cout << "ampl time before refit " << f_ampl << "\t" << f_time << std::endl; - f_ampl = template_fcn->GetParameter(0); - f_time = template_fcn->GetParameter(1); - std::cout << "ampl time after refit " << f_ampl << "\t" << f_time << std::endl; + template_fcn->Draw("same"); PadUpdate(); - std::string junk; - std::cin >> junk; } + + twotemplate_fcn->SetParameters(ymax,x_at_max,ymax,10); + twotemplate_fcn->SetRange(0,_nsamples-0.9); + + if (_verbose == 0) + { + gSubPulse->Fit(twotemplate_fcn, "RNQ"); + } + else + { + std::cout << "doing 2wave fit " << x_at_max << "\t" << ymax << std::endl; + gSubPulse->Fit(twotemplate_fcn, "R"); + gSubPulse->Draw("ap"); + gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); + gPad->SetGridy(1); + PadUpdate(); + //gSubPulse->Print("ALL"); + } + + // Check two component fit + Double_t ampl1 = twotemplate_fcn->GetParameter(0); + Double_t time1 = twotemplate_fcn->GetParameter(1); + Double_t ampl2 = twotemplate_fcn->GetParameter(2); + Double_t time2 = twotemplate_fcn->GetParameter(3); + Double_t newchi2 = twotemplate_fcn->GetChisquare(); + Double_t newndf = twotemplate_fcn->GetNDF(); + Double_t newchi2ndf = 0.; + if ( newndf>0.) + { + newchi2ndf = newchi2/newndf; + } + + // bad two component fit, use original fit + if ( time2>15. || ampl1<0 || ampl2<0. || newchi2ndf>chi2ndf) + { + if (_verbose) + { + std::cout << "Using original " << newchi2ndf << std::endl; + PrintResiduals(gSubPulse,twotemplate_fcn); + } + f_fitmode = 3; + h_chi2ndf->Fill( chi2ndf ); + _verbose = 0; + return 1; + } + + // Get new fit parameters (pick fit closest in time to first fit + if ( std::abs(f_time-time1) < std::abs(f_time-time2) ) + { + f_ampl = ampl1; + f_time = time1; + } + else + { + f_ampl = ampl2; + f_time = time2; + } + + f_chi2 = newchi2; + f_ndf = newndf; + + // poor fit + if ( _verbose && f_ndf>6. && (f_chi2/f_ndf) > 5. ) + { + std::cout << "double fit high chi2/ndf " << f_chi2/f_ndf << std::endl; + PrintResiduals(gSubPulse,twotemplate_fcn); + PadUpdate(); + } + + h_chi2ndf->Fill( f_chi2/f_ndf ); + _verbose = 0; + return 1; + } + + // Try a refit of saturated waveform with different range + template_fcn->SetParameters(ymax, x_at_max); + template_fcn->SetRange( 0., _nsamples-0.5 ); + + if (_verbose == 0) + { + //std::cout << PHWHERE << std::endl; + gSubPulse->Fit(template_fcn, "RNQ"); } else { @@ -1267,24 +1525,34 @@ int MbdSig::FitTemplate( const Int_t sampmax ) std::cout << "ampl time after refit " << f_ampl << "\t" << f_time << std::endl; } - f_ampl = template_fcn->GetParameter(0); - f_time = template_fcn->GetParameter(1); + // pick lower chi2/ndf of two saturated fits + Double_t newchi2 = template_fcn->GetChisquare(); + Double_t newndf = template_fcn->GetNDF(); + if ( (newchi2/newndf)GetParameter(0); + f_time = template_fcn->GetParameter(1); + f_chi2 = newchi2; + f_ndf = newndf; + f_fitmode = 5; + } + + h_chi2ndf->Fill( f_chi2/f_ndf ); - //if ( f_time<0 || f_time>30 ) - //if ( (_ch==185||_ch==155||_ch==249) && (fabs(f_ampl) > 44000.) ) - //double chi2 = template_fcn->GetChisquare(); - //double ndf = template_fcn->GetNDF(); - //if ( (_ch==185||_ch==155||_ch==249) && (fabs(chi2/ndf) > 100.) && nsaturated > 3) - if (_verbose > 0 && fabs(f_ampl) > 0.) + if (_verbose > 0 && std::abs(f_ampl) > 0.) { _verbose = 12; std::cout << "FitTemplate " << _ch << "\t" << f_ampl << "\t" << f_time << std::endl; std::cout << " " << template_fcn->GetChisquare()/template_fcn->GetNDF() << std::endl; gSubPulse->Draw("ap"); gSubPulse->GetHistogram()->SetTitle(gSubPulse->GetName()); + gPad->SetGridx(1); gPad->SetGridy(1); template_fcn->SetLineColor(4); template_fcn->Draw("same"); + + PrintResiduals(gSubPulse,template_fcn); + PadUpdate(); } @@ -1323,6 +1591,16 @@ int MbdSig::SetTemplate(const std::vector& shape, const std::vectorSetParName(1, "time"); SetTemplateSize(900, 1000, -10., 20.); + name = "twotemplate_fcn"; + name += _ch; + twotemplate_fcn = new TF1(name, this, &MbdSig::TwoTemplateFcn, 0, _nsamples, 4, "MbdSig", "TwoTemplateFcn"); + twotemplate_fcn->SetLineColor(3); + twotemplate_fcn->SetParameters(1, 6, 1,8); + twotemplate_fcn->SetParName(0, "ampl"); + twotemplate_fcn->SetParName(1, "time"); + twotemplate_fcn->SetParName(2, "ampl2"); + twotemplate_fcn->SetParName(3, "time2"); + if (_verbose) { std::cout << "SHAPE " << _ch << std::endl; @@ -1334,3 +1612,22 @@ int MbdSig::SetTemplate(const std::vector& shape, const std::vectorGetRange(smin,smax); + + double x{0}; + double y{0}; + for (double samp=0; samp<=smax; samp+=1.0) + { + g->GetPoint(int(samp),x,y); + double yerr = g->GetErrorY(int(samp)); + double resid = (y - f->Eval(x))/yerr; + std::cout << samp << "\t" << x << "\t" << resid << "\t" << y << "\t" << f->Eval(x) << "\t" << yerr << std::endl; + } +} + diff --git a/offline/packages/mbd/MbdSig.h b/offline/packages/mbd/MbdSig.h index 0b8b420ffa..a00607ba03 100644 --- a/offline/packages/mbd/MbdSig.h +++ b/offline/packages/mbd/MbdSig.h @@ -3,13 +3,16 @@ #include "MbdRunningStats.h" -#include +#include #include +#include #include class TTree; +class TF1; class TGraphErrors; +class TH1; class TH2; class MbdCalib; @@ -31,6 +34,9 @@ class MbdSig void SetNSamples( const int s ) { _nsamples = s; } void SetY(const Float_t *y, const int invert = 1); void SetXY(const Float_t *x, const Float_t *y, const int invert = 1); + void SetEvtNum(const int evtnum) { _evt_counter = evtnum; } + + int GetNSamples() { return _nsamples; } void SetCalib(MbdCalib *mcal); @@ -39,6 +45,10 @@ class MbdSig Double_t GetAmpl() { return f_ampl; } Double_t GetTime() { return f_time; } Double_t GetIntegral() { return f_integral; } + Double_t GetChi2() { return f_chi2; } + Double_t GetNDF() { return f_ndf; } + Double_t GetChi2NDF() { return (f_ndf > 0.) ? (f_chi2 / f_ndf) : std::numeric_limits::quiet_NaN(); } + UShort_t GetFitInfo() { return f_fitmode; } /** * Fill hists from data between minsamp and maxsamp bins @@ -108,11 +118,17 @@ class MbdSig // Double_t FitPulse(); void SetTimeOffset(const Double_t o) { f_time_offset = o; } + Double_t SignalTail(const Double_t *x, const Double_t *par); Double_t TemplateFcn(const Double_t *x, const Double_t *par); + Double_t TwoTemplateFcn(const Double_t *x, const Double_t *par); TF1 *GetTemplateFcn() { return template_fcn; } void SetMinMaxFitTime(const Double_t mintime, const Double_t maxtime); + void PrintResiduals(TGraphErrors *g, TF1 *f); + void WritePedHist(); + void WritePedvsEvent(); + void WriteChi2Hist(); void DrawWaveform(); /// Draw Subtracted Waveform void PadUpdate() const; @@ -142,6 +158,10 @@ class MbdSig Double_t f_integral{0.}; /** integral */ + UShort_t f_fitmode{0}; + Double_t f_chi2{0.}; + Double_t f_ndf{0.}; + TH1 *hRawPulse{nullptr}; //! TH1 *hSubPulse{nullptr}; //! TH1 *hpulse{nullptr}; //! @@ -150,22 +170,21 @@ class MbdSig TGraphErrors *gpulse{nullptr}; //! /** for CalcPed0 */ - //std::unique_ptr ped0stats{nullptr}; //! - MbdRunningStats *ped0stats{nullptr}; //! - TH1 *hPed0{nullptr}; //! all events - TH1 *hPedEvt{nullptr}; //! evt-by-event pedestal + MbdRunningStats *ped0stats{nullptr}; //! running pedestal + TH1 *hPed0{nullptr}; //! all events + TH1 *hPedEvt{nullptr}; //! evt-by-event pedestal + TGraphErrors *gPedvsEvent{nullptr}; //! Keep track of pedestal vs evtnum TF1 *ped_fcn{nullptr}; - TF1 *ped_tail{nullptr}; //! tail of prev signal Double_t ped0{0.}; //! Double_t ped0rms{0.}; //! - int use_ped0{0}; //! whether to apply ped0 - Int_t minped0samp{-9999}; //! min sample for event-by-event ped, inclusive - Int_t maxped0samp{-9999}; //! max sample for event-by-event ped, inclusive + int use_ped0{0}; //! whether to apply ped0 + Int_t minped0samp{-9999}; //! min sample for event-by-event ped, inclusive + Int_t maxped0samp{-9999}; //! max sample for event-by-event ped, inclusive Double_t minped0x{0.}; //! min x for event-by-event ped, inclusive Double_t maxped0x{0.}; //! max x for event-by-event ped, inclusive - Double_t ped_presamp{}; //! presamples for ped calculation - Double_t ped_presamp_nsamps{}; //! num of presamples for ped calculation - Double_t ped_presamp_maxsamp{-1}; //! a peak sample for ped calc (-1 = use max) + Double_t ped_presamp{}; //! presamples for ped calculation + Double_t ped_presamp_nsamps{}; //! num of presamples for ped calculation + Double_t ped_presamp_maxsamp{-1}; //! a peak sample for ped calc (-1 = use max) /** for time calibration */ // Double_t time_calib; @@ -180,21 +199,20 @@ class MbdSig Int_t template_npointsy{0}; Double_t template_begintime{0.}; Double_t template_endtime{0.}; - // Double_t template_min_good_amplitude{20.}; //! for template, in original units of waveform data - // Double_t template_max_good_amplitude{4080.}; //! for template, in original units of waveform data - // Double_t template_min_xrange{0.}; //! for template, in original units of waveform data - // Double_t template_max_xrange{0.}; //! for template, in original units of waveform data std::vector template_y; std::vector template_yrms; TF1 *template_fcn{nullptr}; + TF1 *twotemplate_fcn{nullptr}; Double_t fit_min_time{}; //! min time for fit, in original units of waveform data Double_t fit_max_time{}; //! max time for fit, in original units of waveform data std::ofstream *_pileupfile{nullptr}; // for writing out waveforms from prev. crossing pileup // use for calibrating out the tail from these events + TH1 *h_chi2ndf{nullptr}; //! for eval int _verbose{0}; + bool _pedstudyflag{false}; }; #endif // __MBDSIG_H__ diff --git a/offline/packages/micromegas/CylinderGeomMicromegas.cc b/offline/packages/micromegas/CylinderGeomMicromegas.cc index 5681eed3bd..ccf7395d06 100644 --- a/offline/packages/micromegas/CylinderGeomMicromegas.cc +++ b/offline/packages/micromegas/CylinderGeomMicromegas.cc @@ -50,7 +50,7 @@ TVector3 CylinderGeomMicromegas::get_local_from_world_coords( uint tileid, ActsG // convert to local /* this is equivalent to calling surface->globalToLocal but without the "on surface" check, and while returning a full Acts::Vector3 */ - const auto local = surface->transform(geometry->geometry().getGeoContext()).inverse()*global; + const auto local = surface->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse()*global; return TVector3( local.x()/Acts::UnitConstants::cm, local.y()/Acts::UnitConstants::cm, @@ -109,7 +109,7 @@ TVector3 CylinderGeomMicromegas::get_world_from_local_coords( uint tileid, ActsG // convert to global /* this is equivalent to calling surface->localToGlobal but without assuming that the local point is on surface */ - const auto global = surface->transform(geometry->geometry().getGeoContext())*local; + const auto global = surface->localToGlobalTransform(geometry->geometry().getGeoContext())*local; return TVector3( global.x()/Acts::UnitConstants::cm, global.y()/Acts::UnitConstants::cm, diff --git a/offline/packages/micromegas/MicromegasClusterizer.cc b/offline/packages/micromegas/MicromegasClusterizer.cc index c57d6ed3f5..5da9264c11 100644 --- a/offline/packages/micromegas/MicromegasClusterizer.cc +++ b/offline/packages/micromegas/MicromegasClusterizer.cc @@ -157,8 +157,13 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) // geometry PHG4CylinderGeomContainer* geonode = nullptr; for( std::string geonodename: {"CYLINDERGEOM_MICROMEGAS_FULL", "CYLINDERGEOM_MICROMEGAS" } ) - { if(( geonode = findNode::getClass(topNode, geonodename.c_str()) )) { break; -}} + { + // try load node and test + geonode = findNode::getClass(topNode, geonodename); + if( geonode ) { break;} + } + + //ma assert(geonode); // hitset container @@ -182,8 +187,8 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) for( auto hitset_it = hitset_range.first; hitset_it != hitset_range.second; ++hitset_it ) { // get hitset, key and layer - TrkrHitSet* hitset = hitset_it->second; - const TrkrDefs::hitsetkey hitsetkey = hitset_it->first; + const auto& [hitsetkey, hitset] = *hitset_it; + const auto layer = TrkrDefs::getLayer(hitsetkey); const auto tileid = MicromegasDefs::getTileId(hitsetkey); @@ -215,17 +220,32 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) using range_list_t = std::vector; range_list_t ranges; - // loop over hits - const auto hit_range = hitset->getHits(); + // Make a local copy of hitsets, sorted along strips + /* when there are multiple hits on the same strip, only the first one (in time) is kept */ + class StripSortFtor + { + public: + bool operator() ( const TrkrDefs::hitkey& first, const TrkrDefs::hitkey& second ) const + { return MicromegasDefs::getStrip(first) < MicromegasDefs::getStrip(second); } + }; + + using LocalMap = std::map; + LocalMap local_hitmap; + + { + // loop over hits + const auto hit_range = hitset->getHits(); + std::copy( hit_range.first, hit_range.second, std::inserter(local_hitmap, local_hitmap.end()) ); + } // keep track of first iterator of runing cluster - auto begin = hit_range.first; + auto begin = local_hitmap.begin(); // keep track of previous strip uint16_t previous_strip = 0; bool first = true; - for( auto hit_it = hit_range.first; hit_it != hit_range.second; ++hit_it ) + for( auto hit_it = local_hitmap.begin(); hit_it != local_hitmap.end(); ++hit_it ) { // get hit key @@ -233,18 +253,11 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) // get strip number const auto strip = MicromegasDefs::getStrip( hitkey ); - - if( first ) + if( !first && (strip - previous_strip > 1 ) ) { - previous_strip = strip; - first = false; - continue; - - } else if( strip - previous_strip > 1 ) { - // store current cluster range - ranges.push_back( std::make_pair( begin, hit_it ) ); + ranges.emplace_back( begin, hit_it ); // reinitialize begin of next cluster range begin = hit_it; @@ -252,13 +265,13 @@ int MicromegasClusterizer::process_event(PHCompositeNode *topNode) } // update previous strip + first = false; previous_strip = strip; } // store last cluster - if( begin != hit_range.second ) { ranges.push_back( std::make_pair( begin, hit_range.second ) ); -} + if( begin != local_hitmap.end() ) { ranges.emplace_back( begin, local_hitmap.end() ); } // initialize cluster count int cluster_count = 0; diff --git a/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc b/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc index a5269617f7..1c34357280 100644 --- a/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc +++ b/offline/packages/micromegas/MicromegasCombinedDataDecoder.cc @@ -203,13 +203,14 @@ int MicromegasCombinedDataDecoder::process_event(PHCompositeNode* topNode) // loop over sample_range find maximum const auto sample_range = std::make_pair(rawhit->get_sample_begin(), rawhit->get_sample_end()); - std::vector adc_list; + using sample_pair_t = std::pair; + std::vector adc_list; for (auto is = std::max(m_sample_min, sample_range.first); is < std::min(m_sample_max, sample_range.second); ++is) { const uint16_t adc = rawhit->get_adc(is); if (adc != MicromegasDefs::m_adc_invalid) { - adc_list.push_back(adc); + adc_list.emplace_back(is, adc); } } @@ -220,16 +221,18 @@ int MicromegasCombinedDataDecoder::process_event(PHCompositeNode* topNode) // get max adc value in range /* TODO: use more advanced signal processing */ - auto max_adc = *std::max_element(adc_list.begin(), adc_list.end()); + auto max_adc = *std::max_element(adc_list.begin(), adc_list.end(), + [](const sample_pair_t& first, const sample_pair_t& second) + { return first.second < second.second; } ); // compare to hard min_adc value - if (max_adc < m_min_adc) + if (max_adc.second < m_min_adc) { continue; } // compare to threshold - if (max_adc < pedestal + m_n_sigma * rms) + if (max_adc.second < pedestal + m_n_sigma * rms) { continue; } @@ -243,7 +246,8 @@ int MicromegasCombinedDataDecoder::process_event(PHCompositeNode* topNode) << " tile: " << tile << " channel: " << channel << " strip: " << strip - << " adc: " << max_adc + << " sample: " << max_adc.first + << " adc: " << max_adc.second << std::endl; } @@ -251,19 +255,19 @@ int MicromegasCombinedDataDecoder::process_event(PHCompositeNode* topNode) const auto hitset_it = trkrhitsetcontainer->findOrAddHitSet(hitsetkey); // generate hit key - const TrkrDefs::hitkey hitkey = MicromegasDefs::genHitKey(strip); + const TrkrDefs::hitkey hitkey = MicromegasDefs::genHitKey(strip, max_adc.first); // find existing hit, or create - auto hit = hitset_it->second->getHit(hitkey); + auto* hit = hitset_it->second->getHit(hitkey); if (hit) { - // std::cout << "MicromegasCombinedDataDecoder::process_event - duplicated hit, hitsetkey: " << hitsetkey << " strip: " << strip << std::endl; + std::cout << "MicromegasCombinedDataDecoder::process_event - duplicated hit, hitsetkey: " << hitsetkey << " strip: " << strip << std::endl; continue; } // create hit, assign adc and insert in hitset hit = new TrkrHitv2; - hit->setAdc(max_adc); + hit->setAdc(max_adc.second); hitset_it->second->addHitSpecificKey(hitkey, hit); // increment counter diff --git a/offline/packages/micromegas/MicromegasCombinedDataDecoder.h b/offline/packages/micromegas/MicromegasCombinedDataDecoder.h index 32eebc56e0..33033f1992 100644 --- a/offline/packages/micromegas/MicromegasCombinedDataDecoder.h +++ b/offline/packages/micromegas/MicromegasCombinedDataDecoder.h @@ -49,10 +49,10 @@ class MicromegasCombinedDataDecoder : public SubsysReco /** This removes faulty channels for which calibration has failed */ void set_min_adc(double value) { m_min_adc = value; } - /// set min sample for noise estimation + /// set min sample for signal hits void set_sample_min(uint16_t value) { m_sample_min = value; } - /// set min sample for noise estimation + /// set max sample for signal hits void set_sample_max(uint16_t value) { m_sample_max = value; } private: @@ -85,7 +85,7 @@ class MicromegasCombinedDataDecoder : public SubsysReco uint16_t m_sample_min = 0; /// max sample for signal - uint16_t m_sample_max = 100; + uint16_t m_sample_max = 1024; /// keep track of number of hits per hitsetid using hitcountmap_t = std::map; diff --git a/offline/packages/micromegas/MicromegasDefs.cc b/offline/packages/micromegas/MicromegasDefs.cc index 0766d78b8e..8a35461492 100644 --- a/offline/packages/micromegas/MicromegasDefs.cc +++ b/offline/packages/micromegas/MicromegasDefs.cc @@ -25,11 +25,12 @@ namespace * 8 - 16 segmentation type * 0 - 8 tile id */ - static constexpr unsigned int kBitShiftSegmentation = 8; - static constexpr unsigned int kBitShiftTileId = 0; + constexpr unsigned int kBitShiftSegmentation = 8; + constexpr unsigned int kBitShiftTileId = 0; //! bit shift for hit key - static constexpr unsigned int kBitShiftStrip = 0; + constexpr unsigned int kBitShiftStrip = 0; + constexpr unsigned int kBitShiftSample = 8; } @@ -41,10 +42,10 @@ namespace MicromegasDefs { TrkrDefs::hitsetkey key = TrkrDefs::genHitSetKey(TrkrDefs::TrkrId::micromegasId, layer); - TrkrDefs::hitsetkey tmp = to_underlying_type(type); + TrkrDefs::hitsetkey tmp = to_underlying_type(type)&0x1U; key |= (tmp << kBitShiftSegmentation); - tmp = tile; + tmp = tile&0xFFU; key |= (tmp << kBitShiftTileId); return key; @@ -54,28 +55,36 @@ namespace MicromegasDefs SegmentationType getSegmentationType(TrkrDefs::hitsetkey key) { TrkrDefs::hitsetkey tmp = (key >> kBitShiftSegmentation); - return static_cast(tmp); + return static_cast(tmp&0x1U); } //________________________________________________________________ uint8_t getTileId(TrkrDefs::hitsetkey key) { TrkrDefs::hitsetkey tmp = (key >> kBitShiftTileId); - return tmp; + return tmp&0xFFU; } //________________________________________________________________ - TrkrDefs::hitkey genHitKey(uint16_t strip) + TrkrDefs::hitkey genHitKey(uint16_t strip, uint16_t sample) { - TrkrDefs::hitkey key = strip << kBitShiftStrip; - return key; + const TrkrDefs::hitkey key = (strip&0xFFU) << kBitShiftStrip; + const TrkrDefs::hitkey tmp = (sample&0xFFFFU) << kBitShiftSample; + return key|tmp; } //________________________________________________________________ - uint16_t getStrip( TrkrDefs::hitkey key ) + uint8_t getStrip( TrkrDefs::hitkey key ) { TrkrDefs::hitkey tmp = (key >> kBitShiftStrip); - return tmp; + return tmp & 0xFFU; + } + + //________________________________________________________________ + uint16_t getSample( TrkrDefs::hitkey key ) + { + TrkrDefs::hitkey tmp = (key >> kBitShiftSample); + return tmp & 0xFFFFU; } //________________________________________________________________ diff --git a/offline/packages/micromegas/MicromegasDefs.h b/offline/packages/micromegas/MicromegasDefs.h index c95fdffd72..b206b8f895 100644 --- a/offline/packages/micromegas/MicromegasDefs.h +++ b/offline/packages/micromegas/MicromegasDefs.h @@ -60,11 +60,15 @@ namespace MicromegasDefs /*! * @brief Generate a hitkey from strip index inside tile * @param[in] strip strip index + * @param[in] sample sample index */ - TrkrDefs::hitkey genHitKey(uint16_t strip ); + TrkrDefs::hitkey genHitKey(uint16_t strip, uint16_t sample = 0 ); //! get strip from hit key - uint16_t getStrip(TrkrDefs::hitkey); + uint8_t getStrip(TrkrDefs::hitkey); + + //! get sample from hit key + uint16_t getSample(TrkrDefs::hitkey); /*! * @brief Get the segmentation type from cluster key diff --git a/offline/packages/mvtx/CylinderGeom_Mvtx.cc b/offline/packages/mvtx/CylinderGeom_Mvtx.cc index e220d1474d..ab22c80bdc 100644 --- a/offline/packages/mvtx/CylinderGeom_Mvtx.cc +++ b/offline/packages/mvtx/CylinderGeom_Mvtx.cc @@ -8,7 +8,6 @@ #include #include // for operator<<, basic_ostream::operator<<, basic_... -using namespace std; using Segmentation = SegmentationAlpide; CylinderGeom_Mvtx::CylinderGeom_Mvtx( @@ -89,7 +88,7 @@ void CylinderGeom_Mvtx::get_sensor_indices_from_world_coords(std::vector double chip_delta_z = (inner_loc_chip_in_module[8][2] - inner_loc_chip_in_module[0][2]) / 8.0; // int chip_tmp = (int) (world[2]/chip_delta_z) + 4; // 0-9 int chip_tmp = round(world[2] / chip_delta_z) + 4; // 0-9 - // std::cout << " z " << world[2] << " chip_delta_z " << chip_delta_z << " chip_tmp " << chip_tmp << endl; + // std::cout << " z " << world[2] << " chip_delta_z " << chip_delta_z << " chip_tmp " << chip_tmp << std::endl; stave_index = stave_tmp; chip_index = chip_tmp; @@ -102,15 +101,15 @@ bool CylinderGeom_Mvtx::get_pixel_from_local_coords(TVector3 sensor_local, int& double EPS = 5e-6; if (fabs(fabs(sensor_local.X()) - SegmentationAlpide::ActiveMatrixSizeRows / 2.F) < EPS) { - // cout << " Adjusting X, before X= " << sensor_local.X() << endl; + // std::cout << " Adjusting X, before X= " << sensor_local.X() << std::endl; sensor_local.SetX(((sensor_local.X() < 0) ? -1 : 1) * (SegmentationAlpide::ActiveMatrixSizeRows / 2.F - EPS)); - // cout << " Adjusting X, after X= " << sensor_local.X() << endl; + // std::cout << " Adjusting X, after X= " << sensor_local.X() << std::endl; } if (fabs(fabs(sensor_local.Z()) - SegmentationAlpide::ActiveMatrixSizeCols / 2.F) < EPS) { - // cout << " Adjusting Z, before Z= " << sensor_local.Z() << endl; + // std::cout << " Adjusting Z, before Z= " << sensor_local.Z() << std::endl; sensor_local.SetZ(((sensor_local.Z() < 0) ? -1 : 1) * (SegmentationAlpide::ActiveMatrixSizeCols / 2.F - EPS)); - // cout << " Adjusting Z, after Z= " << sensor_local.Z() << endl; + // std::cout << " Adjusting Z, after Z= " << sensor_local.Z() << std::endl; } // YCM (2020-01-02): go from sensor to chip local coords TVector3 in_chip = sensor_local; @@ -122,21 +121,22 @@ bool CylinderGeom_Mvtx::get_pixel_from_local_coords(TVector3 sensor_local, int& int CylinderGeom_Mvtx::get_pixel_from_local_coords(const TVector3& sensor_local) { - int Ngridx, Ngridz; + int Ngridx; + int Ngridz; bool px_in = get_pixel_from_local_coords(sensor_local, Ngridx, Ngridz); if (!px_in) { - cout << PHWHERE + std::cout << PHWHERE << " Pixel is out sensor. (" << sensor_local.X() << ", " << sensor_local.Y() << ", " << sensor_local.Z() << ")." - << endl; + << std::endl; } if (Ngridx < 0 || Ngridx >= get_NX() || Ngridz < 0 || Ngridz >= get_NZ()) { - cout << PHWHERE << "Wrong pixel value X= " << Ngridx << " and Z= " << Ngridz << endl; + std::cout << PHWHERE << "Wrong pixel value X= " << Ngridx << " and Z= " << Ngridz << std::endl; } // numbering starts at zero @@ -157,8 +157,8 @@ TVector3 CylinderGeom_Mvtx::get_local_coords_from_pixel(int iRow, int iCol) bool check = SegmentationAlpide::detectorToLocal((float) iRow, (float) iCol, local); if (!check) { - cout << PHWHERE << "Pixel coord ( " << iRow << ", " << iCol << " )" - << "out of range" << endl; + std::cout << PHWHERE << "Pixel coord ( " << iRow << ", " << iCol << " )" + << "out of range" << std::endl; } // Transform location in chip to location in sensors TVector3 trChipToSens(loc_sensor_in_chip[0], @@ -177,7 +177,7 @@ void CylinderGeom_Mvtx::identify(std::ostream& os) const << ", pixel_x: " << pixel_x << ", pixel_z: " << pixel_z << ", pixel_thickness: " << pixel_thickness - << endl; + << std::endl; return; } @@ -192,17 +192,17 @@ int CylinderGeom_Mvtx::get_NX() const return SegmentationAlpide::NRows; } -int CylinderGeom_Mvtx::get_pixel_X_from_pixel_number(int NXZ) +int CylinderGeom_Mvtx::get_pixel_X_from_pixel_number(int NXZ) const { return NXZ % get_NX(); } -int CylinderGeom_Mvtx::get_pixel_Z_from_pixel_number(int NXZ) +int CylinderGeom_Mvtx::get_pixel_Z_from_pixel_number(int NXZ) const { return NXZ / get_NX(); } -int CylinderGeom_Mvtx::get_pixel_number_from_xbin_zbin(int xbin, int zbin) // obsolete +int CylinderGeom_Mvtx::get_pixel_number_from_xbin_zbin(int xbin, int zbin) const // obsolete { return xbin + zbin * get_NX(); } diff --git a/offline/packages/mvtx/CylinderGeom_Mvtx.h b/offline/packages/mvtx/CylinderGeom_Mvtx.h index e28da2c594..047673a549 100644 --- a/offline/packages/mvtx/CylinderGeom_Mvtx.h +++ b/offline/packages/mvtx/CylinderGeom_Mvtx.h @@ -13,7 +13,7 @@ class CylinderGeom_Mvtx : public PHG4CylinderGeom public: CylinderGeom_Mvtx( int layer, - int in_Nstaves, + int in_N_staves, double in_layer_nominal_radius, double in_phistep, double in_phitilt, @@ -31,7 +31,7 @@ class CylinderGeom_Mvtx : public PHG4CylinderGeom { } - ~CylinderGeom_Mvtx() override {} + ~CylinderGeom_Mvtx() override = default; // from PHObject void identify(std::ostream& os = std::cout) const override; @@ -53,11 +53,11 @@ class CylinderGeom_Mvtx : public PHG4CylinderGeom TVector3 get_local_coords_from_pixel(int NXZ); TVector3 get_local_coords_from_pixel(int iRow, int iCol); - int get_pixel_X_from_pixel_number(int NXZ); + int get_pixel_X_from_pixel_number(int NXZ) const; - int get_pixel_Z_from_pixel_number(int NXZ); + int get_pixel_Z_from_pixel_number(int NXZ) const; - int get_pixel_number_from_xbin_zbin(int xbin, int zbin); // obsolete + int get_pixel_number_from_xbin_zbin(int xbin, int zbin) const; // obsolete double get_stave_phi_tilt() const { return stave_phi_tilt; } double get_stave_phi_0() const { return stave_phi_0; } diff --git a/offline/packages/mvtx/CylinderGeom_MvtxHelper.cc b/offline/packages/mvtx/CylinderGeom_MvtxHelper.cc index 41db23e434..e077d80964 100644 --- a/offline/packages/mvtx/CylinderGeom_MvtxHelper.cc +++ b/offline/packages/mvtx/CylinderGeom_MvtxHelper.cc @@ -23,7 +23,7 @@ CylinderGeom_MvtxHelper::get_local_from_world_coords ( global *= Acts::UnitConstants::cm; - Acts::Vector3 local = surface->transform(tGeometry->geometry().getGeoContext()).inverse() * global; + Acts::Vector3 local = surface->localToGlobalTransform(tGeometry->geometry().getGeoContext()).inverse() * global; local /= Acts::UnitConstants::cm; /// The Acts transform swaps a few of the coordinates @@ -67,7 +67,7 @@ CylinderGeom_MvtxHelper::get_world_from_local_coords ( Acts::Vector3 loc(local.x(), local.y(), local.z()); loc *= Acts::UnitConstants::cm; - Acts::Vector3 glob = surface->transform(tGeometry->geometry().getGeoContext()) * loc; + Acts::Vector3 glob = surface->localToGlobalTransform(tGeometry->geometry().getGeoContext()) * loc; glob /= Acts::UnitConstants::cm; return TVector3(glob(0), glob(1), glob(2)); diff --git a/offline/packages/mvtx/MvtxClusterPruner.cc b/offline/packages/mvtx/MvtxClusterPruner.cc index 24d41db63d..456b302dd9 100644 --- a/offline/packages/mvtx/MvtxClusterPruner.cc +++ b/offline/packages/mvtx/MvtxClusterPruner.cc @@ -12,108 +12,116 @@ #include #include -#include #include +#include -#include #include +#include namespace { //! range adaptor to be able to use range-based for loop - template class range_adaptor + template + class range_adaptor { - public: - range_adaptor( const T& range ):m_range(range){} - const typename T::first_type& begin() {return m_range.first;} - const typename T::second_type& end() {return m_range.second;} - private: + public: + explicit range_adaptor(const T& range) + : m_range(range) + { + } + const typename T::first_type& begin() { return m_range.first; } + const typename T::second_type& end() { return m_range.second; } + + private: T m_range; }; // print cluster information - void print_cluster_information( TrkrDefs::cluskey ckey, TrkrCluster* cluster ) + void print_cluster_information(TrkrDefs::cluskey ckey, TrkrCluster* cluster) { - if( cluster ) + if (cluster) { std::cout << " MVTX cluster: " << ckey - << " position: (" << cluster->getLocalX() << ", " << cluster->getLocalY() << ")" - << " size: " << (int)cluster->getSize() - << " layer: " << (int)TrkrDefs::getLayer(ckey) - << " stave: " << (int) MvtxDefs::getStaveId(ckey) - << " chip: " << (int)MvtxDefs::getChipId(ckey) - << " strobe: " << (int)MvtxDefs::getStrobeId(ckey) - << " index: " << (int)TrkrDefs::getClusIndex(ckey) - << std::endl; - } else { + << " position: (" << cluster->getLocalX() << ", " << cluster->getLocalY() << ")" + << " size: " << (int) cluster->getSize() + << " layer: " << (int) TrkrDefs::getLayer(ckey) + << " stave: " << (int) MvtxDefs::getStaveId(ckey) + << " chip: " << (int) MvtxDefs::getChipId(ckey) + << " strobe: " << MvtxDefs::getStrobeId(ckey) + << " index: " << (int) TrkrDefs::getClusIndex(ckey) + << std::endl; + } + else + { std::cout << " MVTX cluster: " << ckey - << " layer: " << (int)TrkrDefs::getLayer(ckey) - << " stave: " << (int) MvtxDefs::getStaveId(ckey) - << " chip: " << (int)MvtxDefs::getChipId(ckey) - << " strobe: " << (int)MvtxDefs::getStrobeId(ckey) - << " index: " << (int)TrkrDefs::getClusIndex(ckey) - << std::endl; + << " layer: " << (int) TrkrDefs::getLayer(ckey) + << " stave: " << (int) MvtxDefs::getStaveId(ckey) + << " chip: " << (int) MvtxDefs::getChipId(ckey) + << " strobe: " << MvtxDefs::getStrobeId(ckey) + << " index: " << (int) TrkrDefs::getClusIndex(ckey) + << std::endl; } } using hitkeyset_t = std::set; - using clustermap_t = std::map; + using clustermap_t = std::map; -} +} // namespace //_____________________________________________________________________________ -MvtxClusterPruner::MvtxClusterPruner(const std::string &name) +MvtxClusterPruner::MvtxClusterPruner(const std::string& name) : SubsysReco(name) { } //_____________________________________________________________________________ -int MvtxClusterPruner::InitRun(PHCompositeNode * /*topNode*/) +int MvtxClusterPruner::InitRun(PHCompositeNode* /*topNode*/) { std::cout << "MvtxClusterPruner::InitRun - m_use_strict_matching: " << m_use_strict_matching << std::endl; return Fun4AllReturnCodes::EVENT_OK; } //_____________________________________________________________________________ -int MvtxClusterPruner::process_event(PHCompositeNode *topNode) +int MvtxClusterPruner::process_event(PHCompositeNode* topNode) { // load relevant nodes - auto trkrclusters = findNode::getClass(topNode, "TRKR_CLUSTER"); - if( !trkrclusters ) + auto* trkrclusters = findNode::getClass(topNode, "TRKR_CLUSTER"); + if (!trkrclusters) { std::cout << "MvtxClusterPruner::process_event - TRKR_CLUSTER not found. Doing nothing" << std::endl; return Fun4AllReturnCodes::EVENT_OK; } - auto clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); - if( !clusterhitassoc ) + auto* clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); + if (!clusterhitassoc) { std::cout << "MvtxClusterPruner::process_event - TRKR_CLUSTERHITASSOC not found. Doing nothing" << std::endl; return Fun4AllReturnCodes::EVENT_OK; } // lambda method to create map of cluster keys and associated hits - auto get_cluster_map = [trkrclusters,clusterhitassoc]( TrkrDefs::hitsetkey key ) + auto get_cluster_map = [trkrclusters, clusterhitassoc](TrkrDefs::hitsetkey key) { clustermap_t out; // get all clusters for this hitsetkey - const auto cluster_range= trkrclusters->getClusters(key); - for( const auto& [ckey,cluster]:range_adaptor(cluster_range) ) + const auto cluster_range = trkrclusters->getClusters(key); + for (const auto& [ckey, cluster] : range_adaptor(cluster_range)) { // get associated hits const auto& hit_range = clusterhitassoc->getHits(ckey); hitkeyset_t hitkeys; - std::transform(hit_range.first, hit_range.second, std::inserter(hitkeys,hitkeys.end()), - [](const TrkrClusterHitAssoc::Map::value_type& pair ){ return pair.second; }); - out.emplace(ckey,std::move(hitkeys)); + std::transform(hit_range.first, hit_range.second, std::inserter(hitkeys, hitkeys.end()), + [](const TrkrClusterHitAssoc::Map::value_type& pair) + { return pair.second; }); + out.emplace(ckey, std::move(hitkeys)); } return out; }; // loop over MVTX hitset keys const auto hitsetkeys = trkrclusters->getHitSetKeys(TrkrDefs::mvtxId); - for( const auto& hitsetkey:hitsetkeys ) + for (const auto& hitsetkey : hitsetkeys) { // get layer, stave, chip and current strobe const auto layer = TrkrDefs::getLayer(hitsetkey); @@ -125,111 +133,109 @@ int MvtxClusterPruner::process_event(PHCompositeNode *topNode) const auto cluster_map1 = get_cluster_map(hitsetkey); // get clusters for the next strobe - int next_strobe = current_strobe+1; + int next_strobe = current_strobe + 1; const auto hitsetkey_next_strobe = MvtxDefs::genHitSetKey(layer, stave, chip, next_strobe); const auto clusterk_map2 = get_cluster_map(hitsetkey_next_strobe); // loop over clusters from first range - for( auto [ckey1,hitkeys1]:cluster_map1) + for (auto [ckey1, hitkeys1] : cluster_map1) { // increment counter ++m_cluster_counter_total; // get correcponding cluser - auto cluster1 = Verbosity() ? trkrclusters->findCluster(ckey1):nullptr; + auto* cluster1 = Verbosity() ? trkrclusters->findCluster(ckey1) : nullptr; // loop over clusters from second range - for( auto [ckey2,hitkeys2]:clusterk_map2) + for (auto [ckey2, hitkeys2] : clusterk_map2) { - auto cluster2 = Verbosity() ? trkrclusters->findCluster(ckey2):nullptr; + auto* cluster2 = Verbosity() ? trkrclusters->findCluster(ckey2) : nullptr; - if( m_use_strict_matching ) + if (m_use_strict_matching) { // see if hitsets are identical - if(hitkeys1 == hitkeys2) + if (hitkeys1 == hitkeys2) { // increment counter ++m_cluster_counter_deleted; - if( Verbosity() ) + if (Verbosity()) { std::cout << "Removing cluster "; - print_cluster_information( ckey2, cluster2); + print_cluster_information(ckey2, cluster2); std::cout << "Keeping cluster "; - print_cluster_information( ckey1, cluster1); + print_cluster_information(ckey1, cluster1); } // always remove second cluster trkrclusters->removeCluster(ckey2); break; } - - } else { - + } + else + { // make sure first set is larger than second const bool swapped = hitkeys2.size() > hitkeys1.size(); - if( swapped ) { std::swap(hitkeys2,hitkeys1); } + if (swapped) + { + std::swap(hitkeys2, hitkeys1); + } // see if hitkeys2 is a subset of hitkeys1 - if( std::includes(hitkeys1.begin(), hitkeys1.end(), hitkeys2.begin(), hitkeys2.end()) ) + if (std::includes(hitkeys1.begin(), hitkeys1.end(), hitkeys2.begin(), hitkeys2.end())) { // increment counter ++m_cluster_counter_deleted; - if( swapped ) + if (swapped) { - - if( Verbosity() ) + if (Verbosity()) { std::cout << "Removing cluster "; - print_cluster_information( ckey1, cluster1); + print_cluster_information(ckey1, cluster1); std::cout << "Keeping cluster "; - print_cluster_information( ckey2, cluster2); + print_cluster_information(ckey2, cluster2); } // remove first cluster trkrclusters->removeCluster(ckey1); break; - } else { - - if( Verbosity() ) - { - std::cout << "Removing cluster "; - print_cluster_information( ckey2, cluster2); - - std::cout << "Keeping cluster "; - print_cluster_information( ckey1, cluster1); - } + } + if (Verbosity()) + { + std::cout << "Removing cluster "; + print_cluster_information(ckey2, cluster2); - // remove second cluster - trkrclusters->removeCluster(ckey2); + std::cout << "Keeping cluster "; + print_cluster_information(ckey1, cluster1); } + + // remove second cluster + trkrclusters->removeCluster(ckey2); } - } // strict matching + } // strict matching - } // second cluster loop - } // first cluster loop - } // hitsetkey loop + } // second cluster loop + } // first cluster loop + } // hitsetkey loop return Fun4AllReturnCodes::EVENT_OK; - } //_____________________________________________________________________________ -int MvtxClusterPruner::End(PHCompositeNode * /*topNode*/) +int MvtxClusterPruner::End(PHCompositeNode* /*topNode*/) { - std::cout << "MvtxClusterPruner::End -" - << " m_cluster_counter_total: " << m_cluster_counter_total - << std::endl; - std::cout << "MvtxClusterPruner::End -" - << " m_cluster_counter_deleted: " << m_cluster_counter_deleted - << " fraction: " << double( m_cluster_counter_deleted )/m_cluster_counter_total - << std::endl; + << " m_cluster_counter_total: " << m_cluster_counter_total + << std::endl; + std::cout << "MvtxClusterPruner::End -" + << " m_cluster_counter_deleted: " << m_cluster_counter_deleted + << " fraction: " << double(m_cluster_counter_deleted) / m_cluster_counter_total + << std::endl; return Fun4AllReturnCodes::EVENT_OK; } diff --git a/offline/packages/mvtx/MvtxClusterizer.cc b/offline/packages/mvtx/MvtxClusterizer.cc index 7970b369eb..eb54930acd 100644 --- a/offline/packages/mvtx/MvtxClusterizer.cc +++ b/offline/packages/mvtx/MvtxClusterizer.cc @@ -63,7 +63,7 @@ namespace /// convenience square method template - inline constexpr T square(const T &x) + constexpr T square(const T &x) { return x * x; } @@ -71,65 +71,45 @@ namespace bool MvtxClusterizer::are_adjacent( const std::pair &lhs, - const std::pair &rhs) + const std::pair &rhs) const { if (GetZClustering()) { return - // column adjacent - ( (MvtxDefs::getCol(lhs.first) > MvtxDefs::getCol(rhs.first)) ? - MvtxDefs::getCol(lhs.first)<=MvtxDefs::getCol(rhs.first)+1: - MvtxDefs::getCol(rhs.first)<=MvtxDefs::getCol(lhs.first)+1) && + // column adjacent + ((MvtxDefs::getCol(lhs.first) > MvtxDefs::getCol(rhs.first)) ? MvtxDefs::getCol(lhs.first) <= MvtxDefs::getCol(rhs.first) + 1 : MvtxDefs::getCol(rhs.first) <= MvtxDefs::getCol(lhs.first) + 1) && - // row adjacent - ( (MvtxDefs::getRow(lhs.first) > MvtxDefs::getRow(rhs.first)) ? - MvtxDefs::getRow(lhs.first)<=MvtxDefs::getRow(rhs.first)+1: - MvtxDefs::getRow(rhs.first)<=MvtxDefs::getRow(lhs.first)+1); - - } else { - - return + // row adjacent + ((MvtxDefs::getRow(lhs.first) > MvtxDefs::getRow(rhs.first)) ? MvtxDefs::getRow(lhs.first) <= MvtxDefs::getRow(rhs.first) + 1 : MvtxDefs::getRow(rhs.first) <= MvtxDefs::getRow(lhs.first) + 1); + } + return // column identical - MvtxDefs::getCol(rhs.first)==MvtxDefs::getCol(lhs.first) && + MvtxDefs::getCol(rhs.first) == MvtxDefs::getCol(lhs.first) && // row adjacent - ( (MvtxDefs::getRow(lhs.first) > MvtxDefs::getRow(rhs.first)) ? - MvtxDefs::getRow(lhs.first)<=MvtxDefs::getRow(rhs.first)+1: - MvtxDefs::getRow(rhs.first)<=MvtxDefs::getRow(lhs.first)+1); - - } + ((MvtxDefs::getRow(lhs.first) > MvtxDefs::getRow(rhs.first)) ? MvtxDefs::getRow(lhs.first) <= MvtxDefs::getRow(rhs.first) + 1 : MvtxDefs::getRow(rhs.first) <= MvtxDefs::getRow(lhs.first) + 1); } -bool MvtxClusterizer::are_adjacent(RawHit *lhs, RawHit *rhs) +bool MvtxClusterizer::are_adjacent(RawHit *lhs, RawHit *rhs) const { if (GetZClustering()) { return - // phi adjacent (== column) - ((lhs->getPhiBin() > rhs->getPhiBin()) ? - lhs->getPhiBin() <= rhs->getPhiBin()+1: - rhs->getPhiBin() <= lhs->getPhiBin()+1) && + // phi adjacent (== column) + ((lhs->getPhiBin() > rhs->getPhiBin()) ? lhs->getPhiBin() <= rhs->getPhiBin() + 1 : rhs->getPhiBin() <= lhs->getPhiBin() + 1) && - // time adjacent (== row) - ((lhs->getTBin() > rhs->getTBin()) ? - lhs->getTBin() <= rhs->getTBin()+1: - rhs->getTBin() <= lhs->getTBin()+1); - - } else { - - return + // time adjacent (== row) + ((lhs->getTBin() > rhs->getTBin()) ? lhs->getTBin() <= rhs->getTBin() + 1 : rhs->getTBin() <= lhs->getTBin() + 1); + } + return // phi identical (== column) lhs->getPhiBin() == rhs->getPhiBin() && // time adjacent (== row) - ((lhs->getTBin() > rhs->getTBin()) ? - lhs->getTBin() <= rhs->getTBin()+1: - rhs->getTBin() <= lhs->getTBin()+1); - - } + ((lhs->getTBin() > rhs->getTBin()) ? lhs->getTBin() <= rhs->getTBin() + 1 : rhs->getTBin() <= lhs->getTBin() + 1); } MvtxClusterizer::MvtxClusterizer(const std::string &name) @@ -165,7 +145,7 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) } // Create the Cluster node if required - auto trkrclusters = + auto *trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); if (!trkrclusters) { @@ -183,7 +163,7 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(TrkrClusterContainerNode); } - auto clusterhitassoc = + auto *clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); if (!clusterhitassoc) { @@ -208,14 +188,14 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) if (!mClusHitsVerbose) { PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); if (!DetNode) { DetNode = new PHCompositeNode("TRKR"); dstNode->addNode(DetNode); } mClusHitsVerbose = new ClusHitsVerbosev1(); - auto newNode = new PHIODataNode(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject"); + auto *newNode = new PHIODataNode(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject"); DetNode->addNode(newNode); } } @@ -227,13 +207,13 @@ int MvtxClusterizer::InitRun(PHCompositeNode *topNode) if (Verbosity() > 0) { std::cout << "====================== MvtxClusterizer::InitRun() " - "=====================" - << std::endl; + "=====================" + << std::endl; std::cout << " Z-dimension Clustering = " << std::boolalpha << m_makeZClustering - << std::noboolalpha << std::endl; + << std::noboolalpha << std::endl; std::cout << "==================================================================" - "=========" - << std::endl; + "=========" + << std::endl; } return Fun4AllReturnCodes::EVENT_OK; @@ -283,7 +263,7 @@ int MvtxClusterizer::process_event(PHCompositeNode *topNode) // reset MVTX clusters and cluster associations const auto hitsetkeys = m_clusterlist->getHitSetKeys(TrkrDefs::mvtxId); - for( const auto& hitsetkey:hitsetkeys) + for (const auto &hitsetkey : hitsetkeys) { m_clusterlist->removeClusters(hitsetkey); m_clusterhitassoc->removeAssocs(hitsetkey); @@ -337,8 +317,8 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) unsigned int chip = MvtxDefs::getChipId(hitsetitr->first); unsigned int strobe = MvtxDefs::getStrobeId(hitsetitr->first); std::cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first - << " layer " << layer << " stave " << stave << " chip " << chip - << " strobe " << strobe << std::endl; + << " layer " << layer << " stave " << stave << " chip " << chip + << " strobe " << strobe << std::endl; } if (Verbosity() > 2) @@ -394,7 +374,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) std::vector component(num_vertices(G)); // this is the actual clustering, performed by boost - boost::connected_components(G, &component[0]); + boost::connected_components(G, component.data()); // Loop over the components(hits) compiling a list of the // unique connected groups (ie. clusters). @@ -405,7 +385,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) cluster_ids.insert(component[i]); clusters.insert(make_pair(component[i], hitvec[i])); } - for (const auto& clusid:cluster_ids) + for (const auto &clusid : cluster_ids) { auto clusrange = clusters.equal_range(clusid); auto ckey = TrkrDefs::genClusKey(hitset->getHitSetKey(), clusid); @@ -413,7 +393,8 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) // determine the size of the cluster in phi and z std::set phibins; std::set zbins; - std::map m_phi, m_z; // Note, there are no "cut" bins for Svtx Clusters + std::map m_phi; + std::map m_z; // Note, there are no "cut" bins for Svtx Clusters // determine the cluster position... double locxsum = 0.; @@ -426,7 +407,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) // we need the geometry object for this layer to get the global positions int layer = TrkrDefs::getLayer(ckey); - auto layergeom = dynamic_cast(geom_container->GetLayerGeom(layer)); + auto *layergeom = dynamic_cast(geom_container->GetLayerGeom(layer)); if (!layergeom) { exit(1); @@ -574,11 +555,11 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) if (Verbosity() > 0) { std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer - << " rad " << layergeom->get_radius() << " phibins " - << phibins.size() << " pitch " << pitch << " phisize " << phisize - << " zbins " << zbins.size() << " length " << length << " zsize " - << zsize << " local x " << locclusx << " local y " << locclusz - << std::endl; + << " rad " << layergeom->get_radius() << " phibins " + << phibins.size() << " pitch " << pitch << " phisize " << phisize + << " zbins " << zbins.size() << " length " << length << " zsize " + << zsize << " local x " << locclusx << " local y " << locclusz + << std::endl; } auto clus = std::make_unique(); @@ -605,7 +586,7 @@ void MvtxClusterizer::ClusterMvtx(PHCompositeNode *topNode) } } // clusitr loop - } // loop over hitsets + } // loop over hitsets if (Verbosity() > 1) { @@ -650,8 +631,8 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) unsigned int chip = MvtxDefs::getChipId(hitsetitr->first); unsigned int strobe = MvtxDefs::getStrobeId(hitsetitr->first); std::cout << "MvtxClusterizer found hitsetkey " << hitsetitr->first - << " layer " << layer << " stave " << stave << " chip " << chip - << " strobe " << strobe << std::endl; + << " layer " << layer << " stave " << stave << " chip " << chip + << " strobe " << strobe << std::endl; } if (Verbosity() > 2) @@ -695,7 +676,7 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) std::vector component(num_vertices(G)); // this is the actual clustering, performed by boost - boost::connected_components(G, &component[0]); + boost::connected_components(G, component.data()); // Loop over the components(hits) compiling a list of the // unique connected groups (ie. clusters). @@ -709,7 +690,7 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) } // std::cout << "found cluster #: "<< clusters.size()<< std::endl; // loop over the componenets and make clusters - for( const auto& clusid:cluster_ids) + for (const auto &clusid : cluster_ids) { auto clusrange = clusters.equal_range(clusid); @@ -731,7 +712,7 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) // we need the geometry object for this layer to get the global positions int layer = TrkrDefs::getLayer(ckey); - auto layergeom = dynamic_cast( + auto *layergeom = dynamic_cast( geom_container->GetLayerGeom(layer)); if (!layergeom) { @@ -845,11 +826,11 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) if (Verbosity() > 0) { std::cout << " MvtxClusterizer: cluskey " << ckey << " layer " << layer - << " rad " << layergeom->get_radius() << " phibins " - << phibins.size() << " pitch " << pitch << " phisize " << phisize - << " zbins " << zbins.size() << " length " << length << " zsize " - << zsize << " local x " << locclusx << " local y " << locclusz - << std::endl; + << " rad " << layergeom->get_radius() << " phibins " + << phibins.size() << " pitch " << pitch << " phisize " << phisize + << " zbins " << zbins.size() << " length " << length << " zsize " + << zsize << " local x " << locclusx << " local y " << locclusz + << std::endl; } auto clus = std::make_unique(); @@ -875,7 +856,7 @@ void MvtxClusterizer::ClusterMvtxRaw(PHCompositeNode *topNode) m_clusterlist->addClusterSpecifyKey(ckey, clus.release()); } } // clusitr loop - } // loop over hitsets + } // loop over hitsets if (Verbosity() > 1) { @@ -898,11 +879,11 @@ void MvtxClusterizer::PrintClusters(PHCompositeNode *topNode) } std::cout << "================= After MvtxClusterizer::process_event() " - "====================" - << std::endl; + "====================" + << std::endl; std::cout << " There are " << clusterlist->size() - << " clusters recorded: " << std::endl; + << " clusters recorded: " << std::endl; if (Verbosity() > 3) { @@ -910,8 +891,8 @@ void MvtxClusterizer::PrintClusters(PHCompositeNode *topNode) } std::cout << "==================================================================" - "=========" - << std::endl; + "=========" + << std::endl; } return; diff --git a/offline/packages/mvtx/MvtxClusterizer.h b/offline/packages/mvtx/MvtxClusterizer.h index ce4794b5d1..10c65914cd 100644 --- a/offline/packages/mvtx/MvtxClusterizer.h +++ b/offline/packages/mvtx/MvtxClusterizer.h @@ -65,8 +65,8 @@ class MvtxClusterizer : public SubsysReco private: // bool are_adjacent(const pixel lhs, const pixel rhs); bool record_ClusHitsVerbose{false}; - bool are_adjacent(const std::pair &lhs, const std::pair &rhs); - bool are_adjacent(RawHit *lhs, RawHit *rhs); + bool are_adjacent(const std::pair &lhs, const std::pair &rhs) const; + bool are_adjacent(RawHit *lhs, RawHit *rhs) const; void ClusterMvtx(PHCompositeNode *topNode); void ClusterMvtxRaw(PHCompositeNode *topNode); diff --git a/offline/packages/mvtx/MvtxCombinedRawDataDecoder.cc b/offline/packages/mvtx/MvtxCombinedRawDataDecoder.cc index 2a851b56b6..cc3ba5bcb3 100644 --- a/offline/packages/mvtx/MvtxCombinedRawDataDecoder.cc +++ b/offline/packages/mvtx/MvtxCombinedRawDataDecoder.cc @@ -180,11 +180,6 @@ void MvtxCombinedRawDataDecoder::GetNodes(PHCompositeNode *topNode) } } -//_____________________________________________________________________ -int MvtxCombinedRawDataDecoder::Init(PHCompositeNode * /*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} //____________________________________________________________________________.. int MvtxCombinedRawDataDecoder::InitRun(PHCompositeNode *topNode) @@ -365,12 +360,6 @@ int MvtxCombinedRawDataDecoder::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -//_____________________________________________________________________ -int MvtxCombinedRawDataDecoder::End(PHCompositeNode * /*topNode*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - // void MvtxCombinedRawDataDecoder::removeDuplicates( // std::vector > &v) diff --git a/offline/packages/mvtx/MvtxCombinedRawDataDecoder.h b/offline/packages/mvtx/MvtxCombinedRawDataDecoder.h index 0dfce2bcd7..852b6fe1df 100644 --- a/offline/packages/mvtx/MvtxCombinedRawDataDecoder.h +++ b/offline/packages/mvtx/MvtxCombinedRawDataDecoder.h @@ -7,6 +7,8 @@ * \author Jakub Kvapil */ +#include "MvtxPixelMask.h" + #include #include @@ -16,7 +18,6 @@ #include #include -#include "MvtxPixelMask.h" class MvtxEventInfo; class MvtxRawEvtHeader; @@ -33,17 +34,11 @@ class MvtxCombinedRawDataDecoder : public SubsysReco /// constructor explicit MvtxCombinedRawDataDecoder(const std::string& name = "MvtxCombinedRawDataDecoder"); - /// global initialization - int Init(PHCompositeNode* /*dummy*/) override; - /// run initialization - int InitRun(PHCompositeNode* /*dummy*/) override; + int InitRun(PHCompositeNode *topNode) override; /// event processing - int process_event(PHCompositeNode* /*dummy*/) override; - - /// end of processing - int End(PHCompositeNode* /*dummy*/) override; + int process_event(PHCompositeNode *topNode) override; void useRawHitNodeName(const std::string& name) { m_MvtxRawHitNodeName = name; } @@ -63,20 +58,20 @@ class MvtxCombinedRawDataDecoder : public SubsysReco void CreateNodes(PHCompositeNode*); void GetNodes(PHCompositeNode*); - uint64_t gl1rawhitbco = 0; + uint64_t gl1rawhitbco {0}; - TrkrHitSetContainer* hit_set_container = nullptr; - TrkrHitSetContMvtxHelper* mvtx_hit_set_helper = nullptr; - MvtxEventInfo* mvtx_event_header = nullptr; - MvtxRawEvtHeader* mvtx_raw_event_header = nullptr; - MvtxRawHitContainer* mvtx_raw_hit_container = nullptr; - MvtxRawHit* mvtx_rawhit = nullptr; + TrkrHitSetContainer* hit_set_container {nullptr}; + TrkrHitSetContMvtxHelper* mvtx_hit_set_helper {nullptr}; + MvtxEventInfo* mvtx_event_header {nullptr}; + MvtxRawEvtHeader* mvtx_raw_event_header {nullptr}; + MvtxRawHitContainer* mvtx_raw_hit_container {nullptr}; + MvtxRawHit* mvtx_rawhit {nullptr}; - std::string m_MvtxRawHitNodeName = "MVTXRAWHIT"; - std::string m_MvtxRawEvtHeaderNodeName = "MVTXRAWEVTHEADER"; + std::string m_MvtxRawHitNodeName {"MVTXRAWHIT"}; + std::string m_MvtxRawEvtHeaderNodeName {"MVTXRAWEVTHEADER"}; - bool m_readStrWidthFromDB = true; - float m_strobeWidth = 89.; //! microseconds + bool m_readStrWidthFromDB {true}; + float m_strobeWidth {89.}; //! microseconds // mask hot pixels bool m_doOfflineMasking{false}; @@ -85,4 +80,4 @@ class MvtxCombinedRawDataDecoder : public SubsysReco bool m_mvtx_is_triggered{false}; }; -#endif \ No newline at end of file +#endif diff --git a/offline/packages/mvtx/MvtxHitPruner.cc b/offline/packages/mvtx/MvtxHitPruner.cc index 4f141a4c3f..58cbb423c4 100644 --- a/offline/packages/mvtx/MvtxHitPruner.cc +++ b/offline/packages/mvtx/MvtxHitPruner.cc @@ -51,26 +51,33 @@ namespace { //! range adaptor to be able to use range-based for loop - template class range_adaptor + template + class range_adaptor { - public: - range_adaptor( const T& range ):m_range(range){} - const typename T::first_type& begin() {return m_range.first;} - const typename T::second_type& end() {return m_range.second;} - private: + public: + explicit range_adaptor(const T& range) + : m_range(range) + { + } + const typename T::first_type& begin() { return m_range.first; } + const typename T::second_type& end() { return m_range.second; } + + private: T m_range; }; -} +} // namespace -MvtxHitPruner::MvtxHitPruner(const std::string &name) +MvtxHitPruner::MvtxHitPruner(const std::string& name) : SubsysReco(name) { } -int MvtxHitPruner::InitRun(PHCompositeNode * /*topNode*/) -{ return Fun4AllReturnCodes::EVENT_OK; } +int MvtxHitPruner::InitRun(PHCompositeNode* /*topNode*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} -int MvtxHitPruner::process_event(PHCompositeNode *topNode) +int MvtxHitPruner::process_event(PHCompositeNode* topNode) { // get node containing the digitized hits m_hits = findNode::getClass(topNode, "TRKR_HITSET"); @@ -93,12 +100,14 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) std::set bare_hitset_set; const auto hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::mvtxId); - for( const auto& [hitsetkey,hitset]:range_adaptor(hitsetrange) ) + for (const auto& [hitsetkey, hitset] : range_adaptor(hitsetrange)) { - // get strobe, skip if already zero const int strobe = MvtxDefs::getStrobeId(hitsetkey); - if( strobe == 0 ) continue; + if (strobe == 0) + { + continue; + } // get the hitsetkey value for strobe 0 const auto bare_hitsetkey = MvtxDefs::resetStrobe(hitsetkey); @@ -117,43 +126,46 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) for (const auto& bare_hitsetkey : bare_hitset_set) { // find matching hitset of creater - auto bare_hitset = (m_hits->findOrAddHitSet(bare_hitsetkey))->second; + auto* bare_hitset = (m_hits->findOrAddHitSet(bare_hitsetkey))->second; if (Verbosity()) { std::cout - << "MvtxHitPruner::process_event - bare_hitset " << bare_hitsetkey - << " initially has " << bare_hitset->size() << " hits " - << std::endl; + << "MvtxHitPruner::process_event - bare_hitset " << bare_hitsetkey + << " initially has " << bare_hitset->size() << " hits " + << std::endl; } // get all hitsets with non-zero strobe that match the bare hitset key auto bare_hitsetrange = hitset_multimap.equal_range(bare_hitsetkey); - for( const auto& [unused,hitsetkey]:range_adaptor(bare_hitsetrange) ) + for (const auto& [unused, hitsetkey] : range_adaptor(bare_hitsetrange)) { const int strobe = MvtxDefs::getStrobeId(hitsetkey); - if( strobe == 0 ) continue; + if (strobe == 0) + { + continue; + } if (Verbosity()) { std::cout << "MvtxHitPruner::process_event -" - << " process hitsetkey " << hitsetkey - << " from strobe " << strobe - << " for bare_hitsetkey " << bare_hitsetkey - << std::endl; + << " process hitsetkey " << hitsetkey + << " from strobe " << strobe + << " for bare_hitsetkey " << bare_hitsetkey + << std::endl; } // copy all hits to the hitset with strobe 0 - auto hitset = m_hits->findHitSet(hitsetkey); + auto* hitset = m_hits->findHitSet(hitsetkey); if (Verbosity()) { std::cout << "MvtxHitPruner::process_event - hitsetkey " << hitsetkey - << " has strobe " << strobe << " and has " << hitset->size() - << " hits, so copy it" << std::endl; + << " has strobe " << strobe << " and has " << hitset->size() + << " hits, so copy it" << std::endl; } TrkrHitSet::ConstRange hitrangei = hitset->getHits(); - for( const auto& [hitkey,old_hit]:range_adaptor(hitrangei) ) + for (const auto& [hitkey, old_hit] : range_adaptor(hitrangei)) { if (Verbosity()) { @@ -166,9 +178,9 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) if (Verbosity()) { std::cout - << "MvtxHitPruner::process_event - hitkey " << hitkey - << " is already in bare hitsest, do not copy" - << std::endl; + << "MvtxHitPruner::process_event - hitkey " << hitkey + << " is already in bare hitsest, do not copy" + << std::endl; } continue; } @@ -177,11 +189,11 @@ int MvtxHitPruner::process_event(PHCompositeNode *topNode) if (Verbosity()) { std::cout - << "MvtxHitPruner::process_event - copying over hitkey " - << hitkey << std::endl; + << "MvtxHitPruner::process_event - copying over hitkey " + << hitkey << std::endl; } - auto new_hit = new TrkrHitv2; + auto* new_hit = new TrkrHitv2; new_hit->CopyFrom(old_hit); bare_hitset->addHitSpecificKey(hitkey, new_hit); } diff --git a/offline/packages/mvtx/SegmentationAlpide.cc b/offline/packages/mvtx/SegmentationAlpide.cc index 6b9aecddd0..0b1aae48cf 100644 --- a/offline/packages/mvtx/SegmentationAlpide.cc +++ b/offline/packages/mvtx/SegmentationAlpide.cc @@ -5,16 +5,15 @@ */ #include "SegmentationAlpide.h" -#include - #include +#include void SegmentationAlpide::print() { - std::cout << (boost::format("Pixel size: %.2f (along %d rows) %.2f (along %d columns) microns") % (PitchRow * 1e4) % NRows % (PitchCol * 1e4) % NCols).str() + std::cout << std::format("Pixel size: {:.2f} (along {} rows) {:.2f} (along {} columns) microns", (PitchRow * 1e4), NRows, (PitchCol * 1e4), NCols) << std::endl; - std::cout << (boost::format("Passive edges: bottom: %.2f, top: %.2f, left/right: %.2f microns") % (PassiveEdgeReadOut * 1e4) % (PassiveEdgeTop * 1e4) % (PassiveEdgeSide * 1e4)).str() + std::cout << std::format("Passive edges: bottom: {:.2f}, top: {:.2f}, left/right: {:.2f} microns", (PassiveEdgeReadOut * 1e4), (PassiveEdgeTop * 1e4), (PassiveEdgeSide * 1e4)) << std::endl; - std::cout << (boost::format("Active/Total size: %.6f/%.6f (rows) %.6f/%.6f (cols) cm") % ActiveMatrixSizeRows % SensorSizeRows % ActiveMatrixSizeCols % SensorSizeCols).str() + std::cout << std::format("Active/Total size: {:.6f}/{:.6f} (rows) {:.6f}/{:.6f} (cols) cm", ActiveMatrixSizeRows, SensorSizeRows, ActiveMatrixSizeCols, SensorSizeCols) << std::endl; } diff --git a/offline/packages/tpc/DiffuseLaserEventSelector.cc b/offline/packages/tpc/DiffuseLaserEventSelector.cc new file mode 100644 index 0000000000..8a412ba7f2 --- /dev/null +++ b/offline/packages/tpc/DiffuseLaserEventSelector.cc @@ -0,0 +1,86 @@ +#include "DiffuseLaserEventSelector.h" + +#include + +#include + +#include + +#include +#include +#include + +#include + +DiffuseLaserEventSelector::DiffuseLaserEventSelector(const std::string& name) + : SubsysReco(name) +{ +} + +int DiffuseLaserEventSelector::process_event(PHCompositeNode* topNode) +{ + LaserEventInfo* laserEventInfo = + findNode::getClass(topNode, "LaserEventInfo"); + + if (!laserEventInfo) + { + std::cout << PHWHERE + << " LaserEventInfo node is missing. Rejecting event." + << std::endl; + + return Fun4AllReturnCodes::DISCARDEVENT; + } + + EventHeader *eventHeader = findNode::getClass(topNode, "EventHeader"); + if (!eventHeader) + { + std::cout << PHWHERE << " EventHeader Node missing, doing nothing." << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + bool accept = true; + + /* + if (m_requireTPCDiffuseLaser) + { + accept = accept && laserEventInfo->isLaserEvent(); + } + + if (m_requireGL1Laser) + { + accept = accept && laserEventInfo->isGl1LaserEvent(); + } + + if (m_rejectGL1Pileup) + { + accept = accept && !laserEventInfo->isGl1LaserPileupEvent(); + } + */ + + if((eventHeader->get_RunNumber() > 66153 && laserEventInfo->isGl1LaserEvent()) || (eventHeader->get_RunNumber() <= 66153 && laserEventInfo->isLaserEvent())) + { + accept = true; + } + else + { + accept = false; + } + + /*if (Verbosity() > 1) + { + std::cout << "DiffuseLaserEventSelector:" + << " isLaserEvent = " << laserEventInfo->isLaserEvent() + << " isGl1LaserEvent = " << laserEventInfo->isGl1LaserEvent() + << " isGl1LaserPileupEvent = " + << laserEventInfo->isGl1LaserPileupEvent() + << " accept = " << accept + << std::endl; + }*/ + + if (!accept) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} \ No newline at end of file diff --git a/offline/packages/tpc/DiffuseLaserEventSelector.h b/offline/packages/tpc/DiffuseLaserEventSelector.h new file mode 100644 index 0000000000..6b92a7f86c --- /dev/null +++ b/offline/packages/tpc/DiffuseLaserEventSelector.h @@ -0,0 +1,29 @@ +#ifndef DiffuseLaserEventSelector_H +#define DiffuseLaserEventSelector_H + +#include + +#include + +class PHCompositeNode; + +class DiffuseLaserEventSelector : public SubsysReco +{ + public: + DiffuseLaserEventSelector(const std::string& name = "DiffuseLaserEventSelector"); + + ~DiffuseLaserEventSelector() override = default; + + int process_event(PHCompositeNode* topNode) override; + + void RequireTPCDiffuseLaser(bool b) { m_requireTPCDiffuseLaser = b; } + void RequireGL1Laser(bool b) { m_requireGL1Laser = b; } + void RejectGL1Pileup(bool b) { m_rejectGL1Pileup = b; } + + private: + bool m_requireTPCDiffuseLaser = true; + bool m_requireGL1Laser = false; + bool m_rejectGL1Pileup = true; +}; + +#endif \ No newline at end of file diff --git a/offline/packages/tpc/LaserClusterHelper.cc b/offline/packages/tpc/LaserClusterHelper.cc new file mode 100644 index 0000000000..ec9afa36cd --- /dev/null +++ b/offline/packages/tpc/LaserClusterHelper.cc @@ -0,0 +1,124 @@ +#include "LaserClusterHelper.h" + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include + +namespace +{ + Acts::Vector3 invalid(std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN()); +} + +//____________________________________________________________________________ +void LaserClusterHelper::loadNodes(PHCompositeNode* topNode) +{ + m_tGeometry = findNode::getClass(topNode,"ActsGeometry"); + if(!m_tGeometry) + { + std::cout << "LaserClusterHelper::loadNodes - ActsGeometry not found on node tree" << std::endl; + } + + m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + if(!m_geom_container) + { + std::cout << "LaserClusterHelper::loadNodes - TPCGEOMCONTAINER not found on node tree" << std::endl; + } +} + +//____________________________________________________________________________ +Acts::Vector3 LaserClusterHelper::getHitGlobalPosition(TrkrDefs::hitsetkey hitsetkey, TrkrDefs::hitkey hitkey) const +{ + //const Acts::Vector3 invalid(std::numeric_limits::quiet_NaN(), + // std::numeric_limits::quiet_NaN(), + // std::numeric_limits::quiet_NaN()); + + if(!m_tGeometry || !m_geom_container) + { + return invalid; + } + + const int layer = TrkrDefs::getLayer(hitsetkey); + const int side = TpcDefs::getSide(hitsetkey); + + PHG4TpcGeom *layer_geom = m_geom_container->GetLayerCellGeom(layer); + if(!layer_geom) + { + return invalid; + } + + const int iphi = TpcDefs::getPad(hitkey); + const int it = TpcDefs::getTBin(hitkey); + + const double radius = layer_geom->get_radius(); + const double phi = layer_geom->get_phi(iphi, side); + + const double env_x = radius * cos(phi); + const double env_y = radius * sin(phi); + double env_z = 0.0; + //hard code at 0 until better z coordinate calibration is determined + if(m_useZ) + { + double vdrift = m_tGeometry->get_drift_velocity(); + double tdriftmax = layer_geom->get_max_driftlength() / vdrift; + + double zdriftlength = layer_geom->get_zcenter(it) * vdrift; + // convert z drift length to z position in the TPC + env_z = tdriftmax * vdrift - zdriftlength; + if (side == 0) + { + env_z = -env_z; + } + } + + Acts::Vector3 env_global(env_x, env_y, env_z); + return m_tGeometry->transformTpcEnvelopeToWorld(env_global); +} + +//____________________________________________________________________________ +Acts::Vector3 LaserClusterHelper::getClusterCentroid(LaserCluster* cluster) const +{ + //const Acts::Vector3 invalid(std::numeric_limits::quiet_NaN(), + // std::numeric_limits::quiet_NaN(), + // std::numeric_limits::quiet_NaN()); + + if(!cluster) + { + return invalid; + } + + Acts::Vector3 weightedSum(0.0, 0.0, 0.0); + double adcSum = 0.0; + + const unsigned int nhits = cluster->getNhits(); + for(unsigned int i=0; igetHit(i); + const Acts::Vector3 global = getHitGlobalPosition(hit.hitsetkey, hit.hitkey); + if(global.hasNaN()) + { + continue; + } + + weightedSum += hit.adc * global; + adcSum += hit.adc; + } + + if(adcSum <= 0.0) + { + return invalid; + } + + return weightedSum / adcSum; +} \ No newline at end of file diff --git a/offline/packages/tpc/LaserClusterHelper.h b/offline/packages/tpc/LaserClusterHelper.h new file mode 100644 index 0000000000..102fd47f4b --- /dev/null +++ b/offline/packages/tpc/LaserClusterHelper.h @@ -0,0 +1,32 @@ +#ifndef TPC_LASERCLUSTERHELPER_H +#define TPC_LASERCLUSTERHELPER_H + +#include +#include + +class ActsGeometry; +class LaserCluster; +class PHCompositeNode; +class PHG4TpcGeomContainer; + +class LaserClusterHelper +{ + public: + LaserClusterHelper () = default; + + void loadNodes(PHCompositeNode *topNode); + + Acts::Vector3 getHitGlobalPosition(TrkrDefs::hitsetkey, TrkrDefs::hitkey) const; + Acts::Vector3 getClusterCentroid(LaserCluster*) const; + + void set_useZ(bool use) { m_useZ = use; } + private: + + ActsGeometry *m_tGeometry{nullptr}; + PHG4TpcGeomContainer *m_geom_container{nullptr}; + + bool m_useZ{false}; + +}; + +#endif diff --git a/offline/packages/tpc/LaserClusterizer.cc b/offline/packages/tpc/LaserClusterizer.cc index 170f95944d..a965cb7b58 100644 --- a/offline/packages/tpc/LaserClusterizer.cc +++ b/offline/packages/tpc/LaserClusterizer.cc @@ -5,12 +5,13 @@ #include #include #include -#include +#include #include #include // for hitkey, getLayer #include #include #include +#include #include #include @@ -31,13 +32,10 @@ #include #include +#include #include #include #include -//#include -//#include -#include -//#include #include #include @@ -46,34 +44,33 @@ #include #include // for sqrt, cos, sin +#include #include #include #include // for _Rb_tree_cons... +#include +#include +#include #include +#include #include // for pair #include -#include -#include -#include #include namespace bg = boost::geometry; namespace bgi = boost::geometry::index; -using point = bg::model::point; +using point = bg::model::point; using box = bg::model::box; using specHitKey = std::pair; using adcKey = std::pair; using pointKeyLaser = std::pair; using hitData = std::pair; - -int layerMins[3] = {7,23,39}; +int layerMins[3] = {7, 23, 39}; int layerMaxes[3] = {22, 38, 54}; - - namespace { struct thread_data @@ -101,28 +98,25 @@ namespace pthread_mutex_t mythreadlock; const std::vector neighborOffsets = { - point(1, 0, 0), point(-1, 0, 0), - point(0, 1, 0), point(0, -1, 0), - point(0, 0, 1), point(0, 0, -1), - point(0, 0, 2), point(0, 0, -2) - }; - + point(1, 0, 0), point(-1, 0, 0), + point(0, 1, 0), point(0, -1, 0), + point(0, 0, 1), point(0, 0, -1), + point(0, 0, 2), point(0, 0, -2)}; - double layerFunction(double *x, double *par) + double layerFunction(double *x, const double *par) { double A = par[0]; double mu = par[1]; - double binCenter = round(x[0]); double overlapLow = std::max(binCenter - 0.5, mu - 0.5); double overlapHigh = std::min(binCenter + 0.5, mu + 0.5); double overlap = overlapHigh - overlapLow; - if(overlap <= 0.0) + if (overlap <= 0.0) { return 0.0; } - return A*overlap; + return A * overlap; /* if(fabs(x[0] - mu) < 1) { @@ -131,50 +125,187 @@ namespace } return 0.0; */ - - } double phiFunction(double *x, double *par) { - if(par[2] < 0.0) + if (par[2] < 0.0) { return 0.0; } - return par[0] * TMath::Gaus(x[0],par[1],par[2],false); + return par[0] * TMath::Gaus(x[0], par[1], par[2], false); } double timeFunction(double *x, double *par) { - if(par[2] < 0.0) + if (par[2] < 0.0) { return 0.0; } - double g = TMath::Gaus(x[0],par[1],par[2],true); - double cdf = 1 + TMath::Erfc(par[3]*(x[0]-par[1])/(sqrt(2.0)*par[2])); - return par[0]*g*cdf; + double g = TMath::Gaus(x[0], par[1], par[2], true); + double cdf = 1 + TMath::Erfc(par[3] * (x[0] - par[1]) / (sqrt(2.0) * par[2])); + return par[0] * g * cdf; } - void findConnectedRegions3(std::vector &clusHits, std::pair &maxKey) + void splitWeaklyConnectedRegion(const std::vector ®ion, std::vector> &outputRegions, int aVerbosity) + { + int N = region.size(); + /* + std::vector> adj(N); + for(int i=0; i() + neigh.get<0>() - region[j].first.get<0>()) < 0.01 && + fabs(region[i].first.get<1>() + neigh.get<1>() - region[j].first.get<1>()) < 0.01 && + fabs(region[i].first.get<2>() + neigh.get<2>() - region[j].first.get<2>()) < 0.01) + { + adj[i].push_back(j); + adj[j].push_back(i); + break; + } + } + } + } + */ + std::map, int> coordIndex; + for(int i=0; i(std::round(region[i].first.get<0>())); + int p = static_cast(std::round(region[i].first.get<1>())); + int t = static_cast(std::round(region[i].first.get<2>())); + coordIndex[{l,p,t}] = i; + } + std::vector> adj(N); + for(int i=0; i(std::round(region[i].first.get<0>())); + int p = static_cast(std::round(region[i].first.get<1>())); + int t = static_cast(std::round(region[i].first.get<2>())); + for(const auto &neigh : neighborOffsets) + { + int nl = l + static_cast(neigh.get<0>()); + int np = p + static_cast(neigh.get<1>()); + int nt = t + static_cast(neigh.get<2>()); + auto it = coordIndex.find({nl,np,nt}); + if(it != coordIndex.end()) + { + adj[i].push_back(it->second); + } + } + } + + if(aVerbosity > 3) { std::cout << " constructed adjacency list, average degree = " << std::accumulate(adj.begin(), adj.end(), 0.0, [](double s, auto &v) { return s + v.size(); }) / N << ")" << std::endl; +} + + std::vector disc(N, -1); + std::vector low(N, -1); + std::vector parent(N, -1); + std::vector> bridges; + int time=0; + + std::function dfs = [&](int u) + { + disc[u] = low[u] = ++time; + for(auto v : adj[u]) + { + if(disc[v] == -1) + { + parent[v] = u; + dfs(v); + low[u] = std::min(low[u], low[v]); + if(low[v] > disc[u]) + { + bridges.emplace_back(u,v); + } + } + else if(v != parent[u]) + { + low[u] = std::min(low[u], disc[v]); + } + } + }; + + for(int i=0; i 2) { std::cout << " Found " << bridges.size() << " bridges in region of size " << N << std::endl; +} + + std::vector> adj2 = adj; + int removed = 0; + for(auto [u,v] : bridges) + { + if(adj[u].size() > 2 && adj[v].size() > 2) + { + adj2[u].erase(std::remove(adj2[u].begin(), adj2[u].end(), v), adj2[u].end()); + adj2[v].erase(std::remove(adj2[v].begin(), adj2[v].end(), u), adj2[v].end()); + removed++; + if(aVerbosity > 3) { std::cout << " removed weak bridge between nodes " << u << " (deg = " << adj[u].size() << ") and " << v << " (deg = " << adj[v].size() << ")" << std::endl; +} + } + } + + if(aVerbosity > 3) { std::cout << " Removed " << removed << " weak bridges, now finding connected components" << std::endl; +} + + std::vector visited(N, false); + for(int i=0; i sub; + std::queue q; + q.push(i); + visited[i] = true; + while(!q.empty()) + { + int u = q.front(); + q.pop(); + sub.push_back(region[u]); + for(auto v : adj2[u]) + { + if(!visited[v]) + { + visited[v] = true; + q.push(v); + } + } + } + outputRegions.push_back(sub); + if(aVerbosity > 3) { std::cout << " found subregion of size " << sub.size() << std::endl; +} + } + if(aVerbosity > 2) { std::cout << " finished splitting region into " << outputRegions.size() << " subregions" << std::endl; +} +} + + void findConnectedRegions3(std::vector &clusHits, std::pair &maxKey, int aVerbosity) { std::vector> regions; std::vector unvisited; - for(auto &clusHit : clusHits) + unvisited.reserve(clusHits.size()); + for (auto &clusHit : clusHits) { unvisited.push_back(clusHit); } - while(!unvisited.empty()) + while (!unvisited.empty()) { std::vector region; std::queue q; unsigned int mIndex = 0; - int i=0; - for(auto hit : unvisited) + int i = 0; + for (auto hit : unvisited) { - if(hit.second.second.first == maxKey.first && hit.second.second.second == maxKey.second) + if (hit.second.second.first == maxKey.first && hit.second.second.second == maxKey.second) { mIndex = i; break; @@ -183,30 +314,29 @@ namespace } auto seed = unvisited[mIndex]; - unvisited.erase(unvisited.begin()+mIndex); + unvisited.erase(unvisited.begin() + mIndex); q.push(seed); region.push_back(seed); - while(!q.empty()) + while (!q.empty()) { - float ix = q.front().first.get<0>(); - float iy = q.front().first.get<1>(); - float iz = q.front().first.get<2>(); + double ix = q.front().first.get<0>(); + double iy = q.front().first.get<1>(); + double iz = q.front().first.get<2>(); q.pop(); for (auto neigh : neighborOffsets) { - float nx = ix + neigh.get<0>(); - float ny = iy + neigh.get<1>(); - float nz = iz + neigh.get<2>(); + double nx = ix + neigh.get<0>(); + double ny = iy + neigh.get<1>(); + double nz = iz + neigh.get<2>(); - for(unsigned int v=0; v() - nx) < 0.01 && fabs(unvisited[v].first.get<1>() - ny) < 0.01 && fabs(unvisited[v].first.get<2>() - nz) < 0.01) + if (fabs(unvisited[v].first.get<0>() - nx) < 0.01 && fabs(unvisited[v].first.get<1>() - ny) < 0.01 && fabs(unvisited[v].first.get<2>() - nz) < 0.01) { auto newSeed = unvisited[v]; - unvisited.erase(unvisited.begin()+v); + unvisited.erase(unvisited.begin() + v); q.push(newSeed); region.push_back(newSeed); break; @@ -215,18 +345,68 @@ namespace } } regions.push_back(region); + } + + if(aVerbosity > 2) { std::cout << "finished with normal region finding, now splitting weakly connected regions" << std::endl; +} + std::vector> refinedRegions; + int regionNum = 0; + for(auto ®ion : regions) + { + std::vector> tmpRefinedRegions; + if(aVerbosity > 2) { std::cout << "starting to split region " << regionNum << " with " << region.size() << " hits" << std::endl; +} + regionNum++; + splitWeaklyConnectedRegion(region, tmpRefinedRegions, aVerbosity); + if(aVerbosity > 2) { std::cout << "finished splitting region into " << tmpRefinedRegions.size() << std::endl; +} + for(auto &subregion : tmpRefinedRegions) + { + refinedRegions.push_back(subregion); + } + if(aVerbosity > 2) { std::cout << "total refined regions so far: " << refinedRegions.size() << std::endl; +} } + std::sort(refinedRegions.begin(), refinedRegions.end(), [&](const auto &a, const auto &b) + { + bool a_has = false; + bool b_has = false; + for(auto &h : a) + { + if(h.second.second.first == maxKey.first && h.second.second.second == maxKey.second) + { + a_has = true; + break; + } + } + for(auto &h : b) + { + if(h.second.second.first == maxKey.first && h.second.second.second == maxKey.second) + { + b_has = true; + break; + } + } + if(a_has != b_has) + { + return a_has; + } + return a.size() > b.size(); + }); + clusHits.clear(); - for(auto hit : regions[0]) + if(refinedRegions.empty() || refinedRegions[0].empty()) + { + return; + } + for(auto hit : refinedRegions[0]) { clusHits.push_back(hit); } - } - void remove_hits(std::vector &clusHits, bgi::rtree> &rtree, std::multimap &adcMap) { for (auto &clusHit : clusHits) @@ -237,181 +417,146 @@ namespace for (auto iterAdc = adcMap.begin(); iterAdc != adcMap.end();) { - if(iterAdc->second.second == spechitkey) - { - iterAdc = adcMap.erase(iterAdc); - break; - } - else - { - ++iterAdc; - } + if (iterAdc->second.second == spechitkey) + { + iterAdc = adcMap.erase(iterAdc); + break; + } + + ++iterAdc; } } - } void calc_cluster_parameter(std::vector &clusHits, thread_data &my_data, std::pair maxADCKey) { - - - - findConnectedRegions3(clusHits, maxADCKey); - - - double rSum = 0.0; - double phiSum = 0.0; - double tSum = 0.0; + findConnectedRegions3(clusHits, maxADCKey, my_data.Verbosity); + unsigned int nHits = clusHits.size(); + if(nHits == 0) + { + return; + } + double layerSum = 0.0; double iphiSum = 0.0; double itSum = 0.0; - + double adcSum = 0.0; - + double maxAdc = 0.0; TrkrDefs::hitsetkey maxKey = 0; - - unsigned int nHits = clusHits.size(); - - auto *clus = new LaserClusterv2; - + //double secondmaxAdc = 0.0; + //TrkrDefs::hitsetkey secondmaxKey = 0; + + auto *clus = new LaserClusterv3; + int meanSide = 0; - - std::vector usedLayer; - std::vector usedIPhi; - std::vector usedIT; - - double meanLayer = 0.0; - double meanIPhi = 0.0; - double meanIT = 0.0; + + std::vector usedLayer; + std::vector usedIPhi; + std::vector usedIT; + + float meanLayer = 0.0; + float meanIPhi = 0.0; + float meanIT = 0.0; for (auto &clusHit : clusHits) { - float coords[3] = {clusHit.first.get<0>(), clusHit.first.get<1>(), clusHit.first.get<2>()}; + int coords[3] = {(int)clusHit.first.get<0>(), (int)clusHit.first.get<1>(), (int)clusHit.first.get<2>()}; std::pair spechitkey = clusHit.second.second; - unsigned int adc = clusHit.second.first; + uint16_t adc = clusHit.second.first; int side = TpcDefs::getSide(spechitkey.second); - + if (side) { - meanSide++; + meanSide++; } else { - meanSide--; + meanSide--; } - - PHG4TpcGeom *layergeom = my_data.geom_container->GetLayerCellGeom((int) coords[0]); - - double r = layergeom->get_radius(); - double phi = layergeom->get_phi(coords[1], side); - double t = layergeom->get_zcenter(fabs(coords[2])); - - double hitzdriftlength = t * my_data.tGeometry->get_drift_velocity(); - double hitZ = my_data.tdriftmax * my_data.tGeometry->get_drift_velocity() - hitzdriftlength; - - - bool foundLayer = false; - for (float i : usedLayer) - { - if (coords[0] == i) - { - foundLayer = true; - break; - } - } - - if (!foundLayer) - { - usedLayer.push_back(coords[0]); - } - - bool foundIPhi = false; - for (float i : usedIPhi) - { - if (coords[1] == i) - { - foundIPhi = true; - break; - } - } - - if (!foundIPhi) - { - usedIPhi.push_back(coords[1]); - } - - bool foundIT = false; - for (float i : usedIT) - { - if (coords[2] == i) - { - foundIT = true; - break; - } - } - - if (!foundIT) - { - usedIT.push_back(coords[2]); - } - - clus->addHit(); - clus->setHitLayer(clus->getNhits() - 1, coords[0]); - clus->setHitIPhi(clus->getNhits() - 1, coords[1]); - clus->setHitIT(clus->getNhits() - 1, coords[2]); - clus->setHitX(clus->getNhits() - 1, r * cos(phi)); - clus->setHitY(clus->getNhits() - 1, r * sin(phi)); - clus->setHitZ(clus->getNhits() - 1, hitZ); - clus->setHitAdc(clus->getNhits() - 1, (float) adc); - - rSum += r * adc; - phiSum += phi * adc; - tSum += t * adc; - - layerSum += coords[0] * adc; - iphiSum += coords[1] * adc; - itSum += coords[2] * adc; - - meanLayer += coords[0]; - meanIPhi += coords[1]; - meanIT += coords[2]; - - adcSum += adc; - - if (adc > maxAdc) - { - maxAdc = adc; - maxKey = spechitkey.second; - } - - } - - if (nHits == 0) - { - return; - } - - double clusR = rSum / adcSum; - double clusPhi = phiSum / adcSum; - double clusT = tSum / adcSum; - double zdriftlength = clusT * my_data.tGeometry->get_drift_velocity(); - - double clusX = clusR * cos(clusPhi); - double clusY = clusR * sin(clusPhi); - double clusZ = my_data.tdriftmax * my_data.tGeometry->get_drift_velocity() - zdriftlength; - if (meanSide < 0) - { - clusZ = -clusZ; - for (int i = 0; i < (int) clus->getNhits(); i++) + bool foundLayer = false; + for (int i : usedLayer) + { + if (coords[0] == i) + { + foundLayer = true; + break; + } + } + + if (!foundLayer) + { + usedLayer.push_back(coords[0]); + } + + bool foundIPhi = false; + for (int i : usedIPhi) + { + if (coords[1] == i) + { + foundIPhi = true; + break; + } + } + + if (!foundIPhi) + { + usedIPhi.push_back(coords[1]); + } + + bool foundIT = false; + for (int i : usedIT) + { + if (coords[2] == i) + { + foundIT = true; + break; + } + } + + if (!foundIT) + { + usedIT.push_back(coords[2]); + } + + clus->addHit(spechitkey.second, spechitkey.first, adc); + + layerSum += 1.0 * coords[0] * adc; + iphiSum += 1.0 * coords[1] * adc; + itSum += 1.0 * coords[2] * adc; + + meanLayer += 1.0 * coords[0]; + meanIPhi += 1.0 * coords[1]; + meanIT += 1.0 * coords[2]; + + adcSum += 1.0*adc; + + if (1.0*adc > maxAdc) + { + //secondmaxAdc = maxAdc; + //secondmaxKey = maxKey; + maxAdc = adc; + maxKey = spechitkey.second; + } + //else if (1.0*adc > secondmaxAdc) { - clus->setHitZ(i, -1 * clus->getHitZ(i)); + //secondmaxAdc = adc; + //secondmaxKey = spechitkey.second; } + + } - + + if (nHits == 0 || clus->getNhits() == 0) + { + delete clus; + return; + } + std::sort(usedLayer.begin(), usedLayer.end()); std::sort(usedIPhi.begin(), usedIPhi.end()); std::sort(usedIT.begin(), usedIT.end()); @@ -419,52 +564,73 @@ namespace meanLayer = meanLayer / nHits; meanIPhi = meanIPhi / nHits; meanIT = meanIT / nHits; - + double sigmaLayer = 0.0; double sigmaIPhi = 0.0; double sigmaIT = 0.0; - + double sigmaWeightedLayer = 0.0; double sigmaWeightedIPhi = 0.0; double sigmaWeightedIT = 0.0; - - pthread_mutex_lock(&mythreadlock); - my_data.hitHist = new TH3D(Form("hitHist_event%d_side%d_sector%d_module%d_cluster%d",my_data.eventNum,(int)my_data.side,(int)my_data.sector,(int)my_data.module,(int)my_data.cluster_vector.size()),";layer;iphi;it",usedLayer.size()+2,usedLayer[0]-1.5,*usedLayer.rbegin()+1.5,usedIPhi.size()+2,usedIPhi[0]-1.5,*usedIPhi.rbegin()+1.5,usedIT.size()+2,usedIT[0]-1.5,*usedIT.rbegin()+1.5); - - - //TH3D *hitHist = new TH3D(Form("hitHist_event%d_side%d_sector%d_module%d_cluster%d",my_data.eventNum,(int)my_data.side,(int)my_data.sector,(int)my_data.module,(int)my_data.cluster_vector.size()),";layer;iphi;it",usedLayer.size()+2,usedLayer[0]-1.5,*usedLayer.rbegin()+1.5,usedIPhi.size()+2,usedIPhi[0]-1.5,*usedIPhi.rbegin()+1.5,usedIT.size()+2,usedIT[0]-1.5,*usedIT.rbegin()+1.5); for (int i = 0; i < (int) clus->getNhits(); i++) { + LaserClusterHitInfo LCHI = clus->getHit(i); + uint8_t layer = TrkrDefs::getLayer(LCHI.hitsetkey); + uint16_t iphi = TpcDefs::getPad(LCHI.hitkey); + uint16_t it = TpcDefs::getTBin(LCHI.hitkey); + + sigmaLayer += pow(layer - meanLayer, 2); + sigmaIPhi += pow(iphi - meanIPhi, 2); + sigmaIT += pow(it - meanIT, 2); + + sigmaWeightedLayer += LCHI.adc * pow(layer - (layerSum / adcSum), 2); + sigmaWeightedIPhi += LCHI.adc * pow(iphi - (iphiSum / adcSum), 2); + sigmaWeightedIT += LCHI.adc * pow(it - (itSum / adcSum), 2); + } - my_data.hitHist->Fill(clus->getHitLayer(i), clus->getHitIPhi(i), clus->getHitIT(i), clus->getHitAdc(i)); + clus->setNLayers(usedLayer.size()); + clus->setNIPhi(usedIPhi.size()); + clus->setNIT(usedIT.size()); + clus->setLayer(layerSum / adcSum); + clus->setIPhi(iphiSum / adcSum); + clus->setIT(itSum / adcSum); + clus->setSDLayer(sqrt(sigmaLayer / nHits)); + clus->setSDIPhi(sqrt(sigmaIPhi / nHits)); + clus->setSDIT(sqrt(sigmaIT / nHits)); + clus->setSDWeightedLayer(sqrt(sigmaWeightedLayer / adcSum)); + clus->setSDWeightedIPhi(sqrt(sigmaWeightedIPhi / adcSum)); + clus->setSDWeightedIT(sqrt(sigmaWeightedIT / adcSum)); + + if (my_data.doFitting) + { + pthread_mutex_lock(&mythreadlock); + my_data.hitHist = new TH3D(std::format("hitHist_event{}_side{}_sector{}_module{}_cluster{}", my_data.eventNum, (int) my_data.side, (int) my_data.sector, (int) my_data.module, (int) my_data.cluster_vector.size()).c_str(), ";layer;iphi;it", usedLayer.size() + 2, usedLayer[0] - 1.5, *usedLayer.rbegin() + 1.5, usedIPhi.size() + 2, usedIPhi[0] - 1.5, *usedIPhi.rbegin() + 1.5, usedIT.size() + 2, usedIT[0] - 1.5, *usedIT.rbegin() + 1.5); - sigmaLayer += pow(clus->getHitLayer(i) - meanLayer, 2); - sigmaIPhi += pow(clus->getHitIPhi(i) - meanIPhi, 2); - sigmaIT += pow(clus->getHitIT(i) - meanIT, 2); - - sigmaWeightedLayer += clus->getHitAdc(i) * pow(clus->getHitLayer(i) - (layerSum / adcSum), 2); - sigmaWeightedIPhi += clus->getHitAdc(i) * pow(clus->getHitIPhi(i) - (iphiSum / adcSum), 2); - sigmaWeightedIT += clus->getHitAdc(i) * pow(clus->getHitIT(i) - (itSum / adcSum), 2); - } + // TH3D *hitHist = new TH3D(Form("hitHist_event%d_side%d_sector%d_module%d_cluster%d",my_data.eventNum,(int)my_data.side,(int)my_data.sector,(int)my_data.module,(int)my_data.cluster_vector.size()),";layer;iphi;it",usedLayer.size()+2,usedLayer[0]-1.5,*usedLayer.rbegin()+1.5,usedIPhi.size()+2,usedIPhi[0]-1.5,*usedIPhi.rbegin()+1.5,usedIT.size()+2,usedIT[0]-1.5,*usedIT.rbegin()+1.5); - bool fitSuccess = false; - ROOT::Fit::Fitter *fit3D = new ROOT::Fit::Fitter; + for (int i = 0; i < (int) clus->getNhits(); i++) + { + LaserClusterHitInfo LCHI = clus->getHit(i); + uint8_t layer = TrkrDefs::getLayer(LCHI.hitsetkey); + uint16_t iphi = TpcDefs::getPad(LCHI.hitkey); + uint16_t it = TpcDefs::getTBin(LCHI.hitkey); + my_data.hitHist->Fill(layer, iphi, it, LCHI.adc); + } - if(my_data.doFitting) - { + bool fitSuccess = false; + ROOT::Fit::Fitter *fit3D = new ROOT::Fit::Fitter; double par_init[7] = { - maxAdc, - meanLayer, - meanIPhi, 0.75, - meanIT, 0.5, 1 - }; + maxAdc, + meanLayer, + meanIPhi, 0.75, + meanIT, 0.5, 1}; double satThreshold = 900.0; double sigma_ADC = 20.0; - auto nll = [&](const double* par) + auto nll = [&](const double *par) { double nll_val = 0.0; @@ -472,37 +638,37 @@ namespace int ny = my_data.hitHist->GetNbinsY(); int nz = my_data.hitHist->GetNbinsZ(); - double parLayer[2] = {1.0,par[1]}; - double parPhi[4] = {1.0,par[2],par[3]}; - double parTime[4] = {1.0,par[4],par[5],par[6]}; + double parLayer[2] = {1.0, par[1]}; + double parPhi[4] = {1.0, par[2], par[3]}; + double parTime[4] = {1.0, par[4], par[5], par[6]}; double xyz[3]; for (int i = 1; i <= nx; ++i) { - xyz[0] = my_data.hitHist->GetXaxis()->GetBinCenter(i); + xyz[0] = my_data.hitHist->GetXaxis()->GetBinCenter(i); for (int j = 1; j <= ny; ++j) { - xyz[1] = my_data.hitHist->GetYaxis()->GetBinCenter(j); + xyz[1] = my_data.hitHist->GetYaxis()->GetBinCenter(j); for (int k = 1; k <= nz; ++k) { xyz[2] = my_data.hitHist->GetZaxis()->GetBinCenter(k); double observed = my_data.hitHist->GetBinContent(i, j, k); - double expected = par[0]*layerFunction(&xyz[0], parLayer)*phiFunction(&xyz[1], parPhi)*timeFunction(&xyz[2], parTime); + double expected = par[0] * layerFunction(&xyz[0], parLayer) * phiFunction(&xyz[1], parPhi) * timeFunction(&xyz[2], parTime); - if(observed <= my_data.adc_threshold) + if (observed <= my_data.adc_threshold) { double arg = (expected - my_data.adc_threshold) / (sqrt(2.0) * sigma_ADC); double tail_prob = 0.5 * TMath::Erfc(arg); nll_val -= log(tail_prob + 1e-12); } - else if(observed < satThreshold) + else if (observed < satThreshold) { double resid = (observed - expected) / sigma_ADC; nll_val += 0.5 * (resid * resid + log(2 * TMath::Pi() * sigma_ADC * sigma_ADC)); } - else if(observed >= satThreshold) + else if (observed >= satThreshold) { double arg = (satThreshold - expected) / (sqrt(2.0) * sigma_ADC); double tail_prob = 0.5 * TMath::Erfc(arg); @@ -518,170 +684,97 @@ namespace fit3D->Config().ParSettings(0).SetName("amp"); fit3D->Config().ParSettings(0).SetStepSize(10); - fit3D->Config().ParSettings(0).SetLimits(0,5000); + fit3D->Config().ParSettings(0).SetLimits(0, 5000); fit3D->Config().ParSettings(1).SetName("mu_layer"); fit3D->Config().ParSettings(1).SetStepSize(0.1); - fit3D->Config().ParSettings(1).SetLimits(usedLayer[0],*usedLayer.rbegin()); + fit3D->Config().ParSettings(1).SetLimits(usedLayer[0], *usedLayer.rbegin()); fit3D->Config().ParSettings(2).SetName("mu_phi"); fit3D->Config().ParSettings(2).SetStepSize(0.1); - fit3D->Config().ParSettings(2).SetLimits(usedIPhi[0],*usedIPhi.rbegin()); + fit3D->Config().ParSettings(2).SetLimits(usedIPhi[0], *usedIPhi.rbegin()); fit3D->Config().ParSettings(3).SetName("sig_phi"); fit3D->Config().ParSettings(3).SetStepSize(0.1); - fit3D->Config().ParSettings(3).SetLimits(0.01,2); + fit3D->Config().ParSettings(3).SetLimits(0.01, 2); fit3D->Config().ParSettings(4).SetName("mu_t"); fit3D->Config().ParSettings(4).SetStepSize(0.1); - fit3D->Config().ParSettings(4).SetLimits(usedIT[0],*usedIT.rbegin()); + fit3D->Config().ParSettings(4).SetLimits(usedIT[0], *usedIT.rbegin()); fit3D->Config().ParSettings(5).SetName("sig_t"); fit3D->Config().ParSettings(5).SetStepSize(0.1); - fit3D->Config().ParSettings(5).SetLimits(0.01,10); + fit3D->Config().ParSettings(5).SetLimits(0.01, 10); fit3D->Config().ParSettings(6).SetName("lambda_t"); fit3D->Config().ParSettings(6).SetStepSize(0.01); - fit3D->Config().ParSettings(6).SetLimits(0,5); + fit3D->Config().ParSettings(6).SetLimits(0, 5); - - if(usedLayer.size() == 1) + if (usedLayer.size() == 1) { fit3D->Config().ParSettings(1).Fix(); } fitSuccess = fit3D->FitFCN(); - if (my_data.Verbosity > 2) { std::cout << "fit success: " << fitSuccess << std::endl; } - } - pthread_mutex_unlock(&mythreadlock); - - - - if(my_data.doFitting && fitSuccess) - { - - const ROOT::Fit::FitResult& result = fit3D->Result(); - - - PHG4TpcGeom *layergeomLow = my_data.geom_container->GetLayerCellGeom((int) floor(result.Parameter(1))); - PHG4TpcGeom *layergeomHigh = my_data.geom_container->GetLayerCellGeom((int) ceil(result.Parameter(1))); - - double RLow = layergeomLow->get_radius(); - double RHigh = layergeomHigh->get_radius(); - - double phiHigh_RLow = -999.0; - if(ceil(result.Parameter(2)) < layergeomLow->get_phibins()) - { - phiHigh_RLow = layergeomLow->get_phi(ceil(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); - } - double phiHigh_RHigh = -999.0; - if(ceil(result.Parameter(2)) < layergeomHigh->get_phibins()) + + if (fitSuccess) { - phiHigh_RHigh = layergeomHigh->get_phi(ceil(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); - } + const ROOT::Fit::FitResult &result = fit3D->Result(); - double phiLow_RLow = layergeomLow->get_phi(floor(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); - double phiLow_RHigh = layergeomHigh->get_phi(floor(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); + PHG4TpcGeom *layergeomLow = my_data.geom_container->GetLayerCellGeom((int) floor(result.Parameter(1))); + PHG4TpcGeom *layergeomHigh = my_data.geom_container->GetLayerCellGeom((int) ceil(result.Parameter(1))); - double meanR = (result.Parameter(1) - floor(result.Parameter(1))) * (RHigh - RLow) + RLow; + //double RLow = layergeomLow->get_radius(); + //double RHigh = layergeomHigh->get_radius(); - double meanPhi_RLow = ((result.Parameter(2) - floor(result.Parameter(2)))) * (phiHigh_RLow - phiLow_RLow) + phiLow_RLow; - double meanPhi_RHigh = ((result.Parameter(2) - floor(result.Parameter(2)))) * (phiHigh_RHigh - phiLow_RHigh) + phiLow_RHigh; + double phiHigh_RLow = -999.0; + if (ceil(result.Parameter(2)) < layergeomLow->get_phibins()) + { + phiHigh_RLow = layergeomLow->get_phi(ceil(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); + } + double phiHigh_RHigh = -999.0; + if (ceil(result.Parameter(2)) < layergeomHigh->get_phibins()) + { + phiHigh_RHigh = layergeomHigh->get_phi(ceil(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); + } - double meanPhi = 0.5*(meanPhi_RLow + meanPhi_RHigh); - if(phiHigh_RLow == -999.0 && phiHigh_RHigh != -999.0) - { - meanPhi = meanPhi_RHigh; - } - else if(phiHigh_RLow != -999.0 && phiHigh_RHigh == -999.0) - { - meanPhi = meanPhi_RLow; + //double phiLow_RLow = layergeomLow->get_phi(floor(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); + //double phiLow_RHigh = layergeomHigh->get_phi(floor(result.Parameter(2)), (meanSide < 0 ? 0 : 1)); + + if (phiHigh_RLow == -999.0 && phiHigh_RHigh == -999.0) + { + clus->setFitMode(false); + } + else + { + clus->setFitMode(true); + clus->setLayer(result.Parameter(1)); + clus->setIPhi(result.Parameter(2)); + clus->setIT(result.Parameter(4)); + clus->setSDWeightedLayer(sqrt(sigmaWeightedLayer / adcSum)); + clus->setSDWeightedIPhi(result.Parameter(3)); + clus->setSDWeightedIT(result.Parameter(5)); + } } - - if(phiHigh_RLow == -999.0 && phiHigh_RHigh == -999.0) + delete fit3D; + if (my_data.hitHist) { - clus->setAdc(adcSum); - clus->setX(clusX); - clus->setY(clusY); - clus->setZ(clusZ); - clus->setFitMode(false); - clus->setLayer(layerSum / adcSum); - clus->setIPhi(iphiSum / adcSum); - clus->setIT(itSum / adcSum); - clus->setNLayers(usedLayer.size()); - clus->setNIPhi(usedIPhi.size()); - clus->setNIT(usedIT.size()); - clus->setSDLayer(sqrt(sigmaLayer / nHits)); - clus->setSDIPhi(sqrt(sigmaIPhi / nHits)); - clus->setSDIT(sqrt(sigmaIT / nHits)); - clus->setSDWeightedLayer(sqrt(sigmaWeightedLayer / adcSum)); - clus->setSDWeightedIPhi(sqrt(sigmaWeightedIPhi / adcSum)); - clus->setSDWeightedIT(sqrt(sigmaWeightedIT / adcSum)); + delete my_data.hitHist; + my_data.hitHist = nullptr; } - else - { - clus->setAdc(adcSum); - clus->setX(meanR*cos(meanPhi)); - clus->setY(meanR*sin(meanPhi)); - clus->setZ(clusZ); - clus->setFitMode(true); - clus->setLayer(result.Parameter(1)); - clus->setIPhi(result.Parameter(2)); - clus->setIT(result.Parameter(4)); - clus->setNLayers(usedLayer.size()); - clus->setNIPhi(usedIPhi.size()); - clus->setNIT(usedIT.size()); - clus->setSDLayer(sqrt(sigmaLayer / nHits)); - clus->setSDIPhi(sqrt(sigmaIPhi / nHits)); - clus->setSDIT(sqrt(sigmaIT / nHits)); - clus->setSDWeightedLayer(sqrt(sigmaWeightedLayer / adcSum)); - clus->setSDWeightedIPhi(result.Parameter(3)); - clus->setSDWeightedIT(result.Parameter(5)); - } - } - else - { - clus->setAdc(adcSum); - clus->setX(clusX); - clus->setY(clusY); - clus->setZ(clusZ); - clus->setFitMode(false); - clus->setLayer(layerSum / adcSum); - clus->setIPhi(iphiSum / adcSum); - clus->setIT(itSum / adcSum); - clus->setNLayers(usedLayer.size()); - clus->setNIPhi(usedIPhi.size()); - clus->setNIT(usedIT.size()); - clus->setSDLayer(sqrt(sigmaLayer / nHits)); - clus->setSDIPhi(sqrt(sigmaIPhi / nHits)); - clus->setSDIT(sqrt(sigmaIT / nHits)); - clus->setSDWeightedLayer(sqrt(sigmaWeightedLayer / adcSum)); - clus->setSDWeightedIPhi(sqrt(sigmaWeightedIPhi / adcSum)); - clus->setSDWeightedIT(sqrt(sigmaWeightedIT / adcSum)); + pthread_mutex_unlock(&mythreadlock); } - const auto ckey = TrkrDefs::genClusKey(maxKey, my_data.cluster_vector.size()); + pthread_mutex_lock(&mythreadlock); + const auto ckey = TrkrDefs::genClusKey(maxKey, my_data.cluster_vector.size()); my_data.cluster_vector.push_back(clus); my_data.cluster_key_vector.push_back(ckey); - - if(fit3D) - { - delete fit3D; - } - - if(my_data.hitHist) - { - delete my_data.hitHist; - my_data.hitHist = nullptr; - } - + pthread_mutex_unlock(&mythreadlock); } - void ProcessModuleData(thread_data *my_data) { - if (my_data->Verbosity > 2) { pthread_mutex_lock(&mythreadlock); @@ -693,85 +786,84 @@ namespace std::multimap adcMap; - if (my_data->hitsets.size() == 0) + if (my_data->hitsets.empty()) { return; } - for(int i=0; i<(int)my_data->hitsets.size(); i++) + for (int i = 0; i < (int) my_data->hitsets.size(); i++) { auto *hitset = my_data->hitsets[i]; unsigned int layer = my_data->layers[i]; bool side = my_data->side; unsigned int sector = my_data->sector; - TrkrDefs::hitsetkey hitsetKey = TpcDefs::genHitSetKey(layer, sector, (int)side); + TrkrDefs::hitsetkey hitsetKey = TpcDefs::genHitSetKey(layer, sector, (int) side); TrkrHitSet::ConstRange hitrangei = hitset->getHits(); for (TrkrHitSet::ConstIterator hitr = hitrangei.first; hitr != hitrangei.second; ++hitr) { - float_t fadc = hitr->second->getAdc(); - unsigned short adc = 0; - if (fadc > my_data->adc_threshold) - { - adc = (unsigned short) fadc; - } - else - { - continue; - } - - int iphi = TpcDefs::getPad(hitr->first); - int it = TpcDefs::getTBin(hitr->first); - - if(fabs(it - my_data->peakTimeBin) > 5) - { - continue; - } - - point coords = point((int) layer, iphi, it); - - std::vector testduplicate; - rtree.query(bgi::intersects(box(point(layer - 0.001, iphi - 0.001, it - 0.001), - point(layer + 0.001, iphi + 0.001, it + 0.001))), - std::back_inserter(testduplicate)); - if (!testduplicate.empty()) - { - testduplicate.clear(); - continue; - } - - TrkrDefs::hitkey hitKey = TpcDefs::genHitKey(iphi, it); - - auto spechitkey = std::make_pair(hitKey, hitsetKey); - pointKeyLaser coordsKey = std::make_pair(coords, spechitkey); - adcMap.insert(std::make_pair(adc, coordsKey)); + double_t fadc = hitr->second->getAdc(); + unsigned short adc = 0; + if (fadc > my_data->adc_threshold) + { + adc = (unsigned short) fadc; + } + else + { + continue; + } + + int iphi = TpcDefs::getPad(hitr->first); + int it = TpcDefs::getTBin(hitr->first); + + if (fabs(it - my_data->peakTimeBin) > 5) + { + continue; + } + + point coords = point((int) layer, iphi, it); + + std::vector testduplicate; + rtree.query(bgi::intersects(box(point(layer - 0.001, iphi - 0.001, it - 0.001), + point(layer + 0.001, iphi + 0.001, it + 0.001))), + std::back_inserter(testduplicate)); + if (!testduplicate.empty()) + { + testduplicate.clear(); + continue; + } + + TrkrDefs::hitkey hitKey = TpcDefs::genHitKey(iphi, it); + + auto spechitkey = std::make_pair(hitKey, hitsetKey); + pointKeyLaser coordsKey = std::make_pair(coords, spechitkey); + adcMap.insert(std::make_pair(adc, coordsKey)); auto adckey = std::make_pair(adc, spechitkey); - rtree.insert(std::make_pair(point(1.0*layer, 1.0*iphi, 1.0*it), adckey)); + rtree.insert(std::make_pair(point(1.0 * layer, 1.0 * iphi, 1.0 * it), adckey)); } } - //finished filling rtree + // finished filling rtree - while (adcMap.size() > 0) + while (!adcMap.empty()) { auto iterKey = adcMap.rbegin(); - if(iterKey == adcMap.rend()) + if (iterKey == adcMap.rend()) { - break; + break; } - auto coords = iterKey->second.first; int layer = coords.get<0>(); int iphi = coords.get<1>(); int it = coords.get<2>(); - + if (my_data->Verbosity > 2) { pthread_mutex_lock(&mythreadlock); - std::cout << "working on cluster " << my_data->cluster_vector.size() << " side: " << my_data->side << " sector: " << my_data->sector << " module: " << (layer<23 ? 1 : (layer<39 ? 2 : 3) ) << std::endl; + // NOLINTNEXTLINE (readability-avoid-nested-conditional-operator) + std::cout << "working on cluster " << my_data->cluster_vector.size() << " side: " << my_data->side << " sector: " << my_data->sector << " module: " << (layer < 23 ? 1 : (layer < 39 ? 2 : 3)) << std::endl; pthread_mutex_unlock(&mythreadlock); - } std::vector clusHits; @@ -781,17 +873,16 @@ namespace calc_cluster_parameter(clusHits, *my_data, iterKey->second.second); remove_hits(clusHits, rtree, adcMap); - } } void *ProcessModule(void *threadarg) { - auto my_data = static_cast(threadarg); + auto *my_data = static_cast(threadarg); ProcessModuleData(my_data); pthread_exit(nullptr); } -} //namespace +} // namespace LaserClusterizer::LaserClusterizer(const std::string &name) : SubsysReco(name) @@ -818,7 +909,7 @@ int LaserClusterizer::InitRun(PHCompositeNode *topNode) { laserClusterNodeName = "LAMINATION_CLUSTER"; } - auto laserclusters = findNode::getClass(dstNode, laserClusterNodeName); + auto *laserclusters = findNode::getClass(dstNode, laserClusterNodeName); if (!laserclusters) { PHNodeIterator dstiter(dstNode); @@ -835,7 +926,7 @@ int LaserClusterizer::InitRun(PHCompositeNode *topNode) new PHIODataNode(laserclusters, laserClusterNodeName, "PHObject"); DetNode->addNode(LaserClusterContainerNode); } - + m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); if (!m_geom_container) @@ -846,6 +937,7 @@ int LaserClusterizer::InitRun(PHCompositeNode *topNode) // get the first layer to get the clock freq AdcClockPeriod = m_geom_container->GetFirstLayerCellGeom()->get_zstep(); m_tdriftmax = AdcClockPeriod * NZBinsSide; + return Fun4AllReturnCodes::EVENT_OK; } @@ -873,7 +965,7 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - if((eventHeader->get_RunNumber() > 66153 && !m_laserEventInfo->isGl1LaserEvent()) || (eventHeader->get_RunNumber() <= 66153 && !m_laserEventInfo->isLaserEvent())) + if ((eventHeader->get_RunNumber() > 66153 && !m_laserEventInfo->isGl1LaserEvent()) || (eventHeader->get_RunNumber() <= 66153 && !m_laserEventInfo->isLaserEvent())) { return Fun4AllReturnCodes::EVENT_OK; } @@ -897,7 +989,7 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - + // get node for clusters std::string laserClusterNodeName = "LASER_CLUSTER"; if (m_lamination) @@ -921,8 +1013,8 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - TrkrHitSetContainer::ConstRange hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::tpcId);; - + TrkrHitSetContainer::ConstRange hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::tpcId); + struct thread_pair_t { pthread_t thread{}; @@ -938,123 +1030,122 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) if (pthread_mutex_init(&mythreadlock, nullptr) != 0) { - std::cout << std::endl << " mutex init failed" << std::endl; + std::cout << std::endl + << " mutex init failed" << std::endl; return 1; } - - for (unsigned int sec=0; sec<12; sec++) + + for (unsigned int sec = 0; sec < 12; sec++) { - for (int s=0; s<2; s++) + for (int s = 0; s < 2; s++) { - for (unsigned int mod=0; mod<3; mod++) + for (unsigned int mod = 0; mod < 3; mod++) { - - if(Verbosity() > 2) + if (Verbosity() > 2) { std::cout << "making thread for side: " << s << " sector: " << sec << " module: " << mod << std::endl; } - thread_pair_t &thread_pair = threads.emplace_back(); - - std::vector hitsets; - std::vector layers; - - std::vector cluster_vector; - std::vector cluster_key_vector; - - for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; - hitsetitr != hitsetrange.second; - ++hitsetitr) - { - unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); - int side = TpcDefs::getSide(hitsetitr->first); - unsigned int sector = TpcDefs::getSectorId(hitsetitr->first); - if (sector != sec || side != s) - { - continue; - } - if ((mod==0 && (layer<7 || layer>22)) || (mod==1 && (layer<=22 || layer>38) ) || (mod==2 && (layer<=38 || layer>54))) - { - continue; - } - - TrkrHitSet *hitset = hitsetitr->second; - - hitsets.push_back(hitset); - layers.push_back(layer); - - } - - thread_pair.data.geom_container = m_geom_container; - thread_pair.data.tGeometry = m_tGeometry; - thread_pair.data.hitsets = hitsets; - thread_pair.data.layers = layers; - thread_pair.data.side = (bool)s; - thread_pair.data.sector = sec; + thread_pair_t &thread_pair = threads.emplace_back(); + + std::vector hitsets; + std::vector layers; + + std::vector cluster_vector; + std::vector cluster_key_vector; + + for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; + hitsetitr != hitsetrange.second; + ++hitsetitr) + { + unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); + int side = TpcDefs::getSide(hitsetitr->first); + unsigned int sector = TpcDefs::getSectorId(hitsetitr->first); + if (sector != sec || side != s) + { + continue; + } + if ((mod == 0 && (layer < 7 || layer > 22)) || (mod == 1 && (layer <= 22 || layer > 38)) || (mod == 2 && (layer <= 38 || layer > 54))) + { + continue; + } + + TrkrHitSet *hitset = hitsetitr->second; + + hitsets.push_back(hitset); + layers.push_back(layer); + } + + thread_pair.data.geom_container = m_geom_container; + thread_pair.data.tGeometry = m_tGeometry; + thread_pair.data.hitsets = hitsets; + thread_pair.data.layers = layers; + thread_pair.data.side = (bool) s; + thread_pair.data.sector = sec; thread_pair.data.module = mod; - thread_pair.data.cluster_vector = cluster_vector; - thread_pair.data.cluster_key_vector = cluster_key_vector; - thread_pair.data.adc_threshold = m_adc_threshold; - thread_pair.data.peakTimeBin = m_laserEventInfo->getPeakSample(s); - thread_pair.data.layerMin = 3; - thread_pair.data.layerMax = 3; - thread_pair.data.tdriftmax = m_tdriftmax; + thread_pair.data.cluster_vector = cluster_vector; + thread_pair.data.cluster_key_vector = cluster_key_vector; + thread_pair.data.adc_threshold = m_adc_threshold; + thread_pair.data.peakTimeBin = m_laserEventInfo->getPeakSample(s); + thread_pair.data.layerMin = 3; + thread_pair.data.layerMax = 3; + thread_pair.data.tdriftmax = m_tdriftmax; thread_pair.data.eventNum = m_event; thread_pair.data.Verbosity = Verbosity(); thread_pair.data.hitHist = nullptr; thread_pair.data.doFitting = m_do_fitting; - int rc; - rc = pthread_create(&thread_pair.thread, &attr, ProcessModule, (void *) &thread_pair.data); - - if (rc) - { - std::cout << "Error:unable to create thread," << rc << std::endl; - } - - if (m_do_sequential) - { - //wait for termination of thread - int rc2 = pthread_join(thread_pair.thread, nullptr); - if (rc2) - { - std::cout << "Error:unable to join," << rc2 << std::endl; - } - - //add clusters from thread to laserClusterContainer - const auto &data(thread_pair.data); - for(int index = 0; index < (int) data.cluster_vector.size(); ++index) - { - auto cluster = data.cluster_vector[index]; - const auto ckey = data.cluster_key_vector[index]; - - m_clusterlist->addClusterSpecifyKey(ckey, cluster); - } - } + int rc; + rc = pthread_create(&thread_pair.thread, &attr, ProcessModule, (void *) &thread_pair.data); + + if (rc) + { + std::cout << "Error:unable to create thread," << rc << std::endl; + } + + if (m_do_sequential) + { + // wait for termination of thread + int rc2 = pthread_join(thread_pair.thread, nullptr); + if (rc2) + { + std::cout << "Error:unable to join," << rc2 << std::endl; + } + + // add clusters from thread to laserClusterContainer + const auto &data(thread_pair.data); + for (int index = 0; index < (int) data.cluster_vector.size(); ++index) + { + auto *cluster = data.cluster_vector[index]; + const auto ckey = data.cluster_key_vector[index]; + + m_clusterlist->addClusterSpecifyKey(ckey, cluster); + } + } } } } - + pthread_attr_destroy(&attr); if (!m_do_sequential) { - for (const auto & thread_pair : threads) + for (const auto &thread_pair : threads) { int rc2 = pthread_join(thread_pair.thread, nullptr); if (rc2) { - std::cout << "Error:unable to join," << rc2 << std::endl; + std::cout << "Error:unable to join," << rc2 << std::endl; } - - //const auto &data(thread_pair.data); - - for(int index = 0; index < (int) thread_pair.data.cluster_vector.size(); ++index) + + // const auto &data(thread_pair.data); + + for (int index = 0; index < (int) thread_pair.data.cluster_vector.size(); ++index) { - auto cluster = thread_pair.data.cluster_vector[index]; - const auto ckey = thread_pair.data.cluster_key_vector[index]; - - m_clusterlist->addClusterSpecifyKey(ckey, cluster); + auto *cluster = thread_pair.data.cluster_vector[index]; + const auto ckey = thread_pair.data.cluster_key_vector[index]; + + m_clusterlist->addClusterSpecifyKey(ckey, cluster); } } } @@ -1067,5 +1158,4 @@ int LaserClusterizer::process_event(PHCompositeNode *topNode) } return Fun4AllReturnCodes::EVENT_OK; - } diff --git a/offline/packages/tpc/LaserClusterizer.h b/offline/packages/tpc/LaserClusterizer.h index 8dc501a64f..28e4aaac73 100644 --- a/offline/packages/tpc/LaserClusterizer.h +++ b/offline/packages/tpc/LaserClusterizer.h @@ -40,9 +40,9 @@ class LaserClusterizer : public SubsysReco //void calc_cluster_parameter(std::vector &clusHits, std::multimap, std::array>> &adcMap, bool isLamination); //void remove_hits(std::vector &clusHits, boost::geometry::index::rtree> &rtree, std::multimap, std::array>> &adcMap); - void set_adc_threshold(float val) { m_adc_threshold = val; } - void set_min_clus_size(float val) { min_clus_size = val; } - void set_min_adc_sum(float val) { min_adc_sum = val; } + void set_adc_threshold(double val) { m_adc_threshold = val; } + void set_min_clus_size(double val) { min_clus_size = val; } + void set_min_adc_sum(double val) { min_adc_sum = val; } void set_max_time_samples(int val) { m_time_samples_max = val; } void set_lamination(bool val) { m_lamination = val; } void set_do_sequential(bool val) { m_do_sequential = val; } diff --git a/offline/packages/tpc/LaserEventIdentifier.cc b/offline/packages/tpc/LaserEventIdentifier.cc index 8b6035db05..3c214161ae 100644 --- a/offline/packages/tpc/LaserEventIdentifier.cc +++ b/offline/packages/tpc/LaserEventIdentifier.cc @@ -89,7 +89,7 @@ int LaserEventIdentifier::InitRun(PHCompositeNode *topNode) { m_debugFile = new TFile(m_debugFileName.c_str(), "RECREATE"); } - float timeHistMax = m_time_samples_max; + double timeHistMax = m_time_samples_max; timeHistMax -= 0.5; m_itHist_0 = new TH1I("m_itHist_0", "side 0;it", m_time_samples_max, -0.5, timeHistMax); m_itHist_1 = new TH1I("m_itHist_1", "side 1;it", m_time_samples_max, -0.5, timeHistMax); @@ -130,7 +130,7 @@ int LaserEventIdentifier::process_event(PHCompositeNode *topNode) } else if(m_runnumber > 66153) { - if ((gl1pkt->getGTMAllBusyVector() & (1<<14)) == 0) + if ((gl1pkt->getGTMAllBusyVector() & (1U<<14U)) == 0) { m_laserEventInfo->setIsGl1LaserEvent(true); m_laserEventInfo->setIsGl1LaserPileupEvent(false); diff --git a/offline/packages/tpc/LaserEventIdentifier.h b/offline/packages/tpc/LaserEventIdentifier.h index 5c0c5faf54..fa4f43733f 100644 --- a/offline/packages/tpc/LaserEventIdentifier.h +++ b/offline/packages/tpc/LaserEventIdentifier.h @@ -53,8 +53,8 @@ class LaserEventIdentifier : public SubsysReco bool isGl1LaserPileupEvent = false; int peakSample0 = -999; int peakSample1 = -999; - float peakWidth0 = -999; - float peakWidth1 = -999; + double peakWidth0 = -999; + double peakWidth1 = -999; int m_runnumber = 0; uint64_t prev_BCO = 0; diff --git a/offline/packages/tpc/Makefile.am b/offline/packages/tpc/Makefile.am index a2bd71c1cf..f67554f630 100644 --- a/offline/packages/tpc/Makefile.am +++ b/offline/packages/tpc/Makefile.am @@ -35,12 +35,14 @@ lib_LTLIBRARIES = \ libtpc.la pkginclude_HEADERS = \ + LaserClusterHelper.h \ LaserClusterizer.h \ LaserEventInfo.h \ LaserEventInfov1.h \ LaserEventInfov2.h \ LaserEventIdentifier.h \ LaserEventRejecter.h \ + DiffuseLaserEventSelector.h \ TrainingHitsContainer.h \ TrainingHits.h \ Tpc3DClusterizer.h \ @@ -75,10 +77,12 @@ dist_mydata_DATA = \ # sources for tpc library libtpc_la_SOURCES = \ + LaserClusterHelper.cc \ LaserClusterizer.cc \ LaserEventInfov1.cc \ LaserEventInfov2.cc \ LaserEventIdentifier.cc \ + DiffuseLaserEventSelector.cc \ LaserEventRejecter.cc \ TpcRawDataTree.cc \ Tpc3DClusterizer.cc \ @@ -86,6 +90,7 @@ libtpc_la_SOURCES = \ TpcClusterizer.cc \ TpcCombinedRawDataUnpacker.cc \ TpcCombinedRawDataUnpackerDebug.cc \ + TpcDistortionCorrectionContainer.cc \ TpcGlobalPositionWrapper.cc \ TpcLoadDistortionCorrection.cc \ TpcMap.cc \ diff --git a/offline/packages/tpc/Tpc3DClusterizer.cc b/offline/packages/tpc/Tpc3DClusterizer.cc index e19cbf507f..71a0b0f7c0 100644 --- a/offline/packages/tpc/Tpc3DClusterizer.cc +++ b/offline/packages/tpc/Tpc3DClusterizer.cc @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -49,7 +50,7 @@ namespace bg = boost::geometry; namespace bgi = boost::geometry::index; -using point = bg::model::point; +using point = bg::model::point; using box = bg::model::box; using specHitKey = std::pair; using pointKeyLaser = std::pair; @@ -72,7 +73,7 @@ int Tpc3DClusterizer::InitRun(PHCompositeNode *topNode) } // Create the Cluster node if required - auto laserclusters = findNode::getClass(dstNode, "LASER_CLUSTER"); + auto *laserclusters = findNode::getClass(dstNode, "LASER_CLUSTER"); if (!laserclusters) { PHNodeIterator dstiter(dstNode); @@ -111,13 +112,14 @@ int Tpc3DClusterizer::InitRun(PHCompositeNode *topNode) m_clusterTree->Branch("time_erase", &time_erase); m_clusterTree->Branch("time_all", &time_all); } - - if (m_output){ + + if (m_output) + { m_outputFile = new TFile(m_outputFileName.c_str(), "RECREATE"); - m_clusterNT = new TNtuple("clus3D", "clus3D","event:seed:x:y:z:r:phi:phibin:tbin:adc:maxadc:layer:phielem:zelem:size:phisize:tsize:lsize"); + m_clusterNT = new TNtuple("clus3D", "clus3D", "event:seed:x:y:z:r:phi:phibin:tbin:adc:maxadc:layer:phielem:zelem:size:phisize:tsize:lsize"); } - + m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); if (!m_geom_container) @@ -145,10 +147,13 @@ int Tpc3DClusterizer::InitRun(PHCompositeNode *topNode) int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) { ++m_event; - recoConsts* rc = recoConsts::instance(); - if (rc->FlagExist("RANDOMSEED")){ - m_seed = (int)rc->get_IntFlag("RANDOMSEED"); - } else { + recoConsts *rc = recoConsts::instance(); + if (rc->FlagExist("RANDOMSEED")) + { + m_seed = rc->get_IntFlag("RANDOMSEED"); + } + else + { m_seed = std::numeric_limits::quiet_NaN(); } @@ -163,11 +168,12 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) } // get node containing the digitized hits m_hits = findNode::getClass(topNode, "TRKR_HITSET"); - if (!m_hits){ + if (!m_hits) + { std::cout << PHWHERE << "ERROR: Can't find node TRKR_HITSET" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - + // get node for clusters m_clusterlist = findNode::getClass(topNode, "LASER_CLUSTER"); if (!m_clusterlist) @@ -193,7 +199,8 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) bgi::rtree> rtree_reject; for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; - ++hitsetitr){ + ++hitsetitr) + { TrkrHitSet *hitset = hitsetitr->second; unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); int side = TpcDefs::getSide(hitsetitr->first); @@ -202,49 +209,54 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) TrkrHitSet::ConstRange hitrangei = hitset->getHits(); for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr){ + hitr != hitrangei.second; + ++hitr) + { int iphi = TpcDefs::getPad(hitr->first); int it = TpcDefs::getTBin(hitr->first); // std::cout << " iphi: " << iphi << " it: " << it << std::endl; - float_t fadc = (hitr->second->getAdc());// - m_pedestal; // proper int rounding +0.5 + double_t fadc = (hitr->second->getAdc()); // - m_pedestal; // proper int rounding +0.5 unsigned short adc = 0; - if (fadc > 0){ - adc = (unsigned short) fadc; + if (fadc > 0) + { + adc = (unsigned short) fadc; } - if (adc <= 0){ - continue; + if (adc <= 0) + { + continue; } - + std::vector testduplicate; rtree.query(bgi::intersects(box(point(layer - 0.001, iphi - 0.001, it - 0.001), - point(layer + 0.001, iphi + 0.001, it + 0.001))), - std::back_inserter(testduplicate)); - if (!testduplicate.empty()){ - testduplicate.clear(); - continue; + point(layer + 0.001, iphi + 0.001, it + 0.001))), + std::back_inserter(testduplicate)); + if (!testduplicate.empty()) + { + testduplicate.clear(); + continue; } TrkrDefs::hitkey hitKey = TpcDefs::genHitKey(iphi, it); - + auto spechitkey = std::make_pair(hitKey, hitsetKey); rtree_reject.insert(std::make_pair(point(1.0 * layer, 1.0 * iphi, 1.0 * it), spechitkey)); } } - + std::multimap, std::array>> adcMap; // std::cout << "n hitsets: " << std::distance(hitsetrange.first,hitsetrange.second) // << std::endl; for (TrkrHitSetContainer::ConstIterator hitsetitr = hitsetrange.first; hitsetitr != hitsetrange.second; - ++hitsetitr){ + ++hitsetitr) + { TrkrHitSet *hitset = hitsetitr->second; unsigned int layer = TrkrDefs::getLayer(hitsetitr->first); int side = TpcDefs::getSide(hitsetitr->first); unsigned int sector = TpcDefs::getSectorId(hitsetitr->first); - //PHG4TpcGeom *layergeom = m_geom_container->GetLayerCellGeom(layer); - // double r = layergeom->get_radius(); - + // PHG4TpcGeom *layergeom = m_geom_container->GetLayerCellGeom(layer); + // double r = layergeom->get_radius(); + TrkrDefs::hitsetkey hitsetKey = TpcDefs::genHitSetKey(layer, sector, side); TrkrHitSet::ConstRange hitrangei = hitset->getHits(); @@ -252,74 +264,122 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) // << std::endl; // int nhits = 0; for (TrkrHitSet::ConstIterator hitr = hitrangei.first; - hitr != hitrangei.second; - ++hitr){ + hitr != hitrangei.second; + ++hitr) + { int iphi = TpcDefs::getPad(hitr->first); int it = TpcDefs::getTBin(hitr->first); // std::cout << " iphi: " << iphi << " it: " << it << std::endl; - float_t fadc = (hitr->second->getAdc());// - m_pedestal; // proper int rounding +0.5 + double_t fadc = (hitr->second->getAdc()); // - m_pedestal; // proper int rounding +0.5 unsigned short adc = 0; // std::cout << " nhit: " << nhits++ << "adc: " << fadc << " phi: " << iphi << " it: " << it << std::endl; - if (fadc > 0){ - adc = (unsigned short) fadc; + if (fadc > 0) + { + adc = (unsigned short) fadc; } - if (adc <= 0){ - continue; + if (adc <= 0) + { + continue; } - if(layer>=7+32){ - //if(side==1)continue; - if(abs(iphi-0)<=2) continue; - if(abs(iphi-191)<=2) continue; - if(abs(iphi-206)<=1) continue; - if(abs(iphi-383)<=2) continue; - if(abs(iphi-576)<=2) continue; - if(abs(iphi-767)<=2) continue; - if(abs(iphi-960)<=2) continue; - if(abs(iphi-1522)<=2) continue; - if(abs(iphi-1344)<=2) continue; - if(abs(iphi-1536)<=2) continue; - if(abs(iphi-1728)<=2) continue; - if(abs(iphi-1920)<=2) continue; - if(abs(iphi-2111)<=2) continue; - if(abs(iphi-2303)<=2) continue; + if (layer >= 7 + 32) + { + // if(side==1)continue; + if (abs(iphi - 0) <= 2) + { + continue; + } + if (abs(iphi - 191) <= 2) + { + continue; + } + if (abs(iphi - 206) <= 1) + { + continue; + } + if (abs(iphi - 383) <= 2) + { + continue; + } + if (abs(iphi - 576) <= 2) + { + continue; + } + if (abs(iphi - 767) <= 2) + { + continue; + } + if (abs(iphi - 960) <= 2) + { + continue; + } + if (abs(iphi - 1522) <= 2) + { + continue; + } + if (abs(iphi - 1344) <= 2) + { + continue; + } + if (abs(iphi - 1536) <= 2) + { + continue; + } + if (abs(iphi - 1728) <= 2) + { + continue; + } + if (abs(iphi - 1920) <= 2) + { + continue; + } + if (abs(iphi - 2111) <= 2) + { + continue; + } + if (abs(iphi - 2303) <= 2) + { + continue; + } } /* double phi = layergeom->get_phi(iphi); double m_sampa_tbias = 39.6; double zdriftlength = (layergeom->get_zcenter(it)+ m_sampa_tbias) * m_tGeometry->get_drift_velocity(); - - float x = r * cos(phi); - float y = r * sin(phi); - float z = m_tdriftmax * m_tGeometry->get_drift_velocity() - zdriftlength; + + double x = r * cos(phi); + double y = r * sin(phi); + double z = m_tdriftmax * m_tGeometry->get_drift_velocity() - zdriftlength; if (side == 0){ - z = -z; - it = -it; + z = -z; + it = -it; } */ std::array coords = {(int) layer, iphi, it}; - + std::vector testduplicate; rtree.query(bgi::intersects(box(point(layer - 0.001, iphi - 0.001, it - 0.001), - point(layer + 0.001, iphi + 0.001, it + 0.001))), - std::back_inserter(testduplicate)); - if (!testduplicate.empty()){ - testduplicate.clear(); - continue; + point(layer + 0.001, iphi + 0.001, it + 0.001))), + std::back_inserter(testduplicate)); + if (!testduplicate.empty()) + { + testduplicate.clear(); + continue; } - - //test for isolated hit + + // test for isolated hit std::vector testisolated; rtree_reject.query(bgi::intersects(box(point(layer - 1.001, iphi - 1.001, it - 1.001), - point(layer + 1.001, iphi + 1.001, it + 1.001))), - std::back_inserter(testisolated)); - if(testisolated.size()==1){ - //testisolated.clear(); - continue; + point(layer + 1.001, iphi + 1.001, it + 1.001))), + std::back_inserter(testisolated)); + if (testisolated.size() == 1) + { + // testisolated.clear(); + continue; } - + TrkrDefs::hitkey hitKey = TpcDefs::genHitKey(iphi, it); - + auto spechitkey = std::make_pair(hitKey, hitsetKey); auto keyCoords = std::make_pair(spechitkey, coords); adcMap.insert(std::make_pair(adc, keyCoords)); @@ -327,38 +387,43 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) rtree.insert(std::make_pair(point(1.0 * layer, 1.0 * iphi, 1.0 * it), spechitkey)); } } - - if (Verbosity() > 1){ + + if (Verbosity() > 1) + { std::cout << "finished looping over hits" << std::endl; std::cout << "map size: " << adcMap.size() << std::endl; std::cout << "rtree size: " << rtree.size() << std::endl; } - + // done filling rTree - + t_all->restart(); - - while (adcMap.size() > 0){ + + while (!adcMap.empty()) + { auto iterKey = adcMap.rbegin(); - if (iterKey == adcMap.rend()){ + if (iterKey == adcMap.rend()) + { break; } - + auto coords = iterKey->second.second; int layer = coords[0]; int iphi = coords[1]; int it = coords[2]; - + int layerMax = layer + 1; - if (layer == 22 || layer == 38 || layer == 54){ + if (layer == 22 || layer == 38 || layer == 54) + { layerMax = layer; } int layerMin = layer - 1; - if (layer == 7 || layer == 23 || layer == 39){ + if (layer == 7 || layer == 23 || layer == 39) + { layerMin = layer; } - + std::vector clusHits; t_search->restart(); @@ -376,21 +441,24 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) clusHits.clear(); } - if (m_debug){ + if (m_debug) + { m_nClus = (int) m_eventClusters.size(); } t_all->stop(); - if (m_debug){ + if (m_debug) + { time_search = t_search->get_accumulated_time() / 1000.; time_clus = t_clus->get_accumulated_time() / 1000.; time_erase = t_erase->get_accumulated_time() / 1000.; time_all = t_all->get_accumulated_time() / 1000.; - + m_clusterTree->Fill(); } - - if (Verbosity()){ + + if (Verbosity()) + { std::cout << "rtree search time: " << t_search->get_accumulated_time() / 1000. << " sec" << std::endl; std::cout << "clustering time: " << t_clus->get_accumulated_time() / 1000. << " sec" << std::endl; std::cout << "erasing time: " << t_erase->get_accumulated_time() / 1000. << " sec" << std::endl; @@ -401,30 +469,33 @@ int Tpc3DClusterizer::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } -int Tpc3DClusterizer::ResetEvent(PHCompositeNode * /*topNode*/){ +int Tpc3DClusterizer::ResetEvent(PHCompositeNode * /*topNode*/) +{ m_itHist_0->Reset(); m_itHist_1->Reset(); - + if (m_debug) - { - m_tHist_0->Reset(); - m_tHist_1->Reset(); - - m_eventClusters.clear(); - } - + { + m_tHist_0->Reset(); + m_tHist_1->Reset(); + + m_eventClusters.clear(); + } + return Fun4AllReturnCodes::EVENT_OK; } int Tpc3DClusterizer::End(PHCompositeNode * /*topNode*/) { - if (m_debug){ + if (m_debug) + { m_debugFile->cd(); m_clusterTree->Write(); m_debugFile->Close(); } - if (m_output){ + if (m_output) + { m_outputFile->cd(); m_clusterNT->Write(); m_outputFile->Close(); @@ -434,7 +505,7 @@ int Tpc3DClusterizer::End(PHCompositeNode * /*topNode*/) void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHits, std::multimap, std::array>> &adcMap) { - //std::cout << "nu clus" << std::endl; + // std::cout << "nu clus" << std::endl; double rSum = 0.0; double phiSum = 0.0; double tSum = 0.0; @@ -449,14 +520,17 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi TrkrDefs::hitsetkey maxKey = 0; unsigned int nHits = clusHits.size(); - int iphimin = 6666, iphimax = -1; - int ilaymin = 6666, ilaymax = -1; - float itmin = 66666666.6, itmax = -6666666666.6; + int iphimin = 6666; + int iphimax = -1; + int ilaymin = 6666; + int ilaymax = -1; + double itmin = 66666666.6; + double itmax = -6666666666.6; auto *clus = new LaserClusterv1; for (auto &clusHit : clusHits) { - float coords[3] = {clusHit.first.get<0>(), clusHit.first.get<1>(), clusHit.first.get<2>()}; + double coords[3] = {clusHit.first.get<0>(), clusHit.first.get<1>(), clusHit.first.get<2>()}; std::pair spechitkey = clusHit.second; int side = TpcDefs::getSide(spechitkey.second); @@ -468,21 +542,21 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi double phi = layergeom->get_phi(coords[1], side); double t = layergeom->get_zcenter(fabs(coords[2])); int tbin = coords[2]; - int lay = coords[0];//TrkrDefs::getLayer(spechitkey.second); + int lay = coords[0]; // TrkrDefs::getLayer(spechitkey.second); double hitzdriftlength = t * m_tGeometry->get_drift_velocity(); double hitZ = m_tdriftmax * m_tGeometry->get_drift_velocity() - hitzdriftlength; /*std::cout << " lay: " << lay - << " phi: " << phi - << " t: " << t - << " side: " << side - << std::endl; + << " phi: " << phi + << " t: " << t + << " side: " << side + << std::endl; */ - if(phiiphimax){iphimax = phi;} - if(layilaymax){ilaymax = lay;} - if(tbinitmax){itmax = tbin;} + iphimin = std::min(phi, iphimin); + iphimax = std::max(phi, iphimax); + ilaymin = std::min(lay, ilaymin); + ilaymax = std::max(lay, ilaymax); + itmin = std::min(tbin, itmin); + itmax = std::max(tbin, itmax); for (auto &iterKey : adcMap) { @@ -497,7 +571,7 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi clus->setHitX(clus->getNhits() - 1, r * cos(phi)); clus->setHitY(clus->getNhits() - 1, r * sin(phi)); clus->setHitZ(clus->getNhits() - 1, hitZ); - clus->setHitAdc(clus->getNhits() - 1, (float) adc); + clus->setHitAdc(clus->getNhits() - 1, adc); rSum += r * adc; phiSum += phi * adc; @@ -522,7 +596,7 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi if (nHits == 0) { - std::cout << "no hits"<< std::endl; + std::cout << "no hits" << std::endl; return; } @@ -554,55 +628,57 @@ void Tpc3DClusterizer::calc_cluster_parameter(std::vector &clusHi clus->setLayer(layerSum / adcSum); clus->setIPhi(iphiSum / adcSum); clus->setIT(itSum / adcSum); - int phisize = iphimax - iphimin + 1; - int lsize = ilaymax - ilaymin + 1; - int tsize = itmax - itmin +1; + int phisize = iphimax - iphimin + 1; + int lsize = ilaymax - ilaymin + 1; + int tsize = itmax - itmin + 1; if (m_debug) { m_currentCluster = (LaserCluster *) clus->CloneMe(); m_eventClusters.push_back((LaserCluster *) m_currentCluster->CloneMe()); } // if(nHits>1&&tsize>5){ - if(nHits>=1){ + if (nHits >= 1) + { const auto ckey = TrkrDefs::genClusKey(maxKey, m_clusterlist->size()); m_clusterlist->addClusterSpecifyKey(ckey, clus); - } else { + } + else + { delete clus; } - - //event:seed:x:y:z:r:phi:phibin:tbin::adc:maxadc:layer:phielem:zelem:size:phisize:tsize:lsize + // event:seed:x:y:z:r:phi:phibin:tbin::adc:maxadc:layer:phielem:zelem:size:phisize:tsize:lsize //"event:seed:x:y:z:r:phi:phibin:tbin::adc:maxadc:layer:phielem:zelem:size:phisize:tsize:lsize" /* std::cout << " l size: " << lsize - << " phisize : " << phisize - << " tsize: " << tsize - << " maxside: " << maxside - << std::endl; + << " phisize : " << phisize + << " tsize: " << tsize + << " maxside: " << maxside + << std::endl; */ // if (m_output){ - float fX[20] = {0}; - int n = 0; - fX[n++] = m_event; - fX[n++] = m_seed; - fX[n++] = clusX; - fX[n++] = clusY; - fX[n++] = clusZ; - fX[n++] = clusR; - fX[n++] = clusPhi; - fX[n++] = clusiPhi; - fX[n++] = clusT; - fX[n++] = adcSum; - fX[n++] = maxAdc; - fX[n++] = (layerSum/adcSum); - fX[n++] = maxsector; - fX[n++] = maxside; - fX[n++] = nHits; - fX[n++] = phisize; - fX[n++] = tsize; - fX[n++] = lsize; - m_clusterNT->Fill(fX); - // } + float fX[20] = {0}; + int n = 0; + fX[n++] = m_event; + fX[n++] = m_seed; + fX[n++] = clusX; + fX[n++] = clusY; + fX[n++] = clusZ; + fX[n++] = clusR; + fX[n++] = clusPhi; + fX[n++] = clusiPhi; + fX[n++] = clusT; + fX[n++] = adcSum; + fX[n++] = maxAdc; + fX[n++] = (layerSum / adcSum); + fX[n++] = maxsector; + fX[n++] = maxside; + fX[n++] = nHits; + fX[n++] = phisize; + fX[n++] = tsize; + fX[n++] = lsize; + m_clusterNT->Fill(fX); + // } } void Tpc3DClusterizer::remove_hits(std::vector &clusHits, bgi::rtree> &rtree, std::multimap, std::array>> &adcMap) @@ -611,10 +687,11 @@ void Tpc3DClusterizer::remove_hits(std::vector &clusHits, bgi::rt { auto spechitkey = clusHit.second; - if(rtree.size()==0){ + if (rtree.empty()) + { std::cout << "not good" << std::endl; } - //rtree.remove(clusHit); + // rtree.remove(clusHit); for (auto iterAdc = adcMap.begin(); iterAdc != adcMap.end();) { @@ -623,10 +700,8 @@ void Tpc3DClusterizer::remove_hits(std::vector &clusHits, bgi::rt iterAdc = adcMap.erase(iterAdc); break; } - else - { - ++iterAdc; - } + + ++iterAdc; } } } diff --git a/offline/packages/tpc/Tpc3DClusterizer.h b/offline/packages/tpc/Tpc3DClusterizer.h index 54175a3c9a..3e6ad621a9 100644 --- a/offline/packages/tpc/Tpc3DClusterizer.h +++ b/offline/packages/tpc/Tpc3DClusterizer.h @@ -34,7 +34,7 @@ class PHG4TpcGeomContainer; class Tpc3DClusterizer : public SubsysReco { public: -typedef boost::geometry::model::point point; +typedef boost::geometry::model::point point; typedef boost::geometry::model::box box; typedef std::pair specHitKey; typedef std::pair pointKeyLaser; @@ -49,7 +49,7 @@ typedef std::pair pointKeyLaser; // void calc_cluster_parameter(std::vector &clusHits, std::multimap> &adcMap); void calc_cluster_parameter(std::vector &clusHits, std::multimap, std::array>> &adcMap); - // void remove_hits(std::vector &clusHits, boost::geometry::index::rtree > &rtree, std::multimap > &adcMap, std::multimap &adcCoords); + // void remove_hits(std::vector &clusHits, boost::geometry::index::rtree > &rtree, std::multimap > &adcMap, std::multimap &adcCoords); void remove_hits(std::vector &clusHits, boost::geometry::index::rtree> &rtree, std::multimap, std::array>> &adcMap); void set_debug(bool debug) { m_debug = debug; } @@ -57,9 +57,9 @@ typedef std::pair pointKeyLaser; void set_output(bool output) { m_output = output; } void set_output_name(const std::string &name) { m_outputFileName = name; } - void set_pedestal(float val) { pedestal = val; } - void set_min_clus_size(float val) { min_clus_size = val; } - void set_min_adc_sum(float val) { min_adc_sum = val; } + void set_pedestal(double val) { pedestal = val; } + void set_min_clus_size(double val) { min_clus_size = val; } + void set_min_adc_sum(double val) { min_adc_sum = val; } private: int m_event {-1}; @@ -106,8 +106,8 @@ typedef std::pair pointKeyLaser; LaserCluster *m_currentCluster {nullptr}; std::vector m_eventClusters; - std::vector m_currentHit; - std::vector m_currentHit_hardware; + std::vector m_currentHit; + std::vector m_currentHit_hardware; std::unique_ptr t_all; std::unique_ptr t_search; diff --git a/offline/packages/tpc/TpcClusterMover.cc b/offline/packages/tpc/TpcClusterMover.cc index 643fe5587f..a7663349d5 100644 --- a/offline/packages/tpc/TpcClusterMover.cc +++ b/offline/packages/tpc/TpcClusterMover.cc @@ -17,19 +17,20 @@ namespace { - [[maybe_unused]] std::ostream& operator << (std::ostream& out, const Acts::Vector3& v ) + [[maybe_unused]] std::ostream& operator<<(std::ostream& out, const Acts::Vector3& v) { out << "(" << v.x() << ", " << v.y() << ", " << v.z() << ")"; return out; } -} +} // namespace TpcClusterMover::TpcClusterMover() + : inner_tpc_spacing((mid_tpc_min_radius - inner_tpc_min_radius) / 16.0) + , mid_tpc_spacing((outer_tpc_min_radius - mid_tpc_min_radius) / 16.0) + , outer_tpc_spacing((outer_tpc_max_radius - outer_tpc_min_radius) / 16.0) { // initialize layer radii - inner_tpc_spacing = (mid_tpc_min_radius - inner_tpc_min_radius) / 16.0; - mid_tpc_spacing = (outer_tpc_min_radius - mid_tpc_min_radius) / 16.0; - outer_tpc_spacing = (outer_tpc_max_radius - outer_tpc_min_radius) / 16.0; + for (int i = 0; i < 16; ++i) { layer_radius[i] = inner_tpc_min_radius + (double) i * inner_tpc_spacing + 0.5 * inner_tpc_spacing; @@ -44,13 +45,21 @@ TpcClusterMover::TpcClusterMover() } } -void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer *cellgeo) +void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer* cellgeo, ActsGeometry *tGeometry) { if (_verbosity > 0) { - std::cout << "TpcClusterMover: Initializing layer radii for Tpc from cell geometry object" << std::endl; + std::cout << "TpcClusterMover: Getting ActsGeometry, and getting layer radii for Tpc from cell geometry object" << std::endl; } + if(!tGeometry || !cellgeo) + { + std::cout << PHWHERE << " Failed to get ActsGeometry or TPC cell geometry, cannot continue - quit!" << std::endl; + exit(1); + } + + _tGeometry = tGeometry; + int layer = 0; PHG4TpcGeomContainer::ConstRange layerrange = cellgeo->get_begin_end(); for (PHG4TpcGeomContainer::ConstIterator layeriter = layerrange.first; @@ -65,27 +74,28 @@ void TpcClusterMover::initialize_geometry(PHG4TpcGeomContainer *cellgeo) //____________________________________________________________________________.. std::vector> TpcClusterMover::processTrack(const std::vector>& global_in) { - // Get the global positions of the TPC clusters for this track, already corrected for distortions, and move them to the surfaces - // The input object contains all clusters for the track - + // The input object contains all clusters for the track in world coordinates + // The surface radii are in envelope coordinates, we transform the positions to envelope coordinates + std::vector> global_moved; std::vector tpc_global_vec; std::vector tpc_cluskey_vec; - for (const auto& [ckey,global]:global_in) + for (const auto& [ckey, global] : global_in) { const auto trkrid = TrkrDefs::getTrkrId(ckey); if (trkrid == TrkrDefs::tpcId) { tpc_cluskey_vec.push_back(ckey); - tpc_global_vec.push_back(global); + Acts::Vector3 env_global = _tGeometry->transformTpcWorldToEnvelope(global); + tpc_global_vec.push_back(env_global); } else { // si clusters stay where they are - global_moved.emplace_back(ckey,global); + global_moved.emplace_back(ckey, global); } } @@ -140,9 +150,9 @@ std::vector> TpcClusterMover::proces // now move the cluster to the surface radius // we keep the cluster key fixed, change the surface if necessary - Acts::Vector3 global_new(xnew, ynew, znew); - - // add the new position and surface to the return object + Acts::Vector3 env_global_new(xnew, ynew, znew); + // now we transform back to global coordinates and add the new position and surface to the return object + Acts::Vector3 global_new = _tGeometry->transformTpcEnvelopeToWorld(env_global_new); global_moved.emplace_back(cluskey, global_new); if (_verbosity > 2) @@ -158,7 +168,7 @@ std::vector> TpcClusterMover::proces return global_moved; } -int TpcClusterMover::get_circle_circle_intersection(double target_radius, double R, double X0, double Y0, double xclus, double yclus, double &x, double &y) +int TpcClusterMover::get_circle_circle_intersection(double target_radius, double R, double X0, double Y0, double xclus, double yclus, double& x, double& y) const { // finds the intersection of the fitted circle with the cylinder having radius = target_radius const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(target_radius, R, X0, Y0); diff --git a/offline/packages/tpc/TpcClusterMover.h b/offline/packages/tpc/TpcClusterMover.h index dc67312f7f..7eaa0b3495 100644 --- a/offline/packages/tpc/TpcClusterMover.h +++ b/offline/packages/tpc/TpcClusterMover.h @@ -24,10 +24,10 @@ class TpcClusterMover //! Updates the assumed default geometry below to that contained in the //! cell geo - void initialize_geometry(PHG4TpcGeomContainer *cellgeo); + void initialize_geometry(PHG4TpcGeomContainer *cellgeo, ActsGeometry *tGeometry); private: - int get_circle_circle_intersection(double target_radius, double R, double X0, double Y0, double xclus, double yclus, double &x, double &y); + int get_circle_circle_intersection(double target_radius, double R, double X0, double Y0, double xclus, double yclus, double &x, double &y) const; double _z_start = 0.0; double _y_start = 0.0; @@ -48,6 +48,8 @@ class TpcClusterMover double outer_tpc_spacing = 0.0; int _verbosity = 0; + + ActsGeometry *_tGeometry = nullptr; }; #endif diff --git a/offline/packages/tpc/TpcClusterZCrossingCorrection.cc b/offline/packages/tpc/TpcClusterZCrossingCorrection.cc index 24c2552f55..dc4f8589fc 100644 --- a/offline/packages/tpc/TpcClusterZCrossingCorrection.cc +++ b/offline/packages/tpc/TpcClusterZCrossingCorrection.cc @@ -13,32 +13,32 @@ #include // default value, override from macro (cm/ns) -float TpcClusterZCrossingCorrection::_vdrift = 8.0e-03; +double TpcClusterZCrossingCorrection::_vdrift = 8.0e-03; // ns, same value as in pileup generator -float TpcClusterZCrossingCorrection::_time_between_crossings = sphenix_constants::time_between_crossings; +double TpcClusterZCrossingCorrection::_time_between_crossings = sphenix_constants::time_between_crossings; //______________________________________________________________________________________________ -float TpcClusterZCrossingCorrection::correctZ(float zinit, unsigned int side, short int crossing) +double TpcClusterZCrossingCorrection::correctZ(double zinit, unsigned int side, short int crossing) { if (crossing == std::numeric_limits::max()) { - return std::numeric_limits::quiet_NaN(); + return std::numeric_limits::quiet_NaN(); } - float z_bunch_separation = _time_between_crossings * _vdrift; + double z_bunch_separation = _time_between_crossings * _vdrift; // +ve crossing occurs in the future relative to time zero // -ve z side (south, side 0), cluster arrives late, so z seems more positive // +ve z side (north, side 1), cluster arrives late, so z seems more negative - float corrected_z; + double corrected_z; if (side == 0) { - corrected_z = zinit - (float) crossing * z_bunch_separation; + corrected_z = zinit - (double) crossing * z_bunch_separation; } else { - corrected_z = zinit + (float) crossing * z_bunch_separation; + corrected_z = zinit + (double) crossing * z_bunch_separation; } // std::cout << " TpcClusterZCrossingCorrection: crossing " << crossing << " _vdrift " << _vdrift << " zinit " << zinit << " side " << side << " z_bunch_separation " << z_bunch_separation << " corrected_z " << corrected_z << std::endl; diff --git a/offline/packages/tpc/TpcClusterZCrossingCorrection.h b/offline/packages/tpc/TpcClusterZCrossingCorrection.h index 5a95ca7f86..8321d31f7d 100644 --- a/offline/packages/tpc/TpcClusterZCrossingCorrection.h +++ b/offline/packages/tpc/TpcClusterZCrossingCorrection.h @@ -15,34 +15,34 @@ class TpcClusterZCrossingCorrection //@{ //! drift velocity (cm/ns) - static float get_vdrift() { return _vdrift; } + static double get_vdrift() { return _vdrift; } //! time between crossing (ns) - static float get_time_between_crossings() { return _time_between_crossings; } + static double get_time_between_crossings() { return _time_between_crossings; } //! apply correction on a given z - static float correctZ(float zinit, unsigned int side, short int crossing); + static double correctZ(double zinit, unsigned int side, short int crossing); //@} //!@name modifiers //@{ //! drift velocity (cm/ns) - static void set_vdrift( float value ) { _vdrift = value; } + static void set_vdrift( double value ) { _vdrift = value; } //! time between crossing (ns) - static void set_time_between_crossings( float value ) { _time_between_crossings = value; } + static void set_time_between_crossings( double value ) { _time_between_crossings = value; } //@} // TODO: move to private //!@name parameters //@{ //! drift velocity (cm/ns) - static float _vdrift; + static double _vdrift; private: //! time between crossing (ns) - static float _time_between_crossings; + static double _time_between_crossings; //@} diff --git a/offline/packages/tpc/TpcClusterizer.cc b/offline/packages/tpc/TpcClusterizer.cc index bd5fc3c340..abdf695404 100644 --- a/offline/packages/tpc/TpcClusterizer.cc +++ b/offline/packages/tpc/TpcClusterizer.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include // for hitkey, getLayer #include #include @@ -25,17 +26,20 @@ #include #include #include -#include #include #include // for SubsysReco -#include +//#include +#include #include #include #include +#include +#include + #include #include // for PHIODataNode #include // for PHNode @@ -50,6 +54,8 @@ #include +#include +#include #include #include // for sqrt, cos, sin #include @@ -58,13 +64,14 @@ #include #include // for pair #include +#include // Terra incognita.... #include namespace { template - inline constexpr T square(const T &x) + constexpr T square(const T &x) { return x * x; } @@ -79,6 +86,37 @@ namespace unsigned short edge = 0; }; + // NOLINTBEGIN(misc-non-private-member-variables-in-classes) + struct ClusterCounters + { + int overlap = 0; + + int nedge = 0; // Total No. of Edges + + int sledge = 0; // Touching Left Sector Edge + int sredge = 0; // Touching Right Sector Edge + + int tledge = 0; // Touching Left Time Edge + int tredge = 0; // Touching Right Time Edge + + int dledge = 0; // Touching Left Dead Edge + int dredge = 0; // Touching Right Dead Edge + + int hledge = 0; // Touching Left Hot Edge + int hredge = 0; // Touching Right Hot Edge + + int slmix = 0; // Touching Cluster at Left in Phibin + int srmix = 0; // Touching Cluster at Right in Phibin + + int tlmix = 0; // Touching Cluster at Left in Timebin + int trmix = 0; // Touching Cluster at Right in Timebin + + void clear() + { + *this = ClusterCounters{}; + } + }; + // NOLINTEND(misc-non-private-member-variables-in-classes) using vec_dVerbose = std::vector>>; // Neural network parameters and modules @@ -96,16 +134,16 @@ namespace unsigned int layer = 0; int side = 0; unsigned int sector = 0; - float radius = 0; - float drift_velocity = 0; + double radius = 0; + double drift_velocity = 0; unsigned short pads_per_sector = 0; - float phistep = 0; - float pedestal = 0; - float seed_threshold = 0; - float edge_threshold = 0; - float min_err_squared = 0; - float min_clus_size = 0; - float min_adc_sum = 0; + double phistep = 0; + double pedestal = 0; + double seed_threshold = 0; + double edge_threshold = 0; + double min_err_squared = 0; + double min_clus_size = 0; + double min_adc_sum = 0; bool do_assoc = true; bool do_wedge_emulation = true; bool do_singles = true; @@ -118,6 +156,14 @@ namespace unsigned short maxHalfSizeT = 0; unsigned short maxHalfSizePhi = 0; double m_tdriftmax = 0; + + // --- new members for dead/hot map --- + hitMaskTpcSet *deadMap = nullptr; + hitMaskTpcSet *hotMap = nullptr; + bool maskDead = false; + bool maskHot = false; + bool debug = false; + std::vector association_vector; std::vector cluster_vector; std::vector v_hits; @@ -164,13 +210,14 @@ namespace } } - void find_t_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &tdown, int &tup, int &touch, int &edge) + void find_t_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &tdown, int &tup, ClusterCounters &counts, bool &ttop_edge, bool &tbottom_edge) { const int FitRangeT = (int) my_data.maxHalfSizeT; const int NTBinsMax = (int) my_data.tbins; const int FixedWindow = (int) my_data.FixedWindow; tup = 0; tdown = 0; + if (FixedWindow != 0) { tup = FixedWindow; @@ -178,15 +225,26 @@ namespace if (tbin + tup >= NTBinsMax) { tup = NTBinsMax - tbin - 1; - edge++; + if (!ttop_edge) + { + counts.nedge++; + counts.tredge = 1; + ttop_edge = true; + } } if ((tbin - tdown) <= 0) { tdown = tbin; - edge++; + if (!tbottom_edge) + { + counts.nedge++; + counts.tledge = 1; + tbottom_edge = true; + } } return; } + for (int it = 0; it < FitRangeT; it++) { int ct = tbin + it; @@ -194,7 +252,12 @@ namespace if (ct <= 0 || ct >= NTBinsMax) { // tup = it; - edge++; + if (!ttop_edge) + { + counts.nedge++; + counts.tredge = 1; + ttop_edge = true; + } break; // truncate edge } @@ -204,7 +267,7 @@ namespace } if (adcval[phibin][ct] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -216,7 +279,7 @@ namespace adcval[phibin][ct + 2] + adcval[phibin][ct + 3]) { // rising again tup = it + 1; - touch++; + counts.overlap++; break; } } @@ -229,7 +292,12 @@ namespace if (ct <= 0 || ct >= NTBinsMax) { // tdown = it; - edge++; + if (!tbottom_edge) + { + counts.nedge++; + counts.tledge = 1; + tbottom_edge = true; + } break; // truncate edge } if (adcval[phibin][ct] <= 0) @@ -238,7 +306,7 @@ namespace } if (adcval[phibin][ct] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -249,7 +317,7 @@ namespace adcval[phibin][ct - 2] + adcval[phibin][ct - 3]) { // rising again tdown = it + 1; - touch++; + counts.overlap++; break; } } @@ -259,13 +327,14 @@ namespace return; } - void find_phi_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &phidown, int &phiup, int &touch, int &edge) + void find_phi_range(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, int &phidown, int &phiup, ClusterCounters &counts, bool &phitop_edge, bool &phibottom_edge) { int FitRangePHI = (int) my_data.maxHalfSizePhi; int NPhiBinsMax = (int) my_data.phibins; const int FixedWindow = (int) my_data.FixedWindow; phidown = 0; phiup = 0; + if (FixedWindow != 0) { phiup = FixedWindow; @@ -273,22 +342,38 @@ namespace if (phibin + phiup >= NPhiBinsMax) { phiup = NPhiBinsMax - phibin - 1; - edge++; + if (!phitop_edge) + { + counts.nedge++; + counts.sredge = 1; + phitop_edge = true; + } } if (phibin - phidown <= 0) { phidown = phibin; - edge++; + if (!phibottom_edge) + { + counts.nedge++; + counts.sledge = 1; + phibottom_edge = true; + } } return; } + for (int iphi = 0; iphi < FitRangePHI; iphi++) { int cphi = phibin + iphi; if (cphi < 0 || cphi >= NPhiBinsMax) { // phiup = iphi; - edge++; + if (!phitop_edge) + { + counts.nedge++; + counts.sredge = 1; + phitop_edge = true; + } break; // truncate edge } @@ -300,7 +385,7 @@ namespace } if (adcval[cphi][tbin] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -311,7 +396,7 @@ namespace adcval[cphi + 2][tbin] + adcval[cphi + 3][tbin]) { // rising again phiup = iphi + 1; - touch++; + counts.overlap++; break; } } @@ -325,7 +410,12 @@ namespace if (cphi < 0 || cphi >= NPhiBinsMax) { // phidown = iphi; - edge++; + if (!phibottom_edge) + { + counts.nedge++; + counts.sledge = 1; + phibottom_edge = true; + } break; // truncate edge } @@ -336,7 +426,7 @@ namespace } if (adcval[cphi][tbin] == USHRT_MAX) { - touch++; + counts.overlap++; break; } if (my_data.do_split) @@ -347,7 +437,7 @@ namespace adcval[cphi - 2][tbin] + adcval[cphi - 3][tbin]) { // rising again phidown = iphi + 1; - touch++; + counts.overlap++; break; } } @@ -357,28 +447,77 @@ namespace return; } + void check_cluster_touching(const std::vector& ihit_list, const std::vector>& adcval, int phibins, int tbins, ClusterCounters &counts) + { + // Encode (iphi, it) into single integer for fast lookup + std::unordered_set cluster_hits; + cluster_hits.reserve(ihit_list.size()); + + auto encode = [tbins](int phi, int t) + { + return phi * tbins + t; + }; + + for (const auto &hit : ihit_list) + { + cluster_hits.insert(encode(hit.iphi, hit.it)); + } + + for (const auto &hit : ihit_list) + { + int iphi = hit.iphi; + int it = hit.it; + + for (int dphi = -1; dphi <= 1; ++dphi) + { + for (int dt = -1; dt <= 1; ++dt) + { + if (dphi == 0 && dt == 0) { continue; } + + int nphi = iphi + dphi; + int nt = it + dt; + + if (nphi < 0 || nphi >= phibins || + nt < 0 || nt >= tbins) { + continue; + } + + // skip same cluster + if (cluster_hits.contains(encode(nphi, nt))) { continue; } + + // neighbor has signal → touching + if (adcval[nphi][nt] > 0 && + adcval[nphi][nt] != USHRT_MAX) + { + // Check Phi + if (dphi == -1) { counts.slmix = 1; } + if (dphi == 1) { counts.srmix = 1; } + + // Check Time + if (dt == -1) { counts.tlmix = 1; } + if (dt == 1) { counts.trmix = 1; } + } + } + } + } + } + int is_hit_isolated(int iphi, int it, int NPhiBinsMax, int NTBinsMax, const std::vector> &adcval) { // check isolated hits - // const int NPhiBinsMax = (int) my_data.phibins; + // const int NPhiBinsMax = (int) my_data.phibins; // const int NTBinsMax = (int) my_data.tbins; int isosum = 0; int isophimin = iphi - 1; - if (isophimin < 0) - { - isophimin = 0; - } + isophimin = std::max(isophimin, 0); int isophimax = iphi + 1; if (!(isophimax < NPhiBinsMax)) { isophimax = NPhiBinsMax - 1; } int isotmin = it - 1; - if (isotmin < 0) - { - isotmin = 0; - } + isotmin = std::max(isotmin, 0); int isotmax = it + 1; if (!(isotmax < NTBinsMax)) { @@ -420,20 +559,25 @@ namespace return isiso; } - void get_cluster(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, std::vector &ihit_list, int &touch, int &edge) + void get_cluster(int phibin, int tbin, const thread_data &my_data, const std::vector> &adcval, std::vector &ihit_list, ClusterCounters &counts) { + bool ttop_edge = false; + bool tbottom_edge = false; + bool phitop_edge = false; + bool phibottom_edge = false; + // search along phi at the peak in t // const int NPhiBinsMax = (int) my_data.phibins; // const int NTBinsMax = (int) my_data.tbins; int tup = 0; int tdown = 0; - find_t_range(phibin, tbin, my_data, adcval, tdown, tup, touch, edge); + find_t_range(phibin, tbin, my_data, adcval, tdown, tup, counts, ttop_edge, tbottom_edge); // now we have the t extent of the cluster, go find the phi edges for (int it = tbin - tdown; it <= (tbin + tup); it++) { int phiup = 0; int phidown = 0; - find_phi_range(phibin, it, my_data, adcval, phidown, phiup, touch, edge); + find_phi_range(phibin, it, my_data, adcval, phidown, phiup, counts, phitop_edge, phibottom_edge); for (int iphi = (phibin - phidown); iphi <= (phibin + phiup); iphi++) { if (adcval[iphi][it] > 0 && adcval[iphi][it] != USHRT_MAX) @@ -450,7 +594,7 @@ namespace hit.it = it; hit.adc = adcval[iphi][it]; - if (touch > 0) + if (counts.overlap > 0) { if ((iphi == (phibin - phidown)) || (iphi == (phibin + phiup))) @@ -466,7 +610,7 @@ namespace } void calc_cluster_parameter(const int iphi_center, const int it_center, - const std::vector &ihit_list, thread_data &my_data, int ntouch, int nedge) + const std::vector &ihit_list, thread_data &my_data, ClusterCounters counts) { // // get z range from layer geometry @@ -482,6 +626,8 @@ namespace double iphi_sum = 0.0; double iphi2_sum = 0.0; + double it_sum = 0.0; + double radius = my_data.layergeom->get_radius(); // returns center of layer int phibinhi = -1; @@ -490,6 +636,13 @@ namespace int tbinlo = 666666; int clus_size = ihit_list.size(); int max_adc = 0; + + int phibinmax = -1; + int tbinmax = -1; + double cen_adc = 0; + + int size = 0; + if (clus_size <= my_data.min_clus_size) { return; @@ -514,14 +667,16 @@ namespace training_hits->phistep = my_data.layergeom->get_phistep(); training_hits->zstep = my_data.layergeom->get_zstep() * my_data.tGeometry->get_drift_velocity(); training_hits->layer = my_data.layer; - training_hits->ntouch = ntouch; - training_hits->nedge = nedge; + training_hits->ntouch = counts.overlap; + training_hits->nedge = counts.nedge; training_hits->v_adc.fill(0); } - // std::cout << "process list" << std::endl; + // std::cout << "process list" << std::endl; std::vector hitkeyvec; + std::map, double> adc_map; + // keep track of the hit locations in a given cluster std::map m_phi{}; std::map m_z{}; @@ -537,30 +692,22 @@ namespace continue; } - if (adc > max_adc) - { - max_adc = adc; - } - - if (iphi > phibinhi) - { - phibinhi = iphi; - } + size++; - if (iphi < phibinlo) - { - phibinlo = iphi; - } + int adc_int = static_cast(std::round(adc)); - if (it > tbinhi) + if (adc_int > max_adc) { - tbinhi = it; + max_adc = adc_int; + phibinmax = iphi; + tbinmax = it; } - if (it < tbinlo) - { - tbinlo = it; - } + // max_adc = std::max(max_adc, static_cast(std::round(adc))); // preserves rounding (0.5 -> 1) + phibinhi = std::max(iphi, phibinhi); + phibinlo = std::min(iphi, phibinlo); + tbinhi = std::max(it, tbinhi); + tbinlo = std::min(it, tbinlo); // if(it==it_center){ yg_sum += adc; } // update phi sums @@ -577,8 +724,12 @@ namespace t_sum += t * adc; t2_sum += square(t) * adc; + it_sum += it * adc; + adc_sum += adc; + adc_map[{iphi, it}] += adc; + if (my_data.fillClusHitsVerbose) { auto pnew = m_phi.try_emplace(iphi, adc); @@ -617,30 +768,121 @@ namespace return; // skip obvious noise "clusters" } - // This is the global position - double clusiphi = iphi_sum / adc_sum; - double clusphi = my_data.layergeom->get_phi(clusiphi, my_data.side); + TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(my_data.layer, my_data.sector, my_data.side); + + // pads just outside the cluster in phi + const int left_pad = phibinlo - 1; + const int right_pad = phibinhi + 1; - float clusx = radius * cos(clusphi); - float clusy = radius * sin(clusphi); + // --- Dead channels --- + if (my_data.maskDead) + { + auto it = my_data.deadMap->find(tpcHitSetKey); + if (it != my_data.deadMap->end()) + { + const auto &deadset = it->second; + + if (left_pad >= 0 && + left_pad >= my_data.phioffset && + deadset.contains(TpcDefs::genHitKey(left_pad, 0))) + { + counts.nedge++; + counts.dledge = 1; + } + + if (right_pad < (my_data.phibins + my_data.phioffset) && + deadset.contains(TpcDefs::genHitKey(right_pad, 0))) + { + counts.nedge++; + counts.dredge = 1; + } + } + } + + // --- Hot channels --- + if (my_data.maskHot) + { + auto it = my_data.hotMap->find(tpcHitSetKey); + if (it != my_data.hotMap->end()) + { + const auto &hotset = it->second; + + if (left_pad >= 0 && + left_pad >= my_data.phioffset && + hotset.contains(TpcDefs::genHitKey(left_pad, 0))) + { + counts.nedge++; + counts.hledge = 1; + } + + if (right_pad < (my_data.phibins + my_data.phioffset) && + hotset.contains(TpcDefs::genHitKey(right_pad, 0))) + { + counts.nedge++; + counts.hredge = 1; + } + } + } + + // This is local position + double clusiphi = iphi_sum / adc_sum; + double clusit = it_sum / adc_sum; + + // this is the phi position in the TPC envelope + double env_clusphi = my_data.layergeom->get_phi(clusiphi, my_data.side); double clust = t_sum / adc_sum; + + // ADC of centroid bin + int iphi_centroid = static_cast(std::floor(clusiphi)); + int it_centroid = static_cast(std::floor(clusit)); + + auto it_cent = adc_map.find({iphi_centroid, it_centroid}); + if (it_cent != adc_map.end()) + { + cen_adc = it_cent->second; + } + else + { + cen_adc = 0.0; // centroid may not land on a real hit + } + + // Max ADC position in global coordinates + double maxphi = my_data.layergeom->get_phi(phibinmax, my_data.side); + double maxt = my_data.layergeom->get_zcenter(tbinmax); + + // Phase relative to max ADC position + double padphase = 0.0; + double tbinphase = 0.0; + + if (my_data.layergeom->get_phistep() > 0) + { + padphase = (env_clusphi - maxphi) / my_data.layergeom->get_phistep(); + } + + if (my_data.layergeom->get_zstep() > 0) + { + tbinphase = (clust - maxt) / my_data.layergeom->get_zstep(); + } + + // these positions are in the tpc_envelope + double env_clusx = radius * cos(env_clusphi); + double env_clusy = radius * sin(env_clusphi); + // needed for surface identification double zdriftlength = clust * my_data.tGeometry->get_drift_velocity(); // convert z drift length to z position in the TPC - double clusz = my_data.m_tdriftmax * my_data.tGeometry->get_drift_velocity() - zdriftlength; + double env_clusz = my_data.m_tdriftmax * my_data.tGeometry->get_drift_velocity() - zdriftlength; if (my_data.side == 0) { - clusz = -clusz; + env_clusz = -env_clusz; } - // std::cout << " side " << my_data.side << " clusz " << clusz << " clust " << clust << " driftmax " << my_data.m_tdriftmax << std::endl; const double phi_cov = (iphi2_sum / adc_sum - square(clusiphi)) * pow(my_data.layergeom->get_phistep(), 2); const double t_cov = t2_sum / adc_sum - square(clust); - // Get the surface key to find the surface from the - TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey(my_data.layer, my_data.sector, my_data.side); - Acts::Vector3 global(clusx, clusy, clusz); + // get_tpc_surface_from_coords expects a world global position + Acts::Vector3 env_global(env_clusx, env_clusy, env_clusz); + Acts::Vector3 global = my_data.tGeometry->transformTpcEnvelopeToWorld(env_global); TrkrDefs::subsurfkey subsurfkey = 0; - Surface surface = my_data.tGeometry->get_tpc_surface_from_coords( tpcHitSetKey, global, @@ -653,6 +895,8 @@ namespace hitkeyvec.clear(); return; } + // Acts::Vector3 surfcent = surface->center(my_data.tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm; + // std::cout << " surf center = " << surfcent.x() << " " << surfcent.y() << " " << surfcent.z() << std::endl; // Estimate the errors // Blow up error on single pixel clusters by a factor 3 to compensate for threshold effects @@ -662,6 +906,7 @@ namespace char tsize = tbinhi - tbinlo + 1; char phisize = phibinhi - phibinlo + 1; + char rsize = size; // std::cout << "phisize: " << (int) phisize << " phibinhi " << phibinhi << " phibinlo " << phibinlo << std::endl; // phi_cov = (weighted mean of dphi^2) - (weighted mean of dphi)^2, which is essentially the weighted mean of dphi^2. The error is then: // e_phi = sigma_dphi/sqrt(N) = sqrt( sigma_dphi^2 / N ) -- where N is the number of samples of the distribution with standard deviation sigma_dphi @@ -674,7 +919,7 @@ namespace /// convert to Acts units global *= Acts::UnitConstants::cm; // std::cout << "transform" << std::endl; - Acts::Vector3 local = surface->transform(my_data.tGeometry->geometry().getGeoContext()).inverse() * global; + Acts::Vector3 local = surface->localToGlobalTransform(my_data.tGeometry->geometry().getGeoContext()).inverse() * global; local /= Acts::UnitConstants::cm; // std::cout << "done transform" << std::endl; // we need the cluster key and all associated hit keys (note: the cluster key includes the hitset key) @@ -686,46 +931,83 @@ namespace // std::cout << "clus num" << my_data.cluster_vector.size() << " X " << local(0) << " Y " << clust << std::endl; if (sqrt(phi_err_square) > my_data.min_err_squared) { - auto clus = new TrkrClusterv5; - // auto clus = std::make_unique(); + TrkrCluster* clus = nullptr; + + if (my_data.debug) + { + clus = new TrkrClusterv6; + } + else + { + clus = new TrkrClusterv5; + } + clus_base = clus; - clus->setAdc(adc_sum); - clus->setMaxAdc(max_adc); - clus->setEdge(nedge); - clus->setPhiSize(phisize); - clus->setZSize(tsize); - clus->setSubSurfKey(subsurfkey); - clus->setOverlap(ntouch); clus->setLocalX(local(0)); clus->setLocalY(clust); + clus->setSubSurfKey(subsurfkey); + clus->setAdc(adc_sum); + clus->setMaxAdc(max_adc); + clus->setCenAdc(cen_adc); + clus->setPadCen(clusiphi); + clus->setTBinCen(clusit); + clus->setPadMax(phibinmax); + clus->setTBinMax(tbinmax); clus->setPhiError(sqrt(phi_err_square)); clus->setZError(sqrt(t_err_square * pow(my_data.tGeometry->get_drift_velocity(), 2))); + clus->setRSize(rsize); + clus->setPhiSize(phisize); + clus->setZSize(tsize); + clus->setOverlap(counts.overlap); + clus->setEdge(counts.nedge); + clus->setSLEdge(counts.sledge); + clus->setSREdge(counts.sredge); + clus->setTLEdge(counts.tledge); + clus->setTREdge(counts.tredge); + clus->setDLEdge(counts.dledge); + clus->setDREdge(counts.dredge); + clus->setHLEdge(counts.hledge); + clus->setHREdge(counts.hredge); + clus->setSLMix(counts.slmix); + clus->setSRMix(counts.srmix); + clus->setTLMix(counts.tlmix); + clus->setTRMix(counts.trmix); + clus->setPhiBinLo(phibinlo); + clus->setPhiBinHi(phibinhi); + clus->setTBinLo(tbinlo); + clus->setTBinHi(tbinhi); + clus->setPadPhase(padphase); + clus->setTBinPhase(tbinphase); + my_data.cluster_vector.push_back(clus); b_made_cluster = true; } + // This code needs to be reviewed in case of a non-zero TPC tilt - ADF 6/16/26 if (use_nn && clus_base && training_hits) { try { // Create a vector of inputs std::vector inputs; - inputs.emplace_back(torch::stack({torch::from_blob(std::vector(training_hits->v_adc.begin(), training_hits->v_adc.end()).data(), {1, 2 * nd + 1, 2 * nd + 1}, torch::kFloat32), + inputs.emplace_back(torch::stack({torch::from_blob(std::vector(training_hits->v_adc.begin(), training_hits->v_adc.end()).data(), {1, 2 * nd + 1, 2 * nd + 1}, torch::kFloat32), torch::full({1, 2 * nd + 1, 2 * nd + 1}, std::clamp((training_hits->layer - 7) / 16, 0, 2), torch::kFloat32), torch::full({1, 2 * nd + 1, 2 * nd + 1}, training_hits->z / radius, torch::kFloat32)}, 1)); // Execute the model and turn its output into a tensor at::Tensor ten_pos = module_pos.forward(inputs).toTensor(); - float nn_phi = training_hits->phi + std::clamp(ten_pos[0][0][0].item(), -(float) nd, (float) nd) * training_hits->phistep; - float nn_z = training_hits->z + std::clamp(ten_pos[0][1][0].item(), -(float) nd, (float) nd) * training_hits->zstep; - float nn_x = radius * std::cos(nn_phi); - float nn_y = radius * std::sin(nn_phi); - Acts::Vector3 nn_global(nn_x, nn_y, nn_z); + double nn_phi = training_hits->phi + std::clamp(ten_pos[0][0][0].item(), -(double) nd, (double) nd) * training_hits->phistep; + double nn_z = training_hits->z + std::clamp(ten_pos[0][1][0].item(), -(double) nd, (double) nd) * training_hits->zstep; + double nn_x = radius * std::cos(nn_phi); + double nn_y = radius * std::sin(nn_phi); + + Acts::Vector3 nn_env_global(nn_x, nn_y, nn_z); + Acts::Vector3 nn_global = my_data.tGeometry->transformTpcEnvelopeToWorld(nn_env_global); nn_global *= Acts::UnitConstants::cm; - Acts::Vector3 nn_local = surface->transform(my_data.tGeometry->geometry().geoContext).inverse() * nn_global; + Acts::Vector3 nn_local = surface->localToGlobalTransform(my_data.tGeometry->geometry().geoContext).inverse() * nn_global; nn_local /= Acts::UnitConstants::cm; - float nn_t = my_data.m_tdriftmax - std::fabs(nn_z) / my_data.tGeometry->get_drift_velocity(); + double nn_t = my_data.m_tdriftmax - std::fabs(nn_z) / my_data.tGeometry->get_drift_velocity(); clus_base->setLocalX(nn_local(0)); clus_base->setLocalY(nn_t); } @@ -738,19 +1020,19 @@ namespace if (my_data.fillClusHitsVerbose && b_made_cluster) { // push the data back to - my_data.phivec_ClusHitsVerbose.push_back(std::vector>{}); - my_data.zvec_ClusHitsVerbose.push_back(std::vector>{}); + my_data.phivec_ClusHitsVerbose.emplace_back(); + my_data.zvec_ClusHitsVerbose.emplace_back(); auto &vphi = my_data.phivec_ClusHitsVerbose.back(); auto &vz = my_data.zvec_ClusHitsVerbose.back(); for (auto &entry : m_phi) { - vphi.push_back({entry.first, entry.second}); + vphi.emplace_back(entry.first, entry.second); } for (auto &entry : m_z) { - vz.push_back({entry.first, entry.second}); + vz.emplace_back(entry.first, entry.second); } } @@ -809,7 +1091,38 @@ namespace tbinmax -= etacut; } } - // std::cout << PHWHERE << " maxz " << maxz << " tbinmin " << tbinmin << " tbinmax " << tbinmax << std::endl; + // std::cout << PHWHERE << " maxz " << maxz << " tbinmin " << tbinmin << " tbinmax " << tbinmax << std::endl; + + TrkrDefs::hitsetkey tpcHitSetKey = + TpcDefs::genHitSetKey(my_data->layer, my_data->sector, my_data->side); + + // Helper function to check if a pad is masked + auto is_pad_masked = [&](int abs_pad) -> bool + { + TrkrDefs::hitkey key = TpcDefs::genHitKey(abs_pad, 0); + + if (my_data->maskDead) + { + auto it = my_data->deadMap->find(tpcHitSetKey); + if (it != my_data->deadMap->end() && + it->second.contains(key)) + { + return true; + } + } + + if (my_data->maskHot) + { + auto it = my_data->hotMap->find(tpcHitSetKey); + if (it != my_data->hotMap->end() && + it->second.contains(key)) + { + return true; + } + } + + return false; + }; if (my_data->hitset != nullptr) { @@ -846,21 +1159,16 @@ namespace { continue; } - float_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 + if (is_pad_masked(phibin + phioffset)) + { + continue; + } + double_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 unsigned short adc = 0; if (fadc > 0) { adc = (unsigned short) fadc; } - if (phibin >= phibins) - { - continue; - } - if (tbin >= tbins) - { - continue; // tbin is unsigned int, <0 cannot happen - } - if (adc > 0) { if (adc > (my_data->seed_threshold)) @@ -875,7 +1183,7 @@ namespace } if (adc > my_data->edge_threshold) { - adcval[phibin][tbin] = (unsigned short) adc; + adcval[phibin][tbin] = adc; } } } @@ -897,7 +1205,12 @@ namespace continue; } - int pindex = 0; + if (is_pad_masked(nphi + phioffset)) + { + continue; + } + + int pindex = 0; for (unsigned int nt = 0; nt < hitset->size(nphi); nt++) { unsigned short val = (*(hitset->getHits(nphi)))[nt]; @@ -966,8 +1279,11 @@ namespace } } */ + + std::vector> adcval_orig = adcval; + // std::cout << "done filling " << std::endl; - while (all_hit_map.size() > 0) + while (!all_hit_map.empty()) { // std::cout << "all hit map size: " << all_hit_map.size() << std::endl; auto iter = all_hit_map.rbegin(); @@ -993,9 +1309,10 @@ namespace // start with highest adc hit // -> cluster around it and get vector of hits std::vector ihit_list; - int ntouch = 0; - int nedge = 0; - get_cluster(iphi, it, *my_data, adcval, ihit_list, ntouch, nedge); + // Setting all the counters + ClusterCounters counts; + + get_cluster(iphi, it, *my_data, adcval, ihit_list, counts); if (my_data->FixedWindow > 0) { @@ -1013,22 +1330,10 @@ namespace { continue; } - if (wiphi > wphibinhi) - { - wphibinhi = wiphi; - } - if (wiphi < wphibinlo) - { - wphibinlo = wiphi; - } - if (wit > wtbinhi) - { - wtbinhi = wit; - } - if (wit < wtbinlo) - { - wtbinlo = wit; - } + wphibinhi = std::max(wiphi, wphibinhi); + wphibinlo = std::min(wiphi, wphibinlo); + wtbinhi = std::max(wit, wtbinhi); + wtbinlo = std::min(wit, wtbinlo); } char wtsize = wtbinhi - wtbinlo + 1; char wphisize = wphibinhi - wphibinlo + 1; @@ -1043,11 +1348,16 @@ namespace my_data->FixedWindow = 0; // reset hit list and try again without fixed window ihit_list.clear(); - get_cluster(iphi, it, *my_data, adcval, ihit_list, ntouch, nedge); + // resetting all the counters + counts.clear(); + get_cluster(iphi, it, *my_data, adcval, ihit_list, counts); // std::cout << " stepdown size after " << ihit_list.size() << std::endl; my_data->FixedWindow = window_cache; } } + + check_cluster_touching(ihit_list, adcval_orig, my_data->phibins, my_data->tbins, counts); + if (ihit_list.size() <= 1) { remove_hits(ihit_list, all_hit_map, adcval); @@ -1058,7 +1368,7 @@ namespace // -> add hits to truth association // remove hits from all_hit_map // repeat untill all_hit_map empty - calc_cluster_parameter(iphi, it, ihit_list, *my_data, ntouch, nedge); + calc_cluster_parameter(iphi, it, ihit_list, *my_data, counts); remove_hits(ihit_list, all_hit_map, adcval); ihit_list.clear(); } @@ -1075,9 +1385,10 @@ namespace */ // pthread_exit(nullptr); } + void *ProcessSector(void *threadarg) { - auto my_data = static_cast(threadarg); + auto *my_data = static_cast(threadarg); ProcessSectorData(my_data); pthread_exit(nullptr); } @@ -1133,7 +1444,7 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) } // Create the Cluster node if required - auto trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); + auto *trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); if (!trkrclusters) { PHNodeIterator dstiter(dstNode); @@ -1151,7 +1462,7 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(TrkrClusterContainerNode); } - auto clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); + auto *clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); if (!clusterhitassoc) { PHNodeIterator dstiter(dstNode); @@ -1168,7 +1479,7 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(newNode); } - auto training_container = findNode::getClass(dstNode, "TRAINING_HITSET"); + auto *training_container = findNode::getClass(dstNode, "TRAINING_HITSET"); if (!training_container) { PHNodeIterator dstiter(dstNode); @@ -1217,18 +1528,18 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) if (!mClusHitsVerbose) { PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); if (!DetNode) { DetNode = new PHCompositeNode("TRKR"); dstNode->addNode(DetNode); } mClusHitsVerbose = new ClusHitsVerbosev1(); - auto newNode = new PHIODataNode(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject"); + auto *newNode = new PHIODataNode(mClusHitsVerbose, "Trkr_SvtxClusHitsVerbose", "PHObject"); DetNode->addNode(newNode); } } - auto geom = + auto *geom = findNode::getClass(topNode, "TPCGEOMCONTAINER"); if (!geom) { @@ -1238,15 +1549,21 @@ int TpcClusterizer::InitRun(PHCompositeNode *topNode) AdcClockPeriod = geom->GetFirstLayerCellGeom()->get_zstep(); - std::cout << "FirstLayerCellGeomv1 streamer: " << std::endl; - auto *g1 = (PHG4TpcGeomv1*) geom->GetFirstLayerCellGeom(); // cast because << not in the base class - std::cout << *g1 << std::endl; - std::cout << "LayerCellGeomv1 streamer for layer 24: " << std::endl; - auto *g2 = (PHG4TpcGeomv1*) geom->GetLayerCellGeom(24); // cast because << not in the base class - std::cout << *g2 << std::endl; - std::cout << "LayerCellGeomv1 streamer for layer 40: " << std::endl; - auto *g3 = (PHG4TpcGeomv1*) geom->GetLayerCellGeom(40); // cast because << not in the base class - std::cout << *g3 << std::endl; + // the identify now contains all information from the streamer for v2 + geom->GetFirstLayerCellGeom()->identify(); + geom->GetLayerCellGeom(24)->identify(); + geom->GetLayerCellGeom(40)->identify(); + + if (m_maskDeadChannels) + { + m_deadChannelMap.clear(); + makeChannelMask(m_deadChannelMap, m_deadChannelMapName, "TotalDeadChannels"); + } + if (m_maskHotChannels) + { + m_hotChannelMap.clear(); + makeChannelMask(m_hotChannelMap, m_hotChannelMapName, "TotalHotChannels"); + } return Fun4AllReturnCodes::EVENT_OK; } @@ -1434,6 +1751,13 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.min_err_squared = min_err_squared; thread_pair.data.min_clus_size = min_clus_size; thread_pair.data.min_adc_sum = min_adc_sum; + + // --- pass dead/hot map info --- + thread_pair.data.deadMap = &m_deadChannelMap; + thread_pair.data.hotMap = &m_hotChannelMap; + thread_pair.data.maskDead = m_maskDeadChannels; + thread_pair.data.maskHot = m_maskHotChannels; + unsigned short NPhiBins = (unsigned short) layergeom->get_phibins(); unsigned short NPhiBinsSector = NPhiBins / 12; unsigned short NTBins = 0; @@ -1458,7 +1782,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.phioffset = PhiOffset; thread_pair.data.tbins = NTBinsSide; thread_pair.data.toffset = TOffset; - + thread_pair.data.debug = m_debug; thread_pair.data.radius = layergeom->get_radius(); thread_pair.data.drift_velocity = m_tGeometry->get_drift_velocity(); thread_pair.data.pads_per_sector = 0; @@ -1489,18 +1813,18 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); // get cluster - auto cluster = data.cluster_vector[index]; + auto *cluster = data.cluster_vector[index]; // insert in map m_clusterlist->addClusterSpecifyKey(ckey, cluster); if (mClusHitsVerbose) { - for (auto &hit : data.phivec_ClusHitsVerbose[index]) + for (const auto &hit : data.phivec_ClusHitsVerbose[index]) { mClusHitsVerbose->addPhiHit(hit.first, hit.second); } - for (auto &hit : data.zvec_ClusHitsVerbose[index]) + for (const auto &hit : data.zvec_ClusHitsVerbose[index]) { mClusHitsVerbose->addZHit(hit.first, hit.second); } @@ -1547,6 +1871,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.pedestal = pedestal; thread_pair.data.sector = sector; thread_pair.data.side = side; + thread_pair.data.debug = m_debug; thread_pair.data.do_assoc = do_hit_assoc; thread_pair.data.do_wedge_emulation = do_wedge_emulation; thread_pair.data.tGeometry = m_tGeometry; @@ -1554,6 +1879,12 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) thread_pair.data.maxHalfSizePhi = MaxClusterHalfSizePhi; thread_pair.data.verbosity = Verbosity(); + // --- pass dead/hot map info --- + thread_pair.data.deadMap = &m_deadChannelMap; + thread_pair.data.hotMap = &m_hotChannelMap; + thread_pair.data.maskDead = m_maskDeadChannels; + thread_pair.data.maskHot = m_maskHotChannels; + unsigned short NPhiBins = (unsigned short) layergeom->get_phibins(); unsigned short NPhiBinsSector = NPhiBins / 12; unsigned short NTBins = (unsigned short) layergeom->get_zbins(); @@ -1573,13 +1904,13 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) /* PHG4TpcGeom *testlayergeom = geom_container->GetLayerCellGeom(32); - for( float iphi = 1408; iphi < 1408+ 128;iphi+=0.1){ + for( double iphi = 1408; iphi < 1408+ 128;iphi+=0.1){ double clusiphi = iphi; double clusphi = testlayergeom->get_phi(clusiphi); double radius = layergeom->get_radius(); - float clusx = radius * cos(clusphi); - float clusy = radius * sin(clusphi); - float clusz = -37.524; + double clusx = radius * cos(clusphi); + double clusy = radius * sin(clusphi); + double clusz = -37.524; TrkrDefs::hitsetkey tpcHitSetKey = TpcDefs::genHitSetKey( 32,11, 0 ); Acts::Vector3 global(clusx, clusy, clusz); @@ -1624,7 +1955,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); // get cluster - auto cluster = data.cluster_vector[index]; + auto *cluster = data.cluster_vector[index]; // insert in map m_clusterlist->addClusterSpecifyKey(ckey, cluster); @@ -1668,7 +1999,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); // get cluster - auto cluster = data.cluster_vector[index]; + auto *cluster = data.cluster_vector[index]; // insert in map // std::cout << "X: " << cluster->getLocalX() << "Y: " << cluster->getLocalY() << std::endl; @@ -1676,13 +2007,13 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) if (mClusHitsVerbose) { - for (auto &hit : data.phivec_ClusHitsVerbose[index]) + for (const auto &hit : data.phivec_ClusHitsVerbose[index]) { - mClusHitsVerbose->addPhiHit(hit.first, (float) hit.second); + mClusHitsVerbose->addPhiHit(hit.first, (double) hit.second); } - for (auto &hit : data.zvec_ClusHitsVerbose[index]) + for (const auto &hit : data.zvec_ClusHitsVerbose[index]) { - mClusHitsVerbose->addZHit(hit.first, (float) hit.second); + mClusHitsVerbose->addZHit(hit.first, (double) hit.second); } mClusHitsVerbose->push_hits(ckey); } @@ -1698,7 +2029,7 @@ int TpcClusterizer::process_event(PHCompositeNode *topNode) m_clusterhitassoc->addAssoc(ckey, hkey); } - for (auto v_hit : thread_pair.data.v_hits) + for (auto *v_hit : thread_pair.data.v_hits) { if (_store_hits) { @@ -1739,3 +2070,88 @@ int TpcClusterizer::End(PHCompositeNode * /*topNode*/) { return Fun4AllReturnCodes::EVENT_OK; } + +void TpcClusterizer::makeChannelMask(hitMaskTpcSet &aMask, const std::string &dbName, const std::string &totalChannelsToMask) +{ + std::unique_ptr cdbttree; + if (m_maskFromFile) + { + cdbttree = std::make_unique(dbName); + } + else // mask using CDB TTree, default + { + std::string database = CDBInterface::instance()->getUrl(dbName); + + if (database.empty()) + { + std::cout << PHWHERE << "ERROR: CDB URL not found for " << dbName + << ". Masking disabled for this map." << std::endl; + return; + } + + cdbttree = std::make_unique(database); + } + + std::cout << "Masking TPC Channel Map: " << dbName << std::endl; + + int NChan = -1; + NChan = cdbttree->GetSingleIntValue(totalChannelsToMask); + + if (NChan < 0) + { + std::cout << PHWHERE << "ERROR: Invalid or missing " << totalChannelsToMask + << " for " << dbName << ". Masking disabled for this map." << std::endl; + return; + } + + for (int i = 0; i < NChan; i++) + { + int Layer = cdbttree->GetIntValue(i, "layer"); + int Sector = cdbttree->GetIntValue(i, "sector"); + int Side = cdbttree->GetIntValue(i, "side"); + int Pad = cdbttree->GetIntValue(i, "pad"); + + if (Sector < 0 || Sector >= 12) + { + if (Verbosity() > VERBOSITY_A_LOT) + { + std::cout << PHWHERE << "WARNING: sector index " << Sector + << " out of range [0,11] in " << dbName + << ", skipping channel " << i << std::endl; + } + continue; + } + + if (Layer < 7 || Layer > 54) + { + if (Verbosity() > VERBOSITY_A_LOT) + { + std::cout << PHWHERE << "WARNING: layer " << Layer + << " out of TPC range [7,54] in " << dbName + << ", skipping channel " << i << std::endl; + } + continue; + } + + if (Side < 0 || Side > 1) + { + if (Verbosity() > VERBOSITY_A_LOT) + { + std::cout << PHWHERE << "WARNING: side " << Side + << " out of range [0,1] in " << dbName + << ", skipping channel " << i << std::endl; + } + continue; + } + + if (Verbosity() > VERBOSITY_A_LOT) + { + std::cout << dbName << ": Will mask layer: " << Layer << ", sector: " << Sector << ", side: " << Side << ", Pad: " << Pad << std::endl; + } + + TrkrDefs::hitsetkey DeadChannelHitKey = TpcDefs::genHitSetKey(Layer, Sector, Side); + TrkrDefs::hitkey DeadHitKey = TpcDefs::genHitKey((unsigned int) Pad, 0); + aMask[DeadChannelHitKey].insert(DeadHitKey); + } + +} diff --git a/offline/packages/tpc/TpcClusterizer.h b/offline/packages/tpc/TpcClusterizer.h index e7dd61f0bc..c566f5b4f8 100644 --- a/offline/packages/tpc/TpcClusterizer.h +++ b/offline/packages/tpc/TpcClusterizer.h @@ -4,10 +4,13 @@ #include #include #include +#include #include #include -#include +#include + +typedef std::map> hitMaskTpcSet; class ClusHitsVerbosev1; class PHCompositeNode; @@ -41,12 +44,12 @@ class TpcClusterizer : public SubsysReco void set_do_sequential(bool do_seq) { do_sequential = do_seq; } void set_do_split(bool split) { do_split = split; } void set_fixed_window(int fixed) { do_fixed_window = fixed; } - void set_pedestal(float val) { pedestal = val; } - void set_seed_threshold(float val) { seed_threshold = val; } - void set_edge_threshold(float val) { edge_threshold = val; } - void set_min_err_squared(float val) { min_err_squared = val; } - void set_min_clus_size(float val) { min_clus_size = val; } - void set_min_adc_sum(float val) { min_adc_sum = val; } + void set_pedestal(double val) { pedestal = val; } + void set_seed_threshold(double val) { seed_threshold = val; } + void set_edge_threshold(double val) { edge_threshold = val; } + void set_min_err_squared(double val) { min_err_squared = val; } + void set_min_clus_size(double val) { min_clus_size = val; } + void set_min_adc_sum(double val) { min_adc_sum = val; } void set_remove_singles(bool do_sing) { do_singles = do_sing; } void set_read_raw(bool read_raw) { do_read_raw = read_raw; } void set_max_cluster_half_size_phi(unsigned short size) { MaxClusterHalfSizePhi = size; } @@ -69,13 +72,36 @@ class TpcClusterizer : public SubsysReco set_max_cluster_half_size_z(20); set_fixed_window(3); }; - + ClusHitsVerbosev1 *mClusHitsVerbose{nullptr}; - + + void SetMaskChannelsFromFile() + { + m_maskFromFile = true; + } + + void SetDeadChannelMapName(const std::string& dcmap) + { + m_maskDeadChannels = true; + m_deadChannelMapName = dcmap; + } + void SetHotChannelMapName(const std::string& hmap) + { + m_maskHotChannels = true; + m_hotChannelMapName = hmap; + } + + void DetailedClusterAnalysis() + { + m_debug = true; + } + private: bool is_in_sector_boundary(int phibin, int sector, PHG4TpcGeom *layergeom) const; bool record_ClusHitsVerbose{false}; + void makeChannelMask(hitMaskTpcSet& aMask, const std::string& dbName, const std::string& totalChannelsToMask); + TrkrHitSetContainer *m_hits = nullptr; RawHitSetContainer *m_rawhits = nullptr; TrkrClusterContainer *m_clusterlist = nullptr; @@ -105,8 +131,18 @@ class TpcClusterizer : public SubsysReco double m_tdriftmax = 0; double AdcClockPeriod = 53.0; // ns double NZBinsSide = 249; - + TrainingHitsContainer *m_training; + + hitMaskTpcSet m_deadChannelMap; + hitMaskTpcSet m_hotChannelMap; + + bool m_maskDeadChannels {false}; + bool m_maskHotChannels {false}; + bool m_maskFromFile {false}; + bool m_debug{false}; + std::string m_deadChannelMapName; + std::string m_hotChannelMapName; }; #endif diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc index c194567d58..f5e436c6d7 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpacker.cc @@ -57,7 +57,7 @@ void TpcCombinedRawDataUnpacker::ReadZeroSuppressedData() { m_do_zs_emulation = true; m_do_baseline_corr = false; - auto cdb = CDBInterface::instance(); + auto *cdb = CDBInterface::instance(); std::string dir = cdb->getUrl("TPC_ZS_THRESHOLDS"); auto cdbtree = std::make_unique(dir); @@ -75,7 +75,7 @@ void TpcCombinedRawDataUnpacker::ReadZeroSuppressedData() { name.str(""); name << "R"<GetSingleFloatValue(name.str().c_str()); + m_zs_threshold[i] = cdbtree->GetSingleFloatValue(name.str()); if(Verbosity() > 1) { std::cout << "Loading ADU threshold of " << m_zs_threshold[i] << " for region " << i << std::endl; @@ -324,8 +324,8 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) hit_set_key = TpcDefs::genHitSetKey(layer, (mc_sectors[sector % 12]), side); hit_set_container_itr = trkr_hit_set_container->findOrAddHitSet(hit_set_key); - float hpedestal = 0; - float hpedwidth = 0; + double hpedestal = 0; + double hpedwidth = 0; if (Verbosity() > 2) { @@ -372,7 +372,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) auto fee_entries_it = feeentries_map.find(fee_key); std::vector& fee_entries_vec = (*fee_entries_it).second; - float threshold_cut = m_zs_threshold[region]; + double threshold_cut = m_zs_threshold[region]; int nhitschan = 0; @@ -391,7 +391,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) { if (adc > 0) { - if ((float(adc) - hpedestal) > threshold_cut) + if ((double(adc) - hpedestal) > threshold_cut) { nhitschan++; } @@ -424,7 +424,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) { if (adc > 0) { - if ((float(adc) - hpedestal) > threshold_cut) + if ((double(adc) - hpedestal) > threshold_cut) { feehist->Fill(t, adc - hpedestal); if (t < (int) fee_entries_vec.size()) @@ -435,7 +435,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) } } - if ((float(adc) - hpedestal) > threshold_cut) + if ((double(adc) - hpedestal) > threshold_cut) { hit_key = TpcDefs::genHitKey(phibin, (unsigned int) t); // find existing hit, or create new one @@ -443,7 +443,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) if (!hit) { hit = new TrkrHitv2(); - hit->setAdc(float(adc) - hpedestal); + hit->setAdc(double(adc) - hpedestal); hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } @@ -462,10 +462,10 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) fXh[nh++] = channel; // channel; fXh[nh++] = sampadd; // sampadd; fXh[nh++] = sampch; // sampch; - fXh[nh++] = (float) phibin; - fXh[nh++] = (float) t; + fXh[nh++] = (double) phibin; + fXh[nh++] = (double) t; fXh[nh++] = layer; - fXh[nh++] = (float(adc) - hpedestal); + fXh[nh++] = (double(adc) - hpedestal); fXh[nh++] = hpedestal; fXh[nh++] = hpedwidth; m_ntup_hits->Fill(fXh); @@ -499,18 +499,18 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) } std::vector::iterator fee_entries_vec_it = (*fee_entries_it).second.begin(); - std::vector pedvec(hist2d->GetNbinsX(), 0); + std::vector pedvec(hist2d->GetNbinsX(), 0); feebaseline_map.insert(std::make_pair(hiter.first, pedvec)); - std::map>::iterator fee_blm_it = feebaseline_map.find(hiter.first); + std::map>::iterator fee_blm_it = feebaseline_map.find(hiter.first); (*fee_blm_it).second.resize(hist2d->GetNbinsX(), 0); for (int binx = 1; binx < hist2d->GetNbinsX(); binx++) { double timebin = (hist2d->GetXaxis())->GetBinCenter(binx); std::string histname1d = "h" + std::to_string(hiter.first) + "_" + std::to_string((int) timebin); nhisttotal++; - float local_ped = 0; - float local_width = 0; - float entries = fee_entries_vec_it[timebin]; + double local_ped = 0; + double local_width = 0; + double entries = fee_entries_vec_it[timebin]; if (fee_entries_vec_it[timebin] > 100) { nhistfilled++; @@ -532,8 +532,8 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) for (int isum = -3; isum <= 3; isum++) { - float val = hist1d->GetBinContent(maxbin + isum); - float center = hist1d->GetBinCenter(maxbin + isum); + double val = hist1d->GetBinContent(maxbin + isum); + double center = hist1d->GetBinCenter(maxbin + isum); hibin_sum += center * val; hibin2_sum += center * center * val; hadc_sum += val; @@ -601,7 +601,7 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) unsigned int pad_key = create_pad_key(side, layer, phibin); - float fee = 0; + double fee = 0; std::map::iterator chan_it = chan_map.find(pad_key); if (chan_it != chan_map.end()) { @@ -612,10 +612,10 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) } int rx = get_rx(layer); - float corr = 0; + double corr = 0; unsigned int fee_key = create_fee_key(side, sector, rx, fee); - std::map>::iterator fee_blm_it = feebaseline_map.find(fee_key); + std::map>::iterator fee_blm_it = feebaseline_map.find(fee_key); if (fee_blm_it != feebaseline_map.end()) { if (tbin < (int) (*fee_blm_it).second.size()) @@ -623,8 +623,8 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) corr = (*fee_blm_it).second[tbin]; } hitr->second->setAdc(0); - float nuadc = (float(adc) - corr); - nuadc = std::max(nuadc, 0); + double nuadc = (double(adc) - corr); + nuadc = std::max(nuadc, 0); hitr->second->setAdc(nuadc); if (m_writeTree) @@ -642,10 +642,10 @@ int TpcCombinedRawDataUnpacker::process_event(PHCompositeNode* topNode) fXh[nh++] = 0; // channel; fXh[nh++] = 0; // sampadd; fXh[nh++] = 0; // sampch; - fXh[nh++] = (float) phibin; - fXh[nh++] = (float) tbin; + fXh[nh++] = (double) phibin; + fXh[nh++] = (double) tbin; fXh[nh++] = layer; - fXh[nh++] = float(adc); + fXh[nh++] = double(adc); fXh[nh++] = 0; // hpedestal2; fXh[nh++] = 0; // hpedwidth2; fXh[nh++] = corr; diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpacker.h b/offline/packages/tpc/TpcCombinedRawDataUnpacker.h index 8c8bfd353b..0dcb0e555e 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpacker.h +++ b/offline/packages/tpc/TpcCombinedRawDataUnpacker.h @@ -88,8 +88,8 @@ class TpcCombinedRawDataUnpacker : public SubsysReco struct chan_info { unsigned int fee = std::numeric_limits::max(); - float ped = -1; - float width = -1; + double ped = -1; + double width = -1; int entries = 0; }; TNtuple *m_ntup{nullptr}; @@ -113,7 +113,7 @@ class TpcCombinedRawDataUnpacker : public SubsysReco bool m_doChanHitsCut{false}; int m_ChanHitsCut{9999}; - float m_ped_sig_cut{4.0}; + double m_ped_sig_cut{4.0}; bool m_writeTree{false}; bool m_do_baseline_corr{false}; @@ -125,7 +125,7 @@ class TpcCombinedRawDataUnpacker : public SubsysReco std::map chan_map; // stays in place std::map feeadc_map; // histos reset after each event std::map> feeentries_map; // cleared after each event - std::map> feebaseline_map; // cleared after each event + std::map> feebaseline_map; // cleared after each event }; #endif // TPC_COMBINEDRAWDATAUNPACKER_H diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc index 0bb412197f..2e2cc693e6 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc +++ b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.cc @@ -34,6 +34,7 @@ #include #include +#include #include #include // for exit #include // for exit @@ -234,14 +235,8 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) TpcRawHit* tpchit = tpccont->get_hit(i); uint64_t gtm_bco = tpchit->get_gtm_bco(); - if (gtm_bco < bco_min) - { - bco_min = gtm_bco; - } - if (gtm_bco > bco_max) - { - bco_max = gtm_bco; - } + bco_min = std::min(gtm_bco, bco_min); + bco_max = std::max(gtm_bco, bco_max); int fee = tpchit->get_fee(); int channel = tpchit->get_channel(); @@ -303,8 +298,8 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) hit_set_key = TpcDefs::genHitSetKey(layer, (mc_sectors[sector % 12]), side); hit_set_container_itr = trkr_hit_set_container->findOrAddHitSet(hit_set_key); - float hpedestal = 0; - float hpedwidth = 0; + double hpedestal = 0; + double hpedwidth = 0; pedhist.Reset(); if (!m_do_zerosup) @@ -328,7 +323,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) if (!hit) { hit = new TrkrHitv2(); - hit->setAdc(float(adc)); + hit->setAdc(double(adc)); hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } @@ -362,7 +357,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) int hmaxbin = 0; for (int nbin = 1; nbin <= pedhist.GetNbinsX(); nbin++) { - float val = pedhist.GetBinContent(nbin); + double val = pedhist.GetBinContent(nbin); if (val > hmax) { hmaxbin = nbin; @@ -386,8 +381,8 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) for (int isum = -3; isum <= 3; isum++) { - float val = pedhist.GetBinContent(hmaxbin + isum); - float center = pedhist.GetBinCenter(hmaxbin + isum); + double val = pedhist.GetBinContent(hmaxbin + isum); + double center = pedhist.GetBinCenter(hmaxbin + isum); ibin_sum += center * val; ibin2_sum += center * center * val; adc_sum += val; @@ -467,12 +462,12 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) feehist->Fill(t, adc - hpedestal + pedestal_offset); } } - float threshold_cut = (hpedwidth * m_ped_sig_cut); + double threshold_cut = (hpedwidth * m_ped_sig_cut); if (m_do_zs_emulation) { threshold_cut = m_zs_threshold; } - if ((float(adc) - hpedestal) > threshold_cut) + if ((double(adc) - hpedestal) > threshold_cut) { hit_key = TpcDefs::genHitKey(phibin, (unsigned int) t); // find existing hit, or create new one @@ -482,11 +477,11 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) hit = new TrkrHitv2(); if (m_do_baseline_corr) { - hit->setAdc(float(adc) - hpedestal + pedestal_offset); + hit->setAdc(double(adc) - hpedestal + pedestal_offset); } else { - hit->setAdc(float(adc) - hpedestal); + hit->setAdc(double(adc) - hpedestal); } hit_set_container_itr->second->addHitSpecificKey(hit_key, hit); } @@ -505,10 +500,10 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) fXh[nh++] = 0; // channel; fXh[nh++] = 0; // sampadd; fXh[nh++] = 0; // sampch; - fXh[nh++] = (float) phibin; - fXh[nh++] = (float) t; + fXh[nh++] = (double) phibin; + fXh[nh++] = (double) t; fXh[nh++] = layer; - fXh[nh++] = (float(adc) - hpedestal + pedestal_offset); + fXh[nh++] = (double(adc) - hpedestal + pedestal_offset); fXh[nh++] = hpedestal; fXh[nh++] = hpedwidth; @@ -532,17 +527,17 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) if (hiter.second != nullptr) { TH2I* hist2d = hiter.second; - std::vector pedvec(hist2d->GetNbinsX(), 0); + std::vector pedvec(hist2d->GetNbinsX(), 0); feebaseline_map.insert(std::make_pair(hiter.first, pedvec)); - std::map>::iterator fee_blm_it = feebaseline_map.find(hiter.first); + std::map>::iterator fee_blm_it = feebaseline_map.find(hiter.first); (*fee_blm_it).second.resize(hist2d->GetNbinsX(), 0); for (int binx = 1; binx < hist2d->GetNbinsX(); binx++) { - double timebin = ((TAxis*) hist2d->GetXaxis())->GetBinCenter(binx); + double timebin = ( hist2d->GetXaxis())->GetBinCenter(binx); std::string histname1d = "h" + std::to_string(hiter.first) + "_" + std::to_string((int) timebin); TH1D* hist1d = hist2d->ProjectionY(histname1d.c_str(), binx, binx); - float local_ped = 0; + double local_ped = 0; #ifdef DEBUG // if((*hiter).first == 210802&&timebin==383){ @@ -562,8 +557,8 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) for (int isum = -3; isum <= 3; isum++) { - float val = hist1d->GetBinContent(maxbin + isum); - float center = hist1d->GetBinCenter(maxbin + isum); + double val = hist1d->GetBinContent(maxbin + isum); + double center = hist1d->GetBinCenter(maxbin + isum); hibin_sum += center * val; // hibin2_sum += center * center * val; hadc_sum += val; @@ -629,9 +624,9 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) unsigned int pad_key = create_pad_key(side, layer, phibin); - float fee = 0; - float hpedestal2 = 0; - float hpedwidth2 = 0; + double fee = 0; + double hpedestal2 = 0; + double hpedwidth2 = 0; std::map::iterator chan_it = chan_map.find(pad_key); if (chan_it != chan_map.end()) { @@ -642,10 +637,10 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) } int rx = get_rx(layer); - float corr = 0; + double corr = 0; unsigned int fee_key = create_fee_key(side, sector, rx, fee); - std::map>::iterator fee_blm_it = feebaseline_map.find(fee_key); + std::map>::iterator fee_blm_it = feebaseline_map.find(fee_key); if (fee_blm_it != feebaseline_map.end()) { corr = (*fee_blm_it).second[tbin] - pedestal_offset; @@ -694,14 +689,11 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) } if (hpedwidth2 > -100 && hpedestal2 > -100) { - if ((float(adc) - pedestal_offset - corr) > (hpedwidth2 * m_ped_sig_cut)) + if ((double(adc) - pedestal_offset - corr) > (hpedwidth2 * m_ped_sig_cut)) { - float nuadc = (float(adc) - corr - pedestal_offset); - if (nuadc < 0) - { - nuadc = 0; - } - hitr->second->setAdc(float(nuadc)); + double nuadc = (double(adc) - corr - pedestal_offset); + nuadc = std::max(nuadc, 0); + hitr->second->setAdc(nuadc); #ifdef DEBUG // hitr->second->setAdc(10); if (tbin == 383 && layer >= 7 + 32 && fee == 21) @@ -717,7 +709,7 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) << " phibin " << phibin << " adc " << adc << " corr: " << corr - << " adcnu " << (float(adc) - corr - pedestal_offset) + << " adcnu " << (double(adc) - corr - pedestal_offset) << " adc in " << hitr->second->getAdc() << std::endl; } @@ -737,10 +729,10 @@ int TpcCombinedRawDataUnpackerDebug::process_event(PHCompositeNode* topNode) fXh[nh++] = 0; // channel; fXh[nh++] = 0; // sampadd; fXh[nh++] = 0; // sampch; - fXh[nh++] = (float) phibin; - fXh[nh++] = (float) tbin; + fXh[nh++] = (double) phibin; + fXh[nh++] = (double) tbin; fXh[nh++] = layer; - fXh[nh++] = float(adc); + fXh[nh++] = double(adc); fXh[nh++] = hpedestal2; fXh[nh++] = hpedwidth2; fXh[nh++] = corr; diff --git a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.h b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.h index baca369042..dd68e55863 100644 --- a/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.h +++ b/offline/packages/tpc/TpcCombinedRawDataUnpackerDebug.h @@ -28,7 +28,7 @@ class TpcCombinedRawDataUnpackerDebug : public SubsysReco int End(PHCompositeNode *topNode) override; void writeTree() { m_writeTree = true; } void do_zero_suppression(bool b) { m_do_zerosup = b; } - void set_pedestalSigmaCut(float b) { m_ped_sig_cut = b; } + void set_pedestalSigmaCut(double b) { m_ped_sig_cut = b; } void do_noise_rejection(bool b) { m_do_noise_rejection = b; } void doBaselineCorr(bool val) { m_do_baseline_corr = val; } void doZSEmulation(bool val) { m_do_zs_emulation = val; } @@ -49,8 +49,8 @@ class TpcCombinedRawDataUnpackerDebug : public SubsysReco struct chan_info { unsigned int fee = std::numeric_limits::max(); - float ped = -1; - float width = -1; + double ped = -1; + double width = -1; }; unsigned int get_rx(unsigned int layer) { @@ -104,7 +104,7 @@ class TpcCombinedRawDataUnpackerDebug : public SubsysReco int FEE_map[26]{4, 5, 0, 2, 1, 11, 9, 10, 8, 7, 6, 0, 1, 3, 7, 6, 5, 4, 3, 2, 0, 2, 1, 3, 5, 4}; int FEE_R[26]{2, 2, 1, 1, 1, 3, 3, 3, 3, 3, 3, 2, 2, 1, 2, 2, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3}; - float m_ped_sig_cut{4.0}; + double m_ped_sig_cut{4.0}; bool m_writeTree{false}; bool m_do_zerosup{true}; @@ -117,7 +117,7 @@ class TpcCombinedRawDataUnpackerDebug : public SubsysReco std::string outfile_name; std::map chan_map; // stays in place std::map feeadc_map; // histos reset after each event - std::map> feebaseline_map; // cleared after each event + std::map> feebaseline_map; // cleared after each event }; #endif // TPC_COMBINEDRAWDATAUNPACKER_H diff --git a/offline/packages/tpc/TpcDistortionCorrection.cc b/offline/packages/tpc/TpcDistortionCorrection.cc index b759331e77..71b9ea8b2f 100644 --- a/offline/packages/tpc/TpcDistortionCorrection.cc +++ b/offline/packages/tpc/TpcDistortionCorrection.cc @@ -15,7 +15,7 @@ namespace { template - inline constexpr T square(const T& x) + constexpr T square(const T x) { return x * x; } diff --git a/offline/packages/tpc/TpcDistortionCorrectionContainer.cc b/offline/packages/tpc/TpcDistortionCorrectionContainer.cc new file mode 100644 index 0000000000..0202dd8ade --- /dev/null +++ b/offline/packages/tpc/TpcDistortionCorrectionContainer.cc @@ -0,0 +1,61 @@ + +/*! + * \file TpcDistortionCorrectionContainer.cc + * \brief stores distortion correction histograms on the node tree + * \author Hugo Pereira Da Costa + */ + +#include "TpcDistortionCorrectionContainer.h" + +#include +#include +#include + +#include +#include + +//_______________________________________________________________ +void TpcDistortionCorrectionContainer::load_histograms( const std::string& source ) +{ + std::cout << "TpcDistortionCorrectionContainer::load_histograms - reading corrections from " << source << std::endl; + auto *distortion_tfile = TFile::Open(source.c_str()); + if (!distortion_tfile) + { + std::cout << "TpcDistortionCorrectionContainer::load_histograms - cannot open " << source << std::endl; + exit(1); + } + + const std::array extension = {{"_negz", "_posz"}}; + for (int j = 0; j < 2; ++j) + { + m_hDPint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionP")+extension[j]).c_str())); + assert(m_hDPint[j]); + m_hDRint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionR")+extension[j]).c_str())); + assert(m_hDRint[j]); + m_hDZint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionZ")+extension[j]).c_str())); + assert(m_hDZint[j]); + } +} + +//_______________________________________________________________ +void TpcDistortionCorrectionContainer::save_histograms( const std::string& destination ) const +{ + // save everything to root file + std::cout << "TpcDistortionCorrectionContainer::save_histograms - writing histograms to " << destination << std::endl; + std::unique_ptr outputfile(TFile::Open(destination.c_str(), "RECREATE")); + outputfile->cd(); + + for (const auto& h_list : {m_hentries, m_hDRint, m_hDPint, m_hDZint}) + { + for (const auto& h : h_list) + { + if (h) + { + h->Write(h->GetName()); + } + } + } + + // close TFile + outputfile->Close(); +} diff --git a/offline/packages/tpc/TpcDistortionCorrectionContainer.h b/offline/packages/tpc/TpcDistortionCorrectionContainer.h index c7ba14937b..5d8dfa7988 100644 --- a/offline/packages/tpc/TpcDistortionCorrectionContainer.h +++ b/offline/packages/tpc/TpcDistortionCorrectionContainer.h @@ -8,6 +8,7 @@ */ #include +#include class TH1; @@ -17,11 +18,17 @@ class TpcDistortionCorrectionContainer //! constructor TpcDistortionCorrectionContainer() = default; + //! load histograms from input file + void load_histograms( const std::string& /*source*/ ); + + //! save histograms to out file + void save_histograms( const std::string& /*destination*/ ) const; + //! flag to tell us whether to read z data or just 2d data int m_dimensions = 3; bool m_use_scalefactor = false; - float m_scalefactor = 1.0; + double m_scalefactor = 1.0; //! set the phi histogram to be interpreted as radians rather than mm bool m_phi_hist_in_radians = true; diff --git a/offline/packages/tpc/TpcLoadDistortionCorrection.cc b/offline/packages/tpc/TpcLoadDistortionCorrection.cc index 0ce2ffa4e1..09ca916e42 100644 --- a/offline/packages/tpc/TpcLoadDistortionCorrection.cc +++ b/offline/packages/tpc/TpcLoadDistortionCorrection.cc @@ -56,9 +56,9 @@ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) { std::cout << "("<< i <<", "<(iter.findFirst("PHCompositeNode", "RUN")); + auto *runNode = dynamic_cast(iter.findFirst("PHCompositeNode", "RUN")); if (!runNode) { std::cout << "TpcLoadDistortionCorrection::InitRun - RUN Node missing, quitting" << std::endl; @@ -74,33 +74,17 @@ int TpcLoadDistortionCorrection::InitRun(PHCompositeNode* topNode) } // get distortion correction object and create if not found - auto distortion_correction_object = findNode::getClass(topNode, m_node_name[i]); + auto *distortion_correction_object = findNode::getClass(topNode, m_node_name[i]); if (!distortion_correction_object) { std::cout << "TpcLoadDistortionCorrection::InitRun - creating TpcDistortionCorrectionContainer in node " << m_node_name[i] << std::endl; distortion_correction_object = new TpcDistortionCorrectionContainer; - auto node = new PHDataNode(distortion_correction_object, m_node_name[i]); + auto *node = new PHDataNode(distortion_correction_object, m_node_name[i]); runNode->addNode(node); } - std::cout << "TpcLoadDistortionCorrection::InitRun - reading corrections from " << m_correction_filename[i] << std::endl; - auto distortion_tfile = TFile::Open(m_correction_filename[i].c_str()); - if (!distortion_tfile) - { - std::cout << "TpcLoadDistortionCorrection::InitRun - cannot open " << m_correction_filename[i] << std::endl; - exit(1); - } - - const std::array extension = {{"_negz", "_posz"}}; - for (int j = 0; j < 2; ++j) - { - distortion_correction_object->m_hDPint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionP")+extension[j]).c_str())); - assert(distortion_correction_object->m_hDPint[j]); - distortion_correction_object->m_hDRint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionR")+extension[j]).c_str())); - assert(distortion_correction_object->m_hDRint[j]); - distortion_correction_object->m_hDZint[j] = dynamic_cast(distortion_tfile->Get((std::string("hIntDistortionZ")+extension[j]).c_str())); - assert(distortion_correction_object->m_hDZint[j]); - } + // load histograms from file + distortion_correction_object->load_histograms(m_correction_filename[i]); // assign correction object dimension from histograms dimention, assuming all histograms have the same distortion_correction_object->m_dimensions = distortion_correction_object->m_hDPint[0]->GetDimension(); diff --git a/offline/packages/tpc/TpcLoadDistortionCorrection.h b/offline/packages/tpc/TpcLoadDistortionCorrection.h index 6727957487..276d18fec4 100644 --- a/offline/packages/tpc/TpcLoadDistortionCorrection.h +++ b/offline/packages/tpc/TpcLoadDistortionCorrection.h @@ -48,7 +48,7 @@ class TpcLoadDistortionCorrection : public SubsysReco } //! set the scale factor to be applied to the correction - void set_scale_factor(DistortionType i, float value) + void set_scale_factor(DistortionType i, double value) { m_use_scalefactor[i] = true; m_scalefactor[i] = value; @@ -97,7 +97,7 @@ class TpcLoadDistortionCorrection : public SubsysReco std::array m_use_scalefactor = {}; //! scale factors - std::array m_scalefactor = {1.0,1.0,1.0,1.0}; + std::array m_scalefactor = {1.0,1.0,1.0,1.0}; //! set the phi histogram to be interpreted as radians rather than mm std::array m_phi_hist_in_radians = {true,true,true,true}; diff --git a/offline/packages/tpc/TpcRawDataTree.cc b/offline/packages/tpc/TpcRawDataTree.cc index 6199fb7425..1141b5de55 100644 --- a/offline/packages/tpc/TpcRawDataTree.cc +++ b/offline/packages/tpc/TpcRawDataTree.cc @@ -61,7 +61,7 @@ int TpcRawDataTree::InitRun(PHCompositeNode * /*unused*/) m_SampleTree->Branch("nWaveormInFrame", &m_nWaveormInFrame, "nWaveormInFrame/I"); m_SampleTree->Branch("maxFEECount", &m_maxFEECount, "maxFEECount/I"); m_SampleTree->Branch("nSamples", &m_nSamples, "nSamples/I"); - m_SampleTree->Branch("adcSamples", &m_adcSamples[0], "adcSamples[nSamples]/s"); + m_SampleTree->Branch("adcSamples", m_adcSamples.data(), "adcSamples[nSamples]/s"); m_SampleTree->Branch("fee", &m_fee, "fee/I"); m_SampleTree->Branch("sampaAddress", &m_sampaAddress, "sampaAddress/I"); m_SampleTree->Branch("sampaChannel", &m_sampaChannel, "sampaChannel/I"); diff --git a/offline/packages/tpc/TpcRawWriter.cc b/offline/packages/tpc/TpcRawWriter.cc index 5d7711e2bb..bc217516d7 100644 --- a/offline/packages/tpc/TpcRawWriter.cc +++ b/offline/packages/tpc/TpcRawWriter.cc @@ -76,7 +76,7 @@ int TpcRawWriter::InitRun(PHCompositeNode *topNode) } // Create the Cluster node if required - auto trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); + auto *trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); if (!trkrclusters) { PHNodeIterator dstiter(dstNode); @@ -94,7 +94,7 @@ int TpcRawWriter::InitRun(PHCompositeNode *topNode) DetNode->addNode(TrkrClusterContainerNode); } - auto clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); + auto *clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); if (!clusterhitassoc) { PHNodeIterator dstiter(dstNode); @@ -116,7 +116,7 @@ int TpcRawWriter::InitRun(PHCompositeNode *topNode) if (!m_rawhits) { PHNodeIterator dstiter(dstNode); - auto DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); + auto *DetNode = dynamic_cast(dstiter.findFirst("PHCompositeNode", "TRKR")); if (!DetNode) { DetNode = new PHCompositeNode("TRKR"); @@ -124,7 +124,7 @@ int TpcRawWriter::InitRun(PHCompositeNode *topNode) } m_rawhits = new RawHitSetContainerv1; - auto newNode = new PHIODataNode(m_rawhits, "TRKR_RAWHITSET", "PHObject"); + auto *newNode = new PHIODataNode(m_rawhits, "TRKR_RAWHITSET", "PHObject"); DetNode->addNode(newNode); } @@ -311,7 +311,7 @@ int TpcRawWriter::process_event(PHCompositeNode *topNode) // count++; } std::cout << "processing tpc" << std::endl; - float tpc_zmax = m_tGeometry->get_max_driftlength() + m_tGeometry->get_CM_halfwidth(); + double tpc_zmax = m_tGeometry->get_max_driftlength() + m_tGeometry->get_CM_halfwidth(); // loop over the TPC HitSet objects TrkrHitSetContainer::ConstRange tpc_hitsetrange = m_hits->getHitSets(TrkrDefs::TrkrId::tpcId); @@ -405,7 +405,7 @@ int TpcRawWriter::process_event(PHCompositeNode *topNode) { continue; } - float_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 + double_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 unsigned short adc = 0; if (fadc > 0) { diff --git a/offline/packages/tpc/TpcSimpleClusterizer.cc b/offline/packages/tpc/TpcSimpleClusterizer.cc index f439d1d682..ec49c51aec 100644 --- a/offline/packages/tpc/TpcSimpleClusterizer.cc +++ b/offline/packages/tpc/TpcSimpleClusterizer.cc @@ -33,6 +33,7 @@ #include +#include #include #include // for sqrt, cos, sin #include @@ -46,7 +47,7 @@ namespace { template - inline constexpr T square(const T &x) + constexpr T square(const T &x) { return x * x; } @@ -63,7 +64,7 @@ namespace unsigned int layer = 0; int side = 0; unsigned int sector = 0; - float pedestal = 0; + double pedestal = 0; bool do_assoc = true; unsigned short phibins = 0; unsigned short phioffset = 0; @@ -142,22 +143,10 @@ namespace int iphi = iter.second.first + my_data.phioffset; int iz = iter.second.second + my_data.zoffset; - if (iphi > phibinhi) - { - phibinhi = iphi; - } - if (iphi < phibinlo) - { - phibinlo = iphi; - } - if (iz > zbinhi) - { - zbinhi = iz; - } - if (iz < zbinlo) - { - zbinlo = iz; - } + phibinhi = std::max(iphi, phibinhi); + phibinlo = std::min(iphi, phibinlo); + zbinhi = std::max(iz, zbinhi); + zbinlo = std::min(iz, zbinlo); // update phi sums double phi_center = my_data.layergeom->get_phicenter(iphi, my_data.side); @@ -205,7 +194,7 @@ namespace clusz -= (clusz < 0) ? my_data.par0_neg : my_data.par0_pos; // create cluster and fill - auto clus = new TrkrClusterv3; + auto *clus = new TrkrClusterv3; clus->setAdc(adc_sum); /// Get the surface key to find the surface from the map @@ -280,7 +269,7 @@ namespace void *ProcessSector(void *threadarg) { - auto my_data = (struct thread_data *) threadarg; + auto *my_data = (struct thread_data *) threadarg; const auto &pedestal = my_data->pedestal; const auto &phibins = my_data->phibins; @@ -303,7 +292,7 @@ namespace unsigned short phibin = TpcDefs::getPad(hitr->first) - phioffset; unsigned short zbin = TpcDefs::getTBin(hitr->first) - zoffset; - float_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 + double_t fadc = (hitr->second->getAdc()) - pedestal; // proper int rounding +0.5 // std::cout << " layer: " << my_data->layer << " phibin " << phibin << " zbin " << zbin << " fadc " << hitr->second->getAdc() << " pedestal " << pedestal << " fadc " << std::endl unsigned short adc = 0; @@ -332,11 +321,11 @@ namespace all_hit_map.insert(std::make_pair(adc, thisHit)); } // adcval[phibin][zbin] = (unsigned short) adc; - adcval[phibin][zbin] = (unsigned short) adc; + adcval[phibin][zbin] = adc; } } - while (all_hit_map.size() > 0) + while (!all_hit_map.empty()) { auto iter = all_hit_map.rbegin(); if (iter == all_hit_map.rend()) @@ -413,7 +402,7 @@ int TpcSimpleClusterizer::InitRun(PHCompositeNode *topNode) } // Create the Cluster node if required - auto trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); + auto *trkrclusters = findNode::getClass(dstNode, "TRKR_CLUSTER"); if (!trkrclusters) { PHNodeIterator dstiter(dstNode); @@ -431,7 +420,7 @@ int TpcSimpleClusterizer::InitRun(PHCompositeNode *topNode) DetNode->addNode(TrkrClusterContainerNode); } - auto clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); + auto *clusterhitassoc = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); if (!clusterhitassoc) { PHNodeIterator dstiter(dstNode); @@ -614,7 +603,7 @@ int TpcSimpleClusterizer::process_event(PHCompositeNode *topNode) const auto ckey = TrkrDefs::genClusKey(hitsetkey, index); // get cluster - auto cluster = data.cluster_vector[index]; + auto *cluster = data.cluster_vector[index]; // insert in map m_clusterlist->addClusterSpecifyKey(ckey, cluster); diff --git a/offline/packages/tpc/TrainingHits.cc b/offline/packages/tpc/TrainingHits.cc index 3a70db0854..20a810b225 100644 --- a/offline/packages/tpc/TrainingHits.cc +++ b/offline/packages/tpc/TrainingHits.cc @@ -1,17 +1,17 @@ #include "TrainingHits.h" TrainingHits::TrainingHits() + : radius(0.) + , phi(0.) + , z(0.) + , phistep(0.) + , zstep(0.) + , layer(0) + , ntouch(0) + , nedge(0) + , cluskey(0) { v_adc.fill(0); - radius = 0.; - phi = 0.; - z = 0.; - phistep = 0.; - zstep = 0.; - layer = 0; - ntouch = 0; - nedge = 0; - cluskey = 0; } void TrainingHits::Reset() diff --git a/offline/packages/tpc/TrainingHitsContainer.h b/offline/packages/tpc/TrainingHitsContainer.h index 28345adf57..33f38fe36a 100644 --- a/offline/packages/tpc/TrainingHitsContainer.h +++ b/offline/packages/tpc/TrainingHitsContainer.h @@ -1,14 +1,15 @@ #ifndef TRAININGHITSCONTAINER_H #define TRAININGHITSCONTAINER_H -#include #include "TrainingHits.h" +#include + class TrainingHitsContainer : public PHObject { public: TrainingHitsContainer(); - ~TrainingHitsContainer() override {} + ~TrainingHitsContainer() override = default; void Reset() override; std::vector v_hits; diff --git a/offline/packages/tpccalib/Makefile.am b/offline/packages/tpccalib/Makefile.am index faf8c05386..394740acea 100644 --- a/offline/packages/tpccalib/Makefile.am +++ b/offline/packages/tpccalib/Makefile.am @@ -32,12 +32,15 @@ libtpccalib_la_LIBADD = \ -lodbc++ \ -lSubsysReco \ -lg4detectors_io \ + -lmicromegas_io \ -ltrack_io \ -ltrackbase_historic_io \ -ltrack_reco \ -ltpc_io pkginclude_HEADERS = \ + MicromegasDriftEvaluator.h \ + SiliconDriftEvaluator.h \ TpcDirectLaserReconstruction.h \ TpcSpaceChargeMatrixContainer.h \ TpcSpaceChargeMatrixContainerv1.h \ @@ -50,15 +53,15 @@ pkginclude_HEADERS = \ ROOTDICTS = \ + MicromegasDriftEvaluator_Dict.cc \ + SiliconDriftEvaluator_Dict.cc \ TpcSpaceChargeMatrixContainer_Dict.cc \ TpcSpaceChargeMatrixContainerv1_Dict.cc \ TpcSpaceChargeMatrixContainerv2_Dict.cc pcmdir = $(libdir) -nobase_dist_pcm_DATA = \ - TpcSpaceChargeMatrixContainer_Dict_rdict.pcm \ - TpcSpaceChargeMatrixContainerv1_Dict_rdict.pcm \ - TpcSpaceChargeMatrixContainerv2_Dict_rdict.pcm +# more elegant way to create pcm files (without listing them) +nobase_dist_pcm_DATA = $(ROOTDICTS:.cc=_rdict.pcm) libtpccalib_io_la_SOURCES = \ $(ROOTDICTS) \ @@ -66,6 +69,8 @@ libtpccalib_io_la_SOURCES = \ TpcSpaceChargeMatrixContainerv2.cc libtpccalib_la_SOURCES = \ + MicromegasDriftEvaluator.cc \ + SiliconDriftEvaluator.cc \ TpcDirectLaserReconstruction.cc \ TpcSpaceChargeMatrixInversion.cc \ TpcSpaceChargeReconstructionHelper.cc \ diff --git a/offline/packages/tpccalib/MicromegasDriftEvaluator.cc b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc new file mode 100644 index 0000000000..0a57bd2315 --- /dev/null +++ b/offline/packages/tpccalib/MicromegasDriftEvaluator.cc @@ -0,0 +1,637 @@ +#include "MicromegasDriftEvaluator.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace +{ + + template + class range_adaptor + { + public: + explicit range_adaptor(const T& range) + : m_range(range) + { + } + const typename T::first_type& begin() { return m_range.first; } + const typename T::second_type& end() { return m_range.second; } + + private: + T m_range; + }; + + template + constexpr T square(T x) + { + return x * x; + } + template + inline T get_r(T x, T y) + { + return std::sqrt(square(x) + square(y)); + } + + double normalize_angle(double phi) + { + while (phi < 0) + { + phi += 2 * M_PI; + } + while (phi >= 2 * M_PI) + { + phi -= 2 * M_PI; + } + return phi; + } + + bool phi_in_range(double phi, double min, double max) + { + phi = normalize_angle(phi); + min = normalize_angle(min); + max = normalize_angle(max); + return (min < max) ? (phi >= min && phi <= max) + : (phi >= min || phi <= max); + } + + // This function is identical to the version in MicromegasTrackEvaluator_hp.cc + + bool helix_plane_intersection( + double t_min, + double t_max, + double zmin, + double zmax, + double R, + double X0, + double Y0, + double intersect_rz, + double slope_rz, + const TVector3& ptile, + const TVector3& ntile, + TVector3& intersect) + { + // Number of iterations and tolerance for Newton Raphson method + const int max_iter = 10; + const double tol = 1e-6; + + // Define C + double C = ntile.X() * (X0 - ptile.X()) + ntile.Y() * (Y0 - ptile.Y()) + ntile.Z() * (intersect_rz - ptile.Z()); + + // Defines the function and the corresponding derivative to be used in the Newton Raphson method + auto f = [&](double t) + { + double xt = X0 + R * std::cos(t); + double yt = Y0 + R * std::sin(t); + double Rt = std::sqrt(xt * xt + yt * yt); + return ntile.X() * R * std::cos(t) + ntile.Y() * R * std::sin(t) + ntile.Z() * slope_rz * Rt + C; + }; + + auto df = [&](double t) + { + double xt = X0 + R * std::cos(t); + double yt = Y0 + R * std::sin(t); + double Rt = std::sqrt(xt * xt + yt * yt); + return -ntile.X() * R * std::sin(t) + ntile.Y() * R * std::cos(t) + ntile.Z() * R * slope_rz * (Y0 * std::cos(t) - X0 * std::sin(t)) / Rt; + }; + + auto solve_from = [&](double t_seed, TVector3& result) -> bool + { + double t = t_seed; + for (int i = 0; i < max_iter; ++i) + { + double ft = f(t); + double dft = df(t); + if (std::abs(dft) < 1e-8) + { + return false; + } + double t_new = t - ft / dft; + + double x = X0 + R * std::cos(t_new); + double y = Y0 + R * std::sin(t_new); + double Rt_n = std::sqrt(x * x + y * y); + double z = slope_rz * Rt_n + intersect_rz; + double phi = std::atan2(y, x); + + TVector3 cand(x, y, z); + bool phi_ok = phi_in_range(phi, t_min - 1e-4, t_max + 1e-4); + bool z_ok = (z >= zmin - 1e-4 && z <= zmax + 1e-4); + bool proj_ok = (std::abs(ntile.Dot(cand - ptile)) <= 0.05); + + if (std::abs(t_new - t) < tol && proj_ok && phi_ok && z_ok) + { + result = cand; + return true; + } + t = t_new; + } + return false; + }; + + auto wrap = [&](double t) + { + while (t > t_max) + { + t -= 2 * M_PI; + } + while (t < t_min) + { + t += 2 * M_PI; + } + return t; + }; + + std::vector t_seeds; + double t_center = 0.5 * (t_min + t_max); + double delta = 2.0 * M_PI / 3.0; + + // Wrap the angle + for (int i = 0; i < 3; ++i) + { + double t = wrap(t_center + i * delta); + t_seeds.push_back(t); + } + + // Looks for the solution within the tile acceptance in three different phi seeds in the Newton-Raphson (helix_plane could have more than one solution) + for (double t_seed : t_seeds) + { + if (solve_from(t_seed, intersect)) + { + return true; + } + } + return false; + } + + // this is a piecewise fit function for the drift velocity plot + double fit_function_2d(double* x, double* par) + { + const int itile = static_cast(std::floor(x[0])); + const double z = x[1]; + if (itile < 0 || itile >= 8) + { + TF2::RejectPoint(); + return 0.; + } + return par[itile + 1] + par[0] * z; + } + +// root fitting does not like const parameters suggested by clang-tidy +// using NOLINT to suppress this warning + double linear_function(double* x, double* par) // NOLINT(readability-non-const-parameter) + { + return par[0] * x[0] + par[1]; + } + + const std::array k_tile_names = + {"SCOZ", "SCIZ", "NCIZ", "NCOZ", "SEZ", "NEZ", "SWZ", "NWZ"}; + +} // namespace + +MicromegasDriftEvaluator::MicromegasDriftEvaluator(const std::string& name) + : SubsysReco(name) +{ +} + +// --------------------------------------------------------------------------- +int MicromegasDriftEvaluator::Init(PHCompositeNode* topNode) +{ + std::cout << Name() << "::Init" + << " drift_velocity=" << m_drift_velocity << " cm/ns" + << " min_tpc_layer=" << m_min_tpc_layer + << " max_tpc_layer=" << m_max_tpc_layer + << std::endl; + + PHNodeIterator iter(topNode); + auto* dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cerr << Name() << "::Init - DST node missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + iter = PHNodeIterator(dstNode); + auto* evalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "EVAL")); + if (!evalNode) + { + evalNode = new PHCompositeNode("EVAL"); + dstNode->addNode(evalNode); + } + + auto* newNode = new PHIODataNode(new Container, "MicromegasDriftEvaluator::Container", "PHObject"); + newNode->SplitLevel(99); + evalNode->addNode(newNode); + + m_hist3D = new TH3F("MicromegasDriftEval_hist3D", ";tile;z_{track} (cm);#Deltaz (track#minuscluster) (cm)", 8, 0, 8, 220, -110, 110, 100, -10, 10); + m_hist3D->SetDirectory(nullptr); + + return Fun4AllReturnCodes::EVENT_OK; +} + +// --------------------------------------------------------------------------- +int MicromegasDriftEvaluator::InitRun(PHCompositeNode* topNode) +{ + return load_nodes(topNode); +} + +// --------------------------------------------------------------------------- +int MicromegasDriftEvaluator::process_event(PHCompositeNode* topNode) +{ + const auto res = load_nodes(topNode); + if (res != Fun4AllReturnCodes::EVENT_OK) + { + return res; + } + + if (m_container) + { + m_container->Reset(); + } + evaluate_tracks(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +// --------------------------------------------------------------------------- +int MicromegasDriftEvaluator::End(PHCompositeNode* /*topNode*/) +{ + if (!m_hist3D) + { + std::cerr << Name() << "::End - histogram not found, skipping fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + const int nEntries = static_cast(m_hist3D->GetEntries()); + std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; + + auto* h_fit = new TH2F("h_fit", "", 8, 0, 8, 220, -110, 110); + h_fit->SetDirectory(nullptr); + + for (int j = 0; j < 8; ++j) + { + m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); + auto* h2d = static_cast(m_hist3D->Project3D("zy")); + h2d->SetName(std::format("h_{}", k_tile_names[j]).c_str()); + h2d->SetDirectory(nullptr); + + // Fit vertical slices; require a minimum of 10 entries per slice + h2d->FitSlicesY(nullptr, 0, -1, 10); + auto* h_mean = static_cast(gDirectory->Get(std::format("h_{}_1", k_tile_names[j]).c_str())); + + if (!h_mean) + { + delete h2d; + continue; + } + + for (int i = 0; i < h_mean->GetNbinsX(); ++i) + { + const double entries = h2d->Integral(i + 1, i + 1, 1, m_hist3D->GetNbinsZ()); + if (entries > 0) + { + h_fit->SetBinContent(j + 1, i + 1, h_mean->GetBinContent(i + 1)); + } + } + delete h2d; + } + + m_hist3D->GetXaxis()->SetRange(0, 0); + + // This part fits the 8 micromegas modules one at a time but constrains the slopes to be identical. This eliminates the need for perfect translational TPOT alignment + auto* fit2d = new TF2("fit2d", fit_function_2d, 0, 8, -110, 110, 9); + for (int i = 0; i < 9; ++i) + { + fit2d->SetParameter(i, 0.0); + } + + h_fit->Fit(fit2d, "0R"); + + const double slope = fit2d->GetParameter(0); + const double slope_err = fit2d->GetParError(0); + const double new_drift = m_drift_velocity / (1.0 + slope); + const double drift_err = m_drift_velocity / std::pow(1.0 + slope, 2) * slope_err; + + std::cout << Name() << "::End" << " slope=" << slope << " input_drift=" << m_drift_velocity << " cm/ns" << " new_drift=" << new_drift << " cm/ns +/- " << drift_err << " cm/ns" << std::endl; + + // Plot the whole thing + auto* canvas = new TCanvas("drift_calib", "Drift velocity calibration", 2000, 1000); + canvas->Divide(4, 2); + + for (int j = 0; j < 8; ++j) + { + canvas->cd(j + 1); + + m_hist3D->GetXaxis()->SetRange(j + 1, j + 1); + auto* h2d = static_cast(m_hist3D->Project3D("zy")); + h2d->SetName(std::format("hplot_{}", k_tile_names[j]).c_str()); + h2d->SetTitle(std::format("{};z_{{track}} (cm);#Deltaz (track#minuscluster) (cm)", k_tile_names[j]).c_str()); + h2d->SetStats(false); + h2d->Draw("COLZ"); + + auto* h_fit_proj = h_fit->ProjectionY(std::format("h_fit_proj_{}", j).c_str(), j + 1, j + 1); // These give you the Gaussian means for each slice + h_fit_proj->SetMarkerStyle(20); + h_fit_proj->SetMarkerColor(kRed); + h_fit_proj->SetLineColor(kBlack); + + auto* f1d = new TF1(std::format("f1d_{}", j).c_str(), linear_function, -110, 110, 2); + f1d->SetParameter(0, slope); + f1d->SetParameter(1, fit2d->GetParameter(j + 1)); + f1d->SetLineColor(kGreen + 2); + f1d->SetLineWidth(2); + f1d->Draw("same"); + + auto* leg = new TLegend(0.35, 0.75, 0.92, 0.92); + leg->SetHeader(std::format("{} entries, v_{{in}}={:.2f} m/ms", nEntries, m_drift_velocity * 1e4).c_str(), "C"); + leg->AddEntry(h_fit_proj, "Gaussian slice mean", "p"); + leg->AddEntry(f1d, std::format("slope={:.4f} v_{{new}}={:.3f}#pm{:.3f} m/ms", slope, new_drift * 1e4, drift_err * 1e4).c_str(), "l"); + leg->Draw(); + } + + m_hist3D->GetXaxis()->SetRange(0, 0); + + canvas->SaveAs(m_plot_filename.c_str()); + std::cout << Name() << "::End - QA canvas saved to " << m_plot_filename << std::endl; + + // write histograms, fit and results to a ROOT file + if (!m_root_filename.empty()) + { + std::unique_ptr outfile(TFile::Open(m_root_filename.c_str(), "RECREATE")); + if (outfile && !outfile->IsZombie()) + { + outfile->cd(); + m_hist3D->Write(); + h_fit->Write("h_fit_micromegas"); + fit2d->Write(); + canvas->Write(); + TParameter("slope", slope).Write(); + TParameter("drift_velocity_in", m_drift_velocity).Write(); + TParameter("drift_velocity_new", new_drift).Write(); + TParameter("drift_velocity_err", drift_err).Write(); + outfile->Close(); + std::cout << Name() << "::End - histograms and fit results saved to " << m_root_filename << std::endl; + } + else + { + std::cerr << Name() << "::End - could not open " << m_root_filename << " for writing." << std::endl; + } + } + + delete canvas; + delete fit2d; + delete h_fit; + + return Fun4AllReturnCodes::EVENT_OK; +} + +// --------------------------------------------------------------------------- +int MicromegasDriftEvaluator::load_nodes(PHCompositeNode* topNode) +{ + m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); + assert(m_tGeometry); + + m_micromegas_geomcontainer = findNode::getClass(topNode, "CYLINDERGEOM_MICROMEGAS_FULL"); + assert(m_micromegas_geomcontainer); + + m_track_map = findNode::getClass(topNode, m_trackmapname); + + m_cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + assert(m_cluster_map); + + m_container = findNode::getClass(topNode, "MicromegasDriftEvaluator::Container"); + assert(m_container); + + m_globalPositionWrapper.loadNodes(topNode); + + return Fun4AllReturnCodes::EVENT_OK; +} + +// --------------------------------------------------------------------------- +void MicromegasDriftEvaluator::evaluate_tracks() +{ + if (!(m_tGeometry && m_micromegas_geomcontainer && m_track_map && m_cluster_map && m_container && m_hist3D)) + { + return; + } + + m_container->clear_tracks(); + + for (const auto& [track_id, track] : *m_track_map) + { + // valid crossing + const auto crossing = track->get_crossing(); + if (crossing == SHRT_MAX) + { + continue; + } + + std::vector tpc_positions; + + // Also count clusters per subsystem for the cuts + unsigned int n_tpc = 0; + unsigned int n_mvtx = 0; + unsigned int n_intt = 0; + unsigned int n_mm = 0; + + for (const auto* seed : {track->get_silicon_seed(), track->get_tpc_seed()}) + { + if (!seed) + { + continue; + } + for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) + { + const auto ckey = *it; + const auto detid = TrkrDefs::getTrkrId(ckey); + const auto layer = TrkrDefs::getLayer(ckey); + + switch (detid) + { + case TrkrDefs::tpcId: + ++n_tpc; + if (layer >= m_min_tpc_layer && layer < m_max_tpc_layer) + { + auto* const cl = m_cluster_map->findCluster(ckey); + if (cl) + { + tpc_positions.push_back( + m_globalPositionWrapper.getGlobalPositionDistortionCorrected( + ckey, cl, crossing)); + } + } + break; + case TrkrDefs::mvtxId: + ++n_mvtx; + break; + case TrkrDefs::inttId: + ++n_intt; + break; + case TrkrDefs::micromegasId: + ++n_mm; + break; + default: + break; + } + } + } + + // need at least 3 TPC clusters in range + if (tpc_positions.size() < 3) + { + continue; + } + + const auto [slope_rz, intersect_rz] = TrackFitUtils::line_fit(tpc_positions); + const auto [R, X0, Y0] = TrackFitUtils::circle_fit_by_taubin(tpc_positions); + + // reject badly reconstructed / low-pT tracks + if (R < 40.0) + { + continue; + } + + const auto mm_range = m_micromegas_geomcontainer->get_begin_end(); + for (const auto& [mm_layer, base_layergeom] : range_adaptor(mm_range)) + { + const auto* layergeom = static_cast(base_layergeom); + assert(layergeom); + + // skip the phi layer. Only the z-view layer matters here + if (layergeom->get_segmentation_type() != + MicromegasDefs::SegmentationType::SEGMENTATION_Z) + { + continue; + } + + const double layer_radius = layergeom->get_radius(); + auto [xplus, yplus, xminus, yminus] = + TrackFitUtils::circle_circle_intersection(layer_radius, R, X0, Y0); + + if (!std::isfinite(xplus)) + { + continue; + } + + // pick the solution closest in phi to the last TPC cluster + const double last_phi = std::atan2(tpc_positions.back().y(), tpc_positions.back().x()); + const double phi_plus = std::atan2(yplus, xplus); + const double phi_minus = std::atan2(yminus, xminus); + const double phi = (std::abs(last_phi - phi_plus) < std::abs(last_phi - phi_minus)) ? phi_plus : phi_minus; + + const double r_cyl = layer_radius; + const double z_cyl = intersect_rz + slope_rz * r_cyl; + const TVector3 world_cyl(r_cyl * std::cos(phi), r_cyl * std::sin(phi), z_cyl); + + const int tileid = layergeom->find_tile_cylindrical(world_cyl); + if (tileid < 0) + { + continue; + } + + const auto tile_center = layergeom->get_world_from_local_coords(tileid, m_tGeometry, {0, 0}); + const TVector3 ptile(tile_center.x(), tile_center.y(), tile_center.z()); + + const auto tile_norm = layergeom->get_world_from_local_vect(tileid, m_tGeometry, {0, 0, 1}); + const TVector3 ntile(tile_norm.x(), tile_norm.y(), tile_norm.z()); + + const auto phi_range = layergeom->get_phi_range(tileid, m_tGeometry); + const double zmin = layergeom->get_zmin(); + const double zmax = layergeom->get_zmax(); + + TVector3 intersection; + if (!helix_plane_intersection(phi_range.first, phi_range.second, zmin, zmax, R, X0, Y0, intersect_rz, slope_rz, ptile, ntile, intersection)) + { + continue; + } + + const auto local_intersection = layergeom->get_local_from_world_coords(tileid, m_tGeometry, {intersection.x(), intersection.y(), intersection.z()}); + const double y_local = local_intersection.y(); + + if (std::abs(y_local) > m_y_local_cut) + { + continue; + } + + // find the nearest TPOT cluster + const auto hitsetkey = MicromegasDefs::genHitSetKey(mm_layer, MicromegasDefs::SegmentationType::SEGMENTATION_Z, tileid); + const auto clusrange = m_cluster_map->getClusters(hitsetkey); + + double dmin = -1; + ClusterStruct best_cluster; + + for (const auto& [ckey, cl] : range_adaptor(clusrange)) + { + const double cl_y_local = cl->getLocalY(); + const double d = std::abs(y_local - cl_y_local); + if (dmin < 0 || d < dmin) + { + dmin = d; + const auto gpos = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(ckey, cl, crossing); + best_cluster._layer = mm_layer; + best_cluster._tile = tileid; + best_cluster._z = gpos.z(); + } + } + + // require cluster within the z search window + if (dmin < 0 || dmin > m_z_search_win) + { + continue; + } + + // fill track struct and histogram + TrackStruct track_struct; + track_struct._chisquare = track->get_chisq(); + track_struct._ndf = track->get_ndf(); + track_struct._nclusters_tpc = n_tpc; + track_struct._nclusters_mvtx = n_mvtx; + track_struct._nclusters_intt = n_intt; + track_struct._nclusters_micromegas = n_mm; + + track_struct._trk_state_z._layer = mm_layer; + track_struct._trk_state_z._tile = tileid; + track_struct._trk_state_z._z = intersection.z(); + track_struct._trk_state_z._y_local = y_local; + + track_struct._found_cluster_z = best_cluster; + + const double z_track = track_struct._trk_state_z._z; + const double z_cluster = track_struct._found_cluster_z._z; + m_hist3D->Fill(tileid + 0.5, z_track, z_track - z_cluster); + + m_container->add_track(track_struct); + break; + } + } +} diff --git a/offline/packages/tpccalib/MicromegasDriftEvaluator.h b/offline/packages/tpccalib/MicromegasDriftEvaluator.h new file mode 100644 index 0000000000..43bb4393e9 --- /dev/null +++ b/offline/packages/tpccalib/MicromegasDriftEvaluator.h @@ -0,0 +1,148 @@ +#ifndef TPCCALIB_MICROMEGASDRIFTEVALUATOR_H +#define TPCCALIB_MICROMEGASDRIFTEVALUATOR_H + +/* + * Bade Sayki June 10th, 2026 -- LANL + * This module is created to calibrate the drift velocity in the TPC by fitting a helix to the clusters within a certain layer range, and projecting it to the TPOT z view module plane. The default layers in the TPC are set to be 39-55, which correspond to R3. + * This is heavily inspired by and distilled from Dr. Hugo Pereira Da Costa's MicromegasTrackEvaluator_hp module. It is meant to be a more lightweight and specialized version. + * It accumulates a TH3F(tile, z_track, dz) histogram during process_event, then in End() fits a piecewise function to suggest an updated drift velocity. + * If you have any questions, please feel free to message me on mattermost. + * Claude Code tool was used to format and comment this module. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +class ActsGeometry; +class PHG4CylinderGeomContainer; +class TH3; +class TrkrCluster; +class TrkrClusterContainer; +class SvtxTrackMap; + +class MicromegasDriftEvaluator : public SubsysReco +{ + public: + explicit MicromegasDriftEvaluator(const std::string& name = "MicromegasDriftEvaluator"); + + int Init(PHCompositeNode*) override; + int InitRun(PHCompositeNode*) override; + int process_event(PHCompositeNode*) override; + int End(PHCompositeNode*) override; + + struct TrackStateStruct + { + unsigned short _layer {0}; + unsigned short _tile {0}; + double _z {0}; + double _y_local {0}; + }; + + struct ClusterStruct + { + unsigned short _layer {0}; + unsigned short _tile {0}; + double _z {0}; + }; + + struct TrackStruct + { + float _chisquare {0}; + int _ndf {0}; + + unsigned int _nclusters_tpc {0}; + unsigned int _nclusters_mvtx {0}; + unsigned int _nclusters_intt {0}; + unsigned int _nclusters_micromegas {0}; + + TrackStateStruct _trk_state_z; + ClusterStruct _found_cluster_z; + + using List = std::vector; + }; + + class Container : public PHObject + { + public: + explicit Container() = default; + Container(const Container&) = delete; + Container& operator=(const Container&) = delete; + + void Reset() override { _tracks.clear(); } + + const TrackStruct::List& tracks() const { return _tracks; } + void add_track(const TrackStruct& t) { _tracks.push_back(t); } + void clear_tracks() { _tracks.clear(); } + + private: + TrackStruct::List _tracks; + + TrackStateStruct _unused_state; + ClusterStruct _unused_cluster; + + ClassDefOverride(Container, 1) + }; + + void set_trackmapname(const std::string& value) { m_trackmapname = value; } + + /// This function is specifically used to give the fitting function a starting point. Use the initial drift velocity you used when reconstructing. + void set_drift_velocity(double value) { m_drift_velocity = value; } + + /// TPC layer range used for the helix fit. The default is R3, but this is an area with huge static distortions. It can easily be adjusted in the Fun4All macro with these functions. + void set_min_tpc_layer(unsigned int value) { m_min_tpc_layer = value; } + void set_max_tpc_layer(unsigned int value) { m_max_tpc_layer = value; } + + /// This one rejects track states near tile edge + void set_y_local_cut(double value) { m_y_local_cut = value; } + + /// Search window to match a Micromegas cluster to the prediction + void set_z_search_window(double value) { m_z_search_win = value; } + + /// Output filename for the QA plot. Make this a .png + void set_plot_filename(const std::string& value) { m_plot_filename = value; } + + /// Output ROOT filename for histograms and fit results. + void set_root_filename(const std::string& value) { m_root_filename = value; } + + /// If true (default), append -- to output filenames, following sPHENIX convention + void set_add_run_segment(bool value) { m_add_run_segment = value; } + + /// Manually set the segment number used in output filenames (otherwise parsed from the input filename) + void set_segment(int value) { m_segment = value; } + + private: + int load_nodes(PHCompositeNode*); + std::string make_output_filename(const std::string&) const; + void evaluate_tracks(); + + Container* m_container {nullptr}; + ActsGeometry* m_tGeometry {nullptr}; + TpcGlobalPositionWrapper m_globalPositionWrapper; + PHG4CylinderGeomContainer* m_micromegas_geomcontainer {nullptr}; + TrkrClusterContainer* m_cluster_map {nullptr}; + SvtxTrackMap* m_track_map {nullptr}; + + std::string m_trackmapname {"SvtxTrackMap"}; + + // These are all adjustable in your F4A macro. You should probably put in a better m_plot_filename. + double m_drift_velocity {0.00747}; + unsigned int m_min_tpc_layer {39}; + unsigned int m_max_tpc_layer {55}; + double m_y_local_cut {22.0}; + double m_z_search_win {3.0}; + std::string m_plot_filename {"micromegas_drift_calib.png"}; + std::string m_root_filename {"micromegas_drift_calib.root"}; + bool m_add_run_segment {true}; + int m_segment {-1}; + + TH3* m_hist3D {nullptr}; +}; + +#endif diff --git a/offline/packages/tpccalib/MicromegasDriftEvaluatorLinkDef.h b/offline/packages/tpccalib/MicromegasDriftEvaluatorLinkDef.h new file mode 100644 index 0000000000..1c864da87a --- /dev/null +++ b/offline/packages/tpccalib/MicromegasDriftEvaluatorLinkDef.h @@ -0,0 +1,6 @@ +#ifdef __CINT__ + +#pragma link C++ class MicromegasDriftEvaluator::Container+; + +#endif + diff --git a/offline/packages/tpccalib/PHTpcResiduals.cc b/offline/packages/tpccalib/PHTpcResiduals.cc index 54bcb5b42e..7d8ec8e095 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.cc +++ b/offline/packages/tpccalib/PHTpcResiduals.cc @@ -128,6 +128,8 @@ namespace PHTpcResiduals::PHTpcResiduals(const std::string& name) : SubsysReco(name) , m_matrix_container(new TpcSpaceChargeMatrixContainerv2) + , m_matrix_container_pos(new TpcSpaceChargeMatrixContainerv2) + , m_matrix_container_neg(new TpcSpaceChargeMatrixContainerv2) { } @@ -139,6 +141,7 @@ int PHTpcResiduals::Init(PHCompositeNode* /*topNode*/) std::cout << "PHTpcResiduals::Init - m_maxTBeta: " << m_maxTBeta << std::endl; std::cout << "PHTpcResiduals::Init - m_maxResidualDrphi: " << m_maxResidualDrphi << " cm" << std::endl; std::cout << "PHTpcResiduals::Init - m_maxResidualDz: " << m_maxResidualDz << " cm" << std::endl; + std::cout << "PHTpcResiduals::Init - m_ignoreEdgeClusters: " << m_ignoreEdgeClusters << std::endl; std::cout << "PHTpcResiduals::Init - m_minRPhiErr: " << m_minRPhiErr << " cm" << std::endl; std::cout << "PHTpcResiduals::Init - m_minZErr: " << m_minZErr << " cm" << std::endl; std::cout << "PHTpcResiduals::Init - m_minPt: " << m_minPt << " GeV/c" << std::endl; @@ -186,11 +189,25 @@ int PHTpcResiduals::End(PHCompositeNode* /*topNode*/) std::cout << "PHTpcResiduals::End - writing matrices to " << m_outputfile << std::endl; // save matrix container in output file - if (m_matrix_container) + if (m_matrix_container || m_matrix_container_pos || m_matrix_container_neg) { std::unique_ptr outputfile(TFile::Open(m_outputfile.c_str(), "RECREATE")); outputfile->cd(); - m_matrix_container->Write("TpcSpaceChargeMatrixContainer"); + + if( m_matrix_container ) { + std::cout << "PHTpcResiduals::End - writing TpcSpaceChargeMatrixContainer object. entries: " << m_matrix_container->get_entries() << std::endl; + m_matrix_container->Write("TpcSpaceChargeMatrixContainer"); + } + + if( m_matrix_container_pos ) { + std::cout << "PHTpcResiduals::End - writing TpcSpaceChargeMatrixContainer_pos object. entries: " << m_matrix_container_pos->get_entries() << std::endl; + m_matrix_container_pos->Write("TpcSpaceChargeMatrixContainer_pos"); + } + + if( m_matrix_container_neg ) { + std::cout << "PHTpcResiduals::End - writing TpcSpaceChargeMatrixContainer_neg object. entries: " << m_matrix_container_neg->get_entries() << std::endl; + m_matrix_container_neg->Write("TpcSpaceChargeMatrixContainer_neg"); + } } // print counters @@ -456,8 +473,6 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) for (const auto& cluskey : get_cluster_keys(track)) { - // increment counter - ++m_total_clusters; // make sure cluster is from TPC const auto detId = TrkrDefs::getTrkrId(cluskey); @@ -466,6 +481,10 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) continue; } + // increment counter + /* only counts TPC clusters */ + ++m_total_clusters; + // find matching track state const auto stateiter = std::find_if( track->begin_states(), track->end_states(), [&cluskey]( const auto& state_pair ) { return state_pair.second->get_cluskey() == cluskey; } ); @@ -478,6 +497,14 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) // calculate residuals with respect to cluster auto* const cluster = m_clusterContainer->findCluster(cluskey); + + // check cluster + if( !cluster ) { continue; } + + // check if cluster is an edge + if( m_ignoreEdgeClusters && cluster->getEdge() > 0 && cluster->getEdge() < std::numeric_limits::max() ) + { continue; } + const auto globClusPos = m_globalPositionWrapper.getGlobalPositionDistortionCorrected(cluskey, cluster, crossing); const double clusR = get_r(globClusPos(0), globClusPos(1)); const double clusPhi = std::atan2(globClusPos(1), globClusPos(0)); @@ -650,43 +677,58 @@ void PHTpcResiduals::processTrack(SvtxTrack* track) continue; } - // Fill distortion matrices - m_matrix_container->add_to_lhs(index, 0, 0, square(clusR) / erp); - m_matrix_container->add_to_lhs(index, 0, 1, 0); - m_matrix_container->add_to_lhs(index, 0, 2, clusR * trackAlpha / erp); + std::vector containers; + containers.emplace_back( m_matrix_container.get() ); + if( track->get_positive_charge() ) { + containers.emplace_back( m_matrix_container_pos.get() ); + } else { + containers.emplace_back( m_matrix_container_neg.get() ); + } - m_matrix_container->add_to_lhs(index, 1, 0, 0); - m_matrix_container->add_to_lhs(index, 1, 1, 1. / ez); - m_matrix_container->add_to_lhs(index, 1, 2, trackBeta / ez); - m_matrix_container->add_to_lhs(index, 2, 0, clusR * trackAlpha / erp); - m_matrix_container->add_to_lhs(index, 2, 1, trackBeta / ez); - m_matrix_container->add_to_lhs(index, 2, 2, square(trackAlpha) / erp + square(trackBeta) / ez); + for( auto& container:containers ) + { + + if( !container ) { continue; } + + // Fill distortion matrices + container->add_to_lhs(index, 0, 0, square(clusR) / erp); + container->add_to_lhs(index, 0, 1, 0); + container->add_to_lhs(index, 0, 2, clusR * trackAlpha / erp); + + container->add_to_lhs(index, 1, 0, 0); + container->add_to_lhs(index, 1, 1, 1. / ez); + container->add_to_lhs(index, 1, 2, trackBeta / ez); - m_matrix_container->add_to_rhs(index, 0, clusR * drphi / erp); - m_matrix_container->add_to_rhs(index, 1, dz / ez); - m_matrix_container->add_to_rhs(index, 2, trackAlpha * drphi / erp + trackBeta * dz / ez); + container->add_to_lhs(index, 2, 0, clusR * trackAlpha / erp); + container->add_to_lhs(index, 2, 1, trackBeta / ez); + container->add_to_lhs(index, 2, 2, square(trackAlpha) / erp + square(trackBeta) / ez); - // also update rphi reduced matrices - m_matrix_container->add_to_lhs_rphi(index, 0, 0, square(clusR) / erp); - m_matrix_container->add_to_lhs_rphi(index, 0, 1, clusR * trackAlpha / erp); - m_matrix_container->add_to_lhs_rphi(index, 1, 0, clusR * trackAlpha / erp); - m_matrix_container->add_to_lhs_rphi(index, 1, 1, square(trackAlpha) / erp); + container->add_to_rhs(index, 0, clusR * drphi / erp); + container->add_to_rhs(index, 1, dz / ez); + container->add_to_rhs(index, 2, trackAlpha * drphi / erp + trackBeta * dz / ez); - m_matrix_container->add_to_rhs_rphi(index, 0, clusR * drphi / erp); - m_matrix_container->add_to_rhs_rphi(index, 1, trackAlpha * drphi / erp); + // also update rphi reduced matrices + container->add_to_lhs_rphi(index, 0, 0, square(clusR) / erp); + container->add_to_lhs_rphi(index, 0, 1, clusR * trackAlpha / erp); + container->add_to_lhs_rphi(index, 1, 0, clusR * trackAlpha / erp); + container->add_to_lhs_rphi(index, 1, 1, square(trackAlpha) / erp); - // also update z reduced matrices - m_matrix_container->add_to_lhs_z(index, 0, 0, 1. / ez); - m_matrix_container->add_to_lhs_z(index, 0, 1, trackBeta / ez); - m_matrix_container->add_to_lhs_z(index, 1, 0, trackBeta / ez); - m_matrix_container->add_to_lhs_z(index, 1, 1, square(trackBeta) / ez); + container->add_to_rhs_rphi(index, 0, clusR * drphi / erp); + container->add_to_rhs_rphi(index, 1, trackAlpha * drphi / erp); - m_matrix_container->add_to_rhs_z(index, 0, dz / ez); - m_matrix_container->add_to_rhs_z(index, 1, trackBeta * dz / ez); + // also update z reduced matrices + container->add_to_lhs_z(index, 0, 0, 1. / ez); + container->add_to_lhs_z(index, 0, 1, trackBeta / ez); + container->add_to_lhs_z(index, 1, 0, trackBeta / ez); + container->add_to_lhs_z(index, 1, 1, square(trackBeta) / ez); - // update entries in cell - m_matrix_container->add_to_entries(index); + container->add_to_rhs_z(index, 0, dz / ez); + container->add_to_rhs_z(index, 1, trackBeta * dz / ez); + + // update entries in cell + container->add_to_entries(index); + } // increment number of accepted clusters ++m_accepted_clusters; @@ -744,10 +786,10 @@ int PHTpcResiduals::createNodes(PHCompositeNode* /*topNode*/) int PHTpcResiduals::getNodes(PHCompositeNode* topNode) { // clusters - m_clusterContainer = findNode::getClass(topNode, "TRKR_CLUSTER"); + m_clusterContainer = findNode::getClass(topNode, m_clustermapname); if (!m_clusterContainer) { - std::cout << PHWHERE << "No TRKR_CLUSTER node on node tree. Exiting." << std::endl; + std::cout << "PHTpcResiduals::getNodes - cluster map named " << m_clustermapname << " not found." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -755,7 +797,7 @@ int PHTpcResiduals::getNodes(PHCompositeNode* topNode) m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); if (!m_tGeometry) { - std::cout << "ActsTrackingGeometry not on node tree. Exiting." << std::endl; + std::cout << "PHTpcResiduals::getNodes - ActsGeometry not found." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -763,28 +805,12 @@ int PHTpcResiduals::getNodes(PHCompositeNode* topNode) m_trackMap = findNode::getClass(topNode, m_trackmapname); if (!m_trackMap) { - std::cout << PHWHERE << " " << m_trackmapname << " not on node tree. Exiting." << std::endl; + std::cout << "PHTpcResiduals::getNodes - track map named " << m_trackmapname << " not found." << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } // tpc global position wrapper m_globalPositionWrapper.loadNodes(topNode); - if (m_disable_module_edge_corr) - { - m_globalPositionWrapper.set_enable_module_edge_corr(false); - } - if (m_disable_static_corr) - { - m_globalPositionWrapper.set_enable_static_corr(false); - } - if (m_disable_average_corr) - { - m_globalPositionWrapper.set_enable_average_corr(false); - } - if (m_disable_fluctuation_corr) - { - m_globalPositionWrapper.set_enable_fluctuation_corr(false); - } return Fun4AllReturnCodes::EVENT_OK; } @@ -792,5 +818,7 @@ int PHTpcResiduals::getNodes(PHCompositeNode* topNode) //____________________________________________________________________________ void PHTpcResiduals::setGridDimensions(const int phiBins, const int rBins, const int zBins) { - m_matrix_container->set_grid_dimensions(phiBins, rBins, zBins); + if( m_matrix_container ) { m_matrix_container->set_grid_dimensions(phiBins, rBins, zBins); } + if( m_matrix_container_pos ) { m_matrix_container_pos->set_grid_dimensions(phiBins, rBins, zBins); } + if( m_matrix_container_neg ) { m_matrix_container_neg->set_grid_dimensions(phiBins, rBins, zBins); } } diff --git a/offline/packages/tpccalib/PHTpcResiduals.h b/offline/packages/tpccalib/PHTpcResiduals.h index 66da67239d..3db64d5f4c 100644 --- a/offline/packages/tpccalib/PHTpcResiduals.h +++ b/offline/packages/tpccalib/PHTpcResiduals.h @@ -63,11 +63,20 @@ class PHTpcResiduals : public SubsysReco } //@} + /// true to remove "edge" clusters + /** these are clusters that touch the edge of a detector and are considered pathological */ + void setIgnoreEdgeClusters( bool value ) + { m_ignoreEdgeClusters = value; } + + /// minimum value for RPhi error. + /** a too small rphi error is usually a sign of pathological TPC cluster */ void setMinRPhiErr(float minRPhiErr) { m_minRPhiErr = minRPhiErr; } + /// minimum value for z error. + /** a too small z error is usually a sign of pathological TPC cluster */ void setMinZErr(float minZErr) { m_minZErr = minZErr; @@ -106,15 +115,34 @@ class PHTpcResiduals : public SubsysReco m_useMicromegas = value; } - void disableModuleEdgeCorr() { m_disable_module_edge_corr = true; } - void disableStaticCorr() { m_disable_static_corr = true; } - void disableAverageCorr() { m_disable_average_corr = true; } - void disableFluctuationCorr() { m_disable_fluctuation_corr = true; } + void disableModuleEdgeCorr() + { + m_globalPositionWrapper.set_enable_module_edge_corr(false); + } + + void disableStaticCorr() + { + m_globalPositionWrapper.set_enable_static_corr(false); + } + + void disableAverageCorr() + { + m_globalPositionWrapper.set_enable_average_corr(false); + } + + void disableFluctuationCorr() + { + m_globalPositionWrapper.set_enable_fluctuation_corr(false); + } /// modify track map name void setTrackMapName( const std::string& value ) { m_trackmapname = value; } + /// modify track map name + void setClusterMapName( const std::string& value ) + { m_clustermapname = value; } + private: int getNodes(PHCompositeNode *topNode); @@ -129,11 +157,19 @@ class PHTpcResiduals : public SubsysReco /// Gets distortion cell for identifying bins in TPC int getCell(const Acts::Vector3 &loc); - /// Node information for Acts tracking geometry and silicon+MM - /// track fit + //! track map name std::string m_trackmapname = "SvtxSiliconMMTrackMap"; + + //! track map SvtxTrackMap *m_trackMap = nullptr; + + //! acts geometry ActsGeometry *m_tGeometry = nullptr; + + //! cluster map name + std::string m_clustermapname = "TRKR_CLUSTER"; + + //! cluster map TrkrClusterContainer *m_clusterContainer = nullptr; //! tpc global position wrapper @@ -144,6 +180,9 @@ class PHTpcResiduals : public SubsysReco float m_maxTBeta = 1.5; float m_maxResidualDz = 0.5; // cm + /// ignore edge clusters + bool m_ignoreEdgeClusters = false; + float m_minRPhiErr = 0.005; // 0.005cm -- 50um float m_minZErr = 0.01; // 0.01cm -- 100um @@ -166,6 +205,12 @@ class PHTpcResiduals : public SubsysReco /// matrix container std::unique_ptr m_matrix_container; + /// matrix container positive charges only + std::unique_ptr m_matrix_container_pos; + + /// matrix container negative charges only + std::unique_ptr m_matrix_container_neg; + // TODO: check if needed int m_event = 0; @@ -178,12 +223,6 @@ class PHTpcResiduals : public SubsysReco /// require track crossing zero bool m_requireCrossing = false; - /// disable distortion correction - bool m_disable_module_edge_corr = false; - bool m_disable_static_corr = false; - bool m_disable_average_corr = false; - bool m_disable_fluctuation_corr = false; - /// output file std::string m_outputfile = "TpcSpaceChargeMatrices.root"; diff --git a/offline/packages/tpccalib/SiliconDriftEvaluator.cc b/offline/packages/tpccalib/SiliconDriftEvaluator.cc new file mode 100644 index 0000000000..3aef6f937b --- /dev/null +++ b/offline/packages/tpccalib/SiliconDriftEvaluator.cc @@ -0,0 +1,433 @@ +#include "SiliconDriftEvaluator.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +//_____________________________________________________________________ +namespace +{ + + //! pt + template + T get_pt(const T& px, const T& py) + { + return std::sqrt(px * px + py * py); + } + + //_____________________________________________________________________ + // par[0] = constrained slope + // par[1] = offset for eta < 0 + // par[2] = offset for eta >= 0 + // + double fit_function_2d(double* x, double* par) + { + const int ieta = static_cast(std::floor(x[0])); + const double z = x[1]; + if (ieta < 0 || ieta > 1) + { + TF2::RejectPoint(); + return 0.; + } + return par[ieta + 1] + par[0] * z; + } + + //! 1D version used to draw per-eta overlay lines on QA canvas + // NOLINTNEXTLINE(readability-non-const-parameter): ROOT TF1 requires this exact signature + double linear_function(double* x, double* par) + { + return par[0] * x[0] + par[1]; + } + + //! human-readable label for each eta bin + const char* k_eta_labels[2] = {"#eta_{TPC} < 0", "#eta_{TPC} #geq 0"}; + +} // namespace + +//_____________________________________________________________________ +SiliconDriftEvaluator::SiliconDriftEvaluator(const std::string& name) + : SubsysReco(name) +{ +} + +//_____________________________________________________________________ +int SiliconDriftEvaluator::Init(PHCompositeNode* topNode) +{ + // find DST node + PHNodeIterator iter(topNode); + auto* dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dstNode) + { + std::cout << "SiliconDriftEvaluator::Init - DST Node missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + // get EVAL node + iter = PHNodeIterator(dstNode); + auto* evalNode = dynamic_cast(iter.findFirst("PHCompositeNode", "EVAL")); + if (!evalNode) + { + // create + std::cout << "SiliconDriftEvaluator::Init - EVAL node missing - creating" << std::endl; + evalNode = new PHCompositeNode("EVAL"); + dstNode->addNode(evalNode); + } + + // add container to output tree + auto* newNode = new PHIODataNode(new Container, "SiliconDriftEvaluator::Container", "PHObject"); + + // overwrite split level for easier offline browsing + newNode->SplitLevel(99); + evalNode->addNode(newNode); + + // book 3D accumulator histogram + // x = eta bin: 0 = eta<0, 1 = eta>=0 + // y = z_si (cm) + // z = dz (cm) + m_hist3D = new TH3F("SiliconDriftEval_hist3D", ";#eta bin;z_{silicon} (cm);#Deltaz_{TPC-silicon} (cm)", 2, 0, 2, 200, -m_max_z, m_max_z, 200, -m_max_dz, m_max_dz); + m_hist3D->SetDirectory(nullptr); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//_____________________________________________________________________ +int SiliconDriftEvaluator::InitRun(PHCompositeNode* topNode) +{ + return load_nodes(topNode); +} + +//_____________________________________________________________________ +int SiliconDriftEvaluator::process_event(PHCompositeNode* topNode) +{ + // load nodes + const auto res = load_nodes(topNode); + if (res != Fun4AllReturnCodes::EVENT_OK) + { + return res; + } + + // cleanup output + if (m_container) + { + m_container->Reset(); + } + + evaluate_tracks(); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//_____________________________________________________________________ +int SiliconDriftEvaluator::End(PHCompositeNode* /*topNode*/) +{ + if (!m_hist3D) + { + std::cerr << Name() << "::End - histogram not found, skipping fit." << std::endl; + return Fun4AllReturnCodes::EVENT_OK; + } + + const int nEntries = static_cast(m_hist3D->GetEntries()); + std::cout << Name() << "::End - fitting " << nEntries << " entries" << std::endl; + + // build mean-dz TH2F via FitSlicesY, one eta bin at a time + // x = eta bin [0,2), y = z_si (cm), content = mean dz (cm) + auto* h_fit = new TH2F("h_fit_silicon", "", + 2, 0, 2, + 200, -m_max_z, m_max_z); + h_fit->SetDirectory(nullptr); + + for (int ieta = 0; ieta < 2; ++ieta) + { + m_hist3D->GetXaxis()->SetRange(ieta + 1, ieta + 1); + auto* h2d = static_cast(m_hist3D->Project3D("zy")); + h2d->SetName(std::format("h2d_etabin_{}", ieta).c_str()); + h2d->SetDirectory(nullptr); + + // fit vertical slices; require a minimum of m_min_slice_entries per slice + h2d->FitSlicesY(nullptr, 0, -1, m_min_slice_entries); + auto* h_mean = static_cast(gDirectory->Get(std::format("h2d_etabin_{}_1", ieta).c_str())); + + if (!h_mean) + { + delete h2d; + continue; + } + + for (int iz = 1; iz <= h_mean->GetNbinsX(); ++iz) + { + const double entries = h2d->Integral(iz, iz, 1, m_hist3D->GetNbinsZ()); + if (entries > 0) + { + h_fit->SetBinContent(ieta + 1, iz, h_mean->GetBinContent(iz)); + } + } + + delete h2d; + } + + m_hist3D->GetXaxis()->SetRange(0, 0); + + // 2D piecewise fit: shared slope + per-eta offset + auto* fit2d = new TF2("fit2d_silicon", fit_function_2d, 0, 2, -m_max_z, m_max_z, 3); + for (int i = 0; i < 3; ++i) + { + fit2d->SetParameter(i, 0.0); + } + h_fit->Fit(fit2d, "0R"); + + const double slope = fit2d->GetParameter(0); + const double slope_err = fit2d->GetParError(0); + const double off_neg = fit2d->GetParameter(1); // ieta=0, eta<0 + const double off_pos = fit2d->GetParameter(2); // ieta=1, eta>=0 + + const double dv_new = m_drift_velocity / (1.0 + slope); + const double dv_err = m_drift_velocity / std::pow(1.0 + slope, 2) * slope_err; + const double t0_new = (off_pos - off_neg) / (2.0 * dv_new); + + std::cout << Name() << "::End" << " slope=" << slope << " dv_in=" << m_drift_velocity << " cm/ns" << " dv_new=" << dv_new << " +/- " << dv_err << " cm/ns" << " t0_new=" << t0_new << " ns" << std::endl; + + // draw the plot + auto* canvas = new TCanvas("silicon_drift_calib", "Silicon drift velocity calibration", 1400, 700); + canvas->Divide(2, 1); + + for (int ieta = 0; ieta < 2; ++ieta) + { + canvas->cd(ieta + 1); + gPad->SetTopMargin(0.13); + gPad->SetRightMargin(0.18); + + // 2D distribution for this eta bin + m_hist3D->GetXaxis()->SetRange(ieta + 1, ieta + 1); + auto* h2d = static_cast(m_hist3D->Project3D("zy")); + h2d->SetName(std::format("hplot_etabin_{}", ieta).c_str()); + h2d->SetTitle(";z_{silicon} (cm);#Deltaz_{TPC-silicon} (cm)"); + h2d->SetStats(false); + h2d->Draw("COLZ"); + + // mean-dz points from FitSlicesY + auto* h_fit_proj = h_fit->ProjectionY(std::format("h_fit_proj_{}", ieta).c_str(), ieta + 1, ieta + 1); + h_fit_proj->SetMarkerStyle(20); + h_fit_proj->SetMarkerSize(0.6); + h_fit_proj->SetMarkerColor(kRed); + h_fit_proj->SetLineColor(kRed); + h_fit_proj->Draw("same P"); + + // 1D fit line for this eta bin + auto* f1d = new TF1(std::format("f1d_etabin_{}", ieta).c_str(), linear_function, -m_max_z, m_max_z, 2); + f1d->SetParameter(0, slope); + f1d->SetParameter(1, (ieta == 0) ? off_neg : off_pos); + f1d->SetLineColor(kGreen + 2); + f1d->SetLineWidth(2); + f1d->Draw("same"); + + // reference line at dz = 0 + auto* zero = new TLine(-m_max_z, 0, m_max_z, 0); + zero->SetLineStyle(2); + zero->SetLineColor(kGray + 1); + zero->Draw(); + + auto* leg = new TLegend(0.13, 0.76, 0.82, 0.95); + leg->SetBorderSize(0); + leg->SetFillStyle(0); + leg->SetTextSize(0.033); + leg->SetHeader(std::format("{} entries: {} v_{{in}}={:.4f} cm/ns", + k_eta_labels[ieta], nEntries, m_drift_velocity) + .c_str(), + "C"); + leg->AddEntry(h_fit_proj, "Gaussian slice mean", "p"); + leg->AddEntry(f1d, std::format("slope={:.4f} v_{{new}}={:.4f}#pm{:.4f} cm/ns t_{{0}}={:.1f} ns", slope, dv_new, dv_err, t0_new).c_str(), "l"); + leg->Draw(); + } + + m_hist3D->GetXaxis()->SetRange(0, 0); + + canvas->SaveAs(m_plot_filename.c_str()); + std::cout << Name() << "::End - QA canvas saved to " << m_plot_filename << std::endl; + + // write histograms, fit and results to a ROOT file + if (!m_root_filename.empty()) + { + std::unique_ptr outfile(TFile::Open(m_root_filename.c_str(), "RECREATE")); + if (outfile && !outfile->IsZombie()) + { + outfile->cd(); + m_hist3D->Write(); + h_fit->Write("h_fit_silicon"); + fit2d->Write(); + canvas->Write(); + TParameter("slope", slope).Write(); + TParameter("drift_velocity_in", m_drift_velocity).Write(); + TParameter("drift_velocity_new", dv_new).Write(); + TParameter("drift_velocity_err", dv_err).Write(); + TParameter("t0_new", t0_new).Write(); + outfile->Close(); + std::cout << Name() << "::End - histograms and fit results saved to " << m_root_filename << std::endl; + } + else + { + std::cerr << Name() << "::End - could not open " << m_root_filename << " for writing." << std::endl; + } + } + + delete canvas; + delete fit2d; + delete h_fit; + + return Fun4AllReturnCodes::EVENT_OK; +} + +//_____________________________________________________________________ +int SiliconDriftEvaluator::load_nodes(PHCompositeNode* topNode) +{ + // track map + m_track_map = findNode::getClass(topNode, m_trackmapname); + + // local container + m_container = findNode::getClass(topNode, "SiliconDriftEvaluator::Container"); + assert(m_container); + + return Fun4AllReturnCodes::EVENT_OK; +} + +//_____________________________________________________________________ +void SiliconDriftEvaluator::evaluate_tracks() +{ + if (!(m_track_map && m_container && m_hist3D)) + { + return; + } + + // clear array + m_container->clearTracks(); + + for (const auto& [track_id, track] : *m_track_map) + { + // require valid beam-crossing + const auto crossing = track->get_crossing(); + if (crossing == SHRT_MAX) + { + std::cout << "SiliconDriftEvaluator::evaluate_tracks - invalid crossing, track ignored." << std::endl; + continue; + } + + // require both seeds + const auto* si_seed = track->get_silicon_seed(); + const auto* tpc_seed = track->get_tpc_seed(); + if (!si_seed || !tpc_seed) + { + continue; + } + + // count clusters per subsystem + unsigned int n_tpc = 0; + unsigned int n_mvtx = 0; + unsigned int n_intt = 0; + + for (const auto* seed : {track->get_silicon_seed(), track->get_tpc_seed()}) + { + if (!seed) + { + continue; + } + for (auto it = seed->begin_cluster_keys(); it != seed->end_cluster_keys(); ++it) + { + switch (TrkrDefs::getTrkrId(*it)) + { + case TrkrDefs::tpcId: + ++n_tpc; + break; + case TrkrDefs::mvtxId: + ++n_mvtx; + break; + case TrkrDefs::inttId: + ++n_intt; + break; + default: + break; + } + } + } + + // apply selection cuts + if (n_tpc < m_min_nclusters_tpc) + { + continue; + } + if (n_mvtx < m_min_nclusters_mvtx) + { + continue; + } + if (n_intt < m_min_nclusters_intt) + { + continue; + } + + const float eta = tpc_seed->get_eta(); + if (std::abs(eta) > m_max_eta) + { + continue; + } + + const float pt = get_pt(track->get_px(), track->get_py()); + if (pt < m_min_pt) + { + continue; + } + + // get seed z positions at POCA + const auto si_pos = TrackSeedHelper::get_xyz(si_seed); + const auto tpc_pos = TrackSeedHelper::get_xyz(tpc_seed); + + const float z_si = si_pos.z(); + const float z_tpc = tpc_pos.z(); + + // dz = (z_tpc + sign(eta)*crossing*crossing_interval*dv) - z_si + const double sign_eta = (eta >= 0) ? 1.0 : -1.0; + const float z_tpc_corr = z_tpc + sign_eta * crossing * m_crossing_interval * m_drift_velocity; + const float dz = z_tpc_corr - z_si; + + // fill track struct + TrackStruct track_struct; + track_struct._nclusters_mvtx = n_mvtx; + track_struct._nclusters_intt = n_intt; + track_struct._nclusters_tpc = n_tpc; + track_struct._pt = pt; + track_struct._eta = eta; + track_struct._phi = tpc_seed->get_phi(); + track_struct._z_tpc = z_tpc; + track_struct._z_si = z_si; + track_struct._crossing = crossing; + track_struct._dz = dz; + + // fill histogram + // eta bin centre: 0.5 for eta<0, 1.5 for eta>=0 + const double eta_bin = (eta >= 0) ? 1.5 : 0.5; + m_hist3D->Fill(eta_bin, z_si, dz); + + m_container->addTrack(track_struct); + } +} \ No newline at end of file diff --git a/offline/packages/tpccalib/SiliconDriftEvaluator.h b/offline/packages/tpccalib/SiliconDriftEvaluator.h new file mode 100644 index 0000000000..2f188e6c39 --- /dev/null +++ b/offline/packages/tpccalib/SiliconDriftEvaluator.h @@ -0,0 +1,202 @@ +#ifndef G4EVAL_SiliconDriftEvaluator_H +#define G4EVAL_SiliconDriftEvaluator_H + +/* + * Bade Sayki June 16th, 2026 -- LANL + * This module is created to calibrate the drift velocity in the TPC by projecting the silicon seeds and the TPC seeds to the beam axis and calculating the z residuals. + * This is heavily inspired by and distilled from Dr. Hugo Pereira Da Costa's TrackingEvaluator_hp module. It is meant to be a more lightweight and specialized version. + * Claude tool was used to format and comment this module. + */ + +#include +#include + +#include +#include + +class SvtxTrackMap; +class TH2F; +class TH3F; + +class SiliconDriftEvaluator : public SubsysReco +{ + public: + //! constructor + SiliconDriftEvaluator(const std::string& = "SiliconDriftEvaluator"); + + //! global initialization + virtual int Init(PHCompositeNode*); + + //! run initialization + virtual int InitRun(PHCompositeNode*); + + //! event processing + virtual int process_event(PHCompositeNode*); + + //! end of processing + virtual int End(PHCompositeNode*); + + // track information stored in the Container + class TrackStruct + { + public: + using List = std::vector; + + // cluster counts + unsigned int _nclusters_mvtx = 0; + unsigned int _nclusters_intt = 0; + unsigned int _nclusters_tpc = 0; + + // tpc seed kinematics + float _pt = 0; + float _eta = 0; + float _phi = 0; + + // seed z positions + + // z position of the TPC seed at the beamline + float _z_tpc = 0; + + //! z position of the silicon seed at the beamline + float _z_si = 0; + + //! beam-bunch crossing number + short int _crossing = 0; + + //! crossing-corrected dz = z_tpc_corr - z_si (cm) + float _dz = 0; + }; + + //! track container stored on the node tree + class Container : public PHObject + { + public: + //! constructor + explicit Container() = default; + + //! copy constructor + explicit Container(const Container&) = delete; + + //! assignment operator + Container& operator=(const Container&) = delete; + + //! reset + void Reset() override + { + _tracks.clear(); + } + + //!@name accessors + //@{ + + const TrackStruct::List& tracks() const + { + return _tracks; + } + + // modifiers + + void addTrack(const TrackStruct& track) + { + _tracks.push_back(track); + } + + void clearTracks() + { + _tracks.clear(); + } + + private: + //! tracks array + TrackStruct::List _tracks; + + ClassDefOverride(Container, 1) + }; + + //! track map name + void set_trackmapname(const std::string& value) { m_trackmapname = value; } + + // initial drift velocity (cm/ns); used as starting point for the fit and for the crossing correction + void set_drift_velocity(double value) { m_drift_velocity = value; } + + // bunch-crossing interval in ns (default: 106.65237 ns) + void set_crossing_interval(double value) { m_crossing_interval = value; } + + // minimum pT cut on tracks (GeV) + void set_min_pt(double value) { m_min_pt = value; } + + // minimum number of TPC clusters required + void set_min_nclusters_tpc(unsigned int value) { m_min_nclusters_tpc = value; } + + // minimum number of MVTX clusters required + void set_min_nclusters_mvtx(unsigned int value) { m_min_nclusters_mvtx = value; } + + // minimum number of INTT clusters required + void set_min_nclusters_intt(unsigned int value) { m_min_nclusters_intt = value; } + + // maximum abs(eta) of TPC seed accepted + void set_max_eta(double value) { m_max_eta = value; } + + // half-range of the z_si histogram axis (cm) + void set_max_z(double value) { m_max_z = value; } + + // half-range of the dz histogram axis (cm) + void set_max_dz(double value) { m_max_dz = value; } + + //! minimum entries per z slice required by FitSlicesY + void set_min_slice_entries(int value) { m_min_slice_entries = value; } + + // output drift plot filename. Do this in your macro. + void set_plot_filename(const std::string& value) { m_plot_filename = value; } + + // output ROOT filename for histograms and fit results. Do this in your macro. + void set_root_filename(const std::string& value) { m_root_filename = value; } + + private: + //! load nodes + int load_nodes(PHCompositeNode*); + + //! evaluate tracks + void evaluate_tracks(); + + //! evaluation node + Container* m_container = nullptr; + + //! track map + SvtxTrackMap* m_track_map = nullptr; + + //! 3D accumulator histogram: x = eta bin [2], y = z_si, z = dz + TH3F* m_hist3D = nullptr; + + //! track map name + std::string m_trackmapname = "SvtxTrackMap"; + + //! initial drift velocity (cm/ns) + double m_drift_velocity = 0.00747; + + //! bunch-crossing interval (ns) + double m_crossing_interval = 106.65237; + + // track selection cuts + + double m_min_pt = 0.5; + unsigned int m_min_nclusters_tpc = 20; + unsigned int m_min_nclusters_mvtx = 3; + unsigned int m_min_nclusters_intt = 2; + double m_max_eta = 0.9; + + //! histogram range + double m_max_z = 20.0; + double m_max_dz = 10.0; + + //! minimum entries per z slice for FitSlicesY + int m_min_slice_entries = 10; + + //! output QA plot filename + std::string m_plot_filename = "silicon_drift_calib.png"; + + //! output ROOT filename for histograms and fit results + std::string m_root_filename = "silicon_drift_calib.root"; +}; + +#endif // G4EVAL_SiliconDriftEvaluator_H \ No newline at end of file diff --git a/offline/packages/tpccalib/SiliconDriftEvaluatorLinkDef.h b/offline/packages/tpccalib/SiliconDriftEvaluatorLinkDef.h new file mode 100644 index 0000000000..28c8b6830d --- /dev/null +++ b/offline/packages/tpccalib/SiliconDriftEvaluatorLinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class SiliconDriftEvaluator::Container+; + +#endif diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc index b3a8687a7d..87c344bbab 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.cc +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.cc @@ -17,6 +17,8 @@ #include +#include + #include #include @@ -155,11 +157,13 @@ namespace TpcCentralMembraneMatching::TpcCentralMembraneMatching(const std::string& name) : SubsysReco(name) { + /* // calculate stripes center positions CalculateCenters(nPads_R1, R1_e, nGoodStripes_R1_e, keepUntil_R1_e, nStripesIn_R1_e, nStripesBefore_R1_e, cx1_e, cy1_e); CalculateCenters(nPads_R1, R1, nGoodStripes_R1, keepUntil_R1, nStripesIn_R1, nStripesBefore_R1, cx1, cy1); CalculateCenters(nPads_R2, R2, nGoodStripes_R2, keepUntil_R2, nStripesIn_R2, nStripesBefore_R2, cx2, cy2); CalculateCenters(nPads_R3, R3, nGoodStripes_R3, keepUntil_R3, nStripesIn_R3, nStripesBefore_R3, cx3, cy3); + */ } //___________________________________________________________ @@ -977,6 +981,9 @@ int TpcCentralMembraneMatching::getClusterRMatch(double clusterR, int side) //____________________________________________________________________________.. int TpcCentralMembraneMatching::InitRun(PHCompositeNode* topNode) { + + std::cout << "skipOutliers? " << m_skipOutliers << " manualInterp? " << m_manualInterp << std::endl; + if (!m_fieldOn) { m_useHeader = false; @@ -1086,7 +1093,31 @@ int TpcCentralMembraneMatching::InitRun(PHCompositeNode* topNode) // Get truth cluster positions //===================== - const double phi_petal = M_PI / 9.0; // angle span of one petal + CDBTTree *cdbttree = new CDBTTree(m_stripePatternFile); + cdbttree->LoadCalibrations(); + auto cdbMap = cdbttree->GetDoubleEntryMap(); + for (const auto &[index, values] : cdbMap) + { + m_truth_index.push_back(index); + double tmpR = cdbttree->GetDoubleValue(index, "truthR"); + double tmpPhi = cdbttree->GetDoubleValue(index, "truthPhi"); + TVector3 dummyPos(tmpR*cos(tmpPhi), tmpR*sin(tmpPhi), (index / 10000 < 18 ? 1.0 : -1.0)); + m_truth_pos.push_back(dummyPos); + truth_r_phi[(index / 10000 < 18 ? 1 : 0)]->Fill(tmpPhi, tmpR); + if(Verbosity() > 2) + { + std::cout << " index " << index << " x " << dummyPos.X() << " y " << dummyPos.Y() + << " phi " << std::atan2(dummyPos.Y(), dummyPos.X()) + << " radius " << get_r(dummyPos.X(), dummyPos.Y()) << std::endl; + } + if(m_savehistograms) + { + hxy_truth->Fill(dummyPos.X(), dummyPos.Y()); + } + + } + + //const double phi_petal = M_PI / 9.0; // angle span of one petal /* * utility function to @@ -1094,6 +1125,7 @@ int TpcCentralMembraneMatching::InitRun(PHCompositeNode* topNode) * - assign proper z, * - insert in container */ + /* auto save_truth_position = [&](TVector3 source) { source.SetZ(-1); @@ -1256,19 +1288,20 @@ int TpcCentralMembraneMatching::InitRun(PHCompositeNode* topNode) m_truth_index.push_back(truth_index_0); m_truth_index.push_back(truth_index_1); - if (Verbosity() > 2) - { - std::cout << " i " << i << " j " << j << " k " << k << " x1 " << dummyPos.X() << " y1 " << dummyPos.Y() - << " theta " << std::atan2(dummyPos.Y(), dummyPos.X()) - << " radius " << get_r(dummyPos.X(), dummyPos.y()) << std::endl; - } - if (m_savehistograms) - { - hxy_truth->Fill(dummyPos.X(), dummyPos.Y()); - } + if (Verbosity() > 2) + { + std::cout << " i " << i << " j " << j << " k " << k << " x1 " << dummyPos.X() << " y1 " << dummyPos.Y() + << " theta " << std::atan2(dummyPos.Y(), dummyPos.X()) + << " radius " << get_r(dummyPos.X(), dummyPos.y()) << std::endl; + } + if (m_savehistograms) + { + hxy_truth->Fill(dummyPos.X(), dummyPos.Y()); } } } +} +*/ /* int count[2] = {0, 0}; @@ -1461,7 +1494,12 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) // Do the static + average distortion corrections if the container was found // since incorrect z values are in cluster do to wrong t0 of laser flash, fixing based on the side for now // Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), cmclus->getZ()); - Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); + Acts::Vector3 pos = m_laserClusterHelper.getClusterCentroid(cmclus); + if(pos.hasNaN()) + { + continue; + } + //Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); TVector3 tmp_raw(pos[0], pos[1], pos[2]); if (m_dcc_in_module_edge) { @@ -1546,12 +1584,12 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) if (Verbosity() > 2) { - double raw_rad = std::sqrt(cmclus->getX() * cmclus->getX() + cmclus->getY() * cmclus->getY()); + double raw_rad = std::sqrt(tmp_raw.X() * tmp_raw.X() + tmp_raw.Y() * tmp_raw.Y()); double static_rad = sqrt(tmp_static.X() * tmp_static.X() + tmp_static.Y() * tmp_static.Y()); double corr_rad = sqrt(tmp_pos.X() * tmp_pos.X() + tmp_pos.Y() * tmp_pos.Y()); std::cout << "cluster " << clusterIndex << std::endl; clusterIndex++; - std::cout << "found raw cluster " << cmkey << " side " << side << " with x " << cmclus->getX() << " y " << cmclus->getY() << " z " << cmclus->getZ() << " radius " << raw_rad << std::endl; + std::cout << "found raw cluster " << cmkey << " side " << side << " with x " << tmp_raw.X() << " y " << tmp_raw.Y() << " z " << tmp_raw.Z() << " radius " << raw_rad << std::endl; std::cout << " --- static corrected positions: " << tmp_static.X() << " " << tmp_static.Y() << " " << tmp_static.Z() << " radius " << static_rad << std::endl; std::cout << " --- corrected positions: " << tmp_pos.X() << " " << tmp_pos.Y() << " " << tmp_pos.Z() << " radius " << corr_rad << std::endl; } @@ -2121,7 +2159,14 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) cmdiff->setTruthR(m_truth_pos[i].Perp()); cmdiff->setTruthZ(m_truth_pos[i].Z()); - if (m_averageMode) + if (m_totalDistMode) + { + cmdiff->setRecoPhi(raw_pos[reco_index].Phi()); + cmdiff->setRecoR(raw_pos[reco_index].Perp()); + cmdiff->setRecoZ(raw_pos[reco_index].Z()); + cmdiff->setNclusters(reco_nhits[reco_index]); + } + else if (m_averageMode) { cmdiff->setRecoPhi(static_pos[reco_index].Phi()); cmdiff->setRecoR(static_pos[reco_index].Perp()); @@ -2156,6 +2201,14 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) dr = static_pos[reco_index].Perp() - m_truth_pos[i].Perp(); dphi = delta_phi(static_pos[reco_index].Phi() - m_truth_pos[i].Phi()); } + else if(m_totalDistMode) + { + clus_r = raw_pos[reco_index].Perp(); + clus_phi = raw_pos[reco_index].Phi(); + + dr = raw_pos[reco_index].Perp() - m_truth_pos[i].Perp(); + dphi = delta_phi(raw_pos[reco_index].Phi() - m_truth_pos[i].Phi()); + } if (clus_phi < 0) { clus_phi += 2 * M_PI; @@ -2221,11 +2274,21 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) ckey++; } - + // std::cout << "about to fill fluct hist" << std::endl; for (int s = 0; s < 2; s++) { + /* + int N = gr_dR[s]->GetN(); + std::vector dataX(N), dataY(N); + for(int k=0; kGetY()[k]*cos(gr_dR[s]->GetX()[k]); + dataY[k] = gr_dR[s]->GetY()[k]*sin(gr_dR[s]->GetX()[k]); + } + */ + bool firstGoodR = false; for (int j = 1; j <= m_dcc_out->m_hDRint[s]->GetNbinsY(); j++) { @@ -2249,9 +2312,59 @@ int TpcCentralMembraneMatching::process_event(PHCompositeNode* topNode) for (int i = 2; i <= m_dcc_out->m_hDRint[s]->GetNbinsX() - 1; i++) { double phiVal = m_dcc_out->m_hDRint[s]->GetXaxis()->GetBinCenter(i); - m_dcc_out->m_hDRint[s]->SetBinContent(i, j, gr_dR[s]->Interpolate(phiVal, RVal)); - m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal * gr_dPhi[s]->Interpolate(phiVal, RVal)); - } + + /* + double num_dPhi = 0.0; + double num_dR = 0.0; + double den = 0.0; + double smoothing_parameter = 2.0; + + double hX = RVal*cos(phiVal); + double hY = RVal*sin(phiVal); + + + + for(int k=0; k 100.0) continue; + + if(distSq < 1e-9) + { + num_dPhi = gr_dPhi[s]->GetZ()[k]; + num_dR = gr_dR[s]->GetZ()[k]; + + den = 1.0; + + break; + } + + double weight = 1.0 / pow(distSq, smoothing_parameter / 2.0); + num_dPhi += weight * gr_dPhi[s]->GetZ()[k]; + num_dR += weight * gr_dR[s]->GetZ()[k]; + den += weight; + + } + + if(den > 0.0) + { + m_dcc_out->m_hDRint[s]->SetBinContent(i, j, num_dR / den); + m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*(num_dPhi / den)); + } + */ + m_dcc_out->m_hDRint[s]->SetBinContent(i, j, gr_dR[s]->Interpolate(phiVal,RVal)); + if(!m_phiHist_in_rad) + { + m_dcc_out->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi[s]->Interpolate(phiVal,RVal)); + } + else + { + m_dcc_out->m_hDPint[s]->SetBinContent(i, j, gr_dPhi[s]->Interpolate(phiVal,RVal)); + } + } } } @@ -2342,15 +2455,149 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) } } + for(int s=0; s<2; s++) + { + gr_dR_toInterp[s] = (TGraph2D*)gr_dR[s]->Clone(); + gr_dPhi_toInterp[s] = (TGraph2D*)gr_dPhi[s]->Clone(); + } + + //figure out anomolous points to skip and make list + std::vector pointsToSkip[2]; + if(m_skipOutliers) + { + for(int s=0; s<2; s++) + { + std::vector peakBins; + std::vector peakVals; + TH1D *hPeaks = new TH1D("hPeaks","",500,26,80); + int N = gr_dR[s]->GetN(); + + //Make R histogram + for(int i=0; iFill(gr_dR[s]->GetY()[i]); + } + + int bc = 0; + int pbc = 0; + //loop over and find peaks by identifying hist bins where content is higher than adjacent bins + for(int i=1; i<=500; i++) + { + bc = hPeaks->GetBinContent(i); + if(bc > 10 && bc > pbc) + { + if(peakBins.empty() || i > peakBins[peakBins.size()-1] + 1) + { + peakBins.push_back(i); + } + else + { + peakBins[peakBins.size()-1] = i; + } + } + pbc = bc; + } + + //Convert bins to R values, but if two bins are closer than 0.5 cm, pick the one with the largest bin content + for(int i=0; i<(int)peakBins.size(); i++) + { + if(i<(int)peakBins.size()-1 && hPeaks->GetBinCenter(peakBins[i+1]) - hPeaks->GetBinCenter(peakBins[i]) < 0.5) + { + peakVals.push_back((hPeaks->GetBinContent(peakBins[i]) > hPeaks->GetBinContent(peakBins[i+1]) ? hPeaks->GetBinCenter(peakBins[i]) : hPeaks->GetBinCenter(peakBins[i+1]))); + i++; + } + else + { + peakVals.push_back(hPeaks->GetBinCenter(peakBins[i])); + } + } + + std::vector mu; + std::vector sig; + + //fit each peak with a gaussian to get mean and sigma + TF1 *f1 = new TF1("f1","gaus(0)",26,80); + for(int i=0; i<(int)peakVals.size(); i++) + { + f1->SetParameters(hPeaks->GetBinContent(hPeaks->FindBin(peakVals[i])),peakVals[i],0.2); + double lo = (i == 0) ? peakVals[i] - 0.5 : (peakVals[i-1] + peakVals[i])/2.0; + double hi = (i < (int)peakVals.size() - 1) ? (peakVals[i] + peakVals[i+1])/2.0 : peakVals[i] + 1.0; + hPeaks->Fit(f1,"Q","",lo,hi); + + mu.push_back(f1->GetParameter(1)); + sig.push_back(f1->GetParameter(2)); + } + + //for each point in histogram, identify if within 3 sigma from mean of any of the peaks + //if not within 3 sigma from any of them, add to list of points to skip + for(int i=0; iGetY()[i]; + if(RVal_gr > mu[j] - 3*sig[j] && RVal_gr < mu[j] + 3*sig[j]) + { + good = true; + break; + } + } + if(!good) + { + pointsToSkip[s].push_back(i); + } + } + } + } + for (int s = 0; s < 2; s++) { - bool firstGoodR = false; + int N = gr_dR[s]->GetN(); + std::vector dataX(N); + std::vector dataY(N); + double minR = 99.0; + double maxR = 0.0; + + if(m_skipOutliers) + { + int N_toInterp = (int)gr_dR_toInterp[s]->GetN(); + for(int i=N_toInterp-1; i>=0; i--) + { + for(int j=0; j<(int)pointsToSkip[s].size(); j++) + { + if(i == pointsToSkip[s][j]) + { + gr_dR_toInterp[s]->RemovePoint(i); + gr_dPhi_toInterp[s]->RemovePoint(i); + //gr_points[s]->RemovePoint(i); + break; + } + } + } + } + + for(int k=0; kGetY()[k]; + + dataX[k] = RVal*cos(gr_dR[s]->GetX()[k]); + dataY[k] = RVal*sin(gr_dR[s]->GetX()[k]); + + minR = std::min(RVal, minR); + maxR = std::max(RVal, maxR); + } + + //bool firstGoodR = false; for (int j = 1; j <= m_dcc_out_aggregated->m_hDRint[s]->GetNbinsY(); j++) { double RVal = m_dcc_out_aggregated->m_hDRint[s]->GetYaxis()->GetBinCenter(j); double Rlow = m_dcc_out_aggregated->m_hDRint[s]->GetYaxis()->GetBinLowEdge(j); double Rhigh = m_dcc_out_aggregated->m_hDRint[s]->GetYaxis()->GetBinLowEdge(j + 1); + + if(Rhigh < minR || Rlow > maxR) { continue; +} + /* if (!firstGoodR) { for (int p = 0; p < gr_dR[s]->GetN(); p++) @@ -2363,14 +2610,91 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) } continue; } + */ for (int i = 2; i <= m_dcc_out_aggregated->m_hDRint[s]->GetNbinsX() - 1; i++) { double phiVal = m_dcc_out_aggregated->m_hDRint[s]->GetXaxis()->GetBinCenter(i); - m_dcc_out_aggregated->m_hDRint[s]->SetBinContent(i, j, gr_dR[s]->Interpolate(phiVal, RVal)); - m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal * gr_dPhi[s]->Interpolate(phiVal, RVal)); - } + if(m_manualInterp) + { + double num_dPhi = 0.0; + double num_dR = 0.0; + double den = 0.0; + double smoothing_parameter = 2.0; + + double hX = RVal*cos(phiVal); + double hY = RVal*sin(phiVal); + + for(int k=0; k 100.0) { continue; +} + + if(distSq < 1e-9) + { + num_dPhi = gr_dPhi[s]->GetZ()[k]; + num_dR = gr_dR[s]->GetZ()[k]; + + den = 1.0; + + break; + } + + double weight = 1.0 / pow(distSq, smoothing_parameter / 2.0); + num_dPhi += weight * gr_dPhi[s]->GetZ()[k]; + num_dR += weight * gr_dR[s]->GetZ()[k]; + den += weight; + } + + if(den > 0.0) + { + m_dcc_out_aggregated->m_hDRint[s]->SetBinContent(i, j, num_dR / den); + if(!m_phiHist_in_rad) + { + m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*(num_dPhi / den)); + } + else + { + m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, num_dPhi / den); + } + } + } + else + { + m_dcc_out_aggregated->m_hDRint[s]->SetBinContent(i, j, gr_dR_toInterp[s]->Interpolate(phiVal,RVal)); + if(!m_phiHist_in_rad) + { + m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, RVal*gr_dPhi_toInterp[s]->Interpolate(phiVal,RVal)); + } + else + { + m_dcc_out_aggregated->m_hDPint[s]->SetBinContent(i, j, gr_dPhi_toInterp[s]->Interpolate(phiVal,RVal)); + } + } + } } } @@ -2395,6 +2719,9 @@ int TpcCentralMembraneMatching::End(PHCompositeNode* /*topNode*/) gr_points[i]->Write(std::format("gr_points_{}z", (i == 1 ? "pos" : "neg")).c_str()); gr_dR[i]->Write(std::format("gr_dr_{}z", (i == 1 ? "pos" : "neg")).c_str()); gr_dPhi[i]->Write(std::format("gr_dPhi_{}z", (i == 1 ? "pos" : "neg")).c_str()); + + gr_dR_toInterp[i]->Write(std::format("gr_dr_toInterp_{}z", (i == 1 ? "pos" : "neg")).c_str()); + gr_dPhi_toInterp[i]->Write(std::format("gr_dPhi_toInterp_{}z", (i == 1 ? "pos" : "neg")).c_str()); } } @@ -2465,6 +2792,9 @@ int TpcCentralMembraneMatching::GetNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTRUN; } + m_laserClusterHelper.set_useZ(m_useZ); + m_laserClusterHelper.loadNodes(topNode); + // input tpc distortion correction module edge m_dcc_in_module_edge = findNode::getClass(topNode, "TpcDistortionCorrectionContainerModuleEdge"); if (m_dcc_in_module_edge) @@ -2572,8 +2902,8 @@ int TpcCentralMembraneMatching::GetNodes(PHCompositeNode* topNode) std::cout << "TpcCentralMembraneMatching::GetNodes - creating TpcDistortionCorrectionContainer in node " << dcc_out_node_name << std::endl; m_dcc_out = new TpcDistortionCorrectionContainer; m_dcc_out->m_dimensions = 2; - m_dcc_out->m_phi_hist_in_radians = false; - m_dcc_out->m_interpolate_z = true; + m_dcc_out->m_phi_hist_in_radians = m_phiHist_in_rad; + m_dcc_out->m_interpolate_z = false; auto* node = new PHDataNode(m_dcc_out, dcc_out_node_name); runNode->addNode(node); } @@ -2652,6 +2982,7 @@ int TpcCentralMembraneMatching::GetNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } +/* //_____________________________________________________________ void TpcCentralMembraneMatching::CalculateCenters( int nPads, @@ -2722,3 +3053,4 @@ void TpcCentralMembraneMatching::CalculateCenters( nGoodStripes[j] = i_out; } } +*/ diff --git a/offline/packages/tpccalib/TpcCentralMembraneMatching.h b/offline/packages/tpccalib/TpcCentralMembraneMatching.h index 3b3331fc5f..c30a147f1c 100644 --- a/offline/packages/tpccalib/TpcCentralMembraneMatching.h +++ b/offline/packages/tpccalib/TpcCentralMembraneMatching.h @@ -9,6 +9,7 @@ * \author Tony Frawley , Hugo Pereira Da Costa */ +#include #include #include @@ -98,12 +99,36 @@ class TpcCentralMembraneMatching : public SubsysReco m_averageMode = averageMode; } + void set_totalDistMode(bool totalDistMode) + { + m_totalDistMode = totalDistMode; + } + + void set_skipOutliers(bool skipOutliers) + { + m_skipOutliers = skipOutliers; + } + + void set_manualInterp(bool manualInterp) + { + m_manualInterp = manualInterp; + } + void set_event_sequence(int seq) { m_event_sequence = seq; m_event_index = 100 * seq; } + void set_stripePatternFile(const std::string &stripePatternFile) + { + m_stripePatternFile = stripePatternFile; + } + + void set_phiHistInRad(bool rad){ m_phiHist_in_rad = rad; } + + void set_useZ(bool use) { m_useZ = use; } + // void set_laminationFile(const std::string& filename) //{ // m_lamfilename = filename; @@ -136,6 +161,8 @@ class TpcCentralMembraneMatching : public SubsysReco //! tpc distortion correction utility class TpcDistortionCorrection m_distortionCorrection; + bool m_phiHist_in_rad{true}; + //! CMFlashClusterContainer *m_corrected_CMcluster_map{nullptr}; LaserClusterContainer *m_corrected_CMcluster_map{nullptr}; CMFlashDifferenceContainer *m_cm_flash_diffs{nullptr}; @@ -197,9 +224,12 @@ class TpcCentralMembraneMatching : public SubsysReco TTree *match_tree{nullptr}; TTree *event_tree{nullptr}; + std::string m_stripePatternFile = "/sphenix/u/bkimelman/CMStripePattern.root"; + bool m_useHeader{true}; bool m_averageMode{false}; - + bool m_totalDistMode{false}; + std::vector e_matched; std::vector e_truthIndex; std::vector e_truthR; @@ -275,6 +305,9 @@ class TpcCentralMembraneMatching : public SubsysReco TGraph2D *gr_dPhi[2]{nullptr, nullptr}; TGraph *gr_points[2]{nullptr, nullptr}; + TGraph2D *gr_dR_toInterp[2]{nullptr, nullptr}; + TGraph2D *gr_dPhi_toInterp[2]{nullptr, nullptr}; + /// phi cut for matching clusters to pad /** TODO: this will need to be adjusted to match beam-induced time averaged distortions */ double m_phi_cut{0.025}; @@ -298,6 +331,7 @@ class TpcCentralMembraneMatching : public SubsysReco //@} + /* ///@name central membrane pads definitions //@{ static constexpr double mm{1.0}; @@ -364,6 +398,7 @@ class TpcCentralMembraneMatching : public SubsysReco std::array &nStripesIn, std::array &nStripesBefore, double cx[][nRadii], double cy[][nRadii]); + */ /// store centers of all central membrane pads std::vector m_truth_pos; @@ -379,6 +414,8 @@ class TpcCentralMembraneMatching : public SubsysReco bool m_fieldOn{true}; bool m_doFancy{false}; bool m_doHadd{false}; + bool m_skipOutliers{false}; + bool m_manualInterp{false}; std::vector m_reco_RPeaks[2]; double m_m[2]{}; @@ -388,6 +425,9 @@ class TpcCentralMembraneMatching : public SubsysReco std::vector m_reco_RMatches[2]; double m_recoRotation[2][3]{{-999, -999, -999}, {-999, -999, -999}}; + + LaserClusterHelper m_laserClusterHelper; + bool m_useZ{false}; }; #endif // PHTPCCENTRALMEMBRANEMATCHER_H diff --git a/offline/packages/tpccalib/TpcLaminationFitting.cc b/offline/packages/tpccalib/TpcLaminationFitting.cc index 29b4cb106e..df66d95f94 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.cc +++ b/offline/packages/tpccalib/TpcLaminationFitting.cc @@ -3,11 +3,13 @@ #include #include #include -#include +#include #include #include +#include + #include #include @@ -25,10 +27,15 @@ #include #include #include +#include #include #include #include #include +#include +#include +#include + #include #include @@ -50,67 +57,90 @@ void TpcLaminationFitting::set_grid_dimensions(int phibins, int rbins) m_rbins = rbins; } +//___________________________________________________________ +void TpcLaminationFitting::set_lam_grid_dimensions(int phibins, int rbins) +{ + m_lamPhiBins = phibins; + m_lamRBins = rbins; +} + //____________________________________________ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) { for (int s = 0; s < 2; s++) { + + m_hPetal[s] = new TH2D((boost::format("hPetal_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s;#phi;R [cm]") %(s == 1 ? "North" : "South")).str().c_str(), 500, m_phiModMin[s], m_phiModMax[s], 500, 30, 80); + m_parameterScan[s] = new TH2D((boost::format("parameterScan_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s Lamination Parameter Scan;m;B") %(s == 1 ? "North" : "South")).str().c_str(), 41, -0.0205, 0.0205, 49, -3.0625, 3.0625); + //m_parameterScan[s] = new TH2D((boost::format("parameterScan_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s Lamination Parameter Scan;m;B") %(s == 1 ? "North" : "South")).str().c_str(), 101, -0.101, 0.101, 101, -10.1, 10.1); + //m_parameterScan[s] = new TH2D((boost::format("parameterScan_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s Lamination Parameter Scan;A (asymptote);C (decay constant)") %(s == 1 ? "North" : "South")).str().c_str(), 101, -1.005, 0.005, 101, -0.0025, 0.5025); + + + clusterMap[s] = new TH2D((boost::format("clusterMap_%s") %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("TPC %s;#phi;R [cm]") %(s == 1 ? "North" : "South")).str().c_str(), 20000, 0.0, 2*TMath::Pi(), 2000, 28, 80); + for (int l = 0; l < 18; l++) { - double shift = l * M_PI / 9; + double shift = (l * M_PI / 9); if (s == 0) { shift += M_PI / 18; } + m_laminationIdeal[l][s] = shift; + //this function for the offset was determined from fitting the measured lamination offsets vs ideal lamination phi from field off data in run 75103 + //m_laminationOffset[l][s] = -0.00296837 + 0.0014604 * cos(shift - 1.2246); + if(s == 0) + { + //m_laminationOffset[l][s] = -0.00236289 + 0.00143918 * cos(shift - 1.31782); + m_laminationOffset[l][s] = -0.00148465 + 0.00219335 * cos(shift - 1.24219); + } + else + { + //m_laminationOffset[l][s] = -0.00323259 + 0.00138333 * cos(shift - 1.25373); + m_laminationOffset[l][s] = -0.00303345 + 0.0010828 * cos(shift - 1.03718); + } - m_hLamination[l][s] = new TH2D(std::format("hLamination{}_{}", l, (s == 1 ? "North" : "South")).c_str(), std::format("Lamination {} {}, #phi_{{expected}}={:.2f};R [cm];#phi", l, (s == 1 ? "North" : "South"), shift).c_str(), 200, 30, 80, 200, shift - 0.2, shift + 0.2); - //m_fLamination[l][s] = new TF1((std::format("fLamination{}_{}", l, (s == 1 ? "North" : "South")).c_str(), "[0]+[1]*exp(-[2]*x)", 30, 80); - //m_fLamination[l][s] = new TF1((std::format("fLamination{}_{}", l, (s == 1 ? "North" : "South")).c_str(), "[0]*(1+exp(-[2]*(x-[1])))", 30, 80); - m_fLamination[l][s] = new TF1(std::format("fLamination{}_{}", l, (s == 1 ? "North" : "South")).c_str(), "[3]+[0]*(1-exp(-[2]*(x-[1])))", 30, 80); - //m_fLamination[l][s]->SetParameters(-0.022 + shift, log(3.0/(-0.22 + shift)), 0.12); - m_fLamination[l][s]->SetParameters(-0.011, 30, 0.16, 0.0); - m_fLamination[l][s]->SetParLimits(0, -0.22, 0.0); - m_fLamination[l][s]->SetParLimits(1, 0, 80); - m_fLamination[l][s]->SetParLimits(2, 0.0, 3); - m_fLamination[l][s]->FixParameter(3, shift); - m_laminationCenter[l][s] = shift; + if(m_fieldOff) + { + m_hLamination[l][s] = new TH2D((boost::format("hLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("Lamination %d %s, #phi_{ideal}=%.2f;R [cm];#phi") %l %(s == 1 ? "North" : "South") %m_laminationIdeal[l][s]).str().c_str(), m_lamRBins, 30, 80, m_lamPhiBins, m_laminationIdeal[l][s] - 0.2, m_laminationIdeal[l][s] + 0.2); + m_fLamination[l][s] = new TF1((boost::format("fLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), "[0]+[1]", 30, 80); + m_fLamination[l][s]->SetParameters(m_laminationOffset[l][s], m_laminationIdeal[l][s]); + m_fLamination[l][s]->SetParLimits(0, -0.05, 0.05); + m_fLamination[l][s]->FixParameter(1, m_laminationIdeal[l][s]); + } + else + { + m_hLamination[l][s] = new TH2D((boost::format("hLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), (boost::format("Lamination %d %s, #phi_{nominal}=%.2f;R [cm];#phi") %l %(s == 1 ? "North" : "South") %(m_laminationIdeal[l][s]+m_laminationOffset[l][s])).str().c_str(), m_lamRBins, 30, 80, m_lamPhiBins, m_laminationIdeal[l][s]+m_laminationOffset[l][s] - 0.2, m_laminationIdeal[l][s]+m_laminationOffset[l][s] + 0.2); + m_fLamination[l][s] = new TF1((boost::format("fLamination%d_%s") %l %(s == 1 ? "North" : "South")).str().c_str(), "[3]+[0]*(1-exp(-[2]*(x-[1])))", 30, 80); + m_fLamination[l][s]->SetParameters(-0.08, 38, 0.16, 0.0); + m_fLamination[l][s]->SetParLimits(0, -0.02, 0.0); + m_fLamination[l][s]->SetParLimits(1, 0, 50); + m_fLamination[l][s]->SetParLimits(2, 0.0, 1.0); + m_fLamination[l][s]->FixParameter(3, m_laminationIdeal[l][s]+m_laminationOffset[l][s]); + } } } - /* - //Make map for run and ZDC rate for pp mode - m_run_ZDC_map_pp.insert(std::pair(49709, 555.0)); - m_run_ZDC_map_pp.insert(std::pair(52077, 0.0)); - m_run_ZDC_map_pp.insert(std::pair(52078, 0.0)); - m_run_ZDC_map_pp.insert(std::pair(53534, 3013.5)); - m_run_ZDC_map_pp.insert(std::pair(53630, 6849.3)); - m_run_ZDC_map_pp.insert(std::pair(53631, 5577.8)); - m_run_ZDC_map_pp.insert(std::pair(53632, 5151.2)); - m_run_ZDC_map_pp.insert(std::pair(53652, 4600.0)); - m_run_ZDC_map_pp.insert(std::pair(53687, 3967.2)); - m_run_ZDC_map_pp.insert(std::pair(53716, 3070.1)); - m_run_ZDC_map_pp.insert(std::pair(53738, 4510.7)); - m_run_ZDC_map_pp.insert(std::pair(53739, 4165.0)); - m_run_ZDC_map_pp.insert(std::pair(53741, 3738.1)); - m_run_ZDC_map_pp.insert(std::pair(53742, 3721.4)); - m_run_ZDC_map_pp.insert(std::pair(53743, 3693.4)); - m_run_ZDC_map_pp.insert(std::pair(53744, 3581.9)); - m_run_ZDC_map_pp.insert(std::pair(53756, 4471.4)); - m_run_ZDC_map_pp.insert(std::pair(53783, 4825.7)); - m_run_ZDC_map_pp.insert(std::pair(53871, 6871.5)); - m_run_ZDC_map_pp.insert(std::pair(53876, 5082.3)); - m_run_ZDC_map_pp.insert(std::pair(53877, 4758.5)); - m_run_ZDC_map_pp.insert(std::pair(53879, 4315.0)); - - //beam off go into pp - m_run_ZDC_map_pp.insert(std::pair(53098, 0.0)); - m_run_ZDC_map_pp.insert(std::pair(53271, 0.0)); - - m_run_ZDC_map_auau.insert(std::pair(54966, 12400.)); - m_run_ZDC_map_auau.insert(std::pair(54967, 11600.)); - m_run_ZDC_map_auau.insert(std::pair(54968, 10500.)); - m_run_ZDC_map_auau.insert(std::pair(54969, 9680.)); - */ + CDBTTree *cdbttree = new CDBTTree(m_stripePatternFile); + cdbttree->LoadCalibrations(); + auto cdbMap = cdbttree->GetDoubleEntryMap(); + for (const auto &[index, values] : cdbMap) + { + if(index / 10000 == 18) + { + m_truthR[0].push_back(cdbttree->GetDoubleValue(index, "truthR")); + m_truthPhi[0].push_back(cdbttree->GetDoubleValue(index, "truthPhi")); + } + else if(index / 10000 == 0) + { + m_truthR[1].push_back(cdbttree->GetDoubleValue(index, "truthR")); + m_truthPhi[1].push_back(cdbttree->GetDoubleValue(index, "truthPhi")); + } + } + if(m_truthR[0].empty() || m_truthPhi[0].empty() || m_truthR[1].empty() || m_truthPhi[1].empty()) + { + std::cerr << "stripe pattern file passed has no stripes on one side. Exiting" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } int ret = GetNodes(topNode); return ret; @@ -119,7 +149,6 @@ int TpcLaminationFitting::InitRun(PHCompositeNode *topNode) //______________________________________ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) { - //m_correctedCMcluster_map = findNode::getClass(topNode, "LAMINATION_CLUSTER"); m_correctedCMcluster_map = findNode::getClass(topNode, "LASER_CLUSTER"); if (!m_correctedCMcluster_map) { @@ -127,6 +156,25 @@ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } + /* + m_geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + if (!m_geom_container) + { + std::cout << PHWHERE << "ERROR: Can't find node TPCGEOMCONTAINER" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); + if (!m_tGeometry) + { + std::cout << PHWHERE << "ActsGeometry not found on node tree. Exiting" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + */ + + m_laserClusterHelper.set_useZ(m_useZ); + m_laserClusterHelper.loadNodes(topNode); + m_dcc_in_module_edge = findNode::getClass(topNode, "TpcDistortionCorrectionContainerModuleEdge"); if (m_dcc_in_module_edge) { @@ -200,13 +248,17 @@ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) delete m_dcc_out->m_hDZint[i]; m_dcc_out->m_hDZint[i] = new TH2F(std::format("hIntDistortionZ{}", extension[i]).c_str(), std::format("hIntDistortionZ{}", extension[i]).c_str(), m_phibins + 2, phiMin, phiMax, m_rbins + 2, rMin, rMax); delete m_dcc_out->m_hentries[i]; - m_dcc_out->m_hentries[i] = new TH2I(std::format("hEntries{}", extension[i]).c_str(), std::format("hEntries{}", extension[i]).c_str(), m_phibins + 2, phiMin, phiMax, m_rbins + 2, rMin, rMax); + m_dcc_out->m_hentries[i] = new TH2I((boost::format("hEntries%s") % extension[i]).str().c_str(), (boost::format("hEntries%s") % extension[i]).str().c_str(), m_phibins + 2, phiMin, phiMax, m_rbins + 2, rMin, rMax); + + phiDistortionLamination[i] = new TH2F((boost::format("phiDistortionLamination%s") % extension[i]).str().c_str(), (boost::format("phiDistortionLamination%s") % extension[i]).str().c_str(), m_phibins + 2, phiMin, phiMax, m_rbins + 2, rMin, rMax); + } m_laminationTree = new TTree("laminationTree","laminationTree"); m_laminationTree->Branch("side",&m_side); m_laminationTree->Branch("lamIndex",&m_lamIndex); m_laminationTree->Branch("lamPhi",&m_lamPhi); + m_laminationTree->Branch("lamOffset",&m_lamShift); m_laminationTree->Branch("goodFit",&m_goodFit); m_laminationTree->Branch("A",&m_A); m_laminationTree->Branch("B",&m_B); @@ -216,8 +268,11 @@ int TpcLaminationFitting::GetNodes(PHCompositeNode *topNode) m_laminationTree->Branch("C_err",&m_C_err); m_laminationTree->Branch("distanceToFit",&m_dist); m_laminationTree->Branch("nBinsFit",&m_nBins); - - + m_laminationTree->Branch("RMSE",&m_rmse); + //m_laminationTree->Branch("A_zdc",&m_A_zdc); + //m_laminationTree->Branch("B_zdc",&m_B_zdc); + //m_laminationTree->Branch("C_zdc",&m_C_zdc); + return Fun4AllReturnCodes::EVENT_OK; } @@ -260,15 +315,92 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) { const auto &[cmkey, cmclus_orig] = *cmitr; LaserCluster *cmclus = cmclus_orig; - // const unsigned int adc = cmclus->getAdc(); + + if(cmclus->getNLayers() <= m_nLayerCut) + { + continue; + } + + bool side = (bool) TpcDefs::getSide(cmkey); + double weight = 1.0; + if(m_adcWeight) + { + weight = 1.0*cmclus->getAdc(); + } + + //const unsigned int adc = cmclus->getAdc(); + /* bool side = (bool) TpcDefs::getSide(cmkey); - if (cmclus->getNLayers() <= m_nLayerCut) + if (cmclus->getNLayers() < m_nLayerCut) { continue; } + double weight = 1.0; + if(m_adcWeight) + { + weight = 1.0*cmclus->getAdc(); + } + + double meanR = 0.0; + double meanPhi = 0.0; + double meanZ = 0.0; + double meanAdc = 0.0; + for(int i=0; i<(int)cmclus->getNhits(); i++) + { + LaserClusterHitInfo LCHI = cmclus->getHit(i); + int layer = TrkrDefs::getLayer(LCHI.hitsetkey); + PHG4TpcGeom *layer_geom = m_geom_container->GetLayerCellGeom(layer); + double radius = layer_geom->get_radius(); + double phi = layer_geom->get_phi(TpcDefs::getTBin(LCHI.hitkey), TpcDefs::getSide(LCHI.hitsetkey)); + + double tdriftmax = layer_geom->get_max_driftlength() / m_tGeometry->get_drift_velocity(); + + double zdriftlength = layer_geom->get_zcenter(TpcDefs::getPad(LCHI.hitkey)) * m_tGeometry->get_drift_velocity(); + // convert z drift length to z position in the TPC + double env_z = tdriftmax * m_tGeometry->get_drift_velocity() - zdriftlength; + if (TpcDefs::getSide(LCHI.hitsetkey) == 0) + { + env_z = -env_z; + } + + double env_x = radius * cos(phi); + double env_y = radius * sin(phi); + + //hard code at 0 until better z coordinate calibration is determined + env_z = 0.0; + + Acts::Vector3 env_global(env_x, env_y, env_z); + Acts::Vector3 global = m_tGeometry->transformTpcEnvelopeToWorld(env_global); + + double global_x = global.x(); + double global_y = global.y(); + double global_z = global.z(); + + double global_R = sqrt(global_x*global_x + global_y*global_y); + double global_phi = atan2(global_y, global_x); + + meanR += global_R * LCHI.adc; + meanPhi += global_phi * LCHI.adc; + meanZ += global_z * LCHI.adc; + meanAdc += LCHI.adc; + } + + meanR /= meanAdc; + meanPhi /= meanAdc; + meanZ /= meanAdc; + //Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), cmclus->getZ()); - Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); + //Acts::Vector3 pos(cmclus->getX(), cmclus->getY(), (side ? 1.0 : -1.0)); + Acts::Vector3 pos(meanR * cos(meanPhi), meanR * sin(meanPhi), meanZ); + */ + + Acts::Vector3 pos = m_laserClusterHelper.getClusterCentroid(cmclus); + if(pos.hasNaN()) + { + continue; + } + if (m_dcc_in_module_edge) { pos = m_distortionCorrection.get_corrected_position(pos, m_dcc_in_module_edge); @@ -280,25 +412,52 @@ int TpcLaminationFitting::process_event(PHCompositeNode *topNode) TVector3 tmp_pos(pos[0], pos[1], pos[2]); - for (int l = 0; l < 18; l++) + if(cmclus->getNLayers() > m_nLayerCut && (!m_useSDLayerCut || cmclus->getSDWeightedLayer() > 0.5)) { - double shift = m_laminationCenter[l][side]; - - double phi2pi = tmp_pos.Phi(); - if (side && phi2pi < -0.2) - { - phi2pi += 2 * M_PI; - } - if (!side && phi2pi < M_PI / 18 - 0.2) + for (int l = 0; l < 18; l++) { - phi2pi += 2 * M_PI; + double shift = m_laminationIdeal[l][side]; + + double phi2pi = tmp_pos.Phi(); + if (side && phi2pi < -0.2) + { + phi2pi += 2 * M_PI; + } + if (!side && phi2pi < M_PI / 18 - 0.2) + { + phi2pi += 2 * M_PI; + } + + if (phi2pi > shift - 0.2 && phi2pi < shift + 0.2) + { + m_hLamination[l][side]->Fill(tmp_pos.Perp(), phi2pi, weight); + } } + } - if (phi2pi > shift - 0.2 && phi2pi < shift + 0.2) - { - m_hLamination[l][side]->Fill(tmp_pos.Perp(), phi2pi); - } + if(m_useSDLayerCut && cmclus->getSDWeightedLayer() > 0.5) + { + continue; + } + + double phi2pimod = tmp_pos.Phi(); + if (phi2pimod < 0.0) + { + phi2pimod += 2 * M_PI; + } + + clusterMap[side]->Fill(phi2pimod, tmp_pos.Perp(), weight); + + while(side && phi2pimod > M_PI / 9) + { + phi2pimod -= M_PI / 9; } + while(!side && phi2pimod > M_PI / 18) + { + phi2pimod -= M_PI / 9; + } + + m_hPetal[side]->Fill(phi2pimod, tmp_pos.Perp(), weight); } return Fun4AllReturnCodes::EVENT_OK; @@ -328,6 +487,7 @@ int TpcLaminationFitting::fitLaminations() //float ZDC = 4500.0; TF1 *Af[2] = {new TF1("AN","pol1",0,100000), new TF1("AS","pol1",0,100000)}; TF1 *Bf[2] = {new TF1("BN","pol1",0,100000), new TF1("BS","pol1",0,100000)}; + //TF1 *Cf[2] = {new TF1("CN","pol1",0,100000), new TF1("CS","pol1",0,100000)}; double Cseed[2] = {0.16, 0.125}; if(ppMode) @@ -349,9 +509,12 @@ int TpcLaminationFitting::fitLaminations() Af[0]->SetParameters(-0.007999,-1.783e-6); Af[1]->SetParameters(-0.003288,-2.297e-6); - + Bf[0]->SetParameters(31.55,0.0006141); Bf[1]->SetParameters(34.7,0.0005226); + + //Cf[0]->SetParameters(5.33e-5,0.0); + //Cf[1]->SetParameters(4.166e-5,0.0); } else { @@ -379,6 +542,9 @@ int TpcLaminationFitting::fitLaminations() Bf[0]->SetParameters(32.96,0.0002997); Bf[1]->SetParameters(31.19,0.0005622); + //Cf[0]->SetParameters(1.316-5,0.0); + //Cf[1]->SetParameters(1.284e-5,0.0); + Cseed[0] = 0.125; Cseed[1] = 0.122; } @@ -400,13 +566,20 @@ int TpcLaminationFitting::fitLaminations() TGraph *gr = new TGraph(); TGraph *proj = new TGraph(); - //m_fLamination[l][s]->SetParameters(-0.022 + m_laminationCenter[l][s], 4.595 * seedScale, 0.138); - //m_fLamination[l][s]->SetParameters(-0.022 + m_laminationCenter[l][s], log(4.595 * seedScale/(-0.022 + m_laminationCenter[l][s])), 0.138); - //m_fLamination[l][s]->SetParameters(-0.011 + m_laminationCenter[l][s], 0.025, 0.16); - //m_fLamination[l][s]->SetParameters(-0.011, 30, 0.16, m_laminationCenter[l][s]); - m_fLamination[l][s]->SetParameters(Af[s]->Eval(m_ZDC_coincidence), Bf[s]->Eval(m_ZDC_coincidence), Cseed[s], m_laminationCenter[l][s]); - m_fLamination[l][s]->FixParameter(3, m_laminationCenter[l][s]); - + if(m_fieldOff) + { + m_fLamination[l][s]->SetParameters(m_laminationOffset[l][s], m_laminationIdeal[l][s]); + m_fLamination[l][s]->FixParameter(1, m_laminationIdeal[l][s]); + } + else + { + m_A_zdc[s] = Af[s]->Eval(m_ZDC_coincidence); + m_B_zdc[s] = Bf[s]->Eval(m_ZDC_coincidence); + m_C_zdc[s] = Cseed[s]; + m_fLamination[l][s]->SetParameters(Af[s]->Eval(m_ZDC_coincidence), Bf[s]->Eval(m_ZDC_coincidence), Cseed[s], m_laminationIdeal[l][s] + m_laminationOffset[l][s]); + m_fLamination[l][s]->FixParameter(3, m_laminationIdeal[l][s] + m_laminationOffset[l][s]); + } + TF1 *fitSeed = (TF1 *) m_fLamination[l][s]->Clone(); fitSeed->SetName(std::format("fitSeed{}_{}", l, (s == 1 ? "North" : "South")).c_str()); @@ -444,7 +617,7 @@ int TpcLaminationFitting::fitLaminations() { double phi = m_hLamination[l][s]->GetYaxis()->GetBinCenter(j); - if (fabs(phi - m_laminationCenter[l][s]) > 0.05) + if (fabs(phi - m_laminationIdeal[l][s]) > 0.05) { continue; } @@ -481,6 +654,10 @@ int TpcLaminationFitting::fitLaminations() double distToFunc = 0.0; int nBinsUsed = 0; + int nBinsUsed_R_lt_45 = 0; + + double wc = 0.0; + double c = 0.0; for (int i = 1; i <= m_hLamination[l][s]->GetNbinsX(); i++) { @@ -506,14 +683,34 @@ int TpcLaminationFitting::fitLaminations() { distToFunc += j; nBinsUsed++; + if(R < 45.0) + { + nBinsUsed_R_lt_45++; + } break; } } + for(int j=0; j<= nBinAvg; j++) + { + if(m_hLamination[l][s]->GetBinContent(i,funcBin + j) > 0) + { + wc += m_hLamination[l][s]->GetBinContent(i,funcBin + j) * pow(j,2); + c += m_hLamination[l][s]->GetBinContent(i,funcBin + j); + } + if(j != 0 && m_hLamination[l][s]->GetBinContent(i,funcBin - j) > 0) + { + wc += m_hLamination[l][s]->GetBinContent(i,funcBin - j) * pow(j,2); + c += m_hLamination[l][s]->GetBinContent(i,funcBin - j); + } + } } m_distanceToFit[l][s] = distToFunc / nBinsUsed; m_nBinsFit[l][s] = nBinsUsed; - if (nBinsUsed < 10 || distToFunc / nBinsUsed > 1.0) + if(c>0) { m_fitRMSE[l][s] = sqrt(wc / c); + } else { m_fitRMSE[l][s] = -999; +} + if (nBinsUsed < 10 || distToFunc / nBinsUsed > 1.0 || nBinsUsed_R_lt_45 < 5) { m_laminationGoodFit[l][s] = false; } @@ -527,14 +724,9 @@ int TpcLaminationFitting::fitLaminations() return Fun4AllReturnCodes::EVENT_OK; } -int TpcLaminationFitting::InterpolatePhiDistortions(TH2 *simPhiDistortion[2]) + +int TpcLaminationFitting::InterpolatePhiDistortions() { - phiDistortionLamination[0] = (TH2 *) simPhiDistortion[0]->Clone(); - phiDistortionLamination[0]->Reset(); - phiDistortionLamination[0]->SetName("phiDistortionLamination0"); - phiDistortionLamination[1] = (TH2 *) simPhiDistortion[1]->Clone(); - phiDistortionLamination[1]->Reset(); - phiDistortionLamination[1]->SetName("phiDistortionLamination1"); for (int s = 0; s < 2; s++) { @@ -562,51 +754,36 @@ int TpcLaminationFitting::InterpolatePhiDistortions(TH2 *simPhiDistortion[2]) phi -= 2 * M_PI; } int phiBin = phiDistortionLamination[s]->GetXaxis()->FindBin(phi); - //m_fLamination[l][s]->SetParameter(0, m_fLamination[l][s]->GetParameter(0) - m_laminationCenter[l][s]); - m_fLamination[l][s]->SetParameter(3, m_laminationOffset[l][s]); - /* - if(s==0) - { - m_fLamination[l][s]->SetParameter(3, 0.0); - } + if(m_fieldOff) + { + m_laminationOffset[l][s] = m_fLamination[l][s]->GetParameter(0); + m_fLamination[l][s]->SetParameter(1, 0.0); + } else - { - m_fLamination[l][s]->SetParameter(3, 0.0); - } - */ - //m_fLamination[l][s]->SetParameter(3, 0.0); - double phiDistortion = R * m_fLamination[l][s]->Integral(phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i), phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1)) / (phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1) - phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i)); - //m_fLamination[l][s]->SetParameter(0, m_fLamination[l][s]->GetParameter(0) + m_laminationCenter[l][s]); - m_fLamination[l][s]->SetParameter(3, m_laminationCenter[l][s]); + { + //m_fLamination[l][s]->SetParameter(3, -1.0*m_laminationOffset[l][s]); + m_fLamination[l][s]->SetParameter(3, 0.0); + } + double phiDistortion = m_fLamination[l][s]->Integral(phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i), phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1)) / (phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i + 1) - phiDistortionLamination[s]->GetYaxis()->GetBinLowEdge(i)); + if(!m_phiHist_in_rad) + { + phiDistortion *= R; + } + if(m_fieldOff) + { + m_fLamination[l][s]->SetParameter(1, m_laminationIdeal[l][s]); + } + else + { + //m_fLamination[l][s]->SetParameter(3, m_laminationIdeal[l][s]); + m_fLamination[l][s]->SetParameter(3, m_laminationIdeal[l][s] + m_laminationOffset[l][s]); + } phiDistortionLamination[s]->SetBinContent(phiBin, i, phiDistortion); + m_dcc_out->m_hDPint[s]->SetBinContent(phiBin, i, phiDistortion); } } } - for (int s = 0; s < 2; s++) - { - m_dcc_out->m_hDPint[s] = (TH2 *) phiDistortionLamination[s]->Clone(); - m_dcc_out->m_hDPint[s]->SetName(std::format("hIntDistortionP{}", (s == 0 ? "_negz" : "_posz")).c_str()); - } - - /* - for(int s=0; s<2; s++) - { - for(int i=1; i<=m_dcc_out->m_hDPint[s]->GetNbinsX(); i++) - { - for(int j=1; j<=m_dcc_out->m_hDPint[s]->GetNbinsY(); j++) - { - if(phiDistortionLamination[s]->GetBinContent(i,j) != 0.0) - { - m_dcc_out->m_hDPint[s]->SetBinContent(i,j, phiDistortionLamination[s]->GetBinContent(i,j)); - } - } - } - } - */ - - // m_dcc_out->m_hDPint[0] = (TH2*)phiDistortionLamination[0]->Clone(); - // m_dcc_out->m_hDPint[1] = (TH2*)phiDistortionLamination[1]->Clone(); for (int s = 0; s < 2; s++) { @@ -625,17 +802,14 @@ int TpcLaminationFitting::InterpolatePhiDistortions(TH2 *simPhiDistortion[2]) laminationPhiBins.push_back(j); } } - if (laminationPhiBins.size() > 1) { laminationPhiBins.push_back(laminationPhiBins[0]); } - for (int lamPair = 0; lamPair < (int) laminationPhiBins.size() - 1; lamPair++) { double dist0 = m_dcc_out->m_hDPint[s]->GetBinContent(laminationPhiBins[lamPair], i); double dist1 = m_dcc_out->m_hDPint[s]->GetBinContent(laminationPhiBins[lamPair + 1], i); - int nEmptyBins = laminationPhiBins[lamPair + 1] - laminationPhiBins[lamPair] - 1; if (laminationPhiBins[lamPair] > laminationPhiBins[lamPair + 1]) { @@ -646,7 +820,6 @@ int TpcLaminationFitting::InterpolatePhiDistortions(TH2 *simPhiDistortion[2]) bool wrap = false; int wrapBin = -1; for (int j = 1; j <= nEmptyBins; j++) - // for(int j=+ 1; j m_dcc_out->m_hDPint[s]->GetNbinsX() - 1) { @@ -670,9 +843,153 @@ int TpcLaminationFitting::InterpolatePhiDistortions(TH2 *simPhiDistortion[2]) return Fun4AllReturnCodes::EVENT_OK; } -int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) +int TpcLaminationFitting::doGlobalRMatching(int side) { + std::vector distortedPhi; + TF1 *tmpLamFit = (TF1*)m_fLamination[0][side]->Clone(); + + double meanB = 0.0; + + if(m_fieldOff) + { + tmpLamFit->SetParameters(0.0, 0.0); + meanB = -999.99; + } + else + { + double meanA = 0.0; + double meanC = 0.0; + int nGoodFits = 0; + for(int l = 0; l < 18; l++) + { + if(!m_laminationGoodFit[l][side]) + { + continue; + } + meanA += m_fLamination[l][side]->GetParameter(0); + meanB += m_fLamination[l][side]->GetParameter(1); + meanC += m_fLamination[l][side]->GetParameter(2); + nGoodFits++; + } + if(nGoodFits == 0) + { + return Fun4AllReturnCodes::EVENT_OK; + } + + meanA /= nGoodFits; + meanB /= nGoodFits; + meanC /= nGoodFits; + //tmpLamFit->SetParameters(meanA, meanB, meanC, meanOffset); + tmpLamFit->SetParameters(meanA, meanB, meanC, 0.0); + } + + + for(int i=0; i<(int)m_truthPhi[side].size(); i++) + { + double distortedPhiTmp = m_truthPhi[side][i] + tmpLamFit->Eval(m_truthR[side][i]); + while(distortedPhiTmp < m_phiModMin[side]) + { + distortedPhiTmp += M_PI / 9; + } + while(distortedPhiTmp > m_phiModMax[side]) + { + distortedPhiTmp -= M_PI / 9; + } + distortedPhi.push_back(distortedPhiTmp); + } + + double maxSum = 0.0; + double best_m = 0.0; + double best_b = 0.0; + //int mStep = 0; + //int bStep = 0; + //for(double m = -0.02; m<=0.02; m+=0.001) + for(int xbin=1; xbin<=m_parameterScan[side]->GetNbinsX(); xbin++) + { + double m = m_parameterScan[side]->GetXaxis()->GetBinCenter(xbin); + //for(double b=-3.0; b<=3.0; b+=0.125) + for(int ybin=1; ybin<=m_parameterScan[side]->GetNbinsY(); ybin++) + { + double b = m_parameterScan[side]->GetYaxis()->GetBinCenter(ybin); + double sum = 0.0; + for(int i=0; i<(int)m_truthR[side].size(); i++) + { + double distortedTruthR = (m_truthR[side][i] + b)/(1.0 - m); + //double distortedTruthR = boost::math::lambert_w0(-m*b*exp(meanB-m_truthR[side][i]-m))/b + m_truthR[side][i] + m; + int binR = m_hPetal[side]->GetYaxis()->FindBin(distortedTruthR); + int binPhi = m_hPetal[side]->GetXaxis()->FindBin(distortedPhi[i]); + for(int j=-2; j<=2; j++) + { + int neighborBinR = binR + j; + if(neighborBinR < 1 || neighborBinR > m_hPetal[side]->GetNbinsY()) { continue; +} + for(int k=-5; k<=5; k++) + { + int neighborBinPhi = binPhi + k; + if(neighborBinPhi < 1) + { + neighborBinPhi += m_hPetal[side]->GetNbinsX(); + } + if(neighborBinPhi > m_hPetal[side]->GetNbinsX()) + { + neighborBinPhi -= m_hPetal[side]->GetNbinsX(); + } + sum += m_hPetal[side]->GetBinContent(neighborBinPhi, neighborBinR); + } + } + } + + if(Verbosity() > 2) + { + std::cout << "working on side " << side << " m step " << xbin-1 << " b step " << ybin-1 << " with m = " << m << " and b = " << b << " with sum = " << sum << std::endl; + } + + m_parameterScan[side]->Fill(m, b, sum); + + if(sum > maxSum) + { + maxSum = sum; + best_m = m; + best_b = b; + } + //bStep++; + } + //mStep++; + } + + std::cout << "Best R distortion for side " << side << " is m = " << best_m << " and b = " << best_b << " with sum of " << maxSum << std::endl; + + for(int j=2; j<=m_dcc_out->m_hDRint[side]->GetNbinsX()-1; j++) + { + for(int i=2; i<=m_dcc_out->m_hDRint[side]->GetNbinsY()-1; i++) + { + double R = m_dcc_out->m_hDRint[side]->GetYaxis()->GetBinCenter(i); + double distortionR = R * best_m + best_b; + m_dcc_out->m_hDRint[side]->SetBinContent(j, i, distortionR); + } + } + + std::vector bestDistortedR; + for(double i : m_truthR[side]) + { + double distortedR = (i + best_b)/(1.0 - best_m); + bestDistortedR.push_back(distortedR); + } + + m_bestRMatch[side] = new TGraph(distortedPhi.size(), distortedPhi.data(), bestDistortedR.data()); + m_bestRMatch[side]->SetTitle((boost::format("Best R matching TPC %s, m = %.3f b = %.3f") %(side == 0 ? "South" : "North") %best_m %best_b).str().c_str()); + m_bestRMatch[side]->SetName((boost::format("bestRMatch_side%d") %side).str().c_str()); + m_bestRMatch[side]->SetMarkerStyle(25); + m_bestRMatch[side]->SetMarkerSize(0.8); + m_bestRMatch[side]->SetMarkerColor(kRed); + + return Fun4AllReturnCodes::EVENT_OK; +} + +int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) +{ + std::string sql = "SELECT * FROM gl1_scalers WHERE runnumber = " + std::to_string(m_runnumber) + ";"; odbc::Statement *stmt = DBInterface::instance()->getStatement("daq"); odbc::ResultSet *resultSet = stmt->executeQuery(sql); @@ -683,7 +1000,7 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) delete resultSet; return Fun4AllReturnCodes::ABORTRUN; } - + while (resultSet->next()) { int index = resultSet->getInt("index"); @@ -692,20 +1009,20 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) scalers[index][1] = resultSet->getLong("live"); scalers[index][2] = resultSet->getLong("raw"); } - + delete resultSet; - + m_ZDC_coincidence = (1.0*scalers[3][2]/scalers[0][2])/(106e-9); - + std::cout << "Runnumber: " << m_runnumber << " ppMode: " << ppMode << " ZDC coindicence rate: " << m_ZDC_coincidence << std::endl; - + int fitSuccess = fitLaminations(); if (fitSuccess != Fun4AllReturnCodes::EVENT_OK) { std::cout << PHWHERE << " Return code for lamination fitting was " << fitSuccess << " and not successful" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - + if(!m_QAFileName.empty()) { TCanvas *c1 = new TCanvas(); @@ -726,104 +1043,168 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } m_fLamination[l][s]->Draw("same"); - TLine *line = new TLine(30,m_laminationCenter[l][s],80,m_laminationCenter[l][s]); - line->SetLineColor(kBlue); - line->SetLineStyle(2); - line->Draw("same"); + TLegend *leg = new TLegend(0.15,0.15,0.45,0.4); + + TLine *lineIdeal; + TLine *lineOffset; + if(m_fieldOff) + { + lineIdeal = new TLine(30,m_laminationIdeal[l][s],80,m_laminationIdeal[l][s]); + lineIdeal->SetLineColor(kBlue); + leg->AddEntry(lineIdeal,std::format("#phi_{{ideal}}={:.6f}",m_laminationIdeal[l][s]).c_str(), "l"); + } + else + { + lineIdeal = new TLine(30,m_laminationIdeal[l][s],80,m_laminationIdeal[l][s]); + lineIdeal->SetLineColor(kBlue); + leg->AddEntry(lineIdeal,std::format("#phi_{{ideal}}={:.6f}",m_laminationIdeal[l][s]).c_str(), "l"); + + lineOffset = new TLine(30,m_laminationIdeal[l][s]+m_laminationOffset[l][s],80,m_laminationIdeal[l][s]+m_laminationOffset[l][s]); + lineOffset->SetLineColor(kGreen+2); + lineOffset->SetLineStyle(2); + leg->AddEntry(lineOffset,std::format("#phi_{{ideal}}+#phi_{{offset}}={:.6f}",m_laminationOffset[l][s]).c_str(), "l"); + lineOffset->Draw("same"); + } + lineIdeal->Draw("same"); + + leg->Draw("same"); + + TPaveText *pars = new TPaveText(0.6, 0.55, 0.85, 0.85, "NDC"); - pars->AddText("#phi = #phi_{ideal} + A#times (1 - e^{-C#times (R - B)})"); - pars->AddText(std::format("A={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(0), m_fLamination[l][s]->GetParError(0)).c_str()); - pars->AddText(std::format("#phi_{{ideal}}={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(3), m_fLamination[l][s]->GetParError(3)).c_str()); - pars->AddText(std::format("B={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(1), m_fLamination[l][s]->GetParError(1)).c_str()); - pars->AddText(std::format("C={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(2), m_fLamination[l][s]->GetParError(2)).c_str()); - pars->AddText(std::format("Distance to line={:.2f}", m_distanceToFit[l][s]).c_str()); - pars->AddText(std::format("Number of Bins used={}", m_nBinsFit[l][s]).c_str()); + if(m_fieldOff) + { + pars->AddText("#phi = #phi_{ideal} + #phi_{offset}"); + pars->AddText(std::format("#phi_{{ideal}}={:.3f}#pm {:.3f}",m_fLamination[l][s]->GetParameter(1), m_fLamination[l][s]->GetParError(1)).c_str()); + pars->AddText(std::format("#phi_{{offset}}={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(0), m_fLamination[l][s]->GetParError(0)).c_str()); + pars->AddText(std::format("Distance to line={:.2f}", m_distanceToFit[l][s]).c_str()); + pars->AddText(std::format("Number of Bins used={}", m_nBinsFit[l][s]).c_str()); + pars->AddText(std::format("WRMSE={:.2f}", m_fitRMSE[l][s]).c_str()); + } + else + { + pars->AddText("#phi = #phi_{ideal} + A#times (1 - e^{-C#times (R - B)})"); + pars->AddText(std::format("A={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(0), m_fLamination[l][s]->GetParError(0)).c_str()); + //pars->AddText(std::format("#phi_{{ideal}}=%.3f#pm 0.000", m_laminationIdeal[l][s]).c_str()); + pars->AddText(std::format("#phi_{{nominal}}={:.3f}#pm 0.000", (m_laminationIdeal[l][s]+m_laminationOffset[l][s])).c_str()); + //pars->AddText(std::format("#phi_{{offset}}={:.3f}#pm 0.000", m_laminationOffset[l][s]).c_str()); + pars->AddText(std::format("B={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(1), m_fLamination[l][s]->GetParError(1)).c_str()); + pars->AddText(std::format("C={:.3f}#pm {:.3f}", m_fLamination[l][s]->GetParameter(2), m_fLamination[l][s]->GetParError(2)).c_str()); + pars->AddText(std::format("Distance to line={:.2f}", m_distanceToFit[l][s]).c_str()); + pars->AddText(std::format("Number of Bins used={}", m_nBinsFit[l][s]).c_str()); + pars->AddText(std::format("WRMSE={:.2f}", m_fitRMSE[l][s]).c_str()); + } pars->Draw("same"); c1->SaveAs(m_QAFileName.c_str()); } } c1->SaveAs(std::format("{}]", m_QAFileName).c_str()); } + + //TFile *simDistortion = new TFile("/cvmfs/sphenix.sdcc.bnl.gov/gcc-12.1.0/release/release_new/new.10/share/calibrations/distortion_maps/average_minus_static_distortion_inverted_10-new.root", "READ"); + //TH3 *hIntDistortionP_posz = (TH3 *) simDistortion->Get("hIntDistortionP_posz"); + //hIntDistortionP_posz->GetZaxis()->SetRange(2, 2); + //TH2 *simPhiDistortion[2]; + //simPhiDistortion[1] = (TH2 *) hIntDistortionP_posz->Project3D("yx"); + //TH3 *hIntDistortionP_negz = (TH3 *) simDistortion->Get("hIntDistortionP_negz"); + //hIntDistortionP_negz->GetZaxis()->SetRange(hIntDistortionP_negz->GetNbinsZ() - 1, hIntDistortionP_negz->GetNbinsZ() - 1); + //simPhiDistortion[0] = (TH2 *) hIntDistortionP_negz->Project3D("yx"); - TFile *simDistortion = new TFile("/cvmfs/sphenix.sdcc.bnl.gov/gcc-12.1.0/release/release_new/new.10/share/calibrations/distortion_maps/average_minus_static_distortion_inverted_10-new.root", "READ"); - TH3 *hIntDistortionP_posz = (TH3 *) simDistortion->Get("hIntDistortionP_posz"); - hIntDistortionP_posz->GetZaxis()->SetRange(2, 2); - TH2 *simPhiDistortion[2]; - simPhiDistortion[1] = (TH2 *) hIntDistortionP_posz->Project3D("yx"); - TH3 *hIntDistortionP_negz = (TH3 *) simDistortion->Get("hIntDistortionP_negz"); - hIntDistortionP_negz->GetZaxis()->SetRange(hIntDistortionP_negz->GetNbinsZ() - 1, hIntDistortionP_negz->GetNbinsZ() - 1); - simPhiDistortion[0] = (TH2 *) hIntDistortionP_negz->Project3D("yx"); - - int interpolateSuccess = InterpolatePhiDistortions(simPhiDistortion); + int interpolateSuccess = InterpolatePhiDistortions(); if (interpolateSuccess != Fun4AllReturnCodes::EVENT_OK) { std::cout << PHWHERE << " Return code for lamination interpolation was " << interpolateSuccess << " and not successful" << std::endl; return Fun4AllReturnCodes::ABORTRUN; } - - for (int s = 0; s < 2; s++) - { + + /* + for (int s = 0; s < 2; s++) + { scaleFactorMap[s] = (TH2 *) m_dcc_out->m_hDPint[s]->Clone(); scaleFactorMap[s]->SetName(std::format("scaleFactorMap{}", s).c_str()); scaleFactorMap[s]->Divide(simPhiDistortion[s]); - } - - TH3 *hIntDistortionR_posz = (TH3 *) simDistortion->Get("hIntDistortionR_posz"); - hIntDistortionR_posz->GetZaxis()->SetRange(2, 2); - TH2 *simRDistortion[2]; - simRDistortion[1] = (TH2 *) hIntDistortionR_posz->Project3D("yx"); - TH3 *hIntDistortionR_negz = (TH3 *) simDistortion->Get("hIntDistortionR_negz"); - hIntDistortionR_negz->GetZaxis()->SetRange(hIntDistortionR_negz->GetNbinsZ() - 1, hIntDistortionR_negz->GetNbinsZ() - 1); - simRDistortion[0] = (TH2 *) hIntDistortionR_negz->Project3D("yx"); - + } + + TH3 *hIntDistortionR_posz = (TH3 *) simDistortion->Get("hIntDistortionR_posz"); + hIntDistortionR_posz->GetZaxis()->SetRange(2, 2); + TH2 *simRDistortion[2]; + simRDistortion[1] = (TH2 *) hIntDistortionR_posz->Project3D("yx"); + TH3 *hIntDistortionR_negz = (TH3 *) simDistortion->Get("hIntDistortionR_negz"); + hIntDistortionR_negz->GetZaxis()->SetRange(hIntDistortionR_negz->GetNbinsZ() - 1, hIntDistortionR_negz->GetNbinsZ() - 1); + simRDistortion[0] = (TH2 *) hIntDistortionR_negz->Project3D("yx"); + */ + + + for (int s = 0; s < 2; s++) { - /* - for(int i=1; i<=m_dcc_out->m_hDRint[s]->GetNbinsX(); i++) + int RMatchingSuccess = doGlobalRMatching(s); + if (RMatchingSuccess != Fun4AllReturnCodes::EVENT_OK) { - for(int j=1; j<=m_dcc_out->m_hDRint[s]->GetNbinsY(); j++) - { - if(simRDistortion[s]->GetBinContent(i,j) != 0.0) - { - m_dcc_out->m_hDRint[s]->SetBinContent(i,j, simRDistortion[s]->GetBinContent(i,j)); - } - } + std::cout << PHWHERE << " Return code for doGlobalRMatching was " << RMatchingSuccess << " and not successful" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; } + /* + for(int i=1; i<=m_dcc_out->m_hDRint[s]->GetNbinsX(); i++) + { + for(int j=1; j<=m_dcc_out->m_hDRint[s]->GetNbinsY(); j++) + { + if(simRDistortion[s]->GetBinContent(i,j) != 0.0) + { + m_dcc_out->m_hDRint[s]->SetBinContent(i,j, simRDistortion[s]->GetBinContent(i,j)); + } + } + } */ - m_dcc_out->m_hDRint[s] = (TH2 *) simRDistortion[s]->Clone(); - m_dcc_out->m_hDRint[s]->SetName(std::format("hIntDistortionR{}", (s == 0 ? "_negz" : "_posz")).c_str()); - m_dcc_out->m_hDRint[s]->Multiply(scaleFactorMap[s]); + //m_dcc_out->m_hDRint[s] = (TH2 *) simRDistortion[s]->Clone(); + //m_dcc_out->m_hDRint[s]->SetName(std::format("hIntDistortionR{}", (s == 0 ? "_negz" : "_posz")).c_str()); + //m_dcc_out->m_hDRint[s]->Multiply(scaleFactorMap[s]); } - - + + + fill_guarding_bins(m_dcc_out); - - + + for(int s=0; s<2; s++) { for(int l=0; l<18; l++) { m_side = s; m_lamIndex = s*18 + l; - m_lamPhi = m_laminationCenter[l][s]; + m_lamPhi = m_laminationIdeal[l][s]; + m_lamShift = m_laminationOffset[l][s]; m_goodFit = m_laminationGoodFit[l][s]; - m_A = m_fLamination[l][s]->GetParameter(0); - m_B = m_fLamination[l][s]->GetParameter(1); - m_C = m_fLamination[l][s]->GetParameter(2); - m_A_err = m_fLamination[l][s]->GetParError(0); - m_B_err = m_fLamination[l][s]->GetParError(1); - m_C_err = m_fLamination[l][s]->GetParError(2); + if(m_fieldOff) + { + m_A = m_fLamination[l][s]->GetParameter(0); + m_A_err = m_fLamination[l][s]->GetParError(0); + m_B = -999; + m_B_err = -999; + m_C = -999; + m_C_err = -999; + } + else + { + m_A = m_fLamination[l][s]->GetParameter(0); + m_B = m_fLamination[l][s]->GetParameter(1); + m_C = m_fLamination[l][s]->GetParameter(2); + m_A_err = m_fLamination[l][s]->GetParError(0); + m_B_err = m_fLamination[l][s]->GetParError(1); + m_C_err = m_fLamination[l][s]->GetParError(2); + } m_dist = m_distanceToFit[l][s]; m_nBins = m_nBinsFit[l][s]; + m_rmse = m_fitRMSE[l][s]; m_laminationTree->Fill(); } } - + TFile *outputfile = new TFile(m_outputfile.c_str(), "RECREATE"); outputfile->cd(); for (int s = 0; s < 2; s++) { + clusterMap[s]->Write(); for (const auto &h : {m_dcc_out->m_hDRint[s], m_dcc_out->m_hDPint[s], m_dcc_out->m_hDZint[s], m_dcc_out->m_hentries[s]}) { if (h) @@ -832,17 +1213,43 @@ int TpcLaminationFitting::End(PHCompositeNode * /*topNode*/) } } phiDistortionLamination[s]->Write(); - scaleFactorMap[s]->Write(); + //scaleFactorMap[s]->Write(); + m_hPetal[s]->Write(); + if(m_bestRMatch[s]) + { + m_bestRMatch[s]->Write(); + } + m_parameterScan[s]->Write(); } m_laminationTree->Write(); - - m_hLamination[13][0]->Write(); - m_hLamination[13][1]->Write(); - m_hLamination[14][1]->Write(); - + m_A_zdc.Write("A_zdc"); + m_B_zdc.Write("B_zdc"); + m_C_zdc.Write("C_zdc"); + /* for(int s=0; s<2; s++) { + m_A_zdc[s]->Write(std::format("A_zdc_{}",s).c_str()); + m_B_zdc[s]->Write(std::format("B_zdc_{}",s).c_str()); + m_C_zdc[s]->Write(std::format("C_zdc_{}",s).c_str()); + }*/ + if(m_saveAllLaminationHistograms) + { + for(auto &i : m_hLamination) + { + for(auto &j : i) + { + j->Write(); + } + } + } + else + { + m_hLamination[13][0]->Write(); + m_hLamination[13][1]->Write(); + m_hLamination[14][1]->Write(); + } + outputfile->Close(); - + return Fun4AllReturnCodes::EVENT_OK; } @@ -851,7 +1258,7 @@ void TpcLaminationFitting::fill_guarding_bins(TpcDistortionCorrectionContainer * { for (int s = 0; s < 2; s++) { - for (const auto &h : {dcc->m_hDRint[s], dcc->m_hDPint[s]}) + for (const auto &h : {dcc->m_hDPint[s], dcc->m_hDRint[s]}) { const auto phibins = h->GetNbinsX(); const auto rbins = h->GetNbinsY(); diff --git a/offline/packages/tpccalib/TpcLaminationFitting.h b/offline/packages/tpccalib/TpcLaminationFitting.h index 73d77533d3..0a68a10afa 100644 --- a/offline/packages/tpccalib/TpcLaminationFitting.h +++ b/offline/packages/tpccalib/TpcLaminationFitting.h @@ -1,14 +1,20 @@ #ifndef TPCCALIB_TPCLAMINATIONFITTING_H #define TPCCALIB_TPCLAMINATIONFITTING_H + +//#include +//#include + +#include #include #include +//#include #include #include #include - +#include class PHCompositeNode; class LaserClusterContainer; @@ -43,12 +49,31 @@ class TpcLaminationFitting : public SubsysReco m_QAFileName = QAFileName; } + void set_stripePatternFile(const std::string &stripePatternFile) + { + m_stripePatternFile = stripePatternFile; + } + void set_ppMode(bool mode){ ppMode = mode; } - + + void set_phiHistInRad(bool rad){ m_phiHist_in_rad = rad; } + + void set_saveAllLaminationHistograms(bool save){ m_saveAllLaminationHistograms = save; } + + void set_fieldOff(bool fieldOff){ m_fieldOff = fieldOff; } + void set_grid_dimensions(int phibins, int rbins); void set_nLayerCut(unsigned int cut) { m_nLayerCut = cut; } + void set_useSDLayerCut(bool useCut) { m_useSDLayerCut = useCut; } + + void set_adcWeight(bool useADC) { m_adcWeight = useADC; } + + void set_lam_grid_dimensions(int phibins, int rbins); + + void set_useZ(bool use) { m_useZ = use; } + int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; @@ -61,7 +86,8 @@ class TpcLaminationFitting : public SubsysReco int GetNodes(PHCompositeNode *topNode); int fitLaminations(); - int InterpolatePhiDistortions(TH2 *simPhiDistortion[2]); + int InterpolatePhiDistortions(); + int doGlobalRMatching(int side); void fill_guarding_bins(TpcDistortionCorrectionContainer *dcc); TpcDistortionCorrection m_distortionCorrection; @@ -78,16 +104,30 @@ class TpcLaminationFitting : public SubsysReco TH2 *m_hLamination[18][2]{{nullptr}}; TF1 *m_fLamination[18][2]{{nullptr}}; - double m_laminationCenter[18][2]{{0.0}}; + double m_laminationIdeal[18][2]{{0.0}}; + //double m_laminationCenter[18][2]{{0.0}}; double m_laminationOffset[18][2]{{0.0}}; + //double m_laminationOffset{0.00337078}; + //double m_laminationOffset{0.002775}; bool m_laminationGoodFit[18][2]{{false}}; double m_distanceToFit[18][2]{{0.0}}; int m_nBinsFit[18][2]{{0}}; + double m_fitRMSE[18][2]{{0.0}}; + + + TH2 *m_hPetal[2]{nullptr}; + TGraph *m_bestRMatch[2]{nullptr}; + TH2 *m_parameterScan[2]{nullptr}; + TH2 *phiDistortionLamination[2]{nullptr}; - TH2 *scaleFactorMap[2]{nullptr}; + //TH2 *scaleFactorMap[2]{nullptr}; + + TH2 *clusterMap[2]{nullptr}; unsigned int m_nLayerCut{1}; + bool m_useSDLayerCut{true}; + bool m_adcWeight{false}; bool m_useHeader{true}; @@ -102,11 +142,19 @@ class TpcLaminationFitting : public SubsysReco double m_ZDC_coincidence{0}; //std::map m_run_ZDC_map_pp; //std::map m_run_ZDC_map_auau; - + + bool m_phiHist_in_rad{true}; + bool m_saveAllLaminationHistograms{false}; + + std::string m_stripePatternFile = "/sphenix/u/bkimelman/CMStripePattern.root"; + + bool m_fieldOff{false}; + TTree *m_laminationTree{nullptr}; bool m_side{false}; int m_lamIndex{0}; double m_lamPhi{0}; + double m_lamShift{0}; bool m_goodFit{false}; double m_A{0}; double m_B{0}; @@ -115,15 +163,48 @@ class TpcLaminationFitting : public SubsysReco double m_B_err{0}; double m_C_err{0}; double m_dist{0}; + double m_rmse{}; int m_nBins{0}; - int m_phibins{24}; + TVectorD m_A_zdc{2}; + TVectorD m_B_zdc{2}; + TVectorD m_C_zdc{2}; + + int m_lamPhiBins{200}; + int m_lamRBins{200}; + + int m_phibins{80}; static constexpr float m_phiMin{0}; static constexpr float m_phiMax{2. * M_PI}; - int m_rbins{12}; + int m_rbins{52}; static constexpr float m_rMin{20}; // cm static constexpr float m_rMax{80}; // cm + + /* + const int nRadii{8}; + const int nStripes[4]{6,6,8,12}; + const int nPads[4]{96,96,128,192}; + const double RValues[4][8] = {{22.70902789, 23.84100043, 24.97297296, 26.1049455, 27.23691804, 28.36889058, 29.50086312, 30.63283566},{31.7648082, 32.89678074, 34.02875328, 35.16072582, 36.29269836, 37.4246709, 38.55664344, 39.68861597},{42.1705532, 44.2119258, 46.2532984, 48.29467608, 50.336069, 52.3774416, 54.4188015, 56.4601868},{59.46048725, 61.6545823, 63.84867738, 66.04277246, 68.23686754, 70.43096262, 72.6250577, 74.81915277}}; + + const int keepThisAndAfter[8]{1,0,1,0,1,0,1,0}; + const int keepUntil[4][8]{{4,4,5,4,5,5,5,5},{5,5,6,5,6,5,6,5},{7,7,8,7,8,8,8,8},{11,10,11,11,11,11,12,11}}; + + const double phi_petal = M_PI/6.0; + const int pr_mult = 3; + const int dw_mult = 8; + const double diffwidth = 0.06; + const double adjust = 0.015; + */ + + std::vector m_truthR[2]{}; + std::vector m_truthPhi[2]{}; + + double m_phiModMin[2]{-M_PI/18, 0.0}; + double m_phiModMax[2]{M_PI/18, M_PI/9}; + + LaserClusterHelper m_laserClusterHelper; + bool m_useZ{false}; }; #endif diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainer.h b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainer.h index 701bc147d0..767e0f5135 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainer.h +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainer.h @@ -45,6 +45,10 @@ class TpcSpaceChargeMatrixContainer : public PHObject virtual int get_cell_index( int /*iphibin*/, int /*irbin*/, int /*izbin*/ ) const { return -1; } + /// get all entries + virtual int get_entries() const + { return 0; } + /// get entries for a given cell virtual int get_entries( int /*cell_index*/ ) const { return 0; } diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc index 3fa25bbbf3..e13c9baffd 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.cc @@ -8,6 +8,8 @@ #include "TpcSpaceChargeMatrixContainerv2.h" +#include + //___________________________________________________________ TpcSpaceChargeMatrixContainerv2::TpcSpaceChargeMatrixContainerv2() { @@ -56,6 +58,10 @@ int TpcSpaceChargeMatrixContainerv2::get_cell_index(int iphi, int ir, int iz) co return iz + m_zbins * (ir + m_rbins * iphi); } +//___________________________________________________________ +int TpcSpaceChargeMatrixContainerv2::get_entries() const +{ return std::accumulate( m_entries.begin(), m_entries.end(), 0); } + //___________________________________________________________ int TpcSpaceChargeMatrixContainerv2::get_entries(int cell_index) const { diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.h b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.h index 8005e4f1f3..5942a8c126 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.h +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixContainerv2.h @@ -39,6 +39,9 @@ class TpcSpaceChargeMatrixContainerv2 : public TpcSpaceChargeMatrixContainer /// get grid index for given sub-indexes int get_cell_index(int iphibin, int irbin, int izbin) const override; + /// get all entries + int get_entries() const override; + /// get entries for a given cell int get_entries(int cell_index) const override; diff --git a/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc b/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc index 07f08c733c..5fa957ab3e 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeMatrixInversion.cc @@ -165,6 +165,14 @@ bool TpcSpaceChargeMatrixInversion::add_from_file(const std::string& shortfilena return false; } + if( Verbosity() ) { + std::cout << "TpcSpaceChargeMatrixInversion::add_from_file -" + << " file: " << filename + << " objectname: " << objectname + << " entries: " << source->get_entries() + << std::endl; + } + // add object return add(*source); } @@ -200,6 +208,8 @@ void TpcSpaceChargeMatrixInversion::calculate_distortion_corrections(const Inver exit(1); } + std::cout << "TpcSpaceChargeMatrixInversion::calculate_distortion_corrections - entries: " << m_matrix_container->get_entries() << std::endl; + // get grid dimensions from matrix container int phibins = 0; int rbins = 0; @@ -457,22 +467,6 @@ void TpcSpaceChargeMatrixInversion::save_distortion_corrections(const std::strin return; } - // save everything to root file - std::cout << "TpcSpaceChargeMatrixInversion::save_distortions - writing histograms to " << filename << std::endl; - std::unique_ptr outputfile(TFile::Open(filename.c_str(), "RECREATE")); - outputfile->cd(); - - for (const auto& h_list : {m_dcc_average->m_hentries, m_dcc_average->m_hDRint, m_dcc_average->m_hDPint, m_dcc_average->m_hDZint}) - { - for (const auto& h : h_list) - { - if (h) - { - h->Write(h->GetName()); - } - } - } + m_dcc_average->save_histograms(filename); - // close TFile - outputfile->Close(); } diff --git a/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc b/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc index ffbefedc6b..d6e605ceb4 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc +++ b/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.cc @@ -602,53 +602,70 @@ TH3* TpcSpaceChargeReconstructionHelper::add_guarding_bins(const TH3* source, co } } + // fill guarding phi bins + fill_guarding_bins( hout ); + + return hout; +} + +//_____________________________________________________________________________________________________________________- +void TpcSpaceChargeReconstructionHelper::fill_guarding_bins(TH3* source ) +{ + if (!source) + { + std::cout << "TpcSpaceChargeReconstructionHelper::fill_guarding_bins - invalid source histogram" << std::endl; + return; + } + + const auto nbinsx = source->GetNbinsX(); + const auto nbinsy = source->GetNbinsY(); + const auto nbinsz = source->GetNbinsZ(); + // fill guarding phi bins /* * we use 2pi periodicity to do that: * - last valid bin is copied to first guarding bin; * - first valid bin is copied to last guarding bin */ - for (int ir = 0; ir < rbins + 2; ++ir) + for (int ir = 0; ir < nbinsy; ++ir) { - for (int iz = 0; iz < zbins + 2; ++iz) + for (int iz = 0; iz < nbinsz; ++iz) { // copy last bin to first guarding bin - hout->SetBinContent(1, ir + 1, iz + 1, hout->GetBinContent(phibins + 1, ir + 1, iz + 1)); - hout->SetBinError(1, ir + 1, iz + 1, hout->GetBinError(phibins + 1, ir + 1, iz + 1)); + source ->SetBinContent(1, ir + 1, iz + 1, source ->GetBinContent(nbinsx-1, ir + 1, iz + 1)); + source ->SetBinError(1, ir + 1, iz + 1, source ->GetBinError(nbinsx-1, ir + 1, iz + 1)); // copy first bin to last guarding bin - hout->SetBinContent(phibins + 2, ir + 1, iz + 1, hout->GetBinContent(2, ir + 1, iz + 1)); - hout->SetBinError(phibins + 2, ir + 1, iz + 1, hout->GetBinError(2, ir + 1, iz + 1)); + source ->SetBinContent(nbinsx, ir + 1, iz + 1, source ->GetBinContent(2, ir + 1, iz + 1)); + source ->SetBinError(nbinsx, ir + 1, iz + 1, source ->GetBinError(2, ir + 1, iz + 1)); } } // fill guarding r bins - for (int iphi = 0; iphi < phibins + 2; ++iphi) + for (int iphi = 0; iphi < nbinsx; ++iphi) { - for (int iz = 0; iz < zbins + 2; ++iz) + for (int iz = 0; iz < nbinsz; ++iz) { - hout->SetBinContent(iphi + 1, 1, iz + 1, hout->GetBinContent(iphi + 1, 2, iz + 1)); - hout->SetBinError(iphi + 1, 1, iz + 1, hout->GetBinError(iphi + 1, 2, iz + 1)); + source ->SetBinContent(iphi + 1, 1, iz + 1, source ->GetBinContent(iphi + 1, 2, iz + 1)); + source ->SetBinError(iphi + 1, 1, iz + 1, source ->GetBinError(iphi + 1, 2, iz + 1)); - hout->SetBinContent(iphi + 1, rbins + 2, iz + 1, hout->GetBinContent(iphi + 1, rbins + 1, iz + 1)); - hout->SetBinError(iphi + 1, rbins + 2, iz + 1, hout->GetBinError(iphi + 1, rbins + 1, iz + 1)); + source ->SetBinContent(iphi + 1, nbinsy, iz + 1, source ->GetBinContent(iphi + 1, nbinsy-1, iz + 1)); + source ->SetBinError(iphi + 1, nbinsy, iz + 1, source ->GetBinError(iphi + 1, nbinsy-1, iz + 1)); } } // fill guarding z bins - for (int iphi = 0; iphi < phibins + 2; ++iphi) + for (int iphi = 0; iphi < nbinsx; ++iphi) { - for (int ir = 0; ir < rbins + 2; ++ir) + for (int ir = 0; ir < nbinsy; ++ir) { - hout->SetBinContent(iphi + 1, ir + 1, 1, hout->GetBinContent(iphi + 1, ir + 1, 2)); - hout->SetBinError(iphi + 1, ir + 1, 1, hout->GetBinError(iphi + 1, ir + 1, 2)); + source ->SetBinContent(iphi + 1, ir + 1, 1, source ->GetBinContent(iphi + 1, ir + 1, 2)); + source ->SetBinError(iphi + 1, ir + 1, 1, source ->GetBinError(iphi + 1, ir + 1, 2)); - hout->SetBinContent(iphi + 1, ir + 1, zbins + 2, hout->GetBinContent(iphi + 1, ir + 1, zbins + 1)); - hout->SetBinError(iphi + 1, ir + 1, zbins + 2, hout->GetBinError(iphi + 1, ir + 1, zbins + 1)); + source ->SetBinContent(iphi + 1, ir + 1, nbinsz, source ->GetBinContent(iphi + 1, ir + 1, nbinsz-1)); + source ->SetBinError(iphi + 1, ir + 1, nbinsz, source ->GetBinError(iphi + 1, ir + 1, nbinsz-1)); } } - - return hout; } //___________________________________________________________________________________________________ diff --git a/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.h b/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.h index 12e9e4823c..065bf3ad15 100644 --- a/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.h +++ b/offline/packages/tpccalib/TpcSpaceChargeReconstructionHelper.h @@ -71,12 +71,17 @@ class TpcSpaceChargeReconstructionHelper /** * copy input histogram into output, with new name, while adding two "guarding bins" on - * each axis, with identical content and error as the first and last bin of the original histogram - * this is necessary for being able to call TH3->Interpolate() when using these histograms - * to correct for the space charge distortions. + * each axis. Uses fill_guarding_bins to set guarding bin content */ static TH3* add_guarding_bins(const TH3* /*source*/, const TString& /*name*/); + /** + * fill first and last bins (along all axis) of provided histogram with + * either copy of the previous/next (physical) bin, (for r and z) + * or using 2pi invariance for the phi axis. + */ + static void fill_guarding_bins(TH3* /*source*/); + /// shortcut to angular window, needed to define TPOT acceptance using range_t = std::pair; diff --git a/offline/packages/trackbase/ActsAborter.h b/offline/packages/trackbase/ActsAborter.h deleted file mode 100644 index b87aaa25c7..0000000000 --- a/offline/packages/trackbase/ActsAborter.h +++ /dev/null @@ -1,46 +0,0 @@ - -#ifndef TRACKBASE_ACTSABORTER_H -#define TRACKBASE_ACTSABORTER_H - -#include -#include -#include - -struct ActsAborter -{ - unsigned int abortlayer = std::numeric_limits::max(); - unsigned int abortvolume = std::numeric_limits::max(); - - template - bool operator()(propagator_state_t& state, const stepper_t& /*stepper*/, - const navigator_t& navigator, const Acts::Logger& /*logger*/) const - { - if (navigator.targetReached(state.navigation)) - { - return true; - } - - // if (!state.navigation.currentSurface) - if (!navigator.currentSurface(state.navigation)) - { - return false; - } - - auto volumeno = state.navigation.currentSurface->geometryId().volume(); - auto layerno = state.navigation.currentSurface->geometryId().layer(); - auto sensitive = state.navigation.currentSurface->geometryId().sensitive(); - - /// Check that we are in the proper layer and that we've also reached - /// a sensitive surface - if (layerno == abortlayer and volumeno == abortvolume and sensitive != 0) - { - navigator.targetReached(state.navigation, true); - return true; - } - - return false; - } -}; - -#endif diff --git a/offline/packages/trackbase/ActsGeometry.cc b/offline/packages/trackbase/ActsGeometry.cc index 7965193149..c6b320142b 100644 --- a/offline/packages/trackbase/ActsGeometry.cc +++ b/offline/packages/trackbase/ActsGeometry.cc @@ -1,15 +1,21 @@ #include "ActsGeometry.h" -#include #include "TpcDefs.h" #include "TrkrCluster.h" #include "alignmentTransformationContainer.h" + #include +#include + +#include +#include +#include + namespace { /// square template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } @@ -147,9 +153,16 @@ Surface ActsGeometry::get_tpc_surface_from_coords( Acts::Vector3 world, TrkrDefs::subsurfkey& subsurfkey) const { + // Assume that the world coordinates are in the sPHENIX frame, where the TPC is tilted + // We convert the position to tpc envelope coordinates, where we know where everything is + Acts::Vector3 world_envelope = transformTpcWorldToEnvelope(world); + double world_phi = atan2(world_envelope[1], world_envelope[0]); + unsigned int layer = TrkrDefs::getLayer(hitsetkey); unsigned int side = TpcDefs::getSide(hitsetkey); - + unsigned int sector = TpcDefs::getSectorId(hitsetkey); + + // returns an iterator to all of the surfaces for this layer auto mapIter = m_surfMaps.m_tpcSurfaceMap.find(layer); if (mapIter == m_surfMaps.m_tpcSurfaceMap.end()) @@ -158,11 +171,46 @@ Surface ActsGeometry::get_tpc_surface_from_coords( << hitsetkey << std::endl; return nullptr; } - double world_phi = atan2(world[1], world[0]); const auto& surf_vec = mapIter->second; unsigned int surf_index = 999; + // Apparently, tilting the TPC leads to the surfaces not being sorted in phi in the outer layers + // just test all surfaces in each layer for now + for(unsigned int isurf = 0; isurf < surf_vec.size(); ++isurf) + { + Surface this_surf = surf_vec[isurf]; + auto surf_center = this_surf->center(m_tGeometry.getGeoContext()); + surf_center /= 10.0; // convert from mm to cm + //this surface center includes the TPC tilt used in PHG4TpcDetector construction, transform it to tpc envelope coordinates + Acts::Vector3 surf_center_envelope = transformTpcWorldToEnvelope(surf_center); + double surf_phi = atan2(surf_center_envelope[1], surf_center_envelope[0]); + double surfStepPhi = m_tGeometry.tpcSurfStepPhi; + + const double dphi = std::atan2(std::sin(world_phi - surf_phi), std::cos(world_phi - surf_phi)); + if (std::abs(dphi) <= surfStepPhi / 2.0) + { + if(surf_center_envelope.z() < 0 && side != 0) { continue; } + if(surf_center_envelope.z() > 0 && side != 1) { continue; } + surf_index = isurf; + subsurfkey = isurf; + break; + } + } + + if(surf_index == 999) + { + std::cout << "Error: surface not found in ActsGeometry::get_tpc_surface_from_coords " + << " layer " << layer << " side " << side << " sector " << sector + << " world_phi (deg) " << world_phi* 180.0/M_PI + << " world[0] " << world[0] << " world[1] " << world[1] + << " hitsetkey " << hitsetkey << std::endl; + return nullptr; + } + + return surf_vec[surf_index]; + + /* // Predict which surface index this phi and side will correspond to // assumes that the vector elements are ordered positive z, -pi to pi, then negative z, -pi to pi // we use TPC side from the hitsetkey, since z can be either sign in north and south, depending on crossing @@ -170,33 +218,38 @@ Surface ActsGeometry::get_tpc_surface_from_coords( double rounded_nsurf = std::round((double) (surf_vec.size() / 2) * fraction - 0.5); // NOLINT unsigned int nsurfm = (unsigned int) rounded_nsurf; - + std::cout << " surf_vec.size " << surf_vec.size() << " rounded_nsurf " << rounded_nsurf << " initial nsurfm " << nsurfm << std::endl; + if (side == 0) { nsurfm += surf_vec.size() / 2; } unsigned int nsurf = nsurfm % surf_vec.size(); Surface this_surf = surf_vec[nsurf]; - //std::cout << " world_phi " << world_phi << " fraction " << fraction << " rounded_nsurf " << rounded_nsurf << " nsurfm " << nsurfm << " nsurf " << nsurf << std::endl; - - auto vec3d = this_surf->center(m_tGeometry.getGeoContext()); - std::vector surf_center = {vec3d(0) / 10.0, vec3d(1) / 10.0, vec3d(2) / 10.0}; // convert from mm to cm - double surf_phi = atan2(surf_center[1], surf_center[0]); + auto surf_center = this_surf->center(m_tGeometry.getGeoContext()); + surf_center /= 10.0; // convert from mm to cm + //this surface center is from the default geometry, which includes the TPC tilt used in PHG4TpcDetector construction + // transform it to tpc envelope coordinates + Acts::Vector3 surf_center_envelope = m_tpc_world_envelope_transform * surf_center; + + double surf_phi = atan2(surf_center_envelope[1], surf_center_envelope[0]); double surfStepPhi = m_tGeometry.tpcSurfStepPhi; - // std::cout << " surf_phi " << surf_phi << " surfStepPhi " << surfStepPhi << " nsurf " << nsurf << std::endl; - if ((world_phi > surf_phi - surfStepPhi / 2.0 && world_phi < surf_phi + surfStepPhi / 2.0)) + if ((world_phi > surf_phi - surfStepPhi / 2.0) && (world_phi < surf_phi + surfStepPhi / 2.0)) { surf_index = nsurf; subsurfkey = nsurf; + std::cout << "success, found nsurf = " << nsurf << std::endl; } else { // check for the periodic boundary condition auto firstsurf = *surf_vec.begin(); - auto firstsurfcenter = firstsurf->center(geometry().getGeoContext()); - float firstsurf_phi = atan2(firstsurfcenter[1], firstsurfcenter[0]); - if (world_phi < firstsurf_phi - surfStepPhi / 2.0) + auto firstsurfcenter = firstsurf->center(m_tGeometry.getGeoContext()); + firstsurfcenter /= 10.0; + auto firstsurfcenter_envelope = m_tpc_world_envelope_transform * firstsurfcenter; + double firstsurf_phi = atan2(firstsurfcenter_envelope[1], firstsurfcenter_envelope[0]); + if (world_phi < -M_PI) { world_phi += 2.0 * M_PI; } @@ -209,12 +262,16 @@ Surface ActsGeometry::get_tpc_surface_from_coords( } unsigned int new_nsurf = (nsurf+i) % surf_vec.size(); this_surf = surf_vec[new_nsurf]; - vec3d = this_surf->center(geometry().getGeoContext()); - surf_center = {vec3d(0) / 10.0, vec3d(1) / 10.0, vec3d(2) / 10.0}; // convert from mm to cm - surf_phi = atan2(surf_center[1], surf_center[0]); - //std::cout << " new world_phi " << world_phi << " new surf_phi " << surf_phi << " new_nsurf " << new_nsurf << std::endl; - if ((world_phi > surf_phi - surfStepPhi / 2.0 && world_phi < surf_phi + surfStepPhi / 2.0)) + surf_center = this_surf->center(m_tGeometry.getGeoContext()); + surf_center /= 10.0; + surf_center_envelope = m_tpc_world_envelope_transform * surf_center; + surf_phi = atan2(surf_center_envelope[1], surf_center_envelope[0]); + double this_philow = surf_phi - surfStepPhi / 2.0; + double this_phihigh = surf_phi + surfStepPhi / 2.0; + + if ((world_phi > this_philow) && (world_phi < this_phihigh)) { + std::cout << "success, found nsurf = " << new_nsurf << std::endl; surf_index = new_nsurf; subsurfkey = new_nsurf; return surf_vec[surf_index]; @@ -222,8 +279,9 @@ Surface ActsGeometry::get_tpc_surface_from_coords( } return nullptr; } + */ + - return surf_vec[surf_index]; } //________________________________________________________________________________________________ @@ -289,3 +347,17 @@ Acts::Vector2 ActsGeometry::getLocalCoords(TrkrDefs::cluskey key, TrkrCluster* c return local; } + + Acts::Vector3 ActsGeometry::transformTpcWorldToEnvelope(const Acts::Vector3& world) const + { + Acts::Vector3 envelope = m_tpc_world_envelope_transform * world; + + return envelope; + } + + Acts::Vector3 ActsGeometry::transformTpcEnvelopeToWorld(const Acts::Vector3& envelope) const + { + Acts::Vector3 world = m_tpc_world_envelope_transform.inverse() * envelope; + + return world; + } diff --git a/offline/packages/trackbase/ActsGeometry.h b/offline/packages/trackbase/ActsGeometry.h index 957a1a8e62..be9b4e01cd 100644 --- a/offline/packages/trackbase/ActsGeometry.h +++ b/offline/packages/trackbase/ActsGeometry.h @@ -10,7 +10,6 @@ class TrkrCluster; class ActsGeometry { public: - ActsGeometry() = default; ~ActsGeometry() = default; void setGeometry(const ActsTrackingGeometry& tGeometry) @@ -52,6 +51,7 @@ class ActsGeometry void set_CM_halfwidth(double val) { _CM_halfwidth = val; } void set_tpc_tzero(double tz) { _tpc_tzero = tz; } void set_sampa_tzero_bias(double tzb) { _sampa_tzero_bias = tzb; } + void set_tpc_world_envelope_transform(Acts::Transform3 transf) { m_tpc_world_envelope_transform = transf; } double get_tpc_tzero() const { return _tpc_tzero; } double get_sampa_tzero_bias() const { return _sampa_tzero_bias; } @@ -78,12 +78,17 @@ class ActsGeometry Acts::Transform3 makeAffineTransform(Acts::Vector3 rotation, Acts::Vector3 translation) const; + Acts::Vector3 transformTpcWorldToEnvelope(const Acts::Vector3& world) const ; + Acts::Vector3 transformTpcEnvelopeToWorld(const Acts::Vector3& envelope) const ; + Acts::Vector2 getLocalCoords(TrkrDefs::cluskey key, TrkrCluster* cluster) const; Acts::Vector2 getLocalCoords(TrkrDefs::cluskey key, TrkrCluster* cluster, short int crossing) const; private: ActsTrackingGeometry m_tGeometry; ActsSurfaceMaps m_surfMaps; + Acts::Transform3 m_tpc_world_envelope_transform; + Acts::Transform3 m_tpc_envelope_world_transform; double _drift_velocity = 8.0e-3; // cm/ns double _max_driftlength = 102.235; // cm double _CM_halfwidth = 0.28; // cm diff --git a/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h b/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h index fd144c1163..d0de5fadbd 100644 --- a/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h +++ b/offline/packages/trackbase/ActsGsfTrackFittingAlgorithm.h @@ -62,7 +62,7 @@ namespace MixtureReductionAlgorithm::KLDistance; Acts::ComponentMergeMethod mergeMethod = Acts::ComponentMergeMethod::eMaxWeight; - + double reverseFilteringCovarianceScaling = 100.; ActsSourceLink::SurfaceAccessor m_slSurfaceAccessor; GsfFitterFunctionImpl(Fitter&& f, @@ -83,17 +83,18 @@ namespace extensions.updater.connect<&Acts::GainMatrixUpdater::operator()>(&updater); Acts::GsfOptions gsfOptions{ - options.geoContext, - options.magFieldContext, - options.calibrationContext, - extensions, - options.propOptions, - &(*options.referenceSurface), - maxComponents, - weightCutoff, - abortOnError, - disableAllMaterialHandling}; + options.geoContext, options.magFieldContext, + options.calibrationContext}; + gsfOptions.extensions = extensions; + gsfOptions.propagatorPlainOptions = options.propOptions; + gsfOptions.referenceSurface = options.referenceSurface; + gsfOptions.maxComponents = maxComponents; + gsfOptions.weightCutoff = weightCutoff; + gsfOptions.abortOnError = abortOnError; + gsfOptions.disableAllMaterialHandling = disableAllMaterialHandling; gsfOptions.componentMergeMethod = mergeMethod; + gsfOptions.reverseFilteringCovarianceScaling = + reverseFilteringCovarianceScaling; gsfOptions.extensions.calibrator.connect<&calibrator_t::calibrate>( &calibrator); gsfOptions.extensions.surfaceAccessor.connect<&ActsSourceLink::SurfaceAccessor::operator()>(&m_slSurfaceAccessor); @@ -152,5 +153,6 @@ class ActsGsfTrackFittingAlgorithm BetheHeitlerApprox betheHeitlerApprox, std::size_t maxComponents, double weightCutoff, MixtureReductionAlgorithm finalReductionMethod, bool abortOnError, - bool disableAllMaterialHandling, const Acts::Logger& logger = *Acts::getDefaultLogger("GSF", Acts::Logging::FATAL)); + bool disableAllMaterialHandling, double reverseFilteringCovarianceScaling, + const Acts::Logger& logger = *Acts::getDefaultLogger("GSF", Acts::Logging::FATAL)); }; diff --git a/offline/packages/trackbase/ActsSurfaceMaps.cc b/offline/packages/trackbase/ActsSurfaceMaps.cc index d92e387ca0..69cd94ece6 100644 --- a/offline/packages/trackbase/ActsSurfaceMaps.cc +++ b/offline/packages/trackbase/ActsSurfaceMaps.cc @@ -34,6 +34,11 @@ bool ActsSurfaceMaps::isTpcSurface(const Acts::Surface* surface) const return m_tpcVolumeIds.find(surface->geometryId().volume()) != m_tpcVolumeIds.end(); } +bool ActsSurfaceMaps::isSiSurface(const Acts::Surface* surface) const +{ + return m_siVolumeIds.find(surface->geometryId().volume()) != m_siVolumeIds.end(); +} + bool ActsSurfaceMaps::isMicromegasSurface(const Acts::Surface* surface) const { return m_micromegasVolumeIds.find(surface->geometryId().volume()) != m_micromegasVolumeIds.end(); diff --git a/offline/packages/trackbase/ActsSurfaceMaps.h b/offline/packages/trackbase/ActsSurfaceMaps.h index 94c327be79..e90263c49a 100644 --- a/offline/packages/trackbase/ActsSurfaceMaps.h +++ b/offline/packages/trackbase/ActsSurfaceMaps.h @@ -37,6 +37,9 @@ struct ActsSurfaceMaps //! true if given surface corresponds to TPC bool isTpcSurface(const Acts::Surface* surface) const; + //! true if given surface corresponds to the silicon + bool isSiSurface(const Acts::Surface* surface) const; + //! true if given surface corresponds to Micromegas bool isMicromegasSurface(const Acts::Surface* surface) const; @@ -65,6 +68,10 @@ struct ActsSurfaceMaps /** it is used to quickly tell if a given Acts Surface belongs to the TPC */ std::set m_tpcVolumeIds; + //! stores all acts volume ids relevant to the Silicon + /** it is used to quickly tell if a given Acts Surface belongs to the Silicon */ + std::set m_siVolumeIds; + //! stores all acts volume ids relevant to the micromegas /** it is used to quickly tell if a given Acts Surface belongs to micromegas */ std::set m_micromegasVolumeIds; diff --git a/offline/packages/trackbase/ActsTrackFittingAlgorithm.h b/offline/packages/trackbase/ActsTrackFittingAlgorithm.h index 425c669da2..4d794adac8 100644 --- a/offline/packages/trackbase/ActsTrackFittingAlgorithm.h +++ b/offline/packages/trackbase/ActsTrackFittingAlgorithm.h @@ -11,7 +11,7 @@ #include #include #include - +#include #pragma GCC diagnostic push // needed for local Act compilation #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include @@ -27,13 +27,29 @@ namespace Acts { class TrackingGeometry; } +struct MaterialSurfaceSelector + { + std::vector surfaces = {}; + + /// @param surface is the test surface + void operator()(const Acts::Surface* surface) + { + if (surface->surfaceMaterial() != nullptr) + { + if (std::find(surfaces.begin(), surfaces.end(), surface) == + surfaces.end()) + { + surfaces.push_back(surface); + } + } + } + }; class ActsTrackFittingAlgorithm final { public: using TrackParameters = ::Acts::BoundTrackParameters; - using Measurement = ::Acts::BoundVariantMeasurement; - using MeasurementContainer = std::vector; + using MeasurementContainer = ActsExamples::MeasurementContainer; using TrackContainer = Acts::TrackContainer tGeo, // ActsTrackingGeometry(std::shared_ptr tGeo, std::shared_ptr mag, @@ -49,7 +49,7 @@ struct ActsTrackingGeometry /// Acts context, for Kalman options Acts::CalibrationContext calibContext; - Acts::GeometryContext geoContext; + Acts::GeometryContext geoContext = Acts::GeometryContext::dangerouslyDefaultConstruct(); Acts::MagneticFieldContext magFieldContext; const Acts::GeometryContext& getGeoContext() const diff --git a/offline/packages/trackbase/AlignmentTransformation.cc b/offline/packages/trackbase/AlignmentTransformation.cc index b3eb79fcb0..b3c1bbfba2 100644 --- a/offline/packages/trackbase/AlignmentTransformation.cc +++ b/offline/packages/trackbase/AlignmentTransformation.cc @@ -21,6 +21,9 @@ #include #include +#include +#include + #include #include #include @@ -74,11 +77,17 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) // load alignment constants file std::ifstream datafile; - datafile.open(alignmentParamsFile); // looks for default file name on disk + if( !alignmentParamsFile.empty() ) + { + // looks for default file name on disk + datafile.open(alignmentParamsFile); + } + if (datafile.is_open()) { - std::cout << "AlignmentTransformation: Reading alignment parameters from disk file: " - << alignmentParamsFile << " localVerbosity = " << localVerbosity << std::endl; + std::cout + << "AlignmentTransformation: Reading alignment parameters from disk file: " + << alignmentParamsFile << " localVerbosity = " << localVerbosity << std::endl; } else { @@ -162,7 +171,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) std::cout << hitsetkey << " " << alpha << " " << beta << " " << gamma << " " << dx << " " << dy << " " << dz << " " << dgrx << " " << dgry << " " << dgrz << std::endl; } - + // Perturbation translations and angles for stave and sensor Eigen::Vector3d sensorAngles(alpha, beta, gamma); Eigen::Vector3d millepedeTranslation(dx, dy, dz); @@ -194,7 +203,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) Acts::GeometryIdentifier id = surf->geometryId(); - if (localVerbosity) + if (localVerbosity > 1) { std::cout << " Add transform for MVTX with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; std::cout << " final mvtx transform:" << std::endl @@ -223,7 +232,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) transform = newMakeTransform(surf, millepedeTranslation, sensorAngles, localFrameTranslation, sensorAnglesGlobal, trkrId, use_intt_survey_geometry); Acts::GeometryIdentifier id = surf->geometryId(); - if (localVerbosity) + if (localVerbosity > 1) { std::cout << " Add transform for INTT with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; } @@ -254,58 +263,87 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) unsigned int side = TpcDefs::getSide(hitsetkey); unsigned int sector = TpcDefs::getSectorId(hitsetkey); - // std::cout << "New module hitsetkey " << hitsetkey << "test_layer " << test_layer << " side " << side << " sector " << sector << " nlayers " << nlayers << " layer_begin " << layer_begin << std::endl; + // std::cout << "New module hitsetkey " << hitsetkey << "test_layer " << test_layer << " side " << side << " sector " << sector << " nlayers " << nlayers << " layer_begin " << layer_begin << std::endl; // loop over layers in module for (unsigned int this_layer = layer_begin; this_layer < layer_begin + nlayers; ++this_layer) { TrkrDefs::hitsetkey this_hitsetkey = TpcDefs::genHitSetKey(this_layer, sector, side); - // std::cout << " *** module hitsetkey " << hitsetkey << " this_hitsetkey " << this_hitsetkey << " this layer " << this_layer << " side " << side << " sector " << sector << std::endl; - - // is this correct?????? - int subsurfkey_min = (1 - side) * 144 + (144 - sector * 12) - 12 - 6; - int subsurfkey_max = subsurfkey_min + 12; - for (int subsurfkey = subsurfkey_min; subsurfkey < subsurfkey_max; subsurfkey++) - { - int sskey = subsurfkey; - if (sskey < 0) - { - sskey += 288; - } - - surf = surfMaps.getTpcSurface(this_hitsetkey, (unsigned int) sskey); - - Eigen::Vector3d localFrameTranslation(0, 0, 0); - if (test_layer < 4 || use_module_tilt_always) - { - // get the local frame translation that puts the local surface center at the tilted position after the local rotations are applied - unsigned int this_region = (this_layer - 7) / 16; // 0-2 - Eigen::Vector3d this_center = surf->center(m_tGeometry->geometry().getGeoContext()) * 0.1; // mm to cm - double this_radius = std::sqrt(this_center[0] * this_center[0] + this_center[1] * this_center[1]); - float moduleRadius = TpcModuleRadii[side][sector][this_region]; // radius of the center of the module in cm - localFrameTranslation = getTpcLocalFrameTranslation(moduleRadius, this_radius, sensorAngles) * 10; // cm to mm - } - - Acts::Transform3 transform; - transform = newMakeTransform(surf, millepedeTranslation, sensorAngles, localFrameTranslation, sensorAnglesGlobal, trkrId, false); - Acts::GeometryIdentifier id = surf->geometryId(); - - if (localVerbosity) - { - unsigned int layer = this_layer; - std::cout << " Add transform for TPC with surface GeometryIdentifier " << id << std::endl - << " trkrid " << trkrId << " hitsetkey " << this_hitsetkey << " layer " << layer << " sector " << sector << " side " << side - << " subsurfkey " << subsurfkey << std::endl; - Acts::Vector3 center = surf->center(m_tGeometry->geometry().getGeoContext()) * 0.1; // convert to cm - std::cout << "Ideal surface center: " << std::endl - << center << std::endl; - std::cout << "transform matrix: " << std::endl - << transform.matrix() << std::endl; - } - transformMap->addTransform(id, transform); - transformMapTransient->addTransform(id, transform); - } + // std::cout << " *** module hitsetkey " << hitsetkey << " this_hitsetkey " << this_hitsetkey << " this layer " << this_layer << " side " << side << " sector " << sector << std::endl; + + // Each TPC hitsetkey has 12 fake surfaces associated with it + // We want to make a transform for every fake surface in this hitsetkey + // Loop over the sector phi angles for the fake surfaces and get each surface + auto* layergeom = m_tpccellgeo->GetLayerCellGeom((int) this_layer); + auto sec_min_phi = layergeom->get_sector_min_phi(); + auto min_phi = sec_min_phi[side][sector]; + auto sec_max_phi = layergeom->get_sector_max_phi(); + auto max_phi = sec_max_phi[side][sector]; + double dphi = (max_phi - min_phi)/12.0; + for(int is = 0; is < 12; ++is) + { + double phis = min_phi + is*dphi + dphi/2.0; + double radius = layergeom->get_radius(); + double zcenter = 51.0; + if(side == 0) + { + zcenter *= -1; + } + Acts::Vector3 env_pos(radius*std::cos(phis), radius * std::sin(phis), zcenter); + Acts::Vector3 world_pos = m_tGeometry->transformTpcEnvelopeToWorld(env_pos); + unsigned short sskey = 999; + Surface this_surf = m_tGeometry->get_tpc_surface_from_coords(this_hitsetkey, world_pos, sskey); + if(sskey == 999 || !this_surf) + { + std::cout << PHWHERE << "Failed to get surface for layer " << this_layer << " side " << side << " sector " << sector << " quit!" << std::endl; + exit(1); + } + /* + std::cout << " layer " << this_layer << " radius " << radius << " phis " << phis << " min_phi " << min_phi << " max_phi " << max_phi + << " side " << side << " sector " << sector << " world " << world_pos.x() << " " << world_pos.y() << " " << world_pos.z() + <<" world_radius " << sqrt(world_pos.x() * world_pos.x() + world_pos.y() * world_pos.y()) + << " sskey " << sskey << std::endl; + */ + + Eigen::Vector3d localFrameTranslation(0, 0, 0); + use_module_tilt = false; + if (test_layer < 4 || use_module_tilt_always) + { + // get the local frame translation that puts the local surface center at the tilted position after the local rotations are applied + unsigned int this_region = (this_layer - 7) / 16; // 0-2 + Eigen::Vector3d this_center = this_surf->center(m_tGeometry->geometry().getGeoContext()) * 0.1; // mm to cm + //this_center includes the TPC tilt used in PHG4TpcDetector construction, transform to tpc envelope coords + Acts::Vector3 this_center_envelope = m_tGeometry->transformTpcWorldToEnvelope(this_center); + double this_radius = std::sqrt(this_center_envelope[0] * this_center_envelope[0] + this_center_envelope[1] * this_center_envelope[1]); + float moduleRadius = TpcModuleRadii[side][sector][this_region]; // radius of the center of the module in cm + localFrameTranslation = getTpcLocalFrameTranslation(moduleRadius, this_radius, sensorAngles) * 10; // cm to mm + + // set this flag for later use + use_module_tilt = true; + } + + Acts::Transform3 transform; + transform = newMakeTransform(this_surf, millepedeTranslation, sensorAngles, localFrameTranslation, sensorAnglesGlobal, trkrId, false); + Acts::GeometryIdentifier id = this_surf->geometryId(); + + if (localVerbosity) + { + std::cout << " Add transform for TPC with surface GeometryIdentifier " << id + << " trkrid " << trkrId << " hitsetkey " << this_hitsetkey << " layer " << this_layer << " sector " << sector + << " side " << side << std::endl; + if(localVerbosity > 1) + { + Acts::Vector3 center = this_surf->center(m_tGeometry->geometry().getGeoContext()) * 0.1; // convert to cm + std::cout << "Ideal surface center: " << std::endl + << center << std::endl; + std::cout << "transform matrix: " << std::endl + << transform.matrix() << std::endl; + } + } + transformMap->addTransform(id, transform); + transformMapTransient->addTransform(id, transform); + } } break; @@ -328,7 +366,7 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) transform = newMakeTransform(surf, millepedeTranslation, sensorAngles, localFrameTranslation, sensorAnglesGlobal, trkrId, false); Acts::GeometryIdentifier id = surf->geometryId(); - if (localVerbosity) + if (localVerbosity > 1) { std::cout << " Add transform for Micromegas with surface GeometryIdentifier " << id << " trkrid " << trkrId << std::endl; } @@ -347,7 +385,8 @@ void AlignmentTransformation::createMap(PHCompositeNode* topNode) } // copy map into geoContext - m_tGeometry->geometry().geoContext = transformMap; + Acts::GeometryContext gctx{transformMap}; + m_tGeometry->geometry().geoContext = gctx; std::cout << " AlignmentTransformation processed " << linecount << " input lines " << std::endl; @@ -368,7 +407,7 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, // get the acts transform components // Note that Acts transforms local coordinates of (x,z,y) to global (x,y,z) - Acts::Transform3 actsTransform = surf->transform(m_tGeometry->geometry().getGeoContext()); + auto actsTransform = surf->localToGlobalTransform(m_tGeometry->geometry().getGeoContext()); Eigen::Matrix3d actsRotationPart = actsTransform.rotation(); Eigen::Vector3d actsTranslationPart = actsTransform.translation(); @@ -417,69 +456,82 @@ Acts::Transform3 AlignmentTransformation::newMakeTransform(const Surface& surf, Acts::Transform3 transform; //! If we read the survey parameters directly, that is the full transform if (survey) - { - //! The millepede affines will just be what was read in, which was the - //! survey information. This should (in principle) be equivalent to - //! the ideal position + any misalignment - transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * mpLocalRotationAffine; - } - else - { - if (trkrid == TrkrDefs::tpcId) { - transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * actsRotationAffine * mpLocalTranslationAffine * mpLocalRotationAffine; + //! The millepede affines will just be what was read in, which was the + //! survey information. This should (in principle) be equivalent to + //! the ideal position + any misalignment + transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * mpLocalRotationAffine; } - else + else { - if(use_new_silicon_rotation_order) + // not survey. this is the normal usage + + if (trkrid == TrkrDefs::tpcId) { - transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * actsRotationAffine * mpLocalTranslationAffine * mpLocalRotationAffine; + if(use_module_tilt) + { + // use module tilt transforms with local rotation followed by local translation + transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * actsRotationAffine * mpLocalTranslationAffine * mpLocalRotationAffine; + } + else + { + // backward compatibility for old alignment params sets + transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * mpLocalRotationAffine * actsRotationAffine; + } } else { - // needed for backward compatibility to existing local rotations in MVTX - transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * mpLocalRotationAffine * actsRotationAffine; + // silicon and TPOT + if(use_new_silicon_rotation_order) + { + // use new transform order for silicon as well as TPC + transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * actsRotationAffine * mpLocalTranslationAffine * mpLocalRotationAffine; + } + else + { + // needed for backward compatibility to existing local rotation parmeter sets in silicon + transform = mpGlobalTranslationAffine * mpGlobalRotationAffine * actsTranslationAffine * mpLocalRotationAffine * actsRotationAffine; + } } } - } - if (localVerbosity) - { - Acts::Transform3 actstransform = actsTranslationAffine * actsRotationAffine; - - std::cout << "newMakeTransform" << std::endl; - std::cout << "Input sensorAngles: " << std::endl - << sensorAngles << std::endl; - std::cout << "Input sensorAnglesGlobal: " << std::endl - << sensorAnglesGlobal << std::endl; - std::cout << "Input translation: " << std::endl - << millepedeTranslation << std::endl; - std::cout << "mpLocalRotationAffine: " << std::endl - << mpLocalRotationAffine.matrix() << std::endl; - std::cout << "mpLocalTranslationAffine: " << std::endl - << mpLocalTranslationAffine.matrix() << std::endl; - std::cout << "actsRotationAffine: " << std::endl - << actsRotationAffine.matrix() << std::endl; - std::cout << "actsTranslationAffine: " << std::endl - << actsTranslationAffine.matrix() << std::endl; - std::cout << "mpRotationGlobalAffine: " << std::endl - << mpGlobalRotationAffine.matrix() << std::endl; - std::cout << "mpTranslationGlobalAffine: " << std::endl - << mpGlobalTranslationAffine.matrix() << std::endl; - std::cout << "Overall transform: " << std::endl - << transform.matrix() << std::endl; - std::cout << "overall * idealinv " << std::endl - << (transform * actstransform.inverse()).matrix() << std::endl; - std::cout << "overall - ideal " << std::endl; - for (int test = 0; test < transform.matrix().rows(); test++) + if (localVerbosity > 1) { - for (int test2 = 0; test2 < transform.matrix().cols(); test2++) - { - std::cout << transform(test, test2) - actstransform(test, test2) << ", "; - } - std::cout << std::endl; + Acts::Transform3 actstransform = actsTranslationAffine * actsRotationAffine; + + std::cout << "newMakeTransform" << std::endl; + std::cout << "Input sensorAngles: " << std::endl + << sensorAngles << std::endl; + std::cout << "Input sensorAnglesGlobal: " << std::endl + << sensorAnglesGlobal << std::endl; + std::cout << "Input translation: " << std::endl + << millepedeTranslation << std::endl; + std::cout << "mpLocalRotationAffine: " << std::endl + << mpLocalRotationAffine.matrix() << std::endl; + std::cout << "mpLocalTranslationAffine: " << std::endl + << mpLocalTranslationAffine.matrix() << std::endl; + std::cout << "actsRotationAffine: " << std::endl + << actsRotationAffine.matrix() << std::endl; + std::cout << "actsTranslationAffine: " << std::endl + << actsTranslationAffine.matrix() << std::endl; + std::cout << "mpRotationGlobalAffine: " << std::endl + << mpGlobalRotationAffine.matrix() << std::endl; + std::cout << "mpTranslationGlobalAffine: " << std::endl + << mpGlobalTranslationAffine.matrix() << std::endl; + std::cout << "Overall transform: " << std::endl + << transform.matrix() << std::endl; + std::cout << "overall * idealinv " << std::endl + << (transform * actstransform.inverse()).matrix() << std::endl; + std::cout << "overall - ideal " << std::endl; + for (int test = 0; test < transform.matrix().rows(); test++) + { + for (int test2 = 0; test2 < transform.matrix().cols(); test2++) + { + std::cout << transform(test, test2) - actstransform(test, test2) << ", "; + } + std::cout << std::endl; + } } - } return transform; } @@ -508,7 +560,7 @@ Eigen::Vector3d AlignmentTransformation::getTpcLocalFrameTranslation(float modul dy += -Rdiff * (1 - std::cos(gamma)); dz += 0.0; - if (localVerbosity) + if (localVerbosity > 1) { std::cout << " alpha, beta, gamma " << alpha << " " << beta << " " << gamma << " radius " << moduleRadius << " Rdiff " << Rdiff << " dx, dy dz " << dx << " " << dy << " " << dz << std::endl; @@ -530,6 +582,13 @@ int AlignmentTransformation::getNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::ABORTEVENT; } + m_tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + if (!m_tpccellgeo) + { + std::cout << PHWHERE << " unable to find DST node TPCGEOMCONTAINER" << std::endl; + exit(1); + } + return 0; } @@ -603,7 +662,7 @@ void AlignmentTransformation::generateRandomPerturbations(Eigen::Vector3d angleD std::normal_distribution distribution(0, transformDev(2)); perturbationTranslation(2) = distribution(generator); } - if (localVerbosity) + if (localVerbosity > 1) { std::cout << "randomperturbationAngles" << perturbationAngles << " randomperturbationTrans:" << perturbationTranslation << std::endl; } @@ -611,7 +670,7 @@ void AlignmentTransformation::generateRandomPerturbations(Eigen::Vector3d angleD void AlignmentTransformation::extractModuleCenterPositions() { - if (localVerbosity) + if (localVerbosity > 1) { std::cout << "Extracting TPC module center radii:" << std::endl; } @@ -625,26 +684,24 @@ void AlignmentTransformation::extractModuleCenterPositions() for (int isector = 0; isector < 12; ++isector) { - double sectorphi = sectorPhi[iside][iregion]; + double sectorphi = sectorPhi[iside][isector]; TrkrDefs::hitsetkey hitsetkey_in = TpcDefs::genHitSetKey(lin, isector, iside); - if (localVerbosity) - { - std::cout << " hitsetkey_in " << hitsetkey_in << " lin " << lin << " sector " << isector << " side " << iside << " region " << iregion << std::endl; - } - double surf_rad_in = extractModuleCenter(hitsetkey_in, sectorphi); + double surf_rad_in = extractModuleCenter(hitsetkey_in, sectorphi); TrkrDefs::hitsetkey hitsetkey_out = TpcDefs::genHitSetKey(lout, isector, iside); - double surf_rad_out = extractModuleCenter(hitsetkey_out, sectorphi); - double mod_radius = (surf_rad_in + surf_rad_out) / 2.0; + double surf_rad_out = extractModuleCenter(hitsetkey_out, sectorphi); + double mod_radius = (surf_rad_in + surf_rad_out) / 2.0; TpcModuleRadii[iside][isector][iregion] = mod_radius; - if (localVerbosity) - { - std::cout << " hitsetkey_out " << hitsetkey_out << " lout " << lout << " sector " << isector << " side " << iside - << " region " << iregion << " module radius " << mod_radius << std::endl; - } + if (localVerbosity > 1) + { + std::cout << " hitsetkey_in " << hitsetkey_in << " lin " << lin << " sector " << isector << " side " << iside << " region " << iregion << std::endl; + std::cout << " hitsetkey_out " << hitsetkey_out << " lout " << lout << " sector " << isector << " side " << iside << " region " << iregion << std::endl; + std::cout << " module radius " << mod_radius << std::endl; + } + } } } @@ -652,7 +709,7 @@ void AlignmentTransformation::extractModuleCenterPositions() double AlignmentTransformation::extractModuleCenter(TrkrDefs::hitsetkey hitsetkey, double sectorphi) { - // We want the module center position from the ideal geometry + // We want the module center position from the ideal geometry in the tpc envelope frame // the radius and z are not used, only the phi value double x = std::cos(sectorphi + 0.01) * 10.0; @@ -662,7 +719,12 @@ double AlignmentTransformation::extractModuleCenter(TrkrDefs::hitsetkey hitsetke Acts::Vector3 world(x, y, z); TrkrDefs::subsurfkey subsurfkey = 0; - Surface surface = m_tGeometry->get_tpc_surface_from_coords(hitsetkey, world, subsurfkey); + // std::cout << "extractModuleCenter: sectorphi " << sectorphi << " world " << world(0) << " " << world(1) << " " << world(2) << std::endl; + + // Note: the "world" position here is in pre-tilt tpc envelope coordinates, not global coordinates + // But, get_tpc_surface_from_coords() expects a global position as input, so we convert to world coordinates + Acts::Vector3 world_envelope = m_tGeometry->transformTpcEnvelopeToWorld(world); + Surface surface = m_tGeometry->get_tpc_surface_from_coords(hitsetkey, world_envelope, subsurfkey); if (!surface) { std::cout << PHWHERE << "Failed to find surface, quit " << std::endl; @@ -671,7 +733,9 @@ double AlignmentTransformation::extractModuleCenter(TrkrDefs::hitsetkey hitsetke Eigen::Vector3d surf_center = surface->center(m_tGeometry->geometry().getGeoContext()); surf_center /= 10.0; // convert from mm to cm - double surf_radius = std::sqrt(surf_center[0] * surf_center[0] + surf_center[1] * surf_center[1]); + // convert to tpc envelope coords + Acts::Vector3 surf_center_envelope = m_tGeometry->transformTpcWorldToEnvelope(surf_center); + double surf_radius = std::sqrt(surf_center_envelope[0] * surf_center_envelope[0] + surf_center_envelope[1] * surf_center_envelope[1]); return surf_radius; } diff --git a/offline/packages/trackbase/AlignmentTransformation.h b/offline/packages/trackbase/AlignmentTransformation.h index 7055d6c65a..7601f94004 100644 --- a/offline/packages/trackbase/AlignmentTransformation.h +++ b/offline/packages/trackbase/AlignmentTransformation.h @@ -11,15 +11,18 @@ #include class PHCompositeNode; - +class PHG4TpcGeomContainer; class ActsGeometry; class AlignmentTransformation { public: + + /// constructor AlignmentTransformation() = default; - ~AlignmentTransformation() {} + /// destructor + ~AlignmentTransformation() = default; void createMap(PHCompositeNode* topNode); void createAlignmentTransformContainer(PHCompositeNode* topNode); @@ -34,6 +37,9 @@ class AlignmentTransformation Eigen::Vector3d perturbationAnglesGlobal = Eigen::Vector3d(0.0, 0.0, 0.0); Eigen::Vector3d perturbationTranslation = Eigen::Vector3d(0.0, 0.0, 0.0); + /// assign local alignment parameter file to be used instead of CDB, if found + void setAlignmentParamsFile(const std::string& value ) { alignmentParamsFile = value; } + void setMVTXParams(double mvtxDevs[6]) { mvtxAngleDev(0) = mvtxDevs[0]; @@ -128,14 +134,15 @@ class AlignmentTransformation bool use_new_silicon_rotation_order = false; bool use_module_tilt_always = false; + bool use_module_tilt = false; // starts at false in all cases bool use_intt_survey_geometry = false; - + Acts::Transform3 newMakeTransform(const Surface& surf, Eigen::Vector3d& millepedeTranslation, Eigen::Vector3d& sensorAngles, Eigen::Vector3d& localFrameTranslation, Eigen::Vector3d& sensorAnglesGlobal, unsigned int trkrid, bool survey); - Eigen::Vector3d getTpcLocalFrameTranslation(float moduleRadius, float layerRadius, Eigen::Vector3d& localRotation) const; + Eigen::Vector3d getTpcLocalFrameTranslation(float moduleRadius, float layerRadius, Eigen::Vector3d& localRotation) const; void extractModuleCenterPositions(); - double extractModuleCenter(TrkrDefs::hitsetkey hitsetkey, double sectorphi); + double extractModuleCenter(TrkrDefs::hitsetkey hitsetkey, double sectorphi); alignmentTransformationContainer* transformMap = NULL; alignmentTransformationContainer* transformMapTransient = NULL; @@ -147,6 +154,8 @@ class AlignmentTransformation float TpcModuleRadii[2][12][3] = {}; // module radial center in local coords unsigned int innerLayer[3] = {}; double sectorPhi[2][12] = {}; + + PHG4TpcGeomContainer *m_tpccellgeo = nullptr; }; #endif diff --git a/offline/packages/trackbase/Calibrator.cc b/offline/packages/trackbase/Calibrator.cc index 44b66bce1a..ce9839e7f5 100644 --- a/offline/packages/trackbase/Calibrator.cc +++ b/offline/packages/trackbase/Calibrator.cc @@ -6,43 +6,34 @@ void Calibrator::calibrate(const Calibrator::MeasurementContainer& measurements, const Acts::SourceLink& sourceLink, Acts::VectorMultiTrajectory::TrackStateProxy& trackState) const { - trackState.setUncalibratedSourceLink(sourceLink); + trackState.setUncalibratedSourceLink(Acts::SourceLink{sourceLink}); const ActsSourceLink sl = sourceLink.get(); - const ActsSourceLink::Index index = sl.index(); - std::visit( - [&](const auto& uncalibmeas) + const ActsExamples::ConstVariableBoundMeasurementProxy measurement = + measurements.getMeasurement(sl.index()); + + Acts::visit_measurement(measurement.size(), [&](auto N) -> void + { + constexpr std::size_t kMeasurementSize = decltype(N)::value; + const ActsExamples::ConstFixedBoundMeasurementProxy fixedMeasurement = + static_cast>( + measurement); + const auto cov = fixedMeasurement.covariance(); + const TrkrDefs::cluskey cluskey = sl.cluskey(); + const uint8_t layer = TrkrDefs::getLayer(cluskey); + const double misalignmentFactor = gctx.get()->getMisalignmentFactor(layer); + + Acts::ActsSquareMatrix expandedCov = Acts::ActsSquareMatrix::Zero(); + + for (int i = 0; i < cov.rows(); i++) + { + for (int j = 0; j < cov.cols(); j++) { - std::array indices{}; - indices[0] = Acts::BoundIndices::eBoundLoc0; - indices[1] = Acts::BoundIndices::eBoundLoc1; - - Acts::ActsVector<2> loc; - loc(0) = uncalibmeas.parameters()[Acts::eBoundLoc0]; - loc(1) = uncalibmeas.parameters()[Acts::eBoundLoc1]; - - auto cov = uncalibmeas.covariance(); - const TrkrDefs::cluskey cluskey = sl.cluskey(); - const uint8_t layer = TrkrDefs::getLayer(cluskey); - const double misalignmentFactor = gctx.get()->getMisalignmentFactor(layer); - - Acts::ActsSquareMatrix<2> expandedCov = Acts::ActsSquareMatrix<2>::Zero(); - - for (int i = 0; i < cov.rows(); i++) - { - for (int j = 0; j < cov.cols(); j++) - { - expandedCov(i, j) = cov(i, j) * misalignmentFactor; - } - } - - Acts::Measurement meas(sourceLink, - indices, - loc, expandedCov); - - trackState.allocateCalibrated(meas.size()); - trackState.setCalibrated(meas); - }, - (measurements)[index]); + expandedCov(i, j) = cov(i, j) * misalignmentFactor; + } + } + trackState.allocateCalibrated(fixedMeasurement.parameters().eval(), + expandedCov.eval()); + trackState.setProjectorSubspaceIndices(fixedMeasurement.subspaceIndices()); }); } void CalibratorAdapter::calibrate( diff --git a/offline/packages/trackbase/Calibrator.h b/offline/packages/trackbase/Calibrator.h index 2f9d4f2fc0..651091ad5b 100644 --- a/offline/packages/trackbase/Calibrator.h +++ b/offline/packages/trackbase/Calibrator.h @@ -6,7 +6,7 @@ #include "TrkrDefs.h" #include "alignmentTransformationContainer.h" -#include +#include #include #include @@ -14,13 +14,7 @@ class Calibrator { public: - using Measurement = ::Acts::BoundVariantMeasurement; - /// Container of measurements. - /// - /// In contrast to the source links, the measurements themself must not be - /// orderable. The source links stored in the measurements are treated - /// as opaque here and no ordering is enforced on the stored measurements. - using MeasurementContainer = std::vector; + using MeasurementContainer = ActsExamples::MeasurementContainer; void calibrate(const MeasurementContainer& measurements, const Acts::GeometryContext& gctx, diff --git a/offline/packages/trackbase/ClusterErrorPara.cc b/offline/packages/trackbase/ClusterErrorPara.cc index cb62ed10f5..f45a59b14b 100644 --- a/offline/packages/trackbase/ClusterErrorPara.cc +++ b/offline/packages/trackbase/ClusterErrorPara.cc @@ -1,7 +1,8 @@ #include "ClusterErrorPara.h" #include "TrkrCluster.h" - +//#include +#include #include #include @@ -18,58 +19,96 @@ namespace { return x * x; } + } // namespace -ClusterErrorPara::ClusterErrorPara() +ClusterErrorPara::ClusterErrorPara(): + f0{new TF1("f0", "pol1", 0, 10)}, + f1{new TF1("f1", "pol2", 0, 10)}, + f2{new TF1("f2", "pol2", 0, 10)}, + f0fine{new TF1("f0fine", "pol2", 0, 20000)}, + f1fine{new TF1("f1fine", "pol3", 0, 20000)}, + f2fine{new TF1("f2fine", "pol5", 0, 20000)}, + f2fine2{new TF1("f2fine", "pol5", 0, 20000)}, + fz0{new TF1("fz0", "pol2", -2, 2)}, + fz1{new TF1("fz1", "pol4", -2, 2)}, + fz2{new TF1("fz2", "pol2", -2, 2)}, + fz0fine{new TF1("fz0fine", "pol2", 0, 20000)}, + fz1fine{new TF1("fz1fine", "pol3", 0, 20000)}, + fz2fine{new TF1("fz2fine", "pol5", 0, 20000)}, + fmm_55_2{new TF1("fmm_55_2", "pol2", -2, 2)}, + fmm_56_2{new TF1("fmm_56_2", "pol2", -2, 2)}, + fmm_3{new TF1("fmm_3", "pol2", -2, 2)}, + fadcz0{new TF1("fadcz0", "pol5", 0, 20000)}, + fadcz1{new TF1("fadcz1", "pol5", 0, 20000)}, + fadcz2{new TF1("fadcz2", "pol5", 0, 20000)}, + fadcz0fine{new TF1("fadcz0fine", "[0]+([1]/pow(x-[2],2))", 0, 20000)}, + fadcz1fine{new TF1("fadcz1fine", "[0]+([1]/pow(x-[2],2))", 0, 20000)}, + fadcz2fine{new TF1("fadcz2fine", "[0]+([1]/pow(x-[2],2))", 0, 20000)}, + fadcphi0{new TF1("fadcphi0", "pol4", 0, 20000)}, + fadcphi0fine{new TF1("fadcphi0fine", "pol2", 0, 20000)}, + fadcphi1{new TF1("fadcphi1", "pol4", 0, 20000)}, + fadcphi1fine{new TF1("fadcphi1fine", "pol4", 0, 20000)}, + fadcphi2{new TF1("fadcphi2", "pol5", 0, 20000)}, + fadcphi2fine1{new TF1("fadcphi2fine1", "pol4", 0, 20000)}, + fadcphi2fine2{new TF1("fadcphi2fine2", "pol1", 0, 20000)} + { - f0 = new TF1("f0", "pol1", 0, 10); + /* + ftpcR1 = new TF1("ftpcR1", "pol2", 0, 10); + ftpcR1->SetParameter(0, 3.206); + ftpcR1->SetParameter(1, -0.252); + ftpcR1->SetParameter(2, 0.007); + */ + + // f0 = new TF1("f0", "pol1", 0, 10); f0->SetParameter(0, 0.0163943); f0->SetParameter(1, 0.0192931); - f1 = new TF1("f1", "pol2", 0, 10); + // f1 = new TF1("f1", "pol2", 0, 10); f1->SetParameter(0, 0.0119384); f1->SetParameter(1, 0.0253197); f1->SetParameter(2, 0.0404213); - f2 = new TF1("f2", "pol2", 0, 10); + // f2 = new TF1("f2", "pol2", 0, 10); f2->SetParameter(0, 0.0107316); f2->SetParameter(1, 0.0294968); f2->SetParameter(2, 0.0414098); // f2->SetParameter(3,9.75877); - fz0 = new TF1("fz0", "pol2", -2, 2); + // fz0 = new TF1("fz0", "pol2", -2, 2); fz0->SetParameter(0, 0.0520278); fz0->SetParameter(1, -0.00578699); fz0->SetParameter(2, 0.0156972); - fz1 = new TF1("fz1", "pol4", -2, 2); + // fz1 = new TF1("fz1", "pol4", -2, 2); fz1->SetParameter(0, 0.0383233); fz1->SetParameter(1, -0.00577128); fz1->SetParameter(2, 0.0770914); fz1->SetParameter(3, -0.0818139); fz1->SetParameter(4, 0.050305); - fz2 = new TF1("fz2", "pol2", -2, 2); + // fz2 = new TF1("fz2", "pol2", -2, 2); fz2->SetParameter(0, 0.0371611); fz2->SetParameter(1, -0.000694558); fz2->SetParameter(2, 0.0437917); - fmm_55_2 = new TF1("fmm_55_2", "pol2", -2, 2); + // fmm_55_2 = new TF1("fmm_55_2", "pol2", -2, 2); fmm_55_2->SetParameter(0, 0.0430592); fmm_55_2->SetParameter(1, -0.000177174); fmm_55_2->SetParameter(2, 0.0914288); - fmm_56_2 = new TF1("fmm_56_2", "pol2", -2, 2); + // fmm_56_2 = new TF1("fmm_56_2", "pol2", -2, 2); fmm_56_2->SetParameter(0, 0.00363897); fmm_56_2->SetParameter(1, 0.0109713); fmm_56_2->SetParameter(2, 0.032354); - fmm_3 = new TF1("fmm_3", "pol2", -2, 2); + // fmm_3 = new TF1("fmm_3", "pol2", -2, 2); fmm_3->SetParameter(0, 0.00305396); fmm_3->SetParameter(1, 0.00505814); fmm_3->SetParameter(2, 0.0395137); - fadcz0 = new TF1("fadcz0", "pol5", 0, 20000); + // fadcz0 = new TF1("fadcz0", "pol5", 0, 20000); fadcz0->SetParameter(0, 2.08854); fadcz0->SetParameter(1, -0.0536847); fadcz0->SetParameter(2, 0.000989393); @@ -77,7 +116,7 @@ ClusterErrorPara::ClusterErrorPara() fadcz0->SetParameter(4, 4.42178e-08); fadcz0->SetParameter(5, -7.79669e-11); - fadcz1 = new TF1("fadcz1", "pol5", 0, 20000); + // fadcz1 = new TF1("fadcz1", "pol5", 0, 20000); fadcz1->SetParameter(0, 2.35278); fadcz1->SetParameter(1, -0.0535903); fadcz1->SetParameter(2, 0.00088052); @@ -85,7 +124,7 @@ ClusterErrorPara::ClusterErrorPara() fadcz1->SetParameter(4, 3.35361e-08); fadcz1->SetParameter(5, -5.61371e-11); - fadcz2 = new TF1("fadcz2", "pol5", 0, 20000); + // fadcz2 = new TF1("fadcz2", "pol5", 0, 20000); fadcz2->SetParameter(0, 2.53191); fadcz2->SetParameter(1, -0.062285); fadcz2->SetParameter(2, 0.00103893); @@ -93,22 +132,22 @@ ClusterErrorPara::ClusterErrorPara() fadcz2->SetParameter(4, 3.9802e-08); fadcz2->SetParameter(5, -6.67137e-11); - fadcz0fine = new TF1("fadcz0fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); + // fadcz0fine = new TF1("fadcz0fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); fadcz0fine->SetParameter(0, 9.63983e-01); fadcz0fine->SetParameter(1, 2.68585e+01); fadcz0fine->SetParameter(2, -4.78664e+00); - fadcz1fine = new TF1("fadcz1fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); + // fadcz1fine = new TF1("fadcz1fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); fadcz1fine->SetParameter(0, 9.85546e-01); fadcz1fine->SetParameter(1, 1.12622e+02); fadcz1fine->SetParameter(2, -1.26552e+01); - fadcz2fine = new TF1("fadcz2fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); + // fadcz2fine = new TF1("fadcz2fine", "[0]+([1]/pow(x-[2],2))", 0, 20000); fadcz2fine->SetParameter(0, 9.71125e-01); fadcz2fine->SetParameter(1, 6.67244e+01); fadcz2fine->SetParameter(2, -3.55034e+00); - fadcphi0 = new TF1("fadcphi0", "pol4", 0, 20000); + // fadcphi0 = new TF1("fadcphi0", "pol4", 0, 20000); fadcphi0->SetParameter(0, 1.79273); fadcphi0->SetParameter(1, -0.0306044); fadcphi0->SetParameter(2, 0.000355984); @@ -116,26 +155,26 @@ ClusterErrorPara::ClusterErrorPara() fadcphi0->SetParameter(4, 4.26161e-09); // fadcphi0->SetParameter(5,-4.22758e-11); - fadcphi0fine = new TF1("fadcphi0fine", "pol2", 0, 20000); + // fadcphi0fine = new TF1("fadcphi0fine", "pol2", 0, 20000); fadcphi0fine->SetParameter(0, 1.02625); fadcphi0fine->SetParameter(1, -0.00167294); fadcphi0fine->SetParameter(2, 2.2912e-5); - fadcphi1 = new TF1("fadcphi1", "pol4", 0, 20000); + // fadcphi1 = new TF1("fadcphi1", "pol4", 0, 20000); fadcphi1->SetParameter(0, 2.12873); fadcphi1->SetParameter(1, -0.0369604); fadcphi1->SetParameter(2, 0.00042828); fadcphi1->SetParameter(3, -2.3665e-06); fadcphi1->SetParameter(4, 4.87683e-09); - fadcphi1fine = new TF1("fadcphi1fine", "pol4", 0, 20000); + // fadcphi1fine = new TF1("fadcphi1fine", "pol4", 0, 20000); fadcphi1fine->SetParameter(0, 1.11749); fadcphi1fine->SetParameter(1, -0.00354277); fadcphi1fine->SetParameter(2, 5.60236e-05); fadcphi1fine->SetParameter(3, -4.46412e-07); fadcphi1fine->SetParameter(4, 1.22689e-09); - fadcphi2 = new TF1("fadcphi2", "pol5", 0, 20000); + // fadcphi2 = new TF1("fadcphi2", "pol5", 0, 20000); fadcphi2->SetParameter(0, 2.29); fadcphi2->SetParameter(1, -0.0474362); fadcphi2->SetParameter(2, 0.000717789); @@ -143,23 +182,23 @@ ClusterErrorPara::ClusterErrorPara() fadcphi2->SetParameter(4, 2.52007e-08); fadcphi2->SetParameter(5, -4.14747e-11); - fadcphi2fine1 = new TF1("fadcphi2fine1", "pol4", 0, 20000); + // fadcphi2fine1 = new TF1("fadcphi2fine1", "pol4", 0, 20000); fadcphi2fine1->SetParameter(0, 1.39404); fadcphi2fine1->SetParameter(1, -0.0202245); fadcphi2fine1->SetParameter(2, 0.000394666); fadcphi2fine1->SetParameter(3, -3.37831e-06); fadcphi2fine1->SetParameter(4, 1.05017e-08); - fadcphi2fine2 = new TF1("fadcphi2fine2", "pol1", 0, 20000); + // fadcphi2fine2 = new TF1("fadcphi2fine2", "pol1", 0, 20000); fadcphi2fine2->SetParameter(0, 0.997); fadcphi2fine2->SetParameter(1, 0.00047); - f0fine = new TF1("f0fine", "pol2", 0, 20000); + // f0fine = new TF1("f0fine", "pol2", 0, 20000); f0fine->SetParameter(0, 0.98611); f0fine->SetParameter(1, -0.169505); f0fine->SetParameter(2, 1.12907); - f1fine = new TF1("f1fine", "pol3", 0, 20000); + // f1fine = new TF1("f1fine", "pol3", 0, 20000); f1fine->SetParameter(0, 0.968625); f1fine->SetParameter(1, -0.38894); f1fine->SetParameter(2, 3.36493); @@ -172,7 +211,7 @@ ClusterErrorPara::ClusterErrorPara() f2fine->SetParameter(3,-42.4668); f2fine->SetParameter(4,43.6083); */ - f2fine = new TF1("f2fine", "pol5", 0, 20000); + // f2fine = new TF1("f2fine", "pol5", 0, 20000); f2fine->SetLineColor(kBlue); f2fine->SetParameter(0, 1.14119); f2fine->SetParameter(1, -2.81483); @@ -181,18 +220,18 @@ ClusterErrorPara::ClusterErrorPara() f2fine->SetParameter(4, 72.2359); f2fine->SetParameter(5, -20.3802); - fz0fine = new TF1("fz0fine", "pol2", 0, 20000); + // fz0fine = new TF1("fz0fine", "pol2", 0, 20000); fz0fine->SetParameter(0, 0.96933); fz0fine->SetParameter(1, -0.0458534); fz0fine->SetParameter(2, 0.231419); - fz1fine = new TF1("fz1fine", "pol3", 0, 20000); + // fz1fine = new TF1("fz1fine", "pol3", 0, 20000); fz1fine->SetParameter(0, 0.886262); fz1fine->SetParameter(1, -0.0818167); fz1fine->SetParameter(2, 0.805824); fz1fine->SetParameter(3, -0.425423); - fz2fine = new TF1("fz2fine", "pol5", 0, 20000); + // fz2fine = new TF1("fz2fine", "pol5", 0, 20000); fz2fine->SetLineColor(kBlue); fz2fine->SetParameter(0, 0.880153); fz2fine->SetParameter(1, 0.552461); @@ -476,40 +515,258 @@ ClusterErrorPara::ClusterErrorPara() //_________________________________________________________________________________ ClusterErrorPara::error_t ClusterErrorPara::get_clusterv5_modified_error(TrkrCluster* cluster, double /*unused*/, TrkrDefs::cluskey key) { + + static const bool is_data_reco = []() { + recoConsts* rc = recoConsts::instance(); + if (rc->FlagExist("CDB_GLOBALTAG")) + { + if (rc->get_StringFlag("CDB_GLOBALTAG").find("MDC") != std::string::npos) + { + return false; + } + } + return true; // default to data + }(); + /* + static bool is_data_reco{true}; // default to data + static bool is_data_reco_set{false}; // default to data + if(!is_data_reco_set){ + recoConsts* rc = recoConsts::instance(); + if(rc->FlagExist("CDB_GLOBALTAG")) + { + if(rc->get_StringFlag("CDB_GLOBALTAG").find("MDC") != std::string::npos) + { + is_data_reco = false; + } + } + is_data_reco_set = true; + } + */ int layer = TrkrDefs::getLayer(key); double phierror = cluster->getRPhiError(); double zerror = cluster->getZError(); - if (TrkrDefs::getTrkrId(key) == TrkrDefs::tpcId) - { - if (layer == 7 || layer == 22 || layer == 23 || layer == 38 || layer == 39) - { - phierror *= 4; - zerror *= 4; - } - if (cluster->getEdge() >= 3) - { - phierror *= 4; - } - if (cluster->getOverlap() >= 2) - { - phierror *= 2; - } - if (cluster->getPhiSize() == 1) - { - phierror *= 10; + + if(is_data_reco==false){ + if (TrkrDefs::getTrkrId(key) == TrkrDefs::tpcId) + { + if (layer == 7 || layer == 22 || layer == 23 || layer == 38 || layer == 39) + { + phierror *= 4; + zerror *= 4; + } + if (cluster->getEdge() >= 3) + { + phierror *= 4; + } + if (cluster->getOverlap() >= 2) + { + phierror *= 2; + } + if (cluster->getPhiSize() == 1) + { + phierror *= 10; + } + if (cluster->getPhiSize() >= 5) + { + phierror *= 10; + } + + phierror = std::min(phierror, 0.1); + if (phierror < 0.0005) + { + phierror = 0.1; + } + } + }else{ + + if (TrkrDefs::getTrkrId(key) == TrkrDefs::tpcId) + { + if (layer == 7 || layer == 22 || layer == 23 || layer == 38 || layer == 39 || layer == 54) + { + phierror *= 4; + zerror *= 4; + } + if (cluster->getEdge() >= 3) + { + phierror *= 4; + } + if (cluster->getOverlap() >= 2) + { + phierror *= 2; + } + if(layer>=7&&layer<(7+48)){ + //Set phi error + if (cluster->getPhiSize() == 1) + { + phierror *= 1.0; + } + if (cluster->getPhiSize() == 2) + { + phierror*=3.15; + } + if (cluster->getPhiSize() == 3) + { + phierror *=3.5; + } + if (cluster->getPhiSize() >3) + { + phierror *= 4; + } + //Set Z Error + if (cluster->getZSize() == 1){ + zerror*=1.0; + } + if (cluster->getZSize() == 2){ + if(layer>=7&&layer<(7+16)){ + zerror*=7; + } + if(layer>=(7+16)&&layer<(7+32)){ + zerror*=4.5; + } + if(layer>=(7+32)&&layer<(7+48)){ + zerror*=4.5; + } + + } + if ((cluster->getZSize() == 3) || (cluster->getZSize() == 4)){ + if(layer>=7&&layer<(7+16)){ + zerror*=7; + } + if(layer>=(7+16)&&layer<(7+32)){ + zerror*=5; + } + if(layer>=(7+32)&&layer<(7+48)){ + zerror*=5; + } + // zerror*=6; + } + if (cluster->getZSize() >=5){ + if(layer>=7&&layer<(7+16)){ + zerror*=20; + } + if(layer>=(7+16)&&layer<(7+32)){ + zerror*=6; + } + if(layer>=(7+32)&&layer<(7+48)){ + zerror*=7; + } + } + /* + static TF1 ftpcR1("ftpcR1", "pol2", 0, 60); + ftpcR1.SetParameter(0, 3.206); + ftpcR1.SetParameter(1, -0.252); + ftpcR1.SetParameter(2, 0.007); + + static TF1 ftpcR2("ftpcR2", "pol2", 0, 60); + ftpcR2.SetParameter(0, 4.48); + ftpcR2.SetParameter(1, -0.226); + ftpcR2.SetParameter(2, 0.00362); + + static TF1 ftpcR3("ftpcR3", "pol2", 0, 60); + ftpcR3.SetParameter(0, 14.8112); + ftpcR3.SetParameter(1, -0.577); + ftpcR3.SetParameter(2, 0.00605); + + if(layer>=7&&layer<(7+16)){ + phierror*= ftpcR1.Eval(layer); + } + if(layer>=(7+16)&&layer<(7+32)){ + phierror*= ftpcR2.Eval(layer); + } + if(layer>=(7+32)&&layer<(7+48)){ + phierror*= ftpcR3.Eval(layer); + } + ftpcR2.SetParameter(0, 5.593); + ftpcR2.SetParameter(1, -0.2458); + ftpcR2.SetParameter(2, 0.00333455); + + ftpcR3.SetParameter(0, 5.6964); + ftpcR3.SetParameter(1, -0.21338); + ftpcR3.SetParameter(2, 0.002502); + + if(layer>=(7+16)&&layer<(7+32)){ + zerror*= ftpcR2.Eval(layer); + } + if(layer>=(7+32)&&layer<(7+48)){ + zerror*= ftpcR3.Eval(layer); + } + */ + + // Inline pol2 evaluation: p0 + p1*x + p2*x^2 + auto pol2 = [](double x, double p0, double p1, double p2) { + return p0 + p1 * x + p2 * x * x; + }; + + if(layer>=7&&layer<(7+16)){ + phierror *= pol2(layer, 3.206, -0.252, 0.007); + } + if(layer>=(7+16)&&layer<(7+32)){ + phierror *= pol2(layer, 4.48, -0.226, 0.00362); + } + if(layer>=(7+32)&&layer<(7+48)){ + phierror *= pol2(layer, 14.8112, -0.577, 0.00605); + } + + if(layer>=(7+16)&&layer<(7+32)){ + zerror *= pol2(layer, 5.593, -0.2458, 0.00333455); + } + if(layer>=(7+32)&&layer<(7+48)){ + zerror *= pol2(layer, 5.6964, -0.21338, 0.002502); + } + } + if (cluster->getPhiSize() >= 5) + { + phierror *= 10; + } + } + + if (TrkrDefs::getTrkrId(key) == TrkrDefs::mvtxId){ + phierror*=2; + zerror*=2; + } - if (cluster->getPhiSize() >= 5) - { - phierror *= 10; + + if (TrkrDefs::getTrkrId(key) == TrkrDefs::inttId){ + phierror*=9; + if (cluster->getPhiSize() == 1){ + phierror *= 1.25; + } + if (cluster->getPhiSize() == 2){ + phierror *= 2.25; + } + if((layer==3)||(layer==4)){ + phierror*=0.8; + } + if((layer==5)||(layer==6)){ + phierror*=1.2; + } } + + if (TrkrDefs::getTrkrId(key) == TrkrDefs::micromegasId){ + if(layer==55){ + /* + phierror*=5.4; + phierror*=4.6; + phierror*=3.0; + zerror*=0.82; + */ + phierror = 0.0289; + } + + if(layer==56){ + /* + phierror*=0.9; + phierror*=0.95; + zerror*=4.5; + zerror*=3.4; + */ + zerror = 0.577; + } - phierror = std::min(phierror, 0.1); - if (phierror < 0.0005) - { - phierror = 0.1; } } + return std::make_pair(square(phierror), square(zerror)); } diff --git a/offline/packages/trackbase/ClusterErrorPara.h b/offline/packages/trackbase/ClusterErrorPara.h index b125858217..39001d352c 100644 --- a/offline/packages/trackbase/ClusterErrorPara.h +++ b/offline/packages/trackbase/ClusterErrorPara.h @@ -17,6 +17,7 @@ class ClusterErrorPara virtual ~ClusterErrorPara() { + //delete ftpcR1; delete f0; delete f1; delete f2; @@ -71,6 +72,7 @@ class ClusterErrorPara double tpc_z_error(int layer, double beta, TrkrCluster *cluster); private: + // TF1 *ftpcR1 {nullptr}; TF1 *f0 {nullptr}; TF1 *f1 {nullptr}; TF1 *f2 {nullptr}; @@ -128,6 +130,7 @@ class ClusterErrorPara double scale_mm_1 {1.5}; double pull_fine_phi[60]{}; double pull_fine_z[60]{}; + }; #endif diff --git a/offline/packages/trackbase/IBaseDetector.h b/offline/packages/trackbase/IBaseDetector.h index a52e5f1b0b..8f1f0f16d5 100644 --- a/offline/packages/trackbase/IBaseDetector.h +++ b/offline/packages/trackbase/IBaseDetector.h @@ -8,12 +8,20 @@ #pragma once -#include "ActsExamples/Utilities/OptionsFwd.hpp" - #include #include #include - +namespace boost::program_options +{ + class options_description; + class variables_map; +} // namespace boost::program_options + +namespace ActsExamples::Options +{ + using Description = ::boost::program_options::options_description; + using Variables = ::boost::program_options::variables_map; +} // namespace ActsExamples::Options namespace Acts { class TrackingGeometry; class IMaterialDecorator; @@ -34,8 +42,5 @@ class IBaseDetector { virtual void addOptions( boost::program_options::options_description& opt) const = 0; - virtual std::pair finalize( - const boost::program_options::variables_map& vm, - std::shared_ptr mdecorator) = 0; }; } // namespace ActsExamples diff --git a/offline/packages/trackbase/InttDefs.cc b/offline/packages/trackbase/InttDefs.cc index efe0425bec..42b7879a12 100644 --- a/offline/packages/trackbase/InttDefs.cc +++ b/offline/packages/trackbase/InttDefs.cc @@ -22,7 +22,7 @@ namespace static constexpr unsigned int kBitShiftLadderPhiIdWidth = 4; static constexpr unsigned int kBitShiftLadderZIdOffset = 14; static constexpr unsigned int kBitShiftLadderZIdWidth = 2; - static constexpr int crossingOffset = 512; + static constexpr int crossingOffset = 200; // bit shift for hitkey static const unsigned int kBitShiftCol __attribute__((unused)) = 16; diff --git a/offline/packages/trackbase/LaserCluster.h b/offline/packages/trackbase/LaserCluster.h index a4c42e2081..919d36bd60 100644 --- a/offline/packages/trackbase/LaserCluster.h +++ b/offline/packages/trackbase/LaserCluster.h @@ -7,11 +7,22 @@ #ifndef TRACKBASE_LASERCLUSTER_H #define TRACKBASE_LASERCLUSTER_H +#include "TpcDefs.h" + #include + + #include #include +struct LaserClusterHitInfo +{ + TrkrDefs::hitsetkey hitsetkey = 0; + TrkrDefs::hitkey hitkey = 0; + uint16_t adc = 0; +}; + /** * @brief Base class for laser cluster object * @@ -60,6 +71,13 @@ class LaserCluster : public PHObject virtual float getIT() const { return std::numeric_limits::quiet_NaN(); } virtual void setIT(float) {} + virtual unsigned int getLayerInt() const { return std::numeric_limits::max(); } + virtual void setLayerInt(unsigned int) {} + virtual unsigned int getIPhiInt() const { return std::numeric_limits::max(); } + virtual void setIPhiInt(unsigned int) {} + virtual unsigned int getITInt() const { return std::numeric_limits::max(); } + virtual void setITInt(unsigned int) {} + // // cluster info // @@ -121,6 +139,8 @@ class LaserCluster : public PHObject virtual void setHitAdc(int, float) {} virtual float getHitAdc(int) const { return std::numeric_limits::quiet_NaN(); } + virtual void addHit(TrkrDefs::hitsetkey, TrkrDefs::hitkey, uint16_t) {} + virtual LaserClusterHitInfo getHit(int) const { return LaserClusterHitInfo(std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()); } protected: LaserCluster() = default; diff --git a/offline/packages/trackbase/LaserClusterLinkDef.h b/offline/packages/trackbase/LaserClusterLinkDef.h index 4502785e29..e7645e16b6 100644 --- a/offline/packages/trackbase/LaserClusterLinkDef.h +++ b/offline/packages/trackbase/LaserClusterLinkDef.h @@ -1,5 +1,7 @@ #ifdef __CINT__ #pragma link C++ class LaserCluster+; +#pragma link C++ struct LaserClusterHitInfo+; +#pragma link C++ class std::vector+; #endif diff --git a/offline/packages/trackbase/LaserClusterv3.cc b/offline/packages/trackbase/LaserClusterv3.cc new file mode 100644 index 0000000000..a0f9e308c8 --- /dev/null +++ b/offline/packages/trackbase/LaserClusterv3.cc @@ -0,0 +1,78 @@ +/** + * @file trackbase/LaserClusterv3.cc + * @author Ben Kimelman + * @date July 2026 + * @brief Implementation of LaserClusterv3 + */ +#include "LaserClusterv3.h" + +#include +#include // for swap + +void LaserClusterv3::identify(std::ostream& os) const +{ + os << "---LaserClusterv3--------------------" << std::endl; + + os << " " << m_hits.size() << " hits"; + os << " fit? " << m_fitMode; + os << " (layer, iphi, it) = (" << m_posHardware[0]; + os << ", " << m_posHardware[1] << ", "; + os << m_posHardware[2] << ")"; + os << " adc = " << getAdc() << std::endl; + + os << std::endl; + os << "-----------------------------------------------" << std::endl; + + return; +} + +int LaserClusterv3::isValid() const +{ + if(getNhits() == 0) + { + return 0; + } + + return 1; +} + +unsigned int LaserClusterv3::getAdc() const +{ + unsigned int adc = 0; + for(const auto &LCHI : m_hits) + { + adc += (unsigned int) LCHI.adc; + } + return adc; +} + +void LaserClusterv3::CopyFrom( const LaserCluster& source ) +{ + // do nothing if copying onto oneself + if( this == &source ) + { + return; + } + + // parent class method + LaserCluster::CopyFrom( source ); + setLayerInt( source.getLayerInt() ); + setIPhiInt( source.getIPhiInt() ); + setITInt( source.getITInt() ); + setNLayers( source.getNLayers() ); + setNIPhi( source.getNIPhi() ); + setNIT( source.getNIT() ); + setSDLayer( source.getSDLayer() ); + setSDIPhi( source.getSDIPhi() ); + setSDIT( source.getSDIT() ); + setSDWeightedLayer( source.getSDWeightedLayer() ); + setSDWeightedIPhi( source.getSDWeightedIPhi() ); + setSDWeightedIT( source.getSDWeightedIT() ); + + + for(int i=0; i<(int)source.getNhits(); i++){ + LaserClusterHitInfo LCHI = source.getHit(i); + addHit(LCHI.hitsetkey, LCHI.hitkey, LCHI.adc); + } +} + diff --git a/offline/packages/trackbase/LaserClusterv3.h b/offline/packages/trackbase/LaserClusterv3.h new file mode 100644 index 0000000000..1b158e4e5e --- /dev/null +++ b/offline/packages/trackbase/LaserClusterv3.h @@ -0,0 +1,116 @@ +/** + * @file trackbase/LaserClusterv3.h + * @author Ben Kimelman + * @date July 2026 + * @brief Version 3 of CMFLashCluster + */ +#ifndef TRACKBASE_LASERCLUSTERV3_H +#define TRACKBASE_LASERCLUSTERV3_H + +#include "LaserCluster.h" + +#include +#include + +class PHObject; + +/** + * @brief Version 3 of LaserCluster + * + * Note - D. McGlinchey June 2018: + * CINT does not like "override", so ignore where CINT + * complains. Should be checked with ROOT 6 once + * migration occurs. + */ + + +class LaserClusterv3 : public LaserCluster +{ + public: + //! ctor + LaserClusterv3() = default; + + // PHObject virtual overloads + void Reset() override {} + int isValid() const override; + PHObject* CloneMe() const override { return new LaserClusterv3(*this); } + + //! copy content from base class + void CopyFrom( const LaserCluster& ) override; + + //! copy content from base class + void CopyFrom( LaserCluster* source ) override + { CopyFrom( *source ); } + + bool getFitMode() const override { return m_fitMode; } + void setFitMode(bool fitMode) override { m_fitMode = fitMode; } + + unsigned int getLayerInt() const override { return m_posHardware[0]; } + void setLayerInt(unsigned int layer) override { m_posHardware[0] = layer; } + unsigned int getIPhiInt() const override { return m_posHardware[1]; } + void setIPhiInt(unsigned int iphi) override { m_posHardware[1] = iphi; } + unsigned int getITInt() const override { return m_posHardware[2]; } + void setITInt(unsigned int it) override { m_posHardware[2] = it; } + + unsigned int getNhits() const override {return (unsigned int)m_hits.size();} + + // + // cluster info + // + unsigned int getAdc() const override; + + void setNLayers(unsigned int nLayers) override { m_nLayers = nLayers; } + unsigned int getNLayers() const override { return m_nLayers; } + + void setNIPhi(unsigned int nIPhi) override { m_nIPhi = nIPhi; } + unsigned int getNIPhi() const override { return m_nIPhi; } + + void setNIT(unsigned int nIT) override { m_nIT = nIT; } + unsigned int getNIT() const override { return m_nIT; } + + void setSDLayer(float SDLayer) override { m_SDLayer = SDLayer; } + float getSDLayer() const override { return m_SDLayer; } + + void setSDIPhi(float SDIPhi) override { m_SDIPhi = SDIPhi; } + float getSDIPhi() const override { return m_SDIPhi; } + + void setSDIT(float SDIT) override { m_SDIT = SDIT; } + float getSDIT() const override { return m_SDIT; } + + void setSDWeightedLayer(float SDLayer) override { m_SDWeightedLayer = SDLayer; } + float getSDWeightedLayer() const override { return m_SDWeightedLayer; } + + void setSDWeightedIPhi(float SDIPhi) override { m_SDWeightedIPhi = SDIPhi; } + float getSDWeightedIPhi() const override { return m_SDWeightedIPhi; } + + void setSDWeightedIT(float SDIT) override { m_SDWeightedIT = SDIT; } + float getSDWeightedIT() const override { return m_SDWeightedIT; } + + void addHit(TrkrDefs::hitsetkey hitsetkey, TrkrDefs::hitkey hitkey, uint16_t adc) override { m_hits.push_back(LaserClusterHitInfo(hitsetkey, hitkey, adc)); }; + LaserClusterHitInfo getHit(int hitIndex) const override { return m_hits[hitIndex]; }; + + void identify(std::ostream& os = std::cout) const override; + + protected: + + std::vector m_hits; + + unsigned int m_posHardware[3] = {std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()}; + bool m_fitMode{false}; + + /// number of TPC clusters used to create this central mebrane cluster + unsigned int m_nhits = std::numeric_limits::max(); + unsigned int m_nLayers = std::numeric_limits::max(); + unsigned int m_nIPhi = std::numeric_limits::max(); + unsigned int m_nIT = std::numeric_limits::max(); + float m_SDLayer = std::numeric_limits::quiet_NaN(); + float m_SDIPhi = std::numeric_limits::quiet_NaN(); + float m_SDIT = std::numeric_limits::quiet_NaN(); + float m_SDWeightedLayer = std::numeric_limits::quiet_NaN(); + float m_SDWeightedIPhi = std::numeric_limits::quiet_NaN(); + float m_SDWeightedIT = std::numeric_limits::quiet_NaN(); + + ClassDefOverride(LaserClusterv3, 1) +}; + +#endif //TRACKBASE_LASERCLUSTERV3_H diff --git a/offline/packages/trackbase/LaserClusterv3LinkDef.h b/offline/packages/trackbase/LaserClusterv3LinkDef.h new file mode 100644 index 0000000000..769b08954f --- /dev/null +++ b/offline/packages/trackbase/LaserClusterv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class LaserClusterv3+; + +#endif diff --git a/offline/packages/trackbase/MagneticFieldOptions.cc b/offline/packages/trackbase/MagneticFieldOptions.cc index 4043397f76..52ee028196 100644 --- a/offline/packages/trackbase/MagneticFieldOptions.cc +++ b/offline/packages/trackbase/MagneticFieldOptions.cc @@ -7,8 +7,8 @@ #include #include #include -#include -#include +#include +#include #include #include @@ -129,13 +129,13 @@ ActsExamples::Options::readMagneticField(const Variables& vars) { }; if (readRoot) { - auto map = makeMagneticFieldMapXyzFromRoot( + auto map = ActsPlugins::makeMagneticFieldMapXyzFromRoot( std::move(mapBins), file.native(), tree, lengthUnit, fieldUnit, useOctantOnly); return std::make_shared(std::move(map)); } else { - auto map = makeMagneticFieldMapXyzFromText(std::move(mapBins), + auto map = Acts::makeMagneticFieldMapXyzFromText(std::move(mapBins), file.native(), lengthUnit, fieldUnit, useOctantOnly); return std::make_shared(std::move(map)); @@ -148,13 +148,13 @@ ActsExamples::Options::readMagneticField(const Variables& vars) { }; if (readRoot) { - auto map = makeMagneticFieldMapRzFromRoot( + auto map = ActsPlugins::makeMagneticFieldMapRzFromRoot( std::move(mapBins), file.native(), tree, lengthUnit, fieldUnit, useOctantOnly); return std::make_shared(std::move(map)); } else { - auto map = makeMagneticFieldMapRzFromText(std::move(mapBins), + auto map = Acts::makeMagneticFieldMapRzFromText(std::move(mapBins), file.native(), lengthUnit, fieldUnit, useOctantOnly); return std::make_shared(std::move(map)); diff --git a/offline/packages/trackbase/MagneticFieldOptions.h b/offline/packages/trackbase/MagneticFieldOptions.h index 7604c026c4..e827e456be 100644 --- a/offline/packages/trackbase/MagneticFieldOptions.h +++ b/offline/packages/trackbase/MagneticFieldOptions.h @@ -3,7 +3,18 @@ #include #include -#include + +namespace boost::program_options +{ + class options_description; + class variables_map; +} // namespace boost::program_options + +namespace ActsExamples::Options +{ + using Description = ::boost::program_options::options_description; + using Variables = ::boost::program_options::variables_map; +} // namespace ActsExamples::Options namespace ActsExamples { @@ -19,4 +30,4 @@ std::shared_ptr readMagneticField( } // namespace Options } // namespace ActsExamples -#endif // _MAGNETICFIELDOPTIONS_H \ No newline at end of file +#endif // _MAGNETICFIELDOPTIONS_H diff --git a/offline/packages/trackbase/Makefile.am b/offline/packages/trackbase/Makefile.am index 29d090c40a..851afe77ca 100644 --- a/offline/packages/trackbase/Makefile.am +++ b/offline/packages/trackbase/Makefile.am @@ -38,9 +38,7 @@ AM_LDFLAGS = \ pkginclude_HEADERS = \ - ActsAborter.h \ ActsGeometry.h \ - ActsGsfTrackFittingAlgorithm.h \ ActsSourceLink.h \ ActsSurfaceMaps.h \ ActsTrackFittingAlgorithm.h \ @@ -71,8 +69,9 @@ pkginclude_HEADERS = \ LaserClusterContainerv1.h \ LaserClusterv1.h \ LaserClusterv2.h \ - MagneticFieldOptions.h \ + LaserClusterv3.h \ MaterialWiper.h \ + MagneticFieldOptions.h \ MvtxDefs.h \ MvtxEventInfo.h \ MvtxEventInfov1.h \ @@ -116,6 +115,7 @@ pkginclude_HEADERS = \ TrkrClusterv3.h \ TrkrClusterv4.h \ TrkrClusterv5.h \ + TrkrClusterv6.h \ TrkrDefs.h \ TrkrHit.h \ TrkrHitSet.h \ @@ -130,7 +130,8 @@ pkginclude_HEADERS = \ TrkrHitTruthAssoc.h \ TrkrHitTruthAssocv1.h \ TrkrHitv1.h \ - TrkrHitv2.h + TrkrHitv2.h \ + TrkrHitv3.h ROOTDICTS = \ CMFlashClusterContainer_Dict.cc \ @@ -152,6 +153,7 @@ ROOTDICTS = \ LaserCluster_Dict.cc \ LaserClusterv1_Dict.cc \ LaserClusterv2_Dict.cc \ + LaserClusterv3_Dict.cc \ MvtxEventInfo_Dict.cc \ MvtxEventInfov1_Dict.cc \ MvtxEventInfov2_Dict.cc \ @@ -188,6 +190,7 @@ ROOTDICTS = \ TrkrClusterv3_Dict.cc \ TrkrClusterv4_Dict.cc \ TrkrClusterv5_Dict.cc \ + TrkrClusterv6_Dict.cc \ TrkrHitSetContMvtxHelper_Dict.cc \ TrkrHitSetContMvtxHelperv1_Dict.cc \ TrkrHitSetContainer_Dict.cc \ @@ -201,7 +204,8 @@ ROOTDICTS = \ TrkrHitTruthAssocv1_Dict.cc \ TrkrHit_Dict.cc \ TrkrHitv1_Dict.cc \ - TrkrHitv2_Dict.cc + TrkrHitv2_Dict.cc \ + TrkrHitv3_Dict.cc pcmdir = $(libdir) @@ -219,7 +223,6 @@ libtrack_la_SOURCES = \ MagneticFieldOptions.cc \ sPHENIXActsDetectorElement.cc \ TGeoDetectorWithOptions.cc \ - TrackFittingAlgorithmFunctionsGsf.cc \ TrackFittingAlgorithmFunctionsKalman.cc \ TrackFitUtils.cc @@ -240,6 +243,7 @@ libtrack_io_la_SOURCES = \ LaserClusterContainerv1.cc \ LaserClusterv1.cc \ LaserClusterv2.cc \ + LaserClusterv3.cc \ MvtxDefs.cc \ MvtxEventInfo.cc \ MvtxEventInfov1.cc \ @@ -275,6 +279,7 @@ libtrack_io_la_SOURCES = \ TrkrClusterv3.cc \ TrkrClusterv4.cc \ TrkrClusterv5.cc \ + TrkrClusterv6.cc \ TrkrDefs.cc \ TrkrHitSet.cc \ TrkrHitSetContMvtxHelper.cc \ @@ -287,15 +292,16 @@ libtrack_io_la_SOURCES = \ TrkrHitSetTpcv1.cc \ TrkrHitTruthAssocv1.cc \ TrkrHitv1.cc \ - TrkrHitv2.cc + TrkrHitv2.cc \ + TrkrHitv3.cc libtrack_la_LIBADD = \ libtrack_io.la \ -lActsCore \ - -lActsExamplesMagneticField \ - -lActsPluginTGeo \ + -lActsPluginRoot \ -lActsExamplesDetectorTGeo \ -lffamodules \ + -lg4detectors \ -lboost_program_options libtrack_io_la_LIBADD = \ diff --git a/offline/packages/trackbase/MvtxEventInfov1.h b/offline/packages/trackbase/MvtxEventInfov1.h index 5c6b382304..869f735925 100644 --- a/offline/packages/trackbase/MvtxEventInfov1.h +++ b/offline/packages/trackbase/MvtxEventInfov1.h @@ -10,12 +10,11 @@ /* 29/09/2023 */ /***************************/ -#include +#include "MvtxEventInfo.h" +#include #include -#include "MvtxEventInfo.h" - typedef std::pair strobe_L1_pair; /// diff --git a/offline/packages/trackbase/MvtxEventInfov2.cc b/offline/packages/trackbase/MvtxEventInfov2.cc index f1b6fddc14..f9fef23636 100644 --- a/offline/packages/trackbase/MvtxEventInfov2.cc +++ b/offline/packages/trackbase/MvtxEventInfov2.cc @@ -140,12 +140,6 @@ unsigned int MvtxEventInfov2::get_number_L1s() const return mySet.size(); } -std::set MvtxEventInfov2::get_strobe_BCOs() const -{ - std::set mySet = m_strobe_BCOs; - return mySet; -} - std::set MvtxEventInfov2::get_L1_BCOs() const { std::set mySet; diff --git a/offline/packages/trackbase/MvtxEventInfov2.h b/offline/packages/trackbase/MvtxEventInfov2.h index f1e663dd86..9b0b8325a4 100644 --- a/offline/packages/trackbase/MvtxEventInfov2.h +++ b/offline/packages/trackbase/MvtxEventInfov2.h @@ -10,12 +10,11 @@ /* 09/11/2023 */ /***************************/ -#include +#include "MvtxEventInfo.h" +#include #include -#include "MvtxEventInfo.h" - typedef std::pair strobe_L1_pair; /// @@ -51,7 +50,7 @@ class MvtxEventInfov2 : public MvtxEventInfo unsigned int get_number_L1s() const override; // std::set get_strobe_BCOs() const; - std::set get_strobe_BCOs() const override; + std::set get_strobe_BCOs() const override {return m_strobe_BCOs;} std::set get_L1_BCOs() const override; std::set get_strobe_BCO_from_L1_BCO(const uint64_t ival) const override; diff --git a/offline/packages/trackbase/MvtxEventInfov3.h b/offline/packages/trackbase/MvtxEventInfov3.h index d1e11fa129..e0f213780f 100644 --- a/offline/packages/trackbase/MvtxEventInfov3.h +++ b/offline/packages/trackbase/MvtxEventInfov3.h @@ -10,11 +10,11 @@ /* 29/09/2023 */ /***************************/ -#include +#include "MvtxEventInfo.h" +#include #include -#include "MvtxEventInfo.h" /// class MvtxEventInfov3 : public MvtxEventInfo diff --git a/offline/packages/trackbase/ResidualOutlierFinder.h b/offline/packages/trackbase/ResidualOutlierFinder.h index 593f5df981..7a587f56ec 100644 --- a/offline/packages/trackbase/ResidualOutlierFinder.h +++ b/offline/packages/trackbase/ResidualOutlierFinder.h @@ -1,17 +1,23 @@ #ifndef TRACKBASE_RESIDUALOUTLIERFINDER_H #define TRACKBASE_RESIDUALOUTLIERFINDER_H +#include + #include #include #include -#include + #include -#include + +#include + #include #include +#include #include -#include +#include + struct ResidualOutlierFinder { ActsGeometry* m_tGeometry = nullptr; @@ -49,44 +55,14 @@ struct ResidualOutlierFinder auto sourceLink = state.getUncalibratedSourceLink().template get(); const auto& cluskey = sourceLink.cluskey(); - const auto predicted = state.predicted(); - const auto predictedCovariance = state.predictedCovariance(); - float chi2 = std::numeric_limits::max(); - - auto fullCalibrated = state - .template calibrated() - .data(); - auto fullCalibratedCovariance = state - .template calibratedCovariance() - .data(); - - chi2 = Acts::visit_measurement(state.calibratedSize(), [&](auto N) -> double - { - constexpr size_t kMeasurementSize = decltype(N)::value; - typename Acts::TrackStateTraits::Measurement calibrated{ - fullCalibrated}; - - typename Acts::TrackStateTraits::MeasurementCovariance - calibratedCovariance{fullCalibratedCovariance}; - - using ParametersVector = Acts::ActsVector; - const auto H = state.projector().template topLeftCorner().eval(); - ParametersVector res; - res = calibrated - H * predicted; - chi2 = (res.transpose() * ((calibratedCovariance + H * predictedCovariance * H.transpose())).inverse() * res).eval()(0, 0); - - return chi2; }); + double chi2 = Acts::calculatePredictedChi2(state); float distance = Acts::visit_measurement(state.calibratedSize(), [&](auto N) { constexpr size_t kMeasurementSize = decltype(N)::value; - auto residuals = - state.template calibrated() - - state.projector() - .template topLeftCorner() * - state.predicted(); - auto cdistance = residuals.norm(); - return cdistance; }); + auto [residual, residualCovariance] = + calculatePredictedResidual(state); + return residual.norm(); }); if (verbosity > 2) { @@ -108,6 +84,10 @@ struct ResidualOutlierFinder std::cout << PHWHERE << "no geometry set in residual outlier finder" << std::endl; exit(1); } + const auto predicted = state.predicted(); + auto fullCalibrated = state + .template calibrated() + .data(); Acts::FreeVector freeParams = Acts::transformBoundToFreeParameters(state.referenceSurface(), m_tGeometry->geometry().getGeoContext(), @@ -117,7 +97,7 @@ struct ResidualOutlierFinder m_tGeometry->geometry().getGeoContext(), local, Acts::Vector3(1, 1, 1)); float data[] = { - (float) sphenixlayer, (float) layer, (float) volume, distance, chi2, + (float) sphenixlayer, (float) layer, (float) volume, distance, (float)chi2, (float) freeParams[Acts::eFreePos0], (float) freeParams[Acts::eFreePos1], (float) freeParams[Acts::eFreePos2], (float) predicted[Acts::eBoundLoc0], (float) predicted[Acts::eBoundLoc1], (float) global[Acts::eFreePos0], (float) global[Acts::eFreePos1], (float) global[Acts::eFreePos2], diff --git a/offline/packages/trackbase/SpacePoint.h b/offline/packages/trackbase/SpacePoint.h index 74bff8b1c2..354d2beeb9 100644 --- a/offline/packages/trackbase/SpacePoint.h +++ b/offline/packages/trackbase/SpacePoint.h @@ -1,12 +1,14 @@ #ifndef TRACKBASE_SPACEPOINT_H #define TRACKBASE_SPACEPOINT_H -#include -#include -#include "trackbase/TrkrDefs.h" +#include +#include #include -#include +#include + +#include +#include /** * A struct for Acts to take cluster information for seeding @@ -40,8 +42,11 @@ inline bool operator==(SpacePoint a, SpacePoint b) { return (a.m_clusKey == b.m_clusKey); } +using SpacePointContainerType = ActsExamples::SpacePointContainer>; +using proxy_type = typename Acts::SpacePointContainer::SpacePointProxyType; using SpacePointPtr = std::unique_ptr; -using SeedContainer = std::vector>; +using SpacePointContainer = std::vector; +using SeedContainer = std::vector>; #endif diff --git a/offline/packages/trackbase/TGeoDetectorWithOptions.cc b/offline/packages/trackbase/TGeoDetectorWithOptions.cc index 4467c20754..6c0698cec7 100644 --- a/offline/packages/trackbase/TGeoDetectorWithOptions.cc +++ b/offline/packages/trackbase/TGeoDetectorWithOptions.cc @@ -10,9 +10,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -79,36 +79,4 @@ void TGeoDetectorWithOptions::addOptions( "Json file to dump empty config into."); } -auto TGeoDetectorWithOptions::finalize( - const boost::program_options::variables_map& vm, - std::shared_ptr mdecorator) - -> std::pair { - TGeoDetector::Config config; - - config.fileName = vm["geo-tgeo-filename"].as(); - - config.surfaceLogLevel = - Acts::Logging::Level(vm["geo-surface-loglevel"].template as()); - config.layerLogLevel = - Acts::Logging::Level(vm["geo-layer-loglevel"].template as()); - config.volumeLogLevel = - Acts::Logging::Level(vm["geo-volume-loglevel"].template as()); - - // No valid geometry configuration. Stop - if (vm["geo-tgeo-jsonconfig"].as().empty()) { - writeTGeoDetectorConfig(vm, config); - std::exit(EXIT_SUCCESS); - } - // Enable dump from full config - else if (!(vm["geo-tgeo-dump-jsonconfig"].as().compare( - "tgeo_empty_cofig.json") == 0)) { - readTGeoLayerBuilderConfigs(vm, config); - writeTGeoDetectorConfig(vm, config); - } else { - readTGeoLayerBuilderConfigs(vm, config); - } - - return m_detector.finalize(config, std::move(mdecorator)); -} - } // namespace ActsExamples diff --git a/offline/packages/trackbase/TGeoDetectorWithOptions.h b/offline/packages/trackbase/TGeoDetectorWithOptions.h index cc8467c92d..af3358abdf 100644 --- a/offline/packages/trackbase/TGeoDetectorWithOptions.h +++ b/offline/packages/trackbase/TGeoDetectorWithOptions.h @@ -4,20 +4,17 @@ #include "IBaseDetector.h" #include -#include namespace ActsExamples { class TGeoDetectorWithOptions : public IBaseDetector { public: + TGeoDetectorWithOptions(TGeoDetector::Config config) : m_detector(config) {} TGeoDetector m_detector; void addOptions( boost::program_options::options_description& opt) const override; - - auto finalize(const boost::program_options::variables_map& vm, - std::shared_ptr mdecorator) - -> std::pair override; + }; } // namespace ActsExamples diff --git a/offline/packages/trackbase/TrackFittingAlgorithmFunctionsGsf.cc b/offline/packages/trackbase/TrackFittingAlgorithmFunctionsGsf.cc index cecd2898b9..16d5912532 100644 --- a/offline/packages/trackbase/TrackFittingAlgorithmFunctionsGsf.cc +++ b/offline/packages/trackbase/TrackFittingAlgorithmFunctionsGsf.cc @@ -9,7 +9,8 @@ ActsGsfTrackFittingAlgorithm::makeGsfFitterFunction( BetheHeitlerApprox betheHeitlerApprox, std::size_t maxComponents, double weightCutoff, MixtureReductionAlgorithm finalReductionMethod, bool abortOnError, - bool disableAllMaterialHandling, const Acts::Logger& logger) + bool disableAllMaterialHandling, double reverseFilteringCovarianceScaling, + const Acts::Logger& logger) { MultiStepper stepper(std::move(magneticField), logger.cloneWithSuffix("GSFStep")); @@ -35,6 +36,7 @@ ActsGsfTrackFittingAlgorithm::makeGsfFitterFunction( fitterFunction->abortOnError = abortOnError; fitterFunction->disableAllMaterialHandling = disableAllMaterialHandling; fitterFunction->reductionAlg = finalReductionMethod; - + fitterFunction->reverseFilteringCovarianceScaling = + reverseFilteringCovarianceScaling; return fitterFunction; } diff --git a/offline/packages/trackbase/TrkrCluster.h b/offline/packages/trackbase/TrkrCluster.h index 7fd091a527..2035e19796 100644 --- a/offline/packages/trackbase/TrkrCluster.h +++ b/offline/packages/trackbase/TrkrCluster.h @@ -51,57 +51,110 @@ class TrkrCluster : public PHObject // // cluster position // - virtual float getLocalX() const { return NAN; } - virtual void setLocalX(float) {} - virtual float getLocalY() const { return NAN; } - virtual void setLocalY(float) {} + virtual float getLocalX() const { return std::numeric_limits::quiet_NaN(); } + virtual void setLocalX(const float) {} + virtual float getLocalY() const { return std::numeric_limits::quiet_NaN(); } + virtual void setLocalY(const float) {} // // cluster info // - virtual void setAdc(unsigned int) {} + virtual void setAdc(const unsigned int) {} virtual unsigned int getAdc() const { return UINT_MAX; } - virtual void setMaxAdc(uint16_t) {} + virtual void setMaxAdc(const uint16_t) {} virtual unsigned int getMaxAdc() const { return UINT_MAX; } virtual char getOverlap() const { return std::numeric_limits::max(); } - virtual void setOverlap(char) {} + virtual void setOverlap(const char) {} virtual char getEdge() const { return std::numeric_limits::max(); } - virtual void setEdge(char) {} + virtual void setEdge(const char) {} virtual void setTime(const float) {} - virtual float getTime() const { return NAN; } + virtual float getTime() const { return std::numeric_limits::quiet_NaN(); } virtual char getSize() const { return std::numeric_limits::max(); } // // convenience interface // - virtual float getPhiSize() const { return NAN; } - virtual float getZSize() const { return NAN; } - virtual float getPhiError() const { return NAN; } - virtual float getRPhiError() const { return NAN; } - virtual float getZError() const { return NAN; } + virtual float getPhiSize() const { return std::numeric_limits::quiet_NaN(); } + virtual float getZSize() const { return std::numeric_limits::quiet_NaN(); } + virtual float getPhiError() const { return std::numeric_limits::quiet_NaN(); } + virtual float getRPhiError() const { return std::numeric_limits::quiet_NaN(); } + virtual float getZError() const { return std::numeric_limits::quiet_NaN(); } + virtual unsigned int getCenAdc() const { return UINT_MAX; } + virtual float getPadCen() const { return std::numeric_limits::quiet_NaN(); } + virtual float getTBinCen() const { return std::numeric_limits::quiet_NaN(); } + virtual int getPadMax() const { return std::numeric_limits::max(); } + virtual int getTBinMax() const { return std::numeric_limits::max(); } + virtual char getSLEdge() const { return std::numeric_limits::max(); } + virtual char getSREdge() const { return std::numeric_limits::max(); } + virtual char getTLEdge() const { return std::numeric_limits::max(); } + virtual char getTREdge() const { return std::numeric_limits::max(); } + virtual char getDLEdge() const { return std::numeric_limits::max(); } + virtual char getDREdge() const { return std::numeric_limits::max(); } + virtual char getHLEdge() const { return std::numeric_limits::max(); } + virtual char getHREdge() const { return std::numeric_limits::max(); } + virtual char getSLMix() const { return std::numeric_limits::max(); } + virtual char getSRMix() const { return std::numeric_limits::max(); } + virtual char getTLMix() const { return std::numeric_limits::max(); } + virtual char getTRMix() const { return std::numeric_limits::max(); } + virtual unsigned short getPhiBinLo() const { return std::numeric_limits::max(); } + virtual unsigned short getPhiBinHi() const { return std::numeric_limits::max(); } + virtual unsigned short getTBinLo() const { return std::numeric_limits::max(); } + virtual unsigned short getTBinHi() const { return std::numeric_limits::max(); } + virtual float getPadPhase() const { return std::numeric_limits::quiet_NaN(); } + virtual float getTBinPhase() const { return std::numeric_limits::quiet_NaN(); } + virtual float getRSize() const { return std::numeric_limits::quiet_NaN(); } + + virtual void setSLEdge(const char) {}; + virtual void setSREdge(const char) {}; + virtual void setTLEdge(const char) {}; + virtual void setTREdge(const char) {}; + virtual void setDLEdge(const char) {}; + virtual void setDREdge(const char) {}; + virtual void setHLEdge(const char) {}; + virtual void setHREdge(const char) {}; + virtual void setSLMix(const char) {}; + virtual void setSRMix(const char) {}; + virtual void setTLMix(const char) {}; + virtual void setTRMix(const char) {}; + virtual void setPhiBinLo(const unsigned short) {}; + virtual void setPhiBinHi(const unsigned short) {}; + virtual void setTBinLo(const unsigned short) {}; + virtual void setTBinHi(const unsigned short) {}; + virtual void setPadPhase(const float) {}; + virtual void setTBinPhase(const float) {}; + virtual void setRSize(const char) {}; + virtual void setCenAdc(const uint16_t) {}; + virtual void setPadCen(const float) {}; + virtual void setTBinCen(const float) {}; + virtual void setPadMax(const int) {}; + virtual void setTBinMax(const int) {}; + virtual void setPhiError(const float) {}; + virtual void setZError(const float) {}; + virtual void setPhiSize(const char) {}; + virtual void setZSize(const char) {}; /// Acts functions, for Acts modules use only virtual void setActsLocalError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} - virtual float getActsLocalError(unsigned int /*i*/, unsigned int /*j*/) const { return NAN; } + virtual float getActsLocalError(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual TrkrDefs::subsurfkey getSubSurfKey() const { return TrkrDefs::SUBSURFKEYMAX; } - virtual void setSubSurfKey(TrkrDefs::subsurfkey /*id*/) {} + virtual void setSubSurfKey(const TrkrDefs::subsurfkey /*id*/) {} // Global coordinate functions are deprecated, use local // coordinate functions only - virtual float getX() const { return NAN; } + virtual float getX() const { return std::numeric_limits::quiet_NaN(); } virtual void setX(float) {} - virtual float getY() const { return NAN; } + virtual float getY() const { return std::numeric_limits::quiet_NaN(); } virtual void setY(float) {} - virtual float getZ() const { return NAN; } + virtual float getZ() const { return std::numeric_limits::quiet_NaN(); } virtual void setZ(float) {} - virtual float getPosition(int /*coor*/) const { return NAN; } + virtual float getPosition(int /*coor*/) const { return std::numeric_limits::quiet_NaN(); } virtual void setPosition(int /*coor*/, float /*xi*/) {} virtual void setGlobal() {} virtual void setLocal() {} virtual bool isGlobal() const { return true; } - virtual float getError(unsigned int /*i*/, unsigned int /*j*/) const { return NAN; } + virtual float getError(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual void setError(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} - virtual float getSize(unsigned int /*i*/, unsigned int /*j*/) const { return NAN; } + virtual float getSize(unsigned int /*i*/, unsigned int /*j*/) const { return std::numeric_limits::quiet_NaN(); } virtual void setSize(unsigned int /*i*/, unsigned int /*j*/, float /*value*/) {} protected: diff --git a/offline/packages/trackbase/TrkrClusterv2.h b/offline/packages/trackbase/TrkrClusterv2.h index fb7e6eda31..9b4edafc74 100644 --- a/offline/packages/trackbase/TrkrClusterv2.h +++ b/offline/packages/trackbase/TrkrClusterv2.h @@ -7,10 +7,11 @@ #ifndef TRACKBASE_TRKRCLUSTERV2_H #define TRACKBASE_TRKRCLUSTERV2_H -#include #include "TrkrCluster.h" #include "TrkrDefs.h" +#include + class PHObject; /** diff --git a/offline/packages/trackbase/TrkrClusterv3.h b/offline/packages/trackbase/TrkrClusterv3.h index ded341dd35..49cd6dd6e6 100644 --- a/offline/packages/trackbase/TrkrClusterv3.h +++ b/offline/packages/trackbase/TrkrClusterv3.h @@ -7,10 +7,11 @@ #ifndef TRACKBASE_TRKRCLUSTERV3_H #define TRACKBASE_TRKRCLUSTERV3_H -#include #include "TrkrCluster.h" #include "TrkrDefs.h" +#include + class PHObject; /** diff --git a/offline/packages/trackbase/TrkrClusterv4.cc b/offline/packages/trackbase/TrkrClusterv4.cc index 542c1530cc..8ee11bf797 100644 --- a/offline/packages/trackbase/TrkrClusterv4.cc +++ b/offline/packages/trackbase/TrkrClusterv4.cc @@ -13,7 +13,7 @@ namespace { // square convenience function template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } diff --git a/offline/packages/trackbase/TrkrClusterv4.h b/offline/packages/trackbase/TrkrClusterv4.h index 15a17adf3a..439e3d9aef 100644 --- a/offline/packages/trackbase/TrkrClusterv4.h +++ b/offline/packages/trackbase/TrkrClusterv4.h @@ -7,10 +7,11 @@ #ifndef TRACKBASE_TRKRCLUSTERV4_H #define TRACKBASE_TRKRCLUSTERV4_H -#include #include "TrkrCluster.h" #include "TrkrDefs.h" +#include + class PHObject; /** @@ -159,10 +160,10 @@ class TrkrClusterv4 : public TrkrCluster // void setSize(char size) { m_size = size; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(char phisize) { m_phisize = phisize; } + void setPhiSize(char phisize) override { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(char zsize) { m_zsize = zsize; } + void setZSize(char zsize) override { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } void setOverlap(char overlap) override { m_overlap = overlap; } diff --git a/offline/packages/trackbase/TrkrClusterv5.cc b/offline/packages/trackbase/TrkrClusterv5.cc index 58e08745ad..a0cc7fbe52 100644 --- a/offline/packages/trackbase/TrkrClusterv5.cc +++ b/offline/packages/trackbase/TrkrClusterv5.cc @@ -13,7 +13,7 @@ namespace { // square convenience function template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } diff --git a/offline/packages/trackbase/TrkrClusterv5.h b/offline/packages/trackbase/TrkrClusterv5.h index 9e5e0fe7ff..ee3ac20755 100644 --- a/offline/packages/trackbase/TrkrClusterv5.h +++ b/offline/packages/trackbase/TrkrClusterv5.h @@ -7,10 +7,11 @@ #ifndef TRACKBASE_TRKRCLUSTERV5_H #define TRACKBASE_TRKRCLUSTERV5_H -#include #include "TrkrCluster.h" #include "TrkrDefs.h" +#include + class PHObject; /** @@ -53,12 +54,12 @@ class TrkrClusterv5 : public TrkrCluster float getPosition(int coor) const override { return m_local[coor]; } void setPosition(int coor, float xi) override { m_local[coor] = xi; } float getLocalX() const override { return m_local[0]; } - void setLocalX(float loc0) override { m_local[0] = loc0; } + void setLocalX(const float loc0) override { m_local[0] = loc0; } float getLocalY() const override { return m_local[1]; } - void setLocalY(float loc1) override { m_local[1] = loc1; } + void setLocalY(const float loc1) override { m_local[1] = loc1; } TrkrDefs::subsurfkey getSubSurfKey() const override { return m_subsurfkey; } - void setSubSurfKey(TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } + void setSubSurfKey(const TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } // // cluster info @@ -68,7 +69,7 @@ class TrkrClusterv5 : public TrkrCluster return m_adc; } - void setAdc(unsigned int adc) override + void setAdc(const unsigned int adc) override { m_adc = adc; } @@ -78,7 +79,7 @@ class TrkrClusterv5 : public TrkrCluster return m_maxadc; } - void setMaxAdc(uint16_t maxadc) override + void setMaxAdc(const uint16_t maxadc) override { m_maxadc = maxadc; } @@ -95,11 +96,11 @@ class TrkrClusterv5 : public TrkrCluster return m_zerr; } - void setPhiError(float phierror) + void setPhiError(const float phierror) override { m_phierr = phierror; } - void setZError(float zerror) + void setZError(const float zerror) override { m_zerr = zerror; } @@ -155,16 +156,16 @@ class TrkrClusterv5 : public TrkrCluster // void setSize(char size) { m_size = size; } float getPhiSize() const override { return (float) m_phisize; } - void setPhiSize(char phisize) { m_phisize = phisize; } + void setPhiSize(const char phisize) override { m_phisize = phisize; } float getZSize() const override { return (float) m_zsize; } - void setZSize(char zsize) { m_zsize = zsize; } + void setZSize(const char zsize) override { m_zsize = zsize; } char getOverlap() const override { return m_overlap; } - void setOverlap(char overlap) override { m_overlap = overlap; } + void setOverlap(const char overlap) override { m_overlap = overlap; } char getEdge() const override { return m_edge; } - void setEdge(char edge) override { m_edge = edge; } + void setEdge(const char edge) override { m_edge = edge; } // float getPhiSize() const override //{ std::cout << "Deprecated size function"<< std::endl; return NAN;} diff --git a/offline/packages/trackbase/TrkrClusterv6.cc b/offline/packages/trackbase/TrkrClusterv6.cc new file mode 100644 index 0000000000..e9ade93a08 --- /dev/null +++ b/offline/packages/trackbase/TrkrClusterv6.cc @@ -0,0 +1,100 @@ +/** + * @file trackbase/TrkrClusterv6.cc + * @author Ishan Goel + * @date May 2026 + * @brief Implementation of TrkrClusterv6 + */ +#include "TrkrClusterv6.h" + +#include +#include // for swap + +namespace +{ + // square convenience function + template + constexpr T square(const T& x) + { + return x * x; + } +} // namespace + +void TrkrClusterv6::identify(std::ostream& os) const +{ + os << "---TrkrClusterv6--------------------" << std::endl; + + os << " (rphi,z) = (" << getLocalX(); + os << ", " << getLocalY() << ") cm "; + + os << " valid = " << isValid() << std::endl; + + os << std::endl; + os << "-----------------------------------------------" << std::endl; + + return; +} + +int TrkrClusterv6::isValid() const +{ + for (int i = 0; i < 2; ++i) + { + if (std::isnan(getPosition(i))) + { + return 0; + } + } + if (m_adc == 0xFFFF) + { + return 0; + } + + return 1; +} + +void TrkrClusterv6::CopyFrom(const TrkrCluster& source) +{ + // do nothing if copying onto oneself + if (this == &source) + { + return; + } + + // parent class method + TrkrCluster::CopyFrom(source); + + setLocalX(source.getLocalX()); + setLocalY(source.getLocalY()); + setSubSurfKey(source.getSubSurfKey()); + setAdc(source.getAdc()); + setMaxAdc(source.getMaxAdc()); + setCenAdc(source.getCenAdc()); + setPadCen(source.getPadCen()); + setTBinCen(source.getTBinCen()); + setPadMax(source.getPadMax()); + setTBinMax(source.getTBinMax()); + setPhiError(source.getRPhiError()); + setZError(source.getZError()); + setRSize(source.getRSize()); + setPhiSize(source.getPhiSize()); + setZSize(source.getZSize()); + setOverlap(source.getOverlap()); + setEdge(source.getEdge()); + setSLEdge(source.getSLEdge()); + setSREdge(source.getSREdge()); + setTLEdge(source.getTLEdge()); + setTREdge(source.getTREdge()); + setDLEdge(source.getDLEdge()); + setDREdge(source.getDREdge()); + setHLEdge(source.getHLEdge()); + setHREdge(source.getHREdge()); + setSLMix(source.getSLMix()); + setSRMix(source.getSRMix()); + setTLMix(source.getTLMix()); + setTRMix(source.getTRMix()); + setPhiBinLo(source.getPhiBinLo()); + setPhiBinHi(source.getPhiBinHi()); + setTBinLo(source.getTBinLo()); + setTBinHi(source.getTBinHi()); + setPadPhase(source.getPadPhase()); + setTBinPhase(source.getTBinPhase()); +} diff --git a/offline/packages/trackbase/TrkrClusterv6.h b/offline/packages/trackbase/TrkrClusterv6.h new file mode 100644 index 0000000000..683aeded6e --- /dev/null +++ b/offline/packages/trackbase/TrkrClusterv6.h @@ -0,0 +1,223 @@ +/** + * @file trackbase/TrkrClusterv6.h + * @author Ishan Goel + * @date May 2026 + * @brief Version 6 of TrkrCluster + */ +#ifndef TRACKBASE_TRKRCLUSTERV6_H +#define TRACKBASE_TRKRCLUSTERV6_H + +#include "TrkrCluster.h" +#include "TrkrDefs.h" + +#include +#include + +class PHObject; + +/** + * @brief Version 6 of TrkrCluster + * + * This version of TrkrCluster is blown up to contain a maximum of information + */ + +class TrkrClusterv6 : public TrkrCluster +{ + public: + //! ctor + TrkrClusterv6() = default; + + //! dtor + ~TrkrClusterv6() override = default; + + // PHObject virtual overloads + + void identify(std::ostream& os = std::cout) const override; + void Reset() override { *this = TrkrClusterv6(); } + int isValid() const override; + PHObject* CloneMe() const override { return new TrkrClusterv6(*this); } + + //! import PHObject CopyFrom, in order to avoid clang warning + using PHObject::CopyFrom; + + //! copy content from base class + void CopyFrom(const TrkrCluster&) override; + + //! copy content from base class + void CopyFrom(TrkrCluster* source) override + { + if (!source) + { + return; + } + CopyFrom(*source); + } + + // + // cluster position + // + float getPosition(int coor) const override + { + return (coor >= 0 && coor < 2) ? m_local[coor] : std::numeric_limits::quiet_NaN(); + } + void setPosition(const int coor, const float xi) override + { + if (coor >= 0 && coor < 2) + { + m_local[coor] = xi; + } + } + float getLocalX() const override { return m_local[0]; } + void setLocalX(const float loc0) override { m_local[0] = loc0; } + float getLocalY() const override { return m_local[1]; } + void setLocalY(const float loc1) override { m_local[1] = loc1; } + + TrkrDefs::subsurfkey getSubSurfKey() const override { return m_subsurfkey; } + void setSubSurfKey(const TrkrDefs::subsurfkey id) override { m_subsurfkey = id; } + + // + // cluster info + // + unsigned int getAdc() const override { return m_adc; } + void setAdc(const unsigned int adc) override { m_adc = adc; } + + unsigned int getMaxAdc() const override { return m_maxadc; } + void setMaxAdc(const uint16_t maxadc) override { m_maxadc = maxadc; } + + unsigned int getCenAdc() const override { return m_cenadc; } + void setCenAdc(const uint16_t cenadc) override { m_cenadc = cenadc; } + + float getPadCen() const override { return m_padcen; } + void setPadCen(const float padcen) override { m_padcen = padcen; } + + float getTBinCen() const override { return m_tbincen; } + void setTBinCen(const float tbincen) override { m_tbincen = tbincen; } + + int getPadMax() const override { return m_padmax; } + void setPadMax(const int padmax) override { m_padmax = padmax; } + + int getTBinMax() const override { return m_tbinmax; } + void setTBinMax(const int tbinmax) override { m_tbinmax = tbinmax; } + + // + // convenience interface + // + float getRPhiError() const override { return m_phierr; } + float getZError() const override { return m_zerr; } + + void setPhiError(const float phierror) override { m_phierr = phierror; } + void setZError(const float zerror) override { m_zerr = zerror; } + + char getSize() const override { return m_phisize * m_zsize; } + // void setSize(const char size) { m_size = size; } + + float getRSize() const override { return (float) m_rsize; } + void setRSize(const char rsize) override { m_rsize = rsize; } + + float getPhiSize() const override { return (float) m_phisize; } + void setPhiSize(const char phisize) override { m_phisize = phisize; } + + float getZSize() const override { return (float) m_zsize; } + void setZSize(const char zsize) override { m_zsize = zsize; } + + char getOverlap() const override { return m_overlap; } + void setOverlap(const char overlap) override { m_overlap = overlap; } + + char getEdge() const override { return m_edge; } + void setEdge(const char edge) override { m_edge = edge; } + + char getSLEdge() const override { return m_sledge; } + void setSLEdge(const char sledge) override { m_sledge = sledge; } + + char getSREdge() const override { return m_sredge; } + void setSREdge(const char sredge) override { m_sredge = sredge; } + + char getTLEdge() const override { return m_tledge; } + void setTLEdge(const char tledge) override { m_tledge = tledge; } + + char getTREdge() const override { return m_tredge; } + void setTREdge(const char tredge) override { m_tredge = tredge; } + + char getDLEdge() const override { return m_dledge; } + void setDLEdge(const char dledge) override { m_dledge = dledge; } + + char getDREdge() const override { return m_dredge; } + void setDREdge(const char dredge) override { m_dredge = dredge; } + + char getHLEdge() const override { return m_hledge; } + void setHLEdge(const char hledge) override { m_hledge = hledge; } + + char getHREdge() const override { return m_hredge; } + void setHREdge(const char hredge) override { m_hredge = hredge; } + + char getSLMix() const override { return m_slmix; } + void setSLMix(const char slmix) override { m_slmix = slmix; } + + char getSRMix() const override { return m_srmix; } + void setSRMix(const char srmix) override { m_srmix = srmix; } + + char getTLMix() const override { return m_tlmix; } + void setTLMix(const char tlmix) override { m_tlmix = tlmix; } + + char getTRMix() const override { return m_trmix; } + void setTRMix(const char trmix) override { m_trmix = trmix; } + + unsigned short getPhiBinLo() const override { return m_phibinlo; } + void setPhiBinLo(const unsigned short phibinlo) override { m_phibinlo = phibinlo; } + + unsigned short getPhiBinHi() const override { return m_phibinhi; } + void setPhiBinHi(const unsigned short phibinhi) override { m_phibinhi = phibinhi; } + + unsigned short getTBinLo() const override { return m_tbinlo; } + void setTBinLo(const unsigned short tbinlo) override { m_tbinlo = tbinlo; } + + unsigned short getTBinHi() const override { return m_tbinhi; } + void setTBinHi(const unsigned short tbinhi) override { m_tbinhi = tbinhi; } + + float getPadPhase() const override { return m_padphase; } + void setPadPhase(const float padphase) override { m_padphase = padphase; } + + float getTBinPhase() const override { return m_tbinphase; } + void setTBinPhase(const float tbinphase) override { m_tbinphase = tbinphase; } + + private: + float m_local[2]{std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + //< 2D local position [cm] 2 * 32 64bit - cumul 1*64 + TrkrDefs::subsurfkey m_subsurfkey {TrkrDefs::SUBSURFKEYMAX}; //< unique identifier for hitsetkey-surface maps 16 bit + float m_phierr{std::numeric_limits::quiet_NaN()}; + float m_zerr{std::numeric_limits::quiet_NaN()}; + unsigned short m_adc{std::numeric_limits::max()}; //< cluster sum adc 16 + unsigned short m_maxadc{std::numeric_limits::max()}; //< cluster max adc 16 + unsigned short m_cenadc{std::numeric_limits::max()}; //< cluster centroid adc 16 + float m_padcen{std::numeric_limits::quiet_NaN()}; + float m_tbincen{std::numeric_limits::quiet_NaN()}; + int m_padmax{std::numeric_limits::max()}; + int m_tbinmax{std::numeric_limits::max()}; + char m_rsize{std::numeric_limits::max()}; + char m_phisize{std::numeric_limits::max()}; + char m_zsize{std::numeric_limits::max()}; + char m_overlap{std::numeric_limits::max()}; + char m_edge{std::numeric_limits::max()}; + char m_sledge{std::numeric_limits::max()}; + char m_sredge{std::numeric_limits::max()}; + char m_tledge{std::numeric_limits::max()}; + char m_tredge{std::numeric_limits::max()}; + char m_dledge{std::numeric_limits::max()}; + char m_dredge{std::numeric_limits::max()}; + char m_hledge{std::numeric_limits::max()}; + char m_hredge{std::numeric_limits::max()}; + char m_slmix{std::numeric_limits::max()}; + char m_srmix{std::numeric_limits::max()}; + char m_tlmix{std::numeric_limits::max()}; + char m_trmix{std::numeric_limits::max()}; + unsigned short m_phibinlo{std::numeric_limits::max()}; + unsigned short m_phibinhi{std::numeric_limits::max()}; + unsigned short m_tbinlo{std::numeric_limits::max()}; + unsigned short m_tbinhi{std::numeric_limits::max()}; + float m_padphase{std::numeric_limits::quiet_NaN()}; + float m_tbinphase{std::numeric_limits::quiet_NaN()}; + + ClassDefOverride(TrkrClusterv6, 1) +}; + +#endif // TRACKBASE_TRKRCLUSTERV6_H diff --git a/offline/packages/trackbase/TrkrClusterv6LinkDef.h b/offline/packages/trackbase/TrkrClusterv6LinkDef.h new file mode 100644 index 0000000000..936ec262cc --- /dev/null +++ b/offline/packages/trackbase/TrkrClusterv6LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TrkrClusterv6 + ; + +#endif diff --git a/offline/packages/trackbase/TrkrHit.h b/offline/packages/trackbase/TrkrHit.h index 5a2180e162..079fd929d3 100644 --- a/offline/packages/trackbase/TrkrHit.h +++ b/offline/packages/trackbase/TrkrHit.h @@ -11,9 +11,11 @@ #include +#include #include #include #include +#include /** * @brief Base class for hit object @@ -55,6 +57,13 @@ class TrkrHit : public PHObject // after digitization, these are the adc values virtual void setAdc(const unsigned int) {} virtual unsigned int getAdc() const { return 0; } + + // optional per-hit timing payload used by detectors that need to retain + // the frontend bunch-counter value alongside the digitized hit. + virtual void setFPHXBCO(const uint16_t) {} + virtual uint16_t getFPHXBCO() const { return std::numeric_limits::max(); } + virtual void setBCO(const uint64_t) {} + virtual uint64_t getBCO() const { return 0; } /* virtual void setCrossing(const short int) {} virtual short int getCrossing() { return 0;} diff --git a/offline/packages/trackbase/TrkrHitv3.cc b/offline/packages/trackbase/TrkrHitv3.cc new file mode 100644 index 0000000000..02c4958a5e --- /dev/null +++ b/offline/packages/trackbase/TrkrHitv3.cc @@ -0,0 +1,17 @@ +#include "TrkrHitv3.h" + +void TrkrHitv3::CopyFrom(const TrkrHit& source) +{ + // do nothing if copying onto oneself + if (this == &source) + { + return; + } + + // parent class method + TrkrHitv2::CopyFrom(source); + + // copy timing information + setFPHXBCO(source.getFPHXBCO()); + setBCO(source.getBCO()); +} diff --git a/offline/packages/trackbase/TrkrHitv3.h b/offline/packages/trackbase/TrkrHitv3.h new file mode 100644 index 0000000000..c4d06a0efc --- /dev/null +++ b/offline/packages/trackbase/TrkrHitv3.h @@ -0,0 +1,54 @@ +/** + * @file trackbase/TrkrHitv3.h + * @author Cheng-Wei Shih + * @brief Derived class v3 for hit object with INTT timing information + */ +#ifndef TRACKBASE_TRKRHITV3_H +#define TRACKBASE_TRKRHITV3_H + +#include "TrkrHitv2.h" + +#include +#include + +class TrkrHitv3 : public TrkrHitv2 +{ + public: + //! ctor + explicit TrkrHitv3() = default; + + //! dtor + ~TrkrHitv3() override = default; + + void identify(std::ostream& os = std::cout) const override + { + os << "TrkrHitv3 class with adc = " << m_adc + << " and FPHX_BCO = " << m_fphx_bco + << " and BCO = " << m_bco << std::endl; + } + + //! import PHObject CopyFrom, in order to avoid clang warning + using PHObject::CopyFrom; + + //! copy content from base class + void CopyFrom(const TrkrHit&) override; + + //! copy content from base class + void CopyFrom(TrkrHit* source) override + { + CopyFrom(*source); + } + + void setFPHXBCO(const uint16_t bco) override { m_fphx_bco = bco; } + uint16_t getFPHXBCO() const override { return m_fphx_bco; } + void setBCO(const uint64_t bco) override { m_bco = bco; } + uint64_t getBCO() const override { return m_bco; } + + protected: + uint16_t m_fphx_bco = 0; + uint64_t m_bco = 0; + + ClassDefOverride(TrkrHitv3, 1); +}; + +#endif // TRACKBASE_TRKRHITV3_H diff --git a/offline/packages/trackbase/TrkrHitv3LinkDef.h b/offline/packages/trackbase/TrkrHitv3LinkDef.h new file mode 100644 index 0000000000..11a8703b56 --- /dev/null +++ b/offline/packages/trackbase/TrkrHitv3LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class TrkrHitv3 + ; + +#endif diff --git a/offline/packages/trackbase/alignmentTransformationContainer.h b/offline/packages/trackbase/alignmentTransformationContainer.h index e6eb6c2df8..8711ec5b45 100644 --- a/offline/packages/trackbase/alignmentTransformationContainer.h +++ b/offline/packages/trackbase/alignmentTransformationContainer.h @@ -23,7 +23,7 @@ * * Association object holding transformations associated with given tracker hitset */ -class alignmentTransformationContainer : public Acts::GeometryContext +class alignmentTransformationContainer { public: alignmentTransformationContainer(); diff --git a/offline/packages/trackbase/sPHENIXActsDetectorElement.cc b/offline/packages/trackbase/sPHENIXActsDetectorElement.cc index 3daec79ca2..3751f68a6c 100644 --- a/offline/packages/trackbase/sPHENIXActsDetectorElement.cc +++ b/offline/packages/trackbase/sPHENIXActsDetectorElement.cc @@ -6,7 +6,7 @@ sPHENIXActsDetectorElement::~sPHENIXActsDetectorElement() = default; -const Acts::Transform3& sPHENIXActsDetectorElement::transform(const Acts::GeometryContext& ctxt) const +const Acts::Transform3& sPHENIXActsDetectorElement::localToGlobalTransform(const Acts::GeometryContext& ctxt) const { if (alignmentTransformationContainer::use_alignment) { @@ -23,16 +23,7 @@ const Acts::Transform3& sPHENIXActsDetectorElement::transform(const Acts::Geomet auto& layerVec = transformVec[sphlayer]; // get the vector of transforms for this layer if (layerVec.size() > sensor) - { - /* - if(sphlayer > 7) - { - std::cout << "sPHENIXActsDetectorElement: volume " << volume <<" Acts layer " << layer << " sensor " << sensor - << " sphenix layer " << sphlayer << std::endl; - std::cout << layerVec[sensor].matrix() << std::endl; - } - */ - + { return layerVec[sensor]; } @@ -44,7 +35,7 @@ const Acts::Transform3& sPHENIXActsDetectorElement::transform(const Acts::Geomet else { // return the construction transform - const Acts::Transform3& transform = TGeoDetectorElement::transform(ctxt); // ctxt is unused here + const Acts::Transform3& transform = TGeoDetectorElement::nominalTransform(); // ctxt is unused here return transform; } } diff --git a/offline/packages/trackbase/sPHENIXActsDetectorElement.h b/offline/packages/trackbase/sPHENIXActsDetectorElement.h index 7abf4a511f..98a4813989 100644 --- a/offline/packages/trackbase/sPHENIXActsDetectorElement.h +++ b/offline/packages/trackbase/sPHENIXActsDetectorElement.h @@ -2,8 +2,8 @@ #define TRACKBASE_SPHENIXACTSDETECTORELEMENT_H #include -#include -#include +#include +#include /** * This class implements an sphenix detector element to build @@ -13,9 +13,10 @@ class ActsGeometry; -class sPHENIXActsDetectorElement : public Acts::TGeoDetectorElement +class sPHENIXActsDetectorElement : public ActsPlugins::TGeoDetectorElement { public: + using Identifier = ActsPlugins::TGeoDetectorElement::Identifier; sPHENIXActsDetectorElement() = delete; sPHENIXActsDetectorElement(const Identifier& identifier, @@ -24,7 +25,7 @@ class sPHENIXActsDetectorElement : public Acts::TGeoDetectorElement const std::string& axes = "XYZ", double scalor = 10., std::shared_ptr material = nullptr) - : Acts::TGeoDetectorElement(identifier, tGeoNode, tGeoMatrix, + : ActsPlugins::TGeoDetectorElement(identifier, tGeoNode, tGeoMatrix, axes, scalor, material) { } @@ -34,7 +35,7 @@ class sPHENIXActsDetectorElement : public Acts::TGeoDetectorElement Acts::Transform3& tgTransform, std::shared_ptr tgBounds, double tgThickness = 0.) - : Acts::TGeoDetectorElement(identifier, tGeoNode, tgTransform, + : ActsPlugins::TGeoDetectorElement(identifier, tGeoNode, tgTransform, tgBounds, tgThickness) { } @@ -44,21 +45,21 @@ class sPHENIXActsDetectorElement : public Acts::TGeoDetectorElement Acts::Transform3& tgTransform, std::shared_ptr tgBounds, double tgThickness = 0.) - : Acts::TGeoDetectorElement(identifier, tGeoNode, tgTransform, tgBounds, + : ActsPlugins::TGeoDetectorElement(identifier, tGeoNode, tgTransform, tgBounds, tgThickness) { } ~sPHENIXActsDetectorElement() override; - const Acts::Transform3& transform(const Acts::GeometryContext& ctxt) const override; + const Acts::Transform3& localToGlobalTransform(const Acts::GeometryContext& ctxt) const override; private: std::map base_layer_map = {{10, 0}, {12, 3}, {14, 7}, {16, 55}}; }; std::shared_ptr sPHENIXElementFactory( - const Identifier& identifier, const TGeoNode& tGeoNode, + const sPHENIXActsDetectorElement::Identifier& identifier, const TGeoNode& tGeoNode, const TGeoMatrix& tGeoMatrix, const std::string& axes, double scalor, std::shared_ptr material) { diff --git a/offline/packages/trackbase_historic/ActsTransformations.cc b/offline/packages/trackbase_historic/ActsTransformations.cc index ae76cec640..5bf08082e5 100644 --- a/offline/packages/trackbase_historic/ActsTransformations.cc +++ b/offline/packages/trackbase_historic/ActsTransformations.cc @@ -286,7 +286,7 @@ void ActsTransformations::calculateDCA(const Acts::BoundTrackParameters& param, } void ActsTransformations::fillSvtxTrackStates( - const Acts::ConstVectorMultiTrajectory& traj, + const Acts::VectorMultiTrajectory& traj, const size_t& trackTip, SvtxTrack* svtxTrack, const Acts::GeometryContext& geoContext) const @@ -295,8 +295,7 @@ void ActsTransformations::fillSvtxTrackStates( { /// Only fill the track states with non-outlier measurement - const auto typeFlags = state.typeFlags(); - if( !typeFlags.test(Acts::TrackStateFlag::MeasurementFlag) ) + if (!state.typeFlags().isMeasurement()) { return true; } // only fill for state vectors with proper smoothed parameters diff --git a/offline/packages/trackbase_historic/ActsTransformations.h b/offline/packages/trackbase_historic/ActsTransformations.h index 3cc90b7311..986488b4ea 100644 --- a/offline/packages/trackbase_historic/ActsTransformations.h +++ b/offline/packages/trackbase_historic/ActsTransformations.h @@ -70,7 +70,7 @@ class ActsTransformations //___________________________________________________________________________________________________________ void fillSvtxTrackStates( - const Acts::ConstVectorMultiTrajectory& traj, + const Acts::VectorMultiTrajectory& traj, const size_t& trackTip, SvtxTrack* svtxTrack, const Acts::GeometryContext& geoContext diff --git a/offline/packages/trackbase_historic/Makefile.am b/offline/packages/trackbase_historic/Makefile.am index a27554a914..3f1ed12e2a 100644 --- a/offline/packages/trackbase_historic/Makefile.am +++ b/offline/packages/trackbase_historic/Makefile.am @@ -16,9 +16,9 @@ AM_CPPFLAGS = \ AM_LDFLAGS = \ -L$(libdir) \ - -L$(ROOTSYS)/lib \ -L$(OFFLINE_MAIN)/lib \ - -L$(OFFLINE_MAIN)/lib64 + -L$(OFFLINE_MAIN)/lib64 \ + -L$(ROOTSYS)/lib pkginclude_HEADERS = \ ActsTransformations.h \ @@ -180,11 +180,6 @@ libtrackbase_historic_io_la_SOURCES = \ WeightedTrackZeroField.cc \ WeightedTrackMap.cc -AM_LDFLAGS = \ - -L$(libdir) \ - -L$(OFFLINE_MAIN)/lib \ - -L$(OFFLINE_MAIN)/lib64 - # dependency on libtrack.so breaks the io only library concept libtrackbase_historic_io_la_LIBADD = \ -lphool \ diff --git a/offline/packages/trackbase_historic/SvtxTrackSeed_v2.h b/offline/packages/trackbase_historic/SvtxTrackSeed_v2.h index b699ca25ba..c67322ef73 100644 --- a/offline/packages/trackbase_historic/SvtxTrackSeed_v2.h +++ b/offline/packages/trackbase_historic/SvtxTrackSeed_v2.h @@ -1,13 +1,13 @@ #ifndef TRACKBASEHISTORIC_SVTXTRACKSEED_V2_H #define TRACKBASEHISTORIC_SVTXTRACKSEED_V2_H -#include - #include "TrackSeed.h" -#include +#include + #include #include +#include class SvtxTrackSeed_v2 : public TrackSeed { @@ -33,9 +33,9 @@ class SvtxTrackSeed_v2 : public TrackSeed void set_crossing_estimate(const short int cross) override { m_crossing_estimate = cross; } private: - unsigned int m_silicon_seed = std::numeric_limits::max(); - unsigned int m_tpc_seed = std::numeric_limits::max(); - short int m_crossing_estimate = SHRT_MAX; + unsigned int m_silicon_seed {std::numeric_limits::max()}; + unsigned int m_tpc_seed {std::numeric_limits::max()}; + short int m_crossing_estimate {std::numeric_limits::max()}; ClassDefOverride(SvtxTrackSeed_v2, 1); }; diff --git a/offline/packages/trackbase_historic/SvtxTrackState_v3.h b/offline/packages/trackbase_historic/SvtxTrackState_v3.h index 8f32d0e872..a29bd179ca 100644 --- a/offline/packages/trackbase_historic/SvtxTrackState_v3.h +++ b/offline/packages/trackbase_historic/SvtxTrackState_v3.h @@ -78,7 +78,7 @@ class SvtxTrackState_v3 : public SvtxTrackState float _pos[3]{}; float _mom[3]{}; float _covar[21]{}; // 6x6 triangular packed storage - TrkrDefs::cluskey _ckey{}; // clusterkey that is associated with this state + TrkrDefs::cluskey _ckey{std::numeric_limits::max()}; // clusterkey that is associated with this state std::string state_name; ClassDefOverride(SvtxTrackState_v3, 1) diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc index 744949c8fe..4d9282e1f1 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.cc +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.cc @@ -1,14 +1,19 @@ #include "TrackAnalysisUtils.h" +#include "SvtxTrack.h" +#include "TrackSeed.h" + +#include + #include #include #include #include -#include -#include -#include "SvtxTrack.h" -#include "TrackSeed.h" +#include + +#include +#include #include @@ -18,7 +23,7 @@ namespace TrackAnalysisUtils float calc_dedx(TrackSeed* tpcseed, TrkrClusterContainer* clustermap, ActsGeometry* tgeometry, - float thickness_per_region[4]) + const float thickness_per_region[4]) { std::vector clusterKeys; clusterKeys.insert(clusterKeys.end(), tpcseed->begin_cluster_keys(), @@ -95,10 +100,10 @@ namespace TrackAnalysisUtils float calc_dedx_calib(SvtxTrack* track, TrkrClusterContainer* cluster_map, ActsGeometry* tgeometry, - float thickness_per_region[4]) + const float thickness_per_region[4]) { auto clusterKeys = get_cluster_keys(track->get_tpc_seed()); - + std::vector dedxlist; for (unsigned long cluster_key : clusterKeys) { @@ -137,7 +142,7 @@ namespace TrackAnalysisUtils float adc = cluster->getAdc(); float r = std::sqrt(cglob(0) * cglob(0) + cglob(1) * cglob(1)); - auto tpcseed = track->get_tpc_seed(); + auto* tpcseed = track->get_tpc_seed(); float alpha = (r * r) / (2 * r * std::abs(1.0 / tpcseed->get_qOverR())); float beta = std::atan(tpcseed->get_slope()); float alphacorr = std::cos(alpha); @@ -150,14 +155,14 @@ namespace TrackAnalysisUtils { betacorr = 4; } - if(track->get_crossing() < SHRT_MAX) + if (track->get_crossing() < SHRT_MAX) { - double z_crossing_corrected = - TpcClusterZCrossingCorrection::correctZ(cglob.z(), + double z_crossing_corrected = + TpcClusterZCrossingCorrection::correctZ(cglob.z(), TpcDefs::getSide(cluster_key), track->get_crossing()); - double maxz = tgeometry->get_max_driftlength() + tgeometry->get_CM_halfwidth(); - adc /= (1 - ((maxz - abs(z_crossing_corrected)) * 0.50 / maxz)); + double maxz = tgeometry->get_max_driftlength() + tgeometry->get_CM_halfwidth(); + adc /= (1 - ((maxz - abs(z_crossing_corrected)) * 0.50 / maxz)); } adc /= thickness; adc *= alphacorr; @@ -178,7 +183,7 @@ namespace TrackAnalysisUtils return sumdedx; } - TrackAnalysisUtils::DCAPair get_dca(SvtxTrack *track, + TrackAnalysisUtils::DCAPair get_dca(SvtxTrack* track, GlobalVertex* vertex) { Acts::Vector3 vpos(vertex->get_x(), @@ -201,9 +206,8 @@ namespace TrackAnalysisUtils vertexCov(i, j) = vertex->get_error(i, j); } } - - Acts::ActsSquareMatrix<3> rotCov = rot * (posCov+vertexCov) * rot_T; + Acts::ActsSquareMatrix<3> rotCov = rot * (posCov + vertexCov) * rot_T; dca.first.second = sqrt(rotCov(0, 0)); dca.second.second = sqrt(rotCov(2, 2)); @@ -274,12 +278,12 @@ namespace TrackAnalysisUtils std::vector get_cluster_keys(TrackSeed* seed) { std::vector out; - - if (seed) - { - std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out)); - } - + + if (seed) + { + std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(out)); + } + return out; } @@ -296,4 +300,113 @@ namespace TrackAnalysisUtils return out; } + TrackAnalysisUtils::TrackFitResiduals + get_residuals(SvtxTrack* track, TrkrClusterContainer* clustermap, + PHCompositeNode* topNode) + { + TrackAnalysisUtils::TrackFitResiduals residuals; + TpcGlobalPositionWrapper globalWrapper; + globalWrapper.loadNodes(topNode); + globalWrapper.set_suppressCrossing(true); + + + auto* geometry = findNode::getClass(topNode, "ActsGeometry"); + auto* tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + TpcClusterMover mover; + mover.initialize_geometry(tpccellgeo, geometry); + mover.set_verbosity(0); + + std::vector> global_raw; + + for (const auto& key : get_cluster_keys(track)) + { + auto* clus = clustermap->findCluster(key); + + // Fully correct the cluster positions for the crossing and all distortions + Acts::Vector3 global = globalWrapper.getGlobalPositionDistortionCorrected(key, clus, track->get_crossing()); + // add the global positions to a vector to give to the cluster mover + global_raw.emplace_back(key, global); + } + + auto global_moved = mover.processTrack(global_raw); + + for (const auto& ckey : get_cluster_keys(track)) + { + auto* cluster = clustermap->findCluster(ckey); + // loop over global vectors and get this cluster + Acts::Vector3 clusglob(0, 0, 0); + for (const auto& pair : global_raw) + { + auto thiskey = pair.first; + clusglob = pair.second; + if (thiskey == ckey) + { + break; + } + } + + Acts::Vector3 clusglob_moved(0, 0, 0); + for (const auto& pair : global_moved) + { + auto thiskey = pair.first; + clusglob_moved = pair.second; + if (thiskey == ckey) + { + break; + } + } + SvtxTrackState* state = nullptr; + for (auto state_iter = track->begin_states(); + state_iter != track->end_states(); + ++state_iter) + { + SvtxTrackState* tstate = state_iter->second; + auto stateckey = tstate->get_cluskey(); + if (stateckey == ckey) + { + state = tstate; + break; + } + } + Surface surf = geometry->maps().getSurface(ckey, cluster); + Surface surf_ideal = geometry->maps().getSurface(ckey, cluster); // Unchanged by distortion corrections + // if this is a TPC cluster, the crossing correction may have moved it across the central membrane, check the surface + auto trkrid = TrkrDefs::getTrkrId(ckey); + if (trkrid == TrkrDefs::tpcId) + { + TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(ckey); + TrkrDefs::subsurfkey new_subsurfkey = 0; + surf = geometry->get_tpc_surface_from_coords(hitsetkey, clusglob_moved, new_subsurfkey); + } + + auto loc = geometry->getLocalCoords(ckey, cluster, track->get_crossing()); + // in this case we get local coords from transform of corrected global coords + clusglob_moved *= Acts::UnitConstants::cm; // we want mm for transformations + Acts::Vector3 normal = surf->normal(geometry->geometry().getGeoContext(), + Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); + auto local = surf->globalToLocal(geometry->geometry().getGeoContext(), + clusglob_moved, normal); + if (local.ok()) + { + loc = local.value() / Acts::UnitConstants::cm; + } + else + { + // otherwise take the manual calculation for the TPC + // doing it this way just avoids the bounds check that occurs in the surface class method + Acts::Vector3 loct = surf->localToGlobalTransform(geometry->geometry().getGeoContext()).inverse() * clusglob_moved; // global is in mm + loct /= Acts::UnitConstants::cm; + + loc(0) = loct(0); + loc(1) = loct(1); + } + clusglob_moved /= Acts::UnitConstants::cm; // we want cm for the tree + Acts::Vector2 stateloc(state->get_localX(), state->get_localY()); + Acts::Vector3 stateglob(state->get_x(), state->get_y(), state->get_z()); + residuals.local_residuals[ckey] = stateloc - loc; + residuals.global_residuals[ckey] = stateglob - clusglob_moved; + } + return residuals; + } + } // namespace TrackAnalysisUtils diff --git a/offline/packages/trackbase_historic/TrackAnalysisUtils.h b/offline/packages/trackbase_historic/TrackAnalysisUtils.h index 168ff7495f..fc53a45b2d 100644 --- a/offline/packages/trackbase_historic/TrackAnalysisUtils.h +++ b/offline/packages/trackbase_historic/TrackAnalysisUtils.h @@ -4,6 +4,9 @@ #include #include +#include +#include +#include #include class SvtxTrack; @@ -13,6 +16,13 @@ class TrkrClusterContainer; class GlobalVertex; namespace TrackAnalysisUtils { + + struct TrackFitResiduals + { + std::map local_residuals; + std::map global_residuals; + }; + /// Returns DCA as .first and uncertainty on DCA as .second using DCA = std::pair; using DCAPair = std::pair; @@ -28,9 +38,12 @@ namespace TrackAnalysisUtils // to pass these from the geometry object, which keeps the dependencies // of this helper class minimal. This will also help us catch any changes // when/if the tpc geometry changes in the future. This is to get us going - float thickness_per_region[4]); + const float thickness_per_region[4]); float calc_dedx(TrackSeed* tpcseed, TrkrClusterContainer* clustermap, ActsGeometry* tgeometry, - float thickness_per_region[4]); + const float thickness_per_region[4]); + TrackFitResiduals + get_residuals(SvtxTrack* track, TrkrClusterContainer* clustermap, + PHCompositeNode* topNode); }; // namespace TrackAnalysisUtils diff --git a/offline/packages/trackbase_historic/TrackInfoContainer_v3.h b/offline/packages/trackbase_historic/TrackInfoContainer_v3.h index 41d32c3f4c..d1f31d06a5 100644 --- a/offline/packages/trackbase_historic/TrackInfoContainer_v3.h +++ b/offline/packages/trackbase_historic/TrackInfoContainer_v3.h @@ -1,11 +1,12 @@ #ifndef TRACKINFOCONTAINERV3_H #define TRACKINFOCONTAINERV3_H -#include #include "SvtxTrackInfo.h" #include "SvtxTrackInfo_v3.h" #include "TrackInfoContainer.h" +#include + #include class TrackInfoContainer_v3 : public TrackInfoContainer @@ -38,7 +39,7 @@ class TrackInfoContainer_v3 : public TrackInfoContainer } protected: - TClonesArray *_clones = nullptr; + TClonesArray *_clones {nullptr}; private: ClassDefOverride(TrackInfoContainer_v3, 1); diff --git a/offline/packages/trackbase_historic/TrackSeed.h b/offline/packages/trackbase_historic/TrackSeed.h index 3d99703500..371bf557ab 100644 --- a/offline/packages/trackbase_historic/TrackSeed.h +++ b/offline/packages/trackbase_historic/TrackSeed.h @@ -49,8 +49,8 @@ class TrackSeed : public PHObject virtual float get_py() const { return NAN; } virtual short int get_crossing() const { return 0; } - virtual unsigned int get_silicon_seed_index() const { return 0; } - virtual unsigned int get_tpc_seed_index() const { return 0; } + virtual unsigned int get_silicon_seed_index() const { return std::numeric_limits::max(); } + virtual unsigned int get_tpc_seed_index() const { return std::numeric_limits::max(); } virtual short int get_crossing_estimate() const { return 0; } virtual bool empty_cluster_keys() const { return true; } diff --git a/offline/packages/trackbase_historic/TrackSeedHelper.cc b/offline/packages/trackbase_historic/TrackSeedHelper.cc index 99a9198811..0fba4fb80a 100644 --- a/offline/packages/trackbase_historic/TrackSeedHelper.cc +++ b/offline/packages/trackbase_historic/TrackSeedHelper.cc @@ -142,8 +142,8 @@ void TrackSeedHelper::circleFitByTaubin( float qOverR = 1./r; /// Set the charge - const auto& firstpos = positions_2d.at(0); - const auto& secondpos = positions_2d.at(1); + const auto& firstpos = *(positions_2d.begin()); + const auto& secondpos = *(positions_2d.rbegin()); const auto firstphi = atan2(firstpos.second, firstpos.first); const auto secondphi = atan2(secondpos.second, secondpos.first); diff --git a/offline/packages/trackreco/ALICEKF.h b/offline/packages/trackreco/ALICEKF.h index 570b0d7777..86fdfa9ac7 100644 --- a/offline/packages/trackreco/ALICEKF.h +++ b/offline/packages/trackreco/ALICEKF.h @@ -1,13 +1,15 @@ #ifndef ALICEKF_H #define ALICEKF_H +#include "GPUTPCTrackParam.h" + #include + #include #include #include #include #include -#include "GPUTPCTrackParam.h" #include diff --git a/offline/packages/trackreco/ActsAlignmentStates.cc b/offline/packages/trackreco/ActsAlignmentStates.cc index d99fc1c178..070f78e53f 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.cc +++ b/offline/packages/trackreco/ActsAlignmentStates.cc @@ -56,7 +56,7 @@ void ActsAlignmentStates::loadNodes( PHCompositeNode* topNode ) //_________________________________________________________________ void ActsAlignmentStates::fillAlignmentStateMap( const ActsTrackFittingAlgorithm::TrackContainer& tracks, - const std::vector& tips, + const std::vector& tips, SvtxTrack* track, const ActsTrackFittingAlgorithm::MeasurementContainer& measurements) { @@ -117,7 +117,7 @@ void ActsAlignmentStates::fillAlignmentStateMap( { /// Collect only track states which were used in smoothing of KF and are measurements if (! state.hasSmoothed() || - ! state.typeFlags().test(Acts::TrackStateFlag::MeasurementFlag)) + ! state.typeFlags().isMeasurement()) { return true; } @@ -127,10 +127,9 @@ void ActsAlignmentStates::fillAlignmentStateMap( auto ckey = sl.cluskey(); Acts::Vector2 localMeas = Acts::Vector2::Zero(); /// get the local measurement that acts used - std::visit([&](const auto& meas) { - localMeas(0) = meas.parameters()[0]; - localMeas(1) = meas.parameters()[1]; - }, measurements[sl.index()]); + const auto measurement = measurements.getMeasurement(sl.index()); + localMeas(0) = measurement.parameters()[0]; + localMeas(1) = measurement.parameters()[1]; if (m_verbosity > 2) { @@ -142,7 +141,9 @@ void ActsAlignmentStates::fillAlignmentStateMap( auto clus = m_clusterMap->findCluster(ckey); // local state vector - const Acts::Vector2 localState = state.effectiveProjector() * state.smoothed(); + const auto H = state.projectorSubspaceHelper().fullProjector().topLeftCorner( + state.calibratedSize(), Acts::eBoundSize); + const Acts::Vector2 localState = H * state.smoothed(); // Local residual between measurement and smoothed Acts state const Acts::Vector2 localResidual = localMeas - localState; @@ -205,8 +206,8 @@ void ActsAlignmentStates::fillAlignmentStateMap( //! this is the derivative of the state wrt to Acts track parameters //! e.g. (d_0, z_0, phi, theta, q/p, t) - auto localDeriv = state.effectiveProjector() * state.jacobian(); - if(m_verbosity > 2) + auto localDeriv = H * state.jacobian(); + if (m_verbosity > 2) { std::cout << "local deriv " << std::endl << localDeriv << std::endl; } @@ -275,10 +276,10 @@ std::pair ActsAlignmentStates::get_projectionXY(co // get surface X and Y unit vectors in global frame // transform Xlocal = 1.0 to global, subtract the surface center, normalize to 1 Acts::Vector3 xloc(1.0, 0.0, 0.0); - Acts::Vector3 xglob = surface.transform(m_tGeometry->geometry().getGeoContext()) * xloc; + Acts::Vector3 xglob = surface.localToGlobalTransform(m_tGeometry->geometry().getGeoContext()) * xloc; Acts::Vector3 yloc(0.0, 1.0, 0.0); - Acts::Vector3 yglob = surface.transform(m_tGeometry->geometry().getGeoContext()) * yloc; + Acts::Vector3 yglob = surface.localToGlobalTransform(m_tGeometry->geometry().getGeoContext()) * yloc; Acts::Vector3 X = (xglob - sensorCenter) / (xglob - sensorCenter).norm(); Acts::Vector3 Y = (yglob - sensorCenter) / (yglob - sensorCenter).norm(); diff --git a/offline/packages/trackreco/ActsAlignmentStates.h b/offline/packages/trackreco/ActsAlignmentStates.h index caeae77a00..9d891c906d 100644 --- a/offline/packages/trackreco/ActsAlignmentStates.h +++ b/offline/packages/trackreco/ActsAlignmentStates.h @@ -33,7 +33,7 @@ class ActsAlignmentStates explicit ActsAlignmentStates() = default; void fillAlignmentStateMap(const ActsTrackFittingAlgorithm::TrackContainer& tracks, - const std::vector& tips, + const std::vector& tips, SvtxTrack* track, const ActsTrackFittingAlgorithm::MeasurementContainer& measurements); diff --git a/offline/packages/trackreco/ActsEvaluator.cc b/offline/packages/trackreco/ActsEvaluator.cc index 9ecdbf2b7a..9edb4a441a 100644 --- a/offline/packages/trackreco/ActsEvaluator.cc +++ b/offline/packages/trackreco/ActsEvaluator.cc @@ -83,7 +83,7 @@ void ActsEvaluator::next_event(PHCompositeNode* topNode) } void ActsEvaluator::process_track(const ActsTrackFittingAlgorithm::TrackContainer& tracks, - std::vector& trackTips, + std::vector& trackTips, Trajectory::IndexedParameters& paramsMap, SvtxTrack* track, const TrackSeed* seed, @@ -105,7 +105,7 @@ void ActsEvaluator::process_track(const ActsTrackFittingAlgorithm::TrackContaine } void ActsEvaluator::evaluateTrackFit(const ActsTrackFittingAlgorithm::TrackContainer& tracks, - std::vector& trackTips, + std::vector& trackTips, Trajectory::IndexedParameters& paramsMap, SvtxTrack* track, const TrackSeed* seed, @@ -238,7 +238,7 @@ void ActsEvaluator::End() m_trackFile->Close(); } -void ActsEvaluator::visitTrackStates(const Acts::ConstVectorMultiTrajectory& traj, +void ActsEvaluator::visitTrackStates(const Acts::VectorMultiTrajectory& traj, const size_t& trackTip, const ActsTrackFittingAlgorithm::MeasurementContainer& measurements) { @@ -251,7 +251,7 @@ void ActsEvaluator::visitTrackStates(const Acts::ConstVectorMultiTrajectory& tra { /// Only fill the track states with non-outlier measurement auto typeFlags = state.typeFlags(); - if (! typeFlags.test(Acts::TrackStateFlag::MeasurementFlag)) + if (! typeFlags.isMeasurement()) { return true; } @@ -276,10 +276,9 @@ void ActsEvaluator::visitTrackStates(const Acts::ConstVectorMultiTrajectory& tra Acts::Vector2 local = Acts::Vector2::Zero(); /// get the local measurement that acts used - std::visit([&](const auto& meas) { - local(0) = meas.parameters()[0]; - local(1) = meas.parameters()[1]; - }, measurements[sourceLink.index()]); + const auto measurement = measurements.getMeasurement(sourceLink.index()); + local(0) = measurement.parameters()[0]; + local(1) = measurement.parameters()[1]; /// Get global position /// This is an arbitrary vector. Doesn't matter in coordinate transformation @@ -396,7 +395,8 @@ void ActsEvaluator::visitTrackStates(const Acts::ConstVectorMultiTrajectory& tra auto covariance = state.predictedCovariance(); /// Local hit residual info - auto H = state.effectiveProjector(); + const auto H = state.projectorSubspaceHelper().fullProjector().topLeftCorner( + state.calibratedSize(), Acts::eBoundSize); auto resCov = cov + H * covariance * H.transpose(); auto residual = state.effectiveCalibrated() - H * parameters; m_res_x_hit.push_back(residual(Acts::eBoundLoc0)); @@ -907,7 +907,7 @@ void ActsEvaluator::fillProtoTrack(const TrackSeed* seed) } else { - Acts::Vector3 loct = (*surf).transform(m_tGeometry->geometry().getGeoContext()).inverse() * globalTruthPos; + Acts::Vector3 loct = (*surf).localToGlobalTransform(m_tGeometry->geometry().getGeoContext()).inverse() * globalTruthPos; m_t_SL_lx.push_back(loct(0)); m_t_SL_ly.push_back(loct(1)); diff --git a/offline/packages/trackreco/ActsEvaluator.h b/offline/packages/trackreco/ActsEvaluator.h index fda1e1ebb8..fae0515049 100644 --- a/offline/packages/trackreco/ActsEvaluator.h +++ b/offline/packages/trackreco/ActsEvaluator.h @@ -9,7 +9,7 @@ #include #include - +#include #include class TTree; @@ -31,7 +31,6 @@ class TrackSeedContainer; using SourceLink = ActsSourceLink; using Trajectory = ActsExamples::Trajectories; -using Measurement = Acts::Measurement; using Acts::VectorHelpers::eta; using Acts::VectorHelpers::perp; using Acts::VectorHelpers::phi; @@ -52,7 +51,7 @@ class ActsEvaluator void Init(PHCompositeNode* topNode); void process_track(const ActsTrackFittingAlgorithm::TrackContainer& tracks, - std::vector& trackTips, + std::vector& trackTips, Trajectory::IndexedParameters& paramsMap, SvtxTrack* track, const TrackSeed* seed, @@ -65,7 +64,7 @@ class ActsEvaluator /// Function to evaluate Trajectories fit results from the KF void evaluateTrackFit(const ActsTrackFittingAlgorithm::TrackContainer& trackContainer, - std::vector& trackTips, + std::vector& trackTips, Trajectory::IndexedParameters& paramsMap, SvtxTrack* track, const TrackSeed* seed, @@ -83,7 +82,7 @@ class ActsEvaluator void fillFittedTrackParams(const Trajectory::IndexedParameters& paramsMap, const size_t& trackTip); - void visitTrackStates(const Acts::ConstVectorMultiTrajectory& traj, + void visitTrackStates(const Acts::VectorMultiTrajectory& traj, const size_t& trackTip, const ActsTrackFittingAlgorithm::MeasurementContainer& measurements); diff --git a/offline/packages/trackreco/ActsPropagator.cc b/offline/packages/trackreco/ActsPropagator.cc index 8cd4942ea4..27952c6e96 100644 --- a/offline/packages/trackreco/ActsPropagator.cc +++ b/offline/packages/trackreco/ActsPropagator.cc @@ -1,7 +1,5 @@ #include "ActsPropagator.h" -#include - #include #include #include @@ -10,13 +8,51 @@ #include #include -#include + #include #include #include #include +#include #include +#include + +/// local aborter class, used to tell acts to end track propagation when a given layer is used +/** for the time being, the class is defined locally only, because it has no usage outside of ActsPropagator */ +struct ActsAborter +{ + + /// (ACTS) layer id at which propagation should stop + unsigned int abortlayer = std::numeric_limits::max(); + + /// (ACTS) voulme id at which propagation should stop + unsigned int abortvolume = std::numeric_limits::max(); + + /// called at each extrapolation step, by acts, to verify whether to stop propagation or not + template + bool checkAbort( + propagator_state_t& state, const stepper_t& /*stepper*/, + const navigator_t& navigator, const Acts::Logger& /*logger*/) const + { + + if (!navigator.currentSurface(state.navigation)) + { return false; } + const auto& volumeno = state.navigation.currentSurface->geometryId().volume(); + const auto& layerno = state.navigation.currentSurface->geometryId().layer(); + const auto& sensitive = state.navigation.currentSurface->geometryId().sensitive(); + + /// Check that we are in the proper layer and that we've also reached + /// a sensitive surface + if (layerno == abortlayer and volumeno == abortvolume and sensitive != 0) + { return true; } + + return false; + } + +}; + +//____________________________________________________________________ ActsPropagator::SurfacePtr ActsPropagator::makeVertexSurface(const SvtxVertex* vertex) { @@ -25,12 +61,16 @@ ActsPropagator::makeVertexSurface(const SvtxVertex* vertex) vertex->get_y() * Acts::UnitConstants::cm, vertex->get_z() * Acts::UnitConstants::cm)); } + +//____________________________________________________________________ ActsPropagator::SurfacePtr ActsPropagator::makeVertexSurface(const Acts::Vector3& vertex) { return Acts::Surface::makeShared( vertex * Acts::UnitConstants::cm); } + +//____________________________________________________________________ ActsPropagator::BoundTrackParamResult ActsPropagator::makeTrackParams(SvtxTrackState* state, int trackCharge, @@ -48,13 +88,15 @@ ActsPropagator::makeTrackParams(SvtxTrackState* state, Acts::BoundSquareMatrix cov = transformer.rotateSvtxTrackCovToActs(state); return ActsTrackFittingAlgorithm::TrackParameters::create( - surf, - m_geometry->geometry().getGeoContext(), - actsFourPos, momentum, - trackCharge / momentum.norm(), - cov, - Acts::ParticleHypothesis::pion()); + m_geometry->geometry().getGeoContext(), + surf, // NOLINT (performance-unnecessary-value-param) + actsFourPos, momentum, + trackCharge / momentum.norm(), + cov, + Acts::ParticleHypothesis::pion()); } + +//____________________________________________________________________ ActsPropagator::BoundTrackParamResult ActsPropagator::makeTrackParams(SvtxTrack* track, SvtxVertexMap* vertexMap) @@ -85,24 +127,24 @@ ActsPropagator::makeTrackParams(SvtxTrack* track, Acts::BoundSquareMatrix cov = transformer.rotateSvtxTrackCovToActs(track); - return ActsTrackFittingAlgorithm::TrackParameters::create(perigee, - m_geometry->geometry().getGeoContext(), - actsFourPos, momentum, - track->get_charge() / track->get_p(), - cov, - Acts::ParticleHypothesis::pion(), - 1*Acts::UnitConstants::cm); + return ActsTrackFittingAlgorithm::TrackParameters::create( + m_geometry->geometry().getGeoContext(), perigee, + actsFourPos, momentum, + track->get_charge() / track->get_p(), + cov, + Acts::ParticleHypothesis::pion(), + 1 * Acts::UnitConstants::cm); } +//____________________________________________________________________ ActsPropagator::BTPPairResult ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, const unsigned int sphenixLayer) { - unsigned int actsvolume, actslayer; + unsigned int actsvolume = 0; + unsigned int actslayer = 0; if (!checkLayer(sphenixLayer, actsvolume, actslayer) || !m_geometry) - { - return Acts::Result::failure(std::error_code(0, std::generic_category())); - } + { return Acts::Result::failure(std::make_error_code(std::errc::invalid_argument)); } if (m_verbosity > 1) { @@ -111,21 +153,23 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - using Actors = Acts::ActionList<>; - using Aborters = Acts::AbortList; + // create propagator options with proper aborter + using actor_list_t = Acts::ActorList; + using propagator_options_t = SphenixPropagator::Options; - Acts::PropagatorOptions options( - m_geometry->geometry().getGeoContext(), - m_geometry->geometry().magFieldContext); + propagator_options_t options( + m_geometry->geometry().getGeoContext(), + m_geometry->geometry().magFieldContext); - options.abortList.get().abortlayer = actslayer; - options.abortList.get().abortvolume = actsvolume; + // initialize aborter + options.actorList.get().abortlayer = actslayer; + options.actorList.get().abortvolume = actsvolume; auto result = propagator.propagate(params, options); if (result.ok()) { - auto finalparams = *result.value().endParameters; + auto finalparams = *result.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) auto pathlength = result.value().pathLength; auto pair = std::make_pair(pathlength, finalparams); @@ -135,9 +179,9 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, return result.error(); } +//____________________________________________________________________ ActsPropagator::BTPPairResult -ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, - const SurfacePtr& surface) +ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, const SurfacePtr& surface) { if (m_verbosity > 1) { @@ -146,15 +190,14 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, auto propagator = makePropagator(); - Acts::PropagatorOptions<> options(m_geometry->geometry().getGeoContext(), - m_geometry->geometry().magFieldContext); - - auto result = propagator.propagate(params, *surface, - options); + SphenixPropagator::Options options(m_geometry->geometry().getGeoContext(), m_geometry->geometry().magFieldContext); + auto intersect = surface.get()->intersect(m_geometry->geometry().getGeoContext(), params.position(m_geometry->geometry().getGeoContext()), params.momentum(), Acts::BoundaryTolerance::None(), 0.1 * Acts::UnitConstants::mm).closest(); + options.direction = Acts::Direction::fromScalarZeroAsPositive(intersect.pathLength()); + auto result = propagator.template propagate, Acts::ForcedSurfaceReached, Acts::PathLimitReached>(params, *surface, options); if (result.ok()) { - auto finalparams = *result.value().endParameters; + auto finalparams = *result.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) auto pathlength = result.value().pathLength; auto pair = std::make_pair(pathlength, finalparams); @@ -164,6 +207,7 @@ ActsPropagator::propagateTrack(const Acts::BoundTrackParameters& params, return result.error(); } +//____________________________________________________________________ ActsPropagator::BTPPairResult ActsPropagator::propagateTrackFast(const Acts::BoundTrackParameters& params, const SurfacePtr& surface) @@ -174,18 +218,17 @@ ActsPropagator::propagateTrackFast(const Acts::BoundTrackParameters& params, } auto propagator = makeFastPropagator(); + using Propagator = Acts::Propagator; + Propagator::Options> options(m_geometry->geometry().getGeoContext(), + m_geometry->geometry().magFieldContext); - Acts::PropagatorOptions<> options(m_geometry->geometry().getGeoContext(), - m_geometry->geometry().magFieldContext); - - auto result = propagator.propagate(params, *surface, - options); + auto result = propagator.propagate(params, *surface, options); if (result.ok()) { - auto finalparams = *result.value().endParameters; - auto pathlength = result.value().pathLength; - auto pair = std::make_pair(pathlength, finalparams); + const auto finalparams = *result.value().endParameters; // NOLINT(bugprone-unchecked-optional-access) + const auto pathlength = result.value().pathLength; + const auto pair = std::make_pair(pathlength, finalparams); return Acts::Result::success(pair); } @@ -193,6 +236,7 @@ ActsPropagator::propagateTrackFast(const Acts::BoundTrackParameters& params, return result.error(); } +//____________________________________________________________________ ActsPropagator::FastPropagator ActsPropagator::makeFastPropagator() { auto field = m_geometry->geometry().magField; @@ -203,23 +247,22 @@ ActsPropagator::FastPropagator ActsPropagator::makeFastPropagator() { std::cout << "Using const field of val " << m_fieldval << std::endl; } - Acts::Vector3 fieldVec(0, 0, m_fieldval); + const Acts::Vector3 fieldVec(0, 0, m_fieldval); field = std::make_shared(fieldVec); } + // create stepper with proper magnetic field ActsPropagator::Stepper stepper(field); - Acts::Logging::Level logLevel = Acts::Logging::FATAL; - if (m_verbosity > 3) - { - logLevel = Acts::Logging::VERBOSE; - } - + // create logger + const Acts::Logging::Level logLevel = (m_verbosity > 3) ? Acts::Logging::VERBOSE : Acts::Logging::FATAL; std::shared_ptr logger = Acts::getDefaultLogger("ActsPropagator", logLevel); - return ActsPropagator::FastPropagator(stepper, Acts::VoidNavigator(), - logger); + // create propagator and return + return ActsPropagator::FastPropagator(stepper, Acts::VoidNavigator(), logger); } + +//____________________________________________________________________ ActsPropagator::SphenixPropagator ActsPropagator::makePropagator() { auto field = m_geometry->geometry().magField; @@ -230,24 +273,27 @@ ActsPropagator::SphenixPropagator ActsPropagator::makePropagator() field = std::make_shared(fieldVec); } - auto trackingGeometry = m_geometry->geometry().tGeometry; - Stepper stepper(field, m_overstepLimit); + + Stepper stepper(field); + + // create mavigation logger + const Acts::Logging::Level logLevel = (m_verbosity > 3) ? Acts::Logging::VERBOSE:Acts::Logging::FATAL; + std::shared_ptr navlogger = Acts::getDefaultLogger("ActsPropagator::NAVIGATION", logLevel); + + // create navigator + const auto trackingGeometry = m_geometry->geometry().tGeometry; Acts::Navigator::Config cfg{trackingGeometry}; cfg.resolvePassive = false; cfg.resolveMaterial = true; cfg.resolveSensitive = true; - Acts::Navigator navigator(cfg); - - Acts::Logging::Level logLevel = Acts::Logging::FATAL; - if (m_verbosity > 3) - { - logLevel = Acts::Logging::VERBOSE; - } + Acts::Navigator navigator(cfg, navlogger); + // create propagator with proper logger and return std::shared_ptr logger = Acts::getDefaultLogger("ActsPropagator", logLevel); return SphenixPropagator(stepper, navigator, logger); } +//____________________________________________________________________ bool ActsPropagator::checkLayer(const unsigned int& sphenixlayer, unsigned int& actsvolume, unsigned int& actslayer) @@ -318,6 +364,7 @@ bool ActsPropagator::checkLayer(const unsigned int& sphenixlayer, return true; } +//____________________________________________________________________ void ActsPropagator::printTrackParams(const Acts::BoundTrackParameters& params) { std::cout << "Propagating final track fit with momentum: " diff --git a/offline/packages/trackreco/ActsPropagator.h b/offline/packages/trackreco/ActsPropagator.h index 95a4655f81..8356a748c5 100644 --- a/offline/packages/trackreco/ActsPropagator.h +++ b/offline/packages/trackreco/ActsPropagator.h @@ -31,11 +31,11 @@ class ActsPropagator public: using BoundTrackParam = Acts::BoundTrackParameters; using BoundTrackParamResult = Acts::Result; - /// Return type of std::pair using BoundTrackParamPair = std::pair; using BTPPairResult = Acts::Result; using SurfacePtr = std::shared_ptr; using Stepper = Acts::EigenStepper<>; + using FastPropagator = Acts::Propagator; using SphenixPropagator = Acts::Propagator; @@ -50,9 +50,9 @@ class ActsPropagator /// functions below SurfacePtr makeVertexSurface(const SvtxVertex* vertex); SurfacePtr makeVertexSurface(const Acts::Vector3& vertex); - BoundTrackParamResult makeTrackParams(SvtxTrack* track, + BoundTrackParamResult makeTrackParams(SvtxTrack* track, SvtxVertexMap* vertexMap); - BoundTrackParamResult makeTrackParams(SvtxTrackState* state, + BoundTrackParamResult makeTrackParams(SvtxTrackState* state, int trackCharge, SurfacePtr surf); diff --git a/offline/packages/trackreco/DSTClusterPruning.cc b/offline/packages/trackreco/DSTClusterPruning.cc index 15bfe547ca..890e465b96 100644 --- a/offline/packages/trackreco/DSTClusterPruning.cc +++ b/offline/packages/trackreco/DSTClusterPruning.cc @@ -177,6 +177,42 @@ void DSTClusterPruning::prune_clusters() } return; } + if(m_pruneAllSeeds) + { + for(const auto& container : {m_tpc_track_seed_container, m_silicon_track_seed_container}) + { + for (const auto& trackseed : *container) + { + if (!trackseed) + { + if(Verbosity() > 1) + { + std::cout << "No TrackSeed" << std::endl; + } + continue; + } + + for (auto key_iter = trackseed->begin_cluster_keys(); key_iter != trackseed->end_cluster_keys(); ++key_iter) + { + const auto& cluster_key = *key_iter; + auto *cluster = m_cluster_map->findCluster(cluster_key); + if (!cluster) + { + std::cout << "DSTClusterPruning::evaluate_tracks - unable to find cluster for key " << cluster_key << std::endl; + continue; + } + if (!m_reduced_cluster_map->findCluster(cluster_key)) + { + m_cluster = new TrkrClusterv5(); + m_cluster->CopyFrom(cluster); + m_reduced_cluster_map->addClusterSpecifyKey(cluster_key, m_cluster); + } + } + } + } + return; + } + for (const auto& trackseed : *m_track_seed_container) { if (!trackseed) diff --git a/offline/packages/trackreco/DSTClusterPruning.h b/offline/packages/trackreco/DSTClusterPruning.h index c9ec35ea53..5fa2ff9b4f 100644 --- a/offline/packages/trackreco/DSTClusterPruning.h +++ b/offline/packages/trackreco/DSTClusterPruning.h @@ -52,6 +52,12 @@ class DSTClusterPruning : public SubsysReco //! end of processing //int End(PHCompositeNode*) override; + //! dump all clusters on all seeds out + void pruneAllSeeds() + { + m_pruneAllSeeds = true; + } + private: //! load nodes int load_nodes(PHCompositeNode*); @@ -68,6 +74,9 @@ class DSTClusterPruning : public SubsysReco TrackSeedContainer* m_tpc_track_seed_container = nullptr; TrackSeedContainer* m_silicon_track_seed_container = nullptr; +//! set to true if you want to dump out all clusters on all silicon +//! and all tpc seeds individually + bool m_pruneAllSeeds = false; //@} // debugging helpers diff --git a/offline/packages/trackreco/MakeActsGeometry.cc b/offline/packages/trackreco/MakeActsGeometry.cc index 07f3dbe71c..bfd8352a10 100644 --- a/offline/packages/trackreco/MakeActsGeometry.cc +++ b/offline/packages/trackreco/MakeActsGeometry.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -59,24 +60,25 @@ #include #include #include +#include #include #include +#include +#include + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wuninitialized" #include #pragma GCC diagnostic pop -#include #include #include #include -#include -#include #include #include @@ -89,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -173,17 +176,54 @@ int MakeActsGeometry::Init(PHCompositeNode * /*topNode*/) int MakeActsGeometry::InitRun(PHCompositeNode *topNode) { - m_geomContainerTpc = - findNode::getClass(topNode, "TPCGEOMCONTAINER"); + m_geomContainerTpc = findNode::getClass(topNode, "TPCGEOMCONTAINER"); PHG4TpcGeom *layergeom = m_geomContainerTpc->GetLayerCellGeom(20); // z geometry is the same for all layers m_max_driftlength = layergeom->get_max_driftlength(); m_CM_halfwidth = layergeom->get_CM_halfwidth(); - m_maxSurfZ = m_max_driftlength - 0.0001; // add clearance from physical TPC gas volume length to avoid overlaps - + + // Make the transform from TPC envelope to global coordinates + // This transform is built using the tilt and placement variables from layergeom + + double rot_x = layergeom->get_rot_x(); + double rot_y = layergeom->get_rot_y(); + double rot_z = layergeom->get_rot_z(); + double place_x = layergeom->get_place_x(); + double place_y = layergeom->get_place_y(); + double place_z = layergeom->get_place_z(); + Eigen::Vector3d rot(rot_x, rot_y, rot_z); + Eigen::Vector3d trans(place_x, place_y, place_z); + + Eigen::AngleAxisd alpha(rot(0), Eigen::Vector3d::UnitX()); + Eigen::AngleAxisd beta(rot(1), Eigen::Vector3d::UnitY()); + Eigen::AngleAxisd gamma(rot(2), Eigen::Vector3d::UnitZ()); + Eigen::Quaternion q = gamma * beta * alpha; + m_tpc_envelope_world_transform.linear() = q.matrix(); + m_tpc_envelope_world_transform.translation() = trans; + // and the inverse + m_tpc_world_envelope_transform = m_tpc_envelope_world_transform.inverse(); + + // test + Acts::Vector3 test_env(0.0, 0.0, 113.025); + std::cout << "MakeActsGeometry::InitRun transform tests north" << std::endl; + std::cout << " test envelope position (mm) " << test_env.x()*10 << " " << test_env.y()*10 << " " << test_env.z()*10 << std::endl; + Acts::Vector3 test_glob = m_tpc_envelope_world_transform * test_env; + std::cout << " test global position (mm) " << test_glob.x()*10 << " " << test_glob.y()*10 << " " << test_glob.z()*10 << std::endl; + Acts::Vector3 test_env_check = m_tpc_world_envelope_transform * test_glob; + std::cout << " test inverse transform (mm) " << test_env_check.x()*10 << " " << test_env_check.y()*10 << " " << test_env_check.z()*10 << std::endl; + + Acts::Vector3 test_envs(0.0, 0.0, -113.025); + std::cout << "MakeActsGeometry::InitRun transform tests south" << std::endl; + std::cout << " test envelope position (mm) " << test_envs.x()*10 << " " << test_envs.y()*10 << " " << test_envs.z()*10 << std::endl; + Acts::Vector3 test_globs = m_tpc_envelope_world_transform * test_envs; + std::cout << " test global position (mm) " << test_globs.x()*10 << " " << test_globs.y()*10 << " " << test_globs.z()*10 << std::endl; + Acts::Vector3 test_env_checks = m_tpc_world_envelope_transform * test_globs; + std::cout << " test inverse transform (mm) " << test_env_checks.x()*10 << " " << test_env_checks.y()*10 << " " << test_env_checks.z()*10 << std::endl; + // Alignment Transformation declaration of instance - must be here to set initial alignment flag AlignmentTransformation alignment_transformation; + alignment_transformation.setAlignmentParamsFile(m_alignmentParamsFile); alignment_transformation.createAlignmentTransformContainer(topNode); // set parameter for sampling probability distribution @@ -206,8 +246,8 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) alignment_transformation.setUseNewSiliconRotationOrder(m_use_new_silicon_rotation_order); alignment_transformation.setUseModuleTiltAlways(m_use_module_tilt_always); - - + + if (buildAllGeometry(topNode) != Fun4AllReturnCodes::EVENT_OK) { return Fun4AllReturnCodes::ABORTEVENT; @@ -283,6 +323,12 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) } } + // fill Si volume ids + for (const auto &[hitsetid, surface] : m_clusterSurfaceMapSilicon) + { + surfMaps.m_siVolumeIds.insert(surface->geometryId().volume()); + } + // fill Micromegas volume ids for (const auto &[hitsetid, surface] : m_clusterSurfaceMapMmEdit) { @@ -296,20 +342,20 @@ int MakeActsGeometry::InitRun(PHCompositeNode *topNode) m_actsGeometry->set_CM_halfwidth(m_CM_halfwidth); m_actsGeometry->set_tpc_tzero(m_tpc_tzero); m_actsGeometry->set_sampa_tzero_bias(m_sampa_tzero_bias); + m_actsGeometry->set_tpc_world_envelope_transform(m_tpc_world_envelope_transform); // transform world position to TPC envelope position // alignment_transformation.useInttSurveyGeometry(m_inttSurvey); + if (Verbosity() > 1) { alignment_transformation.verbosity(); } alignment_transformation.createMap(topNode); - for (auto &[layer, factor] : m_misalignmentFactor) { alignment_transformation.misalignmentFactor(layer, factor); } - // print - if (Verbosity()) + if (Verbosity() > 3) { for (const auto &id : surfMaps.m_tpcVolumeIds) { @@ -468,7 +514,7 @@ void MakeActsGeometry::editTPCGeometry(PHCompositeNode *topNode) return; } - if (Verbosity() > 3) + if (Verbosity() > 0) { std::cout << "EditTPCGeometry - gas volume: "; tpc_gas_north_vol->Print(); @@ -514,7 +560,7 @@ void MakeActsGeometry::addActsTpcSurfaces(TGeoVolume *tpc_gas_vol, tpc_gas_measurement_vol[ilayer]->SetFillColor(kYellow); tpc_gas_measurement_vol[ilayer]->SetVisibility(kTRUE); - if (Verbosity() > 3) + if (Verbosity() > 0) { std::cout << " Made box for layer " << ilayer << " with dx " << m_layerThickness[ilayer] << " dy " @@ -601,11 +647,18 @@ void MakeActsGeometry::buildActsSurfaces() std::vector argstr = { "-n1", - "--geo-tgeo-jsonconfig", responseFile, - "--mat-input-type", "file", - "--mat-input-file", materialFile + "--geo-tgeo-jsonconfig", responseFile }; + if (m_useActsMaterialMap) + { + argstr.insert(argstr.end(), + { + "--mat-input-type", "file", + "--mat-input-file", materialFile + }); + } + double fieldstrength = std::numeric_limits::quiet_NaN(); if( isConstantField( m_magField, fieldstrength ) ) { @@ -664,7 +717,7 @@ void MakeActsGeometry::buildActsSurfaces() // acts/Examples/Run/Common/src/GeometryExampleBase::ProcessGeometry() in MakeActsGeometry() // so we get access to the results. The layer builder magically gets the TGeoManager - makeGeometry(argstr.size(), argv, m_detector); + makeGeometry(argstr.size(), argv, responseFile, materialFile); for (size_t i = 0; i < argstr.size(); ++i) { @@ -675,15 +728,12 @@ void MakeActsGeometry::buildActsSurfaces() void MakeActsGeometry::setMaterialResponseFile(std::string &responseFile, - std::string &materialFile) + std::string &materialFile) const { responseFile = "tgeo-sphenix-mms.json"; - materialFile = "sphenix-mm-material.json"; - // Check to see if files exist locally - if not, use defaults - std::ifstream file; - - file.open(responseFile); - if (!file.is_open()) + // Check to see if the geometry response file exists locally. If not, use CDB. + std::ifstream responseStream(responseFile); + if (!responseStream.is_open()) { std::cout << responseFile << " not found locally, use CDB version" @@ -691,131 +741,92 @@ void MakeActsGeometry::setMaterialResponseFile(std::string &responseFile, responseFile = CDBInterface::instance()->getUrl("ACTSGEOMETRYCONFIG"); } - file.open(materialFile); - if (!file.is_open()) + if (m_useActsMaterialMap) { - std::cout << materialFile - << " not found locally, use CDB version" + materialFile = "sphenix-mm-material.json"; + std::ifstream materialStream(materialFile); + if (!materialStream.is_open()) + { + std::cout << materialFile + << " not found locally, use CDB version" + << std::endl; + materialFile = CDBInterface::instance()->getUrl("ACTSMATERIALMAP"); + } + + std::cout << "Using Acts material file : " << materialFile << std::endl; - materialFile = CDBInterface::instance()->getUrl("ACTSMATERIALMAP"); + } + else + { + materialFile.clear(); + std::cout << "Using empty Acts material map" << std::endl; } - std::cout << "using Acts material file : " << materialFile - << std::endl; - std::cout << "Using Acts TGeoResponse file : " << responseFile - << std::endl; + std::cout << "Using Acts TGeoResponse file : " << responseFile + << std::endl; return; } -void MakeActsGeometry::makeGeometry(int argc, char *argv[], - ActsExamples::TGeoDetectorWithOptions &detector) +void MakeActsGeometry::makeGeometry(int argc, char *argv[], const std::string& responseFile, const std::string& materialFile) { + // setup and parse options boost::program_options::options_description desc; ActsExamples::Options::addGeometryOptions(desc); ActsExamples::Options::addMaterialOptions(desc); ActsExamples::Options::addMagneticFieldOptions(desc); - // Add specific options for this geometry - detector.addOptions(desc); - auto vm = ActsExamples::Options::parse(desc, argc, argv); - - // The geometry, material and decoration - auto geometry = build(vm, detector); - // Geometry is a pair of (tgeoTrackingGeometry, tgeoContextDecorators) + ActsExamples::TGeoDetector::Config config; + config.surfaceLogLevel = Acts::Logging::FATAL; + config.layerLogLevel = Acts::Logging::FATAL; + config.volumeLogLevel = Acts::Logging::FATAL; + config.logLevel = Acts::Logging::FATAL; + config.detectorElementFactory = sPHENIXElementFactory; + config.readJson(responseFile); - m_tGeometry = geometry.first; - if (m_useField) - { - m_magneticField = ActsExamples::Options::readMagneticField(vm); - } - else + std::shared_ptr matDeco = nullptr; + if (m_useActsMaterialMap) { - m_magneticField = nullptr; - } - - m_geoCtxt = Acts::GeometryContext(); - - unpackVolumes(); - - return; -} - -std::pair, - std::vector>> -MakeActsGeometry::build(const boost::program_options::variables_map &vm, - ActsExamples::TGeoDetectorWithOptions &detector) -{ - // Material decoration - std::shared_ptr matDeco = nullptr; + if (materialFile.find(".json") == std::string::npos && + materialFile.find(".cbor") == std::string::npos) + { + std::cout << "Unsupported Acts material map format: " << materialFile + << std::endl; + exit(1); + } - // Retrieve the filename - auto fileName = vm["mat-input-file"].template as(); - // json or root based decorator - if (fileName.find(".json") != std::string::npos || - fileName.find(".cbor") != std::string::npos) - { // Set up the converter first Acts::MaterialMapJsonConverter::Config jsonGeoConvConfig; // Set up the json-based decorator - matDeco = std::make_shared( - jsonGeoConvConfig, fileName, Acts::Logging::FATAL); + matDeco = std::make_shared( + jsonGeoConvConfig, materialFile, Acts::Logging::FATAL); } else { - matDeco = std::make_shared(); + matDeco = std::make_shared(); } + config.materialDecorator = matDeco; + // this does the building now. The TGeoDetector owns the + // tracking geometry + m_TGeoDetector = std::make_unique(config); - ActsExamples::TGeoDetector::Config config; - - config.elementFactory = sPHENIXElementFactory; - - config.fileName = vm["geo-tgeo-filename"].as(); - - config.surfaceLogLevel = Acts::Logging::FATAL; - config.layerLogLevel = Acts::Logging::FATAL; - config.volumeLogLevel = Acts::Logging::FATAL; - - const auto path = vm["geo-tgeo-jsonconfig"].template as(); - - readTGeoLayerBuilderConfigsFile(path, config); - - // Return the geometry and context decorators - return detector.m_detector.finalize(config, matDeco); -} + // Add specific options for this geometry + m_TGeoDetector->addOptions(desc); + auto vm = ActsExamples::Options::parse(desc, argc, argv); -void MakeActsGeometry::readTGeoLayerBuilderConfigsFile(const std::string &path, - ActsExamples::TGeoDetector::Config &config) -{ - if (path.empty()) + m_tGeometry = m_TGeoDetector->m_detector.trackingGeometry(); + if (m_useField) { - std::cout << "There is no acts geometry response file loaded. Cannot build, exiting" - << std::endl; - exit(1); + m_magneticField = ActsExamples::Options::readMagneticField(vm); } - - nlohmann::json djson; - std::ifstream infile(path, std::ifstream::in | std::ifstream::binary); - infile >> djson; - - config.unitScalor = djson["geo-tgeo-unit-scalor"]; - - config.buildBeamPipe = djson["geo-tgeo-build-beampipe"]; - if (config.buildBeamPipe) + else { - const auto beamPipeParameters = - djson["geo-tgeo-beampipe-parameters"].get>(); - config.beamPipeRadius = beamPipeParameters[0]; - config.beamPipeHalflengthZ = beamPipeParameters[1]; - config.beamPipeLayerThickness = beamPipeParameters[2]; + m_magneticField = nullptr; } - // Fill nested volume configs - for (const auto &volume : djson["Volumes"]) - { - auto &vol = config.volumes.emplace_back(); - vol = volume; - } + unpackVolumes(); + + return; } void MakeActsGeometry::unpackVolumes() @@ -901,15 +912,17 @@ void MakeActsGeometry::makeTpcMapPairs(TrackingVolumePtr &tpcVolume) { auto surf = j->getSharedPtr(); auto vec3d = surf->center(m_geoCtxt); + vec3d /= 10.0; + auto vec3d_envelope = m_tpc_world_envelope_transform * vec3d; // needs to be in TPC envelope coordinates due to tilt in sims - // convert to cm - std::vector world_center = {vec3d(0) / 10.0, - vec3d(1) / 10.0, - vec3d(2) / 10.0}; + std::vector world_center = {vec3d_envelope(0), + vec3d_envelope(1), + vec3d_envelope(2)}; TrkrDefs::hitsetkey hitsetkey = getTpcHitSetKeyFromCoords(world_center); unsigned int layer = TrkrDefs::getLayer(hitsetkey); - + // unsigned int sector = TpcDefs::getSectorId(hitsetkey); + // unsigned int side = TpcDefs::getSide(hitsetkey); // If there is already an entry for this hitsetkey, add the surface // to its corresponding vector // std::map>::iterator mapIter; @@ -919,11 +932,13 @@ void MakeActsGeometry::makeTpcMapPairs(TrackingVolumePtr &tpcVolume) if (mapIter != m_clusterSurfaceMapTpcEdit.end()) { + //std::cout << " Adding surface to map with layer " << layer << " side " << side << " sector " << sector << std::endl; mapIter->second.push_back(surf); } else { // Otherwise make a new map entry + // std::cout << "Starting new surfvec for layer " << layer << " side " << side << " sector " << sector << std::endl; std::vector dumvec; dumvec.push_back(surf); std::pair> tmp = @@ -937,7 +952,7 @@ void MakeActsGeometry::makeTpcMapPairs(TrackingVolumePtr &tpcVolume) //____________________________________________________________________________________________ void MakeActsGeometry::makeMmMapPairs(TrackingVolumePtr &mmVolume) { - if (Verbosity()) + if (Verbosity()>1) { std::cout << "MakeActsGeometry::makeMmMapPairs - mmVolume: " << mmVolume->volumeName() << std::endl; } @@ -999,7 +1014,7 @@ void MakeActsGeometry::makeMmMapPairs(TrackingVolumePtr &mmVolume) continue; } - if (Verbosity()) + if (Verbosity()>1) { std::cout << "MakeActsGeometry::makeMmMapPairs - layer: " << layer << " tileid: " << tileid << std::endl; } @@ -1082,7 +1097,7 @@ void MakeActsGeometry::makeInttMapPairs(TrackingVolumePtr &inttVolume) TrkrDefs::hitsetkey hitsetkey = getInttHitSetKeyFromCoords(layer, world_center); // Add this surface to the map - std::pair tmp = make_pair(hitsetkey, surf); + std::pair tmp = std::make_pair(hitsetkey, surf); m_clusterSurfaceMapSilicon.insert(tmp); if (Verbosity() > 10) @@ -1098,14 +1113,14 @@ void MakeActsGeometry::makeInttMapPairs(TrackingVolumePtr &inttVolume) std::cout << std::endl << " Layer type " << assoc_layer->layerType() << std::endl; - auto assoc_det_element = surf->associatedDetectorElement(); + auto assoc_det_element = surf->surfacePlacement(); if (assoc_det_element != nullptr) { std::cout << " Associated detElement has non-null pointer " << assoc_det_element << std::endl; std::cout << std::endl << " Associated detElement found, thickness = " - << assoc_det_element->thickness() << std::endl; + << surf->thickness() << std::endl; } else { @@ -1165,16 +1180,16 @@ void MakeActsGeometry::makeMvtxMapPairs(TrackingVolumePtr &mvtxVolume) auto vec3d = surf->center(m_geoCtxt); std::vector world_center = {(vec3d(0) - v_globaldisplacement[0]) / 10.0, (vec3d(1) - v_globaldisplacement[1]) / 10.0, (vec3d(2) - v_globaldisplacement[2]) / 10.0}; // convert from mm to cm double layer_rad = sqrt(pow(world_center[0], 2) + pow(world_center[1], 2)); - if (Verbosity() > 0) + if (Verbosity() > 1) { std::cout << "[DEBUG] MVTX surface center (before misalignment): (x,y,z)=(" << vec3d(0) / 10. << "," << vec3d(1) / 10. << "," << vec3d(2) / 10. << "), layer_rad=" << sqrt(pow(vec3d(0) / 10., 2) + pow(vec3d(1) / 10., 2)) << std::endl; std::cout << "[DEBUG] MVTX surface center: (x,y,z)=(" << world_center[0] << "," << world_center[1] << "," << world_center[2] << "), layer_rad=" << layer_rad << std::endl; } - auto detelement = surf->associatedDetectorElement(); + auto detelement = surf->surfacePlacement(); if(!detelement) { - std::cout << PHWHERE << " Did not find associatedDetectorElement, have to quit! " << std::endl; + std::cout << PHWHERE << " Did not find surfacePlacement, have to quit! " << std::endl; exit(1); } @@ -1219,7 +1234,7 @@ void MakeActsGeometry::makeMvtxMapPairs(TrackingVolumePtr &mvtxVolume) } // Add this surface to the map - std::pair tmp = make_pair(hitsetkey, surf); + std::pair tmp = std::make_pair(hitsetkey, surf); m_clusterSurfaceMapSilicon.insert(tmp); if (Verbosity() > 10) @@ -1244,14 +1259,14 @@ void MakeActsGeometry::makeMvtxMapPairs(TrackingVolumePtr &mvtxVolume) << " Layer type " << assoc_layer->layerType() << std::endl; - auto assoc_det_element = surf->associatedDetectorElement(); + auto assoc_det_element = surf->surfacePlacement(); if (assoc_det_element != nullptr) { std::cout << " Associated detElement has non-null pointer " << assoc_det_element << std::endl; std::cout << std::endl << " Associated detElement found, thickness = " - << assoc_det_element->thickness() << std::endl; + << surf->thickness() << std::endl; } else { @@ -1265,7 +1280,9 @@ void MakeActsGeometry::makeMvtxMapPairs(TrackingVolumePtr &mvtxVolume) TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector &world) { - // Look up TPC surface index values from world position of surface center + // This is used only in simulations + // so the input position is assumed to be in tpc envelope coords - i.e. tilt removed + // Look up TPC surface index values from tpc envelope position of surface center // layer unsigned int layer = 999; double layer_rad = sqrt(pow(world[0], 2) + pow(world[1], 2)); @@ -1275,6 +1292,7 @@ TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector= tpc_ref_radius_low && layer_rad < tpc_ref_radius_high) { layer = ilayer; @@ -1317,6 +1335,12 @@ TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector 3 && layer == 15) + { + std::cout << " layer_rad " << layer_rad << " m_layerRadius[layer] " << m_layerRadius[layer-7] << " found layer " << layer << " side " << side << " world " << world[0] << " " << world[1] << " " << world[2] << " phi_world " << phi_world << " readout_mod " << readout_mod << std::endl; + } + if (readout_mod >= m_nTpcModulesPerLayer) { std::cout << PHWHERE @@ -1326,16 +1350,13 @@ TrkrDefs::hitsetkey MakeActsGeometry::getTpcHitSetKeyFromCoords(std::vector 3) + if (Verbosity() > 3 && layer == 7) { - if (layer == 30) - { - std::cout << " world = " << world[0] << " " << world[1] - << " " << world[2] << " phi_world " - << phi_world * 180 / M_PI << " layer " << layer - << " readout_mod " << readout_mod << " side " << side - << " hitsetkey " << hitset_key << std::endl; - } + std::cout << " world = " << world[0] << " " << world[1] + << " " << world[2] << " phi_world " + << phi_world * 180 / M_PI << " layer " << layer + << " readout_mod " << readout_mod << " side " << side + << " hitsetkey " << hitset_key << std::endl; } return hitset_key; diff --git a/offline/packages/trackreco/MakeActsGeometry.h b/offline/packages/trackreco/MakeActsGeometry.h index f437236131..cdc2f231a2 100644 --- a/offline/packages/trackreco/MakeActsGeometry.h +++ b/offline/packages/trackreco/MakeActsGeometry.h @@ -41,7 +41,7 @@ class TGeoVolume; namespace Acts { class Surface; -} +} // namespace Acts using Surface = std::shared_ptr; using TrackingGeometry = std::shared_ptr; @@ -77,6 +77,12 @@ class MakeActsGeometry : public SubsysReco m_magFieldRescale = magFieldRescale; } + /// enable or disable the ACTS surface and volume material map + void setUseActsMaterialMap(bool value) + { + m_useActsMaterialMap = value; + } + // void useInttSurveyGeom(const bool useSurveyGeom) { m_useInttSurveyGeom = useSurveyGeom; } void setMvtxDev(double array[6]) @@ -137,17 +143,22 @@ class MakeActsGeometry : public SubsysReco double getSurfStepPhi() { return m_surfStepPhi; } double getSurfStepZ() { return m_surfStepZ; } + /// assign local alignment parameter file to be used instead of CDB, if found + void set_alignmentParamsFile(const std::string& value ) { m_alignmentParamsFile = value; } + + /// assign TPC drift velocity void set_drift_velocity(double vd) { m_drift_velocity = vd; } + + /// assign TPC T0 void set_tpc_tzero(double tz) { m_tpc_tzero = tz; } void set_sampa_tzero_bias(double tzb) { m_sampa_tzero_bias = tzb; } void set_apply_tpc_tzero_correction(bool flag) { m_apply_tpc_tzero_correction = flag; } - + void set_nSurfPhi(unsigned int value) { m_nSurfPhi = value; } - // void set_maxSurfZ(double value) {m_maxSurfZ = value;} // set to TPC gas volume length - + void set_mvtx_applymisalign(bool b) { m_mvtxapplymisalign = b; } void set_intt_survey(bool surv) { m_inttSurvey = surv; } @@ -174,19 +185,10 @@ class MakeActsGeometry : public SubsysReco void buildActsSurfaces(); /// Function that mimics ActsExamples::GeometryExampleBase - void makeGeometry(int argc, char *argv[], - ActsExamples::TGeoDetectorWithOptions &detector); -#ifndef __CLING__ - std::pair, - std::vector>> - build(const boost::program_options::variables_map &vm, - ActsExamples::TGeoDetectorWithOptions &detector); -#endif - void readTGeoLayerBuilderConfigsFile(const std::string &path, - ActsExamples::TGeoDetector::Config &config); + void makeGeometry(int argc, char *argv[], const std::string& responseFile, const std::string& materialFile); void setMaterialResponseFile(std::string &responseFile, - std::string &materialFile); + std::string &materialFile) const; /// Get hitsetkey from TGeoNode for each detector geometry void getInttKeyFromNode(TGeoNode *gnode); @@ -216,6 +218,7 @@ class MakeActsGeometry : public SubsysReco // void makeTGeoNodeMap(PHCompositeNode *topNode); void unpackVolumes(); + std::unique_ptr m_TGeoDetector = nullptr; /// Subdetector geometry containers for getting layer information PHG4CylinderGeomContainer *m_geomContainerMvtx = nullptr; @@ -234,6 +237,7 @@ class MakeActsGeometry : public SubsysReco std::vector v_globaldisplacement = {0., 0., 0.}; bool m_useField = true; + bool m_useActsMaterialMap = true; std::map m_misalignmentFactor; /// Several maps that connect Acts world to sPHENIX G4 world @@ -273,31 +277,38 @@ class MakeActsGeometry : public SubsysReco /// z does not need spacing as the boxes are rotated around the z axis const double half_width_clearance_z = 0.5; - /// The acts geometry object - ActsExamples::TGeoDetectorWithOptions m_detector; - /// Acts geometry objects that are needed to create (for example) the fitter TrackingGeometry m_tGeometry; std::shared_ptr m_magneticField; - Acts::GeometryContext m_geoCtxt; + Acts::GeometryContext m_geoCtxt = Acts::GeometryContext::dangerouslyDefaultConstruct(); /// Structs to put on the node tree which carry around ActsGeom info ActsGeometry *m_actsGeometry = nullptr; std::map base_layer_map = {{10, 0}, {12, 3}, {14, 7}, {16, 55}}; unsigned int mvtx_chips_per_stave = 9; - + /// Verbosity value handed from PHActsSourceLinks // int m_verbosity = 0; - double m_drift_velocity = 0.; // cm/ns, override from macro - double m_max_driftlength = 0.; // override from macro - double m_CM_halfwidth = 0.; // central membrane half width in cm + /// local alignment parameter file + /** this is passed to Alignment Transformation and used instead of CDB if found */ + std::string m_alignmentParamsFile = "./localAlignmentParamsFile.txt"; + + /// TPC drift velocity overriden from macro (cm/ns) + double m_drift_velocity = 0.; + + /// maximum drift length, overriden from macro (cm) + double m_max_driftlength = 0.; + /// central membrane half width (cm) overriden from macro + double m_CM_halfwidth = 0.; + + /// T0 correction bool m_apply_tpc_tzero_correction = false; double m_tpc_tzero = 0.0; // ns, override from macro double m_sampa_tzero_bias = 0.0; // ns, override from macro - + /// Magnetic field components to set Acts magnetic field std::string m_magField = "1.4"; double m_magFieldRescale = -1.; @@ -314,6 +325,10 @@ class MakeActsGeometry : public SubsysReco bool m_use_module_tilt_always = false; bool m_use_new_silicon_rotation_order = false; + + Acts::Transform3 m_tpc_world_envelope_transform; + Acts::Transform3 m_tpc_envelope_world_transform; + }; #endif diff --git a/offline/packages/trackreco/MakeSourceLinks.cc b/offline/packages/trackreco/MakeSourceLinks.cc index efbbe92853..74c9300d97 100644 --- a/offline/packages/trackreco/MakeSourceLinks.cc +++ b/offline/packages/trackreco/MakeSourceLinks.cc @@ -1,13 +1,12 @@ #include "MakeSourceLinks.h" -#include +#include +#include #include #include #include -#include #include #include -#include #include #include @@ -16,71 +15,75 @@ #include #include -#include #include +#include #include #include #include +#include + #include #include namespace { - template + template inline T square(const T& x) { return x * x; } - [[maybe_unused]] std::ostream& operator << (std::ostream& out, const Acts::Vector3& v ) + [[maybe_unused]] std::ostream& operator<<(std::ostream& out, const Acts::Vector3& v) { out << "(" << v.x() << ", " << v.y() << ", " << v.z() << ")"; return out; } - - [[maybe_unused]] std::ostream& operator << (std::ostream& out, const Acts::Vector2& v ) + [[maybe_unused]] std::ostream& operator<<(std::ostream& out, const Acts::Vector2& v) { out << "(" << v.x() << ", " << v.y() << ")"; return out; } -} +} // namespace -void MakeSourceLinks::initialize(PHG4TpcGeomContainer* cellgeo) +void MakeSourceLinks::initialize(PHG4TpcGeomContainer* cellgeo, ActsGeometry *tGeometry) { // get the TPC layer radii from the geometry object - if (cellgeo) + if (cellgeo && tGeometry) { - _clusterMover.initialize_geometry(cellgeo); + _clusterMover.initialize_geometry(cellgeo, tGeometry); } - } - //___________________________________________________________________________________ +//___________________________________________________________________________________ SourceLinkVec MakeSourceLinks::getSourceLinks( - TrackSeed* track, - ActsTrackFittingAlgorithm::MeasurementContainer& measurements, - TrkrClusterContainer* clusterContainer, - ActsGeometry* tGeometry, - const TpcGlobalPositionWrapper& globalPositionWrapper, - alignmentTransformationContainer* transformMapTransient, - std::set< Acts::GeometryIdentifier>& transient_id_set, - short int crossing - ) + TrackSeed* track, + ActsTrackFittingAlgorithm::MeasurementContainer& measurements, + TrkrClusterContainer* clusterContainer, + ActsGeometry* tGeometry, + const TpcGlobalPositionWrapper& globalPositionWrapper, + alignmentTransformationContainer* transformMapTransient, + std::set& transient_id_set, + short int crossing) { - if(m_verbosity > 1) { std::cout << "Entering MakeSourceLinks::getSourceLinks " << std::endl; } + if (m_verbosity > 1) + { + std::cout << "Entering MakeSourceLinks::getSourceLinks " << std::endl; + } SourceLinkVec sourcelinks; if (m_pp_mode && crossing == SHRT_MAX) { // Need to skip this in the pp case, for AuAu it should not happen - if(m_verbosity > 1) - { std::cout << "Seed has no crossing, and in pp mode: skip this seed" << std::endl; } + if (m_verbosity > 1) + { + std::cout << "Seed has no crossing, and in pp mode: skip this seed" << std::endl; + } return sourcelinks; } @@ -96,84 +99,89 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( ++clusIter) { auto key = *clusIter; - auto cluster = clusterContainer->findCluster(key); + auto* cluster = clusterContainer->findCluster(key); if (!cluster) + { + if (m_verbosity > 0) { - if (m_verbosity > 0) - {std::cout << "MakeSourceLinks: Failed to get cluster with key " << key << " for track seed" << std::endl;} - continue; + std::cout << "MakeSourceLinks: Failed to get cluster with key " << key << " for track seed" << std::endl; } - else - if(m_verbosity > 0) - {std::cout << "MakeSourceLinks: Found cluster with key " << key << " for track seed " << std::endl;} - + continue; + } + if (m_verbosity > 0) + { + std::cout << "MakeSourceLinks: Found cluster with key " << key << " for track seed " << std::endl; + } + /// Make a safety check for clusters that couldn't be attached to a surface auto surf = tGeometry->maps().getSurface(key, cluster); if (!surf) - { - continue; - } - + { + continue; + } + const unsigned int trkrid = TrkrDefs::getTrkrId(key); const unsigned int clus_layer = TrkrDefs::getLayer(key); - if(m_verbosity > 1) { std::cout << " Cluster key " << key << " layer " << clus_layer << " trkrid " << trkrid << " crossing " << crossing << std::endl; } + if (m_verbosity > 1) + { + std::cout << " Cluster key " << key << " layer " << clus_layer << " trkrid " << trkrid << " crossing " << crossing << std::endl; + } // For the TPC, cluster z has to be corrected for the crossing z offset, distortion, and TOF z offset // we do this by modifying the fake surface transform, to move the cluster to the corrected position if (trkrid == TrkrDefs::tpcId) { - Acts::Vector3 global = globalPositionWrapper.getGlobalPositionDistortionCorrected(key, cluster, crossing ); + Acts::Vector3 global = globalPositionWrapper.getGlobalPositionDistortionCorrected(key, cluster, crossing); Acts::Vector3 nominal_global_in = tGeometry->getGlobalPosition(key, cluster); Acts::Vector3 global_in = tGeometry->getGlobalPosition(key, cluster); // The wrapper returns the global position corrected for distortion and the cluster crossing z offset // The cluster z crossing correction has to be applied to the nominal global position (global_in) - double cluster_crossing_corrected_z= TpcClusterZCrossingCorrection::correctZ(global_in.z(), TpcDefs::getSide(key), crossing); - double crossing_correction = cluster_crossing_corrected_z - global_in.z(); + double cluster_crossing_corrected_z = TpcClusterZCrossingCorrection::correctZ(global_in.z(), TpcDefs::getSide(key), crossing); + double crossing_correction = cluster_crossing_corrected_z - global_in.z(); global_in.z() = cluster_crossing_corrected_z; - - if(m_verbosity > 2) + + if (m_verbosity > 2) { - unsigned int this_layer = TrkrDefs::getLayer(key); - unsigned int this_side = TpcDefs::getSide(key); - if(this_layer == 28) - { - std::cout << " crossing " << crossing << " layer " << this_layer << " side " << this_side << " clusterkey " << key << std::endl - << " nominal global_in " << nominal_global_in(0) << " " << nominal_global_in(1) << " " << nominal_global_in(2) - << " global_in " << global_in(0) << " " << global_in(1) << " " << global_in(2) - << " corr glob " << global(0) << " " << global(1) << " " << global(2) << std::endl - << " distortion " << global(0)-global_in(0) << " " - << global(1) - global_in(1) << " " << global(2) - global_in(2) - << " cluster crossing z correction " << crossing_correction - << std::endl; - } + unsigned int this_layer = TrkrDefs::getLayer(key); + unsigned int this_side = TpcDefs::getSide(key); + if (this_layer == 28) + { + std::cout << " crossing " << crossing << " layer " << this_layer << " side " << this_side << " clusterkey " << key << std::endl + << " nominal global_in " << nominal_global_in(0) << " " << nominal_global_in(1) << " " << nominal_global_in(2) + << " global_in " << global_in(0) << " " << global_in(1) << " " << global_in(2) + << " corr glob " << global(0) << " " << global(1) << " " << global(2) << std::endl + << " distortion " << global(0) - global_in(0) << " " + << global(1) - global_in(1) << " " << global(2) - global_in(2) + << " cluster crossing z correction " << crossing_correction + << std::endl; + } } - + // Make an afine transform that implements the distortion correction as a translation - auto correction_translation = (global - global_in)*Acts::UnitConstants::cm; - Acts::Vector3 correction_rotation(0,0,0); // null rotation + auto correction_translation = (global - global_in) * Acts::UnitConstants::cm; + Acts::Vector3 correction_rotation(0, 0, 0); // null rotation Acts::Transform3 tcorr = tGeometry->makeAffineTransform(correction_rotation, correction_translation); auto this_surf = tGeometry->maps().getSurface(key, cluster); Acts::GeometryIdentifier id = this_surf->geometryId(); - auto check_cluster = clusterContainer->findCluster(key); - Acts::Vector2 check_local2d = tGeometry->getLocalCoords(key, check_cluster) * Acts::UnitConstants::cm; // need mm - Acts::Vector3 check_local3d (check_local2d(0), check_local2d(1), 0); - Acts::GeometryContext temp_transient_geocontext; - temp_transient_geocontext = transformMapTransient; - Acts::Vector3 check_before_pos_surf = this_surf->localToGlobal( temp_transient_geocontext, - check_local2d, - Acts::Vector3(1,1,1)); - if(m_verbosity > 2) - { - unsigned int this_layer = TrkrDefs::getLayer(key); - if(this_layer == 28) - { - std::cout << "Check global from transient transform BEFORE via surface method " << check_before_pos_surf(0)/10.0 << " " - << " " << check_before_pos_surf(1)/10.0 << " " << check_before_pos_surf(2)/10.0 << std::endl; - } - } - + auto* check_cluster = clusterContainer->findCluster(key); + Acts::Vector2 check_local2d = tGeometry->getLocalCoords(key, check_cluster) * Acts::UnitConstants::cm; // need mm + Acts::Vector3 check_local3d(check_local2d(0), check_local2d(1), 0); + Acts::GeometryContext temp_transient_geocontext{transformMapTransient}; + Acts::Vector3 check_before_pos_surf = this_surf->localToGlobal(temp_transient_geocontext, + check_local2d, + Acts::Vector3(1, 1, 1)); + if (m_verbosity > 2) + { + unsigned int this_layer = TrkrDefs::getLayer(key); + if (this_layer == 28) + { + std::cout << "Check global from transient transform BEFORE via surface method " << check_before_pos_surf(0) / 10.0 << " " + << " " << check_before_pos_surf(1) / 10.0 << " " << check_before_pos_surf(2) / 10.0 << std::endl; + } + } + // replace the the default alignment transform with the corrected one auto ctxt = tGeometry->geometry().getGeoContext(); alignmentTransformationContainer* transformMap = ctxt.get(); @@ -181,18 +189,18 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( transformMapTransient->replaceTransform(id, corrected_transform); transient_id_set.insert(id); - Acts::Vector3 check_after_pos_surf = this_surf->localToGlobal( temp_transient_geocontext, - check_local2d, - Acts::Vector3(1,1,1)); - if(m_verbosity > 2) - { - unsigned int this_layer = TrkrDefs::getLayer(key); - if(this_layer == 28) - { - std::cout << "Check global from transient transform AFTER via surface method " << check_after_pos_surf(0)/10.0 << " " - << " " << check_after_pos_surf(1)/10.0 << " " << check_after_pos_surf(2)/10.0 << std::endl; - } - } + Acts::Vector3 check_after_pos_surf = this_surf->localToGlobal(temp_transient_geocontext, + check_local2d, + Acts::Vector3(1, 1, 1)); + if (m_verbosity > 2) + { + unsigned int this_layer = TrkrDefs::getLayer(key); + if (this_layer == 28) + { + std::cout << "Check global from transient transform AFTER via surface method " << check_after_pos_surf(0) / 10.0 << " " + << " " << check_after_pos_surf(1) / 10.0 << " " << check_after_pos_surf(2) / 10.0 << std::endl; + } + } } // end TPC specific treatment // corrected TPC transforms are installed, capture the cluster key @@ -200,129 +208,142 @@ SourceLinkVec MakeSourceLinks::getSourceLinks( } // end loop over clusters here - Acts::GeometryContext transient_geocontext; - transient_geocontext = transformMapTransient; + Acts::GeometryContext transient_geocontext{transformMapTransient}; // loop over cluster_vec and make source links - for(auto& cluskey : cluster_vec) + for (auto& cluskey : cluster_vec) + { + if (m_ignoreLayer.contains(TrkrDefs::getLayer(cluskey))) { - if (m_ignoreLayer.contains(TrkrDefs::getLayer(cluskey))) - { - if (m_verbosity > 3) - { - std::cout << PHWHERE << "skipping cluster in layer " - << (unsigned int) TrkrDefs::getLayer(cluskey) << std::endl; - } - continue; - } - - // get local coordinates (TPC time needs conversion to cm) - auto cluster = clusterContainer->findCluster(cluskey); - Acts::Vector2 localPos = tGeometry->getLocalCoords(cluskey, cluster, crossing); // cm - - Surface surf = tGeometry->maps().getSurface(cluskey, cluster); - - Acts::ActsVector<2> loc; - loc[Acts::eBoundLoc0] = localPos(0) * Acts::UnitConstants::cm; // mm - loc[Acts::eBoundLoc1] = localPos(1) * Acts::UnitConstants::cm; - - std::array indices = - {Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; - Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Zero(); - - // get errors - Acts::Vector3 global = tGeometry->getGlobalPosition(cluskey, cluster); - double clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]); - auto para_errors = _ClusErrPara.get_clusterv5_modified_error(cluster, clusRadius, cluskey); - cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; - cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; - cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; - cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; - - ActsSourceLink::Index index = measurements.size(); - - SourceLink sl(surf->geometryId(), index, cluskey); - Acts::SourceLink actsSL{sl}; - Acts::Measurement meas(actsSL, indices, loc, cov); if (m_verbosity > 3) - { - unsigned int this_layer = TrkrDefs::getLayer(cluskey); - if (this_layer == 28) - { - std::cout << "source link in layer " << this_layer << " for cluskey " << cluskey << " is " << sl.index() << ", loc : " - << loc.transpose() << std::endl - << ", cov : " << cov.transpose() << std::endl - << " geo id " << sl.geometryId() << std::endl; - std::cout << "Surface original transform: " << std::endl; - surf.get()->toStream(tGeometry->geometry().getGeoContext(), std::cout); - std::cout << std::endl << "Surface transient transform: " << std::endl; - surf.get()->toStream(transient_geocontext, std::cout); - std::cout << std::endl; - std::cout << "Corrected surface transform:" << std::endl; - std::cout << transformMapTransient->getTransform(surf->geometryId()).matrix() << std::endl; - std::cout << "Cluster error " << cluster->getRPhiError() << " , " << cluster->getZError() << std::endl; - std::cout << "For key " << cluskey << " with local pos " << std::endl - << localPos(0) << ", " << localPos(1) - << std::endl << std::endl; - } + { + std::cout << PHWHERE << "skipping cluster in layer " + << (unsigned int) TrkrDefs::getLayer(cluskey) << std::endl; + } + continue; + } + + // get local coordinates (TPC time needs conversion to cm) + auto* cluster = clusterContainer->findCluster(cluskey); + if (TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::tpcId) + { + if (cluster->getEdge() > m_cluster_edge_rejection) + { + continue; + } } + Acts::Vector2 localPos = tGeometry->getLocalCoords(cluskey, cluster, crossing); // cm + + Surface surf = tGeometry->maps().getSurface(cluskey, cluster); + + Acts::ActsVector<2> loc; + loc[Acts::eBoundLoc0] = localPos(0) * Acts::UnitConstants::cm; // mm + loc[Acts::eBoundLoc1] = localPos(1) * Acts::UnitConstants::cm; + + std::array indices = + {Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; + Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Zero(); + + // get errors + Acts::Vector3 global = tGeometry->getGlobalPosition(cluskey, cluster); + double clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]); + auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, clusRadius, cluskey); + cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; + cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; + cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; - sourcelinks.push_back(actsSL); - measurements.push_back(meas); + ActsSourceLink::Index index = measurements.size(); + + SourceLink sl(surf->geometryId(), index, cluskey); + Acts::SourceLink actsSL{sl}; + measurements.emplaceMeasurement<2>(surf->geometryId(), indices, loc, cov); + if (m_verbosity > 3) + { + unsigned int this_layer = TrkrDefs::getLayer(cluskey); + if (this_layer == 28) + { + std::cout << "source link in layer " << this_layer << " for cluskey " << cluskey << " is " << sl.index() << ", loc : " + << loc.transpose() << std::endl + << ", cov : " << cov.transpose() << std::endl + << " geo id " << sl.geometryId() << std::endl; + std::cout << "Surface original transform: " << std::endl; + surf.get()->toStream(tGeometry->geometry().getGeoContext()); + std::cout << std::endl + << "Surface transient transform: " << std::endl; + surf.get()->toStream(transient_geocontext); + std::cout << std::endl; + std::cout << "Corrected surface transform:" << std::endl; + std::cout << transformMapTransient->getTransform(surf->geometryId()).matrix() << std::endl; + std::cout << "Cluster error " << cluster->getRPhiError() << " , " << cluster->getZError() << std::endl; + std::cout << "For key " << cluskey << " with local pos " << std::endl + << localPos(0) << ", " << localPos(1) + << std::endl + << std::endl; + } } + sourcelinks.push_back(actsSL); + } + SLTrackTimer.stop(); auto SLTime = SLTrackTimer.get_accumulated_time(); if (m_verbosity > 1) - { - std::cout << "PHActsTrkFitter Source Links generation time: " + { + std::cout << "PHActsTrkFitter Source Links generation time: " << SLTime << std::endl; - } + } return sourcelinks; } void MakeSourceLinks::resetTransientTransformMap( - alignmentTransformationContainer* transformMapTransient, - std::set< Acts::GeometryIdentifier>& transient_id_set, - ActsGeometry* tGeometry ) + alignmentTransformationContainer* transformMapTransient, + std::set& transient_id_set, + ActsGeometry* tGeometry) const { - if(m_verbosity > 2) { std::cout << "Resetting TransientTransformMap with transient_id_set size " << transient_id_set.size() << std::endl; } + if (m_verbosity > 2) + { + std::cout << "Resetting TransientTransformMap with transient_id_set size " << transient_id_set.size() << std::endl; + } // loop over modifiedTransformSet and replace transient elements modified for the last track with the default transforms - for(auto& id : transient_id_set) - { - auto ctxt = tGeometry->geometry().getGeoContext(); - alignmentTransformationContainer* transformMap = ctxt.get(); - auto transform = transformMap->getTransform(id); - transformMapTransient->replaceTransform(id, transform); - // std::cout << "replaced transform for id " << id << std::endl; - } + for (const auto& id : transient_id_set) + { + auto ctxt = tGeometry->geometry().getGeoContext(); + alignmentTransformationContainer* transformMap = ctxt.get(); + auto transform = transformMap->getTransform(id); + transformMapTransient->replaceTransform(id, transform); + // std::cout << "replaced transform for id " << id << std::endl; + } transient_id_set.clear(); } - //___________________________________________________________________________________ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( - TrackSeed* track, - ActsTrackFittingAlgorithm::MeasurementContainer& measurements, - TrkrClusterContainer* clusterContainer, - ActsGeometry* tGeometry, - const TpcGlobalPositionWrapper& globalPositionWrapper, - short int crossing - ) + TrackSeed* track, + ActsTrackFittingAlgorithm::MeasurementContainer& measurements, + TrkrClusterContainer* clusterContainer, + ActsGeometry* tGeometry, + const TpcGlobalPositionWrapper& globalPositionWrapper, + short int crossing) { - if(m_verbosity > 1) { std::cout << "Entering MakeSourceLinks::getSourceLinksClusterMover for seed " - << " with crossing " << crossing - << std::endl; } + if (m_verbosity > 1) + { + std::cout << "Entering MakeSourceLinks::getSourceLinksClusterMover for seed " + << " with crossing " << crossing + << std::endl; + } SourceLinkVec sourcelinks; if (m_pp_mode && crossing == SHRT_MAX) { // Need to skip this in the pp case, for AuAu it should not happen - if(m_verbosity > 1) - { std::cout << "Seed has no crossing, and in pp mode: skip this seed" << std::endl; } + if (m_verbosity > 1) + { + std::cout << "Seed has no crossing, and in pp mode: skip this seed" << std::endl; + } return sourcelinks; } @@ -339,13 +360,17 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( ++clusIter) { auto key = *clusIter; - auto cluster = clusterContainer->findCluster(key); + auto* cluster = clusterContainer->findCluster(key); if (!cluster) { if (m_verbosity > 0) - {std::cout << "Failed to get cluster with key " << key << " for track " << track << std::endl;} + { + std::cout << "Failed to get cluster with key " << key << " for track " << track << std::endl; + } else - {std::cout << "PHActsTrkFitter :: Key: " << key << " for track " << track << std::endl;} + { + std::cout << "PHActsTrkFitter :: Key: " << key << " for track " << track << std::endl; + } continue; } @@ -359,40 +384,43 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( const unsigned int trkrid = TrkrDefs::getTrkrId(key); - if(m_verbosity > 1) { std::cout << " Cluster key " << key << " trkrid " << trkrid << " crossing " << crossing << std::endl; } + if (m_verbosity > 1) + { + std::cout << " Cluster key " << key << " trkrid " << trkrid << " crossing " << crossing << std::endl; + } // For the TPC, cluster z has to be corrected for the crossing z offset, distortion, and TOF z offset // we do this locally here and do not modify the cluster, since the cluster may be associated with multiple silicon tracks - const Acts::Vector3 global = globalPositionWrapper.getGlobalPositionDistortionCorrected(key, cluster, crossing ); + const Acts::Vector3 global = globalPositionWrapper.getGlobalPositionDistortionCorrected(key, cluster, crossing); if (trkrid == TrkrDefs::tpcId) { - if(m_verbosity > 2) - { - unsigned int this_layer = TrkrDefs::getLayer(key); - if(this_layer == 28) - { - unsigned int this_side = TpcDefs::getSide(key); - Acts::Vector3 nominal_global_in = tGeometry->getGlobalPosition(key, cluster); - Acts::Vector3 global_in = tGeometry->getGlobalPosition(key, cluster); - double cluster_crossing_corrected_z= TpcClusterZCrossingCorrection::correctZ(global_in.z(), TpcDefs::getSide(key), crossing); - double crossing_correction = cluster_crossing_corrected_z - global_in.z(); - global_in.z() = cluster_crossing_corrected_z; - - std::cout << " crossing " << crossing << " layer " << this_layer << " side " << this_side << " clusterkey " << key << std::endl - << " nominal global_in " << nominal_global_in(0) << " " << nominal_global_in(1) << " " << nominal_global_in(2) << std::endl - << " global_in " << global_in(0) << " " << global_in(1) << " " << global_in(2) << std::endl - << " corr glob " << global(0) << " " << global(1) << " " << global(2) << std::endl - << " distortion " << global(0)-global_in(0) << " " - << global(1) - global_in(1) << " " << global(2) - global_in(2) - << " cluster crossing z correction " << crossing_correction - << std::endl; - } - } + if (m_verbosity > 2) + { + unsigned int this_layer = TrkrDefs::getLayer(key); + if (this_layer == 28) + { + unsigned int this_side = TpcDefs::getSide(key); + Acts::Vector3 nominal_global_in = tGeometry->getGlobalPosition(key, cluster); + Acts::Vector3 global_in = tGeometry->getGlobalPosition(key, cluster); + double cluster_crossing_corrected_z = TpcClusterZCrossingCorrection::correctZ(global_in.z(), TpcDefs::getSide(key), crossing); + double crossing_correction = cluster_crossing_corrected_z - global_in.z(); + global_in.z() = cluster_crossing_corrected_z; + + std::cout << " crossing " << crossing << " layer " << this_layer << " side " << this_side << " clusterkey " << key << std::endl + << " nominal global_in " << nominal_global_in(0) << " " << nominal_global_in(1) << " " << nominal_global_in(2) << std::endl + << " global_in " << global_in(0) << " " << global_in(1) << " " << global_in(2) << std::endl + << " corr glob " << global(0) << " " << global(1) << " " << global(2) << std::endl + << " distortion " << global(0) - global_in(0) << " " + << global(1) - global_in(1) << " " << global(2) - global_in(2) + << " cluster crossing z correction " << crossing_correction + << std::endl; + } + } } // add the global positions to a vector to give to the cluster mover - global_raw.emplace_back(std::make_pair(key, global)); + global_raw.emplace_back(key, global); } // end loop over clusters here @@ -405,10 +433,10 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( } // loop over global positions returned by cluster mover - for(auto&& [cluskey, global] : global_moved) + for (auto&& [cluskey, global] : global_moved) { // std::cout << "Global moved: " << global.x() << " " << global.y() << " " << global.z() << std::endl; - + if (m_ignoreLayer.contains(TrkrDefs::getLayer(cluskey))) { if (m_verbosity > 3) @@ -419,21 +447,26 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( continue; } - auto cluster = clusterContainer->findCluster(cluskey); + auto* cluster = clusterContainer->findCluster(cluskey); Surface surf = tGeometry->maps().getSurface(cluskey, cluster); - if(std::isnan(global.x()) || std::isnan(global.y())) + if (std::isnan(global.x()) || std::isnan(global.y())) { std::cout << "MakeSourceLinks::getSourceLinksClusterMover - invalid position" - << " key: " << cluskey - << " layer: " << (int)TrkrDefs::getLayer(cluskey) - << " position: " << global - << std::endl; + << " key: " << cluskey + << " layer: " << (int) TrkrDefs::getLayer(cluskey) + << " position: " << global + << std::endl; } // if this is a TPC cluster, the crossing correction may have moved it across the central membrane, check the surface auto trkrid = TrkrDefs::getTrkrId(cluskey); if (trkrid == TrkrDefs::tpcId) { + if (cluster->getEdge() > m_cluster_edge_rejection) + { + continue; + } + TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluskey); TrkrDefs::subsurfkey new_subsurfkey = 0; surf = tGeometry->get_tpc_surface_from_coords(hitsetkey, global, new_subsurfkey); @@ -441,7 +474,10 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( if (!surf) { - if(m_verbosity > 2) { std::cout << "MakeSourceLinks::getSourceLinksClusterMover - Failed to find surface for cluskey " << cluskey << std::endl; } + if (m_verbosity > 2) + { + std::cout << "MakeSourceLinks::getSourceLinksClusterMover - Failed to find surface for cluskey " << cluskey << std::endl; + } continue; } @@ -449,7 +485,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( Acts::Vector2 localPos; global *= Acts::UnitConstants::cm; // we want mm for transformations - Acts::Vector3 normal = surf->normal(tGeometry->geometry().getGeoContext(),Acts::Vector3(1,1,1), Acts::Vector3(1,1,1)); + Acts::Vector3 normal = surf->normal(tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); auto local = surf->globalToLocal(tGeometry->geometry().getGeoContext(), global, normal); if (local.ok()) @@ -458,11 +494,14 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( } else { - if(m_verbosity > 2) { std::cout << "MakeSourceLinks::getSourceLinksClusterMover - Taking manual calculation for global to local " << std::endl; } + if (m_verbosity > 2) + { + std::cout << "MakeSourceLinks::getSourceLinksClusterMover - Taking manual calculation for global to local " << std::endl; + } /// otherwise take the manual calculation for the TPC // doing it this way just avoids the bounds check that occurs in the surface class method - Acts::Vector3 loct = surf->transform(tGeometry->geometry().getGeoContext()).inverse() * global ; // global is in mm + Acts::Vector3 loct = surf->localToGlobalTransform(tGeometry->geometry().getGeoContext()).inverse() * global; // global is in mm loct /= Acts::UnitConstants::cm; localPos(0) = loct(0); @@ -474,37 +513,37 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( std::cout << "MakeSourceLinks::getSourceLinksClusterMover - Cluster " << cluskey << " cluster global after mover: " << global << std::endl; std::cout << "MakeSourceLinks::getSourceLinksClusterMover - stored: cluster local X " << cluster->getLocalX() << " cluster local Y " << cluster->getLocalY() << std::endl; - const Acts::Vector2 localTest = tGeometry->getLocalCoords(cluskey, cluster); // cm + const Acts::Vector2 localTest = tGeometry->getLocalCoords(cluskey, cluster); // cm std::cout << "MakeSourceLinks::getSourceLinksClusterMover - localTest from getLocalCoords: " << localTest << std::endl; std::cout << "MakeSourceLinks::getSourceLinksClusterMover - new from inverse transform of cluster global after mover: " << std::endl; - const Acts::Vector3 globalTest = surf->localToGlobal(tGeometry->geometry().getGeoContext(), localTest*Acts::UnitConstants::cm, normal); - std::cout << "MakeSourceLinks::getSourceLinksClusterMover - global from localTest: " << Acts::Vector3(globalTest/Acts::UnitConstants::cm) << std::endl; + const Acts::Vector3 globalTest = surf->localToGlobal(tGeometry->geometry().getGeoContext(), localTest * Acts::UnitConstants::cm, normal); + std::cout << "MakeSourceLinks::getSourceLinksClusterMover - global from localTest: " << Acts::Vector3(globalTest / Acts::UnitConstants::cm) << std::endl; - const Acts::Vector3 globalNew = surf->localToGlobal(tGeometry->geometry().getGeoContext(), localPos*Acts::UnitConstants::cm, normal); - std::cout << "MakeSourceLinks::getSourceLinksClusterMover - global from new local: " << Acts::Vector3(globalNew/Acts::UnitConstants::cm) << std::endl; + const Acts::Vector3 globalNew = surf->localToGlobal(tGeometry->geometry().getGeoContext(), localPos * Acts::UnitConstants::cm, normal); + std::cout << "MakeSourceLinks::getSourceLinksClusterMover - global from new local: " << Acts::Vector3(globalNew / Acts::UnitConstants::cm) << std::endl; } Acts::ActsVector<2> loc; loc[Acts::eBoundLoc0] = localPos(0) * Acts::UnitConstants::cm; loc[Acts::eBoundLoc1] = localPos(1) * Acts::UnitConstants::cm; std::array indices = - {Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; + {Acts::BoundIndices::eBoundLoc0, Acts::BoundIndices::eBoundLoc1}; Acts::ActsSquareMatrix<2> cov = Acts::ActsSquareMatrix<2>::Zero(); double clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]); - auto para_errors = _ClusErrPara.get_clusterv5_modified_error(cluster, clusRadius, cluskey); + auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, clusRadius, cluskey); cov(Acts::eBoundLoc0, Acts::eBoundLoc0) = para_errors.first * Acts::UnitConstants::cm2; cov(Acts::eBoundLoc0, Acts::eBoundLoc1) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc0) = 0; cov(Acts::eBoundLoc1, Acts::eBoundLoc1) = para_errors.second * Acts::UnitConstants::cm2; ActsSourceLink::Index index = measurements.size(); - + SourceLink sl(surf->geometryId(), index, cluskey); Acts::SourceLink actsSL{sl}; - Acts::Measurement meas(actsSL, indices, loc, cov); + measurements.emplaceMeasurement<2>(surf->geometryId(), indices, loc, cov); if (m_verbosity > 3) { std::cout << "MakeSourceLinks::getSourceLinksClusterMover - source link " << sl.index() << ", loc : " @@ -512,7 +551,7 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( << ", cov : " << cov.transpose() << std::endl << " geo id " << sl.geometryId() << std::endl; std::cout << "Surface : " << std::endl; - surf.get()->toStream(tGeometry->geometry().getGeoContext(), std::cout); + surf.get()->toStream(tGeometry->geometry().getGeoContext()); std::cout << std::endl; std::cout << "Cluster error " << cluster->getRPhiError() << " , " << cluster->getZError() << std::endl; std::cout << "For key " << cluskey << " with local pos " << std::endl @@ -521,16 +560,15 @@ SourceLinkVec MakeSourceLinks::getSourceLinksClusterMover( } sourcelinks.push_back(actsSL); - measurements.push_back(meas); } SLTrackTimer.stop(); auto SLTime = SLTrackTimer.get_accumulated_time(); if (m_verbosity > 1) - { - std::cout << "PHMakeSourceLinks::getSourceLinksClusterMover - ActsTrkFitter Source Links generation time: " + { + std::cout << "PHMakeSourceLinks::getSourceLinksClusterMover - ActsTrkFitter Source Links generation time: " << SLTime << std::endl; - } + } return sourcelinks; } diff --git a/offline/packages/trackreco/MakeSourceLinks.h b/offline/packages/trackreco/MakeSourceLinks.h index 8acf4f8272..62b5031624 100644 --- a/offline/packages/trackreco/MakeSourceLinks.h +++ b/offline/packages/trackreco/MakeSourceLinks.h @@ -1,17 +1,17 @@ #ifndef TRACKRECO_MAKESOURCELINKS_H #define TRACKRECO_MAKESOURCELINKS_H -#include #include #include -#include #include +#include +#include #include /// Acts includes to create all necessary definitions -#include #include +#include #include @@ -40,51 +40,48 @@ class TrackSeed; class MakeSourceLinks { public: - MakeSourceLinks() = default; + MakeSourceLinks() = default; - void initialize(PHG4TpcGeomContainer* cellgeo); + void initialize(PHG4TpcGeomContainer* cellgeo, ActsGeometry *tGeometry); - void setVerbosity(int verbosity) {m_verbosity = verbosity;} - - void set_pp_mode(bool ispp) { m_pp_mode = ispp; } + void setVerbosity(int verbosity) { m_verbosity = verbosity; } + void set_pp_mode(bool ispp) { m_pp_mode = ispp; } + void set_cluster_edge_rejection(int edge) { m_cluster_edge_rejection = edge; } void ignoreLayer(int layer) { m_ignoreLayer.insert(layer); } SourceLinkVec getSourceLinks( - TrackSeed* /*seed*/, - ActsTrackFittingAlgorithm::MeasurementContainer& /*measurements*/, - TrkrClusterContainer* /*clusters*/, - ActsGeometry* /*geometry*/, - const TpcGlobalPositionWrapper& /*globalpositionWrapper*/, - alignmentTransformationContainer* /*transformMapTransient*/, - std::set< Acts::GeometryIdentifier>& /*transient_id_set*/, - short int /*crossing*/); + TrackSeed* /*seed*/, + ActsTrackFittingAlgorithm::MeasurementContainer& /*measurements*/, + TrkrClusterContainer* /*clusters*/, + ActsGeometry* /*geometry*/, + const TpcGlobalPositionWrapper& /*globalpositionWrapper*/, + alignmentTransformationContainer* /*transformMapTransient*/, + std::set& /*transient_id_set*/, + short int /*crossing*/); void resetTransientTransformMap( - alignmentTransformationContainer* /*transformMapTransient*/, - std::set< Acts::GeometryIdentifier>& /*transient_id_set*/, - ActsGeometry* /*tGeometry*/ ); + alignmentTransformationContainer* /*transformMapTransient*/, + std::set& /*transient_id_set*/, + ActsGeometry* /*tGeometry*/) const; SourceLinkVec getSourceLinksClusterMover( - TrackSeed* /*seed*/, - ActsTrackFittingAlgorithm::MeasurementContainer& /*measurements*/, - TrkrClusterContainer* /*clusters*/, - ActsGeometry* /*geometry*/, - const TpcGlobalPositionWrapper& /*globalpositionWrapper*/, - short int crossing - ); + TrackSeed* /*seed*/, + ActsTrackFittingAlgorithm::MeasurementContainer& /*measurements*/, + TrkrClusterContainer* /*clusters*/, + ActsGeometry* /*geometry*/, + const TpcGlobalPositionWrapper& /*globalpositionWrapper*/, + short int crossing); private: + int m_verbosity = 0; bool m_pp_mode = false; std::set m_ignoreLayer; - + int m_cluster_edge_rejection = 0; TpcClusterMover _clusterMover; ClusterErrorPara _ClusErrPara; - - }; - #endif diff --git a/offline/packages/trackreco/Makefile.am b/offline/packages/trackreco/Makefile.am index 3b70c0e270..7c34ef2652 100644 --- a/offline/packages/trackreco/Makefile.am +++ b/offline/packages/trackreco/Makefile.am @@ -34,7 +34,6 @@ pkginclude_HEADERS = \ MakeActsGeometry.h \ MakeSourceLinks.h \ nanoflann.hpp \ - PHActsGSF.h \ PHActsKDTreeSeeding.h \ PHActsSiliconSeeding.h \ PHActsVertexPropagator.h \ @@ -61,6 +60,7 @@ pkginclude_HEADERS = \ PHTrackPruner.h \ PHTrackCleaner.h \ PHTrackSelector.h \ + PHTrackTrackSeedSynchronization.h \ PHRaveVertexing.h \ PHSiliconHelicalPropagator.h \ PHSiliconSeedMerger.h \ @@ -75,8 +75,9 @@ pkginclude_HEADERS = \ PHTrackSetMerging.h \ PHTrackSetCopyMerging.h \ PHTruthClustering.h \ - PHTruthTrackSeeding.h \ PHTruthSiliconAssociation.h \ + PHTruthTrackFitter.h \ + PHTruthTrackSeeding.h \ PHTruthVertexing.h \ PrelimDistortionCorrection.h \ PrelimDistortionCorrectionAuAu.h \ @@ -101,7 +102,6 @@ ACTS_SOURCES = \ ActsPropagator.cc \ MakeActsGeometry.cc \ MakeSourceLinks.cc \ - PHActsGSF.cc \ PHActsKDTreeSeeding.cc \ PHActsSiliconSeeding.cc \ PHActsTrkFitter.cc \ @@ -119,7 +119,7 @@ AM_CPPFLAGS += -I$(OFFLINE_MAIN)/include/ActsFatras ACTS_LIBS = \ -lActsCore \ - -lActsPluginTGeo \ + -lActsPluginRoot \ -lActsExamplesDetectorTGeo \ -lActsExamplesFramework @@ -157,13 +157,15 @@ libtrack_reco_la_SOURCES = \ PHTrackClusterAssociator.cc \ PHTrackSeeding.cc \ PHTrackSelector.cc \ + PHTrackTrackSeedSynchronization.cc \ PHTrackSetMerging.cc \ PHTrackPropagating.cc \ PHTrackFitting.cc \ PHTruthClustering.cc \ + PHTruthSiliconAssociation.cc \ + PHTruthTrackFitter.cc \ PHTruthTrackSeeding.cc \ PHTruthVertexing.cc \ - PHTruthSiliconAssociation.cc \ PrelimDistortionCorrection.cc \ PrelimDistortionCorrectionAuAu.cc \ SecondaryVertexFinder.cc \ @@ -174,7 +176,6 @@ libtrack_reco_la_SOURCES = \ libtrack_reco_la_LIBADD = \ -lActsCore \ - -lActsPluginTGeo \ -lActsExamplesDetectorTGeo \ -lActsExamplesFramework \ -lcalo_io \ diff --git a/offline/packages/trackreco/PHActsGSF.cc b/offline/packages/trackreco/PHActsGSF.cc index 4d75b257dd..6523e87beb 100644 --- a/offline/packages/trackreco/PHActsGSF.cc +++ b/offline/packages/trackreco/PHActsGSF.cc @@ -102,7 +102,7 @@ int PHActsGSF::InitRun(PHCompositeNode* topNode) m_tGeometry->geometry().magField, bha, 12, 1e-4, - MixtureReductionAlgorithm::KLDistance, false, false); + MixtureReductionAlgorithm::KLDistance, false, false,100.); if (m_actsEvaluator) { @@ -233,7 +233,7 @@ int PHActsGSF::process_event(PHCompositeNode* topNode) auto magcontext = m_tGeometry->geometry().magFieldContext; auto calcontext = m_tGeometry->geometry().calibContext; - auto ppoptions = Acts::PropagatorPlainOptions(); + auto ppoptions = Acts::PropagatorPlainOptions(m_transient_geocontext, magcontext); ActsTrackFittingAlgorithm::GeneralFitterOptions options{ m_transient_geocontext, @@ -294,8 +294,8 @@ ActsTrackFittingAlgorithm::TrackParameters PHActsGSF::makeSeed(SvtxTrack* track, ActsTransformations transformer; auto cov = transformer.rotateSvtxTrackCovToActs(track); - return ActsTrackFittingAlgorithm::TrackParameters::create(psurf, - m_tGeometry->geometry().getGeoContext(), + return ActsTrackFittingAlgorithm::TrackParameters::create(m_tGeometry->geometry().getGeoContext(), + psurf, fourpos, momentum, charge / momentum.norm(), diff --git a/offline/packages/trackreco/PHActsGSF.h b/offline/packages/trackreco/PHActsGSF.h index ce5bea1749..0a1561675a 100644 --- a/offline/packages/trackreco/PHActsGSF.h +++ b/offline/packages/trackreco/PHActsGSF.h @@ -37,7 +37,6 @@ class SvtxTrack; using SourceLink = ActsSourceLink; using FitResult = ActsTrackFittingAlgorithm::TrackFitterResult; using Trajectory = ActsExamples::Trajectories; -using Measurement = Acts::Measurement; using SurfacePtrVec = std::vector; using SourceLinkVec = std::vector; diff --git a/offline/packages/trackreco/PHActsKDTreeSeeding.cc b/offline/packages/trackreco/PHActsKDTreeSeeding.cc index 3bd70410d9..6914a0e60f 100644 --- a/offline/packages/trackreco/PHActsKDTreeSeeding.cc +++ b/offline/packages/trackreco/PHActsKDTreeSeeding.cc @@ -15,8 +15,8 @@ #include #include #include -#include #include +#include #include #include @@ -33,8 +33,7 @@ #include #include -#include -#include +#include #include #include #include @@ -60,7 +59,7 @@ PHActsKDTreeSeeding::PHActsKDTreeSeeding(const std::string& name) { } -//____________________________________________________________________________.. +//______________________ ______________________________________________________.. PHActsKDTreeSeeding::~PHActsKDTreeSeeding() { } @@ -116,23 +115,18 @@ int PHActsKDTreeSeeding::process_event(PHCompositeNode* topNode) SeedContainer PHActsKDTreeSeeding::runSeeder() { - Acts::SeedFinderOrthogonal finder(m_seedFinderConfig); + auto finder = std::make_unique>(m_seedFinderConfig); auto spacePoints = getMvtxSpacePoints(); + Acts::SpacePointContainerConfig spConfig; + Acts::SpacePointContainerOptions spOptions; + spOptions.beamPos = {0, 0}; - std::function< - std::tuple>( - const SpacePoint* sp)> - create_coordinates = [](const SpacePoint* sp) - { - Acts::Vector3 position(sp->x(), sp->y(), sp->z()); - Acts::Vector2 variance(sp->varianceR(), sp->varianceZ()); - return std::make_tuple(position, variance, sp->t()); - }; - + ActsExamples::SpacePointContainer container(spacePoints); + Acts::SpacePointContainer spContainer(spConfig, spOptions, container); /// Call acts seeding algo - SeedContainer seeds = finder.createSeeds(m_seedFinderOptions, - spacePoints, create_coordinates); + auto seeds = finder->createSeeds(m_seedFinderOptions, spContainer); + if (Verbosity() > 1) { std::cout << "Acts::OrthogonalSeeder found " << seeds.size() @@ -148,19 +142,19 @@ void PHActsKDTreeSeeding::fillTrackSeedContainer(SeedContainer& seeds) { auto siseed = std::make_unique(); std::map positions; - - for (auto& spptr : seed.sp()) + const auto& sps = seed.sp(); + for (int spid = 0; spid < 3; spid++) { - auto ckey = spptr->Id(); + auto ckey = sps[spid]->externalSpacePoint()->Id(); siseed->insert_cluster_key(ckey); auto globalPosition = m_tGeometry->getGlobalPosition( ckey, m_clusterMap->findCluster(ckey)); positions.insert(std::make_pair(ckey, globalPosition)); } - - TrackSeedHelper::circleFitByTaubin(siseed.get(),positions, 0, 8); - TrackSeedHelper::lineFit(siseed.get(),positions, 0, 8); + + TrackSeedHelper::circleFitByTaubin(siseed.get(), positions, 0, 8); + TrackSeedHelper::lineFit(siseed.get(), positions, 0, 8); /// Project to INTT and find matches to add to positions findInttMatches(positions, *siseed); @@ -439,7 +433,7 @@ SpacePointPtr PHActsKDTreeSeeding::makeSpacePoint(const Surface& surf, * uncertainties by a tuned factor that gives the v17 performance * Track reconstruction is an art as much as it is a science... */ - SpacePointPtr spPtr(new SpacePoint{key, x, y, z, r, surf->geometryId(), var[0] * m_uncfactor, var[1] * m_uncfactor,std::nullopt}); + SpacePointPtr spPtr(new SpacePoint{key, x, y, z, r, surf->geometryId(), var[0] * m_uncfactor, var[1] * m_uncfactor, std::nullopt}); if (Verbosity() > 2) { @@ -537,8 +531,7 @@ void PHActsKDTreeSeeding::configureSeedFinder() filterCfg.maxSeedsPerSpM = m_maxSeedsPerSpM; m_seedFinderConfig.seedFilter = - std::make_unique>( - Acts::SeedFilter(filterCfg)); + std::make_unique>(filterCfg); m_seedFinderConfig.rMax = m_rMax; m_seedFinderConfig.deltaRMinTopSP = m_deltaRMinTopSP; @@ -561,8 +554,4 @@ void PHActsKDTreeSeeding::configureSeedFinder() m_seedFinderConfig.rMinMiddle = m_rMinMiddle; m_seedFinderConfig.rMaxMiddle = m_rMaxMiddle; - m_seedFinderConfig = - m_seedFinderConfig.toInternalUnits().calculateDerivedQuantities(); - m_seedFinderOptions = - m_seedFinderOptions.toInternalUnits().calculateDerivedQuantities(m_seedFinderConfig); } diff --git a/offline/packages/trackreco/PHActsKDTreeSeeding.h b/offline/packages/trackreco/PHActsKDTreeSeeding.h index f4db9e5f1d..b05abeb39d 100644 --- a/offline/packages/trackreco/PHActsKDTreeSeeding.h +++ b/offline/packages/trackreco/PHActsKDTreeSeeding.h @@ -28,87 +28,88 @@ class TrackSeed; class PHActsKDTreeSeeding : public SubsysReco { public: - PHActsKDTreeSeeding(const std::string& name = "PHActsKDTreeSeeding"); - - ~PHActsKDTreeSeeding() override; - - int Init(PHCompositeNode* topNode) override; - int InitRun(PHCompositeNode* topNode) override; - int process_event(PHCompositeNode* topNode) override; - int End(PHCompositeNode* topNode) override; - - void useTruthClusters(bool truth) { m_useTruthClusters = truth; } - - private: - void configureSeedFinder(); - int getNodes(PHCompositeNode* topNode); - int createNodes(PHCompositeNode* topNode); - SeedContainer runSeeder(); - void fillTrackSeedContainer(SeedContainer& seeds); - std::vector getMvtxSpacePoints(); - SpacePointPtr makeSpacePoint(const Surface& surf, - const TrkrDefs::cluskey key, - TrkrCluster* clus); - - /// Projects circle fit to INTT radii to find possible INTT clusters - /// belonging to MVTX track stub - void findInttMatches(std::map& clusters, - TrackSeed& seed); - - void matchInttClusters(std::map& clusters, - const double xProj[], - const double yProj[], - const double zProj[]); - - Acts::SeedFilterConfig m_seedFilterConfig; - Acts::SeedFinderOrthogonalConfig m_seedFinderConfig; - Acts::SeedFinderOptions m_seedFinderOptions; - - /// configured to seed in the MVTX using the middle layer - /// as the seed anchor - /// Defines volume to search for seeds in - float m_rMax = 200. * Acts::UnitConstants::mm; - float m_deltaRMinTopSP = 1. * Acts::UnitConstants::mm; - float m_deltaRMaxTopSP = 20. * Acts::UnitConstants::mm; - float m_deltaRMinBottomSP = 1. * Acts::UnitConstants::mm; - float m_deltaRMaxBottomSP = 20. * Acts::UnitConstants::mm; - float m_collisionRegionMin = -300 * Acts::UnitConstants::mm; - float m_collisionRegionMax = 300 * Acts::UnitConstants::mm; - float m_zMin = -300. * Acts::UnitConstants::mm; - float m_zMax = 300. * Acts::UnitConstants::mm; - - /// max number of seeds a single middle sp can belong to - float m_maxSeedsPerSpM = 1; - float m_cotThetaMax = 2.9; - float m_sigmaScattering = 5; - float m_radLengthPerSeed = 0.05; - float m_minPt = 100.; // MeV - float m_bFieldInZ = 0.0014; // kTesla - float m_beamPosX = 0; - float m_beamPosY = 0; - - /// Maximum transverse PCA allowed - float m_impactMax = 20. * Acts::UnitConstants::mm; - - /// Middle spacepoint must fall between these two radii - float m_rMinMiddle = 28. * Acts::UnitConstants::mm; - float m_rMaxMiddle = 36. * Acts::UnitConstants::mm; - - int m_nIteration = 0; - std::string m_trackMapName = "SiliconTrackSeedContainer"; - bool m_useTruthClusters = false; - - ClusterErrorPara m_clusErrPara; - float m_uncfactor = 3.175; - const static int m_nInttLayers = 4; - float m_nInttLayerRadii[m_nInttLayers] = {0}; - float m_rPhiSearchWin = 0.1; - - PHG4CylinderGeomContainer* m_geomContainerIntt = nullptr; - TrkrClusterIterationMapv1* m_iterationMap = nullptr; - ActsGeometry* m_tGeometry = nullptr; - TrkrClusterContainer* m_clusterMap = nullptr; - TrackSeedContainer* m_seedContainer = nullptr; +using proxy_type = typename Acts::SpacePointContainer>, Acts::detail::RefHolder>::SpacePointProxyType; + PHActsKDTreeSeeding(const std::string& name = "PHActsKDTreeSeeding"); + + ~PHActsKDTreeSeeding() override; + + int Init(PHCompositeNode* topNode) override; + int InitRun(PHCompositeNode* topNode) override; + int process_event(PHCompositeNode* topNode) override; + int End(PHCompositeNode* topNode) override; + + void useTruthClusters(bool truth) { m_useTruthClusters = truth; } + +private: + void configureSeedFinder(); + int getNodes(PHCompositeNode* topNode); + int createNodes(PHCompositeNode* topNode); + SeedContainer runSeeder(); + void fillTrackSeedContainer(SeedContainer& seeds); + std::vector getMvtxSpacePoints(); + SpacePointPtr makeSpacePoint(const Surface& surf, + const TrkrDefs::cluskey key, + TrkrCluster* clus); + + /// Projects circle fit to INTT radii to find possible INTT clusters + /// belonging to MVTX track stub + void findInttMatches(std::map& clusters, + TrackSeed& seed); + + void matchInttClusters(std::map& clusters, + const double xProj[], + const double yProj[], + const double zProj[]); + + Acts::SeedFilterConfig m_seedFilterConfig; + Acts::SeedFinderOrthogonalConfig m_seedFinderConfig; + Acts::SeedFinderOptions m_seedFinderOptions; + + /// configured to seed in the MVTX using the middle layer + /// as the seed anchor + /// Defines volume to search for seeds in + float m_rMax = 200. * Acts::UnitConstants::mm; + float m_deltaRMinTopSP = 1. * Acts::UnitConstants::mm; + float m_deltaRMaxTopSP = 20. * Acts::UnitConstants::mm; + float m_deltaRMinBottomSP = 1. * Acts::UnitConstants::mm; + float m_deltaRMaxBottomSP = 20. * Acts::UnitConstants::mm; + float m_collisionRegionMin = -300 * Acts::UnitConstants::mm; + float m_collisionRegionMax = 300 * Acts::UnitConstants::mm; + float m_zMin = -300. * Acts::UnitConstants::mm; + float m_zMax = 300. * Acts::UnitConstants::mm; + + /// max number of seeds a single middle sp can belong to + float m_maxSeedsPerSpM = 1; + float m_cotThetaMax = 2.9; + float m_sigmaScattering = 5; + float m_radLengthPerSeed = 0.05; + float m_minPt = 100.; // MeV + float m_bFieldInZ = 0.0014; // kTesla + float m_beamPosX = 0; + float m_beamPosY = 0; + + /// Maximum transverse PCA allowed + float m_impactMax = 20. * Acts::UnitConstants::mm; + + /// Middle spacepoint must fall between these two radii + float m_rMinMiddle = 28. * Acts::UnitConstants::mm; + float m_rMaxMiddle = 36. * Acts::UnitConstants::mm; + + int m_nIteration = 0; + std::string m_trackMapName = "SiliconTrackSeedContainer"; + bool m_useTruthClusters = false; + + ClusterErrorPara m_clusErrPara; + float m_uncfactor = 3.175; + const static int m_nInttLayers = 4; + float m_nInttLayerRadii[m_nInttLayers] = {0}; + float m_rPhiSearchWin = 0.1; + + PHG4CylinderGeomContainer* m_geomContainerIntt = nullptr; + TrkrClusterIterationMapv1* m_iterationMap = nullptr; + ActsGeometry* m_tGeometry = nullptr; + TrkrClusterContainer* m_clusterMap = nullptr; + TrackSeedContainer* m_seedContainer = nullptr; }; #endif // PHACTSKDTREESEEDING_H diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.cc b/offline/packages/trackreco/PHActsSiliconSeeding.cc index d4741a2ca9..8fd7133c39 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.cc +++ b/offline/packages/trackreco/PHActsSiliconSeeding.cc @@ -43,9 +43,7 @@ #ifndef __clang__ #pragma GCC diagnostic pop #endif -#include -#include -#include +#include #include #include @@ -56,6 +54,28 @@ namespace { return x * x; } + + Acts::Vector3 get_line_surface_intersection(const Surface& surf, + const std::vector& fitpars, + const Acts::Vector3& global, + ActsGeometry* tGeometry) + { + Acts::Vector3 const sensorCenter = surf->center(tGeometry->geometry().getGeoContext()) * 0.1; + Acts::Vector3 sensorNormal = -surf->normal(tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1)); + sensorNormal /= sensorNormal.norm(); + + Acts::Vector3 const linePoint(0., fitpars[1], fitpars[3]); + Acts::Vector3 tangent(1., fitpars[0], fitpars[2]); + tangent /= tangent.norm(); + + // Keep the line direction consistent with the measured cluster direction when possible. + if ((global - linePoint).dot(tangent) < 0) + { + tangent = -1. * tangent; + } + + return TrackFitUtils::get_line_plane_intersection(linePoint, tangent, sensorCenter, sensorNormal); + } } // namespace PHActsSiliconSeeding::PHActsSiliconSeeding(const std::string& name) @@ -86,10 +106,9 @@ PHActsSiliconSeeding::~PHActsSiliconSeeding() int PHActsSiliconSeeding::Init(PHCompositeNode* /*topNode*/) { Acts::SeedFilterConfig sfCfg = configureSeedFilter(); - sfCfg = sfCfg.toInternalUnits(); - m_seedFinderCfg.seedFilter = std::make_unique>( - Acts::SeedFilter(sfCfg)); + m_seedFinderCfg.seedFilter = std::make_unique>( + sfCfg); configureSeeder(); configureSPGrid(); @@ -100,10 +119,10 @@ int PHActsSiliconSeeding::Init(PHCompositeNode* /*topNode*/) } // vector containing the map of z bins in the top and bottom layers - m_bottomBinFinder = std::make_unique>( - nphineighbors, zBinNeighborsBottom); - m_topBinFinder = std::make_unique>( - nphineighbors, zBinNeighborsTop); + m_bottomBinFinder = std::make_unique>( + nphineighbors, zBinNeighborsBottom, 0); + m_topBinFinder = std::make_unique>( + nphineighbors, zBinNeighborsTop, 0); if (m_seedAnalysis) { @@ -196,7 +215,8 @@ int PHActsSiliconSeeding::End(PHCompositeNode* /*topNode*/) void PHActsSiliconSeeding::runSeeder() { - Acts::SeedFinder> seedFinder(m_seedFinderCfg); + Acts::SeedFinder> seedFinder(m_seedFinderCfg); auto eventTimer = std::make_unique("eventTimer"); eventTimer->stop(); @@ -210,20 +230,9 @@ void PHActsSiliconSeeding::runSeeder() std::cout << "Seeding for strobe " << strobe << std::endl; } GridSeeds seedVector; - /// Covariance converter functor needed by seed finder - auto covConverter = [=](const SpacePoint& sp, float zAlign, float rAlign, - float sigmaError) - { - Acts::Vector3 position{sp.x(), sp.y(), sp.z()}; - Acts::Vector2 cov; - cov[0] = (sp.m_varianceR + rAlign * rAlign) * sigmaError; - cov[1] = (sp.m_varianceZ + zAlign * zAlign) * sigmaError; - return std::make_tuple(position, cov, sp.t()); - }; - - Acts::Extent rRangeSPExtent; + eventTimer->restart(); - auto spVec = getSiliconSpacePoints(rRangeSPExtent, strobe); + auto spVec = getSiliconSpacePoints(strobe); eventTimer->stop(); spTime += eventTimer->get_accumulated_time(); if (m_seedAnalysis) @@ -231,37 +240,70 @@ void PHActsSiliconSeeding::runSeeder() h_nInputMeas->Fill(spVec.size()); } - Acts::CylindricalSpacePointGrid grid = - Acts::CylindricalSpacePointGridCreator::createGrid( + Acts::SpacePointContainerConfig spConfig; + spConfig.useDetailedDoubleMeasurementInfo = + m_seedFinderCfg.useDetailedDoubleMeasurementInfo; + // Options + // TODO - check beam pos information + Acts::SpacePointContainerOptions spOptions; + spOptions.beamPos = {0., 0.}; + + // Prepare interface SpacePoint backend-ACTS + ActsExamples::SpacePointContainer container(spVec); + // Prepare Acts API + SpacePointContainerRefHolder + spContainer(spConfig, spOptions, container); + + + + Acts::CylindricalSpacePointGrid grid = + Acts::CylindricalSpacePointGridCreator::createGrid( m_gridCfg, m_gridOptions); - Acts::CylindricalSpacePointGridCreator::fillGrid( + Acts::CylindricalSpacePointGridCreator::fillGrid( m_seedFinderCfg, m_seedFinderOptions, grid, - spVec.begin(), spVec.end(), covConverter, - rRangeSPExtent); + spContainer); + + // Compute radius Range + // we rely on the fact the grid is storing the proxies + // with a sorting in the radius + float minRange = std::numeric_limits::max(); + float maxRange = std::numeric_limits::lowest(); + for (const auto& coll : grid) + { + if (coll.empty()) + { + continue; + } + const auto* firstEl = coll.front(); + const auto* lastEl = coll.back(); + minRange = std::min(firstEl->radius(), minRange); + maxRange = std::max(lastEl->radius(), maxRange); + } - std::array, 2UL> navigation; - navigation[1UL] = m_seedFinderCfg.zBinsCustomLooping; + std::array, 3ul> navigation; + navigation[1ul] = m_seedFinderCfg.zBinsCustomLooping; - auto spacePointsGrouping = Acts::CylindricalBinnedGroup( + auto spacePointsGrouping = Acts::CylindricalBinnedGroup( std::move(grid), *m_bottomBinFinder, *m_topBinFinder, std::move(navigation)); /// variable middle SP radial region of interest const Acts::Range1D rMiddleSPRange( - std::floor(rRangeSPExtent.min(Acts::binR) / 2) * 2 + 1.5, - std::floor(rRangeSPExtent.max(Acts::binR) / 2) * 2 - 1.5); + // TODO check these values in current code with Acts::Extent + std::floor(minRange / 2) * 2 + 1.5, + std::floor(maxRange / 2) * 2 - 1.5); eventTimer->restart(); - SeedContainer seeds; + static thread_local std::vector seeds; seeds.clear(); + decltype(seedFinder)::SeedingState state; - state.spacePointData.resize(spVec.size(), - m_seedFinderCfg.useDetailedDoubleMeasurementInfo); + state.spacePointMutableData.resize(spContainer.size()); for (const auto [bottom, middle, top] : spacePointsGrouping) { seedFinder.createSeedsForGroup(m_seedFinderOptions, state, spacePointsGrouping.grid(), - std::back_inserter(seeds), + seeds, bottom, middle, top, @@ -271,15 +313,13 @@ void PHActsSiliconSeeding::runSeeder() seederTime += eventTimer->get_accumulated_time(); eventTimer->restart(); - seedVector.push_back(seeds); - if (m_streaming) { - makeSvtxTracksWithTime(seedVector, strobe); + makeSvtxTracksWithTime(seeds, strobe); } else { - makeSvtxTracks(seedVector); + makeSvtxTracks(seeds); } eventTimer->stop(); @@ -306,26 +346,17 @@ void PHActsSiliconSeeding::runSeeder() return; } -void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, +void PHActsSiliconSeeding::makeSvtxTracksWithTime(const std::vector& seedVector, const int& strobe) { - int numSeeds = 0; + // int numSeeds = 0; int numGoodSeeds = 0; m_seedid = -1; - for (const auto& seeds : seedVector) + for (const auto& seed : seedVector) { - /// loop over acts triplets - for (const auto& seed : seeds) - { - if (Verbosity() > 1) - { - std::cout << "Seed " << numSeeds << " has " - << seed.sp().size() << " measurements " - << std::endl; - } - numSeeds++; + // numSeeds++; if (m_seedAnalysis) { clearTreeVariables(); @@ -334,10 +365,10 @@ void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, std::map positions; std::vector clus_positions; - - for (const auto& spacePoint : seed.sp()) + const auto& sps = seed.sp(); + for (int spid = 0; spid < 3; spid++) { - const auto& cluskey = spacePoint->Id(); + const auto& cluskey = sps[spid]->externalSpacePoint()->Id(); auto globalPosition = m_tGeometry->getGlobalPosition( cluskey, @@ -380,9 +411,10 @@ void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, { // make the svtxtrack seed with both mvtx + intt clusters auto trackSeed = std::make_unique(); - for (const auto& mvtx_clus : seed.sp()) + + for (int spid = 0; spid < 3; spid++) { - const auto& cluskey = mvtx_clus->Id(); + const auto& cluskey = sps[spid]->externalSpacePoint()->Id(); trackSeed->insert_cluster_key(cluskey); } for (auto& intt_clus : intt_clus_vec) @@ -405,9 +437,9 @@ void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, { /// make a single mvtx only seed auto trackSeed = std::make_unique(); - for (const auto& mvtx_clus : seed.sp()) + for (int spid = 0; spid < 3; spid++) { - const auto& cluskey = mvtx_clus->Id(); + const auto& cluskey = sps[spid]->externalSpacePoint()->Id(); trackSeed->insert_cluster_key(cluskey); } TrackSeedHelper::circleFitByTaubin(trackSeed.get(), positions, 0, 7); @@ -418,34 +450,22 @@ void PHActsSiliconSeeding::makeSvtxTracksWithTime(const GridSeeds& seedVector, m_seedContainer->insert(trackSeed.get()); numGoodSeeds++; } - } + } if (Verbosity() > 4) { std::cout << "num good seeds : " << numGoodSeeds << std::endl; } } -void PHActsSiliconSeeding::makeSvtxTracks(const GridSeeds& seedVector) +void PHActsSiliconSeeding::makeSvtxTracks(const std::vector& seedVector) { int numSeeds = 0; int numGoodSeeds = 0; m_seedid = -1; - int strobe = m_lowStrobeIndex; - /// Loop over grid volumes. In our case this will be strobe - for (const auto& seeds : seedVector) + for (const auto& seed : seedVector) { - /// Loop over actual seeds in this grid volume - for (const auto& seed : seeds) - { - if (Verbosity() > 1) - { - std::cout << "Seed " << numSeeds << " has " - << seed.sp().size() << " measurements " - << std::endl; - } - - if (m_seedAnalysis) + if (m_seedAnalysis) { clearTreeVariables(); m_seedid++; @@ -458,9 +478,10 @@ void PHActsSiliconSeeding::makeSvtxTracks(const GridSeeds& seedVector) std::map positions; auto trackSeed = std::make_unique(); - for (const auto& spacePoint : seed.sp()) + const auto& sps = seed.sp(); + for (int spid = 0; spid < 3; spid++) { - const auto& cluskey = spacePoint->Id(); + const auto& cluskey = sps[spid]->externalSpacePoint()->Id(); cluster_keys.push_back(cluskey); trackSeed->insert_cluster_key(cluskey); @@ -478,7 +499,7 @@ void PHActsSiliconSeeding::makeSvtxTracks(const GridSeeds& seedVector) if (Verbosity() > 1) { std::cout << "Adding cluster with x,y " - << spacePoint->x() << ", " << spacePoint->y() + << sps[spid]->externalSpacePoint()->x() << ", " << sps[spid]->externalSpacePoint()->y() << " mm in detector " << (unsigned int) TrkrDefs::getTrkrId(cluskey) << " with cluskey " << cluskey @@ -599,12 +620,7 @@ void PHActsSiliconSeeding::makeSvtxTracks(const GridSeeds& seedVector) std::cout << "Intt fit time " << circlefittime << " and svtx time " << svtxtracktime << std::endl; } - } - strobe++; - if (strobe > m_highStrobeIndex) - { - std::cout << PHWHERE << "Error: some how grid seed vector is not the same as the number of strobes" << std::endl; - } + } if (m_seedAnalysis) @@ -813,15 +829,19 @@ std::vector PHActsSiliconSeeding::findMatches( std::vector& keys, TrackSeed& seed) { - auto fitpars = TrackFitUtils::fitClusters(clusters, keys, true); + auto fitpars = m_zeroField ? TrackFitUtils::fitClustersZeroField(clusters, keys, true) + : TrackFitUtils::fitClusters(clusters, keys, true); float avgtripletx = 0; float avgtriplety = 0; for (auto& pos : clusters) { - avgtripletx += std::cos(std::atan2(pos(1), pos(0))); - avgtriplety += std::sin(std::atan2(pos(1), pos(0))); + + avgtripletx += std::cos(getPhiFromBeamSpot(pos(1), pos(0))); + avgtriplety += std::sin(getPhiFromBeamSpot(pos(1), pos(0))); } + float avgtripletphi = std::atan2(avgtriplety, avgtripletx); + std::vector dummykeys = keys; std::vector dummyclusters = clusters; @@ -889,6 +909,9 @@ std::vector PHActsSiliconSeeding::findMatches( // get an estimate of the phi of the track at this layer // to know which hitsetkeys to look at float layerradius = 0; + float x0 = 0.0; + float y0 = 0.0; + if (layer > 2) { layerradius = m_geomContainerIntt->GetLayerGeom(layer)->get_radius(); @@ -896,12 +919,21 @@ std::vector PHActsSiliconSeeding::findMatches( else { layerradius = m_geomContainerMvtx->GetLayerGeom(layer)->get_radius(); + x0 = m_mvtx_x0; + y0 = m_mvtx_y0; } + float xfitradius_moved = fitpars[1] - x0; + float yfitradius_moved = fitpars[2] - y0; const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(layerradius, fitpars[0], - fitpars[1], fitpars[2]); - - float approximate_phi1 = atan2(yplus, xplus); - float approximate_phi2 = atan2(yminus, xminus); + xfitradius_moved, yfitradius_moved); + float xp = xplus + x0; + float xm = xminus + x0; + float yp = yplus + y0; + float ym = yminus + y0; + + + float approximate_phi1 = getPhiFromBeamSpot(yp, xp); + float approximate_phi2 = getPhiFromBeamSpot(ym, xm); float approximatephi = approximate_phi1; if (std::fabs(normPhi2Pi(approximate_phi2 - avgtripletphi)) < std::fabs(normPhi2Pi(approximate_phi1 - avgtripletphi))) { @@ -911,7 +943,7 @@ std::vector PHActsSiliconSeeding::findMatches( { auto surf = m_tGeometry->maps().getSiliconSurface(hitsetkey); auto surfcenter = surf->center(m_tGeometry->geometry().geoContext); - float surfphi = atan2(surfcenter.y(), surfcenter.x()); + float surfphi = getPhiFromBeamSpot(surfcenter.y(), surfcenter.x()); float dphi = normPhi2Pi(approximatephi - surfphi); /// Check that the projection is within some reasonable amount of the segment @@ -925,7 +957,8 @@ std::vector PHActsSiliconSeeding::findMatches( /// If we added a cluster, refit the track to get a better projection if (dummyclusters.size() > clusters.size()) { - dummypars = TrackFitUtils::fitClusters(dummyclusters, dummykeys, false); + dummypars = m_zeroField ? TrackFitUtils::fitClustersZeroField(dummyclusters, dummykeys, false) + : TrackFitUtils::fitClusters(dummyclusters, dummykeys, false); } auto range = m_clusterMap->getClusters(hitsetkey); for (auto clusIter = range.first; clusIter != range.second; ++clusIter) @@ -942,12 +975,14 @@ std::vector PHActsSiliconSeeding::findMatches( auto* const cluster = clusIter->second; auto glob = m_tGeometry->getGlobalPosition( cluskey, cluster); - auto intersection = TrackFitUtils::get_helix_surface_intersection(surf, fitpars, glob, m_tGeometry); + auto intersection = m_zeroField ? get_line_surface_intersection(surf, fitpars, glob, m_tGeometry) + : TrackFitUtils::get_helix_surface_intersection(surf, fitpars, glob, m_tGeometry); if (!dummypars.empty()) { - intersection = TrackFitUtils::get_helix_surface_intersection(surf, dummypars, glob, m_tGeometry); + intersection = m_zeroField ? get_line_surface_intersection(surf, dummypars, glob, m_tGeometry) + : TrackFitUtils::get_helix_surface_intersection(surf, dummypars, glob, m_tGeometry); } - auto local = (surf->transform(m_tGeometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); + auto local = (surf->localToGlobalTransform(m_tGeometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); local /= Acts::UnitConstants::cm; m_projgx = intersection.x(); m_projgy = intersection.y(); @@ -1136,14 +1171,16 @@ std::vector> PHActsSiliconSeeding::iterateLayers( { std::vector> inttMatches; auto dummypos = positions; - auto fitpars = TrackFitUtils::fitClusters(dummypos, keys, true); + auto fitpars = m_zeroField ? TrackFitUtils::fitClustersZeroField(dummypos, keys, true) + : TrackFitUtils::fitClusters(dummypos, keys, true); float avgtripletx = 0; float avgtriplety = 0; for (const auto& pos : positions) { - avgtripletx += std::cos(std::atan2(pos(1), pos(0))); - avgtriplety += std::sin(std::atan2(pos(1), pos(0))); + avgtripletx += std::cos(getPhiFromBeamSpot(pos(1), pos(0))); + avgtriplety += std::sin(getPhiFromBeamSpot(pos(1), pos(0))); } + float avgtripletphi = std::atan2(avgtriplety, avgtripletx); int layer34timebucket = std::numeric_limits::max(); @@ -1155,13 +1192,29 @@ std::vector> PHActsSiliconSeeding::iterateLayers( } } + // move the fitted circle center the negative of the MVTX center position + float x0 = 0.0; // cm + float y0 = 0.0; for (int layer = startLayer; layer < endLayer; ++layer) { float layerradius = m_geomContainerIntt->GetLayerGeom(layer)->get_radius(); - const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(layerradius, fitpars[0], fitpars[1], fitpars[2]); + if(layer < 3) + { + x0 = m_mvtx_x0; + y0 = m_mvtx_y0; + } - float approximate_phi1 = atan2(yplus, xplus); - float approximate_phi2 = atan2(yminus, xminus); + float xfitradius_moved = fitpars[1] - x0; + float yfitradius_moved = fitpars[2] - y0; + + const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(layerradius, fitpars[0], xfitradius_moved, yfitradius_moved); + + float xp = xplus + x0; + float xm = xminus + x0; + float yp = yplus + y0; + float ym = yminus + y0; + float approximate_phi1 = getPhiFromBeamSpot(yp, xp); + float approximate_phi2 = getPhiFromBeamSpot(ym, xm); float approximatephi = approximate_phi1; if (std::fabs(normPhi2Pi(approximate_phi2 - avgtripletphi)) < std::fabs(normPhi2Pi(approximate_phi1 - avgtripletphi))) { @@ -1171,7 +1224,7 @@ std::vector> PHActsSiliconSeeding::iterateLayers( { auto surf = m_tGeometry->maps().getSiliconSurface(hitsetkey); auto surfcenter = surf->center(m_tGeometry->geometry().geoContext); - float surfphi = atan2(surfcenter.y(), surfcenter.x()); + float surfphi = getPhiFromBeamSpot(surfcenter.y(), surfcenter.x()); if(Verbosity() > 5) { std::cout << "approximate phis " << approximate_phi1 << " " << approximate_phi2 << " using " << approximatephi @@ -1232,8 +1285,9 @@ std::vector> PHActsSiliconSeeding::iterateLayers( auto* const cluster = clusIter->second; auto glob = m_tGeometry->getGlobalPosition( cluskey, cluster); - auto intersection = TrackFitUtils::get_helix_surface_intersection(surf, fitpars, glob, m_tGeometry); - auto local = (surf->transform(m_tGeometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); + auto intersection = m_zeroField ? get_line_surface_intersection(surf, fitpars, glob, m_tGeometry) + : TrackFitUtils::get_helix_surface_intersection(surf, fitpars, glob, m_tGeometry); + auto local = (surf->localToGlobalTransform(m_tGeometry->geometry().getGeoContext())).inverse() * (intersection * Acts::UnitConstants::cm); local /= Acts::UnitConstants::cm; m_projgx = intersection.x(); m_projgy = intersection.y(); @@ -1386,8 +1440,7 @@ SpacePointPtr PHActsSiliconSeeding::makeSpacePoint( return spPtr; } -std::vector PHActsSiliconSeeding::getSiliconSpacePoints(Acts::Extent& rRangeSPExtent, - const int strobe) +std::vector PHActsSiliconSeeding::getSiliconSpacePoints(const int strobe) { std::vector spVec; unsigned int numSiliconHits = 0; @@ -1404,7 +1457,8 @@ std::vector PHActsSiliconSeeding::getSiliconSpacePoints(Acts: if (det == TrkrDefs::TrkrId::mvtxId) { auto strobeId = MvtxDefs::getStrobeId(hitsetkey); - if (strobeId != strobe) + //if (strobeId != strobe) + if (abs(strobeId - strobe) > 1) { continue; } @@ -1432,7 +1486,6 @@ std::vector PHActsSiliconSeeding::getSiliconSpacePoints(Acts: auto* sp = makeSpacePoint(surface, cluskey, cluster).release(); spVec.push_back(sp); - rRangeSPExtent.extend({sp->x(), sp->y(), sp->z()}); numSiliconHits++; } } @@ -1463,8 +1516,6 @@ void PHActsSiliconSeeding::configureSPGrid() m_gridCfg.phiBinDeflectionCoverage = m_numPhiNeighbors; m_gridOptions.bFieldInZ = m_bField; - m_gridCfg = m_gridCfg.toInternalUnits(); - m_gridOptions = m_gridOptions.toInternalUnits(); } Acts::SeedFilterConfig PHActsSiliconSeeding::configureSeedFilter() const @@ -1518,9 +1569,6 @@ void PHActsSiliconSeeding::configureSeeder() m_seedFinderCfg.sigmaError = m_sigmaError; m_seedFinderCfg.helixCutTolerance = m_helixcut; - m_seedFinderCfg = - m_seedFinderCfg.toInternalUnits().calculateDerivedQuantities(); - m_seedFinderOptions = m_seedFinderOptions.toInternalUnits().calculateDerivedQuantities(m_seedFinderCfg); } int PHActsSiliconSeeding::getNodes(PHCompositeNode* topNode) @@ -1713,6 +1761,15 @@ double PHActsSiliconSeeding::normPhi2Pi(const double phi) return returnPhi; } +float PHActsSiliconSeeding::getPhiFromBeamSpot(float clusy, float clusx) const +{ + // Calculate the phi value for (clusx, clusy) relative to the beam spot (x,y) position + + float phirel = std::atan2(clusy - m_beamSpoty, clusx - m_beamSpotx); + + return phirel; +} + void PHActsSiliconSeeding::largeGridSpacing(const bool spacing) { if (!spacing) diff --git a/offline/packages/trackreco/PHActsSiliconSeeding.h b/offline/packages/trackreco/PHActsSiliconSeeding.h index ea3fe2c1ad..d5e49d7a2e 100644 --- a/offline/packages/trackreco/PHActsSiliconSeeding.h +++ b/offline/packages/trackreco/PHActsSiliconSeeding.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -33,7 +34,10 @@ class TrkrClusterIterationMap; class TrkrClusterCrossingAssoc; using GridSeeds = std::vector>>; - +using SpacePointContainerRefHolder = Acts::SpacePointContainer; +using SpacePointProxy_type = typename SpacePointContainerRefHolder::SpacePointProxyType; +using value_type = SpacePointContainerRefHolder::SpacePointProxyType; +using seed_type = Acts::Seed; /** * This class runs the Acts seeder over the MVTX measurements * to create track stubs for the rest of the stub matching pattern @@ -172,10 +176,24 @@ class PHActsSiliconSeeding : public SubsysReco { m_bField = field; } + void zeroField(const bool flag = true) + { + m_zeroField = flag; + } void minpt(const float pt) { m_minSeedPt = pt; } + void set_mvtxCenterXY(const float X, const float Y) + { + m_mvtx_x0 = X; + m_mvtx_y0 = Y; + } + void set_beamSpotXY(const float X, const float Y) + { + m_beamSpotx = X; + m_beamSpoty = Y; + } /// A function to run the seeder with large (true) /// or small (false) grid spacing @@ -202,10 +220,10 @@ class PHActsSiliconSeeding : public SubsysReco Acts::SeedFilterConfig configureSeedFilter() const; /// Take final seeds and fill the TrackSeedContainer - void makeSvtxTracks(const GridSeeds &seedVector); + void makeSvtxTracks(const std::vector& seedVector); /// Take final seeds and fill the TrackSeedContainer - void makeSvtxTracksWithTime(const GridSeeds &seedVector, const int &strobe); + void makeSvtxTracksWithTime(const std::vector& seedVector, const int &strobe); /// Create a seeding space point out of an Acts::SourceLink SpacePointPtr makeSpacePoint( @@ -215,8 +233,7 @@ class PHActsSiliconSeeding : public SubsysReco TrkrCluster *clus); /// Get all space points for the seeder - std::vector getSiliconSpacePoints(Acts::Extent &rRangeSPExtent, - const int strobe); + std::vector getSiliconSpacePoints(const int strobe); void printSeedConfigs(Acts::SeedFilterConfig &sfconfig); bool isTimingMismatched(TrackSeed& seed) const; @@ -243,6 +260,8 @@ class PHActsSiliconSeeding : public SubsysReco short int getCrossingIntt(TrackSeed &si_track); std::vector getInttCrossings(TrackSeed &si_track); + float getPhiFromBeamSpot(float clusy, float clusx) const; + void createHistograms(); void writeHistograms(); double normPhi2Pi(const double phi); @@ -276,7 +295,7 @@ class PHActsSiliconSeeding : public SubsysReco int m_lowStrobeIndex = 0; int m_highStrobeIndex = 1; /// Configuration classes for Acts seeding - Acts::SeedFinderConfig m_seedFinderCfg; + Acts::SeedFinderConfig m_seedFinderCfg; Acts::CylindricalSpacePointGridConfig m_gridCfg; Acts::CylindricalSpacePointGridOptions m_gridOptions; Acts::SeedFinderOptions m_seedFinderOptions; @@ -338,11 +357,12 @@ class PHActsSiliconSeeding : public SubsysReco /// B field value in z direction /// bfield for space point grid neds to be in kiloTesla float m_bField = 1.4 * Acts::UnitConstants::T; + bool m_zeroField = false; std::vector> zBinNeighborsTop; std::vector> zBinNeighborsBottom; int nphineighbors = 1; - std::unique_ptr> m_bottomBinFinder; - std::unique_ptr> m_topBinFinder; + std::unique_ptr> m_bottomBinFinder; + std::unique_ptr> m_topBinFinder; int m_event = 0; @@ -354,6 +374,15 @@ class PHActsSiliconSeeding : public SubsysReco float m_inttzSearchWin = 2.0; // default to one strip width double m_mvtxrPhiSearchWin = 0.2; float m_mvtxzSearchWin = 0.5; + + // collision point in sPHENIX coordinates, from vertex finder (pp run 3) + float m_beamSpotx = -0.072; // cm + float m_beamSpoty = 0.141; // cm + + // center of MVTX barrel in sPHENIX coordinates - default is for Run 3 pp + float m_mvtx_x0 = 0.6; // cm + float m_mvtx_y0 = -0.1; + /// Whether or not to use truth clusters in hit lookup bool m_useTruthClusters = false; diff --git a/offline/packages/trackreco/PHActsTrackProjection.h b/offline/packages/trackreco/PHActsTrackProjection.h index 0b06ae1ef8..79c5c62f5e 100644 --- a/offline/packages/trackreco/PHActsTrackProjection.h +++ b/offline/packages/trackreco/PHActsTrackProjection.h @@ -1,13 +1,14 @@ #ifndef TRACKRECO_PHACTSTRACKPROJECTION_H #define TRACKRECO_PHACTSTRACKPROJECTION_H -#include -#include -#include +#include "ActsPropagator.h" #include +#include -#include "ActsPropagator.h" +#include + +#include #include #include @@ -17,6 +18,8 @@ #include #include +#include +#include class PHCompositeNode; class RawClusterContainer; @@ -26,10 +29,6 @@ class SvtxTrackMap; class SvtxTrack; class SvtxVertexMap; -#include -#include -#include - /** * This class takes final fitted tracks from the Acts track fitting * and projects them out to cylinders with radius at the same radius diff --git a/offline/packages/trackreco/PHActsTrackPropagator.cc b/offline/packages/trackreco/PHActsTrackPropagator.cc index 449b55f44a..6cf4f8cfbf 100644 --- a/offline/packages/trackreco/PHActsTrackPropagator.cc +++ b/offline/packages/trackreco/PHActsTrackPropagator.cc @@ -11,7 +11,6 @@ #include #include -#include #include #include diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index a26ee1fa0a..3e51729785 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 @@ -129,13 +128,12 @@ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) m_fitCfg.dFit = ActsTrackFittingAlgorithm::makeDirectedKalmanFitterFunction( m_tGeometry->geometry().tGeometry, - m_tGeometry->geometry().magField); + m_tGeometry->geometry().magField, true, true, 0.0, Acts::FreeToBoundCorrection(), *Acts::getDefaultLogger("DirectedKalman", level)); MaterialSurfaceSelector selector; if (m_fitSiliconMMs || m_directNavigation) { - m_tGeometry->geometry().tGeometry->visitSurfaces(selector,false); - //std::cout<<"selector.surfaces.size() "<geometry().tGeometry->visitSurfaces(selector, false); m_materialSurfaces = selector.surfaces; } @@ -146,6 +144,7 @@ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) chi2Cuts.insert(std::make_pair(14, 9)); chi2Cuts.insert(std::make_pair(16, 4)); m_outlierFinder.chi2Cuts = chi2Cuts; + if (m_useOutlierFinder) { m_outlierFinder.m_tGeometry = m_tGeometry; @@ -173,7 +172,7 @@ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) { m_evaluator = std::make_unique(m_evalname); m_evaluator->Init(topNode); - if(m_actsEvaluator && !m_simActsEvaluator) + if (m_actsEvaluator && !m_simActsEvaluator) { m_evaluator->isData(); } @@ -182,10 +181,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) { @@ -287,7 +286,7 @@ int PHActsTrkFitter::End(PHCompositeNode* /*topNode*/) { m_evaluator->End(); } - if(m_useOutlierFinder) + if (m_useOutlierFinder) { m_outlierFinder.Write(); } @@ -314,47 +313,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 +379,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 +388,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) @@ -438,19 +436,20 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) SourceLinkVec sourceLinks; MakeSourceLinks makeSourceLinks; - makeSourceLinks.initialize(_tpccellgeo); + makeSourceLinks.initialize(_tpccellgeo, m_tGeometry); makeSourceLinks.setVerbosity(Verbosity()); makeSourceLinks.set_pp_mode(m_pp_mode); - for(const auto& layer : m_ignoreLayer) + makeSourceLinks.set_cluster_edge_rejection(m_cluster_edge_rejection); + 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 +458,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,59 +515,48 @@ 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()); } - + Acts::GeometryContext geoContext{m_alignmentTransformationMapTransient}; // copy transient map for this track into transient geoContext - m_transient_geocontext = m_alignmentTransformationMapTransient; + m_transient_geocontext = geoContext; // position comes from the silicon seed, unless there is no silicon seed Acts::Vector3 position(0, 0, 0); - if (siseed) + if (siseed && !m_ignoreSilicon) { - 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_forceTpcOnlyFit) { - 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; } continue; } + // filter sourcelinks to remove detectors that we don't want to include in the fit + sourceLinks = filterSourceLinks( sourceLinks ); + if (sourceLinks.empty()) { continue; } /// If using directed navigation, collect surface list to navigate - SurfacePtrVec surfaces_tmp; SurfacePtrVec surfaces; if (m_fitSiliconMMs || m_directNavigation) { - sourceLinks = getSurfaceVector(sourceLinks, surfaces_tmp); + + // get surfaces matching source links + const auto surfaces_tmp = getSurfaceVector(sourceLinks); // skip if there is no surfaces if (surfaces_tmp.empty()) @@ -559,26 +566,33 @@ 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; } } + //else if (m_forceTpcOnlyFit) + //{ + // if (surface_apr->geometryId().volume() < 14) + // { + // 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 +608,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()) { @@ -606,6 +620,13 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } } } + // With an empty ACTS material map, m_materialSurfaces is empty. + // Use the measurement surfaces directly for directed navigation. + if (surfaces.empty()) + { + surfaces = surfaces_tmp; + } + checkSurfaceVec(surfaces); if (Verbosity() > 1) { @@ -619,13 +640,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 +656,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) float seedphi = 0; float seedtheta = 0; float seedeta = 0; - if(siseed) + if (siseed && !m_forceTpcOnlyFit) { seedphi = siseed->get_phi(); seedtheta = siseed->get_theta(); @@ -659,7 +680,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 +691,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(); @@ -684,8 +707,8 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) /// Reset the track seed with the dummy covariance auto seed = ActsTrackFittingAlgorithm::TrackParameters::create( - pSurface, m_transient_geocontext, + pSurface, actsFourPos, momentum, charge / momentum.norm(), @@ -699,13 +722,12 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } /// Set host of propagator options for Acts to do e.g. material integration - Acts::PropagatorPlainOptions ppPlainOptions; - auto calibptr = std::make_unique(); CalibratorAdapter calibrator{*calibptr, measurements}; auto magcontext = m_tGeometry->geometry().magFieldContext; auto calibcontext = m_tGeometry->geometry().calibContext; + auto ppPlainOptions = Acts::PropagatorPlainOptions(m_transient_geocontext, magcontext); ActsTrackFittingAlgorithm::GeneralFitterOptions kfOptions{ @@ -723,8 +745,11 @@ 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; + std::cout << "surfaces size " << surfaces.size() << " and source links size " << sourceLinks.size() << std::endl; + } auto result = fitTrack(sourceLinks, seed, kfOptions, surfaces, calibrator, tracks); fitTimer.stop(); @@ -761,7 +786,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 +831,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 +846,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 +860,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(); @@ -855,14 +875,14 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } 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 - std::vector trackTips; + std::vector trackTips; trackTips.reserve(1); const auto& outtrack = fitOutput.value(); if (outtrack.hasReferenceSurface()) @@ -872,12 +892,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) { @@ -921,10 +941,7 @@ bool PHActsTrkFitter::getTrackFitResult( { h_updateTime->Fill(updateTime); } - - Trajectory trajectory(tracks.trackStateContainer(), - trackTips, indexedParams); - + if (m_actsEvaluator) { m_evaluator->evaluateTrackFit(tracks, trackTips, indexedParams, track, @@ -948,90 +965,105 @@ 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); } //__________________________________________________________________________________ -SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks, SurfacePtrVec& surfaces) const +SourceLinkVec PHActsTrkFitter::filterSourceLinks(const SourceLinkVec& sourceLinks ) const { - SourceLinkVec siliconMMSls; - - // if(Verbosity() > 1) - // std::cout << "Sorting " << sourceLinks.size() << " SLs" << std::endl; - + SourceLinkVec filtered; for (const auto& sl : sourceLinks) { const ActsSourceLink asl = sl.get(); - if (Verbosity() > 1) - { - std::cout << "SL available on : " << asl.geometryId() << std::endl; - } - const auto* const surf = m_tGeometry->geometry().tGeometry->findSurface(asl.geometryId()); - if (m_fitSiliconMMs) - { - // skip TPC surfaces - if (m_tGeometry->maps().isTpcSurface(surf)) - { - continue; - } - // also skip micromegas surfaces if not used - if (m_tGeometry->maps().isMicromegasSurface(surf) && !m_useMicromegas) - { - continue; - } - } + // skip TPC surfaces for fitSilicon MMs + if (m_tGeometry->maps().isTpcSurface(surf) && m_fitSiliconMMs) + { continue; } - if(m_forceSiOnlyFit) - { - if(m_tGeometry->maps().isMicromegasSurface(surf)||m_tGeometry->maps().isTpcSurface(surf)) - { - continue; - } - } + // skip micromegas surfaces if not used + if (m_tGeometry->maps().isMicromegasSurface(surf) && !m_useMicromegas) + { continue; } + + // skip everything but silicons if only silicon fit is required + if (m_forceSiOnlyFit && (m_tGeometry->maps().isMicromegasSurface(surf) || m_tGeometry->maps().isTpcSurface(surf)) ) + { continue; } + + if (m_forceTpcOnlyFit && (m_tGeometry->maps().isMicromegasSurface(surf) || m_tGeometry->maps().isSiSurface(surf)) ) + { continue; } // update vectors - siliconMMSls.push_back(sl); - surfaces.push_back(surf); + filtered.push_back(sl); } - if (Verbosity() > 10) + return filtered; +} + +//__________________________________________________________________________________ +SurfacePtrVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks) const +{ + SurfacePtrVec surfaces; + for (const auto& sl : sourceLinks) { - for (const auto& surf : surfaces) - { - std::cout << "Surface vector : " << surf->geometryId() << std::endl; - } + const ActsSourceLink asl = sl.get(); + const auto* const surf = m_tGeometry->geometry().tGeometry->findSurface(asl.geometryId()); + // std::cout << "sl: " << surf->geometryId() << std::endl; + surfaces.push_back(surf); } - return siliconMMSls; + return surfaces; } void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const { + if (surfaces.size() < 2) + { + return; + } + + // Do not assume volume id has the correct layer, check the surface radius + for (unsigned int i = 0; i < surfaces.size() - 1; i++) { + const auto& surface = surfaces.at(i); + if (std::find(m_materialSurfaces.begin(), m_materialSurfaces.end(), surface) != m_materialSurfaces.end()) + { + continue; + } + const auto thisVolume = surface->geometryId().volume(); - const auto thisLayer = surface->geometryId().layer(); - const auto nextSurface = surfaces.at(i + 1); + const Acts::Vector3 this_center = surface->center(m_tGeometry->geometry().getGeoContext()); + double thisRadius = sqrt(this_center.x()*this_center.x()+this_center.y()*this_center.y()); + + const auto* nextSurface = surfaces.at(i + 1); const auto nextVolume = nextSurface->geometryId().volume(); - const auto nextLayer = nextSurface->geometryId().layer(); + const Acts::Vector3 next_center = nextSurface->center(m_tGeometry->geometry().getGeoContext()); + double nextRadius = sqrt(next_center.x()*next_center.x()+next_center.y()*next_center.y()); + + if (surface->geometryId().approach() == 2 || nextSurface->geometryId().approach() == 2) + { + continue; + } /// Implement a check to ensure surfaces are sorted if (nextVolume == thisVolume) { - if (nextLayer < thisLayer) + // if (nextLayer < thisLayer) + if (nextRadius < thisRadius) { std::cout << "PHActsTrkFitter::checkSurfaceVec - " << "Surface not in order... removing surface" - << surface->geometryId() << std::endl; - + << surface->geometryId() << " with radius " << thisRadius << std::endl; + std::cout << " approach " << nextSurface->geometryId().approach() << " volume " << nextSurface->geometryId().volume() << " layer " << nextSurface->geometryId().layer() << std::endl; + std::cout << " Next surface is " << nextSurface->geometryId() << " with radius " << nextRadius << std::endl; surfaces.erase(surfaces.begin() + i); /// Subtract one so we don't skip a surface @@ -1059,10 +1091,10 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const } 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(); @@ -1075,7 +1107,7 @@ void PHActsTrkFitter::updateSvtxTrack( track->identify(); } - if (!m_fitSiliconMMs && !m_forceSiOnlyFit) + if (!m_fitSiliconMMs && !m_forceSiOnlyFit && !m_forceTpcOnlyFit) { track->clear_states(); } @@ -1102,9 +1134,20 @@ void PHActsTrkFitter::updateSvtxTrack( track->set_y(params.position(m_transient_geocontext)(1) / Acts::UnitConstants::cm); track->set_z(params.position(m_transient_geocontext)(2) / Acts::UnitConstants::cm); - track->set_px(params.momentum()(0)); - track->set_py(params.momentum()(1)); - track->set_pz(params.momentum()(2)); + auto* seed = track->get_tpc_seed(); + + if(!m_forceSiOnlyFit) + { + track->set_px(params.momentum()(0)); + track->set_py(params.momentum()(1)); + track->set_pz(params.momentum()(2)); + } + else + { + track->set_px(seed->get_px()); + track->set_py(seed->get_py()); + track->set_pz(seed->get_pz()); + } track->set_charge(params.charge()); track->set_chisq(trajState.chi2Sum); @@ -1133,31 +1176,72 @@ 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(); + pathLength /= Acts::UnitConstants::cm; + + // create track state and add to track + transformer.addTrackState(track, cluskey, pathLength, trackStateParams, m_transient_geocontext); + } + } + + // also propagate to Micromegas if not used for the fit + /* this is be used to get unbiased residuals in TPOT */ + if ((!m_useMicromegas) && 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) + { + const auto& cluskey = *key_iter; + + // make sure cluster is from Micromegas (TPOT) + const auto detId = TrkrDefs::getTrkrId(cluskey); + if (detId != TrkrDefs::micromegasId) + { continue; } + + // get corresponding surface + const auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluskey); + const auto surface = m_tGeometry->maps().getMMSurface(hitsetkey); + if (!surface) { continue; } + + // propagate + auto result = propagator.propagateTrack(params, surface); + if (!result.ok()) { continue; } // get path length and extrapolated parameters auto& [pathLength, trackStateParams] = result.value(); diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index c6e0afec35..47c7b6d055 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include #include @@ -45,7 +45,6 @@ class PHG4TpcGeomContainer; using SourceLink = ActsSourceLink; using FitResult = ActsTrackFittingAlgorithm::TrackFitterResult; using Trajectory = ActsExamples::Trajectories; -using Measurement = Acts::Measurement; using SurfacePtrVec = std::vector; using SourceLinkVec = std::vector; @@ -78,12 +77,23 @@ class PHActsTrkFitter : public SubsysReco m_fitSiliconMMs = fitSiliconMMs; } - /// with direct navigation, force a fit with only silicon hits + /// FOR ALIGNMENT STUDIES ONLY, USE AT OWN RISK. With direct navigation, force a fit with only silicon hits and a full + /// matched (si+tpc track seed). This requires a standard track fit to be run first, followed by refit configured with + /// the option below. NOTE this uses the TPC track seed pT for the final pT value, to compensate for poor pt resolution + /// with the silicon seeds only. void forceSiOnlyFit(bool forceSiOnlyFit) { m_forceSiOnlyFit = forceSiOnlyFit; } + /// FOR ALIGNMENT STUDIES ONLY, USE AT OWN RISK. With direct navigation, force a fit with only tpc hits and a full + /// matched (si+tpc track seed). This requires a standard track fit to be run first, followed by refit configured with + /// the option below. NOTE this has poor pointing as the Si is not used for an initial guess of the track pointing + void forceTpcOnlyFit(bool forceTpcOnlyFit) + { + m_forceTpcOnlyFit = forceTpcOnlyFit; + } + /// require micromegas in SiliconMM fits void setUseMicromegas(bool value) { @@ -130,20 +140,21 @@ 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(const std::string& name) { m_clusterContainerName = name; } void setDirectNavigation(bool flag) { m_directNavigation = flag; } - + void setClusterEdgeRejection(int edge ) { m_cluster_edge_rejection = edge; } private: /// Get all the nodes int getNodes(PHCompositeNode* topNode); @@ -155,26 +166,28 @@ 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 ActsTrackFittingAlgorithm::TrackFitterResult fitTrack( - const std::vector& sourceLinks, - const ActsTrackFittingAlgorithm::TrackParameters& seed, - const ActsTrackFittingAlgorithm::GeneralFitterOptions& - kfOptions, - const SurfacePtrVec& surfSequence, - const CalibratorAdapter& calibrator, - ActsTrackFittingAlgorithm::TrackContainer& tracks); - - /// Functions to get list of sorted surfaces for direct navigation, if - /// applicable - SourceLinkVec getSurfaceVector(const SourceLinkVec& sourceLinks, - SurfacePtrVec& surfaces) const; + const std::vector& sourceLinks, + const ActsTrackFittingAlgorithm::TrackParameters& seed, + const ActsTrackFittingAlgorithm::GeneralFitterOptions& kfOptions, + const SurfacePtrVec& surfSequence, + const CalibratorAdapter& calibrator, + ActsTrackFittingAlgorithm::TrackContainer& tracks); + + // remove all source links for detectors that we don't want to include in the fit + SourceLinkVec filterSourceLinks(const SourceLinkVec& sourceLinks ) const; + + /// get list of sorted surfaces for direct navigation, if applicable + SurfacePtrVec getSurfaceVector(const SourceLinkVec& sourceLinks) const; + + /// check ordering of the surfaces void checkSurfaceVec(SurfacePtrVec& surfaces) const; bool getTrackFitResult(const FitResult& fitOutput, TrackSeed* seed, @@ -198,7 +211,7 @@ class PHActsTrkFitter : public SubsysReco alignmentTransformationContainer* m_alignmentTransformationMap = nullptr; // added for testing purposes alignmentTransformationContainer* m_alignmentTransformationMapTransient = nullptr; std::set m_transient_id_set; - Acts::GeometryContext m_transient_geocontext; + Acts::GeometryContext m_transient_geocontext = Acts::GeometryContext::dangerouslyDefaultConstruct(); SvtxTrackMap* m_trackMap = nullptr; SvtxTrackMap* m_directedTrackMap = nullptr; TrkrClusterContainer* m_clusterContainer = nullptr; @@ -214,6 +227,7 @@ class PHActsTrkFitter : public SubsysReco bool m_fitSiliconMMs = false; bool m_forceSiOnlyFit = false; + bool m_forceTpcOnlyFit = false; /// requires micromegas present when fitting silicon-MM surfaces bool m_useMicromegas = true; @@ -240,9 +254,10 @@ 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"; + int m_cluster_edge_rejection = 0; //!@name evaluator //@{ bool m_actsEvaluator = false; @@ -253,7 +268,7 @@ class PHActsTrkFitter : public SubsysReco //@} //! tracks -// SvtxTrackMap* m_seedTracks = nullptr; + // SvtxTrackMap* m_seedTracks = nullptr; //! tpc global position wrapper TpcGlobalPositionWrapper m_globalPositionWrapper; @@ -268,7 +283,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,19 +307,6 @@ class PHActsTrkFitter : public SubsysReco std::vector m_materialSurfaces = {}; - struct MaterialSurfaceSelector { - std::vector surfaces = {}; - - /// @param surface is the test surface - void operator()(const Acts::Surface* surface) { - if (surface->surfaceMaterial() != nullptr) { - if (std::find(surfaces.begin(), surfaces.end(), surface) == - surfaces.end()) { - surfaces.push_back(surface); - } - } - } - }; }; #endif diff --git a/offline/packages/trackreco/PHCASeeding.cc b/offline/packages/trackreco/PHCASeeding.cc index abfcc6018a..a589cad71c 100644 --- a/offline/packages/trackreco/PHCASeeding.cc +++ b/offline/packages/trackreco/PHCASeeding.cc @@ -31,6 +31,7 @@ #include #include #include // for getLayer, clu... +#include #include // ROOT includes for debugging @@ -57,6 +58,8 @@ #include // for pair, make_pair #include +#include // for uint8_t, uint16_t, uint32_t + //#define _DEBUG_ #if defined(_DEBUG_) @@ -211,6 +214,17 @@ int PHCASeeding::InitializeGeometry(PHCompositeNode* topNode) Acts::Vector3 PHCASeeding::getGlobalPosition(TrkrDefs::cluskey key, TrkrCluster* cluster) const { + /* + unsigned int layer = TrkrDefs::getLayer(key); + unsigned int side = TpcDefs::getSide(key); + unsigned int sector = TpcDefs::getSectorId(key); + std::cout << " _pp_mode = " << _pp_mode + << " layer " << layer + << " side " << side + << " sector " << sector + << " subsurfkey " << cluster->getSubSurfKey() + << std::endl; + */ return _pp_mode ? m_tGeometry->getGlobalPosition(key, cluster) : m_globalPositionWrapper.getGlobalPositionDistortionCorrected(key, cluster, 0); } diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.cc b/offline/packages/trackreco/PHCosmicsTrkFitter.cc index d4664415ad..2c173d2ed2 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.cc +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.cc @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -45,8 +46,8 @@ #include #include -#include #include +#include #include #include @@ -81,7 +82,6 @@ namespace PHCosmicsTrkFitter::PHCosmicsTrkFitter(const std::string& name) : SubsysReco(name) - , m_trajectories(nullptr) { } @@ -114,10 +114,27 @@ int PHCosmicsTrkFitter::InitRun(PHCompositeNode* topNode) { m_ConstField = true; } + auto level = Acts::Logging::FATAL; + if (Verbosity() > 5) + { + level = Acts::Logging::VERBOSE; + } m_fitCfg.fit = ActsTrackFittingAlgorithm::makeKalmanFitterFunction( m_tGeometry->geometry().tGeometry, - m_tGeometry->geometry().magField); + m_tGeometry->geometry().magField, + true, true, 0.0, Acts::FreeToBoundCorrection(), *Acts::getDefaultLogger("Kalman", level)); + + m_fitCfg.dFit = ActsTrackFittingAlgorithm::makeDirectedKalmanFitterFunction( + m_tGeometry->geometry().tGeometry, + m_tGeometry->geometry().magField, true, true, 0.0, Acts::FreeToBoundCorrection(), *Acts::getDefaultLogger("DirectedKalman", level)); + + MaterialSurfaceSelector selector; + if (m_directNavigation) + { + m_tGeometry->geometry().tGeometry->visitSurfaces(selector, false); + m_materialSurfaces = selector.surfaces; + } m_outlierFinder.verbosity = Verbosity(); std::map chi2Cuts; @@ -207,8 +224,6 @@ int PHCosmicsTrkFitter::ResetEvent(PHCompositeNode* /*topNode*/) std::cout << "Reset PHCosmicsTrkFitter" << std::endl; } - m_trajectories->clear(); - return Fun4AllReturnCodes::EVENT_OK; } @@ -244,7 +259,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) std::cout << " seed map size " << m_seedMap->size() << std::endl; } - for (auto track : *m_seedMap) + for (auto* track : *m_seedMap) { if (!track) { @@ -255,10 +270,10 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) unsigned int siid = track->get_silicon_seed_index(); // get the crossing number - auto siseed = m_siliconSeeds->get(siid); + auto* siseed = m_siliconSeeds->get(siid); short crossing = 0; - auto tpcseed = m_tpcSeeds->get(tpcid); + auto* tpcseed = m_tpcSeeds->get(tpcid); if (Verbosity() > 1) { std::cout << "TPC id " << tpcid << std::endl; @@ -282,7 +297,7 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) SourceLinkVec sourceLinks; MakeSourceLinks makeSourceLinks; - makeSourceLinks.initialize(_tpccellgeo); + makeSourceLinks.initialize(_tpccellgeo, m_tGeometry); makeSourceLinks.setVerbosity(Verbosity()); makeSourceLinks.set_pp_mode(false); @@ -295,7 +310,19 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { // silicon source links sourceLinks = makeSourceLinks.getSourceLinks( - siseed, + siseed, + measurements, + m_clusterContainer, + m_tGeometry, + m_globalPositionWrapper, + m_alignmentTransformationMapTransient, + m_transient_id_set, + crossing); + } + + // tpc source links + const auto tpcSourceLinks = makeSourceLinks.getSourceLinks( + tpcseed, measurements, m_clusterContainer, m_tGeometry, @@ -303,18 +330,6 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_alignmentTransformationMapTransient, m_transient_id_set, crossing); - } - - // tpc source links - const auto tpcSourceLinks = makeSourceLinks.getSourceLinks( - tpcseed, - measurements, - m_clusterContainer, - m_tGeometry, - m_globalPositionWrapper, - m_alignmentTransformationMapTransient, - m_transient_id_set, - crossing); sourceLinks.insert(sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end()); @@ -322,150 +337,53 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { continue; } - int charge = 0; - float cosmicslope = 0; - - getCharge(tpcseed, charge, cosmicslope); + Acts::GeometryContext geoContext{m_alignmentTransformationMapTransient}; // copy transient map for this track into transient geoContext - m_transient_geocontext = m_alignmentTransformationMapTransient; - + m_transient_geocontext = geoContext; + + std::vector pos; + std::vector sorted_positions; + // get positions from cluster keys + // TODO: should implement distortions + TrackSeedHelper::position_map_t positions; + for (auto key_iter = tpcseed->begin_cluster_keys(); key_iter != tpcseed->end_cluster_keys(); ++key_iter) { - // get positions from cluster keys - // TODO: should implement distortions - TrackSeedHelper::position_map_t positions; - for( auto key_iter = tpcseed->begin_cluster_keys(); key_iter != tpcseed->end_cluster_keys(); ++key_iter ) - { - const auto& key(*key_iter); - positions.emplace(key, m_tGeometry->getGlobalPosition( key, m_clusterContainer->findCluster(key))); - } - - TrackSeedHelper::circleFitByTaubin(tpcseed, positions, 0, 58); + const auto& key(*key_iter); + positions.emplace(key, m_tGeometry->getGlobalPosition(key, m_clusterContainer->findCluster(key))); + pos.push_back(positions[key]); } + sorted_positions = pos; - float tpcR = fabs(1. / tpcseed->get_qOverR()); - float tpcx = tpcseed->get_X0(); - float tpcy = tpcseed->get_Y0(); + std::sort(sorted_positions.begin(), sorted_positions.end(), [](const Acts::Vector3& a, const Acts::Vector3& b) + { + float aradius = std::sqrt(a.x()*a.x()+a.y()*a.y()); + if(a.y() < 0) + { + aradius *= -1; + } + float bradius = std::sqrt(b.x()*b.x()+b.y()*b.y()); + if(b.y() < 0) + { + bradius *= -1; + } + return aradius > bradius; }); - const auto intersect = - TrackFitUtils::circle_circle_intersection(m_vertexRadius, - tpcR, tpcx, tpcy); - float intx, inty; + TrackSeedHelper::circleFitByTaubin(tpcseed, positions, 0, 58); - if (std::get<1>(intersect) > std::get<3>(intersect)) - { - intx = std::get<0>(intersect); - inty = std::get<1>(intersect); - } - else - { - intx = std::get<2>(intersect); - inty = std::get<3>(intersect); - } - std::vector keys; - std::vector clusPos; - std::copy(tpcseed->begin_cluster_keys(), tpcseed->end_cluster_keys(), std::back_inserter(keys)); - TrackFitUtils::getTrackletClusters(m_tGeometry, m_clusterContainer, - clusPos, keys); - TrackFitUtils::position_vector_t xypoints, rzpoints; - for (auto& pos : clusPos) - { - float clusr = radius(pos.x(), pos.y()); - if (pos.y() < 0) - { - clusr *= -1; - } - - // exclude silicon and tpot clusters for now - if (std::abs(clusr) > 80 || std::abs(clusr) < 30) - { - continue; - } - xypoints.push_back(std::make_pair(pos.x(), pos.y())); - rzpoints.push_back(std::make_pair(pos.z(), clusr)); - } + Acts::Vector3 pca = calculatePCA(tpcseed, sorted_positions); - auto rzparams = TrackFitUtils::line_fit(rzpoints); - float fulllineintz = std::get<1>(rzparams); - float fulllineslope = std::get<0>(rzparams); + Acts::Vector3 momentum = calculateMomentum(tpcseed, sorted_positions); - float slope = tpcseed->get_slope(); - float intz = m_vertexRadius * slope + tpcseed->get_Z0(); + Acts::Vector3 position = pca * Acts::UnitConstants::cm; - Acts::Vector3 inter(intx, inty, intz); - - std::vector tpcparams{tpcR, tpcx, tpcy, tpcseed->get_slope(), - tpcseed->get_Z0()}; - auto tangent = TrackFitUtils::get_helix_tangent(tpcparams, - inter); - - auto tan = tangent.second; - auto pca = tangent.first; - - float p; - if (m_ConstField) - { - p = std::cosh(tpcseed->get_eta()) * fabs(1. / tpcseed->get_qOverR()) * (0.3 / 100) * fieldstrength; - } - else - { - p = tpcseed->get_p(); - } - - tan *= p; - - //! if we got the opposite seed then z will be backwards, so we take the - //! value of tan.z() multiplied by the sign of the slope determined for - //! the full cosmic track - //! same with px/py since a single cosmic produces two seeds that bend - //! in opposite directions - float theta = std::atan(fulllineslope); - /// Normalize to 0(xyparams); - if (fulllineslopexy < 0) - { - momentum.x() = fabs(tan.x()); - } - else - { - momentum.x() = fabs(tan.x()) * -1; - } - momentum.y() = fabs(tan.y()) * -1; - } - - momentum.z() = pz; - Acts::Vector3 position(pca.x(), pca.y(), - (m_vertexRadius - fulllineintz) / fulllineslope); - - position *= Acts::UnitConstants::cm; - if (!is_valid(momentum)) + if (!is_valid(momentum) || !is_valid(position)) { continue; } + int charge = getCharge(tpcseed, sorted_positions); + auto pSurface = Acts::Surface::makeShared( position); auto actsFourPos = Acts::Vector4(position(0), position(1), @@ -481,25 +399,49 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { clearVectors(); m_seed = tpcid; - m_R = tpcR; - m_X0 = tpcx; - m_Y0 = tpcy; - m_Z0 = fulllineintz; - m_slope = fulllineslope; - m_pcax = position(0); - m_pcay = position(1); - m_pcaz = position(2); + m_R = std::abs(1. / tpcseed->get_qOverR()); + m_X0 = tpcseed->get_X0(); + m_Y0 = tpcseed->get_Y0(); + m_Z0 = tpcseed->get_Z0(); + m_slope = tpcseed->get_slope(); + m_pcax = position(0) / Acts::UnitConstants::cm; + m_pcay = position(1) / Acts::UnitConstants::cm; + m_pcaz = position(2) / Acts::UnitConstants::cm; m_px = momentum(0); m_py = momentum(1); m_pz = momentum(2); + m_charge = charge; - fillVectors(siseed, tpcseed); + fillVectors(tpcseed, siseed); + m_x.push_back(position.x() / Acts::UnitConstants::cm); + m_y.push_back(position.y() / Acts::UnitConstants::cm); + m_z.push_back(position.z() / Acts::UnitConstants::cm); + m_r.push_back(radius(position.x(), position.y()) / Acts::UnitConstants::cm); m_tree->Fill(); } + if (m_dumpSeeds) + { + SvtxTrack_v4 newTrack; + newTrack.set_tpc_seed(tpcseed); + newTrack.set_crossing(crossing); + newTrack.set_silicon_seed(siseed); + + unsigned int trid = m_trackMap->size(); + newTrack.set_id(trid); + newTrack.set_px(momentum.x()); + newTrack.set_py(momentum.y()); + newTrack.set_pz(momentum.z()); + newTrack.set_x(position.x()); + newTrack.set_y(position.y()); + newTrack.set_z(position.z()); + newTrack.set_charge(charge); + m_trackMap->insertWithKey(&newTrack, trid); + continue; + } //! Reset the track seed with the dummy covariance auto seed = ActsTrackFittingAlgorithm::TrackParameters::create( - pSurface, m_transient_geocontext, + pSurface, actsFourPos, momentum, charge / momentum.norm(), @@ -519,13 +461,12 @@ void PHCosmicsTrkFitter::loopTracks(Acts::Logging::Level logLevel) } //! Set host of propagator options for Acts to do e.g. material integration - Acts::PropagatorPlainOptions ppPlainOptions; - auto calibptr = std::make_unique(); CalibratorAdapter calibrator{*calibptr, measurements}; auto magcontext = m_tGeometry->geometry().magFieldContext; auto calibcontext = m_tGeometry->geometry().calibContext; + auto ppPlainOptions = Acts::PropagatorPlainOptions(m_transient_geocontext, magcontext); ActsTrackFittingAlgorithm::GeneralFitterOptions kfOptions{ @@ -585,7 +526,7 @@ bool PHCosmicsTrkFitter::getTrackFitResult(FitResult& fitOutput, /// Make a trajectory state for storage, which conforms to Acts track fit /// analysis tool auto& outtrack = fitOutput.value(); - std::vector trackTips; + std::vector trackTips; trackTips.reserve(1); trackTips.emplace_back(outtrack.tipIndex()); Trajectory::IndexedParameters indexedParams; @@ -608,11 +549,6 @@ bool PHCosmicsTrkFitter::getTrackFitResult(FitResult& fitOutput, std::cout << "For trackTip == " << outtrack.tipIndex() << std::endl; } - Trajectory trajectory(tracks.trackStateContainer(), - trackTips, indexedParams); - - m_trajectories->insert(std::make_pair(track->get_id(), trajectory)); - /// Get position, momentum from the Acts output. Update the values of /// the proto track updateSvtxTrack(trackTips, indexedParams, tracks, track); @@ -646,7 +582,7 @@ inline ActsTrackFittingAlgorithm::TrackFitterResult PHCosmicsTrkFitter::fitTrack } void PHCosmicsTrkFitter::updateSvtxTrack( - std::vector& tips, + std::vector& tips, Trajectory::IndexedParameters& paramsMap, ActsTrackFittingAlgorithm::TrackContainer& tracks, SvtxTrack* track) @@ -793,15 +729,6 @@ int PHCosmicsTrkFitter::createNodes(PHCompositeNode* topNode) dstNode->addNode(svtxNode); } - m_trajectories = findNode::getClass>(topNode, "ActsTrajectories"); - if (!m_trajectories) - { - m_trajectories = new std::map; - auto node = - new PHDataNode>(m_trajectories, "ActsTrajectories"); - svtxNode->addNode(node); - } - m_trackMap = findNode::getClass(topNode, _track_map_name); if (!m_trackMap) @@ -815,7 +742,7 @@ int PHCosmicsTrkFitter::createNodes(PHCompositeNode* topNode) if (!m_alignmentStateMap) { m_alignmentStateMap = new SvtxAlignmentStateMap_v1; - auto node = new PHDataNode(m_alignmentStateMap, "SvtxAlignmentStateMap", "PHObject"); + auto* node = new PHDataNode(m_alignmentStateMap, "SvtxAlignmentStateMap", "PHObject"); svtxNode->addNode(node); } @@ -934,7 +861,7 @@ void PHCosmicsTrkFitter::makeBranches() } void PHCosmicsTrkFitter::fillVectors(TrackSeed* tpcseed, TrackSeed* siseed) { - for (auto seed : {tpcseed, siseed}) + for (auto* seed : {tpcseed, siseed}) { if (!seed) { @@ -945,28 +872,18 @@ void PHCosmicsTrkFitter::fillVectors(TrackSeed* tpcseed, TrackSeed* siseed) ++it) { auto key = *it; - auto cluster = m_clusterContainer->findCluster(key); + auto* cluster = m_clusterContainer->findCluster(key); m_locx.push_back(cluster->getLocalX()); - float ly = cluster->getLocalY(); - if (TrkrDefs::getTrkrId(key) == TrkrDefs::TrkrId::tpcId) - { - double drift_velocity = m_tGeometry->get_drift_velocity(); - double zdriftlength = cluster->getLocalY() * drift_velocity; - double surfCenterZ = 52.89; // 52.89 is where G4 thinks the surface center is - double zloc = surfCenterZ - zdriftlength; // converts z drift length to local z position in the TPC in north - unsigned int side = TpcDefs::getSide(key); - if (side == 0) - { - zloc = -zloc; - } - ly = zloc * 10; - } - m_locy.push_back(ly); + m_locy.push_back(cluster->getLocalY()); auto glob = m_tGeometry->getGlobalPosition(key, cluster); m_x.push_back(glob.x()); m_y.push_back(glob.y()); m_z.push_back(glob.z()); float r = std::sqrt(glob.x() * glob.x() + glob.y() * glob.y()); + if (glob.y() < 0) + { + r *= -1; + } m_r.push_back(r); TVector3 globt(glob.x(), glob.y(), glob.z()); m_phi.push_back(globt.Phi()); @@ -974,7 +891,7 @@ void PHCosmicsTrkFitter::fillVectors(TrackSeed* tpcseed, TrackSeed* siseed) m_phisize.push_back(cluster->getPhiSize()); m_zsize.push_back(cluster->getZSize()); auto para_errors = - m_clusErrPara.get_clusterv5_modified_error(cluster, r, key); + ClusterErrorPara::get_clusterv5_modified_error(cluster, r, key); m_ephi.push_back(std::sqrt(para_errors.first)); m_ez.push_back(std::sqrt(para_errors.second)); @@ -998,119 +915,205 @@ void PHCosmicsTrkFitter::clearVectors() m_ez.clear(); } -void PHCosmicsTrkFitter::getCharge( - TrackSeed* track, - // TrkrClusterContainer* clusterContainer, - // ActsGeometry* tGeometry, - // alignmentTransformationContainer* transformMapTransient, - // float vertexRadius, - int& charge, - float& cosmicslope) +int PHCosmicsTrkFitter::getCharge(TrackSeed* tpcseed, + const std::vector& sorted_positions) { - Acts::GeometryContext transient_geocontext; - transient_geocontext = m_alignmentTransformationMapTransient; // set local/global transforms to distortion corrected ones for this track - - std::vector global_vec; - - for (auto clusIter = track->begin_cluster_keys(); - clusIter != track->end_cluster_keys(); - ++clusIter) + Acts::GeometryContext transient_geocontext{m_alignmentTransformationMapTransient}; + + std::vector tpcparams{(float) std::abs(1. / tpcseed->get_qOverR()), + tpcseed->get_X0(), + tpcseed->get_Y0(), + tpcseed->get_slope(), + tpcseed->get_Z0()}; + + float phi0 = std::atan2(sorted_positions[0].y() - tpcparams[2], sorted_positions[0].x() - tpcparams[1]); + int posphi = 0; + int negphi = 0; + // just take the first 4 outermost clusters as a test to determine the bend angle + // from the outermost radial cluster + for (size_t i = 1; i < 5; i++) { - auto key = *clusIter; - auto cluster = m_clusterContainer->findCluster(key); - if (!cluster) + auto cluspos = sorted_positions[i]; + + float phi = std::atan2(cluspos.y() - tpcparams[2], cluspos.x() - tpcparams[1]); + if (phi > phi0) { - std::cout << "MakeSourceLinks::getCharge: Failed to get cluster with key " << key << " for track seed" << std::endl; - continue; + posphi++; } - - auto surf = m_tGeometry->maps().getSurface(key, cluster); - if (!surf) + else { - continue; + negphi++; } + } + int charge = posphi > negphi ? -1 : 1; + if (Verbosity() > 2) + { + std::cout << "charge is " << charge << std::endl; + } - // get cluster global positions - Acts::Vector2 local = m_tGeometry->getLocalCoords(key, cluster); // converts TPC time to z - Acts::Vector3 glob = surf->localToGlobal(transient_geocontext, - local * Acts::UnitConstants::cm, - Acts::Vector3(1, 1, 1)); - glob /= Acts::UnitConstants::cm; + return charge; +} - global_vec.push_back(glob); +Acts::Vector3 PHCosmicsTrkFitter::calculatePCA(TrackSeed* seed, const std::vector& sorted_positions) const +{ + float tpcR = fabs(1. / seed->get_qOverR()); + float tpcx = seed->get_X0(); + float tpcy = seed->get_Y0(); + + // calculate the pcaxy for the seed wrt a line surface located at (0,m_vertexRadius) in x-y plane + float dx = -tpcx; + float dy = m_vertexRadius - tpcy; + float dist = std::sqrt(dx * dx + dy * dy); + float pcax = tpcx + tpcR * (dx / dist); + float pcay = tpcy + tpcR * (dy / dist); + + auto arcLength = [&](float x, float y) + { + float angle = std::atan2(y - tpcy, x - tpcx); + return tpcR * angle; + }; + + float sum_s = 0; + float sum_z = 0; + float sum_ss = 0; + float sum_sz = 0; + int n = sorted_positions.size(); + // Compute the arc-length parameter for each cluster, then fit to a line + // Fit z = a + b*s using simple linear regression + for (const auto& p : sorted_positions) + { + float s = arcLength(p.x(), p.y()); + sum_s += s; + sum_z += p.z(); + sum_ss += s * s; + sum_sz += s * p.z(); } - Acts::Vector3 globalMostOuter(std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()); - Acts::Vector3 globalSecondMostOuter(0, 999999, 0); - float largestR = 0; - // loop over global positions - for (auto& i : global_vec) - { - Acts::Vector3 global = i; - // float r = std::sqrt(square(global.x()) + square(global.y())); - float r = radius(global.x(), global.y()); + float denom = n * sum_ss - sum_s * sum_s; + float b = (n * sum_sz - sum_s * sum_z) / denom; + float a = (sum_z - b * sum_s) / n; - /// use the top hemisphere to determine the charge - if (r > largestR && global.y() > 0) - { - globalMostOuter = i; - largestR = r; - } + // Then evaluate at the arc length of the PCA to get the z position of the PCA + float s_ca = arcLength(pcax, pcay); + float z_ca = a + b * s_ca; + + return Acts::Vector3(pcax, pcay, z_ca); +} + +Acts::Vector3 PHCosmicsTrkFitter::calculateMomentum(TrackSeed* tpcseed, const std::vector& sorted_positions) +{ + // now calculate the momentum vector + const auto intersect = TrackFitUtils::circle_circle_intersection(m_vertexRadius, std::abs(1. / tpcseed->get_qOverR()), tpcseed->get_X0(), tpcseed->get_Y0()); + float intx; + float inty; + + if (std::get<1>(intersect) > std::get<3>(intersect)) + { + intx = std::get<0>(intersect); + inty = std::get<1>(intersect); + } + else + { + intx = std::get<2>(intersect); + inty = std::get<3>(intersect); + } + if (Verbosity() > 2) + { + std::cout << "XY intersection options " << std::get<0>(intersect) << ", " << std::get<1>(intersect) << " and " << std::get<2>(intersect) << ", " << std::get<3>(intersect) << std::endl; } - //! find the closest cluster to the outermost cluster - float maxdr = std::numeric_limits::max(); - for (auto& i : global_vec) + TrackFitUtils::position_vector_t xypoints; + TrackFitUtils::position_vector_t rzpoints; + for (const auto& p : sorted_positions) { - if (i.y() < 0) + float clusr = radius(p.x(), p.y()); + if (p.y() < 0) { - continue; + clusr *= -1; } - float dr = std::sqrt(square(globalMostOuter.x()) + square(globalMostOuter.y())) - std::sqrt(square(i.x()) + square(i.y())); - //! Place a dr cut to get maximum bend due to TPC clusters having - //! larger fluctuations - if (dr < maxdr && dr > 10) + // exclude silicon and tpot clusters for now + if (std::abs(clusr) > 80 || std::abs(clusr) < 30) { - maxdr = dr; - globalSecondMostOuter = i; + continue; } + xypoints.emplace_back(p.x(), p.y()); + rzpoints.emplace_back(p.z(), clusr); } - //! we have to calculate phi WRT the vertex position outside the detector, - //! not at (0,0) - Acts::Vector3 vertex(0, m_vertexRadius, 0); - globalMostOuter -= vertex; - globalSecondMostOuter -= vertex; + auto rzparams = TrackFitUtils::line_fit(rzpoints); + float fulllineslope = std::get<0>(rzparams); + + float slope = tpcseed->get_slope(); + float intz = m_vertexRadius * slope + tpcseed->get_Z0(); + + Acts::Vector3 inter(intx, inty, intz); - const auto firstphi = atan2(globalMostOuter.y(), globalMostOuter.x()); - const auto secondphi = atan2(globalSecondMostOuter.y(), - globalSecondMostOuter.x()); - auto dphi = secondphi - firstphi; + std::vector tpcparams{(float) std::abs(1. / tpcseed->get_qOverR()), + tpcseed->get_X0(), + tpcseed->get_Y0(), + tpcseed->get_slope(), + tpcseed->get_Z0()}; + auto tangent = TrackFitUtils::get_helix_tangent(tpcparams, + inter); - if (dphi > M_PI) + auto tan = tangent.second; + + float p; + if (m_ConstField) { - dphi = 2. * M_PI - dphi; + p = std::cosh(tpcseed->get_eta()) * fabs(1. / tpcseed->get_qOverR()) * (0.3 / 100) * fieldstrength; } - if (dphi < -M_PI) + else { - dphi = 2 * M_PI + dphi; + p = tpcseed->get_p(); } - if (dphi > 0) + tan *= p; + + //! if we got the opposite seed then z will be backwards, so we take the + //! value of tan.z() multiplied by the sign of the slope determined for + //! the full cosmic track + //! same with px/py since a single cosmic produces two seeds that bend + //! in opposite directions + float theta = std::atan(fulllineslope); + /// Normalize to 0(xyparams); + if (fulllineslopexy < 0) + { + momentum.x() = fabs(tan.x()); + } + else + { + momentum.x() = fabs(tan.x()) * -1; + } + momentum.y() = fabs(tan.y()) * -1; + } - return; + momentum.z() = pz; + + return momentum; } diff --git a/offline/packages/trackreco/PHCosmicsTrkFitter.h b/offline/packages/trackreco/PHCosmicsTrkFitter.h index 2619cc7dd2..c3f95cb8a5 100644 --- a/offline/packages/trackreco/PHCosmicsTrkFitter.h +++ b/offline/packages/trackreco/PHCosmicsTrkFitter.h @@ -39,7 +39,6 @@ class TTree; using SourceLink = ActsSourceLink; using FitResult = ActsTrackFittingAlgorithm::TrackFitterResult; using Trajectory = ActsExamples::Trajectories; -using Measurement = Acts::Measurement; using SurfacePtrVec = std::vector; using SourceLinkVec = std::vector; @@ -63,11 +62,13 @@ class PHCosmicsTrkFitter : public SubsysReco int ResetEvent(PHCompositeNode* topNode) override; + void convertSeeds() { m_dumpSeeds = true; } + void setUpdateSvtxTrackStates(bool fillSvtxTrackStates) { m_fillSvtxTrackStates = fillSvtxTrackStates; } - + void directNavigator() { m_directNavigation = true; } void useActsEvaluator(bool actsEvaluator) { m_actsEvaluator = actsEvaluator; @@ -104,14 +105,15 @@ class PHCosmicsTrkFitter : public SubsysReco int createNodes(PHCompositeNode* topNode); void loopTracks(Acts::Logging::Level logLevel); - void getCharge(TrackSeed* track, int& charge, float& cosmicslope); + int getCharge(TrackSeed* tpcseed, const std::vector& sorted_positions); /// Convert the acts track fit result to an svtx track - void updateSvtxTrack(std::vector& tips, + void updateSvtxTrack(std::vector& tips, Trajectory::IndexedParameters& paramsMap, ActsTrackFittingAlgorithm::TrackContainer& tracks, SvtxTrack* track); - + Acts::Vector3 calculatePCA(TrackSeed* seed, const std::vector& sorted_positions) const; + Acts::Vector3 calculateMomentum(TrackSeed* tpcseed, const std::vector& sorted_positions); /// Helper function to call either the regular navigation or direct /// navigation, depending on m_fitSiliconMMs inline ActsTrackFittingAlgorithm::TrackFitterResult fitTrack( @@ -151,7 +153,7 @@ class PHCosmicsTrkFitter : public SubsysReco // Used for distortion correction transformations alignmentTransformationContainer* m_alignmentTransformationMapTransient = nullptr; std::set m_transient_id_set; - Acts::GeometryContext m_transient_geocontext; + Acts::GeometryContext m_transient_geocontext = Acts::GeometryContext::dangerouslyDefaultConstruct(); /// Number of acts fits that returned an error int m_nBadFits = 0; @@ -163,6 +165,8 @@ class PHCosmicsTrkFitter : public SubsysReco /// A bool to update the SvtxTrackState information (or not) bool m_fillSvtxTrackStates = true; + bool m_directNavigation = false; + // do we have a constant field bool m_ConstField = false; double fieldstrength{std::numeric_limits::quiet_NaN()}; @@ -177,7 +181,6 @@ class PHCosmicsTrkFitter : public SubsysReco std::unique_ptr m_evaluator = nullptr; std::string m_evalname = "ActsEvaluator.root"; - std::map* m_trajectories = nullptr; SvtxTrackMap* m_seedTracks = nullptr; //! tpc global position wrapper @@ -200,9 +203,13 @@ class PHCosmicsTrkFitter : public SubsysReco SvtxAlignmentStateMap* m_alignmentStateMap = nullptr; ActsAlignmentStates m_alignStates; + std::vector m_materialSurfaces = {}; + bool m_zeroField = false; PHG4TpcGeomContainer* _tpccellgeo = nullptr; + bool m_dumpSeeds = false; + //! for diagnosing seed param + clusters bool m_seedClusAnalysis = false; TFile* m_outfile = nullptr; diff --git a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc index 197d7039e3..6e18788b17 100644 --- a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc +++ b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.cc @@ -835,7 +835,9 @@ int PHMicromegasTpcTrackMatching::process_event(PHCompositeNode* topNode) * 1/ drphi and dz are actually calculated in Tile's local reference frame, not in world coordinates * 2/ drphi also includes SC distortion correction, which the world coordinates don't */ - std::cout + if(Verbosity() > 1) + { + std::cout << " Try_mms: " << (int) layer << " drphi " << drphi << " dz " << dz @@ -844,6 +846,7 @@ int PHMicromegasTpcTrackMatching::process_event(PHCompositeNode* topNode) << " pt " << tracklet_tpc->get_pt() << " charge " << tracklet_tpc->get_charge() << std::endl; + } } } // end loop over clusters @@ -889,12 +892,12 @@ int PHMicromegasTpcTrackMatching::GetNodes(PHCompositeNode* topNode) } else { - _cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + _cluster_map = findNode::getClass(topNode, _clustermap_name); } if (!_cluster_map) { - std::cerr << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << std::endl; + std::cerr << PHWHERE << " ERROR: Can't find node " << _clustermap_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } diff --git a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h index 58d2004041..23bd75854f 100644 --- a/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h +++ b/offline/packages/trackreco/PHMicromegasTpcTrackMatching.h @@ -42,7 +42,7 @@ class PHMicromegasTpcTrackMatching : public SubsysReco void set_pt_cut( const float pt) { _pt_cut = pt; } void set_dphi_cut( const float dphi) { _dphi_cut = dphi; } void SetIteration(int iter) { _n_iteration = iter; } - + void set_clustermap_name(const std::string& name) { _clustermap_name = name; } void zeroField(const bool flag) { _zero_field = flag; } int Init(PHCompositeNode* topNode) override; int InitRun(PHCompositeNode* topNode) override; @@ -77,7 +77,7 @@ class PHMicromegasTpcTrackMatching : public SubsysReco unsigned int _max_tpc_layer = 55; // pt cut for field-on data - float _pt_cut = 0.5; + float _pt_cut = 0.2; // delta_phi window between the last cluster in the tracklet and the projection float _dphi_cut = 0.9; @@ -89,6 +89,8 @@ class PHMicromegasTpcTrackMatching : public SubsysReco TrackSeedContainer* _tpc_track_map{nullptr}; TrackSeedContainer* _si_track_map{nullptr}; + std::string _clustermap_name = "TRKR_CLUSTER"; + //! default rphi search window for each layer std::array _rphi_search_win{0.25, 13.0}; diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.cc b/offline/packages/trackreco/PHSiliconSeedMerger.cc index 16c0848456..c2e2d3e9b4 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.cc +++ b/offline/packages/trackreco/PHSiliconSeedMerger.cc @@ -1,4 +1,3 @@ - #include "PHSiliconSeedMerger.h" #include @@ -14,34 +13,67 @@ #include #include -#include - -//____________________________________________________________________________.. +/** + * @brief Construct a PHSiliconSeedMerger with the given subsystem name. + * + * Initializes the PHSiliconSeedMerger and forwards the provided subsystem + * name to the base SubsysReco constructor. + * + * @param name Subsystem name used to register this module in the node tree. + */ PHSiliconSeedMerger::PHSiliconSeedMerger(const std::string& name) : SubsysReco(name) { } -//____________________________________________________________________________.. -PHSiliconSeedMerger::~PHSiliconSeedMerger() -{ -} +/** + * @brief Default destructor for PHSiliconSeedMerger. + * + * Performs default cleanup of the merger object and its owned resources. + */ +PHSiliconSeedMerger::~PHSiliconSeedMerger() = default; -//____________________________________________________________________________.. -int PHSiliconSeedMerger::Init(PHCompositeNode*) +/** + * @brief Perform module initialization (no operation required). + * + * This implementation does not perform any setup and always succeeds. + * + * @return int `EVENT_OK` indicating initialization succeeded. + */ +int PHSiliconSeedMerger::Init(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; } -//____________________________________________________________________________.. +/** + * @brief Initializes run-time resources by retrieving required nodes. + * + * Calls getNodes(topNode) to locate and cache containers needed for processing this run. + * + * @param topNode Root of the node tree from which required nodes are retrieved. + * @return int `EVENT_OK` on success, `ABORTEVENT` or another non-zero code on failure. + */ int PHSiliconSeedMerger::InitRun(PHCompositeNode* topNode) { int ret = getNodes(topNode); return ret; } -//____________________________________________________________________________.. -int PHSiliconSeedMerger::process_event(PHCompositeNode*) +/** + * @brief Merge overlapping silicon seed tracks by consolidating MVTX cluster keys. + * + * Detects seeds whose MVTX cluster key sets fully overlap (one set equals the + * intersection) and treats one seed as a duplicate of the other. The merger + * preserves the seed with the larger MVTX key set; if both seeds share the + * same MVTX strobe and seed merging is enabled, the smaller seed's MVTX keys + * are merged into the preserved seed. After consolidation, duplicate seeds are + * erased from the silicon track container and preserved seeds are updated to + * include any newly merged MVTX cluster keys. + * + * @return Fun4AllReturnCodes::EVENT_OK on successful processing. + * + */ +int PHSiliconSeedMerger::process_event(PHCompositeNode* /*unused*/) { std::multimap> matches; std::set seedsToDelete; @@ -56,8 +88,7 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) ++track1ID) { TrackSeed* track1 = m_siliconTracks->get(track1ID); - - if (seedsToDelete.find(track1ID) != seedsToDelete.end()) + if (seedsToDelete.contains(track1ID)) { continue; } @@ -74,7 +105,10 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { continue; } - track1Strobe = MvtxDefs::getStrobeId(ckey); + if (TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId) + { + track1Strobe = MvtxDefs::getStrobeId(ckey); + } mvtx1Keys.insert(ckey); } @@ -90,7 +124,6 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) { continue; } - TrackSeed* track2 = m_siliconTracks->get(track2ID); if (track2 == nullptr) { @@ -110,7 +143,10 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) continue; } mvtx2Keys.insert(ckey); - track2Strobe = MvtxDefs::getStrobeId(ckey); + if (TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId) + { + track2Strobe = MvtxDefs::getStrobeId(ckey); + } } std::vector intersection; @@ -120,19 +156,18 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) mvtx2Keys.end(), std::back_inserter(intersection)); - /// If we have two clusters in common in the triplet, it is likely - /// from the same track - if (intersection.size() > m_clusterOverlap && track1Strobe == track2Strobe) + /// If the intersection fully encompasses one of the tracks, it is completely duplicated + if (intersection.size() == mvtx1Keys.size() || intersection.size() == mvtx2Keys.size()) { if (Verbosity() > 2) { std::cout << "Track " << track1ID << " keys " << std::endl; - for (auto& key : mvtx1Keys) + for (const auto& key : mvtx1Keys) { std::cout << " ckey: " << key << std::endl; } std::cout << "Track " << track2ID << " keys " << std::endl; - for (auto& key : mvtx2Keys) + for (const auto& key : mvtx2Keys) { std::cout << " ckey: " << key << std::endl; } @@ -143,47 +178,64 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) } } - for (auto& key : mvtx2Keys) + /// one of the tracks is encompassed in the other. Take the larger one + std::set keysToKeep; + if (mvtx1Keys.size() >= mvtx2Keys.size()) { - mvtx1Keys.insert(key); + keysToKeep = mvtx1Keys; + if (track1Strobe == track2Strobe && m_mergeSeeds) + { + keysToKeep.insert(mvtx2Keys.begin(), mvtx2Keys.end()); + } + matches.insert(std::make_pair(track1ID, keysToKeep)); + seedsToDelete.insert(track2ID); + if (Verbosity() > 2) + { + std::cout << " will delete seed " << track2ID << std::endl; + } } - - if (Verbosity() > 2) + else { - std::cout << "Match IDed" << std::endl; - for (auto& key : mvtx1Keys) + keysToKeep = mvtx2Keys; + if (track1Strobe == track2Strobe && m_mergeSeeds) { - std::cout << " total track keys " << key << std::endl; + keysToKeep.insert(mvtx1Keys.begin(), mvtx1Keys.end()); + } + matches.insert(std::make_pair(track2ID, keysToKeep)); + seedsToDelete.insert(track1ID); + if (Verbosity() > 2) + { + std::cout << " will delete seed " << track1ID << std::endl; } } - - matches.insert(std::make_pair(track1ID, mvtx1Keys)); - seedsToDelete.insert(track2ID); - break; } } } - for (const auto& [trackKey, mvtxKeys] : matches) + if (m_mergeSeeds) { - auto track = m_siliconTracks->get(trackKey); - if (Verbosity() > 2) + for (const auto& [trackKey, mvtxKeys] : matches) { - std::cout << "original track: " << std::endl; - track->identify(); - } + auto* track = m_siliconTracks->get(trackKey); + if (Verbosity() > 2) + { + std::cout << "original track: " << std::endl; + track->identify(); + } - for (auto& key : mvtxKeys) - { - if (track->find_cluster_key(key) == track->end_cluster_keys()) + for (const auto& key : mvtxKeys) { - track->insert_cluster_key(key); - if (Verbosity() > 2) - std::cout << "adding " << key << std::endl; + if (track->find_cluster_key(key) == track->end_cluster_keys()) + { + track->insert_cluster_key(key); + if (Verbosity() > 2) + { + std::cout << "adding " << key << std::endl; + } + } } } } - for (const auto& key : seedsToDelete) { if (Verbosity() > 2) @@ -195,31 +247,47 @@ int PHSiliconSeedMerger::process_event(PHCompositeNode*) if (Verbosity() > 2) { - for (const auto& seed : *m_siliconTracks) - { - if (!seed) continue; - seed->identify(); - } + printRemainingDuplicates(); } return Fun4AllReturnCodes::EVENT_OK; } -//____________________________________________________________________________.. -int PHSiliconSeedMerger::ResetEvent(PHCompositeNode*) +/** + * @brief Reset per-event state for the merger. + * + * This implementation performs no per-event cleanup and always reports success. + * + * @return Integer status code: `Fun4AllReturnCodes::EVENT_OK`. + */ +int PHSiliconSeedMerger::ResetEvent(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; } -//____________________________________________________________________________.. -int PHSiliconSeedMerger::End(PHCompositeNode*) +/** + * @brief Perform end-of-run shutdown for the silicon seed merger. + * + * @return int EVENT_OK on successful completion. + */ +int PHSiliconSeedMerger::End(PHCompositeNode* /*unused*/) { return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Retrieve required nodes from the top-level node tree and validate availability. + * + * Locates the silicon TrackSeedContainer using m_trackMapName and stores it in + * m_siliconTracks. If the container is not found, the function logs an error + * message and signals an abort for the current event. + * + * @param topNode Root node used to search for the TrackSeedContainer. + * @return int Fun4AllReturnCodes::EVENT_OK on success, Fun4AllReturnCodes::ABORTEVENT if the silicon TrackSeedContainer is not present. + */ int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) { - m_siliconTracks = findNode::getClass(topNode, m_trackMapName.c_str()); + m_siliconTracks = findNode::getClass(topNode, m_trackMapName); if (!m_siliconTracks) { std::cout << PHWHERE << "No silicon track container, can't merge seeds" @@ -229,3 +297,84 @@ int PHSiliconSeedMerger::getNodes(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } + +void PHSiliconSeedMerger::printRemainingDuplicates() +{ + for (unsigned int track1ID = 0; + track1ID != m_siliconTracks->size(); + ++track1ID) + { + std::set mvtx1Keyscheck; + + TrackSeed* seed = m_siliconTracks->get(track1ID); + if (!seed) + { + continue; + } + int strobe1 = -9999; + for (auto iter = seed->begin_cluster_keys(); + iter != seed->end_cluster_keys(); + ++iter) + { + mvtx1Keyscheck.insert(*iter); + if (TrkrDefs::getTrkrId(*iter) == TrkrDefs::mvtxId) + { + strobe1 = MvtxDefs::getStrobeId(*iter); + } + } + + for (unsigned int track2ID = 0; + track2ID != m_siliconTracks->size(); + ++track2ID) + { + std::set mvtx2Keyscheck; + TrackSeed* seed2 = m_siliconTracks->get(track2ID); + if (!seed2) + { + continue; + } + int strobe2 = -9999; + for (auto iter2 = seed2->begin_cluster_keys(); + iter2 != seed2->end_cluster_keys(); + ++iter2) + { + mvtx2Keyscheck.insert(*iter2); + if (TrkrDefs::getTrkrId(*iter2) == TrkrDefs::mvtxId) + { + strobe2 = MvtxDefs::getStrobeId(*iter2); + } + } + std::vector intersectioncheck; + std::set_intersection(mvtx1Keyscheck.begin(), + mvtx1Keyscheck.end(), + mvtx2Keyscheck.begin(), + mvtx2Keyscheck.end(), + std::back_inserter(intersectioncheck)); + if (track1ID != track2ID) + { + if (intersectioncheck.size() == mvtx1Keyscheck.size() || intersectioncheck.size() == mvtx2Keyscheck.size()) + { + std::cout << "After merge, still have duplicate seeds: " + << " seed1 ID " << track1ID << " strobe " << strobe1 << " nkeys " << mvtx1Keyscheck.size() + << " seed2 ID " << track2ID << " strobe " << strobe2 << " nkeys " << mvtx2Keyscheck.size() + << " intersection size " << intersectioncheck.size() + << std::endl; + std::cout << "seed 1 keys " << std::endl; + std::cout << " "; + for (const auto& key : mvtx1Keyscheck) + { + std::cout << key << ", "; + } + std::cout << std::endl; + std::cout << "seed 2 keys " << std::endl; + std::cout << " "; + for (const auto& key : mvtx2Keyscheck) + { + std::cout << key << ", "; + } + std::cout << std::endl; + } + } + } + } +} \ No newline at end of file diff --git a/offline/packages/trackreco/PHSiliconSeedMerger.h b/offline/packages/trackreco/PHSiliconSeedMerger.h index b8227cd581..b07551977d 100644 --- a/offline/packages/trackreco/PHSiliconSeedMerger.h +++ b/offline/packages/trackreco/PHSiliconSeedMerger.h @@ -25,17 +25,52 @@ class PHSiliconSeedMerger : public SubsysReco int ResetEvent(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; + /** + * Set the name of the track seed container to use when retrieving silicon tracks. + * + * @param name Name of the TrackSeedContainer node (defaults to "SiliconTrackSeedContainer"). + */ void trackMapName(const std::string &name) { m_trackMapName = name; } + /** + * Set the maximum number of overlapping clusters considered during seed merging. + * @param nclusters Maximum number of clusters that may overlap (overlap threshold). + */ void clusterOverlap(const unsigned int nclusters) { m_clusterOverlap = nclusters; } + /** + * @brief Allow merging searches to include the INTT detector. + * + * Configure the merger to include INTT clusters in subsequent processing by disabling the MVTX-only restriction. + */ void searchIntt() { m_mvtxOnly = false; } + /** + * Enable merging of silicon seed tracks during event processing. + * + * When enabled, the module will merge overlapping silicon seed tracks where applicable. + */ + void mergeSeeds() { m_mergeSeeds = true; } private: int getNodes(PHCompositeNode *topNode); - + void printRemainingDuplicates(); TrackSeedContainer *m_siliconTracks{nullptr}; std::string m_trackMapName{"SiliconTrackSeedContainer"}; + /** + * Minimum number of clusters that must be shared between two silicon track seeds + * for them to be considered overlapping. + * + * Defaults to 1. + */ unsigned int m_clusterOverlap{1}; - bool m_mvtxOnly{true}; + + bool m_mergeSeeds{false}; + /** + * Restrict seed processing to the MVTX detector only. + * + * When set to `true`, operations that iterate or merge silicon seed tracks + * will be limited to clusters originating from the MVTX vertex detector. + * When `false`, clusters from other silicon detectors are included. + */ + bool m_mvtxOnly{false}; }; #endif // PHSILICONSEEDMERGER_H diff --git a/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc b/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc index 2e66a6df28..6aaae4bf93 100644 --- a/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc +++ b/offline/packages/trackreco/PHSiliconTpcTrackMatching.cc @@ -445,10 +445,10 @@ int PHSiliconTpcTrackMatching::GetNodes(PHCompositeNode *topNode) svtxNode->addNode(node); } - _cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + _cluster_map = findNode::getClass(topNode, _cluster_map_name); if (!_cluster_map) { - std::cout << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << std::endl; + std::cout << PHWHERE << " ERROR: Can't find node " <<_cluster_map_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } diff --git a/offline/packages/trackreco/PHSiliconTpcTrackMatching.h b/offline/packages/trackreco/PHSiliconTpcTrackMatching.h index acb157bd83..6de4a1dd3a 100644 --- a/offline/packages/trackreco/PHSiliconTpcTrackMatching.h +++ b/offline/packages/trackreco/PHSiliconTpcTrackMatching.h @@ -139,7 +139,10 @@ class PHSiliconTpcTrackMatching : public SubsysReco, public PHParameterInterface void set_file_name(const std::string &name) { _file_name = name; } void set_pp_mode(const bool flag) { _pp_mode = flag; } void set_use_intt_crossing(const bool flag) { _use_intt_crossing = flag; } - + void set_cluster_map_name(const std::string &name) + { + _cluster_map_name = name; + } int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *) override; @@ -210,6 +213,7 @@ class PHSiliconTpcTrackMatching : public SubsysReco, public PHParameterInterface int _n_iteration = 0; std::string _track_map_name = "TpcTrackSeedContainer"; std::string _silicon_track_map_name = "SiliconTrackSeedContainer"; + std::string _cluster_map_name = "TRKR_CLUSTER"; std::string m_fieldMap = "1.4"; std::vector getTrackletClusterList(TrackSeed* tracklet); }; diff --git a/offline/packages/trackreco/PHSimpleKFProp.cc b/offline/packages/trackreco/PHSimpleKFProp.cc index b8f769b45a..3e4d80d869 100644 --- a/offline/packages/trackreco/PHSimpleKFProp.cc +++ b/offline/packages/trackreco/PHSimpleKFProp.cc @@ -49,6 +49,7 @@ #include +#include #include #include #include @@ -60,7 +61,7 @@ namespace { // square template - inline constexpr T square(const T& x) + constexpr T square(const T& x) { return x * x; } @@ -72,12 +73,6 @@ PHSimpleKFProp::PHSimpleKFProp(const std::string& name) : SubsysReco(name) {} -//______________________________________________________ -int PHSimpleKFProp::End(PHCompositeNode* /*unused*/) -{ - return Fun4AllReturnCodes::EVENT_OK; -} - //______________________________________________________ int PHSimpleKFProp::InitRun(PHCompositeNode* topNode) { @@ -89,7 +84,7 @@ int PHSimpleKFProp::InitRun(PHCompositeNode* topNode) // load magnetic field from node tree /* note: if field is not found it is created with default configuration, as defined in PHFieldUtility */ - const auto field_map = PHFieldUtility::GetFieldMapNode(nullptr, topNode); + auto *const field_map = PHFieldUtility::GetFieldMapNode(nullptr, topNode); // alice kalman filter fitter = std::make_unique(_cluster_map, field_map, _min_clusters_per_track, _max_sin_phi, Verbosity()); @@ -104,7 +99,7 @@ int PHSimpleKFProp::InitRun(PHCompositeNode* topNode) fitter->setFixedClusterError(2, _fixed_clus_err.at(2)); // properly set constField in ALICEKF, based on PHFieldConfig - const auto field_config = PHFieldUtility::GetFieldConfigNode(nullptr, topNode); + auto *const field_config = PHFieldUtility::GetFieldConfigNode(nullptr, topNode); if( field_config->get_field_config() == PHFieldConfig::kFieldUniform ) { fitter->setConstBField(field_config->get_field_mag_z()); } @@ -154,7 +149,7 @@ int PHSimpleKFProp::get_nodes(PHCompositeNode* topNode) } // tpc grometry - auto geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); + auto *geom_container = findNode::getClass(topNode, "TPCGEOMCONTAINER"); if (!geom_container) { std::cerr << PHWHERE << "ERROR: Can't find node TPCGEOMCONTAINER" << std::endl; @@ -230,7 +225,7 @@ int PHSimpleKFProp::process_event(PHCompositeNode* topNode) } // if not a TPC track, ignore - auto track = _track_map->get(track_it); + auto *track = _track_map->get(track_it); const bool is_tpc = std::any_of( track->begin_cluster_keys(), track->end_cluster_keys(), @@ -247,7 +242,7 @@ int PHSimpleKFProp::process_event(PHCompositeNode* topNode) // copy seed clusters position into local map std::map trackClusPositions; std::transform(track->begin_cluster_keys(), track->end_cluster_keys(), std::inserter(trackClusPositions, trackClusPositions.end()), - [globalPositions](const auto& key) + [&globalPositions](const auto& key) { return std::make_pair(key, globalPositions.at(key)); }); /// Can't circle fit a seed with less than 3 clusters, skip it @@ -322,7 +317,7 @@ int PHSimpleKFProp::process_event(PHCompositeNode* topNode) // copy seed clusters position into local map std::map pretrackClusPositions; std::transform(pretrack.begin_cluster_keys(), pretrack.end_cluster_keys(), std::inserter(pretrackClusPositions, pretrackClusPositions.end()), - [globalPositions](const auto& key) + [&globalPositions](const auto& key) { return std::make_pair(key, globalPositions.at(key)); }); // fit seed @@ -335,7 +330,7 @@ int PHSimpleKFProp::process_event(PHCompositeNode* topNode) if (finalchain.size() > kl.at(0).size()) { - local_chains.push_back(std::move(finalchain)); + local_chains.push_back(finalchain); } else { @@ -897,9 +892,9 @@ bool PHSimpleKFProp::PropagateStep( // search for closest available cluster within window double query_pt[3] = {new_tx, new_ty, new_tz}; - std::vector index_out(1); - std::vector distance_out(1); - int n_results = _kdtrees[next_layer]->knnSearch(&query_pt[0], 1, &index_out[0], &distance_out[0]); + std::array index_out{}; + std::array distance_out{}; + int n_results = _kdtrees[next_layer]->knnSearch(&query_pt[0], 1, index_out.data(), distance_out.data()); // if no results, then no cluster to add, but propagation is not necessarily done if (!n_results) @@ -912,9 +907,9 @@ bool PHSimpleKFProp::PropagateStep( return true; } const std::vector& point = _ptclouds[next_layer]->pts[index_out[0]]; - TrkrDefs::cluskey closest_ckey = (*((int64_t*) &point[3])); + TrkrDefs::cluskey closest_ckey = std::bit_cast(point[3]); TrkrCluster* clusterCandidate = _cluster_map->findCluster(closest_ckey); - const auto candidate_globalpos = globalPositions.at(closest_ckey); + const auto &candidate_globalpos = globalPositions.at(closest_ckey); const double cand_x = candidate_globalpos(0); const double cand_y = candidate_globalpos(1); const double cand_z = candidate_globalpos(2); @@ -1235,11 +1230,6 @@ std::vector PHSimpleKFProp::PropagateTrack(TrackSeed* track, std::cout << std::endl; } - // get layer for each cluster - std::vector layers; - std::transform(ckeys.begin(), ckeys.end(), std::back_inserter(layers), [](const TrkrDefs::cluskey& key) - { return TrkrDefs::getLayer(key); }); - double old_phi = track_phi; unsigned int old_layer = TrkrDefs::getLayer(ckeys[0]); if (Verbosity() > 1) @@ -1376,7 +1366,7 @@ void PHSimpleKFProp::rejectAndPublishSeeds(std::vector& seeds, con PositionMap local; std::transform(seed.begin_cluster_keys(), seed.end_cluster_keys(), std::inserter(local, local.end()), - [positions](const auto& key) + [&positions](const auto& key) { return std::make_pair(key, positions.at(key)); }); TrackSeedHelper::circleFitByTaubin(&seed,local, 7, 55); TrackSeedHelper::lineFit(&seed,local, 7, 55); diff --git a/offline/packages/trackreco/PHSimpleKFProp.h b/offline/packages/trackreco/PHSimpleKFProp.h index 9a09d65f06..7c4f2726c5 100644 --- a/offline/packages/trackreco/PHSimpleKFProp.h +++ b/offline/packages/trackreco/PHSimpleKFProp.h @@ -47,7 +47,6 @@ class PHSimpleKFProp : public SubsysReco int InitRun(PHCompositeNode* topNode) override; int process_event(PHCompositeNode* topNode) override; - int End(PHCompositeNode* topNode) override; // noop void set_field_dir(const double) @@ -141,8 +140,8 @@ class PHSimpleKFProp : public SubsysReco PositionMap PrepareKDTrees(); bool TransportAndRotate( - double old_layer, - double new_layer, + double old_radius, + double new_radius, double& phi, GPUTPCTrackParam& kftrack, GPUTPCTrackParam::GPUTPCTrackFitParam& fp) const; @@ -161,7 +160,7 @@ class PHSimpleKFProp : public SubsysReco // which means we have to have a way to directly pass a list of clusters in order to extend looping tracks std::vector PropagateTrack(TrackSeed* track, PropagationDirection direction, GPUTPCTrackParam& aliceSeed, const PositionMap& globalPositions) const; std::vector PropagateTrack(TrackSeed* track, std::vector& ckeys, PropagationDirection direction, GPUTPCTrackParam& aliceSeed, const PositionMap& globalPositions) const; - std::vector> RemoveBadClusters(const std::vector>& seeds, const PositionMap& globalPositions) const; + std::vector> RemoveBadClusters(const std::vector>& chains, const PositionMap& globalPositions) const; template struct KDPointCloud diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.cc b/offline/packages/trackreco/PHSimpleVertexFinder.cc index 3d3e4a9fda..954e790ba6 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.cc +++ b/offline/packages/trackreco/PHSimpleVertexFinder.cc @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include @@ -263,7 +263,7 @@ int PHSimpleVertexFinder::process_event(PHCompositeNode * /*topNode*/) { unsigned int thisid = it + vertex_id; // the address of the vertex in the event - auto svtxVertex = std::make_unique(); + auto svtxVertex = std::make_unique(); svtxVertex->set_chisq(0.0); svtxVertex->set_ndof(0); @@ -515,34 +515,13 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr1->get_silicon_seed(); - if (!siliconseed) - { - continue; - } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) - { - continue; - } - if (Verbosity() > 3) - { - std::cout << " tr1 id " << id1 << " has nmvtx at least " << nmvtx << std::endl; - } + continue; + } + if (_require_intt && !passClusterRequirement(tr1, "INTT")) + { + continue; } // look for close DCA matches with all other such tracks @@ -554,34 +533,13 @@ void PHSimpleVertexFinder::checkDCAs(SvtxTrackMap *track_map) { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr2, "MVTX")) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr2->get_silicon_seed(); - if (!siliconseed) - { - continue; - } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) - { - continue; - } - if (Verbosity() > 3) - { - std::cout << " tr2 id " << id2 << " has nmvtx at least " << nmvtx << std::endl; - } + continue; + } + if (_require_intt && !passClusterRequirement(tr2, "INTT")) + { + continue; } // find DCA of these two tracks @@ -616,13 +574,20 @@ void PHSimpleVertexFinder::checkDCAsZF(SvtxTrackMap *track_map) // tr1->identify(); TrackSeed *siliconseed = tr1->get_silicon_seed(); - if (_require_mvtx) - { - if (!siliconseed) - { - continue; - } - } + const bool needs_mvtx_seed = _require_mvtx && _nmvtx_required > 0; + const bool needs_intt_seed = _require_intt && _nintt_required > 0; + if ((needs_mvtx_seed || needs_intt_seed) && !siliconseed) + { + continue; + } + if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) + { + continue; + } + if (_require_intt && !passClusterRequirement(tr1, "INTT")) + { + continue; + } TrackSeed *tpcseed = tr1->get_tpc_seed(); std::vector global_vec; @@ -797,34 +762,13 @@ void PHSimpleVertexFinder::checkDCAs() { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr1, "MVTX")) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr1->get_silicon_seed(); - if (!siliconseed) - { - continue; - } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) - { - continue; - } - if (Verbosity() > 3) - { - std::cout << " tr1 id " << id1 << " has nmvtx at least " << nmvtx << std::endl; - } + continue; + } + if (_require_intt && !passClusterRequirement(tr1, "INTT")) + { + continue; } // look for close DCA matches with all other such tracks @@ -836,36 +780,14 @@ void PHSimpleVertexFinder::checkDCAs() { continue; } - if (_require_mvtx) + if (_require_mvtx && !passClusterRequirement(tr2, "MVTX")) { - unsigned int nmvtx = 0; - TrackSeed *siliconseed = tr2->get_silicon_seed(); - if (!siliconseed) - { - continue; - } - - for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) - { - if (TrkrDefs::getTrkrId(*clusit) == TrkrDefs::mvtxId) - { - nmvtx++; - } - if (nmvtx >= _nmvtx_required) - { - break; - } - } - if (nmvtx < _nmvtx_required) - { - continue; - } - if (Verbosity() > 3) - { - std::cout << " tr2 id " << id2 << " has nmvtx at least " << nmvtx << std::endl; - } + continue; + } + if (_require_intt && !passClusterRequirement(tr2, "INTT")) + { + continue; } - // find DCA of these two tracks if (Verbosity() > 3) { @@ -1324,3 +1246,53 @@ double PHSimpleVertexFinder::getAverage(std::vector &v) return avge; } + +bool PHSimpleVertexFinder::passClusterRequirement(SvtxTrack *track, const std::string &type) +{ + bool pass = false; + + std::vector acceptable_types = {"MVTX", "INTT"}; + bool accept_this_type = std::find(acceptable_types.begin(), acceptable_types.end(), type) != acceptable_types.end(); + + if (!accept_this_type) + { + if (Verbosity() > 3) + { + std::cout << "type " << type << " was not recognised" << std::endl; + } + return false; + } + + unsigned int _nclus_required = type == "MVTX" ? _nmvtx_required : _nintt_required; + if (_nclus_required == 0) + { + return true; + } + + TrackSeed *siliconseed = track->get_silicon_seed(); + if (!siliconseed) + { + return false; + } + + unsigned int nclus = 0; + for (auto clusit = siliconseed->begin_cluster_keys(); clusit != siliconseed->end_cluster_keys(); ++clusit) + { + uint8_t trkrId = type == "MVTX" ? TrkrDefs::mvtxId : TrkrDefs::inttId; + if (TrkrDefs::getTrkrId(*clusit) == trkrId) + { + nclus++; + } + if (nclus >= _nclus_required) + { + pass = true; + } + } + + if (Verbosity() > 3) + { + std::cout << " track id " << track->get_id() << " has " << nclus << " clusters for " << type << std::endl; + } + + return pass; +} diff --git a/offline/packages/trackreco/PHSimpleVertexFinder.h b/offline/packages/trackreco/PHSimpleVertexFinder.h index da0e36fabf..6520174937 100644 --- a/offline/packages/trackreco/PHSimpleVertexFinder.h +++ b/offline/packages/trackreco/PHSimpleVertexFinder.h @@ -46,16 +46,18 @@ class PHSimpleVertexFinder : public SubsysReco void setBeamSpotCutY(const double cutlo, const double cuthi) { _beamline_y_cut_lo = cutlo; _beamline_y_cut_hi = cuthi; } void setDcaCut(const double cut) { _base_dcacut = cut; } void setTrackQualityCut(double cut) { _qual_cut = cut; } - void setRequireMVTX(bool set) { _require_mvtx = set; } + void setRequireMVTX(bool set = true) { _require_mvtx = set; } void setNmvtxRequired(unsigned int n) { _nmvtx_required = n; } + void setRequireINTT(bool set = true) { _require_intt = set; } + void setNinttRequired(unsigned int n) { _nintt_required = n; } void setTrackPtCut(const double cut) { _track_pt_cut = cut; } // void setUseTrackCovariance(bool set) {_use_track_covariance = set;} void setOutlierPairCut(const double cut) { _outlier_cut = cut; } void setTrackMapName(const std::string &name) { _track_map_name = name; } void setVertexMapName(const std::string &name) { _vertex_map_name = name; } - void zeroField(const bool flag) { _zero_field = flag; } - void setTrkrClusterContainerName(std::string &name){ m_clusterContainerName = name; } - void set_pp_mode(bool mode) { _pp_mode = mode; } + void zeroField(const bool flag = true) { _zero_field = flag; } + void setTrkrClusterContainerName(const std::string &name){ m_clusterContainerName = name; } + void set_pp_mode(bool mode = true) { _pp_mode = mode; } private: int GetNodes(PHCompositeNode *topNode); @@ -75,6 +77,7 @@ class PHSimpleVertexFinder : public SubsysReco void removeOutlierTrackPairs(); double getMedian(std::vector &v); double getAverage(std::vector &v); + bool passClusterRequirement(SvtxTrack *track, const std::string &type = "MVTX"); SvtxTrackMap *_track_map{nullptr}; TrkrClusterContainer* _cluster_map{nullptr}; @@ -91,7 +94,9 @@ class PHSimpleVertexFinder : public SubsysReco double _beamline_y_cut_hi = 0.2; double _qual_cut = 10.0; bool _require_mvtx = true; - unsigned int _nmvtx_required = 3; + bool _require_intt = false; + unsigned int _nmvtx_required = 2; + unsigned int _nintt_required = 1; double _track_pt_cut = 0.0; double _outlier_cut = 0.015; diff --git a/offline/packages/trackreco/PHTpcDeltaZCorrection.h b/offline/packages/trackreco/PHTpcDeltaZCorrection.h index 46d099f587..4d383cc854 100644 --- a/offline/packages/trackreco/PHTpcDeltaZCorrection.h +++ b/offline/packages/trackreco/PHTpcDeltaZCorrection.h @@ -32,7 +32,7 @@ class PHTpcDeltaZCorrection : public SubsysReco, public PHParameterInterface int process_event(PHCompositeNode *topNode) override; int End(PHCompositeNode *topNode) override; void SetDefaultParameters() override; - void setTrkrClusterContainerName(std::string &name) { m_clusterContainerName = name; } + void setTrkrClusterContainerName(const std::string &name) { m_clusterContainerName = name; } private: /// load nodes diff --git a/offline/packages/trackreco/PHTrackPruner.cc b/offline/packages/trackreco/PHTrackPruner.cc index fe0e0a137e..6e0cdb9878 100644 --- a/offline/packages/trackreco/PHTrackPruner.cc +++ b/offline/packages/trackreco/PHTrackPruner.cc @@ -34,8 +34,6 @@ #include // for _Rb_tree_const_iterator #include // for pair -using namespace std; - namespace { //! get cluster keys from a given track @@ -83,9 +81,6 @@ PHTrackPruner::PHTrackPruner(const std::string &name) { } -//____________________________________________________________________________.. -PHTrackPruner::~PHTrackPruner() = default; - //____________________________________________________________________________.. int PHTrackPruner::InitRun(PHCompositeNode *topNode) { @@ -103,49 +98,57 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) { // _tpc_seed_map contains the TPC seed track stubs // _si_seed_map contains the silicon seed track stubs - // _svtx_seed_map contains the combined silicon and tpc track seeds // _svtx_track_map contains the fitted acts track stubs if (Verbosity() > 0) { - cout << PHWHERE << " TPC seed map size " << _tpc_seed_map->size() - << " Silicon seed map size " << _si_seed_map->size() - << " Svtx seed map size " << _svtx_seed_map->size() - << " Svtx track map size " << _svtx_track_map->size() - << endl; + std::cout << PHWHERE << " TPC seed map size " << _tpc_seed_map->size() + << " Silicon seed map size " << _si_seed_map->size() + << " Svtx track map size " << _svtx_track_map->size() + << std::endl; } - if (_svtx_track_map->size() == 0) + if (_svtx_track_map->empty()) { return Fun4AllReturnCodes::EVENT_OK; } - std::multimap good_matches; + std::multimap good_matches; + + // increment number of processed tracks + m_total_tracks += _svtx_track_map->size(); for (auto &iter : *_svtx_track_map) { - _svtx_track = iter.second; + auto* svtx_track = iter.second; - if(!checkTrack(_svtx_track)) + if(!checkTrack(svtx_track)) { continue; } - if (Verbosity() > 1) { std::cout<<"Pass track selection"<get_tpc_seed(); - _si_seed = _svtx_track->get_silicon_seed(); - if (_tpc_seed && _si_seed) + if (Verbosity() > 1) { std::cout <<"Pass track selection"<get_tpc_seed(); + auto* si_seed = svtx_track->get_silicon_seed(); + if (tpc_seed && si_seed) { - if (Verbosity() > 1) { std::cout<<"Insert tpcid and siid into good_matches"<find(_tpc_seed); - int siid = _si_seed_map->find(_si_seed); - good_matches.insert(std::make_pair(tpcid, siid)); + if (Verbosity() > 1) { std::cout <<"Insert tpcid and siid into good_matches"<find(tpc_seed); + const size_t siid = _si_seed_map->find(si_seed); + + // check index validity + if( tpcid < _tpc_seed_map->size() && siid < _si_seed_map->size() ) + { + good_matches.emplace(tpcid, siid); + ++m_accepted_tracks; + } } } - for (auto [tpcid, siid] : good_matches) + for (const auto& [tpcid, siid] : good_matches) { - if (Verbosity() > 1) { std::cout<<"Insert pruned svtx seed map"< 1) { std::cout <<"Insert pruned svtx seed map"<(); _svtx_seed->set_silicon_seed_index(siid); _svtx_seed->set_tpc_seed_index(tpcid); @@ -157,13 +160,13 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) if (Verbosity() > 1) { - std::cout << " combined seed id " << _pruned_svtx_seed_map->size() - 1 << " si id " << siid << " tpc id " << tpcid << " crossing estimate " << crossing_estimate << std::endl; + std::cout << " combined seed id " << _pruned_svtx_seed_map->size() - 1 << " si id " << siid << " tpc id " << tpcid << " crossing estimate " << crossing_estimate << std::endl; } } if (Verbosity() > 0) { - std::cout << "final svtx seed map size " << _pruned_svtx_seed_map->size() << std::endl; + std::cout << "final svtx seed map size " << _pruned_svtx_seed_map->size() << std::endl; } if (Verbosity() > 1) @@ -173,9 +176,8 @@ int PHTrackPruner::process_event(PHCompositeNode * /*unused*/) seed->identify(); } - cout << "PHTrackPruner::process_event(PHCompositeNode *topNode) Leaving process_event" << endl; + std::cout << "PHTrackPruner::process_event(PHCompositeNode *topNode) Leaving process_event" << std::endl; } - m_event++; return Fun4AllReturnCodes::EVENT_OK; } @@ -183,21 +185,28 @@ bool PHTrackPruner::checkTrack(SvtxTrack *track) { if(!track) { - if (Verbosity() > 1) { std::cout<<"invalid track"< 1) { std::cout <<"invalid track"<get_pt() < m_track_pt_low_cut) { - if (Verbosity() > 1) { std::cout<<"Track pt "<get_pt()<<" , pt cut "< 1) { std::cout <<"Track pt "<get_pt()<<" , pt cut "<0 && track->get_pt() > m_track_pt_high_cut) + { + if (Verbosity() > 1) { std::cout <<"Track pt "<get_pt()<<" , pt cut "<get_quality() > m_track_quality_high_cut) { - if (Verbosity() > 1) { std::cout<<"Track quality "<get_quality()<<" , quality cut "< 1) { std::cout <<"Track quality "<get_quality()<<" , quality cut "<(cluster_keys) < m_nmvtx_clus_low_cut) { - if (Verbosity() > 1) { std::cout<<"nmvtx "<(cluster_keys)<<" , nmvtx cut "< 1) { std::cout <<"nmvtx "<(cluster_keys)<<" , nmvtx cut "<(cluster_keys) < m_nintt_clus_low_cut) { - if (Verbosity() > 1) { std::cout<<"nintt "<(cluster_keys)<<" , nintt cut "< 1) { std::cout <<"nintt "<(cluster_keys)<<" , nintt cut "<(cluster_keys) < m_ntpc_clus_low_cut) { - if (Verbosity() > 1) { std::cout<<"ntpc "<(cluster_keys)<<" , ntpc cut "< 1) { std::cout <<"ntpc "<(cluster_keys)<<" , ntpc cut "<(cluster_keys) < m_ntpot_clus_low_cut) { - if (Verbosity() > 1) { std::cout<<"nmicromegas "<(cluster_keys)<<" , nmicromegas cut "< 1) { std::cout <<"nmicromegas "<(cluster_keys)<<" , nmicromegas cut "<(state_keys) < m_nmvtx_states_low_cut) { - if (Verbosity() > 1) { std::cout<<"nmvtxstates "<(state_keys)<<" , nmvtxstates cut "< 1) { std::cout <<"nmvtxstates "<(state_keys)<<" , nmvtxstates cut "<(state_keys) < m_nintt_states_low_cut) { - if (Verbosity() > 1) { std::cout<<"ninttstates "<(state_keys)<<" , ninttstates cut "< 1) { std::cout <<"ninttstates "<(state_keys)<<" , ninttstates cut "<(state_keys) < m_ntpc_states_low_cut) { - if (Verbosity() > 1) { std::cout<<"ntpcstates "<(state_keys)<<" , ntpcstates cut "< 1) { std::cout <<"ntpcstates "<(state_keys)<<" , ntpcstates cut "<(state_keys) < m_ntpot_states_low_cut) { - if (Verbosity() > 1) { std::cout<<"nmicromegasstates "<(state_keys)<<" , nmicromegasstates cut "< 1) { std::cout <<"nmicromegasstates "<(state_keys)<<" , nmicromegasstates cut "<(topNode, _svtx_track_map_name); if (!_svtx_track_map) { - cerr << PHWHERE << " ERROR: Can't find " << _svtx_track_map_name.c_str() << endl; + std::cout << PHWHERE << " ERROR: Can't find " << _svtx_track_map_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } _si_seed_map = findNode::getClass(topNode, _si_seed_map_name); if (!_si_seed_map) { - cerr << PHWHERE << " ERROR: Can't find " << _si_seed_map_name.c_str() << endl; + std::cout << PHWHERE << " ERROR: Can't find " << _si_seed_map_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } _tpc_seed_map = findNode::getClass(topNode, _tpc_seed_map_name); if (!_tpc_seed_map) { - cerr << PHWHERE << " ERROR: Can't find " << _tpc_seed_map_name.c_str() << endl; - return Fun4AllReturnCodes::ABORTEVENT; - } - - _svtx_seed_map = findNode::getClass(topNode, _svtx_seed_map_name); - if (!_svtx_seed_map) - { - cerr << PHWHERE << " ERROR: Can't find " << _svtx_seed_map_name.c_str() << endl; + std::cout << PHWHERE << " ERROR: Can't find " << _tpc_seed_map_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } _pruned_svtx_seed_map = findNode::getClass(topNode, _pruned_svtx_seed_map_name); if (!_pruned_svtx_seed_map) { - std::cout << "Creating node " << _pruned_svtx_seed_map_name.c_str() << std::endl; + std::cout << "Creating node " << _pruned_svtx_seed_map_name << std::endl; /// Get the DST Node PHNodeIterator iter(topNode); PHCompositeNode *dstNode = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); @@ -320,17 +324,17 @@ int PHTrackPruner::GetNodes(PHCompositeNode *topNode) svtxNode->addNode(node); } - _cluster_map = findNode::getClass(topNode, "TRKR_CLUSTER"); + _cluster_map = findNode::getClass(topNode, _cluster_map_name); if (!_cluster_map) { - std::cout << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << std::endl; + std::cout << PHWHERE << " ERROR: Can't find node " << _cluster_map_name << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } _tGeometry = findNode::getClass(topNode, "ActsGeometry"); if (!_tGeometry) { - std::cout << PHWHERE << "Error, can't find acts tracking geometry" << std::endl; + std::cout << PHWHERE << "Error, can't find acts tracking geometry" << std::endl; return Fun4AllReturnCodes::ABORTEVENT; } @@ -352,7 +356,7 @@ short int PHTrackPruner::findCrossingGeometrically(unsigned int tpcid, unsigned if (Verbosity() > 1) { - std::cout << "findCrossing: " + std::cout << "findCrossing: " << " tpcid " << tpcid << " si_id " << si_id << " tpc_z " << tpc_z << " si_z " << si_z << " dz " << tpc_z - si_z << " INTT crossing " << crossing << " crossing_estimate " << crossing_estimate << std::endl; } @@ -394,7 +398,7 @@ double PHTrackPruner::getBunchCrossing(unsigned int trid, double z_mismatch) if (side_set.size() == 2 && Verbosity() > 1) { - std::cout << " WARNING: tpc seed " << trid << " changed TPC sides, " + std::cout << " WARNING: tpc seed " << trid << " changed TPC sides, " << " final side " << side << std::endl; } @@ -407,7 +411,7 @@ double PHTrackPruner::getBunchCrossing(unsigned int trid, double z_mismatch) if (Verbosity() > 1) { - std::cout << " gettrackid " << trid << " side " << side << " z_mismatch " << z_mismatch << " crossings " << crossings << std::endl; + std::cout << " gettrackid " << trid << " side " << side << " z_mismatch " << z_mismatch << " crossings " << crossings << std::endl; } return crossings; diff --git a/offline/packages/trackreco/PHTrackPruner.h b/offline/packages/trackreco/PHTrackPruner.h index ef59a64178..ad71782ca5 100644 --- a/offline/packages/trackreco/PHTrackPruner.h +++ b/offline/packages/trackreco/PHTrackPruner.h @@ -24,9 +24,10 @@ class TNtuple; class PHTrackPruner : public SubsysReco { public: - PHTrackPruner(const std::string &name = "PHTrackPruner"); - ~PHTrackPruner() override; + + //! constructor + PHTrackPruner(const std::string &name = "PHTrackPruner"); int InitRun(PHCompositeNode *topNode) override; @@ -34,13 +35,28 @@ class PHTrackPruner : public SubsysReco int End(PHCompositeNode *) override; - void set_pruned_svtx_seed_map_name(const std::string &map_name) { _pruned_svtx_seed_map_name = map_name; } - void set_svtx_seed_map_name(const std::string &map_name) { _svtx_seed_map_name = map_name; } + //! input cluster map name. Default is TRKR_CLUSTER + void set_cluster_map_name(const std::string &map_name) { _cluster_map_name = map_name; } + + //! input silicon seeds map name void set_si_seed_map_name(const std::string &map_name) { _si_seed_map_name = map_name; } + + //! input tpc seeds map name void set_tpc_seed_map_name(const std::string &map_name) { _tpc_seed_map_name = map_name; } + + //! input track map name void set_svtx_track_map_name(const std::string &map_name) { _svtx_track_map_name = map_name; } + //! output pruned track map name + void set_pruned_svtx_seed_map_name(const std::string &map_name) { _pruned_svtx_seed_map_name = map_name; } + + /// low pt cut void set_track_pt_low_cut(const double val) { m_track_pt_low_cut = val; } + + /// high pt cut. + /** enforced only if >0 */ + void set_track_pt_high_cut(const double val) { m_track_pt_high_cut = val; } + void set_track_quality_high_cut(const double val) { m_track_quality_high_cut = val; } void set_nmvtx_clus_low_cut(const int n) { m_nmvtx_clus_low_cut = n; } @@ -61,24 +77,26 @@ class PHTrackPruner : public SubsysReco double getBunchCrossing(unsigned int trid, double z_mismatch); TrackSeedContainer *_pruned_svtx_seed_map{nullptr}; - TrackSeedContainer *_svtx_seed_map{nullptr}; TrackSeedContainer *_tpc_seed_map{nullptr}; TrackSeedContainer *_si_seed_map{nullptr}; - TrackSeed *_tpc_seed{nullptr}; - TrackSeed *_si_seed{nullptr}; + SvtxTrackMap *_svtx_track_map{nullptr}; - SvtxTrack *_svtx_track{nullptr}; TrkrClusterContainer *_cluster_map{nullptr}; ActsGeometry *_tGeometry{nullptr}; - int m_event = 0; + std::string _cluster_map_name = "TRKR_CLUSTER"; std::string _tpc_seed_map_name = "TpcTrackSeedContainer"; std::string _si_seed_map_name = "SiliconTrackSeedContainer"; - std::string _svtx_seed_map_name = "SvtxTrackSeedContainer"; std::string _pruned_svtx_seed_map_name = "PrunedSvtxTrackSeedContainer"; std::string _svtx_track_map_name = "SvtxTrackMap"; + /// low pt cut double m_track_pt_low_cut = 0.5; + + /// high pt cut. + /** enforced only if >0 */ + double m_track_pt_high_cut = 0.; + double m_track_quality_high_cut = 100; int m_nmvtx_clus_low_cut = 3; int m_nintt_clus_low_cut = 2; @@ -90,6 +108,10 @@ class PHTrackPruner : public SubsysReco int m_ntpc_states_low_cut = 35; int m_ntpot_states_low_cut = 2; + //! keep track of track/seed statistics + unsigned long m_total_tracks = 0; + unsigned long m_accepted_tracks = 0; + }; #endif // PHTRACKPRUNER_H diff --git a/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc new file mode 100644 index 0000000000..4559c90619 --- /dev/null +++ b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.cc @@ -0,0 +1,172 @@ +#include "PHTrackTrackSeedSynchronization.h" + +/// Tracking includes +#include +#include +#include +#include +#include +#include // for cluskey, getTrkrId, tpcId + +#include +#include +#include +#include + +#include // for SvtxTrack +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include // for UINT_MAX +#include // for fabs, sqrt +#include // for operator<<, basic_ostream +#include +#include // for _Rb_tree_const_iterator +#include // for pair + +using namespace std; + +//____________________________________________________________________________.. +PHTrackTrackSeedSynchronization::PHTrackTrackSeedSynchronization(const std::string &name) + : SubsysReco(name) +{} + +//____________________________________________________________________________.. +int PHTrackTrackSeedSynchronization::InitRun(PHCompositeNode *topNode) +{ + int ret = GetNodes(topNode); + if (ret != Fun4AllReturnCodes::EVENT_OK) + { + return ret; + } + + return ret; +} + +//____________________________________________________________________________.. +int PHTrackTrackSeedSynchronization::process_event(PHCompositeNode * /*unused*/) +{ + // loop over tracks and synchronize + for( auto &&[key,track]:*_svtx_track_map ) + { synchronize_track(track); } + + return Fun4AllReturnCodes::EVENT_OK; +} + +//____________________________________________________________________________ +bool PHTrackTrackSeedSynchronization::synchronize_track( SvtxTrack* track ) const +{ + { + // silicon seed + auto* seed = track->get_silicon_seed(); + if( seed ) + { + auto index = find_seed_id( _si_seed_map, seed ); + if( index < _si_seed_map->size() ) + { track->set_silicon_seed( _si_seed_map->get(index)); } + } + } + + { + // tpc seed + auto* seed = track->get_tpc_seed(); + if( seed ) + { + auto index = find_seed_id( _tpc_seed_map, seed ); + if( index < _tpc_seed_map->size() ) + { track->set_tpc_seed( _tpc_seed_map->get(index)); } + } + } + + return true; +} + +//__________________________________________________________________________________ +int PHTrackTrackSeedSynchronization::End(PHCompositeNode * /*unused*/) +{ return Fun4AllReturnCodes::EVENT_OK; } + +//__________________________________________________________________________________ +int PHTrackTrackSeedSynchronization::GetNodes(PHCompositeNode *topNode) +{ + + // tracks + _svtx_track_map = findNode::getClass(topNode, _svtx_track_map_name); + if (!_svtx_track_map) + { + cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _svtx_track_map_name << " not found on the node tree." << endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + // silicon seeds + _si_seed_map = findNode::getClass(topNode, _si_seed_map_name); + if (!_si_seed_map) + { + cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _si_seed_map_name << " not found on the node tree." << endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + // tpc seeds + _tpc_seed_map = findNode::getClass(topNode, _tpc_seed_map_name); + if (!_tpc_seed_map) + { + cerr << "PHTrackTrackSeedSynchronization::GetNodes - " << _tpc_seed_map_name << " not found on the node tree." << endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + + +//__________________________________________________________________________________ +size_t PHTrackTrackSeedSynchronization::find_seed_id( TrackSeedContainer* container, TrackSeed* source ) const +{ + // perform quick search + const size_t index = container->find( source ); + if( index < container->size() ) return index; + + // perform deep search based on cluster keys + if( Verbosity() ) + { std::cout << "PHTrackTrackSeedSynchronization::find_seed_id - performing deep search for seed " << source << " in container " << container << std::endl; } + + using cluster_keyset_t=std::set; + + // get cluster key set from seed + auto get_cluster_keyset = [this]( TrackSeed* seed ) + { + cluster_keyset_t ckeys; + if( m_ignore_micromegas ) + { + std::copy_if( seed->begin_cluster_keys(), seed->end_cluster_keys(), std::inserter(ckeys, ckeys.end() ), + []( const TrkrDefs::cluskey& ckey ) { return TrkrDefs::getTrkrId(ckey) != TrkrDefs::micromegasId; } ); + } else { + std::copy( seed->begin_cluster_keys(), seed->end_cluster_keys(), std::inserter(ckeys, ckeys.end() ) ); + } + return ckeys; + + }; + + const auto source_ckeys = get_cluster_keyset( source ); + for( size_t i = 0; i < container->size(); ++i ) + { + auto* seed = container->get(i); + if( !seed ) continue; + + const auto ckeys = get_cluster_keyset( seed ); + if( ckeys == source_ckeys ) + { return i; } + } + + // error + std::cout << "PHTrackTrackSeedSynchronization::find_seed_id - could not find seed " << source << " in container " << container << std::endl; + return container->size(); +} diff --git a/offline/packages/trackreco/PHTrackTrackSeedSynchronization.h b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.h new file mode 100644 index 0000000000..8e02a60b09 --- /dev/null +++ b/offline/packages/trackreco/PHTrackTrackSeedSynchronization.h @@ -0,0 +1,69 @@ +#ifndef PHTRACKTRACKSEEDSYNCHRONIZATION_H +#define PHTRACKTRACKSEEDSYNCHRONIZATION_H + +#include +#include +#include + +#include +#include + +class PHCompositeNode; +class TrackSeedContainer; +class TrackSeed; +class SvtxTrackSeed; +class SvtxTrackMap; +class SvtxTrack; +class TrkrClusterContainer; +class TF1; +class TFile; +class TNtuple; + +class PHTrackTrackSeedSynchronization : public SubsysReco +{ + public: + + //! constructor + PHTrackTrackSeedSynchronization(const std::string& = "PHTrackTrackSeedSynchronization"); + + int InitRun(PHCompositeNode *topNode) override; + + int process_event(PHCompositeNode *) override; + + int End(PHCompositeNode *) override; + + //! input silicon seeds map name + void set_si_seed_map_name(const std::string &map_name) { _si_seed_map_name = map_name; } + + //! input tpc seeds map name + void set_tpc_seed_map_name(const std::string &map_name) { _tpc_seed_map_name = map_name; } + + //! input track map name + void set_svtx_track_map_name(const std::string &map_name) { _svtx_track_map_name = map_name; } + + //! ignore micromegas + void set_ignore_micromegas( bool value ) { m_ignore_micromegas = value; } + + private: + + int GetNodes(PHCompositeNode*); + + /// make sure that the track seed pointers stored in track correspond to those store in the seed containers + bool synchronize_track(SvtxTrack*) const; + + /// find index of seed in container that matches argument seed + size_t find_seed_id( TrackSeedContainer*, TrackSeed* ) const; + + TrackSeedContainer *_tpc_seed_map{nullptr}; + TrackSeedContainer *_si_seed_map{nullptr}; + SvtxTrackMap *_svtx_track_map{nullptr}; + + std::string _tpc_seed_map_name = "TpcTrackSeedContainer"; + std::string _si_seed_map_name = "SiliconTrackSeedContainer"; + std::string _svtx_track_map_name = "SvtxTrackMap"; + + bool m_ignore_micromegas = false; + +}; + +#endif // PHTrackTrackSeedSynchronization_H diff --git a/offline/packages/trackreco/PHTruthSiliconAssociation.cc b/offline/packages/trackreco/PHTruthSiliconAssociation.cc index a0281767ca..7e55450fe5 100644 --- a/offline/packages/trackreco/PHTruthSiliconAssociation.cc +++ b/offline/packages/trackreco/PHTruthSiliconAssociation.cc @@ -556,6 +556,8 @@ std::set PHTruthSiliconAssociation::getInttCrossings(TrackSeed *si_tr unsigned int PHTruthSiliconAssociation::buildTrackSeed(const std::set &clusters, PHG4Particle *g4particle, TrackSeedContainer *container) { auto track = std::make_unique(); + track->set_truth_track_id(g4particle->get_track_id()); + bool silicon = false; for (const auto &cluskey : clusters) { diff --git a/offline/packages/trackreco/PHTruthTrackFitter.cc b/offline/packages/trackreco/PHTruthTrackFitter.cc new file mode 100644 index 0000000000..04e356d7ed --- /dev/null +++ b/offline/packages/trackreco/PHTruthTrackFitter.cc @@ -0,0 +1,756 @@ +#include "PHTruthTrackFitter.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + template + constexpr T square(const T& x) + { + return x * x; + } + + bool is_finite(float value) + { + return std::isfinite(value); + } + + float average_or(float a, float b, float fallback) + { + const bool aok = is_finite(a); + const bool bok = is_finite(b); + + if (aok && bok) + { + return 0.5 * (a + b); + } + if (aok) + { + return a; + } + if (bok) + { + return b; + } + + return fallback; + } + + bool valid_track_id(unsigned int trackid) + { + return trackid != std::numeric_limits::max(); + } + + class InterpolationData + { + public: + InterpolationData(double x, double y, double z, double px, double py, double pz, double weight) + : m_x(x) + , m_y(y) + , m_z(z) + , m_px(px) + , m_py(py) + , m_pz(pz) + , m_weight(weight) + { + } + + double r() const + { + return std::sqrt(square(m_x) + square(m_y)); + } + + double x() const { return m_x; } + double y() const { return m_y; } + double z() const { return m_z; } + double px() const { return m_px; } + double py() const { return m_py; } + double pz() const { return m_pz; } + double weight() const { return m_weight; } + + private: + double m_x = 0; + double m_y = 0; + double m_z = 0; + double m_px = 0; + double m_py = 0; + double m_pz = 0; + double m_weight = 1; + }; + + template + double interpolate_r(const std::vector& hits, double r_extrap, double fallback) + { + double sw = 0; + double swr = 0; + double swr2 = 0; + double swq = 0; + double swrq = 0; + + for (const auto& hit : hits) + { + const auto q = (hit.*accessor)(); + const auto r = hit.r(); + const auto weight = hit.weight(); + if (!std::isfinite(q) || !std::isfinite(r) || !std::isfinite(weight) || weight <= 0) + { + continue; + } + + sw += weight; + swr += weight * r; + swr2 += weight * square(r); + swq += weight * q; + swrq += weight * r * q; + } + + /* + * Fit q(r) = a*r + b with weighted least squares, where q is one of + * x/y/z/px/py/pz. The sums above form the normal equations: + * + * a*swr2 + b*swr = swrq + * a*swr + b*sw = swq + * + * alpha and beta are the Cramer's-rule numerators for the slope and + * intercept. Keeping the final division common is the same as returning + * slope*r_extrap + intercept, but avoids one extra division. + */ + const auto denom = sw * swr2 - square(swr); + const auto scale = std::max(std::abs(sw * swr2), square(swr)); + if (scale <= 0 || std::abs(denom) <= std::numeric_limits::epsilon() * scale) + { + return fallback; + } + + const auto alpha = sw * swrq - swr * swq; + const auto beta = swr2 * swq - swr * swrq; + const auto value = (alpha * r_extrap + beta) / denom; + return std::isfinite(value) ? value : fallback; + } +} // namespace + +PHTruthTrackFitter::PHTruthTrackFitter(const std::string& name) + : SubsysReco(name) +{ +} + +int PHTruthTrackFitter::InitRun(PHCompositeNode* topNode) +{ + if (Verbosity() > 0) + { + std::cout << "PHTruthTrackFitter::InitRun - output track map: " << m_trackMapName << std::endl; + } + + if (createNodes(topNode) != Fun4AllReturnCodes::EVENT_OK) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + + if (getNodes(topNode) != Fun4AllReturnCodes::EVENT_OK) + { + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int PHTruthTrackFitter::process_event(PHCompositeNode* /*topNode*/) +{ + m_trackMap->Reset(); + + unsigned int skipped_tracks = 0; + for (auto* seed : *m_seedMap) + { + if (!seed) + { + continue; + } + + auto* tpc_seed = getSeed(m_tpcSeeds, seed->get_tpc_seed_index()); + auto* silicon_seed = getSeed(m_siliconSeeds, seed->get_silicon_seed_index()); + + if (!tpc_seed && !silicon_seed) + { + ++skipped_tracks; + continue; + } + + const auto truth_track_id = getTruthTrackId(seed, tpc_seed, silicon_seed); + if (!valid_track_id(truth_track_id)) + { + if (Verbosity() > 1) + { + std::cout << "PHTruthTrackFitter::process_event - could not determine truth id for seed" << std::endl; + } + ++skipped_tracks; + continue; + } + + auto* g4particle = m_g4TruthInfo->GetParticle(truth_track_id); + if (!g4particle) + { + if (Verbosity() > 1) + { + std::cout << "PHTruthTrackFitter::process_event - no PHG4Particle for track id " + << truth_track_id << std::endl; + } + ++skipped_tracks; + continue; + } + + const auto* g4vertex = m_g4TruthInfo->GetVtx(g4particle->get_vtx_id()); + if (!g4vertex) + { + if (Verbosity() > 1) + { + std::cout << "PHTruthTrackFitter::process_event - no PHG4VtxPoint for track id " + << truth_track_id << std::endl; + } + ++skipped_tracks; + continue; + } + + SvtxTrack_v4 track; + track.set_tpc_seed(tpc_seed); + track.set_silicon_seed(silicon_seed); + track.set_crossing(getCrossing(tpc_seed, silicon_seed)); + track.set_vertex_id(g4particle->get_vtx_id()); + track.set_charge(getCharge(g4particle, tpc_seed, silicon_seed)); + track.set_chisq(0); + + track.set_x(g4vertex->get_x()); + track.set_y(g4vertex->get_y()); + track.set_z(g4vertex->get_z()); + track.set_px(g4particle->get_px()); + track.set_py(g4particle->get_py()); + track.set_pz(g4particle->get_pz()); + + for (int i = 0; i < 6; ++i) + { + for (int j = i; j < 6; ++j) + { + track.set_error(i, j, 0); + } + } + track.set_error(0, 0, square(m_positionError)); + track.set_error(1, 1, square(m_positionError)); + track.set_error(2, 2, square(m_zError)); + + unsigned int state_index = 1; + for (const auto* track_seed : {silicon_seed, tpc_seed}) + { + if (!track_seed) + { + continue; + } + + for (auto iter = track_seed->begin_cluster_keys(); iter != track_seed->end_cluster_keys(); ++iter) + { + if (addStateFromCluster(&track, *iter, truth_track_id, g4particle, g4vertex, state_index)) + { + ++state_index; + } + } + } + + if (track.size_states() <= 1) + { + if (Verbosity() > 1) + { + std::cout << "PHTruthTrackFitter::process_event - no truth states for track id " + << truth_track_id << std::endl; + } + ++skipped_tracks; + continue; + } + + track.set_ndf(std::max(0, 2 * static_cast(track.size_states()) - 5)); + + const unsigned int track_id = m_trackMap->size(); + track.set_id(track_id); + m_trackMap->insertWithKey(&track, track_id); + } + + if (Verbosity() > 0) + { + std::cout << "PHTruthTrackFitter::process_event - built " << m_trackMap->size() + << " truth tracks, skipped " << skipped_tracks << std::endl; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int PHTruthTrackFitter::End(PHCompositeNode* /*topNode*/) +{ + return Fun4AllReturnCodes::EVENT_OK; +} + +int PHTruthTrackFitter::createNodes(PHCompositeNode* topNode) +{ + PHNodeIterator iter(topNode); + + auto* dst_node = dynamic_cast(iter.findFirst("PHCompositeNode", "DST")); + if (!dst_node) + { + std::cerr << PHWHERE << "DST node is missing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + PHNodeIterator dst_iter(dst_node); + auto* svtx_node = dynamic_cast(dst_iter.findFirst("PHCompositeNode", "SVTX")); + if (!svtx_node) + { + svtx_node = new PHCompositeNode("SVTX"); + dst_node->addNode(svtx_node); + } + + m_trackMap = findNode::getClass(topNode, m_trackMapName); + if (!m_trackMap) + { + m_trackMap = new SvtxTrackMap_v2; + auto* track_node = new PHIODataNode(m_trackMap, m_trackMapName, "PHObject"); + svtx_node->addNode(track_node); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +int PHTruthTrackFitter::getNodes(PHCompositeNode* topNode) +{ + m_seedMap = findNode::getClass(topNode, m_svtxSeedMapName); + if (!m_seedMap) + { + std::cout << PHWHERE << "No " << m_svtxSeedMapName << " on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_tpcSeeds = findNode::getClass(topNode, "TpcTrackSeedContainer"); + if (!m_tpcSeeds) + { + std::cout << PHWHERE << "No TpcTrackSeedContainer on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_siliconSeeds = findNode::getClass(topNode, "SiliconTrackSeedContainer"); + if (!m_siliconSeeds) + { + std::cout << PHWHERE << "No SiliconTrackSeedContainer on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_clusterMap = findNode::getClass(topNode, m_clusterMapName); + if (!m_clusterMap) + { + std::cout << PHWHERE << "No " << m_clusterMapName << " on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_clusterHitMap = findNode::getClass(topNode, "TRKR_CLUSTERHITASSOC"); + if (!m_clusterHitMap) + { + std::cout << PHWHERE << "No TRKR_CLUSTERHITASSOC on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_hitTruthAssoc = findNode::getClass(topNode, "TRKR_HITTRUTHASSOC"); + if (!m_hitTruthAssoc) + { + std::cout << PHWHERE << "No TRKR_HITTRUTHASSOC on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_g4TruthInfo = findNode::getClass(topNode, "G4TruthInfo"); + if (!m_g4TruthInfo) + { + std::cout << PHWHERE << "No G4TruthInfo on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + m_g4HitsTpc = findNode::getClass(topNode, "G4HIT_TPC"); + m_g4HitsIntt = findNode::getClass(topNode, "G4HIT_INTT"); + m_g4HitsMvtx = findNode::getClass(topNode, "G4HIT_MVTX"); + m_g4HitsMicromegas = findNode::getClass(topNode, "G4HIT_MICROMEGAS"); + + m_tGeometry = findNode::getClass(topNode, "ActsGeometry"); + if (m_extrapolateToClusterRadius && !m_tGeometry) + { + std::cout << PHWHERE << "No ActsGeometry on node tree. Bailing" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +TrackSeed* PHTruthTrackFitter::getSeed(TrackSeedContainer* container, unsigned int index) const +{ + if (!container || index >= container->size()) + { + return nullptr; + } + + return container->get(index); +} + +unsigned int PHTruthTrackFitter::getTruthTrackId(const TrackSeed* svtxSeed, + const TrackSeed* tpcSeed, + const TrackSeed* siliconSeed) const +{ + auto truth_track_id = m_invalidTruthTrackId; + for (const auto* seed : {svtxSeed, tpcSeed, siliconSeed}) + { + if (!seed) + { + continue; + } + + const auto seed_truth_track_id = seed->get_truth_track_id(); + if (!valid_track_id(seed_truth_track_id)) + { + continue; + } + + if (valid_track_id(truth_track_id) && seed_truth_track_id != truth_track_id) + { + if (Verbosity() > 0) + { + std::cout << "PHTruthTrackFitter::getTruthTrackId - inconsistent seed truth ids " + << truth_track_id << " and " << seed_truth_track_id << std::endl; + } + return m_invalidTruthTrackId; + } + + truth_track_id = seed_truth_track_id; + } + + return truth_track_id; +} + +std::vector PHTruthTrackFitter::getTruthHits(TrkrDefs::cluskey cluskey) const +{ + std::vector truth_hits; + if (!m_clusterHitMap || !m_hitTruthAssoc) + { + return truth_hits; + } + + const auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluskey); + const auto trkrid = TrkrDefs::getTrkrId(hitsetkey); + const auto hitrange = m_clusterHitMap->getHits(cluskey); + + std::set used_g4hits; + for (auto clushititer = hitrange.first; clushititer != hitrange.second; ++clushititer) + { + const auto hitkey = clushititer->second; + + TrkrHitTruthAssoc::MMap temp_map; + m_hitTruthAssoc->getG4Hits(hitsetkey, hitkey, temp_map); + + for (const auto& hit_truth_iter : temp_map) + { + const auto g4hitkey = hit_truth_iter.second.second; + if (!used_g4hits.insert(g4hitkey).second) + { + continue; + } + + const auto* g4hit = getG4Hit(trkrid, g4hitkey); + if (g4hit) + { + truth_hits.push_back(g4hit); + } + } + } + + return truth_hits; +} + +const PHG4Hit* PHTruthTrackFitter::getG4Hit(unsigned int trkrid, PHG4HitDefs::keytype g4hitkey) const +{ + PHG4HitContainer* container = nullptr; + switch (trkrid) + { + case TrkrDefs::tpcId: + container = m_g4HitsTpc; + break; + case TrkrDefs::inttId: + container = m_g4HitsIntt; + break; + case TrkrDefs::mvtxId: + container = m_g4HitsMvtx; + break; + case TrkrDefs::micromegasId: + container = m_g4HitsMicromegas; + break; + default: + break; + } + + return container ? container->findHit(g4hitkey) : nullptr; +} + +bool PHTruthTrackFitter::addStateFromCluster(SvtxTrack* track, + TrkrDefs::cluskey cluskey, + unsigned int truthTrackId, + const PHG4Particle* particle, + const PHG4VtxPoint* vertex, + unsigned int stateIndex) const +{ + auto* cluster = m_clusterMap->findCluster(cluskey); + if (!cluster) + { + return false; + } + + std::vector interpolation_hits; + double weight_sum = 0; + double x = 0; + double y = 0; + double z = 0; + double px = 0; + double py = 0; + double pz = 0; + double local_x = 0; + double local_y = 0; + + for (const auto* g4hit : getTruthHits(cluskey)) + { + if (!g4hit || g4hit->get_trkid() != static_cast(truthTrackId)) + { + continue; + } + + const auto hit_x = average_or(g4hit->get_x(0), g4hit->get_x(1), std::numeric_limits::quiet_NaN()); + const auto hit_y = average_or(g4hit->get_y(0), g4hit->get_y(1), std::numeric_limits::quiet_NaN()); + const auto hit_z = average_or(g4hit->get_z(0), g4hit->get_z(1), std::numeric_limits::quiet_NaN()); + if (!is_finite(hit_x) || !is_finite(hit_y) || !is_finite(hit_z)) + { + continue; + } + + const auto hit_px = average_or(g4hit->get_px(0), g4hit->get_px(1), particle->get_px()); + const auto hit_py = average_or(g4hit->get_py(0), g4hit->get_py(1), particle->get_py()); + const auto hit_pz = average_or(g4hit->get_pz(0), g4hit->get_pz(1), particle->get_pz()); + const auto hit_local_x = average_or(g4hit->get_local_x(0), g4hit->get_local_x(1), 0); + const auto hit_local_y = average_or(g4hit->get_local_y(0), g4hit->get_local_y(1), 0); + + double weight = g4hit->get_edep(); + if (!std::isfinite(weight) || weight <= 0) + { + weight = 1; + } + + for (int endpoint = 0; endpoint < 2; ++endpoint) + { + const auto endpoint_x = g4hit->get_x(endpoint); + const auto endpoint_y = g4hit->get_y(endpoint); + const auto endpoint_z = g4hit->get_z(endpoint); + if (!is_finite(endpoint_x) || !is_finite(endpoint_y) || !is_finite(endpoint_z)) + { + continue; + } + + const auto endpoint_px = g4hit->get_px(endpoint); + const auto endpoint_py = g4hit->get_py(endpoint); + const auto endpoint_pz = g4hit->get_pz(endpoint); + + interpolation_hits.emplace_back(endpoint_x, + endpoint_y, + endpoint_z, + is_finite(endpoint_px) ? endpoint_px : particle->get_px(), + is_finite(endpoint_py) ? endpoint_py : particle->get_py(), + is_finite(endpoint_pz) ? endpoint_pz : particle->get_pz(), + weight); + } + + weight_sum += weight; + x += weight * hit_x; + y += weight * hit_y; + z += weight * hit_z; + px += weight * hit_px; + py += weight * hit_py; + pz += weight * hit_pz; + local_x += weight * hit_local_x; + local_y += weight * hit_local_y; + } + + if (weight_sum <= 0) + { + return false; + } + + x /= weight_sum; + y /= weight_sum; + z /= weight_sum; + px /= weight_sum; + py /= weight_sum; + pz /= weight_sum; + local_x /= weight_sum; + local_y /= weight_sum; + + if (m_extrapolateToClusterRadius && !interpolation_hits.empty()) + { + const auto cluster_radius = getClusterRadius(cluskey, cluster); + if (std::isfinite(cluster_radius) && cluster_radius > 0) + { + x = interpolate_r<&InterpolationData::x>(interpolation_hits, cluster_radius, x); + y = interpolate_r<&InterpolationData::y>(interpolation_hits, cluster_radius, y); + z = interpolate_r<&InterpolationData::z>(interpolation_hits, cluster_radius, z); + px = interpolate_r<&InterpolationData::px>(interpolation_hits, cluster_radius, px); + py = interpolate_r<&InterpolationData::py>(interpolation_hits, cluster_radius, py); + pz = interpolate_r<&InterpolationData::pz>(interpolation_hits, cluster_radius, pz); + } + else if (Verbosity() > 1) + { + std::cout << "PHTruthTrackFitter::addStateFromCluster - invalid cluster radius for cluster " + << cluskey << ", using truth hit average" << std::endl; + } + } + + float pathlength = getPathLength(vertex, x, y, z, stateIndex); + while (track->count_states(pathlength) != 0) + { + pathlength += 1.e-3; + } + + SvtxTrackState_v3 state(pathlength); + state.set_name("PHTruthTrackFitter"); + state.set_cluskey(cluskey); + state.set_x(x); + state.set_y(y); + state.set_z(z); + state.set_px(px); + state.set_py(py); + state.set_pz(pz); + state.set_localX(local_x); + state.set_localY(local_y); + + for (int i = 0; i < 6; ++i) + { + for (int j = i; j < 6; ++j) + { + state.set_error(i, j, 0); + } + } + state.set_error(0, 0, square(m_positionError)); + state.set_error(1, 1, square(m_positionError)); + state.set_error(2, 2, square(m_zError)); + + track->insert_state(&state); + return true; +} + +float PHTruthTrackFitter::getClusterRadius(TrkrDefs::cluskey cluskey, TrkrCluster* cluster) const +{ + if (!m_tGeometry || !cluster) + { + return std::numeric_limits::quiet_NaN(); + } + + const auto global = m_tGeometry->getGlobalPosition(cluskey, cluster); + const auto radius = std::sqrt(square(global.x()) + square(global.y())); + return std::isfinite(radius) ? radius : std::numeric_limits::quiet_NaN(); +} + +float PHTruthTrackFitter::getPathLength(const PHG4VtxPoint* vertex, + float x, float y, float z, + unsigned int stateIndex) const +{ + if (vertex) + { + const auto dx = x - vertex->get_x(); + const auto dy = y - vertex->get_y(); + const auto dz = z - vertex->get_z(); + const auto pathlength = std::sqrt(square(dx) + square(dy) + square(dz)); + if (std::isfinite(pathlength) && pathlength > 0) + { + return pathlength; + } + } + + return static_cast(stateIndex); +} + +int PHTruthTrackFitter::getCharge(const PHG4Particle* particle, + const TrackSeed* tpcSeed, + const TrackSeed* siliconSeed) const +{ + for (const auto* seed : {tpcSeed, siliconSeed}) + { + if (!seed) + { + continue; + } + + const auto charge = seed->get_charge(); + if (std::abs(charge) == 1) + { + return charge; + } + } + + const auto* pdg_particle = particle ? TDatabasePDG::Instance()->GetParticle(particle->get_pid()) : nullptr; + if (pdg_particle && pdg_particle->Charge() < 0) + { + return -1; + } + + return 1; +} + +short int PHTruthTrackFitter::getCrossing(const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const +{ + for (const auto* seed : {siliconSeed, tpcSeed}) + { + if (!seed) + { + continue; + } + + const auto crossing = seed->get_crossing(); + if (crossing != std::numeric_limits::max()) + { + return crossing; + } + } + + return m_defaultCrossing; +} diff --git a/offline/packages/trackreco/PHTruthTrackFitter.h b/offline/packages/trackreco/PHTruthTrackFitter.h new file mode 100644 index 0000000000..1991cf8399 --- /dev/null +++ b/offline/packages/trackreco/PHTruthTrackFitter.h @@ -0,0 +1,94 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef TRACKRECO_PHTRUTHTRACKFITTER_H +#define TRACKRECO_PHTRUTHTRACKFITTER_H + +#include + +#include +#include + +#include +#include +#include + +class ActsGeometry; +class PHCompositeNode; +class PHG4Hit; +class PHG4HitContainer; +class PHG4Particle; +class PHG4TruthInfoContainer; +class PHG4VtxPoint; +class SvtxTrack; +class SvtxTrackMap; +class TrackSeed; +class TrackSeedContainer; +class TrkrCluster; +class TrkrClusterContainer; +class TrkrClusterHitAssoc; +class TrkrHitTruthAssoc; + +class PHTruthTrackFitter : public SubsysReco +{ + public: + PHTruthTrackFitter(const std::string& name = "PHTruthTrackFitter"); + ~PHTruthTrackFitter() override = default; + + int InitRun(PHCompositeNode* topNode) override; + int process_event(PHCompositeNode* topNode) override; + int End(PHCompositeNode* topNode) override; + + void setTrackMapName(const std::string& name) { m_trackMapName = name; } + void setSvtxSeedMapName(const std::string& name) { m_svtxSeedMapName = name; } + void setTrkrClusterContainerName(const std::string& name) { m_clusterMapName = name; } + void setDefaultCrossing(short int crossing) { m_defaultCrossing = crossing; } + void setPositionError(float value) { m_positionError = value; } + void setZError(float value) { m_zError = value; } + void setExtrapolateToClusterRadius(bool value) { m_extrapolateToClusterRadius = value; } + + private: + int createNodes(PHCompositeNode* topNode); + int getNodes(PHCompositeNode* topNode); + + TrackSeed* getSeed(TrackSeedContainer* container, unsigned int index) const; + unsigned int getTruthTrackId(const TrackSeed* svtxSeed, const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const; + + std::vector getTruthHits(TrkrDefs::cluskey cluskey) const; + const PHG4Hit* getG4Hit(unsigned int trkrid, PHG4HitDefs::keytype g4hitkey) const; + + bool addStateFromCluster(SvtxTrack* track, TrkrDefs::cluskey cluskey, unsigned int truthTrackId, + const PHG4Particle* particle, const PHG4VtxPoint* vertex, + unsigned int stateIndex) const; + float getClusterRadius(TrkrDefs::cluskey cluskey, TrkrCluster* cluster) const; + float getPathLength(const PHG4VtxPoint* vertex, float x, float y, float z, unsigned int stateIndex) const; + int getCharge(const PHG4Particle* particle, const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const; + short int getCrossing(const TrackSeed* tpcSeed, const TrackSeed* siliconSeed) const; + + std::string m_trackMapName = "SvtxTrackMap"; + std::string m_svtxSeedMapName = "SvtxTrackSeedContainer"; + std::string m_clusterMapName = "TRKR_CLUSTER"; + + TrackSeedContainer* m_seedMap = nullptr; + TrackSeedContainer* m_tpcSeeds = nullptr; + TrackSeedContainer* m_siliconSeeds = nullptr; + SvtxTrackMap* m_trackMap = nullptr; + TrkrClusterContainer* m_clusterMap = nullptr; + TrkrClusterHitAssoc* m_clusterHitMap = nullptr; + TrkrHitTruthAssoc* m_hitTruthAssoc = nullptr; + ActsGeometry* m_tGeometry = nullptr; + PHG4TruthInfoContainer* m_g4TruthInfo = nullptr; + + PHG4HitContainer* m_g4HitsTpc = nullptr; + PHG4HitContainer* m_g4HitsIntt = nullptr; + PHG4HitContainer* m_g4HitsMvtx = nullptr; + PHG4HitContainer* m_g4HitsMicromegas = nullptr; + + short int m_defaultCrossing = 0; + float m_positionError = 0.005; + float m_zError = 0.01; + bool m_extrapolateToClusterRadius = true; + + static constexpr unsigned int m_invalidTruthTrackId = std::numeric_limits::max(); +}; + +#endif diff --git a/offline/packages/trackreco/PHTruthTrackSeeding.cc b/offline/packages/trackreco/PHTruthTrackSeeding.cc index 5828ff420d..21a337dbff 100644 --- a/offline/packages/trackreco/PHTruthTrackSeeding.cc +++ b/offline/packages/trackreco/PHTruthTrackSeeding.cc @@ -120,7 +120,10 @@ int PHTruthTrackSeeding::Process(PHCompositeNode* topNode) std::vector ClusterKeyListSilicon; std::vector ClusterKeyListTpc; - PHG4TruthInfoContainer::ConstRange range = m_g4truth_container->GetPrimaryParticleRange(); + PHG4TruthInfoContainer::ConstRange range = + m_include_secondaries + ? m_g4truth_container->GetParticleRange() + : m_g4truth_container->GetPrimaryParticleRange(); for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter) @@ -252,6 +255,8 @@ void PHTruthTrackSeeding::buildTrackSeed(const std::vector& c // This method is called separately for silicon and tpc seeds auto track = std::make_unique(); + track->set_truth_track_id(g4particle->get_track_id()); + bool silicon = false; bool tpc = false; for (const auto& cluskey : clusters) diff --git a/offline/packages/trackreco/PHTruthTrackSeeding.h b/offline/packages/trackreco/PHTruthTrackSeeding.h index abe597b30f..20ab6627eb 100644 --- a/offline/packages/trackreco/PHTruthTrackSeeding.h +++ b/offline/packages/trackreco/PHTruthTrackSeeding.h @@ -60,6 +60,12 @@ class PHTruthTrackSeeding : public PHTrackSeeding _max_layer = maxLayer; } + //! include Geant4 secondary particles when building truth seeds + void set_include_secondaries(bool includeSecondaries) + { + m_include_secondaries = includeSecondaries; + } + //! minimal truth momentum cut double get_min_momentum() const { @@ -106,6 +112,9 @@ class PHTruthTrackSeeding : public PHTrackSeeding unsigned int _min_layer = 0; unsigned int _max_layer = 60; + //! include Geant4 secondary particles in addition to primaries + bool m_include_secondaries = false; + //! minimal truth momentum cut (GeV) double _min_momentum = 50e-3; diff --git a/offline/packages/trackreco/WeightedFitter.cc b/offline/packages/trackreco/WeightedFitter.cc index af7677f5b8..2897b3a337 100644 --- a/offline/packages/trackreco/WeightedFitter.cc +++ b/offline/packages/trackreco/WeightedFitter.cc @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include @@ -139,21 +139,21 @@ WeightedFitter::make_nodes ( m_track_map = findNode::getClass(top_node, m_track_map_node_name); if (!m_track_map) { m_track_map = new SvtxTrackMap_v2; - PHIODataNode* track_map_node = new PHIODataNode(m_track_map, m_track_map_node_name, "PHObject"); + auto* track_map_node = new PHIODataNode(m_track_map, m_track_map_node_name, "PHObject"); svtx_node->addNode(track_map_node); } m_alignment_map = findNode::getClass(top_node, m_alignment_map_node_name); if (!m_alignment_map) { m_alignment_map = new SvtxAlignmentStateMap_v1; - PHIODataNode* alignment_map_node = new PHIODataNode(m_alignment_map, m_alignment_map_node_name, "PHObject"); + auto* alignment_map_node = new PHIODataNode(m_alignment_map, m_alignment_map_node_name, "PHObject"); svtx_node->addNode(alignment_map_node); } m_weighted_track_map = findNode::getClass(top_node, m_weighted_track_map_node_name); if (!m_weighted_track_map) { m_weighted_track_map = new WeightedTrackMap; - PHIODataNode* weighted_track_map_node = new PHIODataNode(m_weighted_track_map, m_weighted_track_map_node_name, "PHObject"); + auto* weighted_track_map_node = new PHIODataNode(m_weighted_track_map, m_weighted_track_map_node_name, "PHObject"); svtx_node->addNode(weighted_track_map_node); } } @@ -350,12 +350,17 @@ WeightedFitter::get_cluster_keys ( m_silicon_seed = m_silicon_track_seed_container->get(track_seed->get_silicon_seed_index()); m_tpc_seed = m_tpc_track_seed_container->get(track_seed->get_tpc_seed_index()); } - m_crossing = m_silicon_seed ? m_silicon_seed->get_crossing() : SHRT_MAX; + + /* + * for TPC only tracks (no associated silicon seed), use nominal crossing as default + * this is consistent with what is done in PHActsTrkFitter + */ + m_crossing = m_silicon_seed ? m_silicon_seed->get_crossing() : 0; m_cluster_keys.clear(); for (auto const* seed : {m_silicon_seed, m_tpc_seed}) { if (!seed) { continue; } - std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(m_cluster_keys)); + std::copy(seed->begin_cluster_keys(), seed->end_cluster_keys(), std::back_inserter(m_cluster_keys)); } return false; @@ -384,8 +389,8 @@ WeightedFitter::get_points ( Surface const surf = m_geometry->maps().getSurface(cluster_key, cluster); if (!surf) { continue; } - - auto local_to_global_transform = surf->transform(m_geometry->geometry().getGeoContext()); // in mm + + auto local_to_global_transform = surf->localToGlobalTransform(m_geometry->geometry().getGeoContext()); // in mm local_to_global_transform.translation() /= Acts::UnitConstants::cm; // converted to cm Eigen::Vector3d local_pos = Eigen::Vector3d { cluster->getLocalX(), cluster->getLocalY(), 0.0 }; // in cm @@ -580,20 +585,26 @@ WeightedFitter::add_track ( fitted_track.set_pz(slope(2)); SvtxAlignmentStateMap::StateVec alignment_states; - for (auto const& point : m_output_cluster_fit_points) { - Acts::Vector3 intersection = m_weighted_track->get_intersection(point.sensor_local_to_global_transform); + for (auto const& point : m_output_cluster_fit_points) + { + const auto intersection = m_weighted_track->get_intersection(point.sensor_local_to_global_transform); double path_length = m_weighted_track->get_path_length_of_intersection(point.sensor_local_to_global_transform); SvtxTrackState_v3 svtx_track_state(path_length); - svtx_track_state.set_x(intersection(0)); - svtx_track_state.set_y(intersection(1)); - svtx_track_state.set_z(intersection(2)); - svtx_track_state.set_px(slope(0)); - svtx_track_state.set_py(slope(1)); - svtx_track_state.set_pz(slope(2)); + svtx_track_state.set_x(intersection.x()); + svtx_track_state.set_y(intersection.y()); + svtx_track_state.set_z(intersection.z()); + svtx_track_state.set_px(slope.x()); + svtx_track_state.set_py(slope.y()); + svtx_track_state.set_pz(slope.z()); svtx_track_state.set_name(std::to_string(point.cluster_key)); svtx_track_state.set_cluskey(point.cluster_key); + // calculate corresponding local coordinate (in cluster surface reference frame) + const auto local = point.sensor_local_to_global_transform.inverse()*intersection; + svtx_track_state.set_localX(local.x() ); + svtx_track_state.set_localY(local.y() ); + Eigen::Matrix Jacobian_fitpars_globpos; for (int i = 0; i < 4; ++i) { Jacobian_fitpars_globpos.col(i) = m_weighted_track->get_partial_derivative(i, path_length); } Eigen::Matrix3d globpos_cov = Jacobian_fitpars_globpos * param_cov * Jacobian_fitpars_globpos.transpose(); diff --git a/offline/packages/trigger/CaloTriggerEmulator.cc b/offline/packages/trigger/CaloTriggerEmulator.cc index eaf00e4f33..9397288033 100644 --- a/offline/packages/trigger/CaloTriggerEmulator.cc +++ b/offline/packages/trigger/CaloTriggerEmulator.cc @@ -1767,8 +1767,17 @@ int CaloTriggerEmulator::process_organizer() } TriggerDefs::TriggerSumKey jet_skey = (*iter_sum).first; - - TriggerDefs::TriggerSumKey hcal_skey = TriggerDefs::getTriggerSumKey(TriggerDefs::TriggerId::jetTId, TriggerDefs::GetDetectorId("HCAL"), TriggerDefs::GetPrimitiveId("JET"), TriggerDefs::getPrimitiveLocId_from_TriggerPrimKey(jet_pkey), TriggerDefs::getSumLocId(jet_skey)); + uint16_t jet_sum_loc = TriggerDefs::getSumLocId(jet_skey); + uint16_t jet_prim_loc = TriggerDefs::getPrimitiveLocId_from_TriggerSumKey(jet_skey); + if (jet_prim_loc >= 12) + { + uint16_t sumeta = TriggerDefs::getSumEtaId(jet_skey); + uint16_t sumphi = TriggerDefs::getSumPhiId(jet_skey); + jet_sum_loc = sumphi%2 + sumeta*2; + } + TriggerDefs::TriggerSumKey hcal_skey = TriggerDefs::getTriggerSumKey(TriggerDefs::TriggerId::jetTId, TriggerDefs::GetDetectorId("HCAL"), TriggerDefs::GetPrimitiveId("JET"), TriggerDefs::getPrimitiveLocId_from_TriggerPrimKey(jet_pkey), jet_sum_loc); + + TriggerDefs::TriggerSumKey emcal_skey = TriggerDefs::getTriggerSumKey(TriggerDefs::TriggerId::jetTId, TriggerDefs::GetDetectorId("EMCAL"), TriggerDefs::GetPrimitiveId("JET"), TriggerDefs::getPrimitiveLocId_from_TriggerPrimKey(jet_pkey), TriggerDefs::getSumLocId(jet_skey)); int i = 0; diff --git a/offline/packages/trigger/MinimumBiasClassifier.cc b/offline/packages/trigger/MinimumBiasClassifier.cc index b9e7f18460..ab47326b86 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.cc +++ b/offline/packages/trigger/MinimumBiasClassifier.cc @@ -5,13 +5,15 @@ #include #include -#include #include #include + #include #include +#include + #include #include @@ -25,7 +27,6 @@ #include #include #include -#include // for _Rb_tree_iterator #include #include // for pair @@ -33,32 +34,62 @@ MinimumBiasClassifier::MinimumBiasClassifier(const std::string &name) : SubsysReco(name) { } + int MinimumBiasClassifier::InitRun(PHCompositeNode *topNode) { if (Verbosity() > 1) { std::cout << __FILE__ << " :: " << __FUNCTION__ << std::endl; } + + if (m_species == MinimumBiasInfo::SPECIES::OO) + { + m_useZDC = false; + m_box_cut = false; + m_hit_cut = 1; + m_max_charge_cut = 400; + m_mbd_charge_cut = 0.4; + m_mbd_time_cut = 20.; + m_z_vtx_cut = 150.; + } + else if (m_species == MinimumBiasInfo::SPECIES::PP) + { + m_useZDC = false; + m_box_cut = false; + m_hit_cut = 1; + m_max_charge_cut = 300; + m_mbd_charge_cut = 0.4; + m_mbd_time_cut = 20.; + } + CDBInterface *m_cdb = CDBInterface::instance(); - std::string centscale_url = m_cdb->getUrl("CentralityScale"); - if (m_overwrite_scale) + std::string centscale_url; + if (!m_overwrite_url_scale.empty()) { centscale_url = m_overwrite_url_scale; std::cout << " Overwriting Scale to " << m_overwrite_url_scale << std::endl; } + else + { + centscale_url = m_cdb->getUrl("CentralityScale"); + } if (Download_centralityScale(centscale_url)) { return Fun4AllReturnCodes::ABORTRUN; } - std::string vertexscale_url = m_cdb->getUrl("CentralityVertexScale"); - if (m_overwrite_vtx) + std::string vertexscale_url; + if (!m_overwrite_url_vtx.empty()) { vertexscale_url = m_overwrite_url_vtx; std::cout << " Overwriting Vtx to " << m_overwrite_url_vtx << std::endl; } + else + { + vertexscale_url = m_cdb->getUrl("CentralityVertexScale"); + } if (Download_centralityVertexScales(vertexscale_url)) { @@ -105,24 +136,35 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() if (m_global_vertex_map->empty()) { m_mb_info->setIsAuAuMinimumBias(false); - return Fun4AllReturnCodes::EVENT_OK; + if (m_abortEvents) + { + return 1; + } + return 0; } GlobalVertex *vtx = m_global_vertex_map->begin()->second; if (!vtx) { m_mb_info->setIsAuAuMinimumBias(false); - return Fun4AllReturnCodes::EVENT_OK; + if (m_abortEvents) + { + return 1; + } + return 0; } if (!vtx->isValid()) { m_mb_info->setIsAuAuMinimumBias(false); - return Fun4AllReturnCodes::EVENT_OK; + if (m_abortEvents) + { + return 1; + } + return 0; } bool minbiascheck = true; - ; m_vertex = vtx->get_z(); @@ -132,12 +174,16 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() { std::cout << "Getting ZDC" << std::endl; } - if (!m_issim) + if (!m_issim && m_useZDC) { if (!m_zdcinfo) { m_mb_info->setIsAuAuMinimumBias(false); - return Fun4AllReturnCodes::EVENT_OK; + if (m_abortEvents) + { + return 1; + } + return 0; } } // Z vertex is within range @@ -169,7 +215,7 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() } // MBD Background cut - if (m_mbd_charge_sum[1] < m_mbd_north_cut && m_mbd_charge_sum[0] > m_mbd_south_cut && minbiascheck) + if (m_box_cut && m_mbd_charge_sum[1] < m_mbd_north_cut && m_mbd_charge_sum[0] > m_mbd_south_cut && minbiascheck) { minbiascheck = false; // m_mb_info->setIsAuAuMinimumBias(false); @@ -179,13 +225,13 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() // Mbd two hit requirement and ZDC energy sum coincidence requirement for (int iside = 0; iside < 2; iside++) { - if (m_mbd_hit[iside] < 2 && minbiascheck) + if (m_mbd_hit[iside] < m_hit_cut && minbiascheck) { minbiascheck = false; // m_mb_info->setIsAuAuMinimumBias(false); // return Fun4AllReturnCodes::EVENT_OK; } - if (!m_issim) + if (!m_issim && m_useZDC) { if (m_zdcinfo->get_zdc_energy(iside) <= m_zdc_cut && minbiascheck) { @@ -195,17 +241,26 @@ int MinimumBiasClassifier::FillMinimumBiasInfo() } } } - if ((m_mbd_charge_sum[0] + m_mbd_charge_sum[1]) > 2100 && minbiascheck) + if ((m_mbd_charge_sum[0] + m_mbd_charge_sum[1]) > m_max_charge_cut && minbiascheck) { minbiascheck = false; // m_mb_info->setIsAuAuMinimumBias(false); // return Fun4AllReturnCodes::EVENT_OK; } - m_mb_info->setIsAuAuMinimumBias(minbiascheck); + if (m_species == MinimumBiasInfo::SPECIES::OO && m_reject_pileup && (m_mbd_charge_sum[0] + m_mbd_charge_sum[1]) > m_pileup_charge_cut && minbiascheck) + { + minbiascheck = false; + } - return Fun4AllReturnCodes::EVENT_OK; + m_mb_info->setIsAuAuMinimumBias(minbiascheck); + if (!minbiascheck && m_abortEvents) + { + return 1; + } + return 0; } + int MinimumBiasClassifier::process_event(PHCompositeNode *topNode) { if (Verbosity()) @@ -214,14 +269,19 @@ int MinimumBiasClassifier::process_event(PHCompositeNode *topNode) } // Get Nodes from the Tree - if (GetNodes(topNode)) + int ret = GetNodes(topNode); + if (ret != Fun4AllReturnCodes::EVENT_OK) { - return Fun4AllReturnCodes::EVENT_OK; + return ret; } if (FillMinimumBiasInfo()) { - return Fun4AllReturnCodes::EVENT_OK; + if (Verbosity()) + { + std::cout << "MinimumBiasClassifier::process_event Aborting Event - not minbias" << std::endl; + } + return Fun4AllReturnCodes::ABORTEVENT; } return Fun4AllReturnCodes::EVENT_OK; @@ -234,7 +294,7 @@ int MinimumBiasClassifier::GetNodes(PHCompositeNode *topNode) std::cout << __FILE__ << " :: " << __FUNCTION__ << " :: " << __LINE__ << std::endl; } - m_mb_info = findNode::getClass(topNode, "MinimumBiasInfo"); + m_mb_info = findNode::getClass(topNode, m_mb_info_nodename); if (!m_mb_info) { @@ -242,7 +302,7 @@ int MinimumBiasClassifier::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - m_mbd_container = findNode::getClass(topNode, "MbdPmtContainer"); + m_mbd_container = findNode::getClass(topNode, m_mbd_pmt_nodename); if (Verbosity()) { std::cout << "Getting MBD Tubes" << std::endl; @@ -254,9 +314,9 @@ int MinimumBiasClassifier::GetNodes(PHCompositeNode *topNode) return Fun4AllReturnCodes::ABORTRUN; } - if (!m_issim) + if (!m_issim && m_useZDC) { - m_zdcinfo = findNode::getClass(topNode, "Zdcinfo"); + m_zdcinfo = findNode::getClass(topNode, m_zdc_info_nodename); if (Verbosity()) { std::cout << "Getting ZDC Info" << std::endl; @@ -273,7 +333,7 @@ int MinimumBiasClassifier::GetNodes(PHCompositeNode *topNode) std::cout << "Getting Vertex Map" << std::endl; } - m_global_vertex_map = findNode::getClass(topNode, "GlobalVertexMap"); + m_global_vertex_map = findNode::getClass(topNode, m_global_vertex_nodename); if (!m_global_vertex_map) { @@ -297,14 +357,14 @@ void MinimumBiasClassifier::CreateNodes(PHCompositeNode *topNode) PHCompositeNode *detNode = dynamic_cast(dstIter.findFirst("PHCompositeNode", "GLOBAL")); if (!detNode) { - std::cout << PHWHERE << "Detector Node missing, making one" << std::endl; detNode = new PHCompositeNode("GLOBAL"); dstNode->addNode(detNode); } + std::string nodename = m_mb_info_nodename; MinimumBiasInfo *mb = new MinimumBiasInfov1(); - PHIODataNode *mbNode = new PHIODataNode(mb, "MinimumBiasInfo", "PHObject"); + PHIODataNode *mbNode = new PHIODataNode(mb, nodename, "PHObject"); detNode->addNode(mbNode); return; diff --git a/offline/packages/trigger/MinimumBiasClassifier.h b/offline/packages/trigger/MinimumBiasClassifier.h index f84add84f8..a1ccb44039 100644 --- a/offline/packages/trigger/MinimumBiasClassifier.h +++ b/offline/packages/trigger/MinimumBiasClassifier.h @@ -1,7 +1,10 @@ #ifndef TRIGGER_MINBIASCLASSIFIER_H #define TRIGGER_MINBIASCLASSIFIER_H +#include "MinimumBiasInfo.h" + #include + #include #include #include // for allocator, string @@ -10,7 +13,6 @@ // Forward declarations -class MinimumBiasInfo; class PHCompositeNode; class Zdcinfo; class MbdPmtContainer; @@ -21,6 +23,7 @@ class MinimumBiasClassifier : public SubsysReco { public: //! constructor + explicit MinimumBiasClassifier(const std::string &name = "MinimumBiasClassifier"); //! destructor @@ -28,7 +31,7 @@ class MinimumBiasClassifier : public SubsysReco ~MinimumBiasClassifier() override = default; int InitRun(PHCompositeNode *) override; - static void CreateNodes(PHCompositeNode *); + void CreateNodes(PHCompositeNode *); int GetNodes(PHCompositeNode *); //! event processing method @@ -47,32 +50,38 @@ class MinimumBiasClassifier : public SubsysReco void setOverwriteScale(const std::string &url) { m_overwrite_url_scale = url; - m_overwrite_scale = true; } void setOverwriteVtx(const std::string &url) { m_overwrite_url_vtx = url; - m_overwrite_vtx = true; } void setIsSim(const bool sim) { m_issim = sim; } + void setSpecies(MinimumBiasInfo::SPECIES spec) { m_species = spec; }; + + void setRejectPileup(bool v) { m_reject_pileup = v; }; + + void abortEvents(const bool abort) { m_abortEvents = abort; }; + + void set_minbiasNodeName(const std::string &name) + { + m_mb_info_nodename = name; + } + void set_mbdPmtNodeName(const std::string &name) + { + m_mbd_pmt_nodename = name; + } + void set_zdcInfoNodeName(const std::string &name) + { + m_zdc_info_nodename = name; + } + void set_globalvertexNodeName(const std::string &name) + { + m_global_vertex_nodename = name; + } + private: - bool m_issim{false}; float getVertexScale(); - std::string m_dbfilename; - - bool m_overwrite_scale{false}; - bool m_overwrite_vtx{false}; - std::string m_overwrite_url_scale{""}; - std::string m_overwrite_url_vtx{""}; - - const float m_z_vtx_cut{60.}; - const float m_mbd_north_cut{10.}; - const float m_mbd_south_cut{150}; - const float m_mbd_charge_cut{0.5}; - const float m_mbd_time_cut{25.}; - // const int m_mbd_tube_cut{2}; - const float m_zdc_cut{60.}; MinimumBiasInfo *m_mb_info{nullptr}; MbdPmtContainer *m_mbd_container{nullptr}; @@ -80,13 +89,45 @@ class MinimumBiasClassifier : public SubsysReco GlobalVertexMap *m_global_vertex_map{nullptr}; Zdcinfo *m_zdcinfo{nullptr}; - std::array m_zdc_energy_sum{}; - std::array m_mbd_charge_sum{}; - std::array m_mbd_hit{}; + bool m_abortEvents{false}; + bool m_issim{false}; + bool m_useZDC{true}; + bool m_box_cut{true}; + bool m_reject_pileup{true}; + + float m_pileup_charge_cut{200.}; + + int m_hit_cut{2}; + double m_max_charge_cut{2100}; double m_centrality_scale{std::numeric_limits::quiet_NaN()}; double m_vertex_scale{std::numeric_limits::quiet_NaN()}; + float m_vertex{std::numeric_limits::quiet_NaN()}; + + float m_z_vtx_cut{60.}; + float m_mbd_north_cut{10.}; + float m_mbd_south_cut{150.}; + float m_mbd_charge_cut{0.5}; + float m_mbd_time_cut{25.}; + // const int m_mbd_tube_cut{2}; + float m_zdc_cut{60.}; + + MinimumBiasInfo::SPECIES m_species{MinimumBiasInfo::SPECIES::AUAU}; + + std::string m_mb_info_nodename{"MinimumBiasInfo"}; + std::string m_mbd_pmt_nodename{"MbdPmtContainer"}; + std::string m_zdc_info_nodename{"Zdcinfo"}; + std::string m_global_vertex_nodename{"GlobalVertexMap"}; + + std::string m_overwrite_url_scale; + std::string m_overwrite_url_vtx; + + + std::array m_zdc_energy_sum{}; + std::array m_mbd_charge_sum{}; + std::array m_mbd_hit{}; + std::vector, float>> m_vertex_scales{}; }; diff --git a/offline/packages/trigger/MinimumBiasInfo.h b/offline/packages/trigger/MinimumBiasInfo.h index 8cd8472e87..94f38b1a8d 100644 --- a/offline/packages/trigger/MinimumBiasInfo.h +++ b/offline/packages/trigger/MinimumBiasInfo.h @@ -6,6 +6,14 @@ class MinimumBiasInfo : public PHObject { public: + + enum SPECIES + { + AUAU = 0, + OO = 1, + PP = 2 + }; + ~MinimumBiasInfo() override {}; void identify(std::ostream &os = std::cout) const override { os << "MinimumBiasInfo base class" << std::endl; }; diff --git a/offline/packages/trigger/TriggerPrimitivev1.h b/offline/packages/trigger/TriggerPrimitivev1.h index f484449096..6b62d34747 100644 --- a/offline/packages/trigger/TriggerPrimitivev1.h +++ b/offline/packages/trigger/TriggerPrimitivev1.h @@ -6,7 +6,6 @@ #include #include -#include /// class TriggerPrimitivev1 : public TriggerPrimitive diff --git a/offline/packages/uspin/SpinDBContent.cc b/offline/packages/uspin/SpinDBContent.cc index 9df8f70610..56c967afc9 100644 --- a/offline/packages/uspin/SpinDBContent.cc +++ b/offline/packages/uspin/SpinDBContent.cc @@ -2,7 +2,66 @@ #include -void SpinDBContent::identify(std::ostream& os) const +void SpinDBContent::identify(std::ostream &os) const { os << "virtual SpinDBContent object" << std::endl; } + +int SpinDBContent::GetPolarizationBlue(int /*bunch*/, float &value, float &error) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationBlue(int /*bunch*/, float &value, float &error, float &syserr) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationBlue(int /*bunch*/, double &value, double &error) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationBlue(int /*bunch*/, double &value, double &error, double &syserr) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationYellow(int /*bunch*/, float &value, float &error) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + return -1; +} +int SpinDBContent::GetPolarizationYellow(int /*bunch*/, float &value, float &error, float &syserr) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationYellow(int /*bunch*/, double &value, double &error) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + return -1; +} + +int SpinDBContent::GetPolarizationYellow(int /*bunch*/, double &value, double &error, double &syserr) const +{ + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); + return -1; +} diff --git a/offline/packages/uspin/SpinDBContent.h b/offline/packages/uspin/SpinDBContent.h index a8cc7ea486..fb75d49a93 100644 --- a/offline/packages/uspin/SpinDBContent.h +++ b/offline/packages/uspin/SpinDBContent.h @@ -71,14 +71,14 @@ class SpinDBContent : public PHObject virtual int GetBadRunFlag() const = 0; virtual int GetCrossingShift() const = 0; - virtual int GetPolarizationBlue(int, float&, float&) const { return -1; } - virtual int GetPolarizationBlue(int, float&, float&, float&) const { return -1; } - virtual int GetPolarizationBlue(int, double&, double&) const { return -1; } - virtual int GetPolarizationBlue(int, double&, double&, double&) const { return -1; } - virtual int GetPolarizationYellow(int, float&, float&) const { return -1; } - virtual int GetPolarizationYellow(int, float&, float&, float&) const { return -1; } - virtual int GetPolarizationYellow(int, double&, double&) const { return -1; } - virtual int GetPolarizationYellow(int, double&, double&, double&) const { return -1; } + virtual int GetPolarizationBlue(int, float&, float&) const; + virtual int GetPolarizationBlue(int, float&, float&, float&) const; + virtual int GetPolarizationBlue(int, double&, double&) const; + virtual int GetPolarizationBlue(int, double&, double&, double&) const; + virtual int GetPolarizationYellow(int, float&, float&) const; + virtual int GetPolarizationYellow(int, float&, float&, float&) const; + virtual int GetPolarizationYellow(int, double&, double&) const; + virtual int GetPolarizationYellow(int, double&, double&, double&) const; virtual int GetSpinPatternBlue(int) const { return -1; } virtual int GetSpinPatternYellow(int) const { return -1; } diff --git a/offline/packages/uspin/SpinDBContentv1.cc b/offline/packages/uspin/SpinDBContentv1.cc index acb110d585..0c67da5cbb 100644 --- a/offline/packages/uspin/SpinDBContentv1.cc +++ b/offline/packages/uspin/SpinDBContentv1.cc @@ -17,41 +17,41 @@ void SpinDBContentv1::InitializeV1() for (int icross = 0; icross < GetNCrossing(); icross++) { - bpol[icross] = (float) GetErrorValue(); - bpolerr[icross] = (float) GetErrorValue(); - bpolsys[icross] = (float) GetErrorValue(); - ypol[icross] = (float) GetErrorValue(); - ypolerr[icross] = (float) GetErrorValue(); - ypolsys[icross] = (float) GetErrorValue(); + bpol[icross] = GetErrorValue(); + bpolerr[icross] = GetErrorValue(); + bpolsys[icross] = GetErrorValue(); + ypol[icross] = GetErrorValue(); + ypolerr[icross] = GetErrorValue(); + ypolsys[icross] = GetErrorValue(); bpat[icross] = GetErrorValue(); ypat[icross] = GetErrorValue(); - scaler_mbd_vtxcut[icross] = (long long) GetErrorValue(); - scaler_mbd_nocut[icross] = (long long) GetErrorValue(); - scaler_zdc_nocut[icross] = (long long) GetErrorValue(); + scaler_mbd_vtxcut[icross] = GetErrorValue(); + scaler_mbd_nocut[icross] = GetErrorValue(); + scaler_zdc_nocut[icross] = GetErrorValue(); bad_bunch[icross] = GetErrorValue(); } - cross_angle = (float) GetErrorValue(); - cross_angle_std = (float) GetErrorValue(); - cross_angle_min = (float) GetErrorValue(); - cross_angle_max = (float) GetErrorValue(); - - asym_bf = (float) GetErrorValue(); - asym_bb = (float) GetErrorValue(); - asym_yf = (float) GetErrorValue(); - asym_yb = (float) GetErrorValue(); - asymerr_bf = (float) GetErrorValue(); - asymerr_bb = (float) GetErrorValue(); - asymerr_yf = (float) GetErrorValue(); - asymerr_yb = (float) GetErrorValue(); - phase_bf = (float) GetErrorValue(); - phase_bb = (float) GetErrorValue(); - phase_yf = (float) GetErrorValue(); - phase_yb = (float) GetErrorValue(); - phaseerr_bf = (float) GetErrorValue(); - phaseerr_bb = (float) GetErrorValue(); - phaseerr_yf = (float) GetErrorValue(); - phaseerr_yb = (float) GetErrorValue(); + cross_angle = GetErrorValue(); + cross_angle_std = GetErrorValue(); + cross_angle_min = GetErrorValue(); + cross_angle_max = GetErrorValue(); + + asym_bf = GetErrorValue(); + asym_bb = GetErrorValue(); + asym_yf = GetErrorValue(); + asym_yb = GetErrorValue(); + asymerr_bf = GetErrorValue(); + asymerr_bb = GetErrorValue(); + asymerr_yf = GetErrorValue(); + asymerr_yb = GetErrorValue(); + phase_bf = GetErrorValue(); + phase_bb = GetErrorValue(); + phase_yf = GetErrorValue(); + phase_yb = GetErrorValue(); + phaseerr_bf = GetErrorValue(); + phaseerr_bb = GetErrorValue(); + phaseerr_yf = GetErrorValue(); + phaseerr_yb = GetErrorValue(); } ///////////////////////////////////////////////////////////////// @@ -307,6 +307,8 @@ int SpinDBContentv1::GetPolarizationBlue(int bunch, float &value, float &error) { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); return (GetErrorValue()); } value = bpol[bunch]; @@ -320,6 +322,9 @@ int SpinDBContentv1::GetPolarizationBlue(int bunch, float &value, float &error, { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); return (GetErrorValue()); } value = bpol[bunch]; @@ -334,6 +339,8 @@ int SpinDBContentv1::GetPolarizationBlue(int bunch, double &value, double &error { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); return (GetErrorValue()); } value = (double) bpol[bunch]; @@ -347,6 +354,9 @@ int SpinDBContentv1::GetPolarizationBlue(int bunch, double &value, double &error { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); return (GetErrorValue()); } value = (double) bpol[bunch]; @@ -361,6 +371,8 @@ int SpinDBContentv1::GetPolarizationYellow(int bunch, float &value, float &error { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); return (GetErrorValue()); } value = ypol[bunch]; @@ -374,6 +386,9 @@ int SpinDBContentv1::GetPolarizationYellow(int bunch, float &value, float &error { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); return (GetErrorValue()); } value = ypol[bunch]; @@ -388,6 +403,8 @@ int SpinDBContentv1::GetPolarizationYellow(int bunch, double &value, double &err { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); return (GetErrorValue()); } value = (double) ypol[bunch]; @@ -401,6 +418,9 @@ int SpinDBContentv1::GetPolarizationYellow(int bunch, double &value, double &err { if (CheckBunchNumber(bunch) == GetErrorValue()) { + value = GetErrorValue(); + error = GetErrorValue(); + syserr = GetErrorValue(); return (GetErrorValue()); } value = (double) ypol[bunch]; diff --git a/offline/packages/uspin/SpinDBNode.cc b/offline/packages/uspin/SpinDBNode.cc index 6bb03fc55d..5b7e480195 100644 --- a/offline/packages/uspin/SpinDBNode.cc +++ b/offline/packages/uspin/SpinDBNode.cc @@ -1,6 +1,14 @@ #include "SpinDBNode.h" +#include "SpinDBContent.h" +#include "SpinDBContentv1.h" +#include "SpinDBOutput.h" + +#include + +#include #include +#include #include #include @@ -9,14 +17,6 @@ #include #include -#include - -#include -#include - -#include "SpinDBContent.h" -#include "SpinDBContentv1.h" -#include "SpinDBOutput.h" SpinDBNode::SpinDBNode(const std::string &name) : SubsysReco(name) diff --git a/simulation/g4simulation/g4bbc/MbdVertexFastSimReco.cc b/simulation/g4simulation/g4bbc/MbdVertexFastSimReco.cc index 45458b9b49..97f801771c 100644 --- a/simulation/g4simulation/g4bbc/MbdVertexFastSimReco.cc +++ b/simulation/g4simulation/g4bbc/MbdVertexFastSimReco.cc @@ -2,7 +2,7 @@ #include "MbdVertexFastSimReco.h" #include -#include +#include #include #include @@ -95,7 +95,7 @@ int MbdVertexFastSimReco::process_event(PHCompositeNode *topNode) return Fun4AllReturnCodes::EVENT_OK; } - MbdVertex *vertex = new MbdVertexv2(); + MbdVertex *vertex = new MbdVertexv3(); if (m_T_Smear >= 0.0) { diff --git a/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl b/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl index f74af6957d..a1dbd352c3 100755 --- a/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl +++ b/simulation/g4simulation/g4detectors/CreateG4Subsystem.pl @@ -1007,7 +1007,7 @@ () print F "dnl no point in suppressing warnings people should \n"; print F "dnl at least see them, so here we go for g++: -Wall\n"; print F "if test \$ac_cv_prog_gxx = yes; then\n"; - print F " CXXFLAGS=\"\$CXXFLAGS -Wall -Werror\"\n"; + print F " CXXFLAGS=\"\$CXXFLAGS -Wall -Wextra -Wshadow -Werror\"\n"; print F "fi\n"; print F "\n"; @@ -1027,8 +1027,8 @@ () print F "AM_CPPFLAGS = \\\n"; print F " -I\$(includedir) \\\n"; - print F " -I\$(OFFLINE_MAIN)/include \\\n"; - print F " -I\$(ROOTSYS)/include \n"; + print F " -isystem\$(OFFLINE_MAIN)/include \\\n"; + print F " -isystem\$(ROOTSYS)/include \n"; print F "\n"; print F "AM_LDFLAGS = \\\n"; diff --git a/simulation/g4simulation/g4detectors/Makefile.am b/simulation/g4simulation/g4detectors/Makefile.am index 9e219fe9e0..6035683444 100644 --- a/simulation/g4simulation/g4detectors/Makefile.am +++ b/simulation/g4simulation/g4detectors/Makefile.am @@ -79,6 +79,7 @@ pkginclude_HEADERS = \ PHG4DetectorSubsystem.h \ PHG4DetectorGroupSubsystem.h \ PHG4FullProjSpacalCellReco.h \ + PHG4GeantinoIonization.h \ PHG4GDMLSubsystem.h \ PHG4HcalDefs.h \ PHG4HcalCellReco.h \ @@ -100,6 +101,7 @@ pkginclude_HEADERS = \ PHG4TpcCylinderGeomContainer.h \ PHG4TpcGeom.h \ PHG4TpcGeomv1.h \ + PHG4TpcGeomv2.h \ PHG4TpcGeomContainer.h \ PHG4ZDCDefs.h \ PHG4ZDCSubsystem.h @@ -137,6 +139,7 @@ ROOTDICTS = \ PHG4TpcCylinderGeomContainer_Dict.cc \ PHG4TpcGeom_Dict.cc \ PHG4TpcGeomv1_Dict.cc \ + PHG4TpcGeomv2_Dict.cc \ PHG4TpcGeomContainer_Dict.cc pcmdir = $(libdir) @@ -177,6 +180,7 @@ libg4detectors_io_la_SOURCES = \ PHG4TpcCylinderGeomContainer.cc \ PHG4TpcGeom.cc \ PHG4TpcGeomv1.cc \ + PHG4TpcGeomv2.cc \ PHG4TpcGeomContainer.cc libg4detectors_la_SOURCES = \ @@ -219,6 +223,7 @@ libg4detectors_la_SOURCES = \ PHG4FullProjSpacalDetector.cc \ PHG4FullProjTiltedSpacalDetector.cc \ PHG4FullProjSpacalCellReco.cc \ + PHG4GeantinoIonization.cc \ PHG4GenHit.cc \ PHG4HcalCellReco.cc \ PHG4HcalDetector.cc \ diff --git a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc new file mode 100644 index 0000000000..b669c58955 --- /dev/null +++ b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.cc @@ -0,0 +1,287 @@ +#include "PHG4GeantinoIonization.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace +{ + // Pure-gas MIP stopping powers in keV/cm. They match the values used by + // the current TPC and Micromegas hit-reconstruction modules. + constexpr double neonMipDedx = 1.56; + constexpr double argonMipDedx = 2.44; + constexpr double cf4MipDedx = 7.00; + constexpr double nitrogenMipDedx = 2.127; + constexpr double isobutaneMipDedx = 5.93; + + // Mean silicon MIP stopping powers in GeV/cm. The MVTX value corresponds + // to 9.6 keV in 25 microns; the INTT value is the value documented by its + // hit reconstruction. + double mvtxMipDedx = 0.00384; + double inttMipDedx = 0.00387; + + // PHG4MicromegasDetector and PHG4MicromegasHitReco both use a fixed + // Ar/isobutane 90/10 gas mixture. + constexpr double tpotMipDedx = + 1e-6 * (0.9 * argonMipDedx + 0.1 * isobutaneMipDedx); +} // namespace + +PHG4GeantinoIonization::PHG4GeantinoIonization(const std::string& name) + : SubsysReco(name) + , m_detectorConfigs{{ + {DetectorId::mvtx, "MVTX", "G4HIT_MVTX", true}, + {DetectorId::intt, "INTT", "G4HIT_INTT", true}, + {DetectorId::tpc, "TPC", "G4HIT_TPC", true}, + {DetectorId::tpot, "MICROMEGAS", "G4HIT_MICROMEGAS", true}}} +{ +} + +int PHG4GeantinoIonization::InitRun(PHCompositeNode* topNode) +{ + if (!m_detectorConfigs[2].enabled) + { + return Fun4AllReturnCodes::EVENT_OK; + } + + // Read the gas fractions from the TPC geometry parameters, as is done in + // PHG4TpcElectronDrift. This keeps the synthetic ionization consistent with + // the geometry built by the macro or loaded from the CDB. + auto* tpcParamsContainer = + findNode::getClass(topNode, "G4GEO_TPC"); + if (!tpcParamsContainer) + { + // Tracking geometry loaded from the CDB initially provides the serialized + // RUN-node parameters. Rebuild G4GEO_TPC from them before TPC hit + // reconstruction, following PHG4TpcElectronDrift::InitRun. + auto* tpcPdbParams = + findNode::getClass(topNode, "G4GEOPARAM_TPC"); + if (!tpcPdbParams) + { + std::cout << PHWHERE + << " Missing both G4GEO_TPC and G4GEOPARAM_TPC" + << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + PHNodeIterator topIter(topNode); + auto* parNode = dynamic_cast( + topIter.findFirst("PHCompositeNode", "PAR")); + if (!parNode) + { + std::cout << PHWHERE << " Missing PAR node" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + PHNodeIterator parIter(parNode); + auto* parTpcNode = dynamic_cast( + parIter.findFirst("PHCompositeNode", "TPC")); + if (!parTpcNode) + { + parTpcNode = new PHCompositeNode("TPC"); + parNode->addNode(parTpcNode); + } + + tpcParamsContainer = new PHParametersContainer("TPC"); + tpcParamsContainer->CreateAndFillFrom(tpcPdbParams, "TPC"); + parTpcNode->addNode( + new PHDataNode( + tpcParamsContainer, "G4GEO_TPC")); + } + + const PHParameters* tpcParams = tpcParamsContainer->GetParameters(0); + if (!tpcParams) + { + std::cout << PHWHERE << " Missing TPC geometry parameters" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } + + const double neonFraction = tpcParams->get_double_param("Ne_frac"); + const double argonFraction = tpcParams->get_double_param("Ar_frac"); + const double cf4Fraction = tpcParams->get_double_param("CF4_frac"); + const double nitrogenFraction = tpcParams->get_double_param("N2_frac"); + const double isobutaneFraction = tpcParams->get_double_param("isobutane_frac"); + + m_tpcMipDedx = + 1e-6 * (neonFraction * neonMipDedx + + argonFraction * argonMipDedx + + cf4Fraction * cf4MipDedx + + nitrogenFraction * nitrogenMipDedx + + isobutaneFraction * isobutaneMipDedx); + + if (Verbosity() > 0) + { + std::cout << Name() + << " TPC gas fractions (Ne/Ar/CF4/N2/isobutane): " + << neonFraction << "/" << argonFraction << "/" + << cf4Fraction << "/" << nitrogenFraction << "/" + << isobutaneFraction + << ", MIP dE/dx: " << m_tpcMipDedx << " GeV/cm" + << std::endl; + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +void PHG4GeantinoIonization::set_mvtx_mip_dedx(const double value) +{ + mvtxMipDedx = value; +} + +void PHG4GeantinoIonization::set_intt_mip_dedx(const double value) +{ + inttMipDedx = value; +} + +double PHG4GeantinoIonization::mip_dedx(const DetectorId detector) const +{ + switch (detector) + { + case DetectorId::mvtx: + return mvtxMipDedx; + case DetectorId::intt: + return inttMipDedx; + case DetectorId::tpc: + return m_tpcMipDedx; + case DetectorId::tpot: + return tpotMipDedx; + } + + return 0; +} + +int PHG4GeantinoIonization::process_event(PHCompositeNode* topNode) +{ + const auto* truthInfo = findNode::getClass(topNode, "G4TruthInfo"); + if (!truthInfo) + { + std::cout << PHWHERE << " Missing G4TruthInfo" << std::endl; + return Fun4AllReturnCodes::ABORTEVENT; + } + + for (const auto& config : m_detectorConfigs) + { + if (!config.enabled) + { + continue; + } + + auto* hits = findNode::getClass(topNode, config.hitNodeName); + if (!hits) + { + if (Verbosity() > 1) + { + std::cout << PHWHERE << " Missing optional node " + << config.hitNodeName << std::endl; + } + continue; + } + + process_detector(hits, truthInfo, config); + } + + return Fun4AllReturnCodes::EVENT_OK; +} + +void PHG4GeantinoIonization::process_detector( + PHG4HitContainer* hits, + const PHG4TruthInfoContainer* truthInfo, + const DetectorConfig& config) const +{ + std::size_t inspected = 0; + std::size_t modified = 0; + std::size_t missingParticle = 0; + std::size_t invalidPath = 0; + + const auto hitRange = hits->getHits(); + for (auto hitIter = hitRange.first; hitIter != hitRange.second; ++hitIter) + { + auto* hit = hitIter->second; + if (!hit) + { + continue; + } + + ++inspected; + + const auto* particle = truthInfo->GetParticle(hit->get_trkid()); + if (!particle) + { + ++missingParticle; + continue; + } + + if (particle->get_name() != m_particleName) + { + continue; + } + + // Keep the operation idempotent. Current stepping actions store negative + // edep/eion sentinels for geantinos. A finite nonnegative value means this + // hit has already been processed. + const double edep = hit->get_edep(); + const double eion = hit->get_eion(); + if (std::isfinite(edep) && edep >= 0 && + std::isfinite(eion) && eion >= 0) + { + continue; + } + + const double dx = hit->get_x(1) - hit->get_x(0); + const double dy = hit->get_y(1) - hit->get_y(0); + const double dz = hit->get_z(1) - hit->get_z(0); + const double pathLength = std::sqrt(dx * dx + dy * dy + dz * dz); + + const double mipDedx = mip_dedx(config.detector); + if (!std::isfinite(pathLength) || pathLength <= 0 || + !std::isfinite(mipDedx) || mipDedx <= 0) + { + ++invalidPath; + continue; + } + + const double syntheticEnergyDeposit = mipDedx * pathLength; + const double syntheticIonization = syntheticEnergyDeposit; + hit->set_edep(syntheticEnergyDeposit); + hit->set_eion(syntheticIonization); + ++modified; + + if (Verbosity() > 2) + { + std::cout << Name() << " " << config.name + << " hit " << hitIter->first + << " track " << hit->get_trkid() + << " path length " << pathLength << " cm" + << " synthetic edep " << syntheticEnergyDeposit << " GeV" + << ", eion " << syntheticIonization << " GeV" + << std::endl; + } + } + + if (Verbosity() > 0) + { + std::cout << Name() << " " << config.name + << ": inspected " << inspected + << ", modified " << modified + << ", missing particle " << missingParticle + << ", invalid path " << invalidPath + << std::endl; + } +} diff --git a/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h new file mode 100644 index 0000000000..ceb532bba1 --- /dev/null +++ b/simulation/g4simulation/g4detectors/PHG4GeantinoIonization.h @@ -0,0 +1,72 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef G4DETECTORS_PHG4GEANTINOIONIZATION_H +#define G4DETECTORS_PHG4GEANTINOIONIZATION_H + +#include + +#include +#include + +class PHCompositeNode; +class PHG4HitContainer; +class PHG4TruthInfoContainer; + +/** + * Replaces the negative energy-deposition sentinel stored for charged + * geantinos with a detector-dependent mean MIP ionization. + * + * This module must run after G4HIT_* nodes are loaded and before detector hit + * reconstruction. It intentionally models only the mean energy deposition; + * downstream detector modules retain their existing fluctuations. + */ +class PHG4GeantinoIonization : public SubsysReco +{ + public: + explicit PHG4GeantinoIonization(const std::string& name = "PHG4GeantinoIonization"); + ~PHG4GeantinoIonization() override = default; + + int InitRun(PHCompositeNode* topNode) override; + int process_event(PHCompositeNode* topNode) override; + + void set_particle_name(const std::string& name) { m_particleName = name; } + + void set_mvtx_enabled(bool value) { m_detectorConfigs[0].enabled = value; } + void set_intt_enabled(bool value) { m_detectorConfigs[1].enabled = value; } + void set_tpc_enabled(bool value) { m_detectorConfigs[2].enabled = value; } + void set_micromegas_enabled(bool value) { m_detectorConfigs[3].enabled = value; } + void set_tpot_enabled(bool value) { set_micromegas_enabled(value); } + + void set_mvtx_mip_dedx(double value); + void set_intt_mip_dedx(double value); + + private: + enum class DetectorId + { + mvtx, + intt, + tpc, + tpot + }; + + struct DetectorConfig + { + DetectorId detector; + std::string name; + std::string hitNodeName; + bool enabled = true; + }; + + void process_detector( + PHG4HitContainer* hits, + const PHG4TruthInfoContainer* truthInfo, + const DetectorConfig& config) const; + + double mip_dedx(DetectorId detector) const; + + std::array m_detectorConfigs; + std::string m_particleName = "chargedgeantino"; + double m_tpcMipDedx = 0; +}; + +#endif // G4DETECTORS_PHG4GEANTINOIONIZATION_H diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeom.h b/simulation/g4simulation/g4detectors/PHG4TpcGeom.h index bdb3bfbae7..93376c1b72 100644 --- a/simulation/g4simulation/g4detectors/PHG4TpcGeom.h +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeom.h @@ -192,6 +192,38 @@ class PHG4TpcGeom : public PHObject return -99999; } + virtual double get_rot_x() const + { + PHOOL_VIRTUAL_WARN("get_rot_x()"); + return 0.0; + } + virtual double get_rot_y() const + { + PHOOL_VIRTUAL_WARN("get_rot_y()"); + return 0.0; + } + virtual double get_rot_z() const + { + PHOOL_VIRTUAL_WARN("get_rot_z()"); + return 0.0; + } + virtual double get_place_x() const + { + PHOOL_VIRTUAL_WARN("get_place_x()"); + return 0.0; + } + virtual double get_place_y() const + { + PHOOL_VIRTUAL_WARN("get_place_y()"); + return 0.0; + } + virtual double get_place_z() const + { + PHOOL_VIRTUAL_WARN("get_place_z()"); + return 0.0; + } + + virtual const std::array, 2> &get_sector_min_phi(); virtual const std::array, 2> &get_sector_max_phi(); @@ -211,6 +243,17 @@ class PHG4TpcGeom : public PHObject { PHOOL_VIRTUAL_WARN("set_phi_bias(const std::array, 2>&)"); } + + + + /* + double get_rot_x() const override { return rot_x; } + double get_rot_y() const override { return rot_y; } + double get_rot_z() const override { return rot_z; } + double get_place_x() const override { return place_x; } + double get_place_y() const override { return place_y; } + double get_place_z() const override { return place_z; } + */ virtual void set_layer(const int) { PHOOL_VIRTUAL_WARN("set_layer(const int)"); } virtual void set_radius(const double) { PHOOL_VIRTUAL_WARN("set_radius(const double)"); } @@ -237,7 +280,15 @@ class PHG4TpcGeom : public PHObject virtual void set_adc_clock(const double) { PHOOL_VIRTUAL_WARN("set_adc_clock(const double)"); } virtual void set_extended_readout_time(const double) { PHOOL_VIRTUAL_WARN("set_extended_readout_time(const double)"); } virtual void set_drift_velocity_sim(const double) { PHOOL_VIRTUAL_WARN("set_drift_velocity_sim(const double)"); } - + + virtual void set_rot_x(const double) { PHOOL_VIRTUAL_WARN("set_rot_x(const double)"); } + virtual void set_rot_y(const double) { PHOOL_VIRTUAL_WARN("set_rot_y(const double)"); } + virtual void set_rot_z(const double) { PHOOL_VIRTUAL_WARN("set_rot_z(const double)"); } + + virtual void set_place_x(const double) { PHOOL_VIRTUAL_WARN("set_place_x(const double)"); } + virtual void set_place_y(const double) { PHOOL_VIRTUAL_WARN("set_place_y(const double)"); } + virtual void set_place_z(const double) { PHOOL_VIRTUAL_WARN("set_place_z(const double)"); } + //! load parameters from PHParameters, which interface to Database/XML/ROOT files virtual void ImportParameters(const PHParameters & /*param*/) { return; } diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc new file mode 100644 index 0000000000..85273db301 --- /dev/null +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.cc @@ -0,0 +1,626 @@ +#include "PHG4TpcGeomv2.h" +#include "PHG4CylinderCellDefs.h" + +#include + +#include + +namespace +{ + // streamer for internal 2dimensional arrays + using array_t = std::array, PHG4TpcGeomv2::NSides>; + std::ostream& operator<<(std::ostream& out, const array_t& array) + { + out << "{ "; + for (const auto& iside : array) + { + out << "{"; + bool first = true; + for (const auto& value : iside) + { + if (!first) + { + out << ", "; + } + first = false; + out << value; + } + out << "} "; + } + out << " }"; + return out; + } +} // namespace + +std::ostream& operator<<(std::ostream& out, const PHG4TpcGeomv2& geom) +{ + out << "PHG4TpcGeomv2 - layer: " << geom.layer << std::endl; + out + << " binnig: " << geom.binning + << ", radius: " << geom.radius + << ", nzbins: " << geom.nzbins + << ", zmin: " << geom.zmin + << ", zstep: " << geom.zstep + << ", nphibins: " << geom.nphibins + << ", phimin: " << geom.phimin + << ", phistep: " << geom.phistep + << ", thickness: " << geom.thickness + << std::endl; + + out << " sector_R_bias: " << geom.sector_R_bias << std::endl; + out << " sector_Phi_bias: " << geom.sector_Phi_bias << std::endl; + out << " sector_min_Phi: " << geom.sector_min_Phi << std::endl; + out << " sector_max_Phi: " << geom.sector_max_Phi << std::endl; + + return out; +} + +void PHG4TpcGeomv2::set_zbins(const int i) +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + nzbins = i; +} + +void PHG4TpcGeomv2::set_zmin(const double z) +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + zmin = z; +} + +int PHG4TpcGeomv2::get_zbins() const +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return nzbins; +} + +double +PHG4TpcGeomv2::get_zmin() const +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return zmin; +} + +double +PHG4TpcGeomv2::get_zstep() const +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return zstep; +} + +void PHG4TpcGeomv2::set_zstep(const double z) +{ + check_binning_method(PHG4CylinderCellDefs::sizebinning); + zstep = z; +} + +int PHG4TpcGeomv2::get_phibins() const +{ + check_binning_method_phi("PHG4TpcGeomv2::get_phibins"); + return nphibins; +} + +double +PHG4TpcGeomv2::get_phistep() const +{ + check_binning_method_phi("PHG4TpcGeomv2::get_phistep"); + return phistep; +} + +double +PHG4TpcGeomv2::get_phimin() const +{ + check_binning_method_phi("PHG4TpcGeomv2::get_phimin"); + return phimin; +} + +void PHG4TpcGeomv2::set_phibins(const int i) +{ + check_binning_method_phi("PHG4TpcGeomv2::set_phibins"); + nphibins = i; +} + +void PHG4TpcGeomv2::set_phistep(const double phi) +{ + check_binning_method_phi("PHG4TpcGeomv2::set_phistep"); + phistep = phi; +} + +void PHG4TpcGeomv2::set_phimin(const double phi) +{ + check_binning_method_phi("PHG4TpcGeomv2::set_phimin"); + phimin = phi; +} + +int PHG4TpcGeomv2::get_etabins() const +{ + check_binning_method_eta("PHG4TpcGeomv2::get_etabins"); + return nzbins; +} + +double +PHG4TpcGeomv2::get_etastep() const +{ + check_binning_method_eta("PHG4TpcGeomv2::get_etastep"); + return zstep; +} +double +PHG4TpcGeomv2::get_etamin() const +{ + check_binning_method_eta("PHG4TpcGeomv2::get_etamin"); + return zmin; +} + +void PHG4TpcGeomv2::set_etamin(const double z) +{ + check_binning_method_eta("PHG4TpcGeomv2::set_etamin"); + zmin = z; +} + +void PHG4TpcGeomv2::set_etastep(const double z) +{ + check_binning_method_eta("PHG4TpcGeomv2::set_etastep"); + zstep = z; +} + +void PHG4TpcGeomv2::set_etabins(const int i) +{ + check_binning_method_eta("PHG4TpcGeomv2::set_etabins"); + nzbins = i; +} + +void PHG4TpcGeomv2::identify(std::ostream& os) const +{ + os << "PHG4TpcGeomv2::identify - layer: " << layer << std::endl; + + os + << " binning: " << binning + << ", radius: " << radius + << ", nzbins: " << nzbins + << ", zmin: " << zmin + << ", zstep: " << zstep + << ", nphibins: " << nphibins + << ", phimin: " << phimin + << ", phistep: " << phistep + << ", thickness: " << thickness + << std::endl; + + os << " sector_R_bias: " << sector_R_bias << std::endl; + os << " sector_Phi_bias: " << sector_Phi_bias << std::endl; + os << " sector_min_Phi: " << sector_min_Phi << std::endl; + os << " sector_max_Phi: " << sector_max_Phi << std::endl; + + os << " rotation: rot_x " << rot_x << " rot_y " << rot_y << " rot_z " << rot_z << std::endl; + os << " translation: place_x " << place_x << " place_y " << place_y << " place_z " << place_z << std::endl; +} + +std::pair +PHG4TpcGeomv2::get_zbounds(const int ibin) const +{ + if (ibin < 0 || ibin >= nzbins) + { + std::cout << PHWHERE << " Asking for invalid bin in z: " << ibin << std::endl; + exit(1); + } + check_binning_method(PHG4CylinderCellDefs::sizebinning); + double zlow = zmin + ibin * zstep; + double zhigh = zlow + zstep; + return std::make_pair(zlow, zhigh); +} + +std::pair +PHG4TpcGeomv2::get_etabounds(const int ibin) const +{ + if (ibin < 0 || ibin >= nzbins) + { + std::cout << PHWHERE << " Asking for invalid bin in z: " << ibin << std::endl; + exit(1); + } + check_binning_method_eta("PHG4TpcGeomv2::get_etabounds"); + // check_binning_method(PHG4CylinderCellDefs::etaphibinning); + double zlow = zmin + ibin * zstep; + double zhigh = zlow + zstep; + return std::make_pair(zlow, zhigh); +} + +std::pair +PHG4TpcGeomv2::get_phibounds(const int ibin) const +{ + if (ibin < 0 || ibin >= nphibins) + { + std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; + exit(1); + } + + double philow = phimin + ibin * phistep; + double phihigh = philow + phistep; + return std::make_pair(philow, phihigh); +} + +int PHG4TpcGeomv2::get_zbin(const double z) const +{ + if (z < zmin || z >= (zmin + nzbins * zstep)) + { + // cout << PHWHERE << "Asking for bin for z outside of z range: " << z << endl; + return -1; + } + + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return floor((z - zmin) / zstep); +} + +int PHG4TpcGeomv2::get_etabin(const double eta) const +{ + if (eta < zmin || eta >= (zmin + nzbins * zstep)) + { + // cout << "Asking for bin for eta outside of eta range: " << eta << endl; + return -1; + } + check_binning_method_eta(); + return floor((eta - zmin) / zstep); +} + +int PHG4TpcGeomv2::get_phibin_new(const double phi) const +{ + double norm_phi = phi; + if (phi < phimin || phi >= (phimin + nphibins * phistep)) + { + int nwraparound = -floor((phi - phimin) * 0.5 / M_PI); + norm_phi += 2 * M_PI * nwraparound; + } + check_binning_method_phi(); + return floor((norm_phi - phimin) / phistep); +} + +int PHG4TpcGeomv2::find_phibin(const double phi, int side) const +{ + if(side < 0 || side > 1) + { + std::cout << PHWHERE << " side is not valid, have to quit!" << std::endl; + exit(1); + } + + double norm_phi = phi; + if (phi < phimin || phi >= (phimin + nphibins * phistep)) + { + int nwraparound = -floor((phi - phimin) * 0.5 / M_PI); + norm_phi += 2 * M_PI * nwraparound; + } + // if (phi > M_PI){ + // norm_phi = phi - 2* M_PI; + // } + // if (phi < phimin){ + // norm_phi = phi + 2* M_PI; + // } + //side = 0; + + int phi_bin = -1; + + for (std::size_t s = 0; s < sector_max_Phi[side].size(); s++) + { + if (norm_phi < sector_max_Phi[side][s] && norm_phi > sector_min_Phi[side][s]) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = (floor(std::abs(sector_max_Phi[side][s] - norm_phi) / phistep) + nphibins / 12 * s); + break; + } + if (s == 11) + { + if (norm_phi < sector_max_Phi[side][s] && norm_phi >= -M_PI) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = floor(std::abs(sector_max_Phi[side][s] - norm_phi) / phistep) + nphibins / 12 * s; + break; + } + if (norm_phi > sector_min_Phi[side][s] + 2 * M_PI) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = floor(std::abs(sector_max_Phi[side][s] - (norm_phi - 2 * M_PI)) / phistep) + nphibins / 12 * s; + break; + } + } + } + return phi_bin; +} + +float PHG4TpcGeomv2::get_pad_float(const double phi, int side) const +{ + if(side < 0 || side > 1) + { + std::cout << PHWHERE << " side is not valid, have to quit!" << std::endl; + exit(1); + } + + double norm_phi = phi; + if (phi < phimin || phi >= (phimin + nphibins * phistep)) + { + int nwraparound = -floor((phi - phimin) * 0.5 / M_PI); + norm_phi += 2 * M_PI * nwraparound; + } + // if (phi > M_PI){ + // norm_phi = phi - 2* M_PI; + // } + // if (phi < phimin){ + // norm_phi = phi + 2* M_PI; + // } + //side = 0; + + float phi_bin = -1; + + for (std::size_t s = 0; s < sector_max_Phi[side].size(); s++) + { + if (norm_phi < sector_max_Phi[side][s] && norm_phi > sector_min_Phi[side][s]) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = (std::abs(sector_max_Phi[side][s] - norm_phi) / phistep) + nphibins / 12 * s; + break; + } + if (s == 11) + { + if (norm_phi < sector_max_Phi[side][s] && norm_phi >= -M_PI) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = (std::abs(sector_max_Phi[side][s] - norm_phi) / phistep) + nphibins / 12 * s; + break; + } + if (norm_phi > sector_min_Phi[side][s] + 2 * M_PI) + { + // NOLINTNEXTLINE(bugprone-integer-division) + phi_bin = (std::abs(sector_max_Phi[side][s] - (norm_phi - 2 * M_PI)) / phistep) + nphibins / 12 * s; + break; + } + } + } + return phi_bin - 0.5; +} + +float PHG4TpcGeomv2::get_tbin_float(const double z) const +{ + if (z < zmin || z >= (zmin + nzbins * zstep)) + { + // cout << PHWHERE << "Asking for bin for z outside of z range: " << z << endl; + return -1; + } + + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return ((z - zmin) / zstep) - 0.5; +} + +int PHG4TpcGeomv2::get_phibin(const double phi, int side) const +{ + if(side < 0 || side > 1) + { + std::cout << PHWHERE << " side is not valid, have to quit!" << std::endl; + exit(1); + } + + double new_phi = phi; + if (phi > M_PI) + { + new_phi = phi - 2 * M_PI; + } + if (phi < phimin) + { + new_phi = phi + 2 * M_PI; + } + // Get phi-bin number + int phi_bin = find_phibin(new_phi, side); + + //side = 0; + // If phi-bin is not defined, check that it is in the dead area and put it to the edge of sector + if (phi_bin < 0) + { + // + for (std::size_t s = 0; s < sector_max_Phi[side].size(); s++) + { + double daPhi = 0; + if (s == 0) + { + daPhi = fabs(sector_min_Phi[side][11] + 2 * M_PI - sector_max_Phi[side][s]); + } + else + { + daPhi = fabs(sector_min_Phi[side][s - 1] - sector_max_Phi[side][s]); + } + + double min_phi = sector_max_Phi[side][s]; + double max_phi = sector_max_Phi[side][s] + daPhi; + if (new_phi <= max_phi && new_phi >= min_phi) + { + if (fabs(max_phi - new_phi) > fabs(new_phi - min_phi)) + { + new_phi = min_phi - phistep / 5; + } + else + { + new_phi = max_phi + phistep / 5; + } + } + } + // exit(1); + + phi_bin = find_phibin(new_phi, side); + if (phi_bin < 0) + { + std::cout << PHWHERE << "Asking for bin for phi outside of phi range: " << phi << std::endl; + exit(1); + // phi_bin=0; + } + } + return phi_bin; +} + +double +PHG4TpcGeomv2::get_zcenter(const int ibin) const +{ + if (ibin < 0 || ibin >= nzbins) + { + std::cout << PHWHERE << "Asking for invalid bin in z: " << ibin << std::endl; + exit(1); + } + check_binning_method(PHG4CylinderCellDefs::sizebinning); + return zmin + (ibin + 0.5) * zstep; +} + +double +PHG4TpcGeomv2::get_etacenter(const int ibin) const +{ + if (ibin < 0 || ibin >= nzbins) + { + std::cout << PHWHERE << "Asking for invalid bin in eta: " << ibin << std::endl; + std::cout << "minbin: 0, maxbin " << nzbins << std::endl; + exit(1); + } + check_binning_method_eta(); + return zmin + (ibin + 0.5) * zstep; +} + +double +PHG4TpcGeomv2::get_phicenter_new(const int ibin) const +{ + if (ibin < 0 || ibin >= nphibins) + { + std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; + exit(1); + } + + check_binning_method_phi(); + + return (phimin + (ibin + 0.5) * phistep); +} + +double +PHG4TpcGeomv2::get_phicenter(const int ibin, const int side) const +{ + if(side < 0 || side > 1) + { + std::cout << PHWHERE << " side is not valid, have to quit!" << std::endl; + exit(1); + } + + // double phi_center = -999; + if (ibin < 0 || ibin >= nphibins) + { + std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; + exit(1); + } + + check_binning_method_phi(); + + //const int side = 0; + unsigned int pads_per_sector = nphibins / 12; + unsigned int sector = ibin / pads_per_sector; + double phi_center = (sector_max_Phi[side][sector] - (ibin + 0.5 - sector * pads_per_sector) * phistep); + if (phi_center <= -M_PI) + { + phi_center += 2 * M_PI; + } + return phi_center; +} + +double +PHG4TpcGeomv2::get_phi(const float ibin, const int side) const +{ + if(side < 0 || side > 1) + { + std::cout << PHWHERE << " side is not valid, have to quit!" << std::endl; + exit(1); + } + + // double phi_center = -999; + if (ibin < 0 || ibin >= nphibins) + { + std::cout << PHWHERE << "Asking for invalid bin in phi: " << ibin << std::endl; + exit(1); + } + + check_binning_method_phi(); + + //const int side = 0; + unsigned int pads_per_sector = nphibins / 12; + unsigned int sector = ibin / pads_per_sector; + double phi = (sector_max_Phi[side][sector] - (ibin + 0.5 - sector * pads_per_sector) * phistep); + if (phi <= -M_PI) + { + phi += 2 * M_PI; + } + return phi; +} + +std::string +PHG4TpcGeomv2::methodname(const int i) const +{ + switch (i) + { + case PHG4CylinderCellDefs::sizebinning: + return "Bins in cm"; + break; + case PHG4CylinderCellDefs::etaphibinning: + return "Eta/Phi bins"; + break; + case PHG4CylinderCellDefs::etaslatbinning: + return "Eta/numslat bins"; + break; + case PHG4CylinderCellDefs::spacalbinning: + return "SPACAL Tower bins"; + break; + default: + break; + } + return "Unknown"; +} + +void PHG4TpcGeomv2::check_binning_method(const int i) const +{ + if (binning != i) + { + std::cout << "different binning method used " << methodname(binning) + << ", not : " << methodname(i) + << std::endl; + exit(1); + } + return; +} + +void PHG4TpcGeomv2::check_binning_method_eta(const std::string& src) const +{ + if (binning != PHG4CylinderCellDefs::etaphibinning && + binning != PHG4CylinderCellDefs::etaslatbinning && + binning != PHG4CylinderCellDefs::spacalbinning) + { + if (!src.empty()) + { + std::cout << src << " : "; + } + + std::cout << "different binning method used " << methodname(binning) + << ", not : " << methodname(PHG4CylinderCellDefs::etaphibinning) + << " or " << methodname(PHG4CylinderCellDefs::etaslatbinning) + << " or " << methodname(PHG4CylinderCellDefs::spacalbinning) + << std::endl; + exit(1); + } + return; +} + +void PHG4TpcGeomv2::check_binning_method_phi(const std::string& src) const +{ + if (binning != PHG4CylinderCellDefs::etaphibinning && + binning != PHG4CylinderCellDefs::sizebinning && + binning != PHG4CylinderCellDefs::etaslatbinning && + binning != PHG4CylinderCellDefs::spacalbinning) + { + if (!src.empty()) + { + std::cout << src << " : "; + } + + std::cout << "different binning method used " << methodname(binning) + << ", not : " << methodname(PHG4CylinderCellDefs::etaphibinning) + << " or " << methodname(PHG4CylinderCellDefs::sizebinning) + << " or " << methodname(PHG4CylinderCellDefs::etaslatbinning) + << " or " << methodname(PHG4CylinderCellDefs::spacalbinning) + << std::endl; + exit(1); + } + return; +} diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h new file mode 100644 index 0000000000..773c6451b2 --- /dev/null +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2.h @@ -0,0 +1,158 @@ +// Tell emacs that this is a C++ source +// -*- C++ -*-. +#ifndef G4DETECTORS_PHG4TPCGEOMV2_H +#define G4DETECTORS_PHG4TPCGEOMV2_H + +#include "PHG4TpcGeom.h" + +#include +#include +#include // for cout, ostream +#include +#include // for pair + +class PHG4TpcGeomv2 : public PHG4TpcGeom +{ + public: + PHG4TpcGeomv2() = default; + + ~PHG4TpcGeomv2() override = default; + + // from PHObject + void identify(std::ostream& os = std::cout) const override; + + int get_layer() const override { return layer; } + double get_radius() const override { return radius; } + double get_thickness() const override { return thickness; } + int get_binning() const override { return binning; } + int get_zbins() const override; + int get_phibins() const override; + double get_zmin() const override; + double get_phistep() const override; + double get_phimin() const override; + double get_zstep() const override; + int get_etabins() const override; + double get_etastep() const override; + double get_etamin() const override; + + double get_max_driftlength() const override { return max_driftlength; } + double get_CM_halfwidth() const override { return CM_halfwidth; } + double get_adc_clock() const override { return adc_clock; } // default sim value + double get_extended_readout_time() const override { return extended_readout_time; } + double get_drift_velocity_sim() const override { return drift_velocity_sim; } + + double get_rot_x() const override { return rot_x; } + double get_rot_y() const override { return rot_y; } + double get_rot_z() const override { return rot_z; } + double get_place_x() const override { return place_x; } + double get_place_y() const override { return place_y; } + double get_place_z() const override { return place_z; } + + std::pair get_zbounds(const int ibin) const override; + std::pair get_phibounds(const int ibin) const override; + std::pair get_etabounds(const int ibin) const override; + double get_etacenter(const int ibin) const override; + double get_zcenter(const int ibin) const override; + double get_phicenter(const int ibin, const int side = 0) const override; + double get_phicenter_new(const int ibin) const override; + double get_phi(const float ibin, const int side = 0) const override; + + int get_etabin(const double eta) const override; + int get_zbin(const double z) const override; + int get_phibin(const double phi, int side = 0) const override; + int get_phibin_new(const double phi) const override; + + float get_pad_float(const double phi, int side = 0) const override; + float get_tbin_float(const double z) const override; + int find_phibin(const double phi, int side = 0) const override; + + void set_layer(const int i) override { layer = i; } + void set_binning(const int i) override { binning = i; } + void set_radius(const double r) override { radius = r; } + void set_thickness(const double t) override { thickness = t; } + void set_zbins(const int i) override; + void set_zmin(const double z) override; + void set_zstep(const double z) override; + void set_phibins(const int i) override; + void set_phistep(const double phi) override; + void set_phimin(const double phi) override; + void set_etabins(const int i) override; + void set_etamin(const double z) override; + void set_etastep(const double z) override; + // capture the z geometry related setup parameters + void set_max_driftlength(const double val) override { max_driftlength = val; } + void set_CM_halfwidth(const double val) override { CM_halfwidth = val; } + void set_adc_clock(const double val) override { adc_clock = val; } + void set_extended_readout_time(const double val) override { extended_readout_time = val; } + void set_drift_velocity_sim(const double val) override { drift_velocity_sim = val; } + void set_rot_x(const double val) override { rot_x = val; } + void set_rot_y(const double val) override { rot_y = val; } + void set_rot_z(const double val) override { rot_z = val; } + void set_place_x(const double val) override { place_x = val; } + void set_place_y(const double val) override { place_y = val; } + void set_place_z(const double val) override { place_z = val; } + + static const int NSides = 2; + + void set_r_bias(const std::array, NSides> &dr) override { sector_R_bias = dr; } + void set_phi_bias(const std::array, NSides> &dphi) override { sector_Phi_bias = dphi; } + + void set_sector_min_phi(const std::array, NSides> &s_min_phi) override + { + sector_min_Phi = s_min_phi; + } + void set_sector_max_phi(const std::array, NSides> &s_max_phi) override + { + sector_max_Phi = s_max_phi; + } + + const std::array, NSides> &get_sector_min_phi() override + { + return sector_min_Phi; + } + const std::array, NSides> &get_sector_max_phi() override + { + return sector_max_Phi; + } + + protected: + void check_binning_method(const int i) const; + void check_binning_method_eta(const std::string& src = "") const; + void check_binning_method_phi(const std::string& src = "") const; + std::string methodname(const int i) const; + int layer{-999}; + int binning{0}; + double radius{std::numeric_limits::quiet_NaN()}; + int nzbins{-1}; + double zmin{std::numeric_limits::quiet_NaN()}; + double zstep{std::numeric_limits::quiet_NaN()}; + int nphibins{-1}; + double phimin{-M_PI}; + double phistep{std::numeric_limits::quiet_NaN()}; + double thickness{std::numeric_limits::quiet_NaN()}; + + double max_driftlength{std::numeric_limits::quiet_NaN()}; + double CM_halfwidth{std::numeric_limits::quiet_NaN()}; + double adc_clock{std::numeric_limits::quiet_NaN()}; + double extended_readout_time{std::numeric_limits::quiet_NaN()}; + double drift_velocity_sim{std::numeric_limits::quiet_NaN()}; + + double rot_x{std::numeric_limits::quiet_NaN()}; + double rot_y{std::numeric_limits::quiet_NaN()}; + double rot_z{std::numeric_limits::quiet_NaN()}; + double place_x{std::numeric_limits::quiet_NaN()}; + double place_y{std::numeric_limits::quiet_NaN()}; + double place_z{std::numeric_limits::quiet_NaN()}; + + std::array, NSides> sector_R_bias; + std::array, NSides> sector_Phi_bias; + std::array, NSides> sector_min_Phi; + std::array, NSides> sector_max_Phi; + + // streamer + friend std::ostream& operator<<(std::ostream&, const PHG4TpcGeomv2&); + + ClassDefOverride(PHG4TpcGeomv2, 1) +}; + +#endif diff --git a/simulation/g4simulation/g4detectors/PHG4TpcGeomv2LinkDef.h b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2LinkDef.h new file mode 100644 index 0000000000..e25664077d --- /dev/null +++ b/simulation/g4simulation/g4detectors/PHG4TpcGeomv2LinkDef.h @@ -0,0 +1,5 @@ +#ifdef __CINT__ + +#pragma link C++ class PHG4TpcGeomv2 + ; + +#endif /* __CINT__ */ diff --git a/simulation/g4simulation/g4dst/Makefile.am b/simulation/g4simulation/g4dst/Makefile.am index 7ea76582d4..3bb3eb1a17 100644 --- a/simulation/g4simulation/g4dst/Makefile.am +++ b/simulation/g4simulation/g4dst/Makefile.am @@ -11,6 +11,7 @@ lib_LTLIBRARIES = \ libg4dst_la_LDFLAGS = \ -L$(libdir) \ -L$(OFFLINE_MAIN)/lib \ + -lbcolumicount_io \ -lcalo_io \ -lcalotrigger_io \ -lcentrality_io \ diff --git a/simulation/g4simulation/g4eval/BaseTruthEval.cc b/simulation/g4simulation/g4eval/BaseTruthEval.cc index 61aef260f7..f899fafcb7 100644 --- a/simulation/g4simulation/g4eval/BaseTruthEval.cc +++ b/simulation/g4simulation/g4eval/BaseTruthEval.cc @@ -147,6 +147,7 @@ bool BaseTruthEval::is_primary(PHG4Particle* particle) } bool is_primary = false; + //particle->identify(); if (particle->get_parent_id() == 0) { is_primary = true; @@ -274,6 +275,46 @@ PHG4Particle* BaseTruthEval::get_primary_particle(PHG4Particle* particle) return returnval; } +PHG4Particle* BaseTruthEval::get_parent_particle(PHG4Particle* particle) +{ + if (!has_reduced_node_pointers()) + { + ++m_Errors; + return nullptr; + } + + if (m_Strict) + { + assert(particle); + } + else if (!particle) + { + ++m_Errors; + return nullptr; + } + + PHG4Particle* returnval = m_TruthInfo->GetParticle(particle->get_parent_id()); + if(!returnval) + { + // std::cout << " did not get parent particle for particle with parent id " << particle->get_parent_id() << std::endl; + returnval = particle; + } + + //std::cout << " parent for particle " << particle->get_track_id() << " is " << particle->get_parent_id() + // << " with pid " << returnval->get_pid() << std::endl; + + if (m_Strict) + { + assert(returnval); + } + else if (!returnval) + { + ++m_Errors; + } + + return returnval; +} + PHG4Particle* BaseTruthEval::get_primary_particle(PHG4Shower* shower) { if (!has_reduced_node_pointers()) diff --git a/simulation/g4simulation/g4eval/BaseTruthEval.h b/simulation/g4simulation/g4eval/BaseTruthEval.h index 83a9e207a6..05b33ccb1d 100644 --- a/simulation/g4simulation/g4eval/BaseTruthEval.h +++ b/simulation/g4simulation/g4eval/BaseTruthEval.h @@ -57,6 +57,9 @@ class BaseTruthEval /// what was the primary particle that is associated with this shower? PHG4Particle* get_primary_particle(PHG4Shower* shower); + /// what was the parent particle of this particle? + PHG4Particle* get_parent_particle(PHG4Particle* particle); + /// which secondary showers are inside this shower? std::set all_secondary_showers(PHG4Shower* shower); diff --git a/simulation/g4simulation/g4eval/SvtxEvaluator.cc b/simulation/g4simulation/g4eval/SvtxEvaluator.cc index 8996509105..206275afa8 100644 --- a/simulation/g4simulation/g4eval/SvtxEvaluator.cc +++ b/simulation/g4simulation/g4eval/SvtxEvaluator.cc @@ -19,6 +19,8 @@ #include #include +#include + #include #include #include @@ -99,7 +101,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) if (_do_vertex_eval) { _ntp_vertex = new TNtuple("ntp_vertex", "vertex => max truth", - "event:seed:vertexID:vx:vy:vz:ntracks:chi2:ndof:" + "event:seed:vertexID:vx:vy:vz:ntracks:chi2:ndof:crossing:" "gvx:gvy:gvz:gvt:gembed:gntracks:gntracksmaps:" "gnembed:nfromtruth:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); @@ -109,7 +111,7 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) { _ntp_gpoint = new TNtuple("ntp_gpoint", "g4point => best vertex", "event:seed:gvx:gvy:gvz:gvt:gntracks:gembed:" - "vx:vy:vz:ntracks:" + "vx:vy:vz:ntracks:crossing:" "nfromtruth:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } @@ -146,8 +148,11 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) { _ntp_cluster = new TNtuple("ntp_cluster", "svtxcluster => max truth", "event:seed:hitID:x:y:z:r:phi:eta:theta:ex:ey:ez:ephi:pez:pephi:" - "e:adc:maxadc:layer:phielem:zelem:size:phisize:zsize:" - "pedge:redge:ovlp:" + "e:adc:maxadc:cenadc:padcen:tbincen:padmax:tbinmax:layer:phielem:zelem:" + "size:phisize:zsize:" + "pedge:redge:sledge:sredge:tledge:tredge:dledge:dredge:hledge:hredge:" + "slmix:srmix:tlmix:trmix:ovlp:" + "phibinlo:phibinhi:tbinlo:tbinhi:padphase:tbinphase:" "trackID:niter:g4hitID:gx:" "gy:gz:gr:gphi:geta:gt:gtrackID:gflavor:" "gpx:gpy:gpz:gvx:gvy:gvz:gvt:" @@ -172,12 +177,13 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gpx:gpy:gpz:gpt:geta:gphi:" "gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gprimary:" + "gembed:gprimary:gcrossing:gparentflavor:gparentid:gprimaryflavor:gprimaryid:" "trackID:px:py:pz:pt:eta:phi:deltapt:deltaeta:deltaphi:" - "siqr:siphi:sithe:six0:siy0:tpqr:tpphi:tpthe:tpx0:tpy0:" + "crossing:siqr:siphi:sithe:six0:siy0:tpqr:tpphi:tpthe:tpx0:tpy0:" "charge:quality:chisq:ndf:nhits:layers:nmaps:nintt:ntpc:nmms:ntpc1:ntpc11:ntpc2:ntpc3:nlmaps:nlintt:nltpc:nlmms:" "vertexID:vx:vy:vz:dca2d:dca2dsigma:dca3dxy:dca3dxysigma:dca3dz:dca3dzsigma:pcax:pcay:pcaz:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:ntrutpc:nwrongtpc:ntrumms:nwrongmms:ntrutpc1:nwrongtpc1:ntrutpc11:nwrongtpc11:ntrutpc2:nwrongtpc2:ntrutpc3:nwrongtpc3:layersfromtruth:" - "npedge:nredge:nbig:novlp:merr:msize:" + "nedge:npedge:nredge:nsledge:nsredge:ntledge:ntredge:ndledge:ndredge:nhledge:nhredge:" + "nslmix:nsrmix:ntlmix:ntrmix:nbig:novlp:merr:msize:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } @@ -192,9 +198,10 @@ int SvtxEvaluator::Init(PHCompositeNode* /*topNode*/) "gpx:gpy:gpz:gpt:geta:gphi:" "gvx:gvy:gvz:gvt:" "gfpx:gfpy:gfpz:gfx:gfy:gfz:" - "gembed:gprimary:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:" + "gembed:gprimary:gcrossing:gparentflavor:gparentid:gprimaryflavor:gprimaryid:nfromtruth:nwrong:ntrumaps:nwrongmaps:ntruintt:nwrongintt:" "ntrutpc:nwrongtpc:ntrumms:nwrongmms:ntrutpc1:nwrongtpc1:ntrutpc11:nwrongtpc11:ntrutpc2:nwrongtpc2:ntrutpc3:nwrongtpc3:layersfromtruth:" - "npedge:nredge:nbig:novlp:merr:msize:" + "nedge:npedge:nredge:nsledge:nsredge:ntledge:ntredge:ndledge:ndredge:nhledge:nhredge:" + "nslmix:nsrmix:ntlmix:ntrmix:nbig:novlp:merr:msize:" "nhittpcall:nhittpcin:nhittpcmid:nhittpcout:nclusall:nclustpc:nclusintt:nclusmaps:nclusmms"); } @@ -408,7 +415,7 @@ void SvtxEvaluator::printInputInfo(PHCompositeNode* topNode) } } - std::cout << "---SVXTRACKS-------------" << std::endl; + std::cout << "---SVTXTRACKS-------------" << std::endl; SvtxTrackMap* trackmap = findNode::getClass(topNode, _trackmapname); if (trackmap) { @@ -426,7 +433,7 @@ void SvtxEvaluator::printInputInfo(PHCompositeNode* topNode) } } - std::cout << "---SVXVERTEXES-------------" << std::endl; + std::cout << "---SVTXVERTEXES-------------" << std::endl; SvtxVertexMap* vertexmap = nullptr; if (_use_initial_vertex) { @@ -1190,6 +1197,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float vx = vertex->get_x(); float vy = vertex->get_y(); float vz = vertex->get_z(); + float crossing = vertex->get_beam_crossing(); float ntracks = vertex->size_tracks(); float chi2 = vertex->get_chisq(); float ndof = vertex->get_ndof(); @@ -1228,6 +1236,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ntracks, chi2, ndof, + crossing, gvx, gvy, gvz, @@ -1373,12 +1382,13 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float vz = std::numeric_limits::quiet_NaN(); float ntracks = std::numeric_limits::quiet_NaN(); float nfromtruth = std::numeric_limits::quiet_NaN(); - + float crossing = std::numeric_limits::quiet_NaN(); if (vertex) { vx = vertex->get_x(); vy = vertex->get_y(); vz = vertex->get_z(); + crossing = vertex->get_beam_crossing(); ntracks = vertex->size_tracks(); nfromtruth = vertexeval->get_ntracks_contribution(vertex, point); } @@ -1394,6 +1404,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) vy, vz, ntracks, + crossing, nfromtruth, nhit_tpc_all, nhit_tpc_in, @@ -1942,10 +1953,28 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float size = 0; float phisize = 0; float zsize = 0; - float maxadc = -999; + float maxadc = -999.; + float padcen = -999.; + float tbincen = -999.; + float padmax = -999.; + float tbinmax = -999.; float redge = std::numeric_limits::quiet_NaN(); float pedge = std::numeric_limits::quiet_NaN(); + float sledge = std::numeric_limits::quiet_NaN(); + float sredge = std::numeric_limits::quiet_NaN(); + float tledge = std::numeric_limits::quiet_NaN(); + float tredge = std::numeric_limits::quiet_NaN(); + float dledge = std::numeric_limits::quiet_NaN(); + float dredge = std::numeric_limits::quiet_NaN(); + float hledge = std::numeric_limits::quiet_NaN(); + float hredge = std::numeric_limits::quiet_NaN(); + float slmix = std::numeric_limits::quiet_NaN(); + float srmix = std::numeric_limits::quiet_NaN(); + float tlmix = std::numeric_limits::quiet_NaN(); + float trmix = std::numeric_limits::quiet_NaN(); float ovlp = std::numeric_limits::quiet_NaN(); + float padphase = -999.; + float tbinphase = -999.; auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, r, cluster_key); phisize = cluster->getPhiSize(); @@ -1954,8 +1983,26 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ez = sqrt(para_errors.second); ephi = sqrt(para_errors.first); maxadc = cluster->getMaxAdc(); + padcen = cluster->getPadCen(); + tbincen = cluster->getTBinCen(); + padmax = cluster->getPadMax(); + tbinmax = cluster->getTBinMax(); pedge = cluster->getEdge(); + sledge = cluster->getSLEdge(); + sredge = cluster->getSREdge(); + tledge = cluster->getTLEdge(); + tredge = cluster->getTREdge(); + dledge = cluster->getDLEdge(); + dredge = cluster->getDREdge(); + hledge = cluster->getHLEdge(); + hredge = cluster->getHREdge(); + slmix = cluster->getSLMix(); + srmix = cluster->getSRMix(); + tlmix = cluster->getTLMix(); + trmix = cluster->getTRMix(); ovlp = cluster->getOverlap(); + padphase = cluster->getPadPhase(); + tbinphase = cluster->getTBinPhase(); if (hitsetlayer == 7 || hitsetlayer == 22 || hitsetlayer == 23 || hitsetlayer == 38 || hitsetlayer == 39) { @@ -1964,6 +2011,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float e = cluster->getAdc(); float adc = cluster->getAdc(); + float cenadc = cluster->getCenAdc(); + float phibinlo = cluster->getPhiBinLo(); + float phibinhi = cluster->getPhiBinHi(); + float tbinlo = cluster->getTBinLo(); + float tbinhi = cluster->getTBinHi(); float local_layer = (float) TrkrDefs::getLayer(cluster_key); float sector = TpcDefs::getSectorId(cluster_key); float side = TpcDefs::getSide(cluster_key); @@ -2127,6 +2179,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) e, adc, maxadc, + cenadc, + padcen, + tbincen, + padmax, + tbinmax, local_layer, sector, side, @@ -2135,7 +2192,25 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) zsize, pedge, redge, + sledge, + sredge, + tledge, + tredge, + dledge, + dredge, + hledge, + hredge, + slmix, + srmix, + tlmix, + trmix, ovlp, + phibinlo, + phibinhi, + tbinlo, + tbinhi, + padphase, + tbinphase, trackID, niter, g4hitID, @@ -2275,10 +2350,28 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float size = 0; float phisize = 0; float zsize = 0; - float maxadc = -999; + float maxadc = -999.; + float padcen = -999.; + float tbincen = -999.; + float padmax = -999.; + float tbinmax= -999.; float redge = std::numeric_limits::quiet_NaN(); float pedge = std::numeric_limits::quiet_NaN(); + float sledge = std::numeric_limits::quiet_NaN(); + float sredge = std::numeric_limits::quiet_NaN(); + float tledge = std::numeric_limits::quiet_NaN(); + float tredge = std::numeric_limits::quiet_NaN(); + float dledge = std::numeric_limits::quiet_NaN(); + float dredge = std::numeric_limits::quiet_NaN(); + float hledge = std::numeric_limits::quiet_NaN(); + float hredge = std::numeric_limits::quiet_NaN(); + float slmix = std::numeric_limits::quiet_NaN(); + float srmix = std::numeric_limits::quiet_NaN(); + float tlmix = std::numeric_limits::quiet_NaN(); + float trmix = std::numeric_limits::quiet_NaN(); float ovlp = std::numeric_limits::quiet_NaN(); + float padphase = -999.; + float tbinphase = -999.; auto para_errors = ClusterErrorPara::get_clusterv5_modified_error(cluster, r, cluster_key); phisize = cluster->getPhiSize(); @@ -2287,11 +2380,34 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ez = sqrt(para_errors.second); ephi = sqrt(para_errors.first); maxadc = cluster->getMaxAdc(); + padcen = cluster->getPadCen(); + tbincen = cluster->getTBinCen(); + padmax = cluster->getPadMax(); + tbinmax = cluster->getTBinMax(); pedge = cluster->getEdge(); + sledge = cluster->getSLEdge(); + sredge = cluster->getSREdge(); + tledge = cluster->getTLEdge(); + tredge = cluster->getTREdge(); + dledge = cluster->getDLEdge(); + dredge = cluster->getDREdge(); + hledge = cluster->getHLEdge(); + hredge = cluster->getHREdge(); + slmix = cluster->getSLMix(); + srmix = cluster->getSRMix(); + tlmix = cluster->getTLMix(); + trmix = cluster->getTRMix(); ovlp = cluster->getOverlap(); + padphase = cluster->getPadPhase(); + tbinphase = cluster->getTBinPhase(); float e = cluster->getAdc(); float adc = cluster->getAdc(); + float cenadc = cluster->getCenAdc(); + float phibinlo = cluster->getPhiBinLo(); + float phibinhi = cluster->getPhiBinHi(); + float tbinlo = cluster->getTBinLo(); + float tbinhi = cluster->getTBinHi(); float local_layer = (float) TrkrDefs::getLayer(cluster_key); float sector = TpcDefs::getSectorId(cluster_key); float side = TpcDefs::getSide(cluster_key); @@ -2424,6 +2540,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) e, adc, maxadc, + cenadc, + padcen, + tbincen, + padmax, + tbinmax, local_layer, sector, side, @@ -2432,7 +2553,25 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) zsize, pedge, redge, + sledge, + sredge, + tledge, + tredge, + dledge, + dredge, + hledge, + hredge, + slmix, + srmix, + tlmix, + trmix, ovlp, + phibinlo, + phibinhi, + tbinlo, + tbinhi, + padphase, + tbinphase, trackID, niter, g4hitID, @@ -2712,7 +2851,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gtrackID = g4particle->get_track_id(); float gflavor = g4particle->get_pid(); - auto g4clustermap = trutheval->all_truth_clusters(g4particle); + auto g4clustermap = trutheval->all_truth_clusters(g4particle); std::set g4clusters; for(const auto& [key, cluster]: g4clustermap) { @@ -2854,7 +2993,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gvy = vtx->get_y(); float gvz = vtx->get_z(); float gvt = vtx->get_t(); - + int gcrossing = std::floor(gvt / sphenix_constants::time_between_crossings); float gfpx = 0.; float gfpy = 0.; float gfpz = 0.; @@ -2880,12 +3019,20 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gembed = trutheval->get_embed(g4particle); float gprimary = trutheval->is_primary(g4particle); - + float gparentflavor = trutheval->get_parent_particle_flavor(g4particle); + PHG4Particle* parent = trutheval->get_parent_particle(g4particle); + float gparentid = parent->get_track_id(); + float gprimaryflavor = trutheval->get_primary_particle_flavor(g4particle); + PHG4Particle* g4primary = trutheval->get_primary_particle(g4particle); + float gprimaryid = g4primary->get_track_id(); + + // matched track quantities float trackID = std::numeric_limits::quiet_NaN(); float charge = std::numeric_limits::quiet_NaN(); float quality = std::numeric_limits::quiet_NaN(); float chisq = std::numeric_limits::quiet_NaN(); float ndf = std::numeric_limits::quiet_NaN(); + float crossing = std::numeric_limits::quiet_NaN(); float local_nhits = 0; float nmaps = 0; float nintt = 0; @@ -2942,8 +3089,21 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float ntrutpc3 = std::numeric_limits::quiet_NaN(); float nwrongtpc3 = std::numeric_limits::quiet_NaN(); float layersfromtruth = std::numeric_limits::quiet_NaN(); + float nedge = 0; float npedge = 0; float nredge = 0; + float nsledge = 0; + float nsredge = 0; + float ntledge = 0; + float ntredge = 0; + float ndledge = 0; + float ndredge = 0; + float nhledge = 0; + float nhredge = 0; + float nslmix = 0; + float nsrmix = 0; + float ntlmix = 0; + float ntrmix = 0; float nbig = 0; float novlp = 0; float merr = 0; @@ -2970,6 +3130,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) quality = track->get_quality(); chisq = track->get_chisq(); ndf = track->get_ndf(); + short int crossing_int = track->get_crossing(); + if (crossing_int != SHRT_MAX) + { + crossing = (float) crossing_int; + } TrackSeed* silseed = track->get_silicon_seed(); TrackSeed* tpcseed = track->get_tpc_seed(); if (tpcseed) @@ -3070,10 +3235,23 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gphierr = sqrt(para_errors.first); govlp = cluster->getOverlap(); gedge = cluster->getEdge(); + nsledge = cluster->getSLEdge(); + nsredge = cluster->getSREdge(); + ntledge = cluster->getTLEdge(); + ntredge = cluster->getTREdge(); + ndledge = cluster->getDLEdge(); + ndredge = cluster->getDREdge(); + nhledge = cluster->getHLEdge(); + nhredge = cluster->getHREdge(); + nslmix = cluster->getSLMix(); + nsrmix = cluster->getSRMix(); + ntlmix = cluster->getTLMix(); + ntrmix = cluster->getTRMix(); if (gedge > 0) { npedge++; + nedge = gedge; } if (gphisize >= 4) { @@ -3323,6 +3501,11 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfz, gembed, gprimary, + (float) gcrossing, + gparentflavor, + gparentid, + gprimaryflavor, + gprimaryid, trackID, px, py, @@ -3333,6 +3516,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) deltapt, deltaeta, deltaphi, + crossing, siqr, siphi, sithe, @@ -3393,8 +3577,21 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ntrutpc3, nwrongtpc3, layersfromtruth, + nedge, npedge, nredge, + nsledge, + nsredge, + ntledge, + ntredge, + ndledge, + ndredge, + nhledge, + nhredge, + nslmix, + nsrmix, + ntlmix, + ntrmix, nbig, novlp, merr, @@ -3495,8 +3692,21 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float nlintt = 0; float nltpc = 0; float nlmms = 0; + float nedge = 0; float npedge = 0; float nredge = 0; + float nsledge = 0; + float nsredge = 0; + float ntledge = 0; + float ntredge = 0; + float ndledge = 0; + float ndredge = 0; + float nhledge = 0; + float nhredge = 0; + float nslmix = 0; + float nsrmix = 0; + float ntlmix = 0; + float ntrmix = 0; float nbig = 0; float novlp = 0; float merr = 0; @@ -3590,10 +3800,23 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) rphierr = sqrt(para_errors.first); rovlp = cluster->getOverlap(); pedge = cluster->getEdge(); + nsledge = cluster->getSLEdge(); + nsredge = cluster->getSREdge(); + ntledge = cluster->getTLEdge(); + ntredge = cluster->getTREdge(); + ndledge = cluster->getDLEdge(); + ndredge = cluster->getDREdge(); + nhledge = cluster->getHLEdge(); + nhredge = cluster->getHREdge(); + nslmix = cluster->getSLMix(); + nsrmix = cluster->getSRMix(); + ntlmix = cluster->getTLMix(); + ntrmix = cluster->getTRMix(); if (pedge > 0) { npedge++; + nedge = pedge; } if (rphisize >= 4) { @@ -3758,7 +3981,12 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gtrackID = std::numeric_limits::quiet_NaN(); float gflavor = std::numeric_limits::quiet_NaN(); - float ng4hits = std::numeric_limits::quiet_NaN(); + float gparentflavor = std::numeric_limits::quiet_NaN(); + float gparentid = std::numeric_limits::quiet_NaN(); + float gprimaryflavor = std::numeric_limits::quiet_NaN(); + float gprimaryid = std::numeric_limits::quiet_NaN(); + + float ng4hits = std::numeric_limits::quiet_NaN(); unsigned int ngmaps = 0; unsigned int ngintt = 0; unsigned int ngmms = 0; @@ -3785,7 +4013,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) float gfz = std::numeric_limits::quiet_NaN(); float gembed = std::numeric_limits::quiet_NaN(); float gprimary = std::numeric_limits::quiet_NaN(); - + int gcrossing = std::numeric_limits::max(); int ispure = 0; float nfromtruth = std::numeric_limits::quiet_NaN(); float nwrong = std::numeric_limits::quiet_NaN(); @@ -3830,6 +4058,14 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gtrackID = g4particle->get_track_id(); gflavor = g4particle->get_pid(); + gparentflavor = (float) trutheval->get_parent_particle_flavor(g4particle); + PHG4Particle* parent = trutheval->get_parent_particle(g4particle); + gparentid = (float) parent->get_track_id(); + gprimaryflavor = (float) trutheval->get_primary_particle_flavor(g4particle); + PHG4Particle* g4primary = trutheval->get_primary_particle(g4particle); + gprimaryid = (float) g4primary->get_track_id(); + // std::cout << " gtrackID " << gtrackID << " gflavor " < g4clusters = clustereval->all_clusters_from(g4particle); ng4hits = g4clusters.size(); gpx = g4particle->get_px(); @@ -3907,6 +4143,7 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gvz = vtx->get_z(); gvt = vtx->get_t(); + gcrossing = std::floor(gvt / sphenix_constants::time_between_crossings); PHG4Hit* outerhit = nullptr; if (_do_eval_light == false) { @@ -4053,8 +4290,13 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) gfx, gfy, gfz, - gembed, + gembed, gprimary, + (float) gcrossing, + gparentflavor, + gparentid, + gprimaryflavor, + gprimaryid, nfromtruth, nwrong, ntrumaps, @@ -4074,8 +4316,21 @@ void SvtxEvaluator::fillOutputNtuples(PHCompositeNode* topNode) ntrutpc3, nwrongtpc3, layersfromtruth, + nedge, npedge, nredge, + nsledge, + nsredge, + ntledge, + ntredge, + ndledge, + ndredge, + nhledge, + nhredge, + nslmix, + nsrmix, + ntlmix, + ntrmix, nbig, novlp, merr, diff --git a/simulation/g4simulation/g4eval/SvtxTruthEval.cc b/simulation/g4simulation/g4eval/SvtxTruthEval.cc index 9500e7134a..25d4cbb125 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthEval.cc +++ b/simulation/g4simulation/g4eval/SvtxTruthEval.cc @@ -324,6 +324,9 @@ std::map> SvtxTruthEval::all_tru std::vector contributing_hits_energy; std::vector> contributing_hits_entry; std::vector> contributing_hits_exit; + // contributing_hits are the original g4hits in world coords + // contributing_hits_entry, contributing_hits_exit are in envelope coords, for use in G4ClusterSize() + // gx, gy, gz are the cluster position in this layer in world coords to compare with data LayerClusterG4Hits(g4hits, contributing_hits, contributing_hits_energy, contributing_hits_entry, contributing_hits_exit, layer, gx, gy, gz, gt, gedep); if (!(gedep > 0)) { @@ -457,8 +460,16 @@ void SvtxTruthEval::LayerClusterG4Hits(const std::set& truth_hits, std // we do not assume that the truth hits know what layer they are in for (auto *this_g4hit : truth_hits) { - float rbegin = std::sqrt(this_g4hit->get_x(0) * this_g4hit->get_x(0) + this_g4hit->get_y(0) * this_g4hit->get_y(0)); - float rend = std::sqrt(this_g4hit->get_x(1) * this_g4hit->get_x(1) + this_g4hit->get_y(1) * this_g4hit->get_y(1)); + // The truth hits are in world coordinates + // They have to be transformed to envelope coords to find what layer they are in + // Then the cluster positions have to be transformed back to world coordinates + Acts::Vector3 world0(this_g4hit->get_x(0), this_g4hit->get_y(0), this_g4hit->get_z(0)); + Acts::Vector3 env0 = _tgeometry->transformTpcWorldToEnvelope(world0); + Acts::Vector3 world1(this_g4hit->get_x(1), this_g4hit->get_y(1), this_g4hit->get_z(1)); + Acts::Vector3 env1 = _tgeometry->transformTpcWorldToEnvelope(world1); + + float rbegin = std::sqrt(env0.x() * env0.x() + env0.y() * env0.y()); + float rend = std::sqrt(env1.x() * env1.x() + env1.y() * env1.y()); // std::cout << " Eval: g4hit " << this_g4hit->get_hit_id() << " layer " << layer << " rbegin " << rbegin << " rend " << rend << std::endl; // make sure the entry point is at lower radius @@ -468,21 +479,21 @@ void SvtxTruthEval::LayerClusterG4Hits(const std::set& truth_hits, std if (rbegin < rend) { - xl[0] = this_g4hit->get_x(0); - yl[0] = this_g4hit->get_y(0); - zl[0] = this_g4hit->get_z(0); - xl[1] = this_g4hit->get_x(1); - yl[1] = this_g4hit->get_y(1); - zl[1] = this_g4hit->get_z(1); + xl[0] = env0.x(); + yl[0] = env0.y(); + zl[0] = env0.z(); + xl[1] = env1.x(); + yl[1] = env1.y(); + zl[1] = env1.z(); } else { - xl[0] = this_g4hit->get_x(1); - yl[0] = this_g4hit->get_y(1); - zl[0] = this_g4hit->get_z(1); - xl[1] = this_g4hit->get_x(0); - yl[1] = this_g4hit->get_y(0); - zl[1] = this_g4hit->get_z(0); + xl[0] = env1.x(); + yl[0] = env1.y(); + zl[0] = env1.z(); + xl[1] = env0.x(); + yl[1] = env0.y(); + zl[1] = env0.z(); std::swap(rbegin, rend); // std::cout << "swapped in and out " << std::endl; } @@ -659,6 +670,14 @@ void SvtxTruthEval::LayerClusterG4Hits(const std::set& truth_hits, std } } + // convert cluster position back to world coordinates + Acts::Vector3 clus_env(gx,gy,gz); + Acts::Vector3 clus_world = _tgeometry->transformTpcEnvelopeToWorld(clus_env); + gx = clus_world.x(); + gy = clus_world.y(); + gz = clus_world.z(); + // what is gr used for? + } // if TPC else { @@ -1082,6 +1101,28 @@ bool SvtxTruthEval::is_primary(PHG4Particle* particle) return _basetrutheval.is_primary(particle); } +PHG4Particle* SvtxTruthEval::get_parent_particle(PHG4Particle* particle) +{ + PHG4Particle* parent = _basetrutheval.get_parent_particle(particle); + return parent; +} + +int SvtxTruthEval::get_parent_particle_flavor(PHG4Particle* particle) +{ + PHG4Particle* parent = _basetrutheval.get_parent_particle(particle); + int parent_pid = parent->get_pid(); + + return parent_pid; +} + +int SvtxTruthEval::get_primary_particle_flavor(PHG4Particle* particle) +{ + PHG4Particle* primary = _basetrutheval.get_primary_particle(particle); + int primary_pid = primary->get_pid(); + + return primary_pid; +} + PHG4Particle* SvtxTruthEval::get_primary_particle(PHG4Hit* g4hit) { if (!has_node_pointers()) diff --git a/simulation/g4simulation/g4eval/SvtxTruthEval.h b/simulation/g4simulation/g4eval/SvtxTruthEval.h index 24a86a5ace..12b0b04ab0 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthEval.h +++ b/simulation/g4simulation/g4eval/SvtxTruthEval.h @@ -46,6 +46,9 @@ class SvtxTruthEval std::set all_truth_hits(PHG4Particle* particle); PHG4Particle* get_particle(PHG4Hit* g4hit); int get_embed(PHG4Particle* particle); + PHG4Particle* get_parent_particle(PHG4Particle* particle); + int get_parent_particle_flavor(PHG4Particle* particle); + int get_primary_particle_flavor(PHG4Particle* particle); PHG4VtxPoint* get_vertex(PHG4Particle* particle); bool is_primary(PHG4Particle* particle); PHG4Particle* get_primary_particle(PHG4Hit* g4hit); diff --git a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc index 6d3c7cd7a7..1e118363b7 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc +++ b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.cc @@ -2,7 +2,8 @@ #include "SvtxTruthRecoTableEval.h" #include "SvtxEvalStack.h" #include "SvtxTrackEval.h" -#include "SvtxTruthEval.h" + +#include "SvtxClusterEval.h" #include #include @@ -19,10 +20,18 @@ #include #include #include +#include #include -#include - +#include +#include +#include +#include +#include +#include +#include +#include +#include //____________________________________________________________________________.. SvtxTruthRecoTableEval::SvtxTruthRecoTableEval(const std::string &name) @@ -53,11 +62,13 @@ int SvtxTruthRecoTableEval::InitRun(PHCompositeNode *topNode) //____________________________________________________________________________.. int SvtxTruthRecoTableEval::process_event(PHCompositeNode *topNode) { + const int verbosity = Verbosity(); + if (!m_svtxevalstack) { m_svtxevalstack = std::make_unique(topNode); m_svtxevalstack->set_strict(false); - m_svtxevalstack->set_verbosity(Verbosity()); + m_svtxevalstack->set_verbosity(verbosity); m_svtxevalstack->set_use_initial_vertex(true); m_svtxevalstack->set_use_genfit_vertex(false); m_svtxevalstack->next_event(topNode); @@ -67,17 +78,15 @@ int SvtxTruthRecoTableEval::process_event(PHCompositeNode *topNode) m_svtxevalstack->next_event(topNode); } - if (Verbosity() > 1) - { - std::cout << "Fill truth map " << std::endl; - } - fillTruthMap(topNode); + SvtxTrackEval *trackeval = m_svtxevalstack->get_track_eval(); + assert(trackeval); + trackeval->set_verbosity(verbosity); - if (Verbosity() > 1) + if (verbosity > 1) { - std::cout << "Fill reco map " << std::endl; + std::cout << "Fill truth/reco maps " << std::endl; } - fillRecoMap(topNode); + fillTruthRecoMaps(topNode, trackeval, verbosity); return Fun4AllReturnCodes::EVENT_OK; } @@ -102,14 +111,13 @@ int SvtxTruthRecoTableEval::End(PHCompositeNode * /*unused*/) return Fun4AllReturnCodes::EVENT_OK; } -void SvtxTruthRecoTableEval::fillTruthMap(PHCompositeNode *topNode) +void SvtxTruthRecoTableEval::fillTruthRecoMaps(PHCompositeNode *topNode, SvtxTrackEval *trackeval, const int verbosity) { PHG4TruthInfoContainer *truthinfo = findNode::getClass(topNode, "G4TruthInfo"); assert(truthinfo); - SvtxTrackEval *trackeval = m_svtxevalstack->get_track_eval(); - trackeval->set_verbosity(Verbosity()); - assert(trackeval); + SvtxTrackMap *trackMap = findNode::getClass(topNode, "SvtxTrackMap"); + assert(trackMap); PHG4TruthInfoContainer::ConstRange range = truthinfo->GetParticleRange(); if (m_scanForPrimaries) @@ -117,96 +125,124 @@ void SvtxTruthRecoTableEval::fillTruthMap(PHCompositeNode *topNode) range = truthinfo->GetPrimaryParticleRange(); } + std::vector selectedTruthIds; + std::unordered_set selectedTruthIdSet; + const double minMomentumTruthMap2 = m_minMomentumTruthMap * m_minMomentumTruthMap; + for (auto iter = range.first; iter != range.second; ++iter) { PHG4Particle *g4particle = iter->second; - const double momentum = CLHEP:: - Hep3Vector(g4particle->get_px(), g4particle->get_py(), g4particle->get_pz()) - .mag(); + const double px = g4particle->get_px(); + const double py = g4particle->get_py(); + const double pz = g4particle->get_pz(); + const double momentum2 = px * px + py * py + pz * pz; - // only record particle above minimal momentum requirement. - if (momentum < m_minMomentumTruthMap) + // only record particle above minimal momentum (square) requirement. + // doing this saves us a slow sqrt operation to calculate the momentum itself + if (momentum2 < minMomentumTruthMap2) { continue; } - int gtrackID = g4particle->get_track_id(); - const std::set &alltracks = trackeval->all_tracks_from(g4particle); + const int gtrackID = g4particle->get_track_id(); + selectedTruthIds.push_back(gtrackID); + selectedTruthIdSet.insert(gtrackID); + } + + SvtxClusterEval *clustereval = trackeval->get_cluster_eval(); + std::map truthMaps; - // not to record zero associations - if (alltracks.empty()) + for (const auto &[key, track] : *trackMap) + { + TrackSeed *siliconSeed = track->get_silicon_seed(); + TrackSeed *tpcSeed = track->get_tpc_seed(); + + std::size_t nclusterKeys = 0; + if (siliconSeed) { - continue; + nclusterKeys += siliconSeed->size_cluster_keys(); + } + if (tpcSeed) + { + nclusterKeys += tpcSeed->size_cluster_keys(); } - PHG4ParticleSvtxMap::WeightedRecoTrackMap recomap; + std::unordered_map nclustersByTruthId; + nclustersByTruthId.reserve(nclusterKeys); - for (auto *track : alltracks) + const auto add_cluster_contributions = [&](TrackSeed *seed) { - /// We fill the map with a key corresponding to the ncluster contribution. - /// This weight could in principle be anything we choose - float clusCont = trackeval->get_nclusters_contribution(track, g4particle); + if (!seed) + { + return; + } + + for (auto clusterIter = seed->begin_cluster_keys(); + clusterIter != seed->end_cluster_keys(); + ++clusterIter) + { + const std::set particles = clustereval->all_truth_particles(*clusterIter); + for (PHG4Particle *g4particle : particles) + { + ++nclustersByTruthId[g4particle->get_track_id()]; + } + } + }; + + // Match SvtxTrackEval::get_track_ckeys ordering. + add_cluster_contributions(siliconSeed); + add_cluster_contributions(tpcSeed); + + SvtxPHG4ParticleMap::WeightedTruthTrackMap truthmap; + SvtxTrack_FastSim *fastsim_track = dynamic_cast(track); - auto iterator = recomap.find(clusCont); - if (iterator == recomap.end()) + const unsigned int trackID = track->get_id(); + for (const auto &[gtrackID, nclusters] : nclustersByTruthId) + { + const float clusCont = static_cast(nclusters); + if (selectedTruthIdSet.contains(gtrackID)) { - std::set dumset; - dumset.insert(track->get_id()); - recomap.insert(std::make_pair(clusCont, dumset)); + truthMaps[gtrackID][clusCont].insert(trackID); } - else + if (!fastsim_track) { - iterator->second.insert(track->get_id()); + truthmap[clusCont].insert(gtrackID); } } - if (Verbosity() > 1) + if (fastsim_track) { - std::cout << " Inserting gtrack id " << gtrackID << " with map size " << recomap.size() << std::endl; + // Preserve SvtxTrackEval::all_truth_particles fast-sim special case for reco->truth maps only. + PHG4Particle *g4particle = truthinfo->GetParticle(fastsim_track->get_truth_track_id()); + const float clusCont = trackeval->get_nclusters_contribution(track, g4particle); + truthmap[clusCont].insert(g4particle->get_track_id()); } - m_truthMap->insert(gtrackID, recomap); + if (verbosity > 1) + { + std::cout << " Inserting track id " << key << " with truth map size " << truthmap.size() << std::endl; + } + m_recoMap->insert(key, std::move(truthmap)); } - m_truthMap->setProcessed(true); -} - -void SvtxTruthRecoTableEval::fillRecoMap(PHCompositeNode *topNode) -{ - SvtxTrackMap *trackMap = findNode::getClass(topNode, "SvtxTrackMap"); - - assert(trackMap); - - SvtxTrackEval *trackeval = m_svtxevalstack->get_track_eval(); - assert(trackeval); - - for (const auto &[key, track] : *trackMap) + for (const int gtrackID : selectedTruthIds) { - const std::set &allparticles = trackeval->all_truth_particles(track); - SvtxPHG4ParticleMap::WeightedTruthTrackMap truthmap; - for (PHG4Particle *g4particle : allparticles) + auto truthMapIter = truthMaps.find(gtrackID); + if (truthMapIter == truthMaps.end() || truthMapIter->second.empty()) { - float clusCont = trackeval->get_nclusters_contribution(track, g4particle); - auto iterator = truthmap.find(clusCont); - if (iterator == truthmap.end()) - { - std::set dumset; - dumset.insert(g4particle->get_track_id()); - truthmap.insert(std::make_pair(clusCont, dumset)); - } - else - { - iterator->second.insert(g4particle->get_track_id()); - } + continue; } - if (Verbosity() > 1) + + if (verbosity > 1) { - std::cout << " Inserting track id " << key << " with truth map size " << truthmap.size() << std::endl; + std::cout << " Inserting gtrack id " << gtrackID << " with map size " << truthMapIter->second.size() << std::endl; } - m_recoMap->insert(key, truthmap); + + m_truthMap->insert(gtrackID, std::move(truthMapIter->second)); } + m_truthMap->setProcessed(true); m_recoMap->setProcessed(true); } diff --git a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.h b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.h index e09b16a9c3..8886385531 100644 --- a/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.h +++ b/simulation/g4simulation/g4eval/SvtxTruthRecoTableEval.h @@ -12,6 +12,7 @@ class PHCompositeNode; class PHG4TruthInfoContainer; class SvtxEvalStack; +class SvtxTrackEval; class SvtxTruthRecoTableEval : public SubsysReco { @@ -34,8 +35,7 @@ class SvtxTruthRecoTableEval : public SubsysReco private: int createNodes(PHCompositeNode *topNode); - void fillTruthMap(PHCompositeNode *topNode); - void fillRecoMap(PHCompositeNode *topNode); + void fillTruthRecoMaps(PHCompositeNode *topNode, SvtxTrackEval *trackeval, int verbosity); bool m_scanForPrimaries = false; diff --git a/simulation/g4simulation/g4eval/compressor_generator.h b/simulation/g4simulation/g4eval/compressor_generator.h index cf1b293479..072dccb60b 100644 --- a/simulation/g4simulation/g4eval/compressor_generator.h +++ b/simulation/g4simulation/g4eval/compressor_generator.h @@ -11,7 +11,7 @@ #include #include -#include "RtypesCore.h" +#include //----------------------------------------------------------------------------- UShort_t residesIn(Float_t raw, std::vector* dict) diff --git a/simulation/g4simulation/g4eval/g4evalfn.cc b/simulation/g4simulation/g4eval/g4evalfn.cc index 47971d974b..5da402f6c7 100644 --- a/simulation/g4simulation/g4eval/g4evalfn.cc +++ b/simulation/g4simulation/g4eval/g4evalfn.cc @@ -1,12 +1,14 @@ +#include "g4evalfn.h" + +#include "TrkrClusLoc.h" +#include "TrkrClusterIsMatcher.h" + #include #include #include #include #include -#include "TrkrClusLoc.h" -#include "TrkrClusterIsMatcher.h" -#include "g4evalfn.h" #include #include diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLAuxStructType.hh b/simulation/g4simulation/g4gdml/PHG4GDMLAuxStructType.hh index 120a335861..5545c16933 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLAuxStructType.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLAuxStructType.hh @@ -36,6 +36,8 @@ #ifndef _PHG4GDMLAUXSTRUCTTYPE_INCLUDED_ #define _PHG4GDMLAUXSTRUCTTYPE_INCLUDED_ +#include + #include struct PHG4GDMLAuxStructType diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWrite.cc b/simulation/g4simulation/g4gdml/PHG4GDMLWrite.cc index ebd0a7cd0a..77ef3ed8c2 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWrite.cc +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWrite.cc @@ -234,7 +234,7 @@ G4Transform3D PHG4GDMLWrite::Write(const G4String& fname, #if XERCES_VERSION_MAJOR >= 3 // DOM L3 as per Xerces 3.0 API xercesc::DOMLSSerializer* writer = - ((xercesc::DOMImplementationLS*) impl)->createLSSerializer(); + static_cast(impl)->createLSSerializer(); xercesc::DOMConfiguration* dc = writer->getDomConfig(); dc->setParameter(xercesc::XMLUni::fgDOMWRTFormatPrettyPrint, true); @@ -242,8 +242,7 @@ G4Transform3D PHG4GDMLWrite::Write(const G4String& fname, #else xercesc::DOMWriter* writer = - ((xercesc::DOMImplementationLS*) impl)->createDOMWriter(); - + static_cast(impl)->createDOMWriter(); if (writer->canSetFeature(xercesc::XMLUni::fgDOMWRTFormatPrettyPrint, true)) writer->setFeature(xercesc::XMLUni::fgDOMWRTFormatPrettyPrint, true); @@ -273,7 +272,7 @@ G4Transform3D PHG4GDMLWrite::Write(const G4String& fname, #if XERCES_VERSION_MAJOR >= 3 // DOM L3 as per Xerces 3.0 API xercesc::DOMLSOutput* theOutput = - ((xercesc::DOMImplementationLS*) impl)->createLSOutput(); + static_cast(impl)->createLSOutput(); theOutput->setByteStream(myFormTarget); writer->write(doc, theOutput); #else diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWrite.hh b/simulation/g4simulation/g4gdml/PHG4GDMLWrite.hh index 0c18c92fcc..f22f534a54 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWrite.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWrite.hh @@ -40,7 +40,7 @@ #ifndef _PHG4GDMLWRITE_INCLUDED_ #define _PHG4GDMLWRITE_INCLUDED_ -#include +#include "PHG4GDMLAuxStructType.hh" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" @@ -52,8 +52,8 @@ #include +#include -#include "PHG4GDMLAuxStructType.hh" class G4LogicalVolume; class G4VPhysicalVolume; diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWriteDefine.hh b/simulation/g4simulation/g4gdml/PHG4GDMLWriteDefine.hh index b7dbf38b81..8619bb18ee 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWriteDefine.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWriteDefine.hh @@ -40,12 +40,12 @@ #ifndef _PHG4GDMLWRITEDEFINE_INCLUDED_ #define _PHG4GDMLWRITEDEFINE_INCLUDED_ +#include "PHG4GDMLWrite.hh" + #include #include #include -#include "PHG4GDMLWrite.hh" - class PHG4GDMLWriteDefine : public PHG4GDMLWrite { diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWriteMaterials.hh b/simulation/g4simulation/g4gdml/PHG4GDMLWriteMaterials.hh index f448bef7b2..e5eb3ac45a 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWriteMaterials.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWriteMaterials.hh @@ -40,11 +40,12 @@ #ifndef _PHG4GDMLWRITEMATERIALS_INCLUDED_ #define _PHG4GDMLWRITEMATERIALS_INCLUDED_ +#include "PHG4GDMLWriteDefine.hh" + #include -#include #include -#include "PHG4GDMLWriteDefine.hh" +#include class G4Isotope; class G4Element; diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWriteSolids.hh b/simulation/g4simulation/g4gdml/PHG4GDMLWriteSolids.hh index 03c67f44a4..c67d13c885 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWriteSolids.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWriteSolids.hh @@ -40,11 +40,11 @@ #ifndef _PHG4GDMLWRITESOLIDS_INCLUDED_ #define _PHG4GDMLWRITESOLIDS_INCLUDED_ +#include "PHG4GDMLWriteMaterials.hh" + #include #include -#include "PHG4GDMLWriteMaterials.hh" - class G4BooleanSolid; class G4Box; class G4Cons; diff --git a/simulation/g4simulation/g4gdml/PHG4GDMLWriteStructure.hh b/simulation/g4simulation/g4gdml/PHG4GDMLWriteStructure.hh index 2bf2aea5fe..9887d0cdf4 100644 --- a/simulation/g4simulation/g4gdml/PHG4GDMLWriteStructure.hh +++ b/simulation/g4simulation/g4gdml/PHG4GDMLWriteStructure.hh @@ -40,11 +40,11 @@ #ifndef _PHG4GDMLWRITESTRUCTURE_INCLUDED_ #define _PHG4GDMLWRITESTRUCTURE_INCLUDED_ +#include "PHG4GDMLWriteParamvol.hh" + #include #include -#include "PHG4GDMLWriteParamvol.hh" - class G4LogicalVolume; class G4VPhysicalVolume; class G4PVDivision; diff --git a/simulation/g4simulation/g4histos/G4VtxNtuple.cc b/simulation/g4simulation/g4histos/G4VtxNtuple.cc index 6446506dac..907cb2559d 100644 --- a/simulation/g4simulation/g4histos/G4VtxNtuple.cc +++ b/simulation/g4simulation/g4histos/G4VtxNtuple.cc @@ -27,7 +27,7 @@ int G4VtxNtuple::Init(PHCompositeNode * /*unused*/) { delete hm; // make cppcheck happy hm = new Fun4AllHistoManager(Name()); - ntup = new TNtuple("vtxntup", "G4Vtxs", "vx:vy:vz"); + ntup = new TNtuple("vtxntup", "G4Vtxs", "vx:vy:vz:vt"); hm->registerHisto(ntup); return 0; } @@ -38,7 +38,10 @@ int G4VtxNtuple::process_event(PHCompositeNode *topNode) if (truthinfo) { PHG4VtxPoint *gvertex = truthinfo->GetPrimaryVtx(truthinfo->GetPrimaryVertexIndex()); - ntup->Fill(gvertex->get_x(), gvertex->get_y(), gvertex->get_z()); + if (gvertex) + { + ntup->Fill(gvertex->get_x(), gvertex->get_y(), gvertex->get_z(), gvertex->get_t()); + } } return 0; } diff --git a/simulation/g4simulation/g4main/Fun4AllDstPileupMerger.cc b/simulation/g4simulation/g4main/Fun4AllDstPileupMerger.cc index 327d611f64..0ddc40a477 100644 --- a/simulation/g4simulation/g4main/Fun4AllDstPileupMerger.cc +++ b/simulation/g4simulation/g4main/Fun4AllDstPileupMerger.cc @@ -274,6 +274,70 @@ void Fun4AllDstPileupMerger::copy_background_event(PHCompositeNode *dstNode, dou } } + // also need to copy the sPHENIX primary particle info + { + // sPHENIX primary particles + const auto range = container_truth->GetSPHENIXPrimaryParticleRange(); + for (auto iter = range.first; iter != range.second; ++iter) + { + const auto &source = iter->second; + if (!source) // guard + { + std::cout << __PRETTY_FUNCTION__ << " - " << __LINE__ << " - null source (sPHENIX primary) particle" << std::endl; + continue; + } + + auto keyiter = trkid_map.find(source->get_track_id()); + if (keyiter == trkid_map.end()) // guard against missing track id in map + { + std::cout << __PRETTY_FUNCTION__ << " - " << __LINE__ << " - track id " << source->get_track_id() << " not found in map" << std::endl; + continue; + } + + auto *dest = new PHG4Particle_t(source); + dest->set_track_id(keyiter->second); + + if (source->get_parent_id() == 0) + { + dest->set_parent_id(0); + } + else + { + keyiter = trkid_map.find(source->get_parent_id()); + if (keyiter != trkid_map.end()) + { + dest->set_parent_id(keyiter->second); + } + else + { + std::cout << "Fun4AllDstPileupMerger::copy_background_event - track id " << source->get_parent_id() << " not found in map" << std::endl; + } + } + + keyiter = trkid_map.find(source->get_primary_id()); + if (keyiter != trkid_map.end()) + { + dest->set_primary_id(keyiter->second); + } + else + { + std::cout << "Fun4AllDstPileupMerger::copy_background_event - track id " << source->get_primary_id() << " not found in map" << std::endl; + } + + keyiter = vtxid_map.find(source->get_vtx_id()); + if (keyiter != vtxid_map.end()) + { + dest->set_vtx_id(keyiter->second); + } + else + { + std::cout << "Fun4AllDstPileupMerger::copy_background_event - vertex id " << source->get_vtx_id() << " not found in map" << std::endl; + } + + m_g4truthinfo->AddsPHENIXPrimaryParticle(dest->get_track_id(), dest); + } + } + // vertex embed flags /* embed flag is stored only for primary vertices, consistently with PHG4TruthEventAction */ for (const auto &pair : vtxid_map) diff --git a/simulation/g4simulation/g4main/Makefile.am b/simulation/g4simulation/g4main/Makefile.am index bff8a37125..c7412330f8 100644 --- a/simulation/g4simulation/g4main/Makefile.am +++ b/simulation/g4simulation/g4main/Makefile.am @@ -36,7 +36,6 @@ libg4testbench_la_LDFLAGS = \ libg4testbench_la_LIBADD = \ libphg4hit.la \ - -lboost_filesystem \ -lffamodules \ -lfun4all \ -lg4decayer \ diff --git a/simulation/g4simulation/g4main/PHG4ProcessMap.cc b/simulation/g4simulation/g4main/PHG4ProcessMap.cc index d44a4668f7..dcadaaa621 100644 --- a/simulation/g4simulation/g4main/PHG4ProcessMap.cc +++ b/simulation/g4simulation/g4main/PHG4ProcessMap.cc @@ -77,7 +77,7 @@ PHG4ProcessMap::GetMCProcess(const G4VProcess* process) const { std::string text = "Unknown process code for "; text += process->GetProcessName(); - std::cerr << "PHG4ProcessMap::GetCodes " << text.c_str() << std::endl; + std::cerr << "PHG4ProcessMap::GetCodes " << text << std::endl; return kPNoProcess; } diff --git a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc index 4db6ecbd51..7243e519de 100644 --- a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc +++ b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.cc @@ -76,8 +76,8 @@ void PHG4TruthTrackingAction::PreUserTrackingAction(const G4Track* track) int vtxindex = ti->get_vtx_id(); // maybe we should do the sPHENIX primary tracking here as here is the place where the parent id etc. are finally set - - if (issPHENIXPrimary(*m_TruthInfoList, ti)) +// Old-- for only keeping sPHENIX primary +/* if (issPHENIXPrimary(*m_TruthInfoList, ti)) { // we also want to set keep this track PHG4TrackUserInfoV1* userinfo = dynamic_cast(track->GetUserInformation()); @@ -89,8 +89,31 @@ void PHG4TruthTrackingAction::PreUserTrackingAction(const G4Track* track) PHG4Particle* newparticle = dynamic_cast(ti->CloneMe()); m_TruthInfoList->AddsPHENIXPrimaryParticle(trackid, newparticle); + }*/ + + +// Now keeping sPHENIX primary as well as decay history + const bool keep_as_sphenix_primary = issPHENIXPrimary(*m_TruthInfoList, ti); + const bool keep_as_decay_history = keepDecayHistory(*m_TruthInfoList, ti); + + if (keep_as_sphenix_primary || keep_as_decay_history) + { + PHG4TrackUserInfoV1* userinfo = + dynamic_cast(track->GetUserInformation()); + + if (userinfo) + { + userinfo->SetKeep(true); + } } + if (keep_as_sphenix_primary) + { + PHG4Particle* newparticle = dynamic_cast(ti->CloneMe()); + + m_TruthInfoList->AddsPHENIXPrimaryParticle(trackid, newparticle); + }//end keeping sPHENIX primary & decay History + m_CurrG4Particle = {track_id_g4, trackid, vtxindex}; // create or add to a new shower object -------------------------------------- @@ -232,10 +255,11 @@ int PHG4TruthTrackingAction::ResetEvent(PHCompositeNode* /*unused*/) } return 0; -} +} PHG4Particle* PHG4TruthTrackingAction::AddParticle(PHG4TruthInfoContainer& truth, G4Track& track) { + int trackid = 0; if (track.GetParentID()) { @@ -305,28 +329,80 @@ PHG4Particle* PHG4TruthTrackingAction::AddParticle(PHG4TruthInfoContainer& truth return truth.AddParticle(trackid, ti)->second; } +/** + * @brief Create or retrieve a truth vertex for a Geant4 track keyed by position and production process. + * + * Uses the track vertex position combined with the mapped MC production process to look up an existing + * vertex or create a new PHG4VtxPoint and register it in the truth container. The vertex index is chosen + * positive for primary tracks and negative for secondaries. + * + * @param truth Container in which to find or register the vertex. + * @param track Geant4 track whose production vertex and creator process determine the vertex key. + * @return PHG4VtxPoint* Pointer to the vertex instance stored in the truth container. + */ PHG4VtxPoint* PHG4TruthTrackingAction::AddVertex(PHG4TruthInfoContainer& truth, const G4Track& track) { G4ThreeVector v = track.GetVertexPosition(); + + // Get G4Track creator process FIRST (needed for vertex map key) + const auto* const g4Process = track.GetCreatorProcess(); + // Convert G4 Process to MC process + const auto process = PHG4ProcessMapPhysics::Instance().GetMCProcess(g4Process); + int vtxindex = (track.GetParentID() == 0 ? truth.maxvtxindex() + 1 : truth.minvtxindex() - 1); - auto [iter, inserted] = m_VertexMap.insert(std::make_pair(v, vtxindex)); + // Use (position, process) as key to distinguish vertices at same location but different processes + // This is important for cases like K0 -> K0_S/K0_L mixing where particles are produced + // at the same position but by different physics processes + auto key = std::make_pair(v, process); + auto [iter, inserted] = m_VertexMap.insert(std::make_pair(key, vtxindex)); // If could not add a unique vertex => return the existing one if (!inserted) { return truth.GetVtxMap().find(iter->second)->second; } - // get G4Track creator process - const auto* const g4Process = track.GetCreatorProcess(); - // convert G4 Process to MC process - const auto process = PHG4ProcessMapPhysics::Instance().GetMCProcess(g4Process); - // otherwise, create and add a new one + + // Create and add a new vertex PHG4VtxPoint* vtxpt = new PHG4VtxPointv2(v[0] / cm, v[1] / cm, v[2] / cm, track.GetGlobalTime() / ns, vtxindex, process); return truth.AddVertex(vtxindex, vtxpt)->second; } +/** + * @brief Determine whether a PHG4Particle should be considered an sPHENIX primary. + * + * Evaluates the particle's production vertex, PDG id longevity, and ancestry to decide + * if it originates as an sPHENIX primary (produced as a primary or from a decay and + * having no long-lived ancestor produced by material interactions). + * + * @param truth Truth container used to look up particle parents and production vertices. + * @param particle Particle to evaluate. + * @return true if the particle is classified as an sPHENIX primary, `false` otherwise. + * + */ + +//For keeping all decay truth info +bool PHG4TruthTrackingAction::keepDecayHistory( + PHG4TruthInfoContainer& truth, + PHG4Particle* particle) const +{ + if (!particle) + { + return false; + } + + PHG4VtxPoint* vtx = truth.GetVtx(particle->get_vtx_id()); + if (!vtx) + { + return false; + } + + const bool from_decay = (vtx->get_process() == PHG4MCProcess::kPDecay); + + return from_decay; +}//End keep decay History + bool PHG4TruthTrackingAction::issPHENIXPrimary(PHG4TruthInfoContainer& truth, PHG4Particle* particle) const { PHG4VtxPoint* vtx = truth.GetVtx(particle->get_vtx_id()); @@ -346,13 +422,15 @@ bool PHG4TruthTrackingAction::issPHENIXPrimary(PHG4TruthInfoContainer& truth, PH // check the production process // if not decay or primary, then it is not a primary // debug print for pid, track id, parent id, and process - /* - std::cout << "PHG4TruthTrackingAction::issPHENIXPrimary - checking particle with track id " << particle->get_track_id() - << ", pid: " << pdgid - << ", parent id: " << particle->get_parent_id() - << ", process: " << process - << std::endl; - */ + // if (pdgid == 311 || pdgid == 130 || pdgid == 310) + //{ + // std::cout << "PHG4TruthTrackingAction::issPHENIXPrimary - checking particle with track id " << particle->get_track_id() + // << ", pid: " << pdgid + // << ", parent id: " << particle->get_parent_id() + // << ", process: " << process + // << std::endl; + //} + if (!(process == PHG4MCProcess::kPPrimary || process == PHG4MCProcess::kPDecay) && particle->get_parent_id()) // all primary particles seems to have unkown process id { return false; diff --git a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h index 5ad050c898..734436115f 100644 --- a/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h +++ b/simulation/g4simulation/g4main/PHG4TruthTrackingAction.h @@ -4,10 +4,12 @@ #define G4MAIN_PHG4TRUTHTRACKINGACTION_H #include "PHG4TrackingAction.h" +#include "PHG4MCProcessDefs.h" #include #include +#include #include class G4Track; @@ -17,6 +19,68 @@ class PHG4TruthEventAction; class PHG4Particle; class PHG4VtxPoint; +/** + * Construct a PHG4TruthTrackingAction associated with an event action. + * @param eventAction Pointer to the owning PHG4TruthEventAction used to record per-event truth information. + */ + +/** + * Destroy the PHG4TruthTrackingAction. + */ + +/** + * Handle actions to perform before Geant4 begins tracking a G4 track. + * @param track The Geant4 track about to be processed. + */ + +/** + * Handle actions to perform after Geant4 finishes tracking a G4 track. + * @param track The Geant4 track that has just been processed. + */ + +/** + * Set required node/interface pointers from the given top-level node. + * @param topNode Pointer to the PHCompositeNode root from which required I/O nodes are retrieved. + * @returns Zero on success, non-zero on failure. + */ + +/** + * Reset per-event state using nodes found under the given composite node. + * @param topNode Pointer to the PHCompositeNode for the current event. + * @returns Zero on success, non-zero on failure. + */ + +/** + * Create or update a truth particle entry corresponding to the provided Geant4 track. + * @param truth Container to which the particle entry will be added or updated. + * @param track Geant4 track from which particle information is derived. + * @returns Pointer to the created or updated PHG4Particle. + */ + +/** + * Create or update a truth vertex entry corresponding to the provided Geant4 track. + * @param truth Container to which the vertex entry will be added or updated. + * @param track Geant4 track whose production point will be recorded as a vertex. + * @returns Pointer to the created or updated PHG4VtxPoint. + */ + +/** + * Determine whether a particle type is considered long-lived for truth-building. + * @param pid Particle PDG identifier. + * @returns `true` if the particle with the given PDG id is treated as long-lived, `false` otherwise. + */ + +/** + * Determine whether a particle should be flagged as an sPHENIX primary. + * @param truth Truth information container used to evaluate primary status. + * @param particle Particle to evaluate. + * @returns `true` if the particle is considered an sPHENIX primary, `false` otherwise. + */ + +/** + * Update the internal upstream G4 particle stack when processing a new Geant4 track. + * @param track Geant4 track used to update parent/ancestor particle bookkeeping. + */ class PHG4TruthTrackingAction : public PHG4TrackingAction { public: @@ -37,7 +101,8 @@ class PHG4TruthTrackingAction : public PHG4TrackingAction int ResetEvent(PHCompositeNode*) override; private: - std::map m_VertexMap; + // Key is (position, process) to distinguish vertices at the same location but different processes + std::map, int> m_VertexMap; //! pointer to the "owning" event action PHG4TruthEventAction* m_EventAction; @@ -51,6 +116,9 @@ class PHG4TruthTrackingAction : public PHG4TrackingAction // check if track is long-lived bool isLongLived(int pid) const; + // check if track should be kept because it is produced by a decay process + bool keepDecayHistory(PHG4TruthInfoContainer& truth, PHG4Particle* particle) const; + // check if track is sPHENIX primary bool issPHENIXPrimary(PHG4TruthInfoContainer& truth, PHG4Particle* particle) const; diff --git a/simulation/g4simulation/g4mvtx/PHG4MvtxDisplayAction.cc b/simulation/g4simulation/g4mvtx/PHG4MvtxDisplayAction.cc index e04230ab24..3e9a58023d 100644 --- a/simulation/g4simulation/g4mvtx/PHG4MvtxDisplayAction.cc +++ b/simulation/g4simulation/g4mvtx/PHG4MvtxDisplayAction.cc @@ -1,7 +1,7 @@ #include "PHG4MvtxDisplayAction.h" #include -#include "g4main/PHG4DisplayAction.h" // for PHG4DisplayAction +#include // for PHG4DisplayAction #include #include diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc b/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc index 5d0eb1e66c..073988fc16 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDetector.cc @@ -3,7 +3,7 @@ #include "PHG4TpcDisplayAction.h" #include -#include +#include #include #include @@ -118,10 +118,36 @@ void PHG4TpcDetector::ConstructMe(G4LogicalVolume *logicWorld) ConstructTpcCageVolume(tpc_envelope_logic); ConstructTpcGasVolume(tpc_envelope_logic); - new G4PVPlacement(nullptr, G4ThreeVector(m_Params->get_double_param("place_x") * cm, m_Params->get_double_param("place_y") * cm, m_Params->get_double_param("place_z") * cm), + G4RotationMatrix rot; + rot.rotateX(m_Params->get_double_param("rot_x")*rad); + rot.rotateY(m_Params->get_double_param("rot_y")*rad); + rot.rotateZ(m_Params->get_double_param("rot_z")*rad); + + G4ThreeVector trans(m_Params->get_double_param("place_x") * cm, m_Params->get_double_param("place_y") * cm, m_Params->get_double_param("place_z") * cm); + + new G4PVPlacement( + G4Transform3D(rot, trans), tpc_envelope_logic, "tpc_envelope", - logicWorld, false, false, OverlapCheck()); - + logicWorld, + false, false, OverlapCheck()); + + std::cout + << PHWHERE << std::endl + << " place_x " << m_Params->get_double_param("place_x")*cm + << " place_y " << m_Params->get_double_param("place_y")*cm + << " place_z " << m_Params->get_double_param("place_z")*cm + << " mm " << std::endl; + std::cout + << " rot_x " << m_Params->get_double_param("rot_x")*rad + << " rot_y " << m_Params->get_double_param("rot_y")*rad + << " rot_z " << m_Params->get_double_param("rot_z")*rad + << " rad " << std::endl; + + G4Point3D test_env(0.0*cm, 0.0*cm, 113.025*cm); + std::cout << " test envelope position (mm) " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; + G4Point3D test_glob = test_env.transform(G4Transform3D(rot,trans)); + std::cout << " test global position (mm) " << test_glob.x() << " " << test_glob.y() << " " << test_glob.z() << std::endl; + // geometry node add_geometry_node(); } @@ -538,7 +564,12 @@ void PHG4TpcDetector::add_geometry_node() auto *newNode = new PHIODataNode(geonode, geonode_name, "PHObject"); geomNode->addNode(newNode); } - + else + { + std::cout << "PHG4TpcGeomContainer already exists with name " << geonode_name << " and it should not! " << std::endl; + geonode->identify(); + } + m_cdb = CDBInterface::instance(); std::string calibdir = m_cdb->getUrl("TPC_FEE_CHANNEL_MAP"); @@ -695,7 +726,7 @@ void PHG4TpcDetector::add_geometry_node() << " phibins " << NPhiBins[iregion] << " phistep " << phi_bin_width_cdb[layer] << std::endl; } - auto *layerseggeo = new PHG4TpcGeomv1; + auto *layerseggeo = new PHG4TpcGeomv2; layerseggeo->set_layer(layer); double r_length = Thickness[iregion]; @@ -731,6 +762,12 @@ void PHG4TpcDetector::add_geometry_node() layerseggeo->set_adc_clock(m_Params->get_double_param("tpc_adc_clock")); layerseggeo->set_extended_readout_time(m_Params->get_double_param("extended_readout_time")); layerseggeo->set_drift_velocity_sim(m_Params->get_double_param("drift_velocity_sim")); + layerseggeo->set_rot_x(m_Params->get_double_param("rot_x")); + layerseggeo->set_rot_y(m_Params->get_double_param("rot_y")); + layerseggeo->set_rot_z(m_Params->get_double_param("rot_z")); + layerseggeo->set_place_x(m_Params->get_double_param("place_x")); + layerseggeo->set_place_y(m_Params->get_double_param("place_y")); + layerseggeo->set_place_z(m_Params->get_double_param("place_z")); } // Chris Pinkenburg: greater causes huge memory growth which causes problems diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc index 8062bd709e..61ca56d4b6 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.cc @@ -25,6 +25,7 @@ #include // for gsl_rng_alloc #include +#include #include // for exit #include #include @@ -32,14 +33,6 @@ PHG4TpcDigitizer::PHG4TpcDigitizer(const std::string &name) : SubsysReco(name) - , TpcMinLayer(7) - , TpcNLayers(48) - , ADCThreshold(2700) // electrons - , TpcEnc(670) // electrons - , Pedestal(50000) // electrons - , ChargeToPeakVolts(20) // mV/fC - , ADCSignalConversionGain(std::numeric_limits::quiet_NaN()) // will be assigned in PHG4TpcDigitizer::InitRun - , ADCNoiseConversionGain(std::numeric_limits::quiet_NaN()) , RandomGenerator(gsl_rng_alloc(gsl_rng_mt19937)) // will be assigned in PHG4TpcDigitizer::InitRun { unsigned int seed = PHRandomSeed(); // fixed seed is handled in this funtcion @@ -273,10 +266,17 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } // for this layer and side, use a vector of a vector of cells for each phibin - phi_sorted_hits.clear(); - for (int iphi = 0; iphi < nphibins; iphi++) + if (phi_sorted_hits.size() != static_cast(nphibins)) { - phi_sorted_hits.emplace_back(); + phi_sorted_hits.clear(); + phi_sorted_hits.resize(nphibins); + } + else + { + for (auto &hits : phi_sorted_hits) + { + hits.clear(); + } } // Loop over all hitsets containing signals for this layer and add them to phi_sorted_hits for their phibin @@ -326,31 +326,24 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) for (unsigned int iphi = 0; iphi < phi_sorted_hits.size(); iphi++) { - // Make a fixed length vector to indicate whether each time bin is signal or noise int ntbins = layergeom->get_zbins(); - is_populated.clear(); - is_populated.assign(ntbins, 2); // mark all as noise only, for now - - // add an empty vector of hits for each t bin - t_sorted_hits.clear(); - for (int it = 0; it < ntbins; it++) - { - t_sorted_hits.emplace_back(); - } + signal_hit_by_tbin.assign(ntbins, nullptr); // add a signal hit from phi_sorted_hits for each t bin that has one for (unsigned int it = 0; it < phi_sorted_hits[iphi].size(); it++) { int tbin = TpcDefs::getTBin(phi_sorted_hits[iphi][it]->first); - is_populated[tbin] = 1; // this bin is a associated with a hit - t_sorted_hits[tbin].push_back(phi_sorted_hits[iphi][it]); + if (!signal_hit_by_tbin[tbin]) + { + signal_hit_by_tbin[tbin] = phi_sorted_hits[iphi][it]->second; + } if (Verbosity() > 2) { if (layer == print_layer) { TrkrDefs::hitkey hitkey = phi_sorted_hits[iphi][it]->first; - std::cout << "iphi " << iphi << " adding existing signal hit to t vector for layer " << layer + std::cout << "iphi " << iphi << " adding existing signal hit for layer " << layer << " side " << side << " tbin " << tbin << " hitkey " << hitkey << " pad " << TpcDefs::getPad(hitkey) @@ -361,11 +354,8 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } } - adc_input.clear(); - adc_hitid.clear(); // initialize entries to zero for each t bin adc_input.assign(ntbins, 0.0); - adc_hitid.assign(ntbins, 0); // Now for this phibin we process all bins ordered by t into hits with noise //====================================================== @@ -374,33 +364,32 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) for (int it = 0; it < ntbins; it++) { - if (is_populated[it] == 1) + TrkrHit *signal_hit = signal_hit_by_tbin[it]; + if (signal_hit) { // This tbin has a hit, add noise - float signal_with_noise = add_noise_to_bin((t_sorted_hits[it][0]->second)->getEnergy()); + float signal_with_noise = add_noise_to_bin(signal_hit->getEnergy()); adc_input[it] = signal_with_noise; - adc_hitid[it] = t_sorted_hits[it][0]->first; if (Verbosity() > 2) { if (layer == print_layer) { std::cout << "existing signal hit: layer " << layer << " iphi " << iphi << " it " << it - << " edep " << (t_sorted_hits[it][0]->second)->getEnergy() + << " edep " << signal_hit->getEnergy() << " adc gain " << ADCSignalConversionGain << " signal with noise " << signal_with_noise << " adc_input " << adc_input[it] << std::endl; } } } - else if (is_populated[it] == 2) + else { if (!skip_noise) { // This t bin does not have a filled cell, add noise float noise = add_noise_to_bin(0.0); adc_input[it] = noise; - adc_hitid[it] = 0; // there is no hit, just add a placeholder in the vector for now, replace it later if (Verbosity() > 2) { @@ -414,13 +403,6 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } } } - else - { - // Cannot happen - std::cout << "Impossible value of is_populated, it = " << it - << " is_populated = " << is_populated[it] << std::endl; - exit(-1); - } } // Now we can digitize the entire stream of t bins for this phi bin @@ -438,7 +420,7 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } // optionally do not trigger on bins with no signal - if ((is_populated[it] == 2) && skip_noise) + if (!signal_hit_by_tbin[it] && skip_noise) { binpointer++; continue; @@ -466,7 +448,8 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) if (it + itup < ntbins && it + itup >= 0) // stay within the bin limits { float input = 0; - if ((is_populated[it + itup] == 2) && skip_noise) + TrkrHit *signal_hit = signal_hit_by_tbin[it + itup]; + if (!signal_hit && skip_noise) { input = add_noise_to_bin(0.0); // no noise added to this bin previously because skip_noise is true } @@ -492,8 +475,8 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) if (layer == print_layer) { std::cout << " Digitizing: iphi " << iphi << " it+itup " << it + itup - << " adc_hitid " << adc_hitid[it + itup] - << " is_populated " << is_populated[it + itup] + << " adc_hitid " << (signal_hit ? hitkey : 0) + << " is_populated " << (signal_hit ? 1 : 2) << " adc_input " << adc_input[it + itup] << " ADCThreshold " << ADCThreshold * ADCNoiseConversionGain << " adc_output " << adc_output @@ -504,10 +487,10 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) } } - if (is_populated[it + itup] == 1) + if (signal_hit) { // this is a signal hit, it already exists - hit = t_sorted_hits[it + itup][0]->second; // pointer valid only for signal hits + hit = signal_hit; } else { @@ -545,20 +528,10 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) else { // set adc value to zero if there is a hit - // we need the hitset key, requires (layer, sector, side) - unsigned int sector = 12 * iphi / nphibins; - TrkrDefs::hitsetkey hitsetkey = TpcDefs::genHitSetKey(layer, sector, side); - auto *hitset = trkrhitsetcontainer->findHitSet(hitsetkey); - if (hitset) + TrkrHit *hit = signal_hit_by_tbin[it]; + if (hit) { - // Get the hitkey - TrkrDefs::hitkey hitkey = TpcDefs::genHitKey(iphi, it); - TrkrHit *hit = nullptr; - hit = hitset->getHit(hitkey); - if (hit) - { - hit->setAdc(0); - } + hit->setAdc(0); } // bin below threshold, move on binpointer++; @@ -573,7 +546,7 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) { std::cout << "From PHG4TpcDigitizer: hitsetcontainer dump at end before cleaning:" << std::endl; } - std::vector> delete_hitkey_list; + std::vector delete_hitkey_list; // Clean up undigitized hits - we want all hitsets for the Tpc // This loop is pretty efficient because the remove methods all take a specified hitset as input @@ -594,6 +567,7 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) // get all of the hits from this hitset TrkrHitSet *hitset = hitset_iter->second; + delete_hitkey_list.clear(); TrkrHitSet::ConstRange hit_range = hitset->getHits(); for (TrkrHitSet::ConstIterator hit_iter = hit_range.first; hit_iter != hit_range.second; @@ -616,28 +590,26 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) std::cout << " -- this hit not digitized - delete it" << std::endl; } // screws up the iterator to delete it here, store the hitkey for later deletion - delete_hitkey_list.emplace_back(hitsetkey, hitkey); + delete_hitkey_list.push_back(hitkey); } } - } - // delete all undigitized hits - for (auto &i : delete_hitkey_list) - { - TrkrHitSet *hitset = trkrhitsetcontainer->findHitSet(i.first); - const unsigned int layer = TrkrDefs::getLayer(i.first); - hitset->removeHit(i.second); - if (Verbosity() > 20) + // delete all undigitized hits + for (auto &hitkey : delete_hitkey_list) { - if (layer == print_layer) + hitset->removeHit(hitkey); + if (Verbosity() > 20) { - std::cout << "removed hit with hitsetkey " << i.first - << " and hitkey " << i.second << std::endl; + if (layer == print_layer) + { + std::cout << "removed hit with hitsetkey " << hitsetkey + << " and hitkey " << hitkey << std::endl; + } } - } - // should also delete all entries with this hitkey from the TrkrHitTruthAssoc map - // hittruthassoc->removeAssoc(delete_hitkey_list[i].first, delete_hitkey_list[i].second); // Slow! Commented out by ADF 9/6/2022 + // should also delete all entries with this hitkey from the TrkrHitTruthAssoc map + // hittruthassoc->removeAssoc(hitsetkey, hitkey); // Slow! Commented out by ADF 9/6/2022 + } } // Final hitset dump @@ -648,7 +620,7 @@ void PHG4TpcDigitizer::DigitizeCylinderCells(PHCompositeNode *topNode) // We want all hitsets for the Tpc TrkrHitSetContainer::ConstRange hitset_range_final = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::tpcId); for (TrkrHitSetContainer::ConstIterator hitset_iter = hitset_range_final.first; - hitset_iter != hitset_range_now.second; + hitset_iter != hitset_range_final.second; ++hitset_iter) { // we have an itrator to one TrkrHitSet for the Tpc from the trkrHitSetContainer diff --git a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h index db7f6eff0f..51048d39f2 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcDigitizer.h @@ -8,14 +8,15 @@ #include #include +#include + #include #include // for string #include // for pair, make_pair #include -#include - class PHCompositeNode; +class TrkrHit; class PHG4TpcDigitizer : public SubsysReco { @@ -23,18 +24,12 @@ class PHG4TpcDigitizer : public SubsysReco PHG4TpcDigitizer(const std::string &name = "PHG4TpcDigitizer"); ~PHG4TpcDigitizer() override; - //! module initialization - int Init(PHCompositeNode * /*topNode*/) override { return 0; } - //! run initialization int InitRun(PHCompositeNode *topNode) override; //! event processing int process_event(PHCompositeNode *topNode) override; - //! end of process - int End(PHCompositeNode * /*topNode*/) override { return 0; }; - void set_adc_scale(const int layer, const unsigned int max_adc, const float energy_per_adc) { _max_adc.insert(std::make_pair(layer, max_adc)); @@ -52,31 +47,28 @@ class PHG4TpcDigitizer : public SubsysReco float added_noise(); float add_noise_to_bin(float signal); - unsigned int TpcMinLayer; - unsigned int TpcNLayers; - float ADCThreshold; - float ADCThreshold_mV = 0; - float TpcEnc; - float Pedestal; - float ChargeToPeakVolts; - float ADCSignalConversionGain; - float ADCNoiseConversionGain; + unsigned int TpcMinLayer {7}; + unsigned int TpcNLayers {48}; + float ADCThreshold {2700}; + float ADCThreshold_mV {0}; + float TpcEnc {670}; + float Pedestal {50000}; + float ChargeToPeakVolts {20}; + float ADCSignalConversionGain {std::numeric_limits::quiet_NaN()}; + float ADCNoiseConversionGain {std::numeric_limits::quiet_NaN()}; - bool skip_noise = false; + bool skip_noise {false}; std::vector > phi_sorted_hits; - std::vector > t_sorted_hits; - std::vector adc_input; - std::vector adc_hitid; - std::vector is_populated; + std::vector signal_hit_by_tbin; // settings std::map _max_adc; std::map _energy_scale; //! random generator that conform with sPHENIX standard - gsl_rng *RandomGenerator; + gsl_rng *RandomGenerator {nullptr}; }; #endif diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc index 9de4cf6639..24d753cb66 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.cc @@ -390,6 +390,14 @@ int PHG4TpcElectronDrift::InitRun(PHCompositeNode *topNode) } } + /* + Acts::Vector3 test_env(10.0, 40.0, 80.0); + std::cout << " test_env " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; + Acts::Vector3 test_glob = m_tGeometry-> transformTpcEnvelopeToWorld(test_env); + std::cout << " test_glob " << test_glob.x() << " " << test_glob.y() << " " << test_glob.z() << std::endl; + Acts::Vector3 test_env_check = m_tGeometry-> transformTpcWorldToEnvelope(test_glob); + std::cout << " test_env_check " << test_env_check.x() << " " << test_env_check.y() << " " << test_env_check.z() << std::endl; + */ return Fun4AllReturnCodes::EVENT_OK; } @@ -556,11 +564,22 @@ int PHG4TpcElectronDrift::process_event(PHCompositeNode *topNode) // values between 0 and 1 const double f = gsl_ran_flat(RandomGenerator.get(), 0.0, 1.0); - const double x_start = hiter->second->get_x(0) + f * (hiter->second->get_x(1) - hiter->second->get_x(0)); - const double y_start = hiter->second->get_y(0) + f * (hiter->second->get_y(1) - hiter->second->get_y(0)); - const double z_start = hiter->second->get_z(0) + f * (hiter->second->get_z(1) - hiter->second->get_z(0)); + const double x_start_glob = hiter->second->get_x(0) + f * (hiter->second->get_x(1) - hiter->second->get_x(0)); + const double y_start_glob = hiter->second->get_y(0) + f * (hiter->second->get_y(1) - hiter->second->get_y(0)); + const double z_start_glob = hiter->second->get_z(0) + f * (hiter->second->get_z(1) - hiter->second->get_z(0)); const double t_start = hiter->second->get_t(0) + f * (hiter->second->get_t(1) - hiter->second->get_t(0)); + Acts::Vector3 start_glob(x_start_glob, y_start_glob, z_start_glob); + Acts::Vector3 start = m_tGeometry->transformTpcWorldToEnvelope(start_glob); // we drift in tpc envelope coords, where E is in the z direction + + const double x_start = start.x(); + const double y_start = start.y(); + const double z_start = start.z(); + /* + std::cout << " xg " << x_start_glob << " x " << x_start + <<" yg " << y_start_glob << " y " << y_start + <<" zg " << z_start_glob << " z " << z_start << std::endl; + */ unsigned int side = 0; if (z_start > 0) { diff --git a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h index de2810e918..f290d7d92f 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcElectronDrift.h @@ -38,6 +38,7 @@ class DistortedTrackContainer; class TpcClusterBuilder; class PHG4TpcGeomContainer; class ClusHitsVerbose; +class ActsGeometry; class PHG4TpcElectronDrift : public SubsysReco, public PHParameterInterface { diff --git a/simulation/g4simulation/g4tpc/PHG4TpcEndCapDetector.cc b/simulation/g4simulation/g4tpc/PHG4TpcEndCapDetector.cc index 583934798d..3029233299 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcEndCapDetector.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcEndCapDetector.cc @@ -94,9 +94,9 @@ void PHG4TpcEndCapDetector::ConstructMe(G4LogicalVolume *logicWorld) m_Params->get_double_param("place_y") * cm, m_Params->get_double_param("place_z") * cm); G4RotationMatrix rotm_center; - rotm_center.rotateX(m_Params->get_double_param("rot_x") * deg); - rotm_center.rotateY(m_Params->get_double_param("rot_y") * deg); - rotm_center.rotateZ(m_Params->get_double_param("rot_z") * deg); + rotm_center.rotateX(m_Params->get_double_param("rot_x") * rad); + rotm_center.rotateY(m_Params->get_double_param("rot_y") * rad); + rotm_center.rotateZ(m_Params->get_double_param("rot_z") * rad); G4Transform3D transform_center(rotm_center, g4vec_center); int i = 0; @@ -107,6 +107,14 @@ void PHG4TpcEndCapDetector::ConstructMe(G4LogicalVolume *logicWorld) G4Transform3D transform_side2 = transform_center * rotm_otherside * g4vec_front_z; m_EndCapAssembly->MakeImprint(logicWorld, transform_side2, i++, OverlapCheck()); + + G4ThreeVector test_env(10.0, 40.0, 80.0); + std::cout << "Endcap: rot_x " << m_Params->get_double_param("rot_x")*rad << " test_env " << test_env.x() << " " << test_env.y() << " " << test_env.z() << std::endl; + G4ThreeVector test_glob1 = test_env.transform(rotm_center); + std::cout << " test_glob1 " << test_glob1.x() << " " << test_glob1.y() << " " << test_glob1.z() << std::endl; + // G4ThreeVector test_glob2 = test_env(transform_side2); + // std::cout << " test_glob2 " << test_glob2.x() << " " << test_glob2.y() << " " << test_glob2.z() << std::endl; + return; } diff --git a/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc b/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc index ec00172916..4cd13647de 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcEndCapSubsystem.cc @@ -116,13 +116,14 @@ void PHG4TpcEndCapSubsystem::SetDefaultParameters() { set_default_int_param("construction_verbosity", 0); // sizes are in cm - // angles are in deg + // angles are in rad // units should be converted to G4 units when used // implement your own here// set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); set_default_double_param("place_z", 0.); - set_default_double_param("rot_x", 0.); + // angles are in rad + set_default_double_param("rot_x", 0.); set_default_double_param("rot_y", 0.); set_default_double_param("rot_z", 0.); diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h b/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h index 8c9e1cc8f3..6c9ff571e6 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlane.h @@ -1,13 +1,14 @@ #ifndef G4TPC_PHG4TPCPADPLANE_H #define G4TPC_PHG4TPCPADPLANE_H -#include +#include "TpcClusterBuilder.h" #include -#include "TpcClusterBuilder.h" #include +#include + #include // for string class TrkrHitSetContainer; diff --git a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc index 6cd968883e..7006241673 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcPadPlaneReadout.cc @@ -40,6 +40,7 @@ #include #include // for getenv #include +#include #include #include // for _Rb_tree_cons... #include // for pair diff --git a/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc b/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc index 8d802c7886..80a04450f4 100644 --- a/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc +++ b/simulation/g4simulation/g4tpc/PHG4TpcSubsystem.cc @@ -144,6 +144,7 @@ void PHG4TpcSubsystem::SetDefaultParameters() set_default_double_param("place_x", 0.); set_default_double_param("place_y", 0.); set_default_double_param("place_z", 0.); + // angles are in radians set_default_double_param("rot_x", 0.); set_default_double_param("rot_y", 0.); set_default_double_param("rot_z", 0.); diff --git a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc index fb6a02ba26..e62f31dce7 100644 --- a/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc +++ b/simulation/g4simulation/g4tpc/TpcClusterBuilder.cc @@ -15,7 +15,7 @@ #include - +#include #include #include // for sqrt, cos, sin #include @@ -183,6 +183,12 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) adc_sum += adc; } + + if(adc_sum == 0) + { + continue; + } + if (mClusHitsVerbose) { if (verbosity > 10) @@ -330,9 +336,11 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) } // end debug printing // get the global vector3 to then get the surface local phi and z - Acts::Vector3 global(clusx, clusy, clusz); + Acts::Vector3 global_env(clusx, clusy, clusz); TrkrDefs::subsurfkey subsurfkey = 0; + // get_tpc_surface_from coords and the Acts transform both expect coordinates in world (i.e. tilted TPC) coordinates + Acts::Vector3 global = m_tGeometry->transformTpcEnvelopeToWorld(global_env); Surface surface = m_tGeometry->get_tpc_surface_from_coords( hitsetkey, global, subsurfkey); @@ -351,7 +359,7 @@ void TpcClusterBuilder::cluster_hits(TrkrTruthTrack* track) global *= Acts::UnitConstants::cm; - Acts::Vector3 local = surface->transform(m_tGeometry->geometry().getGeoContext()).inverse() * global; + Acts::Vector3 local = surface->localToGlobalTransform(m_tGeometry->geometry().getGeoContext()).inverse() * global; local /= Acts::UnitConstants::cm; auto* cluster = new TrkrClusterv4; // diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc index cb2ec42d8b..a429a4c8a8 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.cc @@ -6,38 +6,43 @@ #include #include #include // for hit_idbits -#include -#include #include // for CDBTTree #include -#include - #include +#include +#include #include #include +#include #include #include -#include +#include +#include + +#include #include #include #include -#include // for PHG4CylinderGeom_Spaca... #include #include #include #include #include -#include + +#include + #include #include -#include -#include +#include +#include +#include +#include double CaloWaveformSim::template_function(double *x, double *par) { @@ -53,6 +58,11 @@ CaloWaveformSim::CaloWaveformSim(const std::string &name) CaloWaveformSim::~CaloWaveformSim() { gsl_rng_free(m_RandomGenerator); + delete cdbttree; + delete cdbttree_MC; + delete cdbttree_time; + delete cdbttree_MC_time; + delete h_template; } int CaloWaveformSim::InitRun(PHCompositeNode *topNode) @@ -66,24 +76,22 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) const char *calibroot = getenv("CALIBRATIONROOT"); if (!calibroot) { - std::cerr << "CaloWaveformSim::InitRun missing CALIBRATIONROOT" << std::endl; + std::cout << "CaloWaveformSim::InitRun missing CALIBRATIONROOT" << std::endl; exit(1); } std::string templatefilename = std::string(calibroot) + "/CaloWaveSim/" + m_templatefile; TFile *ft = TFile::Open(templatefilename.c_str()); assert(ft && ft->IsOpen()); - h_template = static_cast(ft->Get("hpwaveform")); - - // Determine run number - EventHeader *evtHeader = findNode::getClass(topNode, "EventHeader"); - m_runNumber = evtHeader ? evtHeader->get_RunNumber() : -1; - if (Verbosity() > 0) + ft->GetObject("hpwaveform", h_template); + if (!h_template) { - std::cout << "CaloWaveformSim::InitRun Run Number: " << m_runNumber << std::endl; + std::cout << "Could not get hpwaveform TProfile from " << templatefilename << std::endl; + gSystem->Exit(1); } + h_template->SetDirectory(nullptr); + ft->Close(); // Detector-specific setup - std::string url; if (m_dettype == CaloTowerDefs::CEMC) { m_detector = "CEMC"; @@ -100,7 +108,7 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) m_sampling_fraction = 0.162166; m_nchannels = 1536; } - else // HCALOUT + else if (m_dettype == CaloTowerDefs::HCALOUT) { m_detector = "HCALOUT"; encode_tower = TowerInfoDefs::encode_hcal; @@ -108,7 +116,11 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) m_sampling_fraction = 3.38021e-02; m_nchannels = 1536; } - + else + { + std::cout << PHWHERE << " Invalid detector type " << m_dettype << ", must call set_dettype() first" << std::endl; + exit(1); + } // Gain settings // nobody understands this construct, please keep in mind that other // people have to read this and figure out what it does @@ -128,92 +140,146 @@ int CaloWaveformSim::InitRun(PHCompositeNode *topNode) } // Data energy calibration - if (!m_overrideCalibName) + // First check if the url is overridden in the macro (default is empty) + // Then check if the calibration name is overridden in the macro (default is empty) + if (m_directURL.empty()) { - m_calibName = m_detector + "_calib_ADC_to_ETower"; + if (m_calibName.empty()) + { + m_calibName = m_detector + "_calib_ADC_to_ETower"; + } + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": replacing calib name with " << m_calibName << std::endl; + } + } + m_directURL = CDBInterface::instance()->getUrl(m_calibName); } - if (!m_overrideFieldName) + else { - m_fieldname = m_detector + "_calib_ADC_to_ETower"; + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": using " << m_directURL << " as direct cdb file" << std::endl; + } } - url = m_giveDirectURL ? m_directURL : CDBInterface::instance()->getUrl(m_calibName); - if (!url.empty()) + if (!m_directURL.empty()) { - cdbttree = new CDBTTree(url); + cdbttree = new CDBTTree(m_directURL); } else { - std::cerr << "CaloWaveformSim::InitRun No data calibration for " << m_calibName << std::endl; + std::cout << Name() << ": CaloWaveformSim::InitRun No data calibration for " << m_calibName << std::endl; exit(1); } + // check if the fieldname was overridden in the macro (default is empty), otherwise set it + if (m_fieldname.empty()) + { + m_fieldname = m_detector + "_calib_ADC_to_ETower"; + } + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": replacing fieldname with " << m_fieldname << std::endl; + } + } // MC energy calibration (optional) - if (!m_overrideMCCalibName) + if (m_directURL_MC.empty()) { - m_MC_calibName = m_detector + "_MC_RECALIB"; + if (m_MC_calibName.empty()) + { + m_MC_calibName = m_detector + "_MC_RECALIB"; + } + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": replacing MC calib name with " << m_MC_calibName << std::endl; + } + } + m_directURL_MC = CDBInterface::instance()->getUrl(m_MC_calibName); } - if (!m_overrideMCFieldName) + else { - m_MC_fieldname = m_detector + "_calib_ADC_to_ETower"; + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": using " << m_directURL_MC << " as direct MC cdb file" << std::endl; + } } - url = m_giveDirectURL_MC ? m_directURL_MC : CDBInterface::instance()->getUrl(m_MC_calibName); - if (!url.empty()) + if (!m_directURL_MC.empty()) { - cdbttree_MC = new CDBTTree(url); + cdbttree_MC = new CDBTTree(m_directURL_MC); } else if (Verbosity() > 0) { std::cout << "CaloWaveformSim::InitRun No MC calibration for " << m_MC_calibName << std::endl; } - // Time calibration (data) - if (!m_overrideTimeCalibName) + if (m_MC_fieldname.empty()) { - m_calibName_time = m_detector + "_meanTime"; - } - if (m_giveDirectURL_time) - { - url = m_directURL_time; + m_MC_fieldname = m_detector + "_calib_ADC_to_ETower"; } else { - url = CDBInterface::instance()->getUrl(m_calibName_time); - if (url.empty()) + if (Verbosity() > 2) { - if (m_dotimecalib) - { - std::cerr << "CaloWaveformSim::InitRun No time calibration for " << m_calibName_time << std::endl; - exit(1); - } + std::cout << PHWHERE << Name() << ": using " << m_MC_fieldname << " as MC fieldname" << std::endl; } } + + // Time calibration (data) if (m_dotimecalib) { - cdbttree_time = new CDBTTree(url); - } - if (Verbosity() > 0 && m_dotimecalib) - { - std::cout << "CaloWaveformSim::InitRun Time calibration from " << url << std::endl; - } + if (m_directURL_time.empty()) + { + if (m_calibName_time.empty()) + { + m_calibName_time = m_detector + "_meanTime"; + } + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": replacing calib name with " << m_calibName << std::endl; + } + } + m_directURL_time = CDBInterface::instance()->getUrl(m_calibName_time); + } + else + { + if (Verbosity() > 2) + { + std::cout << PHWHERE << Name() << ": using " << m_directURL_time << " as direct time cdb file" << std::endl; + } + } + if (m_directURL_time.empty()) + { + std::cout << "CaloWaveformSim::InitRun No time calibration for " << m_calibName_time << std::endl; + exit(1); + } - // Time calibration (MC) - if (!m_overrideMCTimeCalibName) - { - m_MC_calibName_time = m_detector + "_MC_meanTime"; - } - if (m_giveDirectURL_MC_time) - { - url = m_directURL_MC_time; - cdbttree_MC_time = new CDBTTree(url); - } - else - { - url = CDBInterface::instance()->getUrl(m_MC_calibName_time); - if (!url.empty()) + cdbttree_time = new CDBTTree(m_directURL_time); + if (Verbosity() > 0 && m_dotimecalib) + { + std::cout << "CaloWaveformSim::InitRun Time calibration from " << m_directURL_time << std::endl; + } + // Time calibration (MC) + if (m_directURL_MC_time.empty()) + { + if (m_MC_calibName_time.empty()) + { + m_MC_calibName_time = m_detector + "_MC_meanTime"; + } + m_directURL_MC_time = CDBInterface::instance()->getUrl(m_MC_calibName_time); + } + if (!m_directURL_MC_time.empty()) { - cdbttree_MC_time = new CDBTTree(url); + cdbttree_MC_time = new CDBTTree(m_directURL_MC_time); } - else if (m_dotimecalib) + else { std::cerr << "CaloWaveformSim::InitRun No MC time calibration for " << m_MC_calibName_time << std::endl; exit(1); @@ -294,8 +360,8 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) exit(1); } - std::map tbt_smear; - + std::map tbt_smear; + std::map tower_photon_count_mean; // loop over hits for (PHG4HitContainer::ConstIterator hititer = hits->getHits().first; hititer != hits->getHits().second; hititer++) @@ -314,6 +380,7 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) float correction = 1.; maphitetaphi(hit, etabin, phibin, correction); unsigned int key = encode_tower(etabin, phibin); + unsigned int tower_index = decode_tower(key); float calibconst = cdbttree->GetFloatValue(key, m_fieldname); float e_vis = hit->get_light_yield(); e_vis *= correction; @@ -321,16 +388,32 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { auto it = tbt_smear.find(key); - if(it != tbt_smear.end()) + if (it != tbt_smear.end()) { e_vis *= it->second; } else { - tbt_smear[key] = 1.0+ gsl_ran_gaussian(m_RandomGenerator,factor_const); + float val = 1.0 + gsl_ran_gaussian(m_RandomGenerator, factor_const); + if (val < 0.0F) + { + val = 0; + } + tbt_smear[key] = val; e_vis *= tbt_smear[key]; } } + + if (m_use_sipm_occupancy && m_dettype == CaloTowerDefs::CEMC) + { + double kPhotonElecYieldVisibleGeV = kPhotoelectronsPerGeV / kSamplingFraction; + const double photon_count_mean = static_cast(e_vis) * kPhotonElecYieldVisibleGeV; + if (photon_count_mean > 0.) + { + tower_photon_count_mean[tower_index] += photon_count_mean; + } + } + float e_dep = e_vis / m_sampling_fraction; float ADC = (calibconst != 0) ? e_dep / calibconst : 0.; ADC *= m_gain; @@ -351,9 +434,9 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) } float t0 = hit->get_t(0) / m_sampletime; - unsigned int tower_index = decode_tower(key); + // here I will add the truth matching part - // for the cell reco, the truth matching info relys on edep not light yield, I will be consistent here :) + // for the cell reco, the truth matching info relies on edep not light yield, I will be consistent here :) TowerInfo *tower = m_CaloWaveformContainer->get_tower_at_channel(tower_index); TowerInfo::EdepMap &edepMap = tower->get_hitEdepMap(); TowerInfo::ShowerEdepMap &showerMap = tower->get_showerEdepMap(); @@ -371,6 +454,38 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) } } + if (m_use_sipm_occupancy && m_dettype == CaloTowerDefs::CEMC) + { + for (const auto &entry : tower_photon_count_mean) + { + const unsigned int tower_index = entry.first; + const double photon_count_mean = entry.second; + + double photon_count = photon_count_mean; + if (m_use_photon_statistics) + { + const double sigma = std::sqrt(std::max(0., photon_count_mean)); + photon_count = std::max(0., photon_count + gsl_ran_gaussian(m_RandomGenerator, sigma)); + } + + if (photon_count_mean <= 0. || photon_count <= 0. || tower_index >= m_waveforms.size()) + { + continue; + } + + const double poisson_param_per_pixel = photon_count / kSiPMEffectivePixel; + const double expected_active_pixels = + kSiPMEffectivePixel * (1. - std::exp(-poisson_param_per_pixel)); + const double occupancy_ratio = + std::max(0., std::min(1., expected_active_pixels / photon_count)); + const double photon_stat_fac = photon_count / photon_count_mean; + for (int isample = 0; isample < m_nsamples; ++isample) + { + m_waveforms.at(tower_index).at(isample) *= occupancy_ratio * photon_stat_fac; + } + } + } + // do noise here and add to waveform if (m_noiseType == NoiseType::NOISE_TREE) @@ -386,32 +501,51 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) } } + std::vector waveform_pedestal_vector(m_nsamples); for (int i = 0; i < m_nchannels; i++) { - std::vector m_waveform_pedestal; - m_waveform_pedestal.resize(m_nsamples); if (m_noiseType == NoiseType::NOISE_TREE) { TowerInfo *pedestal_tower = m_PedestalContainer->get_tower_at_channel(i); + int pedestalsamples = pedestal_tower->get_nsample(); float pedestal_mean = 0; for (int j = 0; j < m_nsamples; j++) { - m_waveform_pedestal.at(j) = (j < m_pedestalsamples) ? pedestal_tower->get_waveform_value(j) : pedestal_tower->get_waveform_value(m_pedestalsamples - 1); - pedestal_mean += m_waveform_pedestal.at(j); + waveform_pedestal_vector.at(j) = (j < pedestalsamples) ? pedestal_tower->get_waveform_value(j) : pedestal_tower->get_waveform_value(pedestalsamples - 1); + pedestal_mean += waveform_pedestal_vector.at(j); + // it should be around 5000+, dead channels have zero's but who knows what else is out there in the future + if (Verbosity() > 1 && pedestal_tower->get_waveform_value(j) < 1000) + { + std::cout << Name() << " channel: " << j << " too small pedestal value for index " << j << ": " << pedestal_tower->get_waveform_value(j) << std::endl; + pedestal_tower->identify(); + } } pedestal_mean /= m_nsamples; for (int j = 0; j < m_nsamples; j++) { - m_waveform_pedestal.at(j) = (m_waveform_pedestal.at(j) - pedestal_mean) * m_pedestal_scale + pedestal_mean; + // only modify the waveform_pedestal_vector if it is > 0, otherwise there is something wrong with the pedestal + // (for dead channels all samples of the waveform are zero). Doing it this way will also catch single zero samples + if (waveform_pedestal_vector.at(j) != 0) + { + waveform_pedestal_vector.at(j) = (waveform_pedestal_vector.at(j) - pedestal_mean) * m_pedestal_scale + pedestal_mean; + } } } for (int j = 0; j < m_nsamples; j++) { if (m_noiseType == NoiseType::NOISE_TREE) { - // TowerInfo *pedestal_tower = m_PedestalContainer->get_tower_at_channel(i); - // m_waveforms.at(i).at(j) += (j < m_pedestalsamples) ? pedestal_tower->get_waveform_value(j) : pedestal_tower->get_waveform_value(m_pedestalsamples - 1); - m_waveforms.at(i).at(j) += m_waveform_pedestal.at(j); + // set samples which have zero pedestal (dead channels in real data) to zero + // they are supposed to be masked out later, so this is just a safeguard in case + // that changes or doesn't work + if (waveform_pedestal_vector.at(j) == 0) + { + m_waveforms.at(i).at(j) = 0; + } + else + { + m_waveforms.at(i).at(j) += waveform_pedestal_vector.at(j); + } } if (m_noiseType == NoiseType::NOISE_GAUSSIAN) { @@ -421,10 +555,9 @@ int CaloWaveformSim::process_event(PHCompositeNode *topNode) { m_waveforms.at(i).at(j) += m_fixpedestal; } - // saturate at 2^14 - 1 - m_waveforms.at(i).at(j) = std::min<__gnu_cxx::__alloc_traits >::value_type>(m_waveforms.at(i).at(j), 16383); - m_waveforms.at(i).at(j) = std::max<__gnu_cxx::__alloc_traits >::value_type>(m_waveforms.at(i).at(j), 0); - + // saturate at 2^14 - 1 and make sure values are >= 0 + auto &sample = m_waveforms.at(i).at(j); + sample = std::clamp(sample, 0.F, 16383.F); m_CaloWaveformContainer->get_tower_at_channel(i)->set_waveform_value(j, m_waveforms.at(i).at(j)); } } @@ -494,13 +627,6 @@ void CaloWaveformSim::maphitetaphi(PHG4Hit *g4hit, unsigned short &etabin, unsig } } -//____________________________________________________________________________.. -int CaloWaveformSim::End(PHCompositeNode * /*topNode*/) -{ - std::cout << "CaloWaveformSim::End(PHCompositeNode *topNode) This is the End..." << std::endl; - return Fun4AllReturnCodes::EVENT_OK; -} - void CaloWaveformSim::CreateNodeTree(PHCompositeNode *topNode) { PHNodeIterator topNodeItr(topNode); @@ -545,8 +671,12 @@ void CaloWaveformSim::CreateNodeTree(PHCompositeNode *topNode) DetNode = new PHCompositeNode(DetectorNodeName); dstNode->addNode(DetNode); } - m_CaloWaveformContainer = new TowerInfoContainerSimv2(DetectorEnum); - + m_CaloWaveformContainer = new TowerInfoContainerSimv3(DetectorEnum); + for (size_t index = 0; index < m_CaloWaveformContainer->size(); index++) + { + TowerInfo *twr = m_CaloWaveformContainer->get_tower_at_channel(index); + twr->set_nsample(m_nsamples); + } PHIODataNode *newTowerNode = new PHIODataNode(m_CaloWaveformContainer, "WAVEFORM_" + m_detector, "PHObject"); DetNode->addNode(newTowerNode); } diff --git a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h index 80290a5321..4302003e86 100644 --- a/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h +++ b/simulation/g4simulation/g4waveformsim/CaloWaveformSim.h @@ -10,12 +10,16 @@ #ifndef G4WAVEFORMSIM_CALOWAVEFORMSIM_H #define G4WAVEFORMSIM_CALOWAVEFORMSIM_H +#include + #include #include -#include + #include -#include + #include + +#include #include #include @@ -24,7 +28,6 @@ class TProfile; class PHG4Hit; class PHG4CylinderCellGeom_Spacalv1; class PHG4CylinderGeom_Spacalv3; -class TTree; class CDBTTree; class TowerInfoContainer; @@ -36,7 +39,6 @@ class CaloWaveformSim : public SubsysReco int InitRun(PHCompositeNode *topNode) override; int process_event(PHCompositeNode *topNode) override; - int End(PHCompositeNode *topNode) override; // Detector configuration void set_detector_type(CaloTowerDefs::DetectorSystem dettype) { m_dettype = dettype; } @@ -46,74 +48,66 @@ class CaloWaveformSim : public SubsysReco void set_fieldname(const std::string &fieldname) { m_fieldname = fieldname; - m_overrideFieldName = true; } void set_calibName(const std::string &calibName) { m_calibName = calibName; - m_overrideCalibName = true; } void set_directURL_calib(const std::string &url) { - m_giveDirectURL = true; m_directURL = url; } - void set_overrideCalibName(bool overrideCalib) { m_overrideCalibName = overrideCalib; } - void set_overrideFieldName(bool overrideField) { m_overrideFieldName = overrideField; } // Calibration settings (MC energy) void set_MC_fieldname(const std::string &MC_fieldname) { m_MC_fieldname = MC_fieldname; - m_overrideMCFieldName = true; } void set_MC_calibName(const std::string &MC_calibName) { m_MC_calibName = MC_calibName; - m_overrideMCCalibName = true; } void set_directURL_MCcalib(const std::string &url) { - m_giveDirectURL_MC = true; m_directURL_MC = url; } - void set_overrideMCFieldName(bool overrideField) { m_overrideMCFieldName = overrideField; } - void set_overrideMCCalibName(bool overrideCalib) { m_overrideMCCalibName = overrideCalib; } + + void set_use_sipm_occupancy(bool use_sipm_occupancy = true) + { + m_use_sipm_occupancy = use_sipm_occupancy; + } + + void set_use_photon_statistics(bool state = true) + { + m_use_photon_statistics = state; + } // Time calibration (data) void set_fieldname_time(const std::string &fieldname_time) { m_fieldname_time = fieldname_time; - m_overrideTimeFieldName = true; } void set_calibName_time(const std::string &calibName_time) { m_calibName_time = calibName_time; - m_overrideTimeCalibName = true; } void set_directURL_timecalib(const std::string &url) { - m_giveDirectURL_time = true; m_directURL_time = url; } void set_dotimecalib(bool dotimecalib) { m_dotimecalib = dotimecalib; } - void set_overrideTimeFieldName(bool overrideField) { m_overrideTimeFieldName = overrideField; } - void set_overrideTimeCalibName(bool overrideCalib) { m_overrideTimeCalibName = overrideCalib; } // Time calibration (MC) void set_MC_fieldname_time(const std::string &MC_fieldname_time) { m_MC_fieldname_time = MC_fieldname_time; - m_overrideMCTimeFieldName = true; } void set_MC_calibName_time(const std::string &MC_calibName_time) { m_MC_calibName_time = MC_calibName_time; - m_overrideMCTimeCalibName = true; } void set_directURL_MCtimecalib(const std::string &url) { - m_giveDirectURL_MC_time = true; m_directURL_MC_time = url; } void set_smear_const(float val) @@ -121,13 +115,23 @@ class CaloWaveformSim : public SubsysReco m_smear_const = true; factor_const = val; } - void set_overrideMCTimeFieldName(bool overrideField) { m_overrideMCTimeFieldName = overrideField; } - void set_overrideMCTimeCalibName(bool overrideCalib) { m_overrideMCTimeCalibName = overrideCalib; } + + void set_kSamplingFraction(double val) + { + kSamplingFraction = val; + } + void set_kPhotoelectronsPerGeV(double val) + { + kPhotoelectronsPerGeV = val; + } + void set_kSiPMEffectivePixel(double val) + { + kSiPMEffectivePixel = val; + } // Waveform template & sampling void set_templatefile(const std::string &templatefile) { m_templatefile = templatefile; } void set_nsamples(int nsamples) { m_nsamples = nsamples; } - void set_pedestalsamples(int pedestalsamples) { m_pedestalsamples = pedestalsamples; } void set_sampletime(float sampletime) { m_sampletime = sampletime; } void set_nchannels(int nchannels) { m_nchannels = nchannels; } void set_sampling_fraction(float fraction) { m_sampling_fraction = fraction; } @@ -155,54 +159,65 @@ class CaloWaveformSim : public SubsysReco LightCollectionModel &get_light_collection_model() { return light_collection_model; } private: - CaloTowerDefs::DetectorSystem m_dettype{CaloTowerDefs::CEMC}; - std::string m_detector{"CEMC"}; + void CreateNodeTree(PHCompositeNode *topNode); + void maphitetaphi(PHG4Hit *g4hit, + unsigned short &etabin, + unsigned short &phibin, + float &correction); + double template_function(double *x, double *par); + + // function pointers for use different decoders for hcals and cemc + unsigned int (*encode_tower)(unsigned int, unsigned int){TowerInfoDefs::encode_emcal}; + unsigned int (*decode_tower)(unsigned int){TowerInfoDefs::decode_emcal}; + + // containers + TowerInfoContainer *m_CaloWaveformContainer{nullptr}; + TowerInfoContainer *m_PedestalContainer{nullptr}; + + CDBTTree *cdbttree{nullptr}; + CDBTTree *cdbttree_MC{nullptr}; + CDBTTree *cdbttree_time{nullptr}; + CDBTTree *cdbttree_MC_time{nullptr}; + TProfile *h_template{nullptr}; + + gsl_rng *m_RandomGenerator{nullptr}; + PHG4CylinderCellGeom_Spacalv1 *geo{nullptr}; + const PHG4CylinderGeom_Spacalv3 *layergeom{nullptr}; + + CaloTowerDefs::DetectorSystem m_dettype{CaloTowerDefs::DETECTOR_INVALID}; + + std::string m_detector; // Data energy calibration - std::string m_fieldname{"Femc_datadriven_qm1_correction"}; - std::string m_calibName{"cemc_pi0_twrSlope_v1"}; - bool m_overrideCalibName{false}; - bool m_overrideFieldName{false}; - bool m_giveDirectURL{false}; - std::string m_directURL{""}; + std::string m_fieldname; + std::string m_calibName; + std::string m_directURL; + // MC energy calibration - std::string m_MC_fieldname{"Femc_datadriven_qm1_correction"}; - std::string m_MC_calibName{"cemc_pi0_twrSlope_v1"}; - bool m_overrideMCFieldName{false}; - bool m_overrideMCCalibName{false}; - bool m_giveDirectURL_MC{false}; - std::string m_directURL_MC{""}; + std::string m_MC_fieldname; + std::string m_MC_calibName; + std::string m_directURL_MC; bool m_smear_const{false}; float factor_const{0.}; // Data time calibration std::string m_fieldname_time{"time"}; - std::string m_calibName_time{"CEMC_meanTime"}; - bool m_overrideTimeFieldName{false}; - bool m_overrideTimeCalibName{false}; - bool m_dotimecalib{true}; - bool m_giveDirectURL_time{false}; - std::string m_directURL_time{""}; + std::string m_calibName_time; + std::string m_directURL_time; // MC time calibration std::string m_MC_fieldname_time{"time"}; - std::string m_MC_calibName_time{"CEMC_meanTime"}; - bool m_overrideMCTimeFieldName{false}; - bool m_overrideMCTimeCalibName{false}; - bool m_giveDirectURL_MC_time{false}; - std::string m_directURL_MC_time{""}; + std::string m_MC_calibName_time; + std::string m_directURL_MC_time; + + bool m_dotimecalib{true}; // Waveform settings std::string m_templatefile{"waveformtemptempohcalcosmic.root"}; - int m_nsamples{31}; - int m_pedestalsamples{31}; + int m_nsamples{12}; // number of samples for calos in our default data taking configuration float m_sampletime{50. / 3.}; - int m_nchannels{24576}; - float m_sampling_fraction{1.0f}; - - // containers - TowerInfoContainer *m_CaloWaveformContainer{nullptr}; - TowerInfoContainer *m_PedestalContainer{nullptr}; + int m_nchannels{-1}; + float m_sampling_fraction{std::numeric_limits::quiet_NaN()}; // Shaping & noise int m_fixpedestal{1500}; @@ -214,28 +229,17 @@ class CaloWaveformSim : public SubsysReco float m_peakpos{6.}; float m_pedestal_scale{1.}; - gsl_rng *m_RandomGenerator{nullptr}; - PHG4CylinderCellGeom_Spacalv1 *geo{nullptr}; - const PHG4CylinderGeom_Spacalv3 *layergeom{nullptr}; std::vector> m_waveforms; - int m_runNumber{0}; - - unsigned int (*encode_tower)(unsigned int, unsigned int){TowerInfoDefs::encode_emcal}; - unsigned int (*decode_tower)(unsigned int){TowerInfoDefs::decode_emcal}; - CDBTTree *cdbttree{nullptr}, *cdbttree_MC{nullptr}; - CDBTTree *cdbttree_time{nullptr}, *cdbttree_MC_time{nullptr}; - TProfile *h_template{nullptr}; LightCollectionModel light_collection_model; - NoiseType m_noiseType{NOISE_TREE}; + bool m_use_photon_statistics{false}; + bool m_use_sipm_occupancy{false}; + double kSamplingFraction = 2e-2; + double kPhotoelectronsPerGeV = 500.; + double kSiPMEffectivePixel = 40000 * 4.; - void CreateNodeTree(PHCompositeNode *topNode); - void maphitetaphi(PHG4Hit *g4hit, - unsigned short &etabin, - unsigned short &phibin, - float &correction); - double template_function(double *x, double *par); + NoiseType m_noiseType{NOISE_TREE}; }; #endif // G4WAVEFORMSIM_CALOWAVEFORMSIM_H diff --git a/simulation/g4simulation/g4waveformsim/Makefile.am b/simulation/g4simulation/g4waveformsim/Makefile.am index bc96947bdc..744aec7ea8 100644 --- a/simulation/g4simulation/g4waveformsim/Makefile.am +++ b/simulation/g4simulation/g4waveformsim/Makefile.am @@ -2,7 +2,7 @@ AUTOMAKE_OPTIONS = foreign AM_CPPFLAGS = \ -I$(includedir) \ - -I$(OFFLINE_MAIN)/include \ + -isystem$(OFFLINE_MAIN)/include \ -isystem$(ROOTSYS)/include AM_LDFLAGS = \ @@ -20,15 +20,12 @@ libCaloWaveformSim_la_SOURCES = \ CaloWaveformSim.cc libCaloWaveformSim_la_LIBADD = \ - -lphool \ - -lSubsysReco \ -lcalo_io \ - -lfun4all \ + -lcdbobjects \ -lg4detectors \ -lg4detectors_io \ - -lcalo_io \ - -lcdbobjects \ - -lphg4hit + -lphg4hit \ + -lSubsysReco BUILT_SOURCES = testexternals.cc