diff --git a/.github/workflows/reports.yml b/.github/workflows/reports.yml index 9045b8b8c8031..affd78216b50e 100644 --- a/.github/workflows/reports.yml +++ b/.github/workflows/reports.yml @@ -18,10 +18,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.7 - uses: actions/setup-python@v1 + - name: Set up Python 3.10 + uses: actions/setup-python@v5 with: - python-version: 3.7 + python-version: '3.10' - uses: actions/cache@v2 name: Configure pip caching with: @@ -81,7 +81,7 @@ jobs: run: | set -x mkdir -p doc/data - # We create new files once per month, mostly so that + # We create new files once per month, mostly so that # we can keep the query results small. It does not # matter if we get results from different months, # as what matters is how we merge them. @@ -96,7 +96,6 @@ jobs: # being published LAST_RELEASE="${{ github.event.inputs.LAST_RELEASE_DATE }}" MERGED_AFTER=${LAST_RELEASE:-$(date -v -14d +%Y-%m-%d)} - # Here we convert all the json files to per subsystem # logs, using the MERGED_AFTER date to further filter them. # Notice we can have duplicates in each file, @@ -106,7 +105,7 @@ jobs: for f in doc/data/*_prs.json; do for x in Algorithm Analysis Common DataFormats Detectors EventVisualisation Examples Framework Generators Steer Testing Utilities; do cat $f | jq ".repository.pullRequests.edges[].node | select(.files.edges[].node.path | test(\"$x\")) | del(.files) | select(.state == \"MERGED\" and .mergedAt >= \"${MERGED_AFTER}\")" > /tmp/${x}_prs.json - if [ ! X`jq -s length /tmp/${x}_prs.json` = X0 ]; then + if [ ! X`jq -s length /tmp/${x}_prs.json` = X0 ]; then cat /tmp/${x}_prs.json | jq -r '"- [#\(.number)](https://github.com/AliceO2Group/AliceO2/pull/\(.number)) \(.mergedAt | split("T")[0]): \(.title) by [@\(.author.login)](https://github.com/\(.author.login))"' | sort -u >> /tmp/${x}_prs.md fi done diff --git a/.gitignore b/.gitignore index a489daad80115..6db76441528d9 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ compile_commands.json .vscode .ycm_extra_conf.py Session.vim +CMakeLists.txt.user # Datafiles gphysi.dat diff --git a/CCDB/include/CCDB/BasicCCDBManager.h b/CCDB/include/CCDB/BasicCCDBManager.h index 2d54304837d54..7994c60448121 100644 --- a/CCDB/include/CCDB/BasicCCDBManager.h +++ b/CCDB/include/CCDB/BasicCCDBManager.h @@ -180,13 +180,11 @@ class CCDBManagerInstance void setFatalWhenNull(bool b) { mFatalWhenNull = b; } /// A convenience function for MC to fetch - /// valid start and end timestamps given an ALICE run number. + /// valid start and end timestamps for recorded TF data given an ALICE run number. + /// In absence of STF/ETF fields in the RCT with fall back to CTP SOX/EOX then to + /// ECS SOR/EOR. /// On error it fatals (if fatal == true) or else returns the pair -1, -1. std::pair getRunDuration(int runnumber, bool fatal = true); - - /// A convenience function for MC to fetch - /// valid start and end timestamps given an ALICE run number. - /// On error it fatals (if fatal == true) or else returns the pair -1, -1. static std::pair getRunDuration(o2::ccdb::CcdbApi const& api, int runnumber, bool fatal = true); std::string getSummaryString() const; diff --git a/CCDB/include/CCDB/CCDBDownloader.h b/CCDB/include/CCDB/CCDBDownloader.h index 17b65deb06dc2..e53421dcc26fc 100644 --- a/CCDB/include/CCDB/CCDBDownloader.h +++ b/CCDB/include/CCDB/CCDBDownloader.h @@ -52,6 +52,7 @@ typedef struct DownloaderRequestData { HeaderObjectPair_t hoPair; std::map* headers; std::string userAgent; + curl_slist* optionsList; std::function localContentCallback; } DownloaderRequestData; @@ -296,6 +297,7 @@ class CCDBDownloader int hostInd; int locInd; DownloaderRequestData* requestData; + curl_slist** options; } PerformData; #endif @@ -421,6 +423,6 @@ typedef struct DataForClosingSocket { curl_socket_t socket; } DataForClosingSocket; -} // namespace o2 +} // namespace o2::ccdb #endif // O2_CCDB_CCDBDOWNLOADER_H diff --git a/CCDB/src/BasicCCDBManager.cxx b/CCDB/src/BasicCCDBManager.cxx index 390a993c0cb06..0fe72c88fcb46 100644 --- a/CCDB/src/BasicCCDBManager.cxx +++ b/CCDB/src/BasicCCDBManager.cxx @@ -37,22 +37,29 @@ std::pair CCDBManagerInstance::getRunDuration(o2::ccdb::CcdbAp auto response = api.retrieveHeaders("RCT/Info/RunInformation", std::map(), runnumber); if (response.size() != 0) { std::string report{}; - auto strt = response.find("SOX"); + auto strt = response.find("STF"); + auto stop = response.find("ETF"); long valStrt = (strt == response.end()) ? -1L : boost::lexical_cast(strt->second); - if (valStrt < 1) { - report += fmt::format(" Missing/invalid SOX -> use SOR"); - strt = response.find("SOR"); - valStrt = (strt == response.end()) ? -1L : boost::lexical_cast(strt->second); - } - auto stop = response.find("EOX"); long valStop = (stop == response.end()) ? -1L : boost::lexical_cast(stop->second); - if (valStop < 1) { - report += fmt::format(" | Missing/invalid EOX -> use EOR"); - stop = response.find("EOR"); + if (valStrt < 0 || valStop < 0) { + report += "Missing STF/EFT -> use SOX/EOX;"; + strt = response.find("SOX"); + valStrt = (strt == response.end()) ? -1L : boost::lexical_cast(strt->second); + if (valStrt < 1) { + report += fmt::format(" Missing/invalid SOX -> use SOR"); + strt = response.find("SOR"); + valStrt = (strt == response.end()) ? -1L : boost::lexical_cast(strt->second); + } + stop = response.find("EOX"); valStop = (stop == response.end()) ? -1L : boost::lexical_cast(stop->second); - } - if (!report.empty()) { - LOGP(warn, "{}", report); + if (valStop < 1) { + report += fmt::format(" | Missing/invalid EOX -> use EOR"); + stop = response.find("EOR"); + valStop = (stop == response.end()) ? -1L : boost::lexical_cast(stop->second); + } + if (!report.empty()) { + LOGP(warn, "{}", report); + } } if (valStrt > 0 && valStop >= valStrt) { return std::make_pair(valStrt, valStop); diff --git a/CCDB/src/CCDBDownloader.cxx b/CCDB/src/CCDBDownloader.cxx index bd2bf22d0add9..8d13368688cb7 100644 --- a/CCDB/src/CCDBDownloader.cxx +++ b/CCDB/src/CCDBDownloader.cxx @@ -535,8 +535,10 @@ void CCDBDownloader::transferFinished(CURL* easy_handle, CURLcode curlCode) } } --(*performData->requestsLeft); + curl_slist_free_all(*performData->options); delete requestData; delete performData->codeDestination; + curl_easy_cleanup(easy_handle); } } break; } @@ -681,6 +683,7 @@ void CCDBDownloader::asynchSchedule(CURL* handle, size_t* requestCounter) curl_easy_getinfo(handle, CURLINFO_PRIVATE, &requestData); headerMap = &(requestData->hoPair.header); hostsPool = &(requestData->hosts); + auto* options = &(requestData->optionsList); // Prepare temporary data about transfer auto* data = new CCDBDownloader::PerformData(); // Freed in transferFinished @@ -692,6 +695,7 @@ void CCDBDownloader::asynchSchedule(CURL* handle, size_t* requestCounter) data->hostInd = 0; data->locInd = 0; data->requestData = requestData; + data->options = options; // Prepare handle and schedule download setHandleOptions(handle, data); @@ -719,4 +723,4 @@ std::string CCDBDownloader::prepareLogMessage(std::string host_url, std::string return fmt::format("CcdbDownloader finished transfer {}{}{} for {} (agent_id: {}) with http code: {}", host_url, (host_url.back() == '/') ? "" : "/", upath, (ts < 0) ? getCurrentTimestamp() : ts, userAgent, httpCode); } -} // namespace o2 +} // namespace o2::ccdb diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index 46d95bae477d4..4c4aa6ca74a80 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -1656,6 +1656,7 @@ void CcdbApi::scheduleDownload(RequestContext& requestContext, size_t* requestCo data->timestamp = requestContext.timestamp; data->localContentCallback = localContentCallback; data->userAgent = mUniqueAgentID; + data->optionsList = options_list; curl_easy_setopt(curl_handle, CURLOPT_URL, fullUrl.c_str()); initCurlOptionsForRetrieve(curl_handle, (void*)(&data->hoPair), writeCallback, false); diff --git a/CCDB/test/testCcdbApiDownloader.cxx b/CCDB/test/testCcdbApiDownloader.cxx index 68c8333f46ffa..264eff8fdb848 100644 --- a/CCDB/test/testCcdbApiDownloader.cxx +++ b/CCDB/test/testCcdbApiDownloader.cxx @@ -23,7 +23,6 @@ #include #include -#include #include #include @@ -129,7 +128,7 @@ std::vector prepareAsyncHandles(size_t num, std::vectorhoPair.object = dest; - data->hosts.push_back("http://ccdb-test.cern.ch:8080"); + data->hosts.emplace_back("http://ccdb-test.cern.ch:8080"); data->path = "Analysis/ALICE3/Centrality"; data->timestamp = 1646729604010; data->localContentCallback = nullptr; @@ -164,15 +163,20 @@ BOOST_AUTO_TEST_CASE(asynch_schedule_test) } while (transfersLeft > 0) { - downloader.runLoop(0); + downloader.runLoop(false); } for (int i = 0; i < TRANSFERS; i++) { - long httpCode; - curl_easy_getinfo(handles[i], CURLINFO_HTTP_CODE, &httpCode); - BOOST_CHECK(httpCode == 200); - BOOST_CHECK(dests[i]->size() != 0); - curl_easy_cleanup(handles[i]); + // I would claim that accessing the handles after they are complete + // is actually not supported by the current API, because it was + // previously relying on leaking the handles. Disabling the whole + // thing until we verify that's actually the case. + // + // long httpCode; + // curl_easy_getinfo(handles[i], CURLINFO_HTTP_CODE, &httpCode); + // BOOST_CHECK_EQUAL(httpCode, 200); + // BOOST_CHECK_NE(dests[i]->size(), 0); + // curl_easy_cleanup(handles[i]); delete dests[i]; } curl_global_cleanup(); @@ -191,13 +195,11 @@ BOOST_AUTO_TEST_CASE(perform_test) CURLcode curlCode = downloader.perform(handle); - BOOST_CHECK(curlCode == CURLE_OK); - std::cout << "CURL code: " << curlCode << "\n"; + BOOST_CHECK_EQUAL(curlCode, CURLE_OK); long httpCode; curl_easy_getinfo(handle, CURLINFO_HTTP_CODE, &httpCode); - BOOST_CHECK(httpCode == 200); - std::cout << "HTTP code: " << httpCode << "\n"; + BOOST_CHECK_EQUAL(httpCode, 200); curl_easy_cleanup(handle); curl_global_cleanup(); @@ -220,19 +222,13 @@ BOOST_AUTO_TEST_CASE(blocking_batch_test) auto curlCodes = downloader.batchBlockingPerform(handleVector); for (CURLcode code : curlCodes) { - BOOST_CHECK(code == CURLE_OK); - if (code != CURLE_OK) { - std::cout << "CURL Code: " << code << "\n"; - } + BOOST_CHECK_EQUAL(code, CURLE_OK); } for (CURL* handle : handleVector) { long httpCode; curl_easy_getinfo(handle, CURLINFO_HTTP_CODE, &httpCode); - BOOST_CHECK(httpCode == 200); - if (httpCode != 200) { - std::cout << "HTTP Code: " << httpCode << "\n"; - } + BOOST_CHECK_EQUAL(httpCode, 200); curl_easy_cleanup(handle); } @@ -261,19 +257,13 @@ BOOST_AUTO_TEST_CASE(test_with_break) auto curlCodes = downloader.batchBlockingPerform(handleVector); for (CURLcode code : curlCodes) { - BOOST_CHECK(code == CURLE_OK); - if (code != CURLE_OK) { - std::cout << "CURL Code: " << code << "\n"; - } + BOOST_CHECK_EQUAL(code, CURLE_OK); } for (CURL* handle : handleVector) { long httpCode; curl_easy_getinfo(handle, CURLINFO_HTTP_CODE, &httpCode); - BOOST_CHECK(httpCode == 200); - if (httpCode != 200) { - std::cout << "HTTP Code: " << httpCode << "\n"; - } + BOOST_CHECK_EQUAL(httpCode, 200); curl_easy_cleanup(handle); } @@ -292,19 +282,13 @@ BOOST_AUTO_TEST_CASE(test_with_break) auto curlCodes2 = downloader.batchBlockingPerform(handleVector2); for (CURLcode code : curlCodes2) { - BOOST_CHECK(code == CURLE_OK); - if (code != CURLE_OK) { - std::cout << "CURL Code: " << code << "\n"; - } + BOOST_CHECK_EQUAL(code, CURLE_OK); } for (CURL* handle : handleVector2) { long httpCode; curl_easy_getinfo(handle, CURLINFO_HTTP_CODE, &httpCode); - BOOST_CHECK(httpCode == 200); - if (httpCode != 200) { - std::cout << "HTTP Code: " << httpCode << "\n"; - } + BOOST_CHECK_EQUAL(httpCode, 200); curl_easy_cleanup(handle); } @@ -357,18 +341,18 @@ BOOST_AUTO_TEST_CASE(external_loop_test) CURLcode curlCode = downloader->perform(handle); - BOOST_CHECK(curlCode == CURLE_OK); + BOOST_CHECK_EQUAL(curlCode, CURLE_OK); long httpCode; curl_easy_getinfo(handle, CURLINFO_HTTP_CODE, &httpCode); - BOOST_CHECK(httpCode == 200); + BOOST_CHECK_EQUAL(httpCode, 200); curl_easy_cleanup(handle); curl_global_cleanup(); // Check if test timer and external loop are still alive - BOOST_CHECK(uv_is_active((uv_handle_t*)testTimer) != 0); - BOOST_CHECK(uv_loop_alive(uvLoop) != 0); + BOOST_CHECK_NE(uv_is_active((uv_handle_t*)testTimer), 0); + BOOST_CHECK_NE(uv_loop_alive(uvLoop), 0); // Downloader must be closed before uv_loop. // The reason for that are the uv_poll handles attached to the curl multi handle. @@ -384,11 +368,11 @@ BOOST_AUTO_TEST_CASE(external_loop_test) BOOST_AUTO_TEST_CASE(trim_host_url_test) { CCDBDownloader downloader; - BOOST_CHECK(downloader.trimHostUrl("http://localhost:8080") == "http://localhost:8080"); - BOOST_CHECK(downloader.trimHostUrl("http://localhost") == "http://localhost"); - BOOST_CHECK(downloader.trimHostUrl("http://localhost:8080/some/path") == "http://localhost:8080"); - BOOST_CHECK(downloader.trimHostUrl("http://localhost/some/path") == "http://localhost"); - BOOST_CHECK(downloader.trimHostUrl("http://localhost:8080/Task/Detector/1?HTTPOnly=true") == "http://localhost:8080"); + BOOST_CHECK_EQUAL(downloader.trimHostUrl("http://localhost:8080"), "http://localhost:8080"); + BOOST_CHECK_EQUAL(downloader.trimHostUrl("http://localhost"), "http://localhost"); + BOOST_CHECK_EQUAL(downloader.trimHostUrl("http://localhost:8080/some/path"), "http://localhost:8080"); + BOOST_CHECK_EQUAL(downloader.trimHostUrl("http://localhost/some/path"), "http://localhost"); + BOOST_CHECK_EQUAL(downloader.trimHostUrl("http://localhost:8080/Task/Detector/1?HTTPOnly=true"), "http://localhost:8080"); } } // namespace ccdb diff --git a/CMakeLists.txt b/CMakeLists.txt index bf1d83fbb6644..d28f191021fdf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ include(CTest) set(ALIGPU_BUILD_TYPE "O2") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +string(TOUPPER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_UPPER) set_property(GLOBAL PROPERTY REPORT_UNDEFINED_PROPERTIES) cmake_host_system_information(RESULT _totalmem QUERY TOTAL_PHYSICAL_MEMORY) @@ -37,13 +38,10 @@ set_property(GLOBAL PROPERTY JOB_POOLS analysis=${ANALYSIS_COMPILE_POOL}) include(O2BuildSanityChecks) o2_build_sanity_checks() -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED TRUE) -find_package(ONNXRuntime::ONNXRuntime CONFIG) -if (ONNXRuntime::ONNXRuntime_FOUND) - add_definitions(-DZDC_FASTSIM_ONNX) -endif() +include(dependencies/FindONNXRuntime.cmake) include(O2CheckCXXFeatures) o2_check_cxx_features() diff --git a/CODEOWNERS b/CODEOWNERS index bd60d671f75a2..144380ff96161 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -40,7 +40,7 @@ /DataFormats/Detectors/Passive @sawenzel @benedikt-voelkel /DataFormats/Detectors/TOF @noferini /DataFormats/Detectors/TPC @davidrohr @wiechula @shahor02 -/DataFormats/Detectors/TRD @f3sch @bazinski @martenole +/DataFormats/Detectors/TRD @f3sch @bazinski @martenole @wille10 /DataFormats/Detectors/Upgrades @mconcas /DataFormats/Detectors/Upgrades/ITS3 @fgrosa @arossi81 /DataFormats/Detectors/ZDC @coppedis @@ -49,7 +49,7 @@ #/DataFormats/Legacy #/DataFormats/MemoryResources /DataFormats/Parameters @shahor02 -/DataFormats/QualityControl @knopers8 @Barthelemy @chiarazampolli +/DataFormats/QualityControl @knopers8 @Barthelemy @justonedev1 @chiarazampolli /DataFormats/Reconstruction @shahor02 #/DataFormats/TimeFrame /DataFormats/common @shahor02 @@ -71,7 +71,7 @@ /Detectors/Passive @sawenzel @benedikt-voelkel /Detectors/TOF @noferini /Detectors/TPC @davidrohr @wiechula @shahor02 -/Detectors/TRD @f3sch @bazinski @martenole +/Detectors/TRD @f3sch @bazinski @martenole @wille10 /Detectors/Upgrades @mconcas /Detectors/Upgrades/ITS3 @fgrosa @arossi81 @mconcas @f3sch /Detectors/ZDC @coppedis @@ -121,8 +121,8 @@ /Testing /Utilities @AliceO2Group/framework-admins -/Utilities/Mergers @Barthelemy @knopers8 -/Utilities/DataSampling @Barthelemy @knopers8 +/Utilities/Mergers @Barthelemy @knopers8 @justonedev1 +/Utilities/DataSampling @Barthelemy @knopers8 @justonedev1 #/Utilities/DataCompression #/Utilities/DataFlow #/Utilities/MCStepLogger diff --git a/Common/DCAFitter/include/DCAFitter/DCAFitterN.h b/Common/DCAFitter/include/DCAFitter/DCAFitterN.h index c7f6631de5abe..548cb7321e104 100644 --- a/Common/DCAFitter/include/DCAFitter/DCAFitterN.h +++ b/Common/DCAFitter/include/DCAFitter/DCAFitterN.h @@ -188,6 +188,7 @@ class DCAFitterN void setMaxSnp(float s) { mMaxSnp = s; } void setMaxStep(float s) { mMaxStep = s; } void setMinXSeed(float x) { mMinXSeed = x; } + void setCollinear(bool isCollinear) { mIsCollinear = isCollinear; } int getNCandidates() const { return mCurHyp; } int getMaxIter() const { return mMaxIter; } @@ -324,6 +325,7 @@ class DCAFitterN bool mPropagateToPCA = true; // create tracks version propagated to PCA bool mUsePropagator = false; // use propagator with 3D B-field, set automatically if material correction is requested bool mRefitWithMatCorr = false; // when doing propagateTracksToVertex, propagate tracks to V0 with material corrections and rerun minimization again + bool mIsCollinear = false; // use collinear fits when there 2 crossing points o2::base::Propagator::MatCorrType mMatCorr = o2::base::Propagator::MatCorrType::USEMatCorrNONE; // material corrections type int mMaxIter = 20; // max number of iterations float mBz = 0; // bz field, to be set by user @@ -339,7 +341,7 @@ class DCAFitterN float mMaxStep = 2.0; // Max step for propagation with Propagator int mFitterID = 0; // locat fitter ID (mostly for debugging) size_t mCallID = 0; - ClassDefNV(DCAFitterN, 1); + ClassDefNV(DCAFitterN, 2); }; ///_________________________________________________________________________ @@ -355,8 +357,8 @@ int DCAFitterN::process(const Tr&... args) for (int i = 0; i < N; i++) { mTrAux[i].set(*mOrigTrPtr[i], mBz); } - if (!mCrossings.set(mTrAux[0], *mOrigTrPtr[0], mTrAux[1], *mOrigTrPtr[1], mMaxDXYIni)) { // even for N>2 it should be enough to test just 1 loop - return 0; // no crossing + if (!mCrossings.set(mTrAux[0], *mOrigTrPtr[0], mTrAux[1], *mOrigTrPtr[1], mMaxDXYIni, mIsCollinear)) { // even for N>2 it should be enough to test just 1 loop + return 0; // no crossing } for (int ih = 0; ih < MAXHYP; ih++) { mPropFailed[ih] = false; diff --git a/Common/DCAFitter/include/DCAFitter/HelixHelper.h b/Common/DCAFitter/include/DCAFitter/HelixHelper.h index 87575367e1af5..39dee1d399848 100644 --- a/Common/DCAFitter/include/DCAFitter/HelixHelper.h +++ b/Common/DCAFitter/include/DCAFitter/HelixHelper.h @@ -59,7 +59,7 @@ struct CrossInfo { float yDCA[2] = {}; int nDCA = 0; - int circlesCrossInfo(const TrackAuxPar& trax0, const TrackAuxPar& trax1, float maxDistXY = MaxDistXYDef) + int circlesCrossInfo(const TrackAuxPar& trax0, const TrackAuxPar& trax1, float maxDistXY = MaxDistXYDef, bool isCollinear = false) { const auto& trcA = trax0.rC > trax1.rC ? trax0 : trax1; // designate the largest circle as A const auto& trcB = trax0.rC > trax1.rC ? trax1 : trax0; @@ -74,14 +74,24 @@ struct CrossInfo { if (dist - rsum > maxDistXY) { // too large distance return nDCA; } - notTouchingXY(dist, xDist, yDist, trcA, trcB.rC); + notTouchingXY(dist, xDist, yDist, trcA, trcB.rC, isCollinear); } else if (dist + trcB.rC < trcA.rC) { // the small circle is nestled into large one w/o touching // select the point of closest approach of 2 circles - notTouchingXY(dist, xDist, yDist, trcA, -trcB.rC); + notTouchingXY(dist, xDist, yDist, trcA, -trcB.rC, isCollinear); } else { // 2 intersection points - // to simplify calculations, we move to new frame x->x+Xc0, y->y+Yc0, so that - // the 1st one is centered in origin - if (std::abs(xDist) < std::abs(yDist)) { + if (isCollinear) { + /// collinear tracks, e.g. electrons from photon conversion + /// if there are 2 crossings of the circle it is better to take + /// a weighted average of the crossing points as a radius + float r2r = trcA.rC + trcB.rC; + float r1_r = trcA.rC / r2r; + float r2_r = trcB.rC / r2r; + xDCA[0] = r2_r * trcA.xC + r1_r * trcB.xC; + yDCA[0] = r2_r * trcA.yC + r1_r * trcB.yC; + nDCA = 1; + } else if (std::abs(xDist) < std::abs(yDist)) { + // to simplify calculations, we move to new frame x->x+Xc0, y->y+Yc0, so that + // the 1st one is centered in origin float a = (trcA.rC * trcA.rC - trcB.rC * trcB.rC + dist2) / (2. * yDist), b = -xDist / yDist, ab = a * b, bb = b * b; float det = ab * ab - (1. + bb) * (a * a - trcA.rC * trcA.rC); if (det > 0.) { @@ -116,18 +126,28 @@ struct CrossInfo { return nDCA; } - void notTouchingXY(float dist, float xDist, float yDist, const TrackAuxPar& trcA, float rBSign) + void notTouchingXY(float dist, float xDist, float yDist, const TrackAuxPar& trcA, float rBSign, bool isCollinear = false) { - // fast method to calculate DCA between 2 circles, assuming that they don't touch each outer: - // the parametric equation of lines connecting the centers is x = xA + t/dist * xDist, y = yA + t/dist * yDist - // with xA,yY being the center of the circle A ( = trcA.xC, trcA.yC ), xDist = trcB.xC = trcA.xC ... - // There are 2 special cases: - // (a) small circle is inside the large one: provide rBSign as -trcB.rC - // (b) circle are side by side: provide rBSign as trcB.rC + if (isCollinear) { + /// for collinear tracks it is better to take + /// a weighted average of the crossing points as a radius + float r2r = trcA.rC + std::abs(rBSign); + float r1_r = trcA.rC / r2r; + float r2_r = std::abs(rBSign) / r2r; + xDCA[0] = r2_r * trcA.xC + r1_r * (xDist + trcA.xC); + yDCA[0] = r2_r * trcA.yC + r1_r * (yDist + trcA.yC); + } else { + // fast method to calculate DCA between 2 circles, assuming that they don't touch each outer: + // the parametric equation of lines connecting the centers is x = xA + t/dist * xDist, y = yA + t/dist * yDist + // with xA,yY being the center of the circle A ( = trcA.xC, trcA.yC ), xDist = trcB.xC = trcA.xC ... + // There are 2 special cases: + // (a) small circle is inside the large one: provide rBSign as -trcB.rC + // (b) circle are side by side: provide rBSign as trcB.rC + auto t2d = (dist + trcA.rC - rBSign) / dist; + xDCA[0] = trcA.xC + 0.5 * (xDist * t2d); + yDCA[0] = trcA.yC + 0.5 * (yDist * t2d); + } nDCA = 1; - auto t2d = (dist + trcA.rC - rBSign) / dist; - xDCA[0] = trcA.xC + 0.5 * (xDist * t2d); - yDCA[0] = trcA.yC + 0.5 * (yDist * t2d); } template @@ -251,12 +271,12 @@ struct CrossInfo { } template - int set(const TrackAuxPar& trax0, const T& tr0, const TrackAuxPar& trax1, const T& tr1, float maxDistXY = MaxDistXYDef) + int set(const TrackAuxPar& trax0, const T& tr0, const TrackAuxPar& trax1, const T& tr1, float maxDistXY = MaxDistXYDef, bool isCollinear = false) { // calculate up to 2 crossings between 2 circles nDCA = 0; if (trax0.rC > o2::constants::math::Almost0 && trax1.rC > o2::constants::math::Almost0) { // both are not straight lines - nDCA = circlesCrossInfo(trax0, trax1, maxDistXY); + nDCA = circlesCrossInfo(trax0, trax1, maxDistXY, isCollinear); } else if (trax0.rC < o2::constants::math::Almost0 && trax1.rC < o2::constants::math::Almost0) { // both are straigt lines nDCA = linesCrossInfo(trax0, tr0, trax1, tr1, maxDistXY); } else { @@ -269,9 +289,9 @@ struct CrossInfo { CrossInfo() = default; template - CrossInfo(const TrackAuxPar& trax0, const T& tr0, const TrackAuxPar& trax1, const T& tr1, float maxDistXY = MaxDistXYDef) + CrossInfo(const TrackAuxPar& trax0, const T& tr0, const TrackAuxPar& trax1, const T& tr1, float maxDistXY = MaxDistXYDef, bool isCollinear = false) { - set(trax0, tr0, trax1, tr1, maxDistXY); + set(trax0, tr0, trax1, tr1, maxDistXY, isCollinear); } ClassDefNV(CrossInfo, 1); }; diff --git a/Common/MathUtils/include/MathUtils/SMatrixGPU.h b/Common/MathUtils/include/MathUtils/SMatrixGPU.h index d0820778550dd..7175339db8592 100644 --- a/Common/MathUtils/include/MathUtils/SMatrixGPU.h +++ b/Common/MathUtils/include/MathUtils/SMatrixGPU.h @@ -32,6 +32,7 @@ #include "GPUCommonArray.h" #include "GPUCommonMath.h" #include "GPUCommonAlgorithm.h" +#include "GPUCommonLogger.h" namespace o2::math_utils { @@ -980,7 +981,7 @@ GPUdi() void Inverter::InvertBunchKaufman(MatRepSymGPU& rhs, int& if // invert D(j:j+1,j:j+1) temp2 = *mjj * *(mjj + j + 1) - *(mjj + j) * *(mjj + j); if (temp2 == 0) { - printf("SymMatrix::bunch_invert: error in pivot choice"); + LOGF(error, "SymMatrix::bunch_invert: error in pivot choice"); } temp2 = 1. / temp2; // this quotient is guaranteed to exist by the choice @@ -1070,7 +1071,7 @@ GPUdi() void Inverter::InvertBunchKaufman(MatRepSymGPU& rhs, int& if } else // 2x2 pivot, compute columns j and j-1 of the inverse { if (piv[j - 1] != 0) { - printf("error in piv %lf \n", static_cast(piv[j - 1])); + LOGF(error, "error in piv %lf \n", static_cast(piv[j - 1])); } s = 2; if (j < nrow) { diff --git a/Common/MathUtils/include/MathUtils/detail/StatAccumulator.h b/Common/MathUtils/include/MathUtils/detail/StatAccumulator.h index 50a09804da6ed..abb8a716cc5ee 100644 --- a/Common/MathUtils/include/MathUtils/detail/StatAccumulator.h +++ b/Common/MathUtils/include/MathUtils/detail/StatAccumulator.h @@ -66,6 +66,7 @@ struct StatAccumulator { sum += other.sum; sum2 += other.sum2; wsum += other.wsum; + n += other.n; return *this; } diff --git a/Common/SimConfig/include/SimConfig/SimConfig.h b/Common/SimConfig/include/SimConfig/SimConfig.h index 36babc21592b3..b288083098d6c 100644 --- a/Common/SimConfig/include/SimConfig/SimConfig.h +++ b/Common/SimConfig/include/SimConfig/SimConfig.h @@ -180,7 +180,7 @@ class SimConfig SimConfigData mConfigData; //! // adjust/overwrite some option settings when collision context is used - void adjustFromCollContext(); + void adjustFromCollContext(std::string const& collcontextfile, std::string const& prefix); ClassDefNV(SimConfig, 1); }; diff --git a/Common/SimConfig/src/SimConfig.cxx b/Common/SimConfig/src/SimConfig.cxx index 016e6e05a6961..ce5d2687979e1 100644 --- a/Common/SimConfig/src/SimConfig.cxx +++ b/Common/SimConfig/src/SimConfig.cxx @@ -256,7 +256,17 @@ bool SimConfig::resetFromParsedMap(boost::program_options::variables_map const& mConfigData.mFilterNoHitEvents = true; } mConfigData.mFromCollisionContext = vm["fromCollContext"].as(); - adjustFromCollContext(); + // we decompose the argument to fetch + // (a) collision contextfilename + // (b) sim prefix to use from the context + auto pos = mConfigData.mFromCollisionContext.find(':'); + std::string collcontextfile{mConfigData.mFromCollisionContext}; + std::string simprefix{mConfigData.mOutputPrefix}; + if (pos != std::string::npos) { + collcontextfile = mConfigData.mFromCollisionContext.substr(0, pos); + simprefix = mConfigData.mFromCollisionContext.substr(pos + 1); + } + adjustFromCollContext(collcontextfile, simprefix); // analyse vertex options if (!parseVertexModeString(vm["vertexMode"].as(), mConfigData.mVertexMode)) { @@ -323,28 +333,28 @@ bool SimConfig::parseFieldString(std::string const& fieldstring, int& fieldvalue return true; } -void SimConfig::adjustFromCollContext() +void SimConfig::adjustFromCollContext(std::string const& collcontextfile, std::string const& prefix) { // When we use pregenerated collision contexts, some options // need to be auto-adjusted. Do so and inform about this in the logs. - if (mConfigData.mFromCollisionContext == "") { + if (collcontextfile == "") { return; } - auto context = o2::steer::DigitizationContext::loadFromFile(mConfigData.mFromCollisionContext); + auto context = o2::steer::DigitizationContext::loadFromFile(collcontextfile); if (context) { // find the events belonging to a source that corresponds to a sim prefix - LOG(info) << "Looking up simprefixes " << mConfigData.mOutputPrefix; - int sourceid = context->findSimPrefix(mConfigData.mOutputPrefix); + LOG(info) << "Looking up simprefixes " << prefix; + int sourceid = context->findSimPrefix(prefix); if (sourceid == -1) { - LOG(error) << "Could not find collisions with sim prefix " << mConfigData.mOutputPrefix << " in the collision context. The collision contet specifies the following prefixes:"; - for (auto& prefix : context->getSimPrefixes()) { - LOG(info) << prefix; + LOG(error) << "Could not find collisions with sim prefix " << prefix << " in the collision context. The collision context specifies the following prefixes:"; + for (auto& sp : context->getSimPrefixes()) { + LOG(info) << sp; } LOG(fatal) << "Aborting due to prefix error"; } else { auto collisionmap = context->getCollisionIndicesForSource(sourceid); - LOG(info) << "Found " << collisionmap.size() << " events in the collisioncontext for prefix " << mConfigData.mOutputPrefix; + LOG(info) << "Found " << collisionmap.size() << " events in the collisioncontext for prefix " << prefix; // check if collisionmap is dense (otherwise it will get screwed up with order/indexing in ROOT output) bool good = true; @@ -368,7 +378,7 @@ void SimConfig::adjustFromCollContext() LOG(info) << "Setting number of events to simulate to " << mConfigData.mNEvents; } } else { - LOG(fatal) << "Could not open collision context file " << mConfigData.mFromCollisionContext; + LOG(fatal) << "Could not open collision context file " << collcontextfile; } } diff --git a/Common/Utils/include/CommonUtils/BoostHistogramUtils.h b/Common/Utils/include/CommonUtils/BoostHistogramUtils.h index 85ff950aa2717..9b61bc839ddec 100644 --- a/Common/Utils/include/CommonUtils/BoostHistogramUtils.h +++ b/Common/Utils/include/CommonUtils/BoostHistogramUtils.h @@ -714,6 +714,29 @@ auto ReduceBoostHistoFastSliceByValue(boost::histogram::histogram& hist return ReduceBoostHistoFastSlice(hist2d, binXLow, binXHigh, binYLow, binYHigh, includeOverflowUnderflow); } +/// \brief Function to integrate 1d boost histogram in specified range +/// \param hist 1d boost histogram +/// \param min lower integration range +/// \param max upper integration range +/// \return sum of bin contents in specified range +template +double getIntegralBoostHist(boost::histogram::histogram& hist, double min, double max) +{ + // find bins for min and max values + std::array axisLimitsIndex = {hist.axis(0).index(min), hist.axis(0).index(max)}; + // over/underflow bin have to be protected + for (auto& bin : axisLimitsIndex) { + if (bin < 0) { + bin = 0; + } else if (bin >= hist.axis(0).size()) { + bin = hist.axis(0).size() - 1; + } + } + // Reduce histogram to desired range + auto slicedHist = ReduceBoostHistoFastSlice1D(hist, axisLimitsIndex[0], axisLimitsIndex[1], false); + return boost::histogram::algorithm::sum(slicedHist); +} + } // namespace utils } // end namespace o2 diff --git a/Common/Utils/include/CommonUtils/RootSerializableKeyValueStore.h b/Common/Utils/include/CommonUtils/RootSerializableKeyValueStore.h index 80545997af159..c29a3024de6e1 100644 --- a/Common/Utils/include/CommonUtils/RootSerializableKeyValueStore.h +++ b/Common/Utils/include/CommonUtils/RootSerializableKeyValueStore.h @@ -141,8 +141,15 @@ class RootSerializableKeyValueStore mStore.clear(); } - /// print list of keys and type information - void print() const; + /// print list of keys, values (and optionally type information) + void print(bool includetypeinfo = false) const; + + /// resets store to the store of another object + void copyFrom(RootSerializableKeyValueStore const& other) + { + mStore.clear(); + mStore = other.mStore; + } private: std::map mStore; diff --git a/Common/Utils/include/CommonUtils/TreeStreamRedirector.h b/Common/Utils/include/CommonUtils/TreeStreamRedirector.h index 8199009df400d..80858fecea87b 100644 --- a/Common/Utils/include/CommonUtils/TreeStreamRedirector.h +++ b/Common/Utils/include/CommonUtils/TreeStreamRedirector.h @@ -41,7 +41,7 @@ namespace utils class TreeStreamRedirector { public: - TreeStreamRedirector(const char* fname = "", const char* option = "update"); + TreeStreamRedirector(const char* fname = "", const char* option = "recreate"); virtual ~TreeStreamRedirector(); void Close(); TFile* GetFile() { return mDirectory->GetFile(); } diff --git a/Common/Utils/src/RootSerializableKeyValueStore.cxx b/Common/Utils/src/RootSerializableKeyValueStore.cxx index 7bc424300674e..0e0902f6cc4f2 100644 --- a/Common/Utils/src/RootSerializableKeyValueStore.cxx +++ b/Common/Utils/src/RootSerializableKeyValueStore.cxx @@ -14,11 +14,57 @@ using namespace o2::utils; -void RootSerializableKeyValueStore::print() const +namespace +{ +template +std::string stringFromType(char* buffer) +{ + T value; + std::memcpy(&value, buffer, sizeof(T)); + return std::to_string(value); +} +} // namespace + +void RootSerializableKeyValueStore::print(bool includetypeinfo) const { for (auto& p : mStore) { const auto& key = p.first; const auto info = p.second; - std::cout << "key: " << key << " of-type: " << info.typeinfo_name << "\n"; + auto tinfo = info.typeinfo_name; + + std::string value("unknown-value"); + // let's try to decode the value as a string if we can + if (tinfo == typeid(int).name()) { + value = stringFromType(info.bufferptr); + } + // let's try to decode the value as a string if we can + else if (tinfo == typeid(unsigned int).name()) { + value = stringFromType(info.bufferptr); + } + // let's try to decode the value as a string if we can + else if (tinfo == typeid(short).name()) { + value = stringFromType(info.bufferptr); + } + // let's try to decode the value as a string if we can + else if (tinfo == typeid(unsigned short).name()) { + value = stringFromType(info.bufferptr); + } + // let's try to decode the value as a string if we can + else if (tinfo == typeid(double).name()) { + value = stringFromType(info.bufferptr); + } + // let's try to decode the value as a string if we can + else if (tinfo == typeid(float).name()) { + value = stringFromType(info.bufferptr); + } + // let's try to decode the value as a string if we can + else if (tinfo == typeid(std::string).name()) { + value = *(get(key)); + } + std::cout << "key: " << key << " value: " << value; + if (includetypeinfo) { + std::cout << " type: " << info.typeinfo_name; + } + std::cout << "\n"; } } diff --git a/Common/Utils/src/TreeStreamRedirector.cxx b/Common/Utils/src/TreeStreamRedirector.cxx index 4c21fcd602543..06fb3d65678c4 100644 --- a/Common/Utils/src/TreeStreamRedirector.cxx +++ b/Common/Utils/src/TreeStreamRedirector.cxx @@ -117,7 +117,7 @@ void TreeStreamRedirector::Close() TDirectory* backup = gDirectory; mDirectory->cd(); for (auto& layout : mDataLayouts) { - layout->getTree().Write(layout->getName()); + layout->getTree().Write(layout->getName(), TObject::kOverwrite); } mDataLayouts.clear(); if (backup) { diff --git a/DEBUGGING.md b/DEBUGGING.md index cda0d2a94ed81..c782b99987ef9 100644 --- a/DEBUGGING.md +++ b/DEBUGGING.md @@ -1,3 +1,7 @@ + + # How do I run in debug mode? By default, O2 builds with optimizations (`-O2`) turned on, while leaving debug symbols available. diff --git a/DataFormats/Detectors/CTP/include/DataFormatsCTP/RunManager.h b/DataFormats/Detectors/CTP/include/DataFormatsCTP/RunManager.h index fcb5b8734b179..2df164474e4c4 100644 --- a/DataFormats/Detectors/CTP/include/DataFormatsCTP/RunManager.h +++ b/DataFormats/Detectors/CTP/include/DataFormatsCTP/RunManager.h @@ -39,6 +39,7 @@ class CTPRunManager void printActiveRuns() const; int saveRunScalersToCCDB(int i); int saveRunConfigToCCDB(CTPConfiguration* cfg, long timeStart); + static CTPConfiguration getConfigFromCCDB(long timestamp, std::string run, bool& ok); static CTPConfiguration getConfigFromCCDB(long timestamp, std::string run); CTPRunScalers getScalersFromCCDB(long timestamp, std::string, bool& ok); int loadScalerNames(); diff --git a/DataFormats/Detectors/CTP/src/Configuration.cxx b/DataFormats/Detectors/CTP/src/Configuration.cxx index 25eb8185dfded..a26feae5d7f85 100644 --- a/DataFormats/Detectors/CTP/src/Configuration.cxx +++ b/DataFormats/Detectors/CTP/src/Configuration.cxx @@ -1111,7 +1111,7 @@ int CTPInputsConfiguration::getInputIndexFromName(std::string& name) { std::string namecorr = name; if ((name[0] == '0') || (name[0] == 'M') || (name[0] == '1')) { - namecorr.substr(1, namecorr.size() - 1); + namecorr = namecorr.substr(1, namecorr.size() - 1); } else { LOG(warn) << "Input name without level:" << name; } diff --git a/DataFormats/Detectors/CTP/src/RunManager.cxx b/DataFormats/Detectors/CTP/src/RunManager.cxx index 2916fba924883..a41af579d84e6 100644 --- a/DataFormats/Detectors/CTP/src/RunManager.cxx +++ b/DataFormats/Detectors/CTP/src/RunManager.cxx @@ -186,6 +186,14 @@ int CTPRunManager::processMessage(std::string& topic, const std::string& message LOG(info) << "EOX received"; mEOX = 1; } + static int nerror = 0; + if (topic == "rocnts") { + if (nerror < 1) { + LOG(warning) << "Skipping topic rocnts"; + nerror++; + } + return 0; + } // std::vector tokens; if (firstcounters.size() > 0) { @@ -198,7 +206,7 @@ int CTPRunManager::processMessage(std::string& topic, const std::string& message mNew = 0; LOG(warning) << "v2 scaler size"; } else { - LOG(error) << "Scalers size wrong:" << tokens.size() << " expected:" << CTPRunScalers::NCOUNTERS + 1 << " or " << CTPRunScalers::NCOUNTERSv2 + 1; + LOG(warning) << "Scalers size wrong:" << tokens.size() << " expected:" << CTPRunScalers::NCOUNTERS + 1 << " or " << CTPRunScalers::NCOUNTERSv2 + 1; return 1; } } @@ -298,7 +306,7 @@ int CTPRunManager::saveRunConfigToCCDB(CTPConfiguration* cfg, long timeStart) LOG(info) << "CTP config saved in ccdb:" << mCCDBHost << " run:" << cfg->getRunNumber() << " tmin:" << tmin << " tmax:" << tmax; return 0; } -CTPConfiguration CTPRunManager::getConfigFromCCDB(long timestamp, std::string run) +CTPConfiguration CTPRunManager::getConfigFromCCDB(long timestamp, std::string run, bool& ok) { auto& mgr = o2::ccdb::BasicCCDBManager::instance(); mgr.setURL(mCCDBHost); @@ -307,12 +315,24 @@ CTPConfiguration CTPRunManager::getConfigFromCCDB(long timestamp, std::string ru auto ctpconfigdb = mgr.getSpecific(CCDBPathCTPConfig, timestamp, metadata); if (ctpconfigdb == nullptr) { LOG(info) << "CTP config not in database, timestamp:" << timestamp; + ok = 0; } else { // ctpconfigdb->printStream(std::cout); LOG(info) << "CTP config found. Run:" << run; + ok = 1; } return *ctpconfigdb; } +CTPConfiguration CTPRunManager::getConfigFromCCDB(long timestamp, std::string run) +{ + bool ok; + auto ctpconfig = getConfigFromCCDB(timestamp, run, ok); + if (ok == 0) { + LOG(error) << "CTP config not in CCDB"; + return CTPConfiguration(); + } + return ctpconfig; +} CTPRunScalers CTPRunManager::getScalersFromCCDB(long timestamp, std::string run, bool& ok) { auto& mgr = o2::ccdb::BasicCCDBManager::instance(); diff --git a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h index 92fc2bfa46a6d..3521991070583 100644 --- a/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h +++ b/DataFormats/Detectors/Common/include/DetectorsCommonDataFormats/SimTraits.h @@ -95,7 +95,11 @@ class SimTraits /*IT3*/ VS{ "IT3Hit" }, /*TRK*/ VS{ "TRKHit" }, /*FT3*/ VS{ "FT3Hit" }, - /*FCT*/ VS{ "FCTHit" } + /*FCT*/ VS{ "FCTHit" }, + /*TF3*/ VS{ "TF3Hit" }, + /*RCH*/ VS{ "RCHHit" }, + /*MI3*/ VS{ "MI3Hit" }, + /*ECL*/ VS{ "ECLHit" } #endif }; // clang-format on diff --git a/DataFormats/Detectors/EMCAL/CMakeLists.txt b/DataFormats/Detectors/EMCAL/CMakeLists.txt index 80b00474465b8..9c93bae30ddf6 100644 --- a/DataFormats/Detectors/EMCAL/CMakeLists.txt +++ b/DataFormats/Detectors/EMCAL/CMakeLists.txt @@ -22,6 +22,7 @@ o2_add_library(DataFormatsEMCAL src/ErrorTypeFEE.cxx src/CellLabel.cxx src/ClusterLabel.cxx + src/CompressedTriggerData.cxx PUBLIC_LINK_LIBRARIES O2::CommonDataFormat O2::Headers O2::MathUtils diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ClusterLabel.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ClusterLabel.h index a52f018d3d8bc..b6db76f91ff34 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ClusterLabel.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ClusterLabel.h @@ -38,12 +38,12 @@ class ClusterLabel struct labelWithE { /// \brief Constructor - labelWithE() : energyFraction(0.), label(0) {} + labelWithE() : label(0), energyFraction(0.) {} /// \brief Constructor - /// \param e Energy fraction /// \param l MC label - labelWithE(float e, int l) : energyFraction(e), label(l) {} + /// \param e Energy fraction + labelWithE(int l, float e) : label(l), energyFraction(e) {} /// \brief Comparison lower operator comparing cells based on energy /// diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/CompressedTriggerData.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/CompressedTriggerData.h new file mode 100644 index 0000000000000..5fbf2187ab5dd --- /dev/null +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/CompressedTriggerData.h @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_EMCAL_COMPRESSEDTRIGGERDATA_H +#define ALICEO2_EMCAL_COMPRESSEDTRIGGERDATA_H + +#include +#include + +namespace o2::emcal +{ + +/// \struct CompressedTRU +/// \brief Compressed reconstructed TRU information +/// \ingroup EMCALDataFormat +struct CompressedTRU { + uint8_t mTRUIndex; ///< TRU index + uint8_t mTriggerTime; ///< Trigger time of the TRU + bool mFired; ///< Fired status of the TRU + uint8_t mNumberOfPatches; ///< Number of patches found for the TRU +}; + +/// \struct CompressedTriggerPatch +/// \brief Compressed reconstructed L0 trigger patch information +/// \ingroup EMCALDataFormat +struct CompressedTriggerPatch { + uint8_t mTRUIndex; ///< Index of the TRU where the trigger patch has been found + uint8_t mPatchIndexInTRU; ///< Index of the trigger patch in the TRU + uint8_t mTime; ///< Reconstructed time of the trigger patch + uint16_t mADC; ///< ADC sum of the trigger patch +}; + +/// \struct CompressedL0TimeSum +/// \brief Compressed L0 timesum information +/// \ingroup EMCALDataFormat +struct CompressedL0TimeSum { + uint16_t mIndex; ///< Absolute ID of the FastOR + uint16_t mTimesum; ///< ADC value of the time-sum (4-integral) +}; + +/// \brief Output stream operator of the CompressedTRU +/// \param stream Stream to write to +/// \param tru TRU data to be streamed +/// \return Stream after writing +std::ostream& operator<<(std::ostream& stream, const CompressedTRU& tru); + +/// \brief Output stream operator of the CompressedTriggerPatch +/// \param stream Stream to write to +/// \param patch Trigger patch to be streamed +/// \return Stream after writing +std::ostream& operator<<(std::ostream& stream, const CompressedTriggerPatch& patch); + +/// \brief Output stream operator of the CompressedL0TimeSum +/// \param stream Stream to write to +/// \param timesum FastOR L0 timesum to be streamed +/// \return Stream after writing +std::ostream& operator<<(std::ostream& stream, const CompressedL0TimeSum& timesum); + +} // namespace o2::emcal + +#endif // ALICEO2_EMCAL_COMPRESSEDTRIGGERDATA_H \ No newline at end of file diff --git a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ErrorTypeFEE.h b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ErrorTypeFEE.h index d8e750c9ad0ba..cc3540cd388d3 100644 --- a/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ErrorTypeFEE.h +++ b/DataFormats/Detectors/EMCAL/include/DataFormatsEMCAL/ErrorTypeFEE.h @@ -58,6 +58,7 @@ class ErrorTypeFEE GEOMETRY_ERROR, ///< Decoded position outside EMCAL GAIN_ERROR, ///< Error due to gain type LINK_ERROR, ///< Error due to missing DDL links + TRU_ERROR, ///< Errors from TRU data STU_ERROR, ///< Error from STU data UNDEFINED ///< Error source undefined }; @@ -105,7 +106,11 @@ class ErrorTypeFEE /// \brief Set the error as STU decoder error and store the error code /// \param gainError Error code of the STU decoder error - void setSTUDecoderErrorType(int gainError) { setError(ErrorSource_t::STU_ERROR, gainError); } + void setSTUDecoderErrorType(int stuerror) { setError(ErrorSource_t::STU_ERROR, stuerror); } + + /// \brief Set the error as TRU decoder error and store the error code + /// \param gainError Error code of the TRU decoder error + void setTRUDecoderErrorType(int truerror) { setError(ErrorSource_t::TRU_ERROR, truerror); } /// \brief Set the error type of the object /// \param errorsource Error type of the object @@ -175,6 +180,10 @@ class ErrorTypeFEE /// \return Error code (-1 in case the object is not a STU decoder error) int getSTUDecoderErrorType() const { return getRawErrorForType(ErrorSource_t::STU_ERROR); } + /// \brief Get the error code of the obect in case the object is a TRU decoder error + /// \return Error code (-1 in case the object is not a STU decoder error) + int getTRUDecoderErrorType() const { return getRawErrorForType(ErrorSource_t::TRU_ERROR); } + /// \brief Get subspecification of the error /// \return Subspecification of the error int getSubspecification() const { return mSubspecification; } @@ -191,7 +200,7 @@ class ErrorTypeFEE /// \brief Get the number of error types /// \return Number of error types (including undefined) - static constexpr int getNumberOfErrorTypes() { return 7; } + static constexpr int getNumberOfErrorTypes() { return 10; } /// \brief Get the name of the error type /// \param errorTypeID ID of the error type diff --git a/DataFormats/Detectors/EMCAL/src/ClusterLabel.cxx b/DataFormats/Detectors/EMCAL/src/ClusterLabel.cxx index 6e3bd4f147447..2d3abd09d0b04 100644 --- a/DataFormats/Detectors/EMCAL/src/ClusterLabel.cxx +++ b/DataFormats/Detectors/EMCAL/src/ClusterLabel.cxx @@ -71,5 +71,5 @@ void ClusterLabel::orderLabels() { // Sort the pairs based on values in descending order std::sort(mClusterLabels.begin(), mClusterLabels.end(), - [](const labelWithE& a, const labelWithE& b) { return a.label >= b.label; }); + [](const labelWithE& a, const labelWithE& b) { return a.energyFraction >= b.energyFraction; }); } diff --git a/DataFormats/Detectors/EMCAL/src/CompressedTriggerData.cxx b/DataFormats/Detectors/EMCAL/src/CompressedTriggerData.cxx new file mode 100644 index 0000000000000..e60b58c958d03 --- /dev/null +++ b/DataFormats/Detectors/EMCAL/src/CompressedTriggerData.cxx @@ -0,0 +1,31 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include "DataFormatsEMCAL/CompressedTriggerData.h" + +std::ostream& o2::emcal::operator<<(std::ostream& stream, const o2::emcal::CompressedTRU& tru) +{ + stream << "TRU " << tru.mTRUIndex << ": Fired " << (tru.mFired ? "yes" : "no") << ", time " << (tru.mFired ? std::to_string(static_cast(tru.mTriggerTime)) : "Undefined") << ", number of patches " << tru.mNumberOfPatches; + return stream; +} + +std::ostream& o2::emcal::operator<<(std::ostream& stream, const o2::emcal::CompressedTriggerPatch& patch) +{ + stream << "Patch " << patch.mPatchIndexInTRU << " in TRU " << patch.mTRUIndex << ": Time " << patch.mTime << ", ADC " << patch.mADC; + return stream; +} + +std::ostream& o2::emcal::operator<<(std::ostream& stream, const o2::emcal::CompressedL0TimeSum& timesum) +{ + stream << "FastOR " << timesum.mIndex << ": " << timesum.mTimesum << " ADC counts"; + return stream; +} \ No newline at end of file diff --git a/DataFormats/Detectors/EMCAL/src/ErrorTypeFEE.cxx b/DataFormats/Detectors/EMCAL/src/ErrorTypeFEE.cxx index c1c933eaba92e..21d985b2a832a 100644 --- a/DataFormats/Detectors/EMCAL/src/ErrorTypeFEE.cxx +++ b/DataFormats/Detectors/EMCAL/src/ErrorTypeFEE.cxx @@ -37,6 +37,9 @@ void ErrorTypeFEE::PrintStream(std::ostream& stream) const case ErrorSource_t::GAIN_ERROR: typestring = "gain type error"; break; + case ErrorSource_t::TRU_ERROR: + typestring = "STU decoder error"; + break; case ErrorSource_t::STU_ERROR: typestring = "STU decoder error"; break; @@ -74,6 +77,8 @@ const char* ErrorTypeFEE::getErrorTypeName(unsigned int errorTypeID) return "Geometry"; case ErrorSource_t::GAIN_ERROR: return "GainType"; + case ErrorSource_t::TRU_ERROR: + return "TRUDecoding"; case ErrorSource_t::STU_ERROR: return "STUDecoding"; case ErrorSource_t::LINK_ERROR: @@ -100,8 +105,10 @@ const char* ErrorTypeFEE::getErrorTypeTitle(unsigned int errorTypeID) return "Geometry"; case ErrorSource_t::GAIN_ERROR: return "Gain"; + case ErrorSource_t::TRU_ERROR: + return "TRU Decoding"; case ErrorSource_t::STU_ERROR: - return "STUDecoding"; + return "STU Decoding"; case ErrorSource_t::LINK_ERROR: return "Link missing"; case ErrorSource_t::UNDEFINED: @@ -111,7 +118,7 @@ const char* ErrorTypeFEE::getErrorTypeTitle(unsigned int errorTypeID) }; } -std::ostream& operator<<(std::ostream& stream, const ErrorTypeFEE& error) +std::ostream& o2::emcal::operator<<(std::ostream& stream, const ErrorTypeFEE& error) { error.PrintStream(stream); return stream; diff --git a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RecPoints.h b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RecPoints.h index c5e0a827de132..d7ee2e67613fc 100644 --- a/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RecPoints.h +++ b/DataFormats/Detectors/FIT/FV0/include/DataFormatsFV0/RecPoints.h @@ -28,7 +28,7 @@ namespace fv0 struct ChannelDataFloat { int channel = -1; // channel Id - double time = -20000; // time in ps, 0 at the LHC clk center + double time = -20000; // time in ns, 0 at the LHC clk center double charge = -20000; // charge [channels] int adcId = -1; // QTC chain diff --git a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h index a766b7d72bd9d..3f063c8b8509d 100644 --- a/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h +++ b/DataFormats/Detectors/GlobalTracking/include/DataFormatsGlobalTracking/RecoContainer.h @@ -340,6 +340,7 @@ struct RecoContainer { o2::ctp::LumiInfo mCTPLumi; gsl::span clusterShMapTPC; ///< externally set TPC clusters sharing map + gsl::span occupancyMapTPC; ///< externally set TPC clusters occupancy map std::unique_ptr inputsTPCclusters; // special struct for TPC clusters access std::unique_ptr inputsTRD; // special struct for TRD tracklets, trigger records @@ -371,7 +372,7 @@ struct RecoContainer { void addITSClusters(o2::framework::ProcessingContext& pc, bool mc); void addMFTClusters(o2::framework::ProcessingContext& pc, bool mc); - void addTPCClusters(o2::framework::ProcessingContext& pc, bool mc, bool shmap); + void addTPCClusters(o2::framework::ProcessingContext& pc, bool mc, bool shmap, bool occmap); void addTPCTriggers(o2::framework::ProcessingContext& pc); void addTOFClusters(o2::framework::ProcessingContext& pc, bool mc); void addHMPClusters(o2::framework::ProcessingContext& pc, bool mc); diff --git a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx index fdfdf1e18fd96..a79e2736dde60 100644 --- a/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx +++ b/DataFormats/Detectors/GlobalTracking/src/RecoContainer.cxx @@ -119,6 +119,7 @@ void DataRequest::requestTPCTracks(bool mc) addInput({"trackTPCClRefs", "TPC", "CLUSREFS", 0, Lifetime::Timeframe}); if (requestMap.find("clusTPC") != requestMap.end()) { addInput({"clusTPCshmap", "TPC", "CLSHAREDMAP", 0, Lifetime::Timeframe}); + addInput({"clusTPCoccmap", "TPC", "TPCOCCUPANCYMAP", 0, Lifetime::Timeframe}); } if (mc) { addInput({"trackTPCMCTR", "TPC", "TRACKSMCLBL", 0, Lifetime::Timeframe}); @@ -255,6 +256,7 @@ void DataRequest::requestTPCClusters(bool mc) } if (requestMap.find("trackTPC") != requestMap.end()) { addInput({"clusTPCshmap", "TPC", "CLSHAREDMAP", 0, Lifetime::Timeframe}); + addInput({"clusTPCoccmap", "TPC", "TPCOCCUPANCYMAP", 0, Lifetime::Timeframe}); } if (mc) { addInput({"clusTPCMC", ConcreteDataTypeMatcher{"TPC", "CLNATIVEMCLBL"}, Lifetime::Timeframe}); @@ -678,7 +680,8 @@ void RecoContainer::collectData(ProcessingContext& pc, const DataRequest& reques req = reqMap.find("clusTPC"); if (req != reqMap.end()) { - addTPCClusters(pc, req->second, reqMap.find("trackTPC") != reqMap.end()); + auto tracksON = reqMap.find("trackTPC") != reqMap.end(); + addTPCClusters(pc, req->second, tracksON, tracksON); } req = reqMap.find("trigTPC"); @@ -1060,12 +1063,15 @@ void RecoContainer::addMFTClusters(ProcessingContext& pc, bool mc) } //__________________________________________________________ -void RecoContainer::addTPCClusters(ProcessingContext& pc, bool mc, bool shmap) +void RecoContainer::addTPCClusters(ProcessingContext& pc, bool mc, bool shmap, bool occmap) { inputsTPCclusters = o2::tpc::getWorkflowTPCInput(pc, 0, mc); if (shmap) { clusterShMapTPC = pc.inputs().get>("clusTPCshmap"); } + if (occmap) { + occupancyMapTPC = pc.inputs().get>("clusTPCoccmap"); + } } //__________________________________________________________ diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CompCluster.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CompCluster.h index 0cd5d0e11f19f..18acc82e72239 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CompCluster.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/CompCluster.h @@ -82,6 +82,11 @@ class CompCluster } } + bool operator==(const CompCluster& cl) const + { + return mData == cl.mData; + } + void print() const; ClassDefNV(CompCluster, 2); diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TimeDeadMap.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TimeDeadMap.h index aaf7a1a95aa04..a0b214f705d7c 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TimeDeadMap.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TimeDeadMap.h @@ -73,8 +73,8 @@ class TimeDeadMap } } - void decodeMap(unsigned long orbit, o2::itsmft::NoiseMap& noisemap, bool includeStaticMap = true) - { // for time-dependent and (optionally) static part + void decodeMap(unsigned long orbit, o2::itsmft::NoiseMap& noisemap, bool includeStaticMap = true, long orbitGapAllowed = 330000) + { // for time-dependent and (optionally) static part. Use orbitGapAllowed = -1 to ignore check on orbit difference if (mMAP_VERSION != "3" && mMAP_VERSION != "4") { LOG(error) << "Trying to decode time-dependent deadmap version " << mMAP_VERSION << ". Not implemented, doing nothing."; @@ -84,14 +84,16 @@ class TimeDeadMap if (mEvolvingDeadMap.empty()) { LOG(warning) << "Time-dependent dead map is empty. Doing nothing."; return; - } else if (orbit > mEvolvingDeadMap.rbegin()->first + 11000 * 300 || orbit < mEvolvingDeadMap.begin()->first - 11000 * 300) { - // the map should not leave several minutes uncovered. - LOG(warning) << "Time-dependent dead map: the requested orbit " << orbit << " seems to be out of the range stored in the map."; } std::vector closestVec; long dT = getMapAtOrbit(orbit, closestVec); + if (orbitGapAllowed >= 0 && std::abs(dT) > orbitGapAllowed) { + LOG(warning) << "Requested orbit " << orbit << ", found " << orbit - dT << ". Orbit gap is too high, skipping time-dependent map."; + closestVec.clear(); + } + // add static part if requested. something may be masked twice if (includeStaticMap && mMAP_VERSION != "3") { closestVec.insert(closestVec.end(), mStaticDeadMap.begin(), mStaticDeadMap.end()); @@ -125,18 +127,19 @@ class TimeDeadMap void getStaticMap(std::vector& mmap) { mmap = mStaticDeadMap; }; long getMapAtOrbit(unsigned long orbit, std::vector& mmap) - { // fills mmap and returns orbit - lower_bound + { // fills mmap and returns requested_orbit - found_orbit. Found orbit is the highest key lower or equal to the requested one if (mEvolvingDeadMap.empty()) { LOG(warning) << "Requested orbit " << orbit << "from an empty time-dependent map. Doing nothing"; return (long)orbit; } - auto closest = mEvolvingDeadMap.lower_bound(orbit); - if (closest != mEvolvingDeadMap.end()) { + auto closest = mEvolvingDeadMap.upper_bound(orbit); + if (closest != mEvolvingDeadMap.begin()) { + --closest; mmap = closest->second; return (long)orbit - closest->first; } else { - mmap = mEvolvingDeadMap.rbegin()->second; - return (long)(orbit)-mEvolvingDeadMap.rbegin()->first; + mmap = mEvolvingDeadMap.begin()->second; + return (long)(orbit)-mEvolvingDeadMap.begin()->first; } } diff --git a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h index 7a027c2a2156c..27b059cc61ecf 100644 --- a/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h +++ b/DataFormats/Detectors/ITSMFT/common/include/DataFormatsITSMFT/TrkClusRef.h @@ -29,7 +29,7 @@ struct TrkClusRef : public o2::dataformats::RangeRefComp<4> { uint16_t pattern = 0; ///< layers pattern GPUd() int getNClusters() const { return getEntries(); } - bool hasHitOnLayer(int i) { return pattern & (0x1 << i); } + bool hasHitOnLayer(int i) const { return pattern & (0x1 << i); } void setClusterSize(int l, int size) { @@ -41,11 +41,9 @@ struct TrkClusRef : public o2::dataformats::RangeRefComp<4> { clsizes |= (size << (l * 4)); } - int getClusterSize(int l) + int getClusterSize(int l) const { - if (l >= 8) - return 0; - return (clsizes >> (l * 4)) & 0xf; + return (l >= 8) ? 0 : (clsizes >> (l * 4)) & 0xf; } int getClusterSizes() const diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h index 4225faf8437c4..ace488b652559 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/CalibdEdxCorrection.h @@ -22,6 +22,7 @@ #ifndef GPUCA_GPUCODE_DEVICE #include #include +#include #endif // o2 includes @@ -96,6 +97,18 @@ class CalibdEdxCorrection /// \param outFileName name of the output file void dumpToTree(const char* outFileName = "calib_dedx.root") const; + /// Parameters averaged over all stacks + const std::array getMeanParams(ChargeType charge) const; + + /// Parameters averaged over all sectors for a stack type + const std::array getMeanParams(const GEMstack stack, ChargeType charge) const; + + /// Single fit parameters averaged over all sectors for a stack type + float getMeanParam(ChargeType charge, uint32_t param) const; + + /// Single fit parameters averaged over all sectors for a stack type + float getMeanParam(const GEMstack stack, ChargeType charge, uint32_t param) const; + #endif private: diff --git a/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h b/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h index 87b8b3d6c7130..e410cd00dd3f6 100644 --- a/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h +++ b/DataFormats/Detectors/TPC/include/DataFormatsTPC/LtrCalibData.h @@ -43,6 +43,11 @@ struct LtrCalibData { std::vector nTrackTF; ///< number of laser tracks per TF std::vector dEdx; ///< dE/dx of each track + bool isValid() const + { + return (std::abs(dvCorrectionA - 1.f) < 0.2) || (std::abs(dvCorrectionC - 1.f) < 0.2); + } + float getDriftVCorrection() const { float correction = 0; diff --git a/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx b/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx index b843577f1976a..28a44f15cf18c 100644 --- a/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx +++ b/DataFormats/Detectors/TPC/src/CalibdEdxCorrection.cxx @@ -11,6 +11,7 @@ #include "DataFormatsTPC/CalibdEdxCorrection.h" +#include #include // o2 includes @@ -86,3 +87,51 @@ void CalibdEdxCorrection::dumpToTree(const char* outFileName) const } } } + +const std::array CalibdEdxCorrection::getMeanParams(ChargeType charge) const +{ + std::array params{}; + + for (int index = 0; index < FitSize / 2; ++index) { + std::transform(params.begin(), params.end(), mParams[index + charge * FitSize / 2], params.begin(), std::plus<>()); + } + std::for_each(params.begin(), params.end(), [](auto& val) { val /= (0.5f * FitSize); }); + return params; +} + +const std::array CalibdEdxCorrection::getMeanParams(const GEMstack stack, ChargeType charge) const +{ + std::array params{}; + + for (int index = 0; index < SECTORSPERSIDE * SIDES; ++index) { + std::transform(params.begin(), params.end(), getParams(StackID{index, stack}, charge), params.begin(), std::plus<>()); + } + std::for_each(params.begin(), params.end(), [](auto& val) { val /= (SECTORSPERSIDE * SIDES); }); + return params; +} + +float CalibdEdxCorrection::getMeanParam(ChargeType charge, uint32_t param) const +{ + if (param >= ParamSize) { + return 0.f; + } + float mean{}; + for (int index = 0; index < FitSize / 2; ++index) { + mean += mParams[index + charge * FitSize / 2][param]; + } + + return mean / (0.5f * FitSize); +} + +float CalibdEdxCorrection::getMeanParam(const GEMstack stack, ChargeType charge, uint32_t param) const +{ + if (param >= ParamSize) { + return 0.f; + } + float mean{}; + for (int index = 0; index < SECTORSPERSIDE * SIDES; ++index) { + mean += getParams(StackID{index, stack}, charge)[param]; + } + + return mean / (SECTORSPERSIDE * SIDES); +} diff --git a/DataFormats/QualityControl/CMakeLists.txt b/DataFormats/QualityControl/CMakeLists.txt index 0d17d0d1d0f9e..c0f40a88f88c1 100644 --- a/DataFormats/QualityControl/CMakeLists.txt +++ b/DataFormats/QualityControl/CMakeLists.txt @@ -10,67 +10,65 @@ # or submit itself to any jurisdiction. file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include) -### Prepare the list of methods in FlagReasonFactory -file(READ "etc/flagReasons.csv" CSV_FLAG_REASONS) +### Prepare the list of methods in FlagTypeFactory +file(READ "etc/flagTypes.csv" CSV_FLAG_TYPES) # delete the CSV file header -string(REPLACE \"id\",\"method\",\"name\",\"bad\",\"obsolete\" "" CSV_FLAG_REASONS ${CSV_FLAG_REASONS}) +string(REPLACE \"id\",\"method\",\"name\",\"bad\",\"obsolete\" "" CSV_FLAG_TYPES ${CSV_FLAG_TYPES}) # detects if there is obsolete flag '1' in the last column, adds [[deprecated]] if so and retains the rest of the string string(REGEX REPLACE \([0-9]+,\".[^\"]*.\",.[^\"]*.,[0-1]\),1 "[[deprecated]] \\1,1" - CSV_FLAG_REASONS - ${CSV_FLAG_REASONS}) + CSV_FLAG_TYPES + ${CSV_FLAG_TYPES}) # replaces the flag reason entry with a c++ method to create it string(REGEX REPLACE \([0-9]+\),\"\(.[^\"]*.\)\",\(.[^\"]*.\),\([0-1]\),[0-1] - "static FlagReason \\2\(\) { return { static_cast\(\\1\), \\3, static_cast\(\\4\) }; }" - CSV_FLAG_REASONS - ${CSV_FLAG_REASONS}) + "static FlagType \\2\(\) { return { static_cast\(\\1\), \\3, static_cast\(\\4\) }; }" + CSV_FLAG_TYPES + ${CSV_FLAG_TYPES}) # put the method lists inside the template -configure_file("include/DataFormatsQualityControl/FlagReasonFactory.h.in" - "${CMAKE_CURRENT_BINARY_DIR}/include/DataFormatsQualityControl/FlagReasonFactory.h" +configure_file("include/DataFormatsQualityControl/FlagTypeFactory.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/include/DataFormatsQualityControl/FlagTypeFactory.h" @ONLY) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/DataFormatsQualityControl/FlagReasonFactory.h" +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/DataFormatsQualityControl/FlagTypeFactory.h" DESTINATION include/DataFormatsQualityControl) o2_add_library(DataFormatsQualityControl - SOURCES src/FlagReasons.cxx - src/TimeRangeFlag.cxx - src/TimeRangeFlagCollection.cxx - PUBLIC_LINK_LIBRARIES O2::Headers - O2::FrameworkLogger + SOURCES src/FlagType.cxx + src/QualityControlFlag.cxx + src/QualityControlFlagCollection.cxx + PUBLIC_LINK_LIBRARIES O2::FrameworkLogger O2::DetectorsCommonDataFormats PUBLIC_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/include include ) o2_target_root_dictionary(DataFormatsQualityControl - HEADERS include/DataFormatsQualityControl/FlagReasons.h - include/DataFormatsQualityControl/TimeRangeFlag.h - include/DataFormatsQualityControl/TimeRangeFlagCollection.h) - + HEADERS include/DataFormatsQualityControl/FlagType.h + include/DataFormatsQualityControl/QualityControlFlag.h + include/DataFormatsQualityControl/QualityControlFlagCollection.h) if(BUILD_TESTING) -o2_add_test(FlagReasons - SOURCES test/testFlagReasons.cxx +o2_add_test(FlagTypes + SOURCES test/testFlagTypes.cxx COMPONENT_NAME DataFormatsQualityControl PUBLIC_LINK_LIBRARIES O2::DataFormatsQualityControl - TARGETVARNAME flagreasons) + TARGETVARNAME flagtypes) -target_include_directories(${flagreasons} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include) +target_include_directories(${flagtypes} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/include) -o2_add_test(TimeRangeFlag - SOURCES test/testTimeRangeFlag.cxx +o2_add_test(QualityControlFlag + SOURCES test/testQualityControlFlag.cxx COMPONENT_NAME DataFormatsQualityControl PUBLIC_LINK_LIBRARIES O2::DataFormatsQualityControl - TARGETVARNAME timerangeflag) + TARGETVARNAME qualitycontrolflag) -target_include_directories(${timerangeflag} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include) +target_include_directories(${qualitycontrolflag} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include) -o2_add_test(TimeRangeFlagCollection - SOURCES test/testTimeRangeFlagCollection.cxx +o2_add_test(QualityControlFlagCollection + SOURCES test/testQualityControlFlagCollection.cxx COMPONENT_NAME DataFormatsQualityControl PUBLIC_LINK_LIBRARIES O2::DataFormatsQualityControl - TARGETVARNAME timerangeflagcollection) + TARGETVARNAME qualitycontrolflagcollection) -target_include_directories(${timerangeflagcollection} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include) +target_include_directories(${qualitycontrolflagcollection} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/include) endif() diff --git a/DataFormats/QualityControl/README.md b/DataFormats/QualityControl/README.md index ededa028c7b93..486856c983306 100644 --- a/DataFormats/QualityControl/README.md +++ b/DataFormats/QualityControl/README.md @@ -1,63 +1,99 @@ \page refDataFormatsQualityControl Data Formats Quality Control -Data formats for tagging good quality data for analysis. +## Tagging Good Quality Data for Processing and Analysis -# Flagging time ranges -## General idea -* Each detector has its own CCDB (QCDB) entry - TimeRangeFlagCollection -* The CCDB Entry validity will be run or fill, depending on the final data taking granularity -* Each entry can define sub ranges (TimeRangeFlags) of certain data characteristics (FlagReasons) inside the CCDB Entry validity -* Flags are defined in a CSV master file, they are used to derive the Data Tags - the final filters for good quality data during analysis. -* Data Tag are stored as CCDB entries. They might require different detectors and may suppress different flags dependent on the analysis type. - -## Implementation - -[Flag Reason](include/DataFormatsQualityControl/FlagReasons.h) is defined with an identifier number, a name and a 'bad quality' determinant. -The latter decides if such a flag should mark the data quality as bad by default. -FlagReasons can be created only with FlagReasonFactory, so that the list of available reasons is common and centralised. -For example: -``` -id: 10 -name: Limited Acceptance -bad: true -``` -The list of available FlagReasons is defined in [etc/flagReasons.csv](etc/flagReasons.csv), which is used to generate the corresponding list of methods in FlagReasonFactory. -The existing flags should never be modified, except for marking them as obsolete. -New flags may be added via pull requests if there is no flag which conveys a similar meaning. +This document outlines the data formats used for tagging good quality data for further processing and analysis. +They allow us to describe problems affecting the data in concrete time intervals. +Using this information, data can be filtered out according to criteria specific to a given analysis type. + +### Data Quality Control workflow + +Data quality is determined through two methods: + +1. **Automated Checks:** The Quality Control framework runs Checks which may return quality Flags. +2. **Manual Review:** Detector experts review data using the Run Condition Table (RCT) and can modify or add Flags. + +Both methods utilize the same data format for Flags. +During processing (both synchronous and asynchronous), Checks produce Qualities and associate them with Flags. +The Quality Control framework then transmits these Flags to the RCT through a gRPC interface (**not ready yet**, to be done in the scope of QC-978). +Detector experts can then review the automatically generated Flags and make any necessary modifications or additions directly in the RCT. + +### Quality Control Flag Structure + +A [Quality Control Flag](include/DataFormatsQualityControl/QualityControlFlag.h) consists of the following elements: + +* **Flag Type:** This identifies the specific issue the flag represents. (More details below) +* **Time Range:** This defines the time period affected by the flag. +* **Comment (Optional):** This allows human-readable explanations for assigning the flag. +* **Source String:** This identifies the entity (person or software module) that created the flag. + +**Example:** -With [TimeRangeFlags](include/DataFormatsQualityControl/TimeRangeFlag.h) we can define the time range of a chosen FlagReason, add an additional comment and specify the source of this flag. -For example: ``` -start: 1612707603626 +flag: Limited Acceptance MC Reproducible +start: 1612707603626 end: 1613999652000 -flag: Limited Acceptance comment: Sector B in TPC inactive -source: o2::quality_control_modules::tpc::ClustersCheck +source: TPC/Clusters Check ``` -[TimeRangeFlagCollection](include/DataFormatsQualityControl/TimeRangeFlagCollection.h) contains all TimeRangeFlags for the validity range (run or fill). -TimeRangeFlags may overlap, e.g. if they use different FlagReasons and they are sorted by their start time. -If certain period does not include any TimeRangeFlags with *bad* FlagReasons, then the data quality can be considered as good. -The [TimeRangeFlagCollection test](test/testTimeRangeFlagCollection.cxx) shows the usage example. +### Flag Types + +[Flag Types](include/DataFormatsQualityControl/FlagType.h) define the specific categories of issues represented by flags. +Each Flag Type has the following attributes: + +* **Identifier Number:** A unique numerical ID for the Flag Type. +* **Name:** A human-readable name describing the issue. +* **"Bad Quality" Determinant:** This boolean constant indicates whether the type inherently signifies bad data quality. + +#### Creating and Managing Flag Types + +* **FlagTypeFactory** ensures a centralized and consistent list of available Flag Types. + New types can only be created through this factory. +* **[flagTypes.csv](etc/flagTypes.csv)** defines the existing Flag Types, including their ID, name, and "bad quality" determinant, factory method name and a switch to deprecate a flag. + The table serves as the source to automatically generate the corresponding methods in FlagTypeFactory. +* **Adding new Flag Types:** If a new issue requires a flag not currently defined, propose the addition by contacting the async QC coordinators. + They have the authority to add new Flag Types to the RCT. + These changes will then be reflected in the [flagTypes.csv](etc/flagTypes.csv) file through a pull request. +* **Modification of existing Flag Types:** Existing Flag Types should not be modified in terms of their definition. + Instead, one may create a new Flag Type and mark the existing one as obsolete in the CSV table. + This will add the `[[ deprecated ]]` attribute to the corresponding method. -TimeRangeFlagCollections are supposed to be created automatically with QC Post-processing Tasks based on Quality Objects created by QC Checks. -However, they might be created manually by QA experts as well. -The procedure to do that has to be defined. +#### Currently available Flag Types -## TODO -* Define the complete list of available Flag Reasons -* implement CCDB storage and access - - define CCDB storage place e.g. - * `/QC/QualityFlags` - * `Analysis/QualityFlags/` -* Data Tags Definitions and Data Tags +This section details the currently available Flag Types and provides a brief explanation of their intended use cases. -### Notes on plans for Data Tags +* **Good:** a Check or an expert sees nothing wrong with given time interval, but would like to add a comment. + Note that the absence of any flag for a run implies good data quality. + Thus, there is no need to mark it explicitly as such by using this flag type. +* **No Detector Data:** a complete and unexpected absence of data for a specific detector. +* **Limited Acceptance MC Not Reproducible:** a part of a detector did not acquire good data and this condition cannot be reproduced in Monte Carlo. + If an automated Check cannot determine MC reproducibility, it should default to "Not Reproducible" for later expert review. +* **Limited Acceptance MC Reproducible:** a part of a detector did not acquire good data, but this condition can be reproduced in Monte Carlo. +* **Bad Tracking:** analyses relying on accurate track reconstruction should not use this data. +* **Bad PID:** analyses relying on correct identification of all kinds of tracked particles should not use this data. +* **Bad Hadron PID:** analyses relying on correct hadron identification should not use this data. +* **Bad Electron PID:** analyses relying on correct electron identification should not use this data. +* **Bad Photon Calorimetry:** analyses relying on correct photon calorimetry should not use this data. +* **Bad EMCalorimetry:** analyses relying on correct electromagnetic calorimetry should not use this data. +* **Unknown:** the exact impact of an issue on the data is unclear, but it's likely bad. + Treat data with this flag with caution until further investigation. +* **Unknown Quality:** the quality of data could not be determined definitively. +* **Invalid:** there was an issue with processing the flags. + +## Usage in Analysis framework (plans, wishlist) + +## General idea +* RCT exports a read-only copy of the flags for each detector, run and pass combination in the CCDB. +* The Analysis framework uses the flags and user selection criteria to provide their Analysis Task with data matching these criteria. + **Data Tags** are the structures defining the good time intervals for the provided criteria. + +## Notes on plans for Data Tags Data Tag definition has: * name -* global suppression list for bad flag reasons (applies to all detectors) -* global requirement list for not bad flag reasons +* global suppression list for bad flag types (applies to all detectors) +* global requirement list for not bad flag types * list of needed detectors, * list of suppression list and requirement list specific to detectors @@ -94,10 +130,3 @@ Example configurations } ] ``` - -## Wishlist / Ideas -* executable to add flags to the flag store -* executable to extrags the flag store -* summary of all masks for one TimeRangeFlagCollection -* functionality to extract flags for a specific detector (from CCDB) -* cut class to specify detectors and flags which to exclude \ No newline at end of file diff --git a/DataFormats/QualityControl/etc/flagReasons.csv b/DataFormats/QualityControl/etc/flagReasons.csv deleted file mode 100644 index 23acc1b3000fa..0000000000000 --- a/DataFormats/QualityControl/etc/flagReasons.csv +++ /dev/null @@ -1,15 +0,0 @@ -"id","method","name","bad","obsolete" -1,"Unknown","Unknown",1,0 -2,"UnknownQuality","Unknown Quality",1,0 -3,"CertifiedByExpert","Certified by Expert",0,0 -10,"NoDetectorData","No Detector Data",1,0 -11,"LimitedAcceptance","Limited acceptance",1,0 -12,"BadPID","Bad PID",1,0 -13,"BadTracking","Bad Tracking",1,0 -14,"BadHadronPID","Bad Hadron PID",1,0 -15,"BadElectronPID","Bad Electron PID",1,0 -16,"BadEMCalorimetry","Bad EM Calorimetry",1,0 -17,"BadPhotonCalorimetry","Bad Photon Calorimetry",1,0 -65500,"ObsoleteFlagExample","Obsolete flag example",1,1 -65501,"NotBadFlagExample","Not bad flag example",0,0 -65535,"Invalid","Invalid",1,0 diff --git a/DataFormats/QualityControl/etc/flagTypes.csv b/DataFormats/QualityControl/etc/flagTypes.csv new file mode 100644 index 0000000000000..b4504b0f8f896 --- /dev/null +++ b/DataFormats/QualityControl/etc/flagTypes.csv @@ -0,0 +1,15 @@ +"id","method","name","bad","obsolete" +1,"UnknownQuality","Unknown Quality",1,0 +3,"NoDetectorData","No Detector Data",1,0 +4,"LimitedAcceptanceMCNotReproducible","Limited Acceptance MC Not Reproducible",1,0 +5,"LimitedAcceptanceMCReproducible","Limited Acceptance MC Reproducible",1,0 +6,"BadPID","Bad PID",1,0 +7,"BadTracking","Bad Tracking",1,0 +8,"BadHadronPID","Bad Hadron PID",1,0 +9,"Good","Good",0,0 +10,"Invalid","Invalid",1,0 +11,"BadElectronPID","Bad Electron PID",1,0 +12,"BadEMCalorimetry","Bad EM Calorimetry",1,0 +13,"BadPhotonCalorimetry","Bad Photon Calorimetry",1,0 +14,"Unknown","Unknown",1,0 +65501,"NotBadFlagExample","Not bad flag example",0,0 \ No newline at end of file diff --git a/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagReasons.h b/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagReasons.h deleted file mode 100644 index 67f5b4cc27cde..0000000000000 --- a/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagReasons.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#ifndef ALICEO2_ANALYSIS_FLAGREASONS -#define ALICEO2_ANALYSIS_FLAGREASONS - -/// \file FlagReasons.h -/// \brief classes keeping reasons for flagging time ranges -/// \author Jens Wiechula, jens.wiechula@ikf.uni-frankfurt.de -/// \author Piotr Konopka, piotr.jan.konopka@cern.ch - -// STL -#include -#include - -// ROOT includes -#include - -namespace o2 -{ -namespace quality_control -{ - -class FlagReasonFactory; -class TimeRangeFlagCollection; - -class FlagReason -{ - private: - uint16_t mId; - std::string mName; - bool mBad; // if true, data should become bad by default - - // By making the constructor private and FlagReasons available only in the FlagReasonFactory - // we forbid to declare any flags in the user code. If you need a new FlagReason, please add it FlagReasonFactory. - private: - FlagReason(uint16_t id, const char* name, bool bad) : mId(id), mName(name), mBad(bad) {} - - public: - FlagReason(); - FlagReason& operator=(const FlagReason&) = default; - FlagReason(const FlagReason&) = default; - bool operator==(const FlagReason& rhs) const; - bool operator!=(const FlagReason& rhs) const; - bool operator<(const FlagReason& rhs) const; - bool operator>(const FlagReason& rhs) const; - - uint16_t getID() const { return mId; } - const std::string& getName() const { return mName; } - bool getBad() const { return mBad; } - - friend std::ostream& operator<<(std::ostream& os, FlagReason const& me); - friend class FlagReasonFactory; - friend class TimeRangeFlagCollection; - - ClassDefNV(FlagReason, 1); -}; - -} // namespace quality_control -} // namespace o2 - -// TODO: remove once we include it in QualityControl -#include "DataFormatsQualityControl/FlagReasonFactory.h" - -#endif diff --git a/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagType.h b/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagType.h new file mode 100644 index 0000000000000..94e4a301a1784 --- /dev/null +++ b/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagType.h @@ -0,0 +1,64 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_QUALITYCONTROL_FLAGTYPE_H +#define O2_QUALITYCONTROL_FLAGTYPE_H + +// STL +#include +#include + +// ROOT includes +#include + +namespace o2 +{ +namespace quality_control +{ + +class FlagTypeFactory; +class QualityControlFlagCollection; + +class FlagType +{ + private: + uint16_t mId; + std::string mName; + bool mBad; // if true, data should become bad by default + + // By making the constructor private and FlagTypes available only in the FlagTypeFactory + // we forbid to declare any flags in the user code. If you need a new FlagType, please add it FlagTypeFactory. + private: + FlagType(uint16_t id, const char* name, bool bad) : mId(id), mName(name), mBad(bad) {} + + public: + FlagType(); + FlagType& operator=(const FlagType&) = default; + FlagType(const FlagType&) = default; + bool operator==(const FlagType& rhs) const; + bool operator!=(const FlagType& rhs) const; + bool operator<(const FlagType& rhs) const; + bool operator>(const FlagType& rhs) const; + + uint16_t getID() const { return mId; } + const std::string& getName() const { return mName; } + bool getBad() const { return mBad; } + + friend std::ostream& operator<<(std::ostream& os, FlagType const& me); + friend class FlagTypeFactory; + friend class QualityControlFlagCollection; + + ClassDefNV(FlagType, 1); +}; + +} // namespace quality_control +} // namespace o2 +#endif // O2_QUALITYCONTROL_FLAGTYPE_H diff --git a/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagReasonFactory.h.in b/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagTypeFactory.h.in similarity index 67% rename from DataFormats/QualityControl/include/DataFormatsQualityControl/FlagReasonFactory.h.in rename to DataFormats/QualityControl/include/DataFormatsQualityControl/FlagTypeFactory.h.in index 59bd7b4c5628f..38b6c463d239f 100644 --- a/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagReasonFactory.h.in +++ b/DataFormats/QualityControl/include/DataFormatsQualityControl/FlagTypeFactory.h.in @@ -9,23 +9,23 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file FlagReasonFactory.h -/// \brief A class to create FlagReasons based on the predefined CSV list. +/// \file FlagTypeFactory.h +/// \brief A class to create FlagTypes based on the predefined CSV list. /// \author Piotr Konopka, piotr.jan.konopka@cern.ch -#ifndef O2_FLAGREASONFACTORY_H -#define O2_FLAGREASONFACTORY_H +#ifndef O2_FLAGTYPEFACTORY_H +#define O2_FLAGTYPEFACTORY_H -#include "DataFormatsQualityControl/FlagReasons.h" +#include "DataFormatsQualityControl/FlagType.h" namespace o2::quality_control { -class FlagReasonFactory { +class FlagTypeFactory { public: -FlagReasonFactory() = delete; -@CSV_FLAG_REASONS@ +FlagTypeFactory() = delete; +@CSV_FLAG_TYPES@ }; } // namespace o2::quality_control -#endif // O2_FLAGREASONFACTORY_H \ No newline at end of file +#endif // O2_FLAGTYPEFACTORY_H \ No newline at end of file diff --git a/DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlag.h b/DataFormats/QualityControl/include/DataFormatsQualityControl/QualityControlFlag.h similarity index 67% rename from DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlag.h rename to DataFormats/QualityControl/include/DataFormatsQualityControl/QualityControlFlag.h index b8e1efbce1f40..16123b74895ab 100644 --- a/DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlag.h +++ b/DataFormats/QualityControl/include/DataFormatsQualityControl/QualityControlFlag.h @@ -9,11 +9,11 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef ALICEO2_ANALYSIS_TIMERANGEFLAGS -#define ALICEO2_ANALYSIS_TIMERANGEFLAGS +#ifndef O2_QUALITYCONTROL_QCFLAG_H +#define O2_QUALITYCONTROL_QCFLAG_H -/// \file TimeRangeFlag.h -/// \brief Class to define a time range of a flag type +/// \file QualityControlFlag.h +/// \brief Class to define a flag type with a time range and comments /// \author Jens Wiechula, jens.wiechula@ikf.uni-frankfurt.de /// \author Piotr Konopka, piotr.jan.konopka@cern.ch @@ -26,63 +26,62 @@ #include -#include "DataFormatsQualityControl/FlagReasons.h" -#include "DataFormatsQualityControl/FlagReasonFactory.h" +#include "DataFormatsQualityControl/FlagType.h" +#include "DataFormatsQualityControl/FlagTypeFactory.h" namespace o2 { namespace quality_control { -/// \class TimeRangeFlag +/// \class QualityControlFlag /// A Class for associating a bit mask with a time range -class TimeRangeFlag +class QualityControlFlag { public: using time_type = uint64_t; - using flag_type = FlagReason; using RangeInterval = o2::math_utils::detail::Bracket; - TimeRangeFlag() = default; - TimeRangeFlag(TimeRangeFlag const&) = default; - TimeRangeFlag(time_type start, time_type end, flag_type flag, std::string comment = "", std::string source = "Unknown"); + QualityControlFlag() = default; + QualityControlFlag(QualityControlFlag const&) = default; + QualityControlFlag(time_type start, time_type end, FlagType flag, std::string comment = "", std::string source = "Unknown"); time_type getStart() const { return mInterval.getMin(); } time_type getEnd() const { return mInterval.getMax(); } RangeInterval& getInterval() { return mInterval; } - flag_type getFlag() const { return mFlag; } + FlagType getFlag() const { return mFlag; } const std::string& getComment() const { return mComment; } const std::string& getSource() const { return mSource; } void setStart(time_type start) { mInterval.setMin(start); } void setEnd(time_type end) { mInterval.setMax(end); } void setInterval(RangeInterval interval) { mInterval = interval; } - void setFlag(flag_type flag) { mFlag = flag; } + void setFlag(FlagType flag) { mFlag = flag; } void setComment(const std::string& comment) { mComment = comment; } void setSource(const std::string& source) { mSource = source; } /// equal operator - bool operator==(const TimeRangeFlag& rhs) const; + bool operator==(const QualityControlFlag& rhs) const; /// comparison operators - bool operator<(const TimeRangeFlag& rhs) const; - bool operator>(const TimeRangeFlag& rhs) const; + bool operator<(const QualityControlFlag& rhs) const; + bool operator>(const QualityControlFlag& rhs) const; /// write data to ostream void streamTo(std::ostream& output) const; /// overloading output stream operator - friend std::ostream& operator<<(std::ostream& output, const TimeRangeFlag& data); + friend std::ostream& operator<<(std::ostream& output, const QualityControlFlag& data); private: RangeInterval mInterval = {}; ///< time interval of the masked range - flag_type mFlag; ///< flag reason + FlagType mFlag; ///< flag reason std::string mComment = ""; ///< optional comment, which may extend the reason std::string mSource = "Unknown"; ///< optional (but encouraged) source of the flag (e.g. Qc Check name) - ClassDefNV(TimeRangeFlag, 1); + ClassDefNV(QualityControlFlag, 1); }; } // namespace quality_control } // namespace o2 -#endif +#endif // O2_QUALITYCONTROL_QCFLAG_H diff --git a/DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlagCollection.h b/DataFormats/QualityControl/include/DataFormatsQualityControl/QualityControlFlagCollection.h similarity index 61% rename from DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlagCollection.h rename to DataFormats/QualityControl/include/DataFormatsQualityControl/QualityControlFlagCollection.h index 30a8230fc66e2..120605f048cbe 100644 --- a/DataFormats/QualityControl/include/DataFormatsQualityControl/TimeRangeFlagCollection.h +++ b/DataFormats/QualityControl/include/DataFormatsQualityControl/QualityControlFlagCollection.h @@ -9,10 +9,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#ifndef ALICEO2_ANALYSIS_TIMERANGEMASK -#define ALICEO2_ANALYSIS_TIMERANGEMASK - -/// \file TimeRangeFlagCollection.h +#ifndef O2_QUALITYCONTROL_QCFLAGCOLLECTION_H +#define O2_QUALITYCONTROL_QCFLAGCOLLECTION_H +/// \file QualityControlFlagCollection.h /// \brief classes for defining time ranges with a certain mask to be able to cut on /// \author Jens Wiechula, jens.wiechula@ikf.uni-frankfurt.de @@ -24,7 +23,7 @@ // O2 includes #include "MathUtils/detail/Bracket.h" -#include "DataFormatsQualityControl/TimeRangeFlag.h" +#include "DataFormatsQualityControl/QualityControlFlag.h" // STL #include @@ -34,28 +33,28 @@ namespace o2 namespace quality_control { -/// \class TimeRangeFlagCollection -/// A Class for keeping several time ranges of type TimeRangeFlag -class TimeRangeFlagCollection +/// \class QualityControlFlagCollection +/// A Class for keeping several time ranges of type QualityControlFlag +class QualityControlFlagCollection { public: - using collection_t = std::set; + using collection_t = std::set; using time_type = uint64_t; using RangeInterval = o2::math_utils::detail::Bracket; - explicit TimeRangeFlagCollection(std::string name, std::string detector = "TST", RangeInterval validityRange = {}, - int runNumber = 0, std::string periodName = "Invalid", std::string passName = "Invalid", - std::string provenance = "qc"); + explicit QualityControlFlagCollection(std::string name, std::string detector = "TST", RangeInterval validityRange = {}, + int runNumber = 0, std::string periodName = "Invalid", std::string passName = "Invalid", + std::string provenance = "qc"); - void insert(TimeRangeFlag&&); - void insert(const TimeRangeFlag&); + void insert(QualityControlFlag&&); + void insert(const QualityControlFlag&); size_t size() const; - // moves all non-repeating TimeRangeFlags from other to this - void merge(TimeRangeFlagCollection& other); - // add all non-repeating TimeRangeFlags from other to this. - void merge(const TimeRangeFlagCollection& other); + // moves all non-repeating QualityControlFlags from other to this + void merge(QualityControlFlagCollection& other); + // add all non-repeating QualityControlFlags from other to this. + void merge(const QualityControlFlagCollection& other); collection_t::const_iterator begin() const; collection_t::const_iterator end() const; @@ -81,22 +80,23 @@ class TimeRangeFlagCollection void streamFrom(std::istream& input); /// overloading output stream operator - friend std::ostream& operator<<(std::ostream& output, const TimeRangeFlagCollection& data); + friend std::ostream& operator<<(std::ostream& output, const QualityControlFlagCollection& data); private: - std::string mDetID; // three letter detector code - std::string mName; // some description of the collection, e.g. "Raw data checks", "QA Expert masks" + std::string mDetID; // three letter detector code + std::string mName; // some description of the collection, e.g. "Raw data checks", "QA Expert masks" // with std::set we can sort the flags in time and have merge() for granted. - collection_t mTimeRangeFlags; + collection_t mQualityControlFlags; RangeInterval mValidityRange; // we need a validity range to e.g. state that there are no TRFs for given time interval int mRunNumber; std::string mPeriodName; std::string mPassName; std::string mProvenance; - ClassDefNV(TimeRangeFlagCollection, 1); + ClassDefNV(QualityControlFlagCollection, 1); }; } // namespace quality_control } // namespace o2 -#endif + +#endif // O2_QUALITYCONTROL_QCFLAGCOLLECTION_H diff --git a/DataFormats/QualityControl/src/DataFormatsQualityControlLinkDef.h b/DataFormats/QualityControl/src/DataFormatsQualityControlLinkDef.h index 8d77bccef4b7c..ab10c361b29f9 100644 --- a/DataFormats/QualityControl/src/DataFormatsQualityControlLinkDef.h +++ b/DataFormats/QualityControl/src/DataFormatsQualityControlLinkDef.h @@ -15,8 +15,8 @@ #pragma link off all classes; #pragma link off all functions; -#pragma link C++ class o2::quality_control::FlagReason + ; -#pragma link C++ class o2::quality_control::TimeRangeFlag + ; -#pragma link C++ class o2::quality_control::TimeRangeFlagCollection + ; +#pragma link C++ class o2::quality_control::FlagType + ; +#pragma link C++ class o2::quality_control::QualityControlFlag + ; +#pragma link C++ class o2::quality_control::QualityControlFlagCollection + ; #endif diff --git a/DataFormats/QualityControl/src/FlagReasons.cxx b/DataFormats/QualityControl/src/FlagType.cxx similarity index 70% rename from DataFormats/QualityControl/src/FlagReasons.cxx rename to DataFormats/QualityControl/src/FlagType.cxx index e85a0d0c7faa7..27e59911ed775 100644 --- a/DataFormats/QualityControl/src/FlagReasons.cxx +++ b/DataFormats/QualityControl/src/FlagType.cxx @@ -9,8 +9,8 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "DataFormatsQualityControl/FlagReasons.h" -#include "DataFormatsQualityControl/FlagReasonFactory.h" +#include "DataFormatsQualityControl/FlagType.h" +#include "DataFormatsQualityControl/FlagTypeFactory.h" #include #include @@ -18,29 +18,29 @@ namespace o2::quality_control { -FlagReason::FlagReason() +FlagType::FlagType() { - *this = FlagReasonFactory::Invalid(); + *this = FlagTypeFactory::Invalid(); } -std::ostream& operator<<(std::ostream& os, FlagReason const& my) +std::ostream& operator<<(std::ostream& os, FlagType const& my) { os << "Flag Reason: id - " << my.mId << ", name - " << my.mName << ", bad - " << (my.mBad ? "true" : "false"); return os; } -bool FlagReason::operator==(const FlagReason& rhs) const +bool FlagType::operator==(const FlagType& rhs) const { return std::tie(mId, mName, mBad) == std::tie(rhs.mId, rhs.mName, rhs.mBad); } -bool FlagReason::operator!=(const FlagReason& rhs) const +bool FlagType::operator!=(const FlagType& rhs) const { return std::tie(mId, mName, mBad) != std::tie(rhs.mId, rhs.mName, rhs.mBad); } -bool FlagReason::operator<(const FlagReason& rhs) const +bool FlagType::operator<(const FlagType& rhs) const { return std::tie(mId, mName, mBad) < std::tie(rhs.mId, rhs.mName, rhs.mBad); } -bool FlagReason::operator>(const FlagReason& rhs) const +bool FlagType::operator>(const FlagType& rhs) const { return std::tie(mId, mName, mBad) > std::tie(rhs.mId, rhs.mName, rhs.mBad); } diff --git a/DataFormats/QualityControl/src/TimeRangeFlag.cxx b/DataFormats/QualityControl/src/QualityControlFlag.cxx similarity index 74% rename from DataFormats/QualityControl/src/TimeRangeFlag.cxx rename to DataFormats/QualityControl/src/QualityControlFlag.cxx index f96d5bc9b7b72..ce749cad5315f 100644 --- a/DataFormats/QualityControl/src/TimeRangeFlag.cxx +++ b/DataFormats/QualityControl/src/QualityControlFlag.cxx @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "DataFormatsQualityControl/TimeRangeFlag.h" +#include "DataFormatsQualityControl/QualityControlFlag.h" #include #include @@ -17,20 +17,20 @@ namespace o2::quality_control { -TimeRangeFlag::TimeRangeFlag(time_type start, time_type end, flag_type flag, std::string comment, std::string source) +QualityControlFlag::QualityControlFlag(time_type start, time_type end, FlagType flag, std::string comment, std::string source) : mInterval(start, end), mFlag(flag), mComment(comment), mSource(source) { if (mInterval.isInvalid()) { - throw std::runtime_error("TimeRangeFlag start time '" + std::to_string(mInterval.getMin()) + "' is larger than end time '" + std::to_string(mInterval.getMax()) + "'"); + throw std::runtime_error("QualityControlFlag start time '" + std::to_string(mInterval.getMin()) + "' is larger than end time '" + std::to_string(mInterval.getMax()) + "'"); } } -bool TimeRangeFlag::operator==(const TimeRangeFlag& rhs) const +bool QualityControlFlag::operator==(const QualityControlFlag& rhs) const { return std::tie(mInterval, mFlag, mComment, mSource) == std::tie(rhs.mInterval, rhs.mFlag, rhs.mComment, rhs.mSource); } -bool TimeRangeFlag::operator<(const TimeRangeFlag& rhs) const +bool QualityControlFlag::operator<(const QualityControlFlag& rhs) const { // We don't use the comparison mechanism in Bracket, // because std::set which is used in TRFCollection assumes that a < b, a > b <=> a == b. @@ -38,16 +38,16 @@ bool TimeRangeFlag::operator<(const TimeRangeFlag& rhs) const return std::tie(static_cast(mInterval.getMin()), static_cast(mInterval.getMax()), mFlag, mComment, mSource) < std::tie(static_cast(rhs.mInterval.getMin()), static_cast(rhs.mInterval.getMax()), rhs.mFlag, rhs.mComment, rhs.mSource); } -bool TimeRangeFlag::operator>(const TimeRangeFlag& rhs) const +bool QualityControlFlag::operator>(const QualityControlFlag& rhs) const { // we don't use the comparison mechanism in Bracket, // because std::set which is used in TRFCollection assumes that a < b, a > b <=> a == b return std::tie(static_cast(mInterval.getMin()), static_cast(mInterval.getMax()), mFlag, mComment, mSource) > std::tie(static_cast(rhs.mInterval.getMin()), static_cast(rhs.mInterval.getMax()), rhs.mFlag, rhs.mComment, rhs.mSource); } -void TimeRangeFlag::streamTo(std::ostream& output) const +void QualityControlFlag::streamTo(std::ostream& output) const { - output << "TimeRangeFlag:\n"; + output << "QualityControlFlag:\n"; output << "- Start: " << mInterval.getMin() << "\n"; output << "- End: " << mInterval.getMax() << "\n"; output << "- " << mFlag << "\n"; @@ -55,7 +55,7 @@ void TimeRangeFlag::streamTo(std::ostream& output) const output << "- Source: " << mSource; } -std::ostream& operator<<(std::ostream& output, const TimeRangeFlag& data) +std::ostream& operator<<(std::ostream& output, const QualityControlFlag& data) { data.streamTo(output); return output; diff --git a/DataFormats/QualityControl/src/TimeRangeFlagCollection.cxx b/DataFormats/QualityControl/src/QualityControlFlagCollection.cxx similarity index 65% rename from DataFormats/QualityControl/src/TimeRangeFlagCollection.cxx rename to DataFormats/QualityControl/src/QualityControlFlagCollection.cxx index ee3adc8dc7f2f..042ef2f218d09 100644 --- a/DataFormats/QualityControl/src/TimeRangeFlagCollection.cxx +++ b/DataFormats/QualityControl/src/QualityControlFlagCollection.cxx @@ -10,8 +10,8 @@ // or submit itself to any jurisdiction. // O2 include -#include "DataFormatsQualityControl/TimeRangeFlagCollection.h" -#include "DataFormatsQualityControl/FlagReasonFactory.h" +#include "DataFormatsQualityControl/QualityControlFlagCollection.h" +#include "DataFormatsQualityControl/FlagTypeFactory.h" #include "Framework/Logger.h" #include @@ -25,56 +25,56 @@ namespace o2::quality_control constexpr const char* csvHeader = "start,end,flag_id,flag_name,flag_bad,comment,source"; constexpr size_t csvColumns = 7; -TimeRangeFlagCollection::TimeRangeFlagCollection(std::string name, std::string detector, RangeInterval validityRange, - int runNumber, std::string periodName, std::string passName, - std::string provenance) +QualityControlFlagCollection::QualityControlFlagCollection(std::string name, std::string detector, RangeInterval validityRange, + int runNumber, std::string periodName, std::string passName, + std::string provenance) : mName(std::move(name)), mDetID(std::move(detector)), mValidityRange(validityRange), mRunNumber(runNumber), mPeriodName(std::move(periodName)), mPassName(passName), mProvenance(std::move(provenance)) { } -void TimeRangeFlagCollection::insert(TimeRangeFlag&& trf) +void QualityControlFlagCollection::insert(QualityControlFlag&& trf) { - mTimeRangeFlags.insert(std::move(trf)); + mQualityControlFlags.insert(std::move(trf)); } -void TimeRangeFlagCollection::insert(const TimeRangeFlag& trf) +void QualityControlFlagCollection::insert(const QualityControlFlag& trf) { - mTimeRangeFlags.insert(trf); + mQualityControlFlags.insert(trf); } -size_t TimeRangeFlagCollection::size() const +size_t QualityControlFlagCollection::size() const { - return mTimeRangeFlags.size(); + return mQualityControlFlags.size(); } -void TimeRangeFlagCollection::merge(TimeRangeFlagCollection& other) +void QualityControlFlagCollection::merge(QualityControlFlagCollection& other) { if (mDetID != other.mDetID) { - // We assume that one TimeRangeFlagCollection should correspond to one detector at most. + // We assume that one QualityControlFlagCollection should correspond to one detector at most. // However, if this becomes annoying, we can reconsider it. throw std::runtime_error( "The detector ID of the target collection '" + mDetID + "' is different than the other '" + mDetID); } - mTimeRangeFlags.merge(other.mTimeRangeFlags); + mQualityControlFlags.merge(other.mQualityControlFlags); } -void TimeRangeFlagCollection::merge(const TimeRangeFlagCollection& other) +void QualityControlFlagCollection::merge(const QualityControlFlagCollection& other) { - TimeRangeFlagCollection otherCopy{other}; + QualityControlFlagCollection otherCopy{other}; merge(otherCopy); } -TimeRangeFlagCollection::collection_t::const_iterator TimeRangeFlagCollection::begin() const +QualityControlFlagCollection::collection_t::const_iterator QualityControlFlagCollection::begin() const { - return mTimeRangeFlags.begin(); + return mQualityControlFlags.begin(); } -TimeRangeFlagCollection::collection_t::const_iterator TimeRangeFlagCollection::end() const +QualityControlFlagCollection::collection_t::const_iterator QualityControlFlagCollection::end() const { - return mTimeRangeFlags.end(); + return mQualityControlFlags.end(); } -void TimeRangeFlagCollection::streamTo(std::ostream& output) const +void QualityControlFlagCollection::streamTo(std::ostream& output) const { auto escapeComma = [](const std::string& str) { return boost::algorithm::replace_all_copy(str, ",", "\\,"); @@ -88,7 +88,7 @@ void TimeRangeFlagCollection::streamTo(std::ostream& output) const } } -void TimeRangeFlagCollection::streamFrom(std::istream& input) +void QualityControlFlagCollection::streamFrom(std::istream& input) { std::string line; std::getline(input, line); @@ -100,9 +100,9 @@ void TimeRangeFlagCollection::streamFrom(std::istream& input) while (std::getline(input, line)) { boost::tokenizer> tok(line); - TimeRangeFlag::time_type start = 0; - TimeRangeFlag::time_type end = 0; - FlagReason flag = FlagReasonFactory::Invalid(); + QualityControlFlag::time_type start = 0; + QualityControlFlag::time_type end = 0; + FlagType flag = FlagTypeFactory::Invalid(); std::string comment; std::string source; auto it = tok.begin(); @@ -115,7 +115,7 @@ void TimeRangeFlagCollection::streamFrom(std::istream& input) LOG(error) << "Invalid line, empty start time of a flag, skipping..."; valid = false; } else { - start = static_cast(std::stoull(*it)); + start = static_cast(std::stoull(*it)); } break; } @@ -124,7 +124,7 @@ void TimeRangeFlagCollection::streamFrom(std::istream& input) LOG(error) << "Invalid line, empty end time of a flag, skipping..."; valid = false; } else { - end = static_cast(std::stoull(*it)); + end = static_cast(std::stoull(*it)); } break; } @@ -179,37 +179,37 @@ void TimeRangeFlagCollection::streamFrom(std::istream& input) } } -std::ostream& operator<<(std::ostream& output, const TimeRangeFlagCollection& data) +std::ostream& operator<<(std::ostream& output, const QualityControlFlagCollection& data) { data.streamTo(output); return output; } -const std::string& TimeRangeFlagCollection::getName() const +const std::string& QualityControlFlagCollection::getName() const { return mName; } -const std::string& TimeRangeFlagCollection::getDetector() const +const std::string& QualityControlFlagCollection::getDetector() const { return mDetID; } -int TimeRangeFlagCollection::getRunNumber() const +int QualityControlFlagCollection::getRunNumber() const { return mRunNumber; } -const std::string& TimeRangeFlagCollection::getPeriodName() const +const std::string& QualityControlFlagCollection::getPeriodName() const { return mPeriodName; } -const std::string& TimeRangeFlagCollection::getPassName() const +const std::string& QualityControlFlagCollection::getPassName() const { return mPassName; } -const std::string& TimeRangeFlagCollection::getProvenance() const +const std::string& QualityControlFlagCollection::getProvenance() const { return mProvenance; } diff --git a/DataFormats/QualityControl/test/testFlagReasons.cxx b/DataFormats/QualityControl/test/testFlagReasons.cxx deleted file mode 100644 index 9e7ff15383674..0000000000000 --- a/DataFormats/QualityControl/test/testFlagReasons.cxx +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#define BOOST_TEST_MODULE Test quality_control FlagReasons class -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK - -#include - -#include -#include - -// o2 includes -#include "DataFormatsQualityControl/FlagReasons.h" -#include "DataFormatsQualityControl/FlagReasonFactory.h" - -using namespace o2::quality_control; - -BOOST_AUTO_TEST_CASE(FlagReasons) -{ - static_assert(std::is_constructible::value == false, - "FlagReason should not be constructible outside of its static methods and the factory."); - - FlagReason rDefault; - BOOST_CHECK_EQUAL(rDefault, FlagReasonFactory::Invalid()); - - auto r1 = FlagReasonFactory::Unknown(); - BOOST_CHECK_EQUAL(r1.getID(), 1); - BOOST_CHECK_EQUAL(r1.getName(), "Unknown"); - BOOST_CHECK_EQUAL(r1.getBad(), true); - - std::cout << r1 << std::endl; - - auto r2 = r1; - BOOST_CHECK_EQUAL(r2.getID(), 1); - BOOST_CHECK_EQUAL(r1.getName(), r2.getName()); - BOOST_CHECK_EQUAL(r2.getName(), "Unknown"); - BOOST_CHECK_EQUAL(r2.getBad(), true); - - BOOST_CHECK_EQUAL(r1, r2); - BOOST_CHECK((r1 != r2) == false); - BOOST_CHECK(!(r1 < r2)); - BOOST_CHECK(!(r1 > r2)); - - auto r3 = FlagReasonFactory::LimitedAcceptance(); - BOOST_CHECK(r3 > r1); - BOOST_CHECK(!(r3 < r1)); -} diff --git a/DataFormats/QualityControl/test/testFlagTypes.cxx b/DataFormats/QualityControl/test/testFlagTypes.cxx new file mode 100644 index 0000000000000..2fe904aa1c167 --- /dev/null +++ b/DataFormats/QualityControl/test/testFlagTypes.cxx @@ -0,0 +1,56 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test quality_control FlagTypes class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include + +#include +#include + +// o2 includes +#include "DataFormatsQualityControl/FlagType.h" +#include "DataFormatsQualityControl/FlagTypeFactory.h" + +using namespace o2::quality_control; + +BOOST_AUTO_TEST_CASE(FlagTypes) +{ + static_assert(std::is_constructible::value == false, + "FlagType should not be constructible outside of its static methods and the factory."); + + FlagType fDefault; + BOOST_CHECK_EQUAL(fDefault, FlagTypeFactory::Invalid()); + + auto f1 = FlagTypeFactory::Unknown(); + BOOST_CHECK_EQUAL(f1.getID(), 14); + BOOST_CHECK_EQUAL(f1.getName(), "Unknown"); + BOOST_CHECK_EQUAL(f1.getBad(), true); + + BOOST_CHECK_NO_THROW(std::cout << f1 << std::endl); + + auto f2 = f1; + BOOST_CHECK_EQUAL(f2.getID(), 14); + BOOST_CHECK_EQUAL(f1.getName(), f2.getName()); + BOOST_CHECK_EQUAL(f2.getName(), "Unknown"); + BOOST_CHECK_EQUAL(f2.getBad(), true); + + BOOST_CHECK_EQUAL(f1, f2); + BOOST_CHECK((f1 != f2) == false); + BOOST_CHECK(!(f1 < f2)); + BOOST_CHECK(!(f1 > f2)); + + auto f3 = FlagTypeFactory::LimitedAcceptanceMCNotReproducible(); + BOOST_CHECK(f3 < f1); + BOOST_CHECK(!(f3 > f1)); +} diff --git a/DataFormats/QualityControl/test/testQualityControlFlag.cxx b/DataFormats/QualityControl/test/testQualityControlFlag.cxx new file mode 100644 index 0000000000000..2990b3bbd355f --- /dev/null +++ b/DataFormats/QualityControl/test/testQualityControlFlag.cxx @@ -0,0 +1,40 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test quality_control QualityControlFlag class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +// boost includes +#include + +// o2 includes +#include "DataFormatsQualityControl/QualityControlFlag.h" + +using namespace o2::quality_control; + +BOOST_AUTO_TEST_CASE(test_QualityControlFlag) +{ + QualityControlFlag qcFlag1{12, 34, FlagTypeFactory::BadTracking(), "comment", "source"}; + + BOOST_CHECK_EQUAL(qcFlag1.getStart(), 12); + BOOST_CHECK_EQUAL(qcFlag1.getEnd(), 34); + BOOST_CHECK_EQUAL(qcFlag1.getFlag(), FlagTypeFactory::BadTracking()); + BOOST_CHECK_EQUAL(qcFlag1.getComment(), "comment"); + BOOST_CHECK_EQUAL(qcFlag1.getSource(), "source"); + + BOOST_CHECK_THROW((QualityControlFlag{12, 0, FlagTypeFactory::BadTracking()}), std::runtime_error); + + QualityControlFlag qcFlag2{10, 34, FlagTypeFactory::BadTracking(), "comment", "source"}; + + BOOST_CHECK(qcFlag1 > qcFlag2); + BOOST_CHECK(!(qcFlag1 < qcFlag2)); +} \ No newline at end of file diff --git a/DataFormats/QualityControl/test/testQualityControlFlagCollection.cxx b/DataFormats/QualityControl/test/testQualityControlFlagCollection.cxx new file mode 100644 index 0000000000000..198ae29bc53a6 --- /dev/null +++ b/DataFormats/QualityControl/test/testQualityControlFlagCollection.cxx @@ -0,0 +1,136 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test quality_control QualityControlFlagCollection class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +// boost includes +#include +// STL +#include +// o2 includes +#include "DataFormatsQualityControl/QualityControlFlagCollection.h" +#include "DataFormatsQualityControl/QualityControlFlag.h" +#include "DataFormatsQualityControl/FlagTypeFactory.h" + +using namespace o2::quality_control; + +BOOST_AUTO_TEST_CASE(test_QualityControlFlagCollection_Methods) +{ + QualityControlFlag flag1{12, 34, FlagTypeFactory::BadTracking(), "comment", "source"}; + QualityControlFlag flag2{10, 34, FlagTypeFactory::BadTracking(), "comment", "source"}; + + QualityControlFlagCollection qcfc1{"Raw data checks", "TOF", {10, 20000}, 12345, "LHC22k5", "passMC", "qc_mc"}; + qcfc1.insert(flag1); // by copy + qcfc1.insert(flag2); + qcfc1.insert({50, 77, FlagTypeFactory::Invalid()}); // by move + BOOST_CHECK_EQUAL(qcfc1.size(), 3); + BOOST_CHECK_EQUAL(qcfc1.getName(), "Raw data checks"); + BOOST_CHECK_EQUAL(qcfc1.getDetector(), "TOF"); + BOOST_CHECK_EQUAL(qcfc1.getStart(), 10); + BOOST_CHECK_EQUAL(qcfc1.getEnd(), 20000); + BOOST_CHECK_EQUAL(qcfc1.getRunNumber(), 12345); + BOOST_CHECK_EQUAL(qcfc1.getPeriodName(), "LHC22k5"); + BOOST_CHECK_EQUAL(qcfc1.getPassName(), "passMC"); + BOOST_CHECK_EQUAL(qcfc1.getProvenance(), "qc_mc"); + + QualityControlFlagCollection qcfc2{"Reco checks", "TOF"}; + qcfc2.insert({50, 77, FlagTypeFactory::Invalid()}); // this is a duplicate to an entry in qcfc1 + qcfc2.insert({51, 77, FlagTypeFactory::Invalid()}); + qcfc2.insert({1234, 3434, FlagTypeFactory::LimitedAcceptanceMCNotReproducible()}); + qcfc2.insert({50, 77, FlagTypeFactory::LimitedAcceptanceMCNotReproducible()}); + BOOST_CHECK_EQUAL(qcfc2.size(), 4); + + // Try merging. Duplicate entries should be left in the 'other' objects. + // Notice that we merge the two partial TRFCs into the third, which covers all cases + QualityControlFlagCollection qcfc3{"ALL", "TOF"}; + qcfc3.merge(qcfc1); + qcfc3.merge(qcfc2); + BOOST_CHECK_EQUAL(qcfc1.size(), 0); + BOOST_CHECK_EQUAL(qcfc2.size(), 1); + BOOST_CHECK_EQUAL(qcfc3.size(), 6); + + // Try const merging. It should copy the elements and keep the 'other' intact. + QualityControlFlagCollection qcfc4{"ALL", "TOF"}; + const auto& constTrfc3 = qcfc3; + qcfc4.merge(constTrfc3); + BOOST_CHECK_EQUAL(qcfc3.size(), 6); + BOOST_CHECK_EQUAL(qcfc4.size(), 6); + + // Try merging different detectors - it should throw. + QualityControlFlagCollection qcfc5{"ALL", "TPC"}; + BOOST_CHECK_THROW(qcfc5.merge(qcfc3), std::runtime_error); + BOOST_CHECK_THROW(qcfc5.merge(constTrfc3), std::runtime_error); + + // try printing + std::cout << qcfc3 << std::endl; + + // iterating + for (const auto& flag : qcfc3) { + (void)flag; + } +} + +BOOST_AUTO_TEST_CASE(test_QualityControlFlagCollection_IO) +{ + { + QualityControlFlagCollection qcfc1{"xyz", "TST"}; + + std::stringstream store; + qcfc1.streamTo(store); + + QualityControlFlagCollection qcfc2{"xyz", "TST"}; + qcfc2.streamFrom(store); + + BOOST_CHECK_EQUAL(qcfc2.size(), 0); + } + { + QualityControlFlagCollection qcfc1{"xyz", "TST"}; + qcfc1.insert({50, 77, FlagTypeFactory::Invalid(), "a comment", "a source"}); + qcfc1.insert({51, 77, FlagTypeFactory::Invalid()}); + qcfc1.insert({1234, 3434, FlagTypeFactory::LimitedAcceptanceMCNotReproducible()}); + qcfc1.insert({50, 77, FlagTypeFactory::LimitedAcceptanceMCNotReproducible()}); + qcfc1.insert({43434, 63421, FlagTypeFactory::NotBadFlagExample()}); + + std::stringstream store; + qcfc1.streamTo(store); + + QualityControlFlagCollection qcfc2{"xyz", "TST"}; + qcfc2.streamFrom(store); + + BOOST_REQUIRE_EQUAL(qcfc1.size(), qcfc2.size()); + for (auto it1 = qcfc1.begin(), it2 = qcfc2.begin(); it1 != qcfc1.end() && it2 != qcfc2.end(); ++it1, ++it2) { + BOOST_CHECK_EQUAL(*it1, *it2); + } + } + { + std::stringstream store; + store << "start,end,flag_id,invalid,header,format\n"; + store << R"(123,345,11,"fdsa",1,"comment","source")"; + QualityControlFlagCollection qcfc1{"A", "TST"}; + BOOST_CHECK_THROW(qcfc1.streamFrom(store), std::runtime_error); + } + { + std::stringstream store; + store << "start,end,flag_id,flag_name,flag_bad,comment,source\n"; + store << R"(123,345,11,"fdsa",1,"comment","source","toomanycolumns")" << '\n'; + store << R"(123,345,11,"fdsa",1)" << '\n'; + store << R"(123,,11,"fdsa",1,"comment","source")" << '\n'; + store << R"(,345,11,"fdsa",1,"comment","source")" << '\n'; + store << R"(123,345,,"fdsa",1,"comment","source")" << '\n'; + store << R"(123,345,11,"",1,"comment","source")" << '\n'; + store << R"(123,345,11,"fdsa",,"comment","source")" << '\n'; + QualityControlFlagCollection qcfc1{"A", "TST"}; + BOOST_CHECK_NO_THROW(qcfc1.streamFrom(store)); + BOOST_CHECK_EQUAL(qcfc1.size(), 0); + } +} diff --git a/DataFormats/QualityControl/test/testTimeRangeFlag.cxx b/DataFormats/QualityControl/test/testTimeRangeFlag.cxx deleted file mode 100644 index 47eef61199103..0000000000000 --- a/DataFormats/QualityControl/test/testTimeRangeFlag.cxx +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#define BOOST_TEST_MODULE Test quality_control TimeRangeFlag class -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK - -// boost includes -#include - -// o2 includes -#include "DataFormatsQualityControl/TimeRangeFlag.h" - -using namespace o2::quality_control; - -BOOST_AUTO_TEST_CASE(test_TimeRangeFlag) -{ - TimeRangeFlag trf1{12, 34, FlagReasonFactory::BadTracking(), "comment", "source"}; - - BOOST_CHECK_EQUAL(trf1.getStart(), 12); - BOOST_CHECK_EQUAL(trf1.getEnd(), 34); - BOOST_CHECK_EQUAL(trf1.getFlag(), FlagReasonFactory::BadTracking()); - BOOST_CHECK_EQUAL(trf1.getComment(), "comment"); - BOOST_CHECK_EQUAL(trf1.getSource(), "source"); - - BOOST_CHECK_THROW((TimeRangeFlag{12, 0, FlagReasonFactory::BadTracking()}), std::runtime_error); - - TimeRangeFlag trf2{10, 34, FlagReasonFactory::BadTracking(), "comment", "source"}; - - BOOST_CHECK(trf1 > trf2); - BOOST_CHECK(!(trf1 < trf2)); -} \ No newline at end of file diff --git a/DataFormats/QualityControl/test/testTimeRangeFlagCollection.cxx b/DataFormats/QualityControl/test/testTimeRangeFlagCollection.cxx deleted file mode 100644 index 9f5468ce00865..0000000000000 --- a/DataFormats/QualityControl/test/testTimeRangeFlagCollection.cxx +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -#define BOOST_TEST_MODULE Test quality_control TimeRangeFlagCollection class -#define BOOST_TEST_MAIN -#define BOOST_TEST_DYN_LINK - -// boost includes -#include -// STL -#include -// o2 includes -#include "DataFormatsQualityControl/TimeRangeFlagCollection.h" -#include "DataFormatsQualityControl/TimeRangeFlag.h" - -using namespace o2::quality_control; - -BOOST_AUTO_TEST_CASE(test_TimeRangeFlagCollection_Methods) -{ - TimeRangeFlag trf1{12, 34, FlagReasonFactory::BadTracking(), "comment", "source"}; - TimeRangeFlag trf2{10, 34, FlagReasonFactory::BadTracking(), "comment", "source"}; - - TimeRangeFlagCollection trfc1{"Raw data checks", "TOF", {10, 20000}, 12345, "LHC22k5", "passMC", "qc_mc"}; - trfc1.insert(trf1); // by copy - trfc1.insert(trf2); - trfc1.insert({50, 77, FlagReasonFactory::Invalid()}); // by move - BOOST_CHECK_EQUAL(trfc1.size(), 3); - BOOST_CHECK_EQUAL(trfc1.getName(), "Raw data checks"); - BOOST_CHECK_EQUAL(trfc1.getDetector(), "TOF"); - BOOST_CHECK_EQUAL(trfc1.getStart(), 10); - BOOST_CHECK_EQUAL(trfc1.getEnd(), 20000); - BOOST_CHECK_EQUAL(trfc1.getRunNumber(), 12345); - BOOST_CHECK_EQUAL(trfc1.getPeriodName(), "LHC22k5"); - BOOST_CHECK_EQUAL(trfc1.getPassName(), "passMC"); - BOOST_CHECK_EQUAL(trfc1.getProvenance(), "qc_mc"); - - TimeRangeFlagCollection trfc2{"Reco checks", "TOF"}; - trfc2.insert({50, 77, FlagReasonFactory::Invalid()}); // this is a duplicate to an entry in trfc1 - trfc2.insert({51, 77, FlagReasonFactory::Invalid()}); - trfc2.insert({1234, 3434, FlagReasonFactory::LimitedAcceptance()}); - trfc2.insert({50, 77, FlagReasonFactory::LimitedAcceptance()}); - BOOST_CHECK_EQUAL(trfc2.size(), 4); - - // Try merging. Duplicate entries should be left in the 'other' objects. - // Notice that we merge the two partial TRFCs into the third, which covers all cases - TimeRangeFlagCollection trfc3{"ALL", "TOF"}; - trfc3.merge(trfc1); - trfc3.merge(trfc2); - BOOST_CHECK_EQUAL(trfc1.size(), 0); - BOOST_CHECK_EQUAL(trfc2.size(), 1); - BOOST_CHECK_EQUAL(trfc3.size(), 6); - - // Try const merging. It should copy the elements and keep the 'other' intact. - TimeRangeFlagCollection trfc4{"ALL", "TOF"}; - const auto& constTrfc3 = trfc3; - trfc4.merge(constTrfc3); - BOOST_CHECK_EQUAL(trfc3.size(), 6); - BOOST_CHECK_EQUAL(trfc4.size(), 6); - - // Try merging different detectors - it should throw. - TimeRangeFlagCollection trfc5{"ALL", "TPC"}; - BOOST_CHECK_THROW(trfc5.merge(trfc3), std::runtime_error); - BOOST_CHECK_THROW(trfc5.merge(constTrfc3), std::runtime_error); - - // try printing - std::cout << trfc3 << std::endl; - - // iterating - for (const auto& trf : trfc3) { - (void)trf; - } -} - -BOOST_AUTO_TEST_CASE(test_TimeRangeFlagCollection_IO) -{ - { - TimeRangeFlagCollection trfc1{"xyz", "TST"}; - - std::stringstream store; - trfc1.streamTo(store); - - TimeRangeFlagCollection trfc2{"xyz", "TST"}; - trfc2.streamFrom(store); - - BOOST_CHECK_EQUAL(trfc2.size(), 0); - } - { - TimeRangeFlagCollection trfc1{"xyz", "TST"}; - trfc1.insert({50, 77, FlagReasonFactory::Invalid(), "a comment", "a source"}); - trfc1.insert({51, 77, FlagReasonFactory::Invalid()}); - trfc1.insert({1234, 3434, FlagReasonFactory::LimitedAcceptance()}); - trfc1.insert({50, 77, FlagReasonFactory::LimitedAcceptance()}); - trfc1.insert({43434, 63421, FlagReasonFactory::NotBadFlagExample()}); - - std::stringstream store; - trfc1.streamTo(store); - - TimeRangeFlagCollection trfc2{"xyz", "TST"}; - trfc2.streamFrom(store); - - BOOST_REQUIRE_EQUAL(trfc1.size(), trfc2.size()); - for (auto it1 = trfc1.begin(), it2 = trfc2.begin(); it1 != trfc1.end() && it2 != trfc2.end(); ++it1, ++it2) { - BOOST_CHECK_EQUAL(*it1, *it2); - } - } - { - std::stringstream store; - store << "start,end,flag_id,invalid,header,format\n"; - store << R"(123,345,11,"fdsa",1,"comment","source")"; - TimeRangeFlagCollection trfc1{"A", "TST"}; - BOOST_CHECK_THROW(trfc1.streamFrom(store), std::runtime_error); - } - { - std::stringstream store; - store << "start,end,flag_id,flag_name,flag_bad,comment,source\n"; - store << R"(123,345,11,"fdsa",1,"comment","source","toomanycolumns")" << '\n'; - store << R"(123,345,11,"fdsa",1)" << '\n'; - store << R"(123,,11,"fdsa",1,"comment","source")" << '\n'; - store << R"(,345,11,"fdsa",1,"comment","source")" << '\n'; - store << R"(123,345,,"fdsa",1,"comment","source")" << '\n'; - store << R"(123,345,11,"",1,"comment","source")" << '\n'; - store << R"(123,345,11,"fdsa",,"comment","source")" << '\n'; - TimeRangeFlagCollection trfc1{"A", "TST"}; - BOOST_CHECK_NO_THROW(trfc1.streamFrom(store)); - BOOST_CHECK_EQUAL(trfc1.size(), 0); - } -} diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/DecayNBodyIndex.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/DecayNBodyIndex.h index 590c1b9e3ffff..31a4b8ebc44b3 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/DecayNBodyIndex.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/DecayNBodyIndex.h @@ -59,8 +59,10 @@ class V0Index : public DecayNBodyIndex<2> V0Index(int v, GIndex p, GIndex n) : DecayNBodyIndex<2>(v, {p, n}) {} bool isStandaloneV0() const { return testBit(0); } bool isPhotonOnly() const { return testBit(1); } + bool isCollinear() const { return testBit(2); } void setStandaloneV0() { setBit(0); } void setPhotonOnly() { setBit(1); } + void setCollinear() { setBit(2); } ClassDefNV(V0Index, 1); }; diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h index 9f6b2f00bb37c..29442325e2f66 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOF.h @@ -38,7 +38,7 @@ class MatchInfoTOF int getTOFClIndex() const { return mIdxTOFCl; } int getTrackIndex() const { return mIdxTrack.getIndex(); } - void setChi2(int chi2) { mChi2 = chi2; } + void setChi2(float chi2) { mChi2 = chi2; } float getChi2() const { return mChi2; } o2::track::TrackLTIntegral& getLTIntegralOut() { return mIntLT; } diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOFReco.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOFReco.h index b1d3830e8083c..aa955ca81c1c6 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOFReco.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/MatchInfoTOFReco.h @@ -42,6 +42,8 @@ class MatchInfoTOFReco : public MatchInfoTOF void setFakeMatch() { mFakeMC = true; } void resetFakeMatch() { mFakeMC = false; } bool isFake() const { return mFakeMC; } + float pt() const { return mPt; } + void setPt(float pt) { mPt = pt; } void setTrackType(TrackType value) { mTrackType = value; } TrackType getTrackType() const { return mTrackType; } @@ -49,7 +51,8 @@ class MatchInfoTOFReco : public MatchInfoTOF private: TrackType mTrackType; ///< track type (TPC, ITSTPC, TPCTRD, ITSTPCTRD) bool mFakeMC = false; - ClassDefNV(MatchInfoTOFReco, 3); + float mPt = 0; + ClassDefNV(MatchInfoTOFReco, 4); }; } // namespace dataformats } // namespace o2 diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h index e6d9eef459176..e01ce253156a7 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PID.h @@ -16,6 +16,10 @@ #ifndef ALICEO2_track_PID_H_ #define ALICEO2_track_PID_H_ +#ifndef GPUCA_GPUCODE_DEVICE +#include +#endif + #include "GPUCommonDef.h" #include "GPUCommonRtypes.h" #include "CommonConstants/PhysicsConstants.h" @@ -30,9 +34,12 @@ namespace pid_constants // GPUs currently cannot have static constexpr array mem { typedef uint8_t ID; static constexpr ID NIDsTot = 17; + +#if !defined(GPUCA_GPUCODE_DEVICE) || defined(GPUCA_GPU_DEBUG_PRINT) GPUconstexpr() const char* sNames[NIDsTot + 1] = ///< defined particle names {"Electron", "Muon", "Pion", "Kaon", "Proton", "Deuteron", "Triton", "He3", "Alpha", "Pion0", "Photon", "K0", "Lambda", "HyperTriton", "Hyperhydrog4", "XiMinus", "OmegaMinus", nullptr}; +#endif GPUconstexpr() const float sMasses[NIDsTot] = ///< defined particle masses {o2cp::MassElectron, o2cp::MassMuon, o2cp::MassPionCharged, o2cp::MassKaonCharged, @@ -126,7 +133,7 @@ class PID GPUd() static float getMass2(ID id) { return pid_constants::sMasses2[id]; } GPUd() static float getMass2Z(ID id) { return pid_constants::sMasses2Z[id]; } GPUd() static int getCharge(ID id) { return pid_constants::sCharges[id]; } -#ifndef GPUCA_GPUCODE_DEVICE +#if !defined(GPUCA_GPUCODE_DEVICE) || defined(GPUCA_GPU_DEBUG_PRINT) GPUd() const char* getName() const { return getName(mID); @@ -137,13 +144,13 @@ class PID private: ID mID = Pion; +#if !defined(GPUCA_GPUCODE_DEVICE) || defined(GPUCA_GPU_DEBUG_PRINT) // are 2 strings equal ? (trick from Giulio) GPUdi() static constexpr bool sameStr(char const* x, char const* y) { return !*x && !*y ? true : /* default */ (*x == *y && sameStr(x + 1, y + 1)); } -#ifndef GPUCA_GPUCODE_DEVICE GPUdi() static constexpr ID nameToID(char const* name, ID id) { return id > LastExt ? id : sameStr(name, pid_constants::sNames[id]) ? id : nameToID(name, id + 1); diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h index df807e5a99021..bf47ed03f3b39 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/PrimaryVertexExt.h @@ -27,18 +27,11 @@ struct PrimaryVertexExt : public PrimaryVertex { std::array nSrc{}; // N contributors for each source type std::array nSrcA{}; // N associated and passing cuts for each source type std::array nSrcAU{}; // N ambgous associated and passing cuts for each source type - int VtxID = -1; // original vtx ID + double FT0Time = -1.; // time of closest FT0 trigger float FT0A = -1; // amplitude of closest FT0 A side float FT0C = -1; // amplitude of closest FT0 C side - float FT0Time = -1.; // time of closest FT0 trigger - float rmsT = 0; - float rmsZ = 0; - float rmsTW = 0; - float rmsZW = 0; - float rmsT0 = 0; // w/o ITS - float rmsTW0 = 0; // w/o ITS - float tMAD = 0; - float zMAD = 0; + int VtxID = -1; // original vtx ID + int getNSrc(int i) const { return nSrc[i]; } int getNSrcA(int i) const { return nSrcA[i]; } int getNSrcAU(int i) const { return nSrcAU[i]; } @@ -48,7 +41,7 @@ struct PrimaryVertexExt : public PrimaryVertex { std::string asString() const; #endif - ClassDefNV(PrimaryVertexExt, 5); + ClassDefNV(PrimaryVertexExt, 6); }; #ifndef GPUCA_ALIGPUCODE diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h index dc2799e4592d8..41d3efc2cfd2d 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrization.h @@ -216,6 +216,8 @@ class TrackParametrization GPUd() value_t getYAt(value_t xk, value_t b) const; GPUd() value_t getSnpAt(value_t xk, value_t b) const; GPUd() value_t getSnpAt(value_t alpha, value_t xk, value_t b) const; + GPUd() value_t getPhiAt(value_t xk, value_t b) const; + GPUd() value_t getPhiPosAt(value_t xk, value_t b) const; GPUd() math_utils::Point3D getXYZGloAt(value_t xk, value_t b, bool& ok) const; // parameters manipulation @@ -239,8 +241,10 @@ class TrackParametrization GPUhd() void setUserField(uint16_t v); GPUd() void printParam() const; + GPUd() void printParamHexadecimal(); #ifndef GPUCA_ALIGPUCODE std::string asString() const; + std::string asStringHexadecimal(); #endif GPUd() void updateParam(value_t delta, int i); diff --git a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h index 4f2a3f2811ad6..0f01713d50beb 100644 --- a/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h +++ b/DataFormats/Reconstruction/include/ReconstructionDataFormats/TrackParametrizationWithError.h @@ -79,8 +79,10 @@ class TrackParametrizationWithError : public TrackParametrization GPUd() bool getCovXYZPxPyPzGlo(gpu::gpustd::array& c) const; GPUd() void print() const; + GPUd() void printHexadecimal(); #ifndef GPUCA_ALIGPUCODE std::string asString() const; + std::string asStringHexadecimal(); #endif // parameters + covmat manipulation @@ -100,7 +102,7 @@ class TrackParametrizationWithError : public TrackParametrization void buildCombinedCovMatrix(const TrackParametrizationWithError& rhs, MatrixDSym5& cov) const; value_t getPredictedChi2(const TrackParametrizationWithError& rhs, MatrixDSym5& covToSet) const; - value_t getPredictedChi2(const TrackParametrizationWithError& rhs) const; + GPUd() value_t getPredictedChi2(const TrackParametrizationWithError& rhs) const; bool update(const TrackParametrizationWithError& rhs, const MatrixDSym5& covInv); bool update(const TrackParametrizationWithError& rhs); diff --git a/DataFormats/Reconstruction/src/TrackLTIntegral.cxx b/DataFormats/Reconstruction/src/TrackLTIntegral.cxx index 52a77ce92a4da..3efddff00f512 100644 --- a/DataFormats/Reconstruction/src/TrackLTIntegral.cxx +++ b/DataFormats/Reconstruction/src/TrackLTIntegral.cxx @@ -9,6 +9,10 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#ifndef GPUCA_GPUCODE_DEVICE +#include +#endif + #include "ReconstructionDataFormats/TrackLTIntegral.h" #include "CommonConstants/PhysicsConstants.h" #include "MathUtils/Utils.h" diff --git a/DataFormats/Reconstruction/src/TrackParametrization.cxx b/DataFormats/Reconstruction/src/TrackParametrization.cxx index 99d312f234cc2..ba36045f18606 100644 --- a/DataFormats/Reconstruction/src/TrackParametrization.cxx +++ b/DataFormats/Reconstruction/src/TrackParametrization.cxx @@ -520,6 +520,40 @@ GPUd() typename TrackParametrization::value_t TrackParametrization +GPUd() typename TrackParametrization::value_t TrackParametrization::getPhiAt(value_t xk, value_t b) const +{ + ///< this method is just an alias for obtaining phi @ X in the tree->Draw() + value_t dx = xk - getX(); + if (gpu::CAMath::Abs(dx) < constants::math::Almost0) { + return getPhi(); + } + value_t crv = (gpu::CAMath::Abs(b) < constants::math::Almost0) ? 0.f : getCurvature(b); + value_t x2r = crv * dx; + value_t snp = mP[kSnp] + x2r; + value_t phi = 999.; + if (gpu::CAMath::Abs(snp) < constants::math::Almost1) { + value_t phi = gpu::CAMath::ASin(snp) + getAlpha(); + math_utils::detail::bringTo02Pi(phi); + } + return phi; +} + +//______________________________________________________________ +template +GPUd() typename TrackParametrization::value_t TrackParametrization::getPhiPosAt(value_t xk, value_t b) const +{ + ///< this method is just an alias for obtaining phiPos @ X in the tree->Draw() + value_t phi = 999.; + auto y = getYAt(xk, b); + if (y > -9998.) { + phi = gpu::CAMath::ATan2(y, xk) + getAlpha(); + math_utils::detail::bringTo02Pi(phi); + } + return phi; +} + //______________________________________________________________ template GPUd() typename TrackParametrization::value_t TrackParametrization::getSnpAt(value_t alpha, value_t xk, value_t b) const @@ -555,6 +589,31 @@ std::string TrackParametrization::asString() const return fmt::format("X:{:+.4e} Alp:{:+.3e} Par: {:+.4e} {:+.4e} {:+.4e} {:+.4e} {:+.4e} |Q|:{:d} {:s}", getX(), getAlpha(), getY(), getZ(), getSnp(), getTgl(), getQ2Pt(), getAbsCharge(), getPID().getName()); } + +//_____________________________________________________________ +template +std::string TrackParametrization::asStringHexadecimal() +{ + auto _X = getX(); + auto _Alpha = getAlpha(); + auto _Y = getY(); + auto _Z = getZ(); + auto _Snp = getSnp(); + auto _Tgl = getTgl(); + float _Q2Pt = getQ2Pt(); + float _AbsCharge = getAbsCharge(); + // print parameters as string + return fmt::format("X:{:x} Alp:{:x} Par: {:x} {:x} {:x} {:x} {:x} |Q|:{:x} {:s}", + reinterpret_cast(_X), + reinterpret_cast(_Alpha), + reinterpret_cast(_Y), + reinterpret_cast(_Z), + reinterpret_cast(_Snp), + reinterpret_cast(_Tgl), + reinterpret_cast(_Q2Pt), + reinterpret_cast(_AbsCharge), + getPID().getName()); +} #endif //______________________________________________________________ @@ -564,9 +623,30 @@ GPUd() void TrackParametrization::printParam() const // print parameters #ifndef GPUCA_ALIGPUCODE printf("%s\n", asString().c_str()); -#else - printf("X:%+.4e Alp:%+.3e Par: %+.4e %+.4e %+.4e %+.4e %+.4e |Q|:%d", - getX(), getAlpha(), getY(), getZ(), getSnp(), getTgl(), getQ2Pt(), getAbsCharge()); +#elif !defined(GPUCA_GPUCODE_DEVICE) || (!defined(__OPENCL__) && defined(GPUCA_GPU_DEBUG_PRINT)) + printf("X:%+.4e Alp:%+.3e Par: %+.4e %+.4e %+.4e %+.4e %+.4e |Q|:%d %s", + getX(), getAlpha(), getY(), getZ(), getSnp(), getTgl(), getQ2Pt(), getAbsCharge(), getPID().getName()); +#endif +} + +//______________________________________________________________ +template +GPUd() void TrackParametrization::printParamHexadecimal() +{ + // print parameters +#ifndef GPUCA_ALIGPUCODE + printf("%s\n", asStringHexadecimal().c_str()); +#elif !defined(GPUCA_GPUCODE_DEVICE) || (!defined(__OPENCL__) && defined(GPUCA_GPU_DEBUG_PRINT)) + printf("X:%x Alp:%x Par: %x %x %x %x %x |Q|:%x %s", + gpu::CAMath::Float2UIntReint(getX()), + gpu::CAMath::Float2UIntReint(getAlpha()), + gpu::CAMath::Float2UIntReint(getY()), + gpu::CAMath::Float2UIntReint(getZ()), + gpu::CAMath::Float2UIntReint(getSnp()), + gpu::CAMath::Float2UIntReint(getTgl()), + gpu::CAMath::Float2UIntReint(getQ2Pt()), + gpu::CAMath::Float2UIntReint(getAbsCharge()), + getPID().getName()); #endif } @@ -767,7 +847,7 @@ GPUd() bool TrackParametrization::correctForELoss(value_t xrho, bool an // "dedx" - mean enery loss (GeV/(g/cm^2), if <=kCalcdEdxAuto : calculate on the fly // "anglecorr" - switch for the angular correction //------------------------------------------------------------------ - constexpr value_t kMinP = 0.01f; // kill below this momentum + constexpr value_t kMinP = 0.01f; // kill below this momentum auto m = getPID().getMass(); if (m > 0 && xrho != 0.f) { diff --git a/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx b/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx index 087e662fe41ff..dfe4d7c31b2ab 100644 --- a/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx +++ b/DataFormats/Reconstruction/src/TrackParametrizationWithError.cxx @@ -999,7 +999,7 @@ GPUd() bool TrackParametrizationWithError::correctForMaterial(value_t x // "anglecorr" - switch for the angular correction //------------------------------------------------------------------ constexpr value_t kMSConst2 = 0.0136f * 0.0136f; - constexpr value_t kMinP = 0.01f; // kill below this momentum + constexpr value_t kMinP = 0.01f; // kill below this momentum value_t csp2 = (1.f - this->getSnp()) * (1.f + this->getSnp()); // cos(phi)^2 value_t cst2I = (1.f + this->getTgl() * this->getTgl()); // 1/cos(lambda)^2 @@ -1193,6 +1193,18 @@ std::string TrackParametrizationWithError::asString() const mC[kSigTglZ], mC[kSigTglSnp], mC[kSigTgl2], mC[kSigQ2PtY], mC[kSigQ2PtZ], mC[kSigQ2PtSnp], mC[kSigQ2PtTgl], mC[kSigQ2Pt2]); } + +template +std::string TrackParametrizationWithError::asStringHexadecimal() +{ + return TrackParametrization::asStringHexadecimal() + + fmt::format(" Cov: [{:x}] [{:x} {:x}] [{:x} {:x} {:x}] [{:x} {:x} {:x} {:x}] [{:x} {:x} {:x} {:x} {:x}]", + reinterpret_cast(mC[kSigY2]), reinterpret_cast(mC[kSigZY]), reinterpret_cast(mC[kSigZ2]), + reinterpret_cast(mC[kSigSnpY]), reinterpret_cast(mC[kSigSnpZ]), reinterpret_cast(mC[kSigSnp2]), + reinterpret_cast(mC[kSigTglY]), reinterpret_cast(mC[kSigTglZ]), reinterpret_cast(mC[kSigTglSnp]), + reinterpret_cast(mC[kSigTgl2]), reinterpret_cast(mC[kSigQ2PtY]), reinterpret_cast(mC[kSigQ2PtZ]), + reinterpret_cast(mC[kSigQ2PtSnp]), reinterpret_cast(mC[kSigQ2PtTgl]), reinterpret_cast(mC[kSigQ2Pt2])); +} #endif //______________________________________________________________ @@ -1202,20 +1214,35 @@ GPUd() void TrackParametrizationWithError::print() const // print parameters #ifndef GPUCA_ALIGPUCODE printf("%s\n", asString().c_str()); -#else +#elif !defined(GPUCA_GPUCODE_DEVICE) || (!defined(__OPENCL__) && defined(GPUCA_GPU_DEBUG_PRINT)) TrackParametrization::printParam(); printf( - "\n%7s %+.3e\n" - "%7s %+.3e %+.3e\n" - "%7s %+.3e %+.3e %+.3e\n" - "%7s %+.3e %+.3e %+.3e %+.3e\n" - "%7s %+.3e %+.3e %+.3e %+.3e %+.3e", - "CovMat:", mC[kSigY2], "", mC[kSigZY], mC[kSigZ2], "", mC[kSigSnpY], mC[kSigSnpZ], mC[kSigSnp2], "", mC[kSigTglY], - mC[kSigTglZ], mC[kSigTglSnp], mC[kSigTgl2], "", mC[kSigQ2PtY], mC[kSigQ2PtZ], mC[kSigQ2PtSnp], mC[kSigQ2PtTgl], + "\nCov: [%+.3e] [%+.3e %+.3e] [%+.3e %+.3e %+.3e] [%+.3e %+.3e %+.3e %+.3e] [%+.3e %+.3e %+.3e %+.3e %+.3e]", + mC[kSigY2], mC[kSigZY], mC[kSigZ2], mC[kSigSnpY], mC[kSigSnpZ], mC[kSigSnp2], mC[kSigTglY], + mC[kSigTglZ], mC[kSigTglSnp], mC[kSigTgl2], mC[kSigQ2PtY], mC[kSigQ2PtZ], mC[kSigQ2PtSnp], mC[kSigQ2PtTgl], mC[kSigQ2Pt2]); #endif } +//______________________________________________________________ +template +GPUd() void TrackParametrizationWithError::printHexadecimal() +{ + // print parameters +#ifndef GPUCA_ALIGPUCODE + printf("%s\n", asStringHexadecimal().c_str()); +#elif !defined(GPUCA_GPUCODE_DEVICE) || (!defined(__OPENCL__) && defined(GPUCA_GPU_DEBUG_PRINT)) + TrackParametrization::printParamHexadecimal(); + printf( + "\nCov: [%x] [%x %x] [%x %x %x] [%x %x %x %x] [%x %x %x %x %x]", + gpu::CAMath::Float2UIntReint(mC[kSigY2]), + gpu::CAMath::Float2UIntReint(mC[kSigZY]), gpu::CAMath::Float2UIntReint(mC[kSigZ2]), + gpu::CAMath::Float2UIntReint(mC[kSigSnpY]), gpu::CAMath::Float2UIntReint(mC[kSigSnpZ]), gpu::CAMath::Float2UIntReint(mC[kSigSnp2]), + gpu::CAMath::Float2UIntReint(mC[kSigTglY]), gpu::CAMath::Float2UIntReint(mC[kSigTglZ]), gpu::CAMath::Float2UIntReint(mC[kSigTglSnp]), gpu::CAMath::Float2UIntReint(mC[kSigTgl2]), + gpu::CAMath::Float2UIntReint(mC[kSigQ2PtY]), gpu::CAMath::Float2UIntReint(mC[kSigQ2PtZ]), gpu::CAMath::Float2UIntReint(mC[kSigQ2PtSnp]), gpu::CAMath::Float2UIntReint(mC[kSigQ2PtTgl]), gpu::CAMath::Float2UIntReint(mC[kSigQ2Pt2])); +#endif +} + namespace o2::track { template class TrackParametrizationWithError; diff --git a/DataFormats/common/include/CommonDataFormat/AbstractRef.h b/DataFormats/common/include/CommonDataFormat/AbstractRef.h index cdc65f6c412d6..8dce94d502ffb 100644 --- a/DataFormats/common/include/CommonDataFormat/AbstractRef.h +++ b/DataFormats/common/include/CommonDataFormat/AbstractRef.h @@ -79,6 +79,7 @@ class AbstractRef GPUdi() bool operator==(const AbstractRef& o) const { return getRawWOFlags() == o.getRawWOFlags(); } GPUdi() bool operator!=(const AbstractRef& o) const { return !operator==(o); } + GPUdi() void clear() { setRaw((Base_t(SrcMask & ((0x1 << NBSrc) - 1)) << NBIdx) | Base_t(IdxMask & ((0x1 << NBIdx) - 1))); } protected: Base_t mRef = IdxMask | (SrcMask << NBIdx); // packed reference, dummy by default diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCCompLabel.h b/DataFormats/simulation/include/SimulationDataFormat/MCCompLabel.h index ed0d5300afc35..74c47c87f22d5 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCCompLabel.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCCompLabel.h @@ -129,7 +129,7 @@ class MCCompLabel int getEventID() const { return (mLabel >> nbitsTrackID) & maskEvID; } int getSourceID() const { return (mLabel >> (nbitsTrackID + nbitsEvID)) & maskSrcID; } uint64_t getTrackEventSourceID() const { return static_cast(mLabel & maskFull); } - void get(int& trackID, int& evID, int& srcID, bool& fake) + void get(int& trackID, int& evID, int& srcID, bool& fake) const { /// parse label trackID = getTrackID(); diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h index d58e5c4cf82d9..efaf46806a89a 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCEventHeader.h @@ -142,12 +142,20 @@ class MCEventHeader : public FairMCEventHeader return ref; }; + void print() const; + /// prints a summary of info keys/types attached to this header void printInfo() const { mEventInfo.print(); } + /// inits info fields from another Event header + void copyInfoFrom(MCEventHeader const& other) + { + mEventInfo.copyFrom(other.mEventInfo); + } + /** methods **/ virtual void Reset(); diff --git a/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h b/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h index dec5eed64a9b2..a5322b2f53dbf 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h +++ b/DataFormats/simulation/include/SimulationDataFormat/MCTrack.h @@ -298,8 +298,10 @@ template inline Double_t MCTrackT::GetEnergy() const { const auto mass = GetMass(); - return std::sqrt(mass * mass + mStartVertexMomentumX * mStartVertexMomentumX + - mStartVertexMomentumY * mStartVertexMomentumY + mStartVertexMomentumZ * mStartVertexMomentumZ); + Double_t px = mStartVertexMomentumX; + Double_t py = mStartVertexMomentumY; + Double_t pz = mStartVertexMomentumZ; + return std::sqrt(mass * mass + px * px + py * py + pz * pz); } template diff --git a/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h b/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h index 3225f3536f1cf..dcc50bb8276df 100644 --- a/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h +++ b/DataFormats/simulation/include/SimulationDataFormat/O2DatabasePDG.h @@ -470,6 +470,43 @@ inline void O2DatabasePDG::addALICEParticles(TDatabasePDG* db) 0.185, 0, "Resonance", ionCode); } + // Lambda(1520)0 + ionCode = 102134; + if (!db->GetParticle(ionCode)) { + db->AddParticle("Lambda_1520_0", "Lambda_1520_0", 1.5195, kFALSE, 0.0156, 0, "Resonance", ionCode); + } + if (!db->GetParticle(-ionCode)) { + db->AddParticle("AntiLambda_1520_0", "AntiLambda_1520_0", 1.5195, kFALSE, 0.0156, 0, "Resonance", -ionCode); + } + + // f1 study + ionCode = 20223; + if (!db->GetParticle(ionCode)) { + db->AddParticle("f1_1285", "f1_1285", 1.28210, kFALSE, 0.02420, 0, "Resonance", ionCode); + } + ionCode = 20333; + if (!db->GetParticle(ionCode)) { + db->AddParticle("f1_1420", "f1_1420", 1.42640, kFALSE, 0.05490, 0, "Resonance", ionCode); + } + + // glueball hunting + ionCode = 10221; + if (!db->GetParticle(ionCode)) { + db->AddParticle("f0_1370", "f0_1370", 1.37, kFALSE, 0.200, 0, "Resonance", ionCode); + } + ionCode = 9030221; + if (!db->GetParticle(ionCode)) { + db->AddParticle("f0_1500", "f0_1500", 1.500, kFALSE, 0.112, 0, "Resonance", ionCode); + } + ionCode = 10331; + if (!db->GetParticle(ionCode)) { + db->AddParticle("f0_1710", "f0_1710", 1.710, kFALSE, 0.139, 0, "Resonance", ionCode); + } + ionCode = 335; + if (!db->GetParticle(ionCode)) { + db->AddParticle("f2_1525", "f2_1525", 1.525, kFALSE, 0.073, 0, "Resonance", ionCode); + } + // Xi-/+ (1820) ionCode = 123314; if (!db->GetParticle(ionCode)) { diff --git a/DataFormats/simulation/src/MCEventHeader.cxx b/DataFormats/simulation/src/MCEventHeader.cxx index 41597f889fe48..8a46d84805507 100644 --- a/DataFormats/simulation/src/MCEventHeader.cxx +++ b/DataFormats/simulation/src/MCEventHeader.cxx @@ -15,6 +15,7 @@ #include "FairRootManager.h" #include #include +#include namespace o2 { @@ -61,6 +62,21 @@ void MCEventHeader::extractFileFromKinematics(std::string_view kinefilename, std } } +void MCEventHeader::print() const +{ + // print some used parts from FairMCEventHeader + std::cout << "RunID " << fRunId << "\n"; + std::cout << "EventID " << fEventId << "\n"; + std::cout << "Vertex-X " << fX << "\n"; + std::cout << "Vertex-Y " << fY << "\n"; + std::cout << "Vertex-Z " << fZ << "\n"; + std::cout << "Vertex-T " << fT << "\n"; + std::cout << "Impact-B " << fB << "\n"; + std::cout << "NPrim " << fNPrim << "\n"; + // print meta-fields + printInfo(); +} + /** alternative implementations below void MCEventHeader::extractFileFromKinematics(std::string_view kinefilename, std::string_view targetfilename) { diff --git a/Detectors/AOD/README.md b/Detectors/AOD/README.md index 44104796904d2..42a9840fabc04 100644 --- a/Detectors/AOD/README.md +++ b/Detectors/AOD/README.md @@ -1,3 +1,7 @@ + + # AOD producers The code in this directory is meant to produce `AO2D.root` output diff --git a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h index 13a55526afc56..49ba88c8c5858 100644 --- a/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h +++ b/Detectors/AOD/include/AODProducerWorkflow/AODProducerWorkflowSpec.h @@ -301,6 +301,8 @@ class AODProducerWorkflowDPL : public Task std::vector mMCHROFs; // mapping from MCH tracks ID to corresponding ROF (for SA MCH tracks time extraction) double mITSROFrameHalfLengthNS = -1; // ITS ROF half length double mMFTROFrameHalfLengthNS = -1; // ITS ROF half length + double mITSROFBiasNS = 0; // ITS ROF start bias + double mMFTROFBiasNS = 0; // ITS ROF start bias double mNSigmaTimeTrack = -1; // number track errors sigmas (for gaussian errors only) used in track-vertex matching double mTimeMarginTrackTime = -1; // safety margin in NS used for track-vertex matching (additive to track uncertainty) double mTPCBinNS = -1; // inverse TPC time-bin in ns diff --git a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx index 63491ec048357..388845edc575c 100644 --- a/Detectors/AOD/src/AODProducerWorkflowSpec.cxx +++ b/Detectors/AOD/src/AODProducerWorkflowSpec.cxx @@ -377,7 +377,7 @@ void AODProducerWorkflowDPL::addToMFTTracksTable(mftTracksCursorType& mftTracksC int bcSlice[2] = {-1, -1}; const auto& track = data.getMFTTrack(trackID); const auto& rof = data.getMFTTracksROFRecords()[mMFTROFs[trackID.getIndex()]]; - float trackTime = rof.getBCData().differenceInBC(mStartIR) * o2::constants::lhc::LHCBunchSpacingNS + mMFTROFrameHalfLengthNS; + float trackTime = rof.getBCData().differenceInBC(mStartIR) * o2::constants::lhc::LHCBunchSpacingNS + mMFTROFrameHalfLengthNS + mMFTROFBiasNS; float trackTimeRes = mMFTROFrameHalfLengthNS; bool needBCSlice = collisionID < 0; std::uint64_t bcOfTimeRef; @@ -2422,7 +2422,7 @@ AODProducerWorkflowDPL::TrackExtraInfo AODProducerWorkflowDPL::processBarrelTrac extraInfoHolder.itsClusterSizes = itsTrack.getClusterSizes(); if (src == GIndex::ITS) { // standalone ITS track should set its time from the ROF const auto& rof = data.getITSTracksROFRecords()[mITSROFs[trackIndex.getIndex()]]; - double t = rof.getBCData().differenceInBC(mStartIR) * o2::constants::lhc::LHCBunchSpacingNS + mITSROFrameHalfLengthNS; + double t = rof.getBCData().differenceInBC(mStartIR) * o2::constants::lhc::LHCBunchSpacingNS + mITSROFrameHalfLengthNS + mITSROFBiasNS; setTrackTime(t, mITSROFrameHalfLengthNS, false); } } else if (contributorsGID[GIndex::Source::ITSAB].isIndexSet()) { // this is an ITS-TPC afterburner contributor @@ -2652,9 +2652,10 @@ void AODProducerWorkflowDPL::updateTimeDependentParams(ProcessingContext& pc) const auto& alpParamsITS = o2::itsmft::DPLAlpideParam::Instance(); mITSROFrameHalfLengthNS = 0.5 * (grpECS->isDetContinuousReadOut(o2::detectors::DetID::ITS) ? alpParamsITS.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS : alpParamsITS.roFrameLengthTrig); - + mITSROFBiasNS = o2::itsmft::DPLAlpideParam::Instance().roFrameBiasInBC * o2::constants::lhc::LHCBunchSpacingNS; const auto& alpParamsMFT = o2::itsmft::DPLAlpideParam::Instance(); mMFTROFrameHalfLengthNS = 0.5 * (grpECS->isDetContinuousReadOut(o2::detectors::DetID::MFT) ? alpParamsMFT.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingNS : alpParamsMFT.roFrameLengthTrig); + mMFTROFBiasNS = o2::itsmft::DPLAlpideParam::Instance().roFrameBiasInBC * o2::constants::lhc::LHCBunchSpacingNS; // RS FIXME: this is not yet fetched from the CCDB auto& elParam = o2::tpc::ParameterElectronics::Instance(); diff --git a/Detectors/Align/CMakeLists.txt b/Detectors/Align/CMakeLists.txt index 9c47167c28a6b..d99e1a803612f 100644 --- a/Detectors/Align/CMakeLists.txt +++ b/Detectors/Align/CMakeLists.txt @@ -36,6 +36,8 @@ o2_add_library(Align src/EventVertex.cxx src/AlignConfig.cxx src/Mille.cxx + src/AlgPntDbg.cxx + src/AlgTrcDbg.cxx PUBLIC_LINK_LIBRARIES O2::FrameworkLogger O2::Steer O2::ReconstructionDataFormats @@ -82,6 +84,8 @@ o2_target_root_dictionary( include/Align/GeometricalConstraint.h include/Align/utils.h include/Align/AlignConfig.h + include/Align/AlgPntDbg.h + include/Align/AlgTrcDbg.h ) add_subdirectory(Workflow) diff --git a/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx b/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx index 5c64b23315eb7..78b149b5dd4e8 100644 --- a/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx +++ b/Detectors/Align/Workflow/src/BarrelAlignmentSpec.cxx @@ -38,6 +38,7 @@ #include "TPCCalibration/VDriftHelper.h" #include "TPCCalibration/CorrectionMapsLoader.h" #include "GPUO2Interface.h" +#include "GPUO2InterfaceUtils.h" #include "GPUParam.h" #include "Headers/DataHeader.h" #include "Framework/ConfigParamRegistry.h" @@ -106,6 +107,7 @@ class BarrelAlignmentSpec : public Task bool mIgnoreCCDBAlignment = false; bool mCosmic = false; bool mLoadTPCCalib = false; + int mLane = 0; int mPostProcessing = 0; // special mode of extracting alignment or constraints check GTrackID::mask_t mMPsrc{}; DetID::mask_t mDetMask{}; @@ -131,12 +133,11 @@ void BarrelAlignmentSpec::init(InitContext& ic) mTimer.Reset(); o2::base::GRPGeomHelper::instance().setRequest(mGRPGeomRequest); - int dbg = ic.options().get("debug-output"), inst = ic.services().get().inputTimesliceId; - mController = std::make_unique(mDetMask, mMPsrc, mCosmic, mUseMC, inst); + int dbg = ic.options().get("debug-output"); + mLane = ic.services().get().inputTimesliceId; + mController = std::make_unique(mDetMask, mMPsrc, mCosmic, mUseMC, mLane); if (dbg) { - mDBGOut = std::make_unique(fmt::format("mpDebug_{}.root", inst).c_str(), "recreate"); mController->setDebugOutputLevel(dbg); - mController->setDebugStream(mDBGOut.get()); } mConfMacro = ic.options().get("config-macro"); @@ -191,6 +192,12 @@ void BarrelAlignmentSpec::init(InitContext& ic) if (ic.options().get("apply-xor")) { mTRDTransformer->setApplyXOR(); } + auto prevShift = mTRDTransformer->isShiftApplied(); + if (getenv("ALIEN_JDL_LPMPRODUCTIONTYPE") && std::strcmp(getenv("ALIEN_JDL_LPMPRODUCTIONTYPE"), "MC") == 0) { + // apply artificial pad shift in case non-ideal alignment is used to compensate for shift in current alignment from real data + mTRDTransformer->setApplyShift(false); + } + LOGP(info, "Old TRD shift : {} new : {}", prevShift, mTRDTransformer->isShiftApplied()); mController->setTRDTransformer(mTRDTransformer.get()); } mController->setAllowAfterburnerTracks(ic.options().get("allow-afterburner-tracks")); @@ -206,7 +213,12 @@ void BarrelAlignmentSpec::init(InitContext& ic) void BarrelAlignmentSpec::updateTimeDependentParams(ProcessingContext& pc) { o2::base::GRPGeomHelper::instance().checkUpdates(pc); + auto tinfo = pc.services().get(); if (pc.services().get().globalRunNumberChanged) { + if (mController->getDebugOutputLevel()) { + mDBGOut = std::make_unique(fmt::format("mpDebug_{}_{:08d}_{:010d}.root", mLane, tinfo.runNumber, tinfo.tfCounter).c_str(), "recreate"); + mController->setDebugStream(mDBGOut.get()); + } if (!mIgnoreCCDBAlignment) { for (auto id = DetID::First; id <= DetID::Last; id++) { const auto* alg = o2::base::GRPGeomHelper::instance().getAlignment(id); diff --git a/Detectors/Align/include/Align/AlgPntDbg.h b/Detectors/Align/include/Align/AlgPntDbg.h new file mode 100644 index 0000000000000..12e8205f6b614 --- /dev/null +++ b/Detectors/Align/include/Align/AlgPntDbg.h @@ -0,0 +1,91 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlignmentPoint.h +/// @author ruben.shahoyan@cern.ch, michael.lettrich@cern.ch +/// @since 2021-02-01 +/// @brief Meausered point in the sensor. + +/** + * Compact alignment point info for debugging + */ + +#ifndef ALGPNTDBG_H +#define ALGPNTDBG_H + +#include "Align/AlignmentPoint.h" + +namespace o2 +{ +namespace align +{ + +struct AlgPntDbg { + public: + using DetID = o2::detectors::DetID; + // + enum { + UpperLeg = 0 + }; + // + AlgPntDbg() = default; + AlgPntDbg(const AlgPntDbg&) = default; + ~AlgPntDbg() = default; + AlgPntDbg& operator=(const AlgPntDbg& other) = default; + AlgPntDbg(const AlignmentPoint* point) : mDetID(point->getDetID()), mSID(point->getSID()), mAlpha(point->getAlphaSens()), mX(point->getXTracking()), mY(point->getYTracking()), mZ(point->getZTracking()), mErrYY(point->getYZErrTracking()[0]), mErrZZ(point->getYZErrTracking()[2]), mErrYZ(point->getYZErrTracking()[1]) + { + mSinAlp = std::sin(mAlpha); + mCosAlp = std::cos(mAlpha); + mSnp = point->getTrParamWSA()[2]; // track Snp at the sensor + if (point->isInvDir()) { + setUpperLeg(); + } + } + + float getR() const { return std::sqrt(mX * mX + mY * mY); } + float getYTrack() const { return mY + mYRes; } + float getZTrack() const { return mZ + mZRes; } + float getXTrack() const { return mX; } + float getXLab() const { return mX * mCosAlp - mY * mSinAlp; } + float getYLab() const { return mX * mSinAlp + mY * mCosAlp; } + float getZLap() const { return mZ; } + float getXTrackLab() const { return mX * mCosAlp - getYTrack() * mSinAlp; } + float getYTrackLab() const { return mX * mSinAlp + getYTrack() * mCosAlp; } + float getZTrackLab() const { return getZTrack(); } + float getPhi() const { return std::atan2(getYLab(), getXLab()); } + void setFlag(int i) { mFlags |= 0x1 << i; } + bool getFlag(int i) const { return (mFlags & (0x1 << i)) != 0; } + + void setUpperLeg() { setFlag(int(UpperLeg)); } + bool isUpperLeg() const { return getFlag(int(UpperLeg)); } + + int mDetID{}; // DetectorID + int16_t mSID = -1; // sensor ID in the detector + uint16_t mFlags = 0; // flags + float mAlpha = 0.f; // Alpha of tracking frame + float mSinAlp = 0.f; + float mCosAlp = 0.f; + float mX = 0.f; // tracking X + float mY = 0.f; // tracking Y + float mZ = 0.f; // Z + float mYRes = 0.f; // tracking Y residual (track - point) + float mZRes = 0.f; // Z residual + float mErrYY = 0.f; + float mErrZZ = 0.f; + float mErrYZ = 0.f; + float mSnp = 0.f; + + ClassDefNV(AlgPntDbg, 1); +}; + +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlgTrcDbg.h b/Detectors/Align/include/Align/AlgTrcDbg.h new file mode 100644 index 0000000000000..cb179dd8b9b2f --- /dev/null +++ b/Detectors/Align/include/Align/AlgTrcDbg.h @@ -0,0 +1,90 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlgTrcDbg.h +/// @author ruben.shahoyan@cern.ch + +#ifndef ALGTRCDBG_H +#define ALGTRCDBG_H + +#include "Align/AlignmentTrack.h" +#include "Align/AlgPntDbg.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/Track.h" + +namespace o2 +{ +namespace align +{ + +struct AlgTrcDbg : public o2::track::TrackParCov { + AlgTrcDbg(const AlignmentTrack* trc) { setTrackParam(trc); } + AlgTrcDbg() = default; + ~AlgTrcDbg() = default; + AlgTrcDbg(const AlgTrcDbg&) = default; + AlgTrcDbg& operator=(const AlgTrcDbg&) = default; + + bool setTrackParam(const AlignmentTrack* trc) + { + if (!trc) { + return false; + } + setX(trc->getX()); + setY(trc->getAlpha()); + for (int i = 0; i < 5; i++) { + setParam(trc->getParam(i), i); + } + for (int i = 0; i < 15; i++) { + setCov(trc->getCov()[i], i); + } + mPoints.clear(); + for (int i = 0; i < trc->getNPoints(); i++) { + const auto* tpoint = trc->getPoint(i); + if (tpoint->containsMeasurement()) { + auto& pnt = mPoints.emplace_back(tpoint); + pnt.mYRes = trc->getResidual(0, i); + pnt.mZRes = trc->getResidual(1, i); + } + } + setX(trc->getX()); + setY(trc->getAlpha()); + for (int i = 0; i < 5; i++) { + setParam(trc->getParam(i), i); + } + for (int i = 0; i < 15; i++) { + setCov(trc->getCov()[i], i); + } + for (int i = 0; i < trc->getNPoints(); i++) { + const auto* tpoint = trc->getPoint(i); + if (tpoint->containsMeasurement()) { + auto& pnt = mPoints.emplace_back(tpoint); + pnt.mYRes = trc->getResidual(0, i); + pnt.mZRes = trc->getResidual(1, i); + } + } + mGID.clear(); + mGIDCosmUp.clear(); + return true; + } + + auto getNPoints() const { return mPoints.size(); } + bool isCosmic() const { return mGIDCosmUp.isSourceSet(); } + + std::vector mPoints; + o2::dataformats::GlobalTrackID mGID{}; + o2::dataformats::GlobalTrackID mGIDCosmUp{}; // GID of upper leg in case of cosmic + // + ClassDefNV(AlgTrcDbg, 1); +}; + +} // namespace align +} // namespace o2 +#endif diff --git a/Detectors/Align/include/Align/AlignConfig.h b/Detectors/Align/include/Align/AlignConfig.h index 4252f9ee4364c..91b503c2c923e 100644 --- a/Detectors/Align/include/Align/AlignConfig.h +++ b/Detectors/Align/include/Align/AlignConfig.h @@ -35,6 +35,8 @@ struct AlignConfig : public o2::conf::ConfigurableParamHelper { float q2PtMin[NTrackTypes] = {0.01, 0.01}; float q2PtMax[NTrackTypes] = {10., 10.}; float tglMax[NTrackTypes] = {3., 10.}; + float defPTB0Coll = 0.6; + float defPTB0Cosm = 3.0; int minPoints[NTrackTypes] = {4, 10}; int minDetAcc[NTrackTypes] = {1, 1}; @@ -54,7 +56,7 @@ struct AlignConfig : public o2::conf::ConfigurableParamHelper { int minTOFClusters = 1; // min TOF clusters to accept track int maxTPCRowsCombined = 1; // allow combining clusters on so many rows to a single cluster int discardEdgePadrows = 3; // discard padrow if its distance to stack edge padrow < this - float discardSectorEdgeDepth = 2.; // discard clusters too close to the sector edge + float discardSectorEdgeDepth = 2.5; // discard clusters too close to the sector edge float ITSOverlapMargin = 0.15; // consider for overlaps only clusters within this marging from the chip edge (in cm) float ITSOverlapMaxChi2 = 16; // max chi2 between track and overlapping cluster int ITSOverlapEdgeRows = 1; // require clusters to not have pixels closer than this distance from the edge @@ -71,8 +73,11 @@ struct AlignConfig : public o2::conf::ConfigurableParamHelper { int minTOFClustersCosm = 0; // min TOF clusters to accept track int minTOFClustersCosmLeg = 1; // min TOF clusters per leg to accept track - int minTPCPadRow = 0; // min TPC pad-row to account - int maxTPCPadRow = 151; // max TPC pad-row to account + int minTPCPadRow = 6; // min TPC pad-row to account + int maxTPCPadRow = 146; // max TPC pad-row to account + + float cosmMaxDSnp = 0.025; // reject cosmic tracks with larger than this snp difference + float cosmMaxDTgl = 0.1; // reject cosmic tracks with larger than this tgl difference float maxDCAforVC[2] = {-1, -1}; // DCA cut in R,Z to allow track be subjected to vertex constraint float maxChi2forVC = -1; // track-vertex chi2 cut to allow the track be subjected to vertex constraint diff --git a/Detectors/Align/include/Align/AlignableSensorHMPID.h b/Detectors/Align/include/Align/AlignableSensorHMPID.h index 6064078d1b923..867b72152c73c 100644 --- a/Detectors/Align/include/Align/AlignableSensorHMPID.h +++ b/Detectors/Align/include/Align/AlignableSensorHMPID.h @@ -29,7 +29,7 @@ namespace o2 namespace align { -class AlignableSensorHMPID : public AlignableSensor +class AlignableSensorHMPID final : public AlignableSensor { public: AlignableSensorHMPID(const char* name = 0, int vid = 0, int iid = 0, int isec = 0); diff --git a/Detectors/Align/include/Align/AlignableSensorITS.h b/Detectors/Align/include/Align/AlignableSensorITS.h index de0e6d35629ec..8070869bd8c7b 100644 --- a/Detectors/Align/include/Align/AlignableSensorITS.h +++ b/Detectors/Align/include/Align/AlignableSensorITS.h @@ -29,7 +29,7 @@ namespace o2 namespace align { -class AlignableSensorITS : public AlignableSensor +class AlignableSensorITS final : public AlignableSensor { public: AlignableSensorITS() = default; diff --git a/Detectors/Align/include/Align/AlignableSensorTOF.h b/Detectors/Align/include/Align/AlignableSensorTOF.h index 745251d7dc6f2..d9e11dce98a0c 100644 --- a/Detectors/Align/include/Align/AlignableSensorTOF.h +++ b/Detectors/Align/include/Align/AlignableSensorTOF.h @@ -29,7 +29,7 @@ namespace o2 namespace align { -class AlignableSensorTOF : public AlignableSensor +class AlignableSensorTOF final : public AlignableSensor { public: AlignableSensorTOF() = default; diff --git a/Detectors/Align/include/Align/AlignableSensorTPC.h b/Detectors/Align/include/Align/AlignableSensorTPC.h index 41b48afaa38f7..838e8c8272400 100644 --- a/Detectors/Align/include/Align/AlignableSensorTPC.h +++ b/Detectors/Align/include/Align/AlignableSensorTPC.h @@ -25,7 +25,7 @@ namespace o2 namespace align { -class AlignableSensorTPC : public AlignableSensor +class AlignableSensorTPC final : public AlignableSensor { public: AlignableSensorTPC() = default; diff --git a/Detectors/Align/include/Align/AlignableSensorTRD.h b/Detectors/Align/include/Align/AlignableSensorTRD.h index 65792d597cb3a..eabc3905e9e13 100644 --- a/Detectors/Align/include/Align/AlignableSensorTRD.h +++ b/Detectors/Align/include/Align/AlignableSensorTRD.h @@ -26,7 +26,7 @@ namespace o2 namespace align { -class AlignableSensorTRD : public AlignableSensor +class AlignableSensorTRD final : public AlignableSensor { public: AlignableSensorTRD() = default; @@ -35,7 +35,12 @@ class AlignableSensorTRD : public AlignableSensor int getSector() const { return mSector; } void setSector(int sc) { mSector = (uint8_t)sc; } void dPosTraDParCalib(const AlignmentPoint* pnt, double* deriv, int calibID, const AlignableVolume* parent = nullptr) const final; + + void prepareMatrixL2G(bool reco = false) final; + void prepareMatrixL2GIdeal() final; void prepareMatrixT2L() final; + void prepareMatrixClAlg() final; + void prepareMatrixClAlgReco() final; protected: uint8_t mSector = 0; // sector ID diff --git a/Detectors/Align/include/Align/Controller.h b/Detectors/Align/include/Align/Controller.h index 4def24472ea6d..abbb051be138a 100644 --- a/Detectors/Align/include/Align/Controller.h +++ b/Detectors/Align/include/Align/Controller.h @@ -26,6 +26,7 @@ #include "DetectorsBase/GeometryManager.h" #include "DetectorsBase/Propagator.h" #include "Align/AlignmentTrack.h" +#include "Align/AlgTrcDbg.h" #include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/TrackCosmics.h" #include "DataFormatsTPC/VDriftCorrFact.h" @@ -53,9 +54,8 @@ #include #include #include "Align/Mille.h" -#include "GPUO2Interface.h" -#include "GPUParam.h" -#include "DataFormatsTPC/WorkflowHelper.h" +// #include "GPUO2Interface.h" +// #include "DataFormatsTPC/WorkflowHelper.h" namespace o2 { @@ -72,6 +72,11 @@ namespace utils class TreeStreamRedirector; } +namespace gpu +{ +class GPUParam; +} + namespace align { @@ -220,6 +225,7 @@ class Controller final : public TObject void initMIlleOutput(); void initResidOutput(); bool storeProcessedTrack(o2::dataformats::GlobalTrackID tid = {}); + void extractDbgTrack(); void printStatistics() const; // void genPedeSteerFile(const Option_t* opt = "") const; @@ -302,6 +308,7 @@ class Controller final : public TObject float mMPRecOutFraction = 0.; float mControlFraction = 0.; std::unique_ptr mAlgTrack; // current alignment track + AlgTrcDbg mAlgTrackDbg; // current alignment track debug version const o2::globaltracking::RecoContainer* mRecoData = nullptr; // externally set RecoContainer const o2::trd::TrackletTransformer* mTRDTransformer = nullptr; // TRD tracket transformer bool mTRDTrigRecFilterActive = false; // select TRD triggers processed with ITS diff --git a/Detectors/Align/include/Align/ResidualsControllerFast.h b/Detectors/Align/include/Align/ResidualsControllerFast.h index 171bfb45757d2..5a2f947db9cca 100644 --- a/Detectors/Align/include/Align/ResidualsControllerFast.h +++ b/Detectors/Align/include/Align/ResidualsControllerFast.h @@ -24,7 +24,7 @@ namespace o2 namespace align { -class ResidualsControllerFast : public TObject +class ResidualsControllerFast final : public TObject { public: enum { kCosmicBit = BIT(14), diff --git a/Detectors/Align/macro/CMakeLists.txt b/Detectors/Align/macro/CMakeLists.txt index 49106e647c412..54c8715b074b2 100644 --- a/Detectors/Align/macro/CMakeLists.txt +++ b/Detectors/Align/macro/CMakeLists.txt @@ -10,6 +10,7 @@ # or submit itself to any jurisdiction. install(FILES algconf.C + algDump.C MPRec2Mille.C DESTINATION share/Detectors/Align/macro) @@ -17,6 +18,10 @@ o2_add_test_root_macro(algconf.C PUBLIC_LINK_LIBRARIES O2::Align LABELS align COMPILE_ONLY) +o2_add_test_root_macro(algDump.C + PUBLIC_LINK_LIBRARIES O2::Align + LABELS align COMPILE_ONLY) + o2_add_test_root_macro(MPRec2Mille.C PUBLIC_LINK_LIBRARIES O2::Align LABELS align COMPILE_ONLY) diff --git a/Detectors/Align/macro/algDump.C b/Detectors/Align/macro/algDump.C new file mode 100644 index 0000000000000..865f8a0bbf6a0 --- /dev/null +++ b/Detectors/Align/macro/algDump.C @@ -0,0 +1,93 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "DetectorsBase/GeometryManager.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "ITSMFTReconstruction/ChipMappingITS.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DataFormatsTRD/Constants.h" +#include "TRDBase/Geometry.h" +#include "TOFBase/Geo.h" +#include +#endif + +using DetID = o2::detectors::DetID; + +void algDump(const std::string& geom = "", const std::string& outname = "algdump.root") +{ + o2::base::GeometryManager::loadGeometry(geom.c_str()); + o2::utils::TreeStreamRedirector outstream(outname.c_str(), "recreate"); + TGeoHMatrix* matAlg = nullptr; + TGeoHMatrix matOrig; + TVector3 pos0, pos; + DetID det; + + auto procSens = [](TGeoHMatrix& mat) { + double loc[3] = {0., 0., 0.}, glo[3]; + mat.LocalToMaster(loc, glo); + return TVector3(glo[0], glo[1], glo[2]); + }; + + auto store = [&outstream, &det, &pos, &pos0](int lr, int sid, int sidLr) { + outstream << "gm" + << "det=" << det.getID() << "lr=" << lr << "sid=" << sid << "sidlr=" << sidLr << "pos0=" << pos0 << "pos=" << pos << "\n"; + // printf("xx %d %d %d %f %f %f\n", det.getID(), lr, sid, pos0[0], pos0[1], pos0[1]); + }; + + det = DetID("ITS"); + o2::itsmft::ChipMappingITS mpits; + for (int ic = 0; ic < mpits.getNChips(); ic++) { + int lr = mpits.getLayer(ic); + int ic0 = ic - mpits.getFirstChipsOnLayer(lr); + matAlg = o2::base::GeometryManager::getMatrix(det, ic); + o2::base::GeometryManager::getOriginalMatrix(det, ic, matOrig); + pos0 = procSens(matOrig); + pos = procSens(*matAlg); + store(lr, ic, ic0); + } + + det = DetID("TRD"); + for (int ilr = 0; ilr < o2::trd::constants::NLAYER; ilr++) { // layer + for (int ich = 0; ich < o2::trd::constants::NSTACK * o2::trd::constants::NSECTOR; ich++) { // chamber + int isector = ich / o2::trd::constants::NSTACK; + int istack = ich % o2::trd::constants::NSTACK; + uint16_t sid = o2::trd::Geometry::getDetector(ilr, istack, isector); + const char* symname = Form("TRD/sm%02d/st%d/pl%d", isector, istack, ilr); + if (!gGeoManager->GetAlignableEntry(symname)) { + continue; + } + matAlg = o2::base::GeometryManager::getMatrix(det, sid); + o2::base::GeometryManager::getOriginalMatrix(det, sid, matOrig); + pos0 = procSens(matOrig); + pos = procSens(*matAlg); + store(ilr, sid, ich); + } + } + + det = DetID("TOF"); + int cnt = -1; + for (int isc = 0; isc < 18; isc++) { + for (int istr = 1; istr <= o2::tof::Geo::NSTRIPXSECTOR; istr++) { // strip + const char* symname = Form("TOF/sm%02d/strip%02d", isc, istr); + cnt++; + if (!gGeoManager->GetAlignableEntry(symname)) { + continue; + } + matAlg = o2::base::GeometryManager::getMatrix(det, cnt); + o2::base::GeometryManager::getOriginalMatrix(det, cnt, matOrig); + pos0 = procSens(matOrig); + pos = procSens(*matAlg); + store(0, cnt, cnt); + } + } + outstream.Close(); +} diff --git a/Detectors/Align/src/AlgPntDbg.cxx b/Detectors/Align/src/AlgPntDbg.cxx new file mode 100644 index 0000000000000..b52492b3a5cc4 --- /dev/null +++ b/Detectors/Align/src/AlgPntDbg.cxx @@ -0,0 +1,22 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlgPntDbg.h + +#include "Align/AlgPntDbg.h" + +namespace o2 +{ +namespace align +{ + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlgTrcDbg.cxx b/Detectors/Align/src/AlgTrcDbg.cxx new file mode 100644 index 0000000000000..157ca941449b7 --- /dev/null +++ b/Detectors/Align/src/AlgTrcDbg.cxx @@ -0,0 +1,23 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file AlgTrcDbg.h + +#include "Align/AlgTrcDbg.h" +#include "Framework/Logger.h" + +namespace o2 +{ +namespace align +{ + +} // namespace align +} // namespace o2 diff --git a/Detectors/Align/src/AlignLinkDef.h b/Detectors/Align/src/AlignLinkDef.h index f43d6ee76fbdb..2952c46ec821d 100644 --- a/Detectors/Align/src/AlignLinkDef.h +++ b/Detectors/Align/src/AlignLinkDef.h @@ -39,6 +39,10 @@ #pragma link C++ class o2::align::GeometricalConstraint + ; #pragma link C++ class o2::align::utils; +#pragma link C++ class o2::align::AlgPntDbg + ; +#pragma link C++ class o2::align::AlgTrcDbg + ; +#pragma link C++ class std::vector < o2::align::AlgPntDbg> + ; + #pragma link C++ class o2::align::AlignConfig + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::align::AlignConfig> + ; diff --git a/Detectors/Align/src/AlignableDetectorITS.cxx b/Detectors/Align/src/AlignableDetectorITS.cxx index 67a68fe50dc26..7387ae4620bf3 100644 --- a/Detectors/Align/src/AlignableDetectorITS.cxx +++ b/Detectors/Align/src/AlignableDetectorITS.cxx @@ -156,8 +156,19 @@ int AlignableDetectorITS::processPoints(GIndex gid, int npntCut, bool inv) const auto& clusIdx = recoData->getITSTracksClusterRefs(); // do we want to apply some cuts? int clEntry = track.getFirstClusterEntry(); + int preevSensID = -1; + bool errReported = false; for (int icl = track.getNumberOfClusters(); icl--;) { // clusters refs are stored from outer to inner layers, we loop in inner -> outer direction const auto& clus = mITSClustersArray[(clusIDs[npoints] = clusIdx[clEntry + icl])]; + if (clus.getSensorID() < preevSensID && !errReported) { // clusters are ordered from outer to inner layer, hence decreasing sensorID + std::string errstr{}; + for (int ie = track.getNumberOfClusters(); ie--;) { + errstr += fmt::format(" {}", mITSClustersArray[clusIdx[clEntry + ie]].getSensorID()); + } + LOGP(error, "wrong ITS clusters order? : chips {}", errstr); + errReported = true; + } + preevSensID = clus.getSensorID(); if (clus.getBits()) { // overlapping clusters will have bit set if (clus.isBitSet(EdgeFlags::Biased)) { continue; diff --git a/Detectors/Align/src/AlignableDetectorTPC.cxx b/Detectors/Align/src/AlignableDetectorTPC.cxx index 86bad838f8273..f66d9e3f3ab95 100644 --- a/Detectors/Align/src/AlignableDetectorTPC.cxx +++ b/Detectors/Align/src/AlignableDetectorTPC.cxx @@ -24,6 +24,8 @@ #include "DataFormatsTPC/WorkflowHelper.h" #include #include +#include "GPUO2Interface.h" +#include "DataFormatsTPC/WorkflowHelper.h" #include "GPUParam.inc" namespace o2 @@ -134,7 +136,7 @@ int AlignableDetectorTPC::processPoints(GIndex gid, int npntCut, bool inv) break; } } - mController->getTPCCorrMaps()->Transform(sector, row, cl->getPad(), cl->getTime(), xTmp, yTmp, zTmp, tOffset); + mController->getTPCCorrMaps()->Transform(sector, row, clTmp->getPad(), clTmp->getTime(), xTmp, yTmp, zTmp, tOffset); if (algConf.discardSectorEdgeDepth > 0) { if (std::abs(yTmp) + algConf.discardSectorEdgeDepth > xTmp * TAN10) { if (i + direction != stop) { @@ -215,6 +217,13 @@ int AlignableDetectorTPC::processPoints(GIndex gid, int npntCut, bool inv) gpu::gpustd::array p = {y, z}; gpu::gpustd::array c = {0, 0, 0}; mController->getTPCParam()->GetClusterErrors2(sector, currentRow, z, trkParam.getSnp(), trkParam.getTgl(), -1.f, 0.f, 0.f, c[0], c[2]); // TODO: Note this disables occupancy / charge components of the error estimation + mController->getTPCParam()->UpdateClusterError2ByState(clusterState, c[0], c[2]); + int nrComb = std::abs(row - currentRow) + 1; + if (nrComb > 1) { + float fact = 1. / std::sqrt(nrComb); + c[0] *= fact; + c[2] *= fact; + } if (sysE[0] > 0.f) { c[0] += sysE[0] * sysE[0]; } @@ -222,7 +231,6 @@ int AlignableDetectorTPC::processPoints(GIndex gid, int npntCut, bool inv) c[2] += sysE[1] * sysE[1]; } - mController->getTPCParam()->UpdateClusterError2ByState(clusterState, c[0], c[2]); if (!trkParam.update(p, c)) { break; } diff --git a/Detectors/Align/src/AlignableDetectorTRD.cxx b/Detectors/Align/src/AlignableDetectorTRD.cxx index 117d328e8fc0a..d752553bf6ead 100644 --- a/Detectors/Align/src/AlignableDetectorTRD.cxx +++ b/Detectors/Align/src/AlignableDetectorTRD.cxx @@ -201,18 +201,10 @@ int AlignableDetectorTRD::processPoints(GIndex gid, int npntCut, bool inv) continue; } double locXYZ[3] = {trackletCalibLoc.getX(), trackletCalibLoc.getY(), trackletCalibLoc.getZ()}, locXYZC[3], traXYZ[3]; - const auto& matAlg = sensor->getMatrixClAlg(); // local alignment matrix matAlg.LocalToMaster(locXYZ, locXYZC); // aligned point in the local frame const auto& mat = sensor->getMatrixT2L(); // RS FIXME check if correct mat.MasterToLocal(locXYZC, traXYZ); - - // This is a hack until TRD T2L matrix problem will be solved - const auto trackletCalib = recoData->getTRDCalibratedTracklets()[trkltId]; - traXYZ[0] = trackletCalib.getX(); - traXYZ[1] = trackletCalib.getY(); - traXYZ[2] = trackletCalib.getZ(); - int trkltSec = sensor->getSector(); // trkltDet / (o2::trd::constants::NLAYER * o2::trd::constants::NSTACK); float alpSens = sensor->getAlpTracking(); // o2::math_utils::sector2Angle(trkltSec); if (trkltSec != o2::math_utils::angle2Sector(trkParam.getAlpha()) || diff --git a/Detectors/Align/src/AlignableSensorTRD.cxx b/Detectors/Align/src/AlignableSensorTRD.cxx index 2dc7d25ca5932..aa52567a36fdf 100644 --- a/Detectors/Align/src/AlignableSensorTRD.cxx +++ b/Detectors/Align/src/AlignableSensorTRD.cxx @@ -19,6 +19,7 @@ #include "Align/utils.h" #include "Framework/Logger.h" #include "Align/AlignmentPoint.h" +#include "DetectorsBase/GeometryManager.h" namespace o2 { @@ -33,22 +34,71 @@ AlignableSensorTRD::AlignableSensorTRD(const char* name, int vid, int iid, int i // def c-tor } +//____________________________________________ +void AlignableSensorTRD::prepareMatrixClAlg() +{ + // prepare alignment matrix in the pseudo-LOCAL frame of TRD (account that the chamber has extra X,Y rotations + TGeoHMatrix ma = getMatrixL2GIdeal().Inverse(); + ma *= getMatrixL2G(); + setMatrixClAlg(ma); + // +} + +//____________________________________________ +void AlignableSensorTRD::prepareMatrixClAlgReco() +{ + // prepare alignment matrix in the pseudo-LOCAL frame of TRD (account that the chamber has extra X,Y rotations + TGeoHMatrix ma = getMatrixL2GIdeal().Inverse(); + ma *= getMatrixL2G(); + setMatrixClAlgReco(ma); + // +} + +//____________________________________________ +void AlignableSensorTRD::prepareMatrixL2GIdeal() +{ + TGeoHMatrix Rxy; + Rxy.RotateX(-90); + Rxy.RotateY(-90); + TGeoHMatrix mtmp; + if (!base::GeometryManager::getOriginalMatrix(getSymName(), mtmp)) { + LOG(fatal) << "Failed to find ideal L2G matrix for " << getSymName(); + } + mtmp *= Rxy; + setMatrixL2GIdeal(mtmp); +} + +//____________________________________________ +void AlignableSensorTRD::prepareMatrixL2G(bool reco) +{ + TGeoHMatrix Rxy; + Rxy.RotateX(-90); + Rxy.RotateY(-90); + const char* path = getSymName(); + const TGeoHMatrix* l2g = nullptr; + if (!gGeoManager->GetAlignableEntry(path) || !(l2g = base::GeometryManager::getMatrix(path))) { + LOGP(fatal, "Failed to find L2G matrix for {}alignable {} -> {}", gGeoManager->GetAlignableEntry(path) ? "" : "non-", path, (void*)l2g); + } + TGeoHMatrix mtmp = *l2g; + mtmp *= Rxy; + reco ? setMatrixL2GReco(mtmp) : setMatrixL2G(mtmp); +} + //____________________________________________ void AlignableSensorTRD::prepareMatrixT2L() { // extract from geometry T2L matrix double alp = math_utils::detail::sector2Angle(mSector); mAlp = alp; - double loc[3] = {0, 0, 0}, glo[3]; - getMatrixL2GIdeal().LocalToMaster(loc, glo); - mX = Sqrt(glo[0] * glo[0] + glo[1] * glo[1]); - TGeoHMatrix t2l; - // t2l.SetDx(mX); // to remove when T2L will be clarified - t2l.RotateZ(alp * RadToDeg()); - const TGeoHMatrix l2gi = getMatrixL2GIdeal().Inverse(); - t2l.MultiplyLeft(&l2gi); - + TGeoHMatrix Rs; + Rs.RotateZ(-alp * TMath::RadToDeg()); + TGeoHMatrix m0 = getMatrixL2GIdeal(); + m0.MultiplyLeft(Rs); + TGeoHMatrix t2l = m0.Inverse(); setMatrixT2L(t2l); + double loc[3] = {0, 0, 0}, glo[3]; + t2l.MasterToLocal(loc, glo); + mX = glo[0]; // } diff --git a/Detectors/Align/src/AlignmentTrack.cxx b/Detectors/Align/src/AlignmentTrack.cxx index 2987682ace4e1..554d30e246e29 100644 --- a/Detectors/Align/src/AlignmentTrack.cxx +++ b/Detectors/Align/src/AlignmentTrack.cxx @@ -787,7 +787,7 @@ void AlignmentTrack::Print(Option_t* opt) const for (int ip = 0; ip < getNPoints(); ip++) { printf("#%3d ", ip); auto* pnt = getPoint(ip); - pnt->print(0); // RS FIXME OPT + pnt->print(AlignmentPoint::kMeasurementBit); // RS FIXME OPT // if (res && pnt->containsMeasurement()) { printf(" Residuals : %+.3e %+.3e -> Pulls: %+7.2f %+7.2f\n", @@ -848,17 +848,17 @@ bool AlignmentTrack::iniFit() { // perform initial fit of the track // - trackParam_t trc(*(trackParam_t*)this); - // + const auto& algConf = AlignConfig::Instance(); if (!getFieldON()) { // for field-off data impose nominal momentum + setQ2Pt(isCosmic() ? 1. / algConf.defPTB0Cosm : 1. / algConf.defPTB0Coll); } + trackParam_t trc(*(trackParam_t*)this); mChi2 = mChi2CosmUp = mChi2CosmDn = 0; // // the points are ranged from outer to inner for collision tracks, // and from outer point of lower leg to outer point of upper leg for the cosmic track // // the fit will always start from the outgoing track in inward direction - const auto& algConf = AlignConfig::Instance(); if (!fitLeg(trc, 0, getInnerPointID(), mNeedInv[0])) { if (algConf.verbose > 2) { LOG(warn) << "Failed fitLeg 0"; @@ -922,6 +922,17 @@ bool AlignmentTrack::combineTracks(trackParam_t& trcL, const trackParam_t& trcU) return false; } // + LOGP(debug, "CosmDn: {}", trcL.asString()); + LOGP(debug, "CosmUp: {}", trcU.asString()); + float dsnp = trcL.getSnp() - trcU.getSnp(), dTgl = trcL.getTgl() - trcU.getTgl(); + if (std::abs(dsnp) > algConf.cosmMaxDSnp || std::abs(dTgl) > algConf.cosmMaxDTgl) { + if (algConf.verbose > 2) { + LOGP(error, "Rejecting track with dSnp={} dTgl={}", dsnp, dTgl); + LOGP(error, "CosmDn: {}", trcL.asString()); + LOGP(error, "CosmUp: {}", trcU.asString()); + } + return false; + } // const covMat_t& covU = trcU.getCov(); // const covMat_t& covL = trcL.getCov(); // @@ -968,7 +979,8 @@ bool AlignmentTrack::combineTracks(trackParam_t& trcL, const trackParam_t& trcU) } mChi2 += chi2; // - // printf("Combined: Chi2Tot:%.2f ChiUp:%.2f ChiDn:%.2f ChiCmb:%.2f\n",mChi2,mChi2CosmUp,mChi2CosmDn, chi2); + LOGP(debug, "CosmCB: {}", trcL.asString()); + LOGP(debug, "Combined: Chi2Tot:{} ChiUp:{} ChiDn:{} ChiCmb:{} DSnp:{} DTgl:{} Alp:{}", mChi2, mChi2CosmUp, mChi2CosmDn, chi2, dsnp, dTgl, trcL.getAlpha()); return true; } diff --git a/Detectors/Align/src/Controller.cxx b/Detectors/Align/src/Controller.cxx index ccc275b0d1057..a45314b2285c0 100644 --- a/Detectors/Align/src/Controller.cxx +++ b/Detectors/Align/src/Controller.cxx @@ -44,10 +44,13 @@ #include #include #include +#include "GPUO2Interface.h" +#include "DataFormatsTPC/WorkflowHelper.h" #include #include "CommonUtils/NameConf.h" #include "MathUtils/SymMatrixSolver.h" #include "DataFormatsParameters/GRPObject.h" +#include "GPUParam.h" #include "SimulationDataFormat/MCUtils.h" #include "Steer/MCKinematicsReader.h" @@ -329,8 +332,16 @@ void Controller::process() } continue; } - - if (mUseMC && mDebugOutputLevel) { + if (mDebugOutputLevel && mAlgTrackDbg.setTrackParam(mAlgTrack.get())) { + mAlgTrackDbg.mGID = trackIndex; + (*mDBGOut) << "algtrack" + << "runNumber=" << mTimingInfo.runNumber + << "tfID=" << mTimingInfo.tfCounter + << "orbit=" << mTimingInfo.firstTForbit + << "bz=" << PropagatorD::Instance()->getNominalBz() + << "t=" << mAlgTrackDbg << "\n"; + } + if (mUseMC && mDebugOutputLevel > 1) { auto lbl = mRecoData->getTrackMCLabel(trackIndex); if (lbl.isValid()) { std::vector pntX, pntY, pntZ, trcX, trcY, trcZ, prpX, prpY, prpZ, alpha, xsens, pntXTF, pntYTF, pntZTF, resY, resZ; @@ -421,7 +432,19 @@ void Controller::processCosmic() nTrc++; mStat.data[ProcStat::kInput][ProcStat::kCosmic]++; std::array contributorsGID[2] = {mRecoData->getSingleDetectorRefs(track.getRefBottom()), mRecoData->getSingleDetectorRefs(track.getRefTop())}; - + bool hasTRD = false, hasITS = false, hasTPC = false, hasTOF = false; + if (contributorsGID[0][GTrackID::TRD].isIndexSet() || contributorsGID[1][GTrackID::TRD].isIndexSet()) { + hasTRD = true; + } + if (contributorsGID[0][GTrackID::TOF].isIndexSet() || contributorsGID[1][GTrackID::TOF].isIndexSet()) { + hasTOF = true; + } + if (contributorsGID[0][GTrackID::TPC].isIndexSet() || contributorsGID[1][GTrackID::TPC].isIndexSet()) { + hasTPC = true; + } + if (contributorsGID[0][GTrackID::ITS].isIndexSet() || contributorsGID[1][GTrackID::ITS].isIndexSet()) { + hasITS = true; + } // check detectors contributions AlignableDetector* det = nullptr; int ndet = 0, npnt = 0; @@ -511,7 +534,7 @@ void Controller::processCosmic() if (algConf.verbose > 1) { LOGP(info, "processing cosmic track B-Leg:{} T-Leg:{}, Ndets:{}, Npoints: {}", track.getRefBottom().asString(), track.getRefTop().asString(), ndet, npnt); } - if (ndet < algConf.minDetectorsCosm || (tpcIn && ndet == 1)) { + if (ndet < algConf.minDetectorsCosm /* || (tpcIn && ndet == 1)*/) { continue; } if (npnt < algConf.minPointTotalCosm) { @@ -543,6 +566,16 @@ void Controller::processCosmic() } continue; } + if (mDebugOutputLevel && mAlgTrackDbg.setTrackParam(mAlgTrack.get())) { + mAlgTrackDbg.mGID = track.getRefBottom(); + mAlgTrackDbg.mGIDCosmUp = track.getRefTop(); + (*mDBGOut) << "algtrack" + << "runNumber=" << mTimingInfo.runNumber + << "tfID=" << mTimingInfo.tfCounter + << "orbit=" << mTimingInfo.firstTForbit + << "bz=" << PropagatorD::Instance()->getNominalBz() + << "t=" << mAlgTrackDbg << "\n"; + } storeProcessedTrack(); mStat.data[ProcStat::kAccepted][ProcStat::kCosmic]++; nTrcAcc++; diff --git a/Detectors/Base/include/DetectorsBase/Detector.h b/Detectors/Base/include/DetectorsBase/Detector.h index 6acfa4f5cc46c..1432d93c53821 100644 --- a/Detectors/Base/include/DetectorsBase/Detector.h +++ b/Detectors/Base/include/DetectorsBase/Detector.h @@ -29,7 +29,6 @@ #include #include #include -#include #include "CommonUtils/ShmManager.h" #include "CommonUtils/ShmAllocator.h" #include @@ -42,9 +41,7 @@ #include -namespace o2 -{ -namespace base +namespace o2::base { /// This is the basic class for any AliceO2 detector module, whether it is @@ -260,17 +257,12 @@ T decodeShmMessage(fair::mq::Parts& dataparts, int index, bool*& busy) } // this goes into the source -void attachMessageBufferToParts(fair::mq::Parts& parts, fair::mq::Channel& channel, - void* data, size_t size, void (*func_ptr)(void* data, void* hint), void* hint); +void attachMessageBufferToParts(fair::mq::Parts& parts, fair::mq::Channel& channel, void* data, TClass* cl); template void attachTMessage(Container const& hits, fair::mq::Channel& channel, fair::mq::Parts& parts) { - TMessage* tmsg = new TMessage(); - tmsg->WriteObjectAny((void*)&hits, TClass::GetClass(typeid(hits))); - attachMessageBufferToParts( - parts, channel, tmsg->Buffer(), tmsg->BufferSize(), - [](void* data, void* hint) { delete static_cast(hint); }, tmsg); + attachMessageBufferToParts(parts, channel, (void*)&hits, TClass::GetClass(typeid(hits))); } void* decodeTMessageCore(fair::mq::Parts& dataparts, int index); @@ -746,7 +738,6 @@ class DetImpl : public o2::base::Detector ClassDefOverride(DetImpl, 0); }; -} // namespace base -} // namespace o2 +} // namespace o2::base #endif diff --git a/Detectors/Base/include/DetectorsBase/Propagator.h b/Detectors/Base/include/DetectorsBase/Propagator.h index 600e71e7fb95d..a9e2ce6e0383d 100644 --- a/Detectors/Base/include/DetectorsBase/Propagator.h +++ b/Detectors/Base/include/DetectorsBase/Propagator.h @@ -126,17 +126,17 @@ class PropagatorImpl // Bz at the origin GPUd() void updateField(); - GPUd() value_type getNominalBz() const { return mBz; } + GPUd() value_type getNominalBz() const { return mNominalBz; } GPUd() void setTGeoFallBackAllowed(bool v) { mTGeoFallBackAllowed = v; } GPUd() bool isTGeoFallBackAllowed() const { return mTGeoFallBackAllowed; } GPUd() void setMatLUT(const o2::base::MatLayerCylSet* lut) { mMatLUT = lut; } GPUd() const o2::base::MatLayerCylSet* getMatLUT() const { return mMatLUT; } GPUd() void setGPUField(const o2::gpu::GPUTPCGMPolynomialField* field) { mGPUField = field; } GPUd() const o2::gpu::GPUTPCGMPolynomialField* getGPUField() const { return mGPUField; } - GPUd() void setBz(value_type bz) { mBz = bz; } + GPUd() void setNominalBz(value_type bz) { mNominalBz = bz; } GPUd() bool hasMagFieldSet() const { return mField != nullptr; } - GPUd() void estimateLTFast(o2::track::TrackLTIntegral& lt, const o2::track::TrackParametrization& trc) const; + GPUd() value_type estimateLTFast(o2::track::TrackLTIntegral& lt, const o2::track::TrackParametrization& trc) const; GPUd() float estimateLTIncrement(const o2::track::TrackParametrization& trc, const o2::math_utils::Point3D& postStart, const o2::math_utils::Point3D& posEnd) const; #ifndef GPUCA_GPUCODE @@ -168,7 +168,7 @@ class PropagatorImpl const o2::field::MagFieldFast* mFieldFast = nullptr; ///< External fast field map (barrel only for the moment) o2::field::MagneticField* mField = nullptr; ///< External nominal field map - value_type mBz = 0; ///< nominal field + value_type mNominalBz = 0; ///< nominal field bool mTGeoFallBackAllowed = true; ///< allow fall back to TGeo if requested MatLUT is not available const o2::base::MatLayerCylSet* mMatLUT = nullptr; // externally set LUT diff --git a/Detectors/Base/include/DetectorsBase/Ray.h b/Detectors/Base/include/DetectorsBase/Ray.h index 1701e65c2d638..304ad5f00b03f 100644 --- a/Detectors/Base/include/DetectorsBase/Ray.h +++ b/Detectors/Base/include/DetectorsBase/Ray.h @@ -74,8 +74,8 @@ class Ray GPUd() float getDist() const { return mDistXYZ; } GPUd() float getDist(float deltaT) const { return mDistXYZ * (deltaT > 0 ? deltaT : -deltaT); } - // for debud only - float getPos(float t, int i) const { return mP[i] + t * mD[i]; } + // for debug only + GPUd() float getPos(float t, int i) const { return mP[i] + t * mD[i]; } GPUd() float getPhi(float t) const { diff --git a/Detectors/Base/src/Detector.cxx b/Detectors/Base/src/Detector.cxx index 3168e0e84e1f2..f2b790ffccd5b 100644 --- a/Detectors/Base/src/Detector.cxx +++ b/Detectors/Base/src/Detector.cxx @@ -17,6 +17,7 @@ #include "DetectorsBase/MaterialManager.h" #include "DetectorsCommonDataFormats/DetID.h" #include "Field/MagneticField.h" +#include "Framework/TMessageSerializer.h" #include "TString.h" // for TString #include "TGeoManager.h" @@ -196,16 +197,19 @@ int Detector::registerSensitiveVolumeAndGetVolID(std::string const& name) #include #include #include -namespace o2 -{ -namespace base +namespace o2::base { // this goes into the source -void attachMessageBufferToParts(fair::mq::Parts& parts, fair::mq::Channel& channel, void* data, size_t size, - void (*free_func)(void* data, void* hint), void* hint) +void attachMessageBufferToParts(fair::mq::Parts& parts, fair::mq::Channel& channel, void* data, TClass* cl) { - std::unique_ptr message(channel.NewMessage(data, size, free_func, hint)); - parts.AddPart(std::move(message)); + auto msg = channel.Transport()->CreateMessage(4096, fair::mq::Alignment{64}); + // This will serialize the data directly into the message buffer, without any further + // buffer or copying. Notice how the message will have 8 bytes of header and then + // the serialized data as TBufferFile. In principle one could construct a serialized TMessage payload + // however I did not manage to get it to work for every case. + o2::framework::FairOutputTBuffer buffer(*msg); + o2::framework::TMessageSerializer::serialize(buffer, data, cl); + parts.AddPart(std::move(msg)); } void attachDetIDHeaderMessage(int id, fair::mq::Channel& channel, fair::mq::Parts& parts) { @@ -246,17 +250,14 @@ void* decodeShmCore(fair::mq::Parts& dataparts, int index, bool*& busy) void* decodeTMessageCore(fair::mq::Parts& dataparts, int index) { - class TMessageWrapper : public TMessage - { - public: - TMessageWrapper(void* buf, Int_t len) : TMessage(buf, len) { ResetBit(kIsOwner); } - ~TMessageWrapper() override = default; - }; auto rawmessage = std::move(dataparts.At(index)); - auto message = std::make_unique(rawmessage->GetData(), rawmessage->GetSize()); - return message.get()->ReadObjectAny(message.get()->GetClass()); + o2::framework::FairInputTBuffer buffer((char*)rawmessage->GetData(), rawmessage->GetSize()); + buffer.InitMap(); + auto* cl = buffer.ReadClass(); + buffer.SetBufferOffset(0); + buffer.ResetMap(); + return buffer.ReadObjectAny(cl); } -} // namespace base -} // namespace o2 +} // namespace o2::base ClassImp(o2::base::Detector); diff --git a/Detectors/Base/src/MatLayerCyl.cxx b/Detectors/Base/src/MatLayerCyl.cxx index 6ff822bb7faab..04f68fb81866f 100644 --- a/Detectors/Base/src/MatLayerCyl.cxx +++ b/Detectors/Base/src/MatLayerCyl.cxx @@ -97,8 +97,8 @@ void MatLayerCyl::initSegmentation(float rMin, float rMax, float zHalfSpan, int offs = alignSize(offs + nphi * sizeof(float), getBufferAlignmentBytes()); // account for alignment for (int i = nphi; i--;) { - mSliceCos[i] = std::cos(getPhiBinMin(i)); - mSliceSin[i] = std::sin(getPhiBinMin(i)); + mSliceCos[i] = o2::math_utils::cos(getPhiBinMin(i)); + mSliceSin[i] = o2::math_utils::sin(getPhiBinMin(i)); } o2::gpu::resizeArray(mCells, 0, getNCells(), reinterpret_cast(mFlatBufferPtr + offs)); @@ -273,8 +273,8 @@ void MatLayerCyl::getMeanRMS(MatCell& mean, MatCell& rms) const rms.meanX2X0 /= nc; rms.meanRho -= mean.meanRho * mean.meanRho; rms.meanX2X0 -= mean.meanX2X0 * mean.meanX2X0; - rms.meanRho = rms.meanRho > 0.f ? std::sqrt(rms.meanRho) : 0.f; - rms.meanX2X0 = rms.meanX2X0 > 0.f ? std::sqrt(rms.meanX2X0) : 0.f; + rms.meanRho = rms.meanRho > 0.f ? o2::math_utils::sqrt(rms.meanRho) : 0.f; + rms.meanX2X0 = rms.meanX2X0 > 0.f ? o2::math_utils::sqrt(rms.meanX2X0) : 0.f; } //________________________________________________________________________________ diff --git a/Detectors/Base/src/MatLayerCylSet.cxx b/Detectors/Base/src/MatLayerCylSet.cxx index fb2e720427016..12156fc55b381 100644 --- a/Detectors/Base/src/MatLayerCylSet.cxx +++ b/Detectors/Base/src/MatLayerCylSet.cxx @@ -108,7 +108,7 @@ void MatLayerCylSet::finalizeStructures() for (int i = 1; i < nlr; i++) { const auto& lr = getLayer(i); - if (std::sqrt(lr.getRMin2()) > std::sqrt(get()->mR2Intervals[nRIntervals] + Ray::Tiny)) { + if (o2::math_utils::sqrt(lr.getRMin2()) > o2::math_utils::sqrt(get()->mR2Intervals[nRIntervals] + Ray::Tiny)) { // register gap get()->mInterval2LrID[nRIntervals] = -1; get()->mR2Intervals[++nRIntervals] = lr.getRMin2(); diff --git a/Detectors/Base/src/Propagator.cxx b/Detectors/Base/src/Propagator.cxx index 0575f08e1997c..0d1b53b695536 100644 --- a/Detectors/Base/src/Propagator.cxx +++ b/Detectors/Base/src/Propagator.cxx @@ -62,9 +62,9 @@ void PropagatorImpl::updateField() } const value_type xyz[3] = {0.}; if (mFieldFast) { - mFieldFast->GetBz(xyz, mBz); + mFieldFast->GetBz(xyz, mNominalBz); } else { - mBz = mField->GetBz(xyz[0], xyz[1], xyz[2]); + mNominalBz = mField->GetBz(xyz[0], xyz[1], xyz[2]); } } @@ -519,7 +519,7 @@ GPUd() bool PropagatorImpl::propagateToDCABxByBz(const o2::dataformats: if (d > maxD) { return false; } - value_type crv = track.getCurvature(mBz); + value_type crv = track.getCurvature(mNominalBz); value_type tgfv = -(crv * x - snp) / (crv * y + csp); sn = tgfv / math_utils::detail::sqrt(1.f + tgfv * tgfv); cs = math_utils::detail::sqrt((1. - sn) * (1. + sn)); @@ -616,7 +616,7 @@ GPUd() bool PropagatorImpl::propagateToDCABxByBz(const math_utils::Poin if (d > maxD) { return false; } - value_type crv = track.getCurvature(mBz); + value_type crv = track.getCurvature(mNominalBz); value_type tgfv = -(crv * x - snp) / (crv * y + csp); sn = tgfv / math_utils::detail::sqrt(1.f + tgfv * tgfv); cs = math_utils::detail::sqrt((1. - sn) * (1. + sn)); @@ -668,7 +668,7 @@ GPUd() float PropagatorImpl::estimateLTIncrement(const o2::track::Track //____________________________________________________________ template -GPUd() void PropagatorImpl::estimateLTFast(o2::track::TrackLTIntegral& lt, const o2::track::TrackParametrization& trc) const +GPUd() value_T PropagatorImpl::estimateLTFast(o2::track::TrackLTIntegral& lt, const o2::track::TrackParametrization& trc) const { value_T xdca = 0., ydca = 0., length = 0.; // , zdca = 0. // zdca might be used in future o2::math_utils::CircleXY c; @@ -687,7 +687,7 @@ GPUd() void PropagatorImpl::estimateLTFast(o2::track::TrackLTIntegral& return math_utils::detail::abs(trc.getY() * math_utils::detail::sqrt(1. + trc.getTgl() * trc.getTgl())); // distance from the current point to DCA } }; - trc.getCircleParamsLoc(mBz, c); + trc.getCircleParamsLoc(mNominalBz, c); if (c.rC != 0.) { // helix auto distC = math_utils::detail::sqrt(c.getCenterD2()); // distance from the circle center to origin if (distC > 1.e-3) { @@ -698,7 +698,7 @@ GPUd() void PropagatorImpl::estimateLTFast(o2::track::TrackLTIntegral& auto angcos = (v0x * v1x + v0y * v1y) / (c.rC * c.rC); if (math_utils::detail::abs(angcos) < 1.f) { auto ang = math_utils::detail::acos(angcos); - if ((trc.getSign() > 0.f) == (mBz > 0.f)) { + if ((trc.getSign() > 0.f) == (mNominalBz > 0.f)) { ang = -ang; // we need signeg angle c.rC = -c.rC; // we need signed curvature for zdca } @@ -715,8 +715,10 @@ GPUd() void PropagatorImpl::estimateLTFast(o2::track::TrackLTIntegral& length = straigh_line_approx(); } // since we assume the track or its parent comes from the beam-line or decay, add XY(?) distance to it - length += math_utils::detail::sqrt(xdca * xdca + ydca * ydca); + value_T dcaT = math_utils::detail::sqrt(xdca * xdca + ydca * ydca); + length += dcaT; lt.addStep(length, trc.getP2Inv()); + return dcaT; } //____________________________________________________________ diff --git a/Detectors/CTF/workflow/src/CTFWriterSpec.cxx b/Detectors/CTF/workflow/src/CTFWriterSpec.cxx index 44d726dd7e4f4..ba4542969a712 100644 --- a/Detectors/CTF/workflow/src/CTFWriterSpec.cxx +++ b/Detectors/CTF/workflow/src/CTFWriterSpec.cxx @@ -62,6 +62,7 @@ #include #include #include +#include using namespace o2::framework; @@ -477,22 +478,24 @@ void CTFWriterSpec::run(ProcessingContext& pc) CTFHeader header{mTimingInfo.runNumber, mTimingInfo.creation, mTimingInfo.firstTForbit, mTimingInfo.tfCounter}; size_t szCTF = 0; mSizeReport = ""; - szCTF += processDet(pc, DetID::ITS, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::TPC, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::TRD, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::TOF, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::PHS, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::CPV, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::EMC, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::HMP, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::MFT, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::MCH, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::MID, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::ZDC, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::FT0, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::FV0, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::FDD, header, mCTFTreeOut.get()); - szCTF += processDet(pc, DetID::CTP, header, mCTFTreeOut.get()); + std::array szCTFperDet{0}; // DetID::TST is between FDD and CTP and remains empty + szCTFperDet[DetID::ITS] = processDet(pc, DetID::ITS, header, mCTFTreeOut.get()); + szCTFperDet[DetID::TPC] = processDet(pc, DetID::TPC, header, mCTFTreeOut.get()); + szCTFperDet[DetID::TRD] = processDet(pc, DetID::TRD, header, mCTFTreeOut.get()); + szCTFperDet[DetID::TOF] = processDet(pc, DetID::TOF, header, mCTFTreeOut.get()); + szCTFperDet[DetID::PHS] = processDet(pc, DetID::PHS, header, mCTFTreeOut.get()); + szCTFperDet[DetID::CPV] = processDet(pc, DetID::CPV, header, mCTFTreeOut.get()); + szCTFperDet[DetID::EMC] = processDet(pc, DetID::EMC, header, mCTFTreeOut.get()); + szCTFperDet[DetID::HMP] = processDet(pc, DetID::HMP, header, mCTFTreeOut.get()); + szCTFperDet[DetID::MFT] = processDet(pc, DetID::MFT, header, mCTFTreeOut.get()); + szCTFperDet[DetID::MCH] = processDet(pc, DetID::MCH, header, mCTFTreeOut.get()); + szCTFperDet[DetID::MID] = processDet(pc, DetID::MID, header, mCTFTreeOut.get()); + szCTFperDet[DetID::ZDC] = processDet(pc, DetID::ZDC, header, mCTFTreeOut.get()); + szCTFperDet[DetID::FT0] = processDet(pc, DetID::FT0, header, mCTFTreeOut.get()); + szCTFperDet[DetID::FV0] = processDet(pc, DetID::FV0, header, mCTFTreeOut.get()); + szCTFperDet[DetID::FDD] = processDet(pc, DetID::FDD, header, mCTFTreeOut.get()); + szCTFperDet[DetID::CTP] = processDet(pc, DetID::CTP, header, mCTFTreeOut.get()); + szCTF = std::accumulate(szCTFperDet.begin(), szCTFperDet.end(), 0); if (mReportInterval > 0 && (mTimingInfo.tfCounter % mReportInterval) == 0) { LOGP(important, "CTF {} size report:{} - Total:{}", mTimingInfo.tfCounter, mSizeReport, fmt::group_digits(szCTF)); } @@ -530,6 +533,9 @@ void CTFWriterSpec::run(ProcessingContext& pc) if (mCreateDict && mSaveDictAfter > 0 && (mNCTF % mSaveDictAfter) == 0) { storeDictionaries(); } + int dummy = 0; + pc.outputs().snapshot({"ctfdone", 0}, dummy); + pc.outputs().snapshot(Output{"CTF", "SIZES", 0}, szCTFperDet); } //___________________________________________________________________ @@ -795,7 +801,8 @@ DataProcessorSpec getCTFWriterSpec(DetID::mask_t dets, const std::string& outTyp return DataProcessorSpec{ "ctf-writer", inputs, - Outputs{}, + Outputs{{OutputLabel{"ctfdone"}, "CTF", "DONE", 0, Lifetime::Timeframe}, + {"CTF", "SIZES", 0, Lifetime::Timeframe}}, AlgorithmSpec{adaptFromTask(dets, outType, verbosity, reportInterval)}, // RS FIXME once global/local options clash is solved, --output-type will become device option Options{ //{"output-type", VariantType::String, "ctf", {"output types: ctf (per TF) or dict (create dictionaries) or both or none"}}, {"save-ctf-after", VariantType::Int64, 0ll, {"autosave CTF tree with multiple CTFs after every N CTFs if >0 or every -N MBytes if < 0"}}, diff --git a/Detectors/CTP/macro/TestConfig.C b/Detectors/CTP/macro/TestConfig.C index 0ff91c514ee93..48360996d3439 100644 --- a/Detectors/CTP/macro/TestConfig.C +++ b/Detectors/CTP/macro/TestConfig.C @@ -23,7 +23,11 @@ void TestConfig(bool test = 0) uint64_t timestamp = 1660196771632; std::string run = "523148"; o2::ctp::CTPRunManager::setCCDBHost("https://alice-ccdb.cern.ch"); - auto ctpcfg = o2::ctp::CTPRunManager::getConfigFromCCDB(timestamp, run); + bool ok; + auto ctpcfg = o2::ctp::CTPRunManager::getConfigFromCCDB(timestamp, run, ok); + if (ok == 0) { + std::cout << "Can not get config for run:" << run << std::endl; + } CTPConfiguration ctpconfig; ctpconfig.loadConfigurationRun3(ctpcfg.getConfigString()); // ctpconfig.printStream(std::cout); diff --git a/Detectors/CTP/workflow/include/CTPWorkflow/RawDecoderSpec.h b/Detectors/CTP/workflow/include/CTPWorkflow/RawDecoderSpec.h index 4933477467ba7..607491b5cb48a 100644 --- a/Detectors/CTP/workflow/include/CTPWorkflow/RawDecoderSpec.h +++ b/Detectors/CTP/workflow/include/CTPWorkflow/RawDecoderSpec.h @@ -56,7 +56,8 @@ class RawDecoderSpec : public framework::Task // for digits bool mDoDigits = true; o2::pmr::vector mOutputDigits; - int mMaxOutputSize = 0; + int mMaxInputSize = 0; + bool mMaxInputSizeFatal = 0; // for lumi bool mDoLumi = true; // diff --git a/Detectors/CTP/workflow/src/RawDecoderSpec.cxx b/Detectors/CTP/workflow/src/RawDecoderSpec.cxx index 4bba1d7991321..df0988c871196 100644 --- a/Detectors/CTP/workflow/src/RawDecoderSpec.cxx +++ b/Detectors/CTP/workflow/src/RawDecoderSpec.cxx @@ -40,8 +40,9 @@ void RawDecoderSpec::init(framework::InitContext& ctx) int inp2 = mDecoder.setLumiInp(2, lumiinp2); mOutputLumiInfo.inp1 = inp1; mOutputLumiInfo.inp2 = inp2; - mMaxOutputSize = ctx.options().get("max-output-size"); - LOG(info) << "CTP reco init done. Inputs decoding here:" << decodeinps << " DoLumi:" << mDoLumi << " DoDigits:" << mDoDigits << " NTF:" << mNTFToIntegrate << " Lumi inputs:" << lumiinp1 << ":" << inp1 << " " << lumiinp2 << ":" << inp2 << " Max errors:" << maxerrors << " Max output size:" << mMaxOutputSize; + mMaxInputSize = ctx.options().get("max-input-size"); + mMaxInputSizeFatal = ctx.options().get("max-input-size-fatal"); + LOG(info) << "CTP reco init done. Inputs decoding here:" << decodeinps << " DoLumi:" << mDoLumi << " DoDigits:" << mDoDigits << " NTF:" << mNTFToIntegrate << " Lumi inputs:" << lumiinp1 << ":" << inp1 << " " << lumiinp2 << ":" << inp2 << " Max errors:" << maxerrors << " Max input size:" << mMaxInputSize << " MaxInputSizeFatal:" << mMaxInputSizeFatal; // mOutputLumiInfo.printInputs(); } void RawDecoderSpec::endOfStream(framework::EndOfStreamContext& ec) @@ -111,6 +112,22 @@ void RawDecoderSpec::run(framework::ProcessingContext& ctx) // std::vector lumiPointsHBF1; std::vector filter{InputSpec{"filter", ConcreteDataTypeMatcher{"CTP", "RAWDATA"}, Lifetime::Timeframe}}; + if (mMaxInputSize > 0) { + size_t payloadSize = 0; + for (const auto& ref : o2::framework::InputRecordWalker(inputs, filter)) { + const auto dh = o2::framework::DataRefUtils::getHeader(ref); + payloadSize += o2::framework::DataRefUtils::getPayloadSize(ref); + } + if (payloadSize > (size_t)mMaxInputSize) { + if (mMaxInputSizeFatal) { + LOG(fatal) << "Input data size:" << payloadSize; + } else { + LOG(error) << "Input data size:" << payloadSize; + } + dummyOutput(); + return; + } + } int ret = mDecoder.decodeRaw(inputs, filter, mOutputDigits, lumiPointsHBF1); if (ret == 1) { dummyOutput(); @@ -118,10 +135,6 @@ void RawDecoderSpec::run(framework::ProcessingContext& ctx) } if (mDoDigits) { LOG(info) << "[CTPRawToDigitConverter - run] Writing " << mOutputDigits.size() << " digits. IR rejected:" << mDecoder.getIRRejected() << " TCR rejected:" << mDecoder.getTCRRejected(); - if ((mMaxOutputSize > 0) && (mOutputDigits.size() > mMaxOutputSize)) { - LOG(error) << "CTP raw output size: " << mOutputDigits.size(); - mOutputDigits.clear(); - } ctx.outputs().snapshot(o2::framework::Output{"CTP", "DIGITS", 0}, mOutputDigits); } if (mDoLumi) { @@ -194,6 +207,7 @@ o2::framework::DataProcessorSpec o2::ctp::reco_workflow::getRawDecoderSpec(bool {"lumi-inp1", o2::framework::VariantType::String, "TVX", {"The first input used for online lumi. Name in capital."}}, {"lumi-inp2", o2::framework::VariantType::String, "VBA", {"The second input used for online lumi. Name in capital."}}, {"use-verbose-mode", o2::framework::VariantType::Bool, false, {"Verbose logging"}}, - {"max-output-size", o2::framework::VariantType::Int, 0, {"Do not send output if bigger than max size, 0 - do not check"}}, + {"max-input-size", o2::framework::VariantType::Int, 0, {"Do not process input if bigger than max size, 0 - do not check"}}, + {"max-input-size-fatal", o2::framework::VariantType::Bool, false, {"If true issue fatal error otherwise error on;y"}}, {"ctpinputs-decoding", o2::framework::VariantType::Bool, false, {"Inputs alignment: true - raw decoder - has to be compatible with CTF decoder: allowed options: 10,01,00"}}}}; } diff --git a/Detectors/CTP/workflowScalers/README.md b/Detectors/CTP/workflowScalers/README.md index 4b109f779dc1d..df8df2c55cc44 100644 --- a/Detectors/CTP/workflowScalers/README.md +++ b/Detectors/CTP/workflowScalers/README.md @@ -1,3 +1,7 @@ + + How to generate c++ proto files ? On the computer where project https://gitlab.cern.ch/aliceCTP3/ctp3-ipbus/-/tree/master diff --git a/Detectors/CTP/workflowScalers/py/watchProcess.py b/Detectors/CTP/workflowScalers/py/watchProcess.py new file mode 100755 index 0000000000000..5ac9a98833706 --- /dev/null +++ b/Detectors/CTP/workflowScalers/py/watchProcess.py @@ -0,0 +1,117 @@ +#!/usr/bin/python3 +import requests,re +import os,sys,time,math +import time +from subprocess import Popen, PIPE +def send2(text = "ahoj"): + headers = { 'Content-Type':'application/json',} + data = { + 'text':text, + 'username':'alicetrg', + } + response = requests.post('https://mattermost.web.cern.ch/hooks/75949oimoinr9b47uhp8c1oomh',headers=headers,json=data) + print(response) +# +def send(): + """ + does not work always return can not parse data + """ + Hpar = '\\"Content-Type:application/json\\"' + texth = '\\"text\\"' + text = '\\"lalal\\"' + usernameh = '\\"username\\"' + username = '\\"alicetrg\\"' + dpar = '{}:{},{}:{}'.format(texth,text,usernameh,username) + dpar = "{"+dpar+"}" + dpar = '"'+dpar+'"' + #print(dpar) + cmd = 'curl -g -i -X POST -H {} -d {} https://mattermost.web.cern.ch/hooks/75949oimoinr9b47uhp8c1oomh'.format(Hpar,dpar) + #cmd = 'curl -i -X POST -H {} https://mattermost.web.cern.ch/hooks/75949oimoinr9b47uhp8c1oomh'.format(Hpar) + #cmd='curl -s -o /dev/null {} -F blob=@datafile.root {}/CTP/Calib/{}/{}/{}'.format(wpar, ccdb, actid, tval_s, tval_e) + process = Popen(cmd.split(), stdout = PIPE, stderr = PIPE) + stdo, stde = process.communicate() + print(cmd) + print(stdo) + print("====") + print(stde) +def getLog(service): + #cmd = "journalctl --no-hostname --user-unit "+service + cmd = 'journalctl --no-hostname --user-unit --since "1 day ago" '+service + print(cmd,cmd.split()) + process = Popen(cmd.split(), stdout = PIPE, stderr = PIPE) + stdo, stde= process.communicate() + stdo_str = stdo.decode("utf-8") + if stdo_str.find("No entries") != -1: + print("No entries for service:",service) + return None + #print(stdo) + return stdo_str +NMAX = 3 +def parseLog(log): + nsent = 0 + lines = log.split('\n') + print("# lines:",len(lines)) + print(lines[len(lines)-2]) + for line in lines: + if line.find("ERROR") != -1: + print(line) + if nsent < NMAX: + send2(line) + nsent += 1 + if line.find("ALARM") != -1: + print(line) + if nsent < NMAX: + send2(line) + nsent += 1 +# +nWarn = 0 +nAlarm = 0 +nError = 0 +def printNew(list,n,send = 0): + print(n,len(list)) + sendnow = 0 + if len(list) > n : + sendnow = 1 + for i in list[n:]: + print(i) + n = len(list) + if sendnow and send: + print("sending to mm:",line) + send2(line) + return n +def getLogFile(): + global nWarn, nAlarm,nError + nWarnList = [] + nAlarmList = [] + nErrorList = [] + MAX = 3 + file = "/home/rl/WORK/ctpproxy110424.log" + f = open(file,"r") + nsent = 0 + for line in f: + if line.find("ERROR") != -1: + print(line) + if line.find("ALARM") != -1: + #print(line) + nAlarmList.append(line) + #send2(line) + #nsent += 1 + if line.find("WARN") != -1: + #print(line) + #items = line.split("\]\[") + #items = re.split('\[|\]',line) + nWarnList.append(line) + #print(nWarn) + nWarn = printNew(nWarnList,nWarn) + nAlarm = printNew(nAlarmList,nAlarm,1) + f.close() +if __name__ =="__main__": + #send2("uj0"); + while 1: + now = time.localtime() + current_time = time.strftime("%H:%M:%S",now) + print("===> Time =", current_time) + log = getLogFile() + time.sleep(15) + + #parseLog(log) diff --git a/Detectors/CTP/workflowScalers/src/ctp-ccdb-orbit.cxx b/Detectors/CTP/workflowScalers/src/ctp-ccdb-orbit.cxx index 56f58f946fd22..13c06730d18ce 100644 --- a/Detectors/CTP/workflowScalers/src/ctp-ccdb-orbit.cxx +++ b/Detectors/CTP/workflowScalers/src/ctp-ccdb-orbit.cxx @@ -33,7 +33,10 @@ #include namespace bpo = boost::program_options; // -// get object from ccdb auto pp = ccdbMgr.getSpecific>("CTP/Calib/OrbitResetTest") +// get object from ccdb +// auto & cc = o2::ccdb::BasicCCDNManager::instance(); +// auto pp = ccdbMgr.getSpecific>("CTP/Calib/OrbitResetTest") +// std::cout << (*pp)[0] << std::endl; int main(int argc, char** argv) { const std::string testCCDB = "http://ccdb-test.cern.ch:8080"; @@ -76,18 +79,17 @@ int main(int argc, char** argv) std::vector vect; std::string ccdbPath; auto now = std::chrono::system_clock::now(); - long tt = std::chrono::duration_cast(now.time_since_epoch()).count(); + long tt = std::chrono::duration_cast(now.time_since_epoch()).count(); + vect.push_back(tt); if (action == "sox") { // write to CTP/Calib/FirstRunOrbit std::cout << "===> FirsRunOrbit" << std::endl; - vect.push_back(tt); vect.push_back(vm["run-number"].as()); vect.push_back(vm["sox-orbit"].as()); ccdbPath = "CTP/Calib/FirstRunOrbit"; } else { // write to CTP/Calib/OrbitReset std::cout << "===> ResetOrbit" << std::endl; - vect.push_back(tt); ccdbPath = "CTP/Calib/OrbitReset"; if (vm["testReset"].as()) { ccdbPath += "Test"; @@ -108,7 +110,7 @@ int main(int argc, char** argv) o2::ccdb::CcdbApi api; api.init(ccdbAddress.c_str()); std::map metadata; - long tmin = tt; + long tmin = tt / 1000; long tmax = tmin + 381928219; if (action == "sox") { int64_t runnum = vm["run-number"].as(); diff --git a/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h b/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h index f0d11fca9384b..36e9e209af878 100644 --- a/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h +++ b/Detectors/Calibration/include/DetectorsCalibration/TimeSlotCalibration.h @@ -454,7 +454,7 @@ template void TimeSlotCalibration::print() const { for (int i = 0; i < getNSlots(); i++) { - LOG(info) << "Slot #" << i << " of " << getNSlots(); + LOG(info) << "Slot #" << i + 1 << " of " << getNSlots(); getSlot(i).print(); } } diff --git a/Detectors/Calibration/testMacros/getRunParameters.cxx b/Detectors/Calibration/testMacros/getRunParameters.cxx index 5aa2dc4c60dc2..c06926511c95d 100644 --- a/Detectors/Calibration/testMacros/getRunParameters.cxx +++ b/Detectors/Calibration/testMacros/getRunParameters.cxx @@ -150,15 +150,6 @@ int main(int argc, char* argv[]) writeDetListToFile(dets); LOGP(info, "Checking IR and duration"); - if (run < 519041) { - // LHC22c, d - LOGP(info, "Run number < 519041 --> we are in 22c, or 22d, so IR is < 100 kHz, writing 0.f"); - LOGP(info, "In addition, the duration for these runs is O2end - O2start: if the run was short, this might overestimate the duration"); - // In these runs, sometimes the CCDB does not contain correct scalers, so we use 0 as a placeholder - writeIRtoFile(ir); - writeDurationToFile(run_O2duration); - return 0; - } // Extract CTP info ccdb_inst.setFatalWhenNull(false); diff --git a/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h b/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h index 4384628d01f4c..679a5b9d91f41 100644 --- a/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h +++ b/Detectors/DCS/testWorkflow/src/DCStoDPLconverter.h @@ -50,7 +50,7 @@ using DPCOM = o2::dcs::DataPointCompositeObject; /// A callback function to retrieve the FairMQChannel name to be used for sending /// messages of the specified OutputSpec -o2f::InjectorFunction dcs2dpl(std::unordered_map& dpid2group, bool fbiFirst, bool verbose = false, int FBIPerInterval = 1) +o2f::InjectorFunction dcs2dpl(std::unordered_map>& dpid2group, bool fbiFirst, bool verbose = false, int FBIPerInterval = 1) { return [dpid2group, fbiFirst, verbose, FBIPerInterval](o2::framework::TimingInfo& tinfo, framework::ServiceRegistryRef const& services, fair::mq::Parts& parts, o2f::ChannelRetriever channelRetriever, size_t newTimesliceId, bool& stop) -> bool { @@ -104,7 +104,15 @@ o2f::InjectorFunction dcs2dpl(std::unordered_map& dp // do we want to check if this DP was requested ? auto mapEl = dpid2group.find(src.id); if (verbose) { - LOG(info) << "Received DP " << src.id << " (data = " << src.data << "), matched to output-> " << (mapEl == dpid2group.end() ? "none " : mapEl->second.as()); + std::string dest; + if (mapEl == dpid2group.end()) { + dest = "none"; + } else { + for (const auto& ds : mapEl->second) { + dest += fmt::format("{}, ", ds.as()); + } + } + LOG(info) << "Received DP " << src.id << " (data = " << src.data << "), matched to output-> " << dest; } if (mapEl != dpid2group.end()) { cache[src.id] = src; // this is needed in case in the 1s window we get a new value for the same DP @@ -132,7 +140,9 @@ o2f::InjectorFunction dcs2dpl(std::unordered_map& dp for (auto& it : cache) { auto mapEl = dpid2group.find(it.first); if (mapEl != dpid2group.end()) { - outputs[mapEl->second].push_back(it.second); + for (const auto& ds : mapEl->second) { + outputs[ds].push_back(it.second); + } } } std::uint64_t creation = std::chrono::time_point_cast(timerNow).time_since_epoch().count(); diff --git a/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx b/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx index 770305f909dc1..f8f0dba8fd8f6 100644 --- a/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx +++ b/Detectors/DCS/testWorkflow/src/dcs-proxy.cxx @@ -65,18 +65,18 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) o2::conf::ConfigurableParam::updateFromString(config.options().get("configKeyValues")); std::string url = config.options().get("ccdb-url"); - std::unordered_map dpid2DataDesc; + std::unordered_map> dpid2DataDesc; if (testMode) { DPID dpidtmp; DPID::FILL(dpidtmp, "ADAPOS_LG/TEST_000100", DeliveryType::DPVAL_STRING); - dpid2DataDesc[dpidtmp] = "COMMON"; // i.e. this will go to {DCS/COMMON/0} OutputSpec + dpid2DataDesc[dpidtmp] = {"COMMON"}; // i.e. this will go to {DCS/COMMON/0} OutputSpec DPID::FILL(dpidtmp, "ADAPOS_LG/TEST_000110", DeliveryType::DPVAL_STRING); - dpid2DataDesc[dpidtmp] = "COMMON"; + dpid2DataDesc[dpidtmp] = {"COMMON"}; DPID::FILL(dpidtmp, "ADAPOS_LG/TEST_000200", DeliveryType::DPVAL_STRING); - dpid2DataDesc[dpidtmp] = "COMMON1"; + dpid2DataDesc[dpidtmp] = {"COMMON1"}; DPID::FILL(dpidtmp, "ADAPOS_LG/TEST_000240", DeliveryType::DPVAL_INT); - dpid2DataDesc[dpidtmp] = "COMMON1"; + dpid2DataDesc[dpidtmp] = {"COMMON1"}; } else { @@ -95,7 +95,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) for (auto& el : *dpid2Det) { o2::header::DataDescription tmpd; tmpd.runtimeInit(el.second.c_str(), el.second.size()); - dpid2DataDesc[el.first] = tmpd; + dpid2DataDesc[el.first].push_back(tmpd); } } } @@ -107,7 +107,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& config) // now collect all required outputs to define OutputSpecs for specifyExternalFairMQDeviceProxy std::unordered_map> outMap; for (auto itdp : dpid2DataDesc) { - outMap[itdp.second]++; + for (const auto& ds : itdp.second) { + outMap[ds]++; + } } Outputs dcsOutputs; diff --git a/Detectors/EMCAL/base/CMakeLists.txt b/Detectors/EMCAL/base/CMakeLists.txt index 9a852c00616e3..62a0cb6d9a25b 100644 --- a/Detectors/EMCAL/base/CMakeLists.txt +++ b/Detectors/EMCAL/base/CMakeLists.txt @@ -42,6 +42,13 @@ o2_add_test(Mapper LABELS emcal ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage) +o2_add_test(Geometry + SOURCES test/testGeometry.cxx + PUBLIC_LINK_LIBRARIES O2::EMCALBase + COMPONENT_NAME emcal + LABELS emcal + ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage) + o2_add_test(RCUTrailer SOURCES test/testRCUTrailer.cxx PUBLIC_LINK_LIBRARIES O2::EMCALBase diff --git a/Detectors/EMCAL/base/include/EMCALBase/TriggerMappingV2.h b/Detectors/EMCAL/base/include/EMCALBase/TriggerMappingV2.h index 3b56c1794d3e4..24d8c1686f005 100644 --- a/Detectors/EMCAL/base/include/EMCALBase/TriggerMappingV2.h +++ b/Detectors/EMCAL/base/include/EMCALBase/TriggerMappingV2.h @@ -49,6 +49,7 @@ class TriggerMappingV2 static constexpr unsigned int FASTORSPHI = (5 * FASTORSPHISM) + (1 * FASTORSPHISM / 3) /*EMCAL*/ + (3 * FASTORSPHISM) + (1 * FASTORSPHISM / 3) /*DCAL */; ///< Number of FastOR/EMCALs in Phi static constexpr unsigned int ALLFASTORS = FASTORSETA * FASTORSPHI; ///< Number of FastOR/EMCALs + static constexpr unsigned int PATCHESINTRU = 77; //******************************************** // Index types diff --git a/Detectors/EMCAL/base/src/ClusterFactory.cxx b/Detectors/EMCAL/base/src/ClusterFactory.cxx index 9386f42b4e8e5..0c801de615487 100644 --- a/Detectors/EMCAL/base/src/ClusterFactory.cxx +++ b/Detectors/EMCAL/base/src/ClusterFactory.cxx @@ -89,16 +89,17 @@ o2::emcal::AnalysisCluster ClusterFactory::buildCluster(int clusterIn std::vector cellsIdices; - size_t iCell = 0; bool addClusterLabels = ((clusterLabel != nullptr) && (mCellLabelContainer.size() > 0)); for (auto cellIndex : inputsIndices) { cellsIdices.push_back(cellIndex); if (addClusterLabels) { - for (size_t iLabel = 0; iLabel < mCellLabelContainer[iCell].GetLabelSize(); iLabel++) { - clusterLabel->addValue(mCellLabelContainer[iCell].GetLabel(iLabel), - mCellLabelContainer[iCell].GetAmplitudeFraction(iLabel) * mInputsContainer[iCell].getEnergy()); + for (size_t iLabel = 0; iLabel < mCellLabelContainer[cellIndex].GetLabelSize(); iLabel++) { + if (mCellLabelContainer[cellIndex].GetAmplitudeFraction(iLabel) <= 0.f) { + continue; // skip 0 entries + } + clusterLabel->addValue(mCellLabelContainer[cellIndex].GetLabel(iLabel), + mCellLabelContainer[cellIndex].GetAmplitudeFraction(iLabel) * mInputsContainer[cellIndex].getEnergy()); } - iCell++; } } if (addClusterLabels) { diff --git a/Detectors/EMCAL/base/src/Geometry.cxx b/Detectors/EMCAL/base/src/Geometry.cxx index 826b7a5d75341..5d4b793525e20 100644 --- a/Detectors/EMCAL/base/src/Geometry.cxx +++ b/Detectors/EMCAL/base/src/Geometry.cxx @@ -1026,7 +1026,7 @@ std::tuple Geometry::CalculateCellIndex(Int_t absId) const Int_t nModule = tmp / mNCellsInModule; tmp = tmp % mNCellsInModule; - Int_t nIphi = tmp / mNPHIdiv, nIeta = tmp % mNPHIdiv; + Int_t nIphi = tmp / mNPHIdiv, nIeta = tmp % mNETAdiv; return std::make_tuple(nSupMod, nModule, nIphi, nIeta); } diff --git a/Detectors/EMCAL/base/src/TriggerMappingV2.cxx b/Detectors/EMCAL/base/src/TriggerMappingV2.cxx index 5d5ee46dc6f2f..e60d7b31e5305 100644 --- a/Detectors/EMCAL/base/src/TriggerMappingV2.cxx +++ b/Detectors/EMCAL/base/src/TriggerMappingV2.cxx @@ -390,7 +390,7 @@ TriggerMappingV2::IndexTRU TriggerMappingV2::getTRUIndexFromOnlineHardareAddree( unsigned short branch = (hardwareAddress >> 11) & 0x1; // 0/1 - IndexTRU truIndex = ((ddlID << 1) | branch) - 1; // 0..2 + IndexTRU truIndex = (((ddlID % 2) << 1) | branch) - 1; // 0..2 truIndex = (supermoduleID % 2) ? 2 - truIndex : truIndex; diff --git a/Detectors/EMCAL/base/test/testGeometry.cxx b/Detectors/EMCAL/base/test/testGeometry.cxx new file mode 100644 index 0000000000000..f297410b6959f --- /dev/null +++ b/Detectors/EMCAL/base/test/testGeometry.cxx @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#define BOOST_TEST_MODULE Test EMCAL Base +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include +#include +#include "EMCALBase/Geometry.h" +#include +#include + +std::tuple GetRefCellIndex(int CellId); + +/// \macro Test implementation of the EMCAL Geometry +/// +/// Test coverage: +/// - GetCellIndex (get #sm, #mod, phi index and eta index): all cells (0-17663) +/// - Invalid CellId: exception test for cell -1 and 17664 +BOOST_AUTO_TEST_CASE(Geometry_test) +{ + auto testgeometry = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + + // Check GetCellIndex function for all valid cells by comparing to GetRefCellIndex function + for (int iCell = 0; iCell < 17664; iCell++) { + auto [smod, mod, iphi, ieta] = testgeometry->GetCellIndex(iCell); + auto [smod_ref, mod_ref, iphi_ref, ieta_ref] = GetRefCellIndex(iCell); + BOOST_CHECK_EQUAL(smod, smod_ref); + BOOST_CHECK_EQUAL(mod, mod_ref); + BOOST_CHECK_EQUAL(iphi, iphi_ref); + BOOST_CHECK_EQUAL(ieta, ieta_ref); + } // And then check the exeptions of -1 and 17664 + BOOST_CHECK_EXCEPTION(testgeometry->GetCellIndex(-1), o2::emcal::InvalidCellIDException, [](o2::emcal::InvalidCellIDException const& mCellID) { return -1; }); + BOOST_CHECK_EXCEPTION(testgeometry->GetCellIndex(17664), o2::emcal::InvalidCellIDException, [](o2::emcal::InvalidCellIDException const& mCellID) { return 17664; }); +} + +std::tuple GetRefCellIndex(int CellId) +{ + // Four cells per module: + int ieta = CellId % 2; // cells 0 and 2 (in each module) have eta index 0 + int iphi = (CellId % 4 == 2 || CellId % 4 == 3) ? 1 : 0; // cells 0 and 1 (in each module) have phi index 0 + + int smod = 0, mod = 0; // Super module number and module number + if (CellId >= 0 && CellId < 11520) { // The first 10 super modules are full modules + smod = CellId / 1152; // Their number is their cell number divided by the cells per sm (rounded down) + mod = (CellId % 1152) / 4; // And the module is the cell number within the sm (%) divided by four (four cells in one module) + } else if (CellId >= 11520 && CellId < 12288) { // First two one thirds + smod = 10 + (CellId - 11520) / 384; // +10 to account for the - 11520 + mod = ((CellId - 11520) % 384) / 4; // -11520 to subtract all cells in full super modules + } else if (CellId >= 12288 && CellId < 16896) { // Six two third modules + smod = 12 + (CellId - 12288) / 768; + mod = ((CellId - 12288) % 768) / 4; + } else if (CellId >= 16896 && CellId < 17664) { // Second two one third modules + smod = 18 + (CellId - 16896) / 384; + mod = ((CellId - 16896) % 384) / 4; + } + + return std::make_tuple(smod, mod, iphi, ieta); +} \ No newline at end of file diff --git a/Detectors/EMCAL/calib/CMakeLists.txt b/Detectors/EMCAL/calib/CMakeLists.txt index c9c70d88c9b6b..a8ca8d9505318 100644 --- a/Detectors/EMCAL/calib/CMakeLists.txt +++ b/Detectors/EMCAL/calib/CMakeLists.txt @@ -18,6 +18,7 @@ o2_add_library(EMCALCalib src/TempCalibrationParams.cxx src/TempCalibParamSM.cxx src/GainCalibrationFactors.cxx + src/Pedestal.cxx src/TriggerTRUDCS.cxx src/TriggerSTUDCS.cxx src/TriggerSTUErrorCounter.cxx @@ -37,6 +38,7 @@ o2_target_root_dictionary(EMCALCalib include/EMCALCalib/TempCalibrationParams.h include/EMCALCalib/TempCalibParamSM.h include/EMCALCalib/GainCalibrationFactors.h + include/EMCALCalib/Pedestal.h include/EMCALCalib/TriggerTRUDCS.h include/EMCALCalib/TriggerSTUDCS.h include/EMCALCalib/TriggerSTUErrorCounter.h @@ -90,6 +92,13 @@ o2_add_test(GainCalibrationFactors LABELS emcal ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage) +o2_add_test(Pedestal + SOURCES test/testPedestal.cxx + PUBLIC_LINK_LIBRARIES O2::EMCALCalib + COMPONENT_NAME emcal + LABELS emcal + ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage) + o2_add_test(TriggerTRUDCS SOURCES test/testTriggerTRUDCS.cxx PUBLIC_LINK_LIBRARIES O2::EMCALCalib diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/CalibDB.h b/Detectors/EMCAL/calib/include/EMCALCalib/CalibDB.h index 452d49d0f8053..d4fc0329c0bf5 100644 --- a/Detectors/EMCAL/calib/include/EMCALCalib/CalibDB.h +++ b/Detectors/EMCAL/calib/include/EMCALCalib/CalibDB.h @@ -8,6 +8,10 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. + +#ifndef ALICEO2_EMCAL_CALIBDB +#define ALICEO2_EMCAL_CALIBDB + #include #include #include @@ -31,6 +35,7 @@ class GainCalibrationFactors; class EMCALChannelScaleFactors; class FeeDCS; class ElmbData; +class Pedestal; /// \class CalibDB /// \brief Interface to calibration data from CCDB for EMCAL @@ -45,6 +50,7 @@ class ElmbData; /// - Time calibration /// - Gain calibration /// - Temperature calibration +/// - Pedestals /// Users only need to specify the CCDB server, the timestamp and /// (optionally) additional meta data. Handling of the CCDB path /// and type conversions is done internally - users deal directly @@ -297,6 +303,20 @@ class CalibDB /// \throw TypeMismatchException if object is present but type is different (CCDB corrupted) ElmbData* readTemperatureSensorData(ULong_t timestamp, const std::map& metadata); + /// \brief Store pedestal data in the CCDB + /// \param pedestals Pedestal data to be stored + /// \param metadata Additional metadata that can be used in the query + /// \param timestart Start of the time range of the validity of the object + /// \param timeend End of the time range of the validity of the object + void storePedestalData(Pedestal* pedestals, const std::map& metadata, ULong_t timestart, ULong_t timeend); + + /// \brief Find pedestal data in the CCDB for given timestamp + /// \param timestamp Timestamp used in query + /// \param metadata Additional metadata to be used in the query + /// \throw ObjectNotFoundException if object is not found for the given timestamp + /// \throw TypeMismatchException if object is present but type is different (CCDB corrupted) + Pedestal* readPedestalData(ULong_t timestamp, const std::map& metadata); + /// \brief Set new CCDB server URL /// \param server Name of the CCDB server to be used in queries /// @@ -345,6 +365,10 @@ class CalibDB /// \return Path of the scale factors used in the bad channel calibration in the CCDB static const char* getCDBPathChannelScaleFactors() { return "EMC/Config/ChannelScaleFactors"; } + /// \brief Get CCDB path for the pedestal data + /// \return Path of the pedestal data + static const char* getCDBPathChannelPedestals() { return "EMC/Calib/Pedestal"; } + private: /// \brief Initialize CCDB server (when new object is created or the server URL changes) void @@ -359,3 +383,5 @@ class CalibDB } // namespace emcal } // namespace o2 + +#endif \ No newline at end of file diff --git a/Detectors/EMCAL/calib/include/EMCALCalib/Pedestal.h b/Detectors/EMCAL/calib/include/EMCALCalib/Pedestal.h new file mode 100644 index 0000000000000..7a8983409d995 --- /dev/null +++ b/Detectors/EMCAL/calib/include/EMCALCalib/Pedestal.h @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_EMCAL_PEDESTAL_H +#define ALICEO2_EMCAL_PEDESTAL_H + +#include +#include +#include + +class TH1; +class TH2; + +namespace o2 +{ + +namespace emcal +{ + +/// \class Pedestal +/// \brief CCDB container for pedestal values +/// \ingroup EMCALcalib +/// \author Markus Fasel , Oak Ridge National Laboratory +/// \since July 16th, 2019 +/// +/// Pedestal values can be added for each channel by +/// ~~~.{cxx} +/// o2::emcal::Pedestal ped; +/// ped.addPedestalValue(23, 3, false); +/// ~~~ +/// For the High Gain cells the last parameter should be set to false, for low +/// gain it should be set to true. +/// +/// One can read the pedestal values by calling +/// ~~~.{cxx} +/// auto param = ped.getPedestalValue(23, false); +/// ~~~ +/// This will return the pedestal value for a certain HG cell. +/// For low gain cells you have to set the last parameter false +class Pedestal +{ + public: + /// \brief Constructor + Pedestal() = default; + + /// \brief Destructor + ~Pedestal() = default; + + /// \brief Comparison of two pedestal containers + /// \return true if the two list of pedestal values are the same, false otherwise + bool operator==(const Pedestal& other) const; + + /// \brief Add pedestal to the container + /// \param cellID Absolute ID of cell + /// \param isLowGain Cell type is low gain cell + /// \param pedestal Pedestal value + /// \throw CalibContainerIndexException in case the cell ID exceeds the range of cells in EMCAL + void addPedestalValue(unsigned short cellID, short pedestal, bool isLowGain, bool isLEDMON); + + /// \brief Get the time calibration coefficient for a certain cell + /// \param cellID Absolute ID of cell + /// \param isLowGain Cell type is low gain cell + /// \return Pedestal value of the cell + /// \throw CalibContainerIndexException in case the cell ID exceeds the range of cells in EMCAL + short getPedestalValue(unsigned short cellID, bool isLowGain, bool isLEDMON) const; + + /// \brief Convert the pedestal container to a histogram + /// \param isLowGain Monitor low gain cells + /// \return Histogram representation of the pedestal container + TH1* getHistogramRepresentation(bool isLowGain, bool isLEDMON) const; + + /// \brief Convert the pedestal container to a 2D histogram + /// \param isLowGain Monitor low gain cells + /// \return 2D Histogram representation (heatmap with respect to column and row) of the pedestal container + TH2* getHistogramRepresentation2D(bool isLowGain, bool isLEDMON) const; + + private: + std::array mPedestalValuesHG; ///< Container for the pedestal values (high gain) + std::array mPedestalValuesLG; ///< Container for the pedestal values (low gain) + std::array mPedestalValuesLEDMONHG; ///< Container for the LEDMON pedestal values (high gain) + std::array mPedestalValuesLEDMONLG; ///< Container for the LEDMON pedestal values (low gain) + + ClassDefNV(Pedestal, 1); +}; + +} // namespace emcal + +} // namespace o2 +#endif diff --git a/Detectors/EMCAL/calib/src/CalibDB.cxx b/Detectors/EMCAL/calib/src/CalibDB.cxx index c85aa4358f89a..44dcf728b598c 100644 --- a/Detectors/EMCAL/calib/src/CalibDB.cxx +++ b/Detectors/EMCAL/calib/src/CalibDB.cxx @@ -19,6 +19,7 @@ #include "EMCALCalib/FeeDCS.h" #include "EMCALCalib/CalibDB.h" #include "EMCALCalib/ElmbData.h" +#include "EMCALCalib/Pedestal.h" using namespace o2::emcal; @@ -99,6 +100,14 @@ void CalibDB::storeTemperatureSensorData(ElmbData* dcs, const std::map& metadata, ULong_t rangestart, ULong_t rangeend) +{ + if (!mInit) { + init(); + } + mCCDBManager.storeAsTFileAny(pedestals, getCDBPathTemperatureSensor(), metadata, rangestart, rangeend); +} + BadChannelMap* CalibDB::readBadChannelMap(ULong_t timestamp, const std::map& metadata) { if (!mInit) { @@ -215,3 +224,16 @@ ElmbData* CalibDB::readTemperatureSensorData(ULong_t timestamp, const std::map& metadata) +{ + if (!mInit) { + init(); + } + auto& mgr = CcdbManager::instance(); + Pedestal* result = mgr.getForTimeStamp(getCDBPathChannelPedestals(), timestamp); + if (!result) { + throw ObjectNotFoundException(mCCDBServer, getCDBPathChannelPedestals(), metadata, timestamp); + } + return result; +} \ No newline at end of file diff --git a/Detectors/EMCAL/calib/src/EMCALCalibLinkDef.h b/Detectors/EMCAL/calib/src/EMCALCalibLinkDef.h index 001ac740d381b..7d2328a6f80aa 100644 --- a/Detectors/EMCAL/calib/src/EMCALCalibLinkDef.h +++ b/Detectors/EMCAL/calib/src/EMCALCalibLinkDef.h @@ -23,6 +23,7 @@ #pragma link C++ class o2::emcal::TempCalibrationParams + ; #pragma link C++ class o2::emcal::TempCalibParamSM + ; #pragma link C++ class o2::emcal::GainCalibrationFactors + ; +#pragma link C++ class o2::emcal::Pedestal + ; #pragma link C++ class o2::emcal::TriggerTRUDCS + ; #pragma link C++ class o2::emcal::TriggerSTUDCS + ; #pragma link C++ class o2::emcal::TriggerSTUErrorCounter + ; diff --git a/Detectors/EMCAL/calib/src/Pedestal.cxx b/Detectors/EMCAL/calib/src/Pedestal.cxx new file mode 100644 index 0000000000000..7d67205fc7943 --- /dev/null +++ b/Detectors/EMCAL/calib/src/Pedestal.cxx @@ -0,0 +1,153 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "EMCALBase/Geometry.h" +#include "EMCALCalib/CalibContainerErrors.h" +#include "EMCALCalib/Pedestal.h" + +#include + +#include +#include + +#include + +#include + +using namespace o2::emcal; + +void Pedestal::addPedestalValue(unsigned short cellID, short pedestal, bool isLowGain, bool isLEDMON) +{ + if (cellID >= mPedestalValuesHG.size()) { + throw CalibContainerIndexException(cellID); + } + if (isLEDMON) { + if (isLowGain) { + mPedestalValuesLEDMONLG[cellID] = pedestal; + } else { + mPedestalValuesLEDMONHG[cellID] = pedestal; + } + } else { + if (isLowGain) { + mPedestalValuesLG[cellID] = pedestal; + } else { + mPedestalValuesHG[cellID] = pedestal; + } + } +} + +short Pedestal::getPedestalValue(unsigned short cellID, bool isLowGain, bool isLEDMON) const +{ + if (cellID >= mPedestalValuesHG.size()) { + throw CalibContainerIndexException(cellID); + } + if (isLEDMON) { + if (isLowGain) { + return mPedestalValuesLEDMONLG[cellID]; + } else { + return mPedestalValuesLEDMONHG[cellID]; + } + } else { + if (isLowGain) { + return mPedestalValuesLG[cellID]; + } else { + return mPedestalValuesHG[cellID]; + } + } +} + +TH1* Pedestal::getHistogramRepresentation(bool isLowGain, bool isLEDMON) const +{ + gsl::span data; + std::string histname, histtitle; + if (isLEDMON) { + if (isLowGain) { + histname = "PedestalLG_LEDMON"; + histtitle = "LEDMON Pedestal values Params low Gain"; + data = gsl::span(mPedestalValuesLEDMONLG); + } else { + histname = "PedestalHG_LEDMON"; + histtitle = "LEDMON Pedestal values Params high Gain"; + data = gsl::span(mPedestalValuesLEDMONHG); + } + } else { + if (isLowGain) { + histname = "PedestalLG"; + histtitle = "Pedestal values Params low Gain"; + data = gsl::span(mPedestalValuesLG); + } else { + histname = "PedestalHG"; + histtitle = "Pedestal values Params high Gain"; + data = gsl::span(mPedestalValuesHG); + } + } + + auto hist = new TH1S(histname.data(), histtitle.data(), data.size(), -0.5, data.size() - 0.5); + hist->SetDirectory(nullptr); + for (std::size_t icell{0}; icell < data.size(); ++icell) { + hist->SetBinContent(icell + 1, data[icell]); + } + return hist; +} + +TH2* Pedestal::getHistogramRepresentation2D(bool isLowGain, bool isLEDMON) const +{ + gsl::span data; + std::string histname, histtitle; + if (isLEDMON) { + if (isLowGain) { + histname = "PedestalLG_LEDMON"; + histtitle = "LEDMON Pedestal values Params low Gain"; + data = gsl::span(mPedestalValuesLEDMONLG); + } else { + histname = "PedestalHG_LEDMON"; + histtitle = "LEDMON Pedestal values Params high Gain"; + data = gsl::span(mPedestalValuesLEDMONHG); + } + } else { + if (isLowGain) { + histname = "PedestalLG"; + histtitle = "Pedestal values Params low Gain"; + data = gsl::span(mPedestalValuesLG); + } else { + histname = "PedestalHG"; + histtitle = "Pedestal values Params high Gain"; + data = gsl::span(mPedestalValuesHG); + } + } + + const int MAXROWS = isLEDMON ? 10 : 208, + MAXCOLS = isLEDMON ? 48 : 96; + + auto hist = new TH2S(histname.data(), histtitle.data(), MAXCOLS, -0.5, double(MAXCOLS) - 0.5, MAXROWS, -0.5, double(MAXROWS) - 0.5); + hist->SetDirectory(nullptr); + try { + auto geo = Geometry::GetInstance(); + for (size_t ichan = 0; ichan < data.size(); ichan++) { + if (isLEDMON) { + int col = ichan % 48, + row = ichan / 48; + hist->Fill(col, row, data[ichan]); + } else { + auto position = geo->GlobalRowColFromIndex(ichan); + hist->Fill(std::get<1>(position), std::get<0>(position), data[ichan]); + } + } + } catch (o2::emcal::GeometryNotInitializedException& e) { + LOG(error) << "Geometry needs to be initialized"; + } + return hist; +} + +bool Pedestal::operator==(const Pedestal& other) const +{ + return mPedestalValuesHG == other.mPedestalValuesHG && mPedestalValuesLG == other.mPedestalValuesLG && mPedestalValuesLEDMONHG == other.mPedestalValuesLEDMONHG && mPedestalValuesLEDMONLG == other.mPedestalValuesLEDMONLG; +} diff --git a/Detectors/EMCAL/calib/test/testPedestal.cxx b/Detectors/EMCAL/calib/test/testPedestal.cxx new file mode 100644 index 0000000000000..1adcfd8b9ea25 --- /dev/null +++ b/Detectors/EMCAL/calib/test/testPedestal.cxx @@ -0,0 +1,124 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#define BOOST_TEST_MODULE Test_EMCAL_Calib +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include +#include +#include +#include "EMCALCalib/CalibContainerErrors.h" +#include "EMCALCalib/Pedestal.h" + +/// \brief Standard tests for Pedestal container + +namespace o2 +{ +namespace emcal +{ + +using pedestalarray = std::vector; + +pedestalarray createRandomPedestals(bool isLEDMON) +{ + std::random_device rd{}; + std::mt19937 gen{rd()}; + std::normal_distribution gaussrand{40., 5.}; + pedestalarray pedestalcontainer(isLEDMON ? 480 : 17664); + for (std::size_t ichan{0}; ichan < pedestalcontainer.size(); ++ichan) { + pedestalcontainer[ichan] = std::round(gaussrand(gen)); + } + + return pedestalcontainer; +} + +pedestalarray shiftPedestalValue(const pedestalarray& input, short shift = 1) +{ + pedestalarray shifted; + for (std::size_t ichan{0}; ichan < input.size(); ++ichan) { + shifted[ichan] = input[ichan] + shift; + } + return shifted; +} + +BOOST_AUTO_TEST_CASE(testPedestal) +{ + auto pedestalsHG = createRandomPedestals(false), + pedestalsLG = createRandomPedestals(false), + pedestalsLEDMONHG = createRandomPedestals(true), + pedestalsLEDMONLG = createRandomPedestals(true); + + o2::emcal::Pedestal pedestalObject; + for (std::size_t ichan{0}; ichan < pedestalsHG.size(); ++ichan) { + pedestalObject.addPedestalValue(ichan, pedestalsHG[ichan], false, false); + pedestalObject.addPedestalValue(ichan, pedestalsLG[ichan], true, false); + } + for (std::size_t ichan{0}; ichan < pedestalsLEDMONHG.size(); ++ichan) { + pedestalObject.addPedestalValue(ichan, pedestalsLEDMONHG[ichan], false, true); + pedestalObject.addPedestalValue(ichan, pedestalsLEDMONLG[ichan], true, true); + } + + // test adding entries beyond range + for (std::size_t ichan{17665}; ichan < 18000; ++ichan) { + BOOST_CHECK_EXCEPTION(pedestalObject.addPedestalValue(ichan, 2, false, true), o2::emcal::CalibContainerIndexException, [ichan](const o2::emcal::CalibContainerIndexException& e) { return e.getIndex() == ichan; }); + BOOST_CHECK_EXCEPTION(pedestalObject.addPedestalValue(ichan, 3, true, false), o2::emcal::CalibContainerIndexException, [ichan](const o2::emcal::CalibContainerIndexException& e) { return e.getIndex() == ichan; }); + } + + // test reading values in range + for (std::size_t ichan{0}; ichan < pedestalsHG.size(); ++ichan) { + BOOST_CHECK_EQUAL(pedestalObject.getPedestalValue(ichan, false, false), pedestalsHG[ichan]); + BOOST_CHECK_EQUAL(pedestalObject.getPedestalValue(ichan, true, false), pedestalsLG[ichan]); + } + for (std::size_t ichan{0}; ichan < pedestalsLEDMONHG.size(); ++ichan) { + BOOST_CHECK_EQUAL(pedestalObject.getPedestalValue(ichan, false, true), pedestalsLEDMONHG[ichan]); + BOOST_CHECK_EQUAL(pedestalObject.getPedestalValue(ichan, true, true), pedestalsLEDMONLG[ichan]); + } + + // test reading entries beyond range + for (std::size_t ichan{17665}; ichan < 18000; ++ichan) { + BOOST_CHECK_EXCEPTION(pedestalObject.getPedestalValue(ichan, false, false), o2::emcal::CalibContainerIndexException, [ichan](const o2::emcal::CalibContainerIndexException& e) { return e.getIndex() == ichan; }); + BOOST_CHECK_EXCEPTION(pedestalObject.getPedestalValue(ichan, true, false), o2::emcal::CalibContainerIndexException, [ichan](const o2::emcal::CalibContainerIndexException& e) { return e.getIndex() == ichan; }); + BOOST_CHECK_EXCEPTION(pedestalObject.getPedestalValue(ichan, false, true), o2::emcal::CalibContainerIndexException, [ichan](const o2::emcal::CalibContainerIndexException& e) { return e.getIndex() == ichan; }); + BOOST_CHECK_EXCEPTION(pedestalObject.getPedestalValue(ichan, true, true), o2::emcal::CalibContainerIndexException, [ichan](const o2::emcal::CalibContainerIndexException& e) { return e.getIndex() == ichan; }); + } + + // tests for operator== + // shift pedestal by 1 for false test + // Test all cases: + // - same object + // - same HG, different LG + // - same LG, different HG + // - both HG and LG different + /* + auto shiftedPedestalsHG = shiftPedestalValue(pedestalsHG, 1), + shiftedPedestalsLG = shiftPedestalValue(pedestalsLG, 1); + o2::emcal::Pedestal same, differLow, differHigh, differBoth; + for (std::size_t ichan{0}; ichan < pedestalsHG.size(); ++ichan) { + same.addPedestalValue(ichan, pedestalsHG[ichan], false); + same.addPedestalValue(ichan, pedestalsLG[ichan], true); + differLow.addPedestalValue(ichan, pedestalsHG[ichan], false); + differLow.addPedestalValue(ichan, shiftedPedestalsLG[ichan], true); + differHigh.addPedestalValue(ichan, shiftedPedestalsHG[ichan], false); + differHigh.addPedestalValue(ichan, pedestalsLG[ichan], true); + differBoth.addPedestalValue(ichan, shiftedPedestalsHG[ichan], false); + differBoth.addPedestalValue(ichan, shiftedPedestalsLG[ichan], true); + } + BOOST_CHECK_EQUAL(pedestalObject, same); + BOOST_CHECK_NE(pedestalObject, differLow); + BOOST_CHECK_NE(pedestalObject, differHigh); + BOOST_CHECK_NE(pedestalObject, differBoth); + */ +} + +} // namespace emcal + +} // namespace o2 \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/CMakeLists.txt b/Detectors/EMCAL/calibration/CMakeLists.txt index 28a6d4e11029b..68c8fd1eb69c7 100644 --- a/Detectors/EMCAL/calibration/CMakeLists.txt +++ b/Detectors/EMCAL/calibration/CMakeLists.txt @@ -16,11 +16,17 @@ o2_add_library(EMCALCalibration src/EMCALCalibExtractor.cxx src/EMCALCalibParams.cxx src/EMCDCSProcessor.cxx + src/EMCALPedestalHelper.cxx + src/PedestalCalibDevice.cxx + src/PedestalProcessorDevice.cxx + src/PedestalProcessorData.cxx PUBLIC_LINK_LIBRARIES O2::CCDB O2::EMCALBase O2::EMCALCalib + O2::EMCALReconstruction O2::CommonUtils O2::DetectorsCalibration O2::DetectorsDCS + O2::DetectorsRaw O2::DataFormatsEMCAL O2::Framework O2::Algorithm @@ -38,6 +44,8 @@ o2_target_root_dictionary(EMCALCalibration include/EMCALCalibration/EMCALTimeCalibData.h include/EMCALCalibration/EMCALCalibParams.h include/EMCALCalibration/EMCDCSProcessor.h + include/EMCALCalibration/EMCALPedestalHelper.h + include/EMCALCalibration/PedestalProcessorData.h LINKDEF src/EMCALCalibrationLinkDef.h) o2_add_executable(emcal-channel-calib-workflow @@ -52,6 +60,22 @@ if (OpenMP_CXX_FOUND) target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) endif() +o2_add_executable(emcal-pedestal-processor-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/emc-pedestal-processor-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::EMCALCalibration + O2::DetectorsRaw + O2::DetectorsCalibration) + +o2_add_executable(emcal-pedestal-calib-workflow + COMPONENT_NAME calibration + SOURCES testWorkflow/emc-pedestal-calib-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::EMCALCalibration + O2::DetectorsRaw + O2::DetectorsCalibration) + o2_add_executable(run-calib-offline COMPONENT_NAME emcal TARGETVARNAME targetName @@ -64,6 +88,13 @@ if (OpenMP_CXX_FOUND) target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) endif() +o2_add_test(PedestalProcessorData + SOURCES test/testPedestalProcessorData.cxx + PUBLIC_LINK_LIBRARIES O2::EMCALCalibration + COMPONENT_NAME emcal + LABELS emcal + ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage) + o2_add_test_root_macro(macros/makeEMCALCCDBEntryForDCS.C PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::CCDB LABELS emcal COMPILE_ONLY) diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALCalibExtractor.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALCalibExtractor.h index fc736e6ccedff..035dc92ecfe09 100644 --- a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALCalibExtractor.h +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALCalibExtractor.h @@ -19,6 +19,7 @@ #define EMCALCALIBEXTRACTOR_H_ #include +#include #include #include "CCDB/BasicCCDBManager.h" #include "EMCALCalib/BadChannelMap.h" @@ -28,9 +29,12 @@ #include "CommonUtils/BoostHistogramUtils.h" #include "EMCALBase/Geometry.h" #include "EMCALCalibration/EMCALCalibParams.h" +#include "EMCALCalib/Pedestal.h" +#include "EMCALCalibration/PedestalProcessorData.h" #include #include +#include #if (defined(WITH_OPENMP) && !defined(__CLING__)) #include @@ -55,8 +59,12 @@ class EMCALCalibExtractor }; struct BadChannelCalibTimeInfo { - std::array sigmaCell; // sigma value of time distribution for single cells - double goodCellWindow; // cut value for good cells + std::array sigmaCell; // sigma value of time distribution for single cells + double goodCellWindow; // cut value for good cells + std::array fracHitsPreTrigg; // fraction of hits before the main time peak (pre-trigger pile-up) + double goodCellWindowFracHitsPreTrigg; // cut value for good cells for pre-trigger pile-up + std::array fracHitsPostTrigg; // fraction of hits after the main time peak (post-trigger pile-up) + double goodCellWindowFracHitsPostTrigg; // cut value for good cells for post-trigger pile-up }; public: @@ -95,6 +103,11 @@ class EMCALCalibExtractor double time1 = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); std::map> slices = {{0, {0.1, 0.3}}, {1, {0.3, 0.5}}, {2, {0.5, 1.0}}, {3, {1.0, 4.0}}, {4, {4.0, 39.0}}}; + std::fill(std::begin(mBadCellFracSM), std::end(mBadCellFracSM), 0); // reset all fractions to 0 + for (unsigned int i = 0; i < mBadCellFracFEC.size(); ++i) { + std::fill(std::begin(mBadCellFracFEC[i]), std::end(mBadCellFracFEC[i]), 0); + } + auto histScaled = hist; if (mBCMScaleFactors) { LOG(info) << "Rescaling BCM histo"; @@ -138,6 +151,8 @@ class EMCALCalibExtractor if (calibrationInformation.energyPerHitMap[0][cellID] == 0) { LOG(debug) << "Cell " << cellID << " is dead."; mOutputBCM.addBadChannel(cellID, o2::emcal::BadChannelMap::MaskType_t::DEAD_CELL); + mBadCellFracSM[mGeometry->GetSuperModuleNumber(cellID)] += 1; + mBadCellFracFEC[mGeometry->GetSuperModuleNumber(cellID)][getFECNumberInSM(cellID)] += 1; } else { bool failed = false; for (auto& [sliceIndex, slice] : slices) { @@ -181,6 +196,12 @@ class EMCALCalibExtractor if (calibrationTimeInfo.sigmaCell[cellID] > calibrationTimeInfo.goodCellWindow) { LOG(debug) << "Cell " << cellID << " is flagged due to time distribution"; failed = true; + } else if (calibrationTimeInfo.fracHitsPreTrigg[cellID] > calibrationTimeInfo.goodCellWindowFracHitsPreTrigg) { + LOG(debug) << "Cell " << cellID << " is flagged due to time distribution (pre-trigger)"; + failed = true; + } else if (calibrationTimeInfo.fracHitsPostTrigg[cellID] > calibrationTimeInfo.goodCellWindowFracHitsPostTrigg) { + LOG(debug) << "Cell " << cellID << " is flagged due to time distribution (post-trigger)"; + failed = true; } } } @@ -188,12 +209,25 @@ class EMCALCalibExtractor if (failed) { LOG(debug) << "Cell " << cellID << " is bad."; mOutputBCM.addBadChannel(cellID, o2::emcal::BadChannelMap::MaskType_t::BAD_CELL); + mBadCellFracSM[mGeometry->GetSuperModuleNumber(cellID)] += 1; + mBadCellFracFEC[mGeometry->GetSuperModuleNumber(cellID)][getFECNumberInSM(cellID)] += 1; } else { LOG(debug) << "Cell " << cellID << " is good."; mOutputBCM.addBadChannel(cellID, o2::emcal::BadChannelMap::MaskType_t::GOOD_CELL); } } } + + // Check if the fraction of bad+dead cells in a SM is above a certain threshold + // If yes, mask the whole SM + if (EMCALCalibParams::Instance().fracMaskSMFully_bc < 1) { + checkMaskSM(mOutputBCM); + } + // Same as above for FECs + if (EMCALCalibParams::Instance().fracMaskFECFully_bc < 1) { + checkMaskFEC(mOutputBCM); + } + double time2 = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); double diffTransfer = time2 - time1; LOG(info) << "Total time" << diffTransfer << " ns"; @@ -298,7 +332,7 @@ class EMCALCalibExtractor template BadChannelCalibTimeInfo buildTimeMeanAndSigma(const boost::histogram::histogram& histCellTime) { - std::array meanSigma; + BadChannelCalibTimeInfo timeInfo; for (int i = 0; i < mNcells; ++i) { // calculate sigma per cell const int indexLow = histCellTime.axis(1).index(i); @@ -310,24 +344,45 @@ class EMCALCalibExtractor maxElementIndex = 0; } float maxElementCenter = 0.5 * (boostHistCellSlice.axis(0).bin(maxElementIndex).upper() + boostHistCellSlice.axis(0).bin(maxElementIndex).lower()); - meanSigma[i] = std::sqrt(o2::utils::getVarianceBoost1D(boostHistCellSlice, -999999, maxElementCenter - 50, maxElementCenter + 50)); + timeInfo.sigmaCell[i] = std::sqrt(o2::utils::getVarianceBoost1D(boostHistCellSlice, -999999, maxElementCenter - 50, maxElementCenter + 50)); + + // get number of hits within mean+-25ns (trigger bunch), from -500ns to -25ns before trigger bunch (pre-trigger), and for 25ns to 500ns (post-trigger) + double sumTrigg = o2::utils::getIntegralBoostHist(boostHistCellSlice, maxElementCenter - 25, maxElementCenter + 25); + double sumPreTrigg = o2::utils::getIntegralBoostHist(boostHistCellSlice, maxElementCenter - 500, maxElementCenter - 25); + double sumPostTrigg = o2::utils::getIntegralBoostHist(boostHistCellSlice, maxElementCenter + 25, maxElementCenter + 500); + + // calculate fraction of hits of post and pre-trigger to main trigger bunch + timeInfo.fracHitsPreTrigg[i] = sumTrigg == 0 ? 0. : sumPreTrigg / sumTrigg; + timeInfo.fracHitsPostTrigg[i] = sumTrigg == 0 ? 0. : sumPostTrigg / sumTrigg; } // get the mean sigma and the std. deviation of the sigma distribution // those will be the values we cut on double avMean = 0, avSigma = 0; TRobustEstimator robustEstimator; - robustEstimator.EvaluateUni(meanSigma.size(), meanSigma.data(), avMean, avSigma, 0.5 * meanSigma.size()); + robustEstimator.EvaluateUni(timeInfo.sigmaCell.size(), timeInfo.sigmaCell.data(), avMean, avSigma, 0.5 * timeInfo.sigmaCell.size()); // protection for the following case: For low statistics cases, it can happen that more than half of the cells is in one bin // in that case the sigma will be close to zero. In that case, we take 95% of the data to calculate the truncated mean if (std::abs(avMean) < 0.001 && std::abs(avSigma) < 0.001) { - robustEstimator.EvaluateUni(meanSigma.size(), meanSigma.data(), avMean, avSigma, 0.95 * meanSigma.size()); + robustEstimator.EvaluateUni(timeInfo.sigmaCell.size(), timeInfo.sigmaCell.data(), avMean, avSigma, 0.95 * timeInfo.sigmaCell.size()); } - - BadChannelCalibTimeInfo timeInfo; - timeInfo.sigmaCell = meanSigma; + // timeInfo.sigmaCell = meanSigma; timeInfo.goodCellWindow = avMean + (avSigma * o2::emcal::EMCALCalibParams::Instance().sigmaTime_bc); // only upper limit needed + double avMeanPre = 0, avSigmaPre = 0; + robustEstimator.EvaluateUni(timeInfo.fracHitsPreTrigg.size(), timeInfo.fracHitsPreTrigg.data(), avMeanPre, avSigmaPre, 0.5 * timeInfo.fracHitsPreTrigg.size()); + if (std::abs(avMeanPre) < 0.001 && std::abs(avSigmaPre) < 0.001) { + robustEstimator.EvaluateUni(timeInfo.fracHitsPreTrigg.size(), timeInfo.fracHitsPreTrigg.data(), avMeanPre, avSigmaPre, 0.95 * timeInfo.fracHitsPreTrigg.size()); + } + timeInfo.goodCellWindowFracHitsPreTrigg = avMeanPre + (avSigmaPre * o2::emcal::EMCALCalibParams::Instance().sigmaTimePreTrigg_bc); // only upper limit needed + + double avMeanPost = 0, avSigmaPost = 0; + robustEstimator.EvaluateUni(timeInfo.fracHitsPostTrigg.size(), timeInfo.fracHitsPostTrigg.data(), avMeanPost, avSigmaPost, 0.5 * timeInfo.fracHitsPostTrigg.size()); + if (std::abs(avMeanPost) < 0.001 && std::abs(avSigmaPost) < 0.001) { + robustEstimator.EvaluateUni(timeInfo.fracHitsPostTrigg.size(), timeInfo.fracHitsPostTrigg.data(), avMeanPost, avSigmaPost, 0.95 * timeInfo.fracHitsPostTrigg.size()); + } + timeInfo.goodCellWindowFracHitsPostTrigg = avMeanPost + (avSigmaPost * o2::emcal::EMCALCalibParams::Instance().sigmaTimePostTrigg_bc); // only upper limit needed + return timeInfo; } @@ -395,13 +450,80 @@ class EMCALCalibExtractor return TCP; } - private: - EMCALChannelScaleFactors* mBCMScaleFactors = nullptr; ///< Scale factors for nentries scaling in bad channel calibration - int mSigma = 5; ///< number of sigma used in the calibration to define outliers - int mNThreads = 1; ///< number of threads used for calibration + //____________________________________________ + /// \brief Extract the pedestals from Stat Accumulators + /// \param obj PedestalProcessorData containing the data + /// \return Pedestal data + Pedestal extractPedestals(PedestalProcessorData& obj) + { + Pedestal pedestalData; + // loop over both low and high gain data as well as normal and LEDMON data + for (const auto& isLEDMON : {false, true}) { + auto maxChannels = isLEDMON ? mLEDMONs : mNcells; + for (const auto& isLG : {false, true}) { + for (unsigned short iCell = 0; iCell < maxChannels; ++iCell) { + auto [mean, rms] = obj.getValue(iCell, isLG, isLEDMON); // get mean and rms for pedestals + if (rms > EMCALCalibParams::Instance().maxPedestalRMS) { + mean = mMaxPedestalVal; + } + pedestalData.addPedestalValue(iCell, std::round(mean), isLG, isLEDMON); + } + } + } + return pedestalData; + } - o2::emcal::Geometry* mGeometry = nullptr; - static constexpr int mNcells = 17664; + //____________________________________________ + /// \brief Extract the pedestals from TProfile (for old data) + /// \param objHG TProfile containing the HG data + /// \param objLHG TProfile containing the LG data + /// \param isLEDMON if true, data is LED data + /// \return Pedestal data + Pedestal extractPedestals(TProfile* objHG = nullptr, TProfile* objLG = nullptr, bool isLEDMON = false) + { + Pedestal pedestalData; + auto maxChannels = isLEDMON ? mLEDMONs : mNcells; + // loop over both low and high gain data + for (const auto& isLG : {false, true}) { + auto obj = (isLG == true ? objLG : objHG); + if (!obj) + continue; + for (unsigned short iCell = 0; iCell < maxChannels; ++iCell) { + short mean = static_cast(std::round(obj->GetBinContent(iCell + 1))); + short rms = static_cast(obj->GetBinError(iCell + 1) / obj->GetBinEntries(iCell + 1)); + if (rms > EMCALCalibParams::Instance().maxPedestalRMS) { + mean = mMaxPedestalVal; + } + pedestalData.addPedestalValue(iCell, mean, isLG, isLEDMON); + } + } + return pedestalData; + } + + private: + //____________________________________________ + /// \brief Check if a SM exceeds a certain fraction of dead+bad channels. If yes, mask the entire SM + /// \param bcm -- current bad channel map + void checkMaskSM(o2::emcal::BadChannelMap& bcm); + + /// \brief Check if a FEC exceeds a certain fraction of dead+bad channels. If yes, mask the entire FEC + /// \param bcm -- current bad channel map + void checkMaskFEC(o2::emcal::BadChannelMap& bcm); + + /// \brief Get the FEC ID in a SM (IDs are just for internal handling in this task itself) + /// \param absCellID -- cell ID + unsigned int getFECNumberInSM(int absCellID) const; + + EMCALChannelScaleFactors* mBCMScaleFactors = nullptr; ///< Scale factors for nentries scaling in bad channel calibration + int mSigma = 5; ///< number of sigma used in the calibration to define outliers + int mNThreads = 1; ///< number of threads used for calibration + std::array mBadCellFracSM; ///< Fraction of bad+dead channels per SM + std::array, 20> mBadCellFracFEC; ///< Fraction of bad+dead channels per FEC + + o2::emcal::Geometry* mGeometry = nullptr; ///< pointer to the emcal geometry class + static constexpr int mNcells = 17664; ///< Number of total cells of EMCal + DCal + static constexpr int mLEDMONs = 480; ///< Number of total LEDMONS of EMCal + DCal + static constexpr short mMaxPedestalVal = 1023; ///< Maximum value for pedestals ClassDefNV(EMCALCalibExtractor, 1); }; diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALCalibParams.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALCalibParams.h index daf2451843b5a..2a13fb8ca569e 100644 --- a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALCalibParams.h +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALCalibParams.h @@ -43,6 +43,8 @@ struct EMCALCalibParams : public o2::conf::ConfigurableParamHelper mCalibrator; // output @@ -151,6 +167,11 @@ void EMCALChannelCalibrator::finalizeSlot(o2::calibration // Extract results for the single slot DataInput* c = slot.getContainer(); LOG(info) << "Finalize slot " << slot.getTFStart() << " <= TF <= " << slot.getTFEnd(); + // check if slot contains a minimum amount of data + if (c->getNEvents() < EMCALCalibParams::Instance().minNEventsSaveSlot) { + LOG(info) << "Slot only contains " << c->getNEvents() << " events. Not saving this slot. " << EMCALCalibParams::Instance().minNEventsSaveSlot << " required"; + return; + } if constexpr (std::is_same::value) { if (c->getNEvents() < EMCALCalibParams::Instance().minNEvents_bc) { @@ -244,11 +265,14 @@ template bool EMCALChannelCalibrator::saveLastSlotData(TFile& fl) { LOG(info) << "EMC calib histos are saved in " << fl.GetName(); - // does this work? + // we only have 1 slot auto& cont = o2::calibration::TimeSlotCalibration::getSlots(); auto& slot = cont.at(0); DataInput* c = slot.getContainer(); + // timestamp in hours + int timeNow = static_cast(o2::ccdb::getCurrentTimestamp() / o2::ccdb::CcdbObjectInfo::HOUR); + if constexpr (std::is_same::value) { auto hist = c->getHisto(); auto histTime = c->getHistoTime(); @@ -257,20 +281,36 @@ bool EMCALChannelCalibrator::saveLastSlotData(TFile& fl) TH2F hTime = o2::utils::TH2FFromBoost(histTime, "histTime"); TH1D hNEvents("hNEvents", "hNEvents", 1, 0, 1); hNEvents.SetBinContent(1, c->getNEvents()); + TH1I hGlobalProperties("hGlobalProperties", "hGlobalProperties", 3, -0.5, 2.5); + hGlobalProperties.GetXaxis()->SetBinLabel(1, "Fill nr."); + hGlobalProperties.GetXaxis()->SetBinLabel(2, "run type"); + hGlobalProperties.GetXaxis()->SetBinLabel(3, "ts in hours"); + hGlobalProperties.SetBinContent(1, mFillNr); + hGlobalProperties.SetBinContent(2, mRunType); + hGlobalProperties.SetBinContent(3, timeNow); fl.cd(); hEnergy.Write("EnergyVsCellID"); hTime.Write("TimeVsCellID"); hNEvents.Write("NEvents"); + hGlobalProperties.Write("GlobalProperties"); } else if constexpr (std::is_same::value) { auto histTime = c->getHisto(); TH2F hTime = o2::utils::TH2FFromBoost(histTime); TH1D hNEvents("hNEvents", "hNEvents", 1, 0, 1); hNEvents.SetBinContent(1, c->getNEvents()); + TH1I hGlobalProperties("hGlobalProperties", "hGlobalProperties", 3, -0.5, 2.5); + hGlobalProperties.GetXaxis()->SetBinLabel(1, "Fill nr."); + hGlobalProperties.GetXaxis()->SetBinLabel(2, "run type"); + hGlobalProperties.GetXaxis()->SetBinLabel(3, "ts in hours"); + hGlobalProperties.SetBinContent(1, mFillNr); + hGlobalProperties.SetBinContent(2, mRunType); + hGlobalProperties.SetBinContent(3, timeNow); fl.cd(); hTime.Write("TimeVsCellID"); hNEvents.Write("NEvents"); + hGlobalProperties.Write("GlobalProperties"); } return true; @@ -296,6 +336,31 @@ bool EMCALChannelCalibrator::adoptSavedData(const o2::cal auto& slot = cont.at(0); DataInput* c = slot.getContainer(); + // check run type and fill + TH1I* hGlobalProperties = (TH1I*)fl.Get("GlobalProperties"); + if (!hGlobalProperties) { + LOG(error) << "GlobalProperties histogram not found. Will not load previous calibration histograms"; + } else { + int fillNr = hGlobalProperties->GetBinContent(1); + int runType = hGlobalProperties->GetBinContent(2); + int tsOld = hGlobalProperties->GetBinContent(3); + int tsDiff = (mStartTSCalib > 0 ? mStartTSCalib : static_cast(o2::ccdb::getCurrentTimestamp() / o2::ccdb::CcdbObjectInfo::HOUR)) - tsOld; // get current timestamp if mStartTSCalib is not set + LOG(debug) << "tsOld " << tsOld << " tsNow " << (mStartTSCalib > 0 ? mStartTSCalib : static_cast(o2::ccdb::getCurrentTimestamp() / o2::ccdb::CcdbObjectInfo::HOUR)) << " tsDiff " << tsDiff; + + if (EMCALCalibParams::Instance().requireSameRunType && runType != static_cast(mRunType)) { + LOG(info) << "adoptSavedData: Same run type required but run types differ: " << runType << " != " << static_cast(mRunType); + return false; + } + if (EMCALCalibParams::Instance().requireSameFill && fillNr != mFillNr) { + LOG(info) << "adoptSavedData: Same fill nr. required but fills differ: " << fillNr << " != " << mFillNr; + return false; + } + if (EMCALCalibParams::Instance().tsDiffMax > 0 && (EMCALCalibParams::Instance().tsDiffMax < tsDiff || tsDiff < 0)) { + LOG(info) << "adoptSavedData: Maximum difference in ts is: " << EMCALCalibParams::Instance().tsDiffMax << " but " << tsDiff << " is given"; + return false; + } + } + if constexpr (std::is_same::value) { TH2D* hEnergy = (TH2D*)fl.Get("EnergyVsCellID"); TH2D* hTime = (TH2D*)fl.Get("TimeVsCellID"); diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelData.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelData.h index e8f7716601f06..0919c157c6610 100644 --- a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelData.h +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALChannelData.h @@ -73,7 +73,7 @@ class EMCALChannelData mHistoTime.resize(mNThreads); for (size_t i = 0; i < mNThreads; ++i) { mHisto[i] = boost::histogram::make_histogram(boost::histogram::axis::regular<>(mNBins, 0., mRange), boost::histogram::axis::regular<>(NCELLS, -0.5, NCELLS - 0.5)); - mHistoTime[i] = boost::histogram::make_histogram(boost::histogram::axis::regular<>(mNBinsTime, mRangeTimeHigh, mRangeTimeLow), boost::histogram::axis::regular<>(NCELLS, -0.5, NCELLS - 0.5)); + mHistoTime[i] = boost::histogram::make_histogram(boost::histogram::axis::regular<>(mNBinsTime, mRangeTimeLow, mRangeTimeHigh), boost::histogram::axis::regular<>(NCELLS, -0.5, NCELLS - 0.5)); mVecNEntriesInHisto[i] = 0; } } diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALPedestalHelper.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALPedestalHelper.h new file mode 100644 index 0000000000000..109fa795fd43a --- /dev/null +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/EMCALPedestalHelper.h @@ -0,0 +1,68 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef EMCAL_PEDESTAL_HELPER_H_ +#define EMCAL_PEDESTAL_HELPER_H_ + +#include "CCDB/CcdbApi.h" +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CCDBTimeStampUtils.h" +#include "EMCALReconstruction/Channel.h" +#include "EMCALBase/Geometry.h" +#include "EMCALBase/Mapper.h" +#include "EMCALCalib/CalibDB.h" +#include "EMCALCalib/Pedestal.h" + +#include +#include +#include +#include +#include + +namespace o2::emcal +{ + +class EMCALPedestalHelper +{ + + public: + EMCALPedestalHelper() = default; + ~EMCALPedestalHelper() = default; + + /// \brief Encodes the pedestal object into a string. This function fills fMeanPed which is then converted to a string in createInstructionString + /// \param obj pedestal object as stored in production ccdb + /// \param runNum current runnumber. If -1, will not be added to string that goes in the ccdb, otherwise runNum is the first entrey in the string + std::vector createPedestalInstruction(const Pedestal& obj, const int runNum = -1); + + /// \brief print the vector produced by createInstructionString in a textfile + void dumpInstructions(const std::string_view filename, const gsl::span& data); + + private: + /// \brief initialize fMeanPed with zeros + void setZero(); + + /// \brief converts fMeanPed to a vector of char + /// \param runNum current runnumber. If -1, will not be added to string that goes in the ccdb, otherwise runNum is the first entrey in the string + std::vector createInstructionString(const int runNum = -1); + + static constexpr short kNSM = 20; ///< number of SuperModules + static constexpr short kNRCU = 2; ///< number of readout crates (and DDLs) per SM + static constexpr short kNDTC = 40; ///< links for full SRU + static constexpr short kNBranch = 2; ///< low gain/high gain + static constexpr short kNFEC = 10; ///< 0..9, when including LED Ref + static constexpr short kNChip = 5; ///< really 0,2..4, i.e. skip #1 + static constexpr short kNChan = 16; + short fMeanPed[kNSM][kNRCU][kNBranch][kNFEC][kNChip][kNChan]; +}; + +} // namespace o2::emcal + +#endif \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/PedestalCalibDevice.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/PedestalCalibDevice.h new file mode 100644 index 0000000000000..6d4cfa8ff2775 --- /dev/null +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/PedestalCalibDevice.h @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef EMCAL_PEDESTAL_CALIB_DEVICE_H_ +#define EMCAL_PEDESTAL_CALIB_DEVICE_H_ + +#include +#include + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "EMCALBase/Mapper.h" +#include "EMCALBase/Geometry.h" +#include "EMCALCalibration/PedestalProcessorData.h" +#include "EMCALCalibration/EMCALCalibExtractor.h" +#include "EMCALCalibration/EMCALPedestalHelper.h" + +namespace o2::emcal +{ + +class PedestalCalibDevice : o2::framework::Task +{ + public: + PedestalCalibDevice(bool dumpToFile, bool addRunNum) : mDumpToFile(dumpToFile), mAddRunNumber(addRunNum){}; + ~PedestalCalibDevice() final = default; + + void init(framework::InitContext& ctx) final; + + void run(framework::ProcessingContext& ctx) final; + + void sendData(o2::framework::EndOfStreamContext& ec, const Pedestal& data) const; + + void endOfStream(o2::framework::EndOfStreamContext& ec) final; + + void resetStartTS() { mStartTS = o2::ccdb::getCurrentTimestamp(); } + + static const char* getPedDataBinding() { return "PEDData"; } + + private: + Geometry* mGeometry = nullptr; ///< pointer to the emcal geometry class + o2::emcal::EMCALCalibExtractor mCalibExtractor; ///< instance of the calibration extraction class ///< Calibration postprocessing + PedestalProcessorData mPedestalData; ///< pedestal data to accumulate data + long int mStartTS = 0; ///< timestamp at the start of run used for the object in the ccdb + bool mDumpToFile; ///< if output of pedestal calib (DCS ccdb) should be written to text file + int mRun = 0; ///< current run number + bool mAddRunNumber = false; ///< if true, runNumber will be added to ccdb string +}; + +o2::framework::DataProcessorSpec getPedestalCalibDevice(bool dumpToFile, bool addRunNum); + +} // end namespace o2::emcal + +#endif \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/PedestalProcessorData.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/PedestalProcessorData.h new file mode 100644 index 0000000000000..8030c9bc4739a --- /dev/null +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/PedestalProcessorData.h @@ -0,0 +1,154 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef EMCAL_PEDESTAL_PROCESSOR_DATA_H_ +#define EMCAL_PEDESTAL_PROCESSOR_DATA_H_ +#include +#include +#include +#include +#include +#include "MathUtils/Utils.h" + +#include "Rtypes.h" + +namespace o2::emcal +{ + +/// \class PedestalProcessorData +/// \brief Exchange container between PedestalProcessorDevice and PedestalAggregatorDevice +/// \ingroup EMCALCalib +/// \author Markus Fasel , Oak Ridge National Laboratory +/// \since March 22, 2024 +/// +/// Object containing arrays of stat accumulators that behave like flat profile histograms +/// calculating mean and RMS of a set of ADC values. Corresponding arrays are used for +/// both FEC and LEDMON channels, and in both cases for high and low gain. Distinction between +/// channel and gain type is done via arguments in the fill and get functions, always defining +/// the true cases with LEDMON and low gain. +class PedestalProcessorData +{ + private: + public: + /// \class ChannelIndexException + /// \brief Handling access to invalid channel index (out-of-bounds) + class ChannelIndexException : public std::exception + { + private: + unsigned short mChannelIndex; ///< Index of the channel raising the exception + unsigned short mMaxChannels; ///< Max. number of channels for a given channel type + std::string mErrorMessage; ///< Buffer for the error message + + public: + /// \brief Constructor + /// \param channelIndex Index raising the exception + /// \param maxChannels Maximun number of channels for a given type + ChannelIndexException(unsigned short channelIndex, unsigned short maxChannels) : std::exception(), mChannelIndex(channelIndex), mMaxChannels(maxChannels) + { + mErrorMessage = "Channel index " + std::to_string(mChannelIndex) + " not found (max " + std::to_string(mMaxChannels) + ")"; + } + + /// \brief Destructor + ~ChannelIndexException() noexcept final = default; + + /// \brief Get error message of the exception + /// \return Error message + const char* what() const noexcept final { return mErrorMessage.data(); } + + /// \brief Get channel index raising the exception + /// \return Channel index + unsigned short getChannelIndex() const noexcept { return mChannelIndex; } + + /// \brief Get max number for channels for the type the exception was raised + /// \return Number of channels + unsigned short getMaxChannels() const noexcept { return mMaxChannels; } + }; + + using ProfileHistFEC = std::array; + using ProfileHistLEDMON = std::array; + using PedestalValue = std::tuple; + + /// \brief Constructor + PedestalProcessorData() = default; + + /// \brief Destructor + ~PedestalProcessorData() = default; + + /// \brief Accumulation operator + /// \param other Object to add to this object + /// \return This object after accumulation + /// + /// Adding stat. accumulators for all channels to this object. The state of this + /// object is modified. + PedestalProcessorData& operator+=(const PedestalProcessorData& other); + + /// \brief Fill ADC value for certain channel + /// \param adc ADC value + /// \param tower Absolute tower ID + /// \param lowGain Switch between low and high gain (true = low gain) + /// \param LEDMON Switch between LEDMON and FEE data (true = LEDMON) + /// \throw ChannelIndexException for channel index out-of-range + void fillADC(unsigned short adc, unsigned short tower, bool lowGain, bool LEDMON); + + /// \brief Get mean ADC and RMS for a certain channel + /// \param tower Absolute tower ID + /// \param lowGain Switch between low and high gain (true = low gain) + /// \param LEDMON Switch between LEDMON and FEE data (true = LEDMON) + /// \return std::tuple with mean and rms of the ADC distribution for the given channl + /// \throw ChannelIndexException for channel index out-of-range + PedestalValue getValue(unsigned short tower, bool lowGain, bool LEDMON) const; + + /// \brief Get number of entries for a certain channel + /// \param tower Absolute tower ID + /// \param lowGain Switch between low and high gain (true = low gain) + /// \param LEDMON Switch between LEDMON and FEE data (true = LEDMON) + /// \return Number of entries + /// \throw ChannelIndexException for channel index out-of-range + int getEntriesForChannel(unsigned short tower, bool lowGain, bool LEDMON) const; + + /// \brief Reset object + /// + /// Set all stat accumulators to 0. + void reset(); + + /// \brief Provide access to accumulated data for FEC channels + /// \param lowGain Low gain data + /// \return Accumulated data for low gain (if lowGain) or high gain + const ProfileHistFEC& accessFECData(bool lowGain) const { return lowGain ? mDataFECLG : mDataFECHG; } + + /// \brief Provide access to accumulated data for LEDMON channels + /// \param lowGain Low gain data + /// \return Accumulated data for low gain (if lowGain) or high gain + const ProfileHistLEDMON& accessLEDMONData(bool lowGain) const { return lowGain ? mDataLEDMONLG : mDataLEDMONHG; } + + private: + ProfileHistFEC mDataFECHG; ///< Profile for FEC channels, high gain + ProfileHistFEC mDataFECLG; ///< Profile for FEC channels, low gain + ProfileHistLEDMON mDataLEDMONHG; ///< Profile for LEDMON channels, high gain + ProfileHistLEDMON mDataLEDMONLG; ///< Profile for LEDMON channels, low gain + + ClassDefNV(PedestalProcessorData, 1); +}; + +/// \brief Sum operator for PedestalProcessorData +/// \param lhs Left hand value of the sum operation +/// \param rhs Right hand value of the sum operation +/// \return Sum of the two containers (all channels) +PedestalProcessorData operator+(const PedestalProcessorData& lhs, const PedestalProcessorData& rhs); + +/// @brief Output stream operator for PedestalProcessorData::ChannelIndexException +/// @param stream Stream used for printing +/// @param ex Exception to be printed +/// @return Stream after printing +std::ostream& operator<<(std::ostream& stream, const PedestalProcessorData::ChannelIndexException& ex); + +} // namespace o2::emcal + +#endif \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/include/EMCALCalibration/PedestalProcessorDevice.h b/Detectors/EMCAL/calibration/include/EMCALCalibration/PedestalProcessorDevice.h new file mode 100644 index 0000000000000..5f84862838f0c --- /dev/null +++ b/Detectors/EMCAL/calibration/include/EMCALCalibration/PedestalProcessorDevice.h @@ -0,0 +1,130 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef EMCAL_PEDESTAL_PROCESSOR_DEVICE_H_ +#define EMCAL_PEDESTAL_PROCESSOR_DEVICE_H_ + +#include +#include + +#include "Framework/DataProcessorSpec.h" +#include "Framework/Task.h" +#include "EMCALBase/Mapper.h" +#include "EMCALCalibration/PedestalProcessorData.h" + +namespace o2::emcal +{ + +class Geometry; + +/// \class PedestalProcessorDevice +/// \brief Processor part of the EMCAL pedestal calibration workflow +/// \author Markus Fasel , Oak Ridge National Laboratory +/// \ingroup EMCALCalib +/// \since March 21, 2024 +class PedestalProcessorDevice : o2::framework::Task +{ + private: + /// \class ModuleIndexException + /// \brief Exception handling errors in calculation of the absolute module ID + class ModuleIndexException : public std::exception + { + public: + /// \enum ModuleType_t + /// \brief Type of module raising the exception + enum class ModuleType_t { + CELL_MODULE, ///< Cell module type + LEDMON_MODULE ///< LEDMON module type + }; + + /// \brief Constructor for cell indices + /// \param moduleIndex Index of the module raising the exception + /// \param column Column of the cell + /// \param row Row of the cell + /// \param columnshifted Shifted column index + /// \param rowshifted Shifted row index + ModuleIndexException(int moduleIndex, int column, int row, int columnshifted, int rowshifted) : mModuleType(ModuleType_t::CELL_MODULE), + mIndex(moduleIndex), + mColumn(column), + mRow(row), + mColumnShifted(columnshifted), + mRowShifted(rowshifted) {} + + /// \brief Constructor for LEDMON indices + /// \param moduleIndex Index of the module raising the exception + ModuleIndexException(int moduleIndex) : mModuleType(ModuleType_t::LEDMON_MODULE), mIndex(moduleIndex) {} + + /// \brief Destructor + ~ModuleIndexException() noexcept final = default; + + /// \brief Access to error message + /// \return Error message + const char* what() const noexcept final { return "Invalid cell / LEDMON index"; } + + /// \brief Get type of module raising the exception + /// \return Module type + ModuleType_t getModuleType() const { return mModuleType; } + + /// \brief Get index of the module raising the exception + /// \return Index of the module + int getIndex() const { return mIndex; } + + /// \brief Get column raising the exception (cell-case) + /// \return Column + int getColumn() const { return mColumn; } + + /// \brief Get row raising the exception (cell-case) + /// \return Row + int getRow() const { return mRow; } + + /// \brief Get shifted column raising the exception (cell-case) + /// \return Shifted column + int getColumnShifted() const { return mColumnShifted; } + + /// \brief Get shifted row raising the exception (cell-case) + /// \return Shifted row + int getRowShifted() const { return mRowShifted; } + + private: + ModuleType_t mModuleType; ///< Type of the module raising the exception + int mIndex = -1; ///< Index raising the exception + int mColumn = -1; ///< Column of the module (cell-case) + int mRow = -1; ///< Row of the module (cell-case) + int mColumnShifted = -1; ///< shifted column of the module (cell-case) + int mRowShifted = -1; /// << shifted row of the module (cell-case) + }; + + Geometry* mGeometry = nullptr; + std::unique_ptr mMapper = nullptr; + PedestalProcessorData mPedestalData; + + protected: + int getCellAbsID(int supermoduleID, int column, int row) const; + int geLEDMONAbsID(int supermoduleID, int moduleID) const; + + public: + PedestalProcessorDevice() = default; + ~PedestalProcessorDevice() final = default; + + void init(framework::InitContext& ctx) final; + + void run(framework::ProcessingContext& ctx) final; + + bool isLostTimeframe(framework::ProcessingContext& ctx) const; + + void sendData(framework::ProcessingContext& ctx, const PedestalProcessorData& data) const; +}; + +framework::DataProcessorSpec getPedestalProcessorDevice(bool askDistSTF); + +} // namespace o2::emcal + +#endif \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/src/EMCALCalibExtractor.cxx b/Detectors/EMCAL/calibration/src/EMCALCalibExtractor.cxx index 9f5189afd83de..2219220d93c8e 100644 --- a/Detectors/EMCAL/calibration/src/EMCALCalibExtractor.cxx +++ b/Detectors/EMCAL/calibration/src/EMCALCalibExtractor.cxx @@ -153,7 +153,59 @@ boostHisto EMCALCalibExtractor::buildHitAndEnergyMeanScaled(double emin, double return eSumHistoScaled; } + +//____________________________________________ +void EMCALCalibExtractor::checkMaskSM(o2::emcal::BadChannelMap& bcm) +{ + + for (unsigned int i = 0; i < mBadCellFracSM.size(); ++i) { + if (mGeometry->GetSMType(i) == o2::emcal::EMCALSMType::EMCAL_STANDARD) { + mBadCellFracSM[i] /= 1152.; + } else if (mGeometry->GetSMType(i) == o2::emcal::EMCALSMType::EMCAL_THIRD || mGeometry->GetSMType(i) == o2::emcal::EMCALSMType::DCAL_EXT) { + mBadCellFracSM[i] /= 384.; + } else if (mGeometry->GetSMType(i) == o2::emcal::EMCALSMType::DCAL_STANDARD) { + mBadCellFracSM[i] /= 768.; + } + } + for (unsigned int i = 0; i < mNcells; ++i) { + if (mBadCellFracSM[mGeometry->GetSuperModuleNumber(i)] > EMCALCalibParams::Instance().fracMaskSMFully_bc) { + if (bcm.getChannelStatus(i) == o2::emcal::BadChannelMap::MaskType_t::GOOD_CELL) { // only mask good cells, to keep information about dead channels + bcm.addBadChannel(i, o2::emcal::BadChannelMap::MaskType_t::BAD_CELL); + } + } + } +} + //____________________________________________ +void EMCALCalibExtractor::checkMaskFEC(o2::emcal::BadChannelMap& bcm) +{ + for (unsigned int iSM = 0; iSM < mBadCellFracFEC.size(); ++iSM) { + for (unsigned int iFEC = 0; iFEC < mBadCellFracFEC[iSM].size(); ++iFEC) { + mBadCellFracFEC[iSM][iFEC] /= 32.; // 32 channels per FEC + } + } + + for (unsigned int i = 0; i < mNcells; ++i) { + if (mBadCellFracFEC[mGeometry->GetSuperModuleNumber(i)][getFECNumberInSM(i)] > EMCALCalibParams::Instance().fracMaskFECFully_bc) { + if (bcm.getChannelStatus(i) == o2::emcal::BadChannelMap::MaskType_t::GOOD_CELL) { // only mask good cells, to keep information about dead channels + bcm.addBadChannel(i, o2::emcal::BadChannelMap::MaskType_t::BAD_CELL); + } + } + } +} + +//____________________________________________ +unsigned int EMCALCalibExtractor::getFECNumberInSM(int absCellID) const +{ + std::tuple RowCol = mGeometry->GlobalRowColFromIndex(absCellID); + std::tuple PosInSM = mGeometry->GetPositionInSupermoduleFromGlobalRowCol(std::get<0>(RowCol), std::get<1>(RowCol)); + int iSM = std::get<0>(PosInSM); + int col = std::get<1>(PosInSM); + int row = std::get<2>(PosInSM); + int FECid = static_cast(row / 4.) + 12 * static_cast(col / 8.); + LOG(debug) << "FECid " << FECid << " iSM " << iSM << " row " << row << " col " << col; + return FECid; +} } // end namespace emcal } // end namespace o2 diff --git a/Detectors/EMCAL/calibration/src/EMCALCalibrationLinkDef.h b/Detectors/EMCAL/calibration/src/EMCALCalibrationLinkDef.h index 9964f61f095fe..0cc0451ed81b7 100644 --- a/Detectors/EMCAL/calibration/src/EMCALCalibrationLinkDef.h +++ b/Detectors/EMCAL/calibration/src/EMCALCalibrationLinkDef.h @@ -26,5 +26,6 @@ #pragma link C++ class o2::emcal::EMCALCalibParams + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::emcal::EMCALCalibParams> + ; #pragma link C++ class o2::emcal::EMCDCSProcessor + ; +#pragma link C++ class o2::emcal::PedestalProcessorData + ; #endif diff --git a/Detectors/EMCAL/calibration/src/EMCALPedestalHelper.cxx b/Detectors/EMCAL/calibration/src/EMCALPedestalHelper.cxx new file mode 100644 index 0000000000000..38a6e386c9ca6 --- /dev/null +++ b/Detectors/EMCAL/calibration/src/EMCALPedestalHelper.cxx @@ -0,0 +1,199 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "EMCALCalibration/EMCALPedestalHelper.h" +using namespace o2::emcal; + +std::vector EMCALPedestalHelper::createPedestalInstruction(const Pedestal& obj, const int runNum) +{ + + setZero(); + + o2::emcal::Geometry* geo = o2::emcal::Geometry::GetInstanceFromRunNumber(300000); + o2::emcal::MappingHandler mapper; + + for (int itower = 0; itower < 17664; itower++) { + auto [ddl, row, col] = geo->getOnlineID(itower); + auto [sm, mod, iphi, ieta] = geo->GetCellIndex(itower); + const auto& mapping = mapper.getMappingForDDL(ddl); + int ircu = ddl % 2; + auto addressLG = mapping.getHardwareAddress(row, col, o2::emcal::ChannelType_t::LOW_GAIN), + addressHG = mapping.getHardwareAddress(row, col, o2::emcal::ChannelType_t::HIGH_GAIN); + auto fecLG = o2::emcal::Channel::getFecIndexFromHwAddress(addressLG), + fecHG = o2::emcal::Channel::getFecIndexFromHwAddress(addressHG), + branchLG = o2::emcal::Channel::getBranchIndexFromHwAddress(addressLG), + branchHG = o2::emcal::Channel::getBranchIndexFromHwAddress(addressHG), + chipLG = o2::emcal::Channel::getAltroIndexFromHwAddress(addressLG), + chipHG = o2::emcal::Channel::getAltroIndexFromHwAddress(addressHG), + channelLG = o2::emcal::Channel::getChannelIndexFromHwAddress(addressLG), + channelHG = o2::emcal::Channel::getChannelIndexFromHwAddress(addressHG); + fMeanPed[sm][ircu][branchHG][fecHG][chipHG][channelHG] = obj.getPedestalValue(itower, false, false); + fMeanPed[sm][ircu][branchLG][fecLG][chipLG][channelLG] = obj.getPedestalValue(itower, true, false); + } + + for (int iledmon = 0; iledmon < 480; iledmon++) { + int sm = iledmon / 24, + col = iledmon % 24, + ircu = 0, // LEDMONS always on RCU 0 + iddl = 2 * sm + ircu; + const auto& mapping = mapper.getMappingForDDL(iddl); + auto addressLG = mapping.getHardwareAddress(0, col, o2::emcal::ChannelType_t::LEDMON), + addressHG = mapping.getHardwareAddress(1, col, o2::emcal::ChannelType_t::LEDMON); + auto fecLG = o2::emcal::Channel::getFecIndexFromHwAddress(addressLG), + fecHG = o2::emcal::Channel::getFecIndexFromHwAddress(addressHG), + branchLG = o2::emcal::Channel::getBranchIndexFromHwAddress(addressLG), + branchHG = o2::emcal::Channel::getBranchIndexFromHwAddress(addressHG), + chipLG = o2::emcal::Channel::getAltroIndexFromHwAddress(addressLG), + chipHG = o2::emcal::Channel::getAltroIndexFromHwAddress(addressHG), + channelLG = o2::emcal::Channel::getChannelIndexFromHwAddress(addressLG), + channelHG = o2::emcal::Channel::getChannelIndexFromHwAddress(addressHG); + fMeanPed[sm][ircu][branchHG][fecHG][chipHG][channelHG] = obj.getPedestalValue(iledmon, false, true); + fMeanPed[sm][ircu][branchLG][fecLG][chipLG][channelLG] = obj.getPedestalValue(iledmon, true, true); + } + + return createInstructionString(runNum); +} + +void EMCALPedestalHelper::setZero() +{ + for (int ism = 0; ism < kNSM; ism++) { + for (int ircu = 0; ircu < kNRCU; ircu++) { + for (int ibranch = 0; ibranch < kNBranch; ibranch++) { + for (int ifec = 0; ifec < kNFEC; ifec++) { + for (int ichip = 0; ichip < kNChip; ichip++) { + for (int ichan = 0; ichan < kNChan; ichan++) { + fMeanPed[ism][ircu][ibranch][ifec][ichip][ichan] = 0; + } + } + } + } + } + } +} + +std::vector EMCALPedestalHelper::createInstructionString(const int runNum) +{ + std::stringstream fout; + + if (runNum > 0) { + fout << runNum << std::endl; + } + + unsigned int lineValue = 0; + + const unsigned int FECheaderCode = 0xC0000000; + // const unsigned int FECwordCode = 0x80000000; + const unsigned int FEClineCode = 0x40000000; + + const unsigned int TrailerLineCode = 0xFFFFFFFF; + + short iSM = 0; + short iRCU = 0; + short ibranch = 0; + short iFEC = 0; + short ichip = 0; + short ichan = 0; + short Ped = 0; + short iDTC = 0; + + for (iSM = 0; iSM < kNSM; iSM++) { + int iside = iSM % 2; + int isect = iSM / 2; + if (iSM > 11) { + isect += 3; // skip non-installed sectors + } + + std::bitset activeDTC; + for (iDTC = 0; iDTC < kNDTC; iDTC++) { + if (iDTC == 10 || iDTC == 20 || iDTC == 30) { // skip TRU + activeDTC[iDTC] = 0; + } else { + if (iSM < 10) { // not special third SMs or DCal SMs + activeDTC[iDTC] = 1; + } else { + if (iSM == 10 || iSM == 19) { // SMA5 or SMC12 + if (iDTC < 14) { + activeDTC[iDTC] = 1; + } else { + activeDTC[iDTC] = 0; + } + } else if (iSM == 11 || iSM == 18) { // SMC5 or SMA12 + if (iDTC == 0 || iDTC >= 27) { + activeDTC[iDTC] = 1; + } else { + activeDTC[iDTC] = 0; + } + } else { + // DCal... no FECs in 9,11-13, 23-26, 36-39 + if ((iDTC >= 9 && iDTC <= 13) || (iDTC >= 23 && iDTC <= 26) || + (iDTC >= 36 && iDTC <= 39)) { + activeDTC[iDTC] = 0; + } else { + activeDTC[iDTC] = 1; + } + } // DCal + } // non-EMCal + } // non-TRU + } + + // OK, let's generate the files for all active FECs/DTCs + for (iDTC = 0; iDTC < kNDTC; iDTC++) { + if (activeDTC[iDTC] == 0) { + continue; + } + + lineValue = FECheaderCode | isect << 9 | iside << 8 | iDTC; + fout << lineValue << std::endl; + + iRCU = iDTC / 20; + ibranch = (iDTC % 20) / 10; + iFEC = iDTC % 10; + int ipos = iFEC + 10 * ibranch; + + int dtcselUpper = 0; + int dtcselLower = 0; + if (iRCU == 0) { + dtcselLower = (1 << ipos); + } else { // crate == 1 + dtcselUpper = (1 << ipos); + } + + for (ichip = 0; ichip < kNChip; ichip++) { // ALTRO 0,2,3,4 + if (ichip != 1) { + for (ichan = 0; ichan < kNChan; ichan++) { + if (iFEC != 0 || (ichan < 8 || ichan > 11)) { + Ped = fMeanPed[iSM][iRCU][ibranch][iFEC][ichip][ichan]; + int writeAddr = (ichip << 4) | ichan; + lineValue = FEClineCode | (writeAddr << 12) | Ped; + fout << lineValue << std::endl; + } + } + } + } // chip + + } // iDTC + } // iSM + + if (runNum > 0) { + fout << TrailerLineCode << std::endl; + } + + const std::string instructionString(fout.str()); + std::vector output(instructionString.begin(), instructionString.end()); + return output; +} + +void EMCALPedestalHelper::dumpInstructions(const std::string_view filename, const gsl::span& data) +{ + std::ofstream fout(filename.data()); + fout << data.data(); + fout.close(); +} \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/src/PedestalCalibDevice.cxx b/Detectors/EMCAL/calibration/src/PedestalCalibDevice.cxx new file mode 100644 index 0000000000000..2f4c6ee204a31 --- /dev/null +++ b/Detectors/EMCAL/calibration/src/PedestalCalibDevice.cxx @@ -0,0 +1,116 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/VerbosityConfig.h" +#include "DetectorsRaw/RDHUtils.h" +#include "EMCALBase/Geometry.h" +#include "Framework/TimingInfo.h" +#include "EMCALCalibration/PedestalCalibDevice.h" +#include "EMCALReconstruction/AltroDecoder.h" +#include "EMCALReconstruction/RawReaderMemory.h" +#include "DetectorsCalibration/Utils.h" +#include "EMCALCalib/CalibDB.h" +#include "Framework/ConcreteDataMatcher.h" +#include "CommonUtils/MemFileHelper.h" + +#include + +using namespace o2::emcal; + +void PedestalCalibDevice::init(o2::framework::InitContext& ctx) +{ + LOG(debug) << "[EMCALPedestalCalibDevice - init] Initialize converter "; + if (!mGeometry) { + mGeometry = Geometry::GetInstanceFromRunNumber(300000); + } + if (!mGeometry) { + LOG(error) << "Failure accessing geometry"; + } + + resetStartTS(); +} + +void PedestalCalibDevice::run(o2::framework::ProcessingContext& ctx) +{ + if (!mRun) { + const auto& tinfo = ctx.services().get(); + if (tinfo.runNumber != 0) { + mRun = tinfo.runNumber; + } + } + + constexpr auto originEMC = o2::header::gDataOriginEMC; + auto data = ctx.inputs().get(getPedDataBinding()); + LOG(debug) << "adding pedestal data"; + mPedestalData += data; +} + +//________________________________________________________________ +void PedestalCalibDevice::sendData(o2::framework::EndOfStreamContext& ec, const Pedestal& data) const +{ + LOG(info) << "sending pedestal data"; + constexpr auto originEMC = o2::header::gDataOriginEMC; + + std::map md; + auto clName = o2::utils::MemFileHelper::getClassName(data); + auto flName = o2::ccdb::CcdbApi::generateFileName(clName); + o2::ccdb::CcdbObjectInfo objInfo(o2::emcal::CalibDB::getCDBPathChannelPedestals(), clName, flName, md, mStartTS, o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP, true); + + auto image = o2::ccdb::CcdbApi::createObjectImage(&data, &objInfo); + + ec.outputs().snapshot(o2::framework::Output{o2::calibration::Utils::gDataOriginCDBPayload, "EMC_PEDCALIB", 0}, *image.get()); + ec.outputs().snapshot(o2::framework::Output{o2::calibration::Utils::gDataOriginCDBWrapper, "EMC_PEDCALIB", 0}, objInfo); + + // the following goes to the DCS ccdb + EMCALPedestalHelper helper; + std::vector vecPedData = helper.createPedestalInstruction(data, mAddRunNumber ? mRun : -1); + if (mDumpToFile) { + helper.dumpInstructions("EMCAL-Pedestals.txt", vecPedData); + } + + auto clNameDCS = o2::utils::MemFileHelper::getClassName(vecPedData); + auto flNameDCS = o2::ccdb::CcdbApi::generateFileName(clNameDCS); + o2::ccdb::CcdbObjectInfo objInfoDCS("EMC/Calib/PDData", clNameDCS, flNameDCS, md, mStartTS, o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP, true); + auto imageDCS = o2::ccdb::CcdbApi::createObjectImage(&vecPedData, &objInfoDCS); + + ec.outputs().snapshot(o2::framework::Output{o2::calibration::Utils::gDataOriginCDBPayload, "EMC_PEDCALIBSTR", 1}, *imageDCS.get()); + ec.outputs().snapshot(o2::framework::Output{o2::calibration::Utils::gDataOriginCDBWrapper, "EMC_PEDCALIBSTR", 1}, objInfoDCS); +} + +//________________________________________________________________ +void PedestalCalibDevice::endOfStream(o2::framework::EndOfStreamContext& ec) +{ + + Pedestal pedObj = mCalibExtractor.extractPedestals(mPedestalData); + sendData(ec, pedObj); + // reset Timestamp (probably not needed as program will probably be terminated) + resetStartTS(); +} + +o2::framework::DataProcessorSpec o2::emcal::getPedestalCalibDevice(bool dumpToFile, bool addRunNum) +{ + + std::vector inputs; + inputs.emplace_back(o2::emcal::PedestalCalibDevice::getPedDataBinding(), o2::header::gDataOriginEMC, "PEDDATA", 0, o2::framework::Lifetime::Timeframe); + std::vector outputs; + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "EMC_PEDCALIB"}, o2::framework::Lifetime::Sporadic); + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "EMC_PEDCALIB"}, o2::framework::Lifetime::Sporadic); + + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "EMC_PEDCALIBSTR"}, o2::framework::Lifetime::Sporadic); + outputs.emplace_back(o2::framework::ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "EMC_PEDCALIBSTR"}, o2::framework::Lifetime::Sporadic); + + return o2::framework::DataProcessorSpec{ + "PedestalCalibrator", + inputs, + outputs, + o2::framework::AlgorithmSpec{o2::framework::adaptFromTask(dumpToFile, addRunNum)}, + o2::framework::Options{}}; +} \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/src/PedestalProcessorData.cxx b/Detectors/EMCAL/calibration/src/PedestalProcessorData.cxx new file mode 100644 index 0000000000000..33ef3319b2570 --- /dev/null +++ b/Detectors/EMCAL/calibration/src/PedestalProcessorData.cxx @@ -0,0 +1,122 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include "EMCALCalibration/PedestalProcessorData.h" + +using namespace o2::emcal; + +PedestalProcessorData& PedestalProcessorData::operator+=(const PedestalProcessorData& other) +{ + for (std::size_t ichan{0}; ichan < mDataFECHG.size(); ++ichan) { + mDataFECHG[ichan] += other.mDataFECHG[ichan]; + mDataFECLG[ichan] += other.mDataFECLG[ichan]; + } + for (std::size_t ichan{0}; ichan < mDataLEDMONHG.size(); ++ichan) { + mDataLEDMONHG[ichan] += other.mDataLEDMONHG[ichan]; + mDataLEDMONLG[ichan] += other.mDataLEDMONLG[ichan]; + } + return *this; +} + +void PedestalProcessorData::fillADC(unsigned short adc, unsigned short tower, bool lowGain, bool LEDMON) +{ + auto maxentries = LEDMON ? mDataLEDMONHG.size() : mDataFECHG.size(); + if (tower >= maxentries) { + throw ChannelIndexException(tower, maxentries); + } + if (LEDMON) { + if (lowGain) { + mDataLEDMONLG[tower].add(adc); + } else { + mDataLEDMONHG[tower].add(adc); + } + } else { + if (lowGain) { + mDataFECLG[tower].add(adc); + } else { + mDataFECHG[tower].add(adc); + } + } +} + +PedestalProcessorData::PedestalValue PedestalProcessorData::getValue(unsigned short tower, bool lowGain, bool LEDMON) const +{ + auto maxentries = LEDMON ? mDataLEDMONHG.size() : mDataFECHG.size(); + if (tower >= maxentries) { + throw ChannelIndexException(tower, maxentries); + } + float mean, rms; + if (LEDMON) { + if (lowGain) { + return mDataLEDMONLG[tower].getMeanRMS2(); + } else { + return mDataLEDMONHG[tower].getMeanRMS2(); + } + } else { + if (lowGain) { + return mDataFECLG[tower].getMeanRMS2(); + } else { + return mDataFECHG[tower].getMeanRMS2(); + } + } +} + +int PedestalProcessorData::getEntriesForChannel(unsigned short tower, bool lowGain, bool LEDMON) const +{ + auto maxentries = LEDMON ? mDataLEDMONHG.size() : mDataFECHG.size(); + if (tower >= maxentries) { + throw ChannelIndexException(tower, maxentries); + } + float mean, rms; + if (LEDMON) { + if (lowGain) { + return mDataLEDMONLG[tower].n; + } else { + return mDataLEDMONHG[tower].n; + } + } else { + if (lowGain) { + return mDataFECLG[tower].n; + } else { + return mDataFECHG[tower].n; + } + } +} + +void PedestalProcessorData::reset() +{ + for (auto& acc : mDataFECHG) { + acc.clear(); + } + for (auto& acc : mDataFECLG) { + acc.clear(); + } + for (auto& acc : mDataLEDMONHG) { + acc.clear(); + } + for (auto& acc : mDataLEDMONLG) { + acc.clear(); + } +} + +PedestalProcessorData o2::emcal::operator+(const PedestalProcessorData& lhs, const PedestalProcessorData& rhs) +{ + PedestalProcessorData result(lhs); + result += rhs; + return result; +} + +std::ostream& o2::emcal::operator<<(std::ostream& stream, const PedestalProcessorData::ChannelIndexException& ex) +{ + stream << ex.what(); + return stream; +} \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/src/PedestalProcessorDevice.cxx b/Detectors/EMCAL/calibration/src/PedestalProcessorDevice.cxx new file mode 100644 index 0000000000000..90ddba0ffb75a --- /dev/null +++ b/Detectors/EMCAL/calibration/src/PedestalProcessorDevice.cxx @@ -0,0 +1,228 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/VerbosityConfig.h" +#include "DetectorsRaw/RDHUtils.h" +#include "EMCALBase/Geometry.h" +#include "EMCALCalibration/PedestalProcessorDevice.h" +#include "EMCALReconstruction/AltroDecoder.h" +#include "EMCALReconstruction/RawReaderMemory.h" +#include "Framework/ConcreteDataMatcher.h" +#include "Framework/InputRecordWalker.h" + +#include + +using namespace o2::emcal; + +void PedestalProcessorDevice::init(o2::framework::InitContext& ctx) +{ + LOG(debug) << "[EMCALRawToCellConverter - init] Initialize converter "; + if (!mGeometry) { + mGeometry = Geometry::GetInstanceFromRunNumber(300000); + } + if (!mGeometry) { + LOG(error) << "Failure accessing geometry"; + } + + if (!mMapper) { + mMapper = std::unique_ptr(new o2::emcal::MappingHandler); + } + if (!mMapper) { + LOG(error) << "Failed to initialize mapper"; + } +} + +void PedestalProcessorDevice::run(o2::framework::ProcessingContext& ctx) +{ + constexpr auto originEMC = o2::header::gDataOriginEMC; + constexpr auto descRaw = o2::header::gDataDescriptionRawData; + + mPedestalData.reset(); + + if (isLostTimeframe(ctx)) { + sendData(ctx, mPedestalData); + return; + } + + std::vector filter{{"filter", framework::ConcreteDataTypeMatcher(originEMC, descRaw)}}; + for (const auto& rawData : framework::InputRecordWalker(ctx.inputs(), filter)) { + // Skip SOX headers + auto rdhblock = reinterpret_cast(rawData.payload); + if (o2::raw::RDHUtils::getHeaderSize(rdhblock) == static_cast(o2::framework::DataRefUtils::getPayloadSize(rawData))) { + continue; + } + + o2::emcal::RawReaderMemory rawreader(framework::DataRefUtils::as(rawData)); + rawreader.setRangeSRUDDLs(0, 39); + + // loop over all the DMA pages + while (rawreader.hasNext()) { + try { + rawreader.next(); + } catch (RawDecodingError& e) { + LOG(error) << e.what(); + if (e.getErrorType() == RawDecodingError::ErrorType_t::HEADER_DECODING || e.getErrorType() == RawDecodingError::ErrorType_t::HEADER_INVALID) { + // We must break in case of header decoding as the offset to the next payload is lost + // consequently the parser does not know where to continue leading to an infinity loop + break; + } + // We must skip the page as payload is not consistent + // otherwise the next functions will rethrow the exceptions as + // the page format does not follow the expected format + continue; + } + for (const auto& e : rawreader.getMinorErrors()) { + LOG(warning) << "Found minor Raw decoder error in FEE " << e.getFEEID() << ": " << RawDecodingError::getErrorCodeTitles(RawDecodingError::ErrorTypeToInt(e.getErrorType())); + } + + auto& header = rawreader.getRawHeader(); + auto feeID = raw::RDHUtils::getFEEID(header); + auto triggerbits = raw::RDHUtils::getTriggerType(header); + + if (feeID >= 40) { + continue; // skip STU ddl + } + + // use the altro decoder to decode the raw data, and extract the RCU trailer + AltroDecoder decoder(rawreader); + // check the words of the payload exception in altrodecoder + try { + decoder.decode(); + } catch (AltroDecoderError& e) { + LOG(error) << e.what(); + continue; + } + for (const auto& e : decoder.getMinorDecodingErrors()) { + LOG(warning) << e.what(); + } + + try { + + const auto& map = mMapper->getMappingForDDL(feeID); + uint16_t iSM = feeID / 2; + + // Loop over all the channels + int nBunchesNotOK = 0; + for (auto& chan : decoder.getChannels()) { + int iRow, iCol; + ChannelType_t chantype; + try { + iRow = map.getRow(chan.getHardwareAddress()); + iCol = map.getColumn(chan.getHardwareAddress()); + chantype = map.getChannelType(chan.getHardwareAddress()); + } catch (Mapper::AddressNotFoundException& ex) { + LOG(error) << ex.what(); + continue; + } + + if (!(chantype == o2::emcal::ChannelType_t::HIGH_GAIN || chantype == o2::emcal::ChannelType_t::LOW_GAIN || chantype == o2::emcal::ChannelType_t::LEDMON)) { + continue; + } + + int CellID = -1; + bool isLowGain = false; + try { + if (chantype == o2::emcal::ChannelType_t::HIGH_GAIN || chantype == o2::emcal::ChannelType_t::LOW_GAIN) { + // high- / low-gain cell + CellID = getCellAbsID(iSM, iCol, iRow); + isLowGain = chantype == o2::emcal::ChannelType_t::LOW_GAIN; + } else { + CellID = geLEDMONAbsID(iSM, iCol); // Module index encoded in colum for LEDMONs + isLowGain = iRow == 0; // For LEDMONs gain type is encoded in the row (0 - low gain, 1 - high gain) + } + } catch (ModuleIndexException& e) { + LOG(error) << e.what(); + continue; + } + + // Fill pedestal object + for (auto& bunch : chan.getBunches()) { + for (auto e : bunch.getADC()) { + mPedestalData.fillADC(e, CellID, isLowGain, chantype == o2::emcal::ChannelType_t::LEDMON); + } + } + } + } catch (o2::emcal::MappingHandler::DDLInvalid& ddlerror) { + // Unable to catch mapping + LOG(error) << ddlerror.what(); + } + } + } + + sendData(ctx, mPedestalData); +} + +int PedestalProcessorDevice::getCellAbsID(int supermoduleID, int column, int row) const +{ + auto [phishift, etashift] = mGeometry->ShiftOnlineToOfflineCellIndexes(supermoduleID, row, column); + int cellID = mGeometry->GetAbsCellIdFromCellIndexes(supermoduleID, phishift, etashift); + if (cellID > 17664 || cellID < 0) { + throw ModuleIndexException(cellID, column, row, etashift, phishift); + } + return cellID; +} + +int PedestalProcessorDevice::geLEDMONAbsID(int supermoduleID, int moduleID) const +{ + if (moduleID >= o2::emcal::EMCAL_LEDREFS || moduleID < 0) { + throw ModuleIndexException(moduleID); + } + return supermoduleID * o2::emcal::EMCAL_LEDREFS + moduleID; +} + +bool PedestalProcessorDevice::isLostTimeframe(framework::ProcessingContext& ctx) const +{ + constexpr auto originEMC = header::gDataOriginEMC; + o2::framework::InputSpec dummy{"dummy", + framework::ConcreteDataMatcher{originEMC, + header::gDataDescriptionRawData, + 0xDEADBEEF}}; + static size_t contDeadBeef = 0; // number of times 0xDEADBEEF was seen continuously + for (const auto& ref : o2::framework::InputRecordWalker(ctx.inputs(), {dummy})) { + const auto dh = o2::framework::DataRefUtils::getHeader(ref); + auto payloadSize = o2::framework::DataRefUtils::getPayloadSize(ref); + if (payloadSize == 0) { + auto maxWarn = o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef; + if (++contDeadBeef <= maxWarn) { + LOGP(alarm, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF{}", + dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, payloadSize, + contDeadBeef == maxWarn ? fmt::format(". {} such inputs in row received, stopping reporting", contDeadBeef) : ""); + } + return true; + } + } + contDeadBeef = 0; // if good data, reset the counter + return false; +} + +void PedestalProcessorDevice::sendData(framework::ProcessingContext& ctx, const PedestalProcessorData& data) const +{ + constexpr auto originEMC = o2::header::gDataOriginEMC; + ctx.outputs().snapshot(framework::Output{originEMC, "PEDDATA", 0}, data); +} + +o2::framework::DataProcessorSpec o2::emcal::getPedestalProcessorDevice(bool askDistSTF) +{ + constexpr auto originEMC = o2::header::gDataOriginEMC; + std::vector inputs{{"stf", o2::framework::ConcreteDataTypeMatcher{originEMC, o2::header::gDataDescriptionRawData}, o2::framework::Lifetime::Timeframe}}; + std::vector outputs; + outputs.emplace_back(originEMC, "PEDDATA", 0, o2::framework::Lifetime::Timeframe); + if (askDistSTF) { + inputs.emplace_back("stdDist", "FLP", "DISTSUBTIMEFRAME", 0, o2::framework::Lifetime::Timeframe); + } + + return o2::framework::DataProcessorSpec{ + "PedestalProcessor", + inputs, + outputs, + o2::framework::AlgorithmSpec{o2::framework::adaptFromTask()}, + o2::framework::Options{}}; +} \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/test/testPedestalProcessorData.cxx b/Detectors/EMCAL/calibration/test/testPedestalProcessorData.cxx new file mode 100644 index 0000000000000..e591249fcea5b --- /dev/null +++ b/Detectors/EMCAL/calibration/test/testPedestalProcessorData.cxx @@ -0,0 +1,155 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#define BOOST_TEST_MODULE Test_EMCAL_Calibration +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK + +#include +#include +#include "EMCALCalibration/PedestalProcessorData.h" +#include +#include +#include + +namespace o2 +{ + +namespace emcal +{ + +const int NUMBERFECCHANNELS = 17664, + NUMBERLEDMONCHANNELS = 480; + +void compare(const PedestalProcessorData& testobject, const TProfile& refFECHG, const TProfile& refFECLG, const TProfile& refLEDMONHG, const TProfile& refLEDMONLG, bool testCount, bool verbose) +{ + const double PRECISION = FLT_EPSILON; + const double PRECISIONMEAN = FLT_EPSILON; + for (std::size_t ichan = 0; ichan < NUMBERFECCHANNELS; ichan++) { + auto [meanHG, rmsHG] = testobject.getValue(ichan, false, false); + auto [meanLG, rmsLG] = testobject.getValue(ichan, true, false); + if (verbose) { + std::cout << "Channel " << ichan << ", mean HG " << meanHG << ", RMS HG " << std::sqrt(rmsHG) << ", entries HG " << testobject.getEntriesForChannel(ichan, false, false) << " ref(mean " << refFECHG.GetBinContent(ichan + 1) << ", RMS " << refFECHG.GetBinError(ichan + 1) << ", entries " << refFECHG.GetBinEntries(ichan + 1) << ")" << std::endl; + std::cout << "Channel " << ichan << ", mean LG " << meanLG << ", RMS LG " << std::sqrt(rmsLG) << ", entries LG " << testobject.getEntriesForChannel(ichan, true, false) << " ref(mean " << refFECLG.GetBinContent(ichan + 1) << ", RMS " << refFECLG.GetBinError(ichan + 1) << ", entries " << refFECLG.GetBinEntries(ichan + 1) << ")" << std::endl; + } + BOOST_CHECK_LE(std::abs(meanHG - refFECHG.GetBinContent(ichan + 1)), PRECISIONMEAN); + BOOST_CHECK_LE(std::abs(meanLG - refFECLG.GetBinContent(ichan + 1)), PRECISIONMEAN); + BOOST_CHECK_LE(std::abs(std::sqrt(rmsHG) - refFECHG.GetBinError(ichan + 1)), PRECISION); + BOOST_CHECK_LE(std::abs(std::sqrt(rmsLG) - refFECLG.GetBinError(ichan + 1)), PRECISION); + if (testCount) { + BOOST_CHECK_EQUAL(testobject.getEntriesForChannel(ichan, false, false), refFECHG.GetBinEntries(ichan + 1)); + BOOST_CHECK_EQUAL(testobject.getEntriesForChannel(ichan, true, false), refFECLG.GetBinEntries(ichan + 1)); + } + } + for (std::size_t ichan = 0; ichan < NUMBERLEDMONCHANNELS; ichan++) { + auto [meanHG, rmsHG] = testobject.getValue(ichan, false, true); + auto [meanLG, rmsLG] = testobject.getValue(ichan, true, true); + if (verbose) { + std::cout << "LEDMON " << ichan << ", mean HG " << meanHG << ", RMS HG " << std::sqrt(rmsHG) << ", entries HG " << testobject.getEntriesForChannel(ichan, false, true) << " ref(mean " << refLEDMONHG.GetBinContent(ichan + 1) << ", RMS " << refLEDMONHG.GetBinError(ichan + 1) << ", entries " << refLEDMONHG.GetBinEntries(ichan + 1) << ")" << std::endl; + std::cout << "LEDMON " << ichan << ", mean LG " << meanLG << ", RMS LG " << std::sqrt(rmsLG) << ", entries LG " << testobject.getEntriesForChannel(ichan, true, true) << " ref(mean " << refLEDMONLG.GetBinContent(ichan + 1) << ", RMS " << refLEDMONLG.GetBinError(ichan + 1) << ", entries " << refLEDMONLG.GetBinEntries(ichan + 1) << ")" << std::endl; + } + BOOST_CHECK_LE(std::abs(meanHG - refLEDMONHG.GetBinContent(ichan + 1)), PRECISIONMEAN); + BOOST_CHECK_LE(std::abs(meanLG - refLEDMONLG.GetBinContent(ichan + 1)), PRECISIONMEAN); + BOOST_CHECK_LE(std::abs(std::sqrt(rmsHG) - refLEDMONHG.GetBinError(ichan + 1)), PRECISION); + BOOST_CHECK_LE(std::abs(std::sqrt(rmsLG) - refLEDMONLG.GetBinError(ichan + 1)), PRECISION); + if (testCount) { + BOOST_CHECK_EQUAL(testobject.getEntriesForChannel(ichan, false, true), refLEDMONHG.GetBinEntries(ichan + 1)); + BOOST_CHECK_EQUAL(testobject.getEntriesForChannel(ichan, true, true), refLEDMONLG.GetBinEntries(ichan + 1)); + } + } +} + +BOOST_AUTO_TEST_CASE(testPedestalProcessorData) +{ + // we compare with RMS, so the + TProfile refFECHG("refFECHG", "Reference FEC HG", NUMBERFECCHANNELS, -0.5, NUMBERFECCHANNELS - 0.5, "s"), + refFECLG("refFECLG", "Reference FEC LG", NUMBERFECCHANNELS, -0.5, NUMBERFECCHANNELS - 0.5, "s"), + refLEDMONHG("refLEDMONHG", "Reference LEDMON HG", NUMBERLEDMONCHANNELS, -0.5, NUMBERLEDMONCHANNELS - 0.5, "s"), + refLEDMONLG("refLEDMONLG", "Reference LEDMON LG", NUMBERLEDMONCHANNELS, -0.5, NUMBERLEDMONCHANNELS - 0.5, "s"); + refFECHG.Sumw2(); + refFECLG.Sumw2(); + refLEDMONHG.Sumw2(); + refLEDMONLG.Sumw2(); + + PedestalProcessorData testobject; + + const int NUMBERALTROSAMPLES = 15; + for (auto iev = 0; iev < 1000; iev++) { + for (int ichan = 0; ichan < NUMBERFECCHANNELS; ichan++) { + for (int isample = 0; isample < 15; isample++) { + // short adc_hg = static_cast(adcGeneratorHG(gen)), + // adc_lg = static_cast(adcGeneratorLG(gen)); + auto raw_hg = gRandom->Gaus(40, 6), + raw_lg = gRandom->Gaus(36, 10); + unsigned short adc_hg = static_cast(raw_hg > 0 ? raw_hg : 0), + adc_lg = static_cast(raw_lg > 0 ? raw_lg : 0); + refFECHG.Fill(ichan, adc_hg); + refFECLG.Fill(ichan, adc_lg); + testobject.fillADC(adc_hg, ichan, false, false); + testobject.fillADC(adc_lg, ichan, true, false); + } + } + } + for (auto iev = 0; iev < 1000; iev++) { + for (int ichan = 0; ichan < NUMBERLEDMONCHANNELS; ichan++) { + for (int isample = 0; isample < 15; isample++) { + // short adc_hg = static_cast(adcGeneratorLEDMONHG(gen)), + // adc_lg = static_cast(adcGeneratorLEDMONLG(gen)); + auto raw_hg = gRandom->Gaus(40, 6), + raw_lg = gRandom->Gaus(36, 10); + unsigned short adc_hg = static_cast(raw_hg > 0 ? raw_hg : 0), + adc_lg = static_cast(raw_lg > 0 ? raw_lg : 0); + refLEDMONHG.Fill(ichan, adc_hg); + refLEDMONLG.Fill(ichan, adc_lg); + testobject.fillADC(adc_hg, ichan, false, true); + testobject.fillADC(adc_lg, ichan, true, true); + } + } + } + + // Compare channels + compare(testobject, refFECHG, refFECLG, refLEDMONHG, refLEDMONLG, true, false); + + // Test operator+ + auto testdoubled = testobject + testobject; + TProfile refFECHGdouble(refFECHG), + refFECLGdouble(refFECLG), + refLEDMONHGdouble(refLEDMONHG), + refLEDMONLGdouble(refLEDMONLG); + refFECHGdouble.Add(&refFECHG); + refFECLGdouble.Add(&refFECLG); + refLEDMONHGdouble.Add(&refLEDMONHG); + refLEDMONLGdouble.Add(&refLEDMONLG); + compare(testdoubled, refFECHGdouble, refFECLGdouble, refLEDMONHGdouble, refLEDMONLGdouble, false, false); + + // Test reset function + auto testreset = testobject; + testreset.reset(); + for (std::size_t ichan = 0; ichan < NUMBERFECCHANNELS; ichan++) { + auto [meanHG, rmsHG] = testreset.getValue(ichan, false, false); + auto [meanLG, rmsLG] = testreset.getValue(ichan, true, false); + BOOST_CHECK_EQUAL(meanHG, 0.); + BOOST_CHECK_EQUAL(meanLG, 0.); + BOOST_CHECK_EQUAL(testreset.getEntriesForChannel(ichan, false, false), 0); + BOOST_CHECK_EQUAL(testreset.getEntriesForChannel(ichan, true, false), 0); + } + for (std::size_t ichan = 0; ichan < NUMBERLEDMONCHANNELS; ichan++) { + auto [meanHG, rmsHG] = testreset.getValue(ichan, false, true); + auto [meanLG, rmsLG] = testreset.getValue(ichan, true, true); + BOOST_CHECK_EQUAL(meanHG, 0.); + BOOST_CHECK_EQUAL(meanLG, 0.); + BOOST_CHECK_EQUAL(testreset.getEntriesForChannel(ichan, false, true), 0); + BOOST_CHECK_EQUAL(testreset.getEntriesForChannel(ichan, true, true), 0); + } +} + +} // namespace emcal + +} // namespace o2 \ No newline at end of file diff --git a/Detectors/EMCAL/calibration/testWorkflow/EMCALChannelCalibratorSpec.h b/Detectors/EMCAL/calibration/testWorkflow/EMCALChannelCalibratorSpec.h index a5402e9c1c913..2d6a9dc6c9d01 100644 --- a/Detectors/EMCAL/calibration/testWorkflow/EMCALChannelCalibratorSpec.h +++ b/Detectors/EMCAL/calibration/testWorkflow/EMCALChannelCalibratorSpec.h @@ -172,6 +172,14 @@ class EMCALChannelCalibDevice : public o2::framework::Task timeMeas[0] = std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); } + const auto& tinfo = pc.services().get(); + if (tinfo.globalRunNumberChanged) { // new run is starting + mRunStopRequested = false; + } + if (mRunStopRequested) { + return; + } + o2::base::GRPGeomHelper::instance().checkUpdates(pc); if (mTimeCalibrator) { o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mTimeCalibrator->getCurrentTFInfo()); @@ -196,7 +204,9 @@ class EMCALChannelCalibDevice : public o2::framework::Task if (!mIsConfigured) { // configure calibrators (after calib params are loaded from the CCDB) - configureCalibrators(); + // long tsMS = o2::base::GRPGeomHelper::instance().getOrbitResetTimeMS() + pc.services().get().firstTForbit * o2::constants::lhc::LHCOrbitMUS / 1000; // this reads the ts from the data. + long tsMS = o2::ccdb::getCurrentTimestamp(); + configureCalibrators(tsMS); mIsConfigured = true; } @@ -312,7 +322,7 @@ class EMCALChannelCalibDevice : public o2::framework::Task if (pc.transitionState() == TransitionHandlingState::Requested) { LOG(debug) << "Run stop requested, finalizing"; - // mRunStopRequested = true; + mRunStopRequested = true; if (isBadChannelCalib) { mBadChannelCalibrator->setSaveAtEOR(true); mBadChannelCalibrator->checkSlotsToFinalize(o2::calibration::INFINITE_TF); @@ -335,6 +345,9 @@ class EMCALChannelCalibDevice : public o2::framework::Task void endOfStream(o2::framework::EndOfStreamContext& ec) final { + if (mRunStopRequested) { + return; + } if (isBadChannelCalib) { mBadChannelCalibrator->setSaveAtEOR(true); mBadChannelCalibrator->checkSlotsToFinalize(o2::calibration::INFINITE_TF); @@ -344,6 +357,7 @@ class EMCALChannelCalibDevice : public o2::framework::Task mTimeCalibrator->checkSlotsToFinalize(o2::calibration::INFINITE_TF); sendOutput(ec.outputs()); } + mRunStopRequested = true; } static const char* getCellBinding() { return "EMCCells"; } @@ -366,6 +380,7 @@ class EMCALChannelCalibDevice : public o2::framework::Task bool mRejectL0Triggers = true; ///! reject EMCal Gamma and Jet triggers in the online calibration bool mApplyGainCalib = true; ///! switch if gain calibration should be applied during filling of histograms or not bool mGainCalibFactorsInitialized = false; ///! Gain calibration init status + bool mRunStopRequested = false; ///< flag that the run has stopped std::array timeMeas; ///! Used for time measurement and holds the start and end time in the run function std::vector mSelectedClassMasks = {}; ///! EMCal minimum bias trigger bit. Only this bit will be used for calibration std::unique_ptr mDownsampler; @@ -415,22 +430,42 @@ class EMCALChannelCalibDevice : public o2::framework::Task } /// \brief Configure calibrators from the calib params - void configureCalibrators() + void configureCalibrators(long ts) { + auto currFill = o2::base::GRPGeomHelper::instance().getGRPLHCIF()->getFillNumber(); + auto runtype = o2::base::GRPGeomHelper::instance().getGRPECS()->getRunType(); + LOG(debug) << "currFill " << currFill << " runtype " << runtype; + if (mTimeCalibrator) { LOG(info) << "Configuring time calibrator"; mTimeCalibrator->setSlotLength(EMCALCalibParams::Instance().slotLength_tc); + if (EMCALCalibParams::Instance().slotLength_tc == 0) { + // for infinite slot length do not check if there is enough statistics after every TF + mTimeCalibrator->setCheckIntervalInfiniteSlot(1e5); + } if (EMCALCalibParams::Instance().UpdateAtEndOfRunOnly_tc) { - mBadChannelCalibrator->setUpdateAtTheEndOfRunOnly(); + mTimeCalibrator->setUpdateAtTheEndOfRunOnly(); } + mTimeCalibrator->setSaveFileName("emc-time-calib-" + std::to_string(runtype) + ".root"); + mTimeCalibrator->setFillNr(currFill); + mTimeCalibrator->setRunType(runtype); + mTimeCalibrator->setCurrTSInHours(static_cast(ts / o2::ccdb::CcdbObjectInfo::HOUR)); } if (mBadChannelCalibrator) { LOG(info) << "Configuring bad channel calibrator"; mBadChannelCalibrator->setSlotLength(EMCALCalibParams::Instance().slotLength_bc); + if (EMCALCalibParams::Instance().slotLength_bc == 0) { + // for infinite slot length do not check if there is enough statistics after every TF + mBadChannelCalibrator->setCheckIntervalInfiniteSlot(1e5); + } if (EMCALCalibParams::Instance().UpdateAtEndOfRunOnly_bc) { mBadChannelCalibrator->setUpdateAtTheEndOfRunOnly(); } mBadChannelCalibrator->setIsTest(EMCALCalibParams::Instance().enableTestMode_bc); + mBadChannelCalibrator->setFillNr(currFill); + mBadChannelCalibrator->setRunType(runtype); + mBadChannelCalibrator->setSaveFileName("emc-channel-calib-" + std::to_string(runtype) + ".root"); + mBadChannelCalibrator->setCurrTSInHours(static_cast(ts / o2::ccdb::CcdbObjectInfo::HOUR)); } } }; // namespace calibration @@ -482,7 +517,7 @@ DataProcessorSpec getEMCALChannelCalibDeviceSpec(const std::string calibType, co auto ccdbRequest = std::make_shared(true, // orbitResetTime true, // GRPECS=true - false, // GRPLHCIF + true, // GRPLHCIF false, // GRPMagField false, // askMatLUT o2::base::GRPGeomRequest::None, // geometry diff --git a/Detectors/EMCAL/calibration/testWorkflow/emc-pedestal-calib-workflow.cxx b/Detectors/EMCAL/calibration/testWorkflow/emc-pedestal-calib-workflow.cxx new file mode 100644 index 0000000000000..c624dbaa89784 --- /dev/null +++ b/Detectors/EMCAL/calibration/testWorkflow/emc-pedestal-calib-workflow.cxx @@ -0,0 +1,53 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file emc-channel-calib-workflow.cxx +/// @author Joshua Koenig +/// @since 2024-03-25 +/// @brief Basic workflow for EMCAL pedestal calibration + +#include "CommonUtils/ConfigurableParam.h" +#include "EMCALCalibration/PedestalCalibDevice.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/Variant.h" +#include "Framework/WorkflowSpec.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" + +#include + +using namespace o2::framework; +using namespace o2::emcal; + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + std::vector options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + {"dumpToFile", VariantType::Bool, false, {"if output (that goes to DCS ccdb) should be stored in txt file for local debugging"}}, + {"addRunNumber", VariantType::Bool, false, {"if true, run number will be added to ccdb file as first element of the string"}}}; + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); + bool dumpToFile = cfgc.options().get("dumpToFile"); + bool addRunNumber = cfgc.options().get("addRunNumber"); + + WorkflowSpec specs; + specs.emplace_back(o2::emcal::getPedestalCalibDevice(dumpToFile, addRunNumber)); + + return specs; +} diff --git a/Detectors/EMCAL/calibration/testWorkflow/emc-pedestal-processor-workflow.cxx b/Detectors/EMCAL/calibration/testWorkflow/emc-pedestal-processor-workflow.cxx new file mode 100644 index 0000000000000..efa4dc3f4afda --- /dev/null +++ b/Detectors/EMCAL/calibration/testWorkflow/emc-pedestal-processor-workflow.cxx @@ -0,0 +1,54 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// @file emc-channel-calib-workflow.cxx +/// @author Hannah Bossi +/// @since 2020-12-01 +/// @brief Basic workflow for EMCAL bad channel calibration (adapted from tof-calib-workflow.cxx) + +#include "CommonUtils/ConfigurableParam.h" +#include "EMCALCalibration/PedestalProcessorDevice.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/Variant.h" +#include "Framework/WorkflowSpec.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" + +#include + +using namespace o2::framework; +using namespace o2::emcal; + +// add workflow options, note that customization needs to be declared before +// including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + std::vector options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}, + {"no-askdiststf", VariantType::Bool, false, {"Don't subscribe to FLP/DISTSUBTIMEFRAME (local testing)"}}}; + + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" // the main driver + +WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) +{ + + o2::conf::ConfigurableParam::updateFromString(cfgc.options().get("configKeyValues")); + bool askdiststf = !cfgc.options().get("no-askdiststf"); + + WorkflowSpec specs; + specs.emplace_back(getPedestalProcessorDevice(askdiststf)); + + // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit + // o2::raw::HBFUtilsInitializer hbfIni(cfgc, specs); + return specs; +} diff --git a/Detectors/EMCAL/reconstruction/CMakeLists.txt b/Detectors/EMCAL/reconstruction/CMakeLists.txt index 952db0cf5ba01..983bef1aeba40 100644 --- a/Detectors/EMCAL/reconstruction/CMakeLists.txt +++ b/Detectors/EMCAL/reconstruction/CMakeLists.txt @@ -16,6 +16,7 @@ o2_add_library(EMCALReconstruction src/AltroDecoder.cxx src/Bunch.cxx src/Channel.cxx + src/FastORTimeSeries.cxx src/RecoParam.cxx src/RawDecodingError.cxx src/STUDecoderError.cxx @@ -32,6 +33,7 @@ o2_add_library(EMCALReconstruction src/CTFCoder.cxx src/CTFHelper.cxx src/StuDecoder.cxx + src/TRUDataHandler.cxx PUBLIC_LINK_LIBRARIES O2::Headers AliceO2::InfoLogger O2::DataFormatsEMCAL @@ -49,6 +51,7 @@ o2_target_root_dictionary( include/EMCALReconstruction/RawPayload.h include/EMCALReconstruction/Bunch.h include/EMCALReconstruction/Channel.h + include/EMCALReconstruction/FastORTimeSeries.h include/EMCALReconstruction/CaloFitResults.h include/EMCALReconstruction/CaloRawFitter.h include/EMCALReconstruction/CaloRawFitterStandard.h @@ -59,6 +62,7 @@ o2_target_root_dictionary( include/EMCALReconstruction/DigitReader.h include/EMCALReconstruction/RecoParam.h include/EMCALReconstruction/StuDecoder.h + include/EMCALReconstruction/TRUDataHandler.h ) o2_add_executable(rawreader-file diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/FastORTimeSeries.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/FastORTimeSeries.h new file mode 100644 index 0000000000000..0918fced0f999 --- /dev/null +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/FastORTimeSeries.h @@ -0,0 +1,83 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_EMCAL_FASTORTIMESERIES_H +#define ALICEO2_EMCAL_FASTORTIMESERIES_H + +#include +#include +#include "Rtypes.h" + +namespace o2::emcal +{ + +/// \class FastORTimeSeries +/// \brief Container for FastOR time series +/// \author Markus Fasel , Oak Ridge National Laboratory +/// \ingroup EMCALreconstruction +/// \since April 19, 2024 +/// +/// Time series are encoded in bunches in the raw data, which are usually time-reversed. +/// The FastORTimeSeries handles the time series of all bunches in the readout window, +/// in proper future-direction time order, correcting the time-reversal from the Fake-ALTRO. +/// Consequently the ADC samples are expected in time-reversed format. The function +/// calculateL1TimeSum calculates the timesum of the timeseries as 4-integral with respect to +/// a given L0 time, which is expected at the end of the time integration range. +class FastORTimeSeries +{ + public: + /// @brief Dummy constructor + FastORTimeSeries() = default; + + /// \brief Construcor + /// \param maxsamples Maximum number of time samples + /// \param timesamples Time-reversed raw ADC samples + /// \param starttime Start time + FastORTimeSeries(int maxsamples, const gsl::span timesamples, uint8_t starttime) + { + setSize(maxsamples); + fillReversed(timesamples, starttime); + } + + /// \brief Destructor + ~FastORTimeSeries() = default; + + void setTimeSamples(const gsl::span timesamples, uint8_t starttime) { fillReversed(timesamples, starttime); } + + /// \brief Calculate L0 timesum (4-integral of the ADC series) with respect to a given L0 time + /// \param l0time L0 time (end of the time series) + /// \return Timesum of the time series + uint16_t calculateL1TimeSum(uint8_t l0time) const; + + /// \brief Access raw ADC values (in forward time order) + /// \return ADC values of the time series in forward time order + const gsl::span getADCs() const { return mTimeSamples; } + + /// \brief Clear ADC samples in the time series + void clear(); + + private: + /// \brief Set the container size for the ADC samples + /// \param maxsamples Max. amount of samples to be handled + void setSize(int maxsamples); + + /// \brief Fill the internal time samples in proper time order + /// \param timesamples Time-reversed time samples + /// \param starttime Start time + void fillReversed(const gsl::span timesamples, uint8_t starttime); + + std::vector mTimeSamples; ///< Raw ADC time samples (in forward time order) + + ClassDef(FastORTimeSeries, 1); +}; + +} // namespace o2::emcal + +#endif \ No newline at end of file diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RecoContainer.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RecoContainer.h index c1a9fc151a1d5..36ce04267a47f 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RecoContainer.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/RecoContainer.h @@ -14,8 +14,10 @@ /// \author Markus Fasel , Oak Ridge National Laboratory /// \since May 30, 2023 +#include #include #include +#include #include #include #include @@ -24,6 +26,9 @@ #include #include #include +#include +#include +#include namespace o2::emcal { @@ -49,10 +54,52 @@ struct RecCellInfo { /// \class EventContainer /// \brief Containter of cells for a given event -/// \ingroup EMCALReconstruction +/// \author Markus Fasel , Oak Ridge National Laboratory +/// \ingroup EMCALreconstruction +/// \since May 30, 2023 +/// +/// The EventContainer is part of the reco container and keeps the cell / LEDMON / TRU +/// data of a given event (trigger) defined by the BC and orbit in the raw data header. +/// In case the gain type merging is activated the event container performs on-the-fly +/// merging of high- and low-gain data for cells and LEDMONS keeping only high- or +/// low-gain and preferring the high-gain due to better resolution if not saturated. +/// +/// Error handling: +/// The EventContainer can raise a TRUIndexException in case TRU information with an +/// unexpected index (>= 52) is added / requested. class EventContainer { public: + /// \class TRUIndexException + /// \brief Handler for access of TRU data with invalid TRU index + /// \ingroup EMCALreconstruction + class TRUIndexException final : public std::exception + { + public: + /// \brief Constructor + /// \param index TRU index raising the exception + TRUIndexException(std::size_t index); + + /// \brief Destructor + ~TRUIndexException() noexcept final = default; + + /// \brief Get the error message of the exception + /// \return Error message + const char* what() const noexcept final { return mMessage.data(); } + + /// \brief Get the TRU index raising the exception + /// \return TRU index + std::size_t getIndex() const { return mIndex; } + + /// \brief Print error message on stream + /// \param stream Stream to print on + void printStream(std::ostream& stream) const; + + private: + std::size_t mIndex; ///< TRU index raising the exception + std::string mMessage; ///< Buffer for error message + }; + /// \brief Constructor EventContainer() = default; @@ -95,6 +142,22 @@ class EventContainer /// \return Number of LEDMONs int getNumberOfLEDMONs() const { return mLEDMons.size(); } + /// \brief Read and write access TRU data of a given TRU + /// \param truIndex Index of the TRU + /// \return TRU data handler for the TRU + /// \throw TRUIndexException in case the TRU index is invalid (>= 52) + TRUDataHandler& getTRUData(std::size_t truIndex); + + /// \brief Read-only access TRU data of a given TRU + /// \param truIndex Index of the TRU + /// \return TRU data handler for the TRU + /// \throw TRUIndexException in case the TRU index is invalid (>= 52) + const TRUDataHandler& readTRUData(std::size_t truIndex) const; + + /// \brief Access to container with FastOR time series + /// \return Container with time series + const std::unordered_map& getTimeSeriesContainer() const { return mL0FastORs; } + /// \brief Add cell information to the event container /// \param tower Tower ID /// \param energy Cell energy @@ -129,6 +192,16 @@ class EventContainer setCellCommon(tower, energy, time, celltype, true, hwaddress, ddlID, doMergeHGLG); } + /// \brief Add bunch of time series to the container + /// \param fastORAbsID Absolute ID of the FastOR + /// \param starttime Start time of the bunch + /// \param timesamples Time samples of the bunch in time-reversed format + /// + /// In case a TimeSeries is already present for the given FastOR abs. ID in the container + /// the bunch is added to this, otherwise a new TimeSeries is added with the ADCs of the + /// bunch. + void setFastOR(uint16_t fastORAbsID, uint8_t starttime, const gsl::span timesamples); + /// \brief Sort Cells / LEDMONs in container according to tower / module ID /// \param isLEDmon Switch between Cell and LEDMON void sortCells(bool isLEDmon); @@ -148,21 +221,37 @@ class EventContainer /// \return True if the energy is in the saturation region, false otherwise bool isCellSaturated(double energy) const; - o2::InteractionRecord mInteractionRecord; - uint64_t mTriggerBits = 0; ///< Trigger bits of the event - std::vector mCells; ///< Container of cells in event - std::vector mLEDMons; ///< Container of LEDMONs in event + /// \brief Initialize the TRU handlers + void initTRUs(); + + o2::InteractionRecord mInteractionRecord; ///< Interaction record of the event + uint64_t mTriggerBits = 0; ///< Trigger bits of the event + std::vector mCells; ///< Container of cells in event + std::vector mLEDMons; ///< Container of LEDMONs in event + std::array mTRUData; ///< TRU status + std::unordered_map mL0FastORs; ///< L0 FastOR time series }; /// \class RecoContainer -/// \brief Handler for cells in -/// \ingroup EMCALReconstruction +/// \brief Handler for cells/LEDMONS/Trigger data in timeframes +/// \author Markus Fasel , Oak Ridge National Laboratory +/// \ingroup EMCALreconstruction +/// \since May 30, 2023 +/// +/// The RecoContainer handles the cell/LEDMON/trigger data of all events of a given +/// timeframe during the reconstruction. Event data are handled internally via the +/// EventContainer, where the RecoContainer provides access to. +/// +/// Error handling: +/// The RecoContainer can raise an InteractionNotFoundException in case read access +/// is requested for an interaction based on the o2::InteractionRecord which is not +/// for which no data was inserted into the container. class RecoContainer { public: /// \class InteractionNotFoundException /// \brief Handling of access to trigger interaction record not present in container - class InteractionNotFoundException : public std::exception + class InteractionNotFoundException final : public std::exception { public: /// \brief Constructor @@ -225,7 +314,17 @@ class RecoContainer /// \class RecoContainerReader /// \brief Iterator over reco containers -/// \ingroup EMCALReconstruction +/// \author Markus Fasel , Oak Ridge National Laboratory +/// \ingroup EMCALreconstruction +/// \since May 30, 2023 +/// +/// The RecoContainerReader iterates over the events stored in the RecoContainer in +/// a time-ordered sequence. The function hasNext checks whether there are more +/// events to iterate over, while nextEvent provides access to the next event. +/// +/// Error handling: +/// The RecoContainerReader can raise an InvalidAccessException in case access is tried to +/// invalid data. class RecoContainerReader { public: diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ReconstructionErrors.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ReconstructionErrors.h index 49dd4d34b6937..2f09c83140ec0 100644 --- a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ReconstructionErrors.h +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/ReconstructionErrors.h @@ -163,18 +163,18 @@ GainError_t getGainErrorFromErrorCode(unsigned int errorcode); /// Name is a short single word descriptor used i.e. in /// object names. /// -/// \param errortype Error type of the gain error -/// \return Name connected to gain error type +/// \param errortype Error type of the gain type error +/// \return Name connected to gain type error const char* getGainErrorName(GainError_t errortype); /// \brief Get name of a given gain error code /// /// Name is a short single word descriptor used i.e. in /// object names. Attention: Error code must be a valid -/// geomentry error code. +/// gain type error code. /// -/// \param errorcode Error code of the gain error -/// \return Name connected to gain error type +/// \param errorcode Error code of the gain type error +/// \return Name connected to gain type error const char* getGainErrorName(unsigned int errorcode); /// \brief Get title of a given gain error type @@ -182,37 +182,137 @@ const char* getGainErrorName(unsigned int errorcode); /// Title is a short descriptor used i.e. in /// histogram titles. /// -/// \param errortype Error type of the gain error -/// \return Title connected to gain error type +/// \param errortype Error type of the gain type error +/// \return Title connected to gain type error const char* getGainErrorTitle(GainError_t errortype); /// \brief Get title of a given gain error type /// /// Title is a short descriptor used i.e. in /// histogram titles. Attention: Error code must -/// be a valid geomentry error code. +/// be a valid gain type error code. /// -/// \param errorcode Error code of the gain error -/// \return Title connected to gain error type +/// \param errorcode Error code of the gain type error +/// \return Title connected to gain type error const char* getGainErrorTitle(unsigned int errorcode); /// \brief Get detailed description of a given gain error type /// /// Provides a long description to be used i.e. in error messages. /// -/// \param errortype Error type of the gain error -/// \return Detaied description connected to gain error type +/// \param errortype Error type of the gain type error +/// \return Detaied description connected to gain type error const char* getGainErrorDescription(GainError_t errortype); /// \brief Get detailed description of a given gain error type /// /// Provides a long description to be used i.e. in error messages. -/// Attention: Error code must be a valid gain error code. +/// Attention: Error code must be a valid gain type error code. /// -/// \param errortype Error type of the geometry error -/// \return Detaied description connected to gain error type +/// \param errortype Error type of the gain type error +/// \return Detaied description connected to gain type error const char* getGainErrorDescription(unsigned int errorcode); +/// \enum TRUDecodingError_t +/// \brief Errors related to TRU data decoding +/// \ingroup EMCALReconstruction +/// +/// TRU decoding errors appear during the decoding of the TRU data. +/// They can be raised by the trigger mapping, in case an invalid +/// FastOR index or TRU index is called, or by the TRU data handler if +/// the patch index is outside range. +enum class TRUDecodingError_t { + TRU_INDEX_INVALID, ///< TRU index invalid + PATCH_INDEX_INVALID, ///< Patch index outside range + FASTOR_INDEX_INVALID, ///< FastOR index unknown + UNKNOWN_ERROR ///< Unknown error type +}; + +/// \brief Get the number of TRU error codes +/// \return Number of TRU error codes +constexpr int getNumberOfTRUErrorCodes() { return 3; } + +/// \brief Convert error code to TRU decoding error type +/// +/// Attention: Error code must be a valid error code, handled +/// internally via assert. +/// +/// \param errorcode Error code to be converted +/// \return Error type connected to error code +TRUDecodingError_t getTRUDecodingErrorFromErrorCode(unsigned int errorcode); + +/// \brief Convert TRU decoding error type into numberic representation +/// \param errortype TRU decoding error type +/// \return Error code connected to error type +constexpr int getErrorCodeFromTRUDecodingError(TRUDecodingError_t error) +{ + switch (error) { + case TRUDecodingError_t::TRU_INDEX_INVALID: + return 0; + case TRUDecodingError_t::PATCH_INDEX_INVALID: + return 1; + case TRUDecodingError_t::FASTOR_INDEX_INVALID: + return 2; + case TRUDecodingError_t::UNKNOWN_ERROR: + return -1; + } +} + +/// \brief Get name of a given TRU decoding error type +/// +/// Name is a short single word descriptor used i.e. in +/// object names. +/// +/// \param errortype Error type of the TRU decoding error +/// \return Name connected to TRU decoding error type +const char* getTRUDecodingErrorName(TRUDecodingError_t errortype); + +/// \brief Get name of a given TRU decoding error code +/// +/// Name is a short single word descriptor used i.e. in +/// object names. Attention: Error code must be a valid +/// TRU decoding error code. +/// +/// \param errorcode Error code of the TRU decoding error +/// \return Name connected to TRU decoding error type +const char* getTRUDecodingErrorName(unsigned int errorcode); + +/// \brief Get title of a given TRU decoding error type +/// +/// Title is a short descriptor used i.e. in +/// histogram titles. +/// +/// \param errortype Error type of the TRU decoding error +/// \return Title connected to TRU decoding error +const char* getTRUDecodingErrorTitle(TRUDecodingError_t errortype); + +/// \brief Get title of a given TRU decoding error type +/// +/// Title is a short descriptor used i.e. in +/// histogram titles. Attention: Error code must +/// be a valid TRU decoding error code. +/// +/// \param errorcode Error code of the TRU decoding error +/// \return Title connected to TRU decoding error +const char* getTRUDecodingErrorTitle(unsigned int errorcode); + +/// \brief Get detailed description of a given TRU decoding error type +/// +/// Provides a long description to be used i.e. in error messages. +/// +/// \param errortype Error type of the TRU decoding error +/// \return Detaied description connected to TRU decoding error +const char* getTRUDecodingErrorErrorDescription(TRUDecodingError_t errortype); + +/// \brief Get detailed description of a given TRU decoding error type +/// +/// Provides a long description to be used i.e. in error messages. +/// Attention: Error code must be a valid TRU decoding error code. +/// +/// \param errortype Error type of the TRU decoding error +/// \return Detaied description connected to TRU decoding error +const char* getTRUDecodingErrorErrorDescription(unsigned int errorcode); + } // namespace reconstructionerrors } // namespace emcal diff --git a/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/TRUDataHandler.h b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/TRUDataHandler.h new file mode 100644 index 0000000000000..811faf13a05ff --- /dev/null +++ b/Detectors/EMCAL/reconstruction/include/EMCALReconstruction/TRUDataHandler.h @@ -0,0 +1,185 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef ALICEO2_EMCAL_TRUDataHandler_H +#define ALICEO2_EMCAL_TRUDataHandler_H + +#include +#include +#include +#include +#include +#include + +#include "Rtypes.h" + +#include "EMCALBase/TriggerMappingV2.h" + +namespace o2::emcal +{ + +/// \class TRUDataHandler +/// \brief Helper class to handle decoded TRU data during the reconstruction +/// \author Markus Fasel , Oak Ridge National Laboratory +/// \ingroup EMCALreconstruction +/// \since April 19, 2024 +/// +/// The decoded TRU data contains the following information +/// - Index of the TRU +/// - Trigger time of the TRU +/// - Fired or not +/// - Index of fired patches with time the patch has fired +/// The information is decoded in columns 96 to 105 of the FakeALTRO data. The +/// class does not handle FastOR timesums (colums 0-96), they are handled by a +/// separate class FastORTimeSeries. +class TRUDataHandler +{ + public: + /// \class PatchIndexException + /// \brief Handler of errors related to invalid trigger patch IDs + /// \ingroup EMCALreconstruction + class PatchIndexException final : public std::exception + { + public: + /// \brief Constructor + /// \param index Patch index raising the exception + PatchIndexException(int8_t index); + + /// \brief Destructor + ~PatchIndexException() noexcept final = default; + + /// \brief Get patch index raising the exception + /// \return Patch index + int8_t getIndex() const { return mIndex; } + + /// \brief Access Error message + /// \return Error message + const char* what() const noexcept final + { + return mMessage.data(); + } + + /// \brief Print error on output stream + /// \param stream Stream to be printed to + void printStream(std::ostream& stream) const; + + private: + int8_t mIndex = -1; ///< Patch index rainsing the exception + std::string mMessage; ///< Buffer for error message + }; + + /// \brief Constructor + TRUDataHandler(); + + /// \brief Destructor + ~TRUDataHandler() = default; + + /// \brief Reset handler + void reset(); + + /// \brief Set reconstructed trigger patch + /// \param index Index of the trigger patch in the TRU + /// \param time Decoded time of the patch + /// \throw PatchIndexException in case the patch index is invalid (>= 77) + void setPatch(unsigned int index, unsigned int time) + { + checkPatchIndex(index); + mPatchTimes[index] = time; + } + + /// \brief Mark TRU as fired (containing at least one patch above threshold) + /// \param fired + void setFired(bool fired) { mL0Fired = fired; } + + /// \brief Set the L0 time of the TRU + /// \param l0time L0 time of the TRU + void setL0time(int l0time) { mL0Time = l0time; } + + /// \brief Set the index of the TRU (in global STU indexing scheme) + /// \param index Index of the TRU + void setTRUIndex(int index) { mTRUIndex = index; } + + /// \brief Check whether the TRU was fired (at least one patch above threshold) + /// \return True if the TRU was fired, false otherwise + bool isFired() const { return mL0Fired; } + + int8_t getL0time() const { return mL0Time; } + + /// \brief Check whehther the patch at the given index has fired + /// \param index Index of the patch + /// \return True if the patch has fired, false otherwise + /// \throw PatchIndexException in case the patch index is invalid (>= 77) + bool hasPatch(unsigned int index) const + { + checkPatchIndex(index); + return mPatchTimes[index] < UCHAR_MAX; + } + + /// \brief Get the trigger time of the trigger patch at a given index + /// \param index Index of the trigger patch + /// \return Reconstructed patch time (UCHAR_MAX in case the patch has not fired) + /// \throw PatchIndexException in case the patch index is invalid (>= 77) + uint8_t getPatchTime(unsigned int index) const + { + checkPatchIndex(index); + return mPatchTimes[index]; + } + + /// \brief Check whether the TRU has any patch fired + /// \return True if at least one fired patch was found, false otherwise + bool hasAnyPatch() const + { + for (int ipatch = 0; ipatch < mPatchTimes.size(); ipatch++) { + if (hasPatch(ipatch)) { + return true; + } + } + return false; + } + + /// \brief Get the index of the TRU in global (STU) index schemes + /// \return Index of the TRU + int getTRUIndex() const { return mTRUIndex; } + + /// \brief Print TRU information to an output stream + /// \param stream Stream to print on + void printStream(std::ostream& stream) const; + + private: + /// \brief Check whether the patch index is valid + /// \throw PatchIndexException in case the patch index is invalid (>= 77) + void checkPatchIndex(unsigned int index) const + { + if (index >= mPatchTimes.size()) { + throw PatchIndexException(index); + } + } + + std::array mPatchTimes; ///< Patch times: In case the patch time is smaller than UCHAR_MAX then the patch has fired + bool mL0Fired = false; ///< TRU has fired + int8_t mL0Time = -1; ///< L0 time of the TRU + int8_t mTRUIndex = -1; ///< Index of the TRU + ClassDefNV(TRUDataHandler, 1); +}; + +/// \brief Output stream operator for the TRU data handler +/// \param stream Stream to print on +/// \param data TRU data to be streamed +/// \return Stream after printing +std::ostream& operator<<(std::ostream& stream, const TRUDataHandler& data); + +/// \brief Output stream operator of the PatchIndexException +/// \param stream Stream to print on +/// \param error Error to be streamed +/// \return Stream after printing +std::ostream& operator<<(std::ostream& stream, const TRUDataHandler::PatchIndexException& error); + +} // namespace o2::emcal +#endif diff --git a/Detectors/EMCAL/reconstruction/src/EMCALReconstructionLinkDef.h b/Detectors/EMCAL/reconstruction/src/EMCALReconstructionLinkDef.h index 9482db17c0386..ee39958db5add 100644 --- a/Detectors/EMCAL/reconstruction/src/EMCALReconstructionLinkDef.h +++ b/Detectors/EMCAL/reconstruction/src/EMCALReconstructionLinkDef.h @@ -25,6 +25,8 @@ #pragma link C++ class o2::emcal::CaloRawFitterStandard + ; #pragma link C++ class o2::emcal::CaloRawFitterGamma2 + ; #pragma link C++ class o2::emcal::StuDecoder + ; +#pragma link C++ class o2::emcal::FastORTimeSeries + ; +#pragma link C++ class o2::emcal::TRUDataHandler + ; #pragma link C++ class o2::emcal::RecoParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::emcal::RecoParam> + ; diff --git a/Detectors/EMCAL/reconstruction/src/FastORTimeSeries.cxx b/Detectors/EMCAL/reconstruction/src/FastORTimeSeries.cxx new file mode 100644 index 0000000000000..d23d982047f2b --- /dev/null +++ b/Detectors/EMCAL/reconstruction/src/FastORTimeSeries.cxx @@ -0,0 +1,44 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include "EMCALReconstruction/FastORTimeSeries.h" + +using namespace o2::emcal; + +void FastORTimeSeries::fillReversed(const gsl::span samples, uint8_t starttime) +{ + + for (std::size_t isample = 0; isample < samples.size(); isample++) { + mTimeSamples[starttime - isample] = samples[isample]; + } +} + +uint16_t FastORTimeSeries::calculateL1TimeSum(uint8_t l0time) const +{ + uint16_t timesum = 0; + int firstbin = l0time - 4; // Include sample before the L0 time + for (int isample = firstbin; isample < firstbin + 4; isample++) { + timesum += mTimeSamples[isample]; + } + return timesum; +} + +void FastORTimeSeries::setSize(int maxsamples) +{ + mTimeSamples.resize(maxsamples); +} + +void FastORTimeSeries::clear() +{ + std::fill(mTimeSamples.begin(), mTimeSamples.end(), 0); +} \ No newline at end of file diff --git a/Detectors/EMCAL/reconstruction/src/RecoContainer.cxx b/Detectors/EMCAL/reconstruction/src/RecoContainer.cxx index 4ed49e5876c93..062887287f86b 100644 --- a/Detectors/EMCAL/reconstruction/src/RecoContainer.cxx +++ b/Detectors/EMCAL/reconstruction/src/RecoContainer.cxx @@ -16,7 +16,15 @@ using namespace o2::emcal; -EventContainer::EventContainer(const o2::InteractionRecord& currentIR) : mInteractionRecord(currentIR) {} +EventContainer::EventContainer(const o2::InteractionRecord& currentIR) : mInteractionRecord(currentIR) { initTRUs(); } + +void EventContainer::initTRUs() +{ + for (auto index = 0; index < mTRUData.size(); index++) { + mTRUData[index].setTRUIndex(index); + mTRUData[index].setL0time(INT8_MAX); + } +} void EventContainer::setCellCommon(int tower, double energy, double time, ChannelType_t celltype, bool isLEDmon, int hwaddress, int ddlID, bool doMergeHGLG) { @@ -83,6 +91,16 @@ void EventContainer::setCellCommon(int tower, double energy, double time, Channe } } +void EventContainer::setFastOR(uint16_t fastORAbsID, uint8_t starttime, const gsl::span timesamples) +{ + auto found = mL0FastORs.find(fastORAbsID); + if (found != mL0FastORs.end()) { + found->second.setTimeSamples(timesamples, starttime); + } else { + mL0FastORs[fastORAbsID] = FastORTimeSeries(14, timesamples, starttime); + } +} + void EventContainer::sortCells(bool isLEDmon) { auto& dataContainer = isLEDmon ? mLEDMons : mCells; @@ -94,6 +112,27 @@ bool EventContainer::isCellSaturated(double energy) const return energy / o2::emcal::constants::EMCAL_ADCENERGY > o2::emcal::constants::OVERFLOWCUT; } +TRUDataHandler& EventContainer::getTRUData(std::size_t index) +{ + if (index >= mTRUData.size()) { + throw TRUIndexException(index); + } + return mTRUData[index]; +} + +const TRUDataHandler& EventContainer::readTRUData(std::size_t index) const +{ + if (index >= mTRUData.size()) { + throw TRUIndexException(index); + } + return mTRUData[index]; +} + +EventContainer::TRUIndexException::TRUIndexException(std::size_t index) : mIndex(index), mMessage() +{ + mMessage = "Invalid TRU index " + std::to_string(index); +} + EventContainer& RecoContainer::getEventContainer(const o2::InteractionRecord& currentIR) { auto found = mEvents.find(currentIR); diff --git a/Detectors/EMCAL/reconstruction/src/ReconstructionErrors.cxx b/Detectors/EMCAL/reconstruction/src/ReconstructionErrors.cxx index 30f2a403daac0..d2e5ea6d92a6f 100644 --- a/Detectors/EMCAL/reconstruction/src/ReconstructionErrors.cxx +++ b/Detectors/EMCAL/reconstruction/src/ReconstructionErrors.cxx @@ -147,6 +147,77 @@ const char* getGainErrorDescription(unsigned int errorcode) return getGainErrorDescription(getGainErrorFromErrorCode(errorcode)); } +TRUDecodingError_t getTRUDecodingErrorFromErrorCode(unsigned int errorcode) +{ + switch (errorcode) { + case 0: + return TRUDecodingError_t::TRU_INDEX_INVALID; + case 1: + return TRUDecodingError_t::PATCH_INDEX_INVALID; + case 2: + return TRUDecodingError_t::FASTOR_INDEX_INVALID; + default: + return TRUDecodingError_t::UNKNOWN_ERROR; + } +} + +const char* getTRUDecodingErrorName(TRUDecodingError_t errortype) +{ + switch (errortype) { + case TRUDecodingError_t::TRU_INDEX_INVALID: + return "TRUIndexInvalid"; + case TRUDecodingError_t::PATCH_INDEX_INVALID: + return "PatchIndexInvalid"; + case TRUDecodingError_t::FASTOR_INDEX_INVALID: + return "FastORIndexInvalid"; + default: + return "UnknownError"; + } +} + +const char* getTRUDecodingErrorName(unsigned int errorcode) +{ + return getTRUDecodingErrorName(getTRUDecodingErrorFromErrorCode(errorcode)); +} + +const char* getTRUDecodingErrorTitle(TRUDecodingError_t errortype) +{ + switch (errortype) { + case TRUDecodingError_t::TRU_INDEX_INVALID: + return "TRU index invalid"; + case TRUDecodingError_t::PATCH_INDEX_INVALID: + return "Patch index invalid"; + case TRUDecodingError_t::FASTOR_INDEX_INVALID: + return "FastOR index invalid"; + default: + return "Unknown error"; + } +} + +const char* getTRUDecodingErrorTitle(unsigned int errortype) +{ + return getTRUDecodingErrorTitle(getTRUDecodingErrorFromErrorCode(errortype)); +} + +const char* getTRUDecodingErrorErrorDescription(TRUDecodingError_t errortype) +{ + switch (errortype) { + case TRUDecodingError_t::TRU_INDEX_INVALID: + return "TRU index is invalid"; + case TRUDecodingError_t::PATCH_INDEX_INVALID: + return "Patch index is invalid"; + case TRUDecodingError_t::FASTOR_INDEX_INVALID: + return "FastOR index is invalid"; + default: + return "Unknown error"; + } +} + +const char* getTRUDecodingErrorErrorDescription(unsigned int errorcode) +{ + return getTRUDecodingErrorErrorDescription(getTRUDecodingErrorFromErrorCode(errorcode)); +} + } // namespace reconstructionerrors } // namespace emcal diff --git a/Detectors/EMCAL/reconstruction/src/TRUDataHandler.cxx b/Detectors/EMCAL/reconstruction/src/TRUDataHandler.cxx new file mode 100644 index 0000000000000..d6d9bd3535d5c --- /dev/null +++ b/Detectors/EMCAL/reconstruction/src/TRUDataHandler.cxx @@ -0,0 +1,67 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include "EMCALReconstruction/TRUDataHandler.h" + +using namespace o2::emcal; + +TRUDataHandler::TRUDataHandler() +{ + reset(); +} + +void TRUDataHandler::reset() +{ + mTRUIndex = -1; + mL0Fired = false; + mL0Time = -1; + std::fill(mPatchTimes.begin(), mPatchTimes.end(), UCHAR_MAX); +} + +void TRUDataHandler::printStream(std::ostream& stream) const +{ + std::string patchstring; + for (auto index = 0; index < mPatchTimes.size(); index++) { + if (hasPatch(index)) { + if (patchstring.length()) { + patchstring += ", "; + } + patchstring += std::to_string(index); + } + } + if (!patchstring.length()) { + patchstring = "-"; + } + stream << "TRU: " << static_cast(mTRUIndex) << ", time " << static_cast(mL0Time) << ", fired: " << (mL0Fired ? "yes" : "no") << ", patches: " << patchstring; +} + +TRUDataHandler::PatchIndexException::PatchIndexException(int8_t index) : mIndex(index), mMessage() +{ + mMessage = "Invalid patch index " + std::to_string(index); +} + +void TRUDataHandler::PatchIndexException::printStream(std::ostream& stream) const +{ + stream << what(); +} + +std::ostream& o2::emcal::operator<<(std::ostream& stream, const TRUDataHandler& data) +{ + data.printStream(stream); + return stream; +} + +std::ostream& o2::emcal::operator<<(std::ostream& stream, const TRUDataHandler::PatchIndexException& error) +{ + error.printStream(stream); + return stream; +} \ No newline at end of file diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h index a90a0f1718397..78436eedfd522 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RawToCellConverterSpec.h @@ -20,10 +20,12 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" #include "DataFormatsEMCAL/Cell.h" +#include "DataFormatsEMCAL/CompressedTriggerData.h" #include "DataFormatsEMCAL/TriggerRecord.h" #include "Headers/DataHeader.h" #include "EMCALBase/Geometry.h" #include "EMCALBase/Mapper.h" +#include "EMCALBase/TriggerMappingV2.h" #include "EMCALReconstruction/CaloRawFitter.h" #include "EMCALReconstruction/RawReaderMemory.h" #include "EMCALReconstruction/RecoContainer.h" @@ -37,26 +39,91 @@ namespace emcal { class AltroDecoderError; +class Channel; class MinorAltroDecodingError; class RawDecodingError; +class FastORIndexException; +class TRUIndexException; namespace reco_workflow { /// \class RawToCellConverterSpec -/// \brief Coverter task for Raw data to EMCAL cells +/// \brief Coverter task for Raw data to EMCAL cells and trigger objects /// \author Hadi Hassan , Oak Ridge National Laboratory +/// \author Markus Fasel , Oak Ridge National Laboratory +/// \ingroup EMCALworkflow /// \since December 10, 2019 +//// +/// General reconstruction task of EMCAL raw data of FEC and trigger sources, running during the synchronous +/// reconstruction. The task decodees pages from ALTRO, Fake ALTRO and STU sources, and mergees the data according +/// to events (triggers). The data is then further processed based on the origin of the data: /// +/// - in case of FEC data (cells or LEDMONS) a raw fit is performed, and data from high- and low-gain channels are +/// merged, always preferring the high-gain data if not saturated (better resolution) +/// - in case of Fake ALTRO data (TRU) the L0 timesums, trigger patches and TRU information are reconstructed. For +/// the trigger patches a small peak finder selects the time sample with the max. patch energy. For the L0 timesums +/// a fixed L0 time (8) is used for all event types +/// +/// FEC and trigger information are ordered according to events and streamed to their output buffers, where corresponding +/// trigger records mark ranges in the buffer belonging to the same trigger. Tasks subscribing to outputs from this +/// task must always subscribe to teh trigger records in addition. +/// +/// Several components of the task (raw parsing, ALTRO decoding, channel mapping and geometry, raw fit) can end in error +/// states, particularly due to unexpected data. Error handling is performed internally at different stages. Errors are +/// cathegoriezed as major or minor errors, where major errors prevent decoding the page while minor errors only lead +/// to loss of certain segments. For monitoring tasks must subscribe to EMC/DECODERERR. +/// +/// In order to guarantee data consistency a link checker compares the links contributing to data from a certain trigger +/// to the links activated in the DCS. If not all links are present the timeframe is discarded. In order to switch off +/// that feature the option --no-checkactivelinks must be activated. +/// +/// Inputs: +/// | Input spec | Optional | CCDB | Purpose | +/// |----------------------|----------|------|----------------------------------------------| +/// | EMC/RAWDATA | no | no | EMCAL raw data | +/// | FLP/DISTSUBTIMEFRAME | yes | no | Message send when no data was received in TF | +/// | EMC/RECOPARAM | no | yes | Reconstruction parameters | +/// | EMC/FEEDCS | no | yes | FEE DCS information | +/// +/// Outputs: +/// | Input spec | Subspec (default) | Optional | Purpose | +/// |----------------------|-------------------|-----------|----------------------------------------------------| +/// | EMC/CELLS | 1 | no | EMCAL cell (tower) data | +/// | EMC/CELLSTRGR | 1 | no | Trigger records related to cell data | +/// | EMC/DECODERERR | 1 | yes | Decoder errors (for QC), if enabled | +/// | EMC/TRUS | 1 | yes | TRU information, if trigger reconstruction enabled | +/// | EMC/TRUSTRGR | 1 | yes | Trigger reconrds related to TRU information | +/// | EMC/PATCHES | 1 | yes | Trigger patches, if trigger reconstruction enabled | +/// | EMC/PATCHESTRGR | 1 | yes | Trigger reconrds related to trigger patches | +/// | EMC/FASTORS | 1 | yes | L0 timesums, if trigger reconstruction enabled | +/// | EMC/FASTORSTRGR | 1 | yes | Trigger reconrds related to L0 timesums | +/// +/// Workflow options (via --EMCALRawToCellConverterSpec ...): +/// | Option | Default | Possible values | Purpose | +/// |---------------------|---------|-----------------|------------------------------------------------| +/// | fitmethod | gamma2 | gamma2,standard | Raw fit method | +/// | maxmessage | 100 | any int | Max. amount of error messages on infoLogger | +/// | printtrailer | false | set (bool) | Print RCU trailer (for debugging) | +/// | no-mergeHGLG | false | set (bool) | Do not merge HG and LG channels for same tower | +/// | no-checkactivelinks | false | set (bool) | Do not check for active links per BC | +/// | no-evalpedestal | false | set (bool) | Disable pedestal evaluation | +/// +/// Global switches of the EMCAL reco workflow related to the RawToCellConverter: +/// | Option | Default | Purpose | +/// | -------------------------------|---------|-----------------------------------------------| +/// | disable-decoding-errors | false | Disable sending decoding errors | +/// | disable-trigger-reconstruction | false | Disable trigger reconstruction | +/// | ignore-dist-stf | false | disable subscribing to FLP/DISTSUBTIMEFRAME/0 | class RawToCellConverterSpec : public framework::Task { public: /// \brief Constructor /// \param subspecification Output subspecification for parallel running on multiple nodes /// \param hasDecodingErrors Option to swich on/off creating raw decoding error objects for later monitoring - /// \param loadRecoParamsFromCCDB Option to load the RecoParams from the CCDB + /// \param hasTriggerReconstruction Perform trigger reconstruction and add trigger-related outputs /// \param calibhandler Calibration object handler - RawToCellConverterSpec(int subspecification, bool hasDecodingErrors, std::shared_ptr calibhandler) : framework::Task(), mSubspecification(subspecification), mCreateRawDataErrors(hasDecodingErrors), mCalibHandler(calibhandler){}; + RawToCellConverterSpec(int subspecification, bool hasDecodingErrors, bool hasTriggerReconstruction, std::shared_ptr calibhandler) : framework::Task(), mSubspecification(subspecification), mCreateRawDataErrors(hasDecodingErrors), mDoTriggerReconstruction(hasTriggerReconstruction), mCalibHandler(calibhandler){}; /// \brief Destructor ~RawToCellConverterSpec() override; @@ -88,7 +155,12 @@ class RawToCellConverterSpec : public framework::Task mMaxErrorMessages = maxMessages; } - void setNoiseThreshold(int thresold) { mNoiseThreshold = thresold; } + /// \brief Set noise threshold for gain type errors + /// \param threshold Noise threshold + void setNoiseThreshold(int threshold) { mNoiseThreshold = threshold; } + + /// \brief Get the noise threshold for gain type errors + /// \return Noise threshold int getNoiseThreshold() const { return mNoiseThreshold; } /// \brief Set ID of the subspecification @@ -170,6 +242,32 @@ class RawToCellConverterSpec : public framework::Task int mRowShifted = -1; /// << shifted row of the module (cell-case) }; + /// \struct CellTimeCorrection + /// \brief Correction for cell time + struct CellTimeCorrection { + double mTimeShift; ///< Constant time shift + int mBcMod4; ///< BC-dependent shift + + /// \brief Get the corrected cell time + /// \param rawtime Raw time from fit + /// \return Corrected time + /// + /// The time is corrected for an average shift and the BC phase + double getCorrectedTime(double rawtime) const { return rawtime - mTimeShift - 25. * mBcMod4; } + }; + + /// \struct LocalPosition + /// \brief Position in the supermodule coordinate system + struct LocalPosition { + uint16_t mSupermoduleID; ///< Supermodule ID + uint16_t mFeeID; ///< FEE ID + uint8_t mColumn; ///< Column in supermodule + uint8_t mRow; ///< Row in supermodule + }; + + using TRUContainer = std::vector; + using PatchContainer = std::vector; + /// \brief Check if the timeframe is empty /// \param ctx Processing context of timeframe /// \return True if the timeframe is empty, false otherwise @@ -193,14 +291,12 @@ class RawToCellConverterSpec : public framework::Task int bookEventCells(const gsl::span& cells, bool isLELDMON); /// \brief Send data to output channels - /// \param cells Container with output cells for timeframe - /// \param triggers Container with trigger records for timeframe - /// \param decodingErrors Container with decoding errors for timeframe + /// \param ctx target processing context /// /// Send data to all output channels for the given subspecification. The subspecification /// is determined on the fly in the run method and therefore used as parameter. Consumers /// must use wildcard subspecification via ConcreteDataTypeMatcher. - void sendData(framework::ProcessingContext& ctx, const std::vector& cells, const std::vector& triggers, const std::vector& decodingErrors) const; + void sendData(framework::ProcessingContext& ctx) const; /// \brief Get absolute Cell ID from column/row in supermodule /// \param supermoduleID Index of the supermodule @@ -217,27 +313,180 @@ class RawToCellConverterSpec : public framework::Task /// \throw ModuleIndexException in case of invalid module indices int geLEDMONAbsID(int supermoduleID, int module); + /// \brief Add FEE channel to the current evnet + /// \param currentEvent Event to add the channel to + /// \param currentchannel Current FEE channel + /// \param timeCorrector Handler for correction of the time + /// \param position Channel coordinates + /// \param chantype Channel type (High Gain, Low Gain, LEDMON) + /// + /// Performing a raw fit of the bunches in the channel to extract energy and time, and + /// adding them to the container for FEE data of the given event. + void addFEEChannelToEvent(o2::emcal::EventContainer& currentEvent, const o2::emcal::Channel& currentchannel, const CellTimeCorrection& timeCorrector, const LocalPosition& position, ChannelType_t chantype); + + /// \brief Add TRU channel to the event + /// \param currentEvent Event to add the channel to + /// \param currentchannel Current TRU channel + /// \param position Channel coordinates + /// + /// TRU channels are encoded in colums: + /// - 0-95: FastOR timeseries (time-reversed) + /// - 96-105: bitmap with fired patches and TRU header + /// The TRU index is taken from the hardware address, while the FastOR index is taken from the + /// column number. The TRU and patch times are taken from the time sample in which the corresponding + /// bit is found. + void addTRUChannelToEvent(o2::emcal::EventContainer& currentEvent, const o2::emcal::Channel& currentchannel, const LocalPosition& position); + + /// @brief Build L0 patches from FastOR time series and TRU data of the current event + /// @param currentevent Current event to process + /// @return Compressed patches + /// + /// Only reconstruct patches which were decoded as fired from the raw data. The patch energy and time + /// are calculated from the corresponding FastOR time series as the energy and time with the largest + /// patch energy extracted from all possible time integrals (see reconstructTriggerPatch) + std::tuple buildL0Patches(const EventContainer& currentevent) const; + + /// @brief Build L0 timesums with respect to a given L0 time + /// @param currentevent Current event with FastOR time series + /// @param l0time L0 time of the event + /// @return Container with time series + std::vector buildL0Timesums(const o2::emcal::EventContainer& currentevent, uint8_t l0time) const; + + /// \brief Reconstruct trigger patch energy and time from its FastOR time series + /// \param fastors FastORs contributing to the patch (only present) + /// \return Tuple with 0 - patch ADC, 1 - patch time + /// + /// For all possible combinations reconstruct the 4-time integral of the patches from + /// its contributing FastORs. The patch is reconstructed when the ADC reached its + /// maximum. The patch time is the start time of the 4-integral + std::tuple reconstructTriggerPatch(const gsl::span fastors) const; + + /// \brief Handling of mapper hardware address errors + /// \param error Exception raised by the mapper + /// \param ddlID DDL ID of the segment raising the exception + /// \param hwaddress Hardware address raising the exception + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. void handleAddressError(const Mapper::AddressNotFoundException& error, int ddlID, int hwaddress); + /// \brief Handler function for major ALTRO decoder errors + /// \param altroerror Exception raised by the ALTRO decoder + /// \param ddlID DDL ID of the segment raising the exception + /// \param hwaddress Hardware address raising the exception + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. void handleAltroError(const o2::emcal::AltroDecoderError& altroerror, int ddlID); + /// \brief Handler function for minor ALTRO errors + /// \param altroerror Minor errors created by the ALTRO decoder + /// \param ddlID DDL ID of the segment raising the exception + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. void handleMinorAltroError(const o2::emcal::MinorAltroDecodingError& altroerror, int ddlID); + /// \brief Handler function of mapper errors related to invalid DDL + /// \param error Exception raised by the mapper + /// \param feeID FEE ID (DDL ID) of the segment raising the exception + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. void handleDDLError(const MappingHandler::DDLInvalid& error, int feeID); - void handleGeometryError(const ModuleIndexException& e, int supermoduleID, int cellID, int hwaddress, ChannelType_t chantype); - + /// \brief Handler function of errors related to geometry (invalid supermodule / module/ tower ...) + /// \param error Geometry exception + /// \param supermoduleID Supermodule ID of the exception + /// \param cellID Cell (Tower) ID of the exception + /// \param hwaddress Hardware address raising the exception + /// \param chantype Channel type of the exception + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. + void handleGeometryError(const ModuleIndexException& error, int supermoduleID, int cellID, int hwaddress, ChannelType_t chantype); + + /// \brief Handler function of mapper errors related to invalid DDL + /// \param error Exception raised by the mapper + /// \param feeID FEE ID (DDL ID) of the segment raising the exception + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. void handleFitError(const o2::emcal::CaloRawFitter::RawFitterError_t& fiterror, int ddlID, int cellID, int hwaddress); - /// \brief handler function for gain type errors + /// \brief Handler function for gain type errors /// \param errortype Gain error type - /// \param ddlID ID of the DDL - /// \param hwaddress Hardware address + /// \param ddlID DDL ID of the segment raising the exception + /// \param hwaddress Hardware address raising the exception + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. void handleGainError(const o2::emcal::reconstructionerrors::GainError_t& errortype, int ddlID, int hwaddress); - void handlePageError(const RawDecodingError& e); - - void handleMinorPageError(const RawReaderMemory::MinorError& e); + /// \brief Handler function for raw page decoding errors (i.e. header/trailer corruptions) + /// \param error Raw page error + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. + void handlePageError(const RawDecodingError& error); + + /// \brief Handler function for minor raw page decoding errors (i.e. header/trailer corruptions) + /// \param error Raw page error + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. + void handleMinorPageError(const RawReaderMemory::MinorError& error); + + /// \brief Handler function for FastOR indexing errors + /// \param error FastOR index error + /// \param linkID DDL raising the exception + /// \param indexTRU TRU raising the exception + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. + void handleFastORErrors(const FastORIndexException& error, unsigned int linkID, unsigned int indexTRU); + + /// \brief Handler function patch index exception + /// \param error Patch index error + /// \param linkID DDL raising the exception + /// \param indexTRU TRU raising the exception + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. + void handlePatchError(const TRUDataHandler::PatchIndexException& error, unsigned int linkID, unsigned int indexTRU); + + /// \brief Handler function for TRU index exception + /// \param error TRU index error + /// \param linkID DDL raising the exception + /// \param hwaddress Hardware address of the channel raising the exception + /// + /// Errors are printed to the infoLogger until a user-defiened + /// threshold is reached. In case the export of decoder errors + /// is activated an error object with additional information is + /// produced. + void handleTRUIndexError(const TRUIndexException& error, unsigned int linkID, unsigned int hwaddress); header::DataHeader::SubSpecificationType mSubspecification = 0; ///< Subspecification for output channels int mNoiseThreshold = 0; ///< Noise threshold in raw fit @@ -249,24 +498,33 @@ class RawToCellConverterSpec : public framework::Task bool mPrintTrailer = false; ///< Print RCU trailer bool mDisablePedestalEvaluation = false; ///< Disable pedestal evaluation independent of settings in the RCU trailer bool mCreateRawDataErrors = false; ///< Create raw data error objects for monitoring + bool mDoTriggerReconstruction = false; ///< Do trigger reconstruction std::chrono::time_point mReferenceTime; ///< Reference time for muting messages Geometry* mGeometry = nullptr; ///! mCalibHandler; ///< Handler for calibration objects std::unique_ptr mMapper = nullptr; ///! mTriggerMapping; ///! mRawFitter; ///! mOutputCells; ///< Container with output cells - std::vector mOutputTriggerRecords; ///< Container with output cells + std::vector mOutputTriggerRecords; ///< Container with output trigger records for cells std::vector mOutputDecoderErrors; ///< Container with decoder errors + std::vector mOutputTRUs; ///< Compressed output TRU information + std::vector mOutputTRUTriggerRecords; ///< Container with trigger records for TRU data + std::vector mOutputPatches; ///< Compressed trigger patch information + std::vector mOutputPatchTriggerRecords; ///< Container with trigger records for Patch data + std::vector mOutputTimesums; ///< Compressed L0 timesum information + std::vector mOutputTimesumTriggerRecords; ///< Trigger records for L0 timesum }; /// \brief Creating DataProcessorSpec for the EMCAL Cell Converter Spec /// \param askDISTSTF Include input spec FLP/DISTSUBTIMEFRAME -/// \param loadRecoParamsFromCCDB Obtain reco params from the CCDB +/// \param disableDecodingErrors Obtain reco params from the CCDB +/// \param disableTriggerReconstruction Do not run trigger reconstruction /// \param subspecification Subspecification used in the output spec /// /// Refer to RawToCellConverterSpec::run for input and output specs -framework::DataProcessorSpec getRawToCellConverterSpec(bool askDISTSTF, bool disableDecodingError, int subspecification); +framework::DataProcessorSpec getRawToCellConverterSpec(bool askDISTSTF, bool disableDecodingError, bool disableTriggerReconstruction, int subspecification); } // namespace reco_workflow diff --git a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h index 1cc0544d3c61d..909e356297095 100644 --- a/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h +++ b/Detectors/EMCAL/workflow/include/EMCALWorkflow/RecoWorkflow.h @@ -55,6 +55,7 @@ enum struct OutputType { Digits, ///< EMCAL digits /// \param disableRootInput Disable reading from ROOT file (raw mode) /// \param disableRootOutput Disable writing ROOT files (sync reco) /// \param disableDecodingErrors Diable streaming raw decoding errors (async reco) +/// \param disableTriggerReconstruction Disable trigger reconstrction /// \return EMCAL reconstruction workflow for the configuration provided /// \ingroup EMCALwokflow framework::WorkflowSpec getWorkflow(bool propagateMC = true, @@ -66,7 +67,8 @@ framework::WorkflowSpec getWorkflow(bool propagateMC = true, std::string const& cfgOutput = "clusters", bool disableRootInput = false, bool disableRootOutput = false, - bool disableDecodingErrors = false); + bool disableDecodingErrors = false, + bool disableTriggerReconstruction = false); } // namespace reco_workflow } // namespace emcal diff --git a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx index ac09b842d9ab8..55f464644ab73 100644 --- a/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx +++ b/Detectors/EMCAL/workflow/src/RawToCellConverterSpec.cxx @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -31,6 +32,7 @@ #include "DetectorsRaw/RDHUtils.h" #include "EMCALBase/Geometry.h" #include "EMCALBase/Mapper.h" +#include "EMCALBase/TriggerMappingErrors.h" #include "EMCALCalib/FeeDCS.h" #include "EMCALReconstruction/CaloFitResults.h" #include "EMCALReconstruction/Bunch.h" @@ -75,6 +77,10 @@ void RawToCellConverterSpec::init(framework::InitContext& ctx) LOG(error) << "Failed to initialize mapper"; } + if (!mTriggerMapping) { + mTriggerMapping = std::make_unique(mGeometry); + } + auto fitmethod = ctx.options().get("fitmethod"); if (fitmethod == "standard") { LOG(info) << "Using standard raw fitter"; @@ -131,9 +137,15 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) mOutputCells.clear(); mOutputTriggerRecords.clear(); mOutputDecoderErrors.clear(); + mOutputTRUs.clear(); + mOutputTRUTriggerRecords.clear(); + mOutputPatches.clear(); + mOutputPatchTriggerRecords.clear(); + mOutputTimesums.clear(); + mOutputTimesumTriggerRecords.clear(); if (isLostTimeframe(ctx)) { - sendData(ctx, mOutputCells, mOutputTriggerRecords, mOutputDecoderErrors); + sendData(ctx); return; } @@ -216,6 +228,7 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) if (!currentEvent.getTriggerBits()) { currentEvent.setTriggerBits(triggerbits); } + CellTimeCorrection timeCorrector{timeshift, bcmod4}; if (feeID >= 40) { continue; // skip STU ddl @@ -268,68 +281,33 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) // Loop over all the channels int nBunchesNotOK = 0; for (auto& chan : decoder.getChannels()) { - int iRow, iCol; - ChannelType_t chantype; try { - iRow = map.getRow(chan.getHardwareAddress()); - iCol = map.getColumn(chan.getHardwareAddress()); - chantype = map.getChannelType(chan.getHardwareAddress()); + auto iRow = map.getRow(chan.getHardwareAddress()); + auto iCol = map.getColumn(chan.getHardwareAddress()); + auto chantype = map.getChannelType(chan.getHardwareAddress()); + LocalPosition channelPosition{iSM, feeID, iCol, iRow}; + switch (chantype) { + case o2::emcal::ChannelType_t::HIGH_GAIN: + case o2::emcal::ChannelType_t::LOW_GAIN: + addFEEChannelToEvent(currentEvent, chan, timeCorrector, channelPosition, chantype); + break; + case o2::emcal::ChannelType_t::LEDMON: + // Drop LEDMON reconstruction in case of physics triggers + if (triggerbits & o2::trigger::Cal) { + addFEEChannelToEvent(currentEvent, chan, timeCorrector, channelPosition, chantype); + } + break; + case o2::emcal::ChannelType_t::TRU: + addTRUChannelToEvent(currentEvent, chan, channelPosition); + break; + default: + LOG(error) << "Unknown channel type for HW address " << chan.getHardwareAddress(); + break; + } } catch (Mapper::AddressNotFoundException& ex) { handleAddressError(ex, feeID, chan.getHardwareAddress()); continue; } - - if (!(chantype == o2::emcal::ChannelType_t::HIGH_GAIN || chantype == o2::emcal::ChannelType_t::LOW_GAIN || chantype == o2::emcal::ChannelType_t::LEDMON)) { - continue; - } - - // Drop LEDMON reconstruction in case of physics triggers - if (chantype == o2::emcal::ChannelType_t::LEDMON && !(triggerbits & o2::trigger::Cal)) { - continue; - } - - int CellID = -1; - bool isLowGain = false; - try { - if (chantype == o2::emcal::ChannelType_t::HIGH_GAIN || chantype == o2::emcal::ChannelType_t::LOW_GAIN) { - // high- / low-gain cell - CellID = getCellAbsID(iSM, iCol, iRow); - isLowGain = chantype == o2::emcal::ChannelType_t::LOW_GAIN; - } else { - CellID = geLEDMONAbsID(iSM, iCol); // Module index encoded in colum for LEDMONs - isLowGain = iRow == 0; // For LEDMONs gain type is encoded in the row (0 - low gain, 1 - high gain) - } - } catch (ModuleIndexException& e) { - handleGeometryError(e, iSM, CellID, chan.getHardwareAddress(), chantype); - continue; - } - - // define the conatiner for the fit results, and perform the raw fitting using the stadnard raw fitter - CaloFitResults fitResults; - try { - fitResults = mRawFitter->evaluate(chan.getBunches()); - // Prevent negative entries - we should no longer get here as the raw fit usually will end in an error state - if (fitResults.getAmp() < 0) { - fitResults.setAmp(0.); - } - if (fitResults.getTime() < 0) { - fitResults.setTime(0.); - } - // apply correction for bc mod 4 - double celltime = fitResults.getTime() - timeshift - 25 * bcmod4; - double amp = fitResults.getAmp() * o2::emcal::constants::EMCAL_ADCENERGY; - if (isLowGain) { - amp *= o2::emcal::constants::EMCAL_HGLGFACTOR; - } - if (chantype == o2::emcal::ChannelType_t::LEDMON) { - // Mark LEDMONs as HIGH_GAIN/LOW_GAIN for gain type merging - will be flagged as LEDMON later when pushing to the output container - currentEvent.setLEDMONCell(CellID, amp, celltime, isLowGain ? o2::emcal::ChannelType_t::LOW_GAIN : o2::emcal::ChannelType_t::HIGH_GAIN, chan.getHardwareAddress(), feeID, mMergeLGHG); - } else { - currentEvent.setCell(CellID, amp, celltime, chantype, chan.getHardwareAddress(), feeID, mMergeLGHG); - } - } catch (CaloRawFitter::RawFitterError_t& fiterror) { - handleFitError(fiterror, feeID, CellID, chan.getHardwareAddress()); - } } } catch (o2::emcal::MappingHandler::DDLInvalid& ddlerror) { // Unable to catch mapping @@ -400,10 +378,31 @@ void RawToCellConverterSpec::run(framework::ProcessingContext& ctx) } LOG(debug) << "Next event [Orbit " << interaction.orbit << ", BC (" << interaction.bc << "]: Accepted " << ncellsEvent << " cells and " << nLEDMONsEvent << " LEDMONS"; mOutputTriggerRecords.emplace_back(interaction, currentevent.getTriggerBits(), eventstart, ncellsEvent + nLEDMONsEvent); + + // Add trigger data + if (mDoTriggerReconstruction) { + auto [trus, patches] = buildL0Patches(currentevent); + LOG(debug) << "Found " << patches.size() << " L0 patches from " << trus.size() << " TRUs"; + auto trusstart = mOutputTRUs.size(); + std::copy(trus.begin(), trus.end(), std::back_inserter(mOutputTRUs)); + mOutputTRUTriggerRecords.emplace_back(interaction, currentevent.getTriggerBits(), trusstart, trus.size()); + auto patchesstart = mOutputPatches.size(); + std::copy(patches.begin(), patches.end(), std::back_inserter(mOutputPatches)); + mOutputPatchTriggerRecords.emplace_back(interaction, currentevent.getTriggerBits(), patchesstart, patches.size()); + // For L0 timesums use fixed time, across TRUs and triggers, determined from the patch time QC + // average found to be - will be made configurable + auto timesumsstart = mOutputTimesums.size(); + auto timesums = buildL0Timesums(currentevent, 8); + std::copy(timesums.begin(), timesums.end(), std::back_inserter(mOutputTimesums)); + mOutputTimesumTriggerRecords.emplace_back(interaction, currentevent.getTriggerBits(), timesumsstart, timesums.size()); + } } LOG(info) << "[EMCALRawToCellConverter - run] Writing " << mOutputCells.size() << " cells from " << mOutputTriggerRecords.size() << " events ..."; - sendData(ctx, mOutputCells, mOutputTriggerRecords, mOutputDecoderErrors); + if (mDoTriggerReconstruction) { + LOG(info) << "[EMCALRawToCellConverter - run] Writing " << mOutputTRUs.size() << " TRU infos and " << mOutputPatches.size() << " trigger patches and " << mOutputTimesums.size() << " timesums from " << mOutputTRUTriggerRecords.size() << " events ..."; + } + sendData(ctx); } void RawToCellConverterSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& matcher, void* obj) @@ -438,7 +437,7 @@ bool RawToCellConverterSpec::isLostTimeframe(framework::ProcessingContext& ctx) if (payloadSize == 0) { auto maxWarn = o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef; if (++contDeadBeef <= maxWarn) { - LOGP(alarm, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF{}", + LOGP(warning, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF{}", dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, payloadSize, contDeadBeef == maxWarn ? fmt::format(". {} such inputs in row received, stopping reporting", contDeadBeef) : ""); } @@ -449,6 +448,213 @@ bool RawToCellConverterSpec::isLostTimeframe(framework::ProcessingContext& ctx) return false; } +void RawToCellConverterSpec::addFEEChannelToEvent(o2::emcal::EventContainer& currentEvent, const o2::emcal::Channel& currentchannel, const CellTimeCorrection& timeCorrector, const LocalPosition& position, ChannelType_t chantype) +{ + int CellID = -1; + bool isLowGain = false; + try { + if (chantype == o2::emcal::ChannelType_t::HIGH_GAIN || chantype == o2::emcal::ChannelType_t::LOW_GAIN) { + // high- / low-gain cell + CellID = getCellAbsID(position.mSupermoduleID, position.mColumn, position.mRow); + isLowGain = chantype == o2::emcal::ChannelType_t::LOW_GAIN; + } else { + CellID = geLEDMONAbsID(position.mSupermoduleID, position.mColumn); // Module index encoded in colum for LEDMONs + isLowGain = position.mRow == 0; // For LEDMONs gain type is encoded in the row (0 - low gain, 1 - high gain) + } + } catch (ModuleIndexException& e) { + handleGeometryError(e, position.mSupermoduleID, CellID, currentchannel.getHardwareAddress(), chantype); + return; + } + + // define the conatiner for the fit results, and perform the raw fitting using the stadnard raw fitter + CaloFitResults fitResults; + try { + fitResults = mRawFitter->evaluate(currentchannel.getBunches()); + // Prevent negative entries - we should no longer get here as the raw fit usually will end in an error state + if (fitResults.getAmp() < 0) { + fitResults.setAmp(0.); + } + if (fitResults.getTime() < 0) { + fitResults.setTime(0.); + } + // apply correction for bc mod 4 + double celltime = timeCorrector.getCorrectedTime(fitResults.getTime()); + double amp = fitResults.getAmp() * o2::emcal::constants::EMCAL_ADCENERGY; + if (isLowGain) { + amp *= o2::emcal::constants::EMCAL_HGLGFACTOR; + } + if (chantype == o2::emcal::ChannelType_t::LEDMON) { + // Mark LEDMONs as HIGH_GAIN/LOW_GAIN for gain type merging - will be flagged as LEDMON later when pushing to the output container + currentEvent.setLEDMONCell(CellID, amp, celltime, isLowGain ? o2::emcal::ChannelType_t::LOW_GAIN : o2::emcal::ChannelType_t::HIGH_GAIN, currentchannel.getHardwareAddress(), position.mFeeID, mMergeLGHG); + } else { + currentEvent.setCell(CellID, amp, celltime, chantype, currentchannel.getHardwareAddress(), position.mFeeID, mMergeLGHG); + } + } catch (CaloRawFitter::RawFitterError_t& fiterror) { + handleFitError(fiterror, position.mFeeID, CellID, currentchannel.getHardwareAddress()); + } +} + +void RawToCellConverterSpec::addTRUChannelToEvent(o2::emcal::EventContainer& currentEvent, const o2::emcal::Channel& currentchannel, const LocalPosition& position) +{ + try { + auto tru = mTriggerMapping->getTRUIndexFromOnlineHardareAddree(currentchannel.getHardwareAddress(), position.mFeeID, position.mSupermoduleID); + if (position.mColumn >= 96 && position.mColumn <= 105) { + auto& trudata = currentEvent.getTRUData(tru); + // Trigger patch information encoded columns 95-105 + for (auto& bunch : currentchannel.getBunches()) { + LOG(debug) << "Found bunch of length " << static_cast(bunch.getBunchLength()) << " with start time " << static_cast(bunch.getStartTime()) << " (column " << static_cast(position.mColumn) << ")"; + auto l0time = bunch.getStartTime(); + int isample = 0; + for (auto& adc : bunch.getADC()) { + // patch word might be in any of the samples, need to check all of them + // in case of colum 105 the first 6 bits are the patch word, the remaining 4 bits are the header word + if (adc == 0) { + isample++; + continue; + } + if (position.mColumn == 105) { + std::bitset<6> patchBits(adc & 0x3F); + std::bitset<4> headerbits((adc >> 6) & 0xF); + for (auto localindex = 0; localindex < patchBits.size(); localindex++) { + if (patchBits.test(localindex)) { + auto globalindex = (position.mColumn - 96) * 10 + localindex; + LOG(debug) << "Found patch with index " << globalindex << " in sample " << isample; + // std::cout << "Found patch with index " << globalindex << " in sample " << isample << " (" << (bunch.getStartTime() - isample) << ")" << std::endl; + try { + trudata.setPatch(globalindex, bunch.getStartTime() - isample); + } catch (TRUDataHandler::PatchIndexException& e) { + handlePatchError(e, position.mFeeID, tru); + } + } + } + if (headerbits.test(2)) { + LOG(debug) << "TRU " << tru << ": Found TRU fired (" << tru << ") in sample " << isample; + // std::cout << "TRU " << tru << ": Found TRU fired (" << tru << ") in sample " << isample << " (" << (bunch.getStartTime() - isample) << ")" << std::endl; + trudata.setFired(true); + trudata.setL0time(bunch.getStartTime() - isample); + } + } else { + std::bitset<10> patchBits(adc & 0x3FF); + for (auto localindex = 0; localindex < patchBits.size(); localindex++) { + if (patchBits.test(localindex)) { + auto globalindex = (position.mColumn - 96) * 10 + localindex; + LOG(debug) << "TRU " << tru << ": Found patch with index " << globalindex << " in sample " << isample; + // std::cout << "TRU " << tru << ": Found patch with index " << globalindex << " in sample " << isample << " (" << (bunch.getStartTime() - isample) << ")" << std::endl; + try { + trudata.setPatch(globalindex, bunch.getStartTime() - isample); + } catch (TRUDataHandler::PatchIndexException& e) { + handlePatchError(e, position.mFeeID, tru); + } + } + } + } + isample++; + } + } + } else { + try { + auto absFastOR = mTriggerMapping->getAbsFastORIndexFromIndexInTRU(tru, position.mColumn); + for (auto& bunch : currentchannel.getBunches()) { + // FastOR data reversed internally (positive in time direction) + // -> Start time marks the first timebin, consequently it must be also reversed. + // std::cout << "Adding non-reversed FastOR time series for FastOR " << absFastOR << " (TRU " << tru << ", index " << static_cast(position.mColumn) << ") with start time " << static_cast(bunch.getStartTime()) << " (reversed " << bunch.getStartTime() + 1 - bunch.getADC().size() << "): "; + // for (auto adc : bunch.getADC()) { + // std::cout << adc << ", "; + //} + // std::cout << std::endl; + currentEvent.setFastOR(absFastOR, bunch.getStartTime(), bunch.getADC()); + } + } catch (FastORIndexException& e) { + handleFastORErrors(e, position.mFeeID, tru); + } + } + } catch (TRUIndexException& e) { + handleTRUIndexError(e, position.mFeeID, currentchannel.getHardwareAddress()); + } +} + +std::tuple RawToCellConverterSpec::buildL0Patches(const EventContainer& currentevent) const +{ + LOG(debug) << "Reconstructing patches for Orbit " << currentevent.getInteractionRecord().orbit << ", BC " << currentevent.getInteractionRecord().bc; + TRUContainer eventTRUs; + PatchContainer eventPatches; + auto& fastOrs = currentevent.getTimeSeriesContainer(); + std::set foundFastOrs; + for (auto fastor : fastOrs) { + foundFastOrs.insert(fastor.first); + } + for (std::size_t itru = 0; itru < TriggerMappingV2::ALLTRUS; itru++) { + auto& currenttru = currentevent.readTRUData(itru); + if (!currenttru.hasAnyPatch()) { + continue; + } + auto l0time = currenttru.getL0time(); + LOG(debug) << "Found patches in TRU " << itru << ", fired: " << (currenttru.isFired() ? "yes" : "no") << ", L0 time " << static_cast(l0time); + uint8_t npatches = 0; + for (auto ipatch = 0; ipatch < o2::emcal::TriggerMappingV2::PATCHESINTRU; ipatch++) { + if (currenttru.hasPatch(ipatch)) { + auto patchtime = currenttru.getPatchTime(ipatch); + LOG(debug) << "Found patch " << ipatch << " in TRU " << itru << " with time " << static_cast(patchtime); + auto fastorStart = mTriggerMapping->getAbsFastORIndexFromIndexInTRU(itru, ipatch); + auto fastORs = mTriggerMapping->getFastORIndexFromL0Index(itru, ipatch, 4); + std::array fastors; + std::fill(fastors.begin(), fastors.end(), nullptr); + int indexFastorInTRU = 0; + for (auto fastor : fastORs) { + auto [truID, fastorTRU] = mTriggerMapping->getTRUFromAbsFastORIndex(fastor); + // std::cout << "Patch has abs FastOR " << fastor << " -> " << fastorTRU << " (in TRU)" << std::endl; + auto timeseriesFound = fastOrs.find(fastor); + if (timeseriesFound != fastOrs.end()) { + LOG(debug) << "Adding FastOR (" << indexFastorInTRU << ") with index " << fastor << " to patch"; + fastors[indexFastorInTRU] = &(timeseriesFound->second); + indexFastorInTRU++; + } + } + auto [patchADC, recpatchtime] = reconstructTriggerPatch(fastors); + // Correct for bit shift 12->10 bits due to ALTRO format + patchADC = patchADC << 2; + LOG(debug) << "Reconstructed patch at index " << ipatch << " with peak time " << static_cast(recpatchtime) << " (time sample " << static_cast(patchtime) << ") and energy " << patchADC; + eventPatches.push_back({static_cast(itru), static_cast(ipatch), patchtime, patchADC}); + } + } + eventTRUs.push_back({static_cast(itru), static_cast(l0time), currenttru.isFired(), npatches}); + } + return std::make_tuple(eventTRUs, eventPatches); +} + +std::vector RawToCellConverterSpec::buildL0Timesums(const o2::emcal::EventContainer& currentevent, uint8_t l0time) const +{ + std::vector timesums; + for (const auto& [fastorID, timeseries] : currentevent.getTimeSeriesContainer()) { + timesums.push_back({fastorID, static_cast(timeseries.calculateL1TimeSum(l0time) << 2)}); + } + return timesums; +} + +std::tuple RawToCellConverterSpec::reconstructTriggerPatch(const gsl::span fastors) const +{ + constexpr size_t INTEGRATE_SAMPLES = 4, + MAX_SAMPLES = 12; + double maxpatchenergy = 0; + uint8_t foundtime = 0; + for (size_t itime = 0; itime < MAX_SAMPLES - INTEGRATE_SAMPLES; ++itime) { + double currenttimesum = 0; + for (size_t isample = 0; isample < INTEGRATE_SAMPLES; ++isample) { + for (auto ifastor = 0; ifastor < fastors.size(); ++ifastor) { + if (fastors[ifastor]) { + currenttimesum += fastors[ifastor]->getADCs()[itime + isample]; + } + } + } + if (currenttimesum > maxpatchenergy) { + maxpatchenergy = currenttimesum; + foundtime = itime; + } + } + + return std::make_tuple(maxpatchenergy, foundtime); +} + int RawToCellConverterSpec::bookEventCells(const gsl::span& cells, bool isLELDMON) { double noiseThresholLGnoHG = RecoParam::Instance().getNoiseThresholdLGnoHG(); @@ -719,14 +925,70 @@ void RawToCellConverterSpec::handleMinorPageError(const RawReaderMemory::MinorEr } } -void RawToCellConverterSpec::sendData(framework::ProcessingContext& ctx, const std::vector& cells, const std::vector& triggers, const std::vector& decodingErrors) const +void RawToCellConverterSpec::handleFastORErrors(const FastORIndexException& e, unsigned int linkID, unsigned int indexTRU) +{ + if (mCreateRawDataErrors) { + mOutputDecoderErrors.emplace_back(linkID, ErrorTypeFEE::ErrorSource_t::TRU_ERROR, reconstructionerrors::getErrorCodeFromTRUDecodingError(reconstructionerrors::TRUDecodingError_t::TRU_INDEX_INVALID), indexTRU, -1); + } + if (mNumErrorMessages < mMaxErrorMessages) { + LOG(warning) << " TRU decoding: " << e.what() << " in FEE ID " << linkID << ", TRU " << indexTRU; + mNumErrorMessages++; + if (mNumErrorMessages == mMaxErrorMessages) { + LOG(warning) << "Max. amount of error messages (" << mMaxErrorMessages << " reached, further messages will be suppressed"; + } + } else { + mErrorMessagesSuppressed++; + } +} + +void RawToCellConverterSpec::handlePatchError(const TRUDataHandler::PatchIndexException& e, unsigned int linkID, unsigned int indexTRU) +{ + if (mCreateRawDataErrors) { + mOutputDecoderErrors.emplace_back(linkID, ErrorTypeFEE::ErrorSource_t::TRU_ERROR, reconstructionerrors::getErrorCodeFromTRUDecodingError(reconstructionerrors::TRUDecodingError_t::PATCH_INDEX_INVALID), indexTRU, -1); + } + if (mNumErrorMessages < mMaxErrorMessages) { + LOG(warning) << " TRU decoding: " << e.what() << " in FEE ID " << linkID << ", TRU " << indexTRU; + mNumErrorMessages++; + if (mNumErrorMessages == mMaxErrorMessages) { + LOG(warning) << "Max. amount of error messages (" << mMaxErrorMessages << " reached, further messages will be suppressed"; + } + } else { + mErrorMessagesSuppressed++; + } +} + +void RawToCellConverterSpec::handleTRUIndexError(const TRUIndexException& e, unsigned int linkID, unsigned int hwaddress) +{ + if (mCreateRawDataErrors) { + mOutputDecoderErrors.emplace_back(linkID, ErrorTypeFEE::ErrorSource_t::TRU_ERROR, reconstructionerrors::getErrorCodeFromTRUDecodingError(reconstructionerrors::TRUDecodingError_t::PATCH_INDEX_INVALID), e.getTRUIndex(), hwaddress); + } + if (mNumErrorMessages < mMaxErrorMessages) { + LOG(warning) << " TRU decoding: " << e.what() << " in FEE ID " << linkID << ", TRU " << e.getTRUIndex() << "(hardware address: " << hwaddress << ")"; + mNumErrorMessages++; + if (mNumErrorMessages == mMaxErrorMessages) { + LOG(warning) << "Max. amount of error messages (" << mMaxErrorMessages << " reached, further messages will be suppressed"; + } + } else { + mErrorMessagesSuppressed++; + } +} + +void RawToCellConverterSpec::sendData(framework::ProcessingContext& ctx) const { constexpr auto originEMC = o2::header::gDataOriginEMC; - ctx.outputs().snapshot(framework::Output{originEMC, "CELLS", mSubspecification}, cells); - ctx.outputs().snapshot(framework::Output{originEMC, "CELLSTRGR", mSubspecification}, triggers); + ctx.outputs().snapshot(framework::Output{originEMC, "CELLS", mSubspecification}, mOutputCells); + ctx.outputs().snapshot(framework::Output{originEMC, "CELLSTRGR", mSubspecification}, mOutputTriggerRecords); if (mCreateRawDataErrors) { - LOG(debug) << "Sending " << decodingErrors.size() << " decoding errors"; - ctx.outputs().snapshot(framework::Output{originEMC, "DECODERERR", mSubspecification}, decodingErrors); + LOG(debug) << "Sending " << mOutputDecoderErrors.size() << " decoding errors"; + ctx.outputs().snapshot(framework::Output{originEMC, "DECODERERR", mSubspecification}, mOutputDecoderErrors); + } + if (mDoTriggerReconstruction) { + ctx.outputs().snapshot(framework::Output{originEMC, "TRUS", mSubspecification}, mOutputTRUs); + ctx.outputs().snapshot(framework::Output{originEMC, "TRUSTRGR", mSubspecification}, mOutputTRUTriggerRecords); + ctx.outputs().snapshot(framework::Output{originEMC, "PATCHES", mSubspecification}, mOutputPatches); + ctx.outputs().snapshot(framework::Output{originEMC, "PATCHESTRGR", mSubspecification}, mOutputPatchTriggerRecords); + ctx.outputs().snapshot(framework::Output{originEMC, "FASTORS", mSubspecification}, mOutputTimesums); + ctx.outputs().snapshot(framework::Output{originEMC, "FASTORSTRGR", mSubspecification}, mOutputTimesumTriggerRecords); } } @@ -739,7 +1001,7 @@ RawToCellConverterSpec::ModuleIndexException::ModuleIndexException(int moduleInd RawToCellConverterSpec::ModuleIndexException::ModuleIndexException(int moduleIndex) : mModuleType(ModuleType_t::LEDMON_MODULE), mIndex(moduleIndex) {} -o2::framework::DataProcessorSpec o2::emcal::reco_workflow::getRawToCellConverterSpec(bool askDISTSTF, bool disableDecodingErrors, int subspecification) +o2::framework::DataProcessorSpec o2::emcal::reco_workflow::getRawToCellConverterSpec(bool askDISTSTF, bool disableDecodingErrors, bool disableTriggerReconstruction, int subspecification) { constexpr auto originEMC = o2::header::gDataOriginEMC; std::vector outputs; @@ -749,6 +1011,14 @@ o2::framework::DataProcessorSpec o2::emcal::reco_workflow::getRawToCellConverter if (!disableDecodingErrors) { outputs.emplace_back(originEMC, "DECODERERR", subspecification, o2::framework::Lifetime::Timeframe); } + if (!disableTriggerReconstruction) { + outputs.emplace_back(originEMC, "TRUS", subspecification, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(originEMC, "TRUSTRGR", subspecification, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(originEMC, "PATCHES", subspecification, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(originEMC, "PATCHESTRGR", subspecification, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(originEMC, "FASTORS", subspecification, o2::framework::Lifetime::Timeframe); + outputs.emplace_back(originEMC, "FASTORSTRGR", subspecification, o2::framework::Lifetime::Timeframe); + } std::vector inputs{{"stf", o2::framework::ConcreteDataTypeMatcher{originEMC, o2::header::gDataDescriptionRawData}, o2::framework::Lifetime::Timeframe}}; if (askDISTSTF) { @@ -764,7 +1034,7 @@ o2::framework::DataProcessorSpec o2::emcal::reco_workflow::getRawToCellConverter "EMCALRawToCellConverterSpec", inputs, outputs, - o2::framework::adaptFromTask(subspecification, !disableDecodingErrors, calibhandler), + o2::framework::adaptFromTask(subspecification, !disableDecodingErrors, !disableTriggerReconstruction, calibhandler), o2::framework::Options{ {"fitmethod", o2::framework::VariantType::String, "gamma2", {"Fit method (standard or gamma2)"}}, {"maxmessage", o2::framework::VariantType::Int, 100, {"Max. amout of error messages to be displayed"}}, diff --git a/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx b/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx index db6e95f17f643..28e0deb3ae0b3 100644 --- a/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx +++ b/Detectors/EMCAL/workflow/src/RecoWorkflow.cxx @@ -53,7 +53,8 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, std::string const& cfgOutput, bool disableRootInput, bool disableRootOutput, - bool disableDecodingErrors) + bool disableDecodingErrors, + bool disableTriggerReconstruction) { const std::unordered_map InputMap{ @@ -173,7 +174,7 @@ o2::framework::WorkflowSpec getWorkflow(bool propagateMC, specs.emplace_back(o2::emcal::reco_workflow::getCellConverterSpec(propagateMC, subspecificationIn, subspecificationOut)); } else if (inputType == InputType::Raw) { // raw data will come from upstream - specs.emplace_back(o2::emcal::reco_workflow::getRawToCellConverterSpec(askDISTSTF, disableDecodingErrors, subspecificationOut)); + specs.emplace_back(o2::emcal::reco_workflow::getRawToCellConverterSpec(askDISTSTF, disableDecodingErrors, disableTriggerReconstruction, subspecificationOut)); } } diff --git a/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx b/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx index ceb34695eb0e9..4e31a26ee4b5c 100644 --- a/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx +++ b/Detectors/EMCAL/workflow/src/emc-reco-workflow.cxx @@ -53,6 +53,7 @@ void customize(std::vector& workflowOptions) {"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings"}}, {"disable-mc", o2::framework::VariantType::Bool, false, {"disable sending of MC information"}}, {"disable-decoding-errors", o2::framework::VariantType::Bool, false, {"disable propagating decoding errors"}}, + {"disable-trigger-reconstruction", o2::framework::VariantType::Bool, false, {"disable reconstruction of trigger data"}}, {"ignore-dist-stf", o2::framework::VariantType::Bool, false, {"do not subscribe to FLP/DISTSUBTIMEFRAME/0 message (no lost TF recovery)"}}, {"subspecificationIn", o2::framework::VariantType::Int, 0, {"Subspecification for input in case the workflow runs in parallel on multiple nodes (i.e. different FLPs)"}}, {"subspecificationOut", o2::framework::VariantType::Int, 0, {"Subspecification for output in case the workflow runs in parallel on multiple nodes (i.e. different FLPs)"}}}; @@ -86,7 +87,8 @@ o2::framework::WorkflowSpec defineDataProcessing(o2::framework::ConfigContext co cfgc.options().get("output-type"), cfgc.options().get("disable-root-input"), cfgc.options().get("disable-root-output"), - cfgc.options().get("disable-decoding-errors")); + cfgc.options().get("disable-decoding-errors"), + cfgc.options().get("disable-trigger-reconstruction")); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(cfgc, wf); diff --git a/Detectors/FIT/FT0/base/README.md b/Detectors/FIT/FT0/base/README.md new file mode 100644 index 0000000000000..2ac1732118237 --- /dev/null +++ b/Detectors/FIT/FT0/base/README.md @@ -0,0 +1,18 @@ + + +# FT0 Base + +## Geometry + +The `o2::ft0::Geometry` class contains dimensions and information used for constructing the FT0 geometry as used in simulation. It also provides utility methods for retrieving the center locations of the detector cells. See the below example for how to use the `Geometry` class to query the FT0 cell locations. Note that these are the ideal locations, and that any misalignment is not considered. + +```cpp +o2::ft0::Geometry ft0Geometry; +ft0Geometry.calculateChannelCenter(); +TVector3 cellPosition = ft0Geometry.getChannelCenter(chId); +float x = cellPosition.X(); +float y = cellPosition.Y(); +float z = cellPosition.Z(); +``` diff --git a/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0TimeOffsetSlotContainer.h b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0TimeOffsetSlotContainer.h index 6c470e86d2dea..88f820f28ed70 100644 --- a/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0TimeOffsetSlotContainer.h +++ b/Detectors/FIT/FT0/calibration/include/FT0Calibration/FT0TimeOffsetSlotContainer.h @@ -32,7 +32,7 @@ class FT0TimeOffsetSlotContainer final FT0TimeOffsetSlotContainer(std::size_t minEntries); // constructor is needed due to current version of FITCalibration library, should be removed FT0TimeOffsetSlotContainer(FT0TimeOffsetSlotContainer const&) = default; FT0TimeOffsetSlotContainer(FT0TimeOffsetSlotContainer&&) = default; - FT0TimeOffsetSlotContainer& operator=(FT0TimeOffsetSlotContainer const&) = default; + FT0TimeOffsetSlotContainer& operator=(FT0TimeOffsetSlotContainer&) = default; FT0TimeOffsetSlotContainer& operator=(FT0TimeOffsetSlotContainer&&) = default; bool hasEnoughEntries() const; void fill(const gsl::span& data); @@ -42,6 +42,8 @@ class FT0TimeOffsetSlotContainer final TimeSpectraInfoObject generateCalibrationObject(long tsStartMS, long tsEndMS, const std::string& pathToHists) const; typedef float FlatHistoValue_t; typedef o2::dataformats::FlatHisto2D FlatHisto2D_t; + auto getHistogram() const { return mHistogram; } + auto isFirstTF() const { return mIsFirstTF; } private: // Slot number diff --git a/Detectors/FIT/FT0/calibration/src/FT0TimeOffsetSlotContainer.cxx b/Detectors/FIT/FT0/calibration/src/FT0TimeOffsetSlotContainer.cxx index 9525d4b6c1cc7..1e31d24f8c20d 100644 --- a/Detectors/FIT/FT0/calibration/src/FT0TimeOffsetSlotContainer.cxx +++ b/Detectors/FIT/FT0/calibration/src/FT0TimeOffsetSlotContainer.cxx @@ -96,6 +96,14 @@ void FT0TimeOffsetSlotContainer::fill(const gsl::span& data) void FT0TimeOffsetSlotContainer::merge(FT0TimeOffsetSlotContainer* prev) { LOG(info) << "MERGING"; + if (mIsFirstTF && prev->isFirstTF()) { + // nothing to be done + return; + } else if (mIsFirstTF && !prev->isFirstTF()) { + // need to make mHistogram operational first + mHistogram.init(prev->getHistogram().getNBinsX(), prev->getHistogram().getXMin(), prev->getHistogram().getXMax(), prev->getHistogram().getNBinsY(), prev->getHistogram().getYMin(), prev->getHistogram().getYMax()); + mIsFirstTF = false; + } *this = *prev; if (mCurrentSlot == 0) { // This part should at the stage `hasEnoughData()` but it is const method diff --git a/Detectors/FIT/FV0/base/README.md b/Detectors/FIT/FV0/base/README.md new file mode 100644 index 0000000000000..1fba33c47b690 --- /dev/null +++ b/Detectors/FIT/FV0/base/README.md @@ -0,0 +1,17 @@ + + +# FV0 Base + +## Geometry + +The `o2::fv0::Geometry` class represents the geometry of the FV0 detector as used in simulation. It also provides utility methods for retrieving the center locations of the detector cells. See the below example for how to use the `Geometry` class to query the FV0 cell locations. Note that these are the ideal locations, and that any misalignment is not considered. + +```cpp +o2::fv0::Geometry* fv0Geometry = o2::fv0::Geometry::instance(o2::fv0::Geometry::eUninitialized); +o2::fv0::Point3Dsimple cellPosition = fv0Geometry->getReadoutCenter(chId); +float x = cellPosition.x; +float y = cellPosition.y; +float z = cellPosition.z; +``` diff --git a/Detectors/FIT/FV0/reconstruction/README.md b/Detectors/FIT/FV0/reconstruction/README.md new file mode 100644 index 0000000000000..46de9800fda92 --- /dev/null +++ b/Detectors/FIT/FV0/reconstruction/README.md @@ -0,0 +1,36 @@ + + +# FV0 reconstruction + +Please note that this readme shows how the reconstruction is done _at the moment_. The current reconstruction is not necessarily done the way it _should be_. The algorithm is under review and subject to change. + +The FV0 reconstruction workflow is + +- [O2/Detectors/FIT/FV0/workflow/src/fv0-reco-workflow.cxx](../workflow/src/fv0-reco-workflow.cxx) + +and the actual reconstruction happens in + +- [src/BaseRecoTask.cxx](src/BaseRecoTask.cxx) ([include/FV0Reconstruction/BaseRecoTask.h](include/BaseRecoTask.h)) + +## Channel data reconstruction + +Currently, there's no channel data filtering applied in the FV0 reconstruction. All digit channel data are propagated to RecPoints. The following conversions are made: + +- Channel ID (`uint8_t`) -> Channel ID (`int`) +- CFD time (TDC units, `int16_t`) -> Time in ns (`double`) + - Furthermore, if available and enabled, a time offset correction is applied. For FV0 it is not available nor enabled at the moment. +- Amplitude (ADC channels, `int16_t`) -> Ampltidue (ADC channels, `double`) +- Channel bits (`uint8_t`) -> Channel bits (`int`) + +## RecPoint reconstruction + +The reconstructed RecPoints contain: + +- BC information (`o2::InteractionRecord`) +- Channel data +- Three different times: + - "TimeFirst": time of first signal (w/ charge > `FV0DigParam::chargeThrForMeanTime`) + - "TimeGlobalMean": average of all signals passing some filtering (including CFD in gate) + - "TimeSelectedMean": average of all signals passing a bit stricter filtering (includling CFD in gate) diff --git a/Detectors/FIT/README.md b/Detectors/FIT/README.md index b079dce2cc972..8da3f32d7f4e2 100644 --- a/Detectors/FIT/README.md +++ b/Detectors/FIT/README.md @@ -9,6 +9,9 @@ This is a top page for the FIT detector documentation. diff --git a/Detectors/ForwardAlign/CMakeLists.txt b/Detectors/ForwardAlign/CMakeLists.txt index 48acb71e2c658..bb7d35444e4ff 100644 --- a/Detectors/ForwardAlign/CMakeLists.txt +++ b/Detectors/ForwardAlign/CMakeLists.txt @@ -21,6 +21,7 @@ o2_add_library(ForwardAlign src/SymBDMatrix.cxx src/SymMatrix.cxx src/VectorSparse.cxx + src/MilleRecordWriterSpec.cxx PUBLIC_LINK_LIBRARIES O2::CCDB O2::Steer ROOT::TreePlayer) @@ -37,4 +38,13 @@ o2_target_root_dictionary(ForwardAlign include/ForwardAlign/SymBDMatrix.h include/ForwardAlign/SymMatrix.h include/ForwardAlign/VectorSparse.h + include/ForwardAlign/MilleRecordWriterSpec.h LINKDEF src/ForwardAlignLinkDef.h) + + + +o2_add_executable( + millerecord-writer-workflow + SOURCES src/MilleRecordWriterSpec.cxx src/millerecord-writer-workflow.cxx + COMPONENT_NAME fwdalign + PUBLIC_LINK_LIBRARIES O2::Framework O2::DPLUtils O2::ReconstructionDataFormats O2::SimulationDataFormat O2::ForwardAlign) diff --git a/Detectors/ForwardAlign/include/ForwardAlign/MillePede2.h b/Detectors/ForwardAlign/include/ForwardAlign/MillePede2.h index f3707aa64dabf..2c5bb8ef6dd8d 100644 --- a/Detectors/ForwardAlign/include/ForwardAlign/MillePede2.h +++ b/Detectors/ForwardAlign/include/ForwardAlign/MillePede2.h @@ -156,6 +156,7 @@ class MillePede2 fNGroupsSet = grID; } } + void ResetRecord() { fRecord->Reset(); } void SetNGloPar(const int n) { fNGloPar = n; } void SetNLocPar(const int n) { fNLocPar = n; } void SetNMaxIterations(const int n = 10) { fMaxIter = n; } @@ -285,6 +286,9 @@ class MillePede2 fIsLinear[id] = !v; } + /// \brief Disable record writer for DPL process + void DisableRecordWriter() { fDisableRecordWriter = true; } + protected: /// \brief read data record (if any) at entry recID void ReadRecordData(const long recID, const bool doPrint = false); @@ -360,6 +364,7 @@ class MillePede2 long fCurrRecConstrID; ///< ID of the current constraint record bool fLocFitAdd; ///< Add contribution of carrent track (and not eliminate it) bool fUseRecordWeight; ///< force or ignore the record weight + bool fDisableRecordWriter; ///< disable record writer for DPL process int fMinRecordLength; ///< ignore shorter records int fSelFirst; ///< event selection start int fSelLast; ///< event selection end diff --git a/Detectors/ForwardAlign/include/ForwardAlign/MilleRecordWriterSpec.h b/Detectors/ForwardAlign/include/ForwardAlign/MilleRecordWriterSpec.h new file mode 100644 index 0000000000000..b10ab502dace8 --- /dev/null +++ b/Detectors/ForwardAlign/include/ForwardAlign/MilleRecordWriterSpec.h @@ -0,0 +1,33 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MilleRecordWriterSpec.h +/// \brief Implementation of a data processor to write MillePede record in a root file +/// +/// \author Chi Zhang, CEA-Saclay, chi.zhang@cern.ch + +#ifndef ALICEO2_FWDALIGN_MILLERECORDWRITERSPEC_H +#define ALICEO2_FWDALIGN_MILLERECORDWRITERSPEC_H + +#include "Framework/DataProcessorSpec.h" + +namespace o2 +{ +namespace fwdalign +{ + +framework::DataProcessorSpec getMilleRecordWriterSpec(bool useMC, const char* specName = "fwdalign-millerecord-writer", + const char* fileName = "millerecords.root"); + +} // namespace fwdalign +} // namespace o2 + +#endif // ALICEO2_FWDALIGN_MILLERECORDWRITERSPEC_H \ No newline at end of file diff --git a/Detectors/ForwardAlign/src/ForwardAlignLinkDef.h b/Detectors/ForwardAlign/src/ForwardAlignLinkDef.h index cfc895a101f8b..eb447d28e7868 100644 --- a/Detectors/ForwardAlign/src/ForwardAlignLinkDef.h +++ b/Detectors/ForwardAlign/src/ForwardAlignLinkDef.h @@ -19,6 +19,7 @@ #pragma link C++ class o2::fwdalign::MatrixSq + ; #pragma link C++ class o2::fwdalign::MillePede2 + ; #pragma link C++ class o2::fwdalign::MillePedeRecord + ; +#pragma link C++ class std::vector < o2::fwdalign::MillePedeRecord> + ; #pragma link C++ class o2::fwdalign::MilleRecordReader + ; #pragma link C++ class o2::fwdalign::MilleRecordWriter + ; #pragma link C++ class o2::fwdalign::MinResSolve + ; diff --git a/Detectors/ForwardAlign/src/MillePede2.cxx b/Detectors/ForwardAlign/src/MillePede2.cxx index d66786d658c5c..5ad475d893271 100644 --- a/Detectors/ForwardAlign/src/MillePede2.cxx +++ b/Detectors/ForwardAlign/src/MillePede2.cxx @@ -10,7 +10,7 @@ // or submit itself to any jurisdiction. /// @file MillePede2.cxx - +#include #include "ForwardAlign/MillePede2.h" #include "Framework/Logger.h" #include @@ -147,7 +147,8 @@ MillePede2::MillePede2(const MillePede2& src) fRecordWriter(nullptr), fConstraintsRecWriter(nullptr), fRecordReader(nullptr), - fConstraintsRecReader(nullptr) + fConstraintsRecReader(nullptr), + fDisableRecordWriter(false) { fWghScl[0] = src.fWghScl[0]; fWghScl[1] = src.fWghScl[1]; @@ -314,16 +315,17 @@ void MillePede2::EndChi2Storage() void MillePede2::SetLocalEquation(std::vector& dergb, std::vector& derlc, const double lMeas, const double lSigma) { - if (!fRecordWriter) { - LOG(fatal) << "MillePede2::SetLocalEquation() - aborted: null pointer to record writer"; - return; - } - if (!fRecordWriter->isInitOk()) { - LOG(fatal) << "MillePede2::SetLocalEquation() - aborted: unintialised record writer"; - return; + if (!fDisableRecordWriter) { + if (!fRecordWriter) { + LOG(fatal) << "MillePede2::SetLocalEquation() - aborted: null pointer to record writer"; + return; + } + if (!fRecordWriter->isInitOk()) { + LOG(fatal) << "MillePede2::SetLocalEquation() - aborted: unintialised record writer"; + return; + } + SetRecord(fRecordWriter->getRecord()); } - SetRecord(fRecordWriter->getRecord()); - // write data of single measurement if (lSigma <= 0.0) { // If parameter is fixed, then no equation for (int i = fNLocPar; i--;) { @@ -336,7 +338,6 @@ void MillePede2::SetLocalEquation(std::vector& dergb, std::vectorAddResidual(lMeas); - // Retrieve local param interesting indices for (int i = 0; i < fNLocPar; i++) { if (!IsZero(derlc[i])) { @@ -364,16 +365,17 @@ void MillePede2::SetLocalEquation(std::vector& indgb, std::vector& std::vector& derlc, const int nlc, const double lMeas, const double lSigma) { - if (!fRecordWriter) { - LOG(fatal) << "MillePede2::SetLocalEquation() - aborted: null pointer to record writer"; - return; - } - if (!fRecordWriter->isInitOk()) { - LOG(fatal) << "MillePede2::SetLocalEquation() - aborted: unintialised record writer"; - return; + if (!fDisableRecordWriter) { + if (!fRecordWriter) { + LOG(fatal) << "MillePede2::SetLocalEquation() - aborted: null pointer to record writer"; + return; + } + if (!fRecordWriter->isInitOk()) { + LOG(fatal) << "MillePede2::SetLocalEquation() - aborted: unintialised record writer"; + return; + } + SetRecord(fRecordWriter->getRecord()); } - SetRecord(fRecordWriter->getRecord()); - if (lSigma <= 0.0) { // If parameter is fixed, then no equation for (int i = nlc; i--;) { derlc[i] = 0.0; diff --git a/Detectors/ForwardAlign/src/MilleRecordReader.cxx b/Detectors/ForwardAlign/src/MilleRecordReader.cxx index a169ba77b6e0d..927e7972c222b 100644 --- a/Detectors/ForwardAlign/src/MilleRecordReader.cxx +++ b/Detectors/ForwardAlign/src/MilleRecordReader.cxx @@ -25,7 +25,7 @@ MilleRecordReader::MilleRecordReader() mIsSuccessfulInit(false), mIsConstraintsRec(false), mIsReadEntryOk(false), - mDataTreeName("milleRecords"), + mDataTreeName("o2sim"), mDataBranchName("data"), mRecord(nullptr), mCurrentDataID(-1), diff --git a/Detectors/ForwardAlign/src/MilleRecordWriter.cxx b/Detectors/ForwardAlign/src/MilleRecordWriter.cxx index 8dbe31e91744c..e36c47562c81e 100644 --- a/Detectors/ForwardAlign/src/MilleRecordWriter.cxx +++ b/Detectors/ForwardAlign/src/MilleRecordWriter.cxx @@ -29,8 +29,8 @@ MilleRecordWriter::MilleRecordWriter() mIsSuccessfulInit(false), mIsConstraintsRec(false), mNEntriesAutoSave(10000), - mDataFileName("mft_mille_records.root"), - mDataTreeName("milleRecords"), + mDataFileName("millerecords.root"), + mDataTreeName("o2sim"), mDataBranchName("data"), mRecord(nullptr), mCurrentDataID(-1) @@ -135,6 +135,7 @@ void MilleRecordWriter::terminate() mDataTree->Write(); LOG(info) << "MilleRecordWriter::terminate() - wrote tree " << mDataTreeName.Data(); + mDataFile->Close(); } } diff --git a/Detectors/ForwardAlign/src/MilleRecordWriterSpec.cxx b/Detectors/ForwardAlign/src/MilleRecordWriterSpec.cxx new file mode 100644 index 0000000000000..e3fe8c12a9ad0 --- /dev/null +++ b/Detectors/ForwardAlign/src/MilleRecordWriterSpec.cxx @@ -0,0 +1,42 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file MilleRecordWriterSpec.cxx +/// \brief Implementation of a data processor to write MillePede record in a root file +/// +/// \author Chi Zhang, CEA-Saclay, chi.zhang@cern.ch + +#include "ForwardAlign/MilleRecordWriterSpec.h" + +#include +#include "DPLUtils/MakeRootTreeWriterSpec.h" +#include "ForwardAlign/MillePedeRecord.h" + +namespace o2 +{ +namespace fwdalign +{ + +using namespace o2::framework; + +template +using BranchDefinition = MakeRootTreeWriterSpec::BranchDefinition; + +DataProcessorSpec getMilleRecordWriterSpec(bool useMC, const char* specName, const char* fileName) +{ + return MakeRootTreeWriterSpec(specName, + fileName, + MakeRootTreeWriterSpec::TreeAttributes{"o2sim", "Tree MillePede records for MCH-MID tracks"}, + BranchDefinition{InputSpec{"data", "MUON", "RECORD_MCHMID", Lifetime::Sporadic}, "data"})(); +} + +} // namespace fwdalign +} // namespace o2 \ No newline at end of file diff --git a/Detectors/ForwardAlign/src/millerecord-writer-workflow.cxx b/Detectors/ForwardAlign/src/millerecord-writer-workflow.cxx new file mode 100644 index 0000000000000..9144ef1cb1025 --- /dev/null +++ b/Detectors/ForwardAlign/src/millerecord-writer-workflow.cxx @@ -0,0 +1,41 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file millerecord-writer-workflow.cxx +/// \brief Implementation of a DPL device to run the MillePede record writer +/// +/// \author Chi Zhang, CEA-Saclay, chi.zhang@cern.ch + +#include "ForwardAlign/MilleRecordWriterSpec.h" +#include "Framework/CompletionPolicyHelpers.h" + +using namespace o2::framework; + +void customize(std::vector& policies) +{ + // ordered policies for the writers + policies.push_back(CompletionPolicyHelpers::consumeWhenAllOrdered(".*(?:FWDALIGN|fwdalign).*[W,w]riter.*")); +} + +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + workflowOptions.emplace_back("disable-mc", VariantType::Bool, false, + ConfigParamSpec::HelpString{"disable MC propagation even if available"}); +} + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) +{ + auto useMC = !configcontext.options().get("disable-mc"); + return WorkflowSpec{o2::fwdalign::getMilleRecordWriterSpec(useMC)}; +} \ No newline at end of file diff --git a/Detectors/GRP/calibration/include/GRPCalibration/GRPDCSDPsProcessor.h b/Detectors/GRP/calibration/include/GRPCalibration/GRPDCSDPsProcessor.h index 3113ea0a0da42..98075051356e7 100644 --- a/Detectors/GRP/calibration/include/GRPCalibration/GRPDCSDPsProcessor.h +++ b/Detectors/GRP/calibration/include/GRPCalibration/GRPDCSDPsProcessor.h @@ -42,7 +42,14 @@ inline unsigned long llu2lu(std::uint64_t v) { return (unsigned long)v; } struct GRPEnvVariables { std::unordered_map>> mEnvVars; - + size_t totalEntries() const + { + size_t s = 0; + for (const auto& el : mEnvVars) { + s += el.second.size(); + } + return s; + } void print() { for (const auto& el : mEnvVars) { @@ -116,10 +123,16 @@ struct MagFieldHelper { struct GRPCollimators { std::unordered_map>> mCollimators; - + size_t totalEntries() const + { + size_t s = 0; + for (const auto& el : mCollimators) { + s += el.second.size(); + } + return s; + } void print() { - for (const auto& el : mCollimators) { std::printf("%-60s\n", el.first.c_str()); for (const auto& it : el.second) { @@ -291,7 +304,9 @@ class GRPDCSDPsProcessor { // keep only the latest measurement for (auto& el : mapToReset) { - el.second.erase(el.second.begin(), el.second.end() - 1); + if (el.second.begin() != el.second.end()) { + el.second.erase(el.second.begin(), el.second.end() - 1); + } } } diff --git a/Detectors/GRP/calibration/src/GRPDCSDPsProcessor.cxx b/Detectors/GRP/calibration/src/GRPDCSDPsProcessor.cxx index 2700deed92fe8..f3f96794095d7 100644 --- a/Detectors/GRP/calibration/src/GRPDCSDPsProcessor.cxx +++ b/Detectors/GRP/calibration/src/GRPDCSDPsProcessor.cxx @@ -175,7 +175,6 @@ bool GRPDCSDPsProcessor::processCollimators(const DPCOM& dpcom) bool GRPDCSDPsProcessor::processEnvVar(const DPCOM& dpcom) { - // function to process Data Points that are related to env variables bool match = processPairD(dpcom, "CavernTemperature", mEnvVars.mEnvVars) || processPairD(dpcom, "CavernAtmosPressure", mEnvVars.mEnvVars) || @@ -396,14 +395,14 @@ void GRPDCSDPsProcessor::updateEnvVarsCCDB() void GRPDCSDPsProcessor::updateCollimatorsCCDB() { - // we need to update a CCDB for the Env Variables DPs --> let's prepare the CCDBInfo + // we need to update a CCDB for the Collimators Variables DPs --> let's prepare the CCDBInfo if (mVerbose) { LOG(info) << "Entry related to Collimators needs to be updated with startTime " << mStartValidityColli; } std::map md; md["responsible"] = "Chiara Zampolli"; - o2::calibration::Utils::prepareCCDBobjectInfo(mEnvVars, mccdbCollimatorsInfo, "GLO/Config/Collimators", md, mStartValidityColli, mStartValidityColli + 3 * o2::ccdb::CcdbObjectInfo::DAY); // valid for 3 days + o2::calibration::Utils::prepareCCDBobjectInfo(mCollimators, mccdbCollimatorsInfo, "GLO/Config/Collimators", md, mStartValidityColli, mStartValidityColli + 3 * o2::ccdb::CcdbObjectInfo::DAY); // valid for 3 days return; } diff --git a/Detectors/GRP/workflows/CMakeLists.txt b/Detectors/GRP/workflows/CMakeLists.txt index 0fecb1f34af5a..ea56cf8270335 100644 --- a/Detectors/GRP/workflows/CMakeLists.txt +++ b/Detectors/GRP/workflows/CMakeLists.txt @@ -31,6 +31,15 @@ o2_add_executable(grp-lhc-if-file-workflow O2::GRPCalibration O2::DetectorsCalibration) +o2_add_executable(workflow + COMPONENT_NAME rct-updater + SOURCES src/rct-updater-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::CCDB + O2::DetectorsBase + O2::DetectorsCalibration + O2::DataFormatsParameters) + o2_add_executable(grp-create COMPONENT_NAME ecs SOURCES src/create-grp-ecs.cxx diff --git a/Detectors/GRP/workflows/include/GRPWorkflows/GRPDCSDPsSpec.h b/Detectors/GRP/workflows/include/GRPWorkflows/GRPDCSDPsSpec.h index 52f6be37a226a..6a9b946251eb1 100644 --- a/Detectors/GRP/workflows/include/GRPWorkflows/GRPDCSDPsSpec.h +++ b/Detectors/GRP/workflows/include/GRPWorkflows/GRPDCSDPsSpec.h @@ -45,6 +45,9 @@ class GRPDCSDPsDataProcessor : public Task int64_t mDPsUpdateInterval; bool mReportTiming = false; bool mLHCIFupdated = false; + size_t mEmptyCyclesEnvVars = 0; + size_t mEmptyCyclesCollimators = 0; + size_t mWarnEmptyCycles = 1; }; } // namespace grp diff --git a/Detectors/GRP/workflows/src/GRPDCSDPsSpec.cxx b/Detectors/GRP/workflows/src/GRPDCSDPsSpec.cxx index 24ac29aed05ad..6f214cf7c0b42 100644 --- a/Detectors/GRP/workflows/src/GRPDCSDPsSpec.cxx +++ b/Detectors/GRP/workflows/src/GRPDCSDPsSpec.cxx @@ -46,6 +46,7 @@ void GRPDCSDPsDataProcessor::init(o2::framework::InitContext& ic) std::vector vect; mDPsUpdateInterval = ic.options().get("DPs-update-interval"); + mWarnEmptyCycles = ic.options().get("warn-empty-cycles"); if (mDPsUpdateInterval == 0) { LOG(error) << "GRP DPs update interval set to zero seconds --> changed to 60"; mDPsUpdateInterval = 60; @@ -248,6 +249,14 @@ void GRPDCSDPsDataProcessor::sendCollimatorsDPsoutput(DataAllocator& output) // filling CCDB with Collimators object const auto& payload = mProcessor->getCollimatorsObj(); + if (payload.totalEntries() == 0) { + if ((mEmptyCyclesCollimators % size_t(mWarnEmptyCycles)) == 0) { + LOGP(alarm, "No Collimator DPs were received after {} {}-s cycles", mEmptyCyclesCollimators, mDPsUpdateInterval); + } + mEmptyCyclesCollimators++; + } else { + mEmptyCyclesCollimators = 0; + } auto& info = mProcessor->getccdbCollimatorsInfo(); auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() @@ -264,6 +273,14 @@ void GRPDCSDPsDataProcessor::sendEnvVarsDPsoutput(DataAllocator& output) // filling CCDB with EnvVars object const auto& payload = mProcessor->getEnvVarsObj(); + if (payload.totalEntries() == 0) { + if ((mEmptyCyclesEnvVars % size_t(mWarnEmptyCycles)) == 0) { + LOGP(alarm, "No EnvVar DPs were received after {} {}-s cycles", mEmptyCyclesEnvVars, mDPsUpdateInterval); + } + mEmptyCyclesEnvVars++; + } else { + mEmptyCyclesEnvVars = 0; + } auto& info = mProcessor->getccdbEnvVarsInfo(); auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() << " of size " << image->size() @@ -305,6 +322,7 @@ DataProcessorSpec getGRPDCSDPsDataProcessorSpec() {"use-verbose-mode", VariantType::Bool, false, {"Use verbose mode"}}, {"report-timing", VariantType::Bool, false, {"Report timing for every slice"}}, {"DPs-update-interval", VariantType::Int64, 600ll, {"Interval (in s) after which to update the DPs CCDB entry"}}, + {"warn-empty-cycles", VariantType::Int, 1, {"Warn about empty object after this number of cycles"}}, {"clear-vectors", VariantType::Bool, false, {"Clear vectors when starting processing for a new CCDB entry (latest value will not be kept)"}}}}; } diff --git a/Detectors/GRP/workflows/src/create-grp-ecs.cxx b/Detectors/GRP/workflows/src/create-grp-ecs.cxx index 17549c1070da0..95bfb878cee9d 100644 --- a/Detectors/GRP/workflows/src/create-grp-ecs.cxx +++ b/Detectors/GRP/workflows/src/create-grp-ecs.cxx @@ -134,6 +134,22 @@ int createGRPECSObject(const std::string& dataPeriod, } else { LOGP(alarm, "Upload to {}/{} with validity {}:{} for SOR:{}/EOR:{} FAILED, returned with code {}", ccdbServer, objPath, tstart, tendVal, tstart, tend, retValGLO); } + if ((runType == GRPECSObject::RunType::PHYSICS || runType == GRPECSObject::RunType::COSMICS) && tstart >= tend) { // also create the RCT/Info/RunInformation entry in case the run type is PHYSICS, to be finalized at EOR + char tempChar{}; + std::map mdRCT; + mdRCT["SOR"] = std::to_string(tstart); + mdRCT["EOR"] = std::to_string(tend); + mdRCT["SOX"] = std::to_string(tstartCTP); + mdRCT["EOX"] = std::to_string(tendCTP); + long startValRCT = (long)run; + long endValRCT = (long)(run + 1); + retValRCT = api.storeAsBinaryFile(&tempChar, sizeof(tempChar), "tmp.dat", "char", "RCT/Info/RunInformation", mdRCT, startValRCT, endValRCT); + if (retValRCT == 0) { + LOGP(info, "Uploaded initial RCT object to {}/{} with validity {}:{}", ccdbServer, "RCT/Info/RunInformation", startValRCT, endValRCT); + } else { + LOGP(alarm, "Upload of initial RCT object to {}/{} with validity {}:{} FAILED, returned with code {}", ccdbServer, "RCT/Info/RunInformation", startValRCT, endValRCT, retValRCT); + } + } if (tend > tstart) { // override SOR version to the same limits metadata.erase("EOR"); @@ -157,15 +173,14 @@ int createGRPECSObject(const std::string& dataPeriod, mdRCT["EOX"] = std::to_string(tendCTP); long startValRCT = (long)run; long endValRCT = (long)(run + 1); - retValRCT = api.storeAsBinaryFile(&tempChar, sizeof(tempChar), "tmp.dat", "char", "RCT/Info/RunInformation", mdRCT, startValRCT, endValRCT); + retValRCT = api.updateMetadata("RCT/Info/RunInformation", mdRCT, startValRCT); if (retValRCT == 0) { - LOGP(info, "Uploaded RCT object to {}/{} with validity {}:{}", ccdbServer, "RCT/Info/RunInformation", startValRCT, endValRCT); + LOGP(info, "Updated RCT object to SOR:{}/EOR:{} SOX:{}/EOX:{}", tstart, tend, tstartCTP, tendCTP); } else { - LOGP(alarm, "Uploaded RCT object to {}/{} with validity {}:{} FAILED, returned with code {}", ccdbServer, "RCT/Info/RunInformation", startValRCT, endValRCT, retValRCT); + LOGP(alarm, "Update of RCT object to SOR:{}/EOR:{} SOX:{}/EOX:{} FAILED, returned with code {}", tstart, tend, tstartCTP, tendCTP, retValRCT); } } } - } else { // write a local file auto fname = o2::base::NameConf::getGRPECSFileName(); TFile grpF(fname.c_str(), "recreate"); diff --git a/Detectors/GRP/workflows/src/rct-updater-workflow.cxx b/Detectors/GRP/workflows/src/rct-updater-workflow.cxx new file mode 100644 index 0000000000000..8b75091520724 --- /dev/null +++ b/Detectors/GRP/workflows/src/rct-updater-workflow.cxx @@ -0,0 +1,188 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "Framework/Logger.h" +#include "Framework/ControlService.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/InputSpec.h" +#include "Framework/Task.h" +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCalibration/Utils.h" + +using namespace o2::framework; + +void customize(std::vector& workflowOptions) +{ + std::vector options{{"configKeyValues", o2::framework::VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + std::swap(workflowOptions, options); +} + +#include "DetectorsBase/GRPGeomHelper.h" +#include "CCDB/CcdbApi.h" +#include "DataFormatsParameters/GRPECSObject.h" + +namespace o2::rct +{ +class RCTUpdaterSpec : public o2::framework::Task +{ + public: + RCTUpdaterSpec(std::shared_ptr gr) : mGGCCDBRequest(gr) {} + ~RCTUpdaterSpec() final = default; + + void init(InitContext& ic) final + { + o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); + mUpdateInterval = std::max(0.1f, ic.options().get("update-interval")); + auto ccdb = ic.options().get("ccdb-server"); + if (!ccdb.empty() && ccdb != "none") { + mCCDBApi = std::make_unique(); + mCCDBApi->init(ic.options().get("ccdb-server")); + } else { + LOGP(warn, "No ccdb server provided, no RCT update will be done"); + } + } + + void run(ProcessingContext& pc) final + { + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + auto tinfo = pc.services().get(); + if (tinfo.globalRunNumberChanged) { // do we have RCT object? + const auto* grp = o2::base::GRPGeomHelper::instance().getGRPECS(); + mNHBFPerTF = grp->getNHBFPerTF(); + if (mNHBFPerTF < 1) { + mNHBFPerTF = 32; + } + mRunNumber = tinfo.runNumber; + mUpdateIntervalTF = uint32_t(mUpdateInterval / (mNHBFPerTF * o2::constants::lhc::LHCOrbitMUS * 1e-6)); // convert update interval in seconds to interval in TFs + LOGP(info, "Will update RCT after {} TFs of {} HBFs ({}s was requested)", mUpdateIntervalTF, mNHBFPerTF, mUpdateInterval); + mOrbitReset = o2::base::GRPGeomHelper::instance().getOrbitResetTimeMS(); + mMinOrbit = 0xffffffff; + mMaxOrbit = 0; + if (grp->getRunType() == o2::parameters::GRPECS::PHYSICS || grp->getRunType() == o2::parameters::GRPECS::COSMICS) { + mEnabled = true; + } else { + LOGP(warning, "Run {} type is {}, disabling RCT update", mRunNumber, o2::parameters::GRPECS::RunTypeNames[grp->getRunType()]); + mEnabled = false; + } + if (mEnabled) { + if (mCCDBApi) { + auto md = mCCDBApi->retrieveHeaders("RCT/Info/RunInformation", {}, grp->getRun()); + if (md.empty()) { + mEnabled = false; + LOGP(alarm, "RCT object is missing for {} run {}, disabling RCT updater", o2::parameters::GRPECS::RunTypeNames[grp->getRunType()], grp->getRun()); + } + } + } + } + if (mEnabled) { + if (tinfo.firstTForbit < mMinOrbit) { + mMinOrbit = tinfo.firstTForbit; + } + if (tinfo.firstTForbit > mMaxOrbit) { + mMaxOrbit = tinfo.firstTForbit; + } + if (tinfo.tfCounter > mLastTFUpdate + mUpdateIntervalTF) { // need to update + mLastTFUpdate = tinfo.tfCounter; + updateRCT(); + } + } + } + + void endOfStream(framework::EndOfStreamContext& ec) final + { + if (mEnabled) { + updateRCT(); + mEnabled = false; + } + } + + void stop() final + { + if (mEnabled) { + updateRCT(); + mEnabled = false; + } + } + + void finaliseCCDB(framework::ConcreteDataMatcher& matcher, void* obj) final + { + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } + } + + void updateRCT() + { + std::map mdRCT; + if (mMinOrbit > mMaxOrbit) { + return; + } + mdRCT["STF"] = std::to_string(long(mMinOrbit * o2::constants::lhc::LHCOrbitMUS * 1e-3) + mOrbitReset); + mdRCT["ETF"] = std::to_string(long((mMaxOrbit + mNHBFPerTF - 1) * o2::constants::lhc::LHCOrbitMUS * 1e-3) + mOrbitReset); + long startValRCT = (long)mRunNumber; + long endValRCT = (long)(mRunNumber + 1); + if (mCCDBApi) { + int retValRCT = mCCDBApi->updateMetadata("RCT/Info/RunInformation", mdRCT, startValRCT); + if (retValRCT == 0) { + LOGP(info, "Updated {}/RCT/Info/RunInformation object for run {} with TF start:{} end:{}", mCCDBApi->getURL(), mRunNumber, mdRCT["STF"], mdRCT["ETF"]); + } else { + LOGP(alarm, "Update of RCT object for run {} with TF start:{} end:{} FAILED, returned with code {}", mRunNumber, mdRCT["STF"], mdRCT["ETF"], retValRCT); + } + } else { + LOGP(info, "CCDB update disabled, TF timestamp range is {}:{}", mdRCT["STF"], mdRCT["ETF"]); + } + } + + private: + bool mEnabled = true; + float mUpdateInterval = 1.; + int mUpdateIntervalTF = 1; + uint32_t mMinOrbit = 0xffffffff; + uint32_t mMaxOrbit = 0; + uint32_t mLastTFUpdate = 0; + long mOrbitReset = 0; + int mRunNumber = 0; + int mNHBFPerTF = 32; + std::shared_ptr mGGCCDBRequest; + std::unique_ptr mCCDBApi; +}; +} // namespace o2::rct + +// ------------------------------------------------------------------ +#include "Framework/runDataProcessing.h" +#include "Framework/DataProcessorSpec.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + std::vector inputs{{"ctfdone", "CTF", "DONE", 0, Lifetime::Timeframe}}; + std::vector outputs; + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, "RCTUPD_DUMMY"}, Lifetime::Sporadic); + outputs.emplace_back(ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, "RCTUPD_DUMMY"}, Lifetime::Sporadic); + auto ggRequest = std::make_shared(true, // orbitResetTime + true, // GRPECS=true + false, // GRPLHCIF + false, // GRPMagField + false, // askMatLUT + o2::base::GRPGeomRequest::None, // geometry + inputs, + true); // query only once all objects except mag.field + specs.push_back(DataProcessorSpec{ + "rct-updater", + inputs, + outputs, + AlgorithmSpec{adaptFromTask(ggRequest)}, + Options{ + {"update-interval", VariantType::Float, 1.f, {"update every ... seconds"}}, + {"ccdb-server", VariantType::String, "http://ccdb-test.cern.ch:8080", {"CCDB to update"}}}}); + return specs; +} diff --git a/Detectors/GlobalTracking/CMakeLists.txt b/Detectors/GlobalTracking/CMakeLists.txt index bd5fb4f9976d1..cc62bac02a1cb 100644 --- a/Detectors/GlobalTracking/CMakeLists.txt +++ b/Detectors/GlobalTracking/CMakeLists.txt @@ -36,6 +36,7 @@ o2_add_library(GlobalTracking O2::FT0Reconstruction O2::TPCFastTransformation O2::GPUO2Interface + O2::GPUTracking O2::TPCBase O2::TPCReconstruction O2::TPCCalibration diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchITSTPCQC.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchITSTPCQC.h index 6a6f2f735c6e2..983fadcb0092e 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchITSTPCQC.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchITSTPCQC.h @@ -136,6 +136,7 @@ class MatchITSTPCQC void publishHistograms(const std::shared_ptr& publisher) { for (int i = 0; i < matchType::SIZE; ++i) { + // Pt publisher->startPublishing(mPtNum[i]); publisher->startPublishing(mPtDen[i]); publisher->startPublishing(mFractionITSTPCmatch[i]); @@ -144,66 +145,72 @@ class MatchITSTPCQC publisher->startPublishing(mPtDen_noEta0[i]); publisher->startPublishing(mFractionITSTPCmatch_noEta0[i]); - publisher->startPublishing(mPtPhysPrimNum[i]); - publisher->startPublishing(mPtPhysPrimDen[i]); - publisher->startPublishing(mFractionITSTPCmatchPhysPrim[i]); - + // Phi publisher->startPublishing(mPhiNum[i]); publisher->startPublishing(mPhiDen[i]); publisher->startPublishing(mFractionITSTPCmatchPhi[i]); - if (mUseTrkPID) { // Vs Tracking PID hypothesis - for (int j = 0; j < o2::track::PID::NIDs; ++j) { - // Pt - publisher->startPublishing(mPtNumVsTrkPID[i][j]); - publisher->startPublishing(mPtDenVsTrkPID[i][j]); - publisher->startPublishing(mFractionITSTPCmatchPtVsTrkPID[i][j]); - // Phi - publisher->startPublishing(mPhiNumVsTrkPID[i][j]); - publisher->startPublishing(mPhiDenVsTrkPID[i][j]); - publisher->startPublishing(mFractionITSTPCmatchPhiVsTrkPID[i][j]); - // Eta - publisher->startPublishing(mEtaNumVsTrkPID[i][j]); - publisher->startPublishing(mEtaDenVsTrkPID[i][j]); - publisher->startPublishing(mFractionITSTPCmatchEtaVsTrkPID[i][j]); - } - } - - publisher->startPublishing(mPhiPhysPrimNum[i]); - publisher->startPublishing(mPhiPhysPrimDen[i]); - publisher->startPublishing(mFractionITSTPCmatchPhiPhysPrim[i]); - publisher->startPublishing(mPhiVsPtNum[i]); publisher->startPublishing(mPhiVsPtDen[i]); publisher->startPublishing(mFractionITSTPCmatchPhiVsPt[i]); + // Eta publisher->startPublishing(mEtaNum[i]); publisher->startPublishing(mEtaDen[i]); publisher->startPublishing(mFractionITSTPCmatchEta[i]); - publisher->startPublishing(mEtaPhysPrimNum[i]); - publisher->startPublishing(mEtaPhysPrimDen[i]); - publisher->startPublishing(mFractionITSTPCmatchEtaPhysPrim[i]); - publisher->startPublishing(mEtaVsPtNum[i]); publisher->startPublishing(mEtaVsPtDen[i]); publisher->startPublishing(mFractionITSTPCmatchEtaVsPt[i]); + // Clusters publisher->startPublishing(mClsVsPtNum[i]); publisher->startPublishing(mClsVsPtDen[i]); publisher->startPublishing(mFractionITSTPCmatchClsVsPt[i]); + // Chi2 publisher->startPublishing(mChi2VsPtNum[i]); publisher->startPublishing(mChi2VsPtDen[i]); publisher->startPublishing(mFractionITSTPCmatchChi2VsPt[i]); + // 1/pt publisher->startPublishing(m1OverPtNum[i]); publisher->startPublishing(m1OverPtDen[i]); publisher->startPublishing(mFractionITSTPCmatch1OverPt[i]); - publisher->startPublishing(m1OverPtPhysPrimNum[i]); - publisher->startPublishing(m1OverPtPhysPrimDen[i]); - publisher->startPublishing(mFractionITSTPCmatchPhysPrim1OverPt[i]); + if (mUseTrkPID) { // Vs Tracking PID hypothesis + for (int j = 0; j < o2::track::PID::NIDs; ++j) { + // Pt + publisher->startPublishing(mPtNumVsTrkPID[i][j]); + publisher->startPublishing(mPtDenVsTrkPID[i][j]); + publisher->startPublishing(mFractionITSTPCmatchPtVsTrkPID[i][j]); + + // Phi + publisher->startPublishing(mPhiNumVsTrkPID[i][j]); + publisher->startPublishing(mPhiDenVsTrkPID[i][j]); + publisher->startPublishing(mFractionITSTPCmatchPhiVsTrkPID[i][j]); + + // Eta + publisher->startPublishing(mEtaNumVsTrkPID[i][j]); + publisher->startPublishing(mEtaDenVsTrkPID[i][j]); + publisher->startPublishing(mFractionITSTPCmatchEtaVsTrkPID[i][j]); + } + } + + if (mUseMC) { + publisher->startPublishing(mPhiPhysPrimNum[i]); + publisher->startPublishing(mPhiPhysPrimDen[i]); + publisher->startPublishing(mFractionITSTPCmatchPhiPhysPrim[i]); + publisher->startPublishing(mPtPhysPrimNum[i]); + publisher->startPublishing(mPtPhysPrimDen[i]); + publisher->startPublishing(mFractionITSTPCmatchPhysPrim[i]); + publisher->startPublishing(mEtaPhysPrimNum[i]); + publisher->startPublishing(mEtaPhysPrimDen[i]); + publisher->startPublishing(mFractionITSTPCmatchEtaPhysPrim[i]); + publisher->startPublishing(m1OverPtPhysPrimNum[i]); + publisher->startPublishing(m1OverPtPhysPrimDen[i]); + publisher->startPublishing(mFractionITSTPCmatchPhysPrim1OverPt[i]); + } } publisher->startPublishing(mChi2Matching); publisher->startPublishing(mChi2Refit); @@ -225,8 +232,6 @@ class MatchITSTPCQC void deleteHistograms(); void setBz(float bz) { mBz = bz; } - // track selection - bool selectTrack(o2::tpc::TrackTPC const& track); // still present but not used // ITS track void setMinPtITSCut(float v) { mPtITSCut = v; }; void setEtaITSCut(float v) { mEtaITSCut = v; }; // TODO: define 2 different values for min and max (**) diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h index 879fb7f8049b1..83f4dae0c2476 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTOF.h @@ -219,7 +219,7 @@ class MatchTOF void BestMatches(std::vector& matchedTracksPairs, std::vector* matchedTracks, std::vector* matchedTracksIndex, int* matchedClustersIndex, const gsl::span& FITRecPoints, const std::vector& TOFClusWork, const std::vector* TracksWork, std::vector& CalibInfoTOF, unsigned long Timestamp, bool MCTruthON, const o2::dataformats::MCTruthContainer* TOFClusLabels, const std::vector* TracksLblWork, std::vector* OutTOFLabels, float calibMaxChi2); void BestMatchesHP(std::vector& matchedTracksPairs, std::vector* matchedTracks, std::vector* matchedTracksIndex, int* matchedClustersIndex, const gsl::span& FITRecPoints, const std::vector& TOFClusWork, std::vector& CalibInfoTOF, unsigned long Timestamp, bool MCTruthON, const o2::dataformats::MCTruthContainer* TOFClusLabels, const std::vector* TracksLblWork, std::vector* OutTOFLabels); bool propagateToRefX(o2::track::TrackParCov& trc, float xRef /*in cm*/, float stepInCm /*in cm*/, o2::track::TrackLTIntegral& intLT); - bool propagateToRefXWithoutCov(o2::track::TrackParCov& trc, float xRef /*in cm*/, float stepInCm /*in cm*/, float bz); + bool propagateToRefXWithoutCov(const o2::track::TrackParCov& trc, float xRef /*in cm*/, float stepInCm /*in cm*/, float bz); void updateTimeDependentParams(); @@ -287,6 +287,7 @@ class MatchTOF /// data needed for refit of time-constrained TPC tracks gsl::span mTPCTrackClusIdx; ///< input TPC track cluster indices span gsl::span mTPCRefitterShMap; ///< externally set TPC clusters sharing map + gsl::span mTPCRefitterOccMap; ///< externally set TPC clusters occupancy map const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices o2::gpu::CorrectionMapsHelper* mTPCCorrMapsHelper = nullptr; ///< TPC cluster transformation diff --git a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h index 190a00ce4f3bc..ef45cb21adbd8 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/MatchTPCITS.h @@ -372,6 +372,8 @@ class MatchTPCITS ///< set Bunch filling and init helpers for validation by BCs void setBunchFilling(const o2::BunchFilling& bf); + void setNHBPerTF(int n) { mNHBPerTF = n; } + ///< ITS readout mode void setITSTriggered(bool v) { mITSTriggered = v; } bool isITSTriggered() const { return mITSTriggered; } @@ -421,9 +423,10 @@ class MatchTPCITS #ifdef _ALLOW_DEBUG_TREES_ enum DebugFlagTypes : UInt_t { - MatchTreeAll = 0x1 << 1, ///< produce matching candidates tree for all candidates - MatchTreeAccOnly = 0x1 << 2, ///< fill the matching candidates tree only once the cut is passed - WinnerMatchesTree = 0x1 << 3 ///< separate debug tree for winner matches + MatchTreeAll = 0x1 << 1, ///< produce matching candidates tree for all candidates + MatchTreeAccOnly = 0x1 << 2, ///< fill the matching candidates tree only once the cut is passed + WinnerMatchesTree = 0x1 << 3, ///< separate debug tree for winner matches + TPCOrigTree = 0x1 << 4 ///< original TPC tracks with some aux info }; ///< check if partucular flags are set bool isDebugFlag(UInt_t flags) const { return mDBGFlags & flags; } @@ -448,6 +451,7 @@ class MatchTPCITS ///< fill matching debug tree void fillTPCITSmatchTree(int itsID, int tpcID, int rejFlag, float chi2 = -1., float tCorr = 0.); void dumpWinnerMatches(); + void dumpTPCOrig(bool acc, int tpcIndex); #endif private: @@ -462,7 +466,7 @@ class MatchTPCITS bool prepareFITData(); int prepareInteractionTimes(); int prepareTPCTracksAfterBurner(); - void addTPCSeed(const o2::track::TrackParCov& _tr, float t0, float terr, o2::dataformats::GlobalTrackID srcGID, int tpcID); + int addTPCSeed(const o2::track::TrackParCov& _tr, float t0, float terr, o2::dataformats::GlobalTrackID srcGID, int tpcID); int preselectChipClusters(std::vector& clVecOut, const ClusRange& clRange, const ITSChipClustersRefs& itsChipClRefs, float trackY, float trackZ, float tolerY, float tolerZ) const; @@ -563,6 +567,9 @@ class MatchTPCITS float mBz = 0; ///< nominal Bz int mTFCount = 0; ///< internal TF counter for debugger int mNThreads = 1; ///< number of OMP threads + int mNHBPerTF = 0; + int mNTPCOccBinLength = 0; ///< TPC occ. histo bin length in TBs + float mNTPCOccBinLengthInv; o2::InteractionRecord mStartIR{0, 0}; ///< IR corresponding to the start of the TF ///========== Parameters to be set externally, e.g. from CCDB ==================== @@ -636,6 +643,7 @@ class MatchTPCITS gsl::span mFITInfo; ///< optional input FIT info span gsl::span mTPCRefitterShMap; ///< externally set TPC clusters sharing map + gsl::span mTPCRefitterOccMap; ///< externally set TPC clusters occupancy map const o2::itsmft::TopologyDictionary* mITSDict{nullptr}; // cluster patterns dictionary @@ -667,7 +675,7 @@ class MatchTPCITS std::vector mTPCLblWork; ///< TPC track labels std::vector mITSLblWork; ///< ITS track labels std::vector mWinnerChi2Refit; ///< vector of refitChi2 for winners - + std::vector mTBinClOcc; ///< TPC occupancy histo: i-th entry is the integrated occupancy for ~1 orbit starting from the TB = i*mNTPCOccBinLength // ------------------------------ std::vector mTPCABSeeds; ///< pool of primary TPC seeds for AB ///< indices of selected track entries in mTPCWork (for tracks selected by AfterBurner) diff --git a/Detectors/GlobalTracking/include/GlobalTracking/TrackCuts.h b/Detectors/GlobalTracking/include/GlobalTracking/TrackCuts.h index 3c08b769fb07d..215e5e8a72f63 100644 --- a/Detectors/GlobalTracking/include/GlobalTracking/TrackCuts.h +++ b/Detectors/GlobalTracking/include/GlobalTracking/TrackCuts.h @@ -104,12 +104,11 @@ class TrackCuts const auto& tpcTrk = data.getTPCTrack(contributorsGID[GID::TPC]); math_utils::Point3D v{}; // vertex not defined?! std::array dca; - if (tpcTrk.getPt() < mPtTPCCut || - std::abs(tpcTrk.getEta()) > mEtaTPCCut || // TODO: define 2 different values for min and max (***) - tpcTrk.getNClusters() < mNTPCClustersCut || - (!(const_cast(tpcTrk).propagateParamToDCA(v, mBz, &dca, mDCATPCCut)) || - std::abs(dca[0]) > mDCATPCCutY) || - std::hypot(dca[0], dca[1]) > mDCATPCCut) { + if (tpcTrk.getPt() < mPtTPCCut || std::abs(tpcTrk.getEta()) > mEtaTPCCut || tpcTrk.getNClusters() < mNTPCClustersCut) { // TODO: define 2 different values for min and max (***) + return false; + } + o2::track::TrackPar trTmp(tpcTrk); + if (!trTmp.propagateParamToDCA(v, mBz, &dca, mDCATPCCut) || std::abs(dca[0]) > mDCATPCCutY || std::hypot(dca[0], dca[1]) > mDCATPCCut) { return false; } } diff --git a/Detectors/GlobalTracking/src/MatchCosmics.cxx b/Detectors/GlobalTracking/src/MatchCosmics.cxx index 3d9453bca3f1d..90964fb1c05fa 100644 --- a/Detectors/GlobalTracking/src/MatchCosmics.cxx +++ b/Detectors/GlobalTracking/src/MatchCosmics.cxx @@ -89,12 +89,14 @@ void MatchCosmics::refitWinners(const o2::globaltracking::RecoContainer& data) auto tpcTBinMUSInv = 1. / mTPCTBinMUS; const auto& tpcClusRefs = data.getTPCTracksClusterRefs(); const auto& tpcClusShMap = data.clusterShMapTPC; + const auto& tpcClusOccMap = data.occupancyMapTPC; std::unique_ptr tpcRefitter; if (data.inputsTPCclusters) { tpcRefitter = std::make_unique(&data.inputsTPCclusters->clusterIndex, mTPCCorrMapsHelper, mBz, - tpcClusRefs.data(), tpcClusShMap.data(), - nullptr, o2::base::Propagator::Instance()); + tpcClusRefs.data(), 0, tpcClusShMap.data(), + tpcClusOccMap.data(), tpcClusOccMap.size(), nullptr, o2::base::Propagator::Instance()); + tpcRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500 } const auto& itsClusters = prepareITSClusters(data); diff --git a/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx b/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx index 23bf8b3b3bbcd..440bda85813a3 100644 --- a/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx +++ b/Detectors/GlobalTracking/src/MatchITSTPCQC.cxx @@ -130,22 +130,16 @@ void MatchITSTPCQC::reset() mPtDen[i]->Reset(); mPtNum_noEta0[i]->Reset(); mPtDen_noEta0[i]->Reset(); - mPtPhysPrimNum[i]->Reset(); - mPtPhysPrimDen[i]->Reset(); // Phi mPhiNum[i]->Reset(); mPhiDen[i]->Reset(); - mPhiPhysPrimNum[i]->Reset(); - mPhiPhysPrimDen[i]->Reset(); mPhiVsPtNum[i]->Reset(); mPhiVsPtDen[i]->Reset(); // Eta mEtaNum[i]->Reset(); mEtaDen[i]->Reset(); - mEtaPhysPrimNum[i]->Reset(); - mEtaPhysPrimDen[i]->Reset(); mEtaVsPtNum[i]->Reset(); mEtaVsPtDen[i]->Reset(); @@ -157,6 +151,10 @@ void MatchITSTPCQC::reset() mChi2VsPtNum[i]->Reset(); mChi2VsPtDen[i]->Reset(); + // 1/Pt + m1OverPtNum[i]->Reset(); + m1OverPtDen[i]->Reset(); + if (mUseTrkPID) { // Vs Tracking PID hypothesis for (int j = 0; j < o2::track::PID::NIDs; ++j) { // Pt @@ -170,12 +168,22 @@ void MatchITSTPCQC::reset() mEtaDenVsTrkPID[i][j]->Reset(); } } - // 1/Pt - m1OverPtNum[i]->Reset(); - m1OverPtDen[i]->Reset(); - m1OverPtPhysPrimNum[i]->Reset(); - m1OverPtPhysPrimDen[i]->Reset(); + + if (mUseMC) { + mPtPhysPrimNum[i]->Reset(); + mPtPhysPrimDen[i]->Reset(); + + mPhiPhysPrimNum[i]->Reset(); + mPhiPhysPrimDen[i]->Reset(); + + mEtaPhysPrimNum[i]->Reset(); + mEtaPhysPrimDen[i]->Reset(); + + m1OverPtPhysPrimNum[i]->Reset(); + m1OverPtPhysPrimDen[i]->Reset(); + } } + // Residuals mResidualPt->Reset(); mResidualPhi->Reset(); @@ -192,181 +200,167 @@ void MatchITSTPCQC::reset() //__________________________________________________________ bool MatchITSTPCQC::init() { - + LOGP(debug, "Creating Variable Binning"); std::array title{"TPC", "ITS"}; std::array etaSel{"", ", |eta| < 0.9"}; std::array maxNCls{156, 7}; + // log binning for pT + const Int_t nbinsPt = 100; + const Double_t xminPt = 0.01; + const Double_t xmaxPt = 20; + Double_t* xbinsPt = new Double_t[nbinsPt + 1]; + Double_t xlogminPt = TMath::Log10(xminPt); + Double_t xlogmaxPt = TMath::Log10(xmaxPt); + Double_t dlogxPt = (xlogmaxPt - xlogminPt) / nbinsPt; + for (int i = 0; i <= nbinsPt; i++) { + Double_t xlogPt = xlogminPt + i * dlogxPt; + xbinsPt[i] = TMath::Exp(TMath::Log(10) * xlogPt); + } + + LOGP(debug, "Creating Histograms"); + // Data and MC for (int i = 0; i < matchType::SIZE; ++i) { // Pt mPtNum[i] = new TH1D(Form("mPtNum_%s", title[i].c_str()), Form("Pt distribution of ITSTPC matched tracks, wrt %s tracks %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + mPtNum[i]->Sumw2(); + mPtNum[i]->SetOption("logy"); + mPtNum[i]->GetYaxis()->SetTitleOffset(1.4); mPtDen[i] = new TH1D(Form("mPtDen_%s", title[i].c_str()), Form("Pt distribution of %s tracks %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + mPtDen[i]->Sumw2(); + mPtDen[i]->SetOption("logy"); + mPtDen[i]->GetYaxis()->SetTitleOffset(1.4); mFractionITSTPCmatch[i] = new TEfficiency(Form("mFractionITSTPCmatch_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks wrt %s tracks vs Pt %s; Pt [GeV/c]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); mPtNum_noEta0[i] = new TH1D(Form("mPtNum_noEta0_%s", title[i].c_str()), Form("Pt distribution of ITSTPC matched tracks without |eta| < 0.05, wrt %s tracks %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + mPtNum_noEta0[i]->Sumw2(); + mPtNum_noEta0[i]->SetOption("logy"); + mPtNum_noEta0[i]->GetYaxis()->SetTitleOffset(1.4); mPtDen_noEta0[i] = new TH1D(Form("mPtDen_noEta0_%s", title[i].c_str()), Form("Pt distribution of %s tracks without |eta| < 0.05 %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + mPtDen_noEta0[i]->Sumw2(); + mPtDen_noEta0[i]->SetOption("logy"); + mPtDen_noEta0[i]->GetYaxis()->SetTitleOffset(1.4); mFractionITSTPCmatch_noEta0[i] = new TEfficiency(Form("mFractionITSTPCmatch_noEta0_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks wrt %s tracks vs Pt without |eta| < 0.05 %s; Pt [GeV/c]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f); + // Phi mPhiNum[i] = new TH1F(Form("mPhiNum_%s", title[i].c_str()), Form("Phi distribution of ITSTPC matched tracks, wrt %s tracks %s; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + mPhiNum[i]->Sumw2(); mPhiDen[i] = new TH1F(Form("mPhiDen_%s", title[i].c_str()), Form("Phi distribution of %s tracks %s; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + mPhiDen[i]->Sumw2(); mFractionITSTPCmatchPhi[i] = new TEfficiency(Form("mFractionITSTPCmatchPhi_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Phi wrt %s tracks %s; Phi [rad]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); mPhiVsPtNum[i] = new TH2F(Form("mPhiVsPtNum_%s", title[i].c_str()), Form("Phi vs Pt distribution of ITSTPC matched tracks wrt %s %s; #it{p}_{T} [GeV#it{c}]; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f, 100, 0.f, 2 * TMath::Pi()); + mPhiVsPtNum[i]->Sumw2(); mPhiVsPtDen[i] = new TH2F(Form("mPhiVsPtDen_%s", title[i].c_str()), Form("Phi vs Pt distribution of %s tracks %s; #it{p}_{T} [GeV#it{c}]; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f, 100, 0.f, 2 * TMath::Pi()); + mPhiVsPtDen[i]->Sumw2(); mFractionITSTPCmatchPhiVsPt[i] = new TEfficiency(Form("mFractionITSTPCmatchPhiVsPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks wrt %s tracks %s, Phi vs Pt; #it{p}_{T} [GeV#it{c}]; Phi [rad]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 20.f, 100, 0.f, 2 * TMath::Pi()); + // Eta mEtaNum[i] = new TH1F(Form("mEtaNum_%s", title[i].c_str()), Form("Eta distribution of ITSTPC matched tracks, wrt %s tracks; Eta; dNdEta", title[i].c_str()), 100, -2.f, 2.f); + mEtaNum[i]->Sumw2(); + mEtaNum[i]->GetYaxis()->SetTitleOffset(1.4); mEtaDen[i] = new TH1F(Form("mEtaDen_%s", title[i].c_str()), Form("Eta distribution of %s tracks; Eta; dNdEta", title[i].c_str()), 100, -2.f, 2.f); + mEtaDen[i]->Sumw2(); + mEtaDen[i]->GetYaxis()->SetTitleOffset(1.4); mFractionITSTPCmatchEta[i] = new TEfficiency(Form("mFractionITSTPCmatchEta_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks , wrt %s tracks, vs Eta; Eta; Eff", title[i].c_str()), 100, -2.f, 2.f); mEtaVsPtNum[i] = new TH2F(Form("mEtaVsPtNum_%s", title[i].c_str()), Form("Eta vs Pt distribution of ITSTPC matched tracks, wrt %s tracks; #it{p}_{T} [GeV#it{c}]; Eta", title[i].c_str()), 100, 0.f, 20.f, 100, -2.f, 2.f); + mEtaVsPtNum[i]->Sumw2(); mEtaVsPtDen[i] = new TH2F(Form("mEtaVsPtDen_%s", title[i].c_str()), Form("Eta vs Pt distribution of %s tracks; #it{p}_{T} [GeV#it{c}]; Eta", title[i].c_str()), 100, 0.f, 20.f, 100, -2.f, 2.f); + mEtaVsPtDen[i]->Sumw2(); mFractionITSTPCmatchEtaVsPt[i] = new TEfficiency(Form("mFractionITSTPCmatchEtaVsPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks, wrt %s tracks, Eta vs Pt; #it{p}_{T} [GeV#it{c}]; Eta; Eff", title[i].c_str()), 100, 0.f, 20.f, 100, -2.f, 2.f); + // Clusters mClsVsPtNum[i] = new TH2F(Form("mClsVsPtNum_%s", title[i].c_str()), Form("#Clusters vs Pt distribution of ITSTPC matched tracks, wrt %s tracks; #it{p}_{T} [GeV#it{c}]; #Clusters", title[i].c_str()), 100, 0.f, 20.f, maxNCls[i], 0, maxNCls[i]); + mClsVsPtNum[i]->Sumw2(); mClsVsPtDen[i] = new TH2F(Form("mClsVsPtDen_%s", title[i].c_str()), Form("#Clusters vs Pt distribution of %s tracks; #it{p}_{T} [GeV#it{c}]; #Clusters", title[i].c_str()), 100, 0.f, 20.f, maxNCls[i], 0, maxNCls[i]); + mClsVsPtDen[i]->Sumw2(); mFractionITSTPCmatchClsVsPt[i] = new TEfficiency(Form("mFractionITSTPCmatchClsVsPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks, wrt %s tracks, #Clusters vs Pt; #it{p}_{T} [GeV#it{c}]; #Clusters; Eff", title[i].c_str()), 100, 0.f, 20.f, maxNCls[i], 0, maxNCls[i]); + // Chi2 mChi2VsPtNum[i] = new TH2F(Form("mChi2VsPtNum_%s", title[i].c_str()), Form("Chi2 vs Pt distribution of ITSTPC matched tracks, wrt %s tracks; #it{p}_{T} [GeV#it{c}]; Chi2", title[i].c_str()), 100, 0.f, 20.f, 200, 0, 300); + mChi2VsPtNum[i]->Sumw2(); mChi2VsPtDen[i] = new TH2F(Form("mChi2VsPtDen_%s", title[i].c_str()), Form("Chi2 vs Pt distribution of %s tracks; #it{p}_{T} [GeV#it{c}]; Chi2", title[i].c_str()), 100, 0.f, 20.f, 200, 0, 300); + mChi2VsPtDen[i]->Sumw2(); mFractionITSTPCmatchChi2VsPt[i] = new TEfficiency(Form("mFractionITSTPCmatchChi2VsPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks, wrt %s tracks, Chi2 vs Pt; #it{p}_{T} [GeV#it{c}]; Chi2; Eff", title[i].c_str()), 100, 0.f, 20.f, 200, 0, 300); + + // 1/pt + m1OverPtNum[i] = new TH1D(Form("m1OverPtNum_%s", title[i].c_str()), Form("1/Pt distribution of matched tracks, wrt %s tracks %s; 1/Pt [c/GeV]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + m1OverPtNum[i]->Sumw2(); + m1OverPtDen[i] = new TH1D(Form("m1OverPtDen_%s", title[i].c_str()), Form("1/Pt distribution of %s tracks %s; 1/Pt [c/GeV]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + m1OverPtDen[i]->Sumw2(); + mFractionITSTPCmatch1OverPt[i] = new TEfficiency(Form("mFractionITSTPCmatch1OverPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs 1/Pt, wrt %s tracks %s; 1/Pt [c/GeV]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + if (mUseTrkPID) { // Vs Tracking PID hypothesis for (int j = 0; j < o2::track::PID::NIDs; ++j) { // Pt mPtNumVsTrkPID[i][j] = new TH1D(Form("mPtNumVsTrkPID_%s_PID%i", title[i].c_str(), j), Form("Pt distribution of ITSTPC matched tracks, wrt %s tracks %s, TrkPID %i; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str(), j), 100, 0.f, 20.f); + mPtNumVsTrkPID[i][j]->Sumw2(); mPtDenVsTrkPID[i][j] = new TH1D(Form("mPtDenVsTrkPID_%s_PID%i", title[i].c_str(), j), Form("Pt distribution of %s tracks %s, TrkPID %i; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str(), j), 100, 0.f, 20.f); + mPtDenVsTrkPID[i][j]->Sumw2(); mFractionITSTPCmatchPtVsTrkPID[i][j] = new TEfficiency(Form("mFractionITSTPCmatchPtVsTrkPID_%s_PID%i", title[i].c_str(), j), Form("Fraction of ITSTPC matched tracks wrt %s tracks vs Pt %s, TrkPID %i; Pt [GeV/c]; Eff", title[i].c_str(), etaSel[i].c_str(), j), 100, 0.f, 20.f); + // Phi mPhiNumVsTrkPID[i][j] = new TH1D(Form("mPhiNumVsTrkPID_%s_PID%i", title[i].c_str(), j), Form("Phi distribution of ITSTPC matched tracks, wrt %s tracks %s, TrkPID %i; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str(), j), 100, 0.f, 2 * TMath::Pi()); + mPhiNumVsTrkPID[i][j]->Sumw2(); mPhiDenVsTrkPID[i][j] = new TH1D(Form("mPhiDenVsTrkPID_%s_PID%i", title[i].c_str(), j), Form("Phi distribution of %s tracks %s, TrkPID %i; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str(), j), 100, 0.f, 2 * TMath::Pi()); + mPhiDenVsTrkPID[i][j]->Sumw2(); mFractionITSTPCmatchPhiVsTrkPID[i][j] = new TEfficiency(Form("mFractionITSTPCmatchPhiVsTrkPID_%s_PID%i", title[i].c_str(), j), Form("Fraction of ITSTPC matched tracks wrt %s tracks vs Phi %s, TrkPID %i; Phi [rad]; Eff", title[i].c_str(), etaSel[i].c_str(), j), 100, 0.f, 2 * TMath::Pi()); + // Eta mEtaNumVsTrkPID[i][j] = new TH1D(Form("mEtaNumVsTrkPID_%s_PID%i", title[i].c_str(), j), Form("Eta distribution of ITSTPC matched tracks, wrt %s tracks %s, TrkPID %i; Eta; dNdEta", title[i].c_str(), etaSel[i].c_str(), j), 100, -2.f, 2.f); + mEtaNumVsTrkPID[i][j]->Sumw2(); mEtaDenVsTrkPID[i][j] = new TH1D(Form("mEtaDenVsTrkPID_%s_PID%i", title[i].c_str(), j), Form("Eta distribution of %s tracks %s, TrkPID %i; Eta; dNdEta", title[i].c_str(), etaSel[i].c_str(), j), 100, -2.f, 2.f); + mEtaDenVsTrkPID[i][j]->Sumw2(); mFractionITSTPCmatchEtaVsTrkPID[i][j] = new TEfficiency(Form("mFractionITSTPCmatchEtaVsTrkPID_%s_PID%i", title[i].c_str(), j), Form("Fraction of ITSTPC matched tracks wrt %s tracks vs Eta %s, TrkPID %i; Eta; Eff", title[i].c_str(), etaSel[i].c_str(), j), 100, -2.f, 2.f); } } - - // 1/pt - m1OverPtNum[i] = new TH1D(Form("m1OverPtNum_%s", title[i].c_str()), Form("1/Pt distribution of matched tracks, wrt %s tracks %s; 1/Pt [c/GeV]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); - m1OverPtDen[i] = new TH1D(Form("m1OverPtDen_%s", title[i].c_str()), Form("1/Pt distribution of %s tracks %s; 1/Pt [c/GeV]; dNdPt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); - mFractionITSTPCmatch1OverPt[i] = new TEfficiency(Form("mFractionITSTPCmatch1OverPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs 1/Pt, wrt %s tracks %s; 1/Pt [c/GeV]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); - - // These will be empty in case of no MC info... - mPhiPhysPrimNum[i] = new TH1F(Form("mPhiPhysPrimNum_%s", title[i].c_str()), Form("Phi distribution of matched tracks (physical primary), wrt %s tracks %s; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); - mPhiPhysPrimDen[i] = new TH1F(Form("mPhiPhysPrimDen_%s", title[i].c_str()), Form("Phi distribution of %s tracks (physical primary) %s; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); - mFractionITSTPCmatchPhiPhysPrim[i] = new TEfficiency(Form("mFractionITSTPCmatchPhiPhysPrim_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Phi (physical primary), wrt %s tracks %s; Phi [rad]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); - mEtaPhysPrimNum[i] = new TH1F(Form("mEtaPhysPrimNum_%s", title[i].c_str()), Form("Eta distribution of matched tracks (physical primary), wrt %s tracks; Eta; dNdEta", title[i].c_str()), 100, -2.f, 2.f); - mEtaPhysPrimDen[i] = new TH1F(Form("mEtaPhysPrimDen_%s", title[i].c_str()), Form("Eta distribution of %s tracks (physical primary); Eta; dNdEta", title[i].c_str()), 100, -2.f, 2.f); - mFractionITSTPCmatchEtaPhysPrim[i] = new TEfficiency(Form("mFractionITSTPCmatchEtaPhysPrim_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Eta (physical primary), wrt %s tracks; Eta; Eff", title[i].c_str()), 100, -2.f, 2.f); } mResidualPt = new TH2F("mResidualPt", "Residuals of ITS-TPC matching in #it{p}_{T}; #it{p}_{T}^{ITS-TPC} [GeV/c]; #it{p}_{T}^{ITS-TPC} - #it{p}_{T}^{TPC} [GeV/c]", 100, 0.f, 20.f, 100, -1.f, 1.f); mResidualPhi = new TH2F("mResidualPhi", "Residuals of ITS-TPC matching in #it{#phi}; #it{#phi}^{ITS-TPC} [rad]; #it{#phi}^{ITS-TPC} - #it{#phi}^{TPC} [rad]", 100, 0.f, 2 * TMath::Pi(), 100, -1.f, 1.f); mResidualEta = new TH2F("mResidualEta", "Residuals of ITS-TPC matching in #it{#eta}; #it{#eta}^{ITS-TPC}; #it{#eta}^{ITS-TPC} - #it{#eta}^{TPC}", 100, -2.f, 2.f, 100, -1.f, 1.f); mChi2Matching = new TH1F("mChi2Matching", "Chi2 of matching; chi2", 200, 0, 300); + mChi2Matching->SetOption("logy"); + mChi2Matching->GetYaxis()->SetTitleOffset(1.4); mChi2Refit = new TH1F("mChi2Refit", "Chi2 of refit; chi2", 200, 0, 300); + mChi2Refit->SetOption("logy"); + mChi2Refit->GetYaxis()->SetTitleOffset(1.4); mDCAr = new TH1F("mDCAr", "DCA of TPC tracks; DCAr", 200, -100, 100); mDCArVsPtNum = new TH2F("mDCArVsPtNum", "DCA of TPC tracks Vs Pt Num; #it{p}_{T} [GeV/c]; DCAr", 100, 0, 20., 200, -30, 30); + mDCArVsPtNum->Sumw2(); mDCArVsPtDen = new TH2F("mDCArVsPtDen", "DCA of TPC tracks Vs Pt Den; #it{p}_{T} [GeV/c]; DCAr", 100, 0, 20., 200, -30, 30); + mDCArVsPtDen->Sumw2(); mFractionITSTPCmatchDCArVsPt = new TEfficiency("mFractionITSTPCmatchDCArVsPt", "Fraction of ITSTPC matched tracks wrt TPC vs DCAr; #it{p}_{T} [GeV#it{c}]; DCAr; Eff", 100, 0, 20., 200, -30, 30); - // log binning for pT - const Int_t nbinsPt = 100; - const Double_t xminPt = 0.01; - const Double_t xmaxPt = 20; - Double_t* xbinsPt = new Double_t[nbinsPt + 1]; - Double_t xlogminPt = TMath::Log10(xminPt); - Double_t xlogmaxPt = TMath::Log10(xmaxPt); - Double_t dlogxPt = (xlogmaxPt - xlogminPt) / nbinsPt; - for (int i = 0; i <= nbinsPt; i++) { - Double_t xlogPt = xlogminPt + i * dlogxPt; - xbinsPt[i] = TMath::Exp(TMath::Log(10) * xlogPt); - } mTimeResVsPt = new TH2F("mTimeResVsPt", "Time resolution vs Pt; Pt [GeV/c]; time res [us]", nbinsPt, xbinsPt, 100, 0.f, 2.f); - - for (int i = 0; i < matchType::SIZE; ++i) { - mPtPhysPrimNum[i] = new TH1F(Form("mPtPhysPrimNum_%s", title[i].c_str()), Form("Pt distribution of matched tracks (physical primary), wrt %s tracks %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), nbinsPt, xbinsPt); - mPtPhysPrimDen[i] = new TH1F(Form("mPtPhysPrimDen_%s", title[i].c_str()), Form("Pt distribution of %s tracks (physical primary) %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), nbinsPt, xbinsPt); - mFractionITSTPCmatchPhysPrim[i] = new TEfficiency(Form("mFractionITSTPCmatchPhysPrim_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Pt (physical primary), wrt %s tracks %s; Pt [GeV/c]; Eff", title[i].c_str(), etaSel[i].c_str()), nbinsPt, xbinsPt); - m1OverPtPhysPrimNum[i] = new TH1D(Form("m1OverPtPhysPrimNum_%s", title[i].c_str()), Form("1/Pt distribution of matched tracks (physical primary), wrt %s tracks %s; 1/Pt [c/GeV]; dNd1/Pt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); - m1OverPtPhysPrimDen[i] = new TH1D(Form("m1OverPtPhysPrimDen_%s", title[i].c_str()), Form("1/PtPt distribution of %s tracks (physical primary) %s; 1/Pt [c/GeV]; dNd1/Pt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); - mFractionITSTPCmatchPhysPrim1OverPt[i] = new TEfficiency(Form("mFractionITSTPCmatchPhysPrim1OverPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs 1/Pt (physical primary), wrt %s tracks %s; 1/Pt [c/GeV]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); - - // some extra settings - // Pt - mPtNum[i]->Sumw2(); - mPtDen[i]->Sumw2(); - mPtNum_noEta0[i]->Sumw2(); - mPtDen_noEta0[i]->Sumw2(); - mPtPhysPrimNum[i]->Sumw2(); - mPtPhysPrimDen[i]->Sumw2(); - - // Phi - mPhiNum[i]->Sumw2(); - mPhiDen[i]->Sumw2(); - mPhiVsPtNum[i]->Sumw2(); - mPhiVsPtDen[i]->Sumw2(); - mPhiPhysPrimNum[i]->Sumw2(); - mPhiPhysPrimDen[i]->Sumw2(); - - // Eta - mEtaNum[i]->Sumw2(); - mEtaDen[i]->Sumw2(); - mEtaPhysPrimNum[i]->Sumw2(); - mEtaPhysPrimDen[i]->Sumw2(); - mEtaVsPtNum[i]->Sumw2(); - mEtaVsPtDen[i]->Sumw2(); - - // Clusters - mClsVsPtNum[i]->Sumw2(); - mClsVsPtDen[i]->Sumw2(); - - // Chi2 - mChi2VsPtNum[i]->Sumw2(); - mChi2VsPtDen[i]->Sumw2(); - - if (mUseTrkPID) { // Vs Tracking PID hypothesis - for (int j = 0; j < o2::track::PID::NIDs; ++j) { - // Pt - mPtNumVsTrkPID[i][j]->Sumw2(); - mPtDenVsTrkPID[i][j]->Sumw2(); - // Phi - mPhiNumVsTrkPID[i][j]->Sumw2(); - mPhiDenVsTrkPID[i][j]->Sumw2(); - // Eta - mEtaNumVsTrkPID[i][j]->Sumw2(); - mEtaDenVsTrkPID[i][j]->Sumw2(); - } - } - - m1OverPtNum[i]->Sumw2(); - m1OverPtDen[i]->Sumw2(); - m1OverPtPhysPrimNum[i]->Sumw2(); - m1OverPtPhysPrimDen[i]->Sumw2(); - - mPtNum_noEta0[i]->SetOption("logy"); - mPtDen_noEta0[i]->SetOption("logy"); - mPtNum[i]->SetOption("logy"); - mPtDen[i]->SetOption("logy"); - - mPtNum[i]->GetYaxis()->SetTitleOffset(1.4); - mPtDen[i]->GetYaxis()->SetTitleOffset(1.4); - mPtNum_noEta0[i]->GetYaxis()->SetTitleOffset(1.4); - mPtDen_noEta0[i]->GetYaxis()->SetTitleOffset(1.4); - mEtaNum[i]->GetYaxis()->SetTitleOffset(1.4); - mEtaDen[i]->GetYaxis()->SetTitleOffset(1.4); - } - - mChi2Matching->SetOption("logy"); - mChi2Refit->SetOption("logy"); mTimeResVsPt->SetOption("colz logz logy logx"); - - mChi2Matching->GetYaxis()->SetTitleOffset(1.4); - mChi2Refit->GetYaxis()->SetTitleOffset(1.4); mTimeResVsPt->GetYaxis()->SetTitleOffset(1.4); - mDCArVsPtNum->Sumw2(); - mDCArVsPtDen->Sumw2(); - if (mUseMC) { mcReader.initFromDigitContext("collisioncontext.root"); + + for (int i = 0; i < matchType::SIZE; ++i) { + mPtPhysPrimNum[i] = new TH1F(Form("mPtPhysPrimNum_%s", title[i].c_str()), Form("Pt distribution of matched tracks (physical primary), wrt %s tracks %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), nbinsPt, xbinsPt); + mPtPhysPrimNum[i]->Sumw2(); + mPtPhysPrimDen[i] = new TH1F(Form("mPtPhysPrimDen_%s", title[i].c_str()), Form("Pt distribution of %s tracks (physical primary) %s; Pt [GeV/c]; dNdPt", title[i].c_str(), etaSel[i].c_str()), nbinsPt, xbinsPt); + mPtPhysPrimDen[i]->Sumw2(); + mFractionITSTPCmatchPhiPhysPrim[i] = new TEfficiency(Form("mFractionITSTPCmatchPhiPhysPrim_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Phi (physical primary), wrt %s tracks %s; Phi [rad]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + + mEtaPhysPrimNum[i] = new TH1F(Form("mEtaPhysPrimNum_%s", title[i].c_str()), Form("Eta distribution of matched tracks (physical primary), wrt %s tracks; Eta; dNdEta", title[i].c_str()), 100, -2.f, 2.f); + mEtaPhysPrimNum[i]->Sumw2(); + mEtaPhysPrimDen[i] = new TH1F(Form("mEtaPhysPrimDen_%s", title[i].c_str()), Form("Eta distribution of %s tracks (physical primary); Eta; dNdEta", title[i].c_str()), 100, -2.f, 2.f); + mEtaPhysPrimDen[i]->Sumw2(); + mFractionITSTPCmatchEtaPhysPrim[i] = new TEfficiency(Form("mFractionITSTPCmatchEtaPhysPrim_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Eta (physical primary), wrt %s tracks; Eta; Eff", title[i].c_str()), 100, -2.f, 2.f); + + mPhiPhysPrimNum[i] = new TH1F(Form("mPhiPhysPrimNum_%s", title[i].c_str()), Form("Phi distribution of matched tracks (physical primary), wrt %s tracks %s; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + mPhiPhysPrimNum[i]->Sumw2(); + mPhiPhysPrimDen[i] = new TH1F(Form("mPhiPhysPrimDen_%s", title[i].c_str()), Form("Phi distribution of %s tracks (physical primary) %s; Phi [rad]; dNdPhi", title[i].c_str(), etaSel[i].c_str()), 100, 0.f, 2 * TMath::Pi()); + mPhiPhysPrimDen[i]->Sumw2(); + mFractionITSTPCmatchPhysPrim[i] = new TEfficiency(Form("mFractionITSTPCmatchPhysPrim_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs Pt (physical primary), wrt %s tracks %s; Pt [GeV/c]; Eff", title[i].c_str(), etaSel[i].c_str()), nbinsPt, xbinsPt); + + m1OverPtPhysPrimNum[i] = new TH1D(Form("m1OverPtPhysPrimNum_%s", title[i].c_str()), Form("1/Pt distribution of matched tracks (physical primary), wrt %s tracks %s; 1/Pt [c/GeV]; dNd1/Pt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + m1OverPtPhysPrimNum[i]->Sumw2(); + m1OverPtPhysPrimDen[i] = new TH1D(Form("m1OverPtPhysPrimDen_%s", title[i].c_str()), Form("1/PtPt distribution of %s tracks (physical primary) %s; 1/Pt [c/GeV]; dNd1/Pt", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + m1OverPtPhysPrimDen[i]->Sumw2(); + mFractionITSTPCmatchPhysPrim1OverPt[i] = new TEfficiency(Form("mFractionITSTPCmatchPhysPrim1OverPt_%s", title[i].c_str()), Form("Fraction of ITSTPC matched tracks vs 1/Pt (physical primary), wrt %s tracks %s; 1/Pt [c/GeV]; Eff", title[i].c_str(), etaSel[i].c_str()), 100, -20.f, 20.f); + } } return true; @@ -432,9 +426,6 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) for (size_t itrk = 0; itrk < mTPCTracks.size(); ++itrk) { auto const& trkTpc = mTPCTracks[itrk]; - // if (selectTrack(trkTpc)) { - // isTPCTrackSelectedEntry[itrk] = true; - // } o2::dataformats::GlobalTrackID id(itrk, GID::TPC); if (cuts.isSelected(id, mRecoCont)) { // NB: same cuts for numerator and denominator tracks of ITS-TPC matching @@ -876,31 +867,6 @@ void MatchITSTPCQC::run(o2::framework::ProcessingContext& ctx) } //__________________________________________________________ - -bool MatchITSTPCQC::selectTrack(o2::tpc::TrackTPC const& track) -{ - - if (track.getPt() < mPtCut) { - return false; - } - if (std::abs(track.getEta()) > mEtaCut) { - return false; - } - if (track.getNClusters() < mNTPCClustersCut) { - return false; - } - - math_utils::Point3D v{}; - std::array dca{}; - if (!(const_cast(track).propagateParamToDCA(v, mBz, &dca, mDCATPCCut)) || std::abs(dca[0]) > mDCATPCCutY) { - return false; - } - - return true; -} - -//__________________________________________________________ - void MatchITSTPCQC::finalize() { diff --git a/Detectors/GlobalTracking/src/MatchTOF.cxx b/Detectors/GlobalTracking/src/MatchTOF.cxx index fa1b0c3a3d07a..a384c489520fd 100644 --- a/Detectors/GlobalTracking/src/MatchTOF.cxx +++ b/Detectors/GlobalTracking/src/MatchTOF.cxx @@ -185,12 +185,44 @@ void MatchTOF::run(const o2::globaltracking::RecoContainer& inp, unsigned long f matchingPair.setFakeMatch(); } } + } else { + for (auto& matchingPair : mMatchedTracksPairsSec[sec]) { + int bct0 = int((matchingPair.getSignal() - 10000) * Geo::BC_TIME_INPS_INV); + float tof = matchingPair.getSignal() - bct0 * Geo::BC_TIME_INPS; + if (abs(tof - matchingPair.getLTIntegralOut().getTOF(2)) < 600) { + } else if (abs(tof - matchingPair.getLTIntegralOut().getTOF(3)) < 600) { + } else if (abs(tof - matchingPair.getLTIntegralOut().getTOF(4)) < 600) { + } else if (abs(tof - matchingPair.getLTIntegralOut().getTOF(0)) < 600) { + } else if (abs(tof - matchingPair.getLTIntegralOut().getTOF(1)) < 600) { + } else if (abs(tof - matchingPair.getLTIntegralOut().getTOF(5)) < 600) { + } else if (abs(tof - matchingPair.getLTIntegralOut().getTOF(6)) < 600) { + } else if (abs(tof - matchingPair.getLTIntegralOut().getTOF(7)) < 600) { + } else if (abs(tof - matchingPair.getLTIntegralOut().getTOF(8)) < 600) { + } else { // no pion, kaon, proton, electron, muon, deuteron, triton, 3He, 4He + matchingPair.setFakeMatch(); + } + } } } LOG(debug) << "...done. Now check the best matches"; nMatches[sec] = mMatchedTracksPairsSec[sec].size(); selectBestMatches(sec); + + if (mStoreMatchable) { + for (auto& matchingPair : mMatchedTracksPairsSec[sec]) { + trkType trkTypeSplitted = trkType::TPC; + auto sourceID = matchingPair.getTrackRef().getSource(); + if (sourceID == o2::dataformats::GlobalTrackID::ITSTPC) { + trkTypeSplitted = trkType::ITSTPC; + } else if (sourceID == o2::dataformats::GlobalTrackID::TPCTRD) { + trkTypeSplitted = trkType::TPCTRD; + } else if (sourceID == o2::dataformats::GlobalTrackID::ITSTPCTRD) { + trkTypeSplitted = trkType::ITSTPCTRD; + } + matchingPair.setTrackType(trkTypeSplitted); + } + } } std::string nMatchesStr = "Number of pairs matched per sector: "; for (int sec = o2::constants::math::NSectors - 1; sec > -1; sec--) { @@ -490,6 +522,7 @@ bool MatchTOF::prepareTPCData() mTPCTracksArray = mRecoCont->getTPCTracks(); mTPCTrackClusIdx = mRecoCont->getTPCTracksClusterRefs(); mTPCRefitterShMap = mRecoCont->clusterShMapTPC; + mTPCRefitterOccMap = mRecoCont->occupancyMapTPC; } return true; @@ -520,7 +553,7 @@ void MatchTOF::propagateTPCTracks(int sec) } if (trc.getX() < o2::constants::geom::XTPCOuterRef - 1.) { - if (!propagateToRefX(trc, o2::constants::geom::XTPCOuterRef, 10, intLT0) || TMath::Abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagat> + if (!propagateToRefXWithoutCov(trc, o2::constants::geom::XTPCOuterRef, 10, mBz) || TMath::Abs(trc.getZ()) > Geo::MAXHZTOF) { // we check that the propagat> mNotPropagatedToTOF[trkType::UNCONS]++; continue; } @@ -800,6 +833,7 @@ void MatchTOF::doMatching(int sec) int nStripsCrossedInPropagation = 0; // how many strips were hit during the propagation auto& trackWork = mTracksWork[sec][type][cacheTrk[itrk]]; auto& trefTrk = trackWork.first; + float pt = trefTrk.getPt(); auto& intLT = mLTinfos[sec][type][cacheTrk[itrk]]; float timeShift = intLT.getL() * 33.35641; // integrated time for 0.75 beta particles in ps, to take into account the t.o.f. delay with respect the interaction BC // using beta=0.75 to cover beta range [0.59 , 1.04] also for a 8 m track lenght with a 10 ns track resolution (TRD) @@ -1002,6 +1036,7 @@ void MatchTOF::doMatching(int sec) // set event indexes (to be checked) int eventIndexTOFCluster = mTOFClusSectIndexCache[indices[0]][itof]; mMatchedTracksPairsSec[sec].emplace_back(cacheTrk[itrk], eventIndexTOFCluster, mTOFClusWork[cacheTOF[itof]].getTime(), chi2, trkLTInt[iPropagation], mTrackGid[sec][type][cacheTrk[itrk]], type, (trefTOF.getTime() - (minTrkTime + maxTrkTime - 100E3) * 0.5) * 1E-6, trefTOF.getZ(), resX, resZ); // subracting 100 ns to max track which was artificially added + mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setPt(pt); } } } @@ -1047,6 +1082,7 @@ void MatchTOF::doMatchingForTPC(int sec) for (int itrk = 0; itrk < cacheTrk.size(); itrk++) { auto& trackWork = mTracksWork[sec][trkType::UNCONS][cacheTrk[itrk]]; auto& trefTrk = trackWork.first; + float pt = trefTrk.getPt(); auto& intLT = mLTinfos[sec][trkType::UNCONS][cacheTrk[itrk]]; float timeShift = intLT.getL() * 33.35641; // integrated time for 0.75 beta particles in ps, to take into account the t.o.f. delay with respect the interaction BC @@ -1332,6 +1368,7 @@ void MatchTOF::doMatchingForTPC(int sec) // set event indexes (to be checked) int eventIndexTOFCluster = mTOFClusSectIndexCache[indices[0]][itof]; mMatchedTracksPairsSec[sec].emplace_back(cacheTrk[itrk], eventIndexTOFCluster, mTOFClusWork[cacheTOF[itof]].getTime(), chi2, trkLTInt[ibc][iPropagation], mTrackGid[sec][trkType::UNCONS][cacheTrk[itrk]], trkType::UNCONS, trefTOF.getTime() * 1E-6 - tpctime, trefTOF.getZ(), resX, resZ); // TODO: check if this is correct! + mMatchedTracksPairsSec[sec][mMatchedTracksPairsSec[sec].size() - 1].setPt(pt); } } } @@ -1653,7 +1690,7 @@ bool MatchTOF::propagateToRefX(o2::track::TrackParCov& trc, float xRef, float st } //______________________________________________ -bool MatchTOF::propagateToRefXWithoutCov(o2::track::TrackParCov& trc, float xRef, float stepInCm, float bzField) +bool MatchTOF::propagateToRefXWithoutCov(const o2::track::TrackParCov& trc, float xRef, float stepInCm, float bzField) { // propagate track to matching reference X without using the covariance matrix // we create the copy of the track in a TrackPar object (no cov matrix) @@ -1768,7 +1805,7 @@ bool MatchTOF::makeConstrainedTPCTrack(int matchedID, o2::dataformats::TrackTPCT if (mTPCClusterIdxStruct) { // refit was requested float chi2 = 0; mTPCRefitter->setTrackReferenceX(o2::constants::geom::XTPCInnerRef); - if (mTPCRefitter->RefitTrackAsTrackParCov(trConstr, tpcTrOrig.getClusterRef(), timeTOFTB, &chi2, false, true) < 0) { // outward refit after resetting cov.mat. + if (mTPCRefitter->RefitTrackAsTrackParCov(trConstr, tpcTrOrig.getClusterRef(), timeTOFTB, &chi2, false, true) < 0) { // inward refit after resetting cov.mat. LOGP(debug, "Inward Refit failed {}", trConstr.asString()); return false; } @@ -1797,7 +1834,7 @@ void MatchTOF::checkRefitter() { if (mTPCClusterIdxStruct) { mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, mTPCCorrMapsHelper, mBz, - mTPCTrackClusIdx.data(), mTPCRefitterShMap.data(), - nullptr, o2::base::Propagator::Instance()); + mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), + mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, o2::base::Propagator::Instance()); } } diff --git a/Detectors/GlobalTracking/src/MatchTPCITS.cxx b/Detectors/GlobalTracking/src/MatchTPCITS.cxx index 5bfc9df56369b..afb26ddcf47c9 100644 --- a/Detectors/GlobalTracking/src/MatchTPCITS.cxx +++ b/Detectors/GlobalTracking/src/MatchTPCITS.cxx @@ -45,6 +45,8 @@ #include "ITStracking/IOUtils.h" #include "GPUO2Interface.h" // Needed for propper settings in GPUParam.h +#include "GPUParam.h" +#include "GPUParam.inc" #ifdef WITH_OPENMP #include #endif @@ -400,23 +402,23 @@ int MatchTPCITS::getNMatchRecordsITS(const TrackLocITS& tTPC) const } //______________________________________________ -void MatchTPCITS::addTPCSeed(const o2::track::TrackParCov& _tr, float t0, float terr, GTrackID srcGID, int tpcID) +int MatchTPCITS::addTPCSeed(const o2::track::TrackParCov& _tr, float t0, float terr, GTrackID srcGID, int tpcID) { // account single TPC seed, can be from standalone TPC track or constrained track from match to TRD and/or TOF const float SQRT12DInv = 2. / sqrt(12.); if (_tr.getX() > o2::constants::geom::XTPCInnerRef + 0.1 || std::abs(_tr.getQ2Pt()) > mMinTPCTrackPtInv) { - return; + return -99; } const auto& tpcOrig = mTPCTracksArray[tpcID]; // discard tracks w/o certain number of total or innermost pads (last cluster is innermost one) if (tpcOrig.getNClusterReferences() < mParams->minTPCClusters) { - return; + return -89; } uint8_t clSect = 0, clRow = 0; uint32_t clIdx = 0; tpcOrig.getClusterReference(mTPCTrackClusIdx, tpcOrig.getNClusterReferences() - 1, clSect, clRow, clIdx); if (clRow > mParams->askMinTPCRow[clSect]) { - return; + return -9; } // create working copy of track param bool extConstrained = srcGID.getSource() != GTrackID::TPC; @@ -447,13 +449,14 @@ void MatchTPCITS::addTPCSeed(const o2::track::TrackParCov& _tr, float t0, float } if (!propagateToRefX(trc)) { mTPCWork.pop_back(); // discard track whose propagation to XMatchingRef failed - return; + return -1; } if (mMCTruthON) { mTPCLblWork.emplace_back(mTPCTrkLabels[tpcID]); } // cache work track index mTPCSectIndexCache[o2::math_utils::angle2Sector(trc.getAlpha())].push_back(mTPCWork.size() - 1); + return 0; } //______________________________________________ @@ -467,6 +470,8 @@ bool MatchTPCITS::prepareTPCData() mTPCTrackClusIdx = inp.getTPCTracksClusterRefs(); mTPCClusterIdxStruct = &inp.inputsTPCclusters->clusterIndex; mTPCRefitterShMap = inp.clusterShMapTPC; + mTPCRefitterOccMap = inp.occupancyMapTPC; + if (mMCTruthON) { mTPCTrkLabels = inp.getTPCTracksMCLabels(); } @@ -481,6 +486,32 @@ bool MatchTPCITS::prepareTPCData() mTPCSectIndexCache[sec].reserve(100 + 1.2 * ntrW / o2::constants::math::NSectors); } + mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, mTPCCorrMapsHelper, mBz, mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, o2::base::Propagator::Instance()); + mTPCRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500 + mNTPCOccBinLength = mTPCRefitter->getParam()->rec.tpc.occupancyMapTimeBins; + mTBinClOcc.clear(); + if (mNTPCOccBinLength > 1 && mTPCRefitterOccMap.size()) { + mNTPCOccBinLengthInv = 1. / mNTPCOccBinLength; + int nTPCBins = mNHBPerTF * o2::constants::lhc::LHCMaxBunches / 8, ninteg = 0; + int nTPCOccBins = nTPCBins * mNTPCOccBinLengthInv, sumBins = std::max(1, int(o2::constants::lhc::LHCMaxBunches / 8 * mNTPCOccBinLengthInv)); + mTBinClOcc.resize(nTPCOccBins); + std::vector mltHistTB(nTPCOccBins); + float sm = 0., tb = 0.5 * mNTPCOccBinLength; + for (int i = 0; i < nTPCOccBins; i++) { + mltHistTB[i] = mTPCRefitter->getParam()->GetUnscaledMult(tb); + tb += mNTPCOccBinLength; + } + for (int i = nTPCOccBins; i--;) { + sm += mltHistTB[i]; + if (i + sumBins < nTPCOccBins) { + sm -= mltHistTB[i + sumBins]; + } + mTBinClOcc[i] = sm; + } + } else { + mTBinClOcc.resize(1); + } + auto creator = [this](auto& trk, GTrackID gid, float time0, float terr) { if constexpr (isITSTrack()) { // do nothing, ITS tracks will be processed in a direct loop over ROFs @@ -490,20 +521,27 @@ bool MatchTPCITS::prepareTPCData() } else if (std::abs(trk.getQ2Pt()) > mMinTPCTrackPtInv) { return true; } + int resAdd = -100; + int tpcIndex = -1; if constexpr (isTPCTrack()) { // unconstrained TPC track, with t0 = TrackTPC.getTime0+0.5*(DeltaFwd-DeltaBwd) and terr = 0.5*(DeltaFwd+DeltaBwd) in TimeBins if (!this->mSkipTPCOnly && trk.getNClusters() > 0) { - this->addTPCSeed(trk, this->tpcTimeBin2MUS(time0), this->tpcTimeBin2MUS(terr), gid, gid.getIndex()); + resAdd = this->addTPCSeed(trk, this->tpcTimeBin2MUS(time0), this->tpcTimeBin2MUS(terr), gid, (tpcIndex = gid.getIndex())); } } if constexpr (isTPCTOFTrack()) { // TPC track constrained by TOF time, time and its error in \mus - this->addTPCSeed(trk, time0, terr, gid, this->mRecoCont->getTPCContributorGID(gid)); + resAdd = this->addTPCSeed(trk, time0, terr, gid, (tpcIndex = this->mRecoCont->getTPCContributorGID(gid))); } if constexpr (isTRDTrack()) { // TPC track constrained by TRD trigger time, time and its error in \mus - this->addTPCSeed(trk, time0, terr, gid, this->mRecoCont->getTPCContributorGID(gid)); + resAdd = this->addTPCSeed(trk, time0, terr, gid, (tpcIndex = this->mRecoCont->getTPCContributorGID(gid))); + } +#ifdef _ALLOW_DEBUG_TREES_ + if (resAdd > -10 && mDBGOut && isDebugFlag(TPCOrigTree)) { + dumpTPCOrig(resAdd == 0, tpcIndex); } +#endif // note: TPCTRDTPF tracks are actually TRD track with extra TOF cluster return true; }; @@ -572,7 +610,6 @@ bool MatchTPCITS::prepareTPCData() mITSROFofTPCBin[ib] = itsROF; } */ - mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, mTPCCorrMapsHelper, mBz, mTPCTrackClusIdx.data(), mTPCRefitterShMap.data(), nullptr, o2::base::Propagator::Instance()); mInteractionMUSLUT.clear(); mInteractionMUSLUT.resize(maxTime + 3 * o2::constants::lhc::LHCOrbitMUS, -1); mTimer[SWPrepTPC].Stop(); @@ -1476,6 +1513,8 @@ void MatchTPCITS::fillCalibDebug(int ifit, int iTPC, const o2::dataformats::Trac itsRefAltPID.setX(-10); } } + int tb = mTPCTracksArray[tTPC.sourceID].getTime0() * mNTPCOccBinLengthInv; + float mltTPC = tb < 0 ? mTBinClOcc[0] : (tb >= mTBinClOcc.size() ? mTBinClOcc.back() : mTBinClOcc[tb]); (*mDBGOut) << "refit" << "tpcOrig=" << mTPCTracksArray[tTPC.sourceID] << "itsOrig=" << mITSTracksArray[tITS.sourceID] << "itsRef=" << tITS << "tpcRef=" << tTPC << "matchRefit=" << match << "timeCorr=" << timeC << "dTimeFT0=" << minDiffFT0 << "dTimes=" << dtimes @@ -1485,6 +1524,9 @@ void MatchTPCITS::fillCalibDebug(int ifit, int iTPC, const o2::dataformats::Trac << "itsLbl=" << mITSLblWork[iITS] << "tpcLbl=" << mTPCLblWork[iTPC]; } (*mDBGOut) << "refit" + << "multTPC=" << mltTPC + << "multITSTr=" << mITSTrackROFRec[tITS.roFrame].getNEntries() + << "multITSCl=" << mITSClusterROFRec[tITS.roFrame].getNEntries() << "tf=" << mTFCount << "\n"; } #endif @@ -2783,6 +2825,36 @@ void MatchTPCITS::setDebugFlag(UInt_t flag, bool on) } } +//_________________________________________________________ +void MatchTPCITS::dumpTPCOrig(bool acc, int tpcIndex) +{ + ///< fill debug tree for TPC original tracks (passing pT cut) + mTimer[SWDBG].Start(false); + const auto& tpcOrig = mTPCTracksArray[tpcIndex]; + uint8_t clSect = 0, clRow = 0; + uint32_t clIdx = 0; + tpcOrig.getClusterReference(mTPCTrackClusIdx, tpcOrig.getNClusterReferences() - 1, clSect, clRow, clIdx); + int tb = tpcOrig.getTime0() * mNTPCOccBinLengthInv; + float mltTPC = tb < 0 ? mTBinClOcc[0] : (tb >= mTBinClOcc.size() ? mTBinClOcc.back() : mTBinClOcc[tb]); + (*mDBGOut) << "tpcOrig" + << "tf=" << mTFCount + << "index=" << tpcIndex + << "acc=" << acc + << "chi2TPC=" << tpcOrig.getChi2() + << "nClus=" << tpcOrig.getNClusters() + << "time0=" << tpcOrig.getTime0() + << "trc=" << ((o2::track::TrackParCov&)tpcOrig) + << "minRow=" << clRow + << "multTPC=" << mltTPC; + if (mMCTruthON) { + (*mDBGOut) << "tpcOrig" + << "tpcLbl=" << mTPCTrkLabels[tpcIndex]; + } + (*mDBGOut) << "tpcOrig" + << "\n"; + mTimer[SWDBG].Stop(); +} + //_________________________________________________________ void MatchTPCITS::fillTPCITSmatchTree(int itsID, int tpcID, int rejFlag, float chi2, float tCorr) { @@ -2801,8 +2873,14 @@ void MatchTPCITS::fillTPCITSmatchTree(int itsID, int tpcID, int rejFlag, float c (*mDBGOut) << "match" << "itsLbl=" << mITSLblWork[itsID] << "tpcLbl=" << mTPCLblWork[tpcID]; } + int tb = mTPCTracksArray[trackTPC.sourceID].getTime0() * mNTPCOccBinLengthInv; + float mltTPC = tb < 0 ? mTBinClOcc[0] : (tb >= mTBinClOcc.size() ? mTBinClOcc.back() : mTBinClOcc[tb]); (*mDBGOut) << "match" - << "rejFlag=" << rejFlag << "\n"; + << "rejFlag=" << rejFlag + << "multTPC=" << mltTPC + << "multITSTr=" << mITSTrackROFRec[trackITS.roFrame].getNEntries() + << "multITSCl=" << mITSClusterROFRec[trackITS.roFrame].getNEntries() + << "\n"; mTimer[SWDBG].Stop(); } @@ -2831,7 +2909,12 @@ void MatchTPCITS::dumpWinnerMatches() (*mDBGOut) << "matchWin" << "itsLbl=" << mITSLblWork[iits] << "tpcLbl=" << mTPCLblWork[itpc]; } + int tb = mTPCTracksArray[tTPC.sourceID].getTime0() * mNTPCOccBinLengthInv; + float mltTPC = tb < 0 ? mTBinClOcc[0] : (tb >= mTBinClOcc.size() ? mTBinClOcc.back() : mTBinClOcc[tb]); (*mDBGOut) << "matchWin" + << "multTPC=" << mltTPC + << "multITSTr=" << mITSTrackROFRec[tITS.roFrame].getNEntries() + << "multITSCl=" << mITSClusterROFRec[tITS.roFrame].getNEntries() << "\n"; } mTimer[SWDBG].Stop(); diff --git a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx index 23c1010c994ce..6b83f787be17d 100644 --- a/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/PrimaryVertexingSpec.cxx @@ -161,11 +161,12 @@ void PrimaryVertexingSpec::run(ProcessingContext& pc) } mTimer.Stop(); - LOGP(info, "Found {} PVs, Time CPU/Real:{:.3f}/{:.3f} (DBScan: {:.4f}, Finder:{:.4f}, MADSel:{:.4f}, Rej.Debris:{:.4f}, Reattach:{:.4f}) | {} trials for {} TZ-clusters, max.trials: {}, Slowest TZ-cluster: {} ms of mult {}", + LOGP(info, "Found {} PVs, Time CPU/Real:{:.3f}/{:.3f} (DBScan: {:.4f}, Finder:{:.4f}, MADSel:{:.4f}, Rej.Debris:{:.4f}, Reattach:{:.4f}) | {} trials for {} TZ-clusters, max.trials: {}, Slowest TZ-cluster: {} ms of mult {} | NInitial:{}, Rejections: NoFilledBC:{}, NoIntCand:{}, Debris:{}, Quality:{}, ITSOnly:{}", vertices.size(), mTimer.CpuTime() - timeCPU0, mTimer.RealTime() - timeReal0, - mVertexer.getTimeDBScan().CpuTime(), mVertexer.getTimeVertexing().CpuTime(), mVertexer.getTimeMADSel().CpuTime(), mVertexer.getTimeDebris().CpuTime(), mVertexer.getTimeReAttach().CpuTime(), - mVertexer.getTotTrials(), mVertexer.getNTZClusters(), mVertexer.getMaxTrialsPerCluster(), - mVertexer.getLongestClusterTimeMS(), mVertexer.getLongestClusterMult()); + mVertexer.getTimeDBScan().CpuTime(), mVertexer.getTimeVertexing().CpuTime(), mVertexer.getTimeMADSel().CpuTime(), mVertexer.getTimeDebris().CpuTime(), + mVertexer.getTimeReAttach().CpuTime(), mVertexer.getTotTrials(), mVertexer.getNTZClusters(), mVertexer.getMaxTrialsPerCluster(), + mVertexer.getLongestClusterTimeMS(), mVertexer.getLongestClusterMult(), mVertexer.getNIniFound(), + mVertexer.getNKilledBCValid(), mVertexer.getNKilledIntCand(), mVertexer.getNKilledDebris(), mVertexer.getNKilledQuality(), mVertexer.getNKilledITSOnly()); } void PrimaryVertexingSpec::endOfStream(EndOfStreamContext& ec) diff --git a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx index 99ee70bdc4d1d..28ef8016565bc 100644 --- a/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/SecondaryVertexingSpec.cxx @@ -256,7 +256,7 @@ DataProcessorSpec getSecondaryVertexingSpec(GTrackID::mask_t src, bool enableCas false, // GRPLHCIF true, // GRPMagField true, // askMatLUT - useGeom && enableStrangenesTracking ? o2::base::GRPGeomRequest::Aligned : o2::base::GRPGeomRequest::None, // geometry + useGeom || enableStrangenesTracking ? o2::base::GRPGeomRequest::Aligned : o2::base::GRPGeomRequest::None, // geometry dataRequest->inputs, true); if (!useGeom && enableStrangenesTracking) { diff --git a/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx b/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx index b56c1217551ff..0dc20811087ae 100644 --- a/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/src/TPCITSMatchingSpec.cxx @@ -184,6 +184,7 @@ void TPCITSMatchingDPL::updateTimeDependentParams(ProcessingContext& pc) mMatching.setITSTimeBiasInBC(alpParams.roFrameBiasInBC); mMatching.setSkipTPCOnly(mSkipTPCOnly); mMatching.setITSTriggered(!o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS)); + mMatching.setNHBPerTF(o2::base::GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF()); mMatching.setMCTruthOn(mUseMC); mMatching.setUseFT0(mUseFT0); mMatching.setVDriftCalib(mCalibMode); diff --git a/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt b/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt index 5fbd9f15e01e6..17bad37b3c14e 100644 --- a/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt +++ b/Detectors/GlobalTrackingWorkflow/study/CMakeLists.txt @@ -14,10 +14,13 @@ o2_add_library(GlobalTrackingStudy SOURCES src/TPCTrackStudy.cxx src/TrackingStudy.cxx + src/SVStudy.cxx src/TrackMCStudy.cxx src/TPCDataFilter.cxx src/ITSOffsStudy.cxx src/DumpTracks.cxx + src/V0Ext.cxx + src/TrackInfoExt.cxx PUBLIC_LINK_LIBRARIES O2::GlobalTracking O2::GlobalTrackingWorkflowReaders O2::GlobalTrackingWorkflowHelpers @@ -26,6 +29,17 @@ o2_add_library(GlobalTrackingStudy O2::TPCWorkflow O2::SimulationDataFormat) +o2_target_root_dictionary( + GlobalTrackingStudy + HEADERS include/GlobalTrackingStudy/V0Ext.h + include/GlobalTrackingStudy/TrackInfoExt.h +) + +o2_add_executable(study-workflow + COMPONENT_NAME sv + SOURCES src/sv-study-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::GlobalTrackingStudy) + o2_add_executable(study-workflow COMPONENT_NAME tpc-track SOURCES src/tpc-track-study-workflow.cxx diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/SVStudy.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/SVStudy.h new file mode 100644 index 0000000000000..9c9453215c9a0 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/SVStudy.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_SV_STUDY_H +#define O2_SV_STUDY_H + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" +#include "ReconstructionDataFormats/Track.h" +#include "MathUtils/detail/Bracket.h" +#include "DataFormatsTPC/ClusterNative.h" + +namespace o2::svstudy +{ +/// create a processor spec +o2::framework::DataProcessorSpec getSVStudySpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, bool useMC); + +} // namespace o2::svstudy + +#endif diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackInfoExt.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackInfoExt.h new file mode 100644 index 0000000000000..90db0ca4ee37c --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/TrackInfoExt.h @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// class for extended Track info (for debugging) + +#ifndef ALICEO2_TRINFOEXT_H +#define ALICEO2_TRINFOEXT_H + +#include "ReconstructionDataFormats/MatchInfoTOF.h" +#include "ReconstructionDataFormats/DCA.h" +#include "ReconstructionDataFormats/VtxTrackIndex.h" +#include "ReconstructionDataFormats/Track.h" + +namespace o2 +{ +namespace dataformats +{ + +struct TrackInfoExt { + o2::track::TrackParCov track; + DCA dca{}; + VtxTrackIndex gid; + MatchInfoTOF infoTOF; + float ttime = 0; + float ttimeE = 0; + float xmin = 0; + float chi2ITSTPC = 0.f; + float q2ptITS = 0.f; + float q2ptTPC = 0.f; + float q2ptITSTPC = 0.f; + float q2ptITSTPCTRD = 0.f; + int nClTPC = 0; + int nClITS = 0; + int pattITS = 0; + ClassDefNV(TrackInfoExt, 1); +}; + +} // namespace dataformats +} // namespace o2 + +#endif diff --git a/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/V0Ext.h b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/V0Ext.h new file mode 100644 index 0000000000000..1beddf693c458 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/include/GlobalTrackingStudy/V0Ext.h @@ -0,0 +1,44 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// class for extended V0 info (for debugging) + +#ifndef ALICEO2_V0EXT_H +#define ALICEO2_V0EXT_H + +#include "ReconstructionDataFormats/V0.h" + +namespace o2 +{ +namespace dataformats +{ + +struct ProngInfoExt { + o2::track::TrackParCov trackTPC; + int nClTPC = 0; + int nClITS = 0; + int pattITS = 0; + float chi2ITSTPC = 0.f; + ClassDefNV(ProngInfoExt, 1); +}; + +struct V0Ext { + V0 v0; + V0Index v0ID; + std::array prInfo{}; + const ProngInfoExt& getPrInfo(int i) const { return prInfo[i]; } + ClassDefNV(V0Ext, 1); +}; + +} // namespace dataformats +} // namespace o2 + +#endif diff --git a/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h b/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h index c85dd2d378ccb..9b14e24d03cb4 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h +++ b/Detectors/GlobalTrackingWorkflow/study/src/GlobalTrackingStudyLinkDef.h @@ -15,4 +15,11 @@ #pragma link off all classes; #pragma link off all functions; +#pragma link C++ class o2::dataformats::ProngInfoExt + ; +#pragma link C++ class o2::dataformats::V0Ext + ; +#pragma link C++ class o2::dataformats::TrackInfoExt + ; +#pragma link C++ class std::vector < o2::dataformats::TrackInfoExt> + ; +#pragma link C++ class std::vector < o2::dataformats::ProngInfoExt> + ; +#pragma link C++ class std::vector < o2::dataformats::V0Ext> + ; + #endif diff --git a/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx new file mode 100644 index 0000000000000..c1fa8b51b9d57 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/SVStudy.cxx @@ -0,0 +1,330 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "DetectorsVertexing/SVertexerParams.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/V0.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DataFormatsCalibration/MeanVertexObject.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "SimulationDataFormat/MCEventLabel.h" +#include "SimulationDataFormat/MCUtils.h" +#include "CommonDataFormat/BunchFilling.h" +#include "CommonUtils/NameConf.h" +#include "DataFormatsFT0/RecPoints.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/CCDBParamSpec.h" +#include "FT0Reconstruction/InteractionTag.h" +#include "ITSMFTBase/DPLAlpideParam.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "GlobalTrackingStudy/TrackingStudy.h" +#include "TPCBase/ParameterElectronics.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "DataFormatsFT0/RecPoints.h" +#include "DataFormatsITSMFT/TrkClusRef.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "ReconstructionDataFormats/VtxTrackRef.h" +#include "ReconstructionDataFormats/DCA.h" +#include "Steer/MCKinematicsReader.h" +#include "DCAFitter/DCAFitterN.h" +#include "MathUtils/fit.h" +#include "GlobalTrackingStudy/V0Ext.h" + +namespace o2::svstudy +{ + +using namespace o2::framework; +using DetID = o2::detectors::DetID; +using DataRequest = o2::globaltracking::DataRequest; + +using PVertex = o2::dataformats::PrimaryVertex; +using V2TRef = o2::dataformats::VtxTrackRef; +using VTIndex = o2::dataformats::VtxTrackIndex; +using GTrackID = o2::dataformats::GlobalTrackID; +using TBracket = o2::math_utils::Bracketf_t; +using V0ID = o2::dataformats::V0Index; + +using timeEst = o2::dataformats::TimeStampWithError; + +class SVStudySpec : public Task +{ + public: + SVStudySpec(std::shared_ptr dr, std::shared_ptr gr, GTrackID::mask_t src, bool useMC) + : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) {} + ~SVStudySpec() final = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(EndOfStreamContext& ec) final; + void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; + void process(o2::globaltracking::RecoContainer& recoData); + o2::dataformats::V0Ext processV0(int iv, o2::globaltracking::RecoContainer& recoData); + + private: + void updateTimeDependentParams(ProcessingContext& pc); + bool refitV0(const V0ID& id, o2::dataformats::V0& v0, o2::globaltracking::RecoContainer& recoData); + std::shared_ptr mDataRequest; + std::shared_ptr mGGCCDBRequest; + bool mUseMC{false}; ///< MC flag + std::unique_ptr mDBGOut; + float mSelK0 = -1; + bool mRefit = false; + float mMaxEta = 0.8; + float mBz = 0; + GTrackID::mask_t mTracksSrc{}; + o2::vertexing::DCAFitterN<2> mFitterV0; + o2::steer::MCKinematicsReader mcReader; // reader of MC information +}; + +void SVStudySpec::init(InitContext& ic) +{ + o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); + mDBGOut = std::make_unique("svStudy.root", "recreate"); + mRefit = ic.options().get("refit"); + mSelK0 = ic.options().get("sel-k0"); + mMaxEta = ic.options().get("max-eta"); +} + +void SVStudySpec::run(ProcessingContext& pc) +{ + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer + updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions + process(recoData); +} + +void SVStudySpec::updateTimeDependentParams(ProcessingContext& pc) +{ + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + static bool initOnceDone = false; + if (!initOnceDone) { // this params need to be queried only once + initOnceDone = true; + const auto& svparam = o2::vertexing::SVertexerParams::Instance(); + // Note: reading of the ITS AlpideParam needed for ITS timing is done by the RecoContainer + mFitterV0.setBz(mBz); + mFitterV0.setUseAbsDCA(svparam.useAbsDCA); + mFitterV0.setPropagateToPCA(false); + mFitterV0.setMaxR(svparam.maxRIni); + mFitterV0.setMinParamChange(svparam.minParamChange); + mFitterV0.setMinRelChi2Change(svparam.minRelChi2Change); + mFitterV0.setMaxDZIni(svparam.maxDZIni); + mFitterV0.setMaxDXYIni(svparam.maxDXYIni); + mFitterV0.setMaxChi2(svparam.maxChi2); + mFitterV0.setMatCorrType(o2::base::Propagator::MatCorrType(svparam.matCorr)); + mFitterV0.setUsePropagator(svparam.usePropagator); + mFitterV0.setRefitWithMatCorr(svparam.refitWithMatCorr); + mFitterV0.setMaxStep(svparam.maxStep); + mFitterV0.setMaxSnp(svparam.maxSnp); + mFitterV0.setMinXSeed(svparam.minXSeed); + } + mBz = o2::base::Propagator::Instance()->getNominalBz(); + mFitterV0.setBz(mBz); +} + +o2::dataformats::V0Ext SVStudySpec::processV0(int iv, o2::globaltracking::RecoContainer& recoData) +{ + o2::dataformats::V0Ext v0ext; + auto invalidate = [&v0ext]() { v0ext.v0ID.setVertexID(-1); }; + + auto v0s = recoData.getV0s(); + auto v0IDs = recoData.getV0sIdx(); + static int tfID = 0; + + const auto& v0id = v0IDs[iv]; + if (mRefit && !refitV0(v0id, v0ext.v0, recoData)) { + invalidate(); + return v0ext; + } + const auto& v0sel = mRefit ? v0ext.v0 : v0s[iv]; + if (mMaxEta < std::abs(v0sel.getEta())) { + invalidate(); + return v0ext; + } + if (mSelK0 > 0 && std::abs(std::sqrt(v0sel.calcMass2AsK0()) - 0.497) > mSelK0) { + invalidate(); + return v0ext; + } + if (!mRefit) { + v0ext.v0 = v0sel; + } + v0ext.v0ID = v0id; + for (int ip = 0; ip < 2; ip++) { + auto& prInfo = v0ext.prInfo[ip]; + auto gid = v0ext.v0ID.getProngID(ip); + auto gidset = recoData.getSingleDetectorRefs(gid); + // get TPC tracks, if any + if (gidset[GTrackID::TPC].isSourceSet()) { + const auto& tpcTr = recoData.getTPCTrack(gidset[GTrackID::TPC]); + prInfo.trackTPC = tpcTr; + prInfo.nClTPC = tpcTr.getNClusters(); + } + // get ITS tracks, if any + if (gid.includesDet(DetID::ITS)) { + auto gidITS = recoData.getITSContributorGID(gid); + if (gidset[GTrackID::ITS].isSourceSet()) { + const auto& itsTr = recoData.getITSTrack(recoData.getITSContributorGID(gid)); + prInfo.nClITS = itsTr.getNClusters(); + for (int il = 0; il < 7; il++) { + if (itsTr.hasHitOnLayer(il)) { + prInfo.pattITS |= 0x1 << il; + } + } + } else { + const auto& itsTrf = recoData.getITSABRefs()[gidset[GTrackID::ITSAB]]; + prInfo.nClITS = itsTrf.getNClusters(); + for (int il = 0; il < 7; il++) { + if (itsTrf.hasHitOnLayer(il)) { + prInfo.pattITS |= 0x1 << il; + } + } + prInfo.pattITS |= 0x1 << 31; // flag AB + } + if (gidset[GTrackID::ITSTPC].isSourceSet()) { + auto mtc = recoData.getTPCITSTrack(gidset[GTrackID::ITSTPC]); + prInfo.chi2ITSTPC = mtc.getChi2Match(); + } + } + } + return v0ext; +} + +void SVStudySpec::process(o2::globaltracking::RecoContainer& recoData) +{ + auto v0IDs = recoData.getV0sIdx(); + auto nv0 = v0IDs.size(); + if (nv0 > recoData.getV0s().size()) { + mRefit = true; + } + std::map> pv2sv; + static int tfID = 0; + for (int iv = 0; iv < nv0; iv++) { + const auto v0id = v0IDs[iv]; + pv2sv[v0id.getVertexID()].push_back(iv); + } + std::vector v0extVec; + for (auto it : pv2sv) { + int pvID = it.first; + auto& vv = it.second; + if (pvID < 0 || vv.size() == 0) { + continue; + } + v0extVec.clear(); + for (int iv0 : vv) { + auto v0ext = processV0(iv0, recoData); + if (v0ext.v0ID.getVertexID() < 0) { + continue; + } + v0extVec.push_back(v0ext); + } + if (v0extVec.size()) { + const auto& pv = recoData.getPrimaryVertex(pvID); + (*mDBGOut) << "v0" + << "orbit=" << recoData.startIR.orbit << "tfID=" << tfID + << "v0Ext=" << v0extVec + << "pv=" << pv + << "\n"; + } + tfID++; + } +} + +bool SVStudySpec::refitV0(const V0ID& id, o2::dataformats::V0& v0, o2::globaltracking::RecoContainer& recoData) +{ + auto seedP = recoData.getTrackParam(id.getProngID(0)); + auto seedN = recoData.getTrackParam(id.getProngID(1)); + bool isTPConly = (id.getProngID(0).getSource() == GTrackID::TPC) || (id.getProngID(1).getSource() == GTrackID::TPC); + const auto& svparam = o2::vertexing::SVertexerParams::Instance(); + if (svparam.mTPCTrackPhotonTune && isTPConly) { + mFitterV0.setMaxDZIni(svparam.mTPCTrackMaxDZIni); + mFitterV0.setMaxDXYIni(svparam.mTPCTrackMaxDXYIni); + mFitterV0.setMaxChi2(svparam.mTPCTrackMaxChi2); + mFitterV0.setCollinear(true); + } + int nCand = mFitterV0.process(seedP, seedN); + if (svparam.mTPCTrackPhotonTune && isTPConly) { // restore + // Reset immediately to the defaults + mFitterV0.setMaxDZIni(svparam.maxDZIni); + mFitterV0.setMaxDXYIni(svparam.maxDXYIni); + mFitterV0.setMaxChi2(svparam.maxChi2); + mFitterV0.setCollinear(false); + } + if (nCand == 0) { // discard this pair + return false; + } + const int cand = 0; + if (!mFitterV0.isPropagateTracksToVertexDone(cand) && !mFitterV0.propagateTracksToVertex(cand)) { + return false; + } + const auto& trPProp = mFitterV0.getTrack(0, cand); + const auto& trNProp = mFitterV0.getTrack(1, cand); + std::array pP{}, pN{}; + trPProp.getPxPyPzGlo(pP); + trNProp.getPxPyPzGlo(pN); + std::array pV0 = {pP[0] + pN[0], pP[1] + pN[1], pP[2] + pN[2]}; + auto p2V0 = pV0[0] * pV0[0] + pV0[1] * pV0[1] + pV0[2] * pV0[2]; + const auto& pv = recoData.getPrimaryVertex(id.getVertexID()); + const auto v0XYZ = mFitterV0.getPCACandidatePos(cand); + float dx = v0XYZ[0] - pv.getX(), dy = v0XYZ[1] - pv.getY(), dz = v0XYZ[2] - pv.getZ(), prodXYZv0 = dx * pV0[0] + dy * pV0[1] + dz * pV0[2]; + float cosPA = prodXYZv0 / std::sqrt((dx * dx + dy * dy + dz * dz) * p2V0); + new (&v0) o2::dataformats::V0(v0XYZ, pV0, mFitterV0.calcPCACovMatrixFlat(cand), trPProp, trNProp); + v0.setDCA(mFitterV0.getChi2AtPCACandidate(cand)); + v0.setCosPA(cosPA); + return true; +} + +void SVStudySpec::endOfStream(EndOfStreamContext& ec) +{ + mDBGOut.reset(); +} + +void SVStudySpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } +} + +DataProcessorSpec getSVStudySpec(GTrackID::mask_t srcTracks, bool useMC) +{ + std::vector outputs; + auto dataRequest = std::make_shared(); + + dataRequest->requestTracks(srcTracks, useMC); + dataRequest->requestPrimaryVertertices(useMC); + dataRequest->requestSecondaryVertices(useMC); + dataRequest->inputs.emplace_back("meanvtx", "GLO", "MEANVERTEX", 0, Lifetime::Condition, ccdbParamSpec("GLO/Calib/MeanVertex", {}, 1)); + auto ggRequest = std::make_shared(false, // orbitResetTime + false, // GRPECS=true + false, // GRPLHCIF + true, // GRPMagField + true, // askMatLUT + o2::base::GRPGeomRequest::None, // geometry + dataRequest->inputs, + true); + + return DataProcessorSpec{ + "sv-study", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, srcTracks, useMC)}, + Options{ + {"refit", VariantType::Bool, false, {"refit SVertices"}}, + {"sel-k0", VariantType::Float, -1.f, {"If positive, select K0s with this mass margin"}}, + {"max-eta", VariantType::Float, 1.2f, {"Cut on track eta"}}, + }}; +} + +} // namespace o2::svstudy diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx index 3abcfe583f670..0e1dc7baaa69c 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TPCTrackStudy.cxx @@ -77,6 +77,7 @@ class TPCTrackStudySpec : public Task int mTFEnd = 999999999; int mTFCount = -1; bool mUseR = false; + bool mRepRef = false; std::unique_ptr mDBGOut; std::unique_ptr mDBGOutCl; float mITSROFrameLengthMUS = 0.; @@ -87,6 +88,7 @@ class TPCTrackStudySpec : public Task gsl::span mTPCTrackClusIdx; ///< input TPC track cluster indices span gsl::span mTPCTracksArray; ///< input TPC tracks span gsl::span mTPCRefitterShMap; ///< externally set TPC clusters sharing map + gsl::span mTPCRefitterOccMap; ///< externally set TPC clusters occupancy map const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices gsl::span mTPCTrkLabels; ///< input TPC Track MC labels std::unique_ptr mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction @@ -98,6 +100,7 @@ void TPCTrackStudySpec::init(InitContext& ic) mXRef = ic.options().get("target-x"); mNMoves = std::max(2, ic.options().get("n-moves")); mUseR = ic.options().get("use-r-as-x"); + mRepRef = ic.options().get("repeat-ini-ref"); mUseGPUModel = ic.options().get("use-gpu-fitter"); mTFStart = ic.options().get("tf-start"); mTFEnd = ic.options().get("tf-end"); @@ -169,6 +172,7 @@ void TPCTrackStudySpec::process(o2::globaltracking::RecoContainer& recoData) mTPCTrackClusIdx = recoData.getTPCTracksClusterRefs(); mTPCClusterIdxStruct = &recoData.inputsTPCclusters->clusterIndex; mTPCRefitterShMap = recoData.clusterShMapTPC; + mTPCRefitterOccMap = recoData.occupancyMapTPC; std::vector intRecs; if (mUseMC) { // extract MC tracks @@ -181,8 +185,8 @@ void TPCTrackStudySpec::process(o2::globaltracking::RecoContainer& recoData) mTPCTrkLabels = recoData.getTPCTracksMCLabels(); } - mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, &mTPCCorrMapsLoader, prop->getNominalBz(), mTPCTrackClusIdx.data(), mTPCRefitterShMap.data(), nullptr, o2::base::Propagator::Instance()); - + mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, &mTPCCorrMapsLoader, prop->getNominalBz(), mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, o2::base::Propagator::Instance()); + mTPCRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500 float vdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin float tpcTBBias = mTPCVDriftHelper.getVDriftObject().getTimeOffset() / (8 * o2::constants::lhc::LHCBunchSpacingMUS); std::vector clSector, clRow; @@ -376,7 +380,12 @@ void TPCTrackStudySpec::process(o2::globaltracking::RecoContainer& recoData) << "counter=" << counter << "copy=" << it << "maxCopy=" << mnm - << "movTrackRef=" << trfm + << "movTrackRef=" << trfm; + if (mRepRef) { + (*mDBGOut) << "tpcMov" + << "iniTrackRef=" << trf << "time=" << tr.getTime0(); + } + (*mDBGOut) << "tpcMov" << "imposedTB=" << tb << "dz=" << dz << "clX=" << clX @@ -416,6 +425,7 @@ DataProcessorSpec getTPCTrackStudySpec(GTrackID::mask_t srcTracks, GTrackID::mas {"tf-start", VariantType::Int, 0, {"1st TF to process"}}, {"tf-end", VariantType::Int, 999999999, {"last TF to process"}}, {"use-gpu-fitter", VariantType::Bool, false, {"use GPU track model for refit instead of TrackParCov"}}, + {"repeat-ini-ref", VariantType::Bool, false, {"store ini-refit param with every moved track"}}, {"use-r-as-x", VariantType::Bool, false, {"Use radius instead of target sector X"}}}; auto dataRequest = std::make_shared(); diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackInfoExt.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackInfoExt.cxx new file mode 100644 index 0000000000000..f1415e73c10b6 --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackInfoExt.cxx @@ -0,0 +1,14 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// class for extended track info (for debugging) + +#include "GlobalTrackingStudy/TrackInfoExt.h" diff --git a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx index 09e44fe8b36b9..9a0957c1038d2 100644 --- a/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx +++ b/Detectors/GlobalTrackingWorkflow/study/src/TrackingStudy.cxx @@ -12,6 +12,7 @@ #include #include #include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsITSMFT/TrkClusRef.h" #include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" #include "ReconstructionDataFormats/TrackTPCITS.h" #include "ReconstructionDataFormats/GlobalTrackID.h" @@ -30,6 +31,7 @@ #include "DetectorsCommonDataFormats/DetID.h" #include "DetectorsBase/GRPGeomHelper.h" #include "GlobalTrackingStudy/TrackingStudy.h" +#include "GlobalTrackingStudy/TrackInfoExt.h" #include "TPCBase/ParameterElectronics.h" #include "ReconstructionDataFormats/PrimaryVertex.h" #include "ReconstructionDataFormats/PrimaryVertexExt.h" @@ -80,7 +82,7 @@ class TrackingStudySpec : public Task float mMaxVTTimeDiff = 80.; // \mus float mTPCDCAYCut = 2.; float mTPCDCAZCut = 2.; - float mMinX = 6.; + float mMinX = 46.; float mMaxEta = 0.8; float mMinPt = 0.1; int mMinTPCClusters = 60; @@ -144,23 +146,19 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) static int TFCount = 0; int nv = vtxRefs.size(); o2::dataformats::PrimaryVertexExt pveDummy; - o2::dataformats::PrimaryVertex vtxDummy(mMeanVtx.getPos(), {}, {}, 0); - std::vector pveVec(nv - 1); + o2::dataformats::PrimaryVertexExt vtxDummy(mMeanVtx.getPos(), {}, {}, 0); + std::vector pveVec(nv); + pveVec.back() = vtxDummy; const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); float tBiasITS = alpParams.roFrameBiasInBC * o2::constants::lhc::LHCBunchSpacingMUS; - std::vector dtvec, dzvec; const o2::ft0::InteractionTag& ft0Params = o2::ft0::InteractionTag::Instance(); - + std::vector trcExtVec; for (int iv = 0; iv < nv; iv++) { LOGP(debug, "processing PV {} of {}", iv, nv); const auto& vtref = vtxRefs[iv]; if (iv != nv - 1) { auto& pve = pveVec[iv]; static_cast(pve) = pvvec[iv]; - dtvec.clear(); - dzvec.clear(); - dtvec.reserve(pve.getNContributors()); - dzvec.reserve(pve.getNContributors()); float bestTimeDiff = 1000, bestTime = -999; int bestFTID = -1; if (mTracksSrc[GTrackID::FT0]) { @@ -180,16 +178,11 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) if (bestFTID >= 0) { pve.FT0A = FITInfo[bestFTID].getTrigger().getAmplA(); pve.FT0C = FITInfo[bestFTID].getTrigger().getAmplC(); - pve.FT0Time = FITInfo[bestFTID].getInteractionRecord().differenceInBCMUS(recoData.startIR); + pve.FT0Time = double(FITInfo[bestFTID].getInteractionRecord().differenceInBCMUS(recoData.startIR)) + FITInfo[bestFTID].getCollisionTimeMean() * 1e-6; // time in \mus } pve.VtxID = iv; } - float meanT = 0, meanZ = 0, rmsT = 0, rmsZ = 0; - float meanTW = 0, meanZW = 0, rmsTW = 0, rmsZW = 0, WT = 0, WZ = 0; - float meanT0 = 0, rmsT0 = 0; - float meanTW0 = 0, rmsTW0 = 0, WT0 = 0; - int nContAdd = 0, nContAdd0 = 0, ntITS = 0; - int nAdjusted = 0; + trcExtVec.clear(); float q2ptITS, q2ptTPC, q2ptITSTPC, q2ptITSTPCTRD; for (int is = 0; is < GTrackID::NSources; is++) { DetID::mask_t dm = GTrackID::getSourceDetectorsMask(is); @@ -213,6 +206,7 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) } bool hasITS = GTrackID::getSourceDetectorsMask(is)[GTrackID::ITS]; bool acceptGlo = true; + int nclTPC = 0, nclITS = 0, pattITS = 0; while (1) { // do we cound this track for global multiplicity? if (!(acceptGlo = abs(trc.getEta()) < mMaxEta && trc.getPt() > mMinPt)) { @@ -224,7 +218,7 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) GTrackID tpcTrID; if (GTrackID::getSourceDetectorsMask(is)[GTrackID::TPC] && recoData.isTrackSourceLoaded(GTrackID::TPC) && (tpcTrID = recoData.getTPCContributorGID(vid))) { auto& tpcTr = recoData.getTPCTrack(tpcTrID); - if (!(acceptGlo = tpcTr.getNClusters() >= mMinTPCClusters)) { + if (!(acceptGlo = (nclTPC = tpcTr.getNClusters()) >= mMinTPCClusters)) { break; } } @@ -236,124 +230,58 @@ void TrackingStudySpec::process(o2::globaltracking::RecoContainer& recoData) } break; } - if (!hasITS) { continue; } - float ttime = 0, ttimeE = 0; - recoData.getTrackTime(vid, ttime, ttimeE); - bool acceptForPV0 = pvCont; - if (vid.getSource() == GTrackID::ITS) { - ttimeE *= mITSROFrameLengthMUS; - ttime += ttimeE + tBiasITS; - ttimeE *= 1. / sqrt(3); - if (++ntITS > 0) { // do not allow ITS in the MAD - acceptForPV0 = false; - } - } else if (vid.getSource() == GTrackID::ITSTPC) { - float bcf = ttime / o2::constants::lhc::LHCBunchSpacingMUS + o2::constants::lhc::LHCMaxBunches; - int bcWrtROF = int(bcf - alpParams.roFrameBiasInBC) % alpParams.roFrameLengthInBC; - if (bcWrtROF == 0) { - float dbc = bcf - (int(bcf / alpParams.roFrameBiasInBC)) * alpParams.roFrameBiasInBC; - if (std::abs(dbc) < 1e-6 && (++nAdjusted) > 1) { - acceptForPV0 = false; // do not allow more than 1 adjusted track MAD - } - } - } else if (vid.getSource() == GTrackID::TPC) { - ttimeE *= o2::constants::lhc::LHCBunchSpacingMUS * 8; - } - if (pvCont) { - float dt = ttime - pveVec[iv].getTimeStamp().getTimeStamp(); - float tW = 1. / (ttimeE * ttimeE), zW = 1. / trc.getSigmaZ2(); - dzvec.push_back(dca.getZ()); - WT += tW; - WZ += zW; - meanT += dt; - meanTW += dt * tW; - meanZ += dca.getZ(); - meanZW += dca.getZ() * zW; - - rmsT += dt * dt; - rmsTW += dt * dt * tW; - rmsZ += dca.getZ() * dca.getZ(); - rmsZW += dca.getZ() * dca.getZ() * zW; - nContAdd++; - if (acceptForPV0) { - dtvec.push_back(dt); - WT0 += tW; - meanT0 += dt; - meanTW0 += dt * tW; - rmsT0 += dt * dt; - rmsTW0 += dt * dt * tW; - nContAdd0++; - } - LOGP(debug, "dt={} dz={}, tW={}, zW={} t={} tE={} {}", dt, dca.getZ(), tW, zW, ttime, ttimeE, vid.asString()); - } if (acceptGlo) { - q2ptITS = q2ptTPC = q2ptITSTPC = q2ptITSTPCTRD = 0.; + auto& trcExt = trcExtVec.emplace_back(); + recoData.getTrackTime(vid, trcExt.ttime, trcExt.ttimeE); + trcExt.track = trc; + trcExt.dca = dca; + trcExt.gid = vid; + trcExt.xmin = xmin; auto gidRefs = recoData.getSingleDetectorRefs(vid); if (gidRefs[GTrackID::ITS].isIndexSet()) { - q2ptITS = recoData.getTrackParam(gidRefs[GTrackID::ITS]).getQ2Pt(); + const auto& itsTr = recoData.getITSTrack(gidRefs[GTrackID::ITS]); + trcExt.q2ptITS = itsTr.getQ2Pt(); + trcExt.nClITS = itsTr.getNClusters(); + for (int il = 0; il < 7; il++) { + if (itsTr.hasHitOnLayer(il)) { + trcExt.pattITS |= 0x1 << il; + } + } + } else if (gidRefs[GTrackID::ITSAB].isIndexSet()) { + const auto& itsTrf = recoData.getITSABRefs()[gidRefs[GTrackID::ITSAB]]; + trcExt.nClITS = itsTrf.getNClusters(); + for (int il = 0; il < 7; il++) { + if (itsTrf.hasHitOnLayer(il)) { + trcExt.pattITS |= 0x1 << il; + } + } } if (gidRefs[GTrackID::TPC].isIndexSet()) { - q2ptTPC = recoData.getTrackParam(gidRefs[GTrackID::TPC]).getQ2Pt(); + trcExt.q2ptTPC = recoData.getTrackParam(gidRefs[GTrackID::TPC]).getQ2Pt(); + trcExt.nClTPC = nclTPC; } if (gidRefs[GTrackID::ITSTPC].isIndexSet()) { - q2ptITSTPC = recoData.getTrackParam(gidRefs[GTrackID::ITSTPC]).getQ2Pt(); + const auto& trTPCITS = recoData.getTPCITSTrack(gidRefs[GTrackID::ITSTPC]); + trcExt.q2ptITSTPC = trTPCITS.getQ2Pt(); + trcExt.chi2ITSTPC = trTPCITS.getChi2Match(); } if (gidRefs[GTrackID::TRD].isIndexSet()) { - q2ptITSTPCTRD = recoData.getTrackParam(gidRefs[GTrackID::TRD]).getQ2Pt(); + trcExt.q2ptITSTPCTRD = recoData.getTrackParam(gidRefs[GTrackID::TRD]).getQ2Pt(); + } + if (gidRefs[GTrackID::TOF].isIndexSet()) { + trcExt.infoTOF = recoData.getTOFMatch(vid); } - - (*mDBGOut) << "dca" - << "tfID=" << TFCount << "ttime=" << ttime << "ttimeE=" << ttimeE - << "gid=" << vid << "pvid=" << (iv == nv - 1 ? -1 : iv) << "pv=" << (iv == nv - 1 ? vtxDummy : pvvec[iv]) - << "trc=" << trc << "pvCont=" << pvCont << "ambig=" << ambig << "dca=" << dca << "xmin=" << xmin - << "q2ptITS=" << q2ptITS << "q2ptTPC=" << q2ptTPC << "q2ptITSTPC=" << q2ptITSTPC << "q2ptITSTPCTRD=" << q2ptITSTPCTRD - << "\n"; } } } - - if (iv != nv - 1) { - auto& pve = pveVec[iv]; - if (nContAdd) { - rmsT /= nContAdd; - rmsZ /= nContAdd; - meanT /= nContAdd; - meanZ /= nContAdd; - pve.rmsT = (rmsT - meanT * meanT); - pve.rmsT = pve.rmsT > 0 ? std::sqrt(pve.rmsT) : 0; - pve.rmsZ = rmsZ - meanZ * meanZ; - pve.rmsZ = pve.rmsZ > 0 ? std::sqrt(pve.rmsZ) : 0; - } - if (nContAdd0) { - rmsT0 /= nContAdd0; - meanT0 /= nContAdd0; - pve.rmsT0 = (rmsT0 - meanT0 * meanT0); - pve.rmsT0 = pve.rmsT0 > 0 ? std::sqrt(pve.rmsT0) : 0; - } - if (WT0 > 0) { - rmsTW0 /= WT0; - meanTW0 /= WT0; - pve.rmsTW0 = (rmsTW0 - meanTW0 * meanTW0); - pve.rmsTW0 = pve.rmsTW0 > 0 ? std::sqrt(pve.rmsTW0) : 0; - } - // - if (WT > 0 && WZ > 0) { - rmsTW /= WT; - meanTW /= WT; - pve.rmsTW = (rmsTW - meanTW * meanTW); - pve.rmsTW = pve.rmsTW > 0 ? std::sqrt(pve.rmsTW) : 0; - rmsZW /= WZ; - meanZW /= WZ; - pve.rmsZW = rmsZW - meanZW * meanZW; - pve.rmsZW = pve.rmsZ > 0 ? std::sqrt(pve.rmsZ) : 0; - } - pve.tMAD = o2::math_utils::MAD2Sigma(dtvec.size(), dtvec.data()); - pve.zMAD = o2::math_utils::MAD2Sigma(dzvec.size(), dzvec.data()); - } + (*mDBGOut) << "trpv" + << "orbit=" << recoData.startIR.orbit << "tfID=" << TFCount + << "pve=" << pveVec[iv] << "trc=" << trcExtVec << "\n"; } + int nvtot = mMaxNeighbours < 0 ? -1 : (int)pveVec.size(); auto insSlot = [maxSlots = mMaxNeighbours](std::vector& vc, float v, int slot, std::vector& vid, int id) { @@ -499,7 +427,7 @@ DataProcessorSpec getTrackingStudySpec(GTrackID::mask_t srcTracks, GTrackID::mas {"max-tpc-dcaz", VariantType::Float, 2.f, {"Cut on TPC dcaZ"}}, {"max-eta", VariantType::Float, 0.8f, {"Cut on track eta"}}, {"min-pt", VariantType::Float, 0.1f, {"Cut on track pT"}}, - {"min-x-prop", VariantType::Float, 6.f, {"track should be propagated to this X at least"}}, + {"min-x-prop", VariantType::Float, 46.f, {"track should be propagated to this X at least"}}, }}; } diff --git a/Detectors/GlobalTrackingWorkflow/study/src/V0Ext.cxx b/Detectors/GlobalTrackingWorkflow/study/src/V0Ext.cxx new file mode 100644 index 0000000000000..0ae0fd3bda96a --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/V0Ext.cxx @@ -0,0 +1,14 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +// class for extended V0 info (for debugging) + +#include "GlobalTrackingStudy/V0Ext.h" diff --git a/Detectors/GlobalTrackingWorkflow/study/src/sv-study-workflow.cxx b/Detectors/GlobalTrackingWorkflow/study/src/sv-study-workflow.cxx new file mode 100644 index 0000000000000..fba5e67452f1f --- /dev/null +++ b/Detectors/GlobalTrackingWorkflow/study/src/sv-study-workflow.cxx @@ -0,0 +1,73 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "GlobalTrackingStudy/SVStudy.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/CallbacksPolicy.h" +#include "DetectorsBase/DPLWorkflowUtils.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" + +using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; + +// ------------------------------------------------------------------ +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::vector options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation"}}, + {"track-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of track sources to use"}}, + {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + + GID::mask_t allowedSourcesTrc = GID::getSourcesMask("ITS,TPC,ITS-TPC,TPC-TOF,TPC-TRD,ITS-TPC-TRD,TPC-TRD-TOF,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); + + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + + auto useMC = !configcontext.options().get("disable-mc"); + + GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(configcontext.options().get("track-sources")); + GID::mask_t srcCls{}; + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC); + o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); // P-vertex is always needed + o2::globaltracking::InputHelper::addInputSpecsSVertex(configcontext, specs); // S-vertex is always needed + specs.emplace_back(o2::svstudy::getSVStudySpec(srcTrc, useMC)); + + // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return std::move(specs); +} diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h index 520f5779c1d06..86064f84d881f 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/include/TPCInterpolationWorkflow/TPCInterpolationSpec.h @@ -38,7 +38,7 @@ namespace tpc class TPCInterpolationDPL : public Task { public: - TPCInterpolationDPL(std::shared_ptr dr, o2::dataformats::GlobalTrackID::mask_t src, std::shared_ptr gr, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput) : mDataRequest(dr), mSources(src), mGGCCDBRequest(gr), mUseMC(useMC), mProcessITSTPConly(processITSTPConly), mSendTrackData(sendTrackData), mDebugOutput(debugOutput) {} + TPCInterpolationDPL(std::shared_ptr dr, o2::dataformats::GlobalTrackID::mask_t src, o2::dataformats::GlobalTrackID::mask_t srcMap, std::shared_ptr gr, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput) : mDataRequest(dr), mSources(src), mSourcesMap(srcMap), mGGCCDBRequest(gr), mUseMC(useMC), mProcessITSTPConly(processITSTPConly), mSendTrackData(sendTrackData), mDebugOutput(debugOutput) {} ~TPCInterpolationDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -53,6 +53,7 @@ class TPCInterpolationDPL : public Task o2::tpc::VDriftHelper mTPCVDriftHelper{}; const o2::itsmft::TopologyDictionary* mITSDict = nullptr; ///< cluster patterns dictionary o2::dataformats::GlobalTrackID::mask_t mSources{}; ///< which input sources are configured + o2::dataformats::GlobalTrackID::mask_t mSourcesMap{}; ///< possible subset of mSources specifically for map creation bool mUseMC{false}; ///< MC flag bool mProcessITSTPConly{false}; ///< should also tracks without outer point (ITS-TPC only) be processed? bool mProcessSeeds{false}; ///< process not only most complete track, but also its shorter parts @@ -64,7 +65,7 @@ class TPCInterpolationDPL : public Task }; /// create a processor spec -framework::DataProcessorSpec getTPCInterpolationSpec(o2::dataformats::GlobalTrackID::mask_t srcCls, o2::dataformats::GlobalTrackID::mask_t srcVtx, o2::dataformats::GlobalTrackID::mask_t srcTrk, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput); +framework::DataProcessorSpec getTPCInterpolationSpec(o2::dataformats::GlobalTrackID::mask_t srcCls, o2::dataformats::GlobalTrackID::mask_t srcVtx, o2::dataformats::GlobalTrackID::mask_t srcTrk, o2::dataformats::GlobalTrackID::mask_t srcTrkMap, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput); } // namespace tpc } // namespace o2 diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx index 89e3ae19cf65b..ac1ad304caba4 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/TPCInterpolationSpec.cxx @@ -52,6 +52,9 @@ void TPCInterpolationDPL::init(InitContext& ic) mSlotLength = ic.options().get("sec-per-slot"); mProcessSeeds = ic.options().get("process-seeds"); mMatCorr = ic.options().get("matCorrType"); + if (mProcessSeeds && mSources != mSourcesMap) { + LOG(fatal) << "process-seeds option is not compatible with using different track sources for vDrift and map extraction"; + } } void TPCInterpolationDPL::updateTimeDependentParams(ProcessingContext& pc) @@ -63,7 +66,7 @@ void TPCInterpolationDPL::updateTimeDependentParams(ProcessingContext& pc) initOnceDone = true; // other init-once stuff const auto& param = SpacePointsCalibConfParam::Instance(); - mInterpolation.init(mSources); + mInterpolation.init(mSources, mSourcesMap); if (mProcessITSTPConly) { mInterpolation.setProcessITSTPConly(); } @@ -74,10 +77,10 @@ void TPCInterpolationDPL::updateTimeDependentParams(ProcessingContext& pc) if (nTracksPerTfMax > 0) { LOGP(info, "We will stop processing tracks after validating {} tracks per TF, since we want to accumulate {} tracks for a slot with {} TFs", nTracksPerTfMax, param.maxTracksPerCalibSlot, nTfs); - if (param.additionalTracksITSTPC > 0) { - int nITSTPCadd = param.additionalTracksITSTPC / nTfs; - LOGP(info, "In addition up to {} ITS-TPC tracks are processed per TF", nITSTPCadd); - mInterpolation.setAddITSTPCTracksPerTF(nITSTPCadd); + if (param.additionalTracksMap > 0) { + int nTracksAdditional = param.additionalTracksMap / nTfs; + LOGP(info, "In addition up to {} additional tracks are processed per TF", nTracksAdditional); + mInterpolation.setAddTracksForMapPerTF(nTracksAdditional); } } else if (nTracksPerTfMax < 0) { LOG(info) << "The number of processed tracks per TF is not limited"; @@ -155,7 +158,7 @@ void TPCInterpolationDPL::endOfStream(EndOfStreamContext& ec) mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } -DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t srcCls, GTrackID::mask_t srcVtx, GTrackID::mask_t srcTrk, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput) +DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t srcCls, GTrackID::mask_t srcVtx, GTrackID::mask_t srcTrk, GTrackID::mask_t srcTrkMap, bool useMC, bool processITSTPConly, bool sendTrackData, bool debugOutput) { auto dataRequest = std::make_shared(); std::vector outputs; @@ -196,7 +199,7 @@ DataProcessorSpec getTPCInterpolationSpec(GTrackID::mask_t srcCls, GTrackID::mas "tpc-track-interpolation", dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(dataRequest, srcTrk, ggRequest, useMC, processITSTPConly, sendTrackData, debugOutput)}, + AlgorithmSpec{adaptFromTask(dataRequest, srcTrk, srcTrkMap, ggRequest, useMC, processITSTPConly, sendTrackData, debugOutput)}, Options{ {"matCorrType", VariantType::Int, 2, {"material correction type (definition in Propagator.h)"}}, {"sec-per-slot", VariantType::UInt32, 600u, {"number of seconds per calibration time slot (put 0 for infinite slot length)"}}, diff --git a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx index f124cd965c796..0905942c956a4 100644 --- a/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx +++ b/Detectors/GlobalTrackingWorkflow/tpcinterpolationworkflow/src/tpc-interpolation-workflow.cxx @@ -39,6 +39,7 @@ void customize(std::vector& workflowOptions) {"disable-mc", VariantType::Bool, false, {"disable MC propagation even if available"}}, {"vtx-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources used for the vertex finding"}}, {"tracking-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of sources to use for track inter-/extrapolation"}}, + {"tracking-sources-map-extraction", VariantType::String, std::string{GID::ALL}, {"can be subset of \"tracking-sources\""}}, {"send-track-data", VariantType::Bool, false, {"Send also the track information to the aggregator"}}, {"debug-output", VariantType::Bool, false, {"Dump extended tracking information for debugging"}}, {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; @@ -69,14 +70,24 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) GID::mask_t allowedSources = GID::getSourcesMask("ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); GID::mask_t srcVtx = allowedSources & GID::getSourcesMask(configcontext.options().get("vtx-sources")); GID::mask_t srcTracks = allowedSources & GID::getSourcesMask(configcontext.options().get("tracking-sources")); + GID::mask_t srcTracksMap = allowedSources & GID::getSourcesMask(configcontext.options().get("tracking-sources-map-extraction")); if (srcTracks.count() > srcVtx.count()) { LOGP(error, "More sources configured for inter-/extrapolation: {} than for vertexing: {}. Additional sources will be ignored", GID::getSourcesNames(srcTracks), GID::getSourcesNames(srcVtx)); srcTracks &= srcVtx; } + srcTracksMap &= srcVtx; + if (((srcTracksMap | srcTracks) ^ srcTracks).any()) { + LOGP(fatal, "tracking-sources-map-extraction ({}) must be a subset of tracking-sources ({}).", GID::getSourcesNames(srcTracksMap), GID::getSourcesNames(srcTracks)); + } else if (srcTracksMap != srcTracks) { + LOGP(info, "Will extract residual from different track types. For vDrift from {} and for distortion map from {}", GID::getSourcesNames(srcTracks), GID::getSourcesNames(srcTracksMap)); + } else { + LOGP(info, "Only a single track source is defined for residuals extraction: {}", GID::getSourcesNames(srcTracks)); + } LOG(debug) << "Data sources for inter-/extrapolation: " << GID::getSourcesNames(srcTracks); // check first if ITS-TPC tracks were specifically requested from command line bool processITSTPConly = srcTracks[GID::ITSTPC]; srcTracks |= GID::getSourcesMask("ITS,TPC,ITS-TPC"); // now add them in any case + srcTracksMap |= GID::getSourcesMask("ITS,TPC,ITS-TPC"); srcVtx |= srcTracks; GID::mask_t srcClusters = srcTracks; if (srcTracks[GID::ITSTPCTRD] || srcTracks[GID::ITSTPCTRDTOF]) { @@ -94,7 +105,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) auto sendTrackData = configcontext.options().get("send-track-data"); auto debugOutput = configcontext.options().get("debug-output"); - specs.emplace_back(o2::tpc::getTPCInterpolationSpec(srcClusters, srcVtx, srcTracks, useMC, processITSTPConly, sendTrackData, debugOutput)); + specs.emplace_back(o2::tpc::getTPCInterpolationSpec(srcClusters, srcVtx, srcTracks, srcTracksMap, useMC, processITSTPConly, sendTrackData, debugOutput)); if (!configcontext.options().get("disable-root-output")) { specs.emplace_back(o2::tpc::getTPCResidualWriterSpec(sendTrackData, debugOutput)); } diff --git a/Detectors/HMPID/README.md b/Detectors/HMPID/README.md index 775f2ad24d77c..3a744b72812ea 100644 --- a/Detectors/HMPID/README.md +++ b/Detectors/HMPID/README.md @@ -8,4 +8,5 @@ This is a top page for the HMPID detector documentation. diff --git a/Detectors/HMPID/calibration/README.md b/Detectors/HMPID/calibration/README.md index 674ff2eca1265..a9a08309bb061 100644 --- a/Detectors/HMPID/calibration/README.md +++ b/Detectors/HMPID/calibration/README.md @@ -1,4 +1,8 @@ -#HMPID calibration + + +# HMPID calibration For a local test, use diff --git a/Detectors/HMPID/calibration/src/HMPIDDCSProcessor.cxx b/Detectors/HMPID/calibration/src/HMPIDDCSProcessor.cxx index 7b3a88bf27385..02852a3213b30 100644 --- a/Detectors/HMPID/calibration/src/HMPIDDCSProcessor.cxx +++ b/Detectors/HMPID/calibration/src/HMPIDDCSProcessor.cxx @@ -708,6 +708,7 @@ std::unique_ptr HMPIDDCSProcessor::finalizeHv(int iCh, int iSec) } else { (pHvTF).reset(new TF1(Form("HV%i%i", iCh, iSec), "[0]+x*[1]", hvFirstTime, hvLastTime)); + pGrHV->Fit(Form("HV%i%i", iCh, iSec), "Q"); // ef added } } else { LOGP(warn, "No entries in High Voltage for HV{}{}", iCh, iSec); diff --git a/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h b/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h index 9d843feda64bc..b01935f4cac5d 100644 --- a/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h +++ b/Detectors/HMPID/simulation/include/HMPIDSimulation/HMPIDDigitizer.h @@ -59,7 +59,7 @@ class HMPIDDigitizer } } } - + // void setOrbit(double timeNS) {mOrbit = } uint32_t getOrbit() { return mOrbit; }; uint16_t getBc() { return mBc; }; @@ -99,7 +99,7 @@ class HMPIDDigitizer std::vector mDigits; // internal store for digits constexpr static double TRACKHOLDTIME = 1200; // defines the window for pile-up after a trigger received in nanoseconds - constexpr static double BUSYTIME = 22000; // the time for which no new trigger can be received in nanoseconds + constexpr static double BUSYTIME = 40000; // the time for which no new trigger can be received in nanoseconds std::map mIndexForPad; //! logarithmic mapping of pad to digit index diff --git a/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx b/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx index 1a6509fc75654..63f6552e70242 100644 --- a/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx +++ b/Detectors/HMPID/workflow/src/DataDecoderSpec.cxx @@ -178,7 +178,7 @@ void DataDecoderTask::decodeTF(framework::ProcessingContext& pc) if (payloadSize == 0) { auto maxWarn = o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef; if (++contDeadBeef <= maxWarn) { - LOGP(alarm, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF{}", + LOGP(warning, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF{}", dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, payloadSize, contDeadBeef == maxWarn ? fmt::format(". {} such inputs in row received, stopping reporting", contDeadBeef) : ""); } diff --git a/Detectors/HMPID/workflow/src/DataDecoderSpec2.cxx b/Detectors/HMPID/workflow/src/DataDecoderSpec2.cxx index 3a86fafa127bc..62a46ca5f30d8 100644 --- a/Detectors/HMPID/workflow/src/DataDecoderSpec2.cxx +++ b/Detectors/HMPID/workflow/src/DataDecoderSpec2.cxx @@ -187,7 +187,7 @@ void DataDecoderTask2::decodeTF(framework::ProcessingContext& pc) if (payloadSize == 0) { auto maxWarn = o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef; if (++contDeadBeef <= maxWarn) { - LOGP(alarm, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF{}", + LOGP(warning, "Found input [{}/{}/{:#x}] TF#{} 1st_orbit:{} Payload {} : assuming no payload for all links in this TF{}", dh->dataOrigin.str, dh->dataDescription.str, dh->subSpecification, dh->tfCounter, dh->firstTForbit, payloadSize, contDeadBeef == maxWarn ? fmt::format(". {} such inputs in row received, stopping reporting", contDeadBeef) : ""); } diff --git a/Detectors/ITSMFT/ITS/macros/test/CheckSquasher.C b/Detectors/ITSMFT/ITS/macros/test/CheckSquasher.C index df26dabf38895..70bdb46abfe37 100644 --- a/Detectors/ITSMFT/ITS/macros/test/CheckSquasher.C +++ b/Detectors/ITSMFT/ITS/macros/test/CheckSquasher.C @@ -39,11 +39,11 @@ void CheckSquasher(const uint chipId = 0, const uint startingROF = 0, const unsi TColor::InvertPalette(); gStyle->SetOptStat(0); // Geometry - o2::base::GeometryManager::loadGeometry(""); - auto gman = o2::its::GeometryTGeo::Instance(); + auto& cc = o2::ccdb::BasicCCDBManager::instance(); + cc.setTimestamp(o2::ccdb::getCurrentTimestamp()); + auto* gman = cc.get("ITS/Config/Geometry"); gman->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); // Topology dictionary - auto& cc = o2::ccdb::BasicCCDBManager::instance(); auto mdict = cc.get("ITS/Calib/ClusterDictionary"); auto fITSclus = TFile::Open(fname.data(), "r"); auto treeITSclus = (TTree*)fITSclus->Get("o2sim"); @@ -60,6 +60,8 @@ void CheckSquasher(const uint chipId = 0, const uint startingROF = 0, const unsi auto clSpan = gsl::span(ITSclus->data(), ITSclus->size()); std::vector hHitMapsVsFrame(nRofs); + TH2D* hHitMapSuperimposed = nullptr; + hHitMapSuperimposed = new TH2D(Form("chip%i_superimposed", chipId), Form("chip %i superimposed; ; ; Counts", chipId), 1024, -0.5, 1023.5, 512, -0.5, 511.5); treeITSclus->GetEvent(0); LOGP(info, "there are {} rofs in this TF", ITSrof->size()); @@ -69,7 +71,7 @@ void CheckSquasher(const uint chipId = 0, const uint startingROF = 0, const unsi getClusterPatterns(pattVec, ITSclus, ITSpatt, *mdict); for (unsigned int iR{0}; iR < nRofs; iR++) { - LOGP(info, "Processing rof {}", iR + startingROF); + LOGP(info, "===============\n \tProcessing rof {} \n\t===============", iR + startingROF); hHitMapsVsFrame[iR] = new TH2D(Form("chip%i_rof%i", chipId, startingROF + iR), Form("chip %i rof %i; ; ; Counts", chipId, startingROF + iR), 1024, -0.5, 1023.5, 512, -0.5, 511.5); // work on data @@ -83,6 +85,7 @@ void CheckSquasher(const uint chipId = 0, const uint startingROF = 0, const unsi auto sID = clus.getSensorID(); if (sID == chipId) { + LOGP(info, "Processing cluster {}", clusInd); clus.print(); // auto labels = clusLabArr->getLabels(clusInd); @@ -106,6 +109,7 @@ void CheckSquasher(const uint chipId = 0, const uint startingROF = 0, const unsi if ((tempChar & s) != 0) // checking active pixels { hHitMapsVsFrame[iR]->Fill(col + ic, row + ir); + hHitMapSuperimposed->Fill(col + ic, row + ir); } ic++; s >>= 1; @@ -125,6 +129,7 @@ void CheckSquasher(const uint chipId = 0, const uint startingROF = 0, const unsi } } auto canvas = new TCanvas(Form("chip%d", chipId), Form("chip%d", chipId), nRofs * 1000, 600); + auto canvasSuperimposition = new TCanvas(Form("chip%d_superimposed", chipId), Form("chip%d_superimposed", chipId), 600, 600); canvas->Divide(nRofs, 1); for (unsigned int i{0}; i < nRofs; ++i) { @@ -133,6 +138,10 @@ void CheckSquasher(const uint chipId = 0, const uint startingROF = 0, const unsi gPad->SetGridy(); hHitMapsVsFrame[i]->Draw("colz"); } + canvasSuperimposition->cd(); + gPad->SetGridx(); + gPad->SetGridy(); + hHitMapSuperimposed->Draw("colz"); } void getClusterPatterns(std::vector& pattVec, std::vector* ITSclus, std::vector* ITSpatt, o2::itsmft::TopologyDictionary& mdict) diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ImpactParameter.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ImpactParameter.cxx index 885ae108754ef..16c38edeb0250 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/ImpactParameter.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/ImpactParameter.cxx @@ -360,12 +360,13 @@ void ImpactParameterStudy::process(o2::globaltracking::RecoContainer& recoData) auto pt = trc.getPt(); o2::gpu::gpustd::array dcaInfo{-999., -999.}; // LOGP(info, " ---> Bz={}", o2::base::Propagator::Instance()->getNominalBz()); - if (o2::base::Propagator::Instance()->propagateToDCABxByBz({Pvtx_refitted.getX(), Pvtx_refitted.getY(), Pvtx_refitted.getZ()}, const_cast(trc), 2.f, matCorr, &dcaInfo)) { + o2::track::TrackPar trcTmp{trc}; + if (o2::base::Propagator::Instance()->propagateToDCABxByBz({Pvtx_refitted.getX(), Pvtx_refitted.getY(), Pvtx_refitted.getZ()}, trcTmp, 2.f, matCorr, &dcaInfo)) { impParRPhi = dcaInfo[0] * toMicrometers; impParZ = dcaInfo[1] * toMicrometers; mHistoImpParXy->Fill(pt, impParRPhi); mHistoImpParZ->Fill(pt, impParZ); - double phi = trc.getPhi(); + double phi = trcTmp.getPhi(); mHistoImpParXyPhi->Fill(phi, impParRPhi); mHistoImpParZPhi->Fill(phi, impParZ); if (phi < TMath::Pi()) { @@ -376,7 +377,7 @@ void ImpactParameterStudy::process(o2::globaltracking::RecoContainer& recoData) mHistoImpParXyBottom->Fill(pt, impParRPhi); mHistoImpParZBottom->Fill(pt, impParZ); } - double sign = trc.getSign(); + double sign = trcTmp.getSign(); if (sign < 0) { mHistoImpParXyNegativeCharge->Fill(pt, impParRPhi); mHistoImpParZNegativeCharge->Fill(pt, impParZ); @@ -557,4 +558,4 @@ DataProcessorSpec getImpactParameterStudy(mask_t srcTracksMask, mask_t srcCluste } // namespace study } // namespace its -} // namespace o2 \ No newline at end of file +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx b/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx index 87c76e492e0fa..bbe7a6ec5e9bb 100644 --- a/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx +++ b/Detectors/ITSMFT/ITS/postprocessing/studies/src/TrackCheck.cxx @@ -477,7 +477,7 @@ void TrackCheckStudy::process() } int trackID, evID, srcID; bool fake; - const_cast(lab).get(trackID, evID, srcID, fake); + lab.get(trackID, evID, srcID, fake); auto& cluster = mClusters[iCluster]; auto layer = mGeometry->getLayer(cluster.getSensorID()); mParticleInfo[srcID][evID][trackID].clusters |= (1 << layer); @@ -510,7 +510,7 @@ void TrackCheckStudy::process() } int trackID, evID, srcID; bool fake; - const_cast(lab).get(trackID, evID, srcID, fake); + lab.get(trackID, evID, srcID, fake); if (srcID == 99) { // skip QED unaccounted++; @@ -723,7 +723,7 @@ void TrackCheckStudy::process() } bool fakec; - const_cast(lab).get(TrackID, EvID, SrcID, fakec); + lab.get(TrackID, EvID, SrcID, fakec); double intHisto = 0; for (int hg = 0; hg < 7; hg++) { if (mParticleInfo[SrcID][EvID][TrackID].pdg == PdgcodeClusterFake[hg] || mParticleInfo[SrcID][EvID][TrackID].pdg == -1 * (PdgcodeClusterFake[hg])) { @@ -819,7 +819,7 @@ void TrackCheckStudy::process() } int trackID, evID, srcID; bool fake; - const_cast(lab).get(trackID, evID, srcID, fake); + lab.get(trackID, evID, srcID, fake); if (srcID == 99) { continue; // skip QED } diff --git a/Detectors/ITSMFT/ITS/simulation/src/digi2raw.cxx b/Detectors/ITSMFT/ITS/simulation/src/digi2raw.cxx index 0998272f745d0..a82ad4001aff3 100644 --- a/Detectors/ITSMFT/ITS/simulation/src/digi2raw.cxx +++ b/Detectors/ITSMFT/ITS/simulation/src/digi2raw.cxx @@ -42,7 +42,7 @@ constexpr int DefRDHVersion = o2::raw::RDHUtils::getVersion& m2r, std::string_view outDir, std::string_view outPrefix, std::string_view fileFor); void digi2raw(std::string_view inpName, std::string_view outDir, std::string_view fileFor, int verbosity, uint32_t rdhV = DefRDHVersion, bool enablePadding = false, - bool noEmptyHBF = false, int superPageSizeInB = 1024 * 1024); + bool noEmptyHBF = false, bool noEmptyROF = false, int superPageSizeInB = 1024 * 1024); int main(int argc, char** argv) { @@ -63,6 +63,7 @@ int main(int argc, char** argv) add_option("rdh-version,r", bpo::value()->default_value(DefRDHVersion), "RDH version to use"); add_option("enable-padding", bpo::value()->default_value(false)->implicit_value(true), "enable GBT word padding to 128 bits even for RDH V7"); add_option("no-empty-hbf,e", bpo::value()->default_value(false)->implicit_value(true), "do not create empty HBF pages (except for HBF starting TF)"); + add_option("no-empty-rof", bpo::value()->default_value(false)->implicit_value(true), "do not create empty ROF blocks"); add_option("hbfutils-config,u", bpo::value()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); add_option("configKeyValues", bpo::value()->default_value(""), "comma-separated configKeyValues"); @@ -96,7 +97,8 @@ int main(int argc, char** argv) vm["verbosity"].as(), vm["rdh-version"].as(), vm["enable-padding"].as(), - vm["no-empty-hbf"].as()); + vm["no-empty-hbf"].as(), + vm["no-empty-rof"].as()); LOG(info) << "HBFUtils settings used for conversion:"; o2::raw::HBFUtils::Instance().print(); @@ -104,7 +106,7 @@ int main(int argc, char** argv) return 0; } -void digi2raw(std::string_view inpName, std::string_view outDir, std::string_view fileFor, int verbosity, uint32_t rdhV, bool enablePadding, bool noEmptyHBF, int superPageSizeInB) +void digi2raw(std::string_view inpName, std::string_view outDir, std::string_view fileFor, int verbosity, uint32_t rdhV, bool enablePadding, bool noEmptyHBF, bool noEmptyROF, int superPageSizeInB) { TStopwatch swTot; swTot.Start(); @@ -178,9 +180,9 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie LOG(info) << "Processing ROF:" << rofRec.getROFrame() << " with " << nDigROF << " entries"; rofRec.print(); } - if (!nDigROF) { + if (!nDigROF && noEmptyROF) { if (verbosity) { - LOG(info) << "Frame is empty"; // ?? + LOG(info) << "Frame is empty"; } continue; } diff --git a/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt index 0b106235a5f67..d11660a116a2f 100644 --- a/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/CMakeLists.txt @@ -13,6 +13,7 @@ o2_add_library(ITStracking TARGETVARNAME targetName SOURCES src/ClusterLines.cxx src/Cluster.cxx + src/Configuration.cxx src/ROframe.cxx src/TimeFrame.cxx src/IOUtils.cxx @@ -36,6 +37,15 @@ o2_add_library(ITStracking O2::ITSMFTReconstruction O2::DataFormatsITS) + +o2_add_library(ITSTrackingInterface + TARGETVARNAME targetName + SOURCES src/TrackingInterface.cxx + PRIVATE_LINK_LIBRARIES + O2::ITStracking + O2::Framework + O2::GPUTracking) + if (OpenMP_CXX_FOUND) target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Array.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Array.h index 7bbc7bb098091..f4f73e715c305 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Array.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Array.h @@ -17,9 +17,6 @@ #define ITSTRACKINGGPU_ARRAY_H_ #include "GPUCommonDef.h" -#ifdef __HIPCC__ -#include -#endif namespace o2 { @@ -27,9 +24,6 @@ namespace its { namespace gpu { - -namespace -{ template struct ArrayTraits final { typedef T InternalArray[Size]; @@ -44,7 +38,6 @@ struct ArrayTraits final { return const_cast(internalArray); } }; -} // namespace template struct Array final { diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h index 3a8af39d1ee63..ecb25b7bc9d71 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/ClusterLinesGPU.h @@ -18,9 +18,6 @@ #include "GPUCommonDef.h" #include /// Required to properly compile MathUtils #include "ITStracking/ClusterLines.h" -#ifdef __HIPCC__ -#include -#endif namespace o2 { diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Context.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Context.h index 294016ffdcaee..bfc4c63756e0b 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Context.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Context.h @@ -19,9 +19,6 @@ #include #include #include "ITStracking/Definitions.h" -#ifdef __HIPCC__ -#include -#endif namespace o2 { diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Stream.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Stream.h index 0ac38e7a8ac4c..b6fbbe166cafe 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Stream.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/Stream.h @@ -18,10 +18,6 @@ #include "ITStracking/Definitions.h" -#ifdef __HIPCC__ -#include -#endif - namespace o2 { namespace its diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h index 947a160bda305..2a2fadb21caeb 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TimeFrameGPU.h @@ -13,10 +13,6 @@ #ifndef TRACKINGITSGPU_INCLUDE_TIMEFRAMEGPU_H #define TRACKINGITSGPU_INCLUDE_TIMEFRAMEGPU_H -#ifdef __HIPCC__ -#include -#endif - #include "ITStracking/TimeFrame.h" #include "ITStracking/Configuration.h" @@ -35,6 +31,12 @@ class GPUChainITS; } namespace its { +template +struct gpuPair { + T1 first; + T2 second; +}; + namespace gpu { @@ -42,7 +44,6 @@ class DefaultGPUAllocator : public ExternalAllocator { void* allocate(size_t size) override; }; - template struct StaticTrackingParameters { StaticTrackingParameters& operator=(const StaticTrackingParameters& t) = default; @@ -195,7 +196,8 @@ class TimeFrameGPU : public TimeFrame void loadTrackSeedsChi2Device(); void loadRoadsDevice(); void loadTrackSeedsDevice(std::vector&); - void createTrackITSExtDevice(const unsigned int&); + void createCellNeighboursDevice(const unsigned int& layer, std::vector>& neighbours); + void createTrackITSExtDevice(std::vector&); void downloadTrackITSExtDevice(std::vector&); void initDeviceChunks(const int, const int); template @@ -223,6 +225,7 @@ class TimeFrameGPU : public TimeFrame // Hybrid Road* getDeviceRoads() { return mRoadsDevice; } TrackITSExt* getDeviceTrackITSExt() { return mTrackITSExtDevice; } + gpuPair* getDeviceNeighbours(const int layer) { return mNeighboursDevice[layer]; } TrackingFrameInfo* getDeviceTrackingFrameInfo(const int); TrackingFrameInfo** getDeviceArrayTrackingFrameInfo() { return mTrackingFrameInfoDeviceArray; } Cluster** getDeviceArrayClusters() const { return mClustersDeviceArray; } @@ -270,6 +273,7 @@ class TimeFrameGPU : public TimeFrame Road* mRoadsDevice; TrackITSExt* mTrackITSExtDevice; + std::array*, nLayers - 2> mNeighboursDevice; std::array mTrackingFrameInfoDevice; TrackingFrameInfo** mTrackingFrameInfoDeviceArray; diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h index f315389de4c7d..3fea14af708a8 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h +++ b/Detectors/ITSMFT/ITS/tracking/GPU/ITStrackingGPU/TrackingKernels.h @@ -14,14 +14,16 @@ #define ITSTRACKINGGPU_TRACKINGKERNELS_H_ #include "DetectorsBase/Propagator.h" -#include "GPUCommonLogger.h" +#include "GPUCommonDef.h" namespace o2 { namespace its { +class CellSeed; namespace gpu { +#ifdef GPUCA_GPUCODE // GPUg() global kernels must only when compiled by GPU compiler GPUd() bool fitTrack(TrackITSExt& track, int start, int end, @@ -45,8 +47,9 @@ GPUg() void fitTrackSeedsKernel( const int startLevel, float maxChi2ClusterAttachment, float maxChi2NDF, - const o2::base::Propagator* propagator); - + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType = o2::base::PropagatorF::MatCorrType::USEMatCorrLUT); +#endif } // namespace gpu void trackSeedHandler(CellSeed* trackSeeds, @@ -57,7 +60,8 @@ void trackSeedHandler(CellSeed* trackSeeds, const int startLevel, float maxChi2ClusterAttachment, float maxChi2NDF, - const o2::base::Propagator* propagator); + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType); } // namespace its } // namespace o2 #endif // ITSTRACKINGGPU_TRACKINGKERNELS_H_ diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu index e7753087715d5..79f4e40dc5f10 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/ClusterLinesGPU.cu @@ -11,6 +11,7 @@ /// /// \author matteo.concas@cern.ch +#include #include "ITStrackingGPU/ClusterLinesGPU.h" namespace o2 @@ -134,4 +135,4 @@ GPUd() void ClusterLinesGPU::computeClusterCentroid() } } // namespace gpu } // namespace its -} // namespace o2 \ No newline at end of file +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Context.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Context.cu index 2df3544012e59..f3bced9463020 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Context.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Context.cu @@ -9,6 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include #include "ITStrackingGPU/Context.h" #include "ITStrackingGPU/Utils.h" diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Stream.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Stream.cu index 980ba507bd613..885587d8d4544 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Stream.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Stream.cu @@ -10,6 +10,7 @@ // or submit itself to any jurisdiction. /// +#include #include "ITStrackingGPU/Stream.h" #include "ITStrackingGPU/Utils.h" #include "GPUCommonLogger.h" @@ -39,4 +40,4 @@ const GPUStream& Stream::get() const } // namespace gpu } // namespace its -} // namespace o2 \ No newline at end of file +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu index 585f081916257..e758bf4990c4f 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TimeFrameGPU.cu @@ -9,6 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. /// +#include #include #include @@ -499,20 +500,18 @@ void TimeFrameGPU::loadClustersDevice() template void TimeFrameGPU::loadTrackingFrameInfoDevice(const int iteration) { - for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { - LOGP(debug, "gpu-transfer: loading {} tfinfo on layer {}, for {} MB.", mTrackingFrameInfo[iLayer].size(), iLayer, mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo) / MB); - allocMemAsync(reinterpret_cast(&mTrackingFrameInfoDevice[iLayer]), mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo), nullptr, getExtAllocator()); - // Register and move data - if (!iteration) { + if (!iteration) { + for (auto iLayer{0}; iLayer < nLayers; ++iLayer) { + LOGP(info, "gpu-transfer: loading {} tfinfo on layer {}, for {} MB.", mTrackingFrameInfo[iLayer].size(), iLayer, mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo) / MB); + allocMemAsync(reinterpret_cast(&mTrackingFrameInfoDevice[iLayer]), mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo), nullptr, getExtAllocator()); + // Register and move data checkGPUError(cudaHostRegister(mTrackingFrameInfo[iLayer].data(), mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo), cudaHostRegisterPortable)); + checkGPUError(cudaMemcpyAsync(mTrackingFrameInfoDevice[iLayer], mTrackingFrameInfo[iLayer].data(), mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo), cudaMemcpyHostToDevice, mGpuStreams[0].get())); } - checkGPUError(cudaMemcpyAsync(mTrackingFrameInfoDevice[iLayer], mTrackingFrameInfo[iLayer].data(), mTrackingFrameInfo[iLayer].size() * sizeof(TrackingFrameInfo), cudaMemcpyHostToDevice, mGpuStreams[0].get())); - } - allocMemAsync(reinterpret_cast(&mTrackingFrameInfoDeviceArray), nLayers * sizeof(TrackingFrameInfo*), nullptr, getExtAllocator()); - if (!iteration) { + allocMemAsync(reinterpret_cast(&mTrackingFrameInfoDeviceArray), nLayers * sizeof(TrackingFrameInfo*), nullptr, getExtAllocator()); checkGPUError(cudaHostRegister(mTrackingFrameInfoDevice.data(), nLayers * sizeof(TrackingFrameInfo*), cudaHostRegisterPortable)); + checkGPUError(cudaMemcpyAsync(mTrackingFrameInfoDeviceArray, mTrackingFrameInfoDevice.data(), nLayers * sizeof(TrackingFrameInfo*), cudaMemcpyHostToDevice, mGpuStreams[0].get())); } - checkGPUError(cudaMemcpyAsync(mTrackingFrameInfoDeviceArray, mTrackingFrameInfoDevice.data(), nLayers * sizeof(TrackingFrameInfo*), cudaMemcpyHostToDevice, mGpuStreams[0].get())); } template @@ -564,14 +563,25 @@ void TimeFrameGPU::loadTrackSeedsDevice(std::vector& seeds) } template -void TimeFrameGPU::createTrackITSExtDevice(const unsigned int& nSeeds) +void TimeFrameGPU::createCellNeighboursDevice(const unsigned int& layer, std::vector>& neighbours) +{ + mCellsNeighbours[layer].clear(); + mCellsNeighbours[layer].resize(neighbours.size()); + LOGP(debug, "gpu-allocation: reserving {} neighbours, for {} MB.", neighbours.size(), neighbours.size() * sizeof(gpuPair) / MB); + allocMemAsync(reinterpret_cast(&mNeighboursDevice[layer]), neighbours.size() * sizeof(gpuPair), &(mGpuStreams[0]), getExtAllocator()); + checkGPUError(cudaMemsetAsync(mNeighboursDevice[layer], 0, neighbours.size() * sizeof(gpuPair), mGpuStreams[0].get())); + checkGPUError(cudaHostRegister(neighbours.data(), neighbours.size() * sizeof(std::pair), cudaHostRegisterPortable)); +} + +template +void TimeFrameGPU::createTrackITSExtDevice(std::vector& seeds) { mTrackITSExt.clear(); - mTrackITSExt.resize(nSeeds); - LOGP(info, "gpu-allocation: reserving {} tracks, for {} MB.", nSeeds, nSeeds * sizeof(o2::its::TrackITSExt) / MB); - allocMemAsync(reinterpret_cast(&mTrackITSExtDevice), nSeeds * sizeof(o2::its::TrackITSExt), &(mGpuStreams[0]), getExtAllocator()); - checkGPUError(cudaMemsetAsync(mTrackITSExtDevice, 0, nSeeds * sizeof(o2::its::TrackITSExt), mGpuStreams[0].get())); - checkGPUError(cudaHostRegister(mTrackITSExt.data(), nSeeds * sizeof(o2::its::TrackITSExt), cudaHostRegisterPortable)); + mTrackITSExt.resize(seeds.size()); + LOGP(debug, "gpu-allocation: reserving {} tracks, for {} MB.", seeds.size(), seeds.size() * sizeof(o2::its::TrackITSExt) / MB); + allocMemAsync(reinterpret_cast(&mTrackITSExtDevice), seeds.size() * sizeof(o2::its::TrackITSExt), &(mGpuStreams[0]), getExtAllocator()); + checkGPUError(cudaMemsetAsync(mTrackITSExtDevice, 0, seeds.size() * sizeof(o2::its::TrackITSExt), mGpuStreams[0].get())); + checkGPUError(cudaHostRegister(mTrackITSExt.data(), seeds.size() * sizeof(o2::its::TrackITSExt), cudaHostRegisterPortable)); } template @@ -606,4 +616,4 @@ template class TimeFrameGPU<7>; template class GpuTimeFrameChunk<7>; } // namespace gpu } // namespace its -} // namespace o2 \ No newline at end of file +} // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu index 7c09851eaa2fb..0bca6360d268c 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TracerGPU.cu @@ -9,6 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include #include "ITStrackingGPU/TracerGPU.h" #if !defined(__HIPCC__) && defined(__USE_GPU_TRACER__) @@ -44,4 +45,4 @@ Tracer::~Tracer() } // namespace gpu } // namespace its } // namespace o2 -#endif \ No newline at end of file +#endif diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx index 343dcf498dee5..ef444cdc79b92 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackerTraitsGPU.cxx @@ -16,7 +16,6 @@ #include #include -#define INVALID_TRIGGER_ERROR_NO_HOST_CODE // workaround to fix undefined type in GPUg() protection on host #include "DataFormatsITS/TrackITS.h" #include "ITStrackingGPU/TrackerTraitsGPU.h" @@ -312,9 +311,9 @@ int TrackerTraitsGPU::getTFNumberOfCells() const //////////////////////////////////////////////////////////////////////////////// // Hybrid tracking template -void TrackerTraitsGPU::computeTrackletsHybrid(const int iteration, int, int) +void TrackerTraitsGPU::computeTrackletsHybrid(const int iteration, int iROFslice, int iVertex) { - TrackerTraits::computeLayerTracklets(iteration, iteration, iteration); + TrackerTraits::computeLayerTracklets(iteration, iROFslice, iVertex); } template @@ -327,6 +326,44 @@ template void TrackerTraitsGPU::findCellsNeighboursHybrid(const int iteration) { TrackerTraits::findCellsNeighbours(iteration); + // for (int iLayer{0}; iLayer < mTrkParams[iteration].CellsPerRoad() - 1; ++iLayer) { + // const int nextLayerCellsNum{static_cast(mTimeFrameGPU->getCells()[iLayer + 1].size())}; + // mTimeFrameGPU->getCellsNeighboursLUT()[iLayer].clear(); + // mTimeFrameGPU->getCellsNeighboursLUT()[iLayer].resize(nextLayerCellsNum, 0); + // if (mTimeFrameGPU->getCells()[iLayer + 1].empty() || + // mTimeFrameGPU->getCellsLookupTable()[iLayer].empty()) { + // mTimeFrameGPU->getCellsNeighbours()[iLayer].clear(); + // continue; + // } + + // int layerCellsNum{static_cast(mTimeFrameGPU->getCells()[iLayer].size())}; + // std::vector> cellsNeighbours; + // cellsNeighbours.reserve(nextLayerCellsNum); + // mTimeFrameGPU->createCellNeighboursDevice(iLayer, cellsNeighbours); + + // // // [...] + // // cellNeighboursHandler(mTimeFrameGPU->getDeviceNeighbours(iLayer)); + // // // // Compute Cell Neighbours LUT + // // // checkGPUError(cub::DeviceScan::ExclusiveSum(mTimeFrameGPU->getChunk(chunkId).getDeviceCUBTmpBuffer(), // d_temp_storage + // // // mTimeFrameGPU->getChunk(chunkId).getTimeFrameGPUParameters()->tmpCUBBufferSize, // temp_storage_bytes + // // // mTimeFrameGPU->getChunk(chunkId).getDeviceCellNeigboursLookupTables(iLayer), // d_in + // // // mTimeFrameGPU->getChunk(chunkId).getDeviceCellNeigboursLookupTables(iLayer), // d_out + // // // mTimeFrameGPU->getHostNCells(chunkId)[iLayer + 1], // num_items + // // // mTimeFrameGPU->getStream(chunkId).get())); + + // // cellsNeighboursHandler(mTimeFrameGPU->getDeviceNeighbours(iLayer)); + // // // [...] + + // std::sort(cellsNeighbours.begin(), cellsNeighbours.end(), [](const std::pair& a, const std::pair& b) { + // return a.second < b.second; + // }); + // mTimeFrameGPU->getCellsNeighbours()[iLayer].clear(); + // mTimeFrameGPU->getCellsNeighbours()[iLayer].reserve(cellsNeighbours.size()); + // for (auto& cellNeighboursIndex : cellsNeighbours) { + // mTimeFrameGPU->getCellsNeighbours()[iLayer].push_back(cellNeighboursIndex.first); + // } + // std::inclusive_scan(mTimeFrameGPU->getCellsNeighboursLUT()[iLayer].begin(), mTimeFrameGPU->getCellsNeighboursLUT()[iLayer].end(), mTimeFrameGPU->getCellsNeighboursLUT()[iLayer].begin()); + // } }; template @@ -349,13 +386,18 @@ void TrackerTraitsGPU::findRoads(const int iteration) updatedCellId.clear(); processNeighbours(iLayer, --level, lastCellSeed, lastCellId, updatedCellSeed, updatedCellId); } - trackSeeds.insert(trackSeeds.end(), updatedCellSeed.begin(), updatedCellSeed.end()); + for (auto& seed : updatedCellSeed) { + if (seed.getQ2Pt() > 1.e3 || seed.getChi2() > mTrkParams[0].MaxChi2NDF * ((startLevel + 2) * 2 - 5)) { + continue; + } + trackSeeds.push_back(seed); + } } if (!trackSeeds.size()) { LOGP(info, "No track seeds found, skipping track finding"); continue; } - mTimeFrameGPU->createTrackITSExtDevice(trackSeeds.size()); + mTimeFrameGPU->createTrackITSExtDevice(trackSeeds); mTimeFrameGPU->loadTrackSeedsDevice(trackSeeds); trackSeedHandler( @@ -367,7 +409,8 @@ void TrackerTraitsGPU::findRoads(const int iteration) startLevel, // const int startLevel, mTrkParams[0].MaxChi2ClusterAttachment, // float maxChi2ClusterAttachment, mTrkParams[0].MaxChi2NDF, // float maxChi2NDF, - mTimeFrameGPU->getDevicePropagator()); // const o2::base::Propagator* propagator + mTimeFrameGPU->getDevicePropagator(), // const o2::base::Propagator* propagator + mCorrType); // o2::base::PropagatorImpl::MatCorrType mTimeFrameGPU->downloadTrackITSExtDevice(trackSeeds); @@ -377,6 +420,9 @@ void TrackerTraitsGPU::findRoads(const int iteration) }); for (auto& track : tracks) { + if (!track.getChi2()) { + continue; // this is to skip the unset tracks that are put at the beginning of the vector by the sorting. To see if this can be optimised. + } int nShared = 0; bool isFirstShared{false}; for (int iLayer{0}; iLayer < mTrkParams[0].NLayers; ++iLayer) { diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu index 6ca04a94efe93..080c7aafaf4e5 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/TrackingKernels.cu @@ -10,6 +10,7 @@ // or submit itself to any jurisdiction. /// +#include #include #include #include @@ -41,11 +42,22 @@ // O2 track model #include "ReconstructionDataFormats/Track.h" +#include "DetectorsBase/Propagator.h" using namespace o2::track; -#ifdef __HIPCC__ -#include "TrackParametrization.cxx" -#include "TrackParametrizationWithError.cxx" -#endif + +#define gpuCheckError(x) \ + { \ + gpuAssert((x), __FILE__, __LINE__); \ + } +inline void gpuAssert(cudaError_t code, const char* file, int line, bool abort = true) +{ + if (code != cudaSuccess) { + LOGF(error, "GPUassert: %s %s %d", cudaGetErrorString(code), file, line); + if (abort) { + throw std::runtime_error("GPU assert failed."); + } + } +} namespace o2 { @@ -76,33 +88,31 @@ GPUd() bool fitTrack(TrackITSExt& track, if (!track.o2::track::TrackParCovF::rotate(trackingHit.alphaTrackingFrame)) { return false; } + + if (!prop->propagateToX(track, + trackingHit.xTrackingFrame, + Bz, + o2::base::PropagatorImpl::MAX_SIN_PHI, + o2::base::PropagatorImpl::MAX_STEP, + matCorrType)) { + return false; + } + if (matCorrType == o2::base::PropagatorF::MatCorrType::USEMatCorrNONE) { - if (!track.propagateTo(trackingHit.xTrackingFrame, Bz)) { + track.setChi2(track.getChi2() + track.getPredictedChi2(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)); + if (!track.TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) { + return false; + } + const float xx0 = (iLayer > 2) ? 1.e-2f : 5.e-3f; // Rough layer thickness + constexpr float radiationLength = 9.36f; // Radiation length of Si [cm] + constexpr float density = 2.33f; // Density of Si [g/cm^3] + if (!track.correctForMaterial(xx0, xx0 * radiationLength * density, true)) { return false; } - } else { - // FIXME - // if (!prop->propagateToX(track, trackingHit.xTrackingFrame, - // prop->getNominalBz(), - // o2::base::PropagatorImpl::MAX_SIN_PHI, - // o2::base::PropagatorImpl::MAX_STEP, - // matCorrType)) { - // return false; - // } - } - track.setChi2(track.getChi2() + track.getPredictedChi2Unchecked(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)); - if (!track.TrackParCov::update(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)) { - return false; } - const float xx0 = (iLayer > 2) ? 1.e-2f : 5.e-3f; // Rough layer thickness - constexpr float radiationLength = 9.36f; // Radiation length of Si [cm] - constexpr float density = 2.33f; // Density of Si [g/cm^3] - if (!track.correctForMaterial(xx0, xx0 * radiationLength * density, true)) { - return false; - } + auto predChi2{track.getPredictedChi2(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)}; - auto predChi2{track.getPredictedChi2Unchecked(trackingHit.positionTrackingFrame, trackingHit.covarianceTrackingFrame)}; if ((nCl >= 3 && predChi2 > chi2clcut) || predChi2 < 0.f) { return false; } @@ -125,32 +135,33 @@ GPUg() void fitTrackSeedsKernel( const int startLevel, float maxChi2ClusterAttachment, float maxChi2NDF, - const o2::base::Propagator* propagator) + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType) { for (int iCurrentTrackSeedIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentTrackSeedIndex < nSeeds; iCurrentTrackSeedIndex += blockDim.x * gridDim.x) { auto& seed = trackSeeds[iCurrentTrackSeedIndex]; - if (seed.getQ2Pt() > 1.e3 || seed.getChi2() > maxChi2NDF * ((startLevel + 2) * 2 - (nLayers - 2))) { - continue; - } + TrackITSExt temporaryTrack{seed}; + temporaryTrack.resetCovariance(); temporaryTrack.setChi2(0); int* clusters = seed.getClusters(); for (int iL{0}; iL < 7; ++iL) { temporaryTrack.setExternalClusterIndex(iL, clusters[iL], clusters[iL] != constants::its::UnusedIndex); } - bool fitSuccess = fitTrack(temporaryTrack, // TrackITSExt& track, - 0, // int lastLayer, - nLayers, // int firstLayer, - 1, // int firstCluster, - maxChi2ClusterAttachment, // float maxChi2ClusterAttachment, - maxChi2NDF, // float maxChi2NDF, - o2::constants::math::VeryBig, // float maxQoverPt, - 0, // nCl, - Bz, // float Bz, - foundTrackingFrameInfo, // TrackingFrameInfo** trackingFrameInfo, - propagator, // const o2::base::Propagator* propagator, - o2::base::PropagatorImpl::MatCorrType::USEMatCorrNONE); // o2::base::PropagatorImpl::MatCorrType::USEMatCorrLUT + + bool fitSuccess = fitTrack(temporaryTrack, // TrackITSExt& track, + 0, // int lastLayer, + nLayers, // int firstLayer, + 1, // int firstCluster, + maxChi2ClusterAttachment, // float maxChi2ClusterAttachment, + maxChi2NDF, // float maxChi2NDF, + o2::constants::math::VeryBig, // float maxQoverPt, + 0, // nCl, + Bz, // float Bz, + foundTrackingFrameInfo, // TrackingFrameInfo** trackingFrameInfo, + propagator, // const o2::base::Propagator* propagator, + matCorrType); // o2::base::PropagatorF::MatCorrType matCorrType if (!fitSuccess) { continue; } @@ -158,18 +169,18 @@ GPUg() void fitTrackSeedsKernel( temporaryTrack.resetCovariance(); temporaryTrack.setChi2(0); - fitSuccess = fitTrack(temporaryTrack, // TrackITSExt& track, - nLayers - 1, // int lastLayer, - -1, // int firstLayer, - -1, // int firstCluster, - maxChi2ClusterAttachment, // float maxChi2ClusterAttachment, - maxChi2NDF, // float maxChi2NDF, - 50.f, // float maxQoverPt, - 0, // nCl, - Bz, // float Bz, - foundTrackingFrameInfo, // TrackingFrameInfo** trackingFrameInfo, - propagator, // const o2::base::Propagator* propagator, - o2::base::PropagatorImpl::MatCorrType::USEMatCorrNONE); // o2::base::PropagatorImpl::MatCorrType::USEMatCorrLUT + fitSuccess = fitTrack(temporaryTrack, // TrackITSExt& track, + nLayers - 1, // int lastLayer, + -1, // int firstLayer, + -1, // int firstCluster, + maxChi2ClusterAttachment, // float maxChi2ClusterAttachment, + maxChi2NDF, // float maxChi2NDF, + 50.f, // float maxQoverPt, + 0, // nCl, + Bz, // float Bz, + foundTrackingFrameInfo, // TrackingFrameInfo** trackingFrameInfo, + propagator, // const o2::base::Propagator* propagator, + matCorrType); // o2::base::PropagatorF::MatCorrType matCorrType if (!fitSuccess) { continue; } @@ -177,6 +188,58 @@ GPUg() void fitTrackSeedsKernel( } } +template // Version for new tracker to supersede the old one +GPUg() void computeLayerCellNeighboursKernel( + CellSeed* cellsCurrentLayer, + CellSeed* cellsNextLayer, + int* neighboursLUT, + const int* cellsNextLayerLUT, + gpuPair* cellNeighbours, + const float maxChi2ClusterAttachment, + const float bz, + const int layerIndex, + const int* nCells, + const int maxCellNeighbours = 1e2) +{ + for (int iCurrentCellIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentCellIndex < nCells[layerIndex]; iCurrentCellIndex += blockDim.x * gridDim.x) { + const auto& currentCellSeed{cellsCurrentLayer[iCurrentCellIndex]}; + const int nextLayerTrackletIndex{currentCellSeed.getSecondTrackletIndex()}; + const int nextLayerFirstCellIndex{cellsNextLayerLUT[nextLayerTrackletIndex]}; + const int nextLayerLastCellIndex{cellsNextLayerLUT[nextLayerTrackletIndex + 1]}; + int foundNeighbours{0}; + for (int iNextCell{nextLayerFirstCellIndex}; iNextCell < nextLayerLastCellIndex; ++iNextCell) { + CellSeed nextCellSeed{cellsNextLayer[iNextCell]}; // Copy + if (nextCellSeed.getFirstTrackletIndex() != nextLayerTrackletIndex) { // Check if cells share the same tracklet + break; + } + if (!nextCellSeed.rotate(currentCellSeed.getAlpha()) || + !nextCellSeed.propagateTo(currentCellSeed.getX(), bz)) { + continue; + } + float chi2 = currentCellSeed.getPredictedChi2(nextCellSeed); + if (chi2 > maxChi2ClusterAttachment) /// TODO: switch to the chi2 wrt cluster to avoid correlation + { + continue; + } + if constexpr (initRun) { + atomicAdd(neighboursLUT + iNextCell, 1); + } else { + if (foundNeighbours >= maxCellNeighbours) { + printf("its-gpu-neighbours-finder: data loss on layer: %d: number of neightbours exceeded the threshold!\n"); + continue; + } + cellNeighbours[neighboursLUT[iNextCell] + foundNeighbours++] = {iCurrentCellIndex, iNextCell}; + + // FIXME: this is prone to race conditions: check on level is not atomic + const int currentCellLevel{currentCellSeed.getLevel()}; + if (currentCellLevel >= nextCellSeed.getLevel()) { + atomicExch(cellsNextLayer[iNextCell].getLevelPtr(), currentCellLevel + 1); // Update level on corresponding cell + } + } + } + } +} + //////////////////////////////////////////////////////////////////////////////// // Legacy Kernels, to possibly take inspiration from //////////////////////////////////////////////////////////////////////////////// @@ -335,7 +398,7 @@ GPUg() void computeLayerTrackletsKernelSingleRof( const float zAtRmin{tanLambda * (minR - currentCluster.radius) + currentCluster.zCoordinate}; const float zAtRmax{tanLambda * (maxR - currentCluster.radius) + currentCluster.zCoordinate}; const float sqInverseDeltaZ0{1.f / (Sq(currentCluster.zCoordinate - primaryVertex.getZ()) + 2.e-8f)}; /// protecting from overflows adding the detector resolution - const float sigmaZ{std::sqrt(Sq(resolution) * Sq(tanLambda) * ((Sq(inverseR0) + sqInverseDeltaZ0) * Sq(meanDeltaR) + 1.f) + Sq(meanDeltaR * mSAngle))}; + const float sigmaZ{o2::gpu::CAMath::Sqrt(Sq(resolution) * Sq(tanLambda) * ((Sq(inverseR0) + sqInverseDeltaZ0) * Sq(meanDeltaR) + 1.f) + Sq(meanDeltaR * mSAngle))}; const int4 selectedBinsRect{getBinsRect(currentCluster, layerIndex, *utils, zAtRmin, zAtRmax, sigmaZ * trkPars->NSigmaCut, phiCut)}; if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) { @@ -458,7 +521,7 @@ GPUg() void computeLayerTrackletsKernelMultipleRof( const float zAtRmin{tanLambda * (minR - currentCluster.radius) + currentCluster.zCoordinate}; const float zAtRmax{tanLambda * (maxR - currentCluster.radius) + currentCluster.zCoordinate}; const float sqInverseDeltaZ0{1.f / (Sq(currentCluster.zCoordinate - primaryVertex.getZ()) + 2.e-8f)}; /// protecting from overflows adding the detector resolution - const float sigmaZ{std::sqrt(Sq(resolution) * Sq(tanLambda) * ((Sq(inverseR0) + sqInverseDeltaZ0) * Sq(meanDeltaR) + 1.f) + Sq(meanDeltaR * mSAngle))}; + const float sigmaZ{o2::gpu::CAMath::Sqrt(Sq(resolution) * Sq(tanLambda) * ((Sq(inverseR0) + sqInverseDeltaZ0) * Sq(meanDeltaR) + 1.f) + Sq(meanDeltaR * mSAngle))}; const int4 selectedBinsRect{getBinsRect(currentCluster, layerIndex, *utils, zAtRmin, zAtRmax, sigmaZ * trkPars->NSigmaCut, phiCut)}; @@ -576,45 +639,6 @@ GPUg() void computeLayerCellsKernel( } } -template -GPUg() void computeLayerCellNeighboursKernel(CellSeed* cellsCurrentLayer, - CellSeed* cellsNextLayer, - const int layerIndex, - const int* cellsNextLayerLUT, - int* neighboursLUT, - int* cellNeighbours, - const int* nCells, - const int maxCellNeighbours = 1e2) -{ - for (int iCurrentCellIndex = blockIdx.x * blockDim.x + threadIdx.x; iCurrentCellIndex < nCells[layerIndex]; iCurrentCellIndex += blockDim.x * gridDim.x) { - const CellSeed& currentCell = cellsCurrentLayer[iCurrentCellIndex]; - const int nextLayerTrackletIndex{currentCell.getSecondTrackletIndex()}; - const int nextLayerFirstCellIndex{cellsNextLayerLUT[nextLayerTrackletIndex]}; - const int nextLayerLastCellIndex{cellsNextLayerLUT[nextLayerTrackletIndex + 1]}; - int foundNeighbours{0}; - for (int iNextCell{nextLayerFirstCellIndex}; iNextCell < nextLayerLastCellIndex; ++iNextCell) { - CellSeed& nextCell = cellsNextLayer[iNextCell]; - if (nextCell.getFirstTrackletIndex() != nextLayerTrackletIndex) { // Check if cells share the same tracklet - break; - } - if constexpr (initRun) { - atomicAdd(neighboursLUT + iNextCell, 1); - } else { - if (foundNeighbours >= maxCellNeighbours) { - printf("its-gpu-neighbours-finder: on layer: %d: found more neighbours (%d) than maximum allowed per cell, skipping writing. This is lossy!\n", layerIndex, neighboursLUT[iNextCell]); - continue; - } - cellNeighbours[neighboursLUT[iNextCell] + foundNeighbours++] = iCurrentCellIndex; - - const int currentCellLevel{currentCell.getLevel()}; - if (currentCellLevel >= nextCell.getLevel()) { - atomicExch(nextCell.getLevelPtr(), currentCellLevel + 1); - } - } - } - } -} - template GPUg() void computeLayerRoadsKernel( const int level, @@ -665,6 +689,31 @@ GPUg() void computeLayerRoadsKernel( } } // namespace gpu +template +void cellNeighboursHandler(CellSeed* cellsCurrentLayer, + CellSeed* cellsNextLayer, + int* neighboursLUT, + const int* cellsNextLayerLUT, + gpuPair* cellNeighbours, + const float maxChi2ClusterAttachment, + const float bz, + const int layerIndex, + const int* nCells, + const int maxCellNeighbours = 1e2) +{ + gpu::computeLayerCellNeighboursKernel<<<20, 512>>>( + cellsCurrentLayer, // CellSeed* cellsCurrentLayer, + cellsNextLayer, // CellSeed* cellsNextLayer, + neighboursLUT, // int* neighboursLUT, + cellsNextLayerLUT, // const int* cellsNextLayerLUT, + cellNeighbours, // gpuPair* cellNeighbours, + maxChi2ClusterAttachment, // const float maxChi2ClusterAttachment, + bz, // const float bz, + layerIndex, // const int layerIndex, + nCells, // const int* nCells, + maxCellNeighbours); // const int maxCellNeighbours = 1e2 +} + void trackSeedHandler(CellSeed* trackSeeds, TrackingFrameInfo** foundTrackingFrameInfo, o2::its::TrackITSExt* tracks, @@ -673,9 +722,10 @@ void trackSeedHandler(CellSeed* trackSeeds, const int startLevel, float maxChi2ClusterAttachment, float maxChi2NDF, - const o2::base::Propagator* propagator) + const o2::base::Propagator* propagator, + const o2::base::PropagatorF::MatCorrType matCorrType) { - gpu::fitTrackSeedsKernel<<<20, 512>>>( + gpu::fitTrackSeedsKernel<<<20, 256>>>( trackSeeds, // CellSeed* trackSeeds, foundTrackingFrameInfo, // TrackingFrameInfo** foundTrackingFrameInfo, tracks, // o2::its::TrackITSExt* tracks, @@ -684,7 +734,11 @@ void trackSeedHandler(CellSeed* trackSeeds, startLevel, // const int startLevel, maxChi2ClusterAttachment, // float maxChi2ClusterAttachment, maxChi2NDF, // float maxChi2NDF, - propagator); // const o2::base::Propagator* propagator + propagator, // const o2::base::Propagator* propagator + matCorrType); // o2::base::PropagatorF::MatCorrType matCorrType + + gpuCheckError(cudaPeekAtLastError()); + gpuCheckError(cudaDeviceSynchronize()); } } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Utils.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Utils.cu index d49837c6272e1..99a24f347bd48 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Utils.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/Utils.cu @@ -9,6 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include #include "ITStrackingGPU/Utils.h" #include "ITStrackingGPU/Context.h" #include "ITStracking/Constants.h" @@ -19,6 +20,7 @@ #include #include #include +#include namespace { @@ -282,14 +284,6 @@ void utils::gpuMemcpyFromSymbol(void* dst, const void* symbol, int size) { checkGPUError(cudaMemcpyFromSymbol(dst, symbol, size, 0, cudaMemcpyDeviceToHost), __FILE__, __LINE__); } - -GPUd() int utils::getLaneIndex() -{ - uint32_t laneIndex; - asm volatile("mov.u32 %0, %%laneid;" - : "=r"(laneIndex)); - return static_cast(laneIndex); -} } // namespace gpu } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cu b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cu index 42881e5ed7d4b..9a1ed507ae5a4 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cu +++ b/Detectors/ITSMFT/ITS/tracking/GPU/cuda/VertexerTraitsGPU.cu @@ -11,6 +11,7 @@ // /// \author matteo.concas@cern.ch +#include #include #include #include @@ -92,7 +93,6 @@ VertexerTraitsGPU::VertexerTraitsGPU() VertexerTraitsGPU::~VertexerTraitsGPU() { - gpu::utils::gpuFree(mDeviceIndexTableUtils); } void VertexerTraitsGPU::initialise(const TrackingParameters& trackingParams) diff --git a/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt b/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt index 30a7ec655c8ae..3c5614b172040 100644 --- a/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/tracking/GPU/hip/CMakeLists.txt @@ -23,30 +23,11 @@ if(HIP_ENABLED) ../cuda/VertexerTraitsGPU.cu ../cuda/Utils.cu PUBLIC_INCLUDE_DIRECTORIES ../ - PRIVATE_INCLUDE_DIRECTORIES - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Base - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Base/hip - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/DataTypes - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Global # "GPUErrors.h" - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/SliceTracker - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/TRDTracking # GPUTRDTracker.h - ${CMAKE_SOURCE_DIR}/DataFormats/Reconstruction/src - ${CMAKE_SOURCE_DIR}/DataFormats/Detectors/TPC/include # "DataFormatsTPC/dEdxInfo.h" - ${CMAKE_SOURCE_DIR}/DataFormats/Detectors/TRD/include # "DataFormatsTRD/Constants.h" - ${CMAKE_SOURCE_DIR}/Detectors/Base/src - ${CMAKE_SOURCE_DIR}/Detectors/TRD/base/include # "TRDBase/GeometryFlat.h" - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Definitions - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Merger - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/TPCConvert - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/DataCompression - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/ITS - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/TPCClusterFinder - ${CMAKE_SOURCE_DIR}/GPU/GPUTracking/Refit PUBLIC_LINK_LIBRARIES O2::ITStracking O2::GPUTracking O2::SimulationDataFormat O2::ReconstructionDataFormats hip::host + PRIVATE_LINK_LIBRARIES O2::GPUTrackingHIPExternalProvider TARGETVARNAME targetName) endif() diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cluster.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cluster.h index 3778f487db25d..0f136edfebfb3 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cluster.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Cluster.h @@ -54,7 +54,9 @@ struct Cluster final { GPUhdi() void Cluster::print() const { +#if !defined(GPUCA_GPUCODE_DEVICE) || (!defined(__OPENCL__) && defined(GPUCA_GPU_DEBUG_PRINT)) printf("Cluster: %f %f %f %f %f %d %d\n", xCoordinate, yCoordinate, zCoordinate, phi, radius, clusterId, indexTableBinIndex); +#endif } struct TrackingFrameInfo { @@ -70,10 +72,12 @@ struct TrackingFrameInfo { o2::gpu::gpustd::array covarianceTrackingFrame = {999., 999., 999.}; GPUdi() void print() const { +#if !defined(GPUCA_GPUCODE_DEVICE) || (!defined(__OPENCL__) && defined(GPUCA_GPU_DEBUG_PRINT)) printf("x: %f y: %f z: %f xTF: %f alphaTF: %f posTF: %f %f covTF: %f %f %f\n", xCoordinate, yCoordinate, zCoordinate, xTrackingFrame, alphaTrackingFrame, positionTrackingFrame[0], positionTrackingFrame[1], covarianceTrackingFrame[0], covarianceTrackingFrame[1], covarianceTrackingFrame[2]); +#endif } ClassDefNV(TrackingFrameInfo, 1); diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h index 41077c2f0eeb1..550b8405770dc 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ClusterLines.h @@ -173,9 +173,9 @@ GPUhdi() void Line::getDCAComponents(const Line& line, const float point[3], flo destArray[0] = line.originPoint[0] - point[0] + line.cosinesDirector[0] * cdelta; destArray[3] = line.originPoint[1] - point[1] + line.cosinesDirector[1] * cdelta; destArray[5] = line.originPoint[2] - point[2] + line.cosinesDirector[2] * cdelta; - destArray[1] = std::sqrt(destArray[0] * destArray[0] + destArray[3] * destArray[3]); - destArray[2] = std::sqrt(destArray[0] * destArray[0] + destArray[5] * destArray[5]); - destArray[4] = std::sqrt(destArray[3] * destArray[3] + destArray[5] * destArray[5]); + destArray[1] = o2::gpu::CAMath::Sqrt(destArray[0] * destArray[0] + destArray[3] * destArray[3]); + destArray[2] = o2::gpu::CAMath::Sqrt(destArray[0] * destArray[0] + destArray[5] * destArray[5]); + destArray[4] = o2::gpu::CAMath::Sqrt(destArray[3] * destArray[3] + destArray[5] * destArray[5]); } inline bool Line::operator==(const Line& rhs) const diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h index fc8d128c6eec1..a700dc1e806c0 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/Configuration.h @@ -31,6 +31,16 @@ namespace o2 namespace its { +enum class TrackingMode { + Sync, + Async, + Cosmics, + Unset, // Special value to leave a default in case we want to override via Configurable Params +}; + +std::string asString(TrackingMode mode); +std::ostream& operator<<(std::ostream& os, TrackingMode v); + template class Configuration : public Param { @@ -123,19 +133,11 @@ struct VertexingParameters { struct TimeFrameGPUParameters { TimeFrameGPUParameters() = default; - // TimeFrameGPUParameters(size_t cubBufferSize, - // size_t maxTrkClu, - // size_t cluLayCap, - // size_t cluROfCap, - // size_t maxTrkCap, - // size_t maxVertCap, - // size_t maxROFs); size_t tmpCUBBufferSize = 1e5; // In average in pp events there are required 4096 bytes size_t maxTrackletsPerCluster = 1e2; size_t clustersPerLayerCapacity = 2.5e5; size_t clustersPerROfCapacity = 1.5e3; - // size_t trackletsCapacity = maxTrackletsPerCluster * clustersPerROfCapacity; size_t validatedTrackletsCapacity = 1e3; size_t cellsLUTsize = validatedTrackletsCapacity; size_t maxNeighboursSize = 1e2; @@ -145,32 +147,10 @@ struct TimeFrameGPUParameters { size_t maxVerticesCapacity = 5e4; size_t nMaxROFs = 1e3; size_t nTimeFrameChunks = 3; + size_t nROFsPerChunk = 768; // pp defaults int maxGPUMemoryGB = -1; }; -// inline TimeFrameGPUParameters::TimeFrameGPUParameters(size_t cubBufferSize, -// size_t maxTrkClu, -// size_t cluLayCap, -// size_t cluROfCap, -// size_t maxTrkCap, -// size_t maxVertCap, -// size_t maxROFs, -// size_t validatedTrackletsCapacity, -// size_t cellsLUTsize, -// size_t maxNeighboursSize, -// size_t neighboursLUTsize, -// size_t maxRoadPerRofSize, -// size_t maxLinesCapacity) : tmpCUBBufferSize{cubBufferSize}, -// maxTrackletsPerCluster{maxTrkClu}, -// clustersPerLayerCapacity{cluLayCap}, -// clustersPerROfCapacity{cluROfCap}, -// maxLinesCapacity{maxTrkCap}, -// maxVerticesCapacity{maxVertCap}, -// nMaxROFs{maxROFs} -// { -// trackletsCapacity = maxTrackletsPerCluster * clustersPerLayerCapacity; -// } - } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h index a39ee1b96c72a..d35e5bc545904 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/ROframe.h @@ -58,8 +58,8 @@ class ROframe final const TrackingFrameInfo& getClusterTrackingFrameInfo(int layerId, const Cluster& cl) const; const MCCompLabel& getClusterFirstLabel(int layerId, const Cluster& cl) const; const MCCompLabel& getClusterFirstLabel(int layerId, const int clId) const; - gsl::span getClusterLabels(int layerId, const int clId) const; - gsl::span getClusterLabels(int layerId, const Cluster& cl) const; + const gsl::span getClusterLabels(int layerId, const int clId) const; + const gsl::span getClusterLabels(int layerId, const Cluster& cl) const; int getClusterExternalIndex(int layerId, const int clId) const; std::vector getTracksId(const int layerId, const std::vector& cl); @@ -75,7 +75,7 @@ class ROframe final private: const int mROframeId; - o2::dataformats::MCTruthContainer* mMClabels = nullptr; + const o2::dataformats::MCTruthContainer* mMClabels = nullptr; std::vector mPrimaryVertices; std::vector> mClusters; std::vector> mTrackingFrameInfo; @@ -115,12 +115,12 @@ inline const MCCompLabel& ROframe::getClusterFirstLabel(int layerId, const int c return *(mMClabels->getLabels(getClusterExternalIndex(layerId, clId)).begin()); } -inline gsl::span ROframe::getClusterLabels(int layerId, const int clId) const +inline const gsl::span ROframe::getClusterLabels(int layerId, const int clId) const { return mMClabels->getLabels(getClusterExternalIndex(layerId, clId)); } -inline gsl::span ROframe::getClusterLabels(int layerId, const Cluster& cl) const +inline const gsl::span ROframe::getClusterLabels(int layerId, const Cluster& cl) const { return getClusterLabels(layerId, cl.clusterId); } @@ -153,7 +153,7 @@ void ROframe::addTrackingFrameInfoToLayer(int layer, T&&... values) inline void ROframe::setMClabelsContainer(const dataformats::MCTruthContainer* ptr) { - mMClabels = const_cast*>(ptr); + mMClabels = ptr; } inline void ROframe::addClusterExternalIndexToLayer(int layer, const int idx) diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h index 5e9f5e80b6ec3..3d99192d8f478 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TimeFrame.h @@ -108,7 +108,7 @@ class TimeFrame void setBeamPosition(const float x, const float y, const float s2, const float base = 50.f, const float systematic = 0.f) { isBeamPositionOverridden = true; - resetBeamXY(x, y, s2 / std::sqrt(base * base + systematic)); + resetBeamXY(x, y, s2 / o2::gpu::CAMath::Sqrt(base * base + systematic)); } float getBeamX() const; @@ -270,6 +270,7 @@ class TimeFrame std::vector> mCellSeedsChi2; std::vector> mRoads; std::vector> mTracks; + std::vector> mCellsNeighbours; const o2::base::PropagatorImpl* mPropagatorDevice = nullptr; // Needed only for GPU protected: @@ -295,7 +296,6 @@ class TimeFrame std::vector> mTrackletLabels; std::vector> mCellLabels; std::vector> mCellsLookupTable; - std::vector> mCellsNeighbours; std::vector> mCellsNeighboursLUT; std::vector> mTracksLabel; std::vector mBogusClusters; /// keep track of clusters with wild coordinates diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h index 87540b9344bbd..1930bc8761c66 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackerTraits.h @@ -103,9 +103,9 @@ class TrackerTraits int mNThreads = 1; bool mApplySmoothing = false; - o2::base::PropagatorImpl::MatCorrType mCorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrNONE; protected: + o2::base::PropagatorImpl::MatCorrType mCorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrNONE; o2::gpu::GPUChainITS* mChain = nullptr; TimeFrame* mTimeFrame; std::vector mTrkParams; diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h index d3a3035bd63cc..36a5fd63b12d1 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/TrackingConfigParam.h @@ -78,6 +78,8 @@ struct TrackerParamConfig : public o2::conf::ConfigurableParamHelpergetX(), v->getY()); + } + mMeanVertex = v; + } + // Task callbacks + void initialise(); + template + void run(framework::ProcessingContext& pc); + + void updateTimeDependentParams(framework::ProcessingContext& pc); + void finaliseCCDB(framework::ConcreteDataMatcher& matcher, void* obj); + + // Custom + void setTraitsFromProvider(VertexerTraits*, TrackerTraits*, TimeFrame*); + void setTrackingMode(TrackingMode mode = TrackingMode::Unset) + { + if (mode == TrackingMode::Unset) { + LOGP(fatal, "ITS Tracking mode Unset is meant to be a default. Specify the mode"); + } + mMode = mode; + } + + private: + bool mIsMC = false; + bool mRunVertexer = true; + bool mCosmicsProcessing = false; + int mUseTriggers = 0; + TrackingMode mMode = TrackingMode::Unset; + bool mOverrideBeamEstimation = false; + const o2::itsmft::TopologyDictionary* mDict = nullptr; + std::unique_ptr mTracker = nullptr; + std::unique_ptr mVertexer = nullptr; + TimeFrame* mTimeFrame = nullptr; + const o2::dataformats::MeanVertexObject* mMeanVertex; +}; + +} // namespace o2::its +#endif // O2_ITS_TRACKINGINTERFACE \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h index 89da9a90df283..365a24cfaee62 100644 --- a/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h +++ b/Detectors/ITSMFT/ITS/tracking/include/ITStracking/VertexerTraits.h @@ -85,13 +85,13 @@ class VertexerTraits TimeFrame*, std::vector*); - VertexingParameters getVertexingParameters() const { return mVrtParams; } static const std::vector> selectClusters(const int* indexTable, const std::array& selectedBinsRect, const IndexTableUtils& utils); // utils VertexingParameters& getVertexingParameters() { return mVrtParams; } + VertexingParameters getVertexingParameters() const { return mVrtParams; } void setIsGPU(const unsigned char isgpu) { mIsGPU = isgpu; }; unsigned char getIsGPU() const { return mIsGPU; }; void dumpVertexerTraits(); diff --git a/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx b/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx index 6ad842a83d78f..8605bb0ecada2 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/ClusterLines.cxx @@ -26,8 +26,8 @@ Line::Line(std::array firstPoint, std::array secondPoint) cosinesDirector[index] = secondPoint[index] - firstPoint[index]; } - float inverseNorm{1.f / std::sqrt(cosinesDirector[0] * cosinesDirector[0] + cosinesDirector[1] * cosinesDirector[1] + - cosinesDirector[2] * cosinesDirector[2])}; + float inverseNorm{1.f / o2::gpu::CAMath::Sqrt(cosinesDirector[0] * cosinesDirector[0] + cosinesDirector[1] * cosinesDirector[1] + + cosinesDirector[2] * cosinesDirector[2])}; for (int index{0}; index < 3; ++index) { cosinesDirector[index] *= inverseNorm; } @@ -73,9 +73,9 @@ std::array Line::getDCAComponents(const Line& line, const std::array(mNrof * (trkParam.ZBins * trkParam.PhiBins + 1), 0)); @@ -375,18 +375,17 @@ void TimeFrame::initialise(const int iteration, const TrackingParameters& trkPar float oneOverR{0.001f * 0.3f * std::abs(mBz) / trkParam.TrackletMinPt}; for (unsigned int iLayer{0}; iLayer < mClusters.size(); ++iLayer) { mMSangles[iLayer] = MSangle(0.14f, trkParam.TrackletMinPt, trkParam.LayerxX0[iLayer]); - mPositionResolution[iLayer] = std::sqrt(0.5f * (trkParam.SystErrorZ2[iLayer] + trkParam.SystErrorY2[iLayer]) + trkParam.LayerResolution[iLayer] * trkParam.LayerResolution[iLayer]); - + mPositionResolution[iLayer] = o2::gpu::CAMath::Sqrt(0.5f * (trkParam.SystErrorZ2[iLayer] + trkParam.SystErrorY2[iLayer]) + trkParam.LayerResolution[iLayer] * trkParam.LayerResolution[iLayer]); if (iLayer < mClusters.size() - 1) { const float& r1 = trkParam.LayerRadii[iLayer]; const float& r2 = trkParam.LayerRadii[iLayer + 1]; - const float res1 = std::hypot(trkParam.PVres, mPositionResolution[iLayer]); - const float res2 = std::hypot(trkParam.PVres, mPositionResolution[iLayer + 1]); - const float cosTheta1half = std::sqrt(1.f - Sq(0.5f * r1 * oneOverR)); - const float cosTheta2half = std::sqrt(1.f - Sq(0.5f * r2 * oneOverR)); + const float res1 = o2::gpu::CAMath::Hypot(trkParam.PVres, mPositionResolution[iLayer]); + const float res2 = o2::gpu::CAMath::Hypot(trkParam.PVres, mPositionResolution[iLayer + 1]); + const float cosTheta1half = o2::gpu::CAMath::Sqrt(1.f - Sq(0.5f * r1 * oneOverR)); + const float cosTheta2half = o2::gpu::CAMath::Sqrt(1.f - Sq(0.5f * r2 * oneOverR)); float x = r2 * cosTheta1half - r1 * cosTheta2half; - float delta = std::sqrt(1. / (1.f - 0.25f * Sq(x * oneOverR)) * (Sq(0.25f * r1 * r2 * Sq(oneOverR) / cosTheta2half + cosTheta1half) * Sq(res1) + Sq(0.25f * r1 * r2 * Sq(oneOverR) / cosTheta1half + cosTheta2half) * Sq(res2))); - mPhiCuts[iLayer] = std::min(std::asin(0.5f * x * oneOverR) + 2.f * mMSangles[iLayer] + delta, constants::math::Pi * 0.5f); + float delta = o2::gpu::CAMath::Sqrt(1. / (1.f - 0.25f * Sq(x * oneOverR)) * (Sq(0.25f * r1 * r2 * Sq(oneOverR) / cosTheta2half + cosTheta1half) * Sq(res1) + Sq(0.25f * r1 * r2 * Sq(oneOverR) / cosTheta1half + cosTheta2half) * Sq(res2))); + mPhiCuts[iLayer] = std::min(o2::gpu::CAMath::ASin(0.5f * x * oneOverR) + 2.f * mMSangles[iLayer] + delta, constants::math::Pi * 0.5f); } } @@ -430,7 +429,7 @@ void TimeFrame::fillPrimaryVerticesXandAlpha() } mPValphaX.reserve(mPrimaryVertices.size()); for (auto& pv : mPrimaryVertices) { - mPValphaX.emplace_back(std::array{std::hypot(pv.getX(), pv.getY()), math_utils::computePhi(pv.getX(), pv.getY())}); + mPValphaX.emplace_back(std::array{o2::gpu::CAMath::Hypot(pv.getX(), pv.getY()), math_utils::computePhi(pv.getX(), pv.getY())}); } } diff --git a/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx b/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx index 7ad8cfbf220ed..42df15b24f052 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Tracker.cxx @@ -102,10 +102,10 @@ void Tracker::clustersToTracks(std::function logger, std::f } iVertex++; } while (iVertex < maxNvertices); - logger(fmt::format("\t- Tracklet finding: {} tracklets in {:.2f} ms", nTracklets, timeTracklets)); - logger(fmt::format("\t- Cell finding: {} cells found in {:.2f} ms", nCells, timeCells)); - logger(fmt::format("\t- Neighbours finding: {} neighbours found in {:.2f} ms", nNeighbours, timeNeighbours)); - logger(fmt::format("\t- Track finding: {} tracks found in {:.2f} ms", nTracks + mTimeFrame->getNumberOfTracks(), timeRoads)); + logger(fmt::format("- Tracklet finding: {} tracklets found in {:.2f} ms", nTracklets, timeTracklets)); + logger(fmt::format("- Cell finding: {} cells found in {:.2f} ms", nCells, timeCells)); + logger(fmt::format("- Neighbours finding: {} neighbours found in {:.2f} ms", nNeighbours, timeNeighbours)); + logger(fmt::format("- Track finding: {} tracks found in {:.2f} ms", nTracks + mTimeFrame->getNumberOfTracks(), timeRoads)); total += timeTracklets + timeCells + timeNeighbours + timeRoads; total += evaluateTask(&Tracker::extendTracks, "Extending tracks", logger, iteration); } @@ -130,37 +130,80 @@ void Tracker::clustersToTracksHybrid(std::function logger, { double total{0.}; mTraits->UpdateTrackingParameters(mTrkParams); + int maxNvertices{-1}; + if (mTrkParams[0].PerPrimaryVertexProcessing) { + for (int iROF{0}; iROF < mTimeFrame->getNrof(); ++iROF) { + maxNvertices = std::max(maxNvertices, (int)mTimeFrame->getPrimaryVertices(iROF).size()); + } + } + for (int iteration = 0; iteration < (int)mTrkParams.size(); ++iteration) { - LOGP(info, "Iteration {}", iteration); + int nROFsIterations = mTrkParams[iteration].nROFsPerIterations > 0 ? mTimeFrame->getNrof() / mTrkParams[iteration].nROFsPerIterations + bool(mTimeFrame->getNrof() % mTrkParams[iteration].nROFsPerIterations) : 1; + logger(fmt::format("=========== ITS Hybrid Tracking iteration {} summary ===========", iteration, nROFsIterations, maxNvertices)); + double timeTracklets{0.}, timeCells{0.}, timeNeighbours{0.}, timeRoads{0.}; + int nTracklets{0}, nCells{0}, nNeighbours{0}, nTracks{-static_cast(mTimeFrame->getNumberOfTracks())}; + total += evaluateTask(&Tracker::initialiseTimeFrameHybrid, "Hybrid Timeframe initialisation", logger, iteration); - total += evaluateTask(&Tracker::computeTrackletsHybrid, "Hybrid Tracklet finding", logger, iteration, iteration, iteration); // TODO: iteration argument put just for the sake of the interface, to be updated with the proper ROF slicing - logger(fmt::format("\t- Number of tracklets: {}", mTraits->getTFNumberOfTracklets())); - if (!mTimeFrame->checkMemory(mTrkParams[iteration].MaxMemory)) { - error("Too much memory used during trackleting, check the detector status and/or the selections."); - break; - } - float trackletsPerCluster = mTraits->getTFNumberOfClusters() > 0 ? float(mTraits->getTFNumberOfTracklets()) / mTraits->getTFNumberOfClusters() : 0.f; - if (trackletsPerCluster > mTrkParams[iteration].TrackletsPerClusterLimit) { - error(fmt::format("Too many tracklets per cluster ({}), check the detector status and/or the selections. Current limit is {}", trackletsPerCluster, mTrkParams[iteration].TrackletsPerClusterLimit)); - break; - } + int iVertex{std::min(maxNvertices, 0)}; - total += evaluateTask(&Tracker::computeCellsHybrid, Form("Hybrid Cell finding iteration %d", iteration), logger, iteration); - logger(fmt::format("\t- Number of Cells: {}", mTraits->getTFNumberOfCells())); - if (!mTimeFrame->checkMemory(mTrkParams[iteration].MaxMemory)) { - error("Too much memory used during cell finding, check the detector status and/or the selections."); - break; - } - float cellsPerCluster = mTraits->getTFNumberOfClusters() > 0 ? float(mTraits->getTFNumberOfCells()) / mTraits->getTFNumberOfClusters() : 0.f; - if (cellsPerCluster > mTrkParams[iteration].CellsPerClusterLimit) { - error(fmt::format("Too many cells per cluster ({}), check the detector status and/or the selections. Current limit is {}", cellsPerCluster, mTrkParams[iteration].CellsPerClusterLimit)); - break; - } - total += evaluateTask(&Tracker::findCellsNeighboursHybrid, Form("Hybrid Neighbour finding iteration %d", iteration), logger, iteration); - logger(fmt::format("\t- Number of Neighbours: {}", mTimeFrame->getNumberOfNeighbours())); - total += evaluateTask(&Tracker::findRoads, Form("Hybrid Track finding iteration %d", iteration), logger, iteration); - logger(fmt::format("\t- Number of Tracks: {}", mTimeFrame->getNumberOfTracks())); + do { + for (int iROFs{0}; iROFs < nROFsIterations; ++iROFs) { + timeTracklets += evaluateTask( + &Tracker::computeTrackletsHybrid, "Tracklet finding", [](std::string) {}, iteration, iROFs, iVertex); + nTracklets += mTraits->getTFNumberOfTracklets(); + if (!mTimeFrame->checkMemory(mTrkParams[iteration].MaxMemory)) { + error(fmt::format("Too much memory used during trackleting in iteration {}, check the detector status and/or the selections.", iteration)); + break; + } + float trackletsPerCluster = mTraits->getTFNumberOfClusters() > 0 ? float(mTraits->getTFNumberOfTracklets()) / mTraits->getTFNumberOfClusters() : 0.f; + if (trackletsPerCluster > mTrkParams[iteration].TrackletsPerClusterLimit) { + error(fmt::format("Too many tracklets per cluster ({}) in iteration {}, check the detector status and/or the selections. Current limit is {}", trackletsPerCluster, iteration, mTrkParams[iteration].TrackletsPerClusterLimit)); + break; + } + + timeCells += evaluateTask( + &Tracker::computeCellsHybrid, "Cell finding", [](std::string) {}, iteration); + nCells += mTraits->getTFNumberOfCells(); + if (!mTimeFrame->checkMemory(mTrkParams[iteration].MaxMemory)) { + error(fmt::format("Too much memory used during cell finding in iteration {}, check the detector status and/or the selections.", iteration)); + break; + } + float cellsPerCluster = mTraits->getTFNumberOfClusters() > 0 ? float(mTraits->getTFNumberOfCells()) / mTraits->getTFNumberOfClusters() : 0.f; + if (cellsPerCluster > mTrkParams[iteration].CellsPerClusterLimit) { + error(fmt::format("Too many cells per cluster ({}) in iteration {}, check the detector status and/or the selections. Current limit is {}", cellsPerCluster, iteration, mTrkParams[iteration].CellsPerClusterLimit)); + break; + } + + timeNeighbours += evaluateTask( + &Tracker::findCellsNeighboursHybrid, "Neighbour finding", [](std::string) {}, iteration); + nNeighbours += mTimeFrame->getNumberOfNeighbours(); + timeRoads += evaluateTask( + &Tracker::findRoads, "Road finding", [](std::string) {}, iteration); + } + iVertex++; + } while (iVertex < maxNvertices); + logger(fmt::format(" - Hybrid tracklet finding: {} tracklets found in {:.2f} ms", nTracklets, timeTracklets)); + logger(fmt::format(" - Hybrid cell finding: {} cells found in {:.2f} ms", nCells, timeCells)); + logger(fmt::format(" - Hybrid neighbours finding: {} neighbours found in {:.2f} ms", nNeighbours, timeNeighbours)); + logger(fmt::format(" - Hybrid track finding: {} tracks found in {:.2f} ms", nTracks + mTimeFrame->getNumberOfTracks(), timeRoads)); + total += timeTracklets + timeCells + timeNeighbours + timeRoads; + // total += evaluateTask(&Tracker::extendTracks, "Hybrid extending tracks", logger, iteration); + } + + // total += evaluateTask(&Tracker::findShortPrimaries, "Hybrid short primaries finding", logger); + + std::stringstream sstream; + if (constants::DoTimeBenchmarks) { + sstream << std::setw(2) << " - " + << "Timeframe " << mTimeFrameCounter++ << " processing completed in: " << total << "ms using " << mTraits->getNThreads() << " threads."; + } + logger(sstream.str()); + + if (mTimeFrame->hasMCinformation()) { + computeTracksMClabels(); } + rectifyClusterIndices(); + mNumberOfRuns++; } void Tracker::initialiseTimeFrame(int& iteration) @@ -193,9 +236,9 @@ void Tracker::initialiseTimeFrameHybrid(int& iteration) mTraits->initialiseTimeFrameHybrid(iteration); } -void Tracker::computeTrackletsHybrid(int& iteration, int&, int&) +void Tracker::computeTrackletsHybrid(int& iteration, int& iROFslice, int& iVertex) { - mTraits->computeTrackletsHybrid(iteration, iteration, iteration); // placeholder for the proper ROF/vertex slicing + mTraits->computeTrackletsHybrid(iteration, iROFslice, iVertex); // placeholder for the proper ROF/vertex slicing } void Tracker::computeCellsHybrid(int& iteration) @@ -412,6 +455,7 @@ void Tracker::rectifyClusterIndices() void Tracker::getGlobalConfiguration() { auto& tc = o2::its::TrackerParamConfig::Instance(); + tc.printKeyValues(true, true); if (tc.useMatCorrTGeo) { mTraits->setCorrType(o2::base::PropagatorImpl::MatCorrType::USEMatCorrTGeo); } else if (tc.useFastMaterial) { diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx index 1efd31ab50d7b..079ac3a775c12 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackerTraits.cxx @@ -98,7 +98,7 @@ void TrackerTraits::computeLayerTracklets(const int iteration, int iROFslice, in for (int iV{startVtx}; iV < endVtx; ++iV) { auto& primaryVertex{primaryVertices[iV]}; - const float resolution = std::sqrt(Sq(mTrkParams[iteration].PVres) / primaryVertex.getNContributors() + Sq(tf->getPositionResolution(iLayer))); + const float resolution = o2::gpu::CAMath::Sqrt(Sq(mTrkParams[iteration].PVres) / primaryVertex.getNContributors() + Sq(tf->getPositionResolution(iLayer))); const float tanLambda{(currentCluster.zCoordinate - primaryVertex.getZ()) * inverseR0}; @@ -106,7 +106,7 @@ void TrackerTraits::computeLayerTracklets(const int iteration, int iROFslice, in const float zAtRmax{tanLambda * (tf->getMaxR(iLayer + 1) - currentCluster.radius) + currentCluster.zCoordinate}; const float sqInverseDeltaZ0{1.f / (Sq(currentCluster.zCoordinate - primaryVertex.getZ()) + 2.e-8f)}; /// protecting from overflows adding the detector resolution - const float sigmaZ{std::sqrt(Sq(resolution) * Sq(tanLambda) * ((Sq(inverseR0) + sqInverseDeltaZ0) * Sq(meanDeltaR) + 1.f) + Sq(meanDeltaR * tf->getMSangle(iLayer)))}; + const float sigmaZ{o2::gpu::CAMath::Sqrt(Sq(resolution) * Sq(tanLambda) * ((Sq(inverseR0) + sqInverseDeltaZ0) * Sq(meanDeltaR) + 1.f) + Sq(meanDeltaR * tf->getMSangle(iLayer)))}; const int4 selectedBinsRect{getBinsRect(currentCluster, iLayer, zAtRmin, zAtRmax, sigmaZ * mTrkParams[iteration].NSigmaCut, tf->getPhiCut(iLayer))}; @@ -291,7 +291,7 @@ void TrackerTraits::computeLayerCells(const int iteration) } #ifdef OPTIMISATION_OUTPUT - float resolution{std::sqrt(0.5f * (mTrkParams[iteration].SystErrorZ2[iLayer] + mTrkParams[iteration].SystErrorZ2[iLayer + 1] + mTrkParams[iteration].SystErrorZ2[iLayer + 2] + mTrkParams[iteration].SystErrorY2[iLayer] + mTrkParams[iteration].SystErrorY2[iLayer + 1] + mTrkParams[iteration].SystErrorY2[iLayer + 2])) / mTrkParams[iteration].LayerResolution[iLayer]}; + float resolution{o2::gpu::CAMath::Sqrt(0.5f * (mTrkParams[iteration].SystErrorZ2[iLayer] + mTrkParams[iteration].SystErrorZ2[iLayer + 1] + mTrkParams[iteration].SystErrorZ2[iLayer + 2] + mTrkParams[iteration].SystErrorY2[iLayer] + mTrkParams[iteration].SystErrorY2[iLayer + 1] + mTrkParams[iteration].SystErrorY2[iLayer + 2])) / mTrkParams[iteration].LayerResolution[iLayer]}; resolution = resolution > 1.e-12 ? resolution : 1.f; #endif const int currentLayerTrackletsNum{static_cast(tf->getTracklets()[iLayer].size())}; @@ -774,7 +774,7 @@ void TrackerTraits::findShortPrimaries() continue; } - float pvRes{mTrkParams[0].PVres / std::sqrt(float(pvs[iV].getNContributors()))}; + float pvRes{mTrkParams[0].PVres / o2::gpu::CAMath::Sqrt(float(pvs[iV].getNContributors()))}; const float posVtx[2]{0.f, pvs[iV].getZ()}; const float covVtx[3]{pvRes, 0.f, pvRes}; float chi2 = temporaryTrack.getPredictedChi2(posVtx, covVtx); @@ -876,9 +876,9 @@ bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool outward, co } } const float phi{hypoParam.getPhi()}; - const float ePhi{std::sqrt(hypoParam.getSigmaSnp2() / hypoParam.getCsp2())}; + const float ePhi{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaSnp2() / hypoParam.getCsp2())}; const float z{hypoParam.getZ()}; - const float eZ{std::sqrt(hypoParam.getSigmaZ2())}; + const float eZ{o2::gpu::CAMath::Sqrt(hypoParam.getSigmaZ2())}; const int4 selectedBinsRect{getBinsRect(iLayer, phi, mTrkParams[iteration].NSigmaCut * ePhi, z, mTrkParams[iteration].NSigmaCut * eZ)}; if (selectedBinsRect.x == 0 && selectedBinsRect.y == 0 && selectedBinsRect.z == 0 && selectedBinsRect.w == 0) { @@ -965,7 +965,7 @@ bool TrackerTraits::trackFollowing(TrackITSExt* track, int rof, bool outward, co /// frame coordinates whereas the others are referred to the global frame. track::TrackParCov TrackerTraits::buildTrackSeed(const Cluster& cluster1, const Cluster& cluster2, const TrackingFrameInfo& tf3) { - const float ca = std::cos(tf3.alphaTrackingFrame), sa = std::sin(tf3.alphaTrackingFrame); + const float ca = o2::gpu::CAMath::Cos(tf3.alphaTrackingFrame), sa = o2::gpu::CAMath::Sin(tf3.alphaTrackingFrame); const float x1 = cluster1.xCoordinate * ca + cluster1.yCoordinate * sa; const float y1 = -cluster1.xCoordinate * sa + cluster1.yCoordinate * ca; const float z1 = cluster1.zCoordinate; @@ -977,9 +977,9 @@ track::TrackParCov TrackerTraits::buildTrackSeed(const Cluster& cluster1, const const float z3 = tf3.positionTrackingFrame[1]; const bool zeroField{std::abs(getBz()) < o2::constants::math::Almost0}; - const float tgp = zeroField ? std::atan2(y3 - y1, x3 - x1) : 1.f; + const float tgp = zeroField ? o2::gpu::CAMath::ATan2(y3 - y1, x3 - x1) : 1.f; const float crv = zeroField ? 1.f : math_utils::computeCurvature(x3, y3, x2, y2, x1, y1); - const float snp = zeroField ? tgp / std::sqrt(1.f + tgp * tgp) : crv * (x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2, x1, y1)); + const float snp = zeroField ? tgp / o2::gpu::CAMath::Sqrt(1.f + tgp * tgp) : crv * (x3 - math_utils::computeCurvatureCentreX(x3, y3, x2, y2, x1, y1)); const float tgl12 = math_utils::computeTanDipAngle(x1, y1, x2, y2, z1, z2); const float tgl23 = math_utils::computeTanDipAngle(x2, y2, x3, y3, z2, z3); const float q2pt = zeroField ? 1.f / o2::track::kMostProbablePt : crv / (getBz() * o2::constants::math::B2C); diff --git a/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx b/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx new file mode 100644 index 0000000000000..492976d164227 --- /dev/null +++ b/Detectors/ITSMFT/ITS/tracking/src/TrackingInterface.cxx @@ -0,0 +1,352 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITSMFTBase/DPLAlpideParam.h" +#include "ITSBase/GeometryTGeo.h" + +#include "ITSReconstruction/FastMultEstConfig.h" +#include "ITSReconstruction/FastMultEst.h" + +#include "ITStracking/TrackingInterface.h" + +#include "DataFormatsITSMFT/ROFRecord.h" +#include "DataFormatsITSMFT/PhysTrigger.h" +#include "DataFormatsTRD/TriggerRecord.h" +#include "CommonDataFormat/IRFrame.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "ITStracking/TrackingConfigParam.h" + +namespace o2 +{ +using namespace framework; +namespace its +{ +void ITSTrackingInterface::initialise() +{ + mRunVertexer = true; + mCosmicsProcessing = false; + std::vector trackParams; + if (mMode == TrackingMode::Unset) { + mMode = (TrackingMode)(o2::its::TrackerParamConfig::Instance().trackingMode); + LOGP(info, "Tracking mode not set, trying to fetch it from configurable params to: {}", asString(mMode)); + } + if (mMode == TrackingMode::Async) { + trackParams.resize(3); + for (auto& param : trackParams) { + param.ZBins = 64; + param.PhiBins = 32; + param.CellsPerClusterLimit = 1.e3f; + param.TrackletsPerClusterLimit = 1.e3f; + } + trackParams[1].TrackletMinPt = 0.2f; + trackParams[1].CellDeltaTanLambdaSigma *= 2.; + trackParams[2].TrackletMinPt = 0.1f; + trackParams[2].CellDeltaTanLambdaSigma *= 4.; + trackParams[2].MinTrackLength = 4; + LOG(info) << "Initializing tracker in async. phase reconstruction with " << trackParams.size() << " passes"; + } else if (mMode == TrackingMode::Sync) { + trackParams.resize(1); + trackParams[0].ZBins = 64; + trackParams[0].PhiBins = 32; + trackParams[0].MinTrackLength = 4; + LOG(info) << "Initializing tracker in sync. phase reconstruction with " << trackParams.size() << " passes"; + } else if (mMode == TrackingMode::Cosmics) { + mCosmicsProcessing = true; + mRunVertexer = false; + trackParams.resize(1); + trackParams[0].MinTrackLength = 4; + trackParams[0].CellDeltaTanLambdaSigma *= 10; + trackParams[0].PhiBins = 4; + trackParams[0].ZBins = 16; + trackParams[0].PVres = 1.e5f; + trackParams[0].MaxChi2ClusterAttachment = 60.; + trackParams[0].MaxChi2NDF = 40.; + trackParams[0].TrackletsPerClusterLimit = 100.; + trackParams[0].CellsPerClusterLimit = 100.; + LOG(info) << "Initializing tracker in reconstruction for cosmics with " << trackParams.size() << " passes"; + + } else { + throw std::runtime_error(fmt::format("Unsupported ITS tracking mode {:s} ", asString(mMode))); + } + + for (auto& params : trackParams) { + params.CorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrLUT; + } + mTracker->setParameters(trackParams); +} + +template +void ITSTrackingInterface::run(framework::ProcessingContext& pc) +{ + auto compClusters = pc.inputs().get>("compClusters"); + gsl::span patterns = pc.inputs().get>("patterns"); + gsl::span physTriggers; + std::vector fromTRD; + if (mUseTriggers == 2) { // use TRD triggers + o2::InteractionRecord ir{0, pc.services().get().firstTForbit}; + auto trdTriggers = pc.inputs().get>("phystrig"); + for (const auto& trig : trdTriggers) { + if (trig.getBCData() >= ir && trig.getNumberOfTracklets()) { + ir = trig.getBCData(); + fromTRD.emplace_back(o2::itsmft::PhysTrigger{ir, 0}); + } + } + physTriggers = gsl::span(fromTRD.data(), fromTRD.size()); + } else if (mUseTriggers == 1) { // use Phys triggers from ITS stream + physTriggers = pc.inputs().get>("phystrig"); + } + + auto rofsinput = pc.inputs().get>("ROframes"); + auto& rofs = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0}, rofsinput.begin(), rofsinput.end()); + auto& irFrames = pc.outputs().make>(Output{"ITS", "IRFRAMES", 0}); + const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); // RS: this should come from CCDB + + irFrames.reserve(rofs.size()); + int nBCPerTF = alpParams.roFrameLengthInBC; + + LOGP(info, "ITSTracker pulled {} clusters, {} RO frames", compClusters.size(), rofs.size()); + + const dataformats::MCTruthContainer* labels = nullptr; + gsl::span mc2rofs; + if (mIsMC) { + labels = pc.inputs().get*>("itsmclabels").release(); + // get the array as read-only span, a snapshot is sent forward + pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0}, pc.inputs().get>("ITSMC2ROframes")); + LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; + } + + auto& allClusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0}); + auto& allTracks = pc.outputs().make>(Output{"ITS", "TRACKS", 0}); + auto& vertROFvec = pc.outputs().make>(Output{"ITS", "VERTICESROF", 0}); + auto& vertices = pc.outputs().make>(Output{"ITS", "VERTICES", 0}); + + // MC + static pmr::vector dummyMCLabTracks, dummyMCLabVerts; + auto& allTrackLabels = mIsMC ? pc.outputs().make>(Output{"ITS", "TRACKSMCTR", 0}) : dummyMCLabTracks; + auto& allVerticesLabels = mIsMC ? pc.outputs().make>(Output{"ITS", "VERTICESMCTR", 0}) : dummyMCLabVerts; + + std::uint32_t roFrame = 0; + + bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS); + LOG(info) << "ITSTracker RO: continuous=" << continuous; + + if (mOverrideBeamEstimation) { + mTimeFrame->setBeamPosition(mMeanVertex->getX(), + mMeanVertex->getY(), + mMeanVertex->getSigmaY2(), + mTracker->getParameters()[0].LayerResolution[0], + mTracker->getParameters()[0].SystErrorY2[0]); + } + + mTracker->setBz(o2::base::Propagator::Instance()->getNominalBz()); + + gsl::span::iterator pattIt = patterns.begin(); + + gsl::span rofspan(rofs); + mTimeFrame->loadROFrameData(rofspan, compClusters, pattIt, mDict, labels); + pattIt = patterns.begin(); + std::vector savedROF; + auto logger = [&](std::string s) { LOG(info) << s; }; + auto fatalLogger = [&](std::string s) { LOG(fatal) << s; }; + auto errorLogger = [&](std::string s) { LOG(error) << s; }; + + FastMultEst multEst; // mult estimator + std::vector processingMask; + int cutVertexMult{0}, cutRandomMult = int(rofs.size()) - multEst.selectROFs(rofs, compClusters, physTriggers, processingMask); + mTimeFrame->setMultiplicityCutMask(processingMask); + float vertexerElapsedTime{0.f}; + if (mRunVertexer) { + vertROFvec.reserve(rofs.size()); + // Run seeding vertexer + if constexpr (isGPU) { + vertexerElapsedTime = mVertexer->clustersToVerticesHybrid(logger); + } else { + vertexerElapsedTime = mVertexer->clustersToVertices(logger); + } + } else { // cosmics + mTimeFrame->resetRofPV(); + } + const auto& multEstConf = FastMultEstConfig::Instance(); // parameters for mult estimation and cuts + for (auto iRof{0}; iRof < rofspan.size(); ++iRof) { + std::vector vtxVecLoc; + auto& vtxROF = vertROFvec.emplace_back(rofspan[iRof]); + vtxROF.setFirstEntry(vertices.size()); + if (mRunVertexer) { + auto vtxSpan = mTimeFrame->getPrimaryVertices(iRof); + vtxROF.setNEntries(vtxSpan.size()); + bool selROF = vtxSpan.size() == 0; + for (auto iV{0}; iV < vtxSpan.size(); ++iV) { + auto& v = vtxSpan[iV]; + if (multEstConf.isVtxMultCutRequested() && !multEstConf.isPassingVtxMultCut(v.getNContributors())) { + continue; // skip vertex of unwanted multiplicity + } + selROF = true; + vertices.push_back(v); + if (mIsMC) { + auto vLabels = mTimeFrame->getPrimaryVerticesLabels(iRof)[iV]; + allVerticesLabels.reserve(allVerticesLabels.size() + vLabels.size()); + std::copy(vLabels.begin(), vLabels.end(), std::back_inserter(allVerticesLabels)); + } + } + if (processingMask[iRof] && !selROF) { // passed selection in clusters and not in vertex multiplicity + LOGP(info, "ROF {} rejected by the vertex multiplicity selection [{},{}]", iRof, multEstConf.cutMultVtxLow, multEstConf.cutMultVtxHigh); + processingMask[iRof] = selROF; + cutVertexMult++; + } + } else { // cosmics + vtxVecLoc.emplace_back(Vertex()); + vtxVecLoc.back().setNContributors(1); + vtxROF.setNEntries(vtxVecLoc.size()); + for (auto& v : vtxVecLoc) { + vertices.push_back(v); + } + mTimeFrame->addPrimaryVertices(vtxVecLoc); + } + } + LOG(info) << fmt::format(" - rejected {}/{} ROFs: random/mult.sel:{} (seed {}), vtx.sel:{}", cutRandomMult + cutVertexMult, rofspan.size(), cutRandomMult, multEst.lastRandomSeed, cutVertexMult); + LOG(info) << fmt::format(" - Vertex seeding total elapsed time: {} ms for {} vertices found in {} ROFs", vertexerElapsedTime, mTimeFrame->getPrimaryVerticesNum(), rofspan.size()); + + if (mOverrideBeamEstimation) { + LOG(info) << fmt::format(" - Beam position set to: {}, {} from meanvertex object", mTimeFrame->getBeamX(), mTimeFrame->getBeamY()); + } else { + LOG(info) << fmt::format(" - Beam position computed for the TF: {}, {}", mTimeFrame->getBeamX(), mTimeFrame->getBeamY()); + } + if (mCosmicsProcessing && compClusters.size() > 1500 * rofspan.size()) { + LOG(error) << "Cosmics processing was requested with an average detector occupancy exceeding 1.e-7, skipping TF processing."; + } else { + + mTimeFrame->setMultiplicityCutMask(processingMask); + // Run CA tracker + if constexpr (isGPU) { + if (mMode == o2::its::TrackingMode::Async) { + mTracker->clustersToTracksHybrid(logger, fatalLogger); + } else { + mTracker->clustersToTracksHybrid(logger, errorLogger); + } + } else { + if (mMode == o2::its::TrackingMode::Async) { + mTracker->clustersToTracks(logger, fatalLogger); + } else { + mTracker->clustersToTracks(logger, errorLogger); + } + } + size_t totTracks{mTimeFrame->getNumberOfTracks()}, totClusIDs{mTimeFrame->getNumberOfUsedClusters()}; + allTracks.reserve(totTracks); + allClusIdx.reserve(totClusIDs); + + if (mTimeFrame->hasBogusClusters()) { + LOG(warning) << fmt::format(" - The processed timeframe had {} clusters with wild z coordinates, check the dictionaries", mTimeFrame->hasBogusClusters()); + } + + for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { + auto& rof{rofs[iROF]}; + auto& tracks = mTimeFrame->getTracks(iROF); + auto number{tracks.size()}; + auto first{allTracks.size()}; + int offset = -rof.getFirstEntry(); // cluster entry!!! + rof.setFirstEntry(first); + rof.setNEntries(number); + + if (processingMask[iROF]) { + irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1).info = tracks.size(); + } + allTrackLabels.reserve(mTimeFrame->getTracksLabel(iROF).size()); // should be 0 if not MC + std::copy(mTimeFrame->getTracksLabel(iROF).begin(), mTimeFrame->getTracksLabel(iROF).end(), std::back_inserter(allTrackLabels)); + // Some conversions that needs to be moved in the tracker internals + for (unsigned int iTrk{0}; iTrk < tracks.size(); ++iTrk) { + auto& trc{tracks[iTrk]}; + trc.setFirstClusterEntry(allClusIdx.size()); // before adding tracks, create final cluster indices + int ncl = trc.getNumberOfClusters(), nclf = 0; + for (int ic = TrackITSExt::MaxClusters; ic--;) { // track internally keeps in->out cluster indices, but we want to store the references as out->in!!! + auto clid = trc.getClusterIndex(ic); + if (clid >= 0) { + trc.setClusterSize(ic, mTimeFrame->getClusterSize(clid)); + allClusIdx.push_back(clid); + nclf++; + } + } + assert(ncl == nclf); + allTracks.emplace_back(trc); + } + } + LOGP(info, "ITSTracker pushed {} tracks and {} vertices", allTracks.size(), vertices.size()); + if (mIsMC) { + LOGP(info, "ITSTracker pushed {} track labels", allTrackLabels.size()); + LOGP(info, "ITSTracker pushed {} vertex labels", allVerticesLabels.size()); + } + } +} + +void ITSTrackingInterface::updateTimeDependentParams(framework::ProcessingContext& pc) +{ + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + static bool initOnceDone = false; + if (!initOnceDone) { // this params need to be queried only once + initOnceDone = true; + pc.inputs().get("itscldict"); // just to trigger the finaliseCCDB + pc.inputs().get*>("itsalppar"); + if (pc.inputs().getPos("itsTGeo") >= 0) { + pc.inputs().get("itsTGeo"); + } + GeometryTGeo* geom = GeometryTGeo::Instance(); + geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, o2::math_utils::TransformType::T2G)); + mVertexer->getGlobalConfiguration(); + mTracker->getGlobalConfiguration(); + if (mOverrideBeamEstimation) { + pc.inputs().get("meanvtx"); + } + } +} + +void ITSTrackingInterface::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } + if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { + LOG(info) << "cluster dictionary updated"; + setClusterDictionary((const o2::itsmft::TopologyDictionary*)obj); + return; + } + // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level + if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { + LOG(info) << "Alpide param updated"; + const auto& par = o2::itsmft::DPLAlpideParam::Instance(); + par.printKeyValues(); + return; + } + if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { + LOGP(info, "Mean vertex acquired"); + setMeanVertex((const o2::dataformats::MeanVertexObject*)obj); + return; + } + if (matcher == ConcreteDataMatcher("ITS", "GEOMTGEO", 0)) { + LOG(info) << "ITS GeometryTGeo loaded from ccdb"; + o2::its::GeometryTGeo::adopt((o2::its::GeometryTGeo*)obj); + return; + } +} + +void ITSTrackingInterface::setTraitsFromProvider(VertexerTraits* vertexerTraits, + TrackerTraits* trackerTraits, + TimeFrame* frame) +{ + mVertexer = std::make_unique(vertexerTraits); + mTracker = std::make_unique(trackerTraits); + mTimeFrame = frame; + mVertexer->adoptTimeFrame(*mTimeFrame); + mTracker->adoptTimeFrame(*mTimeFrame); +} + +template void ITSTrackingInterface::run(framework::ProcessingContext& pc); +template void ITSTrackingInterface::run(framework::ProcessingContext& pc); +} // namespace its +} // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx b/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx index 05303a95a22da..acc59a66a7c2c 100644 --- a/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx +++ b/Detectors/ITSMFT/ITS/tracking/src/Vertexer.cxx @@ -67,6 +67,7 @@ float Vertexer::clustersToVerticesHybrid(std::function logg void Vertexer::getGlobalConfiguration() { auto& vc = o2::its::VertexerParamConfig::Instance(); + vc.printKeyValues(true, true); auto& grc = o2::its::GpuRecoParamConfig::Instance(); VertexingParameters verPar; @@ -90,8 +91,7 @@ void Vertexer::getGlobalConfiguration() verPar.PhiBins = vc.PhiBins; TimeFrameGPUParameters tfGPUpar; - tfGPUpar.maxGPUMemoryGB = grc.maxGPUMemoryGB; - tfGPUpar.maxVerticesCapacity = grc.maxVerticesCapacity; + // tfGPUpar.nROFsPerChunk = grc.nROFsPerChunk; mTraits->updateVertexingParameters(verPar, tfGPUpar); } diff --git a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt index 785417d915a67..3609560eccf72 100644 --- a/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt +++ b/Detectors/ITSMFT/ITS/workflow/CMakeLists.txt @@ -28,7 +28,8 @@ o2_add_library(ITSWorkflow src/DCSAdaposParserWorkflow.cxx src/DCSAdaposParserSpec.cxx src/DCSDataGeneratorWorkflow.cxx - src/DCSGeneratorSpec.cxx + src/DCSGeneratorSpec.cxx + src/TrackWriterWorkflow.cxx PUBLIC_LINK_LIBRARIES O2::Framework O2::SimConfig O2::DetectorsDCS @@ -37,7 +38,7 @@ o2_add_library(ITSWorkflow O2::DataFormatsTRD O2::DataFormatsGlobalTracking O2::SimulationDataFormat - O2::ITStracking + O2::ITSTrackingInterface O2::ITSReconstruction O2::ITSMFTReconstruction O2::ITSMFTWorkflow @@ -58,6 +59,11 @@ o2_add_executable(cluster-writer-workflow COMPONENT_NAME its PUBLIC_LINK_LIBRARIES O2::ITSWorkflow) +o2_add_executable(track-writer-workflow + SOURCES src/its-track-writer-workflow.cxx + COMPONENT_NAME its + PUBLIC_LINK_LIBRARIES O2::ITSWorkflow) + o2_add_executable(cluster-reader-workflow SOURCES src/its-cluster-reader-workflow.cxx COMPONENT_NAME its diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h index 68ef7f0c022b2..02e278eeedda9 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/CookedTrackerSpec.h @@ -35,7 +35,7 @@ namespace its class CookedTrackerDPL : public Task { public: - CookedTrackerDPL(std::shared_ptr gr, bool useMC, int trgType, const std::string& trMode); + CookedTrackerDPL(std::shared_ptr gr, bool useMC, int trgType, const TrackingMode& trMode); ~CookedTrackerDPL() override = default; void init(InitContext& ic) final; void run(ProcessingContext& pc) final; @@ -51,7 +51,7 @@ class CookedTrackerDPL : public Task bool mUseMC = true; bool mRunVertexer = true; int mUseTriggers = 0; - std::string mMode = "async"; + TrackingMode mMode = TrackingMode::Sync; const o2::itsmft::TopologyDictionary* mDict = nullptr; std::unique_ptr mGRP = nullptr; o2::its::CookedTracker mTracker; diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h index 9106881139a3e..7f9efa2098893 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/RecoWorkflow.h @@ -16,9 +16,7 @@ #include "Framework/WorkflowSpec.h" -#include "GPUO2Interface.h" -#include "GPUReconstruction.h" -#include "GPUChainITS.h" +#include "GPUDataTypes.h" namespace o2 { diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h index 07761f20fd872..18fd2bda0c4df 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/ThresholdCalibratorSpec.h @@ -161,6 +161,7 @@ class ITSThresholdCalibrator : public Task // Tree to save threshold info in full threshold scan case TFile* mRootOutfile = nullptr; TTree* mThresholdTree = nullptr; + TTree* mScTree = nullptr; TTree* mSlopeTree = nullptr; short int vChipid[N_COL]; short int vRow[N_COL]; @@ -169,9 +170,11 @@ class ITSThresholdCalibrator : public Task float vNoise[N_COL]; unsigned char vPoints[N_COL]; short int vMixData[N_COL]; - unsigned char vCharge[N_COL]; float vSlope[N_COL]; float vIntercept[N_COL]; + unsigned char vCharge[N_COL]; + unsigned char vHits[N_COL]; + short int mColStep = 8; // save s-curves to tree every mColStep pixels on 1 row // Initialize pointers for doing error function fits TH1F* mFitHist = nullptr; @@ -231,7 +234,7 @@ class ITSThresholdCalibrator : public Task short int mRunTypeUp = -1; short int mRunTypeRU[N_RU] = {0}; short int mRunTypeChip[24120] = {0}; - short int mChipLastRow[24120] = {-1}; + short int mChipLastRow[24120] = {0}; bool mActiveLinks[N_RU][3] = {{false}}; std::set mRuSet; short int mRu = 0; diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterWorkflow.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterWorkflow.h new file mode 100644 index 0000000000000..038b3bca6bdb8 --- /dev/null +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackWriterWorkflow.h @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_ITS_TRACK_WRITER_WORKFLOW_H +#define O2_ITS_TRACK_WRITER_WORKFLOW_H + +#include "Framework/WorkflowSpec.h" + +namespace o2 +{ +namespace its +{ + +namespace track_writer_workflow +{ +framework::WorkflowSpec getWorkflow(bool useMC); +} + +} // namespace its +} // namespace o2 +#endif \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h index 10a9a9d7c0bee..be9965fc8be58 100644 --- a/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h +++ b/Detectors/ITSMFT/ITS/workflow/include/ITSWorkflow/TrackerSpec.h @@ -21,19 +21,13 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" -#include "ITStracking/TimeFrame.h" -#include "ITStracking/Tracker.h" -#include "ITStracking/TrackerTraits.h" -#include "ITStracking/Vertexer.h" -#include "ITStracking/VertexerTraits.h" +#include "ITStracking/TrackingInterface.h" -#include "GPUO2Interface.h" -#include "GPUReconstruction.h" -#include "GPUChainITS.h" -#include "CommonUtils/StringUtils.h" -#include "TStopwatch.h" +#include "GPUDataTypes.h" #include "DetectorsBase/GRPGeomHelper.h" +#include "TStopwatch.h" + namespace o2 { namespace its @@ -45,47 +39,27 @@ class TrackerDPL : public framework::Task TrackerDPL(std::shared_ptr gr, bool isMC, int trgType, - const std::string& trModeS, + const TrackingMode& trMode = TrackingMode::Unset, const bool overrBeamEst = false, - o2::gpu::GPUDataTypes::DeviceType dType = o2::gpu::GPUDataTypes::DeviceType::CPU); + gpu::GPUDataTypes::DeviceType dType = gpu::GPUDataTypes::DeviceType::CPU); ~TrackerDPL() override = default; void init(framework::InitContext& ic) final; void run(framework::ProcessingContext& pc) final; void endOfStream(framework::EndOfStreamContext& ec) final; void finaliseCCDB(framework::ConcreteDataMatcher& matcher, void* obj) final; void stop() final; - void setClusterDictionary(const o2::itsmft::TopologyDictionary* d) { mDict = d; } - void setMeanVertex(const o2::dataformats::MeanVertexObject* v) - { - if (!v) { - return; - } - mMeanVertex = v; - } private: void updateTimeDependentParams(framework::ProcessingContext& pc); - - bool mIsMC = false; - bool mRunVertexer = true; - bool mCosmicsProcessing = false; - int mUseTriggers = 0; - std::string mMode = "sync"; - bool mOverrideBeamEstimation = false; - std::shared_ptr mGGCCDBRequest; - const o2::itsmft::TopologyDictionary* mDict = nullptr; std::unique_ptr mRecChain = nullptr; std::unique_ptr mChainITS = nullptr; - std::unique_ptr mTracker = nullptr; - std::unique_ptr mVertexer = nullptr; - TimeFrame* mTimeFrame = nullptr; - const o2::dataformats::MeanVertexObject* mMeanVertex; + std::shared_ptr mGGCCDBRequest; + ITSTrackingInterface mITSTrackingInterface; TStopwatch mTimer; }; -/// create a processor spec -/// run ITS CA tracker -framework::DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int useTrig, const std::string& trModeS, const bool overrBeamEst, o2::gpu::GPUDataTypes::DeviceType dType); +using o2::its::TrackingMode; +framework::DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int useTrig, const std::string& trMode, const bool overrBeamEst = false, gpu::GPUDataTypes::DeviceType dType = gpu::GPUDataTypes::DeviceType::CPU); } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx index 71987d0480566..16e2c65a37e33 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ClustererSpec.cxx @@ -46,6 +46,7 @@ void ClustererDPL::init(InitContext& ic) mUseClusterDictionary = !ic.options().get("ignore-cluster-dictionary"); o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); mNThreads = std::max(1, ic.options().get("nthreads")); + LOGP(info, "Initialising ITSClusterer with {} threads", mNThreads); mState = 1; } diff --git a/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx index 463932dc9294c..01e649f982896 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/CookedTrackerSpec.cxx @@ -52,7 +52,7 @@ namespace its using Vertex = o2::dataformats::Vertex>; -CookedTrackerDPL::CookedTrackerDPL(std::shared_ptr gr, bool useMC, int trgType, const std::string& trMode) : mGGCCDBRequest(gr), mUseMC(useMC), mUseTriggers{trgType}, mMode(trMode) +CookedTrackerDPL::CookedTrackerDPL(std::shared_ptr gr, bool useMC, int trgType, const TrackingMode& trMode) : mGGCCDBRequest(gr), mUseMC(useMC), mUseTriggers{trgType}, mMode(trMode) { mVertexerTraitsPtr = std::make_unique(); mVertexerPtr = std::make_unique(mVertexerTraitsPtr.get()); @@ -232,7 +232,7 @@ void CookedTrackerDPL::updateTimeDependentParams(ProcessingContext& pc) mTracker.setGeometry(geom); mTracker.setConfigParams(); LOG(info) << "Tracking mode " << mMode; - if (mMode == "cosmics") { + if (mMode == TrackingMode::Cosmics) { LOG(info) << "Setting cosmics parameters..."; mTracker.setParametersCosmics(); mRunVertexer = false; @@ -263,13 +263,13 @@ void CookedTrackerDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) return; } if (matcher == ConcreteDataMatcher("ITS", "GEOMTGEO", 0)) { - LOG(info) << "ITS GeomtetryTGeo loaded from ccdb"; + LOG(info) << "ITS GeometryTGeo loaded from ccdb"; o2::its::GeometryTGeo::adopt((o2::its::GeometryTGeo*)obj); return; } } -DataProcessorSpec getCookedTrackerSpec(bool useMC, bool useGeom, int trgType, const std::string& trMode) +DataProcessorSpec getCookedTrackerSpec(bool useMC, bool useGeom, int trgType, const std::string& trModeS) { std::vector inputs; inputs.emplace_back("compClusters", "ITS", "COMPCLUSTERS", 0, Lifetime::Timeframe); @@ -312,7 +312,11 @@ DataProcessorSpec getCookedTrackerSpec(bool useMC, bool useGeom, int trgType, co "its-cooked-tracker", inputs, outputs, - AlgorithmSpec{adaptFromTask(ggRequest, useMC, trgType, trMode)}, + AlgorithmSpec{adaptFromTask(ggRequest, + useMC, + trgType, + trModeS == "sync" ? o2::its::TrackingMode::Sync : trModeS == "async" ? o2::its::TrackingMode::Async + : o2::its::TrackingMode::Cosmics)}, Options{{"nthreads", VariantType::Int, 1, {"Number of threads"}}}}; } diff --git a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx index 767651d731301..dc75d90150eb8 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/RecoWorkflow.cxx @@ -31,7 +31,6 @@ namespace o2 { namespace its { - namespace reco_workflow { @@ -64,7 +63,6 @@ framework::WorkflowSpec getWorkflow(bool useMC, cfg.runITSTracking = true; cfg.itsTriggerType = useTrig; cfg.itsOverrBeamEst = overrideBeamPosition; - cfg.itsTrackingMode = trmode == "sync" ? 0 : (trmode == "async" ? 1 : 2); Inputs ggInputs; auto ggRequest = std::make_shared(false, true, false, true, true, diff --git a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx index 391ef5c38677c..895e70866e5ba 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/ThresholdCalibratorSpec.cxx @@ -67,6 +67,15 @@ void ITSThresholdCalibrator::init(InitContext& ic) { LOGF(info, "ITSThresholdCalibrator init...", mSelfName); + for (int i = 0; i < 24120; i++) { + mChipLastRow[i] = -1; + } + + mColStep = ic.options().get("s-curve-col-step"); + if (mColStep >= N_COL) { + LOG(warning) << "mColStep = " << mColStep << ": saving s-curves of only 1 pixel (pix 0) per row"; + } + std::string fittype = ic.options().get("fittype"); if (fittype == "derivative") { this->mFitType = DERIVATIVE; @@ -359,41 +368,49 @@ void ITSThresholdCalibrator::initThresholdTree(bool recreate /*=true*/) // Initialize ROOT output file // to prevent premature external usage, use temporary name const char* option = recreate ? "RECREATE" : "UPDATE"; - this->mRootOutfile = new TFile(filename.c_str(), option); + mRootOutfile = new TFile(filename.c_str(), option); + + // Tree containing the s-curves points + mScTree = new TTree("s-curve-points", "s-curve-points"); + mScTree->Branch("chipid", &vChipid, "vChipID[1024]/S"); + mScTree->Branch("row", &vRow, "vRow[1024]/S"); // Initialize output TTree branches - this->mThresholdTree = new TTree("ITS_calib_tree", "ITS_calib_tree"); - this->mThresholdTree->Branch("chipid", &vChipid, "vChipID[1024]/S"); - this->mThresholdTree->Branch("row", &vRow, "vRow[1024]/S"); - if (this->mScanType == 'T') { - this->mThresholdTree->Branch("thr", &vThreshold, "vThreshold[1024]/S"); - this->mThresholdTree->Branch("noise", &vNoise, "vNoise[1024]/F"); - this->mThresholdTree->Branch("spoints", &vPoints, "vPoints[1024]/b"); - this->mThresholdTree->Branch("success", &vSuccess, "vSuccess[1024]/O"); + mThresholdTree = new TTree("ITS_calib_tree", "ITS_calib_tree"); + mThresholdTree->Branch("chipid", &vChipid, "vChipID[1024]/S"); + mThresholdTree->Branch("row", &vRow, "vRow[1024]/S"); + if (mScanType == 'T') { + mThresholdTree->Branch("thr", &vThreshold, "vThreshold[1024]/S"); + mThresholdTree->Branch("noise", &vNoise, "vNoise[1024]/F"); + mThresholdTree->Branch("spoints", &vPoints, "vPoints[1024]/b"); + mThresholdTree->Branch("success", &vSuccess, "vSuccess[1024]/O"); + + mScTree->Branch("chg", &vCharge, "vCharge[1024]/b"); + mScTree->Branch("hits", &vHits, "vHits[1024]/b"); } else if (mScanType == 'D' || mScanType == 'A') { // this->mScanType == 'D' and this->mScanType == 'A' - this->mThresholdTree->Branch("n_hits", &vThreshold, "vThreshold[1024]/S"); + mThresholdTree->Branch("n_hits", &vThreshold, "vThreshold[1024]/S"); } else if (mScanType == 'P') { - this->mThresholdTree->Branch("n_hits", &vThreshold, "vThreshold[1024]/S"); - this->mThresholdTree->Branch("strobedel", &vMixData, "vMixData[1024]/S"); + mThresholdTree->Branch("n_hits", &vThreshold, "vThreshold[1024]/S"); + mThresholdTree->Branch("strobedel", &vMixData, "vMixData[1024]/S"); } else if (mScanType == 'p') { - this->mThresholdTree->Branch("n_hits", &vThreshold, "vThreshold[1024]/S"); - this->mThresholdTree->Branch("strobedel", &vMixData, "vMixData[1024]/S"); - this->mThresholdTree->Branch("charge", &vCharge, "vCharge[1024]/b"); + mThresholdTree->Branch("n_hits", &vThreshold, "vThreshold[1024]/S"); + mThresholdTree->Branch("strobedel", &vMixData, "vMixData[1024]/S"); + mThresholdTree->Branch("charge", &vCharge, "vCharge[1024]/b"); if (doSlopeCalculation) { - this->mSlopeTree = new TTree("line_tree", "line_tree"); - this->mSlopeTree->Branch("chipid", &vChipid, "vChipID[1024]/S"); - this->mSlopeTree->Branch("row", &vRow, "vRow[1024]/S"); - this->mSlopeTree->Branch("slope", &vSlope, "vSlope[1024]/F"); - this->mSlopeTree->Branch("intercept", &vIntercept, "vIntercept[1024]/F"); + mSlopeTree = new TTree("line_tree", "line_tree"); + mSlopeTree->Branch("chipid", &vChipid, "vChipID[1024]/S"); + mSlopeTree->Branch("row", &vRow, "vRow[1024]/S"); + mSlopeTree->Branch("slope", &vSlope, "vSlope[1024]/F"); + mSlopeTree->Branch("intercept", &vIntercept, "vIntercept[1024]/F"); } } else if (mScanType == 'R') { - this->mThresholdTree->Branch("n_hits", &vThreshold, "vThreshold[1024]/S"); - this->mThresholdTree->Branch("vresetd", &vMixData, "vMixData[1024]/S"); + mThresholdTree->Branch("n_hits", &vThreshold, "vThreshold[1024]/S"); + mThresholdTree->Branch("vresetd", &vMixData, "vMixData[1024]/S"); } else if (mScanType == 'r') { - this->mThresholdTree->Branch("thr", &vThreshold, "vThreshold[1024]/S"); - this->mThresholdTree->Branch("noise", &vNoise, "vNoise[1024]/F"); - this->mThresholdTree->Branch("success", &vSuccess, "vSuccess[1024]/O"); - this->mThresholdTree->Branch("vresetd", &vMixData, "vMixData[1024]/S"); + mThresholdTree->Branch("thr", &vThreshold, "vThreshold[1024]/S"); + mThresholdTree->Branch("noise", &vNoise, "vNoise[1024]/F"); + mThresholdTree->Branch("success", &vSuccess, "vSuccess[1024]/O"); + mThresholdTree->Branch("vresetd", &vMixData, "vMixData[1024]/S"); } return; @@ -770,7 +787,18 @@ void ITSThresholdCalibrator::extractThresholdRow(const short int& chipID, const this->saveThreshold(); // save before moving to the next vresetd } } - } + + // Fill the ScTree tree + if (mScanType == 'T' || mScanType == 'I' || mScanType == 'V') { // TODO: store also for other scans? + for (int ichg = mMin; ichg <= mMax; ichg++) { + for (short int col_i = 0; col_i < this->N_COL; col_i += mColStep) { + vCharge[col_i] = ichg; + vHits[col_i] = mPixelHits[chipID][row][col_i][0][ichg - mMin]; + } + mScTree->Fill(); + } + } + } // end of the else // Saves threshold information to internal memory if (mScanType != 'P' && mScanType != 'p' && mScanType != 'R' && mScanType != 'r') { @@ -823,20 +851,24 @@ void ITSThresholdCalibrator::saveThreshold() void ITSThresholdCalibrator::finalizeOutput() { // Check that objects actually exist in memory - if (!(this->mRootOutfile) || !(this->mThresholdTree) || (doSlopeCalculation && !(this->mSlopeTree))) { + if (!(mScTree) || !(this->mRootOutfile) || !(this->mThresholdTree) || (doSlopeCalculation && !(this->mSlopeTree))) { return; } // Ensure that everything has been written to the ROOT file this->mRootOutfile->cd(); this->mThresholdTree->Write(nullptr, TObject::kOverwrite); + this->mScTree->Write(nullptr, TObject::kOverwrite); + if (doSlopeCalculation) { this->mSlopeTree->Write(nullptr, TObject::kOverwrite); } - // Clean up the mThresholdTree and ROOT output file + // Clean up the mThresholdTree, mScTree and ROOT output file delete this->mThresholdTree; this->mThresholdTree = nullptr; + delete mScTree; + mScTree = nullptr; if (doSlopeCalculation) { delete this->mSlopeTree; this->mSlopeTree = nullptr; @@ -2015,7 +2047,8 @@ DataProcessorSpec getITSThresholdCalibratorSpec(const ITSCalibInpConf& inpConf) {"finalize-at-eos", VariantType::Bool, false, {"Call the finalize() method at the end of stream: to be used in case end-of-run flags are not available so to force calculations at end of run"}}, {"charge-a", VariantType::Int, 0, {"To use with --calculate-slope, it defines the charge (in DAC) for the 1st point used for the slope calculation"}}, {"charge-b", VariantType::Int, 0, {"To use with --calculate-slope, it defines the charge (in DAC) for the 2nd point used for the slope calculation"}}, - {"meb-select", VariantType::Int, -1, {"Select from which multi-event buffer consider the hits: 0,1 or 2"}}}}; + {"meb-select", VariantType::Int, -1, {"Select from which multi-event buffer consider the hits: 0,1 or 2"}}, + {"s-curve-col-step", VariantType::Int, 8, {"save s-curves points to tree every s-curve-col-step pixels on 1 row"}}}}; } } // namespace its } // namespace o2 diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackWriterWorkflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackWriterWorkflow.cxx new file mode 100644 index 0000000000000..ae2cb3648ec86 --- /dev/null +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackWriterWorkflow.cxx @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITSWorkflow/TrackWriterWorkflow.h" +#include "ITSWorkflow/TrackWriterSpec.h" + +namespace o2 +{ +namespace its +{ + +namespace track_writer_workflow +{ + +framework::WorkflowSpec getWorkflow(bool useMC) +{ + framework::WorkflowSpec specs; + + specs.emplace_back(o2::its::getTrackWriterSpec(useMC)); + + return specs; +} + +} // namespace track_writer_workflow +} // namespace its +} // namespace o2 \ No newline at end of file diff --git a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx index f993187546de5..367fa8673cc70 100644 --- a/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx +++ b/Detectors/ITSMFT/ITS/workflow/src/TrackerSpec.cxx @@ -9,39 +9,12 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// @file TrackerSpec.cxx - #include -#include "TGeoGlobalMagField.h" - #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" #include "Framework/CCDBParamSpec.h" #include "ITSWorkflow/TrackerSpec.h" -#include "DataFormatsITSMFT/CompCluster.h" -#include "DataFormatsITS/TrackITS.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "SimulationDataFormat/MCTruthContainer.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsITSMFT/PhysTrigger.h" - -#include "ITStracking/ROframe.h" -#include "ITStracking/IOUtils.h" -#include "ITStracking/TrackingConfigParam.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "ITSMFTReconstruction/ClustererParam.h" - -#include "Field/MagneticField.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsBase/Propagator.h" -#include "ITSBase/GeometryTGeo.h" -#include "CommonDataFormat/IRFrame.h" -#include "DetectorsCommonDataFormats/DetectorNameConf.h" -#include "DataFormatsTRD/TriggerRecord.h" -#include "ITSReconstruction/FastMultEstConfig.h" -#include "ITSReconstruction/FastMultEst.h" -#include namespace o2 { @@ -53,16 +26,13 @@ using Vertex = o2::dataformats::Vertex>; TrackerDPL::TrackerDPL(std::shared_ptr gr, bool isMC, int trgType, - const std::string& trModeS, + const TrackingMode& trMode, const bool overrBeamEst, o2::gpu::GPUDataTypes::DeviceType dType) : mGGCCDBRequest(gr), - mIsMC{isMC}, - mUseTriggers{trgType}, - mMode{trModeS}, - mOverrideBeamEstimation{overrBeamEst}, - mRecChain{o2::gpu::GPUReconstruction::CreateInstance(dType, true)} + mRecChain{o2::gpu::GPUReconstruction::CreateInstance(dType, true)}, + mITSTrackingInterface{isMC, trgType, overrBeamEst} { - std::transform(mMode.begin(), mMode.end(), mMode.begin(), [](unsigned char c) { return std::tolower(c); }); + mITSTrackingInterface.setTrackingMode(trMode); } void TrackerDPL::init(InitContext& ic) @@ -71,60 +41,10 @@ void TrackerDPL::init(InitContext& ic) mTimer.Reset(); o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); mChainITS.reset(mRecChain->AddChain()); - mVertexer = std::make_unique(mChainITS->GetITSVertexerTraits()); - mTracker = std::make_unique(mChainITS->GetITSTrackerTraits()); - mTimeFrame = mChainITS->GetITSTimeframe(); - mVertexer->adoptTimeFrame(*mTimeFrame); - mTracker->adoptTimeFrame(*mTimeFrame); - mRunVertexer = true; - mCosmicsProcessing = false; - std::vector trackParams; - - if (mMode == "async") { - - trackParams.resize(3); - for (auto& param : trackParams) { - param.ZBins = 64; - param.PhiBins = 32; - param.CellsPerClusterLimit = 1.e3f; - param.TrackletsPerClusterLimit = 1.e3f; - } - trackParams[1].TrackletMinPt = 0.2f; - trackParams[1].CellDeltaTanLambdaSigma *= 2.; - trackParams[2].TrackletMinPt = 0.1f; - trackParams[2].CellDeltaTanLambdaSigma *= 4.; - trackParams[2].MinTrackLength = 4; - LOG(info) << "Initializing tracker in async. phase reconstruction with " << trackParams.size() << " passes"; - - } else if (mMode == "sync") { - trackParams.resize(1); - trackParams[0].ZBins = 64; - trackParams[0].PhiBins = 32; - trackParams[0].MinTrackLength = 4; - LOG(info) << "Initializing tracker in sync. phase reconstruction with " << trackParams.size() << " passes"; - } else if (mMode == "cosmics") { - mCosmicsProcessing = true; - mRunVertexer = false; - trackParams.resize(1); - trackParams[0].MinTrackLength = 4; - trackParams[0].CellDeltaTanLambdaSigma *= 10; - trackParams[0].PhiBins = 4; - trackParams[0].ZBins = 16; - trackParams[0].PVres = 1.e5f; - trackParams[0].MaxChi2ClusterAttachment = 60.; - trackParams[0].MaxChi2NDF = 40.; - trackParams[0].TrackletsPerClusterLimit = 100.; - trackParams[0].CellsPerClusterLimit = 100.; - LOG(info) << "Initializing tracker in reconstruction for cosmics with " << trackParams.size() << " passes"; - - } else { - throw std::runtime_error(fmt::format("Unsupported ITS tracking mode {:s} ", mMode)); - } - - for (auto& params : trackParams) { - params.CorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrLUT; - } - mTracker->setParameters(trackParams); + mITSTrackingInterface.setTraitsFromProvider(mChainITS->GetITSVertexerTraits(), + mChainITS->GetITSTrackerTraits(), + mChainITS->GetITSTimeframe()); + mITSTrackingInterface.initialise(); } void TrackerDPL::stop() @@ -137,255 +57,20 @@ void TrackerDPL::run(ProcessingContext& pc) auto cput = mTimer.CpuTime(); auto realt = mTimer.RealTime(); mTimer.Start(false); - updateTimeDependentParams(pc); - auto compClusters = pc.inputs().get>("compClusters"); - gsl::span patterns = pc.inputs().get>("patterns"); - gsl::span physTriggers; - std::vector fromTRD; - if (mUseTriggers == 2) { // use TRD triggers - o2::InteractionRecord ir{0, pc.services().get().firstTForbit}; - auto trdTriggers = pc.inputs().get>("phystrig"); - for (const auto& trig : trdTriggers) { - if (trig.getBCData() >= ir && trig.getNumberOfTracklets()) { - ir = trig.getBCData(); - fromTRD.emplace_back(o2::itsmft::PhysTrigger{ir, 0}); - } - } - physTriggers = gsl::span(fromTRD.data(), fromTRD.size()); - } else if (mUseTriggers == 1) { // use Phys triggers from ITS stream - physTriggers = pc.inputs().get>("phystrig"); - } - - auto rofsinput = pc.inputs().get>("ROframes"); - auto& rofs = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0}, rofsinput.begin(), rofsinput.end()); - auto& irFrames = pc.outputs().make>(Output{"ITS", "IRFRAMES", 0}); - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); // RS: this should come from CCDB - - irFrames.reserve(rofs.size()); - int nBCPerTF = alpParams.roFrameLengthInBC; - - LOGP(info, "ITSTracker pulled {} clusters, {} RO frames", compClusters.size(), rofs.size()); - - const dataformats::MCTruthContainer* labels = nullptr; - gsl::span mc2rofs; - if (mIsMC) { - labels = pc.inputs().get*>("itsmclabels").release(); - // get the array as read-only span, a snapshot is sent forward - pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0}, pc.inputs().get>("ITSMC2ROframes")); - LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; - } - - auto& allClusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0}); - auto& allTracks = pc.outputs().make>(Output{"ITS", "TRACKS", 0}); - auto& vertROFvec = pc.outputs().make>(Output{"ITS", "VERTICESROF", 0}); - auto& vertices = pc.outputs().make>(Output{"ITS", "VERTICES", 0}); - - // MC - static pmr::vector dummyMCLabTracks, dummyMCLabVerts; - auto& allTrackLabels = mIsMC ? pc.outputs().make>(Output{"ITS", "TRACKSMCTR", 0}) : dummyMCLabTracks; - auto& allVerticesLabels = mIsMC ? pc.outputs().make>(Output{"ITS", "VERTICESMCTR", 0}) : dummyMCLabVerts; - - std::uint32_t roFrame = 0; - - bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS); - LOG(info) << "ITSTracker RO: continuous=" << continuous; - - if (mOverrideBeamEstimation) { - mTimeFrame->setBeamPosition(mMeanVertex->getX(), - mMeanVertex->getY(), - mMeanVertex->getSigmaY2(), - mTracker->getParameters()[0].LayerResolution[0], - mTracker->getParameters()[0].SystErrorY2[0]); - } - - mTracker->setBz(o2::base::Propagator::Instance()->getNominalBz()); - - gsl::span::iterator pattIt = patterns.begin(); - - gsl::span rofspan(rofs); - mTimeFrame->loadROFrameData(rofspan, compClusters, pattIt, mDict, labels); - pattIt = patterns.begin(); - std::vector savedROF; - auto logger = [&](std::string s) { LOG(info) << s; }; - auto fatalLogger = [&](std::string s) { LOG(fatal) << s; }; - auto errorLogger = [&](std::string s) { LOG(error) << s; }; - - FastMultEst multEst; // mult estimator - std::vector processingMask; - int cutVertexMult{0}, cutRandomMult = int(rofs.size()) - multEst.selectROFs(rofs, compClusters, physTriggers, processingMask); - mTimeFrame->setMultiplicityCutMask(processingMask); - float vertexerElapsedTime{0.f}; - if (mRunVertexer) { - vertROFvec.reserve(rofs.size()); - // Run seeding vertexer - vertexerElapsedTime = mVertexer->clustersToVertices(logger); - } else { // cosmics - mTimeFrame->resetRofPV(); - } - const auto& multEstConf = FastMultEstConfig::Instance(); // parameters for mult estimation and cuts - for (auto iRof{0}; iRof < rofspan.size(); ++iRof) { - std::vector vtxVecLoc; - auto& vtxROF = vertROFvec.emplace_back(rofspan[iRof]); - vtxROF.setFirstEntry(vertices.size()); - if (mRunVertexer) { - auto vtxSpan = mTimeFrame->getPrimaryVertices(iRof); - vtxROF.setNEntries(vtxSpan.size()); - bool selROF = vtxSpan.size() == 0; - for (auto iV{0}; iV < vtxSpan.size(); ++iV) { - auto& v = vtxSpan[iV]; - if (multEstConf.isVtxMultCutRequested() && !multEstConf.isPassingVtxMultCut(v.getNContributors())) { - continue; // skip vertex of unwanted multiplicity - } - selROF = true; - vertices.push_back(v); - if (mIsMC) { - auto vLabels = mTimeFrame->getPrimaryVerticesLabels(iRof)[iV]; - allVerticesLabels.reserve(allVerticesLabels.size() + vLabels.size()); - std::copy(vLabels.begin(), vLabels.end(), std::back_inserter(allVerticesLabels)); - } - } - if (processingMask[iRof] && !selROF) { // passed selection in clusters and not in vertex multiplicity - LOG(debug) << fmt::format("ROF {} rejected by the vertex multiplicity selection [{},{}]", - iRof, - multEstConf.cutMultVtxLow, - multEstConf.cutMultVtxHigh); - processingMask[iRof] = selROF; - cutVertexMult++; - } - } else { // cosmics - vtxVecLoc.emplace_back(Vertex()); - vtxVecLoc.back().setNContributors(1); - vtxROF.setNEntries(vtxVecLoc.size()); - for (auto& v : vtxVecLoc) { - vertices.push_back(v); - } - mTimeFrame->addPrimaryVertices(vtxVecLoc); - } - } - LOG(info) << fmt::format(" - rejected {}/{} ROFs: random/mult.sel:{} (seed {}), vtx.sel:{}", cutRandomMult + cutVertexMult, rofspan.size(), cutRandomMult, multEst.lastRandomSeed, cutVertexMult); - LOG(info) << fmt::format(" - Vertex seeding total elapsed time: {} ms for {} vertices found in {} ROFs", vertexerElapsedTime, mTimeFrame->getPrimaryVerticesNum(), rofspan.size()); - - if (mOverrideBeamEstimation) { - LOG(info) << fmt::format(" - Beam position set to: {}, {} from meanvertex object", mTimeFrame->getBeamX(), mTimeFrame->getBeamY()); - } else { - LOG(info) << fmt::format(" - Beam position computed for the TF: {}, {}", mTimeFrame->getBeamX(), mTimeFrame->getBeamY()); - } - if (mCosmicsProcessing && compClusters.size() > 1500 * rofspan.size()) { - LOG(error) << "Cosmics processing was requested with an average detector occupancy exceeding 1.e-7, skipping TF processing."; - } else { - - mTimeFrame->setMultiplicityCutMask(processingMask); - // Run CA tracker - if (mMode == "async") { - mTracker->clustersToTracks(logger, fatalLogger); - } else { - mTracker->clustersToTracks(logger, errorLogger); - } - size_t totTracks{mTimeFrame->getNumberOfTracks()}, totClusIDs{mTimeFrame->getNumberOfUsedClusters()}; - allTracks.reserve(totTracks); - allClusIdx.reserve(totClusIDs); - - if (mTimeFrame->hasBogusClusters()) { - LOG(warning) << fmt::format(" - The processed timeframe had {} clusters with wild z coordinates, check the dictionaries", mTimeFrame->hasBogusClusters()); - } - - for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { - auto& rof{rofs[iROF]}; - auto& tracks = mTimeFrame->getTracks(iROF); - auto number{tracks.size()}; - auto first{allTracks.size()}; - int offset = -rof.getFirstEntry(); // cluster entry!!! - rof.setFirstEntry(first); - rof.setNEntries(number); - - if (processingMask[iROF]) { - irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1).info = tracks.size(); - } - allTrackLabels.reserve(mTimeFrame->getTracksLabel(iROF).size()); // should be 0 if not MC - std::copy(mTimeFrame->getTracksLabel(iROF).begin(), mTimeFrame->getTracksLabel(iROF).end(), std::back_inserter(allTrackLabels)); - // Some conversions that needs to be moved in the tracker internals - for (unsigned int iTrk{0}; iTrk < tracks.size(); ++iTrk) { - auto& trc{tracks[iTrk]}; - trc.setFirstClusterEntry(allClusIdx.size()); // before adding tracks, create final cluster indices - int ncl = trc.getNumberOfClusters(), nclf = 0; - for (int ic = TrackITSExt::MaxClusters; ic--;) { // track internally keeps in->out cluster indices, but we want to store the references as out->in!!! - auto clid = trc.getClusterIndex(ic); - if (clid >= 0) { - trc.setClusterSize(ic, mTimeFrame->getClusterSize(clid)); - allClusIdx.push_back(clid); - nclf++; - } - } - assert(ncl == nclf); - allTracks.emplace_back(trc); - } - } - LOGP(info, "ITSTracker pushed {} tracks and {} vertices", allTracks.size(), vertices.size()); - if (mIsMC) { - LOGP(info, "ITSTracker pushed {} track labels", allTrackLabels.size()); - LOGP(info, "ITSTracker pushed {} vertex labels", allVerticesLabels.size()); - } - } + mITSTrackingInterface.updateTimeDependentParams(pc); + mITSTrackingInterface.run(pc); mTimer.Stop(); - LOG(info) << "CPU Reconstruction time for this TF " << mTimer.CpuTime() - cput << " s (cpu), " << mTimer.RealTime() - realt << " s (wall)"; -} - -///_______________________________________ -void TrackerDPL::updateTimeDependentParams(ProcessingContext& pc) -{ - o2::base::GRPGeomHelper::instance().checkUpdates(pc); - static bool initOnceDone = false; - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - pc.inputs().get("cldict"); // just to trigger the finaliseCCDB - pc.inputs().get*>("alppar"); - if (pc.inputs().getPos("itsTGeo") >= 0) { - pc.inputs().get("itsTGeo"); - } - GeometryTGeo* geom = GeometryTGeo::Instance(); - geom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, o2::math_utils::TransformType::T2G)); - mVertexer->getGlobalConfiguration(); - mTracker->getGlobalConfiguration(); - if (mOverrideBeamEstimation) { - pc.inputs().get("meanvtx"); - } - } + LOGP(info, "CPU Reconstruction time for this TF {} s (cpu), {} s (wall)", mTimer.CpuTime() - cput, mTimer.RealTime() - realt); } -///_______________________________________ void TrackerDPL::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) { - if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { - return; - } - if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { - LOG(info) << "cluster dictionary updated"; - setClusterDictionary((const o2::itsmft::TopologyDictionary*)obj); - return; - } - // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level - if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { - LOG(info) << "Alpide param updated"; - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - return; - } - if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { - LOGP(info, "mean vertex acquired"); - setMeanVertex((const o2::dataformats::MeanVertexObject*)obj); - return; - } - if (matcher == ConcreteDataMatcher("ITS", "GEOMTGEO", 0)) { - LOG(info) << "ITS GeomtetryTGeo loaded from ccdb"; - o2::its::GeometryTGeo::adopt((o2::its::GeometryTGeo*)obj); - return; - } + mITSTrackingInterface.finaliseCCDB(matcher, obj); } void TrackerDPL::endOfStream(EndOfStreamContext& ec) { - LOGF(info, "ITS CA-Tracker total timing: Cpu: %.3e Real: %.3e s in %d slots", - mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); + LOGF(info, "ITS CA-Tracker total timing: Cpu: %.3e Real: %.3e s in %d slots", mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1); } DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int trgType, const std::string& trModeS, const bool overrBeamEst, o2::gpu::GPUDataTypes::DeviceType dType) @@ -400,8 +85,8 @@ DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int trgType, const st } else if (trgType == 2) { inputs.emplace_back("phystrig", "TRD", "TRKTRGRD", 0, Lifetime::Timeframe); } - inputs.emplace_back("cldict", "ITS", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/ClusterDictionary")); - inputs.emplace_back("alppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); + inputs.emplace_back("itscldict", "ITS", "CLUSDICT", 0, Lifetime::Condition, ccdbParamSpec("ITS/Calib/ClusterDictionary")); + inputs.emplace_back("itsalppar", "ITS", "ALPIDEPARAM", 0, Lifetime::Condition, ccdbParamSpec("ITS/Config/AlpideParam")); auto ggRequest = std::make_shared(false, // orbitResetTime true, // GRPECS=true false, // GRPLHCIF @@ -437,7 +122,13 @@ DataProcessorSpec getTrackerSpec(bool useMC, bool useGeom, int trgType, const st "its-tracker", inputs, outputs, - AlgorithmSpec{adaptFromTask(ggRequest, useMC, trgType, trModeS, overrBeamEst, dType)}, + AlgorithmSpec{adaptFromTask(ggRequest, + useMC, + trgType, + trModeS == "sync" ? o2::its::TrackingMode::Sync : trModeS == "async" ? o2::its::TrackingMode::Async + : o2::its::TrackingMode::Cosmics, + overrBeamEst, + dType)}, Options{}}; } diff --git a/Detectors/ITSMFT/ITS/workflow/src/its-track-writer-workflow.cxx b/Detectors/ITSMFT/ITS/workflow/src/its-track-writer-workflow.cxx new file mode 100644 index 0000000000000..d06ab366ef54c --- /dev/null +++ b/Detectors/ITSMFT/ITS/workflow/src/its-track-writer-workflow.cxx @@ -0,0 +1,36 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "ITSWorkflow/TrackWriterWorkflow.h" +#include "Framework/ConfigParamSpec.h" +#include "Framework/CompletionPolicyHelpers.h" + +using namespace o2::framework; + +void customize(std::vector& policies) +{ + // ordered policies for the writers + policies.push_back(CompletionPolicyHelpers::consumeWhenAllOrdered(".*(?:ITS|its).*[W,w]riter.*")); +} + +void customize(std::vector& workflowOptions) +{ + workflowOptions.push_back(ConfigParamSpec{"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation even if available"}}); +} + +#include "Framework/runDataProcessing.h" +#include "Framework/Logger.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + auto useMC = !configcontext.options().get("disable-mc"); + return std::move(o2::its::track_writer_workflow::getWorkflow(useMC)); +} diff --git a/Detectors/ITSMFT/MFT/simulation/src/digi2raw.cxx b/Detectors/ITSMFT/MFT/simulation/src/digi2raw.cxx index 452832d6e74ab..00f49ce81bb02 100644 --- a/Detectors/ITSMFT/MFT/simulation/src/digi2raw.cxx +++ b/Detectors/ITSMFT/MFT/simulation/src/digi2raw.cxx @@ -42,7 +42,7 @@ constexpr int DefRDHVersion = o2::raw::RDHUtils::getVersion& m2r, std::string_view outDir, std::string_view outPrefix, std::string_view fileFor); void digi2raw(std::string_view inpName, std::string_view outDir, std::string_view fileFor, int verbosity, uint32_t rdhV = DefRDHVersion, bool enablePadding = false, - bool noEmptyHBF = false, int superPageSizeInB = 1024 * 1024); + bool noEmptyHBF = false, bool noEmptyROF = false, int superPageSizeInB = 1024 * 1024); int main(int argc, char** argv) { @@ -63,6 +63,7 @@ int main(int argc, char** argv) add_option("rdh-version,r", bpo::value()->default_value(DefRDHVersion), "RDH version to use"); add_option("enable-padding", bpo::value()->default_value(false)->implicit_value(true), "enable GBT word padding to 128 bits even for RDH V7"); add_option("no-empty-hbf,e", bpo::value()->default_value(false)->implicit_value(true), "do not create empty HBF pages (except for HBF starting TF)"); + add_option("no-empty-rof", bpo::value()->default_value(false)->implicit_value(true), "do not create empty ROF blocks"); add_option("hbfutils-config,u", bpo::value()->default_value(std::string(o2::base::NameConf::DIGITIZATIONCONFIGFILE)), "config file for HBFUtils (or none)"); add_option("configKeyValues", bpo::value()->default_value(""), "comma-separated configKeyValues"); @@ -96,7 +97,8 @@ int main(int argc, char** argv) vm["verbosity"].as(), vm["rdh-version"].as(), vm["enable-padding"].as(), - vm["no-empty-hbf"].as()); + vm["no-empty-hbf"].as(), + vm["no-empty-rof"].as()); LOG(info) << "HBFUtils settings used for conversion:"; o2::raw::HBFUtils::Instance().print(); @@ -104,7 +106,7 @@ int main(int argc, char** argv) return 0; } -void digi2raw(std::string_view inpName, std::string_view outDir, std::string_view fileFor, int verbosity, uint32_t rdhV, bool enablePadding, bool noEmptyHBF, int superPageSizeInB) +void digi2raw(std::string_view inpName, std::string_view outDir, std::string_view fileFor, int verbosity, uint32_t rdhV, bool enablePadding, bool noEmptyHBF, bool noEmptyROF, int superPageSizeInB) { TStopwatch swTot; swTot.Start(); @@ -178,9 +180,9 @@ void digi2raw(std::string_view inpName, std::string_view outDir, std::string_vie LOG(info) << "Processing ROF:" << rofRec.getROFrame() << " with " << nDigROF << " entries"; rofRec.print(); } - if (!nDigROF) { + if (!nDigROF && noEmptyROF) { if (verbosity) { - LOG(info) << "Frame is empty"; // ?? + LOG(info) << "Frame is empty"; } continue; } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h index 8a4139a9c3bfe..74798b04a3b39 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/AlpideCoder.h @@ -122,7 +122,7 @@ class AlpideCoder /// decode alpide data for the next non-empty chip from the buffer template - static int decodeChip(ChipPixelData& chipData, T& buffer, CG cidGetter) + static int decodeChip(ChipPixelData& chipData, T& buffer, std::vector& seenChips, CG cidGetter) { // read record for single non-empty chip, updating on change module and cycle. // return number of records filled (>0), EOFFlag or Error @@ -198,6 +198,7 @@ class AlpideCoder #endif return unexpectedEOF("CHIP_EMPTY:Timestamp"); // abandon cable data } + seenChips.push_back(chipIDGlo); chipData.resetChipID(); expectInp = ExpectChipHeader | ExpectChipEmpty; continue; @@ -438,6 +439,9 @@ class AlpideCoder prevPix = currPix++; } } + if (chipData.getData().size()) { + seenChips.push_back(chipData.getChipID()); + } return chipData.getData().size(); } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DigitPixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DigitPixelReader.h index 2e6221e12fb9d..2a6d44ec0d0ab 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DigitPixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/DigitPixelReader.h @@ -112,6 +112,8 @@ class DigitPixelReader : public PixelReader mMaxBCSeparationToSquash = n; } + void squashNeighbours(const uint16_t& iROF, const int& iDigit, const int& maxDigits, ChipPixelData& chipData); + private: void addPixel(ChipPixelData& chipData, const Digit* dig) { diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h index ddc4db51fe2a8..c15a8bc82d117 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RUDecodeData.h @@ -34,22 +34,23 @@ struct RUDecodeData { static constexpr int MaxChipsPerRU = 196; // max number of chips the RU can readout static constexpr int MaxLinksPerRU = 3; // max number of GBT links per RU - std::array cableData{}; // cable data in compressed ALPIDE format - std::vector chipsData{}; // fully decoded data in 1st nChipsFired chips - std::array links{}; // link entry RSTODO: consider removing this and using pointer - std::array cableHWID{}; // HW ID of cable whose data is in the corresponding slot of cableData - std::array cableLinkID{}; // ID of the GBT link transmitting this cable data - std::array cableLinkPtr{}; // Ptr of the GBT link transmitting this cable data - std::unordered_map linkHBFToDump{}; // FEEID<<32+hbfEntry to dump in case of error - int ruSWID = -1; // SW (stave) ID - int nChipsFired = 0; // number of chips with data or with errors - int lastChipChecked = 0; // last chips checked among nChipsFired - int nNonEmptyLinks = 0; // number of non-empty links for current ROF - int nLinks = 0; // number of links seen for this TF - int nLinksDone = 0; // number of links finished for this TF - int verbosity = 0; // verbosity level, for -1,0 print only summary data, for 1: print once every error - bool ROFRampUpStage = false; // flag that the data come from the ROF rate ramp-up stage - GBTCalibData calibData{}; // calibration info from GBT calibration word + std::array cableData{}; // cable data in compressed ALPIDE format + std::vector chipsData{}; // fully decoded data in 1st nChipsFired chips + std::vector seenChipIDs{}; // IDs of all chips seen during ROF decoding, including empty ones + std::array links{}; // link entry RSTODO: consider removing this and using pointer + std::array cableHWID{}; // HW ID of cable whose data is in the corresponding slot of cableData + std::array cableLinkID{}; // ID of the GBT link transmitting this cable data + std::array cableLinkPtr{}; // Ptr of the GBT link transmitting this cable data + std::unordered_map linkHBFToDump{}; // FEEID<<32+hbfEntry to dump in case of error + int ruSWID = -1; // SW (stave) ID + int nChipsFired = 0; // number of chips with data or with errors + int lastChipChecked = 0; // last chips checked among nChipsFired + int nNonEmptyLinks = 0; // number of non-empty links for current ROF + int nLinks = 0; // number of links seen for this TF + int nLinksDone = 0; // number of links finished for this TF + int verbosity = 0; // verbosity level, for -1,0 print only summary data, for 1: print once every error + bool ROFRampUpStage = false; // flag that the data come from the ROF rate ramp-up stage + GBTCalibData calibData{}; // calibration info from GBT calibration word std::unordered_map> chipErrorsTF{}; // vector of chip decoding errors seen in the given TF const RUInfo* ruInfo = nullptr; @@ -58,6 +59,10 @@ struct RUDecodeData { memset(&links[0], -1, MaxLinksPerRU * sizeof(int)); } void clear(); + void clearSeenChipIDs() + { + seenChipIDs.clear(); + } void setROFInfo(ChipPixelData* chipData, const GBTLink* lnk); template int decodeROF(const Mapping& mp, const o2::InteractionRecord ir); @@ -79,6 +84,7 @@ int RUDecodeData::decodeROF(const Mapping& mp, const o2::InteractionRecord ir) std::array doneChips{}; auto* chipData = &chipsData[0]; + seenChipIDs.clear(); for (int icab = 0; icab < ruInfo->nCables; icab++) { // cableData is ordered in such a way to have chipIDs in increasing order if (!cableData[icab].getSize()) { continue; @@ -88,14 +94,14 @@ int RUDecodeData::decodeROF(const Mapping& mp, const o2::InteractionRecord ir) } auto cabHW = cableHWID[icab]; auto chIdGetter = [this, &mp, cabHW](int cid) { - //return mp.getGlobalChipID(cid, cabHW, *this->ruInfo); + // return mp.getGlobalChipID(cid, cabHW, *this->ruInfo); auto chip = mp.getGlobalChipID(cid, cabHW, *this->ruInfo); return chip; }; int ret = 0; // dumpcabledata(icab); - while ((ret = AlpideCoder::decodeChip(*chipData, cableData[icab], chIdGetter)) || chipData->isErrorSet()) { // we register only chips with hits or errors flags set + while ((ret = AlpideCoder::decodeChip(*chipData, cableData[icab], seenChipIDs, chIdGetter)) || chipData->isErrorSet()) { // we register only chips with hits or errors flags set setROFInfo(chipData, cableLinkPtr[icab]); auto nhits = chipData->getData().size(); if (nhits && doneChips[chipData->getChipID()]) { diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h index 0047f8311ba29..e4f83a5b31b28 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelDecoder.h @@ -60,8 +60,8 @@ class RawPixelDecoder final : public PixelReader void collectROFCableData(int iru); int decodeNextTrigger() final; - template - int fillDecodedDigits(DigitContainer& digits, ROFContainer& rofs, STATVEC& chipStatus); + template + int fillDecodedDigits(DigitContainer& digits, ROFContainer& rofs); template void fillChipsStatus(STATVEC& chipStatus); @@ -120,6 +120,7 @@ class RawPixelDecoder final : public PixelReader void setSkipRampUpData(bool v = true) { mSkipRampUpData = v; } bool getSkipRampUpData() const { return mSkipRampUpData; } + auto getNROFsProcessed() const { return mROFCounter; } struct LinkEntry { int entry = -1; @@ -127,6 +128,7 @@ class RawPixelDecoder final : public PixelReader uint16_t getSquashingDepth() { return 0; } bool doIRMajorityPoll(); + bool isRampUpStage() const { return mROFRampUpStage; } void reset(); private: @@ -178,8 +180,8 @@ class RawPixelDecoder final : public PixelReader ///______________________________________________________________ /// Fill decoded digits to global vector template -template -int RawPixelDecoder::fillDecodedDigits(DigitContainer& digits, ROFContainer& rofs, STATVEC& chipStatus) +template +int RawPixelDecoder::fillDecodedDigits(DigitContainer& digits, ROFContainer& rofs) { if (mInteractionRecord.isDummy()) { return 0; // nothing was decoded @@ -189,7 +191,6 @@ int RawPixelDecoder::fillDecodedDigits(DigitContainer& digits, ROFConta for (unsigned int iru = 0; iru < mRUDecodeVec.size(); iru++) { for (int ic = 0; ic < mRUDecodeVec[iru].nChipsFired; ic++) { const auto& chip = mRUDecodeVec[iru].chipsData[ic]; - chipStatus[chip.getChipID()] = 1; for (const auto& hit : mRUDecodeVec[iru].chipsData[ic].getData()) { digits.emplace_back(chip.getChipID(), hit.getRow(), hit.getCol()); } @@ -204,8 +205,8 @@ int RawPixelDecoder::fillDecodedDigits(DigitContainer& digits, ROFConta ///______________________________________________________________ /// Fill decoded digits to global vector template <> -template -int RawPixelDecoder::fillDecodedDigits(DigitContainer& digits, ROFContainer& rofs, STATVEC& chipStatus) +template +int RawPixelDecoder::fillDecodedDigits(DigitContainer& digits, ROFContainer& rofs) { if (mInteractionRecord.isDummy()) { return 0; // nothing was decoded @@ -215,7 +216,6 @@ int RawPixelDecoder::fillDecodedDigits(DigitContainer& digits, R for (auto chipData = mOrderedChipsPtr.rbegin(); chipData != mOrderedChipsPtr.rend(); ++chipData) { assert(mLastReadChipID < (*chipData)->getChipID()); mLastReadChipID = (*chipData)->getChipID(); - chipStatus[mLastReadChipID] = 1; for (const auto& hit : (*chipData)->getData()) { digits.emplace_back(mLastReadChipID, hit.getRow(), hit.getCol()); } @@ -232,13 +232,12 @@ template template void RawPixelDecoder::fillChipsStatus(STATVEC& chipStatus) { - if (mInteractionRecord.isDummy()) { + if (mInteractionRecord.isDummy() || mROFRampUpStage) { return; // nothing was decoded } for (unsigned int iru = 0; iru < mRUDecodeVec.size(); iru++) { - for (int ic = 0; ic < mRUDecodeVec[iru].nChipsFired; ic++) { - const auto& chip = mRUDecodeVec[iru].chipsData[ic]; - chipStatus[chip.getChipID()] = 1; + for (auto chID : mRUDecodeVec[iru].seenChipIDs) { + chipStatus[chID] = 1; } } } diff --git a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h index b1fefcdb91b63..97716059f12d6 100644 --- a/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h +++ b/Detectors/ITSMFT/common/reconstruction/include/ITSMFTReconstruction/RawPixelReader.h @@ -1256,7 +1256,8 @@ class RawPixelReader : public PixelReader auto chIdGetter = [this, cabHW, ri](int cid) { return this->mMAP.getGlobalChipID(cid, cabHW, *ri); }; - while ((res = mCoder.decodeChip(*chipData, cableData, chIdGetter))) { // we register only chips with hits or errors flags set + std::vector dummyStat; + while ((res = mCoder.decodeChip(*chipData, cableData, dummyStat, chIdGetter))) { // we register only chips with hits or errors flags set if (res > 0) { #ifdef _RAW_READER_ERROR_CHECKS_ // for the IB staves check if the cable ID is the same as the chip ID on the module diff --git a/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx b/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx index 5f0cca0650e7f..b8d88a6fc4223 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/DigitPixelReader.cxx @@ -147,10 +147,17 @@ bool DigitPixelReader::getNextChipData(ChipPixelData& chipData) size_t initialSize{chipData.getData().size()}; // Compile mask for repeated digits (digits with same row,col) for (size_t iPixel{0}, iDigitNext{0}; iPixel < initialSize; ++iPixel) { - auto& pixel = chipData.getData()[iPixel]; + const auto& pixel = chipData.getData()[iPixel]; + for (; iDigitNext < nDigitsNext; ++iDigitNext) { + const auto* digitNext = &mDigits[mBookmarkNextROFs[iROF - 1] + iDigitNext]; + if (digitNext->getRow() == pixel.getRowDirect() && digitNext->getColumn() == pixel.getCol()) { + mSquashedDigitsMask[mBookmarkNextROFs[iROF - 1] + iDigitNext] = true; + break; + } + } // seek to iDigitNext which is inferior than itC - mMaxSquashDist - auto mincol = pixel.getCol() > mMaxSquashDist ? pixel.getCol() - mMaxSquashDist : 0; - auto minrow = pixel.getRowDirect() > mMaxSquashDist ? pixel.getRowDirect() - mMaxSquashDist : 0; + const auto mincol = pixel.getCol() > mMaxSquashDist ? pixel.getCol() - mMaxSquashDist : 0; + const auto minrow = pixel.getRowDirect() > mMaxSquashDist ? pixel.getRowDirect() - mMaxSquashDist : 0; if (iDigitNext == nDigitsNext) { // in case iDigitNext loop below reached the end iDigitNext--; } @@ -162,8 +169,8 @@ bool DigitPixelReader::getNextChipData(ChipPixelData& chipData) continue; } const auto* digitNext = &mDigits[mBookmarkNextROFs[iROF - 1] + iDigitNext]; - auto drow = static_cast(digitNext->getRow()) - static_cast(pixel.getRowDirect()); - auto dcol = static_cast(digitNext->getColumn()) - static_cast(pixel.getCol()); + const auto drow = digitNext->getRow() - pixel.getRowDirect(); + const auto dcol = digitNext->getColumn() - pixel.getCol(); if (!dcol && !drow) { mSquashedDigitsMask[mBookmarkNextROFs[iROF - 1] + iDigitNext] = true; break; @@ -173,10 +180,10 @@ bool DigitPixelReader::getNextChipData(ChipPixelData& chipData) // loop over chip pixels for (int iPixel{0}, iDigitNext{0}; iPixel < initialSize; ++iPixel) { - auto& pixel = chipData.getData()[iPixel]; + const o2::itsmft::PixelData pixel = chipData.getData()[iPixel]; // we need a copy to avoid the reference to be invalidated // seek to iDigitNext which is inferior than itC - mMaxSquashDist - auto mincol = pixel.getCol() > mMaxSquashDist ? pixel.getCol() - mMaxSquashDist : 0; - auto minrow = pixel.getRowDirect() > mMaxSquashDist ? pixel.getRowDirect() - mMaxSquashDist : 0; + const auto mincol = pixel.getCol() > mMaxSquashDist ? pixel.getCol() - mMaxSquashDist : 0; + const auto minrow = pixel.getRowDirect() > mMaxSquashDist ? pixel.getRowDirect() - mMaxSquashDist : 0; if (iDigitNext == nDigitsNext) { // in case iDigitNext loop below reached the end iDigitNext--; } @@ -188,24 +195,25 @@ bool DigitPixelReader::getNextChipData(ChipPixelData& chipData) continue; } const auto* digitNext = &mDigits[mBookmarkNextROFs[iROF - 1] + iDigitNext]; - auto drow = static_cast(digitNext->getRow()) - static_cast(pixel.getRowDirect()); - auto dcol = static_cast(digitNext->getColumn()) - static_cast(pixel.getCol()); - if (!dcol && !drow) { - // same pixel fired in two ROFs - mSquashedDigitsMask[mBookmarkNextROFs[iROF - 1] + iDigitNext] = true; - continue; - } + const auto drow = digitNext->getRow() - pixel.getRowDirect(); + const auto dcol = digitNext->getColumn() - pixel.getCol(); + // if (!dcol && !drow) { + // same pixel fired in two ROFs, but we did it already + // mSquashedDigitsMask[mBookmarkNextROFs[iROF - 1] + iDigitNext] = true; + // continue; + // } if (dcol > mMaxSquashDist || (dcol == mMaxSquashDist && drow > mMaxSquashDist)) { break; // all greater iDigitNexts will not match to this pixel too } if (dcol < -mMaxSquashDist || (drow > mMaxSquashDist || drow < -mMaxSquashDist)) { continue; } else { - chipData.getData().emplace_back(digitNext); // push squashed pixel mSquashedDigitsMask[mBookmarkNextROFs[iROF - 1] + iDigitNext] = true; + chipData.getData().emplace_back(digitNext); // push squashed pixel if (mDigitsMCTruth) { chipData.getPixIds().push_back(mBookmarkNextROFs[iROF - 1] + iDigitNext); } + squashNeighbours(iROF, iDigitNext, nDigitsNext, chipData); // recursively squash neighbours } } } @@ -224,6 +232,34 @@ bool DigitPixelReader::getNextChipData(ChipPixelData& chipData) return true; } +//______________________________________________________________________________ +void DigitPixelReader::squashNeighbours(const uint16_t& iROF, const int& iDigit, const int& maxDigits, ChipPixelData& chipData) +{ // Recursively find and squash neighbours + const auto* digit = &mDigits[mBookmarkNextROFs[iROF - 1] + iDigit]; // current pivot digit, already pushed back and marked + + for (int iOtherDigit{0}; iOtherDigit < maxDigits; ++iOtherDigit) { + if (mSquashedDigitsMask[mBookmarkNextROFs[iROF - 1] + iOtherDigit]) { + continue; + } + const auto* otherDigit = &mDigits[mBookmarkNextROFs[iROF - 1] + iOtherDigit]; + const auto drow = otherDigit->getRow() - digit->getRow(); + const auto dcol = otherDigit->getColumn() - digit->getColumn(); + if (dcol > mMaxSquashDist || (dcol == mMaxSquashDist && drow > mMaxSquashDist)) { + break; // all greater iOtherDigits will not match to this pixel too + } + if (dcol < -mMaxSquashDist || (drow > mMaxSquashDist || drow < -mMaxSquashDist)) { + continue; + } else { + mSquashedDigitsMask[mBookmarkNextROFs[iROF - 1] + iOtherDigit] = true; + chipData.getData().emplace_back(otherDigit); // push squashed pixel + if (mDigitsMCTruth) { + chipData.getPixIds().push_back(mBookmarkNextROFs[iROF - 1] + iOtherDigit); + } + squashNeighbours(iROF, iOtherDigit, maxDigits, chipData); // recursively squash neighbours + } + } +} + //______________________________________________________________________________ void DigitPixelReader::openInput(const std::string inpName, o2::detectors::DetID det) { diff --git a/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx b/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx index 1443744c5ce79..9cd5d8e0054bd 100644 --- a/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx +++ b/Detectors/ITSMFT/common/reconstruction/src/RawPixelDecoder.cxx @@ -95,6 +95,8 @@ int RawPixelDecoder::decodeNextTrigger() collectROFCableData(iru); } + mROFCounter++; + if (!doIRMajorityPoll()) { continue; // no links with data } @@ -109,12 +111,13 @@ int RawPixelDecoder::decodeNextTrigger() ru.ROFRampUpStage = mROFRampUpStage; mNPixelsFiredROF += ru.decodeROF(mMAP, mInteractionRecord); mNChipsFiredROF += ru.nChipsFired; + } else { + ru.clearSeenChipIDs(); } } if (mNChipsFiredROF || (mAlloEmptyROFs && mNLinksDone < mNLinksInTF)) { // fill some statistics mTrigger = mLinkForTriggers ? mLinkForTriggers->trigger : 0; - mROFCounter++; mNChipsFired += mNChipsFiredROF; mNPixelsFired += mNPixelsFiredROF; mCurRUDecodeID = 0; // getNextChipData will start from here diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DeadMapBuilderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DeadMapBuilderSpec.h index 99dca8475f2a6..14f4575ee972c 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DeadMapBuilderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/DeadMapBuilderSpec.h @@ -107,7 +107,7 @@ class ITSMFTDeadMapBuilder : public Task std::string mDataSource = "chipsstatus"; - int mTFSampling = 1000; + int mTFSampling = 350; std::string mSamplingMode = "first-orbit-run"; // Use this default to ensure process of first TF. At the moment, use any other option to sample on absolute orbit value. o2::itsmft::TimeDeadMap mMapObject; diff --git a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/STFDecoderSpec.h b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/STFDecoderSpec.h index f521341d120bb..d0b64f2a678ac 100644 --- a/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/STFDecoderSpec.h +++ b/Detectors/ITSMFT/common/workflow/include/ITSMFTWorkflow/STFDecoderSpec.h @@ -82,6 +82,7 @@ class STFDecoder : public Task int mDumpOnError = 0; int mNThreads = 1; int mVerbosity = 0; + long mROFErrRepIntervalMS = 0; size_t mTFCounter = 0; size_t mEstNDig = 0; size_t mEstNClus = 0; diff --git a/Detectors/ITSMFT/common/workflow/src/DeadMapBuilderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/DeadMapBuilderSpec.cxx index 3194a62d6b273..8bb86a547fb25 100644 --- a/Detectors/ITSMFT/common/workflow/src/DeadMapBuilderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/DeadMapBuilderSpec.cxx @@ -269,9 +269,9 @@ void ITSMFTDeadMapBuilder::PrepareOutputCcdb(EndOfStreamContext* ec, std::string if (ec != nullptr) { - LOG(info) << "Sending object " << info.getPath() << "/" << info.getFileName() - << "to ccdb-populator, of size " << image->size() << " bytes, valid for " - << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + LOG(important) << "Sending object " << info.getPath() << "/" << info.getFileName() + << "to ccdb-populator, of size " << image->size() << " bytes, valid for " + << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); if (mRunMFT) { ec->outputs().snapshot(Output{o2::calibration::Utils::gDataOriginCDBPayload, "TimeDeadMap", 1}, *image.get()); @@ -284,9 +284,9 @@ void ITSMFTDeadMapBuilder::PrepareOutputCcdb(EndOfStreamContext* ec, std::string else if (!ccdburl.empty()) { // send from this workflow - LOG(info) << mSelfName << "sending object " << ccdburl << "/browse/" << info.getFileName() - << " of size " << image->size() << " bytes, valid for " - << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); + LOG(important) << mSelfName << " sending object " << ccdburl << "/browse/" << info.getPath() << "/" << info.getFileName() + << " of size " << image->size() << " bytes, valid for " + << info.getStartValidityTimestamp() << " : " << info.getEndValidityTimestamp(); o2::ccdb::CcdbApi mApi; mApi.init(ccdburl); @@ -335,7 +335,7 @@ void ITSMFTDeadMapBuilder::stop() LOG(warning) << "endOfStream not processed. Sending output to ccdb from the " << detname << "deadmap builder workflow."; PrepareOutputCcdb(nullptr, mCCDBUrl); } else { - LOG(warning) << "endOfStream not processed. Nothing forwarded as output."; + LOG(alarm) << "endOfStream not processed. Nothing forwarded as output."; } isEnded = true; } @@ -378,7 +378,7 @@ DataProcessorSpec getITSMFTDeadMapBuilderSpec(std::string datasource, bool doMFT inputs, outputs, AlgorithmSpec{adaptFromTask(datasource, doMFT)}, - Options{{"tf-sampling", VariantType::Int, 1000, {"Process every Nth TF. Selection according to first TF orbit."}}, + Options{{"tf-sampling", VariantType::Int, 350, {"Process every Nth TF. Selection according to first TF orbit."}}, {"sampling-mode", VariantType::String, "first-orbit-run", {"Use absolute orbit value or offset from first processed orbit."}}, {"tf-length", VariantType::Int, 32, {"Orbits per TF."}}, {"skip-static-map", VariantType::Bool, false, {"Do not fill static part of the map."}}, diff --git a/Detectors/ITSMFT/common/workflow/src/STFDecoderSpec.cxx b/Detectors/ITSMFT/common/workflow/src/STFDecoderSpec.cxx index 2b80a5ffcac01..92ad20129c36f 100644 --- a/Detectors/ITSMFT/common/workflow/src/STFDecoderSpec.cxx +++ b/Detectors/ITSMFT/common/workflow/src/STFDecoderSpec.cxx @@ -81,6 +81,8 @@ void STFDecoder::init(InitContext& ic) mApplyNoiseMap = !ic.options().get("ignore-noise-map"); mUseClusterDictionary = !ic.options().get("ignore-cluster-dictionary"); try { + float fr = ic.options().get("rof-lenght-error-freq"); + mROFErrRepIntervalMS = fr <= 0. ? -1 : long(fr * 1e3); mNThreads = std::max(1, ic.options().get("nthreads")); mDecoder->setNThreads(mNThreads); mUnmutExtraLanes = ic.options().get("unmute-extra-lanes"); @@ -159,6 +161,8 @@ void STFDecoder::run(ProcessingContext& pc) mDecoder->setDecodeNextAuto(false); o2::InteractionRecord lastIR{}, firstIR{0, pc.services().get().firstTForbit}; + int nTriggersProcessed = mDecoder->getNROFsProcessed(); + static long lastErrReportTS = 0; while (mDecoder->decodeNextTrigger() >= 0) { if ((!lastIR.isDummy() && lastIR >= mDecoder->getInteractionRecord()) || firstIR > mDecoder->getInteractionRecord()) { const int MaxErrLog = 2; @@ -166,22 +170,32 @@ void STFDecoder::run(ProcessingContext& pc) if (errLocCount++ < MaxErrLog) { LOGP(warn, "Impossible ROF IR {}, previous was {}, TF 1st IR was {}, discarding in decoding", mDecoder->getInteractionRecord().asString(), lastIR.asString(), firstIR.asString()); } + nTriggersProcessed = 0x7fffffff; // to account for a problem with event continue; } lastIR = mDecoder->getInteractionRecord(); - if (mDoDigits || mClusterer->getMaxROFDepthToSquash()) { // call before clusterization, since the latter will hide the digits - mDecoder->fillDecodedDigits(digVec, digROFVec, chipStatus); // lot of copying involved + mDecoder->fillChipsStatus(chipStatus); + if (mDoDigits || mClusterer->getMaxROFDepthToSquash()) { // call before clusterization, since the latter will hide the digits + mDecoder->fillDecodedDigits(digVec, digROFVec); // lot of copying involved if (mDoCalibData) { mDecoder->fillCalibData(calVec); } - } else { - mDecoder->fillChipsStatus(chipStatus); } if (mDoClusters && !mClusterer->getMaxROFDepthToSquash()) { // !!! THREADS !!! mClusterer->process(mNThreads, *mDecoder.get(), &clusCompVec, mDoPatterns ? &clusPattVec : nullptr, &clusROFVec); } } + nTriggersProcessed = mDecoder->getNROFsProcessed() - nTriggersProcessed - 1; + const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); + int expectedTFSize = static_cast(o2::constants::lhc::LHCMaxBunches * o2::base::GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF() / alpParams.roFrameLengthInBC); // 3564*32 / ROF Length in BS = number of ROFs per TF + if ((expectedTFSize != nTriggersProcessed) && mROFErrRepIntervalMS > 0 && mTFCounter > 1 && nTriggersProcessed > 0) { + long currTS = std::chrono::time_point_cast(std::chrono::system_clock::now()).time_since_epoch().count(); + if (currTS - lastErrReportTS > mROFErrRepIntervalMS) { + LOGP(error, "Inconsistent number of ROF per TF. From parameters: {} from readout: {} (muting further reporting for {} ms)", expectedTFSize, nTriggersProcessed, mROFErrRepIntervalMS); + lastErrReportTS = currTS; + } + } if (mDoClusters && mClusterer->getMaxROFDepthToSquash()) { // Digits squashing require to run on a batch of digits and uses a digit reader, cannot (?) run with decoder // - Setup decoder for running on a batch of digits @@ -406,6 +420,7 @@ DataProcessorSpec getSTFDecoderSpec(const STFDecoderInp& inp) {"allow-empty-rofs", VariantType::Bool, false, {"record ROFs w/o any hit"}}, {"ignore-noise-map", VariantType::Bool, false, {"do not mask pixels flagged in the noise map"}}, {"accept-rof-rampup-data", VariantType::Bool, false, {"do not discard data during ROF ramp up"}}, + {"rof-lenght-error-freq", VariantType::Float, 60.f, {"do not report ROF lenght error more frequently than this value, disable if negative"}}, {"ignore-cluster-dictionary", VariantType::Bool, false, {"do not use cluster dictionary, always store explicit patterns"}}}}; } diff --git a/Detectors/MUON/MCH/Align/CMakeLists.txt b/Detectors/MUON/MCH/Align/CMakeLists.txt index 2ef8fd3495658..15ab93353eaa2 100644 --- a/Detectors/MUON/MCH/Align/CMakeLists.txt +++ b/Detectors/MUON/MCH/Align/CMakeLists.txt @@ -13,16 +13,20 @@ o2_add_library(MCHAlign SOURCES src/Aligner.cxx src/AlignmentSpec.cxx + src/AlignRecordSpec.cxx PUBLIC_LINK_LIBRARIES O2::MathUtils O2::CCDB O2::DataFormatsMCH O2::ForwardAlign O2::MCHTracking + O2::GlobalTracking + O2::GlobalTrackingWorkflow O2::MCHGeometryTransformer O2::CommonUtils O2::DataFormatsParameters O2::DetectorsBase + O2::DetectorsRaw O2::Framework O2::DetectorsRaw O2::Headers @@ -31,7 +35,9 @@ o2_add_library(MCHAlign o2_target_root_dictionary(MCHAlign HEADERS - include/MCHAlign/Aligner.h) + include/MCHAlign/Aligner.h + include/MCHAlign/AlignmentSpec.h + include/MCHAlign/AlignRecordSpec.h) o2_add_executable( alignment-workflow @@ -42,5 +48,12 @@ o2_add_executable( O2::MCHAlign Boost::program_options) +o2_add_executable( + align-record-workflow + SOURCES src/align-record-workflow.cxx + COMPONENT_NAME mch + PUBLIC_LINK_LIBRARIES + O2::MCHAlign) + diff --git a/Detectors/MUON/MCH/Align/include/MCHAlign/AlignRecordSpec.h b/Detectors/MUON/MCH/Align/include/MCHAlign/AlignRecordSpec.h new file mode 100644 index 0000000000000..7d4415fed040f --- /dev/null +++ b/Detectors/MUON/MCH/Align/include/MCHAlign/AlignRecordSpec.h @@ -0,0 +1,35 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file AlignRecordSpec.h +/// \brief Definition of the process for creating alignment record during reconstruction +/// +/// \author Chi ZHANG, CEA-Saclay, chi.zhang@cern.ch + +#ifndef O2_MCH_ALIGNRECORD_H_ +#define O2_MCH_ALIGNRECORD_H_ + +#include "Framework/DataProcessorSpec.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" + +using GID = o2::dataformats::GlobalTrackID; + +namespace o2 +{ +namespace mch +{ + +o2::framework::DataProcessorSpec getAlignRecordSpec(bool useMC, bool disableCCDB = false); + +} // end namespace mch +} // end namespace o2 + +#endif // O2_MCH_ALIGNRECORD_H_ \ No newline at end of file diff --git a/Detectors/MUON/MCH/Align/include/MCHAlign/Aligner.h b/Detectors/MUON/MCH/Align/include/MCHAlign/Aligner.h index fe18c337cbe9a..450c860dba7d9 100644 --- a/Detectors/MUON/MCH/Align/include/MCHAlign/Aligner.h +++ b/Detectors/MUON/MCH/Align/include/MCHAlign/Aligner.h @@ -107,13 +107,13 @@ class Aligner : public TObject public: Aligner(); - ~Aligner() = default; + ~Aligner(); // initialize - void init(TString DataRecFName = "recDataFile.root", TString ConsRecFName = "recConsFile.root"); + void init(TString DataRecFName = "millerecords.root", TString ConsRecFName = "milleconstraints.root"); // terminate - void terminate(void); + void terminate(); // array dimendions enum { @@ -184,9 +184,7 @@ class Aligner : public TObject AllSides = SideTop | SideBottom | SideLeft | SideRight }; - o2::fwdalign::MillePedeRecord* ProcessTrack(Track& track, const o2::mch::geo::TransformationCreator& transformation, Bool_t doAlignment, Double_t weight = 1); - - void ProcessTrack(o2::fwdalign::MillePedeRecord*); + void ProcessTrack(Track& track, const o2::mch::geo::TransformationCreator& transformation, Bool_t doAlignment, Double_t weight = 1); //@name modifiers //@{ @@ -302,6 +300,8 @@ class Aligner : public TObject /// get error on a given parameter double GetParError(int iPar) const; + o2::fwdalign::MillePedeRecord& GetRecord() { return fTrackRecord; } + void ReAlign(std::vector& params, std::vector& misAlignments); void SetAlignmentResolution(const TClonesArray* misAlignArray, int chId, double chResX, double chResY, double deResX, double deResY); @@ -316,6 +316,11 @@ class Aligner : public TObject mRead = true; } + void DisableRecordWriter() + { + fDisableRecordWriter = true; + } + private: /// Not implemented Aligner(const Aligner& right); @@ -396,9 +401,6 @@ class Aligner : public TObject /// Detector independent alignment class o2::fwdalign::MillePede2* fMillepede; // AliMillePede2 implementation - /// MCH cluster class - o2::mch::Cluster* fCluster; - /// Number of standard deviations for chi2 cut int fNStdDev; @@ -452,9 +454,8 @@ class Aligner : public TObject /// preform evaluation bool fDoEvaluation; - /// original local track params - LocalTrackParam* fTrackParamOrig; - LocalTrackParam* fTrackParamNew; + /// disable record saving + bool fDisableRecordWriter; LocalTrackClusterResidual* fTrkClRes; diff --git a/Detectors/MUON/MCH/Align/src/AlignRecordSpec.cxx b/Detectors/MUON/MCH/Align/src/AlignRecordSpec.cxx new file mode 100644 index 0000000000000..0a61d38a36b2a --- /dev/null +++ b/Detectors/MUON/MCH/Align/src/AlignRecordSpec.cxx @@ -0,0 +1,366 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include +#include + +#include "MCHAlign/AlignRecordSpec.h" + +#include "DataFormatsMCH/TrackMCH.h" +#include "DataFormatsMCH/Cluster.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "MathUtils/Utils.h" +#include "CCDB/BasicCCDBManager.h" +#include "DataFormatsParameters/GRPObject.h" +#include "DataFormatsParameters/GRPMagField.h" +#include "DetectorsBase/GeometryManager.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "DetectorsBase/Propagator.h" +#include "Framework/AnalysisDataModel.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/DataProcessorSpec.h" +#include "Framework/DataTypes.h" +#include "Framework/TableBuilder.h" +#include "Framework/CCDBParamSpec.h" +#include "Framework/CallbackService.h" +#include "Framework/Task.h" +#include "FT0Base/Geometry.h" +#include "GlobalTracking/MatchTOF.h" +#include "ReconstructionDataFormats/Cascade.h" +#include "GlobalTracking/MatchGlobalFwd.h" +#include "MCHTracking/TrackExtrap.h" +#include "MCHTracking/TrackFitter.h" +#include "MCHTracking/TrackParam.h" +#include "MCHAlign/Aligner.h" +#include "MCHBase/TrackerParam.h" +#include "ForwardAlign/MillePedeRecord.h" +#include "DetectorsCommonDataFormats/AlignParam.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsCommonDataFormats/DetectorNameConf.h" +#include "MCHGeometryTransformer/Transformations.h" +#include "ReconstructionDataFormats/GlobalFwdTrack.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "ReconstructionDataFormats/PrimaryVertex.h" +#include "ReconstructionDataFormats/StrangeTrack.h" +#include "ReconstructionDataFormats/Track.h" +#include "ReconstructionDataFormats/TrackTPCITS.h" +#include "ReconstructionDataFormats/TrackMCHMID.h" + +#include +#include + +const int fgNCh = 10; +const int fgNDetElemCh[fgNCh] = {4, 4, 4, 4, 18, 18, 26, 26, 26, 26}; +const int fgSNDetElemCh[fgNCh + 1] = {0, 4, 8, 12, 16, 34, 52, 78, 104, 130, 156}; + +namespace o2 +{ +namespace mch +{ + +using namespace o2; +using namespace o2::framework; +using namespace o2::framework::expressions; + +using namespace std; +using std::cout; +using std::endl; +using DataRequest = o2::globaltracking::DataRequest; +using GID = o2::dataformats::GlobalTrackID; + +class AlignRecordTask +{ + public: + //_________________________________________________________________________________________________ + AlignRecordTask(std::shared_ptr dataRequest, std::shared_ptr ccdbRequest, bool useMC = true) + : mDataRequest(dataRequest), mCCDBRequest(ccdbRequest), mUseMC(useMC) {} + + //_________________________________________________________________________________________________ + void init(framework::InitContext& ic) + { + + LOG(info) << "initializing align record maker"; + mTrackCount = 0; + mTrackMatched = 0; + if (mCCDBRequest) { + base::GRPGeomHelper::instance().setRequest(mCCDBRequest); + } else { + auto grpFile = ic.options().get("grp-file"); + if (std::filesystem::exists(grpFile)) { + const auto grp = parameters::GRPObject::loadFrom(grpFile); + base::Propagator::initFieldFromGRP(grp); + TrackExtrap::setField(); + TrackExtrap::useExtrapV2(); + mAlign.SetBFieldOn(mch::TrackExtrap::isFieldON()); + } else { + LOG(fatal) << "GRP file doesn't exist!"; + } + } + + // Configuration for alignment object + mAlign.SetDoEvaluation(false); + mAlign.DisableRecordWriter(); + mAlign.SetAllowedVariation(0, 2.0); + mAlign.SetAllowedVariation(1, 0.3); + mAlign.SetAllowedVariation(2, 0.002); + mAlign.SetAllowedVariation(3, 2.0); + + // Configuration for track fitter + const auto& trackerParam = TrackerParam::Instance(); + trackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion); + trackFitter.setChamberResolution(trackerParam.chamberResolutionX, trackerParam.chamberResolutionY); + trackFitter.smoothTracks(true); + trackFitter.useChamberResolution(); + mImproveCutChi2 = 2. * trackerParam.sigmaCutForImprovement * trackerParam.sigmaCutForImprovement; + + // Configuration for chamber fixing + auto input_fixchambers = ic.options().get("fix-chamber"); + std::stringstream string_chambers(input_fixchambers); + string_chambers >> std::ws; + while (string_chambers.good()) { + string substr; + std::getline(string_chambers, substr, ','); + LOG(info) << Form("%s%d", "Fixing chamber: ", std::stoi(substr)); + mAlign.FixChamber(std::stoi(substr)); + } + + // Init for output saving + auto OutputRecFileName = ic.options().get("output-record-data"); + auto OutputConsFileName = ic.options().get("output-record-constraint"); + mAlign.init(OutputRecFileName, OutputConsFileName); + + ic.services().get().set([this]() { + LOG(info) << "Saving records into ROOT file"; + LOG(info) << "Nb of records to be saved: " << mTrackCount; + LOG(info) << "Nb of matched MCH-MID tracks: " << mTrackMatched; + mAlign.terminate(); + }); + } + + //_________________________________________________________________________________________________ + void finaliseCCDB(framework::ConcreteDataMatcher& matcher, void* obj) + { + /// finalize the track extrapolation setting + if (mCCDBRequest && base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + if (matcher == framework::ConcreteDataMatcher("GLO", "GRPMAGFIELD", 0)) { + TrackExtrap::setField(); + TrackExtrap::useExtrapV2(); + mAlign.SetBFieldOn(mch::TrackExtrap::isFieldON()); + } + + if (matcher == framework::ConcreteDataMatcher("GLO", "GEOMALIGN", 0)) { + LOG(info) << "Loading reference geometry from CCDB"; + transformation = geo::transformationFromTGeoManager(*gGeoManager); + for (int i = 0; i < 156; i++) { + int iDEN = GetDetElemId(i); + transform[iDEN] = transformation(iDEN); + } + } + } + } + + //_________________________________________________________________________________________________ + void run(framework::ProcessingContext& pc) + { + if (mCCDBRequest) { + base::GRPGeomHelper::instance().checkUpdates(pc); + } + + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); + + const auto& mchTracks = recoData.getMCHTracks(); + const auto& mchmidMatches = recoData.getMCHMIDMatches(); + const auto& mchClusters = recoData.getMCHTrackClusters(); + mTrackMatched += mchmidMatches.size(); + + for (auto const& mchmidMatch : mchmidMatches) { + + int mchTrackID = mchmidMatch.getMCHRef().getIndex(); + const auto& mchTrack = mchTracks[mchTrackID]; + int first = mchTrack.getFirstClusterIdx(); + int last = mchTrack.getLastClusterIdx(); + int Ncluster = last - first + 1; + + if (Ncluster <= 9) { + continue; + } + + mch::Track convertedTrack; + + for (int i = first; i <= last; i++) { + const auto& cluster = mchClusters[i]; + convertedTrack.createParamAtCluster(cluster); + } + + // Erase removable track + if (!RemoveTrack(convertedTrack)) { + mAlign.ProcessTrack(convertedTrack, transformation, false, weightRecord); + mTrackCount += 1; + pc.outputs().snapshot(Output{"MUON", "RECORD_MCHMID", 0}, mAlign.GetRecord()); + } + } + } + + private: + //_________________________________________________________________________________________________ + bool RemoveTrack(mch::Track& track) + { + bool removeTrack = false; + + try { + trackFitter.fit(track, false); + } catch (exception const& e) { + removeTrack = true; + return removeTrack; + } + + auto itStartingParam = std::prev(track.rend()); + + while (true) { + try { + trackFitter.fit(track, true, false, (itStartingParam == track.rbegin()) ? nullptr : &itStartingParam); + } catch (exception const&) { + removeTrack = true; + break; + } + + double worstLocalChi2 = -1.0; + + track.tagRemovableClusters(0x1F, false); + auto itWorstParam = track.end(); + + for (auto itParam = track.begin(); itParam != track.end(); ++itParam) { + if (itParam->getLocalChi2() > worstLocalChi2) { + worstLocalChi2 = itParam->getLocalChi2(); + itWorstParam = itParam; + } + } + + if (worstLocalChi2 < mImproveCutChi2) { + break; + } + + if (!itWorstParam->isRemovable()) { + removeTrack = true; + track.removable(); + break; + } + + auto itNextParam = track.removeParamAtCluster(itWorstParam); + auto itNextToNextParam = (itNextParam == track.end()) ? itNextParam : std::next(itNextParam); + itStartingParam = track.rbegin(); + + if (track.getNClusters() < 10) { + removeTrack = true; + break; + } else { + while (itNextToNextParam != track.end()) { + if (itNextToNextParam->getClusterPtr()->getChamberId() != itNextParam->getClusterPtr()->getChamberId()) { + itStartingParam = std::make_reverse_iterator(++itNextParam); + break; + } + ++itNextToNextParam; + } + } + } + + if (!removeTrack) { + for (auto& param : track) { + param.setParameters(param.getSmoothParameters()); + param.setCovariances(param.getSmoothCovariances()); + } + } + + return removeTrack; + } + + //_________________________________________________________________________________________________ + Int_t GetDetElemId(Int_t iDetElemNumber) + { + // make sure detector number is valid + if (!(iDetElemNumber >= fgSNDetElemCh[0] && + iDetElemNumber < fgSNDetElemCh[fgNCh])) { + LOG(fatal) << "Invalid detector element number: " << iDetElemNumber; + } + /// get det element number from ID + // get chamber and element number in chamber + int iCh = 0; + int iDet = 0; + for (int i = 1; i <= fgNCh; i++) { + if (iDetElemNumber < fgSNDetElemCh[i]) { + iCh = i; + iDet = iDetElemNumber - fgSNDetElemCh[i - 1]; + break; + } + } + + // make sure detector index is valid + if (!(iCh > 0 && iCh <= fgNCh && iDet < fgNDetElemCh[iCh - 1])) { + LOG(fatal) << "Invalid detector element id: " << 100 * iCh + iDet; + } + + // add number of detectors up to this chamber + return 100 * iCh + iDet; + } + + std::shared_ptr mCCDBRequest; ///< pointer to the CCDB requests + std::shared_ptr mDataRequest; + GID::mask_t mInputSources; + bool mUseMC = true; + parameters::GRPMagField* grpmag; + TGeoManager* geo; + + mch::TrackFitter trackFitter; + double mImproveCutChi2{}; + int mTrackCount{}; + int mTrackMatched{}; + mch::Aligner mAlign{}; + Double_t weightRecord{1.0}; + std::vector mRecords; + + map transform; + mch::geo::TransformationCreator transformation; +}; + +//_________________________________________________________________________________________________ +o2::framework::DataProcessorSpec getAlignRecordSpec(bool useMC, bool disableCCDB) +{ + auto dataRequest = std::make_shared(); + o2::dataformats::GlobalTrackID::mask_t src = o2::dataformats::GlobalTrackID::getSourcesMask("MCH-MID"); + dataRequest->requestMCHClusters(false); + dataRequest->requestTracks(src, useMC); + + vector outputSpecs{}; + auto ccdbRequest = disableCCDB ? nullptr : std::make_shared(false, // orbitResetTime + false, // GRPECS=true + false, // GRPLHCIF + true, // GRPMagField + false, // askMatLUT + base::GRPGeomRequest::Aligned, // geometry + dataRequest->inputs, + true); // query only once all objects except mag.field + + outputSpecs.emplace_back("MUON", "RECORD_MCHMID", 0, Lifetime::Sporadic); + + return DataProcessorSpec{ + "mch-align-record", + dataRequest->inputs, + outputSpecs, + AlgorithmSpec{adaptFromTask(dataRequest, ccdbRequest, useMC)}, + Options{{"geo-file", VariantType::String, o2::base::NameConf::getAlignedGeomFileName(), {"Name of the reference geometry file"}}, + {"grp-file", VariantType::String, o2::base::NameConf::getGRPFileName(), {"Name of the grp file"}}, + {"fix-chamber", VariantType::String, "", {"Chamber fixing, ex 1,2,3"}}, + {"output-record-data", VariantType::String, "recDataFile.root", {"Option for name of output record file for data"}}, + {"output-record-constraint", VariantType::String, "recConsFile.root", {"Option for name of output record file for constraint"}}}}; +} + +} // namespace mch +} // namespace o2 \ No newline at end of file diff --git a/Detectors/MUON/MCH/Align/src/Aligner.cxx b/Detectors/MUON/MCH/Align/src/Aligner.cxx index 39a00cdd893d9..71bafad5b9ff3 100644 --- a/Detectors/MUON/MCH/Align/src/Aligner.cxx +++ b/Detectors/MUON/MCH/Align/src/Aligner.cxx @@ -29,6 +29,7 @@ #include "ForwardAlign/MillePedeRecord.h" #include "Framework/Logger.h" #include "MCHAlign/Aligner.h" +#include "MathUtils/Cartesian.h" #include "MCHTracking/Track.h" #include "MCHTracking/TrackParam.h" #include "MCHGeometryTransformer/Transformations.h" @@ -131,8 +132,7 @@ Aligner::Aligner() fStartFac(65536), fResCutInitial(1000), fResCut(100), - fMillepede(nullptr), // to be modified - fCluster(nullptr), + fMillepede(nullptr), fNStdDev(3), fDetElemNumber(0), fGlobalParameterStatus(std::vector(fNGlobal)), @@ -147,11 +147,9 @@ Aligner::Aligner() mWithConstraintsRecReader(false), mConstraintsRecReader(nullptr), fTransformCreator(), - // fGeoCombiTransInverse(), fDoEvaluation(false), + fDisableRecordWriter(false), mRead(false), - fTrackParamOrig(nullptr), - fTrackParamNew(nullptr), fTrkClRes(nullptr), fTFile(nullptr), fTTree(nullptr) @@ -185,6 +183,14 @@ Aligner::Aligner() } } +//________________________________________________________________________ +Aligner::~Aligner() +{ + delete mRecordWriter; + delete mRecordReader; + delete fMillepede; +} + //_____________________________________________________________________ void Aligner::init(TString DataRecFName, TString ConsRecFName) { @@ -200,15 +206,18 @@ void Aligner::init(TString DataRecFName, TString ConsRecFName) } if (!mRead) { - - mRecordWriter->setCyclicAutoSave(mNEntriesAutoSave); - mRecordWriter->setDataFileName(DataRecFName); - fMillepede->SetRecordWriter(mRecordWriter); - - if (mWithConstraintsRecWriter) { - mConstraintsRecWriter->setCyclicAutoSave(mNEntriesAutoSave); - mConstraintsRecWriter->setDataFileName(ConsRecFName); - fMillepede->SetConstraintsRecWriter(mConstraintsRecWriter); + if (!fDisableRecordWriter) { + mRecordWriter->setCyclicAutoSave(mNEntriesAutoSave); + mRecordWriter->setDataFileName(DataRecFName); + fMillepede->SetRecordWriter(mRecordWriter); + + if (mWithConstraintsRecWriter) { + mConstraintsRecWriter->setCyclicAutoSave(mNEntriesAutoSave); + mConstraintsRecWriter->setDataFileName(ConsRecFName); + fMillepede->SetConstraintsRecWriter(mConstraintsRecWriter); + } + } else { + fMillepede->SetRecord(&fTrackRecord); } } else { @@ -283,7 +292,11 @@ void Aligner::init(TString DataRecFName, TString ConsRecFName) fMillepede->InitMille(fNGlobal, fNLocal, fNStdDev, fResCut, fResCutInitial, fGlobalParameterStatus); if (!mRead) { - mRecordWriter->init(); + if (!fDisableRecordWriter) { + mRecordWriter->init(); + } else { + fMillepede->DisableRecordWriter(); + } } fInitialized = true; @@ -315,12 +328,6 @@ void Aligner::init(TString DataRecFName, TString ConsRecFName) const int kSplitlevel = 98; const int kBufsize = 32000; - // fTrackParamOrig = new LocalTrackParam(); - // fTTree->Branch("fTrackParamOrig", "LocalTrackParam", &fTrackParamOrig, kBufsize, kSplitlevel); - - // fTrackParamNew = new LocalTrackParam(); - // fTTree->Branch("fTrackParamNew", "LocalTrackParam", &fTrackParamNew, kBufsize, kSplitlevel); - fTrkClRes = new o2::mch::LocalTrackClusterResidual(); fTTree->Branch("fClDetElem", &(fTrkClRes->fClDetElem), "fClDetElem/I"); fTTree->Branch("fClDetElemNumber", &(fTrkClRes->fClDetElemNumber), "fClDetElemNumber/I"); @@ -351,24 +358,24 @@ void Aligner::init(TString DataRecFName, TString ConsRecFName) //_____________________________________________________ void Aligner::terminate() { - mRecordWriter->terminate(); fInitialized = kFALSE; LOG(info) << "Closing Evaluation TFile"; - if (fTFile && fTTree) { - fTFile->cd(); - fTTree->Write(); - fTFile->Close(); + if (fDoEvaluation) { + if (fTFile && fTTree) { + fTFile->cd(); + fTTree->Write(); + fTFile->Close(); + } } } //_____________________________________________________ -o2::fwdalign::MillePedeRecord* Aligner::ProcessTrack(Track& track, const o2::mch::geo::TransformationCreator& transformation, bool doAlignment, double weight) +void Aligner::ProcessTrack(Track& track, const o2::mch::geo::TransformationCreator& transformation, bool doAlignment, double weight) { /// process track for alignment minimization - // reset track records - fTrackRecord.Reset(); + if (fMillepede->GetRecord()) { fMillepede->GetRecord()->Reset(); } @@ -436,8 +443,7 @@ o2::fwdalign::MillePedeRecord* Aligner::ProcessTrack(Track& track, const o2::mch // 'inverse' (GlobalToLocal) rotation matrix // const double* r(fGeoCombiTransInverse.GetRotationMatrix()); - - auto trans = transformation(cluster->getDEId()); + o2::math_utils::Transform3D trans = transformation(cluster->getDEId()); // LOG(info) << Form("cluster ID: %i", cluster->getDEId()); TMatrixD transMat(3, 4); trans.GetTransformMatrix(transMat); @@ -455,7 +461,6 @@ o2::fwdalign::MillePedeRecord* Aligner::ProcessTrack(Track& track, const o2::mch r[9] = transMat(0, 3); r[10] = transMat(1, 3); r[11] = transMat(2, 3); - // calculate measurements if (fBFieldOn) { @@ -529,42 +534,17 @@ o2::fwdalign::MillePedeRecord* Aligner::ProcessTrack(Track& track, const o2::mch } // copy track record - mRecordWriter->setRecordRun(fRunNumber); - mRecordWriter->setRecordWeight(weight); - fTrackRecord = *fMillepede->GetRecord(); + if (!fDisableRecordWriter) { + mRecordWriter->setRecordRun(fRunNumber); + mRecordWriter->setRecordWeight(weight); + } // save record data if (doAlignment) { - mRecordWriter->fillRecordTree(); - } - - // return record - return &fTrackRecord; -} - -//______________________________________________________________________________ -void Aligner::ProcessTrack(o2::fwdalign::MillePedeRecord* trackRecord) -{ - LOG(fatal) << __PRETTY_FUNCTION__ << " is disabled"; - - /// process track record - if (!trackRecord) { - return; - } - - // // make sure record storage is initialized - if (!fMillepede->GetRecord()) { - mRecordWriter->init(); + if (!fDisableRecordWriter) { + mRecordWriter->fillRecordTree(); + } } - // // copy content - *fMillepede->GetRecord() = *trackRecord; - - // save record - mRecordWriter->fillRecordTree(); - // write to local file - // mRecordWriter->terminate(); - - return; } //_____________________________________________________________________ diff --git a/Detectors/MUON/MCH/Align/src/AlignmentSpec.cxx b/Detectors/MUON/MCH/Align/src/AlignmentSpec.cxx index 2d50a8235bc0c..948ac1bda9117 100644 --- a/Detectors/MUON/MCH/Align/src/AlignmentSpec.cxx +++ b/Detectors/MUON/MCH/Align/src/AlignmentSpec.cxx @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -74,6 +75,7 @@ #include "MCHTracking/TrackExtrap.h" #include "MCHTracking/TrackParam.h" #include "MCHTracking/TrackFitter.h" +#include "MCHBase/TrackerParam.h" #include "ReconstructionDataFormats/TrackMCHMID.h" namespace o2 @@ -88,15 +90,6 @@ using namespace o2; class AlignmentTask { public: - double Reso_X{0.4}; - double Reso_Y{0.4}; - double ImproveCut{6.0}; - - int tracksGood = 0; - int tracksGoodwithoutFit = 0; - int tracksAll = 0; - int trackMCHMID = 0; - const int fgNDetElemCh[10] = {4, 4, 4, 4, 18, 18, 26, 26, 26, 26}; const int fgSNDetElemCh[11] = {0, 4, 8, 12, 16, 34, 52, 78, 104, 130, 156}; const int fgNDetElemHalfCh[20] = {2, 2, 2, 2, 2, 2, 2, 2, 9, @@ -170,22 +163,6 @@ class AlignmentTask LOG(info) << "Re-alignment mode"; } - auto param_config = ic.options().get("fitter-config"); - if (param_config == "PbPb") { - Reso_X = 0.2; - Reso_Y = 0.2; - ImproveCut = 4.0; - LOG(info) << "Using PbPb parameter set for TrackFitter"; - } else if (param_config == "pp") { - Reso_X = 0.4; - Reso_Y = 0.4; - ImproveCut = 6.0; - LOG(info) << "Using pp parameter set for TrackFitter"; - } else { - LOG(fatal) << "Please enter a correct parameter configuration option"; - exit(-1); - } - if (mCCDBRequest) { LOG(info) << "Loading magnetic field and reference geometry from CCDB"; base::GRPGeomHelper::instance().setRequest(mCCDBRequest); @@ -229,26 +206,31 @@ class AlignmentTask } } - trackFitter.smoothTracks(true); - trackFitter.setChamberResolution(Reso_X, Reso_Y); - trackFitter.useChamberResolution(); - - mAlign.SetDoEvaluation(true); + auto doEvaluation = ic.options().get("do-evaluation"); + mAlign.SetDoEvaluation(doEvaluation); // Variation range for parameters mAlign.SetAllowedVariation(0, 2.0); mAlign.SetAllowedVariation(1, 0.3); mAlign.SetAllowedVariation(2, 0.002); mAlign.SetAllowedVariation(3, 2.0); + // Configuration for track fitter + const auto& trackerParam = TrackerParam::Instance(); + trackFitter.setBendingVertexDispersion(trackerParam.bendingVertexDispersion); + trackFitter.setChamberResolution(trackerParam.chamberResolutionX, trackerParam.chamberResolutionY); + trackFitter.smoothTracks(true); + trackFitter.useChamberResolution(); + mImproveCutChi2 = 2. * trackerParam.sigmaCutForImprovement * trackerParam.sigmaCutForImprovement; + // Fix chambers - auto chambers = ic.options().get("fix-chamber"); - for (int i = 0; i < chambers.length(); ++i) { - if (chambers[i] == ',') { - continue; - } - int chamber = chambers[i] - '0'; - LOG(info) << Form("%s%d", "Fixing chamber: ", chamber); - mAlign.FixChamber(chamber); + auto input_fixchambers = ic.options().get("fix-chamber"); + std::stringstream string_chambers(input_fixchambers); + string_chambers >> std::ws; + while (string_chambers.good()) { + string substr; + std::getline(string_chambers, substr, ','); + LOG(info) << Form("%s%d", "Fixing chamber: ", std::stoi(substr)); + mAlign.FixChamber(std::stoi(substr)); } doMatched = ic.options().get("matched"); @@ -298,12 +280,10 @@ class AlignmentTask for (int iMCHTrack = mchROF.getFirstIdx(); iMCHTrack <= mchROF.getLastIdx(); ++iMCHTrack) { - tracksAll += 1; // MCH-MID matching if (!FindMuon(iMCHTrack, muonTracks)) { continue; } - trackMCHMID += 1; auto mchTrack = mchTracks.at(iMCHTrack); int id_track = iMCHTrack; @@ -313,21 +293,17 @@ class AlignmentTask if (nb_clusters <= 9) { continue; } - tracksGoodwithoutFit += 1; // Format conversion from TrackMCH to Track(MCH internal use) mch::Track convertedTrack = MCHFormatConvert(mchTrack, mchClusters, doReAlign); // Erase removable track - if (RemoveTrack(convertedTrack, ImproveCut)) { + if (RemoveTrack(convertedTrack)) { continue; - } else { - tracksGood += 1; } // Track processing, saving residuals - o2::fwdalign::MillePedeRecord* mchRecord = mAlign.ProcessTrack(convertedTrack, transformation, - doAlign, weightRecord); + mAlign.ProcessTrack(convertedTrack, transformation, doAlign, weightRecord); } } } @@ -345,27 +321,22 @@ class AlignmentTask auto mchTrack = mchTracks.at(iMCHTrack); int id_track = iMCHTrack; int nb_clusters = mchTrack.getNClusters(); - tracksAll += 1; // Track selection, saving only tracks having exactly 10 clusters if (nb_clusters <= 9) { continue; } - tracksGoodwithoutFit += 1; // Format conversion from TrackMCH to Track(MCH internal use) Track convertedTrack = MCHFormatConvert(mchTrack, mchClusters, doReAlign); // Erase removable track - if (RemoveTrack(convertedTrack, ImproveCut)) { + if (RemoveTrack(convertedTrack)) { continue; - } else { - tracksGood += 1; } // Track processing, saving residuals - o2::fwdalign::MillePedeRecord* mchRecord = mAlign.ProcessTrack(convertedTrack, transformation, - doAlign, weightRecord); + mAlign.ProcessTrack(convertedTrack, transformation, doAlign, weightRecord); } } } @@ -445,14 +416,6 @@ class AlignmentTask } auto tEnd = std::chrono::high_resolution_clock::now(); mElapsedTime = tEnd - tStart; - // Evaluation for track removing and selection - LOG(info) << Form("%s%d", "Number of good tracks used in alignment process: ", tracksGood); - LOG(info) << Form("%s%d", "Number of good tracks without fit processing: ", tracksGoodwithoutFit); - LOG(info) << Form("%s%d", "Number of MCH-MID tracks: ", trackMCHMID); - LOG(info) << Form("%s%d", "Total number of tracks loaded: ", tracksAll); - LOG(info) << Form("%s%f", "Ratio of MCH-MID track: ", double(trackMCHMID) / tracksAll); - LOG(info) << Form("%s%f", "Ratio before fit: ", double(tracksGoodwithoutFit) / tracksAll); - LOG(info) << Form("%s%f", "Ratio after fit: ", double(tracksGood) / tracksAll); // Generate new geometry w.r.t alignment results if (doAlign) { @@ -573,10 +536,9 @@ class AlignmentTask } //_________________________________________________________________________________________________ - bool RemoveTrack(Track& track, double ImproveCut) + bool RemoveTrack(Track& track) { - double maxChi2Cluster = 2 * ImproveCut * ImproveCut; bool removeTrack = false; try { @@ -610,7 +572,7 @@ class AlignmentTask } } - if (worstLocalChi2 < maxChi2Cluster) { + if (worstLocalChi2 < mImproveCutChi2) { break; } @@ -905,6 +867,7 @@ class AlignmentTask geo::TransformationCreator transformation{}; TrackFitter trackFitter{}; + double mImproveCutChi2{}; std::chrono::duration mElapsedTime{}; }; @@ -933,8 +896,8 @@ o2::framework::DataProcessorSpec getAlignmentSpec(bool disableCCDB) Options{{"geo-file-ref", VariantType::String, o2::base::NameConf::getAlignedGeomFileName(), {"Name of the reference geometry file"}}, {"geo-file-ideal", VariantType::String, o2::base::NameConf::getGeomFileName(), {"Name of the ideal geometry file"}}, {"grp-file", VariantType::String, o2::base::NameConf::getGRPFileName(), {"Name of the grp file"}}, - {"fitter-config", VariantType::String, "", {"Option of parameter set for TrackFitter, pp or PbPb"}}, {"do-align", VariantType::Bool, false, {"Switch for alignment, otherwise only residuals will be stored"}}, + {"do-evaluation", VariantType::Bool, false, {"Option for saving residuals for evaluation"}}, {"do-realign", VariantType::Bool, false, {"Switch for re-alignment using another geometry"}}, {"matched", VariantType::Bool, false, {"Switch for using MCH-MID matched tracks"}}, {"fix-chamber", VariantType::String, "", {"Chamber fixing, ex 1,2,3"}}, diff --git a/Detectors/MUON/MCH/Align/src/align-record-workflow.cxx b/Detectors/MUON/MCH/Align/src/align-record-workflow.cxx new file mode 100644 index 0000000000000..5640fcfb205b4 --- /dev/null +++ b/Detectors/MUON/MCH/Align/src/align-record-workflow.cxx @@ -0,0 +1,76 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file align-record-workflow.cxx +/// \brief Implementation of a DPL device to create MillePede record for muon alignment +/// +/// \author Chi ZHANG, CEA-Saclay, chi.zhang@cern.ch + +#include "MCHAlign/AlignRecordSpec.h" + +#include "Framework/CompletionPolicy.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "CommonUtils/ConfigurableParam.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "Framework/CallbacksPolicy.h" +#include "ForwardAlign/MilleRecordWriterSpec.h" + +using namespace o2::framework; +using namespace std; + +using GID = o2::dataformats::GlobalTrackID; + +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::vector options{ + {"disable-mc", o2::framework::VariantType::Bool, false, {"disable MC propagation"}}, + {"disable-root-input", o2::framework::VariantType::Bool, false, {"disable root-files input reader"}}, + {"disable-root-output", o2::framework::VariantType::Bool, false, {"do not write output root files"}}, + {"disable-ccdb", VariantType::Bool, false, {"disable input files from CCDB"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); +} + +#include "Framework/runDataProcessing.h" +WorkflowSpec defineDataProcessing(const ConfigContext& configcontext) +{ + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + o2::conf::ConfigurableParam::writeINI("o2mchalignrecord-workflow_configuration.ini"); + + auto useMC = !configcontext.options().get("disable-mc"); + bool disableCCDB = configcontext.options().get("disable-ccdb"); + bool disableRootOutput = configcontext.options().get("disable-root-output"); + + WorkflowSpec specs; + specs.emplace_back(o2::mch::getAlignRecordSpec(useMC, disableCCDB)); + auto srcTracks = GID::getSourcesMask("MCH"); + auto srcClusters = GID::getSourcesMask("MCH"); + auto matchMask = GID::getSourcesMask("MCH-MID"); + + if (!disableRootOutput) { + specs.emplace_back(o2::fwdalign::getMilleRecordWriterSpec(useMC)); + } + + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcClusters, matchMask, srcTracks, useMC, srcClusters, srcTracks); + + // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return std::move(specs); +} \ No newline at end of file diff --git a/Detectors/MUON/MCH/Conditions/README.md b/Detectors/MUON/MCH/Conditions/README.md index d2475900d4d31..dcea47d201867 100644 --- a/Detectors/MUON/MCH/Conditions/README.md +++ b/Detectors/MUON/MCH/Conditions/README.md @@ -21,7 +21,7 @@ The BadChannel and RejectList objects can be uploaded, e.g. for debug purposes, ```shell $ o2-mch-bad-channels-ccdb --help -This program dump MCH bad channels CCDB object +This program get/set MCH bad channels CCDB object Usage: -h [ --help ] produce help message -c [ --ccdb ] arg (=http://localhost:6464) @@ -37,6 +37,9 @@ Usage: -q [ --query ] dump bad channel object from CCDB -v [ --verbose ] verbose output -s [ --solar ] arg solar ids to reject + -d [ --ds ] arg dual sampas indices to reject + -e [ --de ] arg DE ids to reject + -a [ --alias ] arg DCS alias (HV or LV) to reject ``` @@ -44,5 +47,5 @@ For instance, to create a debug RejectList object which declares solar number 32 ```shell $ o2-mch-bad-channels-ccdb -p -s 32 -t RejectList --starttimestamp 1667260801000 --endtimestamp 1672531199000 -storing default MCH bad channels (valid from 1667260801000to 1672531199000) to MCH/Calib/RejectList +storing default MCH bad channels (valid from 1667260801000 to 1672531199000) to MCH/Calib/RejectList ``` diff --git a/Detectors/MUON/MCH/Conditions/src/bad-channels-ccdb.cxx b/Detectors/MUON/MCH/Conditions/src/bad-channels-ccdb.cxx index e3d2ca9c3e7de..db1cb53f51c5a 100644 --- a/Detectors/MUON/MCH/Conditions/src/bad-channels-ccdb.cxx +++ b/Detectors/MUON/MCH/Conditions/src/bad-channels-ccdb.cxx @@ -17,9 +17,12 @@ #include #include #include "DataFormatsMCH/DsChannelId.h" -#include "MCHRawElecMap/Mapper.h" -#include "MCHMappingInterface/Segmentation.h" +#include "MCHConditions/DCSAliases.h" +#include "MCHConstants/DetectionElements.h" #include "MCHGlobalMapping/DsIndex.h" +#include "MCHGlobalMapping/Mapper.h" +#include "MCHMappingInterface/Segmentation.h" +#include "MCHRawElecMap/Mapper.h" namespace po = boost::program_options; @@ -46,50 +49,81 @@ void queryBadChannels(const std::string ccdbUrl, } } -void uploadBadChannels(const std::string ccdbUrl, - const std::string badChannelType, - uint64_t startTimestamp, - uint64_t endTimestamp, - std::vector solarsToReject, - std::vector dsToReject, - bool makeDefault) +void rejectDS(const o2::mch::raw::DsDetId& dsDetId, BadChannelsVector& bv) { - BadChannelsVector bv; - - auto det2elec = o2::mch::raw::createDet2ElecMapper(); + static auto det2elec = o2::mch::raw::createDet2ElecMapper(); + const auto& seg = o2::mch::mapping::segmentation(dsDetId.deId()); + auto dsElecId = det2elec(dsDetId); + seg.forEachPadInDualSampa(dsDetId.dsId(), [&](int pad) { + uint8_t channel = seg.padDualSampaChannel(pad); + const auto c = o2::mch::DsChannelId(dsElecId->solarId(), dsElecId->elinkId(), channel); + bv.emplace_back(c); + }); +} - for (auto solar : solarsToReject) { +void rejectSolars(const std::vector solarIds, BadChannelsVector& bv) +{ + for (auto solar : solarIds) { auto ds = o2::mch::raw::getDualSampas(solar); for (const auto& dsDetId : ds) { - o2::mch::mapping::Segmentation seg(dsDetId.deId()); - for (uint8_t channel = 0; channel < 64; channel++) { - auto dsElecId = det2elec(dsDetId); - auto padId = seg.findPadByFEE(dsDetId.dsId(), channel); - if (seg.isValid(padId)) { - const auto c = o2::mch::DsChannelId(solar, dsElecId->elinkId(), channel); - bv.emplace_back(c); - } - } + rejectDS(dsDetId, bv); } } +} - for (auto ds : dsToReject) { +void rejectDSs(const std::vector dsIdxs, BadChannelsVector& bv) +{ + for (auto ds : dsIdxs) { if (ds >= o2::mch::NumberOfDualSampas) { - std::cout << "Error: invalid DS index" << std::endl; + std::cout << "Error: invalid DS index " << ds << std::endl; continue; } o2::mch::raw::DsDetId dsDetId = o2::mch::getDsDetId(ds); - o2::mch::mapping::Segmentation seg(dsDetId.deId()); - for (uint8_t channel = 0; channel < 64; channel++) { - auto dsElecId = det2elec(dsDetId); - auto padId = seg.findPadByFEE(dsDetId.dsId(), channel); - if (seg.isValid(padId)) { - const auto c = o2::mch::DsChannelId(dsElecId->solarId(), dsElecId->elinkId(), channel); - bv.emplace_back(c); - } + rejectDS(dsDetId, bv); + } +} + +void rejectHVLVs(const std::vector dcsAliases, BadChannelsVector& bv) +{ + for (auto alias : dcsAliases) { + if (!o2::mch::dcs::isValid(alias)) { + std::cout << "Error: invalid alias " << alias << std::endl; + continue; + } + for (auto ds : o2::mch::dcs::aliasToDsIndices(alias)) { + o2::mch::raw::DsDetId dsDetId = o2::mch::getDsDetId(ds); + rejectDS(dsDetId, bv); } } +} + +void rejectDEs(const std::vector deIds, BadChannelsVector& bv) +{ + static auto det2elec = o2::mch::raw::createDet2ElecMapper(); + for (auto de : deIds) { + if (!o2::mch::constants::isValidDetElemId(de)) { + std::cout << "Error: invalid DE ID " << de << std::endl; + continue; + } + const auto& seg = o2::mch::mapping::segmentation(de); + seg.forEachPad([&](int pad) { + auto ds = seg.padDualSampaId(pad); + o2::mch::raw::DsDetId dsDetId(de, ds); + auto dsElecId = det2elec(dsDetId); + uint8_t channel = seg.padDualSampaChannel(pad); + const auto c = o2::mch::DsChannelId(dsElecId->solarId(), dsElecId->elinkId(), channel); + bv.emplace_back(c); + }); + } +} +void uploadBadChannels(const std::string ccdbUrl, + const std::string badChannelType, + uint64_t startTimestamp, + uint64_t endTimestamp, + const BadChannelsVector& bv, + bool makeDefault) +{ o2::ccdb::CcdbApi api; api.init(ccdbUrl); std::map md; @@ -139,7 +173,9 @@ int main(int argc, char** argv) ("query,q",po::bool_switch(&query),"dump bad channel object from CCDB") ("verbose,v",po::bool_switch(&verbose),"verbose output") ("solar,s",po::value>()->multitoken(),"solar ids to reject") - ("dsToReject,d", po::value>()->multitoken(), "dual sampas indices to reject") + ("ds,d", po::value>()->multitoken(), "dual sampas indices to reject") + ("de,e", po::value>()->multitoken(), "DE ids to reject") + ("alias,a", po::value>()->multitoken(), "DCS alias (HV or LV) to reject") ; // clang-format on @@ -171,16 +207,21 @@ int main(int argc, char** argv) } if (put) { - std::vector solarsToReject; - std::vector dsToReject; + BadChannelsVector bv; if (vm.count("solar")) { - solarsToReject = vm["solar"].as>(); + rejectSolars(vm["solar"].as>(), bv); + } + if (vm.count("ds")) { + rejectDSs(vm["ds"].as>(), bv); + } + if (vm.count("de")) { + rejectDEs(vm["de"].as>(), bv); } - if (vm.count("dsToReject")) { - dsToReject = vm["dsToReject"].as>(); + if (vm.count("alias")) { + rejectHVLVs(vm["alias"].as>(), bv); } - uploadBadChannels(ccdbUrl, badChannelType, startTimestamp, endTimestamp, solarsToReject, dsToReject, uploadDefault); + uploadBadChannels(ccdbUrl, badChannelType, startTimestamp, endTimestamp, bv, uploadDefault); } return 0; } diff --git a/Detectors/MUON/MCH/GlobalMapping/CMakeLists.txt b/Detectors/MUON/MCH/GlobalMapping/CMakeLists.txt index 5191a9ab72713..335f5245a8f29 100644 --- a/Detectors/MUON/MCH/GlobalMapping/CMakeLists.txt +++ b/Detectors/MUON/MCH/GlobalMapping/CMakeLists.txt @@ -21,6 +21,7 @@ o2_add_library(MCHGlobalMapping PUBLIC_LINK_LIBRARIES O2::MCHRawElecMap O2::MCHMappingInterface O2::MCHConditions + O2::Framework PRIVATE_LINK_LIBRARIES O2::MCHConstants) o2_target_root_dictionary(MCHGlobalMapping diff --git a/Detectors/MUON/MCH/GlobalMapping/include/MCHGlobalMapping/Mapper.h b/Detectors/MUON/MCH/GlobalMapping/include/MCHGlobalMapping/Mapper.h index 790363f52d662..c477bdb601216 100644 --- a/Detectors/MUON/MCH/GlobalMapping/include/MCHGlobalMapping/Mapper.h +++ b/Detectors/MUON/MCH/GlobalMapping/include/MCHGlobalMapping/Mapper.h @@ -22,7 +22,7 @@ namespace o2::mch::dcs { /** get the list of dual sampa indices corresponding to a given DCS Alias */ -std::set aliasToDsIndices(std::string_view alias); +std::set aliasToDsIndices(std::string_view alias); /** get indices of all dual sampas of a set of cathodes (={deId,plane}). * returned set might be empty if input Cathodes are not valid ones. */ diff --git a/Detectors/MUON/MCH/GlobalMapping/src/DsIndex.cxx b/Detectors/MUON/MCH/GlobalMapping/src/DsIndex.cxx index faf9949ad6f2d..ac11defff938c 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/DsIndex.cxx +++ b/Detectors/MUON/MCH/GlobalMapping/src/DsIndex.cxx @@ -12,7 +12,10 @@ #include "MCHGlobalMapping/DsIndex.h" #include +#include #include + +#include "Framework/Logger.h" #include "MCHMappingInterface/Segmentation.h" namespace o2::mch @@ -38,12 +41,16 @@ uint8_t numberOfDualSampaChannels(DsIndex dsIndex) auto dsId = det.dsId(); auto deId = det.deId(); const auto& seg = o2::mch::mapping::segmentation(deId); - seg.bending().forEachPadInDualSampa(dsId, [&nch](int /*catPadIndex*/) { ++nch; }); - seg.nonBending().forEachPadInDualSampa(dsId, [&nch](int /*catPadIndex*/) { ++nch; }); + seg.forEachPadInDualSampa(dsId, [&nch](int /*dePadIndex*/) { ++nch; }); channelsPerDS.emplace_back(nch); } } - return channelsPerDS[dsIndex]; + if (dsIndex < o2::mch::NumberOfDualSampas) { + return channelsPerDS[dsIndex]; + } else { + LOGP(error, "invalid Dual Sampa index: {}", dsIndex); + } + return 0; } std::map buildDetId2DsIndexMap() @@ -72,13 +79,23 @@ std::map buildDetId2DsIndexMap() DsIndex getDsIndex(const o2::mch::raw::DsDetId& dsDetId) { static std::map m = buildDetId2DsIndexMap(); - return m[encode(dsDetId)]; + try { + return m.at(encode(dsDetId)); + } catch (const std::exception&) { + LOGP(error, "invalid Dual Sampa Id: {}", raw::asString(dsDetId)); + } + return NumberOfDualSampas; } o2::mch::raw::DsDetId getDsDetId(DsIndex dsIndex) { static std::map m = inverseMap(buildDetId2DsIndexMap()); - return raw::decodeDsDetId(m[dsIndex]); + try { + return raw::decodeDsDetId(m.at(dsIndex)); + } catch (const std::exception&) { + LOGP(error, "invalid Dual Sampa index: {}", dsIndex); + } + return raw::DsDetId(0, 0); } } // namespace o2::mch diff --git a/Detectors/MUON/MCH/GlobalMapping/src/HV.cxx b/Detectors/MUON/MCH/GlobalMapping/src/HV.cxx index 723d8a335ee58..c11a5b3598652 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/HV.cxx +++ b/Detectors/MUON/MCH/GlobalMapping/src/HV.cxx @@ -14,7 +14,6 @@ #include "MCHConditions/Chamber.h" #include "MCHConditions/DetectionElement.h" #include "MCHConditions/Number.h" -#include "MCHGlobalMapping/DsIndex.h" #include "MCHMappingInterface/Segmentation.h" #include "MCHRawElecMap/DsDetId.h" #include "MCHRawElecMap/Mapper.h" @@ -37,13 +36,13 @@ double findXmean(const o2::mch::mapping::Segmentation& seg, int dsId) return xmean / n; } -std::set hvAliasToDsIndices(std::string_view alias) +std::set hvAliasToDsIndices(std::string_view alias) { const auto chamber = aliasToChamber(alias); bool slat = isSlat(chamber); int deId = aliasToDetElemId(alias).value(); - std::set indices; - for (auto dsIndex = 0; dsIndex < o2::mch::NumberOfDualSampas; ++dsIndex) { + std::set indices; + for (DsIndex dsIndex = 0; dsIndex < o2::mch::NumberOfDualSampas; ++dsIndex) { const auto& dd = getDsDetId(dsIndex); if (dd.deId() != deId) { continue; diff --git a/Detectors/MUON/MCH/GlobalMapping/src/HV.h b/Detectors/MUON/MCH/GlobalMapping/src/HV.h index 995a96d1efe9e..7aca4a0bb5822 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/HV.h +++ b/Detectors/MUON/MCH/GlobalMapping/src/HV.h @@ -15,9 +15,11 @@ #include #include +#include "MCHGlobalMapping/DsIndex.h" + namespace o2::mch::dcs { -std::set hvAliasToDsIndices(std::string_view alias); +std::set hvAliasToDsIndices(std::string_view alias); } #endif diff --git a/Detectors/MUON/MCH/GlobalMapping/src/LV.cxx b/Detectors/MUON/MCH/GlobalMapping/src/LV.cxx index 862304aa1e575..fb17d50718c41 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/LV.cxx +++ b/Detectors/MUON/MCH/GlobalMapping/src/LV.cxx @@ -15,7 +15,6 @@ #include "MCHConditions/Chamber.h" #include "MCHConditions/Plane.h" #include "MCHConstants/DetectionElements.h" -#include "MCHGlobalMapping/DsIndex.h" #include "MCHRawElecMap/Mapper.h" #include "Quadrant.h" #include "Slat.h" @@ -33,10 +32,10 @@ std::set lvAliasToCathode(std::string_view alias) } } -std::set lvAliasToDsIndices(std::string_view alias) +std::set lvAliasToDsIndices(std::string_view alias) { auto cathodes = lvAliasToCathode(alias); - std::set dsIndices; + std::set dsIndices; for (auto cathode : cathodes) { auto deId = cathode.deId; auto plane = cathode.plane; diff --git a/Detectors/MUON/MCH/GlobalMapping/src/LV.h b/Detectors/MUON/MCH/GlobalMapping/src/LV.h index 42bb5dc7e8ab8..631c68b225f2a 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/LV.h +++ b/Detectors/MUON/MCH/GlobalMapping/src/LV.h @@ -15,9 +15,11 @@ #include #include +#include "MCHGlobalMapping/DsIndex.h" + namespace o2::mch::dcs { -std::set lvAliasToDsIndices(std::string_view alias); +std::set lvAliasToDsIndices(std::string_view alias); } #endif diff --git a/Detectors/MUON/MCH/GlobalMapping/src/Mapper.cxx b/Detectors/MUON/MCH/GlobalMapping/src/Mapper.cxx index c587f11b052f4..65efb18d8981f 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/Mapper.cxx +++ b/Detectors/MUON/MCH/GlobalMapping/src/Mapper.cxx @@ -28,7 +28,7 @@ namespace o2::mch::dcs { -std::set solarAliasToDsIndices(std::string_view alias) +std::set solarAliasToDsIndices(std::string_view alias) { const auto chamber = aliasToChamber(alias); if (dcs::isQuadrant(chamber)) { @@ -38,7 +38,7 @@ std::set solarAliasToDsIndices(std::string_view alias) } } -std::set aliasToDsIndices(std::string_view alias) +std::set aliasToDsIndices(std::string_view alias) { auto m = aliasToMeasurementType(alias); switch (m) { diff --git a/Detectors/MUON/MCH/GlobalMapping/src/Quadrant.cxx b/Detectors/MUON/MCH/GlobalMapping/src/Quadrant.cxx index b5132b9210bc0..bc5eded62211c 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/Quadrant.cxx +++ b/Detectors/MUON/MCH/GlobalMapping/src/Quadrant.cxx @@ -90,7 +90,7 @@ Cathode lvAliasToCathode(std::string_view alias) } } -std::set solarAliasToDsIndices(std::string_view alias) +std::set solarAliasToDsIndices(std::string_view alias) { /** For St12, to get the solar alias to dual sampas relationship * we "just" have to convert the solar crate number to a LV diff --git a/Detectors/MUON/MCH/GlobalMapping/src/Quadrant.h b/Detectors/MUON/MCH/GlobalMapping/src/Quadrant.h index 66b7d1e50d3bd..0a1103f8008df 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/Quadrant.h +++ b/Detectors/MUON/MCH/GlobalMapping/src/Quadrant.h @@ -13,13 +13,14 @@ #define O2_MCH_GLOBAL_MAPPING_QUADRANT_H #include "MCHConditions/Cathode.h" +#include "MCHGlobalMapping/DsIndex.h" #include #include namespace o2::mch::dcs::quadrant { Cathode lvAliasToCathode(std::string_view alias); -std::set solarAliasToDsIndices(std::string_view alias); +std::set solarAliasToDsIndices(std::string_view alias); } // namespace o2::mch::dcs::quadrant #endif diff --git a/Detectors/MUON/MCH/GlobalMapping/src/Slat.cxx b/Detectors/MUON/MCH/GlobalMapping/src/Slat.cxx index 2e16c5f20afd9..c6258cb18fec3 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/Slat.cxx +++ b/Detectors/MUON/MCH/GlobalMapping/src/Slat.cxx @@ -12,7 +12,6 @@ #include "MCHConditions/DetectionElement.h" #include "MCHConditions/Number.h" #include "MCHConditions/SolarCrate.h" -#include "MCHGlobalMapping/DsIndex.h" #include "MCHRawElecMap/Mapper.h" #include "Slat.h" #include @@ -74,7 +73,7 @@ std::set lvAliasToCathode(std::string_view alias) return cathodes; } -std::set solarAliasToDsIndices(std::string_view alias) +std::set solarAliasToDsIndices(std::string_view alias) { /** For St345 the relation solar alias to dual sampas * is a bit more involved than for quadrants. @@ -85,7 +84,7 @@ std::set solarAliasToDsIndices(std::string_view alias) */ int solarCrate = aliasToSolarCrate(alias); static auto solarIds = raw::getSolarUIDs(); - std::set dsIndices; + std::set dsIndices; for (auto solarId : solarIds) { if (solarId / 8 == solarCrate) { auto dsDetIds = raw::getDualSampas(solarId); diff --git a/Detectors/MUON/MCH/GlobalMapping/src/Slat.h b/Detectors/MUON/MCH/GlobalMapping/src/Slat.h index e4eff8190f2c0..e936ed6aa3ab6 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/Slat.h +++ b/Detectors/MUON/MCH/GlobalMapping/src/Slat.h @@ -12,14 +12,15 @@ #ifndef O2_MCH_GLOBAL_MAPPING_SLAT_H #define O2_MCH_GLOBAL_MAPPING_SLAT_H -#include #include "MCHConditions/Cathode.h" +#include "MCHGlobalMapping/DsIndex.h" +#include #include namespace o2::mch::dcs::slat { std::set lvAliasToCathode(std::string_view alias); -std::set solarAliasToDsIndices(std::string_view alias); +std::set solarAliasToDsIndices(std::string_view alias); } // namespace o2::mch::dcs::slat #endif diff --git a/Detectors/MUON/MCH/GlobalMapping/src/global-mapper.cxx b/Detectors/MUON/MCH/GlobalMapping/src/global-mapper.cxx index 099053cb558f4..e981824bc3e09 100644 --- a/Detectors/MUON/MCH/GlobalMapping/src/global-mapper.cxx +++ b/Detectors/MUON/MCH/GlobalMapping/src/global-mapper.cxx @@ -13,6 +13,7 @@ #include "DataFormatsMCH/DsChannelId.h" #include "MCHConditions/DCSAliases.h" +#include "MCHGlobalMapping/DsIndex.h" #include "MCHGlobalMapping/Mapper.h" #include "MCHRawElecMap/DsDetId.h" #include "MCHRawElecMap/DsElecId.h" @@ -88,7 +89,7 @@ void dcs2json() o2::mch::dcs::MeasurementType::LV_V_FEE_ANALOG, o2::mch::dcs::MeasurementType::LV_V_SOLAR}); - std::map> dsIndicesPerAliasBase; + std::map> dsIndicesPerAliasBase; for (auto alias : aliases) { auto s = stripAlias(alias); @@ -121,13 +122,11 @@ void dcs2json() std::vector computeDualSampaInfos() { - uint16_t dsBin{0}; - auto elec2det = createElec2DetMapper(); auto det2elec = createDet2ElecMapper(); auto solar2FeeLink = createSolar2FeeLinkMapper(); - for (uint16_t dsIndex = 0; dsIndex < o2::mch::NumberOfDualSampas; ++dsIndex) { + for (o2::mch::DsIndex dsIndex = 0; dsIndex < o2::mch::NumberOfDualSampas; ++dsIndex) { DsDetId det{o2::mch::getDsDetId(dsIndex)}; auto elec = det2elec(det); if (!elec.has_value()) { @@ -209,6 +208,8 @@ void solar2json(bool mchview) if (mchview) { writer.Key("dsbin"); writer.Int(dsi.dsBinX); + writer.Key("dsIndex"); + writer.Int(dsi.dsBin); } else { writer.Key("binX"); writer.Int(dsi.dsBinX); diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.cxx b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.cxx index d79f953f5b323..e17c5457ca26e 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.cxx +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.cxx @@ -126,11 +126,11 @@ CathodeSegmentation::CathodeSegmentation( { fillRtree(); for (auto dualSampaId : mDualSampaIds) { - mDualSampaId2CatPadIndices.emplace(dualSampaId, getCatPadIndices(dualSampaId)); + mDualSampaId2CatPadIndices.emplace(dualSampaId, catPadIndices(dualSampaId)); } } -std::vector CathodeSegmentation::getCatPadIndices(int dualSampaId) const +std::vector CathodeSegmentation::catPadIndices(int dualSampaId) const { std::vector pi; @@ -147,6 +147,15 @@ std::vector CathodeSegmentation::getCatPadIndices(int dualSampaId) const return pi; } +std::vector CathodeSegmentation::getCatPadIndices(int dualSampaId) const +{ + auto it = mDualSampaId2CatPadIndices.find(dualSampaId); + if (it == mDualSampaId2CatPadIndices.end()) { + return {}; + } + return it->second; +} + std::vector CathodeSegmentation::getCatPadIndices(double xmin, double ymin, double xmax, double ymax) const diff --git a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.h b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.h index 3482bf6b3fbee..a20f341a7afb7 100644 --- a/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.h +++ b/Detectors/MUON/MCH/Mapping/Impl4/src/CathodeSegmentationImpl4.h @@ -48,7 +48,7 @@ class CathodeSegmentation std::vector> padSizes); /// Return the list of catPadIndices for the pads of the given dual sampa. - std::vector getCatPadIndices(int dualSampaIds) const; + std::vector getCatPadIndices(int dualSampaId) const; /// Return the list of catPadIndices for the pads contained in the box /// {xmin,ymin,xmax,ymax}. @@ -105,6 +105,8 @@ class CathodeSegmentation double squaredDistance(int catPadIndex, double x, double y) const; + std::vector catPadIndices(int dualSampaId) const; + private: int mSegType; bool mIsBendingPlane; diff --git a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.h b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.h index dfd0c391f56fa..320742718646c 100644 --- a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.h +++ b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.h @@ -78,7 +78,7 @@ class Segmentation * Validity of the returned value can be tested using isValid() */ ///@{ - /** Find the pads at position (x,y) (in cm). + /** Find the pads at position (x,y) (in cm). Returns true is the bpad and nbpad has been filled with a valid dePadIndex, false otherwise (if position is outside the segmentation area). @param bpad the dePadIndex of the bending pad at position (x,y) @@ -116,6 +116,9 @@ class Segmentation template void forEachPad(CALLABLE&& func) const; + template + void forEachPadInDualSampa(int dualSampaId, CALLABLE&& func) const; + template void forEachNeighbouringPad(int dePadIndex, CALLABLE&& func) const; @@ -123,9 +126,9 @@ class Segmentation void forEachPadInArea(double xmin, double ymin, double xmax, double ymax, CALLABLE&& func) const; ///@} - /** @name Access to individual cathode segmentations. - * Not needed in most cases. - */ + /** @name Access to individual cathode segmentations. + * Not needed in most cases. + */ ///@{ const CathodeSegmentation& bending() const; const CathodeSegmentation& nonBending() const; diff --git a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.inl b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.inl index 717ed8fb72128..76582bdb9b5bf 100644 --- a/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.inl +++ b/Detectors/MUON/MCH/Mapping/Interface/include/MCHMappingInterface/Segmentation.inl @@ -121,6 +121,20 @@ void Segmentation::forEachPad(CALLABLE&& func) const }); } +template +void Segmentation::forEachPadInDualSampa(int dualSampaId, CALLABLE&& func) const +{ + bool isBending = dualSampaId < 1024; + if (isBending) { + mBending.forEachPadInDualSampa(dualSampaId, func); + } else { + int offset{mPadIndexOffset}; + mNonBending.forEachPadInDualSampa(dualSampaId, [&offset, &func](int catPadIndex) { + func(catPadIndex + offset); + }); + } +} + template void Segmentation::forEachPadInArea(double xmin, double ymin, double xmax, double ymax, CALLABLE&& func) const { diff --git a/Detectors/MUON/MCH/README.md b/Detectors/MUON/MCH/README.md index 997ee3814d71c..af31c15a746cb 100644 --- a/Detectors/MUON/MCH/README.md +++ b/Detectors/MUON/MCH/README.md @@ -7,23 +7,25 @@ This is a top page for the MCH detector documentation. diff --git a/Detectors/MUON/MCH/Simulation/README.md b/Detectors/MUON/MCH/Simulation/README.md index 06f512d02020e..a04520141e327 100644 --- a/Detectors/MUON/MCH/Simulation/README.md +++ b/Detectors/MUON/MCH/Simulation/README.md @@ -1,3 +1,7 @@ + + # How to make a simulation including MCH ## Only MCH diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Hit.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Hit.h index d216654a36add..6382b60b48e8a 100644 --- a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Hit.h +++ b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Hit.h @@ -25,19 +25,25 @@ class Hit : public ::o2::BasicXYZEHit public: Hit(int trackId = 0, short detElemId = 0, math_utils::Point3D entrancePoint = {}, const math_utils::Point3D exitPoint = {}, - float eloss = 0.0, float length = 0.0, float tof = 0.0) - : ::o2::BasicXYZEHit(entrancePoint.x(), entrancePoint.y(), entrancePoint.z(), tof, eloss, trackId, detElemId), mLength{length}, mExitPoint(exitPoint) + float eloss = 0.0, float length = 0.0, float entranceTof = 0.0, float eTot = 0.0) + : ::o2::BasicXYZEHit(entrancePoint.x(), entrancePoint.y(), entrancePoint.z(), entranceTof, eloss, trackId, detElemId), mLength{length}, mExitPoint(exitPoint), mEtot{eTot} { } math_utils::Point3D entrancePoint() const { return GetPos(); } math_utils::Point3D exitPoint() const { return mExitPoint; } + // time in s + float entranceTof() const { return GetTime(); } + // particle energy in GeV + float eTot() const { return mEtot; } + short detElemId() const { return GetDetectorID(); } private: float mLength = {}; math_utils::Point3D mExitPoint = {}; + float mEtot = {}; ClassDefNV(Hit, 1); }; diff --git a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h index c9c46a846f2ea..09faf3af2e279 100644 --- a/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h +++ b/Detectors/MUON/MCH/Simulation/include/MCHSimulation/Response.h @@ -32,11 +32,12 @@ class Response public: Response(Station station); ~Response() = default; - float getChargeSpread() const { return mChargeSpread; } float getPitch() const { return mPitch; } float getSigmaIntegration() const { return mSigmaIntegration; } bool isAboveThreshold(float charge) const { return charge > mChargeThreshold; } + bool isAngleEffect() const { return mAngleEffect; } + bool isMagnetEffect() const { return mMagnetEffect; } /** Converts energy deposition into a charge. * @@ -65,6 +66,20 @@ class Response /// compute the number of samples corresponding to the charge in ADC units uint32_t nSamples(float charge) const; + /// compute deteriation of y-resolution due to track inclination and B-field + float inclandbfield(float thetawire, float betagamma, float bx) const; + + private: + MathiesonOriginal mMathieson{}; ///< Mathieson function + float mPitch = 0.f; ///< anode-cathode pitch (cm) + float mChargeSlope = 0.f; ///< charge slope used in E to charge conversion + float mChargeSpread = 0.f; ///< width of the charge distribution (cm) + float mSigmaIntegration = 0.f; ///< number of sigmas used for charge distribution + float mChargeCorr = 0.f; ///< amplitude of charge correlation between cathodes + float mChargeThreshold = 0.f; ///< minimum fraction of charge considered + bool mAngleEffect = true; ///< switch for angle effect influencing charge deposition + bool mMagnetEffect = true; ///< switch for magnetic field influencing charge deposition + /// Ratio of particle mean eloss with respect MIP's Khalil Boudjemline, sep 2003, PhD.Thesis and Particle Data Book float eLossRatio(float logbetagamma) const; /// ToDo: check Aliroot formula vs PDG, if really log_10 and not ln or bug in Aliroot @@ -74,22 +89,11 @@ class Response /// Angle effect: Normalisation form theta=10 degres to theta between 0 and 10 (Khalil BOUDJEMLINE sep 2003 Ph.D Thesis) /// Angle with respect to the wires assuming that chambers are perpendicular to the z axis. - float angleEffectNorma(float elossratio) const; + float angleEffectNorma(float angle) const; /// Magnetic field effect: Normalisation form theta=16 degres (eq. 10 degrees B=0) to theta between -20 and 20 (Lamia Benhabib jun 2006 ) /// Angle with respect to the wires assuming that chambers are perpendicular to the z axis. float magAngleEffectNorma(float angle, float bfield) const; - - private: - MathiesonOriginal mMathieson{}; ///< Mathieson function - float mPitch = 0.f; ///< anode-cathode pitch (cm) - float mChargeSlope = 0.f; ///< charge slope used in E to charge conversion - float mChargeSpread = 0.f; ///< width of the charge distribution (cm) - float mSigmaIntegration = 0.f; ///< number of sigmas used for charge distribution - float mChargeCorr = 0.f; ///< amplitude of charge correlation between cathodes - float mChargeThreshold = 0.f; ///< minimum fraction of charge considered - bool mAngleEffect = true; ///< switch for angle effect influencing charge deposition - bool mMagnetEffect = true; ///< switch for magnetic field influencing charge deposition }; } // namespace mch } // namespace o2 diff --git a/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx b/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx index 7cb6814226555..5078f464aabe5 100644 --- a/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx +++ b/Detectors/MUON/MCH/Simulation/src/DEDigitizer.cxx @@ -17,6 +17,8 @@ #include "DetectorsRaw/HBFUtils.h" #include "MCHSimulation/DigitizerParam.h" +#include +#include "Field/MagneticField.h" /// Convert collision time to ROF time (ROF duration = 4 BC) std::pair time2ROFtime(const o2::InteractionRecord& time) @@ -25,9 +27,11 @@ std::pair time2ROFtime(const o2::InteractionReco return std::make_pair(o2::InteractionRecord(time.bc - bc, time.orbit), bc); } +//_________________________________________________________________________________________________ + namespace o2::mch { - +//_________________________________________________________________________________________________ DEDigitizer::DEDigitizer(int deId, math_utils::Transform3D transformation, std::mt19937& random) : mDeId{deId}, mResponse{deId < 300 ? Station::Type1 : Station::Type2345}, @@ -78,6 +82,26 @@ void DEDigitizer::processHit(const Hit& hit, const InteractionRecord& collisionT auto localX = mResponse.getAnod(lpos.X()); auto localY = lpos.Y(); + // calculate angle between track and wire assuming wire perpendicular to z-axis + // take global coordinates to avoid issues with rotations of detection elements + // neglect rotation of chambers w.r.t. beam + auto thetawire = atan((exitPoint.Y() - entrancePoint.Y()) / (entrancePoint.Z() - exitPoint.Z())); + + // local b-field + double b[3] = {0., 0., 0.}; + double x[3] = {entrancePoint.X(), entrancePoint.Y(), entrancePoint.Z()}; + if (TGeoGlobalMagField::Instance()->GetField()) { + TGeoGlobalMagField::Instance()->Field(x, b); + } else { + LOG(fatal) << "no b field in MCH DEDigitizer"; + } + + // calculate track betagamma + // assume beta = 1 and mass of charged muon to calculate track betagamma from particle energy + auto betagamma = hit.eTot() / 0.1056583745; + auto yAngleEffect = mResponse.inclandbfield(thetawire, betagamma, b[0]); + localY += yAngleEffect; + // borders of charge integration area auto dxy = mResponse.getSigmaIntegration() * mResponse.getChargeSpread(); auto xMin = localX - dxy; diff --git a/Detectors/MUON/MCH/Simulation/src/Response.cxx b/Detectors/MUON/MCH/Simulation/src/Response.cxx index 5c990284eee71..9cc4956772edc 100644 --- a/Detectors/MUON/MCH/Simulation/src/Response.cxx +++ b/Detectors/MUON/MCH/Simulation/src/Response.cxx @@ -47,7 +47,6 @@ Response::Response(Station station) mChargeCorr = ResponseParam::Instance().chargeCorrelation; mChargeThreshold = ResponseParam::Instance().chargeThreshold; } - //_____________________________________________________________________ float Response::etocharge(float edepos) const { @@ -90,12 +89,49 @@ uint32_t Response::nSamples(float charge) const return std::round(std::pow(charge / signalParam[1], 1. / signalParam[2]) + signalParam[0]); } //_____________________________________________________________________ +float Response::inclandbfield(float thetawire, float betagamma, float bx) const +{ + float yAngleEffect = 0; + // auxiliary variables for b-field and inclination angle effect + float eLossParticleElossMip = 0.0; + float sigmaEffect10degrees = 0.0; + float sigmaEffectThetadegrees = 0.0; + + if (isAngleEffect()) { + if (!isMagnetEffect()) { + thetawire = abs(thetawire); + if ((betagamma > 3.2) && (thetawire * TMath::RadToDeg() <= 15.)) { + betagamma = log(betagamma); // check if ln or log10 + eLossParticleElossMip = eLossRatio(betagamma); + sigmaEffect10degrees = angleEffect10(eLossParticleElossMip); + sigmaEffectThetadegrees = sigmaEffect10degrees / angleEffectNorma(thetawire * TMath::RadToDeg()); + if (o2::mch::Station() == o2::mch::Station::Type1) { + sigmaEffectThetadegrees /= 1.09833 + 0.017 * (thetawire * TMath::RadToDeg()); + } + yAngleEffect = 0.0001 * gRandom->Gaus(0, sigmaEffectThetadegrees); // error due to the angle effect in cm + } + } else { + if ((betagamma > 3.2) && (abs(thetawire * TMath::RadToDeg()) <= 15.)) { + betagamma = log(betagamma); + eLossParticleElossMip = eLossRatio(betagamma); + sigmaEffect10degrees = angleEffect10(eLossParticleElossMip); + sigmaEffectThetadegrees = sigmaEffect10degrees / magAngleEffectNorma(thetawire * TMath::RadToDeg(), bx / 10.); // check b-field unit in aliroot and O2 + if (o2::mch::Station() == o2::mch::Station::Type1) { + sigmaEffectThetadegrees /= 1.09833 + 0.017 * (thetawire * TMath::RadToDeg()); + } + yAngleEffect = 0.0001 * gRandom->Gaus(0, sigmaEffectThetadegrees); + } + } + } + return yAngleEffect; +} +//_____________________________________________________________________ float Response::eLossRatio(float logbetagamma) const { // Ratio of particle mean eloss with respect MIP's Khalil Boudjemline, sep 2003, PhD.Thesis and Particle Data Book /// copied from aliroot AliMUONv1.cxx float eLossRatioParam[5] = {1.02138, -9.54149e-02, +7.83433e-02, -9.98208e-03, +3.83279e-04}; - return eLossRatioParam[0] + eLossRatioParam[1] * logbetagamma + eLossRatioParam[2] * std::pow(logbetagamma, 2) + eLossRatioParam[3] * std::pow(logbetagamma, 3) + eLossRatioParam[4] * std::pow(logbetagamma, 4); + return eLossRatioParam[0] + eLossRatioParam[1] * logbetagamma + eLossRatioParam[2] * logbetagamma * logbetagamma + eLossRatioParam[3] * logbetagamma * logbetagamma * logbetagamma + eLossRatioParam[4] * logbetagamma * logbetagamma * logbetagamma * logbetagamma; } //_____________________________________________________________________ float Response::angleEffect10(float elossratio) const @@ -103,16 +139,16 @@ float Response::angleEffect10(float elossratio) const /// Angle effect in tracking chambers at theta =10 degres as a function of ElossRatio (Khalil BOUDJEMLINE sep 2003 Ph.D Thesis) (in micrometers) /// copied from aliroot AliMUONv1.cxx float angleEffectParam[3] = {1.90691e+02, -6.62258e+01, 1.28247e+01}; - return angleEffectParam[0] + angleEffectParam[1] * elossratio + angleEffectParam[2] * std::pow(elossratio, 2); + return angleEffectParam[0] + angleEffectParam[1] * elossratio + angleEffectParam[2] * elossratio * elossratio; } //_____________________________________________________________________ -float Response::angleEffectNorma(float elossratio) const +float Response::angleEffectNorma(float angle) const { /// Angle effect: Normalisation form theta=10 degres to theta between 0 and 10 (Khalil BOUDJEMLINE sep 2003 Ph.D Thesis) /// Angle with respect to the wires assuming that chambers are perpendicular to the z axis. /// copied from aliroot AliMUONv1.cxx float angleEffectParam[4] = {4.148, -6.809e-01, 5.151e-02, -1.490e-03}; - return angleEffectParam[0] + angleEffectParam[1] * elossratio + angleEffectParam[2] * std::pow(elossratio, 2) + angleEffectParam[3] * std::pow(elossratio, 3); + return angleEffectParam[0] + angleEffectParam[1] * angle + angleEffectParam[2] * angle * angle + angleEffectParam[3] * angle * angle * angle; } //_____________________________________________________________________ float Response::magAngleEffectNorma(float angle, float bfield) const @@ -122,5 +158,5 @@ float Response::magAngleEffectNorma(float angle, float bfield) const /// copied from aliroot AliMUONv1.cxx float angleEffectParam[7] = {8.6995, 25.4022, 13.8822, 2.4717, 1.1551, -0.0624, 0.0012}; float aux = std::abs(angle - angleEffectParam[0] * bfield); - return 121.24 / ((angleEffectParam[1] + angleEffectParam[2] * std::abs(bfield)) + angleEffectParam[3] * aux + angleEffectParam[4] * std::pow(aux, 2) + angleEffectParam[5] * std::pow(aux, 3) + angleEffectParam[6] * std::pow(aux, 4)); + return 121.24 / ((angleEffectParam[1] + angleEffectParam[2] * std::abs(bfield)) + angleEffectParam[3] * aux + angleEffectParam[4] * aux * aux + angleEffectParam[5] * aux * aux * aux + angleEffectParam[6] * aux * aux * aux * aux); } diff --git a/Detectors/MUON/MCH/Simulation/src/Stepper.cxx b/Detectors/MUON/MCH/Simulation/src/Stepper.cxx index 744e3063aab9e..123a8eee0dba9 100644 --- a/Detectors/MUON/MCH/Simulation/src/Stepper.cxx +++ b/Detectors/MUON/MCH/Simulation/src/Stepper.cxx @@ -59,6 +59,7 @@ void Stepper::process(const TVirtualMC& vmc) if (t.isEntering()) { float x, y, z; vmc.TrackPosition(x, y, z); + mTof = (float)vmc.TrackTime(); mEntrancePoint.SetXYZ(x, y, z); resetStep(); } @@ -68,9 +69,11 @@ void Stepper::process(const TVirtualMC& vmc) if (t.isExiting() || t.isStopped()) { float x, y, z; + float etot; vmc.TrackPosition(x, y, z); + etot = (float)vmc.Etot(); mHits->emplace_back(stack->GetCurrentTrackNumber(), detElemId, mEntrancePoint, - math_utils::Point3D{x, y, z}, mTrackEloss, mTrackLength); + math_utils::Point3D{x, y, z}, mTrackEloss, mTrackLength, mTof, etot); resetStep(); } } diff --git a/Detectors/MUON/MCH/Simulation/src/Stepper.h b/Detectors/MUON/MCH/Simulation/src/Stepper.h index 26298ca8fa4de..9bab9c87e82e5 100644 --- a/Detectors/MUON/MCH/Simulation/src/Stepper.h +++ b/Detectors/MUON/MCH/Simulation/src/Stepper.h @@ -43,6 +43,7 @@ class Stepper private: float mTrackEloss{0.0}; float mTrackLength{0.0}; + float mTof{0.0}; std::vector* mHits{nullptr}; math_utils::Point3D mEntrancePoint; }; diff --git a/Detectors/MUON/MCH/Simulation/test/testDigitizer.cxx b/Detectors/MUON/MCH/Simulation/test/testDigitizer.cxx index 2a550220bb137..d300abdf65de1 100644 --- a/Detectors/MUON/MCH/Simulation/test/testDigitizer.cxx +++ b/Detectors/MUON/MCH/Simulation/test/testDigitizer.cxx @@ -28,7 +28,9 @@ #include "MCHSimulation/Hit.h" #include "SimulationDataFormat/MCCompLabel.h" #include "SimulationDataFormat/MCTruthContainer.h" +#include "Field/MagneticField.h" #include "TGeoManager.h" +#include "TGeoGlobalMagField.h" #include "boost/format.hpp" #include #include @@ -50,6 +52,20 @@ struct GEOMETRY { } }; +void initField(float l3Current, float dipoleCurrent) +{ + /// Create the magnetic field map if not already done + if (TGeoGlobalMagField::Instance()->GetField()) { + return; + } + + auto field = + o2::field::MagneticField::createFieldMap(l3Current, dipoleCurrent, o2::field::MagneticField::kConvLHC, false, 3500., + "A-A", "$(O2_ROOT)/share/Common/maps/mfchebKGI_sym.root"); + TGeoGlobalMagField::Instance()->SetField(field); + TGeoGlobalMagField::Instance()->Lock(); +} + namespace { short detElemId1 = 101; @@ -100,6 +116,8 @@ BOOST_AUTO_TEST_CASE(DigitizerTest) o2::conf::ConfigurableParam::setValue("MCHDigitizer", "seed", 123); o2::mch::Digitizer digitizer(transformation); + initField(-30000.0, -6000.0); + int trackId1 = 0; int trackId2 = 1; int trackId3 = 2; @@ -108,13 +126,14 @@ BOOST_AUTO_TEST_CASE(DigitizerTest) float eloss = 1.e-6; float length = 0.f; float tof = 0.f; + float energ = 10.0; std::vector hits1(2); - hits1.at(0) = o2::mch::Hit(trackId1, detElemId1, entrancePoint1, exitPoint1, eloss, length, tof); - hits1.at(1) = o2::mch::Hit(trackId2, detElemId2, entrancePoint2, exitPoint2, eloss, length, tof); + hits1.at(0) = o2::mch::Hit(trackId1, detElemId1, entrancePoint1, exitPoint1, eloss, length, tof, energ); + hits1.at(1) = o2::mch::Hit(trackId2, detElemId2, entrancePoint2, exitPoint2, eloss, length, tof, energ); std::vector hits2(1); - hits2.at(0) = o2::mch::Hit(trackId3, detElemId3, entrancePoint3, exitPoint3, eloss, length, tof); + hits2.at(0) = o2::mch::Hit(trackId3, detElemId3, entrancePoint3, exitPoint3, eloss, length, tof, energ); digitizer.processHits(hits1, collisionTime1, 0, 0); digitizer.processHits(hits2, collisionTime2, 0, 0); diff --git a/Detectors/MUON/MCH/Status/README.md b/Detectors/MUON/MCH/Status/README.md index dc2600d43c5c8..5e29dab124c87 100644 --- a/Detectors/MUON/MCH/Status/README.md +++ b/Detectors/MUON/MCH/Status/README.md @@ -1,3 +1,7 @@ + + # MCH StatusMap The status map is an object that list all pads that are not perfect, for some reason. Each such pad gets ascribed a `uint32_t` integer mask, representing the source of information that was used to decide that pad is bad. diff --git a/Detectors/MUON/MCH/Status/include/MCHStatus/StatusMap.h b/Detectors/MUON/MCH/Status/include/MCHStatus/StatusMap.h index 8d082f9fe34a9..7e7bb707588f5 100644 --- a/Detectors/MUON/MCH/Status/include/MCHStatus/StatusMap.h +++ b/Detectors/MUON/MCH/Status/include/MCHStatus/StatusMap.h @@ -13,6 +13,8 @@ #define O2_MCH_CONDITIONS_STATUSMAP_H #include "MCHGlobalMapping/ChannelCode.h" +#include "MCHGlobalMapping/DsIndex.h" +#include "MCHRawElecMap/DsDetId.h" #include "DataFormatsMCH/DsChannelId.h" #include #include @@ -29,12 +31,13 @@ namespace o2::mch * Each potentially bad channel is ascribed a 32-bits mask that indicate * the source of information used to incriminate it. * - * So far only two sources exist : + * So far only three sources exist : * - kBadPedestal : the list generated at each pedestal run at Pt2 * - kRejectList : a (manual) list + * - kBadHV : the list derived from the DCS HV values * * In the future (based on our experience during Run1,2), we'll most probably - * need to add information from the DCS HV (and possibly LV) values as well. + * need to add information from the DCS LV values as well. * */ class StatusMap @@ -43,7 +46,8 @@ class StatusMap enum Status : uint32_t { kOK = 0, kBadPedestal = 1 << 0, - kRejectList = 1 << 1 + kRejectList = 1 << 1, + kBadHV = 1 << 2 }; using iterator = std::map::iterator; @@ -67,6 +71,24 @@ class StatusMap */ void add(gsl::span badchannels, uint32_t mask); + /** add all the channels of the badDS referenced using DsIndex + * to this status map, assigning them the corresponding mask. + * @throw runtime_error if the mask is invalid + */ + void addDS(DsIndex badDS, uint32_t mask); + + /** add all the channels of the badDS referenced using DsDetId + * to this status map, assigning them the corresponding mask. + * @throw runtime_error if the mask is invalid + */ + void addDS(raw::DsDetId badDS, uint32_t mask); + + /** add all the channels of the badDE referenced using DE Id + * to this status map, assigning them the corresponding mask. + * @throw runtime_error if the mask is invalid + */ + void addDE(uint16_t badDE, uint32_t mask); + /** whether or not this statusmap contains no (potentially) bad channels */ bool empty() const { return mStatus.empty(); } diff --git a/Detectors/MUON/MCH/Status/src/StatusMap.cxx b/Detectors/MUON/MCH/Status/src/StatusMap.cxx index 40957186ba244..3a4d3bee0d617 100644 --- a/Detectors/MUON/MCH/Status/src/StatusMap.cxx +++ b/Detectors/MUON/MCH/Status/src/StatusMap.cxx @@ -10,7 +10,12 @@ // or submit itself to any jurisdiction. #include "MCHStatus/StatusMap.h" + +#include + #include "Framework/Logger.h" +#include "MCHConstants/DetectionElements.h" +#include "MCHMappingInterface/Segmentation.h" #include @@ -21,7 +26,7 @@ namespace o2::mch void assertValidMask(uint32_t mask) { - uint32_t maxMask = StatusMap::kBadPedestal + StatusMap::kRejectList; + static constexpr uint32_t maxMask = StatusMap::kBadPedestal | StatusMap::kRejectList | StatusMap::kBadHV; if (mask > maxMask) { throw std::runtime_error(fmt::format("invalid mask {} (max allowed is {}", mask, maxMask)); @@ -36,8 +41,8 @@ void StatusMap::add(gsl::span badchannels, uint32_t mask) ChannelCode cc(id.getSolarId(), id.getElinkId(), id.getChannel()); mStatus[cc] |= mask; } catch (const std::exception& e) { - // Catch exceptions thrown by the ChannelCode constructor - LOGP(warning, "Error processing channel - SolarId: {} ElinkId: {} Channel: {}. Error: {}. This channel is skipped.", id.getSolarId(), id.getElinkId(), id.getChannel(), e.what()); + LOGP(warning, "Error processing channel - SolarId: {} ElinkId: {} Channel: {}. Error: {}. This channel is skipped.", + id.getSolarId(), id.getElinkId(), id.getChannel(), e.what()); } } } @@ -50,6 +55,54 @@ void StatusMap::add(gsl::span badchannels, uint32_t mask) } } +void StatusMap::addDS(DsIndex badDS, uint32_t mask) +{ + if (badDS >= NumberOfDualSampas) { + LOGP(warning, "Error processing Dual Sampa - index: {}. This DS is skipped.", badDS); + return; + } + addDS(getDsDetId(badDS), mask); +} + +void StatusMap::addDS(raw::DsDetId badDS, uint32_t mask) +{ + assertValidMask(mask); + auto deId = badDS.deId(); + if (!constants::isValidDetElemId(deId)) { + LOGP(warning, "Error processing Dual Sampa - {}. This DS is skipped.", raw::asString(badDS)); + return; + } + const auto& seg = mapping::segmentation(deId); + seg.forEachPadInDualSampa(badDS.dsId(), [&](int dePadIndex) { + try { + ChannelCode cc(deId, dePadIndex); + mStatus[cc] |= mask; + } catch (const std::exception& e) { + LOGP(warning, "Error processing channel - {} padIndex: {}. Error: {}. This channel is skipped.", + raw::asString(badDS), dePadIndex, e.what()); + } + }); +} + +void StatusMap::addDE(uint16_t badDE, uint32_t mask) +{ + assertValidMask(mask); + if (!constants::isValidDetElemId(badDE)) { + LOGP(warning, "Error processing DE - Id: {}. This DE is skipped.", badDE); + return; + } + const auto& seg = mapping::segmentation(badDE); + seg.forEachPad([&](int dePadIndex) { + try { + ChannelCode cc(badDE, dePadIndex); + mStatus[cc] |= mask; + } catch (const std::exception& e) { + LOGP(warning, "Error processing channel - deId: {} padIndex: {}. Error: {}. This channel is skipped.", + badDE, dePadIndex, e.what()); + } + }); +} + uint32_t StatusMap::status(const ChannelCode& id) const { auto s = mStatus.find(id); diff --git a/Detectors/MUON/MCH/Status/src/testStatusMap.cxx b/Detectors/MUON/MCH/Status/src/testStatusMap.cxx index 3fd737ad06ede..2ab7ebba79dab 100644 --- a/Detectors/MUON/MCH/Status/src/testStatusMap.cxx +++ b/Detectors/MUON/MCH/Status/src/testStatusMap.cxx @@ -18,6 +18,7 @@ #include #include "MCHGlobalMapping/ChannelCode.h" +#include "MCHGlobalMapping/DsIndex.h" #include "MCHStatus/StatusMap.h" #include @@ -39,6 +40,12 @@ std::vector cc{ {1025, 8}, {515, 1863}}; +o2::mch::DsIndex ds = 246; // 56 pads, contains chid[1] + +uint16_t de = 1025; // 6976 pads, contains cc[2] + +uint32_t badMask = 1 << 3; + BOOST_AUTO_TEST_CASE(ClearShouldGiveEmptyMap) { o2::mch::StatusMap statusMap; @@ -50,21 +57,35 @@ BOOST_AUTO_TEST_CASE(ClearShouldGiveEmptyMap) BOOST_AUTO_TEST_CASE(AddChannelIdWithInvalidMaskShouldThrow) { o2::mch::StatusMap statusMap; - BOOST_CHECK_THROW(statusMap.add(chid, 4), std::runtime_error); + BOOST_CHECK_THROW(statusMap.add(chid, badMask), std::runtime_error); } BOOST_AUTO_TEST_CASE(AddChannelCodeWithInvalidMaskShouldThrow) { o2::mch::StatusMap statusMap; - BOOST_CHECK_THROW(statusMap.add(cc, 4), std::runtime_error); + BOOST_CHECK_THROW(statusMap.add(cc, badMask), std::runtime_error); } -std::array maskList = { +BOOST_AUTO_TEST_CASE(AddDSWithInvalidMaskShouldThrow) +{ + o2::mch::StatusMap statusMap; + BOOST_CHECK_THROW(statusMap.addDS(0, badMask), std::runtime_error); +} + +BOOST_AUTO_TEST_CASE(AddDEWithInvalidMaskShouldThrow) +{ + o2::mch::StatusMap statusMap; + BOOST_CHECK_THROW(statusMap.addDE(100, badMask), std::runtime_error); +} + +std::array maskList = { o2::mch::StatusMap::kBadPedestal, o2::mch::StatusMap::kRejectList, - o2::mch::StatusMap::kRejectList + o2::mch::StatusMap::kBadPedestal}; + o2::mch::StatusMap::kBadHV, + o2::mch::StatusMap::kBadPedestal | o2::mch::StatusMap::kBadHV, + o2::mch::StatusMap::kRejectList | o2::mch::StatusMap::kBadPedestal | o2::mch::StatusMap::kBadHV}; -BOOST_DATA_TEST_CASE(CheckAddedChannelsGetTheRightMask, bdata::xrange(maskList.size() + 1), maskIndex) +BOOST_DATA_TEST_CASE(CheckAddedChannelsGetTheRightMask, bdata::xrange(maskList.size()), maskIndex) { o2::mch::StatusMap statusMap; auto mask = maskList[maskIndex]; @@ -74,15 +95,62 @@ BOOST_DATA_TEST_CASE(CheckAddedChannelsGetTheRightMask, bdata::xrange(maskList.s } } +BOOST_AUTO_TEST_CASE(CheckChannelStatusCombination) +{ + auto size = [](const o2::mch::StatusMap& statusMap) { + int n = 0; + for (const auto& status : statusMap) { + ++n; + } + return n; + }; + o2::mch::StatusMap statusMap; + statusMap.add(cc, o2::mch::StatusMap::kBadPedestal); + BOOST_CHECK_EQUAL(size(statusMap), 4); + statusMap.add(chid, o2::mch::StatusMap::kRejectList); + BOOST_CHECK_EQUAL(size(statusMap), 4); + statusMap.addDS(ds, o2::mch::StatusMap::kBadHV); + BOOST_CHECK_EQUAL(size(statusMap), 59); + statusMap.addDE(de, o2::mch::StatusMap::kBadHV); + BOOST_CHECK_EQUAL(size(statusMap), 7034); + BOOST_CHECK_EQUAL(statusMap.status(cc[0]), o2::mch::StatusMap::kBadPedestal | o2::mch::StatusMap::kRejectList); + BOOST_CHECK_EQUAL(statusMap.status(cc[1]), o2::mch::StatusMap::kBadPedestal | o2::mch::StatusMap::kRejectList | o2::mch::StatusMap::kBadHV); + BOOST_CHECK_EQUAL(statusMap.status(cc[2]), o2::mch::StatusMap::kBadPedestal | o2::mch::StatusMap::kBadHV); + BOOST_CHECK_EQUAL(statusMap.status(cc[3]), o2::mch::StatusMap::kBadPedestal); +} + BOOST_AUTO_TEST_CASE(ApplyMaskShouldReturnASubsetDependingOnMask) { + auto size = [](const std::map>& badChannels) { + int n = 0; + for (const auto& channels : badChannels) { + n += channels.second.size(); + } + return n; + }; o2::mch::StatusMap statusMap; statusMap.add(cc, o2::mch::StatusMap::kBadPedestal); statusMap.add(chid, o2::mch::StatusMap::kRejectList); + statusMap.addDS(ds, o2::mch::StatusMap::kBadHV); + statusMap.addDE(de, o2::mch::StatusMap::kBadHV); auto badPed = applyMask(statusMap, o2::mch::StatusMap::kBadPedestal); auto rejectList = applyMask(statusMap, o2::mch::StatusMap::kRejectList); - auto all = applyMask(statusMap, o2::mch::StatusMap::kBadPedestal | o2::mch::StatusMap::kRejectList); - BOOST_CHECK_EQUAL(badPed.size(), cc.size()); - BOOST_CHECK_EQUAL(rejectList.size(), chid.size()); - BOOST_CHECK_EQUAL(all.size(), 4); + auto badHV = applyMask(statusMap, o2::mch::StatusMap::kBadHV); + auto badHVOrRL = applyMask(statusMap, o2::mch::StatusMap::kBadHV | o2::mch::StatusMap::kRejectList); + auto any = applyMask(statusMap, o2::mch::StatusMap::kBadPedestal | o2::mch::StatusMap::kRejectList | o2::mch::StatusMap::kBadHV); + BOOST_CHECK_EQUAL(badPed.size(), 4); + BOOST_CHECK_EQUAL(size(badPed), 4); + BOOST_CHECK_EQUAL(badPed[1025][0], 8); + BOOST_CHECK_EQUAL(rejectList.size(), 2); + BOOST_CHECK_EQUAL(size(rejectList), 2); + BOOST_CHECK_EQUAL(rejectList[100][0], 15665); + BOOST_CHECK_EQUAL(badHV.size(), 2); + BOOST_CHECK_EQUAL(size(badHV), 7032); + BOOST_CHECK_EQUAL(badHV[1025].size(), 6976); + BOOST_CHECK_EQUAL(badHVOrRL.size(), 3); + BOOST_CHECK_EQUAL(size(badHVOrRL), 7033); + BOOST_CHECK_EQUAL(badHVOrRL[515].size(), 0); + BOOST_CHECK_EQUAL(any.size(), 4); + BOOST_CHECK_EQUAL(size(any), 7034); + BOOST_CHECK_EQUAL(any[302][0], 20117); } diff --git a/Detectors/MUON/MID/README.md b/Detectors/MUON/MID/README.md index a7d6e0030a7ff..d3cc0f92d5f66 100644 --- a/Detectors/MUON/MID/README.md +++ b/Detectors/MUON/MID/README.md @@ -7,7 +7,9 @@ This is a top page for the MID detector documentation. + # TPC average distortion correction The average correction for TPC space charge distortions is based on residuals of TPC clusters with respect to global ITS-TPC-TRD-TOF tracks. diff --git a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/SpacePointsCalibConfParam.h b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/SpacePointsCalibConfParam.h index 1c5d88dbb67c6..2465cbf512d2b 100644 --- a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/SpacePointsCalibConfParam.h +++ b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/SpacePointsCalibConfParam.h @@ -25,8 +25,8 @@ namespace tpc // These are configurable params for the TPC space point calibration struct SpacePointsCalibConfParam : public o2::conf::ConfigurableParamHelper { - int maxTracksPerCalibSlot = 3'500'000; ///< the number of tracks which is required to obtain an average correction map - int additionalTracksITSTPC = 2'000'000; ///< will be added to maxTracksPerCalibSlot for track sample with uniform acceptance (no PHOS hole) + int maxTracksPerCalibSlot = 500'000; ///< the number of tracks which is required to obtain an average correction map + int additionalTracksMap = 3'500'000; ///< will be added to maxTracksPerCalibSlot for track sample with uniform acceptance (no PHOS hole) // define track cuts for track interpolation int minTPCNCls = 70; ///< min number of TPC clusters @@ -38,6 +38,7 @@ struct SpacePointsCalibConfParam : public o2::conf::ConfigurableParamHelper mTrackTimes{}; ///< time estimates for all input tracks in micro seconds std::vector mSeeds{}; ///< seeding track parameters (ITS tracks) std::map mTrackTypes; ///< mapping of track source to array index in mTrackIndices - std::array, 4> mTrackIndices; ///< keep GIDs of input tracks separately for each track type + std::array, 4> mTrackIndices; ///< keep GIDs of input tracks separately for each track type gsl::span mTPCTracksClusIdx; ///< input TPC cluster indices from span const ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices // ITS specific input only needed for debugging diff --git a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h index 819766573e26a..0c60e3cd6b94c 100644 --- a/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h +++ b/Detectors/TPC/calibration/SpacePoints/include/SpacePoints/TrackResiduals.h @@ -564,7 +564,7 @@ inline float TrackResiduals::getY2X(int ix, int ip) const if (mUniformBins[VoxF]) { return (0.5f + ip) * mDY2X[ix] - mMaxY2X[ix]; } - return mMaxY2X[ix] * (mY2XBinsCenter[ip] - mY2XBinsDH[ip]); + return mMaxY2X[ix] * mY2XBinsCenter[ip]; } //_____________________________________________________ diff --git a/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx b/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx index ea6fda70d92b9..a32bf17fcd1c5 100644 --- a/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx +++ b/Detectors/TPC/calibration/SpacePoints/src/TrackInterpolation.cxx @@ -38,7 +38,7 @@ using namespace o2::tpc; using GTrackID = o2::dataformats::GlobalTrackID; using DetID = o2::detectors::DetID; -void TrackInterpolation::init(o2::dataformats::GlobalTrackID::mask_t src) +void TrackInterpolation::init(o2::dataformats::GlobalTrackID::mask_t src, o2::dataformats::GlobalTrackID::mask_t srcMap) { // perform initialization LOG(info) << "Start initializing TrackInterpolation"; @@ -58,13 +58,16 @@ void TrackInterpolation::init(o2::dataformats::GlobalTrackID::mask_t src) mParams = &SpacePointsCalibConfParam::Instance(); mSourcesConfigured = src; + mSourcesConfiguredMap = srcMap; + mSingleSourcesConfigured = (mSourcesConfigured == mSourcesConfiguredMap); mTrackTypes.insert({GTrackID::ITSTPC, 0}); mTrackTypes.insert({GTrackID::ITSTPCTRD, 1}); mTrackTypes.insert({GTrackID::ITSTPCTOF, 2}); mTrackTypes.insert({GTrackID::ITSTPCTRDTOF, 3}); mInitDone = true; - LOGP(info, "Done initializing TrackInterpolation. Configured track input: {}", GTrackID::getSourcesNames(mSourcesConfigured)); + LOGP(info, "Done initializing TrackInterpolation. Configured track input: {}. Track input specifically for map: {}", + GTrackID::getSourcesNames(mSourcesConfigured), mSingleSourcesConfigured ? "identical" : GTrackID::getSourcesNames(mSourcesConfiguredMap)); } bool TrackInterpolation::isInputTrackAccepted(const GTrackID& gid, const o2::globaltracking::RecoContainer::GlobalIDSet& gidTable, const o2::dataformats::PrimaryVertex& pv) const @@ -114,19 +117,19 @@ bool TrackInterpolation::isInputTrackAccepted(const GTrackID& gid, const o2::glo return true; } -GTrackID::Source TrackInterpolation::findValidSource(GTrackID::Source src) const +GTrackID::Source TrackInterpolation::findValidSource(const GTrackID::mask_t mask, const GTrackID::Source src) const { - LOGP(debug, "Trying to find valid source for {}", GTrackID::getSourcesNames(src)); + LOGP(debug, "Trying to find valid source for {} in {}", GTrackID::getSourceName(src), GTrackID::getSourcesNames(mask)); if (src == GTrackID::ITSTPCTRDTOF) { - if (mSourcesConfigured[GTrackID::ITSTPCTRD]) { + if (mask[GTrackID::ITSTPCTRD]) { return GTrackID::ITSTPCTRD; - } else if (mSourcesConfigured[GTrackID::ITSTPC]) { + } else if (mask[GTrackID::ITSTPC]) { return GTrackID::ITSTPC; } else { return GTrackID::NSources; } } else if (src == GTrackID::ITSTPCTRD || src == GTrackID::ITSTPCTOF) { - if (mSourcesConfigured[GTrackID::ITSTPC]) { + if (mask[GTrackID::ITSTPC]) { return GTrackID::ITSTPC; } else { return GTrackID::NSources; @@ -146,12 +149,30 @@ void TrackInterpolation::prepareInputTrackSample(const o2::globaltracking::RecoC auto vtxRefs = mRecoCont->getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs int nv = vtxRefs.size() - 1; GTrackID::mask_t allowedSources = GTrackID::getSourcesMask("ITS-TPC,ITS-TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD-TOF"); + constexpr std::array SrcFast = {int(GTrackID::ITSTPCTRD), int(GTrackID::ITSTPCTOF), int(GTrackID::ITSTPCTRDTOF)}; for (int iv = 0; iv < nv; iv++) { LOGP(debug, "processing PV {} of {}", iv, nv); const auto& vtref = vtxRefs[iv]; auto pv = pvvec[iv]; + if (mParams->minTOFTRDPVContributors > 0) { // we want only PVs constrained by fast detectors + int nfound = 0; + bool usePV = false; + for (uint32_t is = 0; is < SrcFast.size() && !usePV; is++) { + int src = SrcFast[is], idMin = vtref.getFirstEntryOfSource(src), idMax = idMin + vtref.getEntriesOfSource(src); + for (int i = idMin; i < idMax; i++) { + if (trackIndex[i].isPVContributor() && (++nfound == mParams->minTOFTRDPVContributors)) { + usePV = true; + break; + } + } + } + if (!usePV) { + continue; + } + } + for (int is = GTrackID::NSources; is >= 0; is--) { if (!allowedSources[is]) { continue; @@ -169,9 +190,9 @@ void TrackInterpolation::prepareInputTrackSample(const o2::globaltracking::RecoC } auto gidTable = mRecoCont->getSingleDetectorRefs(vid); if (!mSourcesConfigured[is]) { - auto src = findValidSource(static_cast(vid.getSource())); + auto src = findValidSource(mSourcesConfigured, static_cast(vid.getSource())); if (src == GTrackID::ITSTPCTRD || src == GTrackID::ITSTPC) { - LOGP(debug, "Found valid source {}", GTrackID::getSourcesNames(src)); + LOGP(debug, "prepareInputTrackSample: Found valid source {}", GTrackID::getSourceName(src)); vid = gidTable[src]; gidTable = mRecoCont->getSingleDetectorRefs(vid); } else { @@ -241,7 +262,7 @@ void TrackInterpolation::process() // in blocks. std::random_device rd; std::mt19937 g(rd()); - std::vector trackIndices; // here we keep the GIDs for all track types in a single vector to use in loop + std::vector trackIndices; // here we keep the GIDs for all track types in a single vector to use in loop std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRDTOF]].end(), g); std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTRD]].end(), g); std::shuffle(mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPCTOF]].end(), g); @@ -252,12 +273,12 @@ void TrackInterpolation::process() trackIndices.insert(trackIndices.end(), mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].begin(), mTrackIndices[mTrackTypes[GTrackID::ITSTPC]].end()); int nSeeds = mSeeds.size(); - int maxOutputTracks = (mMaxTracksPerTF >= 0) ? mMaxTracksPerTF + mAddTracksITSTPC : nSeeds; + int maxOutputTracks = (mMaxTracksPerTF >= 0) ? mMaxTracksPerTF + mAddTracksForMapPerTF : nSeeds; mTrackData.reserve(maxOutputTracks); mClRes.reserve(maxOutputTracks * param::NPadRows); bool maxTracksReached = false; for (int iSeed = 0; iSeed < nSeeds; ++iSeed) { - if (mMaxTracksPerTF >= 0 && mTrackDataCompact.size() >= mMaxTracksPerTF + mAddTracksITSTPC) { + if (mMaxTracksPerTF >= 0 && mTrackDataCompact.size() >= mMaxTracksPerTF + mAddTracksForMapPerTF) { LOG(info) << "Maximum number of tracks per TF reached. Skipping the remaining " << nSeeds - iSeed << " tracks."; break; } @@ -265,6 +286,20 @@ void TrackInterpolation::process() if (mParams->enableTrackDownsampling && !isTrackSelected(mSeeds[seedIndex])) { continue; } + if (!mSingleSourcesConfigured && !mSourcesConfiguredMap[mGIDs[seedIndex].getSource()]) { + auto src = findValidSource(mSourcesConfiguredMap, static_cast(mGIDs[seedIndex].getSource())); + if (src == GTrackID::ITSTPCTRD || src == GTrackID::ITSTPC) { + LOGP(debug, "process: Found valid source {}", GTrackID::getSourceName(src)); + mGIDs.push_back(mGIDtables[seedIndex][src]); + mGIDtables.push_back(mRecoCont->getSingleDetectorRefs(mGIDs.back())); + mTrackTimes.push_back(mTrackTimes[seedIndex]); + mSeeds.push_back(mSeeds[seedIndex]); + } + } + if (mMaxTracksPerTF >= 0 && mTrackDataCompact.size() >= mMaxTracksPerTF) { + LOG(debug) << "We already have reached mMaxTracksPerTF, but we continue to create seeds until mAddTracksForMapPerTF is also reached"; + continue; + } if (mGIDs[seedIndex].includesDet(DetID::TRD) || mGIDs[seedIndex].includesDet(DetID::TOF)) { interpolateTrack(seedIndex); if (mProcessSeeds) { @@ -283,8 +318,16 @@ void TrackInterpolation::process() extrapolateTrack(seedIndex); } } + if (mSeeds.size() > nSeeds) { + LOGP(info, "Up to {} tracks out of {} additional seeds will be processed", mAddTracksForMapPerTF, mSeeds.size() - nSeeds); + } for (int iSeed = nSeeds; iSeed < (int)mSeeds.size(); ++iSeed) { + if (!mProcessSeeds && mAddTracksForMapPerTF > 0 && mTrackDataCompact.size() >= mMaxTracksPerTF + mAddTracksForMapPerTF) { + LOG(info) << "Maximum number of additional tracks per TF reached. Skipping the remaining " << mSeeds.size() - iSeed << " tracks."; + break; + } // this loop will only be entered in case mProcessSeeds is set + LOGP(debug, "Processing additional track {}", mGIDs[iSeed].asString()); if (mGIDs[iSeed].includesDet(DetID::TRD) || mGIDs[iSeed].includesDet(DetID::TOF)) { interpolateTrack(iSeed); } else { diff --git a/Detectors/TPC/calibration/SpacePoints/test/testTrackResiduals.cxx b/Detectors/TPC/calibration/SpacePoints/test/testTrackResiduals.cxx new file mode 100644 index 0000000000000..a5105329f8eb6 --- /dev/null +++ b/Detectors/TPC/calibration/SpacePoints/test/testTrackResiduals.cxx @@ -0,0 +1,61 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file testTrackResiduals.cxx +/// \brief perform functionality tests related to TPC average space charge distortion correction maps (currently only binning) +/// +/// \author Ole Schmidt, ole.schmidt@cern.ch + +#define BOOST_TEST_MODULE Test TrackResidualsTest class +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include +#include "SpacePoints/TrackResiduals.h" + +namespace o2::tpc +{ + +// testing default binning and custom binning +BOOST_AUTO_TEST_CASE(TrackResidualsBinning_test) +{ + TrackResiduals residUniform; + TrackResiduals residCustom; + residUniform.initBinning(); + + // fill uniform binning in Y/X manually + std::vector binY2X; + for (int iBin = 0; iBin <= residUniform.getNY2XBins(); ++iBin) { + binY2X.push_back(-1. + 2. / residUniform.getNY2XBins() * iBin); + } + residCustom.setY2XBinning(binY2X); + // fill uniform binning in Z/X manually + std::vector binZ2X; + for (int iBin = 0; iBin <= residUniform.getNZ2XBins(); ++iBin) { + binZ2X.push_back(1. / residUniform.getNZ2XBins() * iBin); + } + residCustom.setZ2XBinning(binZ2X); + residCustom.initBinning(); + + float x, p, z, xRef, pRef, zRef; + for (int ix = 0; ix < residUniform.getNXBins(); ++ix) { + for (int ip = 0; ip < residUniform.getNY2XBins(); ++ip) { + for (int iz = 0; iz < residUniform.getNZ2XBins(); ++iz) { + residUniform.getVoxelCoordinates(0, ix, ip, iz, xRef, pRef, zRef); + residCustom.getVoxelCoordinates(0, ix, ip, iz, x, p, z); + BOOST_CHECK_SMALL(x - xRef, 1e-6f); + BOOST_CHECK_SMALL(p - pRef, 1e-6f); + BOOST_CHECK_SMALL(z - zRef, 1e-6f); + } + } + } +} + +} // namespace o2::tpc diff --git a/Detectors/TPC/calibration/doc/README.md b/Detectors/TPC/calibration/doc/README.md index 919ca36a75bc6..48c5f5fa66230 100644 --- a/Detectors/TPC/calibration/doc/README.md +++ b/Detectors/TPC/calibration/doc/README.md @@ -1,8 +1,11 @@ # TPC Calibration diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalculatedEdx.h b/Detectors/TPC/calibration/include/TPCCalibration/CalculatedEdx.h index adcb2f4f76f9e..9a6cd8488f7c8 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalculatedEdx.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalculatedEdx.h @@ -83,7 +83,7 @@ class CalculatedEdx void setDebug(const bool debug) { mDebug = debug; } /// \param field magnetic field in kG, used for track propagation - void setField(const float field) { mField = field; } + void setFieldNominalGPUBz(const float field) { mFieldNominalGPUBz = field; } /// \param maxMissingCl maximum number of missing clusters for subthreshold check void setMaxMissingCl(int maxMissingCl) { mMaxMissingCl = maxMissingCl; } @@ -92,7 +92,7 @@ class CalculatedEdx void setStreamer() { mStreamer = std::make_unique("dEdxDebug.root", "recreate"); }; /// \return returns magnetic field in kG - float getField() { return mField; } + float getFieldNominalGPUBz() { return mFieldNominalGPUBz; } /// \return returns maxMissingCl for subthreshold cluster treatment int getMaxMissingCl() { return mMaxMissingCl; } @@ -144,7 +144,7 @@ class CalculatedEdx std::unique_ptr mRefit{nullptr}; ///< TPC refitter used for TPC tracks refit during the reconstruction int mMaxMissingCl{2}; ///< maximum number of missing clusters for subthreshold check - float mField{5}; ///< magnetic field in kG, used for track propagation + float mFieldNominalGPUBz{5}; ///< magnetic field in kG, used for track propagation bool mPropagateTrack{false}; ///< propagating the track instead of performing a refit bool mDebug{false}; ///< use the debug streamer CalibdEdxContainer mCalibCont; ///< calibration container diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h index cf77c69374f77..15c9a8648a796 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibLaserTracks.h @@ -161,6 +161,7 @@ class CalibLaserTracks int mTriggerPos{0}; ///< trigger position, if < 0 it treats it as the CE position float mBz{0.5}; ///< Bz field in Tesla float mDriftV{0}; ///< drift velocity used during reconstruction + float mTOffsetMUS{0}; ///< time offset in \mus to impose float mZbinWidth{0}; ///< width of a bin in us uint64_t mTFstart{0}; ///< start time of processed time frames uint64_t mTFend{0}; ///< end time of processed time frames diff --git a/Detectors/TPC/calibration/include/TPCCalibration/CalibPadGainTracks.h b/Detectors/TPC/calibration/include/TPCCalibration/CalibPadGainTracks.h index 0e28fe794a028..b3fd532c06b8e 100644 --- a/Detectors/TPC/calibration/include/TPCCalibration/CalibPadGainTracks.h +++ b/Detectors/TPC/calibration/include/TPCCalibration/CalibPadGainTracks.h @@ -104,7 +104,7 @@ class CalibPadGainTracks : public CalibPadGainTracksBase /// \param vTPCTracksArrayInp vector of tpc tracks /// \param tpcTrackClIdxVecInput set the TPCClRefElem member variable /// \param clIndex set the ClusterNativeAccess member variable - void setMembers(gsl::span* vTPCTracksArrayInp, gsl::span* tpcTrackClIdxVecInput, const o2::tpc::ClusterNativeAccess& clIndex); + void setMembers(gsl::span* vTPCTracksArrayInp, gsl::span* tpcTrackClIdxVecInput, const o2::tpc::ClusterNativeAccess& clIndex, gsl::span TPCRefitterShMap, gsl::span TPCRefitterOccMap); /// this function sets the mode of the class. /// e.g. mode=0 -> use the truncated mean from the track for normalizing the dedx @@ -134,7 +134,7 @@ class CalibPadGainTracks : public CalibPadGainTracksBase void setPropagateTrack(const bool propagate) { mPropagateTrack = propagate; } /// \param field magnetic field in kG, used for track propagation - void setField(const float field) { mField = field; } + void setFieldNominalGPUBz(const float field) { mFieldNominalGPUBz = field; } /// \param chargeType type of charge which is used for the dE/dx and the pad-by-pad histograms void setChargeType(const ChargeType chargeType) { mChargeType = chargeType; } @@ -176,7 +176,7 @@ class CalibPadGainTracks : public CalibPadGainTracksBase bool getPropagateTrack() const { return mPropagateTrack; } /// \return returns magnetic field which is used for propagation of track parameters - float getField() const { return mField; }; + float getFieldNominalGPUBz() const { return mFieldNominalGPUBz; }; /// dump object to disc /// \param outFileName name of the output file @@ -220,11 +220,12 @@ class CalibPadGainTracks : public CalibPadGainTracksBase gsl::span* mTracks{nullptr}; ///* mTPCTrackClIdxVecInput{nullptr}; /// mTPCRefitterShMap; /// mTPCRefitterOccMap; /// mBufVec; ///* tpcTrackClIdx void CalculatedEdx::setRefit() { - mRefit = std::make_unique(mClusterIndex, &mTPCCorrMapsHelper, mField, mTPCTrackClIdxVecInput->data(), nullptr, mTracks); + mRefit = std::make_unique(mClusterIndex, &mTPCCorrMapsHelper, mFieldNominalGPUBz, mTPCTrackClIdxVecInput->data(), 0, nullptr, nullptr, -1, mTracks); } void CalculatedEdx::fillMissingClusters(int missingClusters[4], float minChargeTot, float minChargeMax, int method) @@ -477,9 +478,9 @@ void CalculatedEdx::loadCalibsFromCCDB(long runNumberOrTimeStamp) // set the magnetic field auto magField = cm.get("GLO/Config/GRPMagField"); o2::base::Propagator::initFieldFromGRP(magField); - float bz = 5.00668f * magField->getL3Current() / 30000.; + float bz = GPUO2InterfaceUtils::getNominalGPUBz(*magField); LOGP(info, "Magnetic field: {}", bz); - setField(bz); + setFieldNominalGPUBz(bz); // set the propagator auto propagator = o2::base::Propagator::Instance(); diff --git a/Detectors/TPC/calibration/src/CalibLaserTracks.cxx b/Detectors/TPC/calibration/src/CalibLaserTracks.cxx index 81e3d9f99dde5..1e4218c527f02 100644 --- a/Detectors/TPC/calibration/src/CalibLaserTracks.cxx +++ b/Detectors/TPC/calibration/src/CalibLaserTracks.cxx @@ -16,6 +16,7 @@ #include "MathUtils/Utils.h" #include "TPCBase/ParameterGas.h" #include "TPCBase/ParameterElectronics.h" +#include "TPCBase/ParameterDetector.h" #include "TPCCalibration/CalibLaserTracks.h" #include "TLinearFitter.h" #include @@ -239,8 +240,10 @@ void CalibLaserTracks::updateParameters() { const auto& gasParam = ParameterGas::Instance(); const auto& electronicsParam = ParameterElectronics::Instance(); + const auto& detpar = o2::tpc::ParameterDetector::Instance(); mDriftV = gasParam.DriftV; mZbinWidth = electronicsParam.ZbinWidth; + mTOffsetMUS = detpar.DriftTimeOffset * mZbinWidth; } //______________________________________________________________________________ @@ -335,6 +338,8 @@ void CalibLaserTracks::fillCalibData(LtrCalibData& calibData, const std::vector< calibData.dvOffsetC = dvC.x1; calibData.dvCorrectionC = dvC.x2; calibData.nTracksC = uint16_t(pairsC.size()); + + calibData.refTimeOffset = mTOffsetMUS; } //______________________________________________________________________________ diff --git a/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx b/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx index 97927107d56a9..93cdb7c47ee37 100644 --- a/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx +++ b/Detectors/TPC/calibration/src/CalibPadGainTracks.cxx @@ -37,10 +37,7 @@ void CalibPadGainTracks::processTracks(const int nMaxTracks) { std::unique_ptr refit; if (!mPropagateTrack) { - mBufVec.resize(mClusterIndex->nClustersTotal); - o2::gpu::GPUO2InterfaceRefit::fillSharedClustersMap(mClusterIndex, *mTracks, mTPCTrackClIdxVecInput->data(), mBufVec.data()); - mClusterShMapTPC = mBufVec.data(); - refit = std::make_unique(mClusterIndex, mTPCCorrMapsHelper, mField, mTPCTrackClIdxVecInput->data(), mClusterShMapTPC); + refit = std::make_unique(mClusterIndex, mTPCCorrMapsHelper, mFieldNominalGPUBz, mTPCTrackClIdxVecInput->data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size()); } const size_t loopEnd = (nMaxTracks < 0) ? mTracks->size() : ((nMaxTracks > mTracks->size()) ? mTracks->size() : size_t(nMaxTracks)); @@ -310,11 +307,13 @@ void CalibPadGainTracks::dumpToFile(const char* outFileName, const char* outName fOut.Close(); } -void CalibPadGainTracks::setMembers(gsl::span* vTPCTracksArrayInp, gsl::span* tpcTrackClIdxVecInput, const o2::tpc::ClusterNativeAccess& clIndex) +void CalibPadGainTracks::setMembers(gsl::span* vTPCTracksArrayInp, gsl::span* tpcTrackClIdxVecInput, const o2::tpc::ClusterNativeAccess& clIndex, gsl::span TPCRefitterShMap, gsl::span TPCRefitterOccMap) { mTracks = vTPCTracksArrayInp; mTPCTrackClIdxVecInput = tpcTrackClIdxVecInput; mClusterIndex = &clIndex; + mTPCRefitterShMap = TPCRefitterShMap; + mTPCRefitterOccMap = TPCRefitterOccMap; } void CalibPadGainTracks::setMomentumRange(const float momMin, const float momMax) diff --git a/Detectors/TPC/calibration/src/TPCVDriftTglCalibration.cxx b/Detectors/TPC/calibration/src/TPCVDriftTglCalibration.cxx index c4134a6f856ab..61f0d816e1c11 100644 --- a/Detectors/TPC/calibration/src/TPCVDriftTglCalibration.cxx +++ b/Detectors/TPC/calibration/src/TPCVDriftTglCalibration.cxx @@ -28,6 +28,7 @@ using Slot = o2::calibration::TimeSlot; using clbUtils = o2::calibration::Utils; float TPCVDTglContainer::driftVRef = 0.f; +float TPCVDTglContainer::tOffsetRef = 0.f; //_____________________________________________ void TPCVDriftTglCalibration::initOutput() @@ -89,7 +90,8 @@ void TPCVDriftTglCalibration::finalizeSlot(Slot& slot) std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), corrFact, corrFactErr, - float(cont->driftVFullMean)}); + float(cont->driftVFullMean), + cont->tOffsetRef, 0.f}); // at this stage the correction object is defined wrt average corrected drift used for the slot processing, we want to redefine it to run-constant reference vdrift vd.normalize(cont->driftVRef); diff --git a/Detectors/TPC/calibration/src/VDriftHelper.cxx b/Detectors/TPC/calibration/src/VDriftHelper.cxx index f114084b215b8..fb262acc1afa1 100644 --- a/Detectors/TPC/calibration/src/VDriftHelper.cxx +++ b/Detectors/TPC/calibration/src/VDriftHelper.cxx @@ -32,7 +32,7 @@ VDriftHelper::VDriftHelper() const auto& elpar = o2::tpc::ParameterElectronics::Instance(); mVD.corrFact = 1.0; mVD.refVDrift = gaspar.DriftV; - mVD.refTimeOffset = detpar.DriftTimeOffset / elpar.ZbinWidth; + mVD.refTimeOffset = detpar.DriftTimeOffset * elpar.ZbinWidth; // convert time bins to \mus // was it imposed from the command line? mVD.creationTime = 1; // just to be above 0 if (o2::conf::ConfigurableParam::getProvenance("TPCGasParam.DriftV") == o2::conf::ConfigurableParam::EParamProvenance::kRT) { // we stick to this value @@ -57,6 +57,10 @@ void VDriftHelper::accountLaserCalibration(const LtrCalibData* calib, long fallB if (!calib || mForceParamDrift) { // laser may set only DriftParam (the offset is 0) return; } + if (!calib->isValid()) { + LOGP(warn, "Ignoring invalid laser calibration (corrections: A-side={}, C-side={}, NTracks: A-side={} C-side={})", calib->dvCorrectionA, calib->dvCorrectionC, calib->nTracksA, calib->nTracksC); + return; + } // old entries of laser calib have no update time assigned long updateTS = calib->creationTime > 0 ? calib->creationTime : fallBackTimeStamp; LOG(info) << "accountLaserCalibration " << calib->refVDrift << " / " << calib->getDriftVCorrection() << " t " << updateTS << " vs " << mVDLaser.creationTime; @@ -69,6 +73,7 @@ void VDriftHelper::accountLaserCalibration(const LtrCalibData* calib, long fallB mVDLaser.refVDrift = ref; mVDLaser.corrFact = 1. / corr; mVDLaser.creationTime = calib->creationTime; + mVDLaser.refTimeOffset = calib->refTimeOffset; mUpdated = true; mSource = Source::Laser; if (mMayRenormSrc & (0x1U << Source::Laser)) { // this was 1st setting? @@ -79,7 +84,7 @@ void VDriftHelper::accountLaserCalibration(const LtrCalibData* calib, long fallB mMayRenormSrc &= ~(0x1U << Source::Laser); // unset MayRenorm } else if (ref != prevRef) { // we want to keep the same reference over the run, this may happen if run-time laser calibration is supplied LOGP(warn, "VDriftHelper: renorming updated TPC refVDrift={}/correction={} previous refVDrift {}, source: {}", mVDLaser.refVDrift, mVDLaser.corrFact, prevRef, getSourceName(mSource)); - mVDLaser.normalizeOffset(prevRef); + mVDLaser.normalize(prevRef); } } } @@ -134,6 +139,8 @@ void VDriftHelper::extractCCDBInputs(ProcessingContext& pc, bool laser, bool its // prefer among laser and tgl VDrift the one with the latest update time auto saveVD = mVD; mVD = mVDTPCITSTgl.creationTime < mVDLaser.creationTime ? mVDLaser : mVDTPCITSTgl; + auto& loserVD = mVDTPCITSTgl.creationTime < mVDLaser.creationTime ? mVDTPCITSTgl : mVDLaser; + if (mForceParamDrift) { mVD.refVDrift = saveVD.refVDrift; mVD.corrFact = saveVD.corrFact; @@ -144,13 +151,20 @@ void VDriftHelper::extractCCDBInputs(ProcessingContext& pc, bool laser, bool its mVD.timeOffsetCorr = 0.f; } mSource = mVDTPCITSTgl.creationTime < mVDLaser.creationTime ? Source::Laser : Source::ITSTPCTgl; - LOGP(info, "Will prefer TPC Drift from {} with time {} to {} with time {}", - SourceNames[int(mSource)], mVD.creationTime, - mSource == Source::Laser ? SourceNames[int(Source::ITSTPCTgl)] : SourceNames[int(Source::Laser)], - mSource == Source::Laser ? mVDTPCITSTgl.creationTime : mVDLaser.creationTime); + auto loseCTime = loserVD.creationTime; + loserVD = mVD; // override alternative VD to avoid normalization problems later + loserVD.creationTime = loseCTime; + std::string rep = fmt::format("Prefer TPC Drift from {} with time {} to {} with time {}", + SourceNames[int(mSource)], mVD.creationTime, mSource == Source::Laser ? SourceNames[int(Source::ITSTPCTgl)] : SourceNames[int(Source::Laser)], + mSource == Source::Laser ? mVDTPCITSTgl.creationTime : mVDLaser.creationTime); if (mForceParamDrift || mForceParamOffset) { - LOGP(info, "but {} is imposed from the command line", mForceParamDrift ? "VDrift" : "DriftTimeOffset"); + std::string impos = mForceParamDrift ? "VDrift" : ""; + if (mForceParamOffset) { + impos += mForceParamDrift ? " and DriftTimeOffset" : "DriftTimeOffset"; + } + rep += fmt::format(" but {} imposed from command line", impos); } + LOGP(info, "{}", rep); } } diff --git a/Detectors/TPC/qc/include/TPCQC/PID.h b/Detectors/TPC/qc/include/TPCQC/PID.h index 35bab481f6f10..3dc4db891823b 100644 --- a/Detectors/TPC/qc/include/TPCQC/PID.h +++ b/Detectors/TPC/qc/include/TPCQC/PID.h @@ -70,7 +70,7 @@ class PID // To set the elementary track cuts void setPIDCuts(int minnCls = 60, float absTgl = 1., float mindEdxTot = 10.0, - float maxdEdxTot = 70., float minpTPC = 0.05, float maxpTPC = 20., float minpTPCMIPs = 0.45, float maxpTPCMIPs = 0.55) + float maxdEdxTot = 70., float minpTPC = 0.05, float maxpTPC = 20., float minpTPCMIPs = 0.45, float maxpTPCMIPs = 0.55, bool turnOffHistosForAsync = false) { mCutMinnCls = minnCls; mCutAbsTgl = absTgl; @@ -80,6 +80,7 @@ class PID mCutMaxpTPC = maxpTPC; mCutMinpTPCMIPs = minpTPCMIPs; mCutMaxpTPCMIPs = maxpTPCMIPs; + mTurnOffHistosForAsync = turnOffHistosForAsync; } void setCreateCanvas(int createCanvas = 1) { @@ -91,15 +92,16 @@ class PID const std::unordered_map>>& getMapOfCanvas() const { return mMapCanvas; } private: - int mCutMinnCls = 60; // minimum N clusters - float mCutAbsTgl = 1.f; // AbsTgl max cut - float mCutMindEdxTot = 10.f; // dEdxTot min value - float mCutMaxdEdxTot = 70.f; // dEdxTot max value - float mCutMinpTPC = 0.05f; // pTPC min value - float mCutMaxpTPC = 20.f; // pTPC max value - float mCutMinpTPCMIPs = 0.45f; // pTPC min value for MIPs - float mCutMaxpTPCMIPs = 0.55f; // pTPC max value for MIPs - bool mCreateCanvas = true; // Decide whether to create the TCanvas Object as it cannot be merged + int mCutMinnCls = 60; // minimum N clusters + float mCutAbsTgl = 1.f; // AbsTgl max cut + float mCutMindEdxTot = 10.f; // dEdxTot min value + float mCutMaxdEdxTot = 70.f; // dEdxTot max value + float mCutMinpTPC = 0.05f; // pTPC min value + float mCutMaxpTPC = 20.f; // pTPC max value + float mCutMinpTPCMIPs = 0.45f; // pTPC min value for MIPs + float mCutMaxpTPCMIPs = 0.55f; // pTPC max value for MIPs + bool mCreateCanvas = true; // Decide whether to create the TCanvas Object as it cannot be merged + bool mTurnOffHistosForAsync = false; // Decide whether to turn off some histograms for async to reduce memory std::unordered_map>> mMapHist; // Map for Canvases to be published std::unordered_map>> mMapCanvas; diff --git a/Detectors/TPC/qc/include/TPCQC/Tracks.h b/Detectors/TPC/qc/include/TPCQC/Tracks.h index 419511753b6cf..882e7c9222c29 100644 --- a/Detectors/TPC/qc/include/TPCQC/Tracks.h +++ b/Detectors/TPC/qc/include/TPCQC/Tracks.h @@ -69,13 +69,14 @@ class Tracks // To set the elementary track cuts void setTrackCuts(float AbsEta = 1., - int nClusterCut = 60, float dEdxTot = 20, float cutPtForDCAr = 1.5, float samplingFractionDCAr = 0.1) + int nClusterCut = 60, float dEdxTot = 20, float cutPtForDCAr = 1.5, float samplingFractionDCAr = 0.1, bool turnOffHistosForAsync = false) { mCutAbsEta = AbsEta; mCutMinnCls = nClusterCut; mCutMindEdxTot = dEdxTot; mCutMinPtDCAr = cutPtForDCAr; mSamplingFractionDCAr = samplingFractionDCAr; + mTurnOffHistosForAsync = turnOffHistosForAsync; } // Just for backward compatibility with crrent QC, temporary, will be removed in the next PR @@ -98,11 +99,12 @@ class Tracks const std::unordered_map>& getMapHist() const { return mMapHist; } private: - float mCutAbsEta = 1.f; // Eta cut - int mCutMinnCls = 60; // minimum N clusters - float mCutMindEdxTot = 20.f; // dEdxTot min value - float mCutMinPtDCAr = 1.5f; // minimum pT for DCAr plots DCAr vs. phi, eta, nCluster - float mSamplingFractionDCAr = 0.1f; // sampling rate for calculation of DCAr + float mCutAbsEta = 1.f; // Eta cut + int mCutMinnCls = 60; // minimum N clusters + float mCutMindEdxTot = 20.f; // dEdxTot min value + float mCutMinPtDCAr = 1.5f; // minimum pT for DCAr plots DCAr vs. phi, eta, nCluster + float mSamplingFractionDCAr = 0.1f; // sampling rate for calculation of DCAr + bool mTurnOffHistosForAsync = false; // Decide whether to turn off some histograms for async to reduce memory std::unordered_map> mMapHist; std::vector mHist1D{}; ///< Initialize vector of 1D histograms std::vector mHist2D{}; ///< Initialize vector of 2D histograms diff --git a/Detectors/TPC/qc/src/PID.cxx b/Detectors/TPC/qc/src/PID.cxx index 4c2028eec92cd..482ab83acd6a4 100644 --- a/Detectors/TPC/qc/src/PID.cxx +++ b/Detectors/TPC/qc/src/PID.cxx @@ -41,57 +41,61 @@ constexpr std::array xks{90.f, 108.475f, 151.7f, 188.8f, 227.65f}; const std::vector rocNames{"TPC", "IROC", "OROC1", "OROC2", "OROC3"}; const std::vector nclCuts{60, 25, 14, 12, 10}; const std::vector nclMax{152, 63, 34, 30, 25}; -const binning binsdEdxTot{2000, 0., 6000.}; -const binning binsdEdxMax{2000, 0., 2000.}; const int mipTot = 50; const int mipMax = 50; const binning binsdEdxMIPTot{100, mipTot / 3., mipTot * 3.}; const binning binsdEdxMIPMax{100, mipMax / 3., mipMax * 3.}; -const binning binsSec{36, 0., 36.}; +const int binsPerSector = 5; +const binning binsSec{36 * binsPerSector, 0., 36.}; const auto bins = o2::tpc::qc::helpers::makeLogBinning(200, 0.05, 20); +const int binNumber = 200; +const float binsdEdxTot_MaxValue = 6000.; +const auto binsdEdxTot_Log = o2::tpc::qc::helpers::makeLogBinning(binNumber, 5, binsdEdxTot_MaxValue); +const auto binsdEdxMax_Log = o2::tpc::qc::helpers::makeLogBinning(binNumber, 5, 2000); //______________________________________________________________________________ void PID::initializeHistograms() { TH1::AddDirectory(false); const auto& name = rocNames[0]; - mMapHist["hdEdxTotVspPos"].emplace_back(std::make_unique(fmt::format("hdEdxTotVsP_Pos_{}", name).data(), (fmt::format("Q_{{Tot}} positive particles {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 200, bins.data(), binsdEdxTot.bins, binsdEdxTot.min, binsdEdxTot.max)); - mMapHist["hdEdxTotVspNeg"].emplace_back(std::make_unique(fmt::format("hdEdxTotVsP_Neg_{}", name).data(), (fmt::format("Q_{{Tot}} negative particles {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 200, bins.data(), binsdEdxTot.bins, binsdEdxTot.min, binsdEdxTot.max)); + mMapHist["hdEdxTotVspPos"].emplace_back(std::make_unique(fmt::format("hdEdxTotVsP_Pos_{}", name).data(), (fmt::format("Q_{{Tot}} positive particles {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 200, bins.data(), binNumber, binsdEdxTot_Log.data())); + mMapHist["hdEdxTotVspNeg"].emplace_back(std::make_unique(fmt::format("hdEdxTotVsP_Neg_{}", name).data(), (fmt::format("Q_{{Tot}} negative particles {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 200, bins.data(), binNumber, binsdEdxTot_Log.data())); mMapHist["hNClsPID"].emplace_back(std::make_unique("hNClsPID", "Number of clusters (after cuts); # of clusters; counts", 160, 0, 160)); mMapHist["hNClsSubPID"].emplace_back(std::make_unique("hNClsSubPID", "Number of clusters (after cuts); # of clusters; counts", 160, 0, 160)); - mMapHist["hdEdxVsPhi"].emplace_back(std::make_unique("hdEdxVsPhi", "dEdx (a.u.) vs #phi (rad); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 300, 0, 300)); mMapHist["hdEdxVsTgl"].emplace_back(std::make_unique("hdEdxVsTgl", "dEdx (a.u.) vs tan#lambda; tan#lambda; dEdx (a.u.)", 60, -2, 2, 300, 0, 300)); - mMapHist["hdEdxVsncls"].emplace_back(std::make_unique("hdEdxVsncls", "dEdx (a.u.) vs ncls; ncls; dEdx (a.u.)", 80, 0, 160, 300, 0, 300)); const auto logPtBinning = helpers::makeLogBinning(200, 0.05, 20); if (logPtBinning.size() > 0) { - mMapHist["hdEdxTotVspBeforeCuts"].emplace_back(std::make_unique("hdEdxTotVspBeforeCuts", "dEdx (a.u.) vs p (GeV/#it{c}) (before cuts); p (GeV/#it{c}); dEdx (a.u.)", logPtBinning.size() - 1, logPtBinning.data(), 500, 0, 1000)); - mMapHist["hdEdxMaxVspBeforeCuts"].emplace_back(std::make_unique("hdEdxMaxVspBeforeCuts", "dEdx_Max (a.u.) vs p (GeV/#it{c}) (before cuts); p (GeV/#it{c}); dEdx (a.u.)", logPtBinning.size() - 1, logPtBinning.data(), 500, 0, 1000)); + mMapHist["hdEdxTotVspBeforeCuts"].emplace_back(std::make_unique("hdEdxTotVspBeforeCuts", "dEdx (a.u.) vs p (GeV/#it{c}) (before cuts); p (GeV/#it{c}); dEdx (a.u.)", logPtBinning.size() - 1, logPtBinning.data(), binNumber, binsdEdxTot_Log.data())); + mMapHist["hdEdxMaxVspBeforeCuts"].emplace_back(std::make_unique("hdEdxMaxVspBeforeCuts", "dEdx_Max (a.u.) vs p (GeV/#it{c}) (before cuts); p (GeV/#it{c}); dEdx (a.u.)", logPtBinning.size() - 1, logPtBinning.data(), binNumber, binsdEdxMax_Log.data())); + } + if (!mTurnOffHistosForAsync) { + mMapHist["hdEdxVsPhiMipsAside"].emplace_back(std::make_unique("hdEdxVsPhiMipsAside", "dEdx (a.u.) vs #phi (rad) of MIPs (A side); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 25, 35, 60)); + mMapHist["hdEdxVsPhiMipsCside"].emplace_back(std::make_unique("hdEdxVsPhiMipsCside", "dEdx (a.u.) vs #phi (rad) of MIPs (C side); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 25, 35, 60)); + mMapHist["hdEdxVsPhi"].emplace_back(std::make_unique("hdEdxVsPhi", "dEdx (a.u.) vs #phi (rad); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 300, 0, 300)); + mMapHist["hdEdxVsncls"].emplace_back(std::make_unique("hdEdxVsncls", "dEdx (a.u.) vs ncls; ncls; dEdx (a.u.)", 80, 0, 160, 300, 0, 300)); } - - mMapHist["hdEdxVsPhiMipsAside"].emplace_back(std::make_unique("hdEdxVsPhiMipsAside", "dEdx (a.u.) vs #phi (rad) of MIPs (A side); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 25, 35, 60)); - mMapHist["hdEdxVsPhiMipsCside"].emplace_back(std::make_unique("hdEdxVsPhiMipsCside", "dEdx (a.u.) vs #phi (rad) of MIPs (C side); #phi (rad); dEdx (a.u.)", 180, 0., 2 * M_PI, 25, 35, 60)); for (size_t idEdxType = 0; idEdxType < rocNames.size(); ++idEdxType) { const auto& name = rocNames[idEdxType]; - mMapHist["hdEdxTotVsp"].emplace_back(std::make_unique(fmt::format("hdEdxTotVsP_{}", name).data(), (fmt::format("Q_{{Tot}} {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 200, bins.data(), binsdEdxTot.bins, binsdEdxTot.min, binsdEdxTot.max)); - mMapHist["hdEdxMaxVsp"].emplace_back(std::make_unique(fmt::format("hdEdxMaxVsP_{}", name).data(), (fmt::format("Q_{{Max}} {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Max} (arb. unit)").data(), 200, bins.data(), binsdEdxMax.bins, binsdEdxMax.min, binsdEdxMax.max)); + mMapHist["hdEdxTotVsp"].emplace_back(std::make_unique(fmt::format("hdEdxTotVsP_{}", name).data(), (fmt::format("Q_{{Tot}} {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 200, bins.data(), binNumber, binsdEdxTot_Log.data())); + mMapHist["hdEdxMaxVsp"].emplace_back(std::make_unique(fmt::format("hdEdxMaxVsP_{}", name).data(), (fmt::format("Q_{{Max}} {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Max} (arb. unit)").data(), 200, bins.data(), binNumber, binsdEdxMax_Log.data())); mMapHist["hdEdxTotMIP"].emplace_back(std::make_unique(fmt::format("hdEdxTotMIP_{}", name).data(), (fmt::format("MIP Q_{{Tot}} {}", name) + ";d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), binsdEdxMIPTot.bins, binsdEdxMIPTot.min, binsdEdxMIPTot.max)); mMapHist["hdEdxMaxMIP"].emplace_back(std::make_unique(fmt::format("hdEdxMaxMIP_{}", name).data(), (fmt::format("MIP Q_{{Max}} {}", name) + ";d#it{E}/d#it{x}_{Max} (arb. unit)").data(), binsdEdxMIPMax.bins, binsdEdxMIPMax.min, binsdEdxMIPMax.max)); mMapHist["hdEdxTotMIPVsTgl"].emplace_back(std::make_unique(fmt::format("hdEdxTotMIPVsTgl_{}", name).data(), (fmt::format("MIP Q_{{Tot}} {}", name) + ";#tan(#lambda);d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 50, -2, 2, binsdEdxMIPTot.bins, binsdEdxMIPTot.min, binsdEdxMIPTot.max)); mMapHist["hdEdxMaxMIPVsTgl"].emplace_back(std::make_unique(fmt::format("hdEdxMaxMIPVsTgl_{}", name).data(), (fmt::format("MIP Q_{{Max}} {}", name) + ";#tan(#lambda);d#it{E}/d#it{x}_{Max} (arb. unit)").data(), 50, -2, 2, binsdEdxMIPMax.bins, binsdEdxMIPMax.min, binsdEdxMIPMax.max)); mMapHist["hdEdxTotMIPVsSnp"].emplace_back(std::make_unique(fmt::format("hdEdxTotMIPVsSnp_{}", name).data(), (fmt::format("MIP Q_{{Tot}} {}", name) + ";#sin(#phi);d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 50, -1, 1, binsdEdxMIPTot.bins, binsdEdxMIPTot.min, binsdEdxMIPTot.max)); mMapHist["hdEdxMaxMIPVsSnp"].emplace_back(std::make_unique(fmt::format("hdEdxMaxMIPVsSnp_{}", name).data(), (fmt::format("MIP Q_{{Max}} {}", name) + ";#sin(#phi);d#it{E}/d#it{x}_{Max} (arb. unit)").data(), 50, -1, 1, binsdEdxMIPMax.bins, binsdEdxMIPMax.min, binsdEdxMIPMax.max)); - mMapHist["hdEdxTotMIPVsNcl"].emplace_back(std::make_unique(fmt::format("hdEdxTotMIPVsNcl_{}", name).data(), (fmt::format("MIP Q_{{Tot}} {}", name) + ";N_{clusters};d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), nclMax[idEdxType], 0, nclMax[idEdxType], binsdEdxMIPTot.bins, binsdEdxMIPTot.min, binsdEdxMIPTot.max)); - mMapHist["hdEdxMaxMIPVsNcl"].emplace_back(std::make_unique(fmt::format("hdEdxMaxMIPVsNcl_{}", name).data(), (fmt::format("MIP Q_{{Max}} {}", name) + ";N_{clusters};d#it{E}/d#it{x}_{Max} (arb. unit)").data(), nclMax[idEdxType], 0, nclMax[idEdxType], binsdEdxMIPMax.bins, binsdEdxMIPMax.min, binsdEdxMIPMax.max)); + mMapHist["hdEdxTotMIPVsNcl"].emplace_back(std::make_unique(fmt::format("hdEdxTotMIPVsNcl_{}", name).data(), (fmt::format("MIP Q_{{Tot}} {}", name) + ";N_{clusters};d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), nclMax[idEdxType] - nclCuts[idEdxType], nclCuts[idEdxType], nclMax[idEdxType], binsdEdxMIPTot.bins, binsdEdxMIPTot.min, binsdEdxMIPTot.max)); + mMapHist["hdEdxMaxMIPVsNcl"].emplace_back(std::make_unique(fmt::format("hdEdxMaxMIPVsNcl_{}", name).data(), (fmt::format("MIP Q_{{Max}} {}", name) + ";N_{clusters};d#it{E}/d#it{x}_{Max} (arb. unit)").data(), nclMax[idEdxType] - nclCuts[idEdxType], nclCuts[idEdxType], nclMax[idEdxType], binsdEdxMIPMax.bins, binsdEdxMIPMax.min, binsdEdxMIPMax.max)); mMapHist["hdEdxTotMIPVsSec"].emplace_back(std::make_unique(fmt::format("hdEdxTotMIPVsSec_{}", name).data(), (fmt::format("MIP Q_{{Tot}} {}", name) + ";sector;d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), binsSec.bins, binsSec.min, binsSec.max, binsdEdxMIPTot.bins, binsdEdxMIPTot.min, binsdEdxMIPTot.max)); mMapHist["hdEdxMaxMIPVsSec"].emplace_back(std::make_unique(fmt::format("hdEdxMaxMIPVsSec_{}", name).data(), (fmt::format("MIP Q_{{Max}} {}", name) + ";sector;d#it{E}/d#it{x}_{Max} (arb. unit)").data(), binsSec.bins, binsSec.min, binsSec.max, binsdEdxMIPMax.bins, binsdEdxMIPMax.min, binsdEdxMIPMax.max)); - mMapHist["hMIPNclVsTgl"].emplace_back(std::make_unique(fmt::format("hMIPNclVsTgl_{}", name).data(), (fmt::format("rec. clusters {}", name) + ";#tan(#lambda);d#it{E}/d#it{x}_{Max} (arb. unit)").data(), 50, -2, 2, nclMax[idEdxType], 0, nclMax[idEdxType])); - mMapHist["hMIPNclVsTglSub"].emplace_back(std::make_unique(fmt::format("hMIPNclVsTglSub_{}", name).data(), (fmt::format("rec. + sub-thrs. clusters {}", name) + ";#tan(#lambda);d#it{E}/d#it{x}_{Max} (arb. unit)").data(), 50, -2, 2, nclMax[idEdxType], 0, nclMax[idEdxType])); + mMapHist["hMIPNclVsTgl"].emplace_back(std::make_unique(fmt::format("hMIPNclVsTgl_{}", name).data(), (fmt::format("rec. clusters {}", name) + ";#tan(#lambda); rec clusters").data(), 50, -2, 2, nclMax[idEdxType] - nclCuts[idEdxType], nclCuts[idEdxType], nclMax[idEdxType])); + mMapHist["hMIPNclVsTglSub"].emplace_back(std::make_unique(fmt::format("hMIPNclVsTglSub_{}", name).data(), (fmt::format("sub-thrs. clusters {}", name) + ";#tan(#lambda);sub-thrs. clusters").data(), 50, -2, 2, 20, 0, 20)); if (mCreateCanvas) { - mMapHistCanvas["hdEdxVspHypoPos"].emplace_back(std::make_unique(fmt::format("hdEdxVspHypoPos_{}", name).data(), (fmt::format("Q_{{Tot}} Pos {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 200, bins.data(), binsdEdxTot.bins, binsdEdxTot.min, binsdEdxTot.max)); - mMapHistCanvas["hdEdxVspHypoNeg"].emplace_back(std::make_unique(fmt::format("hdEdxVspHypoNeg_{}", name).data(), (fmt::format("Q_{{Tot}} Neg {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 200, bins.data(), binsdEdxTot.bins, binsdEdxTot.min, binsdEdxTot.max)); + mMapHistCanvas["hdEdxVspHypoPos"].emplace_back(std::make_unique(fmt::format("hdEdxVspHypoPos_{}", name).data(), (fmt::format("Q_{{Tot}} Pos {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 200, bins.data(), binNumber, binsdEdxTot_Log.data())); + mMapHistCanvas["hdEdxVspHypoNeg"].emplace_back(std::make_unique(fmt::format("hdEdxVspHypoNeg_{}", name).data(), (fmt::format("Q_{{Tot}} Neg {}", name) + ";#it{p} (GeV/#it{c});d#it{E}/d#it{x}_{Tot} (arb. unit)").data(), 200, bins.data(), binNumber, binsdEdxTot_Log.data())); } } if (mCreateCanvas) { @@ -133,7 +137,7 @@ bool PID::processTrack(const o2::tpc::TrackTPC& track, size_t nTracks) const auto ncl = uint8_t(track.getNClusters()); const auto eta = track.getEta(); - mMapHist["hdEdxTotVspBeforeCuts"][0]->Fill(phi, dEdx.dEdxTotTPC); + mMapHist["hdEdxTotVspBeforeCuts"][0]->Fill(pTPC, dEdx.dEdxTotTPC); mMapHist["hdEdxMaxVspBeforeCuts"][0]->Fill(pTPC, dEdx.dEdxMaxTPC); if (pTPC < mCutMinpTPC || pTPC > mCutMaxpTPC || ncl < mCutMinnCls) { @@ -143,15 +147,17 @@ bool PID::processTrack(const o2::tpc::TrackTPC& track, size_t nTracks) const std::vector dEdxTot{dEdx.dEdxTotTPC, dEdx.dEdxTotIROC, dEdx.dEdxTotOROC1, dEdx.dEdxTotOROC2, dEdx.dEdxTotOROC3}; const std::vector dEdxMax{dEdx.dEdxMaxTPC, dEdx.dEdxMaxIROC, dEdx.dEdxMaxOROC1, dEdx.dEdxMaxOROC2, dEdx.dEdxMaxOROC3}; const std::vector dEdxNcl{static_cast(dEdx.NHitsIROC + dEdx.NHitsOROC1 + dEdx.NHitsOROC2 + dEdx.NHitsOROC3), dEdx.NHitsIROC, dEdx.NHitsOROC1, dEdx.NHitsOROC2, dEdx.NHitsOROC3}; - const std::vector dEdxNclSub{static_cast(dEdx.NHitsSubThresholdIROC + dEdx.NHitsSubThresholdOROC1 + dEdx.NHitsSubThresholdOROC2 + dEdx.NHitsSubThresholdOROC3), dEdx.NHitsSubThresholdIROC, dEdx.NHitsSubThresholdOROC1, dEdx.NHitsSubThresholdOROC2, dEdx.NHitsSubThresholdOROC3}; + const std::vector dEdxNclSub{static_cast(dEdx.NHitsSubThresholdIROC + dEdx.NHitsSubThresholdOROC1 + dEdx.NHitsSubThresholdOROC2 + dEdx.NHitsSubThresholdOROC3 - (dEdx.NHitsIROC + dEdx.NHitsOROC1 + dEdx.NHitsOROC2 + dEdx.NHitsOROC3)), static_cast(dEdx.NHitsSubThresholdIROC - dEdx.NHitsIROC), static_cast(dEdx.NHitsSubThresholdOROC1 - dEdx.NHitsOROC1), static_cast(dEdx.NHitsSubThresholdOROC2 - dEdx.NHitsOROC2), static_cast(dEdx.NHitsSubThresholdOROC3 - dEdx.NHitsOROC3)}; mMapHist["hdEdxVsTgl"][0]->Fill(tgl, dEdxTot[0]); if (dEdx.dEdxTotTPC <= 0.) { return true; } if (std::abs(tgl) < mCutAbsTgl) { - mMapHist["hdEdxVsPhi"][0]->Fill(phi, dEdxTot[0]); - mMapHist["hdEdxVsncls"][0]->Fill(ncl, dEdxTot[0]); + if (!mTurnOffHistosForAsync) { + mMapHist["hdEdxVsPhi"][0]->Fill(phi, dEdxTot[0]); + mMapHist["hdEdxVsncls"][0]->Fill(ncl, dEdxTot[0]); + } mMapHist["hNClsPID"][0]->Fill(dEdxNcl[0]); mMapHist["hNClsSubPID"][0]->Fill(dEdxNclSub[0]); @@ -171,7 +177,7 @@ bool PID::processTrack(const o2::tpc::TrackTPC& track, size_t nTracks) sec = -1; } - if (dEdxTot[idEdxType] < mCutMindEdxTot || dEdxTot[idEdxType] > binsdEdxTot.max || dEdxNcl[idEdxType] < nclCuts[idEdxType]) { + if (dEdxTot[idEdxType] < mCutMindEdxTot || dEdxTot[idEdxType] > binsdEdxTot_MaxValue || dEdxNcl[idEdxType] < nclCuts[idEdxType]) { continue; } if (std::abs(tgl) < mCutAbsTgl) { @@ -197,10 +203,12 @@ bool PID::processTrack(const o2::tpc::TrackTPC& track, size_t nTracks) } if (std::abs(tgl) < mCutAbsTgl) { - if (track.hasASideClustersOnly()) { - mMapHist["hdEdxVsPhiMipsAside"][0]->Fill(phi, dEdxTot[0]); - } else if (track.hasCSideClustersOnly()) { - mMapHist["hdEdxVsPhiMipsCside"][0]->Fill(phi, dEdxTot[0]); + if (!mTurnOffHistosForAsync) { + if (track.hasASideClustersOnly()) { + mMapHist["hdEdxVsPhiMipsAside"][0]->Fill(phi, dEdxTot[0]); + } else if (track.hasCSideClustersOnly()) { + mMapHist["hdEdxVsPhiMipsCside"][0]->Fill(phi, dEdxTot[0]); + } } mMapHist["hdEdxTotMIP"][idEdxType]->Fill(dEdxTot[idEdxType]); diff --git a/Detectors/TPC/qc/src/TrackClusters.cxx b/Detectors/TPC/qc/src/TrackClusters.cxx index 20ac2af500ba8..bcc071920e2e9 100644 --- a/Detectors/TPC/qc/src/TrackClusters.cxx +++ b/Detectors/TPC/qc/src/TrackClusters.cxx @@ -44,7 +44,6 @@ void TrackClusters::initializeHistograms() { TH1::AddDirectory(false); mMapHist["sharedClusters"].emplace_back(std::make_unique("sharedClusters", "sharedClusters;NSharedClusters;Entries", binsSharedClusters.bins, binsSharedClusters.min, binsSharedClusters.max)); - mMapHist["foundClusters"].emplace_back(std::make_unique("foundClusters", "foundClusters;foundClusters;Entries", binsFoundClusters.bins, binsFoundClusters.min, binsFoundClusters.max)); mMapHist["crossedRows"].emplace_back(std::make_unique("crossedRows", "crossedRows;crossedRows;Entries", binsCrossedRows.bins, binsCrossedRows.min, binsCrossedRows.max)); } @@ -65,7 +64,7 @@ bool TrackClusters::processTrackAndClusters(const std::vector std::vector mBufVec; mBufVec.resize(clusterIndex->nClustersTotal); - o2::gpu::GPUO2InterfaceRefit::fillSharedClustersMap(clusterIndex, *tracks, clusRefs->data(), mBufVec.data()); + o2::gpu::GPUO2InterfaceRefit::fillSharedClustersAndOccupancyMap(clusterIndex, *tracks, clusRefs->data(), mBufVec.data()); for (auto const& track : (*tracks)) { const auto dEdxTot = track.getdEdx().dEdxTotTPC; @@ -81,7 +80,6 @@ bool TrackClusters::processTrackAndClusters(const std::vector o2::TrackMethods::countTPCClusters(track, *clusRefs, mBufVec, *clusterIndex, shared, found, crossed); mMapHist["sharedClusters"][0]->Fill(shared); - mMapHist["foundClusters"][0]->Fill(found); mMapHist["crossedRows"][0]->Fill(crossed); } diff --git a/Detectors/TPC/qc/src/Tracking.cxx b/Detectors/TPC/qc/src/Tracking.cxx index d836f5d378093..e5773804105ce 100644 --- a/Detectors/TPC/qc/src/Tracking.cxx +++ b/Detectors/TPC/qc/src/Tracking.cxx @@ -28,6 +28,7 @@ #include "DataFormatsTPC/TrackTPC.h" #include "TPCQC/Tracking.h" #include "GPUO2InterfaceQA.h" +#include "GPUO2InterfaceUtils.h" #include "GPUO2InterfaceConfiguration.h" #include "CommonUtils/NameConf.h" #include "DataFormatsParameters/GRPObject.h" @@ -49,7 +50,7 @@ void Tracking::initialize(outputModes outputMode, bool postprocessOnly) mQAConfig = std::make_unique(); const auto grp = o2::parameters::GRPObject::loadFrom(); if (grp) { - mQAConfig->configGRP.solenoidBz = 5.00668f * grp->getL3Current() / 30000.; + mQAConfig->configGRP.solenoidBzNominalGPU = GPUO2InterfaceUtils::getNominalGPUBz(*grp); mQAConfig->configGRP.continuousMaxTimeBin = grp->isDetContinuousReadOut(o2::detectors::DetID::TPC) ? -1 : 0; } else { throw std::runtime_error("Failed to initialize run parameters from GRP"); diff --git a/Detectors/TPC/qc/src/Tracks.cxx b/Detectors/TPC/qc/src/Tracks.cxx index c8f16a63d2f1d..c42f35bd24644 100644 --- a/Detectors/TPC/qc/src/Tracks.cxx +++ b/Detectors/TPC/qc/src/Tracks.cxx @@ -29,8 +29,18 @@ ClassImp(o2::tpc::qc::Tracks); using namespace o2::tpc::qc; +struct binning { + int bins; + double min; + double max; +}; // DCA histograms const std::vector types{"A_Pos", "A_Neg", "C_Pos", "C_Neg"}; +const binning binsDCAr{200, -5., 5.}; +const binning binsDCArLargerRange{400, -10., 10.}; +const binning binsEta{200, -1., 1.}; +const binning binsClus{120, 60., 180.}; +const binning binsClusLargerRange{140, 60., 200.}; //______________________________________________________________________________ void Tracks::initializeHistograms() { @@ -38,67 +48,69 @@ void Tracks::initializeHistograms() TH1::AddDirectory(false); const auto logPtBinning = helpers::makeLogBinning(100, 0.05, 20); // 1d hitograms - mMapHist["hNClustersBeforeCuts"] = std::make_unique("hNClustersBeforeCuts", "Number of clusters (before cuts);# TPC clusters", 400, -0.5, 399.5); - mMapHist["hNClustersAfterCuts"] = std::make_unique("hNClustersAfterCuts", "Number of clusters;# TPC clusters", 400, -0.5, 399.5); - mMapHist["hEta"] = std::make_unique("hEta", "Pseudorapidity;#eta", 400, -2., 2.); + mMapHist["hNClustersBeforeCuts"] = std::make_unique("hNClustersBeforeCuts", "Number of clusters (before cuts);# TPC clusters", binsClus.max, 0, binsClus.max); + mMapHist["hNClustersAfterCuts"] = std::make_unique("hNClustersAfterCuts", "Number of clusters;# TPC clusters", binsClus.bins, binsClus.min, binsClus.max); + mMapHist["hEta"] = std::make_unique("hEta", "Pseudorapidity;#eta", binsEta.bins, binsEta.min, binsEta.max); mMapHist["hPhiAside"] = std::make_unique("hPhiAside", "Azimuthal angle, A side;#phi", 360, 0., 2 * M_PI); mMapHist["hPhiCside"] = std::make_unique("hPhiCside", "Azimuthal angle, C side;#phi", 360, 0., 2 * M_PI); mMapHist["hPt"] = std::make_unique("hPt", "Transverse momentum;#it{p}_{T} (GeV/#it{c})", logPtBinning.size() - 1, logPtBinning.data()); mMapHist["hSign"] = std::make_unique("hSign", "Sign of electric charge;charge sign", 3, -1.5, 1.5); - mMapHist["hEtaNeg"] = std::make_unique("hEtaNeg", "Pseudorapidity, neg. tracks;#eta", 400, -2., 2.); - mMapHist["hEtaPos"] = std::make_unique("hEtaPos", "Pseudorapidity, pos. tracks;#eta", 400, -2., 2.); - mMapHist["hPhiAsideNeg"] = std::make_unique("hPhiAsideNeg", "Azimuthal angle, A side, neg. tracks;#phi", 360, 0., 2 * M_PI); - mMapHist["hPhiAsidePos"] = std::make_unique("hPhiAsidePos", "Azimuthal angle, A side, pos. tracks;#phi", 360, 0., 2 * M_PI); - mMapHist["hPhiCsideNeg"] = std::make_unique("hPhiCsideNeg", "Azimuthal angle, C side, neg. tracks;#phi", 360, 0., 2 * M_PI); - mMapHist["hPhiCsidePos"] = std::make_unique("hPhiCsidePos", "Azimuthal angle, C side, pos. tracks;#phi", 360, 0., 2 * M_PI); - mMapHist["hPtNeg"] = std::make_unique("hPtNeg", "Transverse momentum, neg. tracks;#it{p}_{T} (GeV/#it{c})", logPtBinning.size() - 1, logPtBinning.data()); - mMapHist["hPtPos"] = std::make_unique("hPtPos", "Transverse momentum, pos. tracks;#it{p}_{T} (GeV/#it{c})", logPtBinning.size() - 1, logPtBinning.data()); + if (!mTurnOffHistosForAsync) { + mMapHist["hEtaNeg"] = std::make_unique("hEtaNeg", "Pseudorapidity, neg. tracks;#eta", binsEta.bins, binsEta.min, binsEta.max); + mMapHist["hEtaPos"] = std::make_unique("hEtaPos", "Pseudorapidity, pos. tracks;#eta", binsEta.bins, binsEta.min, binsEta.max); + mMapHist["hPhiAsideNeg"] = std::make_unique("hPhiAsideNeg", "Azimuthal angle, A side, neg. tracks;#phi", 360, 0., 2 * M_PI); + mMapHist["hPhiAsidePos"] = std::make_unique("hPhiAsidePos", "Azimuthal angle, A side, pos. tracks;#phi", 360, 0., 2 * M_PI); + mMapHist["hPhiCsideNeg"] = std::make_unique("hPhiCsideNeg", "Azimuthal angle, C side, neg. tracks;#phi", 360, 0., 2 * M_PI); + mMapHist["hPhiCsidePos"] = std::make_unique("hPhiCsidePos", "Azimuthal angle, C side, pos. tracks;#phi", 360, 0., 2 * M_PI); + // 1d ratio histograms + mMapHist["hEtaRatio"] = std::make_unique("hEtaRatio", "Pseudorapidity, ratio neg./pos.;#eta", binsEta.bins, binsEta.min, binsEta.max); + mMapHist["hPhiAsideRatio"] = std::make_unique("hPhiAsideRatio", "Azimuthal angle, A side, ratio neg./pos.;#phi", 360, 0., 2 * M_PI); + mMapHist["hPhiCsideRatio"] = std::make_unique("hPhiCsideRatio", "Azimuthal angle, C side, ratio neg./pos.;#phi", 360, 0., 2 * M_PI); + mMapHist["hPtRatio"] = std::make_unique("hPtRatio", "Transverse momentum, ratio neg./pos. ;#it{p}_{T}", logPtBinning.size() - 1, logPtBinning.data()); + mMapHist["hPhiBothSides"] = std::make_unique("hPhiBothSides", "Azimuthal angle, both sides clusters;#phi", 360, 0., 2 * M_PI); + mMapHist["hPtNeg"] = std::make_unique("hPtNeg", "Transverse momentum, neg. tracks;#it{p}_{T} (GeV/#it{c})", logPtBinning.size() - 1, logPtBinning.data()); + mMapHist["hPtPos"] = std::make_unique("hPtPos", "Transverse momentum, pos. tracks;#it{p}_{T} (GeV/#it{c})", logPtBinning.size() - 1, logPtBinning.data()); + } mMapHist["hEtaBeforeCuts"] = std::make_unique("hEtaBeforeCuts", "Pseudorapidity (before cuts);#eta", 400, -2., 2.); mMapHist["hPtBeforeCuts"] = std::make_unique("hPtBeforeCuts", "Transverse momentum (before cuts);#it{p}_{T} (GeV/#it{c})", logPtBinning.size() - 1, logPtBinning.data()); mMapHist["hQOverPt"] = std::make_unique("hQOverPt", "Charge over transverse momentum;q/#it{p}_{T}", 400, -20., 20.); - mMapHist["hPhiBothSides"] = std::make_unique("hPhiBothSides", "Azimuthal angle, both sides clusters;#phi", 360, 0., 2 * M_PI); // 2d histograms - mMapHist["h2DNClustersEta"] = std::make_unique("h2DNClustersEta", "Number of clusters vs. #eta;#eta;# TPC clusters", 400, -2., 2., 200, -0.5, 199.5); - mMapHist["h2DNClustersPhiAside"] = std::make_unique("h2DNClustersPhiAside", "Number of clusters vs. #phi, A side ;#phi;# TPC clusters", 360, 0., 2 * M_PI, 200, -0.5, 199.5); - mMapHist["h2DNClustersPhiCside"] = std::make_unique("h2DNClustersPhiCside", "Number of clusters vs. #phi, C side ;#phi;# TPC clusters", 360, 0., 2 * M_PI, 200, -0.5, 199.5); - mMapHist["h2DNClustersPt"] = std::make_unique("h2DNClustersPt", "Number of clusters vs. #it{p}_{T};#it{p}_{T} (GeV/#it{c});# TPC clusters", logPtBinning.size() - 1, logPtBinning.data(), 200, -0.5, 199.5); - mMapHist["h2DEtaPhi"] = std::make_unique("h2DEtaPhi", "Tracks in #eta vs. #phi;#phi;#eta", 360, 0., 2 * M_PI, 400, -2., 2.); - mMapHist["h2DEtaPhiNeg"] = std::make_unique("h2DEtaPhiNeg", "Negative tracks in #eta vs. #phi;#phi;#eta", 360, 0., 2 * M_PI, 400, -2., 2.); - mMapHist["h2DEtaPhiPos"] = std::make_unique("h2DEtaPhiPos", "Positive tracks in #eta vs. #phi;#phi;#eta", 360, 0., 2 * M_PI, 400, -2., 2.); + mMapHist["h2DNClustersEta"] = std::make_unique("h2DNClustersEta", "Number of clusters vs. #eta;#eta;# TPC clusters", binsEta.bins, binsEta.min, binsEta.max, binsClusLargerRange.bins, binsClusLargerRange.min, binsClusLargerRange.max); + mMapHist["h2DNClustersPhiAside"] = std::make_unique("h2DNClustersPhiAside", "Number of clusters vs. #phi, A side ;#phi;# TPC clusters", 360, 0., 2 * M_PI, binsClus.bins, binsClus.min, binsClus.max); + mMapHist["h2DNClustersPhiCside"] = std::make_unique("h2DNClustersPhiCside", "Number of clusters vs. #phi, C side ;#phi;# TPC clusters", 360, 0., 2 * M_PI, binsClus.bins, binsClus.min, binsClus.max); + mMapHist["h2DNClustersPt"] = std::make_unique("h2DNClustersPt", "Number of clusters vs. #it{p}_{T};#it{p}_{T} (GeV/#it{c});# TPC clusters", logPtBinning.size() - 1, logPtBinning.data(), binsClusLargerRange.bins, binsClusLargerRange.min, binsClusLargerRange.max); + mMapHist["h2DEtaPhi"] = std::make_unique("h2DEtaPhi", "Tracks in #eta vs. #phi;#phi;#eta", 360, 0., 2 * M_PI, binsEta.bins, binsEta.min, binsEta.max); mMapHist["h2DNClustersEtaBeforeCuts"] = std::make_unique("h2DNClustersEtaBeforeCuts", "NClusters vs. #eta (before cuts);#eta;# TPC clusters", 400, -2., 2., 200, -0.5, 199.5); mMapHist["h2DNClustersPtBeforeCuts"] = std::make_unique("h2DNClustersPtBeforeCuts", "NClusters vs. #it{p}_{T} (before cuts);#it{p}_{T} (GeV/#it{c});# TPC clusters", logPtBinning.size() - 1, logPtBinning.data(), 200, -0.5, 199.5); mMapHist["h2DEtaPhiBeforeCuts"] = std::make_unique("h2DEtaPhiBeforeCuts", "Tracks in #eta vs. #phi (before cuts);#phi;#eta", 360, 0., 2 * M_PI, 400, -2., 2.); - mMapHist["h2DQOverPtPhiAside"] = std::make_unique("h2DQOverPtPhiAside", "Charger over #it{p}_{T} vs. #phi, A side;#phi;q/#it{p}_{T}", 360, 0., 2 * M_PI, 400, -20., 20.); - mMapHist["h2DQOverPtPhiCside"] = std::make_unique("h2DQOverPtPhiCside", "Charger over #it{p}_{T} vs. #phi, C side;#phi;q/#it{p}_{T}", 360, 0., 2 * M_PI, 400, -20., 20.); - // eta vs pt and phi vs pt possitive and negative signs - mMapHist["hEtaVsPtPos"] = std::make_unique("hEtaVsPtPos", "#eta vs. #it{p}_{T} (Pos.);#it{p}_{T} (GeV/#it{c});#eta", logPtBinning.size() - 1, logPtBinning.data(), 400, -2., 2.); - mMapHist["hEtaVsPtNeg"] = std::make_unique("hEtaVsPtNeg", "#eta vs. #it{p}_{T} (Neg.);#it{p}_{T} (GeV/#it{c});#eta", logPtBinning.size() - 1, logPtBinning.data(), 400, -2., 2.); - mMapHist["hPhiVsPtPos"] = std::make_unique("hPhiVsPtPos", "#phi vs. #it{p}_{T} (Pos.);#it{p}_{T} (GeV/#it{c});#phi", logPtBinning.size() - 1, logPtBinning.data(), 360, 0., 2 * M_PI); - mMapHist["hPhiVsPtNeg"] = std::make_unique("hPhiVsPtNeg", "#phi vs. #it{p}_{T} (Neg.);#it{p}_{T} (GeV/#it{c});#phi", logPtBinning.size() - 1, logPtBinning.data(), 360, 0., 2 * M_PI); - - // 1d histograms - mMapHist["hEtaRatio"] = std::make_unique("hEtaRatio", "Pseudorapidity, ratio neg./pos.;#eta", 400, -2., 2.); - mMapHist["hPhiAsideRatio"] = std::make_unique("hPhiAsideRatio", "Azimuthal angle, A side, ratio neg./pos.;#phi", 360, 0., 2 * M_PI); - mMapHist["hPhiCsideRatio"] = std::make_unique("hPhiCsideRatio", "Azimuthal angle, C side, ratio neg./pos.;#phi", 360, 0., 2 * M_PI); - mMapHist["hPtRatio"] = std::make_unique("hPtRatio", "Transverse momentum, ratio neg./pos. ;#it{p}_{T}", logPtBinning.size() - 1, logPtBinning.data()); - + if (!mTurnOffHistosForAsync) { + mMapHist["h2DQOverPtPhiAside"] = std::make_unique("h2DQOverPtPhiAside", "Charger over #it{p}_{T} vs. #phi, A side;#phi;q/#it{p}_{T}", 360, 0., 2 * M_PI, 400, -20., 20.); + mMapHist["h2DQOverPtPhiCside"] = std::make_unique("h2DQOverPtPhiCside", "Charger over #it{p}_{T} vs. #phi, C side;#phi;q/#it{p}_{T}", 360, 0., 2 * M_PI, 400, -20., 20.); + mMapHist["h2DEtaPhiNeg"] = std::make_unique("h2DEtaPhiNeg", "Negative tracks in #eta vs. #phi;#phi;#eta", 360, 0., 2 * M_PI, binsEta.bins, binsEta.min, binsEta.max); + mMapHist["h2DEtaPhiPos"] = std::make_unique("h2DEtaPhiPos", "Positive tracks in #eta vs. #phi;#phi;#eta", 360, 0., 2 * M_PI, binsEta.bins, binsEta.min, binsEta.max); + // eta vs pt and phi vs pt possitive and negative signs + mMapHist["hEtaVsPtPos"] = std::make_unique("hEtaVsPtPos", "#eta vs. #it{p}_{T} (Pos.);#it{p}_{T} (GeV/#it{c});#eta", logPtBinning.size() - 1, logPtBinning.data(), binsEta.bins, binsEta.min, binsEta.max); + mMapHist["hEtaVsPtNeg"] = std::make_unique("hEtaVsPtNeg", "#eta vs. #it{p}_{T} (Neg.);#it{p}_{T} (GeV/#it{c});#eta", logPtBinning.size() - 1, logPtBinning.data(), binsEta.bins, binsEta.min, binsEta.max); + mMapHist["hPhiVsPtPos"] = std::make_unique("hPhiVsPtPos", "#phi vs. #it{p}_{T} (Pos.);#it{p}_{T} (GeV/#it{c});#phi", logPtBinning.size() - 1, logPtBinning.data(), 360, 0., 2 * M_PI); + mMapHist["hPhiVsPtNeg"] = std::make_unique("hPhiVsPtNeg", "#phi vs. #it{p}_{T} (Neg.);#it{p}_{T} (GeV/#it{c});#phi", logPtBinning.size() - 1, logPtBinning.data(), 360, 0., 2 * M_PI); + } // DCA Histograms for (const auto type : types) { - mMapHist[fmt::format("hDCAr_{}", type).data()] = std::make_unique(fmt::format("hDCAr_{}", type).data(), fmt::format("DCAr {};#phi;DCAr (cm)", type).data(), 360, 0, o2::math_utils::twoPid(), 250, -10., 10.); - mMapHist[fmt::format("hDCAr_{}_pTmin", type).data()] = std::make_unique(fmt::format("hDCAr_{}_pTmin", type).data(), fmt::format("DCAr {} #it{{p}}_{{T}}^{{min}};#phi;DCAr (cm)", type).data(), 360, 0, o2::math_utils::twoPid(), 250, -10., 10.); + mMapHist[fmt::format("hDCAr_{}", type).data()] = std::make_unique(fmt::format("hDCAr_{}", type).data(), fmt::format("DCAr {};#phi;DCAr (cm)", type).data(), 360, 0, o2::math_utils::twoPid(), binsDCAr.bins, binsDCAr.min, binsDCAr.max); + mMapHist[fmt::format("hDCAr_{}_pTmin", type).data()] = std::make_unique(fmt::format("hDCAr_{}_pTmin", type).data(), fmt::format("DCAr {} #it{{p}}_{{T}}^{{min}};#phi;DCAr (cm)", type).data(), 360, 0, o2::math_utils::twoPid(), binsDCAr.bins, binsDCAr.min, binsDCAr.max); } // DCA vs variables Histograms - mMapHist["hDCArVsPtPos"] = std::make_unique("hDCArVsPtPos", "DCAr Pos;#it{p}_{T} (GeV/#it{c});DCAr (cm)", logPtBinning.size() - 1, logPtBinning.data(), 250, -10., 10.); - mMapHist["hDCArVsEtaPos"] = std::make_unique("hDCArVsEtaPos", "DCAr Pos;#eta;DCAr (cm)", 400, -2., 2., 250, -10., 10.); - mMapHist["hDCArVsNClsPos"] = std::make_unique("hDCArVsNClsPos", "DCAr Pos;# TPC clusters;DCAr (cm)", 400, -0.5, 399.5, 250, -10., 10.); - mMapHist["hDCArVsPtNeg"] = std::make_unique("hDCArVsPtNeg", "DCAr Neg;#it{p}_{T} (GeV/#it{c});DCAr (cm)", logPtBinning.size() - 1, logPtBinning.data(), 250, -10., 10.); - mMapHist["hDCArVsEtaNeg"] = std::make_unique("hDCArVsEtaNeg", "DCAr Neg;#eta;DCAr (cm)", 400, -2., 2., 250, -10., 10.); - mMapHist["hDCArVsNClsNeg"] = std::make_unique("hDCArVsNClsNeg", "DCAr Neg;# TPC clusters;DCAr (cm)", 400, -0.5, 399.5, 250, -10., 10.); + mMapHist["hDCArVsPtPos"] = std::make_unique("hDCArVsPtPos", "DCAr Pos;#it{p}_{T} (GeV/#it{c});DCAr (cm)", logPtBinning.size() - 1, logPtBinning.data(), binsDCArLargerRange.bins, binsDCArLargerRange.min, binsDCArLargerRange.max); + mMapHist["hDCArVsEtaPos"] = std::make_unique("hDCArVsEtaPos", "DCAr Pos;#eta;DCAr (cm)", binsEta.bins, binsEta.min, binsEta.max, binsDCArLargerRange.bins, binsDCArLargerRange.min, binsDCArLargerRange.max); + mMapHist["hDCArVsNClsPos"] = std::make_unique("hDCArVsNClsPos", "DCAr Pos;# TPC clusters;DCAr (cm)", binsClus.bins, binsClus.min, binsClus.max, binsDCAr.bins, binsDCAr.min, binsDCAr.max); + mMapHist["hDCArVsPtNeg"] = std::make_unique("hDCArVsPtNeg", "DCAr Neg;#it{p}_{T} (GeV/#it{c});DCAr (cm)", logPtBinning.size() - 1, logPtBinning.data(), binsDCArLargerRange.bins, binsDCArLargerRange.min, binsDCArLargerRange.max); + mMapHist["hDCArVsEtaNeg"] = std::make_unique("hDCArVsEtaNeg", "DCAr Neg;#eta;DCAr (cm)", binsEta.bins, binsEta.min, binsEta.max, binsDCArLargerRange.bins, binsDCArLargerRange.min, binsDCArLargerRange.max); + mMapHist["hDCArVsNClsNeg"] = std::make_unique("hDCArVsNClsNeg", "DCAr Neg;# TPC clusters;DCAr (cm)", binsClus.bins, binsClus.min, binsClus.max, binsDCAr.bins, binsDCAr.min, binsDCAr.max); // DCA vs variables Histogram with pT min selection - mMapHist["hDCArVsEtaPos_pTmin"] = std::make_unique("hDCArVsEtaPos_pTmin", "DCAr Pos #it{p}_{T}^{min};#eta;DCAr (cm)", 400, -2., 2., 250, -10., 10.); - mMapHist["hDCArVsNClsPos_pTmin"] = std::make_unique("hDCArVsNClsPos_pTmin", "DCAr Pos #it{p}_{T}^{min};# TPC clusters;DCAr (cm)", 400, -0.5, 399.5, 250, -10., 10.); - mMapHist["hDCArVsEtaNeg_pTmin"] = std::make_unique("hDCArVsEtaNeg_pTmin", "DCAr Neg #it{p}_{T}^{min};#eta;DCAr (cm)", 400, -2., 2., 250, -10., 10.); - mMapHist["hDCArVsNClsNeg_pTmin"] = std::make_unique("hDCArVsNClsNeg_pTmin", "DCAr Neg #it{p}_{T}^{min};# TPC clusters;DCAr (cm)", 400, -0.5, 399.5, 250, -10., 10.); + mMapHist["hDCArVsEtaPos_pTmin"] = std::make_unique("hDCArVsEtaPos_pTmin", "DCAr Pos #it{p}_{T}^{min};#eta;DCAr (cm)", binsEta.bins, binsEta.min, binsEta.max, binsDCAr.bins, binsDCAr.min, binsDCAr.max); + mMapHist["hDCArVsNClsPos_pTmin"] = std::make_unique("hDCArVsNClsPos_pTmin", "DCAr Pos #it{p}_{T}^{min};# TPC clusters;DCAr (cm)", binsClus.bins, binsClus.min, binsClus.max, binsDCAr.bins, binsDCAr.min, binsDCAr.max); + mMapHist["hDCArVsEtaNeg_pTmin"] = std::make_unique("hDCArVsEtaNeg_pTmin", "DCAr Neg #it{p}_{T}^{min};#eta;DCAr (cm)", binsEta.bins, binsEta.min, binsEta.max, binsDCAr.bins, binsDCAr.min, binsDCAr.max); + mMapHist["hDCArVsNClsNeg_pTmin"] = std::make_unique("hDCArVsNClsNeg_pTmin", "DCAr Neg #it{p}_{T}^{min};# TPC clusters;DCAr (cm)", binsClus.bins, binsClus.min, binsClus.max, binsDCAr.bins, binsDCAr.min, binsDCAr.max); } //______________________________________________________________________________ void Tracks::resetHistograms() @@ -200,7 +212,9 @@ bool Tracks::processTrack(const o2::tpc::TrackTPC& track) } else if (hasCSideOnly == 1) { mMapHist["hPhiCside"]->Fill(phi); } else { - mMapHist["hPhiBothSides"]->Fill(phi); + if (!mTurnOffHistosForAsync) { + mMapHist["hPhiBothSides"]->Fill(phi); + } } mMapHist["hPt"]->Fill(pt); @@ -208,20 +222,28 @@ bool Tracks::processTrack(const o2::tpc::TrackTPC& track) mMapHist["hQOverPt"]->Fill(qOverPt); if (sign < 0.) { - mMapHist["hEtaNeg"]->Fill(eta); - mMapHist["hPtNeg"]->Fill(pt); - if (hasASideOnly == 1) { - mMapHist["hPhiAsideNeg"]->Fill(phi); - } else if (hasCSideOnly == 1) { - mMapHist["hPhiCsideNeg"]->Fill(phi); + if (!mTurnOffHistosForAsync) { + mMapHist["hEtaNeg"]->Fill(eta); + mMapHist["hPtNeg"]->Fill(pt); + } + if (!mTurnOffHistosForAsync) { + if (hasASideOnly == 1) { + mMapHist["hPhiAsideNeg"]->Fill(phi); + } else if (hasCSideOnly == 1) { + mMapHist["hPhiCsideNeg"]->Fill(phi); + } } } else { - mMapHist["hEtaPos"]->Fill(eta); - mMapHist["hPtPos"]->Fill(pt); - if (hasASideOnly == 1) { - mMapHist["hPhiAsidePos"]->Fill(phi); - } else if (hasCSideOnly == 1) { - mMapHist["hPhiCsidePos"]->Fill(phi); + if (!mTurnOffHistosForAsync) { + mMapHist["hEtaPos"]->Fill(eta); + mMapHist["hPtPos"]->Fill(pt); + } + if (!mTurnOffHistosForAsync) { + if (hasASideOnly == 1) { + mMapHist["hPhiAsidePos"]->Fill(phi); + } else if (hasCSideOnly == 1) { + mMapHist["hPhiCsidePos"]->Fill(phi); + } } } @@ -230,23 +252,29 @@ bool Tracks::processTrack(const o2::tpc::TrackTPC& track) if (hasASideOnly == 1) { mMapHist["h2DNClustersPhiAside"]->Fill(phi, nCls); - mMapHist["h2DQOverPtPhiAside"]->Fill(phi, qOverPt); + if (!mTurnOffHistosForAsync) { + mMapHist["h2DQOverPtPhiAside"]->Fill(phi, qOverPt); + } } else if (hasCSideOnly == 1) { mMapHist["h2DNClustersPhiCside"]->Fill(phi, nCls); - mMapHist["h2DQOverPtPhiCside"]->Fill(phi, qOverPt); + if (!mTurnOffHistosForAsync) { + mMapHist["h2DQOverPtPhiCside"]->Fill(phi, qOverPt); + } } mMapHist["h2DNClustersPt"]->Fill(pt, nCls); mMapHist["h2DEtaPhi"]->Fill(phi, eta); - if (sign < 0.) { - mMapHist["h2DEtaPhiNeg"]->Fill(phi, eta); - mMapHist["hEtaVsPtNeg"]->Fill(pt, eta); - mMapHist["hPhiVsPtNeg"]->Fill(pt, phi); - } else { - mMapHist["h2DEtaPhiPos"]->Fill(phi, eta); - mMapHist["hEtaVsPtPos"]->Fill(pt, eta); - mMapHist["hPhiVsPtPos"]->Fill(pt, phi); + if (!mTurnOffHistosForAsync) { + if (sign < 0.) { + mMapHist["h2DEtaPhiNeg"]->Fill(phi, eta); + mMapHist["hEtaVsPtNeg"]->Fill(pt, eta); + mMapHist["hPhiVsPtNeg"]->Fill(pt, phi); + } else { + mMapHist["h2DEtaPhiPos"]->Fill(phi, eta); + mMapHist["hEtaVsPtPos"]->Fill(pt, eta); + mMapHist["hPhiVsPtPos"]->Fill(pt, phi); + } } } @@ -256,11 +284,13 @@ bool Tracks::processTrack(const o2::tpc::TrackTPC& track) //______________________________________________________________________________ void Tracks::processEndOfCycle() { - // ===| Dividing of 1D histograms -> Ratios |=== - mMapHist["hEtaRatio"]->Divide(mMapHist["hEtaNeg"].get(), mMapHist["hEtaPos"].get()); - mMapHist["hPhiAsideRatio"]->Divide(mMapHist["hPhiAsideNeg"].get(), mMapHist["hPhiAsidePos"].get()); - mMapHist["hPhiCsideRatio"]->Divide(mMapHist["hPhiCsideNeg"].get(), mMapHist["hPhiCsidePos"].get()); - mMapHist["hPtRatio"]->Divide(mMapHist["hPtNeg"].get(), mMapHist["hPtPos"].get()); + if (!mTurnOffHistosForAsync) { + // ===| Dividing of 1D histograms -> Ratios |=== + mMapHist["hEtaRatio"]->Divide(mMapHist["hEtaNeg"].get(), mMapHist["hEtaPos"].get()); + mMapHist["hPhiAsideRatio"]->Divide(mMapHist["hPhiAsideNeg"].get(), mMapHist["hPhiAsidePos"].get()); + mMapHist["hPhiCsideRatio"]->Divide(mMapHist["hPhiCsideNeg"].get(), mMapHist["hPhiCsidePos"].get()); + mMapHist["hPtRatio"]->Divide(mMapHist["hPtNeg"].get(), mMapHist["hPtPos"].get()); + } } //______________________________________________________________________________ diff --git a/Detectors/TPC/reconstruction/CMakeLists.txt b/Detectors/TPC/reconstruction/CMakeLists.txt index df3bb2ddb4cff..29e6d692968b7 100644 --- a/Detectors/TPC/reconstruction/CMakeLists.txt +++ b/Detectors/TPC/reconstruction/CMakeLists.txt @@ -36,7 +36,7 @@ o2_add_library(TPCReconstruction O2::TPCBase O2::GPUO2Interface O2::TPCFastTransformation - O2::DetectorsRaw + O2::DetectorsRaw O2::DetectorsBase) o2_target_root_dictionary( @@ -112,7 +112,7 @@ o2_add_test(FastTransform PUBLIC_LINK_LIBRARIES O2::TPCReconstruction SOURCES test/testTPCFastTransform.cxx ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage - CONFIGURATIONS RelWithDebInfo Release MinRelSize) + CONFIGURATIONS RelWithDebInfo Release MinSizeRel) # FIXME: should be moved to TPCCalibration as it requires O2::TPCCalibration # which is built after TPCReconstruction diff --git a/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx b/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx index 7d01234ac913f..33537dc373451 100644 --- a/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx +++ b/Detectors/TPC/reconstruction/test/testGPUCATracking.cxx @@ -62,7 +62,7 @@ BOOST_AUTO_TEST_CASE(CATracking_test1) config.configProcessing.runQA = false; //Run QA after tracking config.configProcessing.eventDisplay = nullptr; //Ptr to event display backend, for running standalone OpenGL event display - config.configGRP.solenoidBz = solenoidBz; + config.configGRP.solenoidBzNominalGPU = solenoidBz; config.configGRP.continuousMaxTimeBin = continuous ? GPUSettings::TPC_MAX_TF_TIME_BIN : 0; //Number of timebins in timeframe if continuous, 0 otherwise config.configReconstruction.tpc.nWays = 3; //Should always be 3! diff --git a/Detectors/TPC/simulation/src/Detector.cxx b/Detectors/TPC/simulation/src/Detector.cxx index 3344537dcec4f..60dcc542c70ff 100644 --- a/Detectors/TPC/simulation/src/Detector.cxx +++ b/Detectors/TPC/simulation/src/Detector.cxx @@ -315,6 +315,8 @@ void Detector::CreateMaterials() // Origin: Marek Kowalski IFJ, Krakow, Marek.Kowalski@ifj.edu.pl //----------------------------------------------------------------- + const auto& gasParam = ParameterGas::Instance(); + Int_t iSXFLD = 2; Float_t sXMGMX = 10.0; // init the field tracking params @@ -326,6 +328,23 @@ void Detector::CreateMaterials() Float_t density; + // TODO: load pressure and temperature values from CCDB + const Double_t pressure = gasParam.Pressure; // in mbar + const Double_t temperature = gasParam.Temperature + 273.15; // in K + + // densities were taken for these values + const Double_t t1 = 293.15; // 20°C in K + const Double_t p1 = 1013.25; // 1 atm in mbars + + // sanity check - temperature between 10 and 30 deg, pressure between 800 and 1200 mbar + Double_t ptCorr = 1.; + if (TMath::Abs(temperature - 293.15) > 10. || TMath::Abs(pressure - 1000.) > 200.) { + ptCorr = 1.; + } else { + ptCorr = (pressure * t1) / (p1 * temperature); + } + LOG(info) << "Setting gas density correction to: " << ptCorr; + //***************** Gases ************************* //-------------------------------------------------------------- @@ -345,7 +364,7 @@ void Detector::CreateMaterials() density = 1.842e-3; - o2::base::Detector::Mixture(10, "CO2", amat, zmat, density, 2, wmat); + o2::base::Detector::Mixture(10, "CO2", amat, zmat, density * ptCorr, 2, wmat); // // Air // @@ -360,7 +379,7 @@ void Detector::CreateMaterials() // density = 0.001205; - o2::base::Detector::Mixture(11, "Air", amat, zmat, density, 2, wmat); + o2::base::Detector::Mixture(11, "Air", amat, zmat, density * ptCorr, 2, wmat); //---------------------------------------------------------------- // drift gases 5 mixtures, 5 materials @@ -466,9 +485,9 @@ void Detector::CreateMaterials() } // - o2::base::Detector::Mixture(12, gname1.Data(), amat1, zmat1, density, cnt, wmat1); // nonsensitive - o2::base::Detector::Mixture(13, gname2.Data(), amat1, zmat1, density, cnt, wmat1); // sensitive - o2::base::Detector::Mixture(40, gname3.Data(), amat1, zmat1, density, cnt, wmat1); // sensitive Kr + o2::base::Detector::Mixture(12, gname1.Data(), amat1, zmat1, density * ptCorr, cnt, wmat1); // nonsensitive + o2::base::Detector::Mixture(13, gname2.Data(), amat1, zmat1, density * ptCorr, cnt, wmat1); // sensitive + o2::base::Detector::Mixture(40, gname3.Data(), amat1, zmat1, density * ptCorr, cnt, wmat1); // sensitive Kr //---------------------------------------------------------------------- // solid materials diff --git a/Detectors/TPC/spacecharge/CMakeLists.txt b/Detectors/TPC/spacecharge/CMakeLists.txt index 9af6c14eb351a..a2f4cdb51becb 100644 --- a/Detectors/TPC/spacecharge/CMakeLists.txt +++ b/Detectors/TPC/spacecharge/CMakeLists.txt @@ -64,7 +64,7 @@ o2_add_test(PoissonSolver SOURCES test/testO2TPCPoissonSolver.cxx ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage LABELS tpc - CONFIGURATIONS RelWithDebInfo Release MinRelSize) + CONFIGURATIONS RelWithDebInfo Release MinSizeRel) o2_add_test(TriCubic COMPONENT_NAME spacecharge @@ -72,7 +72,7 @@ o2_add_test(TriCubic SOURCES test/testO2TPCTricubic.cxx ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage LABELS tpc - CONFIGURATIONS RelWithDebInfo Release MinRelSize) + CONFIGURATIONS RelWithDebInfo Release MinSizeRel) if (OpenMP_CXX_FOUND) target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) diff --git a/Detectors/TPC/workflow/CMakeLists.txt b/Detectors/TPC/workflow/CMakeLists.txt index 57ce61e1f436e..3b05e5067108c 100644 --- a/Detectors/TPC/workflow/CMakeLists.txt +++ b/Detectors/TPC/workflow/CMakeLists.txt @@ -62,6 +62,13 @@ o2_add_library(TPCWorkflowGUI O2::TPCMonitor ) +o2_add_library(TPCWorkflowStudies + SOURCES src/TPCRefitter.cxx + TARGETVARNAME targetName + PUBLIC_LINK_LIBRARIES O2::TPCWorkflow + O2::GlobalTrackingWorkflow + ) + o2_add_executable(chunkeddigit-merger COMPONENT_NAME tpc TARGETVARNAME mergertargetName @@ -281,5 +288,9 @@ o2_add_executable(calibration-workflow O2::DetectorsCalibrationWorkflow O2::DataFormatsCalibration O2::CCDB) +o2_add_executable(refitter + SOURCES src/tpc-refitter-workflow.cxx + COMPONENT_NAME tpc + PUBLIC_LINK_LIBRARIES O2::TPCWorkflowStudies) add_subdirectory(readers) diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h index 3222d24667760..207bea0e7fa42 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/CalibLaserTracksSpec.h @@ -121,15 +121,15 @@ class CalibLaserTracksDevice : public o2::framework::Task using clbUtils = o2::calibration::Utils; auto ltrCalib = mCalib.getCalibData(); + if (!ltrCalib.isValid()) { + LOGP(error, "Invalid Laser calibration (corrections: A-side={}, C-side={}, NTracks: A-side={} C-side={}), will NOT upload to CCDB", ltrCalib.dvCorrectionA, ltrCalib.dvCorrectionC, ltrCalib.nTracksA, ltrCalib.nTracksC); + return; + } if (mNormalize) { ltrCalib.normalize(0.); LOGP(info, "After normalization: correction factors: {} / {} for A- / C-Side, reference: {}, vdrift correction: {}", ltrCalib.dvCorrectionA, ltrCalib.dvCorrectionC, ltrCalib.refVDrift, ltrCalib.getDriftVCorrection()); } - if (ltrCalib.getDriftVCorrection() == 0) { - LOG(error) << "Extracted drift correction is 0, something is wrong, will not upload the object"; - return; - } o2::ccdb::CcdbObjectInfo w; auto image = o2::ccdb::CcdbApi::createObjectImage(<rCalib, &w); diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/ClusterSharingMapSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/ClusterSharingMapSpec.h index 1bade0eec9c4d..e6c6939a2c70b 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/ClusterSharingMapSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/ClusterSharingMapSpec.h @@ -18,6 +18,7 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" +#include "Framework/CCDBParamSpec.h" namespace o2 { @@ -39,7 +40,9 @@ o2::framework::DataProcessorSpec getClusterSharingMapSpec() inputs.emplace_back("trackTPC", "TPC", "TRACKS", 0, o2::framework::Lifetime::Timeframe); inputs.emplace_back("trackTPCClRefs", "TPC", "CLUSREFS", 0, o2::framework::Lifetime::Timeframe); inputs.emplace_back("clusTPC", o2::framework::ConcreteDataTypeMatcher{"TPC", "CLUSTERNATIVE"}, o2::framework::Lifetime::Timeframe); + inputs.emplace_back("grpecs", "GLO", "GRPECS", 0, o2::framework::Lifetime::Condition, o2::framework::ccdbParamSpec("GLO/Config/GRPECS", true)); outputs.emplace_back("TPC", "CLSHAREDMAP", 0, o2::framework::Lifetime::Timeframe); + outputs.emplace_back("TPC", "TPCOCCUPANCYMAP", 0, o2::framework::Lifetime::Timeframe); return o2::framework::DataProcessorSpec{ "tpc-clusters-sharing-map-producer", diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/LaserTracksCalibratorSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/LaserTracksCalibratorSpec.h index dad23046c2578..9d8ca28447db7 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/LaserTracksCalibratorSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/LaserTracksCalibratorSpec.h @@ -88,6 +88,10 @@ class LaserTracksCalibratorDevice : public o2::framework::Task const long timeEnd = o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP; for (uint32_t iCalib = 0; iCalib < calibrations.size(); ++iCalib) { const auto& object = calibrations[iCalib]; + if (!object.isValid()) { + LOGP(error, "Invalid Laser calibration (corrections: A-side={}, C-side={}, NTracks: A-side={} C-side={}), will NOT upload to CCDB", object.dvCorrectionA, object.dvCorrectionC, object.nTracksA, object.nTracksC); + continue; + } o2::ccdb::CcdbObjectInfo w; auto image = o2::ccdb::CcdbApi::createObjectImage(&object, &w); diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h index 3ac401609d408..7afc973d7a3ab 100644 --- a/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCCalibPadGainTracksSpec.h @@ -29,7 +29,8 @@ #include "TPCCalibration/VDriftHelper.h" #include "TPCCalibration/CorrectionMapsLoader.h" #include "DetectorsBase/GRPGeomHelper.h" - +#include "GPUO2InterfaceUtils.h" +#include "DataFormatsGlobalTracking/RecoContainer.h" #include using namespace o2::framework; @@ -44,7 +45,7 @@ namespace tpc class TPCCalibPadGainTracksDevice : public o2::framework::Task { public: - TPCCalibPadGainTracksDevice(std::shared_ptr req, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, const uint32_t publishAfterTFs, const bool debug, const bool useLastExtractedMapAsReference, const std::string polynomialsFile, const bool disablePolynomialsCCDB) : mPublishAfter(publishAfterTFs), mDebug(debug), mUseLastExtractedMapAsReference(useLastExtractedMapAsReference), mDisablePolynomialsCCDB(disablePolynomialsCCDB), mCCDBRequest(req) + TPCCalibPadGainTracksDevice(std::shared_ptr dr, std::shared_ptr req, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, const uint32_t publishAfterTFs, const bool debug, const bool useLastExtractedMapAsReference, const std::string polynomialsFile, const bool disablePolynomialsCCDB) : mDataRequest(dr), mPublishAfter(publishAfterTFs), mDebug(debug), mUseLastExtractedMapAsReference(useLastExtractedMapAsReference), mDisablePolynomialsCCDB(disablePolynomialsCCDB), mCCDBRequest(req) { if (!polynomialsFile.empty()) { LOGP(info, "Loading polynomials from file {}", polynomialsFile); @@ -152,9 +153,9 @@ class TPCCalibPadGainTracksDevice : public o2::framework::Task } else if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { } else if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { } else if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { - const auto field = (5.00668f / 30000.f) * o2::base::GRPGeomHelper::instance().getGRPMagField()->getL3Current(); + const auto field = o2::gpu::GPUO2InterfaceUtils::getNominalGPUBz(*o2::base::GRPGeomHelper::instance().getGRPMagField()); LOGP(info, "Setting magnetic field to {} kG", field); - mPadGainTracks.setField(field); + mPadGainTracks.setFieldNominalGPUBz(field); } } @@ -166,10 +167,12 @@ class TPCCalibPadGainTracksDevice : public o2::framework::Task return; } o2::base::GRPGeomHelper::instance().checkUpdates(pc); + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); - auto tracks = pc.inputs().get>("trackTPC"); - auto clRefs = pc.inputs().get>("trackTPCClRefs"); - const auto& clusters = getWorkflowTPCInput(pc); + auto tracks = recoData.getTPCTracks(); + auto clRefs = recoData.getTPCTracksClusterRefs(); + const auto& clusters = recoData.inputsTPCclusters; const auto nTracks = tracks.size(); if (nTracks == 0) { return; @@ -205,7 +208,7 @@ class TPCCalibPadGainTracksDevice : public o2::framework::Task mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); } - mPadGainTracks.setMembers(&tracks, &clRefs, clusters->clusterIndex); + mPadGainTracks.setMembers(&tracks, &clRefs, clusters->clusterIndex, recoData.clusterShMapTPC, recoData.occupancyMapTPC); mPadGainTracks.processTracks(mMaxTracksPerTF); ++mProcessedTFs; if ((mFirstTFSend == mProcessedTFs) || (mPublishAfter && (mProcessedTFs % mPublishAfter) == 0)) { @@ -224,6 +227,7 @@ class TPCCalibPadGainTracksDevice : public o2::framework::Task const bool mDebug{false}; ///< create debug output const bool mUseLastExtractedMapAsReference{false}; ///< using the last extracted gain map as the reference map which will be applied bool mDisablePolynomialsCCDB{false}; ///< do not load the polynomials from the CCDB + std::shared_ptr mDataRequest; ///< reco container data request std::shared_ptr mCCDBRequest; ///< for accessing the b-field uint32_t mProcessedTFs{0}; ///< counter to keep track of the processed TFs uint32_t mTFCounter{0}; ///< counter to keep track of the TFs @@ -245,11 +249,12 @@ class TPCCalibPadGainTracksDevice : public o2::framework::Task DataProcessorSpec getTPCCalibPadGainTracksSpec(const uint32_t publishAfterTFs, const bool debug, const bool useLastExtractedMapAsReference, const std::string polynomialsFile, bool disablePolynomialsCCDB, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) { std::vector inputs; - inputs.emplace_back("trackTPC", gDataOriginTPC, "TRACKS", 0, Lifetime::Timeframe); - inputs.emplace_back("trackTPCClRefs", gDataOriginTPC, "CLUSREFS", 0, Lifetime::Timeframe); - inputs.emplace_back("clusTPC", ConcreteDataTypeMatcher{gDataOriginTPC, "CLUSTERNATIVE"}, Lifetime::Timeframe); + auto dataRequest = std::make_shared(); + dataRequest->requestTracks(o2::dataformats::GlobalTrackID::getSourceMask(o2::dataformats::GlobalTrackID::TPC), false); + dataRequest->requestClusters(o2::dataformats::GlobalTrackID::getSourceMask(o2::dataformats::GlobalTrackID::TPC), false); + if (sclOpts.lumiType == 1) { - inputs.emplace_back("CTPLumi", "CTP", "LUMI", 0, Lifetime::Timeframe); + dataRequest->inputs.emplace_back("CTPLumi", "CTP", "LUMI", 0, Lifetime::Timeframe); } if (!polynomialsFile.empty()) { @@ -257,14 +262,14 @@ DataProcessorSpec getTPCCalibPadGainTracksSpec(const uint32_t publishAfterTFs, c } if (!disablePolynomialsCCDB) { - inputs.emplace_back("tpctopologygain", gDataOriginTPC, "TOPOLOGYGAIN", 0, Lifetime::Condition, ccdbParamSpec(CDBTypeMap.at(CDBType::CalTopologyGain))); + dataRequest->inputs.emplace_back("tpctopologygain", gDataOriginTPC, "TOPOLOGYGAIN", 0, Lifetime::Condition, ccdbParamSpec(CDBTypeMap.at(CDBType::CalTopologyGain))); } if (useLastExtractedMapAsReference) { - inputs.emplace_back("tpcresidualgainmap", gDataOriginTPC, "RESIDUALGAINMAP", 0, Lifetime::Condition, ccdbParamSpec(CDBTypeMap.at(CDBType::CalPadGainResidual))); + dataRequest->inputs.emplace_back("tpcresidualgainmap", gDataOriginTPC, "RESIDUALGAINMAP", 0, Lifetime::Condition, ccdbParamSpec(CDBTypeMap.at(CDBType::CalPadGainResidual))); } - o2::tpc::VDriftHelper::requestCCDBInputs(inputs); + o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); Options opts{ {"nBins", VariantType::Int, 20, {"Number of bins per histogram"}}, {"reldEdxMin", VariantType::Int, 0, {"Minimum x coordinate of the histogram for Q/(dE/dx)"}}, @@ -287,7 +292,7 @@ DataProcessorSpec getTPCCalibPadGainTracksSpec(const uint32_t publishAfterTFs, c {"useEveryNthTF", VariantType::Int, 10, {"Using only a fraction of the data: 1: Use every TF, 10: Use only every tenth TF."}}, {"maxTracksPerTF", VariantType::Int, 10000, {"Maximum number of processed tracks per TF (-1 for processing all tracks)"}}, }; - o2::tpc::CorrectionMapsLoader::requestCCDBInputs(inputs, opts, sclOpts); + o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); auto ccdbRequest = std::make_shared(false, // orbitResetTime false, // GRPECS=true @@ -295,16 +300,16 @@ DataProcessorSpec getTPCCalibPadGainTracksSpec(const uint32_t publishAfterTFs, c true, // GRPMagField true, // askMatLUT o2::base::GRPGeomRequest::None, // geometry - inputs); + dataRequest->inputs); std::vector outputs; outputs.emplace_back(gDataOriginTPC, "TRACKGAINHISTOS", 0, o2::framework::Lifetime::Sporadic); return DataProcessorSpec{ "calib-tpc-gainmap-tracks", - inputs, + dataRequest->inputs, outputs, - AlgorithmSpec{adaptFromTask(ccdbRequest, sclOpts, publishAfterTFs, debug, useLastExtractedMapAsReference, polynomialsFile, disablePolynomialsCCDB)}, + AlgorithmSpec{adaptFromTask(dataRequest, ccdbRequest, sclOpts, publishAfterTFs, debug, useLastExtractedMapAsReference, polynomialsFile, disablePolynomialsCCDB)}, opts}; // end DataProcessorSpec } diff --git a/Detectors/TPC/workflow/include/TPCWorkflow/TPCRefitter.h b/Detectors/TPC/workflow/include/TPCWorkflow/TPCRefitter.h new file mode 100644 index 0000000000000..c57b147cdfd62 --- /dev/null +++ b/Detectors/TPC/workflow/include/TPCWorkflow/TPCRefitter.h @@ -0,0 +1,34 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#ifndef O2_TPC_DATA_FILTER_H +#define O2_TPC_DATA_FILTER_H + +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "Framework/Task.h" +#include "Framework/DataProcessorSpec.h" +#include "ReconstructionDataFormats/Track.h" +#include "MathUtils/detail/Bracket.h" +#include "DataFormatsTPC/ClusterNative.h" + +namespace o2::tpc +{ +struct CorrectionMapsLoaderGloOpts; +} + +namespace o2::trackstudy +{ +/// create a processor spec +o2::framework::DataProcessorSpec getTPCRefitterSpec(o2::dataformats::GlobalTrackID::mask_t srcTracks, o2::dataformats::GlobalTrackID::mask_t srcClus, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts); + +} // namespace o2::trackstudy + +#endif diff --git a/Detectors/TPC/workflow/src/ClusterSharingMapSpec.cxx b/Detectors/TPC/workflow/src/ClusterSharingMapSpec.cxx index 7b8259aa70377..eef3061bc47c3 100644 --- a/Detectors/TPC/workflow/src/ClusterSharingMapSpec.cxx +++ b/Detectors/TPC/workflow/src/ClusterSharingMapSpec.cxx @@ -19,7 +19,9 @@ #include "DataFormatsTPC/WorkflowHelper.h" #include "DataFormatsTPC/TrackTPC.h" #include "GPUO2InterfaceRefit.h" +#include "GPUO2InterfaceUtils.h" #include "TPCWorkflow/ClusterSharingMapSpec.h" +#include "DataFormatsParameters/GRPECSObject.h" using namespace o2::framework; using namespace o2::tpc; @@ -27,13 +29,21 @@ using namespace o2::tpc; void ClusterSharingMapSpec::run(ProcessingContext& pc) { TStopwatch timer; - + static int nHBPerTF = 0; const auto tracksTPC = pc.inputs().get>("trackTPC"); const auto tracksTPCClRefs = pc.inputs().get>("trackTPCClRefs"); const auto& clustersTPC = getWorkflowTPCInput(pc); + if (pc.services().get().globalRunNumberChanged) { // new run is starting + auto grp = pc.inputs().get("grpecs"); + nHBPerTF = grp->getNHBFPerTF(); + LOGP(info, "Will use {} HB per TF from GRPECS", nHBPerTF); + } - auto& bufVec = pc.outputs().make>(Output{o2::header::gDataOriginTPC, "CLSHAREDMAP", 0}, clustersTPC->clusterIndex.nClustersTotal); - o2::gpu::GPUO2InterfaceRefit::fillSharedClustersMap(&clustersTPC->clusterIndex, tracksTPC, tracksTPCClRefs.data(), bufVec.data()); + std::shared_ptr param = o2::gpu::GPUO2InterfaceUtils::getFullParamShared(0.f, nHBPerTF); + auto& bufVecSh = pc.outputs().make>(Output{o2::header::gDataOriginTPC, "CLSHAREDMAP", 0}, clustersTPC->clusterIndex.nClustersTotal); + size_t occupancyMapSize = o2::gpu::GPUO2InterfaceRefit::fillOccupancyMapGetSize(nHBPerTF, param.get()); + auto& bufVecOcc = pc.outputs().make>(Output{o2::header::gDataOriginTPC, "TPCOCCUPANCYMAP", 0}, occupancyMapSize); + o2::gpu::GPUO2InterfaceRefit::fillSharedClustersAndOccupancyMap(&clustersTPC->clusterIndex, tracksTPC, tracksTPCClRefs.data(), bufVecSh.data(), bufVecOcc.data(), nHBPerTF, param.get()); timer.Stop(); LOGF(info, "Timing for TPC clusters sharing map creation: Cpu: %.3e Real: %.3e s", timer.CpuTime(), timer.RealTime()); diff --git a/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx b/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx index 75fedb4a0effe..fc707f433c8c5 100644 --- a/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx +++ b/Detectors/TPC/workflow/src/EntropyEncoderSpec.cxx @@ -22,6 +22,7 @@ #include "Headers/DataHeader.h" #include "TPCReconstruction/TPCFastTransformHelperO2.h" #include "GPUO2InterfaceConfiguration.h" +#include "GPUO2InterfaceUtils.h" #include "GPUParam.h" #include "DataFormatsTPC/ClusterNative.h" #include "TPCClusterDecompressor.inc" @@ -68,18 +69,9 @@ void EntropyEncoderSpec::init(o2::framework::InitContext& ic) mCTFCoder.init(ic); mCTFCoder.setCombineColumns(!ic.options().get("no-ctf-columns-combining")); - mConfig.reset(new o2::gpu::GPUO2InterfaceConfiguration); - mConfig->configGRP.solenoidBz = 0; - mConfParam.reset(new o2::gpu::GPUSettingsO2(mConfig->ReadConfigurableParam())); - mAutoContinuousMaxTimeBin = mConfig->configGRP.continuousMaxTimeBin == -1; - if (mAutoContinuousMaxTimeBin) { - mConfig->configGRP.continuousMaxTimeBin = (256 * o2::constants::lhc::LHCMaxBunches + 2 * o2::tpc::constants::LHCBCPERTIMEBIN - 2) / o2::tpc::constants::LHCBCPERTIMEBIN; - } - mFastTransform = std::move(TPCFastTransformHelperO2::instance()->create(0)); - mParam.reset(new o2::gpu::GPUParam); - mParam->SetDefaults(&mConfig->configGRP, &mConfig->configReconstruction, &mConfig->configProcessing, nullptr); + mParam = GPUO2InterfaceUtils::getFullParam(0.f, 0, &mConfig, &mConfParam, &mAutoContinuousMaxTimeBin); if (mSelIR) { mTPCVDriftHelper.reset(new VDriftHelper); @@ -101,7 +93,7 @@ void EntropyEncoderSpec::run(ProcessingContext& pc) } mConfig->configGRP.continuousMaxTimeBin = (GRPGeomHelper::instance().getGRPECS()->getNHBFPerTF() * o2::constants::lhc::LHCMaxBunches + 2 * o2::tpc::constants::LHCBCPERTIMEBIN - 2) / o2::tpc::constants::LHCBCPERTIMEBIN; - mConfig->configGRP.solenoidBz = (5.00668f / 30000.f) * GRPGeomHelper::instance().getGRPMagField()->getL3Current(); + mConfig->configGRP.solenoidBzNominalGPU = GPUO2InterfaceUtils::getNominalGPUBz(*GRPGeomHelper::instance().getGRPMagField()); mParam->UpdateSettings(&mConfig->configGRP); mTPCVDriftHelper->extractCCDBInputs(pc); diff --git a/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx b/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx index 0d2b4a649dccb..a65b4ccdf3a6d 100644 --- a/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx +++ b/Detectors/TPC/workflow/src/FileReaderWorkflow.cxx @@ -14,9 +14,9 @@ #include "TPCReaderWorkflow/ClusterReaderSpec.h" #include "TPCReaderWorkflow/TriggerReaderSpec.h" #include "TPCReaderWorkflow/TrackReaderSpec.h" +#include "TPCWorkflow/ClusterSharingMapSpec.h" #include "DetectorsRaw/HBFUtilsInitializer.h" #include "Framework/CallbacksPolicy.h" - #include "Algorithm/RangeTokenizer.h" #include "SimulationDataFormat/IOMCTruthContainerView.h" @@ -85,6 +85,11 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) specs.push_back(o2::tpc::getTPCTrackReaderSpec(doMC)); } + + if (isEnabled(InputType::Tracks) && isEnabled(InputType::Clusters)) { // create shared clusters and occupancy maps + specs.emplace_back(o2::tpc::getClusterSharingMapSpec()); + } + o2::raw::HBFUtilsInitializer hbfIni(cfgc, specs); return std::move(specs); } diff --git a/Detectors/TPC/workflow/src/IDCToVectorSpec.cxx b/Detectors/TPC/workflow/src/IDCToVectorSpec.cxx index a1b77b2774228..27dbcf5d85bbf 100644 --- a/Detectors/TPC/workflow/src/IDCToVectorSpec.cxx +++ b/Detectors/TPC/workflow/src/IDCToVectorSpec.cxx @@ -80,31 +80,38 @@ class IDCToVectorDevice : public o2::framework::Task auto pedestalFile = ic.options().get("pedestal-url"); if (pedestalFile.length()) { - if (pedestalFile.find("ccdb") != std::string::npos) { - if (pedestalFile.find("-default") != std::string::npos) { - pedestalFile = o2::base::NameConf::getCCDBServer(); + auto& cdb = o2::ccdb::BasicCCDBManager::instance(); + long timeStamp = o2::ccdb::getCurrentTimestamp(); + const auto tsPos = pedestalFile.find("@"); + std::string pedestalURL = pedestalFile.substr(0, tsPos); + if (pedestalURL.find("ccdb") != std::string::npos) { + if (pedestalURL.find("-default") != std::string::npos) { + pedestalURL = o2::base::NameConf::getCCDBServer(); } - LOGP(info, "Loading pedestals from ccdb: {}", pedestalFile); - auto& cdb = o2::ccdb::BasicCCDBManager::instance(); - cdb.setURL(pedestalFile); + LOGP(info, "Loading pedestals from ccdb: {}", pedestalURL); + cdb.setURL(pedestalURL); if (cdb.isHostReachable()) { - auto pedestalNoise = cdb.get>("TPC/Calib/PedestalNoise"); + if (tsPos != std::string::npos) { + timeStamp = std::stol(pedestalFile.substr(tsPos + 1)); + LOGP(info, "Using custom time stamp {}", timeStamp); + } + auto pedestalNoise = cdb.getForTimeStamp>("TPC/Calib/PedestalNoise", timeStamp); try { if (!pedestalNoise) { throw std::runtime_error("Couldn't retrieve PedestaNoise map"); } mPedestal = std::make_unique(pedestalNoise->at("Pedestals")); } catch (const std::exception& e) { - LOGP(fatal, "could not load pedestals from {} ({}), required for IDC processing", pedestalFile, e.what()); + LOGP(fatal, "could not load pedestals from {} ({}), required for IDC processing", pedestalURL, e.what()); } } else { - LOGP(fatal, "ccdb access to {} requested, but host is not reachable. Cannot load pedestals, required for IDC processing", pedestalFile); + LOGP(fatal, "ccdb access to {} requested, but host is not reachable. Cannot load pedestals, required for IDC processing", pedestalURL); } } else { - LOGP(info, "Loading pedestals from file: {}", pedestalFile); - auto calPads = utils::readCalPads(pedestalFile, "Pedestals"); + LOGP(info, "Loading pedestals from file: {}", pedestalURL); + auto calPads = utils::readCalPads(pedestalURL, "Pedestals"); if (calPads.size() != 1) { - LOGP(fatal, "Pedestal could not be loaded from file {}, required for IDC processing", pedestalFile); + LOGP(fatal, "Pedestal could not be loaded from file {}, required for IDC processing", pedestalURL); } else { mPedestal.reset(calPads[0]); } diff --git a/Detectors/TPC/workflow/src/TPCRefitter.cxx b/Detectors/TPC/workflow/src/TPCRefitter.cxx new file mode 100644 index 0000000000000..cdc4234e6a2cc --- /dev/null +++ b/Detectors/TPC/workflow/src/TPCRefitter.cxx @@ -0,0 +1,486 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include +#include +#include "DataFormatsGlobalTracking/RecoContainer.h" +#include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "TPCCalibration/VDriftHelper.h" +#include "TPCCalibration/CorrectionMapsLoader.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "DetectorsBase/Propagator.h" +#include "DetectorsBase/GeometryManager.h" +#include "SimulationDataFormat/MCEventLabel.h" +#include "SimulationDataFormat/MCUtils.h" +#include "CommonUtils/NameConf.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/CCDBParamSpec.h" +#include "Framework/ControlService.h" +#include "Framework/Task.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsBase/GRPGeomHelper.h" +#include "TPCWorkflow/TPCRefitter.h" +#include "GPUO2InterfaceRefit.h" +#include "TPCBase/ParameterElectronics.h" +#include "CommonUtils/TreeStreamRedirector.h" +#include "Steer/MCKinematicsReader.h" + +namespace o2::trackstudy +{ + +using namespace o2::framework; +using DetID = o2::detectors::DetID; +using DataRequest = o2::globaltracking::DataRequest; + +using PVertex = o2::dataformats::PrimaryVertex; +using V2TRef = o2::dataformats::VtxTrackRef; +using VTIndex = o2::dataformats::VtxTrackIndex; +using GTrackID = o2::dataformats::GlobalTrackID; +using TBracket = o2::math_utils::Bracketf_t; + +using timeEst = o2::dataformats::TimeStampWithError; + +class TPCRefitterSpec final : public Task +{ + public: + TPCRefitterSpec(std::shared_ptr dr, std::shared_ptr gr, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts, GTrackID::mask_t src, bool useMC) + : mDataRequest(dr), mGGCCDBRequest(gr), mTracksSrc(src), mUseMC(useMC) + { + mTPCCorrMapsLoader.setLumiScaleType(sclOpts.lumiType); + mTPCCorrMapsLoader.setLumiScaleMode(sclOpts.lumiMode); + } + ~TPCRefitterSpec() final = default; + void init(InitContext& ic) final; + void run(ProcessingContext& pc) final; + void endOfStream(EndOfStreamContext& ec) final; + void finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) final; + void process(o2::globaltracking::RecoContainer& recoData); + bool getDCAs(const o2::track::TrackPar& track, float& dcar, float& dcaz); + + private: + void updateTimeDependentParams(ProcessingContext& pc); + std::shared_ptr mDataRequest; + std::shared_ptr mGGCCDBRequest; + o2::tpc::VDriftHelper mTPCVDriftHelper{}; + o2::tpc::CorrectionMapsLoader mTPCCorrMapsLoader{}; + bool mUseMC{false}; ///< MC flag + bool mUseGPUModel{false}; + float mXRef = 83.; + float mDCAMinPt = 1.; + int mTFStart = 0; + int mTFEnd = 999999999; + int mTFCount = -1; + int mDCAMinNCl = 80; + bool mUseR = false; + bool mEnableDCA = false; + bool mWriteTrackClusters = false; + std::unique_ptr mDBGOut; + std::unique_ptr mDBGOutCl; + float mITSROFrameLengthMUS = 0.; + GTrackID::mask_t mTracksSrc{}; + o2::steer::MCKinematicsReader mcReader; // reader of MC information + // + // TPC data + gsl::span mTPCTrackClusIdx; ///< input TPC track cluster indices span + gsl::span mTPCTracksArray; ///< input TPC tracks span + gsl::span mTPCRefitterShMap; ///< externally set TPC clusters sharing map + gsl::span mTPCRefitterOccMap; ///< externally set TPC clusters occupancy map + const o2::tpc::ClusterNativeAccess* mTPCClusterIdxStruct = nullptr; ///< struct holding the TPC cluster indices + gsl::span mTPCTrkLabels; ///< input TPC Track MC labels + std::unique_ptr mTPCRefitter; ///< TPC refitter used for TPC tracks refit during the reconstruction +}; + +void TPCRefitterSpec::init(InitContext& ic) +{ + o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); + mXRef = ic.options().get("target-x"); + mUseR = ic.options().get("use-r-as-x"); + mEnableDCA = ic.options().get("enable-dcas"); + mUseGPUModel = ic.options().get("use-gpu-fitter"); + mTFStart = ic.options().get("tf-start"); + mTFEnd = ic.options().get("tf-end"); + mDCAMinPt = ic.options().get("dcaMinPt"); + mDCAMinNCl = ic.options().get("dcaMinNCl"); + if (mXRef < 0.) { + mXRef = 0.; + } + mTPCCorrMapsLoader.init(ic); + mDBGOut = std::make_unique("tpctracks-refitted.root", "recreate"); + mWriteTrackClusters = ic.options().get("dump-clusters"); + if (ic.options().get("dump-clusters")) { + mDBGOutCl = std::make_unique("tpc-trackStudy-cl.root", "recreate"); + } +} + +void TPCRefitterSpec::run(ProcessingContext& pc) +{ + mTFCount++; + if (mTFCount < mTFStart || mTFCount > mTFEnd) { + LOGP(info, "Skipping TF {}", mTFCount); + return; + } + + o2::globaltracking::RecoContainer recoData; + recoData.collectData(pc, *mDataRequest.get()); // select tracks of needed type, with minimal cuts, the real selected will be done in the vertexer + updateTimeDependentParams(pc); // Make sure this is called after recoData.collectData, which may load some conditions + process(recoData); + + if (mTFCount > mTFEnd) { + LOGP(info, "Stopping processing after TF {}", mTFCount); + pc.services().get().endOfStream(); + return; + } +} + +void TPCRefitterSpec::updateTimeDependentParams(ProcessingContext& pc) +{ + o2::base::GRPGeomHelper::instance().checkUpdates(pc); + mTPCVDriftHelper.extractCCDBInputs(pc); + mTPCCorrMapsLoader.extractCCDBInputs(pc); + static bool initOnceDone = false; + if (!initOnceDone) { // this params need to be queried only once + initOnceDone = true; + // none at the moment + } + // we may have other params which need to be queried regularly + bool updateMaps = false; + if (mTPCCorrMapsLoader.isUpdated()) { + mTPCCorrMapsLoader.acknowledgeUpdate(); + updateMaps = true; + } + if (mTPCVDriftHelper.isUpdated()) { + LOGP(info, "Updating TPC fast transform map with new VDrift factor of {} wrt reference {} and DriftTimeOffset correction {} wrt {} from source {}", + mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, + mTPCVDriftHelper.getVDriftObject().timeOffsetCorr, mTPCVDriftHelper.getVDriftObject().refTimeOffset, + mTPCVDriftHelper.getSourceName()); + mTPCVDriftHelper.acknowledgeUpdate(); + updateMaps = true; + } + if (updateMaps) { + mTPCCorrMapsLoader.updateVDrift(mTPCVDriftHelper.getVDriftObject().corrFact, mTPCVDriftHelper.getVDriftObject().refVDrift, mTPCVDriftHelper.getVDriftObject().getTimeOffset()); + } +} + +void TPCRefitterSpec::process(o2::globaltracking::RecoContainer& recoData) +{ + static long counter = -1; + auto prop = o2::base::Propagator::Instance(); + + mTPCTracksArray = recoData.getTPCTracks(); + mTPCTrackClusIdx = recoData.getTPCTracksClusterRefs(); + mTPCClusterIdxStruct = &recoData.inputsTPCclusters->clusterIndex; + mTPCRefitterShMap = recoData.clusterShMapTPC; + mTPCRefitterOccMap = recoData.occupancyMapTPC; + + std::vector intRecs; + if (mUseMC) { // extract MC tracks + const o2::steer::DigitizationContext* digCont = nullptr; + if (!mcReader.initFromDigitContext("collisioncontext.root")) { + throw std::invalid_argument("initialization of MCKinematicsReader failed"); + } + digCont = mcReader.getDigitizationContext(); + intRecs = digCont->getEventRecords(); + mTPCTrkLabels = recoData.getTPCTracksMCLabels(); + } + + mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, &mTPCCorrMapsLoader, prop->getNominalBz(), mTPCTrackClusIdx.data(), 0, mTPCRefitterShMap.data(), mTPCRefitterOccMap.data(), mTPCRefitterOccMap.size(), nullptr, prop); + mTPCRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500 + + float vdriftTB = mTPCVDriftHelper.getVDriftObject().getVDrift() * o2::tpc::ParameterElectronics::Instance().ZbinWidth; // VDrift expressed in cm/TimeBin + float tpcTBBias = mTPCVDriftHelper.getVDriftObject().getTimeOffset() / (8 * o2::constants::lhc::LHCBunchSpacingMUS); + std::vector clSector, clRow; + std::vector clX, clY, clZ, clXI, clYI, clZI; // *I are the uncorrected cluster positions + float dcar, dcaz, dcarRef, dcazRef; + + auto dumpClusters = [this] { + static int tf = 0; + const auto* corrMap = this->mTPCCorrMapsLoader.getCorrMap(); + for (int sector = 0; sector < 36; sector++) { + float alp = ((sector % 18) * 20 + 10) * TMath::DegToRad(); + float sn = TMath::Sin(alp), cs = TMath::Cos(alp); + for (int row = 0; row < 152; row++) { + for (int ic = 0; ic < this->mTPCClusterIdxStruct->nClusters[sector][row]; ic++) { + const auto cl = this->mTPCClusterIdxStruct->clusters[sector][row][ic]; + float x, y, z, xG, yG; + corrMap->TransformIdeal(sector, row, cl.getPad(), cl.getTime(), x, y, z, 0); + o2::math_utils::detail::rotateZ(x, y, xG, yG, sn, cs); + LOGP(debug, "tf:{} s:{} r:{} p:{} t:{} qm:{} qt:{} f:{} x:{} y:{} z:{}", tf, sector, row, cl.getPad(), cl.getTime(), cl.getQmax(), cl.getQtot(), cl.getFlags(), x, y, z); + (*mDBGOutCl) << "tpccl" + << "tf=" << tf << "sect=" << sector << "row=" << row << "pad=" << cl.getPad() << "time=" << cl.getTime() << "qmax=" << cl.getQmax() << "qtot=" << cl.getQtot() + << "sigT=" << cl.getSigmaTime() << "sigP=" << cl.getSigmaPad() + << "flags=" << cl.getFlags() + << "x=" << x << "y=" << y << "z=" << z << "xg=" << xG << "yg=" << yG + << "\n"; + } + } + } + tf++; + }; + + if (mDBGOutCl) { + dumpClusters(); + } + + for (size_t itr = 0; itr < mTPCTracksArray.size(); itr++) { + auto tr = mTPCTracksArray[itr]; // create track copy + if (tr.hasBothSidesClusters()) { + continue; + } + + //========================================================================= + // create refitted copy + auto trackRefit = [itr, this](o2::track::TrackParCov& trc, float t, float chi2refit) -> bool { + int retVal = mUseGPUModel ? this->mTPCRefitter->RefitTrackAsGPU(trc, this->mTPCTracksArray[itr].getClusterRef(), t, &chi2refit, false, true) + : this->mTPCRefitter->RefitTrackAsTrackParCov(trc, this->mTPCTracksArray[itr].getClusterRef(), t, &chi2refit, false, true); + if (retVal < 0) { + LOGP(warn, "Refit failed ({}) with time={}: track#{}[{}]", retVal, t, counter, trc.asString()); + return false; + } + return true; + }; + + auto trackProp = [&tr, itr, prop, this](o2::track::TrackParCov& trc) -> bool { + if (!trc.rotate(tr.getAlpha())) { + LOGP(warn, "Rotation to original track alpha {} failed, track#{}[{}]", tr.getAlpha(), counter, trc.asString()); + return false; + } + float xtgt = this->mXRef; + if (mUseR && !trc.getXatLabR(this->mXRef, xtgt, prop->getNominalBz(), o2::track::DirInward)) { + xtgt = 0; + return false; + } + if (!prop->PropagateToXBxByBz(trc, xtgt)) { + LOGP(warn, "Propagation to X={} failed, track#{}[{}]", xtgt, counter, trc.asString()); + return false; + } + return true; + }; + + auto prepClus = [this, &tr, &clSector, &clRow, &clX, &clY, &clZ, &clXI, &clYI, &clZI](float t) { // extract cluster info + clSector.clear(); + clRow.clear(); + clXI.clear(); + clYI.clear(); + clZI.clear(); + clX.clear(); + clY.clear(); + clZ.clear(); + int count = tr.getNClusters(); + const auto* corrMap = this->mTPCCorrMapsLoader.getCorrMap(); + const o2::tpc::ClusterNative* cl = nullptr; + for (int ic = count; ic--;) { + uint8_t sector, row; + cl = &tr.getCluster(this->mTPCTrackClusIdx, ic, *this->mTPCClusterIdxStruct, sector, row); + clSector.push_back(sector); + clRow.push_back(row); + float x, y, z; + // ideal transformation without distortions + corrMap->TransformIdeal(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track + clXI.push_back(x); + clYI.push_back(y); + clZI.push_back(z); + + // transformation without distortions + mTPCCorrMapsLoader.Transform(sector, row, cl->getPad(), cl->getTime(), x, y, z, t); // nominal time of the track + clX.push_back(x); + clY.push_back(y); + clZ.push_back(z); + } + }; + + //========================================================================= + + auto trf = tr.getOuterParam(); // we refit inward original track + float chi2refit = 0; + if (!trackRefit(trf, tr.getTime0(), chi2refit) || !trackProp(trf)) { + continue; + } + + // propagate original track + if (!trackProp(tr)) { + continue; + } + + if (mWriteTrackClusters) { + prepClus(tr.getTime0()); // original clusters + } + + if (mEnableDCA) { + dcar = dcaz = dcarRef = dcazRef = 9999.f; + if ((trf.getPt() > mDCAMinPt) && (tr.getNClusters() > mDCAMinNCl)) { + getDCAs(trf, dcarRef, dcazRef); + getDCAs(tr, dcar, dcaz); + } + } + + counter++; + // store results + (*mDBGOut) << "tpcIni" + << "counter=" << counter + << "iniTrack=" << tr + << "iniTrackRef=" << trf + << "time=" << tr.getTime0() + << "chi2refit=" << chi2refit; + + if (mWriteTrackClusters) { + (*mDBGOut) << "tpcIni" + << "clSector=" << clSector + << "clRow=" << clRow + << "clX=" << clX + << "clY=" << clY + << "clZ=" << clZ + << "clXI=" << clXI // ideal (uncorrected) cluster positions + << "clYI=" << clYI // ideal (uncorrected) cluster positions + << "clZI=" << clZI; // ideal (uncorrected) cluster positions + } + + if (mEnableDCA) { + (*mDBGOut) << "tpcIni" + << "dcar=" << dcar + << "dcaz=" << dcaz + << "dcarRef=" << dcarRef + << "dcazRef=" << dcazRef; + } + + (*mDBGOut) << "tpcIni" + << "\n"; + + float dz = 0; + + if (mUseMC) { // impose MC time in TPC timebin and refit inward after resetted covariance + // extract MC truth + const o2::MCTrack* mcTrack = nullptr; + auto lbl = mTPCTrkLabels[itr]; + if (!lbl.isValid() || !(mcTrack = mcReader.getTrack(lbl))) { + break; + } + long bc = intRecs[lbl.getEventID()].toLong(); // bunch crossing of the interaction + float bcTB = bc / 8. + tpcTBBias; // the same in TPC timebins, accounting for the TPC time bias + // create MC truth track in O2 format + std::array xyz{(float)mcTrack->GetStartVertexCoordinatesX(), (float)mcTrack->GetStartVertexCoordinatesY(), (float)mcTrack->GetStartVertexCoordinatesZ()}, + pxyz{(float)mcTrack->GetStartVertexMomentumX(), (float)mcTrack->GetStartVertexMomentumY(), (float)mcTrack->GetStartVertexMomentumZ()}; + TParticlePDG* pPDG = TDatabasePDG::Instance()->GetParticle(mcTrack->GetPdgCode()); + if (!pPDG) { + break; + } + o2::track::TrackPar mctrO2(xyz, pxyz, TMath::Nint(pPDG->Charge() / 3), false); + // + // propagate it to the alpha/X of the reconstructed track + if (!mctrO2.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(mctrO2, tr.getX())) { + break; + } + // now create a properly refitted track with correct time and distortions correction + { + auto trfm = tr.getOuterParam(); // we refit inward + // impose MC time in TPC timebin and refit inward after resetted covariance + float chi2refit = 0; + if (!trackRefit(trfm, bcTB, chi2refit) || !trfm.rotate(tr.getAlpha()) || !prop->PropagateToXBxByBz(trfm, tr.getX())) { + LOGP(warn, "Failed to propagate MC-time refitted track#{} [{}] to X/alpha of original track [{}]", counter, trfm.asString(), tr.asString()); + break; + } + // estimate Z shift in case of no-distortions + dz = (tr.getTime0() - bcTB) * vdriftTB; + if (tr.hasCSideClustersOnly()) { + dz = -dz; + } + // + prepClus(bcTB); // clusters for MC time + (*mDBGOut) << "tpcMC" + << "counter=" << counter + << "movTrackRef=" << trfm + << "mcTrack=" << mctrO2 + << "imposedTB=" << bcTB + << "chi2refit=" << chi2refit + << "dz=" << dz + << "clX=" << clX + << "clY=" << clY + << "clZ=" << clZ + << "\n"; + } + break; + } + } +} + +void TPCRefitterSpec::endOfStream(EndOfStreamContext& ec) +{ + mDBGOut.reset(); + mDBGOutCl.reset(); +} + +void TPCRefitterSpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) +{ + if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { + return; + } + if (mTPCVDriftHelper.accountCCDBInputs(matcher, obj)) { + return; + } + if (mTPCCorrMapsLoader.accountCCDBInputs(matcher, obj)) { + return; + } +} + +bool TPCRefitterSpec::getDCAs(const o2::track::TrackPar& track, float& dcar, float& dcaz) +{ + auto propagator = o2::base::Propagator::Instance(); + o2::gpu::gpustd::array dca; + const o2::math_utils::Point3D refPoint{0, 0, 0}; + o2::track::TrackPar propTrack(track); + const auto ok = propagator->propagateToDCABxByBz(refPoint, propTrack, 2., o2::base::Propagator::MatCorrType::USEMatCorrLUT, &dca); + dcar = dca[0]; + dcaz = dca[1]; + if (!ok) { + dcar = 9998.; + dcaz = 9998.; + } + return ok; +} + +DataProcessorSpec getTPCRefitterSpec(GTrackID::mask_t srcTracks, GTrackID::mask_t srcClusters, bool useMC, const o2::tpc::CorrectionMapsLoaderGloOpts& sclOpts) +{ + std::vector outputs; + Options opts{ + {"target-x", VariantType::Float, 83.f, {"Try to propagate to this radius"}}, + {"dump-clusters", VariantType::Bool, false, {"dump all clusters"}}, + {"write-track-clusters", VariantType::Bool, false, {"write clusters associated to the track, uncorrected and corrected positions"}}, + {"tf-start", VariantType::Int, 0, {"1st TF to process"}}, + {"tf-end", VariantType::Int, 999999999, {"last TF to process"}}, + {"use-gpu-fitter", VariantType::Bool, false, {"use GPU track model for refit instead of TrackParCov"}}, + {"use-r-as-x", VariantType::Bool, false, {"Use radius instead of target sector X"}}, + {"enable-dcas", VariantType::Bool, false, {"Propagate to DCA and add it to the tree"}}, + {"dcaMinPt", VariantType::Float, 1.f, {"Min pT of tracks propagated to DCA"}}, + {"dcaMinNCl", VariantType::Int, 80, {"Min number of clusters for tracks propagated to DCA"}}, + }; + auto dataRequest = std::make_shared(); + + dataRequest->requestTracks(srcTracks, useMC); + dataRequest->requestClusters(srcClusters, useMC); + auto ggRequest = std::make_shared(false, // orbitResetTime + true, // GRPECS=true + false, // GRPLHCIF + true, // GRPMagField + true, // askMatLUT + o2::base::GRPGeomRequest::Aligned, // geometry + dataRequest->inputs, + true); + o2::tpc::VDriftHelper::requestCCDBInputs(dataRequest->inputs); + o2::tpc::CorrectionMapsLoader::requestCCDBInputs(dataRequest->inputs, opts, sclOpts); + + return DataProcessorSpec{ + "tpc-refitter", + dataRequest->inputs, + outputs, + AlgorithmSpec{adaptFromTask(dataRequest, ggRequest, sclOpts, srcTracks, useMC)}, + opts}; +} + +} // namespace o2::trackstudy diff --git a/Detectors/TPC/workflow/src/TPCScalerSpec.cxx b/Detectors/TPC/workflow/src/TPCScalerSpec.cxx index b184502dfc945..6065079c05e96 100644 --- a/Detectors/TPC/workflow/src/TPCScalerSpec.cxx +++ b/Detectors/TPC/workflow/src/TPCScalerSpec.cxx @@ -85,10 +85,12 @@ class TPCScalerSpec : public Task const auto orbitResetTimeMS = o2::base::GRPGeomHelper::instance().getOrbitResetTimeMS(); const auto firstTFOrbit = pc.services().get().firstTForbit; const double timestamp = orbitResetTimeMS + firstTFOrbit * o2::constants::lhc::LHCOrbitMUS * 0.001; - + int currRun = pc.services().get().runNumber; if (mEnableMShape) { - if ((mMShapeTPCScaler.getRun() != -1) && pc.services().get().runNumber != mMShapeTPCScaler.getRun()) { - LOGP(error, "Run number {} of processed data and run number {} of loaded TPC M-shape scaler doesnt match!", pc.services().get().runNumber, mMShapeTPCScaler.getRun()); + static int runWarningMS = -1; + if ((mMShapeTPCScaler.getRun() != -1) && currRun != mMShapeTPCScaler.getRun() && runWarningMS != currRun) { + LOGP(alarm, "Run number {} of processed data and run number {} of loaded TPC M-shape scaler doesnt match!", pc.services().get().runNumber, mMShapeTPCScaler.getRun()); + runWarningMS = currRun; } const auto& boundaryPotential = mMShapeTPCScaler.getBoundaryPotential(timestamp); @@ -139,8 +141,10 @@ class TPCScalerSpec : public Task } if (mEnableIDCs) { - if (pc.services().get().runNumber != mTPCScaler.getRun()) { - LOGP(error, "Run number {} of processed data and run number {} of loaded TPC scaler doesnt match!", pc.services().get().runNumber, mTPCScaler.getRun()); + static int runWarningIDC = -1; + if (pc.services().get().runNumber != mTPCScaler.getRun() && runWarningIDC != currRun) { + LOGP(alarm, "Run number {} of processed data and run number {} of loaded TPC scaler doesnt match!", pc.services().get().runNumber, mTPCScaler.getRun()); + runWarningIDC = currRun; } float scalerA = mTPCScaler.getMeanScaler(timestamp, o2::tpc::Side::A); float scalerC = mTPCScaler.getMeanScaler(timestamp, o2::tpc::Side::C); diff --git a/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx b/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx index 00204afa1ea2e..4ab34762fd645 100644 --- a/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx +++ b/Detectors/TPC/workflow/src/TPCTimeSeriesSpec.cxx @@ -99,7 +99,7 @@ class TPCTimeSeries : public Task mXOuterMatching = ic.options().get("refX-for-outer-ITS"); mUseMinBiasTrigger = !ic.options().get("disable-min-bias-trigger"); - if (mSampleTsallis) { + if (mUnbinnedWriter) { for (int iThread = 0; iThread < mNThreads; ++iThread) { mGenerator.emplace_back(std::mt19937(std::random_device{}())); } @@ -1215,11 +1215,11 @@ class TPCTimeSeries : public Task o2::track::TrackPar trackITS(tracksITS[idxITSTrack]); const bool propITSOk = propagator->propagateTo(trackITS, trackITSTPCTmp.getX(), false, mMaxSnp, mFineStep, mMatType); if (propITSOk) { - deltaP0 = track.getParam(0) - trackITSTPCTmp.getParam(0); - deltaP1 = track.getParam(1) - trackITSTPCTmp.getParam(1); - deltaP2 = track.getParam(2) - trackITSTPCTmp.getParam(2); - deltaP3 = track.getParam(3) - trackITSTPCTmp.getParam(3); - deltaP4 = track.getParam(4) - trackITSTPCTmp.getParam(4); + deltaP0 = track.getParam(0) - trackITS.getParam(0); + deltaP1 = track.getParam(1) - trackITS.getParam(1); + deltaP2 = track.getParam(2) - trackITS.getParam(2); + deltaP3 = track.getParam(3) - trackITS.getParam(3); + deltaP4 = track.getParam(4) - trackITS.getParam(4); mBufferVals[iThread].front().setDeltaParam(deltaP2, deltaP3, deltaP4); } } @@ -1304,6 +1304,48 @@ class TPCTimeSeries : public Task } const int triggerMask = 0x1 * minBiasOk + 0x2 * writeData; + float deltaP2ConstrVtx = -999; + float deltaP3ConstrVtx = -999; + float deltaP4ConstrVtx = -999; + + // cov of TPC track constrained at vertex + float covTPCConstrVtxP2 = -999; + float covTPCConstrVtxP3 = -999; + float covTPCConstrVtxP4 = -999; + + // cov of ITS-TPC track at vertex + float covITSTPCConstrVtxP2 = -999; + float covITSTPCConstrVtxP3 = -999; + float covITSTPCConstrVtxP4 = -999; + + float covTPCAtVertex0 = -999; + float covTPCAtVertex1 = -999; + + const bool contributeToVertex = (idxITSTPC.back() != -1); + if (hasITSTPC && contributeToVertex) { + o2::track::TrackParCov trackITSTPCTmp = tracksITSTPC[idxITSTPC.front()]; + o2::gpu::gpustd::array dcaITSTPCTmp{-1, -1}; + if (propagator->propagateToDCA(vertex.getXYZ(), trackITSTPCTmp, propagator->getNominalBz(), mFineStep, mMatType, &dcaITSTPCTmp)) { + o2::track::TrackParCov trackTPC = tracksTPC[iTrk]; + if (trackTPC.rotate(trackITSTPCTmp.getAlpha()) && propagator->propagateTo(trackTPC, trackITSTPCTmp.getX(), false, mMaxSnp, mFineStep, mMatType)) { + // store covariance of TPC track at vertex + covTPCAtVertex0 = trackTPC.getCovarElem(0, 0); + covTPCAtVertex1 = trackTPC.getCovarElem(1, 1); + + trackTPC.update(vertex); + deltaP2ConstrVtx = trackTPC.getParam(2) - trackITSTPCTmp.getParam(2); + deltaP3ConstrVtx = trackTPC.getParam(3) - trackITSTPCTmp.getParam(3); + deltaP4ConstrVtx = trackTPC.getParam(4) - trackITSTPCTmp.getParam(4); + covTPCConstrVtxP2 = trackTPC.getCovarElem(2, 2); + covTPCConstrVtxP3 = trackTPC.getCovarElem(3, 3); + covTPCConstrVtxP4 = trackTPC.getCovarElem(4, 4); + covITSTPCConstrVtxP2 = trackITSTPCTmp.getCovarElem(2, 2); + covITSTPCConstrVtxP3 = trackITSTPCTmp.getCovarElem(3, 3); + covITSTPCConstrVtxP4 = trackITSTPCTmp.getCovarElem(4, 4); + } + } + } + *mStreamer[iThread] << "treeTimeSeries" // DCAs << "triggerMask=" << triggerMask @@ -1343,6 +1385,21 @@ class TPCTimeSeries : public Task << "chi2ITS=" << chi2ITS << "chi2match_ITSTPC=" << chi2match_ITSTPC << "PID=" << trkOrig.getPID().getID() + // TPC cov at vertex (without vertex constrained) + << "covTPCAtVertex0=" << covTPCAtVertex0 + << "covTPCAtVertex1=" << covTPCAtVertex1 + // TPC cov at vertex (with vertex constrained) + << "covTPCConstrVtxP2=" << covTPCConstrVtxP2 + << "covTPCConstrVtxP3=" << covTPCConstrVtxP3 + << "covTPCConstrVtxP4=" << covTPCConstrVtxP4 + // ITS-TPC cov at vertex (with vertex constrained) + << "covITSTPCConstrVtxP2=" << covITSTPCConstrVtxP2 + << "covITSTPCConstrVtxP3=" << covITSTPCConstrVtxP3 + << "covITSTPCConstrVtxP4=" << covITSTPCConstrVtxP4 + // delta Parameter at vertex with TPC track constrained at vertex + << "deltaP2ConstrVtx=" << deltaP2ConstrVtx + << "deltaP3ConstrVtx=" << deltaP3ConstrVtx + << "deltaP4ConstrVtx=" << deltaP4ConstrVtx // << "deltaPar0=" << deltaP0 << "deltaPar1=" << deltaP1 diff --git a/Detectors/TPC/workflow/src/ZSSpec.cxx b/Detectors/TPC/workflow/src/ZSSpec.cxx index 181efbb1824e7..9ae422ae099d9 100644 --- a/Detectors/TPC/workflow/src/ZSSpec.cxx +++ b/Detectors/TPC/workflow/src/ZSSpec.cxx @@ -99,7 +99,7 @@ DataProcessorSpec getZSEncoderSpec(std::vector const& tpcSectors, bool outR auto& sizes = processAttributes->sizes; auto& verbosity = processAttributes->verbosity; - processAttributes->config.configGRP.solenoidBz = 5.00668; + processAttributes->config.configGRP.solenoidBzNominalGPU = 5.00668; std::function&)> digitsFilter = nullptr; if (processAttributes->globalConfig.zsOnTheFlyDigitsFilter) { digitsFilter = [processAttributes](std::vector& digits) { diff --git a/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx b/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx new file mode 100644 index 0000000000000..9a0fdc0e26b53 --- /dev/null +++ b/Detectors/TPC/workflow/src/tpc-refitter-workflow.cxx @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "DetectorsCommonDataFormats/DetID.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" +#include "Framework/CallbacksPolicy.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/ConfigParamSpec.h" +#include "GlobalTrackingWorkflowHelpers/InputHelper.h" +#include "ReconstructionDataFormats/GlobalTrackID.h" +#include "TPCCalibration/CorrectionMapsLoader.h" +#include "TPCWorkflow/TPCRefitter.h" +#include "TPCWorkflow/TPCScalerSpec.h" +#include "DetectorsBase/DPLWorkflowUtils.h" + +using namespace o2::framework; +using GID = o2::dataformats::GlobalTrackID; +using DetID = o2::detectors::DetID; + +// ------------------------------------------------------------------ +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::vector options{ + {"enable-mc", o2::framework::VariantType::Bool, false, {"enable MC propagation"}}, + {"track-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of track sources to use"}}, + {"cluster-sources", VariantType::String, std::string{GID::ALL}, {"comma-separated list of cluster sources to use"}}, + {"disable-root-input", VariantType::Bool, false, {"disable root-files input reader"}}, + {"enable-M-shape-correction", VariantType::Bool, false, {"Enable M-shape distortion correction"}}, + {"disable-IDC-scalers", VariantType::Bool, false, {"Disable TPC scalers for space-charge distortion fluctuation correction"}}, + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::tpc::CorrectionMapsLoader::addGlobalOptions(options); + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + + GID::mask_t allowedSourcesTrc = GID::getSourcesMask("TPC"); + GID::mask_t allowedSourcesClus = GID::getSourcesMask("TPC"); + + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + auto useMC = configcontext.options().get("enable-mc"); + auto sclOpt = o2::tpc::CorrectionMapsLoader::parseGlobalOptions(configcontext.options()); + GID::mask_t srcTrc = allowedSourcesTrc & GID::getSourcesMask(configcontext.options().get("track-sources")); + GID::mask_t srcCls = allowedSourcesClus & GID::getSourcesMask(configcontext.options().get("cluster-sources")); + if (sclOpt.requestCTPLumi) { + srcTrc = srcTrc | GID::getSourcesMask("CTP"); + srcCls = srcCls | GID::getSourcesMask("CTP"); + } + if (sclOpt.lumiType == 2) { + const auto enableMShape = configcontext.options().get("enable-M-shape-correction"); + const auto enableIDCs = !configcontext.options().get("disable-IDC-scalers"); + specs.emplace_back(o2::tpc::getTPCScalerSpec(enableIDCs, enableMShape)); + } + + o2::globaltracking::InputHelper::addInputSpecs(configcontext, specs, srcCls, srcTrc, srcTrc, useMC); + o2::globaltracking::InputHelper::addInputSpecsPVertex(configcontext, specs, useMC); // P-vertex is always needed + specs.emplace_back(o2::trackstudy::getTPCRefitterSpec(srcTrc, srcCls, useMC, sclOpt)); + + // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + + return std::move(specs); +} diff --git a/Detectors/TRD/README.md b/Detectors/TRD/README.md index 0c323e348e181..c7292d690003c 100644 --- a/Detectors/TRD/README.md +++ b/Detectors/TRD/README.md @@ -8,5 +8,6 @@ * \subpage refDetectorsTRDcalibration * \subpage refDetectorsTRDsimulation * \subpage refDetectorsTRDreconstruction +* \subpage refDetectorsTRDpid * \subpage refDetectorsTRDworkflow /doxy --> diff --git a/Detectors/TRD/base/include/TRDBase/TrackletTransformer.h b/Detectors/TRD/base/include/TRDBase/TrackletTransformer.h index 2b6c793a468e3..ca9e71d392231 100644 --- a/Detectors/TRD/base/include/TRDBase/TrackletTransformer.h +++ b/Detectors/TRD/base/include/TRDBase/TrackletTransformer.h @@ -33,6 +33,7 @@ class TrackletTransformer void setCalVdriftExB(const CalVdriftExB* cal) { mCalVdriftExB = cal; }; void setApplyXOR() { mApplyXOR = true; } void setApplyShift(bool f) { mApplyShift = f; } + bool isShiftApplied() const { return mApplyShift; } float calculateZ(int padrow, const PadPlane* padPlane) const; diff --git a/Detectors/TRD/calibration/src/CalibratorGain.cxx b/Detectors/TRD/calibration/src/CalibratorGain.cxx index 028fcdc2bdc23..77efeaeb36f1e 100644 --- a/Detectors/TRD/calibration/src/CalibratorGain.cxx +++ b/Detectors/TRD/calibration/src/CalibratorGain.cxx @@ -52,6 +52,7 @@ void CalibratorGain::initProcessing() if (mInitDone) { return; } + LOG(info) << "Initializing the processing"; for (int iDet = 0; iDet < MAXCHAMBER; ++iDet) { mdEdxhists[iDet] = std::make_unique(Form("hdEdx%d", iDet), "dEdx", NBINSGAINCALIB, 0., NBINSGAINCALIB); } @@ -104,6 +105,7 @@ void CalibratorGain::retrievePrev(o2::framework::ProcessingContext& pc) void CalibratorGain::finalizeSlot(Slot& slot) { LOG(info) << "Finalizing gain calibration"; + print(); // to see current number of slots and their entries // do actual calibration for the data provided in the given slot TStopwatch timer; timer.Start(); @@ -128,7 +130,7 @@ void CalibratorGain::finalizeSlot(Slot& slot) // Fitting histogram mFitFunction->SetParameter(0, mdEdxhists[iDet]->GetMean() / 1.25); - int fitStatus = mdEdxhists[iDet]->Fit("fitConvLandau", "LQB", "", 1, NBINSGAINCALIB - 4); + int fitStatus = mdEdxhists[iDet]->Fit("fitConvLandau", "LQB0", "", 1, NBINSGAINCALIB - 4); if (fitStatus != 0) { LOGF(warn, "Fit for chamber %i failed, nEntries: %d", iDet, nEntries); diff --git a/Detectors/TRD/pid/CMakeLists.txt b/Detectors/TRD/pid/CMakeLists.txt index 012fa642a3047..8894c4384b071 100644 --- a/Detectors/TRD/pid/CMakeLists.txt +++ b/Detectors/TRD/pid/CMakeLists.txt @@ -22,10 +22,11 @@ o2_add_library(TRDPID fmt::fmt TARGETVARNAME libname) -if(ONNXRuntime_FOUND) - target_compile_definitions(${libname} PRIVATE TRDPID_WITH_ONNX) - target_link_libraries(${libname} ONNXRuntime::ONNXRuntime) - target_sources(${libname} src/ML.cxx) +# if(onnxruntime_FOUND) # ONNXRuntime code in TRD currently disabled since it is not tested +if(0) + target_compile_definitions(${libname} PUBLIC TRDPID_WITH_ONNX) + target_link_libraries(${libname} PRIVATE onnxruntime::onnxruntime) + target_sources(${libname} PRIVATE src/ML.cxx) o2_target_root_dictionary(TRDPID HEADERS include/TRDPID/PIDBase.h include/TRDPID/PIDParameters.h diff --git a/Detectors/TRD/pid/README.md b/Detectors/TRD/pid/README.md index 27101dae09eb1..0807dad4802fd 100644 --- a/Detectors/TRD/pid/README.md +++ b/Detectors/TRD/pid/README.md @@ -1,3 +1,7 @@ + + # Particle Identification with TRD ## Usage Activate PID during tracking with the '--with-pid' flag. diff --git a/Detectors/TRD/pid/include/TRDPID/ML.h b/Detectors/TRD/pid/include/TRDPID/ML.h index 0b8d8ea8ea97b..210dfb56d80ff 100644 --- a/Detectors/TRD/pid/include/TRDPID/ML.h +++ b/Detectors/TRD/pid/include/TRDPID/ML.h @@ -21,15 +21,17 @@ #include "DataFormatsTRD/PID.h" #include "Framework/ProcessingContext.h" #include "Framework/InputRecord.h" +#if __has_include() #include +#else +#include +#endif #include #include #include #include -namespace o2 -{ -namespace trd +namespace o2::trd { /// This is the ML Base class which defines the interface all machine learning @@ -68,10 +70,15 @@ class ML : public PIDBase [](void* param, OrtLoggingLevel severity, const char* category, const char* logid, const char* code_location, const char* message) { LOG(warn) << "Ort " << severity << ": [" << logid << "|" << category << "|" << code_location << "]: " << message << ((intptr_t)param == 3 ? " [valid]" : " [error]"); }, - (void*)3}; ///< ONNX enviroment - const OrtApi& mApi{Ort::GetApi()}; ///< ONNX api + (void*)3}; ///< ONNX enviroment + const OrtApi& mApi{Ort::GetApi()}; ///< ONNX api +#if __has_include() std::unique_ptr mSession; ///< ONNX session - Ort::SessionOptions mSessionOptions; ///< ONNX session options +#else + std::unique_ptr mSession; ///< ONNX session +#endif + Ort::SessionOptions mSessionOptions; ///< ONNX session options + Ort::AllocatorWithDefaultOptions mAllocator; // Input/Output std::vector mInputNames; ///< model input names @@ -122,7 +129,6 @@ class PY final : public ML ClassDefNV(PY, 1); }; -} // namespace trd -} // namespace o2 +} // namespace o2::trd #endif diff --git a/Detectors/TRD/pid/src/ML.cxx b/Detectors/TRD/pid/src/ML.cxx index 2ce3b6876a893..bee46b27767a8 100644 --- a/Detectors/TRD/pid/src/ML.cxx +++ b/Detectors/TRD/pid/src/ML.cxx @@ -28,7 +28,11 @@ #include "DetectorsBase/Propagator.h" #include +#if __has_include() #include +#else +#include +#endif #include #include @@ -64,20 +68,33 @@ void ML::init(o2::framework::ProcessingContext& pc) LOG(info) << "Set GraphOptimizationLevel to " << mParams.graphOptimizationLevel; // create actual session +#if __has_include() mSession = std::make_unique(mEnv, reinterpret_cast(model_data.data()), model_data.size(), mSessionOptions); +#else + mSession = std::make_unique(mEnv, reinterpret_cast(model_data.data()), model_data.size(), mSessionOptions); +#endif LOG(info) << "ONNX runtime session created"; // print name/shape of inputs - mInputNames = mSession->GetInputNames(); - mInputShapes = mSession->GetInputShapes(); + for (size_t i = 0; i < mSession->GetInputCount(); ++i) { + mInputNames.push_back(mSession->GetInputNameAllocated(i, mAllocator).get()); + } + for (size_t i = 0; i < mSession->GetInputCount(); ++i) { + mInputShapes.emplace_back(mSession->GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); + } + for (size_t i = 0; i < mSession->GetOutputCount(); ++i) { + mOutputNames.push_back(mSession->GetOutputNameAllocated(i, mAllocator).get()); + } + for (size_t i = 0; i < mSession->GetOutputCount(); ++i) { + mOutputShapes.emplace_back(mSession->GetOutputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); + } + LOG(info) << "Input Node Name/Shape (" << mInputNames.size() << "):"; for (size_t i = 0; i < mInputNames.size(); i++) { LOG(info) << "\t" << mInputNames[i] << " : " << printShape(mInputShapes[i]); } // print name/shape of outputs - mOutputNames = mSession->GetOutputNames(); - mOutputShapes = mSession->GetOutputShapes(); LOG(info) << "Output Node Name/Shape (" << mOutputNames.size() << "):"; for (size_t i = 0; i < mOutputNames.size(); i++) { LOG(info) << "\t" << mOutputNames[i] << " : " << printShape(mOutputShapes[i]); @@ -91,8 +108,15 @@ float ML::process(const TrackTRD& trk, const o2::globaltracking::RecoContainer& try { auto input = prepareModelInput(trk, inputTracks); // create memory mapping to vector above +#if __has_include() auto inputTensor = Ort::Experimental::Value::CreateTensor(input.data(), input.size(), {static_cast(input.size()) / mInputShapes[0][1], mInputShapes[0][1]}); +#else + Ort::MemoryInfo mem_info = + Ort::MemoryInfo::CreateCpu(OrtAllocatorType::OrtArenaAllocator, OrtMemType::OrtMemTypeDefault); + auto inputTensor = Ort::Value::CreateTensor(mem_info, input.data(), input.size(), + {static_cast(input.size()) / mInputShapes[0][1], mInputShapes[0][1]}); +#endif std::vector ortTensor; ortTensor.push_back(std::move(inputTensor)); auto outTensor = mSession->Run(mInputNames, ortTensor, mOutputNames); diff --git a/Detectors/TRD/reconstruction/README.md b/Detectors/TRD/reconstruction/README.md index f4d4f2420ee5a..ba7de48cdbbd8 100644 --- a/Detectors/TRD/reconstruction/README.md +++ b/Detectors/TRD/reconstruction/README.md @@ -1,5 +1,5 @@ # TRD Reconstruction diff --git a/Detectors/TRD/workflow/include/TRDWorkflow/GainCalibSpec.h b/Detectors/TRD/workflow/include/TRDWorkflow/GainCalibSpec.h index eb6641e05adf2..295ce0bf1d0ac 100644 --- a/Detectors/TRD/workflow/include/TRDWorkflow/GainCalibSpec.h +++ b/Detectors/TRD/workflow/include/TRDWorkflow/GainCalibSpec.h @@ -72,7 +72,7 @@ class GainCalibDevice : public o2::framework::Task o2::base::GRPGeomHelper::instance().checkUpdates(pc); auto dataGainCalib = pc.inputs().get>("input"); o2::base::TFIDInfoHelper::fillTFIDInfo(pc, mCalibrator->getCurrentTFInfo()); - LOG(info) << "Processing TF " << mCalibrator->getCurrentTFInfo().tfCounter << " with " << dataGainCalib.size() << " GainCalibHistos entries"; + LOG(debug) << "Processing TF " << mCalibrator->getCurrentTFInfo().tfCounter << " with " << dataGainCalib.size() << " GainCalibHistos entries"; mCalibrator->process(dataGainCalib); if (pc.transitionState() == TransitionHandlingState::Requested) { LOG(info) << "Run stop requested, finalizing"; diff --git a/Detectors/TRD/workflow/io/CMakeLists.txt b/Detectors/TRD/workflow/io/CMakeLists.txt index 4405d12b4f987..a3aea1ce87795 100644 --- a/Detectors/TRD/workflow/io/CMakeLists.txt +++ b/Detectors/TRD/workflow/io/CMakeLists.txt @@ -34,6 +34,10 @@ o2_add_executable(track-reader COMPONENT_NAME trd SOURCES src/trd-track-reader-workflow.cxx PUBLIC_LINK_LIBRARIES O2::TRDWorkflowIO) +o2_add_executable(calib-reader-workflow + COMPONENT_NAME trd + SOURCES src/trd-calib-reader-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::TRDWorkflowIO) o2_add_executable(digittracklet-writer COMPONENT_NAME trd SOURCES src/trd-digittracklet-writer-workflow.cxx diff --git a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibReaderSpec.h b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibReaderSpec.h index afa6bec992795..05d09b3d9cc81 100644 --- a/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibReaderSpec.h +++ b/Detectors/TRD/workflow/io/include/TRDWorkflowIO/TRDCalibReaderSpec.h @@ -20,6 +20,9 @@ #include "Framework/DataProcessorSpec.h" #include "Framework/Task.h" #include "DataFormatsTRD/AngularResidHistos.h" +#include "DataFormatsTRD/GainCalibHistos.h" +#include "DataFormatsTRD/PHData.h" +#include namespace o2 { @@ -41,6 +44,8 @@ class TRDCalibReader : public o2::framework::Task std::string mInFileName{"trdangreshistos.root"}; std::string mInTreeName{"calibdata"}; o2::trd::AngularResidHistos mAngResids, *mAngResidPtr = &mAngResids; + std::vector mPHData, *mPHDataPtr = &mPHData; + std::vector mGainData, *mGainDataPtr = &mGainData; }; /// create a processor spec diff --git a/Detectors/TRD/workflow/io/src/TRDCalibReaderSpec.cxx b/Detectors/TRD/workflow/io/src/TRDCalibReaderSpec.cxx index cb76bb8bbad69..26445f3ef6329 100644 --- a/Detectors/TRD/workflow/io/src/TRDCalibReaderSpec.cxx +++ b/Detectors/TRD/workflow/io/src/TRDCalibReaderSpec.cxx @@ -43,7 +43,17 @@ void TRDCalibReader::connectTree() assert(mFile && !mFile->IsZombie()); mTree.reset((TTree*)mFile->Get(mInTreeName.c_str())); assert(mTree); - mTree->SetBranchAddress("AngularResids", &mAngResidPtr); + auto attachBranch = [this](const char* brName, void* add) { + auto br = this->mTree->GetBranch(brName); + if (!br) { + LOGP(warn, "Branch {} is absent, will send empty output", std::string(brName)); + return; + } + br->SetAddress(add); + }; + attachBranch("AngularResids", &mAngResidPtr); + attachBranch("PulseHeight", &mPHDataPtr); + attachBranch("calibdatagain", &mGainData); LOG(info) << "Loaded tree from " << mInFileName << " with " << mTree->GetEntries() << " entries"; } @@ -54,6 +64,8 @@ void TRDCalibReader::run(ProcessingContext& pc) mTree->GetEntry(currEntry); LOG(info) << "Pushing angular residual histograms filled with " << mAngResids.getNEntries() << " entries at tree entry " << currEntry; pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "ANGRESHISTS", 0}, mAngResids); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "PULSEHEIGHT", 0}, mPHData); + pc.outputs().snapshot(Output{o2::header::gDataOriginTRD, "GAINCALIBHISTS", 0}, mGainData); if (mTree->GetReadEntry() + 1 >= mTree->GetEntries()) { pc.services().get().endOfStream(); @@ -65,6 +77,8 @@ DataProcessorSpec getTRDCalibReaderSpec() { std::vector outputs; outputs.emplace_back(o2::header::gDataOriginTRD, "ANGRESHISTS", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "PULSEHEIGHT", 0, Lifetime::Timeframe); + outputs.emplace_back(o2::header::gDataOriginTRD, "GAINCALIBHISTS", 0, Lifetime::Timeframe); return DataProcessorSpec{ "TRDCalibReader", diff --git a/Detectors/TRD/workflow/io/src/trd-calib-reader-workflow.cxx b/Detectors/TRD/workflow/io/src/trd-calib-reader-workflow.cxx new file mode 100644 index 0000000000000..d45f840d76790 --- /dev/null +++ b/Detectors/TRD/workflow/io/src/trd-calib-reader-workflow.cxx @@ -0,0 +1,49 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +#include "CommonUtils/ConfigurableParam.h" +#include "Framework/CompletionPolicy.h" +#include "Framework/ConfigParamSpec.h" +#include "TRDWorkflowIO/TRDCalibReaderSpec.h" +#include "DetectorsRaw/HBFUtilsInitializer.h" + +using namespace o2::framework; + +// ------------------------------------------------------------------ + +void customize(std::vector& policies) +{ + o2::raw::HBFUtilsInitializer::addNewTimeSliceCallback(policies); +} + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters + std::vector options{ + {"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings ..."}}}; + o2::raw::HBFUtilsInitializer::addConfigOption(options); + std::swap(workflowOptions, options); +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + // Update the (declared) parameters if changed from the command line + o2::conf::ConfigurableParam::updateFromString(configcontext.options().get("configKeyValues")); + + WorkflowSpec specs{{o2::trd::getTRDCalibReaderSpec()}}; + o2::raw::HBFUtilsInitializer hbfIni(configcontext, specs); + return specs; +} diff --git a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx index c92b4bb4fbc12..bceb0f07363aa 100644 --- a/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx +++ b/Detectors/TRD/workflow/src/TRDGlobalTrackingSpec.cxx @@ -41,6 +41,8 @@ // GPU header #include "GPUReconstruction.h" #include "GPUChainTracking.h" +#include "GPUO2InterfaceConfiguration.h" +#include "GPUO2InterfaceUtils.h" #include "GPUSettings.h" #include "GPUDataTypes.h" #include "GPUTRDDef.h" @@ -97,9 +99,15 @@ void TRDGlobalTracking::updateTimeDependentParams(ProcessingContext& pc) cfgRecoStep.inputs.clear(); cfgRecoStep.outputs.clear(); mRec = GPUReconstruction::CreateInstance("CPU", true); - mRec->SetSettings(o2::base::Propagator::Instance()->getNominalBz(), &cfgRecoStep); - mRec->GetNonConstParam().rec.trd.useExternalO2DefaultPropagator = true; + + GPUO2InterfaceConfiguration config; + config.ReadConfigurableParam(config); + config.configGRP.solenoidBzNominalGPU = GPUO2InterfaceUtils::getNominalGPUBz(*o2::base::GRPGeomHelper::instance().getGRPMagField()); + config.configProcessing.o2PropagatorUseGPUField = false; + mRec->SetSettings(&config.configGRP, &config.configReconstruction, &config.configProcessing, &cfgRecoStep); + mChainTracking = mRec->AddChain(); + mChainTracking->SetO2Propagator(o2::base::Propagator::Instance()); mTracker = new GPUTRDTracker(); mTracker->SetNCandidates(mRec->GetProcessingSettings().trdNCandidates); // must be set before initialization @@ -267,7 +275,8 @@ void TRDGlobalTracking::run(ProcessingContext& pc) mChainTracking->ClearIOPointers(); mTPCClusterIdxStruct = &inputTracks.inputsTPCclusters->clusterIndex; - mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, &mTPCCorrMapsLoader, o2::base::Propagator::Instance()->getNominalBz(), inputTracks.getTPCTracksClusterRefs().data(), inputTracks.clusterShMapTPC.data(), nullptr, o2::base::Propagator::Instance()); + mTPCRefitter = std::make_unique(mTPCClusterIdxStruct, &mTPCCorrMapsLoader, o2::base::Propagator::Instance()->getNominalBz(), inputTracks.getTPCTracksClusterRefs().data(), 0, inputTracks.clusterShMapTPC.data(), inputTracks.occupancyMapTPC.data(), inputTracks.occupancyMapTPC.size(), nullptr, o2::base::Propagator::Instance()); + mTPCRefitter->setTrackReferenceX(900); // disable propagation after refit by setting reference to value > 500 auto tmpInputContainer = getRecoInputContainer(pc, &mChainTracking->mIOPtrs, &inputTracks, mUseMC); auto tmpContainer = GPUWorkflowHelper::fillIOPtr(mChainTracking->mIOPtrs, inputTracks, mUseMC, nullptr, GTrackID::getSourcesMask("TRD"), mTrkMask, GTrackID::mask_t{GTrackID::MASK_NONE}); mTrackletsRaw = inputTracks.getTRDTracklets(); @@ -569,8 +578,14 @@ bool TRDGlobalTracking::refitITSTPCTRDTrack(TrackTRD& trk, float timeTRD, o2::gl return false; } } - - int retVal = mTPCRefitter->RefitTrackAsTrackParCov(outerParam, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), (timeTRD + mTPCTDriftOffset) * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit + // propagate to TPC inner boundary + float xtogo = 0; + if (!outerParam.getXatLabR(o2::constants::geom::XTPCInnerRef, xtogo, propagator->getNominalBz(), o2::track::DirOutward) || + !propagator->PropagateToXBxByBz(outerParam, xtogo, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr)) { + LOG(debug) << "Propagation to inner TPC boundary X=" << xtogo << " failed, Xtr=" << outerParam.getX() << " snp=" << outerParam.getSnp(); + return false; + } + int retVal = mTPCRefitter->RefitTrackAsTrackParCov(outerParam, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit if (retVal < 0) { LOG(debug) << "TPC refit outwards failed"; return false; @@ -589,7 +604,7 @@ bool TRDGlobalTracking::refitITSTPCTRDTrack(TrackTRD& trk, float timeTRD, o2::gl return false; } auto posStart = trk.getXYZGlo(); - retVal = mTPCRefitter->RefitTrackAsTrackParCov(trk, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), (timeTRD + mTPCTDriftOffset) * mTPCTBinMUSInv, &chi2In, false, false); // inward refit + retVal = mTPCRefitter->RefitTrackAsTrackParCov(trk, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2In, false, false); // inward refit if (retVal < 0) { LOG(debug) << "TPC refit inwards failed"; return false; @@ -654,7 +669,7 @@ bool TRDGlobalTracking::refitTPCTRDTrack(TrackTRD& trk, float timeTRD, o2::globa outerParam = trk; float chi2Out = 0, timeZErr = 0.; bool pileUpOn = trk.hasPileUpInfo(); // distance to farthest collision within the pileup integration time is set - int retVal = mTPCRefitter->RefitTrackAsTrackParCov(outerParam, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), (timeTRD + mTPCTDriftOffset) * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit + int retVal = mTPCRefitter->RefitTrackAsTrackParCov(outerParam, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2Out, true, false); // outward refit if (retVal < 0) { LOG(debug) << "TPC refit outwards failed"; return false; @@ -675,7 +690,7 @@ bool TRDGlobalTracking::refitTPCTRDTrack(TrackTRD& trk, float timeTRD, o2::globa return false; } auto posStart = trk.getXYZGlo(); - retVal = mTPCRefitter->RefitTrackAsTrackParCov(trk, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), (timeTRD + mTPCTDriftOffset) * mTPCTBinMUSInv, &chi2In, false, false); // inward refit + retVal = mTPCRefitter->RefitTrackAsTrackParCov(trk, mTPCTracksArray[detRefs[GTrackID::TPC]].getClusterRef(), timeTRD * mTPCTBinMUSInv, &chi2In, false, false); // inward refit if (retVal < 0) { LOG(debug) << "TPC refit inwards failed"; return false; @@ -781,6 +796,19 @@ bool TRDGlobalTracking::refitTRDTrack(TrackTRD& trk, float& chi2, bool inwards, } if (!inwards) { // to make sure that the inward fit will start from the trkParam ((o2::track::TrackParCov&)trk) = *trkParam; + } else { // propagate to the TPC outer reference + if (!propagator->PropagateToXBxByBz(*trkParam, o2::constants::geom::XTPCOuterRef, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr, tofL)) { + LOG(debug) << "Propagation to TPC outer reference X after TRD inward refit failed"; + return false; + } + // make sure we are in the correct sector + int sector = o2::math_utils::angle2Sector(trkParam->getPhiPos()); + if (sector != o2::math_utils::angle2Sector(trkParam->getAlpha()) && + !trkParam->rotate(o2::math_utils::sector2Angle(sector)) && + !propagator->PropagateToXBxByBz(*trkParam, o2::constants::geom::XTPCOuterRef, o2::base::Propagator::MAX_SIN_PHI, o2::base::Propagator::MAX_STEP, matCorr, tofL)) { + LOG(debug) << "Propagation/rotation to TPC outer reference X after TRD inward refit failed " << trkParam->asString(); + return false; + } } return true; } diff --git a/Detectors/Upgrades/ALICE3/ECal/base/include/ECalBase/ECalBaseParam.h b/Detectors/Upgrades/ALICE3/ECal/base/include/ECalBase/ECalBaseParam.h index 35d25b0050bba..b8b7c75e2b7d0 100644 --- a/Detectors/Upgrades/ALICE3/ECal/base/include/ECalBase/ECalBaseParam.h +++ b/Detectors/Upgrades/ALICE3/ECal/base/include/ECalBase/ECalBaseParam.h @@ -24,6 +24,8 @@ struct ECalBaseParam : public o2::conf::ConfigurableParamHelper { float rMax = 155.0; // cm float zLength = 350.0; // cm + bool enableFwdEndcap = true; + O2ParamDef(ECalBaseParam, "ECalBase"); }; diff --git a/Detectors/Upgrades/ALICE3/ECal/simulation/include/ECalSimulation/Detector.h b/Detectors/Upgrades/ALICE3/ECal/simulation/include/ECalSimulation/Detector.h index 54e715224f728..14664092a8718 100644 --- a/Detectors/Upgrades/ALICE3/ECal/simulation/include/ECalSimulation/Detector.h +++ b/Detectors/Upgrades/ALICE3/ECal/simulation/include/ECalSimulation/Detector.h @@ -82,6 +82,8 @@ class Detector : public o2::base::DetImpl float mOuterRadius; float mLength; + bool mEnableEndcap{true}; + protected: template friend class o2::base::DetImpl; diff --git a/Detectors/Upgrades/ALICE3/ECal/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/ECal/simulation/src/Detector.cxx index 27ba77f6524a5..aeb58649fa4c5 100644 --- a/Detectors/Upgrades/ALICE3/ECal/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/ECal/simulation/src/Detector.cxx @@ -45,6 +45,7 @@ Detector::Detector(bool active) mInnerRadius = ecalPars.rMin; mOuterRadius = ecalPars.rMax; mLength = ecalPars.zLength; + mEnableEndcap = ecalPars.enableFwdEndcap; } Detector::~Detector() @@ -128,12 +129,14 @@ void Detector::createGeometry() ecalVol->SetTransparency(0); vECal->AddNode(ecalVol, 1, nullptr); - // Buil the ecal endcap - TGeoTube* ecalEndcapShape = new TGeoTube("ECLECsh", 15.f, 160.f, 0.5 * (mOuterRadius - mInnerRadius)); - TGeoVolume* ecalEndcapVol = new TGeoVolume("ECLEC", ecalEndcapShape, medPb); - ecalEndcapVol->SetLineColor(kAzure - 9); - ecalEndcapVol->SetTransparency(0); - vECal->AddNode(ecalEndcapVol, 1, new TGeoTranslation(0, 0, -450.f)); + if (mEnableEndcap) { + // Build the ecal endcap + TGeoTube* ecalEndcapShape = new TGeoTube("ECLECsh", 15.f, 160.f, 0.5 * (mOuterRadius - mInnerRadius)); + TGeoVolume* ecalEndcapVol = new TGeoVolume("ECLEC", ecalEndcapShape, medPb); + ecalEndcapVol->SetLineColor(kAzure - 9); + ecalEndcapVol->SetTransparency(0); + vECal->AddNode(ecalEndcapVol, 1, new TGeoTranslation(0, 0, -450.f)); + } } void Detector::Reset() diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h b/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h index ec735a66f4390..a88ea5a351ad2 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/include/FT3Simulation/Detector.h @@ -115,6 +115,7 @@ class Detector : public o2::base::DetImpl void buildFT3V1(); void buildFT3V3b(); void buildFT3Scoping(); + void buildFT3NewVacuumVessel(); void buildFT3FromFile(std::string); GeometryTGeo* mGeometryTGeo; //! access to geometry details diff --git a/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx index 625f2b28182c5..296bec8aa8922 100644 --- a/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/FT3/simulation/src/Detector.cxx @@ -277,6 +277,78 @@ void Detector::buildFT3V3b() } } +void Detector::buildFT3NewVacuumVessel() +{ + // Build the FT3 detector according to changes proposed during + // https://indico.cern.ch/event/1407704/ + // to adhere to the changes that were presented at the ALICE 3 Upgrade days in March 2024 + // Inner radius at C-side to 7 cm + // Inner radius at A-side stays at 5 cm + + LOG(info) << "Building FT3 Detector: After Upgrade Days March 2024 version"; + + mNumberOfLayers = 12; + float sensorThickness = 30.e-4; + float layersx2X0 = 1.e-2; + std::vector> layersConfigCSide{ + {26., .5, 2.5, 0.1f * layersx2X0}, // {z_layer, r_in, r_out, Layerx2X0} + {30., .5, 2.5, 0.1f * layersx2X0}, + {34., .5, 2.5, 0.1f * layersx2X0}, + {77., 7.0, 35., layersx2X0}, + {100., 7.0, 35., layersx2X0}, + {122., 7.0, 35., layersx2X0}, + {150., 7.0, 68.f, layersx2X0}, + {180., 7.0, 68.f, layersx2X0}, + {220., 7.0, 68.f, layersx2X0}, + {260., 7.0, 68.f, layersx2X0}, + {300., 7.0, 68.f, layersx2X0}, + {350., 7.0, 68.f, layersx2X0}}; + + std::vector> layersConfigASide{ + {26., .5, 2.5, 0.1f * layersx2X0}, // {z_layer, r_in, r_out, Layerx2X0} + {30., .5, 2.5, 0.1f * layersx2X0}, + {34., .5, 2.5, 0.1f * layersx2X0}, + {77., 5.0, 35., layersx2X0}, + {100., 5.0, 35., layersx2X0}, + {122., 5.0, 35., layersx2X0}, + {150., 5.0, 68.f, layersx2X0}, + {180., 5.0, 68.f, layersx2X0}, + {220., 5.0, 68.f, layersx2X0}, + {260., 5.0, 68.f, layersx2X0}, + {300., 5.0, 68.f, layersx2X0}, + {350., 5.0, 68.f, layersx2X0}}; + + mLayerName.resize(2); + mLayerName[0].resize(mNumberOfLayers); + mLayerName[1].resize(mNumberOfLayers); + mLayerID.clear(); + mLayers.resize(2); + + for (auto direction : {0, 1}) { + for (int layerNumber = 0; layerNumber < mNumberOfLayers; layerNumber++) { + std::string directionName = std::to_string(direction); + std::string layerName = GeometryTGeo::getFT3LayerPattern() + directionName + std::string("_") + std::to_string(layerNumber); + mLayerName[direction][layerNumber] = layerName; + float z, rIn, rOut, x0; + if (direction == 0) { // C-Side + z = layersConfigCSide[layerNumber][0]; + rIn = layersConfigCSide[layerNumber][1]; + rOut = layersConfigCSide[layerNumber][2]; + x0 = layersConfigCSide[layerNumber][3]; + } else if (direction == 1) { // A-Side + z = layersConfigASide[layerNumber][0]; + rIn = layersConfigASide[layerNumber][1]; + rOut = layersConfigASide[layerNumber][2]; + x0 = layersConfigASide[layerNumber][3]; + } + + LOG(info) << "Adding Layer " << layerName << " at z = " << z; + // Add layers + auto& thisLayer = mLayers[direction].emplace_back(direction, layerNumber, layerName, z, rIn, rOut, x0); + } + } +} + //_________________________________________________________________________________________________ void Detector::buildFT3Scoping() { @@ -342,7 +414,7 @@ Detector::Detector(bool active) } else { switch (ft3BaseParam.geoModel) { case Default: - buildFT3Scoping(); // FT3Scoping + buildFT3NewVacuumVessel(); // FT3 after Upgrade days March 2024 break; case Telescope: buildBasicFT3(ft3BaseParam); // BasicFT3 = Parametrized telescopic detector (equidistant layers) diff --git a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx index 42ad6a6b62ce3..a2bba7cc5fe35 100644 --- a/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/IOTOF/simulation/src/Detector.cxx @@ -202,7 +202,7 @@ bool Detector::ProcessHits(FairVolume* vol) int lay = vol->getVolumeId(); int volID = vol->getMCid(); - // Is it needed to keep a track reference when the outer ITS volume is encountered? + // Is it needed to keep a track reference when the outer volume is encountered? auto stack = (o2::data::Stack*)fMC->GetStack(); if (fMC->IsTrackExiting() /*&& (lay == 0 || lay == mLayers.size() - 1)*/) { // Keep the track refs for the innermost and outermost layers only diff --git a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Pipe.h b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Pipe.h index 47b803c1bcbd1..1d9858e2dfec3 100644 --- a/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Pipe.h +++ b/Detectors/Upgrades/ALICE3/Passive/include/Alice3DetectorsPassive/Pipe.h @@ -33,7 +33,7 @@ class Alice3Pipe : public Alice3PassiveBase const float a3ipLength = 0.f, const float vacuumVesselRIn = 0.f, const float vacuumVesselThickness = 0.f, - const float vacuumVesselLength = 0.f); + const float vacuumVesselASideLength = 0.f); void ConstructGeometry() override; @@ -48,7 +48,7 @@ class Alice3Pipe : public Alice3PassiveBase float getVacuumVesselRIn() const { return mVacuumVesselRIn; } float getVacuumVesselRMax() const { return mVacuumVesselRIn + mVacuumVesselThick; } float getVacuumVesselWidth() const { return mVacuumVesselThick; } - float getVacuumVesselLength() const { return mVacuumVesselLength; } + float getVacuumVesselLength() const { return mVacuumVesselASideLength; } bool IsTRKActivated() const { return mIsTRKActivated; } bool IsFT3Activated() const { return mIsFT3Activated; } @@ -64,7 +64,7 @@ class Alice3Pipe : public Alice3PassiveBase float mVacuumVesselRIn = 0.; // inner diameter of the vacuum vessel float mVacuumVesselThick = 0.; // outer beam pipe section thickness - float mVacuumVesselLength = 0.; // half length of the outer beampipe around the IP + float mVacuumVesselASideLength = 0.; // Length of the A Side of the vacuum vessel around the IP bool mIsTRKActivated = true; // If TRK is not active don't create TRK layers allocations in the vacuum volume bool mIsFT3Activated = true; diff --git a/Detectors/Upgrades/ALICE3/Passive/src/Pipe.cxx b/Detectors/Upgrades/ALICE3/Passive/src/Pipe.cxx index f7f4c1844f7df..57f30241bd4ff 100644 --- a/Detectors/Upgrades/ALICE3/Passive/src/Pipe.cxx +++ b/Detectors/Upgrades/ALICE3/Passive/src/Pipe.cxx @@ -38,7 +38,7 @@ Alice3Pipe::Alice3Pipe(const char* name, float a3ipLength, float vacuumVesselRIn, float vacuumVesselThickness, - float vacuumVesselLength) + float vacuumVesselASideLength) : Alice3PassiveBase{name, title}, mIsTRKActivated{isTRKActivated}, mIsFT3Activated{isFT3Activated}, @@ -47,7 +47,7 @@ Alice3Pipe::Alice3Pipe(const char* name, mA3IPLength{a3ipLength}, mVacuumVesselRIn{vacuumVesselRIn}, mVacuumVesselThick{vacuumVesselThickness}, - mVacuumVesselLength{vacuumVesselLength} + mVacuumVesselASideLength{vacuumVesselASideLength} { } @@ -95,19 +95,24 @@ void Alice3Pipe::ConstructGeometry() } // We split the naming of the parts if the beam pipe for ALICE 3 into parts - // - pipe - // - vacuum vessel (which hosts the primary vacuum) + // - pipe A Side + // - vacuum vessel (which hosts the primary vacuum and covers all C Side as well) // - iris vacuum vessel (which hosts the secondary vacuum) // A3IP update // Vacuum + Double_t pipeASideLength = mA3IPLength / 2. - mVacuumVesselThick - mVacuumVesselASideLength; + Double_t pipeCSideLength = mA3IPLength / 2. + mVacuumVesselASideLength; TGeoTube* vacuumBasePipe = new TGeoTube("PIPEVACUUM_BASEsh", 0., mPipeRIn, mA3IPLength / 2.); - TGeoTube* vacuumBaseVacuumVessel = new TGeoTube("VACUUM_VESSELVACUUM_BASEsh", mPipeRIn, mVacuumVesselRIn, mVacuumVesselLength / 2.); + TGeoTube* vacuumBaseVacuumVessel = new TGeoTube("VACUUM_VESSELVACUUM_BASEsh", mPipeRIn, mVacuumVesselRIn, pipeCSideLength / 2.); + + TGeoTranslation* posPipeCSide = new TGeoTranslation("PIPE_CSIDE_POSITION", 0, 0, mVacuumVesselASideLength - pipeCSideLength / 2.); + posPipeCSide->RegisterYourself(); // Excavate volumes from the vacuum such that there is place for the TRK barrel layers and FT3 disc layers of the IRIS tracker // And the other passive shapes: coldplate, iris tracker vacuum vessel TGeoCompositeShape* vacuumComposite; TGeoVolume* vacuumVolume; - TString compositeFormula{"PIPEVACUUM_BASEsh+VACUUM_VESSELVACUUM_BASEsh"}; + TString compositeFormula{"PIPEVACUUM_BASEsh+VACUUM_VESSELVACUUM_BASEsh:PIPE_CSIDE_POSITION"}; TString subtractorsFormula; if (!mIsTRKActivated) { @@ -183,28 +188,21 @@ void Alice3Pipe::ConstructGeometry() } // Pipe tubes - Double_t pipeLengthHalf = mA3IPLength / 2. - mVacuumVesselThick - mVacuumVesselLength / 2.; - TGeoTube* pipe = new TGeoTube("PIPEsh", mPipeRIn, mPipeRIn + mPipeThick, pipeLengthHalf / 2.); - TGeoTube* vacuumVesselTube = new TGeoTube("VACUUM_VESSEL_TUBEsh", mVacuumVesselRIn, mVacuumVesselRIn + mVacuumVesselThick, mVacuumVesselLength / 2.); + TGeoTube* pipeASide = new TGeoTube("PIPE_Ash", mPipeRIn, mPipeRIn + mPipeThick, pipeASideLength / 2.); + TGeoTube* pipeCSide = new TGeoTube("PIPE_Csh", mVacuumVesselRIn, mVacuumVesselRIn + mVacuumVesselThick, pipeCSideLength / 2.); TGeoTube* vacuumVesselWall = new TGeoTube("VACUUM_VESSEL_WALLsh", mPipeRIn, mVacuumVesselRIn + mVacuumVesselThick, mVacuumVesselThick / 2.); // Pipe and vacuum vessel positions - TGeoTranslation* posVacuumVesselWallNegZSide = new TGeoTranslation("WALLNEGZ", 0, 0, -mVacuumVesselLength / 2. - mVacuumVesselThick / 2.); - posVacuumVesselWallNegZSide->RegisterYourself(); - TGeoTranslation* posVacuumVesselWallPosZSide = new TGeoTranslation("WALLPOSZ", 0, 0, mVacuumVesselLength / 2. + mVacuumVesselThick / 2.); - posVacuumVesselWallPosZSide->RegisterYourself(); - TGeoTranslation* posPipeNegZSide = new TGeoTranslation("PIPENEGZ", 0, 0, -mVacuumVesselLength / 2. - mVacuumVesselThick - pipeLengthHalf / 2.); - posPipeNegZSide->RegisterYourself(); - TGeoTranslation* posPipePosZSide = new TGeoTranslation("PIPEPOSZ", 0, 0, mVacuumVesselLength / 2. + mVacuumVesselThick + pipeLengthHalf / 2.); - posPipePosZSide->RegisterYourself(); + TGeoTranslation* posVacuumVesselWall = new TGeoTranslation("WALL_POSITION", 0, 0, mVacuumVesselASideLength + mVacuumVesselThick / 2.); + posVacuumVesselWall->RegisterYourself(); + TGeoTranslation* posPipeASide = new TGeoTranslation("PIPE_ASIDE_POSITION", 0, 0, mVacuumVesselASideLength + mVacuumVesselThick + pipeASideLength / 2.); + posPipeASide->RegisterYourself(); // Pipe composite shape and volume TString pipeCompositeFormula = - "VACUUM_VESSEL_WALLsh:WALLNEGZ" - "+VACUUM_VESSEL_WALLsh:WALLPOSZ" - "+VACUUM_VESSEL_TUBEsh" - "+PIPEsh:PIPEPOSZ" - "+PIPEsh:PIPENEGZ"; + "VACUUM_VESSEL_WALLsh:WALL_POSITION" + "+PIPE_Ash:PIPE_ASIDE_POSITION" + "+PIPE_Csh:PIPE_CSIDE_POSITION"; if (subtractorsFormula.Length()) { LOG(info) << "Subtractors formula before : " << subtractorsFormula; diff --git a/Detectors/Upgrades/ALICE3/README.md b/Detectors/Upgrades/ALICE3/README.md new file mode 100644 index 0000000000000..7e1e1c03718d8 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/README.md @@ -0,0 +1,73 @@ + + +# ALICE 3 full simulation + +## Simulation +### Simulation software for Run 5 +Current simulation approach for ALICE 3 is a specification of what it is used in the main O2 simulation package. +It shares the same structure and possibly inherits all the features in place already. +For all of the features that are not really Run-5 specific please refer to the official [O2 Simulation Documentation](https://aliceo2group.github.io/simulation/docs/). + +### Rationale for the "Upgrades" codebase +Run 5 code for the detectors is stored in the `Detectors/Upgrades/ALICE3` directory and its suboflder strucure mimicks the same we have in `Detectors`. +For specific data formats the plan is to keep the same approach in `DataFormats/Upgrades`. + +### Available modules +Run 5 executable is called `o2-sim-run5` and accepts the same syntax as `o2-sim`. +There is also the serial vertsion `o2-sim-serial-run5` that is the serial implementation. +The specific modules for Run 5 are enabled by passing their their IDs to the `-m` parameter of the `o2-sim`. +A list of the available DetIDs is reproted in the table below: + +| Detector ID | Detector description | +|-------------|----------------------------------| +| `A3IP` | Beam pipe | +| `TRK` | Barrel Tracker | +| `TF3` | Time Of Flight detectors | +| `FT3` | Forward endcaps | +| `RCH` | Ring Imaging Cherenkov detectors | +| `ECL` | Electromagnetic Calorimeter | +| `MI3` | Muon Identification | +| `FCT` | Forward Conversion Tracker | +| `A3ABSO` | Absorber | +| `A3MAG` | Magnet | + +Names are arbitrarily chosen and are such as to be orthogonal to any Run 3+ other DetID. +The detector IDs of sensitive modules are mapped to the corresponding `o2::detector::DetID` class definition for convenience, so to be consistent with output names of the hit files. + +### Use the ALICE 3 magnetic field +By definition the `o2-sim-run5` will use the Run 3 magnetic field configurations. +Field description can be overridden with a custom macro with a path exported in the `ALICE3_MAGFIELD_MACRO` environment variable. +The env var `ALICE3_SIM_FIELD` needs also to be set to `ON`. +Example: + +```bash +export ALICE3_SIM_FIELD=ON +export ALICE3_MAGFIELD_MACRO=../ALICE3Field.C +``` + +An exampling macro for a custom magnetic field is stored in `Detectors/Upgrades/macros/ALICE3Field.C`. + +### Run a simple simulation for run 5 +The simplest command to be run to test the simulation is working is: + +```bash +o2-sim-run5 -n 0 +``` +This will not produce any events but will spin the machinery and will produce the `o2sim_geometry.root` file with the whole geometry description. +To enable a specific set of modules, e.g. the beampipe and the TOFs one can specify which modules to enable, e.g.: + +```bash +o2-sim-run5 -n 10 -m A3IP TF3 +``` +### Output of the simulation +The simulation will produce a `o2sim_Hits.root` file with a tree with the hits related to that detector. +Currently, hits are produced for: `TRK`, `FT3`, and `TF3`. +More detectors will be included. + +## Reconstruction +WIP + +## Analysis +WIP \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/RICH/simulation/include/RICHSimulation/RICHRing.h b/Detectors/Upgrades/ALICE3/RICH/simulation/include/RICHSimulation/RICHRing.h index a143b8792c6da..a7892c210e310 100644 --- a/Detectors/Upgrades/ALICE3/RICH/simulation/include/RICHSimulation/RICHRing.h +++ b/Detectors/Upgrades/ALICE3/RICH/simulation/include/RICHSimulation/RICHRing.h @@ -98,6 +98,8 @@ class FWDRich // Silicon: float mZSiliconMin; float mDZSilicon; + + ClassDef(FWDRich, 0); }; class BWDRich @@ -131,6 +133,8 @@ class BWDRich // Silicon: float mZSiliconMin; float mDZSilicon; + + ClassDef(BWDRich, 0); }; } // namespace rich diff --git a/Detectors/Upgrades/ALICE3/RICH/simulation/src/RICHSimulationLinkDef.h b/Detectors/Upgrades/ALICE3/RICH/simulation/src/RICHSimulationLinkDef.h index c9f9727f1fcd6..796191d493166 100644 --- a/Detectors/Upgrades/ALICE3/RICH/simulation/src/RICHSimulationLinkDef.h +++ b/Detectors/Upgrades/ALICE3/RICH/simulation/src/RICHSimulationLinkDef.h @@ -16,6 +16,8 @@ #pragma link off all functions; #pragma link C++ class o2::rich::Ring + ; +#pragma link C++ class o2::rich::BWDRich + ; +#pragma link C++ class o2::rich::FWDRich + ; #pragma link C++ class o2::rich::Detector + ; #pragma link C++ class o2::base::DetImpl < o2::rich::Detector> + ; diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h index ec516ecc8aa2a..47a48167e0562 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/include/TRKSimulation/Detector.h @@ -61,6 +61,7 @@ class Detector : public o2::base::DetImpl } void configDefault(); + void buildTRKNewVacuumVessel(); void configFromFile(std::string fileName = "alice3_TRK_layout.txt"); void configToFile(std::string fileName = "alice3_TRK_layout.txt"); diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx index db326eba84091..d6c4613b6b589 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/Detector.cxx @@ -48,7 +48,7 @@ Detector::Detector(bool active) if (trkPars.configFile != "") { configFromFile(trkPars.configFile); } else { - configDefault(); + buildTRKNewVacuumVessel(); configToFile(); configServices(); } @@ -74,9 +74,12 @@ void Detector::ConstructGeometry() void Detector::configDefault() { + + // Build TRK detector according to the scoping document + mLayers.clear(); - LOGP(warning, "Loading default configuration for ALICE3 TRK"); + LOGP(warning, "Loading Scoping Document configuration for ALICE3 TRK"); mLayers.emplace_back(0, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(0)}, 0.5f, 50.f, 100.e-4); mLayers.emplace_back(1, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(1)}, 1.2f, 50.f, 100.e-4); mLayers.emplace_back(2, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(2)}, 2.5f, 50.f, 100.e-4); @@ -90,6 +93,29 @@ void Detector::configDefault() mLayers.emplace_back(10, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(10)}, 80.f, 258.f, 100.e-3); } +void Detector::buildTRKNewVacuumVessel() +{ + // Build the TRK detector according to changes proposed during + // https://indico.cern.ch/event/1407704/ + // to adhere to the changes that were presented at the ALICE 3 Upgrade days in March 2024 + // L3 -> 7 cm, L4 -> 9 cm + + mLayers.clear(); + + LOGP(warning, "Loading \"After Upgrade Days March 2024\" configuration for ALICE3 TRK"); + mLayers.emplace_back(0, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(0)}, 0.5f, 50.f, 100.e-4); + mLayers.emplace_back(1, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(1)}, 1.2f, 50.f, 100.e-4); + mLayers.emplace_back(2, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(2)}, 2.5f, 50.f, 100.e-4); + mLayers.emplace_back(3, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(3)}, 7.f, 124.f, 100.e-3); + mLayers.emplace_back(4, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(4)}, 9.f, 124.f, 100.e-3); + mLayers.emplace_back(5, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(5)}, 12.f, 124.f, 100.e-3); + mLayers.emplace_back(6, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(6)}, 20.f, 124.f, 100.e-3); + mLayers.emplace_back(7, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(7)}, 30.f, 124.f, 100.e-3); + mLayers.emplace_back(8, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(8)}, 45.f, 258.f, 100.e-3); + mLayers.emplace_back(9, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(9)}, 60.f, 258.f, 100.e-3); + mLayers.emplace_back(10, std::string{GeometryTGeo::getTRKLayerPattern() + std::to_string(10)}, 80.f, 258.f, 100.e-3); +} + void Detector::configFromFile(std::string fileName) { // Override the default geometry if config file provided diff --git a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx index a9ea634777037..7937e3b4de09a 100644 --- a/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx +++ b/Detectors/Upgrades/ALICE3/TRK/simulation/src/TRKServices.cxx @@ -316,7 +316,7 @@ void TRKServices::createMiddleServices(TGeoVolume* motherVolume) motherVolume->AddNode(middleBarrelCoolingH2OVolume, 1, combiTrans); } // Middle barrel connection disks - const float rMinMiddleBarrelDisk = 3.78f; + const float rMinMiddleBarrelDisk = 5.68f; const float rMaxMiddleBarrelDisk = 35.f; const float zLengthMiddleBarrel = 62.f; for (auto& orientation : {Orientation::kASide, Orientation::kCSide}) { diff --git a/Detectors/Upgrades/ALICE3/macros/ALICE3Field.C b/Detectors/Upgrades/ALICE3/macros/ALICE3Field.C new file mode 100644 index 0000000000000..a721a91ed2dcc --- /dev/null +++ b/Detectors/Upgrades/ALICE3/macros/ALICE3Field.C @@ -0,0 +1,66 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +// Author: J. E. Munoz Mendez jesus.munoz@cern.ch + +std::function field() +{ + return [](const double* x, double* b) { + double Rc; + double R1; + double R2; + double B1; + double B2; + double beamStart = 500.; //[cm] + double tokGauss = 1. / 0.1; // conversion from Tesla to kGauss + + bool isMagAbs = true; + + // *********************** + // LAYOUT 1 + // *********************** + + // RADIUS + Rc = 185.; //[cm] + R1 = 220.; //[cm] + R2 = 290.; //[cm] + + // To set the B2 + B1 = 2.; //[T] + B2 = -Rc * Rc / ((R2 * R2 - R1 * R1) * B1); //[T] + + if ((abs(x[2]) <= beamStart) && (sqrt(x[0] * x[0] + x[1] * x[1]) < Rc)) { + b[0] = 0.; + b[1] = 0.; + b[2] = B1 * tokGauss; + } else if ((abs(x[2]) <= beamStart) && + (sqrt(x[0] * x[0] + x[1] * x[1]) >= Rc && + sqrt(x[0] * x[0] + x[1] * x[1]) < R1)) { + b[0] = 0.; + b[1] = 0.; + b[2] = 0.; + } else if ((abs(x[2]) <= beamStart) && + (sqrt(x[0] * x[0] + x[1] * x[1]) >= R1 && + sqrt(x[0] * x[0] + x[1] * x[1]) < R2)) { + b[0] = 0.; + b[1] = 0.; + if (isMagAbs) { + b[2] = B2 * tokGauss; + } else { + b[2] = 0.; + } + } else { + b[0] = 0.; + b[1] = 0.; + b[2] = 0.; + } + }; +} \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/macros/CMakeLists.txt b/Detectors/Upgrades/ALICE3/macros/CMakeLists.txt index 4c6f16c9ffca4..b31687cc85c0e 100644 --- a/Detectors/Upgrades/ALICE3/macros/CMakeLists.txt +++ b/Detectors/Upgrades/ALICE3/macros/CMakeLists.txt @@ -10,4 +10,7 @@ # or submit itself to any jurisdiction. o2_add_test_root_macro(scanXX0.C + LABELS alice3) + +o2_add_test_root_macro(plotHits.C LABELS alice3) \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/macros/plotHits.C b/Detectors/Upgrades/ALICE3/macros/plotHits.C new file mode 100644 index 0000000000000..1f18778e92a17 --- /dev/null +++ b/Detectors/Upgrades/ALICE3/macros/plotHits.C @@ -0,0 +1,112 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +// +// Author: M. Concas + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "ITSMFTSimulation/Hit.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#endif + +void plotHits(const size_t nevents = 100) +{ + TNtuple* tuple = new TNtuple("xyz", "xyz", "x:y:z:color"); + TH2* ep = new TH2F("etaph", "hist_etaph;#varphi;#eta", 150, 0., TMath::TwoPi(), 150, -5, 5); + TH2* zp = new TH2F("zph", "hist_zph;;#varphi;z(cm) ", 150, 0., TMath::TwoPi(), 300, -200, 200); + TH2* zr = new TH2F("zr", "hist_zr;z(cm);r(cm) ", 500, -400, 400, 500, 0, 110); + TH3F* xyz_trk = new TH3F("xyz_trk", "hist_xyz;x(cm);y(cm);z(cm)", 300, -100, 100, 300, -100, 100, 300, -400, 400); + TH3F* xyz_ft3 = new TH3F("xyz_ft3", "hist_xyz;x(cm);y(cm);z(cm)", 300, -100, 100, 300, -100, 100, 300, -400, 400); + TH3F* xyz_tof = new TH3F("xyz_tf3", "hist_xyz;x(cm);y(cm);z(cm)", 300, -100, 100, 300, -100, 100, 300, -400, 400); + + std::vector hitFiles; + hitFiles.push_back(TFile::Open("o2sim_HitsTF3.root")); + hitFiles.push_back(TFile::Open("o2sim_HitsFT3.root")); + hitFiles.push_back(TFile::Open("o2sim_HitsTRK.root")); + + TTree* trkTree = hitFiles[2] ? (TTree*)hitFiles[2]->Get("o2sim") : nullptr; + TTree* ft3Tree = hitFiles[1] ? (TTree*)hitFiles[1]->Get("o2sim") : nullptr; + TTree* tf3Tree = hitFiles[0] ? (TTree*)hitFiles[0]->Get("o2sim") : nullptr; + + // TRK + std::vector* trkHit = nullptr; + trkTree->SetBranchAddress("TRKHit", &trkHit); + + // FT3 + std::vector* ft3Hit = nullptr; + ft3Tree->SetBranchAddress("FT3Hit", &ft3Hit); + + // TF3 + std::vector* tf3Hit = nullptr; + tf3Tree->SetBranchAddress("TF3Hit", &tf3Hit); + + for (size_t iev = 0; iev < std::min(nevents, (size_t)trkTree->GetEntries()); iev++) { + trkTree->GetEntry(iev); + for (const auto& h : *trkHit) { + TVector3 posvec(h.GetX(), h.GetY(), h.GetZ()); + ep->Fill(TVector2::Phi_0_2pi(posvec.Phi()), posvec.Eta()); + zp->Fill(TVector2::Phi_0_2pi(posvec.Phi()), posvec.Z()); + zr->Fill(posvec.Z(), TMath::Hypot(posvec.X(), posvec.Y())); + xyz_trk->Fill(posvec.X(), posvec.Y(), posvec.Z()); + tuple->Fill(posvec.X(), posvec.Y(), posvec.Z(), 40); + } + ft3Tree->GetEntry(iev); + for (const auto& h : *ft3Hit) { + TVector3 posvec(h.GetX(), h.GetY(), h.GetZ()); + ep->Fill(TVector2::Phi_0_2pi(posvec.Phi()), posvec.Eta()); + zp->Fill(TVector2::Phi_0_2pi(posvec.Phi()), posvec.Z()); + zr->Fill(posvec.Z(), TMath::Hypot(posvec.X(), posvec.Y())); + xyz_ft3->Fill(posvec.X(), posvec.Y(), posvec.Z()); + tuple->Fill(posvec.X(), posvec.Y(), posvec.Z(), 30); + } + tf3Tree->GetEntry(iev); + for (const auto& h : *tf3Hit) { + TVector3 posvec(h.GetX(), h.GetY(), h.GetZ()); + ep->Fill(TVector2::Phi_0_2pi(posvec.Phi()), posvec.Eta()); + zp->Fill(TVector2::Phi_0_2pi(posvec.Phi()), posvec.Z()); + zr->Fill(posvec.Z(), TMath::Hypot(posvec.X(), posvec.Y())); + xyz_tof->Fill(posvec.X(), posvec.Y(), posvec.Z()); + tuple->Fill(posvec.X(), posvec.Y(), posvec.Z(), 20); + } + } + + auto* EPcanvas = new TCanvas("EtaPhi", "EP", 1000, 800); + EPcanvas->cd(); + ep->Draw(); + EPcanvas->SaveAs("EtaPhi.png"); + auto* ZPcanvas = new TCanvas("ZPhi", "ZP", 1000, 800); + ZPcanvas->cd(); + zp->Draw(); + ZPcanvas->SaveAs("ZPhi.png"); + auto* RZcanvas = new TCanvas("RZ", "RZ", 1000, 800); + RZcanvas->cd(); + zr->Draw(); + RZcanvas->SaveAs("RZ.png"); + auto* XYZcanvas = new TCanvas("XYZ", "XYZ", 1000, 800); + XYZcanvas->cd(); + xyz_trk->Draw("p"); + xyz_ft3->Draw("same"); + xyz_tof->Draw("same"); + XYZcanvas->SaveAs("XYZ.png"); + auto* XYZ3Dcanvas = new TCanvas("XYZ3D", "XYZ3D", 1000, 800); + XYZ3Dcanvas->cd(); + tuple->Draw("x:y:z:color"); + XYZ3Dcanvas->SaveAs("XYZ3D.png"); +} \ No newline at end of file diff --git a/Detectors/Upgrades/ALICE3/macros/scanXX0.C b/Detectors/Upgrades/ALICE3/macros/scanXX0.C index 2cef4f0fe7dbc..ca982aab87b2f 100644 --- a/Detectors/Upgrades/ALICE3/macros/scanXX0.C +++ b/Detectors/Upgrades/ALICE3/macros/scanXX0.C @@ -45,8 +45,8 @@ constexpr int nBinsPhiScan = 90; constexpr int nBinsEtaScan = 200; constexpr int nBinsZvtxScan = 300; -constexpr float maxEtaScan = 8.; -constexpr int n = 1e4; // testtracks +constexpr float maxEtaScan = 5.; +constexpr int n = 1e6; // testtracks constexpr float len = 1000; // cm void vacuumFormMaterial(TGeoMaterial* mat) @@ -202,7 +202,7 @@ std::vector printMaterialDefinitions(TGeoManager* gman) return materialNames; } -void scanXX0(const float rmax = 200, const float rmin = 0.2, const std::string OnlyMat = "all", const string fileName = "o2sim_geometry.root", const string path = "./") +void scanXX0(const float rmax = 350, const float rmin = 0.1, const std::string OnlyMat = "all", const std::string fileName = "o2sim_geometry.root", const string path = "./") { gStyle->SetPadTopMargin(0.035); gStyle->SetPadRightMargin(0.035); @@ -217,30 +217,30 @@ void scanXX0(const float rmax = 200, const float rmin = 0.2, const std::string O double etaPos = 1.; - TCanvas* canvStack = new TCanvas("canvStack", "canvStack", 2400, 800); + TCanvas* canvStack = new TCanvas("canvStack", "canvStack", 2400, 1400); canvStack->Divide(3, 1); - TCanvas* canv = new TCanvas("canv", "canv", 2400, 800); + TCanvas* canv = new TCanvas("canv", "canv", 2400, 1400); canv->Divide(3, 1); TLegend* legVsPhi = new TLegend(0.25, 0.6, 0.85, 0.9); legVsPhi->SetFillColor(kWhite); - legVsPhi->SetTextSize(0.045); + legVsPhi->SetTextSize(0.025); legVsPhi->SetHeader(Form("ALICE 3, |#it{#eta}| < %0.f, #it{Z}_{vtx} = 0", etaPos)); TLegend* legVsEta = new TLegend(0.25, 0.6, 0.85, 0.9); legVsEta->SetFillColor(kWhite); - legVsEta->SetTextSize(0.045); + legVsEta->SetTextSize(0.025); legVsEta->SetHeader("ALICE 3, 0 < #it{#varphi} < #pi, #it{Z}_{vtx} = 0"); TLegend* legVsZvtx = new TLegend(0.25, 0.6, 0.85, 0.9); legVsZvtx->SetFillColor(kWhite); - legVsZvtx->SetTextSize(0.045); + legVsZvtx->SetTextSize(0.025); legVsZvtx->SetHeader("ALICE 3, #it{#varphi} = #pi/2, #it{#eta} = 0"); - auto* xOverX0VsPhiStack = new THStack("xOverX0VsPhi", ""); - auto* xOverX0VsEtaStack = new THStack("xOverX0VsEta", ""); - auto* xOverX0VsZvtxStack = new THStack("xOverX0VsZvtx", ""); + auto* xOverX0VsPhiStack = new THStack("xOverX0VsPhi", ";#varphi (rad);#it{X/X0}"); + auto* xOverX0VsEtaStack = new THStack("xOverX0VsEta", ";#eta;#it{X/X0}"); + auto* xOverX0VsZvtxStack = new THStack("xOverX0VsZvtx", ";Z_{vtz} (cm);#it{X/X0}"); std::vector xOverX0VsPhi; std::vector xOverX0VsEta; @@ -251,14 +251,17 @@ void scanXX0(const float rmax = 200, const float rmin = 0.2, const std::string O const double phiMin = 0; const double phiMax = 2 * TMath::Pi(); - const double len = 1000.; + const double len = 1200.; std::vector colors = {kAzure + 4, kRed + 1}; // delete gGeoManager; // We re-import the geometry at each iteration int count = 2; auto cols = TColor::GetPalette(); - + float maxPhiHist = 0.f, maxEtaHist = 0.f, maxZHist = 0.f; for (size_t iMaterial{0}; iMaterial < materials.size(); ++iMaterial) { + if (materials[iMaterial] == "VACUUM") { + continue; + } if (OnlyMat != "all" && materials[iMaterial] != OnlyMat) { continue; } @@ -282,8 +285,11 @@ void scanXX0(const float rmax = 200, const float rmin = 0.2, const std::string O xOverX0VsZvtx.emplace_back(new TH1F(Form("xOverX0VsZvtx_step%zu", iMaterial), "", nBinsZvtxScan, -len / 2, len / 2)); ComputeMaterialBudget(rmin, rmax, etaPos, phiMin, phiMax, xOverX0VsPhi.back(), xOverX0VsEta.back(), xOverX0VsZvtx.back()); - + // maxPhiHist = xOverX0VsPhi.back()->GetMaximum() > maxPhiHist ? 1.1 * xOverX0VsPhi.back()->GetMaximum() : maxPhiHist; + // maxEtaHist = xOverX0VsEta.back()->GetMaximum() > maxEtaHist ? 1.1 * xOverX0VsEta.back()->GetMaximum() : maxEtaHist; + // maxZHist = xOverX0VsZvtx.back()->GetMaximum() > maxZHist ? 1.1 * xOverX0VsZvtx.back()->GetMaximum() : maxZHist; double meanX0vsPhi = 0, meanX0vsEta = 0, meanX0vsZvtx = 0; + for (int ix = 1; ix <= xOverX0VsPhi.back()->GetNbinsX(); ix++) { meanX0vsPhi += xOverX0VsPhi.back()->GetBinContent(ix); } @@ -299,6 +305,11 @@ void scanXX0(const float rmax = 200, const float rmin = 0.2, const std::string O } meanX0vsZvtx /= xOverX0VsZvtx.back()->GetNbinsX(); + if (!meanX0vsPhi && !meanX0vsEta && !meanX0vsZvtx) { + LOGP(info, "Material {} allegedly not present, skipping.", materials[iMaterial]); + continue; + } + LOGP(info, "Mean X/X0 vs. phi: {}", meanX0vsPhi); LOGP(info, "Mean X/X0 vs. eta: {}", meanX0vsEta); LOGP(info, "Mean X/X0 vs. Zvtx: {}", meanX0vsZvtx); @@ -336,60 +347,68 @@ void scanXX0(const float rmax = 200, const float rmin = 0.2, const std::string O xOverX0VsZvtx.back()->SetLineColor(iMaterial + 2); xOverX0VsZvtx.back()->SetLineWidth(2); - if (xOverX0VsPhi.size() == 1) { - legVsPhi->AddEntry("", Form("#LT #it{X}/#it{X}_{0} #GT = %0.3f %%", meanX0vsPhi), ""); - legVsEta->AddEntry("", Form("#LT #it{X}/#it{X}_{0} #GT = %0.3f %%", meanX0vsEta), ""); - legVsZvtx->AddEntry("", Form("#LT #it{X}/#it{X}_{0} #GT = %0.3f %%", meanX0vsZvtx), ""); - } + // if (xOverX0VsPhi.size() == materials.size() - 1 /*Vacuum is skipped*/) { + // legVsPhi->AddEntry("", Form("#LT #it{X}/#it{X}_{0} #GT = %0.3f %%", meanX0vsPhi), ""); + // legVsEta->AddEntry("", Form("#LT #it{X}/#it{X}_{0} #GT = %0.3f %%", meanX0vsEta), ""); + // legVsZvtx->AddEntry("", Form("#LT #it{X}/#it{X}_{0} #GT = %0.3f %%", meanX0vsZvtx), ""); + // } + legVsPhi->AddEntry(xOverX0VsPhi.back(), materials[iMaterial].c_str(), "f"); legVsEta->AddEntry(xOverX0VsPhi.back(), materials[iMaterial].c_str(), "f"); legVsZvtx->AddEntry(xOverX0VsZvtx.back(), materials[iMaterial].c_str(), "f"); canv->cd(1)->SetGrid(); if (xOverX0VsPhi.size() == 1) { - xOverX0VsPhi.back()->SetMinimum(1.e-4); - // xOverX0VsPhi.back()->SetMaximum(20.f); + // xOverX0VsPhi.back()->SetMinimum(1.e-4); + xOverX0VsPhi.back()->SetMaximum(1e4); xOverX0VsPhi.back()->DrawCopy("HISTO"); - legVsPhi->Draw(); xOverX0VsPhiStack->Add(xOverX0VsPhi.back()); } else { + xOverX0VsPhi.back()->SetMaximum(1e4); xOverX0VsPhi.back()->DrawCopy("HISTO SAME"); xOverX0VsPhiStack->Add(xOverX0VsPhi.back()); } canv->cd(2)->SetGrid(); if (xOverX0VsEta.size() == 1) { - xOverX0VsEta.back()->SetMinimum(1.e-4); - // xOverX0VsEta.back()->SetMaximum(60.f); + // xOverX0VsEta.back()->SetMinimum(1.e-4); + xOverX0VsEta.back()->SetMaximum(1e4); xOverX0VsEta.back()->DrawCopy("HISTO"); - legVsEta->Draw(); xOverX0VsEtaStack->Add(xOverX0VsEta.back()); } else { + xOverX0VsEta.back()->SetMaximum(1e4); xOverX0VsEta.back()->DrawCopy("HISTO SAME"); xOverX0VsEtaStack->Add(xOverX0VsEta.back()); } canv->cd(3)->SetGrid(); if (xOverX0VsZvtx.size() == 1) { - xOverX0VsZvtx.back()->SetMinimum(1.e-4); - // xOverX0VsZvtx.back()->SetMaximum(120.f); + // xOverX0VsZvtx.back()->SetMinimum(1.e-4); + xOverX0VsZvtx.back()->SetMaximum(1e4); xOverX0VsZvtx.back()->DrawCopy("HISTO"); - legVsZvtx->Draw(); xOverX0VsZvtxStack->Add(xOverX0VsZvtx.back()); } else { + xOverX0VsZvtx.back()->SetMaximum(1e4); xOverX0VsZvtx.back()->DrawCopy("HISTO SAME"); xOverX0VsZvtxStack->Add(xOverX0VsZvtx.back()); } delete gGeoManager; } + canv->cd(1)->SetLogy(); + legVsPhi->Draw(); + canv->cd(2)->SetLogy(); + canv->cd(3)->SetLogy(); canvStack->cd(1)->SetGrid(); + legVsEta->Draw(); + canvStack->cd(1)->SetLogy(); xOverX0VsPhiStack->Draw("HISTO"); canvStack->cd(2)->SetGrid(); + canvStack->cd(2)->SetLogy(); xOverX0VsEtaStack->Draw("HISTO"); canvStack->cd(3)->SetGrid(); + canvStack->cd(3)->SetLogy(); xOverX0VsZvtxStack->Draw("HISTO"); - canvStack->BuildLegend(0.25, 0.6, 0.85, 0.9); - canv->SaveAs("alice3_material_vsphietaz.pdf"); - canvStack->SaveAs("alice3_material_vsphietaz_stack.pdf"); + canv->SaveAs("alice3_material_vsphietaz.png"); + canvStack->SaveAs("alice3_material_vsphietaz_stack.png"); } \ No newline at end of file diff --git a/Detectors/Upgrades/README.md b/Detectors/Upgrades/README.md index 4b071e6a87816..febcb18e746be 100644 --- a/Detectors/Upgrades/README.md +++ b/Detectors/Upgrades/README.md @@ -17,6 +17,7 @@ ENABLE_UPGRADES=ON aliBuild build O2 --defaults o2 Currently two sections are included: # zdc calibration workflows diff --git a/Detectors/ZDC/fastsimulation/CMakeLists.txt b/Detectors/ZDC/fastsimulation/CMakeLists.txt index c3ce25b9cc28c..527a7ca2553a2 100644 --- a/Detectors/ZDC/fastsimulation/CMakeLists.txt +++ b/Detectors/ZDC/fastsimulation/CMakeLists.txt @@ -1,20 +1,20 @@ -# Copyright 2019-2020 CERN and copyright holders of ALICE O2. -# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -# All rights not expressly granted are reserved. - -# This software is distributed under the terms of the GNU General Public -# License v3 (GPL Version 3), copied verbatim in the file "COPYING". - -# In applying this license CERN does not waive the privileges and immunities -# granted to it by virtue of its status as an Intergovernmental Organization -# or submit itself to any jurisdiction. +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. # @author SwirtaB o2_add_library(FASTSimulation SOURCES src/FastSimulations.cxx src/Processors.cxx src/Utils.cxx - PUBLIC_LINK_LIBRARIES ONNXRuntime::ONNXRuntime) + PUBLIC_LINK_LIBRARIES onnxruntime::onnxruntime) o2_data_file(COPY scales DESTINATION Detectors/ZDC/fastsimulation) @@ -22,4 +22,3 @@ o2_add_executable(fastsim-example SOURCES tests/run-example.cxx PUBLIC_LINK_LIBRARIES O2::FASTSimulation COMPONENT_NAME zdc) - diff --git a/Detectors/ZDC/fastsimulation/include/FastSimulations.h b/Detectors/ZDC/fastsimulation/include/FastSimulations.h index 9ac2216ba05bb..9fd89c8fb5838 100644 --- a/Detectors/ZDC/fastsimulation/include/FastSimulations.h +++ b/Detectors/ZDC/fastsimulation/include/FastSimulations.h @@ -17,7 +17,11 @@ #ifndef O2_ZDC_FAST_SIMULATIONS_H #define O2_ZDC_FAST_SIMULATIONS_H +#if __has_include() #include +#else +#include +#endif #include #include @@ -78,8 +82,8 @@ class NeuralFastSimulation Ort::MemoryInfo mMemoryInfo; /// Input/Output names and input shape - std::vector mInputNames; - std::vector mOutputNames; + std::vector mInputNames; + std::vector mOutputNames; std::vector> mInputShapes; /// If model has dynamic axis (for batch processing) this will tell ONNX expected size of those axis /// otherwise mBatchSize has no effect during runtime diff --git a/Detectors/ZDC/fastsimulation/include/Processors.h b/Detectors/ZDC/fastsimulation/include/Processors.h index e389bcd42c271..4ae4d0786bdd9 100644 --- a/Detectors/ZDC/fastsimulation/include/Processors.h +++ b/Detectors/ZDC/fastsimulation/include/Processors.h @@ -17,7 +17,11 @@ #ifndef O2_ZDC_FAST_SIMULATIONS_PROCESSORS_H #define O2_ZDC_FAST_SIMULATIONS_PROCESSORS_H +#if __has_include() #include +#else +#include +#endif #include #include @@ -81,4 +85,4 @@ std::vector readClassifier(const Ort::Value& value, size_t batchSize); std::vector> calculateChannels(const Ort::Value& value, size_t batchSize); } // namespace o2::zdc::fastsim::processors -#endif // O2_ZDC_FAST_SIMULATIONS_PROCESSORS_H \ No newline at end of file +#endif // O2_ZDC_FAST_SIMULATIONS_PROCESSORS_H diff --git a/Detectors/ZDC/fastsimulation/src/FastSimulations.cxx b/Detectors/ZDC/fastsimulation/src/FastSimulations.cxx index 4d3a887ea4e9b..5351eca66e1a3 100644 --- a/Detectors/ZDC/fastsimulation/src/FastSimulations.cxx +++ b/Detectors/ZDC/fastsimulation/src/FastSimulations.cxx @@ -48,13 +48,13 @@ size_t NeuralFastSimulation::getBatchSize() const void NeuralFastSimulation::setInputOutputData() { for (size_t i = 0; i < mSession->GetInputCount(); ++i) { - mInputNames.push_back(mSession->GetInputName(i, mAllocator)); + mInputNames.push_back(mSession->GetInputNameAllocated(i, mAllocator).get()); } for (size_t i = 0; i < mSession->GetInputCount(); ++i) { mInputShapes.emplace_back(mSession->GetInputTypeInfo(i).GetTensorTypeAndShapeInfo().GetShape()); } for (size_t i = 0; i < mSession->GetOutputCount(); ++i) { - mOutputNames.push_back(mSession->GetOutputName(i, mAllocator)); + mOutputNames.push_back(mSession->GetOutputNameAllocated(i, mAllocator).get()); } // Prevent negative values from being passed as tensor shape @@ -96,11 +96,19 @@ bool ConditionalModelSimulation::setInput(std::vector>& input void ConditionalModelSimulation::run() { // Run simulation (single event) with default run options + std::vector tmpInputs; + std::vector tmpOutputs; + for (unsigned int i = 0; i < mInputNames.size(); i++) { + tmpInputs.emplace_back(mInputNames[i].c_str()); + } + for (unsigned int i = 0; i < mOutputNames.size(); i++) { + tmpOutputs.emplace_back(mOutputNames[i].c_str()); + } mModelOutput = mSession->Run(Ort::RunOptions{nullptr}, - mInputNames.data(), + tmpInputs.data(), mInputTensors.data(), mInputTensors.size(), - mOutputNames.data(), + tmpOutputs.data(), mOutputNames.size()); mInputTensors.clear(); } diff --git a/Detectors/ZDC/simulation/CMakeLists.txt b/Detectors/ZDC/simulation/CMakeLists.txt index 96eef618c79d8..dda2e019c02b9 100644 --- a/Detectors/ZDC/simulation/CMakeLists.txt +++ b/Detectors/ZDC/simulation/CMakeLists.txt @@ -17,16 +17,20 @@ list(APPEND LinkLibraries O2::SimulationDataFormat O2::DetectorsRaw O2::Headers) -if (ONNXRuntime::ONNXRuntime_FOUND) +if (onnxruntime_FOUND) list(APPEND LinkLibraries O2::FASTSimulation) endif() o2_add_library(ZDCSimulation + TARGETVARNAME targetName SOURCES src/Detector.cxx src/Digitizer.cxx src/SimCondition.cxx src/ZDCSimParam.cxx src/SpatialPhotonResponse.cxx src/Digits2Raw.cxx src/DigitizerTest.cxx PUBLIC_LINK_LIBRARIES ${LinkLibraries}) +if (onnxruntime_FOUND) + target_compile_definitions(${targetName} PUBLIC ZDC_FASTSIM_ONNX) +endif() o2_target_root_dictionary(ZDCSimulation HEADERS include/ZDCSimulation/Digitizer.h diff --git a/Detectors/ZDC/simulation/include/ZDCSimulation/Detector.h b/Detectors/ZDC/simulation/include/ZDCSimulation/Detector.h index a0a9722a9d2f9..40e4babe8d760 100644 --- a/Detectors/ZDC/simulation/include/ZDCSimulation/Detector.h +++ b/Detectors/ZDC/simulation/include/ZDCSimulation/Detector.h @@ -26,7 +26,13 @@ // inclusions and forward decl for fast sim #ifdef ZDC_FASTSIM_ONNX + +#if __has_include() #include +#else +#include +#endif + namespace o2::zdc { namespace fastsim @@ -42,9 +48,7 @@ class StandardScaler; class FairVolume; -namespace o2 -{ -namespace zdc +namespace o2::zdc { class Detector : public o2::base::DetImpl @@ -197,10 +201,10 @@ class Detector : public o2::base::DetImpl /// Container for hit data std::vector* mHits; - float mLumiLength = 0; //TODO: make part of configurable params - float mTCLIAAPERTURE = 3.5; //TODO: make part of configurable params - float mTCLIAAPERTURENEG = 3.5; //TODO: make part of configurable params - float mVCollSideCCentreY = 0.; //TODO: make part of configurable params + float mLumiLength = 0; // TODO: make part of configurable params + float mTCLIAAPERTURE = 3.5; // TODO: make part of configurable params + float mTCLIAAPERTURENEG = 3.5; // TODO: make part of configurable params + float mVCollSideCCentreY = 0.; // TODO: make part of configurable params int mZNENVVolID = -1; // the volume id for the neutron det envelope volume int mZPENVVolID = -1; // the volume id for the proton det envelope volume @@ -240,12 +244,12 @@ class Detector : public o2::base::DetImpl // fastsim model wrapper #ifdef ZDC_FASTSIM_ONNX - fastsim::NeuralFastSimulation* mFastSimClassifier = nullptr; //! no ROOT serialization + fastsim::NeuralFastSimulation* mFastSimClassifier = nullptr; //! no ROOT serialization fastsim::NeuralFastSimulation* mFastSimModelNeutron = nullptr; //! fastsim::NeuralFastSimulation* mFastSimModelProton = nullptr; //! // Scalers for models inputs - fastsim::processors::StandardScaler* mClassifierScaler = nullptr; //! + fastsim::processors::StandardScaler* mClassifierScaler = nullptr; //! fastsim::processors::StandardScaler* mModelScalerNeutron = nullptr; //! fastsim::processors::StandardScaler* mModelScalerProton = nullptr; //! @@ -273,8 +277,7 @@ class Detector : public o2::base::DetImpl friend class o2::base::DetImpl; ClassDefOverride(Detector, 1); }; -} // namespace zdc -} // namespace o2 +} // namespace o2::zdc #ifdef USESHM namespace o2 diff --git a/Detectors/ZDC/simulation/src/Detector.cxx b/Detectors/ZDC/simulation/src/Detector.cxx index 54c97a28dea89..c6f91d9c2164f 100644 --- a/Detectors/ZDC/simulation/src/Detector.cxx +++ b/Detectors/ZDC/simulation/src/Detector.cxx @@ -271,7 +271,7 @@ void Detector::getDetIDandSecID(TString const& volname, math_utils::Vector3D 0) { detector = ZNA; - xDet = x - math_utils::Vector3D(Geometry::ZNAPOSITION[0], Geometry::ZNAPOSITION[1], Geometry::ZNAPOSITION[2]); + xDet = -(x - math_utils::Vector3D(Geometry::ZNAPOSITION[0], Geometry::ZNAPOSITION[1], Geometry::ZNAPOSITION[2])); } else if (x.Z() < 0) { detector = ZNC; @@ -297,7 +297,7 @@ void Detector::getDetIDandSecID(TString const& volname, math_utils::Vector3D 0) { detector = ZPA; // (NB -> DIFFERENT FROM AliRoot!!!) - xDet = x - math_utils::Vector3D(Geometry::ZPAPOSITION[0], Geometry::ZPAPOSITION[1], Geometry::ZPAPOSITION[2]); + xDet = -(x - math_utils::Vector3D(Geometry::ZPAPOSITION[0], Geometry::ZPAPOSITION[1], Geometry::ZPAPOSITION[2])); } else if (x.Z() < 0) { detector = ZPC; // (NB -> DIFFERENT FROM AliRoot!!!) xDet = x - math_utils::Vector3D(Geometry::ZPCPOSITION[0], Geometry::ZPCPOSITION[1], Geometry::ZPCPOSITION[2]); diff --git a/EventVisualisation/Workflow/CMakeLists.txt b/EventVisualisation/Workflow/CMakeLists.txt index 469d502a2a06c..76266dca57a28 100644 --- a/EventVisualisation/Workflow/CMakeLists.txt +++ b/EventVisualisation/Workflow/CMakeLists.txt @@ -40,6 +40,8 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2" O2::TOFBase O2::PHOSBase O2::EMCALBase + O2::EMCALCalib + O2::EMCALWorkflow O2::MIDBase O2::TOFWorkflowIO O2::TPCReconstruction @@ -74,6 +76,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2" O2::TOFBase O2::PHOSBase O2::EMCALBase + O2::EMCALCalib O2::MIDBase O2::TOFWorkflowIO O2::TPCReconstruction diff --git a/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h b/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h index 83b448568bbff..f8bef1100227f 100644 --- a/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h +++ b/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h @@ -55,7 +55,8 @@ class Geometry; namespace o2::emcal { class Geometry; -} +class CellRecalibrator; +} // namespace o2::emcal namespace o2::event_visualisation { @@ -207,6 +208,9 @@ class EveWorkflowHelper const o2::globaltracking::RecoContainer* mRecoCont = nullptr; const o2::globaltracking::RecoContainer* getRecoContainer() const { return mRecoCont; } void setRecoContainer(const o2::globaltracking::RecoContainer* rc) { mRecoCont = rc; } + void setEMCALCellRecalibrator(o2::emcal::CellRecalibrator* calibrator) { mEMCALCalib = calibrator; } + void setMaxEMCALCellTime(float maxtime) { mEMCALMaxCellTime = maxtime; } + void setMinEMCALCellEnergy(float minenergy) { mEMCALMinCellEnergy = minenergy; } TracksSet mTrackSet; o2::event_visualisation::VisualisationEvent mEvent; std::unordered_map mTotalDataTypes; @@ -221,11 +225,14 @@ class EveWorkflowHelper o2::its::GeometryTGeo* mITSGeom; o2::phos::Geometry* mPHOSGeom; o2::emcal::Geometry* mEMCALGeom; + o2::emcal::CellRecalibrator* mEMCALCalib = nullptr; float mMUS2TPCTimeBins = 5.0098627; float mITSROFrameLengthMUS = 0; ///< ITS RO frame in mus float mMFTROFrameLengthMUS = 0; ///< MFT RO frame in mus float mTPCBin2MUS = 0; + float mEMCALMaxCellTime = 100.; ///< EMCAL cell time cut (in ns) + float mEMCALMinCellEnergy = 0.3; ///< EMCAL cell energy cut (in GeV) static int BCDiffErrCount; const o2::vertexing::PVertexerParams* mPVParams = nullptr; }; diff --git a/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h b/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h index b3431951ed41f..2ea64cab1ff3c 100644 --- a/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h +++ b/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h @@ -19,6 +19,8 @@ #include "ReconstructionDataFormats/GlobalTrackID.h" #include "DataFormatsGlobalTracking/RecoContainer.h" #include "DetectorsBase/GRPGeomHelper.h" +#include "EMCALCalib/CellRecalibrator.h" +#include "EMCALWorkflow/CalibLoader.h" #include "EveWorkflow/DetectorData.h" #include "Framework/Task.h" #include @@ -54,12 +56,13 @@ class O2DPLDisplaySpec : public o2::framework::Task o2::dataformats::GlobalTrackID::mask_t clMask, std::shared_ptr dataRequest, std::shared_ptr gr, + std::shared_ptr emcCalibLoader, const std::string& jsonPath, const std::string& ext, std::chrono::milliseconds timeInterval, int numberOfFiles, int numberOfTracks, bool eveHostNameMatch, int minITSTracks, int minTracks, bool filterITSROF, bool filterTime, const EveWorkflowHelper::Bracket& timeBracket, bool removeTPCEta, - const EveWorkflowHelper::Bracket& etaBracket, bool trackSorting, int onlyNthEvent, bool primaryVertex, int maxPrimaryVertices, bool primaryVertexTriggers, float primaryVertexMinZ, float primaryVertexMaxZ, float primaryVertexMinX, float primaryVertexMaxX, float primaryVertexMinY, float primaryVertexMaxY) - : mDisableWrite(disableWrite), mUseMC(useMC), mTrkMask(trkMask), mClMask(clMask), mDataRequest(dataRequest), mGGCCDBRequest(gr), mJsonPath(jsonPath), mExt(ext), mTimeInterval(timeInterval), mNumberOfFiles(numberOfFiles), mNumberOfTracks(numberOfTracks), mEveHostNameMatch(eveHostNameMatch), mMinITSTracks(minITSTracks), mMinTracks(minTracks), mFilterITSROF(filterITSROF), mFilterTime(filterTime), mTimeBracket(timeBracket), mRemoveTPCEta(removeTPCEta), mEtaBracket(etaBracket), mTrackSorting(trackSorting), mOnlyNthEvent(onlyNthEvent), mPrimaryVertexMode(primaryVertex), mMaxPrimaryVertices(maxPrimaryVertices), mPrimaryVertexTriggers(primaryVertexTriggers), mPrimaryVertexMinZ(primaryVertexMinZ), mPrimaryVertexMaxZ(primaryVertexMaxZ), mPrimaryVertexMinX(primaryVertexMinX), mPrimaryVertexMaxX(primaryVertexMaxX), mPrimaryVertexMinY(primaryVertexMinY), mPrimaryVertexMaxY(primaryVertexMaxY), mRunType(o2::parameters::GRPECS::NONE) + const EveWorkflowHelper::Bracket& etaBracket, bool trackSorting, int onlyNthEvent, bool primaryVertex, int maxPrimaryVertices, bool primaryVertexTriggers, float primaryVertexMinZ, float primaryVertexMaxZ, float primaryVertexMinX, float primaryVertexMaxX, float primaryVertexMinY, float primaryVertexMaxY, float maxEMCALCellTime, float minEMCALCellEnergy) + : mDisableWrite(disableWrite), mUseMC(useMC), mTrkMask(trkMask), mClMask(clMask), mDataRequest(dataRequest), mGGCCDBRequest(gr), mEMCALCalibLoader(emcCalibLoader), mJsonPath(jsonPath), mExt(ext), mTimeInterval(timeInterval), mNumberOfFiles(numberOfFiles), mNumberOfTracks(numberOfTracks), mEveHostNameMatch(eveHostNameMatch), mMinITSTracks(minITSTracks), mMinTracks(minTracks), mFilterITSROF(filterITSROF), mFilterTime(filterTime), mTimeBracket(timeBracket), mRemoveTPCEta(removeTPCEta), mEtaBracket(etaBracket), mTrackSorting(trackSorting), mOnlyNthEvent(onlyNthEvent), mPrimaryVertexMode(primaryVertex), mMaxPrimaryVertices(maxPrimaryVertices), mPrimaryVertexTriggers(primaryVertexTriggers), mPrimaryVertexMinZ(primaryVertexMinZ), mPrimaryVertexMaxZ(primaryVertexMaxZ), mPrimaryVertexMinX(primaryVertexMinX), mPrimaryVertexMaxX(primaryVertexMaxX), mPrimaryVertexMinY(primaryVertexMinY), mPrimaryVertexMaxY(primaryVertexMaxY), mEMCALMaxCellTime(maxEMCALCellTime), mEMCALMinCellEnergy(minEMCALCellEnergy), mRunType(o2::parameters::GRPECS::NONE) { this->mTimeStamp = std::chrono::high_resolution_clock::now() - timeInterval; // first run meets condition @@ -99,6 +102,8 @@ class O2DPLDisplaySpec : public o2::framework::Task float mPrimaryVertexMaxX; // maximum x position of the primary vertex float mPrimaryVertexMinY; // minimum y position of the primary vertex float mPrimaryVertexMaxY; // maximum y position of the primary vertex + float mEMCALMaxCellTime; // max abs EMCAL cell time (in ns) + float mEMCALMinCellEnergy; // min EMCAL cell energy (in GeV) int mEventCounter = 0; std::chrono::time_point mTimeStamp; @@ -108,6 +113,8 @@ class O2DPLDisplaySpec : public o2::framework::Task o2::parameters::GRPECS::RunType mRunType; std::shared_ptr mDataRequest; std::shared_ptr mGGCCDBRequest; + std::shared_ptr mEMCALCalibLoader; + std::unique_ptr mEMCALCalibrator; }; } // namespace o2::event_visualisation diff --git a/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx b/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx index 3b1b40df9aba3..51a8a44634142 100644 --- a/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx +++ b/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx @@ -35,6 +35,7 @@ #include "ITSBase/GeometryTGeo.h" #include "PHOSBase/Geometry.h" #include "EMCALBase/Geometry.h" +#include "EMCALCalib/CellRecalibrator.h" #include #include #include @@ -644,6 +645,30 @@ void EveWorkflowHelper::drawEMC(GID gid) const gsl::span cellsForTrigger(cells.data() + trig.getFirstEntry(), trig.getNumberOfObjects()); for (const auto& cell : cellsForTrigger) { + if (!(cell.getType() == o2::emcal::ChannelType_t::HIGH_GAIN || cell.getType() == o2::emcal::ChannelType_t::LOW_GAIN)) { + // Select FEE cells (excluding LEDMON or TRU cells) + continue; + } + auto cellTime = cell.getTimeStamp(); + auto cellEnergy = cell.getEnergy(); + if (mEMCALCalib) { + // try to recalibrate cell in case calibration is available (bad channel removal, energy calibration, time calibration) + auto calibCell = mEMCALCalib->getCalibratedCell(cell); + if (!calibCell) { + // cell was rejected by bad channel calib + continue; + } + cellTime = calibCell->getTimeStamp(); + cellEnergy = calibCell->getEnergy(); + } + if (std::abs(cellTime) > mEMCALMaxCellTime) { + // cell rejected by time cut (pileup or noise) + continue; + } + if (cellEnergy < mEMCALMinCellEnergy) { + // cell rejected by energy cut (rejection of soft cells) + continue; + } const auto id = cell.getTower(); // Point3D with x,y,z coordinates of cell with absId inside SM const auto relPosCell = this->mEMCALGeom->RelPosCellInSModule(id); @@ -657,7 +682,7 @@ void EveWorkflowHelper::drawEMC(GID gid) TVector3 vPos(gPos.data()); auto vCalo = mEvent.addCalo({.time = static_cast(time), - .energy = cell.getEnergy(), + .energy = cellEnergy, .phi = (float)vPos.Phi(), .eta = (float)vPos.Eta(), .PID = 0, diff --git a/EventVisualisation/Workflow/src/O2DPLDisplay.cxx b/EventVisualisation/Workflow/src/O2DPLDisplay.cxx index 3885bbce959a8..068390f0e22ea 100644 --- a/EventVisualisation/Workflow/src/O2DPLDisplay.cxx +++ b/EventVisualisation/Workflow/src/O2DPLDisplay.cxx @@ -26,6 +26,8 @@ #include "TOFBase/Geo.h" #include "TPCFastTransform.h" #include "TRDBase/Geometry.h" +#include "EMCALCalib/CellRecalibrator.h" +#include "EMCALWorkflow/CalibLoader.h" #include "GlobalTrackingWorkflowHelpers/InputHelper.h" #include "ReconstructionDataFormats/GlobalTrackID.h" #include "ReconstructionDataFormats/PrimaryVertex.h" @@ -76,6 +78,9 @@ void customize(std::vector& workflowOptions) {"primary-vertex-mode", VariantType::Bool, false, {"produce jsons with individual primary vertices, not total time frame data"}}, {"max-primary-vertices", VariantType::Int, 5, {"maximum number of primary vertices to draw per time frame"}}, {"primary-vertex-triggers", VariantType::Bool, false, {"instead of drawing vertices with tracks (and maybe calorimeter triggers), draw vertices with calorimeter triggers (and maybe tracks)"}}, + {"no-calibrate-emcal", VariantType::Bool, false, {"Do not apply on-the-fly EMCAL calibration"}}, + {"emcal-max-celltime", VariantType::Float, 100.f, {"Max. EMCAL cell time (in ns)"}}, + {"emcal-min-cellenergy", VariantType::Float, 0.3f, {"Min. EMCAL cell energy (in GeV)"}}, {"primary-vertex-min-z", VariantType::Float, -o2::constants::math::VeryBig, {"minimum z position for primary vertex"}}, {"primary-vertex-max-z", VariantType::Float, o2::constants::math::VeryBig, {"maximum z position for primary vertex"}}, {"primary-vertex-min-x", VariantType::Float, -o2::constants::math::VeryBig, {"minimum x position for primary vertex"}}, @@ -93,6 +98,9 @@ void O2DPLDisplaySpec::init(InitContext& ic) LOGF(info, "------------------------ O2DPLDisplay::init version ", o2_eve_version, " ------------------------------------"); mData.mConfig.configProcessing.runMC = mUseMC; o2::base::GRPGeomHelper::instance().setRequest(mGGCCDBRequest); + if (mEMCALCalibLoader) { + mEMCALCalibrator = std::make_unique(); + } } void O2DPLDisplaySpec::run(ProcessingContext& pc) @@ -114,6 +122,19 @@ void O2DPLDisplaySpec::run(ProcessingContext& pc) o2::globaltracking::RecoContainer recoCont; recoCont.collectData(pc, *mDataRequest); updateTimeDependentParams(pc); // Make sure that this is called after the RecoContainer collect data, since some condition objects are fetched there + if (mEMCALCalibLoader) { + mEMCALCalibLoader->checkUpdates(pc); + if (mEMCALCalibLoader->hasUpdateBadChannelMap()) { + mEMCALCalibrator->setBadChannelMap(mEMCALCalibLoader->getBadChannelMap()); + } + if (mEMCALCalibLoader->hasUpdateTimeCalib()) { + mEMCALCalibrator->setTimeCalibration(mEMCALCalibLoader->getTimeCalibration()); + } + if (mEMCALCalibLoader->hasUpdateGainCalib()) { + mEMCALCalibrator->setGainCalibration(mEMCALCalibLoader->getGainCalibration()); + } + } + EveWorkflowHelper::FilterSet enabledFilters; enabledFilters.set(EveWorkflowHelper::Filter::ITSROF, this->mFilterITSROF); @@ -122,6 +143,12 @@ void O2DPLDisplaySpec::run(ProcessingContext& pc) enabledFilters.set(EveWorkflowHelper::Filter::TotalNTracks, this->mNumberOfTracks != -1); EveWorkflowHelper helper(enabledFilters, this->mNumberOfTracks, this->mTimeBracket, this->mEtaBracket, this->mPrimaryVertexMode); helper.setRecoContainer(&recoCont); + if (mEMCALCalibrator) { + helper.setEMCALCellRecalibrator(mEMCALCalibrator.get()); + } + helper.setMaxEMCALCellTime(mEMCALMaxCellTime); + helper.setMinEMCALCellEnergy(mEMCALMinCellEnergy); + helper.setITSROFs(); helper.selectTracks(&(mData.mConfig.configCalib), mClMask, mTrkMask, mTrkMask); helper.selectTowers(); @@ -240,6 +267,9 @@ void O2DPLDisplaySpec::finaliseCCDB(ConcreteDataMatcher& matcher, void* obj) if (o2::base::GRPGeomHelper::instance().finaliseCCDB(matcher, obj)) { return; } + if (mEMCALCalibLoader && mEMCALCalibLoader->finalizeCCDB(matcher, obj)) { + return; + } if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { LOGF(info, "ITS cluster dictionary updated"); mData.setITSDict((const o2::itsmft::TopologyDictionary*)obj); @@ -372,6 +402,8 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) auto primaryVertexMaxX = cfgc.options().get("primary-vertex-max-x"); auto primaryVertexMinY = cfgc.options().get("primary-vertex-min-y"); auto primaryVertexMaxY = cfgc.options().get("primary-vertex-max-y"); + auto maxEMCALCellTime = cfgc.options().get("emcal-max-celltime"); + auto minEMCALCellEnergy = cfgc.options().get("emcal-min-cellenergy"); if (numberOfTracks == -1) { tracksSorting = false; // do not sort if all tracks are allowed @@ -385,11 +417,20 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) dataRequest->inputs, true); // query only once all objects except mag.field + std::shared_ptr emcalCalibLoader; + if (!cfgc.options().get("no-calibrate-emcal")) { + emcalCalibLoader = std::make_shared(); + emcalCalibLoader->enableTimeCalib(true); + emcalCalibLoader->enableBadChannelMap(true); + emcalCalibLoader->enableGainCalib(true); + emcalCalibLoader->defineInputSpecs(dataRequest->inputs); + } + specs.emplace_back(DataProcessorSpec{ "o2-eve-export", dataRequest->inputs, {}, - AlgorithmSpec{adaptFromTask(disableWrite, useMC, srcTrk, srcCl, dataRequest, ggRequest, jsonFolder, ext, timeInterval, numberOfFiles, numberOfTracks, eveHostNameMatch, minITSTracks, minTracks, filterITSROF, filterTime, timeBracket, removeTPCEta, etaBracket, tracksSorting, onlyNthEvent, primaryVertexMode, maxPrimaryVertices, primaryVertexTriggers, primaryVertexMinZ, primaryVertexMaxZ, primaryVertexMinX, primaryVertexMaxX, primaryVertexMinY, primaryVertexMaxY)}}); + AlgorithmSpec{adaptFromTask(disableWrite, useMC, srcTrk, srcCl, dataRequest, ggRequest, emcalCalibLoader, jsonFolder, ext, timeInterval, numberOfFiles, numberOfTracks, eveHostNameMatch, minITSTracks, minTracks, filterITSROF, filterTime, timeBracket, removeTPCEta, etaBracket, tracksSorting, onlyNthEvent, primaryVertexMode, maxPrimaryVertices, primaryVertexTriggers, primaryVertexMinZ, primaryVertexMaxZ, primaryVertexMinX, primaryVertexMaxX, primaryVertexMinY, primaryVertexMaxY, maxEMCALCellTime, minEMCALCellEnergy)}}); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(cfgc, specs); diff --git a/Framework/CCDBSupport/src/CCDBHelpers.cxx b/Framework/CCDBSupport/src/CCDBHelpers.cxx index 37c4affe2877e..6c510ad189ac5 100644 --- a/Framework/CCDBSupport/src/CCDBHelpers.cxx +++ b/Framework/CCDBSupport/src/CCDBHelpers.cxx @@ -232,7 +232,7 @@ auto populateCacheWith(std::shared_ptr const& helper, uint64_t cachePopulatedAt = url2uuid->second.cachePopulatedAt; // If timestamp is before the time the element was cached or after the claimed validity, we need to check validity, again // when online. - bool cacheExpired = (validUntil <= timestamp) && (timestamp <= cachePopulatedAt); + bool cacheExpired = (validUntil <= timestamp) || (timestamp <= cachePopulatedAt); checkValidity = (std::abs(int(timingInfo.tfCounter - url2uuid->second.lastCheckedTF)) >= chRate) && (isOnline || cacheExpired); } else { checkValidity = true; // never skip check if the cache is empty @@ -269,6 +269,7 @@ auto populateCacheWith(std::shared_ptr const& helper, // somewhere here pruneFromCache should be called helper->mapURL2UUID[path].etag = headers["ETag"]; // update uuid helper->mapURL2UUID[path].cachePopulatedAt = timestamp; + helper->mapURL2UUID[path].cacheValidUntil = headers["Cache-Valid-Until"].empty() ? 0 : std::stoul(headers["Cache-Valid-Until"]); helper->mapURL2UUID[path].cacheMiss++; helper->mapURL2UUID[path].minSize = std::min(v.size(), helper->mapURL2UUID[path].minSize); helper->mapURL2UUID[path].maxSize = std::max(v.size(), helper->mapURL2UUID[path].maxSize); diff --git a/Framework/CHANGELOG.md b/Framework/CHANGELOG.md index 044274d9515c4..331805f8538fd 100644 --- a/Framework/CHANGELOG.md +++ b/Framework/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2024-03-14: Move DataProcessingDevice to use Signposts + +All the messages from DataProcessingDevice have been migrated to use Signpost. +This will hopefully simplify debugging. + # 2024-02-22: Drop Tracy support Tracy support never took off, so I am dropping it. This was mostly because people do not know about it and having a per process profile GUI was way unpractical. Moreover, needing an extra compile time flag meant one most likely did not have the support compiled in when needed. diff --git a/Framework/Core/CMakeLists.txt b/Framework/Core/CMakeLists.txt index 05bcb1bd53083..d392ba42fe8ac 100644 --- a/Framework/Core/CMakeLists.txt +++ b/Framework/Core/CMakeLists.txt @@ -11,6 +11,7 @@ o2_add_library(Framework SOURCES src/AODReaderHelpers.cxx + src/AnalysisHelpers.cxx src/AlgorithmSpec.cxx src/ArrowSupport.cxx src/ArrowTableSlicingCache.cxx @@ -108,7 +109,7 @@ o2_add_library(Framework src/OptionsHelpers.cxx src/PropertyTreeHelpers.cxx src/ProcessingContext.cxx - src/Plugins.cxx + src/PluginManager.cxx src/RateLimiter.cxx src/ResourcesMonitoringHelper.cxx src/ResourcePolicy.cxx @@ -263,6 +264,11 @@ o2_add_test(Timers NAME test_Framework_test_Timers LABELS framework PUBLIC_LINK_LIBRARIES O2::Framework) +# FIXME: make this a proper test, when it actually does not hang. +o2_add_executable(test-framework-ConsumeWhenAllOrdered + SOURCES test/test_ConsumeWhenAllOrdered.cxx + PUBLIC_LINK_LIBRARIES O2::Framework) + o2_add_test(SuppressionGenerator NAME test_Framework_test_SuppressionGenerator SOURCES test/test_SuppressionGenerator.cxx COMPONENT_NAME Framework @@ -275,6 +281,11 @@ o2_add_test(O2DatabasePDG NAME test_Framework_test_O2DatabasePDG LABELS framework PUBLIC_LINK_LIBRARIES O2::Framework O2::FrameworkPhysicsSupport) +o2_add_executable(crashing-workflow + SOURCES test/test_CrashingWorkflow.cxx + COMPONENT_NAME Framework + PUBLIC_LINK_LIBRARIES O2::Framework) + # All the tests which require ROOT to work add_executable(o2-test-framework-root test/test_Root2ArrowTable.cxx @@ -284,6 +295,7 @@ target_link_libraries(o2-test-framework-root PRIVATE O2::Catch2) target_link_libraries(o2-test-framework-root PRIVATE ROOT::ROOTDataFrame) set_property(TARGET o2-test-framework-root PROPERTY RUNTIME_OUTPUT_DIRECTORY ${outdir}) add_test(NAME framework:root COMMAND o2-test-framework-root --skip-benchmarks) +add_test(NAME framework:crash COMMAND sh -e -c "PATH=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}:$PATH ${CMAKE_CURRENT_LIST_DIR}/test/test_AllCrashTypes.sh") o2_add_test(InfoLogger NAME test_Framework_test_InfoLogger SOURCES test/test_InfoLogger.cxx diff --git a/Framework/Core/COOKBOOK.md b/Framework/Core/COOKBOOK.md index d92006e63d650..c327651ae53ca 100644 --- a/Framework/Core/COOKBOOK.md +++ b/Framework/Core/COOKBOOK.md @@ -524,8 +524,7 @@ Sometimes (e.g. when running a child inside valgrind) it might be useful to disa some-workflow --monitoring-backend=no-op:// ``` -notice that the -will not function properly if you do so. +notice that the will not function properly if you do so. ## Profiling diff --git a/Framework/Core/README.md b/Framework/Core/README.md index 70a35ddbaaf9d..8d3ad9db01135 100644 --- a/Framework/Core/README.md +++ b/Framework/Core/README.md @@ -277,6 +277,8 @@ however, no API is provided to explicitly send it. All the created DataChunks ar When an error happens during processing of some data, the writer of the `process` function should simply throw an exception. By default the exception is caught by the `DataProcessingDevice` and a message is printed (if `std::exeception` derived `what()` method is used, otherwise a generic message is given). Users can provide themselves an error handler by specifying via the `onError` callback specified in `DataProcessorSpec`. This will allow in the future to reinject data into the flow in case of an error. +When the exception is thrown inside processing function its message and stack trace is printed. However, the application itself is not terminated. If the error encountered is so severe that current workflow cannot continue it is advisable to call `LOG(fatal)` with proper describing message, which makes the application shutdown with non zero error code. + ### Services Services are utility classes which `DataProcessor`s can access to request out-of-bound, deployment dependent, functionalities. For example a service could be used to post metrics to the monitoring system or to get a GPU context. The former would be dependent on whether you are running on your laptop (where monitoring could simply mean print out metrics on the command line) or in a large cluster (where monitoring probably means to send metrics to an aggregator device which then pushes them to the backend. diff --git a/Framework/Core/include/Framework/ASoA.h b/Framework/Core/include/Framework/ASoA.h index 76e1edae9fcca..9cc7e0c71f939 100644 --- a/Framework/Core/include/Framework/ASoA.h +++ b/Framework/Core/include/Framework/ASoA.h @@ -67,6 +67,7 @@ struct Binding { void accessingInvalidIndexFor(const char* getter); void dereferenceWithWrongType(); +void missingFilterDeclaration(int hash, int ai); template auto createFieldsFromColumns(framework::pack) @@ -1006,7 +1007,7 @@ struct is_binding_compatible : std::conditional_t -static std::string getLabelFromType() +static constexpr std::string getLabelFromType() { if constexpr (soa::is_index_table_v>) { using TT = typename std::decay_t::first_t; @@ -1039,19 +1040,19 @@ static std::string getLabelFromType() } template -static auto hasColumnForKey(framework::pack, std::string const& key) +static constexpr auto hasColumnForKey(framework::pack, std::string const& key) { return ((C::inherited_t::mLabel == key) || ...); } template -static std::pair hasKey(std::string const& key) +static constexpr std::pair hasKey(std::string const& key) { return {hasColumnForKey(typename T::persistent_columns_t{}, key), getLabelFromType()}; } template -static auto haveKey(framework::pack, std::string const& key) +static constexpr auto haveKey(framework::pack, std::string const& key) { return std::vector{hasKey(key)...}; } @@ -1060,7 +1061,7 @@ void notFoundColumn(const char* label, const char* key); void missingOptionalPreslice(const char* label, const char* key); template -static std::string getLabelFromTypeForKey(std::string const& key) +static constexpr std::string getLabelFromTypeForKey(std::string const& key) { if constexpr (soa::is_type_with_originals_v>) { using Os = typename std::decay_t::originals; @@ -1189,6 +1190,20 @@ namespace o2::soa template inline constexpr bool is_soa_iterator_v = framework::is_base_of_template_v || framework::is_specialization_v; +template +inline constexpr bool is_soa_filtered_iterator_v() +{ + if constexpr (!is_soa_iterator_v) { + return false; + } else { + if constexpr (std::is_same_v) { + return true; + } else { + return false; + } + } +} + template using is_soa_table_t = typename framework::is_specialization; diff --git a/Framework/Core/include/Framework/AlgorithmSpec.h b/Framework/Core/include/Framework/AlgorithmSpec.h index 39d0582a0f1ee..e08d829e489bd 100644 --- a/Framework/Core/include/Framework/AlgorithmSpec.h +++ b/Framework/Core/include/Framework/AlgorithmSpec.h @@ -83,17 +83,6 @@ struct AlgorithmSpec { struct AlgorithmPlugin { virtual AlgorithmSpec create() = 0; }; - -template -struct StringLiteral { - constexpr StringLiteral(const char (&str)[N]) - { - std::copy_n(str, N, value); - } - - char value[N]; -}; - // Allow fetching inputs from the context using a string literal. template struct Input { diff --git a/Framework/Core/include/Framework/AnalysisDataModel.h b/Framework/Core/include/Framework/AnalysisDataModel.h index 2395c195330db..0df1186f4d04e 100644 --- a/Framework/Core/include/Framework/AnalysisDataModel.h +++ b/Framework/Core/include/Framework/AnalysisDataModel.h @@ -12,9 +12,12 @@ #define O2_FRAMEWORK_ANALYSISDATAMODEL_H_ #include "Framework/ASoA.h" + #include #include #include +#include // std::move + #include "Framework/DataTypes.h" #include "CommonConstants/MathConstants.h" #include "CommonConstants/PhysicsConstants.h" @@ -153,22 +156,32 @@ DECLARE_SOA_DYNAMIC_COLUMN(Pz, pz, //! Momentum in z-direction in GeV/c auto pt = 1.f / std::abs(signed1Pt); return pt * tgl; }); - +DECLARE_SOA_DYNAMIC_COLUMN(PVector, pVector, //! Momentum vector in x,y,z-directions in GeV/c + [](float signed1Pt, float snp, float alpha, float tgl) -> std::array { + const auto pt = 1.f / std::abs(signed1Pt); + // FIXME: GCC & clang should optimize to sincosf + const float cs = cosf(alpha), sn = sinf(alpha); + const auto r = std::sqrt((1.f - snp) * (1.f + snp)); + const auto px = pt * (r * cs - snp * sn); + const auto py = pt * (snp * cs + r * sn); + const auto pz = pt * tgl; + return std::array{px, py, pz}; + }); DECLARE_SOA_EXPRESSION_COLUMN(P, p, float, //! Momentum in Gev/c ifnode(nabs(aod::track::signed1Pt) <= o2::constants::math::Almost0, o2::constants::math::VeryBig, 0.5f * (ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::track::tgl)) + 1.f / ntan(o2::constants::math::PIQuarter - 0.5f * natan(aod::track::tgl))) / nabs(aod::track::signed1Pt))); DECLARE_SOA_DYNAMIC_COLUMN(Energy, energy, //! Track energy, computed under the mass assumption given as input [](float signed1Pt, float tgl, float mass) -> float { const auto pt = 1.f / std::abs(signed1Pt); - const auto p = 0.5f * (tan(o2::constants::math::PIQuarter - 0.5f * atan(tgl)) + 1.f / tan(o2::constants::math::PIQuarter - 0.5f * atan(tgl))) * pt; - return sqrt(p * p + mass * mass); + const auto p = 0.5f * (std::tan(o2::constants::math::PIQuarter - 0.5f * std::atan(tgl)) + 1.f / std::tan(o2::constants::math::PIQuarter - 0.5f * std::atan(tgl))) * pt; + return std::sqrt(p * p + mass * mass); }); DECLARE_SOA_DYNAMIC_COLUMN(Rapidity, rapidity, //! Track rapidity, computed under the mass assumption given as input [](float signed1Pt, float tgl, float mass) -> float { const auto pt = 1.f / std::abs(signed1Pt); const auto pz = pt * tgl; - const auto p = 0.5f * (tan(o2::constants::math::PIQuarter - 0.5f * atan(tgl)) + 1.f / tan(o2::constants::math::PIQuarter - 0.5f * atan(tgl))) * pt; - const auto energy = sqrt(p * p + mass * mass); - return 0.5f * log((energy + pz) / (energy - pz)); + const auto p = 0.5f * (std::tan(o2::constants::math::PIQuarter - 0.5f * std::atan(tgl)) + 1.f / std::tan(o2::constants::math::PIQuarter - 0.5f * std::atan(tgl))) * pt; + const auto energy = std::sqrt(p * p + mass * mass); + return 0.5f * std::log((energy + pz) / (energy - pz)); }); // TRACKPARCOV TABLE definition @@ -367,6 +380,7 @@ DECLARE_SOA_TABLE_FULL(StoredTracks, "Tracks", "AOD", "TRACK", //! On disk versi track::Px, track::Py, track::Pz, + track::PVector, track::Energy, track::Rapidity, track::Sign, @@ -386,6 +400,8 @@ DECLARE_SOA_TABLE_FULL(StoredTracksIU, "Tracks_IU", "AOD", "TRACK_IU", //! On di track::Px, track::Py, track::Pz, + track::PVector, + track::Energy, track::Rapidity, track::Sign, o2::soa::Marker<2>); @@ -1341,8 +1357,10 @@ DECLARE_SOA_COLUMN(V0Type, v0Type, uint8_t); //! cust DECLARE_SOA_DYNAMIC_COLUMN(IsStandardV0, isStandardV0, //! is standard V0 [](uint8_t V0Type) -> bool { return V0Type & (1 << 0); }); -DECLARE_SOA_DYNAMIC_COLUMN(IsPhotonV0, isPhotonV0, //! is standard V0 +DECLARE_SOA_DYNAMIC_COLUMN(IsPhotonV0, isPhotonV0, //! is TPC-only V0 for which the photon-mass-hypothesis was good [](uint8_t V0Type) -> bool { return V0Type & (1 << 1); }); +DECLARE_SOA_DYNAMIC_COLUMN(IsCollinearV0, isCollinearV0, //! is V0 for which the photon-mass-hypothesis was good and was fitted collinearly + [](uint8_t V0Type) -> bool { return V0Type & (1 << 2); }); } // namespace v0 @@ -1357,7 +1375,8 @@ DECLARE_SOA_TABLE_VERSIONED(V0s_002, "AOD", "V0", 2, //! Run 3 V0 table (version v0::PosTrackId, v0::NegTrackId, v0::V0Type, v0::IsStandardV0, - v0::IsPhotonV0); + v0::IsPhotonV0, + v0::IsCollinearV0); using V0s = V0s_002; //! this defines the current default version using V0 = V0s::iterator; @@ -1561,6 +1580,8 @@ DECLARE_SOA_DYNAMIC_COLUMN(GetHepMCStatusCode, getHepMCStatusCode, //! The HepMC [](uint8_t flags, int statusCode) -> int { if ((flags & o2::aod::mcparticle::enums::ProducedByTransport) == 0x0) { return o2::mcgenstatus::getHepMCStatusCode(statusCode); } else { return -1; } }); DECLARE_SOA_DYNAMIC_COLUMN(IsPhysicalPrimary, isPhysicalPrimary, //! True if particle is considered a physical primary according to the ALICE definition [](uint8_t flags) -> bool { return (flags & o2::aod::mcparticle::enums::PhysicalPrimary) == o2::aod::mcparticle::enums::PhysicalPrimary; }); +DECLARE_SOA_DYNAMIC_COLUMN(PVector, pVector, //! Momentum vector in x,y,z-directions in GeV/c + [](float px, float py, float pz) -> std::array { return std::array{px, py, pz}; }); DECLARE_SOA_EXPRESSION_COLUMN(Phi, phi, float, //! Phi in the range [0, 2pi) o2::constants::math::PI + natan2(-1.0f * aod::mcparticle::py, -1.0f * aod::mcparticle::px)); @@ -1599,6 +1620,7 @@ DECLARE_SOA_TABLE_FULL(StoredMcParticles_000, "McParticles", "AOD", "MCPARTICLE" mcparticle::Daughter0Id, mcparticle::Daughter1Id, mcparticle::Weight, mcparticle::Px, mcparticle::Py, mcparticle::Pz, mcparticle::E, mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, + mcparticle::PVector, mcparticle::ProducedByGenerator, mcparticle::FromBackgroundEvent, mcparticle::GetGenStatusCode, @@ -1612,6 +1634,7 @@ DECLARE_SOA_TABLE_FULL_VERSIONED(StoredMcParticles_001, "McParticles", "AOD", "M mcparticle::MothersIds, mcparticle::DaughtersIdSlice, mcparticle::Weight, mcparticle::Px, mcparticle::Py, mcparticle::Pz, mcparticle::E, mcparticle::Vx, mcparticle::Vy, mcparticle::Vz, mcparticle::Vt, + mcparticle::PVector, mcparticle::ProducedByGenerator, mcparticle::FromBackgroundEvent, mcparticle::GetGenStatusCode, diff --git a/Framework/Core/include/Framework/AnalysisHelpers.h b/Framework/Core/include/Framework/AnalysisHelpers.h index 2cfee5b525549..65543bd067f1e 100644 --- a/Framework/Core/include/Framework/AnalysisHelpers.h +++ b/Framework/Core/include/Framework/AnalysisHelpers.h @@ -14,7 +14,7 @@ #include "Framework/DataAllocator.h" #include "Framework/Traits.h" #include "Framework/TableBuilder.h" -#include "Framework/AnalysisDataModel.h" +#include "Framework/ASoA.h" #include "Framework/OutputSpec.h" #include "Framework/OutputRef.h" #include "Framework/InputSpec.h" @@ -482,6 +482,8 @@ auto getTableFromFilter(const T& table, soa::SelectionVector&& selection) } } +void initializePartitionCaches(std::set const& hashes, std::shared_ptr const& schema, expressions::Filter const& filter, gandiva::NodePtr& tree, gandiva::FilterPtr& gfilter); + template struct Partition { Partition(expressions::Node&& filter_) : filter{std::forward(filter_)} @@ -494,29 +496,14 @@ struct Partition { setTable(table); } - void intializeCaches(std::shared_ptr const& schema) + void intializeCaches(std::set const& hashes, std::shared_ptr const& schema) { - if (tree == nullptr) { - expressions::Operations ops = createOperations(filter); - if (isSchemaCompatible(schema, ops)) { - tree = createExpressionTree(ops, schema); - } else { - throw std::runtime_error("Partition filter does not match declared table type"); - } - } - if (gfilter == nullptr) { - gfilter = framework::expressions::createFilter(schema, framework::expressions::makeCondition(tree)); - } - } - - void inline bindTable(T const& table) - { - setTable(table); + initializePartitionCaches(hashes, schema, filter, tree, gfilter); } - void setTable(T const& table) + void bindTable(T const& table) { - intializeCaches(table.asArrowTable()->schema()); + intializeCaches(T::table_t::hashes(), table.asArrowTable()->schema()); if (dataframeChanged) { mFiltered = getTableFromFilter(table, soa::selectionToVector(framework::expressions::createSelection(table.asArrowTable(), gfilter))); dataframeChanged = false; diff --git a/Framework/Core/include/Framework/AnalysisManagers.h b/Framework/Core/include/Framework/AnalysisManagers.h index 9061ff297a924..f341f60392e9f 100644 --- a/Framework/Core/include/Framework/AnalysisManagers.h +++ b/Framework/Core/include/Framework/AnalysisManagers.h @@ -28,7 +28,7 @@ #include "Framework/RootConfigParamHelpers.h" #include "Framework/ExpressionHelpers.h" #include "Framework/CommonServices.h" -#include "Framework/Plugins.h" +#include "Framework/PluginManager.h" #include "Framework/RootMessageContext.h" #include "Framework/DeviceSpec.h" @@ -94,7 +94,7 @@ struct PartitionManager> { static void doSetPartition(Partition& partition, T2& table) { if constexpr (std::is_same_v) { - partition.setTable(table); + partition.bindTable(table); } } @@ -465,8 +465,8 @@ struct ServiceManager> { { if constexpr (o2::framework::is_base_of_template_v) { T p = T{}; - auto loadableServices = ServiceHelpers::parseServiceSpecString(p.loadSpec.c_str()); - ServiceHelpers::loadFromPlugin(loadableServices, specs); + auto loadableServices = PluginManager::parsePluginSpecString(p.loadSpec.c_str()); + PluginManager::loadFromPlugin(loadableServices, specs); } return true; } @@ -532,6 +532,15 @@ struct OptionManager { { /// Recurse, in case we are brace constructible if constexpr (std::is_base_of_v) { + if constexpr (requires { x.prefix; }) { + homogeneous_apply_refs([prefix = x.prefix](C& y) { // apend group prefix if set + if constexpr (requires { y.name; }) { + y.name = prefix + "." + y.name; + } + return true; + }, + x); + } homogeneous_apply_refs([&options](auto& y) { return OptionManager>::appendOption(options, y); }, x); return true; } else { diff --git a/Framework/Core/include/Framework/AnalysisTask.h b/Framework/Core/include/Framework/AnalysisTask.h index 6560bc646986e..9d623adcf2bd3 100644 --- a/Framework/Core/include/Framework/AnalysisTask.h +++ b/Framework/Core/include/Framework/AnalysisTask.h @@ -16,21 +16,16 @@ #include "Framework/AlgorithmSpec.h" #include "Framework/CallbackService.h" #include "Framework/ConfigContext.h" -#include "Framework/Condition.h" #include "Framework/ControlService.h" #include "Framework/DataProcessorSpec.h" #include "Framework/Expressions.h" -#include "Framework/ExpressionHelpers.h" #include "Framework/EndOfStreamContext.h" #include "Framework/GroupSlicer.h" -#include "Framework/Logger.h" #include "Framework/StructToTuple.h" -#include "Framework/FunctionalHelpers.h" #include "Framework/Traits.h" -#include "Framework/VariantHelpers.h" -#include "Framework/RuntimeError.h" #include "Framework/TypeIdHelpers.h" #include "Framework/ArrowTableSlicingCache.h" +#include "Framework/AnalysisDataModel.h" #include #include @@ -47,9 +42,6 @@ namespace o2::framework /// /// adaptAnalysisTask(constructor args, ...); /// -// FIXME: for the moment this needs to stay outside AnalysisTask -// because we cannot inherit from it due to a C++17 bug -// in GCC 7.3. We need to move to 7.4+ struct AnalysisTask { }; @@ -87,15 +79,15 @@ struct AnalysisDataProcessorBuilder { } template - static inline auto getSources() + static inline auto getSources() requires soa::is_soa_index_table_v> { - if constexpr (soa::is_soa_index_table_v) { - return getInputSpecs(typename T::sources_t{}); - } else if constexpr (soa::is_soa_extension_table_v>) { - return getInputSpecs(typename aod::MetadataTrait::metadata::sources{}); - } else { - always_static_assert("Can be only used with index or extension table"); - } + return getInputSpecs(typename T::sources_t{}); + } + + template + static inline auto getSources() requires soa::is_soa_extension_table_v> + { + return getInputSpecs(typename aod::MetadataTrait::metadata::sources{}); } template @@ -110,125 +102,89 @@ struct AnalysisDataProcessorBuilder { return inputMetadata; } - template - static void doAppendInputWithMetadata(const char* name, bool value, std::vector& inputs) + template + static void addGroupingCandidates(std::vector& bk, std::vector& bku) { - using metadata = typename aod::MetadataTrait>::metadata; - static_assert(std::is_same_v == false, - "Could not find metadata. Did you register your type?"); - std::vector inputMetadata; - inputMetadata.emplace_back(ConfigParamSpec{std::string{"control:"} + name, VariantType::Bool, value, {"\"\""}}); - if constexpr (soa::is_soa_index_table_v> || soa::is_soa_extension_table_v>) { - auto inputSources = getInputMetadata>(); - inputMetadata.insert(inputMetadata.end(), inputSources.begin(), inputSources.end()); - } - auto newInput = InputSpec{metadata::tableLabel(), metadata::origin(), metadata::description(), metadata::version(), Lifetime::Timeframe, inputMetadata}; - DataSpecUtils::updateInputList(inputs, std::move(newInput)); + [&bk, &bku](framework::pack) mutable { + auto key = std::string{"fIndex"} + o2::framework::cutString(soa::getLabelFromType>()); + ([&bk, &bku, &key]() mutable { + if constexpr (soa::relatedByIndex, std::decay_t>()) { + auto binding = soa::getLabelFromTypeForKey>(key); + if constexpr (o2::soa::is_smallgroups_v>) { + framework::updatePairList(bku, binding, key); + } else { + framework::updatePairList(bk, binding, key); + } + } + }(), + ...); + }(framework::pack{}); } - static void doAppendEnumeration(const char*, int64_t, int64_t, int64_t, std::vector& inputs) + template + static void addOriginal(const char* name, bool value, std::vector& inputs) requires soa::is_type_with_metadata_v>> { + using metadata = typename aod::MetadataTrait>::metadata; std::vector inputMetadata; - // FIXME: for the moment we do not support begin, end and step. - auto newInput = InputSpec{"enumeration", "DPL", "ENUM", 0, Lifetime::Enumeration, inputMetadata}; - DataSpecUtils::updateInputList(inputs, std::move(newInput)); - } - - template - static void doAppendInputWithMetadata(framework::pack, const char* name, bool value, std::vector& inputs) - { - (doAppendInputWithMetadata(name, value, inputs), ...); + inputMetadata.emplace_back(ConfigParamSpec{std::string{"control:"} + name, VariantType::Bool, value, {"\"\""}}); + if constexpr (soa::is_soa_index_table_v> || soa::is_soa_extension_table_v>) { + auto inputSources = getInputMetadata>(); + inputMetadata.insert(inputMetadata.end(), inputSources.begin(), inputSources.end()); + } + DataSpecUtils::updateInputList(inputs, InputSpec{metadata::tableLabel(), metadata::origin(), metadata::description(), metadata::version(), Lifetime::Timeframe, inputMetadata}); } - template - static void appendSomethingWithMetadata(int ai, const char* name, bool value, std::vector& inputs, std::vector& eInfos, size_t hash) + template + static void inputsFromArgs(R (C::*)(Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos, std::vector& bk, std::vector& bku) requires(std::is_lvalue_reference_v&&...) { - static_assert(std::is_lvalue_reference_v, "Argument to process needs to be a reference (&)."); - using dT = std::decay_t; - if constexpr (is_enumeration_v
== false) { - if constexpr (soa::is_soa_filtered_v
) { - auto fields = createFieldsFromColumns(typename dT::table_t::persistent_columns_t{}); - eInfos.emplace_back(ai, hash, dT::hashes(), std::make_shared(fields)); - } else if constexpr (soa::is_soa_iterator_v
) { - auto fields = createFieldsFromColumns(typename dT::parent_t::persistent_columns_t{}); - if constexpr (std::is_same_v) { - eInfos.emplace_back(ai, hash, dT::parent_t::hashes(), std::make_shared(fields)); - } - } - doAppendInputWithMetadata(soa::make_originals_from_type
(), name, value, inputs); - } else { - doAppendEnumeration(name, dT::begin, dT::end, dT::step, inputs); + // update grouping cache + if constexpr (soa::is_soa_iterator_v>>>) { + addGroupingCandidates(bk, bku); } - } - template - static void appendGroupingCandidate(std::vector& bk, std::vector& bku, std::string& key) - { - if constexpr (soa::relatedByIndex, std::decay_t>()) { - auto binding = soa::getLabelFromTypeForKey>(key); - if constexpr (!o2::soa::is_smallgroups_v>) { - if (std::find_if(bk.begin(), bk.end(), [&binding, &key](auto const& entry) { return (entry.first == binding) && (entry.second == key); }) == bk.end()) { - bk.emplace_back(binding, key); - } + // populate input list and expression infos + int ai = -1; + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + ([&name, &value, &eInfos, &inputs, &hash, &ai]() mutable { + ++ai; + using T = std::decay_t; + if constexpr (is_enumeration_v) { + std::vector inputMetadata; + // FIXME: for the moment we do not support begin, end and step. + DataSpecUtils::updateInputList(inputs, InputSpec{"enumeration", "DPL", "ENUM", 0, Lifetime::Enumeration, inputMetadata}); } else { - if (std::find_if(bku.begin(), bku.end(), [&binding, &key](auto const& entry) { return (entry.first == binding) && (entry.second == key); }) == bku.end()) { - bku.emplace_back(binding, key); + // populate expression infos + if constexpr (soa::is_soa_filtered_v) { + auto fields = soa::createFieldsFromColumns(typename T::persistent_columns_t{}); + eInfos.emplace_back(ai, hash, T::hashes(), std::make_shared(fields)); + } else if constexpr (soa::is_soa_filtered_iterator_v()) { + auto fields = soa::createFieldsFromColumns(typename T::parent_t::persistent_columns_t{}); + eInfos.emplace_back(ai, hash, T::parent_t::hashes(), std::make_shared(fields)); } + // add inputs from the originals + [&name, &value, &inputs](framework::pack) mutable { + (addOriginal(name, value, inputs), ...); + }(soa::make_originals_from_type()); } - } - } - - template - static void appendGroupingCandidates(std::vector& bk, std::vector& bku, framework::pack) - { - auto key = std::string{"fIndex"} + o2::framework::cutString(soa::getLabelFromType>()); - (appendGroupingCandidate(bk, bku, key), ...); + return true; + }() && + ...); } - template - static void inputsFromArgs(R (C::*)(Args...), const char* name, bool value, std::vector& inputs, std::vector& eInfos, std::vector& bk, std::vector& bku) + template + static auto extractTableFromRecord(InputRecord& record) requires soa::is_type_with_metadata_v> { - int ai = 0; - auto hash = o2::framework::TypeIdHelpers::uniqueId(); - if constexpr (soa::is_soa_iterator_v>>>) { - appendGroupingCandidates(bk, bku, framework::pack{}); + auto table = record.get(aod::MetadataTrait::metadata::tableLabel())->asArrowTable(); + if (table->num_rows() == 0) { + table = makeEmptyTable(aod::MetadataTrait::metadata::tableLabel()); } - (appendSomethingWithMetadata(ai++, name, value, inputs, eInfos, hash), ...); - } - - template - static auto signatures(InputRecord&, R (C::*)(Grouping, Args...)) - { - return std::declval>(); - } - - template - static auto bindGroupingTable(InputRecord& record, R (C::*)(Grouping, Args...), std::vector& infos) - { - auto hash = o2::framework::TypeIdHelpers::uniqueId(); - return extractSomethingFromRecord(record, infos, hash); - } - - template - static auto bindGroupingTable(InputRecord&, R (C::*)(), std::vector&) - { - static_assert(always_static_assert_v, "Your task process method needs at least one argument"); - return o2::soa::Table<>{nullptr}; + return table; } template - static auto extractTableFromRecord(InputRecord& record) + static auto extractTableFromRecord(InputRecord& record) requires soa::is_type_with_originals_v { - if constexpr (soa::is_type_with_metadata_v>) { - auto table = record.get(aod::MetadataTrait::metadata::tableLabel())->asArrowTable(); - if (table->num_rows() == 0) { - table = makeEmptyTable(aod::MetadataTrait::metadata::tableLabel()); - } - return table; - } else if constexpr (soa::is_type_with_originals_v) { - return extractFromRecord(record, typename T::originals{}); - } - O2_BUILTIN_UNREACHABLE(); + return extractFromRecord(record, typename T::originals{}); } template @@ -245,16 +201,10 @@ struct AnalysisDataProcessorBuilder { static auto extractFilteredFromRecord(InputRecord& record, ExpressionInfo& info, pack const&) { auto table = o2::soa::ArrowHelpers::joinTables(std::vector>{extractTableFromRecord(record)...}); - if (info.tree != nullptr && info.filter == nullptr) { - info.filter = framework::expressions::createFilter(table->schema(), framework::expressions::makeCondition(info.tree)); - } - if (info.tree != nullptr && info.filter != nullptr && info.resetSelection == true) { - info.selection = framework::expressions::createSelection(table, info.filter); - info.resetSelection = false; - } + expressions::updateFilterInfo(info, table); if constexpr (!o2::soa::is_smallgroups_v>) { if (info.selection == nullptr) { - throw runtime_error_f("Null selection for %d (arg %d), missing Filter declaration?", info.processHash, info.argumentIndex); + soa::missingFilterDeclaration(info.processHash, info.argumentIndex); } } if constexpr (soa::is_soa_iterator_v) { @@ -265,45 +215,45 @@ struct AnalysisDataProcessorBuilder { } template - static auto extractSomethingFromRecord(InputRecord& record, std::vector& infos, size_t phash) + static auto extract(InputRecord&, std::vector&, size_t) requires is_enumeration_v { - using decayed = std::decay_t; - - if constexpr (is_enumeration_v == false) { - if constexpr (soa::is_soa_filtered_v) { - return extractFilteredFromRecord(record, *std::find_if(infos.begin(), infos.end(), [&phash](ExpressionInfo const& i) { return (i.processHash == phash && i.argumentIndex == AI); }), soa::make_originals_from_type()); - } else if constexpr (soa::is_soa_iterator_v) { - if constexpr (std::is_same_v) { - return extractFilteredFromRecord(record, *std::find_if(infos.begin(), infos.end(), [&phash](ExpressionInfo const& i) { return (i.processHash == phash && i.argumentIndex == AI); }), soa::make_originals_from_type()); - } else { - return extractFromRecord(record, soa::make_originals_from_type()); - } - } else { - return extractFromRecord(record, soa::make_originals_from_type()); - } - O2_BUILTIN_UNREACHABLE(); + return T{}; + } + + template + static auto extract(InputRecord& record, std::vector& infos, size_t phash) requires soa::is_soa_iterator_v + { + if constexpr (std::is_same_v) { + return extractFilteredFromRecord(record, *std::find_if(infos.begin(), infos.end(), [&phash](ExpressionInfo const& i) { return (i.processHash == phash && i.argumentIndex == AI); }), soa::make_originals_from_type()); } else { - return decayed{}; + return extractFromRecord(record, soa::make_originals_from_type()); } } - template - static auto bindAssociatedTables(InputRecord& record, R (C::*)(Grouping, Args...), std::vector& infos) + template + static auto extract(InputRecord& record, std::vector& infos, size_t phash) requires soa::is_soa_table_like_v { - constexpr auto p = pack{}; - auto hash = o2::framework::TypeIdHelpers::uniqueId(); - return std::make_tuple(extractSomethingFromRecord(p) + 1>(record, infos, hash)...); + if constexpr (soa::is_soa_filtered_v) { + return extractFilteredFromRecord(record, *std::find_if(infos.begin(), infos.end(), [&phash](ExpressionInfo const& i) { return (i.processHash == phash && i.argumentIndex == AI); }), soa::make_originals_from_type()); + } else { + return extractFromRecord(record, soa::make_originals_from_type()); + } } - template - static auto bindAssociatedTables(InputRecord&, R (C::*)(), std::vector&) + template + static auto bindGroupingTable(InputRecord& record, R (C::*)(Grouping, Args...), std::vector& infos) requires(!std::is_same_v || sizeof...(Args) > 0) { - static_assert(always_static_assert_v, "Your task process method needs at least one argument"); - return std::tuple<>{}; + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + return extract, 0>(record, infos, hash); } - template - using is_external_index_to_t = std::is_same; + template + static auto bindAssociatedTables(InputRecord& record, R (C::*)(Grouping, Args...), std::vector& infos) requires(!std::is_same_v || sizeof...(Args) > 0) + { + constexpr auto p = pack{}; + constexpr auto hash = o2::framework::TypeIdHelpers::uniqueId(); + return std::make_tuple(extract, has_type_at_v(p) + 1>(record, infos, hash)...); + } template static void overwriteInternalIndices(std::tuple& dest, std::tuple const& src) @@ -403,7 +353,7 @@ struct AnalysisDataProcessorBuilder { }, task); - invokeProcessWithArgsGeneric(task, processingFunction, slice.groupingElement(), associatedSlices); + invokeProcessWithArgs(task, processingFunction, slice.groupingElement(), associatedSlices); } } else { // bind partitions and grouping table @@ -413,72 +363,18 @@ struct AnalysisDataProcessorBuilder { }, task); - invokeProcessWithArgsGeneric(task, processingFunction, groupingTable, associatedTables); + invokeProcessWithArgs(task, processingFunction, groupingTable, associatedTables); } } } template - static void invokeProcessWithArgsGeneric(C& task, T processingFunction, G g, std::tuple& at) + static void invokeProcessWithArgs(C& task, T processingFunction, G g, std::tuple& at) { std::invoke(processingFunction, task, g, std::get(at)...); } - - template - static void invokeProcessWithArgs(T& task, G g, std::tuple& at) - { - task.process(g, std::get(at)...); - } -}; - -namespace -{ -template -class has_process -{ - template - static std::true_type test(decltype(&C::process)); - template - static std::false_type test(...); - - public: - static constexpr bool value = decltype(test(nullptr))::value; }; -template -inline constexpr bool has_process_v = has_process::value; - -template -class has_run -{ - template - static std::true_type test(decltype(&C::run)); - template - static std::false_type test(...); - - public: - static constexpr bool value = decltype(test(nullptr))::value; -}; - -template -inline constexpr bool has_run_v = has_run::value; - -template -class has_init -{ - template - static std::true_type test(decltype(&C::init)); - template - static std::false_type test(...); - - public: - static constexpr bool value = decltype(test(nullptr))::value; -}; - -template -inline constexpr bool has_init_v = has_init::value; -} // namespace - struct SetDefaultProcesses { std::vector> map; }; @@ -595,7 +491,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) homogeneous_apply_refs([&inputs](auto& x) { return ConditionManager>::appendCondition(inputs, x); }, *task.get()); /// parse process functions defined by corresponding configurables - if constexpr (has_process_v) { + if constexpr (requires { AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, "default", true, inputs, expressionInfos, bindingsKeys, bindingsKeysUnsorted); }) { AnalysisDataProcessorBuilder::inputsFromArgs(&T::process, "default", true, inputs, expressionInfos, bindingsKeys, bindingsKeysUnsorted); } homogeneous_apply_refs( @@ -668,7 +564,7 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) }, *task.get()); - if constexpr (has_init_v) { + if constexpr (requires { task->init(ic); }) { task->init(ic); } @@ -703,11 +599,11 @@ DataProcessorSpec adaptAnalysisTask(ConfigContext const& ctx, Args&&... args) // prepare outputs homogeneous_apply_refs([&pc](auto&& x) { return OutputManager>::prepare(pc, x); }, *task.get()); // execute run() - if constexpr (has_run_v) { + if constexpr (requires { task->run(pc); }) { task->run(pc); } // execute process() - if constexpr (has_process_v) { + if constexpr (requires { AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), &T::process, expressionInfos, slices); }) { AnalysisDataProcessorBuilder::invokeProcess(*(task.get()), pc.inputs(), &T::process, expressionInfos, slices); } // execute optional process() diff --git a/Framework/Core/include/Framework/ArrowTableSlicingCache.h b/Framework/Core/include/Framework/ArrowTableSlicingCache.h index e1649f54810cc..2edc23a63ce76 100644 --- a/Framework/Core/include/Framework/ArrowTableSlicingCache.h +++ b/Framework/Core/include/Framework/ArrowTableSlicingCache.h @@ -14,7 +14,6 @@ #include "Framework/ServiceHandle.h" #include -#include #include namespace o2::framework @@ -37,6 +36,8 @@ struct SliceInfoUnsortedPtr { using StringPair = std::pair; +void updatePairList(std::vector& list, std::string const& binding, std::string const& key); + struct ArrowTableSlicingCacheDef { constexpr static ServiceKind service_kind = ServiceKind::Global; std::vector bindingsKeys; diff --git a/Framework/Core/include/Framework/AsyncQueue.h b/Framework/Core/include/Framework/AsyncQueue.h index 37971fbe03bfb..6945c2a5ab1da 100644 --- a/Framework/Core/include/Framework/AsyncQueue.h +++ b/Framework/Core/include/Framework/AsyncQueue.h @@ -32,8 +32,9 @@ struct AsyncTaskId { /// An actuatual task to be executed struct AsyncTask { - // The task to be executed - std::function task; + // The task to be executed. Id can be used as unique + // id for the signpost in the async_queue stream. + std::function task; // The associated task spec AsyncTaskId id = {-1}; TimesliceId timeslice = {TimesliceId::INVALID}; @@ -49,10 +50,11 @@ struct AsyncQueue { }; struct AsyncQueueHelpers { + using AsyncCallback = std::function; static AsyncTaskId create(AsyncQueue& queue, AsyncTaskSpec spec); // Schedule a task with @a taskId to be executed whenever the timeslice // is past timeslice. If debounce is provided, only execute the task - static void post(AsyncQueue& queue, AsyncTaskId taskId, std::function task, TimesliceId timeslice, int64_t debounce = 0); + static void post(AsyncQueue& queue, AsyncTaskId taskId, AsyncCallback task, TimesliceId timeslice, int64_t debounce = 0); /// Run all the tasks which are older than the oldestPossible timeslice /// executing them by: /// 1. sorting the tasks by timeslice diff --git a/Framework/Core/include/Framework/DataAllocator.h b/Framework/Core/include/Framework/DataAllocator.h index 029e922aeb90b..d746031ad58c5 100644 --- a/Framework/Core/include/Framework/DataAllocator.h +++ b/Framework/Core/include/Framework/DataAllocator.h @@ -23,7 +23,6 @@ #include "Framework/TypeTraits.h" #include "Framework/Traits.h" #include "Framework/SerializationMethods.h" -#include "Framework/CheckTypes.h" #include "Framework/ServiceRegistry.h" #include "Framework/RuntimeError.h" #include "Framework/RouteState.h" @@ -211,18 +210,14 @@ class DataAllocator auto* s = new std::string(args...); adopt(spec, s); return *s; - } else if constexpr (std::is_base_of_v) { - return call_if_defined_forward>([&](auto* p) { - auto tb = std::move(LifetimeHolder(new typename std::decay_t::type(args...))); - adopt(spec, tb); - return std::move(tb); - }); - } else if constexpr (std::is_base_of_v) { - return call_if_defined_forward>([&](auto* p) { - auto t2t = std::move(LifetimeHolder(new typename std::decay_t::type(args...))); - adopt(spec, t2t); - return std::move(t2t); - }); + } else if constexpr (requires { static_cast(std::declval>()); }) { + auto tb = std::move(LifetimeHolder(new std::decay_t(args...))); + adopt(spec, tb); + return tb; + } else if constexpr (requires { static_cast(std::declval>()); }) { + auto t2t = std::move(LifetimeHolder(new std::decay_t(args...))); + adopt(spec, t2t); + return t2t; } else if constexpr (sizeof...(Args) == 0) { if constexpr (is_messageable::value == true) { return *reinterpret_cast(newChunk(spec, sizeof(T)).data()); diff --git a/Framework/Core/include/Framework/DataTypes.h b/Framework/Core/include/Framework/DataTypes.h index 423a05a221776..011c71fa27b38 100644 --- a/Framework/Core/include/Framework/DataTypes.h +++ b/Framework/Core/include/Framework/DataTypes.h @@ -79,8 +79,9 @@ namespace o2::aod::mcparticle::enums { enum MCParticleFlags : uint8_t { ProducedByTransport = 0x1, - FromBackgroundEvent = 0x2, // Particle from background event (may have been used several times) - PhysicalPrimary = 0x4 // Particle is a physical primary according to ALICE definition + FromBackgroundEvent = 0x2, // Particle from background event (may have been used several times) + PhysicalPrimary = 0x4, // Particle is a physical primary according to ALICE definition + FromOutOfBunchPileUpCollision = 0x8 // Particle from out-of-bunch pile up collision (currently Run 2 only) }; } // namespace o2::aod::mcparticle::enums diff --git a/Framework/Core/include/Framework/DebugGUI.h b/Framework/Core/include/Framework/DebugGUI.h index c7a611d50a1d4..6b92859e42c0f 100644 --- a/Framework/Core/include/Framework/DebugGUI.h +++ b/Framework/Core/include/Framework/DebugGUI.h @@ -40,8 +40,7 @@ struct DebugGUI { virtual void updateMouseButton(bool isClicked) = 0; virtual void updateMouseWheel(int direction) = 0; virtual void updateWindowSize(int x, int y) = 0; - virtual void keyDown(char key) = 0; - virtual void keyUp(char key) = 0; + virtual void keyEvent(char key, bool down) = 0; virtual void charIn(char key) = 0; virtual void* initGUI(char const* windowTitle, ServiceRegistry& registry) = 0; diff --git a/Framework/Core/include/Framework/ExpressionHelpers.h b/Framework/Core/include/Framework/ExpressionHelpers.h index 2f80a107c694e..b531a39519272 100644 --- a/Framework/Core/include/Framework/ExpressionHelpers.h +++ b/Framework/Core/include/Framework/ExpressionHelpers.h @@ -12,7 +12,6 @@ #define O2_FRAMEWORK_EXPRESSIONS_HELPERS_H_ #include "Framework/Expressions.h" -#include #include #include diff --git a/Framework/Core/include/Framework/Expressions.h b/Framework/Core/include/Framework/Expressions.h index 349549badf0e8..9843457550b99 100644 --- a/Framework/Core/include/Framework/Expressions.h +++ b/Framework/Core/include/Framework/Expressions.h @@ -40,7 +40,6 @@ class Projector; #include #include #include -#include #include namespace gandiva { @@ -452,7 +451,7 @@ using Operations = std::vector; Operations createOperations(Filter const& expression); /// Function to check compatibility of a given arrow schema with operation sequence -bool isSchemaCompatible(gandiva::SchemaPtr const& Schema, Operations const& opSpecs); +bool isTableCompatible(std::set const& hashes, Operations const& specs); /// Function to create gandiva expression tree from operation sequence gandiva::NodePtr createExpressionTree(Operations const& opSpecs, gandiva::SchemaPtr const& Schema); @@ -496,6 +495,8 @@ std::shared_ptr createProjectors(framework::pack, std: return createProjectorHelper(sizeof...(C), projectors.data(), schema, fields); } + +void updateFilterInfo(ExpressionInfo& info, std::shared_ptr& table); } // namespace o2::framework::expressions #endif // O2_FRAMEWORK_EXPRESSIONS_H_ diff --git a/Framework/Core/include/Framework/PluginManager.h b/Framework/Core/include/Framework/PluginManager.h new file mode 100644 index 0000000000000..38966c5a969a9 --- /dev/null +++ b/Framework/Core/include/Framework/PluginManager.h @@ -0,0 +1,137 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#ifndef O2_FRAMEWORK_PLUGIN_MANAGER_H_ +#define O2_FRAMEWORK_PLUGIN_MANAGER_H_ + +#include "Framework/Plugins.h" +#include +#include +#include + +// Struct to hold live plugin information which the plugin itself cannot +// know and that is owned by the framework. +struct PluginInfo { + uv_lib_t* dso = nullptr; + std::string name; + DPLPluginHandle* instance = nullptr; +}; + +// Struct to hold information about the location of a plugin +struct LoadablePlugin { + std::string name; + std::string library; +}; + +namespace o2::framework +{ +struct PluginManager { + using WrapperProcessCallback = std::function; + + template + static T* getByName(DPLPluginHandle* handle, char const* name) + { + while (handle != nullptr) { + if (strncmp(handle->name, name, strlen(name)) == 0) { + return reinterpret_cast(handle->instance); + } + handle = handle->previous; + } + return nullptr; + } + /// Load a DSO called @a dso and insert its handle in @a infos + /// On successfull completion @a onSuccess is called passing + /// the DPLPluginHandle provided by the library. + static void load(std::vector& infos, const char* dso, std::function& onSuccess); + /// Load an called @plugin from a library called @a library and + /// return the associtated AlgorithmSpec. + static auto loadAlgorithmFromPlugin(std::string library, std::string plugin) -> AlgorithmSpec; + /// Wrap an algorithm with some lambda @wrapper which will be called + /// with the original callback and the ProcessingContext. + static auto wrapAlgorithm(AlgorithmSpec const& spec, WrapperProcessCallback&& wrapper) -> AlgorithmSpec; + + /// Parse a comma separated list of : plugin declarations. + static std::vector parsePluginSpecString(char const* str); + + template + static void loadFromPlugin(std::vector const& loadablePlugins, std::vector& specs) + { + struct LoadedDSO { + std::string library; + uv_lib_t handle; + }; + + struct LoadedPlugin { + std::string name; + ServicePlugin* factory; + }; + std::vector loadedDSOs; + std::vector loadedPlugins; + for (auto& loadablePlugin : loadablePlugins) { + auto loadedDSO = std::find_if(loadedDSOs.begin(), loadedDSOs.end(), [&loadablePlugin](auto& dso) { + return dso.library == loadablePlugin.library; + }); + + if (loadedDSO == loadedDSOs.end()) { + uv_lib_t handle; +#ifdef __APPLE__ + auto libraryName = fmt::format("lib{}.dylib", loadablePlugin.library); +#else + auto libraryName = fmt::format("lib{}.so", loadablePlugin.library); +#endif + auto ret = uv_dlopen(libraryName.c_str(), &handle); + if (ret != 0) { + LOGP(error, "Could not load library {}", loadablePlugin.library); + LOG(error) << uv_dlerror(&handle); + continue; + } + loadedDSOs.push_back({loadablePlugin.library, handle}); + loadedDSO = loadedDSOs.end() - 1; + } + int result = 0; + + auto loadedPlugin = std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&loadablePlugin](auto& plugin) { + return plugin.name == loadablePlugin.name; + }); + + if (loadedPlugin == loadedPlugins.end()) { + DPLPluginHandle* (*dpl_plugin_callback)(DPLPluginHandle*); + result = uv_dlsym(&loadedDSO->handle, "dpl_plugin_callback", (void**)&dpl_plugin_callback); + if (result == -1) { + LOG(error) << uv_dlerror(&loadedDSO->handle); + continue; + } + + DPLPluginHandle* pluginInstance = dpl_plugin_callback(nullptr); + PLUGIN* factory = PluginManager::getByName(pluginInstance, loadablePlugin.name.c_str()); + if (factory == nullptr) { + LOGP(error, "Could not find service {} in library {}", loadablePlugin.name, loadablePlugin.library); + continue; + } + + loadedPlugins.push_back({loadablePlugin.name, factory}); + loadedPlugin = loadedPlugins.begin() + loadedPlugins.size() - 1; + } + assert(loadedPlugin != loadedPlugins.end()); + assert(loadedPlugin->factory != nullptr); + + CONCRETE* spec = loadedPlugin->factory->create(); + if (!spec) { + LOG(error) << "Plugin " << loadablePlugin.name << " could not be created"; + continue; + } + LOGP(debug, "Loading service {} from {}", loadablePlugin.name, loadablePlugin.library); + specs.push_back(*spec); + } + } +}; + +} // namespace o2::framework +#endif // O2_FRAMEWORK_PLUGIN_MANAGER_H_ diff --git a/Framework/Core/include/Framework/Plugins.h b/Framework/Core/include/Framework/Plugins.h index 788470b472f2a..c29d96f7e0781 100644 --- a/Framework/Core/include/Framework/Plugins.h +++ b/Framework/Core/include/Framework/Plugins.h @@ -12,10 +12,7 @@ #define O2_FRAMEWORK_PLUGINS_H_ #include "Framework/AlgorithmSpec.h" -#include #include -#include -#include namespace o2::framework { @@ -82,14 +79,6 @@ struct DPLPluginHandle { DPLPluginHandle* previous = nullptr; }; -// Struct to hold live plugin information which the plugin itself cannot -// know and that is owned by the framework. -struct PluginInfo { - uv_lib_t* dso = nullptr; - std::string name; - DPLPluginHandle* instance = nullptr; -}; - #define DEFINE_DPL_PLUGIN(NAME, KIND) \ extern "C" { \ DPLPluginHandle* dpl_plugin_callback(DPLPluginHandle* previous) \ @@ -111,34 +100,4 @@ struct PluginInfo { } \ } -namespace o2::framework -{ -struct PluginManager { - using WrapperProcessCallback = std::function; - - template - static T* getByName(DPLPluginHandle* handle, char const* name) - { - while (handle != nullptr) { - if (strncmp(handle->name, name, strlen(name)) == 0) { - return reinterpret_cast(handle->instance); - } - handle = handle->previous; - } - return nullptr; - } - /// Load a DSO called @a dso and insert its handle in @a infos - /// On successfull completion @a onSuccess is called passing - /// the DPLPluginHandle provided by the library. - static void load(std::vector& infos, const char* dso, std::function& onSuccess); - /// Load an called @plugin from a library called @a library and - /// return the associtated AlgorithmSpec. - static auto loadAlgorithmFromPlugin(std::string library, std::string plugin) -> AlgorithmSpec; - /// Wrap an algorithm with some lambda @wrapper which will be called - /// with the original callback and the ProcessingContext. - static auto wrapAlgorithm(AlgorithmSpec const& spec, WrapperProcessCallback&& wrapper) -> AlgorithmSpec; -}; - -} // namespace o2::framework - #endif // O2_FRAMEWORK_PLUGINS_H_ diff --git a/Framework/Core/include/Framework/ServiceSpec.h b/Framework/Core/include/Framework/ServiceSpec.h index 910620fcd0655..abac3ad05914c 100644 --- a/Framework/Core/include/Framework/ServiceSpec.h +++ b/Framework/Core/include/Framework/ServiceSpec.h @@ -327,11 +327,6 @@ struct LoadableService { std::string library; }; -struct ServiceHelpers { - static std::vector parseServiceSpecString(char const* str); - static void loadFromPlugin(std::vector const& loadableServices, std::vector& specs); -}; - } // namespace o2::framework #endif // O2_FRAMEWORK_SERVICESPEC_H_ diff --git a/Framework/Core/include/Framework/StepTHn.h b/Framework/Core/include/Framework/StepTHn.h index 61c664e094a29..0302f604eae39 100644 --- a/Framework/Core/include/Framework/StepTHn.h +++ b/Framework/Core/include/Framework/StepTHn.h @@ -95,6 +95,8 @@ class StepTHnT : public StepTHn StepTHnT(const char* name, const char* title, const int nSteps, const int nAxes, const int* nBins, const double* xmin, const double* xmax); ~StepTHnT() override = default; + Long64_t Merge(TCollection* list) override; + protected: TArray* createArray(const TArray* src = nullptr) const override { @@ -105,8 +107,6 @@ class StepTHnT : public StepTHn } } - Long64_t Merge(TCollection* list) override; - ClassDef(StepTHnT, 1) // THn like container }; diff --git a/Framework/Core/include/Framework/TMessageSerializer.h b/Framework/Core/include/Framework/TMessageSerializer.h index 17f3f65ce2030..769d23a7a3427 100644 --- a/Framework/Core/include/Framework/TMessageSerializer.h +++ b/Framework/Core/include/Framework/TMessageSerializer.h @@ -18,9 +18,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -30,12 +27,6 @@ namespace o2::framework class FairOutputTBuffer; class FairInputTBuffer; -// utilities to produce a span over a byte buffer held by various message types -// this is to avoid littering code with casts and conversions (span has a signed index type(!)) -gsl::span as_span(const FairInputTBuffer& msg); -gsl::span as_span(const FairOutputTBuffer& msg); -gsl::span as_span(const fair::mq::Message& msg); - // A TBufferFile which we can use to serialise data to a FairMQ message. class FairOutputTBuffer : public TBufferFile { @@ -153,18 +144,5 @@ inline void TMessageSerializer::Deserialize(const fair::mq::Message& msg, std::u output = deserialize(input); } -// gsl::narrow is used to do a runtime narrowing check, this might be a bit paranoid, -// we would probably be fine with e.g. gsl::narrow_cast (or just a static_cast) -inline gsl::span as_span(const fair::mq::Message& msg) -{ - return gsl::span{static_cast(msg.GetData()), gsl::narrow::size_type>(msg.GetSize())}; -} - -inline gsl::span as_span(const FairInputTBuffer& msg) -{ - return gsl::span{reinterpret_cast(msg.Buffer()), - gsl::narrow::size_type>(msg.BufferSize())}; -} - } // namespace o2::framework #endif // FRAMEWORK_TMESSAGESERIALIZER_H diff --git a/Framework/Core/include/Framework/Variant.h b/Framework/Core/include/Framework/Variant.h index d9ef196f56e0d..54e4b54be9606 100644 --- a/Framework/Core/include/Framework/Variant.h +++ b/Framework/Core/include/Framework/Variant.h @@ -41,16 +41,16 @@ enum class VariantType : int { Int = 0, Array2DInt, Array2DFloat, Array2DDouble, - LabeledArrayInt, - LabeledArrayFloat, - LabeledArrayDouble, + LabeledArrayInt, // 2D array + LabeledArrayFloat, // 2D array + LabeledArrayDouble, // 2D array UInt8, UInt16, UInt32, UInt64, Int8, Int16, - LabeledArrayString, + LabeledArrayString, // 2D array Empty, Dict, Unknown }; @@ -285,7 +285,7 @@ struct variant_helper { template struct variant_helper { - static std::string get(const S* store) { return std::string(strdup(*reinterpret_cast(store))); } + static std::string get(const S* store) { return std::string(*reinterpret_cast(store)); } static void set(S* store, std::string value) { *reinterpret_cast(store) = strdup(value.data()); } }; diff --git a/Framework/Core/src/ASoA.cxx b/Framework/Core/src/ASoA.cxx index 043183d67478d..f04a0027ee498 100644 --- a/Framework/Core/src/ASoA.cxx +++ b/Framework/Core/src/ASoA.cxx @@ -25,6 +25,10 @@ void dereferenceWithWrongType() { throw o2::framework::runtime_error_f("Trying to dereference index with a wrong type in _as<>. Note that if you have several compatible index targets in your process() signature, the last one will be the one actually bound to the getter."); } +void missingFilterDeclaration(int hash, int ai) +{ + throw o2::framework::runtime_error_f("Null selection for %d (arg %d), missing Filter declaration?", hash, ai); +} SelectionVector selectionToVector(gandiva::Selection const& sel) { diff --git a/Framework/Core/src/AnalysisHelpers.cxx b/Framework/Core/src/AnalysisHelpers.cxx new file mode 100644 index 0000000000000..c0f804b47f5af --- /dev/null +++ b/Framework/Core/src/AnalysisHelpers.cxx @@ -0,0 +1,29 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/ExpressionHelpers.h" + +namespace o2::framework +{ +void initializePartitionCaches(std::set const& hashes, std::shared_ptr const& schema, expressions::Filter const& filter, gandiva::NodePtr& tree, gandiva::FilterPtr& gfilter) +{ + if (tree == nullptr) { + expressions::Operations ops = createOperations(filter); + if (isTableCompatible(hashes, ops)) { + tree = createExpressionTree(ops, schema); + } else { + throw std::runtime_error("Partition filter does not match declared table type"); + } + } + if (gfilter == nullptr) { + gfilter = framework::expressions::createFilter(schema, framework::expressions::makeCondition(tree)); + } +} +} // namespace o2::framework diff --git a/Framework/Core/src/ArrowTableSlicingCache.cxx b/Framework/Core/src/ArrowTableSlicingCache.cxx index 871dfc300f8bb..4b31f96e32fba 100644 --- a/Framework/Core/src/ArrowTableSlicingCache.cxx +++ b/Framework/Core/src/ArrowTableSlicingCache.cxx @@ -19,6 +19,13 @@ namespace o2::framework { +void updatePairList(std::vector& list, std::string const& binding, std::string const& key) +{ + if (std::find_if(list.begin(), list.end(), [&binding, &key](auto const& entry) { return (entry.first == binding) && (entry.second == key); }) == list.end()) { + list.emplace_back(binding, key); + } +} + std::pair SliceInfoPtr::getSliceFor(int value) const { int64_t offset = 0; diff --git a/Framework/Core/src/AsyncQueue.cxx b/Framework/Core/src/AsyncQueue.cxx index 44115d4985e91..36c0c17009f82 100644 --- a/Framework/Core/src/AsyncQueue.cxx +++ b/Framework/Core/src/AsyncQueue.cxx @@ -10,9 +10,11 @@ // or submit itself to any jurisdiction. #include "Framework/AsyncQueue.h" -#include "Framework/Logger.h" +#include "Framework/Signpost.h" #include +O2_DECLARE_DYNAMIC_LOG(async_queue); + namespace o2::framework { auto AsyncQueueHelpers::create(AsyncQueue& queue, AsyncTaskSpec spec) -> AsyncTaskId @@ -23,7 +25,7 @@ auto AsyncQueueHelpers::create(AsyncQueue& queue, AsyncTaskSpec spec) -> AsyncTa return id; } -auto AsyncQueueHelpers::post(AsyncQueue& queue, AsyncTaskId id, std::function task, TimesliceId timeslice, int64_t debounce) -> void +auto AsyncQueueHelpers::post(AsyncQueue& queue, AsyncTaskId id, AsyncCallback task, TimesliceId timeslice, int64_t debounce) -> void { AsyncTask taskToPost; taskToPost.task = task; @@ -38,7 +40,8 @@ auto AsyncQueueHelpers::run(AsyncQueue& queue, TimesliceId oldestPossible) -> vo if (queue.tasks.empty()) { return; } - LOGP(debug, "Attempting at running {} tasks", queue.tasks.size()); + O2_SIGNPOST_ID_GENERATE(opid, async_queue); + O2_SIGNPOST_START(async_queue, opid, "run", "Attempting at running %zu tasks with oldestPossible timeframe %zu", queue.tasks.size(), oldestPossible.value); std::vector order; order.resize(queue.tasks.size()); std::iota(order.begin(), order.end(), 0); @@ -47,6 +50,10 @@ auto AsyncQueueHelpers::run(AsyncQueue& queue, TimesliceId oldestPossible) -> vo if (task.timeslice.value <= oldestPossible.value) { task.runnable = true; } + O2_SIGNPOST_EVENT_EMIT(async_queue, opid, "run", + "Task %d (timeslice %zu), score %d, debounce %d is %{public}s when oldestPossible timeframe is %zu", + task.id.value, task.timeslice.value, queue.prototypes[task.id.value].score, task.debounce, + task.runnable ? "runnable" : "not runnable", oldestPossible.value); } // Sort by runnable, timeslice, then priority and finally debounce @@ -69,34 +76,43 @@ auto AsyncQueueHelpers::run(AsyncQueue& queue, TimesliceId oldestPossible) -> vo return queue.tasks[a].timeslice.value > queue.tasks[b].timeslice.value; } }); + for (auto i : order) { if (queue.tasks[i].runnable) { - LOGP(debug, "AsyncQueue: Running task {}, timeslice {}, score {}, debounce {}", queue.tasks[i].id.value, queue.tasks[i].timeslice.value, queue.prototypes[queue.tasks[i].id.value].score, queue.tasks[i].debounce); + O2_SIGNPOST_EVENT_EMIT(async_queue, opid, "run", "Running task %d (%d), (timeslice %zu), score %d, debounce %d", queue.tasks[i].id.value, i, queue.tasks[i].timeslice.value, queue.prototypes[queue.tasks[i].id.value].score, queue.tasks[i].debounce); } else { - LOGP(debug, "AsyncQueue: Skipping task {}, timeslice {}, score {}, debounce {}", queue.tasks[i].id.value, queue.tasks[i].timeslice.value, queue.prototypes[queue.tasks[i].id.value].score, queue.tasks[i].debounce); + O2_SIGNPOST_EVENT_EMIT(async_queue, opid, "run", "Skipping task %d (%d) (timeslice %zu), score %d, debounce %d", queue.tasks[i].id.value, i, queue.tasks[i].timeslice.value, queue.prototypes[queue.tasks[i].id.value].score, queue.tasks[i].debounce); } } // Keep only the tasks with the highest debounce value for a given id auto newEnd = std::unique(order.begin(), order.end(), [&queue](int a, int b) { return queue.tasks[a].runnable == queue.tasks[b].runnable && queue.tasks[a].id.value == queue.tasks[b].id.value && queue.tasks[a].debounce >= 0 && queue.tasks[b].debounce >= 0; }); + for (auto ii = newEnd; ii != order.end(); ii++) { + O2_SIGNPOST_EVENT_EMIT(async_queue, opid, "dropping", "Dropping task %d for timeslice %zu", queue.tasks[*ii].id.value, queue.tasks[*ii].timeslice.value); + } order.erase(newEnd, order.end()); if (order.empty() && queue.tasks.size() > 0) { - LOGP(debug, "AsyncQueue: not running iteration {} timeslice {} pending {}.", order.size(), queue.iteration, oldestPossible.value, queue.tasks.size()); + O2_SIGNPOST_END(async_queue, opid, "run", "Not running iteration %zu pending %zu.", + queue.iteration, queue.tasks.size()); return; } else if (order.empty()) { + O2_SIGNPOST_END(async_queue, opid, "run", "Not running iteration %zu. No tasks.", queue.iteration); return; } - LOGP(debug, "AsyncQueue: Running {} tasks in iteration {} timeslice {}", order.size(), queue.iteration, oldestPossible.value); - bool obsolete = true; + O2_SIGNPOST_EVENT_EMIT(async_queue, opid, "run", "Running %zu tasks in iteration %zu", order.size(), queue.iteration); + int runCount = 0; for (auto i : order) { if (queue.tasks[i].runnable) { + runCount++; // If a task is runable, we can run the task and remove it from the queue - LOGP(debug, "Running task {} ({})", queue.prototypes[queue.tasks[i].id.value].name, i); - queue.tasks[i].task(); - LOGP(debug, "Done running {}", i); + O2_SIGNPOST_EVENT_EMIT(async_queue, opid, "run", "Running task %{public}s (%d) for timeslice %zu", + queue.prototypes[queue.tasks[i].id.value].name.c_str(), i, + queue.tasks[i].timeslice.value); + queue.tasks[i].task(opid.value); + O2_SIGNPOST_EVENT_EMIT(async_queue, opid, "run", "Done running %d", i); } } // Remove all runnable tasks regardless they actually @@ -105,6 +121,7 @@ auto AsyncQueueHelpers::run(AsyncQueue& queue, TimesliceId oldestPossible) -> vo return task.runnable; }), queue.tasks.end()); + O2_SIGNPOST_END(async_queue, opid, "run", "Done running %d/%zu tasks", runCount, order.size()); } auto AsyncQueueHelpers::reset(AsyncQueue& queue) -> void diff --git a/Framework/Core/src/CommandInfo.cxx b/Framework/Core/src/CommandInfo.cxx index 7127ecdc3c8ca..7edcba08193c1 100644 --- a/Framework/Core/src/CommandInfo.cxx +++ b/Framework/Core/src/CommandInfo.cxx @@ -27,7 +27,7 @@ CommandInfo::CommandInfo(int argc, char* const* argv) for (size_t ai = 1; ai < argc; ++ai) { const char* arg = argv[ai]; - if (strpbrk(arg, "\" ;@") != nullptr || arg[0] == 0) { + if (strpbrk(arg, "\" ;@&") != nullptr || arg[0] == 0) { commandStream << " '" << arg << "'"; } else if (strpbrk(arg, "'") != nullptr) { commandStream << " \"" << arg << "\""; diff --git a/Framework/Core/src/CommonDataProcessors.cxx b/Framework/Core/src/CommonDataProcessors.cxx index 593cb8d1ac1f8..9817a57734c1d 100644 --- a/Framework/Core/src/CommonDataProcessors.cxx +++ b/Framework/Core/src/CommonDataProcessors.cxx @@ -39,7 +39,7 @@ #include "Framework/ExternalFairMQDeviceProxy.h" #include "Framework/RuntimeError.h" #include "Framework/RateLimiter.h" -#include "Framework/Plugins.h" +#include "Framework/PluginManager.h" #include "Framework/DeviceSpec.h" #include "WorkflowHelpers.h" #include diff --git a/Framework/Core/src/CommonDriverServices.cxx b/Framework/Core/src/CommonDriverServices.cxx index 893087d555210..6fd27b700e047 100644 --- a/Framework/Core/src/CommonDriverServices.cxx +++ b/Framework/Core/src/CommonDriverServices.cxx @@ -11,6 +11,7 @@ #include "CommonDriverServices.h" #include "Framework/CommonServices.h" +#include "Framework/PluginManager.h" // Make sure we can use aggregated initialisers. #pragma GCC diagnostic push @@ -24,14 +25,14 @@ std::vector o2::framework::CommonDriverServices::defaultServices() std::vector specs{ CommonServices::configurationSpec()}; // Load plugins depending on the environment - std::vector loadableServices = {}; + std::vector loadableServices = {}; char* loadableServicesEnv = getenv("DPL_LOAD_DRIVER_SERVICES"); // String to define the services to load is: // // library1:name1,library2:name2,... if (loadableServicesEnv) { - loadableServices = ServiceHelpers::parseServiceSpecString(loadableServicesEnv); - ServiceHelpers::loadFromPlugin(loadableServices, specs); + loadableServices = PluginManager::parsePluginSpecString(loadableServicesEnv); + PluginManager::loadFromPlugin(loadableServices, specs); } return specs; } diff --git a/Framework/Core/src/CommonServices.cxx b/Framework/Core/src/CommonServices.cxx index 0d0828729ef42..7f145fe4318ff 100644 --- a/Framework/Core/src/CommonServices.cxx +++ b/Framework/Core/src/CommonServices.cxx @@ -36,13 +36,14 @@ #include "Framework/Tracing.h" #include "Framework/Monitoring.h" #include "Framework/AsyncQueue.h" -#include "Framework/Plugins.h" +#include "Framework/PluginManager.h" #include "Framework/DeviceContext.h" #include "Framework/DataProcessingContext.h" #include "Framework/StreamContext.h" #include "Framework/DeviceState.h" #include "Framework/DeviceConfig.h" #include "Framework/DefaultsHelpers.h" +#include "Framework/Signpost.h" #include "TextDriverClient.h" #include "WSDriverClient.h" @@ -82,6 +83,8 @@ using Value = o2::monitoring::tags::Value; O2_DECLARE_DYNAMIC_LOG(data_processor_context); O2_DECLARE_DYNAMIC_LOG(stream_context); +O2_DECLARE_DYNAMIC_LOG(async_queue); +O2_DECLARE_DYNAMIC_LOG(policies); namespace o2::framework { @@ -128,6 +131,7 @@ o2::framework::ServiceSpec CommonServices::monitoringSpec() } }, .exit = [](ServiceRegistryRef registry, void* service) { auto* monitoring = reinterpret_cast(service); + monitoring->flushBuffer(); delete monitoring; }, .kind = ServiceKind::Serial}; } @@ -580,11 +584,13 @@ o2::framework::ServiceSpec CommonServices::decongestionSpec() (uint64_t)oldestPossibleOutput.timeslice.value, oldestPossibleOutput.slot.index == -1 ? "channel" : "slot", (uint64_t)(oldestPossibleOutput.slot.index == -1 ? oldestPossibleOutput.channel.value : oldestPossibleOutput.slot.index)); + O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid, "oldest_possible_timeslice", "Ordered active %d", decongestion->orderedCompletionPolicyActive); if (decongestion->orderedCompletionPolicyActive) { auto oldNextTimeslice = decongestion->nextTimeslice; decongestion->nextTimeslice = std::max(decongestion->nextTimeslice, (int64_t)oldestPossibleOutput.timeslice.value); + O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid, "oldest_possible_timeslice", "Next timeslice %" PRIi64, decongestion->nextTimeslice); if (oldNextTimeslice != decongestion->nextTimeslice) { - LOGP(error, "Some Lifetime::Timeframe data got dropped starting at {}", oldNextTimeslice); + O2_SIGNPOST_EVENT_EMIT_ERROR(data_processor_context, cid, "oldest_possible_timeslice", "Some Lifetime::Timeframe data got dropped starting at %" PRIi64, oldNextTimeslice); timesliceIndex.rescan(); } } @@ -630,7 +636,7 @@ o2::framework::ServiceSpec CommonServices::decongestionSpec() auto oldestPossibleOutput = relayer.getOldestPossibleOutput(); if (oldestPossibleOutput.timeslice.value == decongestion.lastTimeslice) { - O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid, "oldest_possible_timeslice", "Not sending already sent value: %" PRIu64, (uint64_t)oldestPossibleOutput.timeslice.value); + O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid, "oldest_possible_timeslice", "Synchronous: Not sending already sent value: %" PRIu64, (uint64_t)oldestPossibleOutput.timeslice.value); return; } if (oldestPossibleOutput.timeslice.value < decongestion.lastTimeslice) { @@ -646,14 +652,15 @@ o2::framework::ServiceSpec CommonServices::decongestionSpec() O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid, "oldest_possible_timeslice", "Queueing oldest possible timeslice %" PRIu64 " propagation for execution.", (uint64_t)oldestPossibleOutput.timeslice.value); AsyncQueueHelpers::post( - queue, decongestion.oldestPossibleTimesliceTask, [ref = services, oldestPossibleOutput, &decongestion, &proxy, &spec, device, ×liceIndex]() { - O2_SIGNPOST_ID_FROM_POINTER(cid, data_processor_context, &decongestion); + queue, decongestion.oldestPossibleTimesliceTask, [ref = services, oldestPossibleOutput, &decongestion, &proxy, &spec, device, ×liceIndex](size_t id) { + O2_SIGNPOST_ID_GENERATE(cid, async_queue); + cid.value = id; if (decongestion.lastTimeslice >= oldestPossibleOutput.timeslice.value) { - O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid, "oldest_possible_timeslice", "Not sending already sent value: %" PRIu64 "> %" PRIu64, + O2_SIGNPOST_EVENT_EMIT(async_queue, cid, "oldest_possible_timeslice", "Not sending already sent value: %" PRIu64 "> %" PRIu64, decongestion.lastTimeslice, (uint64_t)oldestPossibleOutput.timeslice.value); return; } - O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid, "oldest_possible_timeslice", "Running oldest possible timeslice %" PRIu64 " propagation.", + O2_SIGNPOST_EVENT_EMIT(async_queue, cid, "oldest_possible_timeslice", "Running oldest possible timeslice %" PRIu64 " propagation.", (uint64_t)oldestPossibleOutput.timeslice.value); DataProcessingHelpers::broadcastOldestPossibleTimeslice(ref, oldestPossibleOutput.timeslice.value); @@ -662,26 +669,31 @@ o2::framework::ServiceSpec CommonServices::decongestionSpec() auto& state = proxy.getForwardChannelState(ChannelIndex{fi}); // TODO: this we could cache in the proxy at the bind moment. if (info.channelType != ChannelAccountingType::DPL) { - O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid, "oldest_possible_timeslice", "Skipping channel %{public}s", info.name.c_str()); + O2_SIGNPOST_EVENT_EMIT(async_queue, cid, "oldest_possible_timeslice", "Skipping channel %{public}s", info.name.c_str()); continue; } if (DataProcessingHelpers::sendOldestPossibleTimeframe(ref, info, state, oldestPossibleOutput.timeslice.value)) { - O2_SIGNPOST_EVENT_EMIT(data_processor_context, cid, "oldest_possible_timeslice", + O2_SIGNPOST_EVENT_EMIT(async_queue, cid, "oldest_possible_timeslice", "Forwarding to channel %{public}s oldest possible timeslice %" PRIu64 ", priority %d", info.name.c_str(), (uint64_t)oldestPossibleOutput.timeslice.value, 20); } } decongestion.lastTimeslice = oldestPossibleOutput.timeslice.value; - if (decongestion.orderedCompletionPolicyActive) { + }, + TimesliceId{oldestPossibleTimeslice}, -1); + if (decongestion.orderedCompletionPolicyActive) { + AsyncQueueHelpers::post( + queue, decongestion.oldestPossibleTimesliceTask, [ref = services, oldestPossibleOutput, &decongestion, &proxy, &spec, device, ×liceIndex](size_t id) { + O2_SIGNPOST_ID_GENERATE(cid, async_queue); int64_t oldNextTimeslice = decongestion.nextTimeslice; decongestion.nextTimeslice = std::max(decongestion.nextTimeslice, (int64_t)oldestPossibleOutput.timeslice.value); if (oldNextTimeslice != decongestion.nextTimeslice) { - LOGP(error, "Some Lifetime::Timeframe data got dropped starting at {}", oldNextTimeslice); + O2_SIGNPOST_EVENT_EMIT_ERROR(async_queue, cid, "oldest_possible_timeslice", "Some Lifetime::Timeframe data got dropped starting at %" PRIi64, oldNextTimeslice); timesliceIndex.rescan(); } - } }, - TimesliceId{oldestPossibleTimeslice}, -1); }, + TimesliceId{oldestPossibleOutput.timeslice.value}, -1); + } }, .kind = ServiceKind::Serial}; } @@ -840,6 +852,16 @@ o2::framework::ServiceSpec CommonServices::dataProcessingStats() if (deploymentMode != DeploymentMode::OnlineDDS && deploymentMode != DeploymentMode::OnlineECS && deploymentMode != DeploymentMode::OnlineAUX && deploymentMode != DeploymentMode::FST) { arrowAndResourceLimitingMetrics = true; } + // Input proxies should not report cpu_usage_fraction, + // because of the rate limiting which biases the measurement. + auto& spec = services.get(); + bool enableCPUUsageFraction = true; + auto isProxy = [](DataProcessorLabel const& label) -> bool { return label == DataProcessorLabel{"input-proxy"}; }; + if (std::find_if(spec.labels.begin(), spec.labels.end(), isProxy) != spec.labels.end()) { + O2_SIGNPOST_ID_GENERATE(mid, policies); + O2_SIGNPOST_EVENT_EMIT(policies, mid, "metrics", "Disabling cpu_usage_fraction metric for proxy %{public}s", spec.name.c_str()); + enableCPUUsageFraction = false; + } std::vector metrics = { MetricSpec{.name = "errors", @@ -923,6 +945,7 @@ o2::framework::ServiceSpec CommonServices::dataProcessingStats() .maxRefreshLatency = onlineRefreshLatency, .sendInitialValue = true}, MetricSpec{.name = "cpu_usage_fraction", + .enabled = enableCPUUsageFraction, .metricId = (int)ProcessingStatsId::CPU_USAGE_FRACTION, .kind = Kind::Rate, .scope = Scope::Online, @@ -1237,7 +1260,7 @@ std::vector CommonServices::defaultServices(std::string extraPlugin loadableServicesStr += "O2FrameworkDataTakingSupport:InfoLoggerContext,O2FrameworkDataTakingSupport:InfoLogger"; } // Load plugins depending on the environment - std::vector loadableServices = {}; + std::vector loadablePlugins = {}; char* loadableServicesEnv = getenv("DPL_LOAD_SERVICES"); // String to define the services to load is: // @@ -1248,8 +1271,8 @@ std::vector CommonServices::defaultServices(std::string extraPlugin } loadableServicesStr += loadableServicesEnv; } - loadableServices = ServiceHelpers::parseServiceSpecString(loadableServicesStr.c_str()); - ServiceHelpers::loadFromPlugin(loadableServices, specs); + loadablePlugins = PluginManager::parsePluginSpecString(loadableServicesStr.c_str()); + PluginManager::loadFromPlugin(loadablePlugins, specs); // I should make it optional depending wether the GUI is there or not... specs.push_back(CommonServices::guiMetricsSpec()); if (numThreads) { diff --git a/Framework/Core/src/DPLWebSocket.cxx b/Framework/Core/src/DPLWebSocket.cxx index 146a13206b55a..77018f8cb44b4 100644 --- a/Framework/Core/src/DPLWebSocket.cxx +++ b/Framework/Core/src/DPLWebSocket.cxx @@ -152,12 +152,12 @@ struct GUIWebSocketHandler : public WebSocketHandler { } case GUIOpcodes::Keydown: { char key = *frame; - mContext.gui->plugin->keyDown(key); + mContext.gui->plugin->keyEvent(key, true); break; } case GUIOpcodes::Keyup: { char key = *frame; - mContext.gui->plugin->keyUp(key); + mContext.gui->plugin->keyEvent(key, false); break; } case GUIOpcodes::Charin: { diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index 58ea6524f0b7d..602fe7cc29548 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -92,6 +92,8 @@ struct formatter : ostream_format O2_DECLARE_DYNAMIC_LOG(device); // Special log to keep track of the lifetime of the parts O2_DECLARE_DYNAMIC_LOG(parts); +// Special log to track the async queue behavior +O2_DECLARE_DYNAMIC_LOG(async_queue); using namespace o2::framework; using ConfigurationInterface = o2::configuration::ConfigurationInterface; @@ -119,7 +121,8 @@ void on_transition_requested_expired(uv_timer_t* handle) { auto* state = (DeviceState*)handle->data; state->loopReason |= DeviceState::TIMER_EXPIRED; - LOGP(info, "Timer expired. Forcing transition to READY"); + O2_SIGNPOST_ID_FROM_POINTER(cid, device, handle); + O2_SIGNPOST_EVENT_EMIT_WARN(device, cid, "callback", "Exit transition timer expired. Exiting."); state->transitionHandling = TransitionHandlingState::Expired; } @@ -218,8 +221,13 @@ void run_callback(uv_work_t* handle) { auto* task = (TaskStreamInfo*)handle->data; auto ref = ServiceRegistryRef{*task->registry, ServiceRegistry::globalStreamSalt(task->id.index + 1)}; + // We create a new signpost interval for this specific data processor. Same id, same data processor. + auto& dataProcessorContext = ref.get(); + O2_SIGNPOST_ID_FROM_POINTER(sid, device, &dataProcessorContext); + O2_SIGNPOST_START(device, sid, "run_callback", "Starting run callback on stream %d", task->id.index); DataProcessingDevice::doPrepare(ref); DataProcessingDevice::doRun(ref); + O2_SIGNPOST_END(device, sid, "run_callback", "Done processing data for stream %d", task->id.index); } // Once the processing in a thread is done, this is executed on the main thread. @@ -364,6 +372,9 @@ void DataProcessingDevice::Init() auto ref = ServiceRegistryRef{mServiceRegistry}; auto& context = ref.get(); auto& spec = getRunningDevice(mRunningDevice, ref); + + O2_SIGNPOST_ID_FROM_POINTER(cid, device, &context); + O2_SIGNPOST_START(device, cid, "Init", "Entering Init callback."); context.statelessProcess = spec.algorithm.onProcess; context.statefulProcess = nullptr; context.error = spec.algorithm.onError; @@ -404,8 +415,10 @@ void DataProcessingDevice::Init() /// FIXME: we should pass the salt in, so that the message /// can access information which were stored in the stream. ServiceRegistryRef ref{serviceRegistry, ServiceRegistry::globalDeviceSalt()}; + auto& context = ref.get(); auto& err = error_from_ref(e); - LOGP(error, "Exception caught: {} ", err.what); + O2_SIGNPOST_ID_FROM_POINTER(cid, device, &context); + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "Init", "Exception caught while in Init: %{public}s. Invoking errorCallback.", err.what); demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO); auto& stats = ref.get(); stats.updateStats({(int)ProcessingStatsId::EXCEPTION_COUNT, DataProcessingStats::Op::Add, 1}); @@ -417,8 +430,10 @@ void DataProcessingDevice::Init() auto& err = error_from_ref(e); /// FIXME: we should pass the salt in, so that the message /// can access information which were stored in the stream. - LOGP(error, "Exception caught: {} ", err.what); ServiceRegistryRef ref{serviceRegistry, ServiceRegistry::globalDeviceSalt()}; + auto& context = ref.get(); + O2_SIGNPOST_ID_FROM_POINTER(cid, device, &context); + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "Init", "Exception caught while in Init: %{public}s. Exiting with 1.", err.what); demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO); auto& stats = ref.get(); stats.updateStats({(int)ProcessingStatsId::EXCEPTION_COUNT, DataProcessingStats::Op::Add, 1}); @@ -483,6 +498,7 @@ void DataProcessingDevice::Init() ServiceRegistry::Salt streamSalt = ServiceRegistry::streamSalt(si + 1, ServiceRegistry::globalDeviceSalt().dataProcessorId); mServiceRegistry.lateBindStreamServices(state, *options, streamSalt); } + O2_SIGNPOST_END(device, cid, "Init", "Exiting Init callback."); } void on_signal_callback(uv_signal_t* handle, int signum) @@ -675,9 +691,11 @@ static auto forwardInputs = [](ServiceRegistryRef registry, TimesliceSlot slot, auto& asyncQueue = registry.get(); auto& decongestion = registry.get(); - LOG(debug) << "Queuing forwarding oldestPossible " << oldestTimeslice.timeslice.value; + auto& timesliceIndex = registry.get(); + O2_SIGNPOST_ID_GENERATE(aid, async_queue); + O2_SIGNPOST_EVENT_EMIT(async_queue, aid, "forwardInputs", "Queuing forwarding oldestPossible %zu", oldestTimeslice.timeslice.value); AsyncQueueHelpers::post( - asyncQueue, decongestion.oldestPossibleTimesliceTask, [&proxy, &decongestion, registry, oldestTimeslice]() { + asyncQueue, decongestion.oldestPossibleTimesliceTask, [&proxy, &decongestion, registry, oldestTimeslice, ×liceIndex](size_t aid) { // DataProcessingHelpers::broadcastOldestPossibleTimeslice(proxy, oldestTimeslice.timeslice.value); if (oldestTimeslice.timeslice.value <= decongestion.lastTimeslice) { LOG(debug) << "Not sending already sent oldest possible timeslice " << oldestTimeslice.timeslice.value; @@ -686,13 +704,17 @@ static auto forwardInputs = [](ServiceRegistryRef registry, TimesliceSlot slot, for (int fi = 0; fi < proxy.getNumForwardChannels(); fi++) { auto& info = proxy.getForwardChannelInfo(ChannelIndex{fi}); auto& state = proxy.getForwardChannelState(ChannelIndex{fi}); + O2_SIGNPOST_ID_GENERATE(aid, async_queue); // TODO: this we could cache in the proxy at the bind moment. if (info.channelType != ChannelAccountingType::DPL) { - LOG(debug) << "Skipping channel"; + O2_SIGNPOST_EVENT_EMIT(async_queue, aid, "forwardInputsCallback", "Skipping channel %{public}s because it's not a DPL channel", + info.name.c_str()); + continue; } if (DataProcessingHelpers::sendOldestPossibleTimeframe(registry, info, state, oldestTimeslice.timeslice.value)) { - LOGP(debug, "Forwarding to channel {} oldest possible timeslice {}, prio 20", info.name, oldestTimeslice.timeslice.value); + O2_SIGNPOST_EVENT_EMIT(async_queue, aid, "forwardInputsCallback", "Forwarding to channel %{public}s oldest possible timeslice %zu, prio 20", + info.name.c_str(), oldestTimeslice.timeslice.value); } } }, @@ -1065,7 +1087,9 @@ void DataProcessingDevice::fillContext(DataProcessorContext& context, DeviceCont /// can access information which were stored in the stream. ServiceRegistryRef ref{serviceRegistry, ServiceRegistry::globalDeviceSalt()}; auto& err = error_from_ref(e); - LOGP(error, "Exception caught: {} ", err.what); + auto& context = ref.get(); + O2_SIGNPOST_ID_FROM_POINTER(cid, device, &context); + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "Run", "Exception while running: %{public}s. Invoking callback.", err.what); demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO); auto& stats = ref.get(); stats.updateStats({(int)ProcessingStatsId::EXCEPTION_COUNT, DataProcessingStats::Op::Add, 1}); @@ -1078,15 +1102,18 @@ void DataProcessingDevice::fillContext(DataProcessorContext& context, DeviceCont auto& err = error_from_ref(e); /// FIXME: we should pass the salt in, so that the message /// can access information which were stored in the stream. - LOGP(error, "Exception caught: {} ", err.what); ServiceRegistryRef ref{serviceRegistry, ServiceRegistry::globalDeviceSalt()}; + auto& context = ref.get(); + O2_SIGNPOST_ID_FROM_POINTER(cid, device, &context); demangled_backtrace_symbols(err.backtrace, err.maxBacktrace, STDERR_FILENO); auto& stats = ref.get(); stats.updateStats({(int)ProcessingStatsId::EXCEPTION_COUNT, DataProcessingStats::Op::Add, 1}); switch (errorPolicy) { case TerminationPolicy::QUIT: + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "Run", "Exception while running: %{public}s. Rethrowing.", err.what); throw e; default: + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "Run", "Exception while running: %{public}s. Skipping to next timeframe.", err.what); break; } }; @@ -1134,6 +1161,9 @@ void DataProcessingDevice::PreRun() { auto ref = ServiceRegistryRef{mServiceRegistry}; auto& state = ref.get(); + + O2_SIGNPOST_ID_FROM_POINTER(cid, device, state.loop); + O2_SIGNPOST_START(device, cid, "PreRun", "Entering PreRun callback."); state.quitRequested = false; state.streaming = StreamingState::Streaming; for (auto& info : state.inputChannelInfos) { @@ -1154,13 +1184,16 @@ void DataProcessingDevice::PreRun() context.preStartStreamCallbacks(streamRef); } } catch (std::exception& e) { - LOGP(error, "Exception caught: {} ", e.what()); + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "PreRun", "Exception of type std::exception caught in PreRun: %{public}s. Rethrowing.", e.what()); + O2_SIGNPOST_END(device, cid, "PreRun", "Exiting PreRun due to exception thrown."); throw; } catch (o2::framework::RuntimeErrorRef& e) { auto& err = error_from_ref(e); - LOGP(error, "Exception caught: {} ", err.what); + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "PreRun", "Exception of type o2::framework::RuntimeErrorRef caught in PreRun: %{public}s. Rethrowing.", err.what); + O2_SIGNPOST_END(device, cid, "PreRun", "Exiting PreRun due to exception thrown."); throw; } catch (...) { + O2_SIGNPOST_END(device, cid, "PreRun", "Unknown exception being thrown. Rethrowing."); throw; } @@ -1175,6 +1208,7 @@ void DataProcessingDevice::PreRun() auto& monitoring = ref.get(); monitoring.send(Metric{(uint64_t)1, "device_state"}.addTag(Key::Subsystem, Value::DPL)); + O2_SIGNPOST_END(device, cid, "PreRun", "Exiting PreRun callback."); } void DataProcessingDevice::PostRun() @@ -1207,6 +1241,8 @@ void DataProcessingDevice::Run() auto& state = ref.get(); state.loopReason = DeviceState::LoopReason::FIRST_LOOP; bool firstLoop = true; + O2_SIGNPOST_ID_FROM_POINTER(lid, device, state.loop); + O2_SIGNPOST_START(device, lid, "device_state", "First iteration of the device loop"); while (state.transitionHandling != TransitionHandlingState::Expired) { if (state.nextFairMQState.empty() == false) { (void)this->ChangeState(state.nextFairMQState.back()); @@ -1236,6 +1272,7 @@ void DataProcessingDevice::Run() state.loopReason |= DeviceState::LoopReason::PREVIOUSLY_ACTIVE; } if (NewStatePending()) { + O2_SIGNPOST_EVENT_EMIT(device, lid, "run_loop", "New state pending. Waiting for it to be handled."); shouldNotWait = true; state.loopReason |= DeviceState::LoopReason::NEW_STATE_PENDING; } @@ -1261,25 +1298,26 @@ void DataProcessingDevice::Run() uv_update_time(state.loop); uv_timer_start(deviceContext.gracePeriodTimer, on_transition_requested_expired, timeout * 1000, 0); if (mProcessingPolicies.termination == TerminationPolicy::QUIT) { - LOGP(info, "New state requested. Waiting for {} seconds before quitting.", timeout); + O2_SIGNPOST_EVENT_EMIT_INFO(device, lid, "run_loop", "New state requested. Waiting for %d seconds before quitting.", (int)deviceContext.exitTransitionTimeout); } else { - LOGP(info, "New state requested. Waiting for {} seconds before switching to READY state.", timeout); + O2_SIGNPOST_EVENT_EMIT_INFO(device, lid, "run_loop", "New state requested. Waiting for %d seconds before switching to READY state.", (int)deviceContext.exitTransitionTimeout); } } else { state.transitionHandling = TransitionHandlingState::Expired; - if (timeout == 0 && mProcessingPolicies.termination == TerminationPolicy::QUIT) { - LOGP(info, "New state requested. No timeout set, quitting immediately as per --completion-policy"); - } else if (timeout == 0 && mProcessingPolicies.termination != TerminationPolicy::QUIT) { - LOGP(info, "New state requested. No timeout set, switching to READY state immediately"); + if (deviceContext.exitTransitionTimeout == 0 && mProcessingPolicies.termination == TerminationPolicy::QUIT) { + O2_SIGNPOST_EVENT_EMIT_INFO(device, lid, "run_loop", "New state requested. No timeout set, quitting immediately as per --completion-policy"); + } else if (deviceContext.exitTransitionTimeout == 0 && mProcessingPolicies.termination != TerminationPolicy::QUIT) { + O2_SIGNPOST_EVENT_EMIT_INFO(device, lid, "run_loop", "New state requested. No timeout set, switching to READY state immediately"); } else if (mProcessingPolicies.termination == TerminationPolicy::QUIT) { - LOGP(info, "New state pending and we are already idle, quitting immediately as per --completion-policy"); + O2_SIGNPOST_EVENT_EMIT_INFO(device, lid, "run_loop", "New state pending and we are already idle, quitting immediately as per --completion-policy"); } else { - LOGP(info, "New state pending and we are already idle, switching to READY immediately."); + O2_SIGNPOST_EVENT_EMIT_INFO(device, lid, "runb_loop", "New state pending and we are already idle, switching to READY immediately."); } } } // If we are Idle, we can then consider the transition to be expired. if (state.transitionHandling == TransitionHandlingState::Requested && state.streaming == StreamingState::Idle) { + O2_SIGNPOST_EVENT_EMIT(device, lid, "run_loop", "State transition requested and we are now in Idle. We can consider it to be completed."); state.transitionHandling = TransitionHandlingState::Expired; } if (state.severityStack.empty() == false) { @@ -1299,8 +1337,8 @@ void DataProcessingDevice::Run() // - we can trigger further events from the queue // - we can guarantee this is the last thing we do in the loop ( // assuming no one else is adding to the queue before this point). - auto onDrop = [®istry = mServiceRegistry](TimesliceSlot slot, std::vector& dropped, TimesliceIndex::OldestOutputInfo oldestOutputInfo) { - LOGP(debug, "Dropping message from slot {}. Forwarding as needed.", slot.index); + auto onDrop = [®istry = mServiceRegistry, lid](TimesliceSlot slot, std::vector& dropped, TimesliceIndex::OldestOutputInfo oldestOutputInfo) { + O2_SIGNPOST_START(device, lid, "run_loop", "Dropping message from slot %" PRIu64 ". Forwarding as needed.", (uint64_t)slot.index); ServiceRegistryRef ref{registry}; ref.get(); ref.get(); @@ -1319,7 +1357,9 @@ void DataProcessingDevice::Run() auto& dpContext = ref.get(); dpContext.preLoopCallbacks(ref); } + O2_SIGNPOST_END(device, lid, "run_loop", "Run loop completed. %{}s", shouldNotWait ? "Will immediately schedule a new one" : "Waiting for next event."); uv_run(state.loop, shouldNotWait ? UV_RUN_NOWAIT : UV_RUN_ONCE); + O2_SIGNPOST_START(device, lid, "run_loop", "Run loop started. Loop reason %d.", state.loopReason); if ((state.loopReason & state.tracingFlags) != 0) { state.severityStack.push_back((int)fair::Logger::GetConsoleSeverity()); fair::Logger::SetConsoleSeverity(fair::Severity::trace); @@ -1327,16 +1367,15 @@ void DataProcessingDevice::Run() fair::Logger::SetConsoleSeverity((fair::Severity)state.severityStack.back()); state.severityStack.pop_back(); } - LOGP(debug, "Loop reason mask {:b} & {:b} = {:b}", - state.loopReason, state.tracingFlags, - state.loopReason & state.tracingFlags); + O2_SIGNPOST_EVENT_EMIT(device, lid, "run_loop", "Loop reason mask %x & %x = %x", state.loopReason, state.tracingFlags, state.loopReason & state.tracingFlags); if ((state.loopReason & DeviceState::LoopReason::OOB_ACTIVITY) != 0) { - LOGP(debug, "We were awakened by a OOB event. Rescanning everything."); + O2_SIGNPOST_EVENT_EMIT(device, lid, "run_loop", "Out of band activity detected. Rescanning everything."); relayer.rescan(); } if (!state.pendingOffers.empty()) { + O2_SIGNPOST_EVENT_EMIT(device, lid, "run_loop", "Pending %" PRIu64 " offers. updating the ComputingQuotaEvaluator.", (uint64_t)state.pendingOffers.size()); ref.get().updateOffers(state.pendingOffers, uv_now(state.loop)); } } @@ -1411,6 +1450,8 @@ void DataProcessingDevice::Run() mWasActive = false; } } + + O2_SIGNPOST_END(device, lid, "run_loop", "Run loop completed. Transition handling state %d.", state.transitionHandling); auto& spec = ref.get(); /// Cleanup messages which are still pending on exit. for (size_t ci = 0; ci < spec.inputChannels.size(); ++ci) { @@ -1425,6 +1466,8 @@ void DataProcessingDevice::Run() void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) { auto& context = ref.get(); + O2_SIGNPOST_ID_FROM_POINTER(dpid, device, &context); + O2_SIGNPOST_START(device, dpid, "do_prepare", "Starting DataProcessorContext::doPrepare."); *context.wasActive = false; { @@ -1441,17 +1484,19 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) // real data input channels, they have to signal EndOfStream themselves. auto& state = ref.get(); auto& spec = ref.get(); - context.allDone = std::any_of(state.inputChannelInfos.begin(), state.inputChannelInfos.end(), [](const auto& info) { + O2_SIGNPOST_ID_FROM_POINTER(cid, device, state.inputChannelInfos.data()); + O2_SIGNPOST_START(device, cid, "do_prepare", "Reported channel states."); + context.allDone = std::any_of(state.inputChannelInfos.begin(), state.inputChannelInfos.end(), [cid](const auto& info) { if (info.channel) { - LOGP(debug, "Input channel {}{} has {} parts left and is in state {}.", info.channel->GetName(), (info.id.value == ChannelIndex::INVALID ? " (non DPL)" : ""), info.parts.fParts.size(), (int)info.state); + O2_SIGNPOST_EVENT_EMIT(device, cid, "do_prepare", "Input channel %{public}s%{public}s has %zu parts left and is in state %d.", + info.channel->GetName().c_str(), (info.id.value == ChannelIndex::INVALID ? " (non DPL)" : ""), info.parts.fParts.size(), (int)info.state); } else { - LOGP(debug, "External channel {} is in state {}.", info.id.value, (int)info.state); + O2_SIGNPOST_EVENT_EMIT(device, cid, "do_prepare", "External channel %d is in state %d.", info.id.value, (int)info.state); } return (info.parts.fParts.empty() == true && info.state != InputChannelState::Pull); }); - - // Whether or not all the channels are completed - LOGP(debug, "Processing {} input channels.", spec.inputChannels.size()); + O2_SIGNPOST_END(device, cid, "do_prepare", "End report."); + O2_SIGNPOST_EVENT_EMIT(device, dpid, "do_prepare", "Processing %zu input channels.", spec.inputChannels.size()); /// Sort channels by oldest possible timeframe and /// process them in such order. static std::vector pollOrder; @@ -1463,13 +1508,14 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) // Nothing to poll... if (pollOrder.empty()) { + O2_SIGNPOST_END(device, dpid, "do_prepare", "Nothing to poll. Waiting for next iteration."); return; } auto currentOldest = state.inputChannelInfos[pollOrder.front()].oldestForChannel; auto currentNewest = state.inputChannelInfos[pollOrder.back()].oldestForChannel; auto delta = currentNewest.value - currentOldest.value; - LOGP(debug, "oldest possible timeframe range {}, {} => {} delta", currentOldest.value, currentNewest.value, - delta); + O2_SIGNPOST_EVENT_EMIT(device, dpid, "do_prepare", "Oldest possible timeframe range %" PRIu64 " => %" PRIu64 " delta %" PRIu64, + (int64_t)currentOldest.value, (int64_t)currentNewest.value, (int64_t)delta); auto& infos = state.inputChannelInfos; if (context.balancingInputs) { @@ -1495,12 +1541,13 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) } pollOrder.erase(newEnd, pollOrder.end()); } - LOGP(debug, "processing {} channels", pollOrder.size()); + O2_SIGNPOST_END(device, dpid, "do_prepare", "%zu channels pass the channel inbalance balance check.", pollOrder.size()); for (auto sci : pollOrder) { auto& info = state.inputChannelInfos[sci]; auto& channelSpec = spec.inputChannels[sci]; - LOGP(debug, "Processing channel {}", channelSpec.name); + O2_SIGNPOST_ID_FROM_POINTER(cid, device, &info); + O2_SIGNPOST_START(device, cid, "channels", "Processing channel %s", channelSpec.name.c_str()); if (info.state != InputChannelState::Completed && info.state != InputChannelState::Pull) { context.allDone = false; @@ -1511,14 +1558,19 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) if (info.parts.Size()) { DataProcessingDevice::handleData(ref, info); } - LOGP(debug, "Flushing channel {} which is in state {} and has {} parts still pending.", channelSpec.name, (int)info.state, info.parts.Size()); + O2_SIGNPOST_END(device, cid, "channels", "Flushing channel %s which is in state %d and has %zu parts still pending.", + channelSpec.name.c_str(), (int)info.state, info.parts.Size()); continue; } if (info.channel == nullptr) { + O2_SIGNPOST_END(device, cid, "channels", "Channel %s which is in state %d is nullptr and has %zu parts still pending.", + channelSpec.name.c_str(), (int)info.state, info.parts.Size()); continue; } // Only poll DPL channels for now. if (info.channelType != ChannelAccountingType::DPL) { + O2_SIGNPOST_END(device, cid, "channels", "Channel %s which is in state %d is not a DPL channel and has %zu parts still pending.", + channelSpec.name.c_str(), (int)info.state, info.parts.Size()); continue; } auto& socket = info.channel->GetSocket(); @@ -1530,7 +1582,7 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) socket.Events(&info.hasPendingEvents); // If we do not read, we can continue. if ((info.hasPendingEvents & 1) == 0 && (info.parts.Size() == 0)) { - LOGP(debug, "No pending events and no remaining parts to process for channel {}", channelSpec.name); + O2_SIGNPOST_END(device, cid, "channels", "No pending events and no remaining parts to process for channel %{public}s", channelSpec.name.c_str()); continue; } } @@ -1547,13 +1599,13 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) // to process. bool newMessages = false; while (true) { - LOGP(debug, "Receiving loop called for channel {} ({}) with oldest possible timeslice {}", - info.channel->GetName(), info.id.value, info.oldestForChannel.value); + O2_SIGNPOST_EVENT_EMIT(device, cid, "channels", "Receiving loop called for channel %{public}s (%d) with oldest possible timeslice %zu", + channelSpec.name.c_str(), info.id.value, info.oldestForChannel.value); if (info.parts.Size() < 64) { fair::mq::Parts parts; info.channel->Receive(parts, 0); if (parts.Size()) { - LOGP(debug, "Receiving some parts {}", parts.Size()); + O2_SIGNPOST_EVENT_EMIT(device, cid, "channels", "Received %zu parts from channel %{public}s (%d).", parts.Size(), channelSpec.name.c_str(), info.id.value); } for (auto&& part : parts) { info.parts.fParts.emplace_back(std::move(part)); @@ -1578,15 +1630,21 @@ void DataProcessingDevice::doPrepare(ServiceRegistryRef ref) info.readPolled = false; *context.wasActive |= newMessages; } + O2_SIGNPOST_END(device, cid, "channels", "Done processing channel %{public}s (%d).", + channelSpec.name.c_str(), info.id.value); } } void DataProcessingDevice::doRun(ServiceRegistryRef ref) { auto& context = ref.get(); + O2_SIGNPOST_ID_FROM_POINTER(dpid, device, &context); auto switchState = [ref](StreamingState newState) { auto& state = ref.get(); - LOG(detail) << "New state " << (int)newState << " old state " << (int)state.streaming; + auto& context = ref.get(); + O2_SIGNPOST_ID_FROM_POINTER(dpid, device, &context); + O2_SIGNPOST_END(device, dpid, "state", "End of processing state %d", (int)state.streaming); + O2_SIGNPOST_START(device, dpid, "state", "Starting processing state %d", (int)newState); state.streaming = newState; ref.get().notifyStreamingState(state.streaming); }; @@ -1625,7 +1683,7 @@ void DataProcessingDevice::doRun(ServiceRegistryRef ref) } if (state.streaming == StreamingState::EndOfStreaming) { - LOGP(detail, "We are in EndOfStreaming. Flushing queues."); + O2_SIGNPOST_EVENT_EMIT(device, dpid, "state", "We are in EndOfStreaming. Flushing queues."); // We keep processing data until we are Idle. // FIXME: not sure this is the correct way to drain the queues, but // I guess we will see. @@ -1646,7 +1704,7 @@ void DataProcessingDevice::doRun(ServiceRegistryRef ref) context.postEOSCallbacks(eosContext); for (auto& channel : spec.outputChannels) { - LOGP(detail, "Sending end of stream to {}", channel.name); + O2_SIGNPOST_EVENT_EMIT(device, dpid, "state", "Sending end of stream to %{public}s.", channel.name.c_str()); DataProcessingHelpers::sendEndOfStream(ref, channel); } // This is needed because the transport is deleted before the device. @@ -1658,7 +1716,7 @@ void DataProcessingDevice::doRun(ServiceRegistryRef ref) *context.wasActive = true; } // On end of stream we shut down all output pollers. - LOGP(detail, "Shutting down output pollers"); + O2_SIGNPOST_EVENT_EMIT(device, dpid, "state", "Shutting down output pollers."); for (auto& poller : state.activeOutputPollers) { uv_poll_stop(poller); } @@ -1667,7 +1725,7 @@ void DataProcessingDevice::doRun(ServiceRegistryRef ref) if (state.streaming == StreamingState::Idle) { // On end of stream we shut down all output pollers. - LOGP(detail, "We are in Idle. Shutting down output pollers."); + O2_SIGNPOST_EVENT_EMIT(device, dpid, "state", "Shutting down output pollers."); for (auto& poller : state.activeOutputPollers) { uv_poll_stop(poller); } @@ -1708,6 +1766,10 @@ struct WaitBackpressurePolicy { void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& info) { auto& context = ref.get(); + // This is the same id as the upper level function, so we get the events + // associated with the same interval. We will simply use "handle_data" as + // the category. + O2_SIGNPOST_ID_FROM_POINTER(cid, device, &info); enum struct InputType : int { Invalid = 0, @@ -1731,6 +1793,7 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& // than an input, because we do not want the outer loop actually be exposed // to the implementation details of the messaging layer. auto getInputTypes = [&info, &context]() -> std::optional> { + O2_SIGNPOST_ID_FROM_POINTER(cid, device, &info); auto ref = ServiceRegistryRef{*context.registry}; auto& stats = ref.get(); auto& parts = info.parts; @@ -1752,7 +1815,7 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& auto* headerData = parts.At(pi)->GetData(); auto sih = o2::header::get(headerData); if (sih) { - LOGP(debug, "Got SourceInfoHeader with state {}", (int)sih->state); + O2_SIGNPOST_EVENT_EMIT(device, cid, "handle_data", "Got SourceInfoHeader with state %d", (int)sih->state); info.state = sih->state; insertInputInfo(pi, 2, InputType::SourceInfo); *context.wasActive = true; @@ -1767,12 +1830,12 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& auto dh = o2::header::get(headerData); if (!dh) { insertInputInfo(pi, 0, InputType::Invalid); - LOGP(error, "Header is not a DataHeader?"); + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "handle_data", "Header is not a DataHeader?"); continue; } if (dh->payloadSize > parts.At(pi + 1)->GetSize()) { insertInputInfo(pi, 0, InputType::Invalid); - LOGP(error, "DataHeader payloadSize mismatch"); + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "handle_data", "DataHeader payloadSize mismatch"); continue; } auto dph = o2::header::get(headerData); @@ -1785,7 +1848,7 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& } if (!dph) { insertInputInfo(pi, 2, InputType::Invalid); - LOGP(error, "Header stack does not contain DataProcessingHeader"); + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "handle_data", "Header stack does not contain DataProcessingHeader"); continue; } if (dh->splitPayloadParts > 0 && dh->splitPayloadParts == dh->splitPayloadIndex) { @@ -1800,7 +1863,7 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& // pair. size_t finalSplitPayloadIndex = pi + (dh->splitPayloadParts > 0 ? dh->splitPayloadParts : 1) * 2; if (finalSplitPayloadIndex > parts.Size()) { - LOGP(error, "DataHeader::splitPayloadParts invalid"); + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "handle_data", "DataHeader::splitPayloadParts invalid"); insertInputInfo(pi, 0, InputType::Invalid); continue; } @@ -1811,7 +1874,7 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& } } if (results.size() + nTotalPayloads != parts.Size()) { - LOG(error) << "inconsistent number of inputs extracted"; + O2_SIGNPOST_EVENT_EMIT_ERROR(device, cid, "handle_data", "inconsistent number of inputs extracted. %zu vs parts (%zu)", results.size() + nTotalPayloads, parts.Size()); return std::nullopt; } return results; @@ -1865,7 +1928,9 @@ void DataProcessingDevice::handleData(ServiceRegistryRef ref, InputChannelInfo& ii += (nMessages / 2) - 1; } auto onDrop = [ref](TimesliceSlot slot, std::vector& dropped, TimesliceIndex::OldestOutputInfo oldestOutputInfo) { - LOGP(debug, "Dropping message from slot {}. Forwarding as needed. Timeslice {}", slot.index, oldestOutputInfo.timeslice.value); + O2_SIGNPOST_ID_GENERATE(cid, async_queue); + O2_SIGNPOST_EVENT_EMIT(async_queue, cid, "onDrop", "Dropping message from slot %zu. Forwarding as needed. Timeslice %zu", + slot.index, oldestOutputInfo.timeslice.value); ref.get(); ref.get(); ref.get(); @@ -2276,6 +2341,7 @@ bool DataProcessingDevice::tryDispatchComputation(ServiceRegistryRef ref, std::v *context.registry}; ProcessingContext processContext{record, ref, ref.get()}; { + O2_SIGNPOST_EVENT_EMIT(device, aid, "device", "Invoking preProcessingCallbacks"); // Notice this should be thread safe and reentrant // as it is called from many threads. streamContext.preProcessingCallbacks(processContext); @@ -2429,6 +2495,7 @@ bool DataProcessingDevice::tryDispatchComputation(ServiceRegistryRef ref, std::v if (action.op == CompletionPolicy::CompletionOp::Process) { cleanTimers(action.slot, record); } + O2_SIGNPOST_END(device, aid, "device", "Done processing action on slot %lu for action %{public}s", action.slot.index, fmt::format("{}", action.op).c_str()); } O2_SIGNPOST_END(device, sid, "device", "Start processing ready actions"); diff --git a/Framework/Core/src/DataRelayer.cxx b/Framework/Core/src/DataRelayer.cxx index 1daf4bbd2a20b..bcb5f2a0d9d74 100644 --- a/Framework/Core/src/DataRelayer.cxx +++ b/Framework/Core/src/DataRelayer.cxx @@ -54,6 +54,8 @@ using DataHeader = o2::header::DataHeader; using DataProcessingHeader = o2::framework::DataProcessingHeader; using Verbosity = o2::monitoring::Verbosity; +O2_DECLARE_DYNAMIC_LOG(data_relayer); + namespace o2::framework { @@ -369,6 +371,8 @@ void DataRelayer::pruneCache(TimesliceSlot slot, OnDropCallback onDrop) } bool anyDropped = std::any_of(dropped.begin(), dropped.end(), [](auto& m) { return m.size(); }); if (anyDropped) { + O2_SIGNPOST_ID_GENERATE(aid, data_relayer); + O2_SIGNPOST_EVENT_EMIT(data_relayer, aid, "pruneCache", "Dropping stuff from slot %zu %zu", slot.index, oldestPossibleTimeslice.timeslice.value); onDrop(slot, dropped, oldestPossibleTimeslice); } } @@ -440,6 +444,8 @@ DataRelayer::RelayChoice &nPayloads, &cache = mCache, numInputTypes = mDistinctRoutesIndex.size()](TimesliceId timeslice, int input, TimesliceSlot slot) { + O2_SIGNPOST_ID_GENERATE(aid, data_relayer); + O2_SIGNPOST_EVENT_EMIT(data_relayer, aid, "saveInSlot", "saving %zu in slot %zu", timeslice.value, slot.index); auto cacheIdx = numInputTypes * slot.index + input; MessageSet& target = cache[cacheIdx]; cachedStateMetrics[cacheIdx] = CacheEntryStatus::PENDING; @@ -573,8 +579,14 @@ DataRelayer::RelayChoice return RelayChoice{.type = RelayChoice::Type::Invalid, .timeslice = timeslice}; } + O2_SIGNPOST_ID_GENERATE(aid, data_relayer); TimesliceIndex::ActionTaken action; std::tie(action, slot) = index.replaceLRUWith(pristineContext, timeslice); + uint64_t const* debugTimestamp = std::get_if(&pristineContext.get(0)); + if (action != TimesliceIndex::ActionTaken::Wait) { + O2_SIGNPOST_EVENT_EMIT(data_relayer, aid, "saveInSlot", + "Slot %zu updated with %zu using action %d, %" PRIu64, slot.index, timeslice.value, (int)action, *debugTimestamp); + } updateStatistics(action); diff --git a/Framework/Core/src/DeviceSpecHelpers.cxx b/Framework/Core/src/DeviceSpecHelpers.cxx index 565f85e895f31..30197538f2dda 100644 --- a/Framework/Core/src/DeviceSpecHelpers.cxx +++ b/Framework/Core/src/DeviceSpecHelpers.cxx @@ -1512,6 +1512,7 @@ void DeviceSpecHelpers::prepareArguments(bool defaultQuiet, bool defaultStopped, realOdesc.add_options()("shm-allocation", bpo::value()); realOdesc.add_options()("shm-no-cleanup", bpo::value()); realOdesc.add_options()("shmid", bpo::value()); + realOdesc.add_options()("shm-metadata-msg-size", bpo::value()->default_value("0")); realOdesc.add_options()("shm-monitor", bpo::value()); realOdesc.add_options()("channel-prefix", bpo::value()); realOdesc.add_options()("network-interface", bpo::value()); @@ -1695,6 +1696,7 @@ boost::program_options::options_description DeviceSpecHelpers::getForwardedDevic ("shm-allocation", bpo::value()->default_value("rbtree_best_fit"), "shm allocation method") // ("shm-no-cleanup", bpo::value()->default_value("false"), "no shm cleanup") // ("shmid", bpo::value(), "shmid") // + ("shm-metadata-msg-size", bpo::value()->default_value("0"), "numeric value in B used for padding FairMQ header, see FairMQ v.1.6.0") // ("environment", bpo::value(), "comma separated list of environment variables to set for the device") // ("stacktrace-on-signal", bpo::value()->default_value("simple"), // "dump stacktrace on specified signal(s) (any of `all`, `segv`, `bus`, `ill`, `abrt`, `fpe`, `sys`.)" // @@ -1709,7 +1711,7 @@ boost::program_options::options_description DeviceSpecHelpers::getForwardedDevic ("infologger-mode", bpo::value(), "O2_INFOLOGGER_MODE override") // ("infologger-severity", bpo::value(), "minimun FairLogger severity which goes to info logger") // ("dpl-tracing-flags", bpo::value(), "pipe separated list of events to trace") // - ("signposts", bpo::value(), // + ("signposts", bpo::value()->default_value(defaultSignposts), // "comma separated list of signposts to enable (any of `completion`, `data_processor_context`, `stream_context`, `device`, `monitoring_service`)") // ("child-driver", bpo::value(), "external driver to start childs with (e.g. valgrind)"); // diff --git a/Framework/Core/src/Expressions.cxx b/Framework/Core/src/Expressions.cxx index b30bf5049f0d3..b3301e2cf4040 100644 --- a/Framework/Core/src/Expressions.cxx +++ b/Framework/Core/src/Expressions.cxx @@ -716,27 +716,6 @@ bool isTableCompatible(std::set const& hashes, Operations const& specs opHashes.begin(), opHashes.end()); } -bool isSchemaCompatible(gandiva::SchemaPtr const& Schema, Operations const& opSpecs) -{ - std::set opFieldNames; - for (auto const& spec : opSpecs) { - if (spec.left.datum.index() == 3) { - opFieldNames.insert(std::get(spec.left.datum)); - } - if (spec.right.datum.index() == 3) { - opFieldNames.insert(std::get(spec.right.datum)); - } - } - - std::set schemaFieldNames; - for (auto const& field : Schema->fields()) { - schemaFieldNames.insert(field->name()); - } - - return std::includes(schemaFieldNames.begin(), schemaFieldNames.end(), - opFieldNames.begin(), opFieldNames.end()); -} - void updateExpressionInfos(expressions::Filter const& filter, std::vector& eInfos) { if (eInfos.empty()) { @@ -756,4 +735,15 @@ void updateExpressionInfos(expressions::Filter const& filter, std::vector& table) +{ + if (info.tree != nullptr && info.filter == nullptr) { + info.filter = framework::expressions::createFilter(table->schema(), framework::expressions::makeCondition(info.tree)); + } + if (info.tree != nullptr && info.filter != nullptr && info.resetSelection == true) { + info.selection = framework::expressions::createSelection(table, info.filter); + info.resetSelection = false; + } +} + } // namespace o2::framework::expressions diff --git a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx index 4846363efd93b..820181ff353ed 100644 --- a/Framework/Core/src/ExternalFairMQDeviceProxy.cxx +++ b/Framework/Core/src/ExternalFairMQDeviceProxy.cxx @@ -381,6 +381,7 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve return; } std::string missing = ""; + bool showAlarm = false; for (auto mi : unmatchedDescriptions) { auto& spec = routes[mi].matcher; missing += " " + DataSpecUtils::describe(spec); @@ -407,10 +408,13 @@ void injectMissingData(fair::mq::Device& device, fair::mq::Parts& parts, std::ve parts.AddPart(std::move(headerMessage)); // add empty payload message parts.AddPart(device.NewMessageFor(channelName, 0, 0)); + if ((concrete.origin != o2::header::gDataOriginEMC && concrete.origin != o2::header::gDataOriginPHS && concrete.origin != o2::header::gDataOriginHMP) || concrete.description != o2::header::DataDescription{"RAWDATA"}) { + showAlarm = true; + } } static int maxWarn = 10; // Correct would be o2::conf::VerbosityConfig::Instance().maxWarnDeadBeef, but Framework does not depend on CommonUtils..., but not so critical since receives will send correct number of DEADBEEF messages static int contDeadBeef = 0; - if (++contDeadBeef <= maxWarn) { + if (showAlarm && ++contDeadBeef <= maxWarn) { LOGP(alarm, "Found {}/{} data specs, missing data specs: {}, injecting 0xDEADBEEF{}", foundDataSpecs, expectedDataSpecs, missing, contDeadBeef == maxWarn ? " - disabling alarm now to stop flooding the log" : ""); } } diff --git a/Framework/Core/src/Plugins.cxx b/Framework/Core/src/PluginManager.cxx similarity index 72% rename from Framework/Core/src/Plugins.cxx rename to Framework/Core/src/PluginManager.cxx index c4a0ee7fd6dc5..96666722fc169 100644 --- a/Framework/Core/src/Plugins.cxx +++ b/Framework/Core/src/PluginManager.cxx @@ -8,7 +8,7 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include "Framework/Plugins.h" +#include "Framework/PluginManager.h" #include "Framework/Logger.h" #include #include @@ -16,6 +16,55 @@ namespace o2::framework { +std::vector PluginManager::parsePluginSpecString(char const* str) +{ + std::vector loadablePlugins; + enum struct ParserState : int { + IN_LIBRARY, + IN_NAME, + IN_END, + IN_ERROR, + }; + const char* cur = str; + const char* next = cur; + ParserState state = ParserState::IN_LIBRARY; + std::string_view library; + std::string_view name; + while (cur && *cur != '\0') { + ParserState previousState = state; + state = ParserState::IN_ERROR; + switch (previousState) { + case ParserState::IN_LIBRARY: + next = strchr(cur, ':'); + if (next != nullptr) { + state = ParserState::IN_NAME; + library = std::string_view(cur, next - cur); + } + break; + case ParserState::IN_NAME: + next = strchr(cur, ','); + if (next == nullptr) { + state = ParserState::IN_END; + name = std::string_view(cur, strlen(cur)); + } else { + name = std::string_view(cur, next - cur); + state = ParserState::IN_LIBRARY; + } + loadablePlugins.push_back({std::string(name), std::string(library)}); + break; + case ParserState::IN_END: + break; + case ParserState::IN_ERROR: + LOG(error) << "Error while parsing DPL_LOAD_SERVICES"; + break; + } + if (!next) { + break; + } + cur = next + 1; + }; + return loadablePlugins; +} void PluginManager::load(std::vector& libs, const char* dso, std::function& onSuccess) { diff --git a/Framework/Core/src/RateLimiter.cxx b/Framework/Core/src/RateLimiter.cxx index 5f6ff24adfd7c..f381148223280 100644 --- a/Framework/Core/src/RateLimiter.cxx +++ b/Framework/Core/src/RateLimiter.cxx @@ -33,32 +33,36 @@ int RateLimiter::check(ProcessingContext& ctx, int maxInFlight, size_t minSHM) auto device = ctx.services().get().device(); auto& deviceState = ctx.services().get(); if (maxInFlight && device->GetChannels().count("metric-feedback")) { - int waitMessage = 0; - int recvTimeot = 0; auto& dtc = ctx.services().get(); const auto& device = ctx.services().get().device(); const auto& deviceContext = ctx.services().get(); - int timeout = deviceContext.exitTransitionTimeout; + bool timeout = deviceContext.exitTransitionTimeout; + bool timeoutForMessage = dtc.deploymentMode == DeploymentMode::OnlineDDS || dtc.deploymentMode == DeploymentMode::OnlineECS; + bool waitMessage = false; + int recvTimeout = 0; + auto startTime = std::chrono::system_clock::now(); + static constexpr float MESSAGE_DELAY_TIME = 15.f; while ((mSentTimeframes - mConsumedTimeframes) >= maxInFlight) { - if (recvTimeot != 0 && waitMessage == 0) { + if (recvTimeout != 0 && !waitMessage && (timeoutForMessage == false || std::chrono::duration_cast>(std::chrono::system_clock::now() - startTime).count() > MESSAGE_DELAY_TIME)) { if (dtc.deploymentMode == DeploymentMode::OnlineDDS || dtc.deploymentMode == DeploymentMode::OnlineECS || dtc.deploymentMode == DeploymentMode::FST) { LOG(alarm) << "Maximum number of TF in flight reached (" << maxInFlight << ": published " << mSentTimeframes << " - finished " << mConsumedTimeframes << "), waiting"; } else { LOG(info) << "Maximum number of TF in flight reached (" << maxInFlight << ": published " << mSentTimeframes << " - finished " << mConsumedTimeframes << "), waiting"; } - waitMessage = 1; + waitMessage = true; + timeoutForMessage = false; } auto msg = device->NewMessageFor("metric-feedback", 0, 0); int64_t count = 0; do { - count = device->Receive(msg, "metric-feedback", 0, recvTimeot); + count = device->Receive(msg, "metric-feedback", 0, recvTimeout); if (timeout && count <= 0 && device->NewStatePending()) { return 1; } - } while (count <= 0 && recvTimeot > 0); + } while (count <= 0 && recvTimeout > 0 && !timeoutForMessage); if (count <= 0) { - recvTimeot = timeout ? -1 : 1000; + recvTimeout = timeout || timeoutForMessage ? 1000 : -1; continue; } assert(msg->GetSize() == 8); @@ -68,7 +72,7 @@ int RateLimiter::check(ProcessingContext& ctx, int maxInFlight, size_t minSHM) if (dtc.deploymentMode == DeploymentMode::OnlineDDS || dtc.deploymentMode == DeploymentMode::OnlineECS || dtc.deploymentMode == DeploymentMode::FST) { LOG(important) << (mSentTimeframes - mConsumedTimeframes) << " / " << maxInFlight << " TF in flight, continuing to publish"; } else { - LOG(important) << (mSentTimeframes - mConsumedTimeframes) << " / " << maxInFlight << " TF in flight, continuing to publish"; + LOG(info) << (mSentTimeframes - mConsumedTimeframes) << " / " << maxInFlight << " TF in flight, continuing to publish"; } } diff --git a/Framework/Core/src/ServiceSpec.cxx b/Framework/Core/src/ServiceSpec.cxx index fdbe0c0c4dd4b..4f38651b68924 100644 --- a/Framework/Core/src/ServiceSpec.cxx +++ b/Framework/Core/src/ServiceSpec.cxx @@ -104,124 +104,4 @@ ServiceSpecs ServiceSpecHelpers::filterDisabled(ServiceSpecs originals, Override return result; } -std::vector ServiceHelpers::parseServiceSpecString(char const* str) -{ - std::vector loadableServices; - enum struct ParserState : int { - IN_LIBRARY, - IN_NAME, - IN_END, - IN_ERROR, - }; - const char* cur = str; - const char* next = cur; - ParserState state = ParserState::IN_LIBRARY; - std::string_view library; - std::string_view name; - while (cur && *cur != '\0') { - ParserState previousState = state; - state = ParserState::IN_ERROR; - switch (previousState) { - case ParserState::IN_LIBRARY: - next = strchr(cur, ':'); - if (next != nullptr) { - state = ParserState::IN_NAME; - library = std::string_view(cur, next - cur); - } - break; - case ParserState::IN_NAME: - next = strchr(cur, ','); - if (next == nullptr) { - state = ParserState::IN_END; - name = std::string_view(cur, strlen(cur)); - } else { - name = std::string_view(cur, next - cur); - state = ParserState::IN_LIBRARY; - } - loadableServices.push_back({std::string(name), std::string(library)}); - break; - case ParserState::IN_END: - break; - case ParserState::IN_ERROR: - LOG(error) << "Error while parsing DPL_LOAD_SERVICES"; - break; - } - if (!next) { - break; - } - cur = next + 1; - }; - return loadableServices; -} - -void ServiceHelpers::loadFromPlugin(std::vector const& loadableServices, std::vector& specs) -{ - struct LoadedDSO { - std::string library; - uv_lib_t handle; - }; - - struct LoadedPlugin { - std::string name; - ServicePlugin* factory; - }; - std::vector loadedDSOs; - std::vector loadedPlugins; - for (auto& loadableService : loadableServices) { - auto loadedDSO = std::find_if(loadedDSOs.begin(), loadedDSOs.end(), [&loadableService](auto& dso) { - return dso.library == loadableService.library; - }); - - if (loadedDSO == loadedDSOs.end()) { - uv_lib_t handle; -#ifdef __APPLE__ - auto libraryName = fmt::format("lib{}.dylib", loadableService.library); -#else - auto libraryName = fmt::format("lib{}.so", loadableService.library); -#endif - auto ret = uv_dlopen(libraryName.c_str(), &handle); - if (ret != 0) { - LOGP(error, "Could not load library {}", loadableService.library); - LOG(error) << uv_dlerror(&handle); - continue; - } - loadedDSOs.push_back({loadableService.library, handle}); - loadedDSO = loadedDSOs.end() - 1; - } - int result = 0; - - auto loadedPlugin = std::find_if(loadedPlugins.begin(), loadedPlugins.end(), [&loadableService](auto& plugin) { - return plugin.name == loadableService.name; - }); - - if (loadedPlugin == loadedPlugins.end()) { - DPLPluginHandle* (*dpl_plugin_callback)(DPLPluginHandle*); - result = uv_dlsym(&loadedDSO->handle, "dpl_plugin_callback", (void**)&dpl_plugin_callback); - if (result == -1) { - LOG(error) << uv_dlerror(&loadedDSO->handle); - continue; - } - - DPLPluginHandle* pluginInstance = dpl_plugin_callback(nullptr); - ServicePlugin* factory = PluginManager::getByName(pluginInstance, loadableService.name.c_str()); - if (factory == nullptr) { - LOGP(error, "Could not find service {} in library {}", loadableService.name, loadableService.library); - continue; - } - - loadedPlugins.push_back({loadableService.name, factory}); - loadedPlugin = loadedPlugins.begin() + loadedPlugins.size() - 1; - } - assert(loadedPlugin != loadedPlugins.end()); - assert(loadedPlugin->factory != nullptr); - - ServiceSpec* spec = loadedPlugin->factory->create(); - if (!spec) { - LOG(error) << "Plugin " << loadableService.name << " could not be created"; - continue; - } - LOGP(debug, "Loading service {} from {}", loadableService.name, loadableService.library); - specs.push_back(*spec); - } -} } // namespace o2::framework diff --git a/Framework/Core/src/StreamContext.cxx b/Framework/Core/src/StreamContext.cxx index 2ce0c1c427cbd..0712025849447 100644 --- a/Framework/Core/src/StreamContext.cxx +++ b/Framework/Core/src/StreamContext.cxx @@ -31,12 +31,17 @@ void StreamContext::preStartStreamCallbacks(ServiceRegistryRef ref) /// Invoke callbacks to be executed before every process method invokation void StreamContext::preProcessingCallbacks(ProcessingContext& pcx) { + O2_SIGNPOST_ID_FROM_POINTER(dpid, stream_context, &pcx); + O2_SIGNPOST_START(stream_context, dpid, "callbacks", "Starting StreamContext preProcessingCallbacks"); for (auto& handle : preProcessingHandles) { - LOG(debug) << "Invoking preProcessingCallbacks for" << handle.service; + O2_SIGNPOST_ID_FROM_POINTER(cid, stream_context, handle.service); + O2_SIGNPOST_START(stream_context, cid, "callbacks", "Starting StreamContext::preProcessingCallbacks for service %{public}s", handle.spec.name.c_str()); assert(handle.service); assert(handle.callback); handle.callback(pcx, handle.service); + O2_SIGNPOST_END(stream_context, cid, "callbacks", "Ending StreamContext::preProcessingCallbacks for service %{public}s", handle.spec.name.c_str()); } + O2_SIGNPOST_END(stream_context, dpid, "callbacks", "Ending StreamContext preProcessingCallbacks"); } /// Invoke callbacks to be executed after every process method invokation diff --git a/Framework/Core/src/TimesliceIndex.cxx b/Framework/Core/src/TimesliceIndex.cxx index 4d5cf443e5385..2ddf2007d0100 100644 --- a/Framework/Core/src/TimesliceIndex.cxx +++ b/Framework/Core/src/TimesliceIndex.cxx @@ -9,7 +9,9 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. #include "Framework/TimesliceIndex.h" -#include "Framework/Logger.h" +#include "Framework/Signpost.h" + +O2_DECLARE_DYNAMIC_LOG(timeslice_index); namespace o2::framework { @@ -33,6 +35,8 @@ void TimesliceIndex::associate(TimesliceId timestamp, TimesliceSlot slot) mVariables[slot.index].put({0, static_cast(timestamp.value)}); mVariables[slot.index].commit(); mDirty[slot.index] = true; + O2_SIGNPOST_ID_GENERATE(tid, timeslice_index); + O2_SIGNPOST_EVENT_EMIT(timeslice_index, tid, "associate", "Associating timestamp %zu to slot %zu", timestamp.value, slot.index); } TimesliceSlot TimesliceIndex::findOldestSlot(TimesliceId timestamp) const @@ -63,13 +67,18 @@ TimesliceSlot TimesliceIndex::findOldestSlot(TimesliceId timestamp) const std::tuple TimesliceIndex::replaceLRUWith(data_matcher::VariableContext& newContext, TimesliceId timestamp) { auto oldestSlot = findOldestSlot(timestamp); + O2_SIGNPOST_ID_GENERATE(tid, timeslice_index); if (TimesliceIndex::isValid(oldestSlot) == false) { mVariables[oldestSlot.index] = newContext; + auto debugTimestamp = std::get_if(&mVariables[oldestSlot.index].get(0)); + O2_SIGNPOST_EVENT_EMIT(timeslice_index, tid, "replaceLRUWith", "slot %zu timeslice %zu (%" PRIu64 ")", oldestSlot.index, timestamp.value, *debugTimestamp); return std::make_tuple(ActionTaken::ReplaceUnused, oldestSlot); } auto oldTimestamp = std::get_if(&mVariables[oldestSlot.index].get(0)); if (oldTimestamp == nullptr) { mVariables[oldestSlot.index] = newContext; + auto debugTimestamp = std::get_if(&mVariables[oldestSlot.index].get(0)); + O2_SIGNPOST_EVENT_EMIT(timeslice_index, tid, "replaceLRUWith", "slot %zu timeslice %zu (%" PRIu64 ")", oldestSlot.index, timestamp.value, *debugTimestamp); return std::make_tuple(ActionTaken::ReplaceUnused, oldestSlot); } @@ -80,9 +89,12 @@ std::tuple TimesliceIndex::replaceLR if (*newTimestamp > *oldTimestamp) { switch (mBackpressurePolicy) { - case BackpressureOp::DropAncient: + case BackpressureOp::DropAncient: { mVariables[oldestSlot.index] = newContext; + auto debugTimestamp = std::get_if(&mVariables[oldestSlot.index].get(0)); + O2_SIGNPOST_EVENT_EMIT(timeslice_index, tid, "replaceLRUWith", "slot %zu timeslice %zu (%" PRIu64 ")", oldestSlot.index, timestamp.value, *debugTimestamp); return std::make_tuple(ActionTaken::ReplaceObsolete, oldestSlot); + } case BackpressureOp::DropRecent: return std::make_tuple(ActionTaken::DropObsolete, TimesliceSlot{TimesliceSlot::INVALID}); case BackpressureOp::Wait: @@ -90,9 +102,12 @@ std::tuple TimesliceIndex::replaceLR } } else { switch (mBackpressurePolicy) { - case BackpressureOp::DropRecent: + case BackpressureOp::DropRecent: { mVariables[oldestSlot.index] = newContext; + auto debugTimestamp = std::get_if(&mVariables[oldestSlot.index].get(0)); + O2_SIGNPOST_EVENT_EMIT(timeslice_index, tid, "replaceLRUWith", "slot %zu timeslice %zu (%" PRIu64 ")", oldestSlot.index, timestamp.value, *debugTimestamp); return std::make_tuple(ActionTaken::ReplaceObsolete, oldestSlot); + } case BackpressureOp::DropAncient: return std::make_tuple(ActionTaken::DropObsolete, TimesliceSlot{TimesliceSlot::INVALID}); case BackpressureOp::Wait: @@ -124,9 +139,12 @@ bool TimesliceIndex::didReceiveData() const TimesliceIndex::OldestInputInfo TimesliceIndex::setOldestPossibleInput(TimesliceId timestamp, ChannelIndex channel) { + O2_SIGNPOST_ID_GENERATE(tid, timeslice_index); // Each channel oldest possible input must be monotoically increasing. if (timestamp.value < mChannels[channel.value].oldestForChannel.value) { - LOG(error) << "Received bogus oldest possible timeslice " << timestamp.value << " for channel " << channel.value << ". Expected >= " << mChannels[channel.value].oldestForChannel.value; + O2_SIGNPOST_EVENT_EMIT_ERROR(timeslice_index, tid, "setOldestPossibleInput", + "Received bogus oldest possible timeslice %zu for channel %d. Expected >= %zu.", + timestamp.value, channel.value, mChannels[channel.value].oldestForChannel.value); } mChannels[channel.value].oldestForChannel = timestamp; OldestInputInfo result{timestamp, channel}; @@ -144,11 +162,13 @@ TimesliceIndex::OldestInputInfo TimesliceIndex::setOldestPossibleInput(Timeslice } } if (changed && mOldestPossibleInput.timeslice.value != result.timeslice.value) { - LOG(debug) << "Success: Oldest possible input is " << result.timeslice.value << " due to channel " << result.channel.value; + O2_SIGNPOST_EVENT_EMIT(timeslice_index, tid, "setOldestPossibleInput", "Success: Oldest possible input is %zu due to channel %d", + result.timeslice.value, result.channel.value); } else if (mOldestPossibleInput.timeslice.value != result.timeslice.value) { - LOG(debug) << "Oldest possible input updated from timestamp: " << mOldestPossibleInput.timeslice.value << " --> " << result.timeslice.value; + O2_SIGNPOST_EVENT_EMIT(timeslice_index, tid, "setOldestPossibleInput", "Oldest possible input updated from timestamp: %zu --> %zu", + mOldestPossibleInput.timeslice.value, result.timeslice.value); } else { - LOG(debug) << "No change in oldest possible input"; + O2_SIGNPOST_EVENT_EMIT(timeslice_index, tid, "setOldestPossibleInput", "No change in oldest possible input"); } mOldestPossibleInput = result; return mOldestPossibleInput; @@ -187,13 +207,17 @@ TimesliceIndex::OldestOutputInfo TimesliceIndex::updateOldestPossibleOutput() result.channel = {(int)-1}; } } - if (changed && mOldestPossibleOutput.timeslice.value != result.timeslice.value) { - LOGP(debug, "Oldest possible output {} due to {} {}", - result.timeslice.value, - result.channel.value == -1 ? "slot" : "channel", - result.channel.value == -1 ? mOldestPossibleOutput.slot.index : mOldestPossibleOutput.channel.value); - } else if (mOldestPossibleOutput.timeslice.value != result.timeslice.value) { - LOG(debug) << "Oldest possible output updated from oldest Input : " << mOldestPossibleOutput.timeslice.value << " --> " << result.timeslice.value; + O2_SIGNPOST_ID_GENERATE(tid, timeslice_index); + if (mOldestPossibleOutput.timeslice.value != result.timeslice.value) { + if (changed) { + O2_SIGNPOST_EVENT_EMIT(timeslice_index, tid, "updateOldestPossibleOutput", "Oldest possible output %zu (before %zu) due to %s %zu", + result.timeslice.value, mOldestPossibleOutput.timeslice.value, + result.channel.value == -1 ? "slot" : "channel", + result.channel.value == -1 ? result.slot.index : result.channel.value); + } else { + O2_SIGNPOST_EVENT_EMIT(timeslice_index, tid, "updateOldestPossibleOutput", "Oldest possible output updated from oldest Input : %zu --> %zu", + mOldestPossibleOutput.timeslice.value, result.timeslice.value); + } } mOldestPossibleOutput = result; diff --git a/Framework/Core/src/WorkflowHelpers.cxx b/Framework/Core/src/WorkflowHelpers.cxx index f5a66722aa713..bd875ad421f6e 100644 --- a/Framework/Core/src/WorkflowHelpers.cxx +++ b/Framework/Core/src/WorkflowHelpers.cxx @@ -21,7 +21,7 @@ #include "Framework/RawDeviceService.h" #include "Framework/StringHelpers.h" #include "Framework/ChannelSpecHelpers.h" -#include "Framework/Plugins.h" +#include "Framework/PluginManager.h" #include "Framework/DataTakingContext.h" #include "Framework/DefaultsHelpers.h" diff --git a/Framework/Core/src/runDataProcessing.cxx b/Framework/Core/src/runDataProcessing.cxx index c72b4da73a45a..f91716d28cfd7 100644 --- a/Framework/Core/src/runDataProcessing.cxx +++ b/Framework/Core/src/runDataProcessing.cxx @@ -22,7 +22,7 @@ #include "Framework/DataProcessingDevice.h" #include "Framework/DataProcessingContext.h" #include "Framework/DataProcessorSpec.h" -#include "Framework/Plugins.h" +#include "Framework/PluginManager.h" #include "Framework/DeviceControl.h" #include "Framework/DeviceExecution.h" #include "Framework/DeviceInfo.h" diff --git a/Framework/Core/test/test_ASoA.cxx b/Framework/Core/test/test_ASoA.cxx index d38c8183dc459..a2bce16e970fe 100644 --- a/Framework/Core/test/test_ASoA.cxx +++ b/Framework/Core/test/test_ASoA.cxx @@ -12,6 +12,7 @@ #include "Framework/ASoA.h" #include "Framework/Expressions.h" #include "Framework/AnalysisHelpers.h" +#include "CommonConstants/MathConstants.h" #include "gandiva/tree_expr_builder.h" #include "arrow/status.h" #include "gandiva/filter.h" diff --git a/Framework/Core/test/test_AlgorithmWrapper.cxx b/Framework/Core/test/test_AlgorithmWrapper.cxx index 7671b6afa194b..6a02aea62c528 100644 --- a/Framework/Core/test/test_AlgorithmWrapper.cxx +++ b/Framework/Core/test/test_AlgorithmWrapper.cxx @@ -14,7 +14,7 @@ #include "Framework/ServiceRegistry.h" #include "Framework/RawDeviceService.h" #include "Framework/runDataProcessing.h" -#include "Framework/Plugins.h" +#include "Framework/PluginManager.h" #include using namespace o2::framework; diff --git a/Framework/Core/test/test_AllCrashTypes.sh b/Framework/Core/test/test_AllCrashTypes.sh new file mode 100755 index 0000000000000..54898fd9c4c5d --- /dev/null +++ b/Framework/Core/test/test_AllCrashTypes.sh @@ -0,0 +1,23 @@ +#!/bin/sh -e +echo $PATH +printf "ok\nTesting runtime-init..." +o2-framework-crashing-workflow --crash-type=runtime-init --completion-policy=quit -b --run | grep -q "Exception caught while in Init: This is a std::runtime_error. Exiting with 1." || { printf "runtime error not found" ; exit 1; } +printf "ok\nTesting framework-init..." +o2-framework-crashing-workflow --crash-type=framework-init --completion-policy=quit -b --run | grep -q "Exception caught while in Init: This is a o2::framework::runtime_error. Exiting with 1." || { printf "framework error not found" ; exit 1; } +printf "ok\nTesting framework-run..." +o2-framework-crashing-workflow --crash-type=framework-run --completion-policy=quit -b --run | grep -q "Unhandled o2::framework::runtime_error reached the top of main of o2-framework-crashing-workflow, device shutting down. Reason: This is a o2::framework::runtime_error" || { printf "framework error not found" ; exit 1; } +printf "ok\nTesting runtime-run..." +o2-framework-crashing-workflow --crash-type=runtime-run --completion-policy=quit --run | grep -q "Unhandled o2::framework::runtime_error reached the top of main of o2-framework-crashing-workflow, device shutting down. Reason: This is a std::runtime_error" || { echo "runtime error not found" ; exit 1; } +printf "ok\n" + +export O2_NO_CATCHALL_EXCEPTIONS=1 +echo O2_NO_CATCHALL_EXCEPTIONS enabled +printf "ok\nTesting runtime-init..." +o2-framework-crashing-workflow --crash-type=runtime-init --completion-policy=quit -b --run | grep -v -q "Exception caught: This is a std::runtime_error" || { printf "runtime error not found" ; exit 1; } +printf "ok\nTesting framework-init..." +o2-framework-crashing-workflow --crash-type=framework-init --completion-policy=quit -b --run | grep -v -q "Exception caught: This is a o2::framework::runtime_error" || { printf "framework error not found" ; exit 1; } +printf "ok\nTesting framework-run..." +o2-framework-crashing-workflow --crash-type=framework-run --completion-policy=quit -b --run | grep -v -q "Unhandled o2::framework::runtime_error reached the top of main of o2-framework-crashing-workflow, device shutting down. Reason: This is a o2::framework::runtime_error" || { printf "framework error not found" ; exit 1; } +printf "ok\nTesting runtime-run..." +o2-framework-crashing-workflow --crash-type=runtime-run --completion-policy=quit --run | grep -v -q "Unhandled o2::framework::runtime_error reached the top of main of o2-framework-crashing-workflow, device shutting down. Reason: This is a std::runtime_error" || { echo "runtime error not found" ; exit 1; } +printf "ok" diff --git a/Framework/Core/test/test_AnalysisTask.cxx b/Framework/Core/test/test_AnalysisTask.cxx index b18554dcf5fc3..87c8e655d1330 100644 --- a/Framework/Core/test/test_AnalysisTask.cxx +++ b/Framework/Core/test/test_AnalysisTask.cxx @@ -132,9 +132,11 @@ struct TestCCDBObject { struct KTask { struct : public ConfigurableGroup { + std::string prefix = "foo"; Configurable anInt{"someConfigurable", {}, "Some Configurable Object"}; Configurable anotherInt{"someOtherConfigurable", {}, "Some Configurable Object"}; } foo; + Configurable anThirdInt{"someThirdConfigurable", {}, "Some Configurable Object"}; struct : public ConditionGroup { Condition test{"path"}; @@ -241,7 +243,7 @@ TEST_CASE("TestPartitionIteration") TestA testA{tableA}; PartitionTest p1 = aod::test::x < 4.0f; - p1.setTable(testA); + p1.bindTable(testA); REQUIRE(4 == p1.size()); REQUIRE(p1.begin() != p1.end()); auto i = 0; @@ -257,7 +259,7 @@ TEST_CASE("TestPartitionIteration") auto selection = expressions::createSelection(testA.asArrowTable(), f1); FilteredTest filtered{{testA.asArrowTable()}, o2::soa::selectionToVector(selection)}; PartitionFilteredTest p2 = aod::test::y > 9.0f; - p2.setTable(filtered); + p2.bindTable(filtered); REQUIRE(2 == p2.size()); i = 0; @@ -270,7 +272,7 @@ TEST_CASE("TestPartitionIteration") REQUIRE(i == 2); PartitionNestedFilteredTest p3 = aod::test::x < 3.0f; - p3.setTable(*(p2.mFiltered)); + p3.bindTable(*(p2.mFiltered)); REQUIRE(1 == p3.size()); i = 0; for (auto& p : p3) { diff --git a/Framework/Core/test/test_AsyncQueue.cxx b/Framework/Core/test/test_AsyncQueue.cxx index c3ac4ea06bd82..635eb131cc666 100644 --- a/Framework/Core/test/test_AsyncQueue.cxx +++ b/Framework/Core/test/test_AsyncQueue.cxx @@ -22,9 +22,9 @@ TEST_CASE("TestDebouncing") // Push two tasks on the queue with the same id auto count = 0; AsyncQueueHelpers::post( - queue, taskId, [&count]() { count += 1; }, TimesliceId{0}, 10); + queue, taskId, [&count](size_t) { count += 1; }, TimesliceId{0}, 10); AsyncQueueHelpers::post( - queue, taskId, [&count]() { count += 2; }, TimesliceId{1}, 20); + queue, taskId, [&count](size_t) { count += 2; }, TimesliceId{1}, 20); AsyncQueueHelpers::run(queue, TimesliceId{2}); REQUIRE(count == 2); } @@ -39,9 +39,9 @@ TEST_CASE("TestPriority") // Push two tasks on the queue with the same id auto count = 0; AsyncQueueHelpers::post( - queue, taskId1, [&count]() { count += 10; }, TimesliceId{0}); + queue, taskId1, [&count](size_t) { count += 10; }, TimesliceId{0}); AsyncQueueHelpers::post( - queue, taskId2, [&count]() { count /= 10; }, TimesliceId{0}); + queue, taskId2, [&count](size_t) { count /= 10; }, TimesliceId{0}); AsyncQueueHelpers::run(queue, TimesliceId{2}); REQUIRE(count == 10); } @@ -56,9 +56,9 @@ TEST_CASE("TestOldestTimeslice") // Push two tasks on the queue with the same id auto count = 0; AsyncQueueHelpers::post( - queue, taskId1, [&count]() { count += 10; }, TimesliceId{1}); + queue, taskId1, [&count](size_t) { count += 10; }, TimesliceId{1}); AsyncQueueHelpers::post( - queue, taskId2, [&count]() { count += 20; }, TimesliceId{0}); + queue, taskId2, [&count](size_t) { count += 20; }, TimesliceId{0}); AsyncQueueHelpers::run(queue, TimesliceId{0}); REQUIRE(count == 20); AsyncQueueHelpers::run(queue, TimesliceId{0}); @@ -77,11 +77,11 @@ TEST_CASE("TestOldestTimesliceWithBounce") // Push two tasks on the queue with the same id auto count = 0; AsyncQueueHelpers::post( - queue, taskId1, [&count]() { count += 10; }, TimesliceId{2}); + queue, taskId1, [&count](size_t) { count += 10; }, TimesliceId{2}); AsyncQueueHelpers::post( - queue, taskId2, [&count]() { count += 20; }, TimesliceId{1}, 10); + queue, taskId2, [&count](size_t) { count += 20; }, TimesliceId{1}, 10); AsyncQueueHelpers::post( - queue, taskId2, [&count]() { count += 30; }, TimesliceId{1}, 20); + queue, taskId2, [&count](size_t) { count += 30; }, TimesliceId{1}, 20); AsyncQueueHelpers::run(queue, TimesliceId{0}); REQUIRE(count == 0); REQUIRE(queue.tasks.size() == 3); @@ -103,11 +103,11 @@ TEST_CASE("TestOldestTimesliceWithNegativeBounce") // Push two tasks on the queue with the same id auto count = 0; AsyncQueueHelpers::post( - queue, taskId1, [&count]() { count += 10; }, TimesliceId{2}); + queue, taskId1, [&count](size_t) { count += 10; }, TimesliceId{2}); AsyncQueueHelpers::post( - queue, taskId2, [&count]() { count += 20; }, TimesliceId{1}, -10); + queue, taskId2, [&count](size_t) { count += 20; }, TimesliceId{1}, -10); AsyncQueueHelpers::post( - queue, taskId2, [&count]() { count += 30; }, TimesliceId{1}, -20); + queue, taskId2, [&count](size_t) { count += 30; }, TimesliceId{1}, -20); AsyncQueueHelpers::run(queue, TimesliceId{0}); REQUIRE(count == 0); REQUIRE(queue.tasks.size() == 3); @@ -128,13 +128,13 @@ TEST_CASE("TestOldestTimeslicePerTimeslice") // Push two tasks on the queue with the same id auto count = 0; AsyncQueueHelpers::post( - queue, taskId1, [&count]() { count += 10; }, TimesliceId{1}); + queue, taskId1, [&count](size_t) { count += 10; }, TimesliceId{1}); REQUIRE(queue.tasks.size() == 1); AsyncQueueHelpers::run(queue, TimesliceId{0}); REQUIRE(queue.tasks.size() == 1); REQUIRE(count == 0); AsyncQueueHelpers::post( - queue, taskId1, [&count]() { count += 20; }, TimesliceId{2}); + queue, taskId1, [&count](size_t) { count += 20; }, TimesliceId{2}); REQUIRE(queue.tasks.size() == 2); AsyncQueueHelpers::run(queue, TimesliceId{1}); REQUIRE(queue.tasks.size() == 1); diff --git a/Framework/Core/test/test_ConsumeWhenAllOrdered.cxx b/Framework/Core/test/test_ConsumeWhenAllOrdered.cxx new file mode 100644 index 0000000000000..8be6d539e6781 --- /dev/null +++ b/Framework/Core/test/test_ConsumeWhenAllOrdered.cxx @@ -0,0 +1,89 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/ConfigParamSpec.h" +#include "Framework/DataTakingContext.h" +#include "Framework/CompletionPolicyHelpers.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ControlService.h" +#include "Framework/Configurable.h" +#include "Framework/RunningWorkflowInfo.h" +#include "Framework/CallbackService.h" +#include "Framework/EndOfStreamContext.h" +#include "Framework/CompletionPolicyHelpers.h" +#include + +void customize(std::vector& policies) +{ + policies.push_back(o2::framework::CompletionPolicyHelpers::consumeWhenAllOrdered("fake-output-proxy")); +} + +#include +#include + +using namespace o2::framework; + +#include "Framework/runDataProcessing.h" + +// This is how you can define your processing in a declarative way +WorkflowSpec defineDataProcessing(ConfigContext const& specs) +{ + DataProcessorSpec producer{ + .name = "producer", + .outputs = {OutputSpec{{"counter"}, "TST", "A1"}}, + .algorithm = AlgorithmSpec{adaptStateless( + [](DataAllocator& outputs, ProcessingContext& pcx) { + static int counter = 0; + auto& aData = outputs.make(OutputRef{"counter"}); + aData = counter++; + if (counter == 100) { + pcx.services().get().endOfStream(); + } + })}, + }; + + DataProcessorSpec producerSkipping{ + .name = "producerSkipping", + .outputs = {OutputSpec{{"counter"}, "TST", "A2"}}, + .algorithm = AlgorithmSpec{adaptStateless( + [](DataAllocator& outputs, ProcessingContext& pcx) { + static int counter = -1; + counter++; + if (((counter % 10) == 4) || ((counter % 10) == 5)) { + return; + } + auto& aData = outputs.make(OutputRef{"counter"}); + aData = counter; + if (counter == 100) { + pcx.services().get().endOfStream(); + } + })}, + }; + + DataProcessorSpec outputProxy{ + .name = "fake-output-proxy", + .inputs = { + InputSpec{"x", "TST", "A1", Lifetime::Timeframe}, + InputSpec{"y", "TST", "A2", Lifetime::Timeframe}}, + .algorithm = adaptStateful([](CallbackService& callbacks) { + static int count = 0; + auto eosCallback = [](EndOfStreamContext &ctx) { + if (count != 80) { + LOGP(fatal, "Wrong number of timeframes seen: {} != 80", count); + } + }; + callbacks.set(eosCallback); + return adaptStateless([](Input<"x", int> const& x) + { + std::cout << "See: " << count++ << " with contents " << (int)x << std::endl; + }); })}; + + return WorkflowSpec{producer, producerSkipping, outputProxy}; +} diff --git a/Framework/Core/test/test_CrashingWorkflow.cxx b/Framework/Core/test/test_CrashingWorkflow.cxx new file mode 100644 index 0000000000000..396b48a85c166 --- /dev/null +++ b/Framework/Core/test/test_CrashingWorkflow.cxx @@ -0,0 +1,88 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. +#include "Framework/ConfigParamSpec.h" +#include "Framework/AlgorithmSpec.h" +#include "Framework/Configurable.h" +#include "Framework/Logger.h" +#include "Framework/CallbackService.h" +#include "Framework/Signpost.h" + +O2_DECLARE_DYNAMIC_LOG(crash_test); + +using namespace o2::framework; + +struct WorkflowOptions { + Configurable crashType{"crash-type", "fatal-init", {"how should this crash? (fatal-init, fatal-run, runtime-init, runtime-fail, abort-init, abort-run)"}}; +}; + +#include "Framework/runDataProcessing.h" + +AlgorithmSpec simpleCrashingSource(std::string const& what) +{ + return AlgorithmSpec{adaptStateful([what](InitContext& ctx) { + O2_SIGNPOST_ID_FROM_POINTER(ii, crash_test, &ctx); + O2_SIGNPOST_START(crash_test, ii, "Init", "Starting Init"); + O2_SIGNPOST_EVENT_EMIT(crash_test, ii, "Init", "%{public}s selected", what.c_str()); + + if (what == "fatal-init") { + LOG(fatal) << "This should have a fatal"; + } else if (what == "runtime-init") { + throw std::runtime_error("This is a std::runtime_error"); + } else if (what == "abort-init") { + abort(); + } else if (what == "framework-init") { + throw o2::framework::runtime_error("This is a o2::framework::runtime_error"); + } else if (what == "framework-prerun") { + ctx.services().get().set([](ServiceRegistryRef, int) { + throw o2::framework::runtime_error("This is o2::framework::runtime_error in PreProcessing"); + }); + } else if (what == "runtime-prerun") { + ctx.services().get().set([](ServiceRegistryRef, int) { + throw std::runtime_error("This is std::runtime_error in PreProcessing"); + }); + } + O2_SIGNPOST_END(crash_test, ii, "Init", "Init Done"); + return adaptStateless([what](ProcessingContext& pCtx) { + O2_SIGNPOST_ID_FROM_POINTER(ri, crash_test, &pCtx); + O2_SIGNPOST_START(crash_test, ri, "Run", "Starting Run"); + O2_SIGNPOST_EVENT_EMIT(crash_test, ri, "Run", "%{public}s selected", what.c_str()); + if (what == "fatal-run") { + LOG(fatal) << "This should have a fatal"; + } else if (what == "runtime-run") { + throw std::runtime_error("This is a std::runtime_error"); + } else if (what == "abort-run") { + abort(); + } else if (what == "framework-run") { + throw o2::framework::runtime_error("This is a o2::framework::runtime_error"); + } + O2_SIGNPOST_EVENT_EMIT_ERROR(crash_test, ri, "Run", "Unknown option for crash-type: %{public}s.", what.c_str()); + O2_SIGNPOST_END(crash_test, ri, "Init", "Run Done"); + exit(1); + }); + })}; +} + +// This is how you can define your processing in a declarative way +WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + auto crashType = config.options().get("crash-type"); + DataProcessorSpec a{ + .name = "deliberately-crashing", + .outputs = {OutputSpec{{"a1"}, "TST", "A1"}}, + .algorithm = AlgorithmSpec{simpleCrashingSource(crashType)}}; + DataProcessorSpec b{ + .name = "B", + .inputs = {InputSpec{"x", "TST", "A1", Lifetime::Timeframe}}, + .algorithm = AlgorithmSpec{adaptStateless([](ProcessingContext&) {})}}; + + return workflow::concat(WorkflowSpec{a, b}); +} + diff --git a/Framework/Core/test/test_FrameworkDataFlowToDDS.cxx b/Framework/Core/test/test_FrameworkDataFlowToDDS.cxx index e2082f13b40df..3c08bbae74475 100644 --- a/Framework/Core/test/test_FrameworkDataFlowToDDS.cxx +++ b/Framework/Core/test/test_FrameworkDataFlowToDDS.cxx @@ -355,19 +355,19 @@ TEST_CASE("TestDDS") }"/> dpl_json - cat ${DDS_LOCATION}/dpl_json.asset | foo --id A_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_A_to_B,type=push,method=bind,address=ipc://@localhostworkflow-id_22000,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_C,type=push,method=bind,address=ipc://@localhostworkflow-id_22001,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc + cat ${DDS_LOCATION}/dpl_json.asset | foo --id A_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_A_to_B,type=push,method=bind,address=ipc://@localhostworkflow-id_22000,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_C,type=push,method=bind,address=ipc://@localhostworkflow-id_22001,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-metadata-msg-size 0 --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --signposts "" --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc dpl_json - cat ${DDS_LOCATION}/dpl_json.asset | foo --id B_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_B_to_D,type=push,method=bind,address=ipc://@localhostworkflow-id_22002,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_B,type=pull,method=connect,address=ipc://@localhostworkflow-id_22000,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc + cat ${DDS_LOCATION}/dpl_json.asset | foo --id B_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_B_to_D,type=push,method=bind,address=ipc://@localhostworkflow-id_22002,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_B,type=pull,method=connect,address=ipc://@localhostworkflow-id_22000,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-metadata-msg-size 0 --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --signposts "" --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc dpl_json - cat ${DDS_LOCATION}/dpl_json.asset | foo --id C_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_C_to_D,type=push,method=bind,address=ipc://@localhostworkflow-id_22003,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_C,type=pull,method=connect,address=ipc://@localhostworkflow-id_22001,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc + cat ${DDS_LOCATION}/dpl_json.asset | foo --id C_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_C_to_D,type=push,method=bind,address=ipc://@localhostworkflow-id_22003,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_C,type=pull,method=connect,address=ipc://@localhostworkflow-id_22001,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-metadata-msg-size 0 --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --signposts "" --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc dpl_json - cat ${DDS_LOCATION}/dpl_json.asset | foo --id D_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_B_to_D,type=pull,method=connect,address=ipc://@localhostworkflow-id_22002,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_C_to_D,type=pull,method=connect,address=ipc://@localhostworkflow-id_22003,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal simple --timeframes-rate-limit 0 --a-param 1 --b-param "" --c-param "foo;bar" --session dpl_workflow-id --plugin odc + cat ${DDS_LOCATION}/dpl_json.asset | foo --id D_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_B_to_D,type=pull,method=connect,address=ipc://@localhostworkflow-id_22002,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_C_to_D,type=pull,method=connect,address=ipc://@localhostworkflow-id_22003,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-metadata-msg-size 0 --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --signposts "" --stacktrace-on-signal simple --timeframes-rate-limit 0 --a-param 1 --b-param "" --c-param "foo;bar" --session dpl_workflow-id --plugin odc @@ -383,6 +383,7 @@ TEST_CASE("TestDDS") REQUIRE(strdiffchr(ss.str().data(), expected) == strdiffchr(expected, ss.str().data())); REQUIRE(ss.str() == expected); } + TEST_CASE("TestDDSExpendable") { auto workflow = defineDataProcessingExpendable(); @@ -621,19 +622,19 @@ TEST_CASE("TestDDSExpendable") }"/> dpl_json - cat ${DDS_LOCATION}/dpl_json.asset | foo --id A_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_A_to_B,type=push,method=bind,address=ipc://@localhostworkflow-id_22000,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_C,type=push,method=bind,address=ipc://@localhostworkflow-id_22001,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc + cat ${DDS_LOCATION}/dpl_json.asset | foo --id A_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_A_to_B,type=push,method=bind,address=ipc://@localhostworkflow-id_22000,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_C,type=push,method=bind,address=ipc://@localhostworkflow-id_22001,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-metadata-msg-size 0 --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --signposts "" --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc dpl_json - cat ${DDS_LOCATION}/dpl_json.asset | foo --id B_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_B_to_D,type=push,method=bind,address=ipc://@localhostworkflow-id_22002,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_B,type=pull,method=connect,address=ipc://@localhostworkflow-id_22000,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc + cat ${DDS_LOCATION}/dpl_json.asset | foo --id B_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_B_to_D,type=push,method=bind,address=ipc://@localhostworkflow-id_22002,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_B,type=pull,method=connect,address=ipc://@localhostworkflow-id_22000,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-metadata-msg-size 0 --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --signposts "" --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc dpl_json - cat ${DDS_LOCATION}/dpl_json.asset | foo --id C_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_C_to_D,type=push,method=bind,address=ipc://@localhostworkflow-id_22003,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_C,type=pull,method=connect,address=ipc://@localhostworkflow-id_22001,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc + cat ${DDS_LOCATION}/dpl_json.asset | foo --id C_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_C_to_D,type=push,method=bind,address=ipc://@localhostworkflow-id_22003,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_A_to_C,type=pull,method=connect,address=ipc://@localhostworkflow-id_22001,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-metadata-msg-size 0 --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --signposts "" --stacktrace-on-signal simple --timeframes-rate-limit 0 --session dpl_workflow-id --plugin odc dpl_json - cat ${DDS_LOCATION}/dpl_json.asset | foo --id D_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_B_to_D,type=pull,method=connect,address=ipc://@localhostworkflow-id_22002,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_C_to_D,type=pull,method=connect,address=ipc://@localhostworkflow-id_22003,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --stacktrace-on-signal simple --timeframes-rate-limit 0 --a-param 1 --b-param "" --c-param "foo;bar" --session dpl_workflow-id --plugin odc + cat ${DDS_LOCATION}/dpl_json.asset | foo --id D_dds%TaskIndex%_%CollectionIndex% --shm-monitor false --log-color false --batch --color false --channel-config "name=from_B_to_D,type=pull,method=connect,address=ipc://@localhostworkflow-id_22002,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --channel-config "name=from_C_to_D,type=pull,method=connect,address=ipc://@localhostworkflow-id_22003,transport=shmem,rateLogging=0,rcvBufSize=1,sndBufSize=1" --bad-alloc-attempt-interval 50 --bad-alloc-max-attempts 1 --early-forward-policy never --io-threads 1 --jobs 4 --severity info --shm-allocation rbtree_best_fit --shm-metadata-msg-size 0 --shm-mlock-segment false --shm-mlock-segment-on-creation false --shm-no-cleanup false --shm-segment-id 0 --shm-throw-bad-alloc true --shm-zero-segment false --signposts "" --stacktrace-on-signal simple --timeframes-rate-limit 0 --a-param 1 --b-param "" --c-param "foo;bar" --session dpl_workflow-id --plugin odc odc_expendable_task diff --git a/Framework/Core/test/test_FrameworkDataFlowToO2Control.cxx b/Framework/Core/test/test_FrameworkDataFlowToO2Control.cxx index f3a69e44339a4..bbd5b78fbbb68 100644 --- a/Framework/Core/test/test_FrameworkDataFlowToO2Control.cxx +++ b/Framework/Core/test/test_FrameworkDataFlowToO2Control.cxx @@ -211,6 +211,8 @@ const std::vector expectedTasks{ - "'info'" - "--shm-allocation" - "'rbtree_best_fit'" + - "--shm-metadata-msg-size" + - "'0'" - "--shm-mlock-segment" - "'false'" - "--shm-mlock-segment-on-creation" @@ -221,6 +223,8 @@ const std::vector expectedTasks{ - "'0'" - "--shm-zero-segment" - "'false'" + - "--signposts" + - "''" - "--stacktrace-on-signal" - "'simple'" - "--timeframes-rate-limit" @@ -304,6 +308,8 @@ const std::vector expectedTasks{ - "'info'" - "--shm-allocation" - "'rbtree_best_fit'" + - "--shm-metadata-msg-size" + - "'0'" - "--shm-mlock-segment" - "'false'" - "--shm-mlock-segment-on-creation" @@ -314,6 +320,8 @@ const std::vector expectedTasks{ - "'0'" - "--shm-zero-segment" - "'false'" + - "--signposts" + - "''" - "--stacktrace-on-signal" - "'simple'" - "--timeframes-rate-limit" @@ -397,6 +405,8 @@ const std::vector expectedTasks{ - "'info'" - "--shm-allocation" - "'rbtree_best_fit'" + - "--shm-metadata-msg-size" + - "'0'" - "--shm-mlock-segment" - "'false'" - "--shm-mlock-segment-on-creation" @@ -407,6 +417,8 @@ const std::vector expectedTasks{ - "'0'" - "--shm-zero-segment" - "'false'" + - "--signposts" + - "''" - "--stacktrace-on-signal" - "'simple'" - "--timeframes-rate-limit" @@ -487,6 +499,8 @@ const std::vector expectedTasks{ - "'info'" - "--shm-allocation" - "'rbtree_best_fit'" + - "--shm-metadata-msg-size" + - "'0'" - "--shm-mlock-segment" - "'false'" - "--shm-mlock-segment-on-creation" @@ -497,6 +511,8 @@ const std::vector expectedTasks{ - "'0'" - "--shm-zero-segment" - "'false'" + - "--signposts" + - "''" - "--stacktrace-on-signal" - "'simple'" - "--timeframes-rate-limit" diff --git a/Framework/Foundation/include/Framework/FunctionalHelpers.h b/Framework/Foundation/include/Framework/FunctionalHelpers.h index 7e060e8816e3b..12470a7eb0f1c 100644 --- a/Framework/Foundation/include/Framework/FunctionalHelpers.h +++ b/Framework/Foundation/include/Framework/FunctionalHelpers.h @@ -25,6 +25,16 @@ struct memfun_type { }; } // namespace +template +struct StringLiteral { + constexpr StringLiteral(const char (&str)[N]) + { + std::copy_n(str, N, value); + } + + char value[N]; +}; + /// Type helper to hold metadata about a lambda or a class /// method. template diff --git a/Framework/Foundation/include/Framework/Signpost.h b/Framework/Foundation/include/Framework/Signpost.h index 9ea8aea1192a9..1ddaaa6fb793f 100644 --- a/Framework/Foundation/include/Framework/Signpost.h +++ b/Framework/Foundation/include/Framework/Signpost.h @@ -26,9 +26,8 @@ struct o2_log_handle_t { // Helper function which replaces engineering types with a printf // compatible format string. -// FIXME: make this consteval when available in C++20 template -constexpr auto remove_engineering_type(char const (&src)[N]) +consteval auto remove_engineering_type(char const (&src)[N]) { std::array res = {}; // do whatever string manipulation you want in res. @@ -501,7 +500,7 @@ void o2_debug_log_set_stacktrace(_o2_log_t* log, int stacktrace) } else if (O2_BUILTIN_UNLIKELY(private_o2_log_##log->stacktrace)) { \ _o2_signpost_event_emit(private_o2_log_##log, id, name, remove_engineering_type(format).data(), ##__VA_ARGS__); \ } else { \ - O2_LOG_MACRO_RAW(info, format, ##__VA_ARGS__); \ + O2_LOG_MACRO_RAW(info, remove_engineering_type(format).data(), ##__VA_ARGS__); \ } \ }) @@ -512,7 +511,7 @@ void o2_debug_log_set_stacktrace(_o2_log_t* log, int stacktrace) } else if (O2_BUILTIN_UNLIKELY(private_o2_log_##log->stacktrace)) { \ _o2_signpost_event_emit(private_o2_log_##log, id, name, remove_engineering_type(format).data(), ##__VA_ARGS__); \ } \ - O2_LOG_MACRO_RAW(error, format, ##__VA_ARGS__); \ + O2_LOG_MACRO_RAW(error, remove_engineering_type(format).data(), ##__VA_ARGS__); \ }) // Similar to the above, however it will also print a normal warning message regardless of the signpost being enabled or not. @@ -522,7 +521,7 @@ void o2_debug_log_set_stacktrace(_o2_log_t* log, int stacktrace) } else if (O2_BUILTIN_UNLIKELY(private_o2_log_##log->stacktrace)) { \ _o2_signpost_event_emit(private_o2_log_##log, id, name, remove_engineering_type(format).data(), ##__VA_ARGS__); \ } \ - O2_RAW_LOG_RAW(warn, ##__VA_ARGS__); \ + O2_LOG_MACRO_RAW(warn, remove_engineering_type(format).data(), ##__VA_ARGS__); \ }) #define O2_SIGNPOST_START(log, id, name, format, ...) \ diff --git a/Framework/GUISupport/src/FrameworkGUIDebugger.cxx b/Framework/GUISupport/src/FrameworkGUIDebugger.cxx index 005f7082d77b4..2fc8c7623c857 100644 --- a/Framework/GUISupport/src/FrameworkGUIDebugger.cxx +++ b/Framework/GUISupport/src/FrameworkGUIDebugger.cxx @@ -1216,22 +1216,22 @@ std::function getGUIDebugger(std::vector const& infos, void updateMousePos(float x, float y) { ImGuiIO& io = ImGui::GetIO(); - io.MousePos = ImVec2(x, y); + io.AddMousePosEvent(x, y); } void updateMouseButton(bool clicked) { ImGuiIO& io = ImGui::GetIO(); - io.MouseDown[0] = clicked; + io.AddMouseButtonEvent(0, clicked); } void updateMouseWheel(int direction) { ImGuiIO& io = ImGui::GetIO(); if (direction > 0) { - io.MouseWheel++; + io.AddMouseWheelEvent(0, 1.0); } else { - io.MouseWheel--; + io.AddMouseWheelEvent(0, -1.0); } } @@ -1241,16 +1241,52 @@ void updateWindowSize(int x, int y) io.DisplaySize = ImVec2(x, y); } -void keyDown(char key) +void keyEvent(char key, bool down) { ImGuiIO& io = ImGui::GetIO(); - io.KeysDown[io.KeyMap[(int)key]] = true; -} - -void keyUp(char key) -{ - ImGuiIO& io = ImGui::GetIO(); - io.KeysDown[io.KeyMap[(int)key]] = false; + switch (key) { + case 0: + io.AddKeyEvent(ImGuiKey_Tab, down); + break; + case 1: + io.AddKeyEvent(ImGuiKey_LeftArrow, down); + break; + case 2: + io.AddKeyEvent(ImGuiKey_RightArrow, down); + break; + case 3: + io.AddKeyEvent(ImGuiKey_UpArrow, down); + break; + case 4: + io.AddKeyEvent(ImGuiKey_DownArrow, down); + break; + case 5: + io.AddKeyEvent(ImGuiKey_PageUp, down); + break; + case 6: + io.AddKeyEvent(ImGuiKey_PageDown, down); + break; + case 7: + io.AddKeyEvent(ImGuiKey_Home, down); + break; + case 8: + io.AddKeyEvent(ImGuiKey_End, down); + break; + case 10: + io.AddKeyEvent(ImGuiKey_Delete, down); + break; + case 11: + io.AddKeyEvent(ImGuiKey_Backspace, down); + break; + case 13: + io.AddKeyEvent(ImGuiKey_Enter, down); + break; + case 14: + io.AddKeyEvent(ImGuiKey_Escape, down); + break; + default: + io.AddKeyEvent((ImGuiKey)key, down); + } } void charIn(char key) diff --git a/Framework/GUISupport/src/FrameworkGUIDebugger.h b/Framework/GUISupport/src/FrameworkGUIDebugger.h index 5de5e350ddf8d..d352f9899353b 100644 --- a/Framework/GUISupport/src/FrameworkGUIDebugger.h +++ b/Framework/GUISupport/src/FrameworkGUIDebugger.h @@ -43,8 +43,7 @@ void updateMousePos(float x, float y); void updateMouseButton(bool clicked); void updateMouseWheel(int direction); void updateWindowSize(int x, int y); -void keyDown(char key); -void keyUp(char key); +void keyEvent(char key, bool pressed); void charIn(char key); } // namespace gui diff --git a/Framework/GUISupport/src/Plugin.cxx b/Framework/GUISupport/src/Plugin.cxx index 7a356f6e55d9b..17d13fbf56cd3 100644 --- a/Framework/GUISupport/src/Plugin.cxx +++ b/Framework/GUISupport/src/Plugin.cxx @@ -57,13 +57,9 @@ struct ImGUIDebugGUI : o2::framework::DebugGUI { { o2::framework::gui::updateWindowSize(x, y); } - void keyDown(char key) override + void keyEvent(char key, bool down) override { - o2::framework::gui::keyDown(key); - } - void keyUp(char key) override - { - o2::framework::gui::keyUp(key); + o2::framework::gui::keyEvent(key, down); } void charIn(char key) override { diff --git a/Framework/TestWorkflows/CMakeLists.txt b/Framework/TestWorkflows/CMakeLists.txt index 8aaf01ff55dcf..bfbdcfc6f169b 100644 --- a/Framework/TestWorkflows/CMakeLists.txt +++ b/Framework/TestWorkflows/CMakeLists.txt @@ -127,6 +127,11 @@ o2_add_dpl_workflow(test-ccdb-fetcher PUBLIC_LINK_LIBRARIES O2::DataFormatsTOF O2::Framework COMPONENT_NAME TestWorkflows) +o2_add_executable(fairmq-header-size-test + SOURCES src/o2FairMQHeaderSizeTest.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + COMPONENT_NAME TestWorkflows) + add_executable(o2-test-deadlock src/o2DeadlockReproducer.cxx) target_link_libraries(o2-test-deadlock PUBLIC FairMQ::FairMQ) add_test(NAME o2-test-deadlock COMMAND o2-test-deadlock --channel-config "name=data,type=sub,method=bind,address=ipc://127.0.0.1,rateLogging=0" --id foo --transport zeromq --control static) diff --git a/Framework/TestWorkflows/src/o2AnalysisTaskExample.cxx b/Framework/TestWorkflows/src/o2AnalysisTaskExample.cxx index 9913b0e7c560e..24cb592c445c9 100644 --- a/Framework/TestWorkflows/src/o2AnalysisTaskExample.cxx +++ b/Framework/TestWorkflows/src/o2AnalysisTaskExample.cxx @@ -8,6 +8,7 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. +#include "Framework/AnalysisDataModel.h" #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" diff --git a/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx b/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx index c0da7a24c1a90..05bf3aabaceab 100644 --- a/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx +++ b/Framework/TestWorkflows/src/o2AnalysisWorkflow.cxx @@ -15,8 +15,8 @@ #include "Framework/runDataProcessing.h" #include "Framework/AnalysisTask.h" +#include "Framework/AnalysisDataModel.h" #include -#include using namespace o2; using namespace o2::framework; diff --git a/Framework/TestWorkflows/src/o2FairMQHeaderSizeTest.cxx b/Framework/TestWorkflows/src/o2FairMQHeaderSizeTest.cxx new file mode 100644 index 0000000000000..7471da547297a --- /dev/null +++ b/Framework/TestWorkflows/src/o2FairMQHeaderSizeTest.cxx @@ -0,0 +1,96 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file o2FairMQHeaderSizeTest.cxx +/// \brief Just a simple workflow to test how much messages can be stored internally, +/// when nothing is consumed. Used for tuning parameter shm-message-metadata-size. +/// +/// \author Michal Tichak, michal.tichak@cern.ch + +#include "Framework/ConfigParamSpec.h" +#include "Framework/ControlService.h" +#include "Framework/CallbackService.h" +#include "Framework/EndOfStreamContext.h" +#include "Framework/DeviceSpec.h" +#include "Framework/ControlService.h" +#include "Framework/runDataProcessing.h" + +#include +#include +#include +#include + +using namespace o2::framework; + +static std::random_device rd; +static std::mt19937 gen(rd()); + +std::string random_string(size_t length) +{ + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + std::uniform_int_distribution<> dis(0, sizeof(alphanum) - 2); + + std::string randomString; + randomString.reserve(length); + + for (int i = 0; i < length; ++i) { + randomString.push_back(alphanum[dis(gen)]); + } + + return randomString; +} + +std::string filename() +{ + std::stringstream ss; + ss << "messages_count_" << random_string(10) << ".data"; + return std::move(ss).str(); +} + +WorkflowSpec defineDataProcessing(ConfigContext const& specs) +{ + return WorkflowSpec{ + {"A", + Inputs{}, + {OutputSpec{{"a"}, "TST", "A"}}, + AlgorithmSpec{ + [numberOfMessages = 0, filename = filename()](ProcessingContext& ctx) mutable { + using namespace std::chrono; + ++numberOfMessages; + // LOG(info) << "Generating message #" << ++numberOfMessages; + + { + auto file = std::ofstream(filename, std::ios_base::out | std::ios_base::trunc); + // file << duration_cast(system_clock::now().time_since_epoch()).count() << "," << numberOfMessages << "\n"; + file << numberOfMessages; + } + + auto& aData = ctx.outputs().make(Output{"TST", "A", 0}, 1); + aData[0] = 1; + }}}, + {"B", + {InputSpec{"x", "TST", "A"}}, + Outputs{}, + AlgorithmSpec{[](InitContext& ic) { + return [](ProcessingContext& ctx) { + while (true) { + std::this_thread::sleep_for(std::chrono::milliseconds{100}); + } + // auto& data = ctx.inputs().get("x"); + // LOG(info) << "Reading message: " << data; + }; + }}}, + }; +} diff --git a/Framework/Utils/include/DPLUtils/RootTreeReader.h b/Framework/Utils/include/DPLUtils/RootTreeReader.h index 109d79f9fad78..bc743d713b520 100644 --- a/Framework/Utils/include/DPLUtils/RootTreeReader.h +++ b/Framework/Utils/include/DPLUtils/RootTreeReader.h @@ -321,7 +321,7 @@ class GenericRootTreeReader mSizeBranch->GetEntry(entry); auto* buffer = reinterpret_cast(data); if (buffer->size() == datasize) { - LOG(info) << "branch " << mName << ": publishing binary chunk of " << datasize << " bytes(s)"; + LOG(debug) << "branch " << mName << ": publishing binary chunk of " << datasize << " bytes(s)"; snapshot(mKey, std::move(*buffer)); } else { LOG(error) << "branch " << mName << ": inconsitent size of binary chunk " diff --git a/GPU/Common/GPUCommonDef.h b/GPU/Common/GPUCommonDef.h index 51ff8b4800de5..dac0a9695cdea 100644 --- a/GPU/Common/GPUCommonDef.h +++ b/GPU/Common/GPUCommonDef.h @@ -40,17 +40,17 @@ #endif #endif -#if !(defined(__CINT__) || defined(__ROOTCINT__) || defined(__CLING__) || defined(__ROOTCLING__) || defined(G__ROOT)) //No GPU code for ROOT +#if !(defined(__CINT__) || defined(__ROOTCINT__) || defined(__CLING__) || defined(__ROOTCLING__) || defined(G__ROOT)) // No GPU code for ROOT #if defined(__CUDACC__) || defined(__OPENCL__) || defined(__HIPCC__) || defined(__OPENCL_HOST__) - #define GPUCA_GPUCODE //Compiled by GPU compiler + #define GPUCA_GPUCODE // Compiled by GPU compiler #endif #if defined(__CUDA_ARCH__) || defined(__OPENCL__) || defined(__HIP_DEVICE_COMPILE__) - #define GPUCA_GPUCODE_DEVICE //Executed on device + #define GPUCA_GPUCODE_DEVICE // Executed on device #endif #endif -//Definitions for C++11 features not supported by CINT / OpenCL +// Definitions for C++11 features not supported by CINT / OpenCL #ifdef GPUCA_NOCOMPAT #define CON_DELETE = delete #define CON_DEFAULT = default @@ -72,8 +72,8 @@ #define VOLATILE volatile #endif -//Set AliRoot / O2 namespace -#if defined(GPUCA_STANDALONE) || (defined(GPUCA_O2_LIB) && !defined(GPUCA_O2_INTERFACE)) || defined(GPUCA_ALIROOT_LIB) || defined(GPUCA_GPULIBRARY) || defined (GPUCA_GPUCODE) +// Set AliRoot / O2 namespace +#if defined(GPUCA_STANDALONE) || (defined(GPUCA_O2_LIB) && !defined(GPUCA_O2_INTERFACE)) || defined(GPUCA_ALIROOT_LIB) || defined (GPUCA_GPUCODE) #define GPUCA_ALIGPUCODE #endif #ifdef GPUCA_ALIROOT_LIB @@ -98,7 +98,7 @@ #endif -//API Definitions for GPU Compilation +// API Definitions for GPU Compilation #include "GPUCommonDefAPI.h" // clang-format on diff --git a/GPU/Common/GPUCommonLogger.h b/GPU/Common/GPUCommonLogger.h index 0c07ec7049140..6818564c048db 100644 --- a/GPU/Common/GPUCommonLogger.h +++ b/GPU/Common/GPUCommonLogger.h @@ -30,7 +30,7 @@ struct DummyLogger { } // namespace o2::gpu::detail #endif -#if defined(__OPENCL__) +#if defined(__OPENCL__) || (defined(GPUCA_GPUCODE_DEVICE) && !defined(GPUCA_GPU_DEBUG_PRINT)) #define LOG(...) o2::gpu::detail::DummyLogger() #define LOGF(...) #define LOGP(...) diff --git a/GPU/Common/GPUCommonMath.h b/GPU/Common/GPUCommonMath.h index 439d198f8bcb4..cf15d9ee0409b 100644 --- a/GPU/Common/GPUCommonMath.h +++ b/GPU/Common/GPUCommonMath.h @@ -71,10 +71,11 @@ class GPUCommonMath GPUd() static float Log(float x); GPUd() static float Exp(float x); GPUhdni() static float Copysign(float x, float y); - GPUd() static float TwoPi() { return 6.2831853f; } - GPUd() static float Pi() { return 3.1415927f; } + GPUd() static CONSTEXPR float TwoPi() { return 6.2831853f; } + GPUd() static CONSTEXPR float Pi() { return 3.1415927f; } GPUd() static float Round(float x); GPUd() static float Floor(float x); + GPUd() static unsigned int Float2UIntReint(const float& x); GPUd() static unsigned int Float2UIntRn(float x); GPUd() static int Float2IntRn(float x); GPUd() static float Modf(float x, float y); @@ -207,6 +208,18 @@ GPUdi() float2 GPUCommonMath::MakeFloat2(float x, float y) } GPUdi() float GPUCommonMath::Modf(float x, float y) { return CHOICE(fmodf(x, y), fmodf(x, y), fmod(x, y)); } + +GPUdi() unsigned int GPUCommonMath::Float2UIntReint(const float& x) +{ +#if defined(GPUCA_GPUCODE_DEVICE) && (defined(__CUDACC__) || defined(__HIPCC__)) + return __float_as_uint(x); +#elif defined(GPUCA_GPUCODE_DEVICE) && (defined(__OPENCL__) || defined(__OPENCLCPP__)) + return as_uint(x); +#else + return reinterpret_cast(x); +#endif +} + GPUdi() unsigned int GPUCommonMath::Float2UIntRn(float x) { return (unsigned int)(int)(x + 0.5f); } GPUdi() float GPUCommonMath::Floor(float x) { return CHOICE(floorf(x), floorf(x), floor(x)); } diff --git a/GPU/Common/GPUCommonRtypes.h b/GPU/Common/GPUCommonRtypes.h index bb6cc73ed9419..be1923d9b0e8b 100644 --- a/GPU/Common/GPUCommonRtypes.h +++ b/GPU/Common/GPUCommonRtypes.h @@ -15,7 +15,9 @@ #ifndef GPUCOMMONRTYPES_H #define GPUCOMMONRTYPES_H -#if defined(GPUCA_STANDALONE) || (defined(GPUCA_O2_LIB) && !defined(GPUCA_O2_INTERFACE)) || defined(GPUCA_GPULIBRARY) // clang-format off +#include "GPUCommonDef.h" + +#if defined(GPUCA_STANDALONE) || (defined(GPUCA_O2_LIB) && !defined(GPUCA_O2_INTERFACE)) || defined(GPUCA_GPUCODE) // clang-format off #if !defined(ROOT_Rtypes) && !defined(__CLING__) #define GPUCOMMONRTYPES_H_ACTIVE #define ClassDef(name,id) diff --git a/GPU/Common/GPUCommonTypeTraits.h b/GPU/Common/GPUCommonTypeTraits.h index a44a277368491..2ae524f8d1c76 100644 --- a/GPU/Common/GPUCommonTypeTraits.h +++ b/GPU/Common/GPUCommonTypeTraits.h @@ -15,6 +15,8 @@ #ifndef GPUCOMMONTYPETRAITS_H #define GPUCOMMONTYPETRAITS_H +#include "GPUCommonDef.h" + #if !defined(GPUCA_GPUCODE_DEVICE) || defined(__CUDACC__) || defined(__HIPCC__) #ifndef GPUCA_GPUCODE_COMPILEKERNELS #include diff --git a/GPU/GPUTracking/Base/GPUConstantMem.h b/GPU/GPUTracking/Base/GPUConstantMem.h index d18e7863e2001..17e6268764606 100644 --- a/GPU/GPUTracking/Base/GPUConstantMem.h +++ b/GPU/GPUTracking/Base/GPUConstantMem.h @@ -21,11 +21,9 @@ #include "GPUErrors.h" // Dummies for stuff not supported in legacy code (ROOT 5 / OPENCL1.2) -#if defined(GPUCA_NOCOMPAT_ALLCINT) && (!defined(GPUCA_GPULIBRARY) || !defined(GPUCA_ALIROOT_LIB)) +#if defined(GPUCA_NOCOMPAT_ALLCINT) #include "GPUTPCGMMerger.h" -#include "GPUTRDTracker.h" #else -#include "GPUTRDDef.h" namespace GPUCA_NAMESPACE { namespace gpu @@ -33,6 +31,17 @@ namespace gpu class GPUTPCGMMerger { }; +} // namespace gpu +} // namespace GPUCA_NAMESPACE +#endif +#if defined(GPUCA_NOCOMPAT_ALLCINT) && (!defined(GPUCA_GPUCODE) || !defined(GPUCA_ALIROOT_LIB)) +#include "GPUTRDTracker.h" +#else +#include "GPUTRDDef.h" +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ template class GPUTRDTracker_t { @@ -43,7 +52,7 @@ class GPUTRDTracker_t #endif // Dummies for stuff not suppored in legacy code, or for what requires O2 headers while not available -#if defined(GPUCA_NOCOMPAT_ALLCINT) && (!defined(GPUCA_GPULIBRARY) || !defined(GPUCA_ALIROOT_LIB)) && defined(GPUCA_HAVE_O2HEADERS) +#if defined(GPUCA_NOCOMPAT_ALLCINT) && (!defined(GPUCA_GPUCODE) || !defined(GPUCA_ALIROOT_LIB)) && defined(GPUCA_HAVE_O2HEADERS) #include "GPUTPCConvert.h" #include "GPUTPCCompression.h" #include "GPUTPCDecompression.h" diff --git a/GPU/GPUTracking/Base/GPUParam.cxx b/GPU/GPUTracking/Base/GPUParam.cxx index a516f974a1cdc..e7a1232e1c070 100644 --- a/GPU/GPUTracking/Base/GPUParam.cxx +++ b/GPU/GPUTracking/Base/GPUParam.cxx @@ -42,6 +42,7 @@ void GPUParam::SetDefaults(float solenoidBz) new (&tpcGeometry) GPUTPCGeometry; new (&rec) GPUSettingsRec; occupancyMap = nullptr; + occupancyTotal = 0; #ifdef GPUCA_TPC_GEOMETRY_O2 const float kErrorsY[4] = {0.06, 0.24, 0.12, 0.1}; @@ -90,9 +91,7 @@ void GPUParam::SetDefaults(float solenoidBz) #endif par.dAlpha = 0.349066f; - bzkG = solenoidBz; - constBz = bzkG * GPUCA_NAMESPACE::gpu::gpu_common_constants::kCLight; - qptB5Scaler = CAMath::Abs(bzkG) > 0.1f ? CAMath::Abs(bzkG) / 5.006680f : 1.f; + UpdateBzOnly(solenoidBz); par.dodEdx = 0; constexpr float plusZmin = 0.0529937; @@ -124,29 +123,19 @@ void GPUParam::SetDefaults(float solenoidBz) par.debugLevel = 0; par.resetTimers = false; par.earlyTpcTransform = false; - - polynomialField.Reset(); // set very wrong initial value in order to see if the field was not properly initialised - GPUTPCGMPolynomialFieldManager::GetPolynomialField(bzkG, polynomialField); } void GPUParam::UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p, const GPURecoStepConfiguration* w) { if (g) { - bzkG = g->solenoidBz; - constBz = bzkG * GPUCA_NAMESPACE::gpu::gpu_common_constants::kCLight; + UpdateBzOnly(g->solenoidBzNominalGPU); par.assumeConstantBz = g->constBz; par.toyMCEventsFlag = g->homemadeEvents; par.continuousTracking = g->continuousMaxTimeBin != 0; par.continuousMaxTimeBin = g->continuousMaxTimeBin == -1 ? GPUSettings::TPC_MAX_TF_TIME_BIN : g->continuousMaxTimeBin; - polynomialField.Reset(); - if (par.assumeConstantBz) { - GPUTPCGMPolynomialFieldManager::GetPolynomialField(GPUTPCGMPolynomialFieldManager::kUniform, bzkG, polynomialField); - } else { - GPUTPCGMPolynomialFieldManager::GetPolynomialField(bzkG, polynomialField); - } } par.earlyTpcTransform = rec.tpc.forceEarlyTransform == -1 ? (!par.continuousTracking) : rec.tpc.forceEarlyTransform; - qptB5Scaler = CAMath::Abs(bzkG) > 0.1f ? CAMath::Abs(bzkG) / 5.006680f : 1.f; + qptB5Scaler = CAMath::Abs(bzkG) > 0.1f ? CAMath::Abs(bzkG) / 5.006680f : 1.f; // Repeat here, since passing in g is optional if (p) { par.debugLevel = p->debugLevel; par.resetTimers = p->resetTimers; @@ -160,9 +149,22 @@ void GPUParam::UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessi } } +void GPUParam::UpdateBzOnly(float newSolenoidBz) +{ + bzkG = newSolenoidBz; + bzCLight = bzkG * GPUCA_NAMESPACE::gpu::gpu_common_constants::kCLight; + polynomialField.Reset(); + if (par.assumeConstantBz) { + GPUTPCGMPolynomialFieldManager::GetPolynomialField(GPUTPCGMPolynomialFieldManager::kUniform, bzkG, polynomialField); + } else { + GPUTPCGMPolynomialFieldManager::GetPolynomialField(bzkG, polynomialField); + } + qptB5Scaler = CAMath::Abs(bzkG) > 0.1f ? CAMath::Abs(bzkG) / 5.006680f : 1.f; +} + void GPUParam::SetDefaults(const GPUSettingsGRP* g, const GPUSettingsRec* r, const GPUSettingsProcessing* p, const GPURecoStepConfiguration* w) { - SetDefaults(g->solenoidBz); + SetDefaults(g->solenoidBzNominalGPU); if (r) { rec = *r; if (rec.fitPropagateBzOnly == -1) { @@ -182,7 +184,7 @@ void GPUParam::UpdateRun3ClusterErrors(const float* yErrorParam, const float* zE ParamErrors[yz][rowType][0] = param[0] * param[0]; ParamErrors[yz][rowType][1] = param[1] * param[1] * tpcGeometry.PadHeightByRegion(regionMap[rowType]); ParamErrors[yz][rowType][2] = param[2] * param[2] / tpcGeometry.TPCLength() / tpcGeometry.PadHeightByRegion(regionMap[rowType]); - ParamErrors[yz][rowType][3] = param[3] * param[3]; + ParamErrors[yz][rowType][3] = param[3] * param[3] * rec.tpc.clusterErrorOccupancyScaler * rec.tpc.clusterErrorOccupancyScaler; } } #endif @@ -216,7 +218,7 @@ void GPUParam::LoadClusterErrors(bool Print) for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { for (int k = 0; k < 4; k++) { - ParamErrorsSeeding0[i][j][k] = clparam->GetParamErrorsSeeding0(i, j, k); + ParamErrorsSeeding0[i][j][k] = clparam->GetParamRMS0(i, j, k); } } } @@ -274,29 +276,10 @@ std::string GPUParamRTC::generateRTCCode(const GPUParam& param, bool useConstexp { return "#ifndef GPUCA_GPUCODE_DEVICE\n" "#include \n" + "#include \n" "#endif\n" "namespace o2::gpu { class GPUDisplayFrontendInterface; }\n" + qConfigPrintRtc(std::make_tuple(¶m.rec.tpc, ¶m.rec.trd, ¶m.rec, ¶m.par), useConstexpr); } static_assert(sizeof(GPUCA_NAMESPACE::gpu::GPUParam) == sizeof(GPUCA_NAMESPACE::gpu::GPUParamRTC), "RTC param size mismatch"); - -o2::base::Propagator* GPUParam::GetDefaultO2Propagator(bool useGPUField) const -{ - o2::base::Propagator* prop = nullptr; -#ifdef GPUCA_HAVE_O2HEADERS -#ifdef GPUCA_STANDALONE - if (useGPUField == false) { - throw std::runtime_error("o2 propagator withouzt gpu field unsupported"); - } -#endif - prop = o2::base::Propagator::Instance(useGPUField); - if (useGPUField) { - prop->setGPUField(&polynomialField); - prop->setBz(polynomialField.GetNominalBz()); - } -#else - throw std::runtime_error("o2 propagator unsupported"); -#endif - return prop; -} diff --git a/GPU/GPUTracking/Base/GPUParam.h b/GPU/GPUTracking/Base/GPUParam.h index ff27e5d1084be..852f52bf68862 100644 --- a/GPU/GPUTracking/Base/GPUParam.h +++ b/GPU/GPUTracking/Base/GPUParam.h @@ -54,12 +54,13 @@ struct GPUParam_t { S par; float bzkG; - float constBz; + float bzCLight; float qptB5Scaler; GPUTPCGeometry tpcGeometry; // TPC Geometry GPUTPCGMPolynomialField polynomialField; // Polynomial approx. of magnetic field for TPC GM const unsigned int* occupancyMap; // Ptr to TPC occupancy map + unsigned int occupancyTotal; // Total occupancy in the TPC (nCl / nHbf) GPUParamSlice SliceParam[GPUCA_NSLICES]; @@ -81,8 +82,8 @@ struct GPUParam : public internal::GPUParam_t void SetDefaults(float solenoidBz); void SetDefaults(const GPUSettingsGRP* g, const GPUSettingsRec* r = nullptr, const GPUSettingsProcessing* p = nullptr, const GPURecoStepConfiguration* w = nullptr); void UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p = nullptr, const GPURecoStepConfiguration* w = nullptr); + void UpdateBzOnly(float newSolenoidBz); void LoadClusterErrors(bool Print = 0); - o2::base::Propagator* GetDefaultO2Propagator(bool useGPUField = false) const; void UpdateRun3ClusterErrors(const float* yErrorParam, const float* zErrorParam); #endif @@ -96,19 +97,20 @@ struct GPUParam : public internal::GPUParam_t } return 0.174533f + par.dAlpha * iSlice; } - GPUd() float GetClusterErrorSeeding(int yz, int type, float zDiff, float angle2) const; - GPUd() void GetClusterErrorsSeeding2(char sector, int row, float z, float sinPhi, float DzDs, float time, float avgInvCharge, float invCharge, float& ErrY2, float& ErrZ2) const; - GPUd() float GetSystematicClusterErrorIFC2(float x, float y, float z, bool sideC) const; + GPUd() float GetClusterErrorSeeding(int yz, int type, float zDiff, float angle2, float unscaledMult) const; + GPUd() void GetClusterErrorsSeeding2(char sector, int row, float z, float sinPhi, float DzDs, float time, float& ErrY2, float& ErrZ2) const; + GPUd() float GetSystematicClusterErrorIFC2(float trackX, float trackY, float z, bool sideC) const; + GPUd() float GetSystematicClusterErrorC122(float trackX, float trackY, char sector) const; - GPUd() float GetClusterError2(int yz, int type, float zDiff, float angle2, float scaledMult, float scaledAvgInvCharge, float scaledInvCharge) const; + GPUd() float GetClusterError2(int yz, int type, float zDiff, float angle2, float unscaledMult, float scaledAvgInvCharge, float scaledInvCharge) const; GPUd() void GetClusterErrors2(char sector, int row, float z, float sinPhi, float DzDs, float time, float avgInvCharge, float invCharge, float& ErrY2, float& ErrZ2) const; GPUd() void UpdateClusterError2ByState(short clusterState, float& ErrY2, float& ErrZ2) const; - GPUd() float GetScaledMult(float time) const; + GPUd() float GetUnscaledMult(float time) const; GPUd() void Slice2Global(int iSlice, float x, float y, float z, float* X, float* Y, float* Z) const; GPUd() void Global2Slice(int iSlice, float x, float y, float z, float* X, float* Y, float* Z) const; - GPUd() bool rejectEdgeClusterByY(float uncorrectedY, int iRow) const; + GPUd() bool rejectEdgeClusterByY(float uncorrectedY, int iRow, float trackSigmaY) const; }; #endif diff --git a/GPU/GPUTracking/Base/GPUParam.inc b/GPU/GPUTracking/Base/GPUParam.inc index 433ed873172d5..f9e3059a1afce 100644 --- a/GPU/GPUTracking/Base/GPUParam.inc +++ b/GPU/GPUTracking/Base/GPUParam.inc @@ -47,16 +47,37 @@ GPUdi() void MEM_LG(GPUParam)::Global2Slice(int iSlice, float X, float Y, float #ifdef GPUCA_TPC_GEOMETRY_O2 MEM_CLASS_PRE() -GPUdi() void MEM_LG(GPUParam)::GetClusterErrorsSeeding2(char sector, int iRow, float z, float sinPhi, float DzDs, float time, float avgInvCharge, float invCharge, float& ErrY2, float& ErrZ2) const +GPUdi() void MEM_LG(GPUParam)::GetClusterErrorsSeeding2(char sector, int iRow, float z, float sinPhi, float DzDs, float time, float& ErrY2, float& ErrZ2) const { - GetClusterErrors2(sector, iRow, z, sinPhi, DzDs, time, avgInvCharge, invCharge, ErrY2, ErrZ2); + const int rowType = tpcGeometry.GetROC(iRow); + z = CAMath::Abs(tpcGeometry.TPCLength() - CAMath::Abs(z)); + const float s2 = CAMath::Min(sinPhi * sinPhi, 0.95f * 0.95f); + const float sec2 = 1.f / (1.f - s2); + const float angleY2 = s2 * sec2; // dy/dx + const float angleZ2 = DzDs * DzDs * sec2; // dz/dx + + const float unscaledMult = time >= 0.f ? GetUnscaledMult(time) / tpcGeometry.Row2X(iRow) : 0.f; + + ErrY2 = GetClusterErrorSeeding(0, rowType, z, angleY2, unscaledMult); // Returns Err2 + ErrZ2 = GetClusterErrorSeeding(1, rowType, z, angleZ2, unscaledMult); // Returns Err2 +} + +MEM_CLASS_PRE() +GPUdi() float MEM_LG(GPUParam)::GetClusterErrorSeeding(int yz, int type, float zDiff, float angle2, float unscaledMult) const // Note, returns Err2 despite the name not containing 2 +{ + MakeType(const float*) c = ParamErrors[yz][type]; // Note: c[0] = p[0]^2, c[1] = p[1]^2 * padHeight, c[2] = p[2]^2 / tpcLength / padHeight, c[3] = p[3]^2 * clusterErrorOccupancyScaler^2 + float v = c[0] + c[1] * angle2 + c[2] * zDiff + c[3] * (unscaledMult * unscaledMult); + v = CAMath::Abs(v); + v *= yz ? rec.tpc.clusterError2CorrectionZ : rec.tpc.clusterError2CorrectionY; + v += yz ? rec.tpc.clusterError2AdditionalZSeeding : rec.tpc.clusterError2AdditionalYSeeding; + return v; } MEM_CLASS_PRE() -GPUdi() float MEM_LG(GPUParam)::GetClusterError2(int yz, int type, float zDiff, float angle2, float scaledMult, float scaledInvAvgCharge, float scaledInvCharge) const +GPUdi() float MEM_LG(GPUParam)::GetClusterError2(int yz, int type, float zDiff, float angle2, float unscaledMult, float scaledInvAvgCharge, float scaledInvCharge) const { - MakeType(const float*) c = ParamErrors[yz][type]; // Note: c[0] = p[0]^2, c[1] = p[1]^2 * padHeight, c[2] = p[2]^2 / tpcLength / padHeight, c[3] = p[3]^2 - float v = c[0] + c[1] * angle2 * scaledInvAvgCharge + c[2] * zDiff * scaledInvCharge + c[3] * (scaledMult * scaledMult) * (scaledInvAvgCharge * scaledInvAvgCharge); + MakeType(const float*) c = ParamErrors[yz][type]; // Note: c[0] = p[0]^2, c[1] = p[1]^2 * padHeight, c[2] = p[2]^2 / tpcLength / padHeight, c[3] = p[3]^2 * clusterErrorOccupancyScaler^2 + float v = c[0] + c[1] * angle2 * scaledInvAvgCharge + c[2] * zDiff * scaledInvCharge + c[3] * (unscaledMult * unscaledMult) * (scaledInvAvgCharge * scaledInvAvgCharge); v = CAMath::Abs(v); v *= yz ? rec.tpc.clusterError2CorrectionZ : rec.tpc.clusterError2CorrectionY; v += yz ? rec.tpc.clusterError2AdditionalZ : rec.tpc.clusterError2AdditionalY; @@ -97,10 +118,23 @@ GPUdi() float MEM_LG(GPUParam)::GetSystematicClusterErrorIFC2(float x, float y, return sysErr; } +MEM_CLASS_PRE() +GPUdi() float MEM_LG(GPUParam)::GetSystematicClusterErrorC122(float x, float y, char sector) const +{ + const float dx = x - 83.f; + if (dx > occupancyTotal * rec.tpc.sysClusErrorC12Box) { + return 0.f; + } + CONSTEXPR float dEdgeInv = 18.f / CAMath::Pi(); + const float dy = (sector == (GPUCA_NSLICES / 2 + 1) ? 0.5f : -0.5f) * (y / x) * dEdgeInv + 0.5f; + const float errC12 = rec.tpc.sysClusErrorC12Norm * occupancyTotal * dy; + return errC12 * errC12; +} + #else // GPUCA_TPC_GEOMETRY_O2 MEM_CLASS_PRE() -GPUdi() float MEM_LG(GPUParam)::GetClusterErrorSeeding(int yz, int type, float zDiff, float angle2) const +GPUdi() float MEM_LG(GPUParam)::GetClusterErrorSeeding(int yz, int type, float zDiff, float angle2, float scaledMult) const { MakeType(const float*) c = ParamErrorsSeeding0[yz][type]; float v = c[0] + c[1] * zDiff + c[2] * angle2; @@ -109,26 +143,23 @@ GPUdi() float MEM_LG(GPUParam)::GetClusterErrorSeeding(int yz, int type, float z } MEM_CLASS_PRE() -GPUdi() void MEM_LG(GPUParam)::GetClusterErrorsSeeding2(char sector, int iRow, float z, float sinPhi, float DzDs, float time, float avgInvCharge, float invCharge, float& ErrY2, float& ErrZ2) const +GPUdi() void MEM_LG(GPUParam)::GetClusterErrorsSeeding2(char sector, int iRow, float z, float sinPhi, float DzDs, float time, float& ErrY2, float& ErrZ2) const { int rowType = tpcGeometry.GetROC(iRow); z = CAMath::Abs(tpcGeometry.TPCLength() - CAMath::Abs(z)); - float s2 = sinPhi * sinPhi; - if (s2 > 0.95f * 0.95f) { - s2 = 0.95f * 0.95f; - } + const float s2 = CAMath::Min(sinPhi * sinPhi, 0.95f * 0.95f); float sec2 = 1.f / (1.f - s2); float angleY2 = s2 * sec2; // dy/dx float angleZ2 = DzDs * DzDs * sec2; // dz/dx - ErrY2 = GetClusterErrorSeeding(0, rowType, z, angleY2); - ErrZ2 = GetClusterErrorSeeding(1, rowType, z, angleZ2); + ErrY2 = GetClusterErrorSeeding(0, rowType, z, angleY2, 0.f); + ErrZ2 = GetClusterErrorSeeding(1, rowType, z, angleZ2, 0.f); ErrY2 = ErrY2 * ErrY2 * rec.tpc.clusterError2CorrectionY + rec.tpc.clusterError2AdditionalY; ErrZ2 = ErrZ2 * ErrZ2 * rec.tpc.clusterError2CorrectionZ + rec.tpc.clusterError2AdditionalZ; } MEM_CLASS_PRE() -GPUdi() float MEM_LG(GPUParam)::GetClusterError2(int yz, int type, float zDiff, float angle2, float time, float avgInvCharge, float invCharge) const +GPUdi() float MEM_LG(GPUParam)::GetClusterError2(int yz, int type, float zDiff, float angle2, float unscaledMult, float avgInvCharge, float invCharge) const { MakeType(const float*) c = ParamS0Par[yz][type]; float v = c[0] + c[1] * zDiff + c[2] * angle2 + c[3] * zDiff * zDiff + c[4] * angle2 * angle2 + c[5] * zDiff * angle2; @@ -142,7 +173,13 @@ GPUdi() float MEM_LG(GPUParam)::GetClusterError2(int yz, int type, float zDiff, } MEM_CLASS_PRE() -GPUdi() float MEM_LG(GPUParam)::GetSystematicClusterErrorIFC2(float x, float y, float z, bool sideC) const +GPUdi() float MEM_LG(GPUParam)::GetSystematicClusterErrorIFC2(float trackX, float trackY, float z, bool sideC) const +{ + return 0; +} + +MEM_CLASS_PRE() +GPUdi() float MEM_LG(GPUParam)::GetSystematicClusterErrorC122(float trackX, float trackY, char sector) const { return 0; } @@ -152,23 +189,19 @@ GPUdi() float MEM_LG(GPUParam)::GetSystematicClusterErrorIFC2(float x, float y, MEM_CLASS_PRE() GPUdi() void MEM_LG(GPUParam)::GetClusterErrors2(char sector, int iRow, float z, float sinPhi, float DzDs, float time, float avgInvCharge, float invCharge, float& ErrY2, float& ErrZ2) const { - // Calibrated cluster error from OCDB for Y and Z const int rowType = tpcGeometry.GetROC(iRow); z = CAMath::Abs(tpcGeometry.TPCLength() - CAMath::Abs(z)); - float s2 = sinPhi * sinPhi; - if (s2 > 0.95f * 0.95f) { - s2 = 0.95f * 0.95f; - } + const float s2 = CAMath::Min(sinPhi * sinPhi, 0.95f * 0.95f); const float sec2 = 1.f / (1.f - s2); const float angleY2 = s2 * sec2; // dy/dx const float angleZ2 = DzDs * DzDs * sec2; // dz/dx - const float mult = time >= 0.f ? GetScaledMult(time) / tpcGeometry.Row2X(iRow) : 0.f; + const float unscaledMult = time >= 0.f ? GetUnscaledMult(time) / tpcGeometry.Row2X(iRow) : 0.f; const float scaledInvAvgCharge = avgInvCharge * rec.tpc.clusterErrorChargeScaler > 0.f ? avgInvCharge * rec.tpc.clusterErrorChargeScaler : 1.f; const float scaledInvCharge = invCharge * rec.tpc.clusterErrorChargeScaler > 0.f ? invCharge * rec.tpc.clusterErrorChargeScaler : 1.f; - ErrY2 = GetClusterError2(0, rowType, z, angleY2, mult, scaledInvAvgCharge, scaledInvCharge); - ErrZ2 = GetClusterError2(1, rowType, z, angleZ2, mult, scaledInvAvgCharge, scaledInvCharge); + ErrY2 = GetClusterError2(0, rowType, z, angleY2, unscaledMult, scaledInvAvgCharge, scaledInvCharge); + ErrZ2 = GetClusterError2(1, rowType, z, angleZ2, unscaledMult, scaledInvAvgCharge, scaledInvCharge); } MEM_CLASS_PRE() @@ -193,23 +226,23 @@ GPUdi() void MEM_LG(GPUParam)::UpdateClusterError2ByState(short clusterState, fl } MEM_CLASS_PRE() -GPUdi() float MEM_LG(GPUParam)::GetScaledMult(float time) const +GPUdi() float MEM_LG(GPUParam)::GetUnscaledMult(float time) const { #if !defined(__OPENCL__) || defined(__OPENCLCPP__) if (!occupancyMap) { return 0.f; } const unsigned int bin = CAMath::Max(0.f, time / rec.tpc.occupancyMapTimeBins); - return occupancyMap[bin] * rec.tpc.clusterErrorOccupancyScaler; + return occupancyMap[bin]; #else return 0.f; #endif } MEM_CLASS_PRE() -GPUdi() bool MEM_LG(GPUParam)::rejectEdgeClusterByY(float uncorrectedY, int iRow) const +GPUdi() bool MEM_LG(GPUParam)::rejectEdgeClusterByY(float uncorrectedY, int iRow, float trackSigmaY) const { - return CAMath::Abs(uncorrectedY) > (tpcGeometry.NPads(iRow) - 1) * 0.5f * tpcGeometry.PadWidth(iRow) + rec.tpc.rejectEdgeClustersMargin; + return CAMath::Abs(uncorrectedY) > (tpcGeometry.NPads(iRow) - 1) * 0.5f * tpcGeometry.PadWidth(iRow) + rec.tpc.rejectEdgeClustersMargin + trackSigmaY * rec.tpc.rejectEdgeClustersSigmaMargin; } } // namespace gpu diff --git a/GPU/GPUTracking/Base/GPUReconstruction.cxx b/GPU/GPUTracking/Base/GPUReconstruction.cxx index f3997994a3b50..9246fc5df348f 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.cxx +++ b/GPU/GPUTracking/Base/GPUReconstruction.cxx @@ -1049,7 +1049,11 @@ int GPUReconstruction::EnqueuePipeline(bool terminate) if (q->retVal) { return q->retVal; } - return mChains[0]->FinalizePipelinedProcessing(); + if (terminate) { + return 0; + } else { + return mChains[0]->FinalizePipelinedProcessing(); + } } GPUChain* GPUReconstruction::GetNextChainInQueue() @@ -1132,16 +1136,16 @@ int GPUReconstruction::ReadSettings(const char* dir) return 0; } -void GPUReconstruction::SetSettings(float solenoidBz, const GPURecoStepConfiguration* workflow) +void GPUReconstruction::SetSettings(float solenoidBzNominalGPU, const GPURecoStepConfiguration* workflow) { #ifdef GPUCA_O2_LIB GPUO2InterfaceConfiguration config; - config.ReadConfigurableParam_internal(); - config.configGRP.solenoidBz = solenoidBz; + config.ReadConfigurableParam(config); + config.configGRP.solenoidBzNominalGPU = solenoidBzNominalGPU; SetSettings(&config.configGRP, &config.configReconstruction, &config.configProcessing, workflow); #else GPUSettingsGRP grp; - grp.solenoidBz = solenoidBz; + grp.solenoidBzNominalGPU = solenoidBzNominalGPU; SetSettings(&grp, nullptr, nullptr, workflow); #endif } diff --git a/GPU/GPUTracking/Base/GPUReconstruction.h b/GPU/GPUTracking/Base/GPUReconstruction.h index dc629d86553e2..324304ae8c2f6 100644 --- a/GPU/GPUTracking/Base/GPUReconstruction.h +++ b/GPU/GPUTracking/Base/GPUReconstruction.h @@ -53,6 +53,11 @@ struct GPUMemorySizeScalers; struct GPUReconstructionPipelineContext; class GPUROOTDumpCore; +namespace gpu_reconstruction_kernels +{ +struct deviceEvent; +} + class GPUReconstruction { friend class GPUChain; @@ -120,56 +125,9 @@ class GPUReconstruction static GPUReconstruction* CreateInstance(const char* type, bool forceType, GPUReconstruction* master = nullptr); static bool CheckInstanceAvailable(DeviceType type); - // Helpers for kernel launches - template - class classArgument - { - }; - - typedef void* deviceEvent; // We use only pointers anyway, and since cl_event and cudaEvent_t and hipEvent_t are actually pointers, we can cast them to deviceEvent (void*) this way. - enum class krnlDeviceType : int { CPU = 0, Device = 1, Auto = -1 }; - struct krnlExec { - constexpr krnlExec(unsigned int b, unsigned int t, int s, krnlDeviceType d = krnlDeviceType::Auto) : nBlocks(b), nThreads(t), stream(s), device(d), step(GPUCA_RECO_STEP::NoRecoStep) {} - constexpr krnlExec(unsigned int b, unsigned int t, int s, GPUCA_RECO_STEP st) : nBlocks(b), nThreads(t), stream(s), device(krnlDeviceType::Auto), step(st) {} - constexpr krnlExec(unsigned int b, unsigned int t, int s, krnlDeviceType d, GPUCA_RECO_STEP st) : nBlocks(b), nThreads(t), stream(s), device(d), step(st) {} - unsigned int nBlocks; - unsigned int nThreads; - int stream; - krnlDeviceType device; - GPUCA_RECO_STEP step; - }; - struct krnlRunRange { - constexpr krnlRunRange() = default; - constexpr krnlRunRange(unsigned int a) : start(a), num(0) {} - constexpr krnlRunRange(unsigned int s, int n) : start(s), num(n) {} - - unsigned int start = 0; - int num = 0; - }; - struct krnlEvent { - constexpr krnlEvent(deviceEvent e = nullptr, deviceEvent* el = nullptr, int n = 1) : ev(e), evList(el), nEvents(n) {} - deviceEvent ev; - deviceEvent* evList; - int nEvents; - }; - - struct krnlProperties { - krnlProperties(int t = 0, int b = 1, int b2 = 0) : nThreads(t), minBlocks(b), forceBlocks(b2) {} - unsigned int nThreads; - unsigned int minBlocks; - unsigned int forceBlocks; - unsigned int total() { return forceBlocks ? forceBlocks : (nThreads * minBlocks); } - }; - - struct krnlSetup { - krnlExec x; - krnlRunRange y; - krnlEvent z; - double t; - }; // Global steering functions template @@ -238,11 +196,10 @@ class GPUReconstruction const GPUSettingsDeviceBackend& GetDeviceBackendSettings() { return mDeviceBackendSettings; } const GPUSettingsProcessing& GetProcessingSettings() const { return mProcessingSettings; } bool IsInitialized() const { return mInitialized; } - void SetSettings(float solenoidBz, const GPURecoStepConfiguration* workflow = nullptr); + void SetSettings(float solenoidBzNominalGPU, const GPURecoStepConfiguration* workflow = nullptr); void SetSettings(const GPUSettingsGRP* grp, const GPUSettingsRec* rec = nullptr, const GPUSettingsProcessing* proc = nullptr, const GPURecoStepConfiguration* workflow = nullptr); void SetResetTimers(bool reset) { mProcessingSettings.resetTimers = reset; } // May update also after Init() void SetDebugLevelTmp(int level) { mProcessingSettings.debugLevel = level; } // Temporarily, before calling SetSettings() - GPUParam& GetNonConstParam() { return mHostConstantMem->param; } // Kind of hack, but needed for manual updates after SetSettings(), if the default configKeyValues parsing for SetSettings() is used. void UpdateSettings(const GPUSettingsGRP* g, const GPUSettingsProcessing* p = nullptr); void SetOutputControl(const GPUOutputControl& v) { mOutputControl = v; } void SetOutputControl(void* ptr, size_t size); @@ -287,7 +244,7 @@ class GPUReconstruction int InitPhaseAfterDevice(); void WriteConstantParams(); virtual int ExitDevice() = 0; - virtual size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, deviceEvent ev = nullptr) = 0; + virtual size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, gpu_reconstruction_kernels::deviceEvent* ev = nullptr) = 0; void UpdateMaxMemoryUsed(); int EnqueuePipeline(bool terminate = false); GPUChain* GetNextChainInQueue(); diff --git a/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx b/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx index fca2c802a602e..73c3bc22726b2 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx +++ b/GPU/GPUTracking/Base/GPUReconstructionCPU.cxx @@ -12,7 +12,6 @@ /// \file GPUReconstructionCPU.cxx /// \author David Rohr -#define GPUCA_GPURECONSTRUCTIONCPU_IMPLEMENTATION #include "GPUReconstructionCPU.h" #include "GPUReconstructionIncludes.h" #include "GPUChain.h" @@ -49,6 +48,7 @@ static inline int omp_get_max_threads() { return 1; } #endif using namespace GPUCA_NAMESPACE::gpu; +using namespace GPUCA_NAMESPACE::gpu::gpu_reconstruction_kernels; constexpr GPUReconstructionCPU::krnlRunRange GPUReconstructionCPU::krnlRunRangeNone; constexpr GPUReconstructionCPU::krnlEvent GPUReconstructionCPU::krnlEventNone; @@ -61,7 +61,7 @@ GPUReconstructionCPU::~GPUReconstructionCPU() } template -int GPUReconstructionCPUBackend::runKernelBackend(krnlSetup& _xyz, const Args&... args) +inline int GPUReconstructionCPUBackend::runKernelBackendInternal(const krnlSetupTime& _xyz, const Args&... args) { auto& x = _xyz.x; auto& y = _xyz.y; @@ -103,26 +103,38 @@ int GPUReconstructionCPUBackend::runKernelBackend(krnlSetup& _xyz, const Args&.. } template <> -int GPUReconstructionCPUBackend::runKernelBackend(krnlSetup& _xyz, void* const& ptr, unsigned long const& size) +inline int GPUReconstructionCPUBackend::runKernelBackendInternal(const krnlSetupTime& _xyz, void* const& ptr, unsigned long const& size) { memset(ptr, 0, size); return 0; } +template +int GPUReconstructionCPUBackend::runKernelBackend(const krnlSetupArgs& args) +{ + return std::apply([this, &args](auto&... vals) { return runKernelBackendInternal(args.s, vals...); }, args.v); +} + template -GPUReconstruction::krnlProperties GPUReconstructionCPUBackend::getKernelPropertiesBackend() +krnlProperties GPUReconstructionCPUBackend::getKernelPropertiesBackend() { return krnlProperties{1, 1}; } -size_t GPUReconstructionCPU::TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) { return 0; } -size_t GPUReconstructionCPU::GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev, deviceEvent* evList, int nEvents) { return 0; } -size_t GPUReconstructionCPU::GPUMemCpyAlways(bool onGpu, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev, deviceEvent* evList, int nEvents) +#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward, x_types) \ + template int GPUReconstructionCPUBackend::runKernelBackend(const krnlSetupArgs& args); \ + template krnlProperties GPUReconstructionCPUBackend::getKernelPropertiesBackend(); +#include "GPUReconstructionKernelList.h" +#undef GPUCA_KRNL + +size_t GPUReconstructionCPU::TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent* ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) { return 0; } +size_t GPUReconstructionCPU::GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev, deviceEvent* evList, int nEvents) { return 0; } +size_t GPUReconstructionCPU::GPUMemCpyAlways(bool onGpu, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev, deviceEvent* evList, int nEvents) { memcpy(dst, src, size); return 0; } -size_t GPUReconstructionCPU::WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream, deviceEvent ev) { return 0; } +size_t GPUReconstructionCPU::WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream, deviceEvent* ev) { return 0; } int GPUReconstructionCPU::GPUDebug(const char* state, int stream, bool force) { return 0; } size_t GPUReconstructionCPU::TransferMemoryResourcesHelper(GPUProcessor* proc, int stream, bool all, bool toGPU) { @@ -375,11 +387,17 @@ unsigned int GPUReconstructionCPU::SetAndGetNestedLoopOmpFactor(bool condition, return mNestedLoopOmpFactor; } -void GPUReconstructionCPU::UpdateParamOccupancyMap(const unsigned int* mapHost, const unsigned int* mapGPU, int stream) +void GPUReconstructionCPU::UpdateParamOccupancyMap(const unsigned int* mapHost, const unsigned int* mapGPU, unsigned int occupancyTotal, int stream) { param().occupancyMap = mapHost; + param().occupancyTotal = occupancyTotal; if (IsGPU()) { + if (!((size_t)¶m().occupancyTotal - (size_t)¶m().occupancyMap == sizeof(param().occupancyMap) && sizeof(param().occupancyMap) == sizeof(size_t) && sizeof(param().occupancyTotal) < sizeof(size_t))) { + throw std::runtime_error("occupancy data not consecutive in GPUParam"); + } const auto threadContext = GetThreadContext(); - WriteToConstantMemory((char*)&processors()->param.occupancyMap - (char*)processors(), &mapGPU, sizeof(mapGPU), stream); + size_t tmp[2] = {(size_t)mapGPU, 0}; + memcpy(&tmp[1], &occupancyTotal, sizeof(occupancyTotal)); + WriteToConstantMemory((char*)&processors()->param.occupancyMap - (char*)processors(), &tmp, sizeof(param().occupancyMap) + sizeof(param().occupancyTotal), stream); } } diff --git a/GPU/GPUTracking/Base/GPUReconstructionCPU.h b/GPU/GPUTracking/Base/GPUReconstructionCPU.h index af4194d878a79..7778c56292ed5 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionCPU.h +++ b/GPU/GPUTracking/Base/GPUReconstructionCPU.h @@ -12,8 +12,8 @@ /// \file GPUReconstructionCPU.h /// \author David Rohr -#ifndef GPURECONSTRUCTIONIMPL_H -#define GPURECONSTRUCTIONIMPL_H +#ifndef GPURECONSTRUCTIONICPU_H +#define GPURECONSTRUCTIONICPU_H #include "GPUReconstruction.h" #include "GPUReconstructionHelpers.h" @@ -24,6 +24,7 @@ #include "GPUGeneralKernels.h" #include "GPUReconstructionKernelIncludes.h" +#include "GPUReconstructionKernels.h" namespace GPUCA_NAMESPACE { @@ -38,59 +39,16 @@ class GPUReconstructionCPUBackend : public GPUReconstruction protected: GPUReconstructionCPUBackend(const GPUSettingsDeviceBackend& cfg) : GPUReconstruction(cfg) {} template - int runKernelBackend(krnlSetup& _xyz, const Args&... args); + int runKernelBackend(const gpu_reconstruction_kernels::krnlSetupArgs& args); + template + int runKernelBackendInternal(const gpu_reconstruction_kernels::krnlSetupTime& _xyz, const Args&... args); template - krnlProperties getKernelPropertiesBackend(); + gpu_reconstruction_kernels::krnlProperties getKernelPropertiesBackend(); unsigned int mNestedLoopOmpFactor = 1; static int getOMPThreadNum(); static int getOMPMaxThreads(); }; -template -class GPUReconstructionKernels : public T -{ - public: - using krnlSetup = GPUReconstruction::krnlSetup; - template - using classArgument = GPUReconstruction::classArgument; - virtual ~GPUReconstructionKernels() = default; // NOLINT: BUG: Do not declare override in template class! AMD hcc will not create the destructor otherwise. - GPUReconstructionKernels(const GPUSettingsDeviceBackend& cfg) : T(cfg) {} - - protected: -#define GPUCA_KRNL(x_class, attributes, x_arguments, x_forward) \ - virtual int runKernelImpl(classArgument, krnlSetup& _xyz GPUCA_M_STRIP(x_arguments)) \ - { \ - return T::template runKernelBackend(_xyz GPUCA_M_STRIP(x_forward)); \ - } \ - virtual GPUReconstruction::krnlProperties getKernelPropertiesImpl(classArgument) \ - { \ - return T::template getKernelPropertiesBackend(); \ - } -#include "GPUReconstructionKernels.h" -#undef GPUCA_KRNL -}; - -#ifndef GPUCA_GPURECONSTRUCTIONCPU_IMPLEMENTATION -// Hide the function bodies for all files but GPUReconstructionCPU.cxx, otherwise we get symbol clashes when the compiler inlines -template <> -class GPUReconstructionKernels : public GPUReconstructionCPUBackend -{ - public: - using krnlSetup = GPUReconstruction::krnlSetup; - template - using classArgument = GPUReconstruction::classArgument; - virtual ~GPUReconstructionKernels() = default; // NOLINT: Do not declare override in template class! AMD hcc will not create the destructor otherwise. - GPUReconstructionKernels(const GPUSettingsDeviceBackend& cfg) : GPUReconstructionCPUBackend(cfg) {} - - protected: -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ - virtual int runKernelImpl(classArgument, krnlSetup& _xyz GPUCA_M_STRIP(x_arguments)); \ - virtual krnlProperties getKernelPropertiesImpl(classArgument); -#include "GPUReconstructionKernels.h" -#undef GPUCA_KRNL -}; -#endif - class GPUReconstructionCPU : public GPUReconstructionKernels { friend GPUReconstruction* GPUReconstruction::GPUReconstruction_Create_CPU(const GPUSettingsDeviceBackend& cfg); @@ -101,12 +59,12 @@ class GPUReconstructionCPU : public GPUReconstructionKernels - int runKernel(const krnlExec& x, const krnlRunRange& y = krnlRunRangeNone, const krnlEvent& z = krnlEventNone, const Args&... args); + template + int runKernel(krnlSetup&& setup, Args&&... args); template - const krnlProperties getKernelProperties() + const gpu_reconstruction_kernels::krnlProperties getKernelProperties() { - return getKernelPropertiesImpl(GPUReconstruction::template classArgument()); + return getKernelPropertiesImpl(gpu_reconstruction_kernels::classArgument()); } template @@ -126,7 +84,7 @@ class GPUReconstructionCPU : public GPUReconstructionKernels, bool cpuFallback, double& timer, krnlSetup&& setup GPUCA_M_STRIP(x_arguments)) \ + { \ + if (cpuFallback) { \ + return GPUReconstructionCPU::runKernelImpl(krnlSetupArgs(setup.x, setup.y, setup.z, timer GPUCA_M_STRIP(x_forward))); \ + } else { \ + return runKernelImpl(krnlSetupArgs(setup.x, setup.y, setup.z, timer GPUCA_M_STRIP(x_forward))); \ + } \ + } +#include "GPUReconstructionKernelList.h" +#undef GPUCA_KRNL + int registerMemoryForGPU_internal(const void* ptr, size_t size) override { return 0; } int unregisterMemoryForGPU_internal(const void* ptr) override { return 0; } @@ -155,23 +125,23 @@ class GPUReconstructionCPU : public GPUReconstructionKernelsPtr(), res->PtrDevice()); } - size_t TransferMemoryResourceToHost(GPUMemoryResource* res, int stream = -1, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { return TransferMemoryInternal(res, stream, ev, evList, nEvents, false, res->PtrDevice(), res->Ptr()); } + size_t TransferMemoryResourceToGPU(GPUMemoryResource* res, int stream = -1, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { return TransferMemoryInternal(res, stream, ev, evList, nEvents, true, res->Ptr(), res->PtrDevice()); } + size_t TransferMemoryResourceToHost(GPUMemoryResource* res, int stream = -1, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { return TransferMemoryInternal(res, stream, ev, evList, nEvents, false, res->PtrDevice(), res->Ptr()); } size_t TransferMemoryResourcesToGPU(GPUProcessor* proc, int stream = -1, bool all = false) { return TransferMemoryResourcesHelper(proc, stream, all, true); } size_t TransferMemoryResourcesToHost(GPUProcessor* proc, int stream = -1, bool all = false) { return TransferMemoryResourcesHelper(proc, stream, all, false); } - size_t TransferMemoryResourceLinkToGPU(short res, int stream = -1, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { return TransferMemoryResourceToGPU(&mMemoryResources[res], stream, ev, evList, nEvents); } - size_t TransferMemoryResourceLinkToHost(short res, int stream = -1, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { return TransferMemoryResourceToHost(&mMemoryResources[res], stream, ev, evList, nEvents); } - virtual size_t GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1); - virtual size_t GPUMemCpyAlways(bool onGpu, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1); - size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, deviceEvent ev = nullptr) override; - virtual size_t TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst); + size_t TransferMemoryResourceLinkToGPU(short res, int stream = -1, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { return TransferMemoryResourceToGPU(&mMemoryResources[res], stream, ev, evList, nEvents); } + size_t TransferMemoryResourceLinkToHost(short res, int stream = -1, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { return TransferMemoryResourceToHost(&mMemoryResources[res], stream, ev, evList, nEvents); } + virtual size_t GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1); + virtual size_t GPUMemCpyAlways(bool onGpu, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1); + size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, deviceEvent* ev = nullptr) override; + virtual size_t TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent* ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst); int InitDevice() override; int ExitDevice() override; int GetThread(); virtual int PrepareTextures() { return 0; } - virtual int DoStuckProtection(int stream, void* event) { return 0; } + virtual int DoStuckProtection(int stream, deviceEvent event) { return 0; } // Pointers to tracker classes GPUProcessorProcessors mProcShadow; // Host copy of tracker objects that will be used on the GPU @@ -206,7 +176,7 @@ class GPUReconstructionCPU : public GPUReconstructionKernels> mTimers; RecoStepTimerMeta mTimersRecoSteps[GPUDataTypes::N_RECO_STEPS]; HighResTimer timerTotal; - template + template HighResTimer& getKernelTimer(RecoStep step, int num = 0, size_t addMemorySize = 0); template HighResTimer& getTimer(const char* name, int num = -1); @@ -220,17 +190,18 @@ class GPUReconstructionCPU : public GPUReconstructionKernels -inline int GPUReconstructionCPU::runKernel(const krnlExec& x, const krnlRunRange& y, const krnlEvent& z, const Args&... args) +template +inline int GPUReconstructionCPU::runKernel(krnlSetup&& setup, Args&&... args) { HighResTimer* t = nullptr; - GPUCA_RECO_STEP myStep = S::GetRecoStep() == GPUCA_RECO_STEP::NoRecoStep ? x.step : S::GetRecoStep(); + GPUCA_RECO_STEP myStep = S::GetRecoStep() == GPUCA_RECO_STEP::NoRecoStep ? setup.x.step : S::GetRecoStep(); if (myStep == GPUCA_RECO_STEP::NoRecoStep) { throw std::runtime_error("Failure running general kernel without defining RecoStep"); } - int cpuFallback = IsGPU() ? (x.device == krnlDeviceType::CPU ? 2 : (mRecoStepsGPU & myStep) != myStep) : 0; - unsigned int nThreads = x.nThreads; - unsigned int nBlocks = x.nBlocks; + int cpuFallback = IsGPU() ? (setup.x.device == krnlDeviceType::CPU ? 2 : (mRecoStepsGPU & myStep) != myStep) : 0; + unsigned int& nThreads = setup.x.nThreads; + unsigned int& nBlocks = setup.x.nBlocks; + const unsigned int stream = setup.x.stream; auto prop = getKernelProperties(); const int autoThreads = cpuFallback ? 1 : prop.nThreads; const int autoBlocks = cpuFallback ? 1 : (prop.forceBlocks ? prop.forceBlocks : (prop.minBlocks * mBlockCount)); @@ -250,35 +221,30 @@ inline int GPUReconstructionCPU::runKernel(const krnlExec& x, const krnlRunRange throw std::runtime_error("GPUCA_MAX_THREADS exceeded"); } if (mProcessingSettings.debugLevel >= 3) { - GPUInfo("Running kernel %s (Stream %d, Range %d/%d, Grid %d/%d) on %s", GetKernelName(), x.stream, y.start, y.num, nBlocks, nThreads, cpuFallback == 2 ? "CPU (forced)" : cpuFallback ? "CPU (fallback)" : mDeviceName.c_str()); + GPUInfo("Running kernel %s (Stream %d, Range %d/%d, Grid %d/%d) on %s", GetKernelName(), stream, setup.y.start, setup.y.num, nBlocks, nThreads, cpuFallback == 2 ? "CPU (forced)" : cpuFallback ? "CPU (fallback)" : mDeviceName.c_str()); } if (nThreads == 0 || nBlocks == 0) { return 0; } if (mProcessingSettings.debugLevel >= 1) { - t = &getKernelTimer(myStep, !IsGPU() || cpuFallback ? getOMPThreadNum() : x.stream); + t = &getKernelTimer(myStep, !IsGPU() || cpuFallback ? getOMPThreadNum() : stream); if ((!mProcessingSettings.deviceTimers || !IsGPU() || cpuFallback) && (mNestedLoopOmpFactor < 2 || getOMPThreadNum() == 0)) { t->Start(); } } - krnlSetup setup{{nBlocks, nThreads, x.stream, x.device, x.step}, y, z, 0.}; - if (cpuFallback) { - if (GPUReconstructionCPU::runKernelImpl(classArgument(), setup, args...)) { - return 1; - } - } else { - if (runKernelImpl(classArgument(), setup, args...)) { - return 1; - } - } - if (GPUDebug(GetKernelName(), x.stream)) { + double deviceTimerTime = 0.; + int retVal = runKernelImplWrapper(gpu_reconstruction_kernels::classArgument(), cpuFallback, deviceTimerTime, std::forward(setup), std::forward(args)...); + if (GPUDebug(GetKernelName(), stream)) { throw std::runtime_error("kernel failure"); } if (mProcessingSettings.debugLevel >= 1) { if (t) { - if (!(!mProcessingSettings.deviceTimers || !IsGPU() || cpuFallback)) { - t->AddTime(setup.t); - } else if (mNestedLoopOmpFactor < 2 || getOMPThreadNum() == 0) { + if (deviceTimerTime != 0.) { + t->AddTime(deviceTimerTime); + if (t->IsRunning()) { + t->Abort(); + } + } else if (t->IsRunning()) { t->Stop(); } } @@ -286,16 +252,16 @@ inline int GPUReconstructionCPU::runKernel(const krnlExec& x, const krnlRunRange throw std::runtime_error("kernel error code"); } } - return 0; + return retVal; } -#define GPUCA_KRNL(x_class, attributes, x_arguments, x_forward) \ +#define GPUCA_KRNL(x_class, ...) \ template <> \ constexpr const char* GPUReconstructionCPU::GetKernelName() \ { \ return GPUCA_M_STR(GPUCA_M_KRNL_NAME(x_class)); \ } -#include "GPUReconstructionKernels.h" +#include "GPUReconstructionKernelList.h" #undef GPUCA_KRNL template @@ -305,13 +271,13 @@ inline void GPUReconstructionCPU::AddGPUEvents(T*& events) events = (T*)mEvents.back().data(); } -template +template HighResTimer& GPUReconstructionCPU::getKernelTimer(RecoStep step, int num, size_t addMemorySize) { static int id = getNextTimerId(); timerMeta* timer = getTimerById(id); if (timer == nullptr) { - timer = insertTimer(id, GetKernelName(), J, NSLICES, 0, step); + timer = insertTimer(id, GetKernelName(), -1, NSLICES, 0, step); } if (addMemorySize) { timer->memSize += addMemorySize; diff --git a/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.h b/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.h index a7707cc629b3b..9e119629271ab 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.h +++ b/GPU/GPUTracking/Base/GPUReconstructionDeviceBase.h @@ -56,10 +56,10 @@ class GPUReconstructionDeviceBase : public GPUReconstructionCPU virtual const GPUTPCTracker* CPUTracker(int iSlice) { return &processors()->tpcTrackers[iSlice]; } int GPUDebug(const char* state = "UNKNOWN", int stream = -1, bool force = false) override = 0; - size_t TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) override = 0; - size_t GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override = 0; - size_t GPUMemCpyAlways(bool onGpu, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override; - size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, deviceEvent ev = nullptr) override = 0; + size_t TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent* ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) override = 0; + size_t GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override = 0; + size_t GPUMemCpyAlways(bool onGpu, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override; + size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, deviceEvent* ev = nullptr) override = 0; int StartHelperThreads() override; int StopHelperThreads() override; @@ -81,7 +81,7 @@ class GPUReconstructionDeviceBase : public GPUReconstructionCPU int mNSlaveThreads = 0; // Number of slave threads currently active struct DebugEvents { - void *DebugStart, *DebugStop; // Debug timer events + deviceEvent DebugStart, DebugStop; // Debug timer events }; DebugEvents* mDebugEvents = nullptr; @@ -94,7 +94,7 @@ class GPUReconstructionDeviceBase : public GPUReconstructionCPU void runConstantRegistrators(); }; -inline size_t GPUReconstructionDeviceBase::GPUMemCpyAlways(bool onGpu, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev, deviceEvent* evList, int nEvents) +inline size_t GPUReconstructionDeviceBase::GPUMemCpyAlways(bool onGpu, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev, deviceEvent* evList, int nEvents) { if (onGpu) { return GPUMemCpy(dst, src, size, stream, toGPU, ev, evList, nEvents); diff --git a/GPU/GPUTracking/Base/GPUReconstructionIncludes.h b/GPU/GPUTracking/Base/GPUReconstructionIncludes.h index 825fe3a77ef52..4575c77b6ff54 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionIncludes.h +++ b/GPU/GPUTracking/Base/GPUReconstructionIncludes.h @@ -29,14 +29,11 @@ #include #include -#if defined(GPUCA_ALIROOT_LIB) && !defined(GPUCA_GPULIBRARY) +#if defined(GPUCA_ALIROOT_LIB) && !defined(GPUCA_GPUCODE) #include "AliHLTDefinitions.h" #include "AliHLTSystem.h" #endif -#define RANDOM_ERROR -//#define RANDOM_ERROR || rand() % 500 == 1 - #define GPUCA_GPUReconstructionUpdateDefaults() \ if (mProcessingSettings.trackletConstructorInPipeline < 0) { \ mProcessingSettings.trackletConstructorInPipeline = GPUCA_CONSTRUCTOR_IN_PIPELINE; \ diff --git a/GPU/GPUTracking/Base/GPUReconstructionKernelMacros.h b/GPU/GPUTracking/Base/GPUReconstructionKernelMacros.h index 65b47be99a7bf..1a48333534f62 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionKernelMacros.h +++ b/GPU/GPUTracking/Base/GPUReconstructionKernelMacros.h @@ -31,7 +31,7 @@ #define GPUCA_M_KRNL_NAME_A(...) GPUCA_M_CAT(GPUCA_M_KRNL_NAME_B, GPUCA_M_SINGLEOPT(__VA_ARGS__))(__VA_ARGS__) #define GPUCA_M_KRNL_NAME(...) GPUCA_M_KRNL_NAME_A(GPUCA_M_STRIP(__VA_ARGS__)) -#ifdef GPUCA_GPUCODE +#if defined(GPUCA_GPUCODE) || defined(GPUCA_GPUCODE_HOSTONLY) #ifndef GPUCA_KRNL_REG #define GPUCA_KRNL_REG(...) #endif @@ -40,9 +40,6 @@ #define GPUCA_KRNL_CUSTOM(...) #endif #define GPUCA_KRNL_CUSTOM_INTERNAL_PROP(...) -#ifndef GPUCA_KRNL_BACKEND_XARGS -#define GPUCA_KRNL_BACKEND_XARGS -#endif #define GPUCA_ATTRRES_REG(XX, reg, num, ...) GPUCA_M_EXPAND(GPUCA_M_CAT(GPUCA_KRNL_REG, XX))(num) GPUCA_ATTRRES2(XX, __VA_ARGS__) #define GPUCA_ATTRRES2_REG(XX, reg, num, ...) GPUCA_M_EXPAND(GPUCA_M_CAT(GPUCA_KRNL_REG, XX))(num) GPUCA_ATTRRES3(XX, __VA_ARGS__) #define GPUCA_ATTRRES_CUSTOM(XX, custom, args, ...) GPUCA_M_EXPAND(GPUCA_M_CAT(GPUCA_KRNL_CUSTOM, XX))(args) GPUCA_ATTRRES2(XX, __VA_ARGS__) @@ -55,12 +52,12 @@ #define GPUCA_ATTRRES2(XX, ...) GPUCA_M_EXPAND(GPUCA_M_CAT(GPUCA_ATTRRES2_, GPUCA_M_FIRST(__VA_ARGS__)))(XX, __VA_ARGS__) #define GPUCA_ATTRRES(XX, ...) GPUCA_M_EXPAND(GPUCA_M_CAT(GPUCA_ATTRRES_, GPUCA_M_FIRST(__VA_ARGS__)))(XX, __VA_ARGS__) // GPU Kernel entry point for single sector -#define GPUCA_KRNLGPU_SINGLE_DEF(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNLGPU_SINGLE_DEF(x_class, x_attributes, x_arguments, ...) \ GPUg() void GPUCA_ATTRRES(,GPUCA_M_SHIFT(GPUCA_M_STRIP(x_attributes))) GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))(GPUCA_CONSMEM_PTR int iSlice_internal GPUCA_M_STRIP(x_arguments)) #ifdef GPUCA_KRNL_DEFONLY -#define GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_SINGLE_DEF(x_class, x_attributes, x_arguments, x_forward); +#define GPUCA_KRNLGPU_SINGLE(...) GPUCA_KRNLGPU_SINGLE_DEF(__VA_ARGS__); #else -#define GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_SINGLE_DEF(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward, ...) GPUCA_KRNLGPU_SINGLE_DEF(x_class, x_attributes, x_arguments, x_forward, __VA_ARGS__) \ { \ GPUshared() typename GPUCA_M_STRIP_FIRST(x_class)::MEM_LOCAL(GPUSharedMemory) smem; \ GPUCA_M_STRIP_FIRST(x_class)::template Thread(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, GPUCA_M_STRIP_FIRST(x_class)::Processor(GPUCA_CONSMEM)[iSlice_internal] GPUCA_M_STRIP(x_forward)); \ @@ -68,12 +65,12 @@ #endif // GPU Kernel entry point for multiple sector -#define GPUCA_KRNLGPU_MULTI_DEF(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNLGPU_MULTI_DEF(x_class, x_attributes, x_arguments, ...) \ GPUg() void GPUCA_ATTRRES(,GPUCA_M_SHIFT(GPUCA_M_STRIP(x_attributes))) GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)(GPUCA_CONSMEM_PTR int firstSlice, int nSliceCount GPUCA_M_STRIP(x_arguments)) #ifdef GPUCA_KRNL_DEFONLY -#define GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_MULTI_DEF(x_class, x_attributes, x_arguments, x_forward); +#define GPUCA_KRNLGPU_MULTI(...) GPUCA_KRNLGPU_MULTI_DEF(__VA_ARGS__); #else -#define GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_MULTI_DEF(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward, ...) GPUCA_KRNLGPU_MULTI_DEF(x_class, x_attributes, x_arguments, x_forward, __VA_ARGS__) \ { \ const int iSlice_internal = nSliceCount * (get_group_id(0) + (get_num_groups(0) % nSliceCount != 0 && nSliceCount * (get_group_id(0) + 1) % get_num_groups(0) != 0)) / get_num_groups(0); \ const int nSliceBlockOffset = get_num_groups(0) * iSlice_internal / nSliceCount; \ @@ -85,11 +82,11 @@ #endif // GPU Host wrapper pre- and post-parts -#define GPUCA_KRNL_PRE(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNL_PRE(x_class, ...) \ template <> class GPUCA_KRNL_BACKEND_CLASS::backendInternal { \ public: \ template \ - static inline void runKernelBackendMacro(krnlSetup& _xyz, T* me, GPUCA_KRNL_BACKEND_XARGS const Args&... args) \ + static inline void runKernelBackendMacro(const krnlSetupTime& _xyz, T* me, const Args&... args) \ { \ auto& x = _xyz.x; \ auto& y = _xyz.y; @@ -99,52 +96,52 @@ }; // GPU Host wrappers for single kernel, multi-sector, or auto-detection -#define GPUCA_KRNL_single(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_PRE(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNL_single(...) \ + GPUCA_KRNLGPU_SINGLE(__VA_ARGS__) \ + GPUCA_KRNL_PRE(__VA_ARGS__) \ if (y.num > 1) { \ throw std::runtime_error("Kernel called with invalid number of sectors"); \ } else { \ - GPUCA_KRNL_CALL_single(x_class, x_attributes, x_arguments, x_forward) \ + GPUCA_KRNL_CALL_single(__VA_ARGS__) \ } \ GPUCA_KRNL_POST() -#define GPUCA_KRNL_multi(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_PRE(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_CALL_multi(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNL_multi(...) \ + GPUCA_KRNLGPU_MULTI(__VA_ARGS__) \ + GPUCA_KRNL_PRE(__VA_ARGS__) \ + GPUCA_KRNL_CALL_multi(__VA_ARGS__) \ GPUCA_KRNL_POST() -#define GPUCA_KRNL_(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_single(x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_simple(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_single(x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_both(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_PRE(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNL_(...) GPUCA_KRNL_single(__VA_ARGS__) +#define GPUCA_KRNL_simple(...) GPUCA_KRNL_single(__VA_ARGS__) +#define GPUCA_KRNL_both(...) \ + GPUCA_KRNLGPU_SINGLE(__VA_ARGS__) \ + GPUCA_KRNLGPU_MULTI(__VA_ARGS__) \ + GPUCA_KRNL_PRE(__VA_ARGS__) \ if (y.num <= 1) { \ - GPUCA_KRNL_CALL_single(x_class, x_attributes, x_arguments, x_forward) \ + GPUCA_KRNL_CALL_single(__VA_ARGS__) \ } else { \ - GPUCA_KRNL_CALL_multi(x_class, x_attributes, x_arguments, x_forward) \ + GPUCA_KRNL_CALL_multi(__VA_ARGS__) \ } \ GPUCA_KRNL_POST() -#define GPUCA_KRNL_LOAD_(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_simple(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_both(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) +#define GPUCA_KRNL_LOAD_(...) GPUCA_KRNL_LOAD_single(__VA_ARGS__) +#define GPUCA_KRNL_LOAD_simple(...) GPUCA_KRNL_LOAD_single(__VA_ARGS__) +#define GPUCA_KRNL_LOAD_both(...) \ + GPUCA_KRNL_LOAD_single(__VA_ARGS__) \ + GPUCA_KRNL_LOAD_multi(__VA_ARGS__) #define GPUCA_KRNL_PROP(x_class, x_attributes) \ - template <> const GPUReconstruction::krnlProperties GPUCA_KRNL_BACKEND_CLASS::getKernelPropertiesBackend() { \ - krnlProperties ret = krnlProperties{GPUCA_ATTRRES(_INTERNAL_PROP,GPUCA_M_SHIFT(GPUCA_M_STRIP(x_attributes)))}; \ - return ret.nThreads > 0 ? ret : krnlProperties{(int)mThreadCount}; \ + template <> gpu_reconstruction_kernels::krnlProperties GPUCA_KRNL_BACKEND_CLASS::getKernelPropertiesBackend() { \ + gpu_reconstruction_kernels::krnlProperties ret = gpu_reconstruction_kernels::krnlProperties{GPUCA_ATTRRES(_INTERNAL_PROP,GPUCA_M_SHIFT(GPUCA_M_STRIP(x_attributes)))}; \ + return ret.nThreads > 0 ? ret : gpu_reconstruction_kernels::krnlProperties{(int)mThreadCount}; \ } // Generate GPU kernel and host wrapper -#define GPUCA_KRNL_WRAP(x_func, x_class, x_attributes, x_arguments, x_forward) GPUCA_M_CAT(x_func, GPUCA_M_STRIP_FIRST(x_attributes))(x_class, x_attributes, x_arguments, x_forward) -#endif +#define GPUCA_KRNL_WRAP(x_func, x_class, x_attributes, ...) GPUCA_M_CAT(x_func, GPUCA_M_STRIP_FIRST(x_attributes))(x_class, x_attributes, __VA_ARGS__) +#endif // GPUCA_GPUCODE -#define GPUCA_KRNL_LB(a, b, c, d) GPUCA_KRNL(a, (GPUCA_M_STRIP(b), REG, (GPUCA_M_CAT(GPUCA_LB_, GPUCA_M_KRNL_NAME(a)))), c, d) +#define GPUCA_KRNL_LB(x_class, x_attributes, ...) GPUCA_KRNL(x_class, (GPUCA_M_STRIP(x_attributes), REG, (GPUCA_M_CAT(GPUCA_LB_, GPUCA_M_KRNL_NAME(x_class)))), __VA_ARGS__) -#endif +#endif // O2_GPU_GPURECONSTRUCTIONKERNELMACROS_H // clang-format on diff --git a/GPU/GPUTracking/Base/GPUReconstructionKernels.h b/GPU/GPUTracking/Base/GPUReconstructionKernels.h new file mode 100644 index 0000000000000..840cf8b5944b6 --- /dev/null +++ b/GPU/GPUTracking/Base/GPUReconstructionKernels.h @@ -0,0 +1,132 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUReconstructionKernels.h +/// \author David Rohr + +#ifndef GPURECONSTRUCTIONKERNELS_H +#define GPURECONSTRUCTIONKERNELS_H + +#include "GPUReconstruction.h" + +namespace GPUCA_NAMESPACE +{ +namespace gpu +{ + +namespace gpu_reconstruction_kernels +{ +struct deviceEvent { + constexpr deviceEvent() = default; + constexpr deviceEvent(std::nullptr_t p) : v(nullptr){}; + template + void set(T val) { v = reinterpret_cast(val); } + template + T& get() { return reinterpret_cast(v); } + template + T* getEventList() { return reinterpret_cast(this); } + bool isSet() const { return v; } + + private: + void* v = nullptr; // We use only pointers anyway, and since cl_event and cudaEvent_t and hipEvent_t are actually pointers, we can cast them to deviceEvent (void*) this way. +}; + +template +struct classArgument { + using t = T; + static constexpr int i = I; +}; + +struct krnlExec { + constexpr krnlExec(unsigned int b, unsigned int t, int s, GPUReconstruction::krnlDeviceType d = GPUReconstruction::krnlDeviceType::Auto) : nBlocks(b), nThreads(t), stream(s), device(d), step(GPUCA_RECO_STEP::NoRecoStep) {} + constexpr krnlExec(unsigned int b, unsigned int t, int s, GPUCA_RECO_STEP st) : nBlocks(b), nThreads(t), stream(s), device(GPUReconstruction::krnlDeviceType::Auto), step(st) {} + constexpr krnlExec(unsigned int b, unsigned int t, int s, GPUReconstruction::krnlDeviceType d, GPUCA_RECO_STEP st) : nBlocks(b), nThreads(t), stream(s), device(d), step(st) {} + unsigned int nBlocks; + unsigned int nThreads; + int stream; + GPUReconstruction::krnlDeviceType device; + GPUCA_RECO_STEP step; +}; +struct krnlRunRange { + constexpr krnlRunRange() = default; + constexpr krnlRunRange(unsigned int a) : start(a), num(0) {} + constexpr krnlRunRange(unsigned int s, int n) : start(s), num(n) {} + + unsigned int start = 0; + int num = 0; +}; +struct krnlEvent { + constexpr krnlEvent(deviceEvent* e = nullptr, deviceEvent* el = nullptr, int n = 1) : ev(e), evList(el), nEvents(n) {} + deviceEvent* ev; + deviceEvent* evList; + int nEvents; +}; + +struct krnlProperties { + krnlProperties(int t = 0, int b = 1, int b2 = 0) : nThreads(t), minBlocks(b), forceBlocks(b2) {} + unsigned int nThreads; + unsigned int minBlocks; + unsigned int forceBlocks; + unsigned int total() { return forceBlocks ? forceBlocks : (nThreads * minBlocks); } +}; + +struct krnlSetup { + krnlSetup(const krnlExec& xx, const krnlRunRange& yy = {0, -1}, const krnlEvent& zz = {nullptr, nullptr, 0}) : x(xx), y(yy), z(zz) {} + krnlExec x; + krnlRunRange y; + krnlEvent z; +}; + +struct krnlSetupTime : public krnlSetup { + double& t; +}; + +template +struct krnlSetupArgs : public gpu_reconstruction_kernels::classArgument { + krnlSetupArgs(const krnlExec& xx, const krnlRunRange& yy, const krnlEvent& zz, double& tt, const Args&... args) : s{{xx, yy, zz}, tt}, v(args...) {} + const krnlSetupTime s; + std::tuple sizeof(void*)), const Args&, const Args>::type...> v; +}; +} // namespace gpu_reconstruction_kernels + +template +class GPUReconstructionKernels : public T +{ + public: + GPUReconstructionKernels(const GPUSettingsDeviceBackend& cfg) : T(cfg) {} + + protected: + using deviceEvent = gpu_reconstruction_kernels::deviceEvent; + using krnlExec = gpu_reconstruction_kernels::krnlExec; + using krnlRunRange = gpu_reconstruction_kernels::krnlRunRange; + using krnlEvent = gpu_reconstruction_kernels::krnlEvent; + using krnlSetup = gpu_reconstruction_kernels::krnlSetup; + using krnlSetupTime = gpu_reconstruction_kernels::krnlSetupTime; + template + using krnlSetupArgs = gpu_reconstruction_kernels::krnlSetupArgs; + +#define GPUCA_KRNL(x_class, attributes, x_arguments, x_forward, x_types) \ + virtual int runKernelImpl(const krnlSetupArgs& args) \ + { \ + return T::template runKernelBackend(args); \ + } \ + virtual gpu_reconstruction_kernels::krnlProperties getKernelPropertiesImpl(gpu_reconstruction_kernels::classArgument) \ + { \ + return T::template getKernelPropertiesBackend(); \ + } +#include "GPUReconstructionKernelList.h" +#undef GPUCA_KRNL +}; + +} // namespace gpu +} // namespace GPUCA_NAMESPACE + +#endif diff --git a/GPU/GPUTracking/Base/GPUReconstructionKernels.template.h b/GPU/GPUTracking/Base/GPUReconstructionKernels.template.h index d4e1ac6099fd7..8194214a180e4 100644 --- a/GPU/GPUTracking/Base/GPUReconstructionKernels.template.h +++ b/GPU/GPUTracking/Base/GPUReconstructionKernels.template.h @@ -9,7 +9,7 @@ // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -/// \file GPUReconstructionKernels.h +/// \file GPUReconstructionKernelList.h /// \author David Rohr // No header protection, this may be used multiple times diff --git a/GPU/GPUTracking/Base/cuda/CMakeLists.txt b/GPU/GPUTracking/Base/cuda/CMakeLists.txt index e55f2f6e3c08e..6bade1363b7ce 100644 --- a/GPU/GPUTracking/Base/cuda/CMakeLists.txt +++ b/GPU/GPUTracking/Base/cuda/CMakeLists.txt @@ -11,14 +11,14 @@ set(MODULE GPUTrackingCUDA) +# -------------------------------- Status Message ------------------------------------------------------- if(DEFINED CUDA_COMPUTETARGET) set(TMP_TARGET "(Compute Target ${CUDA_COMPUTETARGET})") endif() message(STATUS "Building GPUTracking with CUDA support ${TMP_TARGET}") -set(SRCS GPUReconstructionCUDA.cu GPUReconstructionCUDAGenRTC.cu GPUReconstructionCUDAKernels.cu) +set(SRCS GPUReconstructionCUDA.cu GPUReconstructionCUDAGenRTC.cxx GPUReconstructionCUDAKernels.cu) set(HDRS GPUReconstructionCUDA.h GPUReconstructionCUDAInternals.h GPUReconstructionCUDADef.h GPUReconstructionCUDAIncludes.h CUDAThrustHelpers.h) - # -------------------------------- Prepare RTC ------------------------------------------------------- if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") enable_language(ASM) @@ -27,27 +27,29 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") else() set(defineIncludeSrc "${MODULE}") endif() - set(CURTC_DEFINES "-D$,$-D>") - set(CURTC_INCLUDES "-I$,EXCLUDE,^/usr/include/?>,$-I>" + set(GPU_RTC_DEFINES "-D$,$-D>") + set(GPU_RTC_INCLUDES "-I$,EXCLUDE,^/usr/include/?>,$-I>" -I${CMAKE_SOURCE_DIR}/Detectors/Base/src -I${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src ) if(ALIGPU_BUILD_TYPE STREQUAL "O2") - set(CURTC_INCLUDES ${CURTC_INCLUDES} "-I$,EXCLUDE,^/usr/include/?>,$-I>") + set(GPU_RTC_INCLUDES ${GPU_RTC_INCLUDES} "-I$,EXCLUDE,^/usr/include/?>,$-I>") endif() #set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -keep") - set(CUDARTC_FLAGS "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}} -std=c++${CMAKE_CUDA_STANDARD}") + # build flags to use for RTC + set(GPU_RTC_FLAGS "${CMAKE_CUDA_FLAGS} ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -std=c++${CMAKE_CUDA_STANDARD}") if(CUDA_COMPUTETARGET) foreach(CUDA_ARCH ${CUDA_COMPUTETARGET}) - set(CUDARTC_FLAGS "${CUDARTC_FLAGS} -gencode arch=compute_${CUDA_ARCH},code=sm_${CUDA_ARCH}") + set(GPU_RTC_FLAGS "${GPU_RTC_FLAGS} -gencode arch=compute_${CUDA_ARCH},code=sm_${CUDA_ARCH}") endforeach() list (GET CUDA_COMPUTETARGET 0 RTC_CUDA_ARCH) set(RTC_CUDA_ARCH "${RTC_CUDA_ARCH}0") else() set(RTC_CUDA_ARCH "750") endif() - separate_arguments(CUDARTC_FLAGS) + set(GPU_RTC_FLAGS_SEPARATED "${GPU_RTC_FLAGS}") + separate_arguments(GPU_RTC_FLAGS_SEPARATED) # convenience variables if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") @@ -56,68 +58,65 @@ if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") set(GPUDIR ${CMAKE_SOURCE_DIR}/GPU/GPUTracking) endif() - set(CURTC_SRC ${GPUDIR}/Base/cuda/GPUReconstructionCUDArtc.cu) - set(CURTC_BIN ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionCUDArtc) + set(GPU_RTC_SRC ${GPUDIR}/Base/cuda/GPUReconstructionCUDArtc.cu) + set(GPU_RTC_BIN ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionCUDArtc) # cmake-format: off add_custom_command( - OUTPUT ${CURTC_BIN}.src - COMMAND cat ${GPUDIR}/Base/cuda/GPUReconstructionCUDAIncludes.h > ${CURTC_BIN}.src - COMMAND ${CMAKE_CXX_COMPILER} ${CURTC_DEFINES} ${CURTC_INCLUDES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -D__CUDACC__ -x c++ -E ${CURTC_SRC} >> ${CURTC_BIN}.src - MAIN_DEPENDENCY ${CURTC_SRC} - IMPLICIT_DEPENDS CXX ${CURTC_SRC} + OUTPUT ${GPU_RTC_BIN}.src + COMMAND cat ${GPUDIR}/Base/cuda/GPUReconstructionCUDAIncludes.h > ${GPU_RTC_BIN}.src + COMMAND ${CMAKE_CXX_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_CUDA_STANDARD} -D__CUDA_ARCH__=${RTC_CUDA_ARCH} -D__CUDACC__ -x c++ -E ${GPU_RTC_SRC} >> ${GPU_RTC_BIN}.src + MAIN_DEPENDENCY ${GPU_RTC_SRC} + IMPLICIT_DEPENDS CXX ${GPU_RTC_SRC} COMMAND_EXPAND_LISTS + COMMENT "Preparing CUDA RTC source file ${GPU_RTC_BIN}.src" ) - create_binary_resource(${CURTC_BIN}.src ${CURTC_BIN}.src.o) + create_binary_resource(${GPU_RTC_BIN}.src ${GPU_RTC_BIN}.src.o) add_custom_command( - OUTPUT ${CURTC_BIN}.command - COMMAND echo -n "${CMAKE_CUDA_COMPILER} ${CUDARTC_FLAGS} ${CURTC_DEFINES}" > ${CURTC_BIN}.command + OUTPUT ${GPU_RTC_BIN}.command + COMMAND echo -n "${CMAKE_CUDA_COMPILER} ${GPU_RTC_FLAGS_SEPARATED} ${GPU_RTC_DEFINES} -fatbin" > ${GPU_RTC_BIN}.command COMMAND_EXPAND_LISTS VERBATIM + COMMENT "Preparing CUDA RTC command file ${GPU_RTC_BIN}.command" ) - create_binary_resource(${CURTC_BIN}.command ${CURTC_BIN}.command.o) + create_binary_resource(${GPU_RTC_BIN}.command ${GPU_RTC_BIN}.command.o) - set(SRCS ${SRCS} ${CURTC_BIN}.src.o ${CURTC_BIN}.command.o) + set(SRCS ${SRCS} ${GPU_RTC_BIN}.src.o ${GPU_RTC_BIN}.command.o) endif() # -------------------------------- End RTC ------------------------------------------------------- if(ALIGPU_BUILD_TYPE STREQUAL "O2") + set(TMP_BASELIB O2::GPUTracking) o2_add_library( ${MODULE} SOURCES ${SRCS} + PUBLIC_LINK_LIBRARIES ${TMP_BASELIB} O2::ITStrackingCUDA PRIVATE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/Detectors/Base/src ${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src ${CMAKE_SOURCE_DIR}/DataFormats/Reconstruction/src ${CMAKE_CURRENT_SOURCE_DIR} - PUBLIC_LINK_LIBRARIES O2::GPUTracking O2::ITStrackingCUDA O2::FrameworkFoundation3rdparty TARGETVARNAME targetName) target_compile_definitions(${targetName} PUBLIC $) - set_target_properties(${targetName} PROPERTIES LINKER_LANGUAGE CXX) - install(FILES ${HDRS} DESTINATION include/GPU) endif() if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") - set(targetName Ali${MODULE}) + set(targetName "Ali${MODULE}") + set(TMP_BASELIB AliGPUTracking) # Generate the dictionary get_directory_property(incdirs INCLUDE_DIRECTORIES) - generate_dictionary("${targetName}" "" "GPUReconstructionCUDA.h" - "${incdirs} .") + generate_dictionary("${targetName}" "" "GPUReconstructionCUDA.h" "${incdirs} .") # Generate the ROOT map Dependecies generate_rootmap("${targetName}" "" "") # Add a library to the project using the specified source files add_library_tested(${targetName} SHARED ${SRCS} G__${targetName}.cxx) - # CUDA run-time and driver - target_link_libraries(${targetName} PUBLIC AliGPUTracking) - - # Additional compilation flags - set_target_properties(${targetName} PROPERTIES COMPILE_FLAGS "") + target_link_libraries(${targetName} PUBLIC ${TMP_BASELIB}) # Installation install(TARGETS ${targetName} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib) @@ -127,13 +126,15 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") endif() if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") + set(targetName "${MODULE}") + set(TMP_BASELIB GPUTracking) add_library(${MODULE} SHARED ${SRCS}) - target_link_libraries(${MODULE} PUBLIC GPUTracking) - set(targetName ${MODULE}) + target_link_libraries(${MODULE} PUBLIC ${TMP_BASELIB}) install(TARGETS GPUTrackingCUDA) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) endif() +# Setting target architecture and adding GPU libraries target_link_libraries(${targetName} PRIVATE cuda cudart nvrtc) set_target_cuda_arch(${targetName}) @@ -144,6 +145,7 @@ if(OpenMP_CXX_FOUND) set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler -fopenmp") endif() +# Special handling of GPU kernels in case of per-kernel compilation / RDC if(NOT DEFINED GPUCA_CUDA_COMPILE_MODE) if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") set(GPUCA_CUDA_COMPILE_MODE "onefile") @@ -156,6 +158,7 @@ if(GPUCA_CUDA_COMPILE_MODE STREQUAL "onefile") elseif(GPUCA_CUDA_COMPILE_MODE STREQUAL "perkernel") add_library(GPUTrackingCUDAKernels OBJECT $,REPLACE,[^A-Za-z0-9]+,_>,PREPEND,${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_>,APPEND,.cu>, >) set_property(TARGET GPUTrackingCUDAKernels PROPERTY CUDA_FATBIN_COMPILATION ON) + set_property(TARGET GPUTrackingCUDAKernels PROPERTY CUDA_SEPARABLE_COMPILATION OFF) target_compile_definitions(${targetName} PRIVATE GPUCA_KERNEL_COMPILE_MODE=1) target_compile_definitions(GPUTrackingCUDAKernels PRIVATE $) target_include_directories(GPUTrackingCUDAKernels PRIVATE $) @@ -165,7 +168,7 @@ elseif(GPUCA_CUDA_COMPILE_MODE STREQUAL "perkernel") COMMAND cp -u $ ${CMAKE_CURRENT_BINARY_DIR}/cuda_kernel_module_fatbin/ COMMAND ${CMAKE_LINKER} --relocatable --format binary --output ${CMAKE_CURRENT_BINARY_DIR}/GPUTrackingCUDAKernelModules.o $>,PREPEND,${CMAKE_CURRENT_BINARY_DIR}/cuda_kernel_module_fatbin/>,${CMAKE_CURRENT_BINARY_DIR}> DEPENDS GPUTrackingCUDAKernels $ - COMMENT "Compiling fatbin kernels" + COMMENT "Compiling fatbin kernels ${CMAKE_CURRENT_BINARY_DIR}/GPUTrackingCUDAKernelModules.o" VERBATIM COMMAND_EXPAND_LISTS ) @@ -189,9 +192,15 @@ elseif(GPUCA_CUDA_COMPILE_MODE STREQUAL "rdc") else() message(FATAL_ERROR "Invalid compile mode") endif() +if(NOT GPUCA_CUDA_COMPILE_MODE STREQUAL "rdc") + set_property(TARGET ${targetName} PROPERTY CUDA_SEPARABLE_COMPILATION OFF) + set_target_properties(${targetName} PROPERTIES LINKER_LANGUAGE CXX) +endif() -add_library(GPUTrackingCUDAExternalProvider OBJECT GPUReconstructionCUDAExternalProvider.cu) -add_library(O2::GPUTrackingCUDAExternalProvider ALIAS GPUTrackingCUDAExternalProvider) -set_property(TARGET GPUTrackingCUDAExternalProvider PROPERTY CUDA_SEPARABLE_COMPILATION ON) -target_compile_definitions(GPUTrackingCUDAExternalProvider PRIVATE $) -target_include_directories(GPUTrackingCUDAExternalProvider PRIVATE $) +if(ALIGPU_BUILD_TYPE STREQUAL "O2" OR CONFIG_O2_EXTENSIONS) + add_library(GPUTrackingCUDAExternalProvider OBJECT GPUReconstructionCUDAExternalProvider.cu) + add_library(O2::GPUTrackingCUDAExternalProvider ALIAS GPUTrackingCUDAExternalProvider) + set_property(TARGET GPUTrackingCUDAExternalProvider PROPERTY CUDA_SEPARABLE_COMPILATION ON) + target_compile_definitions(GPUTrackingCUDAExternalProvider PRIVATE $) + target_include_directories(GPUTrackingCUDAExternalProvider PRIVATE $) +endif() diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu index ad412af2962c5..a51b3f9e2261f 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.cu @@ -26,8 +26,13 @@ #if defined(GPUCA_KERNEL_COMPILE_MODE) && GPUCA_KERNEL_COMPILE_MODE == 1 #include "utils/qGetLdBinarySymbols.h" -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) QGET_LD_BINARY_SYMBOLS(GPUCA_M_CAT3(cuda_kernel_module_fatbin_krnl_, GPUCA_M_KRNL_NAME(x_class), _fatbin)) -#include "GPUReconstructionKernels.h" +#ifndef __HIPCC__ // CUDA +#define PER_KERNEL_OBJECT_EXT _fatbin +#else // HIP +#define PER_KERNEL_OBJECT_EXT _hip_cxx_o +#endif +#define GPUCA_KRNL(x_class, ...) QGET_LD_BINARY_SYMBOLS(GPUCA_M_CAT3(cuda_kernel_module_fatbin_krnl_, GPUCA_M_KRNL_NAME(x_class), PER_KERNEL_OBJECT_EXT)) +#include "GPUReconstructionKernelList.h" #undef GPUCA_KRNL #endif @@ -39,9 +44,7 @@ static constexpr size_t RESERVE_EXTRA_MEM_OFFSET = 1L * 512 * 1024 * 1024; using namespace GPUCA_NAMESPACE::gpu; -__global__ void dummyInitKernel(void*) -{ -} +__global__ void dummyInitKernel(void*) {} #include "GPUReconstructionIncludesITS.h" @@ -55,9 +58,6 @@ GPUReconstructionCUDABackend::GPUReconstructionCUDABackend(const GPUSettingsDevi GPUReconstructionCUDABackend::~GPUReconstructionCUDABackend() { if (mMaster == nullptr) { - for (unsigned int i = 0; i < mInternals->kernelModules.size(); i++) { - cuModuleUnload(*mInternals->kernelModules[i]); - } delete mInternals; } } @@ -87,6 +87,13 @@ void GPUReconstructionCUDABackend::GPUFailedMsgA(const long long int error, cons GPUReconstructionCUDA::GPUReconstructionCUDA(const GPUSettingsDeviceBackend& cfg) : GPUReconstructionKernels(cfg) { mDeviceBackendSettings.deviceType = DeviceType::CUDA; +#ifndef __HIPCC__ // CUDA + mRtcSrcExtension = ".cu"; + mRtcBinExtension = ".fatbin"; +#else // HIP + mRtcSrcExtension = ".hip"; + mRtcBinExtension = ".o"; +#endif } GPUReconstructionCUDA::~GPUReconstructionCUDA() @@ -116,8 +123,17 @@ void GPUReconstructionCUDA::UpdateAutomaticProcessingSettings() int GPUReconstructionCUDA::InitDevice_Runtime() { +#ifndef __HIPCC__ // CUDA + constexpr int reqVerMaj = 2; + constexpr int reqVerMin = 0; +#endif + if (mProcessingSettings.rtc.enable && mProcessingSettings.rtc.runTest == 2) { + genAndLoadRTC(); + exit(0); + } + if (mMaster == nullptr) { - cudaDeviceProp cudaDeviceProp; + cudaDeviceProp deviceProp; int count, bestDevice = -1; double bestDeviceSpeed = -1, deviceSpeed; if (GPUFailedMsgI(cudaGetDeviceCount(&count))) { @@ -127,8 +143,6 @@ int GPUReconstructionCUDA::InitDevice_Runtime() if (mProcessingSettings.debugLevel >= 2) { GPUInfo("Available CUDA devices:"); } - const int reqVerMaj = 2; - const int reqVerMin = 0; std::vector devicesOK(count, false); std::vector devMemory(count, 0); bool contextCreated = false; @@ -137,7 +151,11 @@ int GPUReconstructionCUDA::InitDevice_Runtime() GPUInfo("Examining device %d", i); } size_t free, total; +#ifndef __HIPCC__ // CUDA if (GPUFailedMsgI(cudaInitDevice(i, 0, 0))) { +#else // HIP + if (GPUFailedMsgI(hipSetDevice(i))) { +#endif if (mProcessingSettings.debugLevel >= 4) { GPUWarning("Couldn't create context for device %d. Skipping it.", i); } @@ -158,25 +176,28 @@ int GPUReconstructionCUDA::InitDevice_Runtime() if (mProcessingSettings.debugLevel >= 4) { GPUInfo("Obtained current memory usage for device %d", i); } - if (GPUFailedMsgI(cudaGetDeviceProperties(&cudaDeviceProp, i))) { + if (GPUFailedMsgI(cudaGetDeviceProperties(&deviceProp, i))) { continue; } if (mProcessingSettings.debugLevel >= 4) { GPUInfo("Obtained device properties for device %d", i); } int deviceOK = true; - const char* deviceFailure = ""; - if (cudaDeviceProp.major < reqVerMaj || (cudaDeviceProp.major == reqVerMaj && cudaDeviceProp.minor < reqVerMin)) { + [[maybe_unused]] const char* deviceFailure = ""; +#ifndef __HIPCC__ + if (deviceProp.major < reqVerMaj || (deviceProp.major == reqVerMaj && deviceProp.minor < reqVerMin)) { deviceOK = false; deviceFailure = "Too low device revision"; - } else if (free < std::max(mDeviceMemorySize, REQUIRE_MIN_MEMORY)) { + } +#endif + if (free < std::max(mDeviceMemorySize, REQUIRE_MIN_MEMORY)) { deviceOK = false; deviceFailure = "Insufficient GPU memory"; } - deviceSpeed = (double)cudaDeviceProp.multiProcessorCount * (double)cudaDeviceProp.clockRate * (double)cudaDeviceProp.warpSize * (double)free * (double)cudaDeviceProp.major * (double)cudaDeviceProp.major; + deviceSpeed = (double)deviceProp.multiProcessorCount * (double)deviceProp.clockRate * (double)deviceProp.warpSize * (double)free * (double)deviceProp.major * (double)deviceProp.major; if (mProcessingSettings.debugLevel >= 2) { - GPUImportant("Device %s%2d: %s (Rev: %d.%d - Mem Avail %lu / %lu)%s %s", deviceOK ? " " : "[", i, cudaDeviceProp.name, cudaDeviceProp.major, cudaDeviceProp.minor, free, (size_t)cudaDeviceProp.totalGlobalMem, deviceOK ? " " : " ]", deviceOK ? "" : deviceFailure); + GPUImportant("Device %s%2d: %s (Rev: %d.%d - Mem Avail %lu / %lu)%s %s", deviceOK ? " " : "[", i, deviceProp.name, deviceProp.major, deviceProp.minor, free, (size_t)deviceProp.totalGlobalMem, deviceOK ? " " : " ]", deviceOK ? "" : deviceFailure); } if (!deviceOK) { continue; @@ -195,8 +216,10 @@ int GPUReconstructionCUDA::InitDevice_Runtime() bool noDevice = false; if (bestDevice == -1) { - GPUWarning("No %sCUDA Device available, aborting CUDA Initialisation", count ? "appropriate " : ""); + GPUWarning("No %sCUDA Device available, aborting CUDA Initialisation (Required mem: %lld)", count ? "appropriate " : "", (long long int)mDeviceMemorySize); +#ifndef __HIPCC__ GPUImportant("Requiring Revision %d.%d, Mem: %lu", reqVerMaj, reqVerMin, std::max(mDeviceMemorySize, REQUIRE_MIN_MEMORY)); +#endif noDevice = true; } else if (mProcessingSettings.deviceNum > -1) { if (mProcessingSettings.deviceNum >= (signed)count) { @@ -217,59 +240,68 @@ int GPUReconstructionCUDA::InitDevice_Runtime() } mDeviceId = bestDevice; - GPUFailedMsgI(cudaGetDeviceProperties(&cudaDeviceProp, mDeviceId)); + GPUFailedMsgI(cudaGetDeviceProperties(&deviceProp, mDeviceId)); if (mProcessingSettings.debugLevel >= 2) { - GPUInfo("Using CUDA Device %s with Properties:", cudaDeviceProp.name); - GPUInfo("\ttotalGlobalMem = %lld", (unsigned long long int)cudaDeviceProp.totalGlobalMem); - GPUInfo("\tsharedMemPerBlock = %lld", (unsigned long long int)cudaDeviceProp.sharedMemPerBlock); - GPUInfo("\tregsPerBlock = %d", cudaDeviceProp.regsPerBlock); - GPUInfo("\twarpSize = %d", cudaDeviceProp.warpSize); - GPUInfo("\tmemPitch = %lld", (unsigned long long int)cudaDeviceProp.memPitch); - GPUInfo("\tmaxThreadsPerBlock = %d", cudaDeviceProp.maxThreadsPerBlock); - GPUInfo("\tmaxThreadsDim = %d %d %d", cudaDeviceProp.maxThreadsDim[0], cudaDeviceProp.maxThreadsDim[1], cudaDeviceProp.maxThreadsDim[2]); - GPUInfo("\tmaxGridSize = %d %d %d", cudaDeviceProp.maxGridSize[0], cudaDeviceProp.maxGridSize[1], cudaDeviceProp.maxGridSize[2]); - GPUInfo("\ttotalConstMem = %lld", (unsigned long long int)cudaDeviceProp.totalConstMem); - GPUInfo("\tmajor = %d", cudaDeviceProp.major); - GPUInfo("\tminor = %d", cudaDeviceProp.minor); - GPUInfo("\tclockRate = %d", cudaDeviceProp.clockRate); - GPUInfo("\tmemoryClockRate = %d", cudaDeviceProp.memoryClockRate); - GPUInfo("\tmultiProcessorCount = %d", cudaDeviceProp.multiProcessorCount); - GPUInfo("\ttextureAlignment = %lld", (unsigned long long int)cudaDeviceProp.textureAlignment); + GPUInfo("Using CUDA Device %s with Properties:", deviceProp.name); + GPUInfo("\ttotalGlobalMem = %lld", (unsigned long long int)deviceProp.totalGlobalMem); + GPUInfo("\tsharedMemPerBlock = %lld", (unsigned long long int)deviceProp.sharedMemPerBlock); + GPUInfo("\tregsPerBlock = %d", deviceProp.regsPerBlock); + GPUInfo("\twarpSize = %d", deviceProp.warpSize); + GPUInfo("\tmemPitch = %lld", (unsigned long long int)deviceProp.memPitch); + GPUInfo("\tmaxThreadsPerBlock = %d", deviceProp.maxThreadsPerBlock); + GPUInfo("\tmaxThreadsDim = %d %d %d", deviceProp.maxThreadsDim[0], deviceProp.maxThreadsDim[1], deviceProp.maxThreadsDim[2]); + GPUInfo("\tmaxGridSize = %d %d %d", deviceProp.maxGridSize[0], deviceProp.maxGridSize[1], deviceProp.maxGridSize[2]); + GPUInfo("\ttotalConstMem = %lld", (unsigned long long int)deviceProp.totalConstMem); + GPUInfo("\tmajor = %d", deviceProp.major); + GPUInfo("\tminor = %d", deviceProp.minor); + GPUInfo("\tclockRate = %d", deviceProp.clockRate); + GPUInfo("\tmemoryClockRate = %d", deviceProp.memoryClockRate); + GPUInfo("\tmultiProcessorCount = %d", deviceProp.multiProcessorCount); + GPUInfo("\ttextureAlignment = %lld", (unsigned long long int)deviceProp.textureAlignment); GPUInfo(" "); } - if (cudaDeviceProp.warpSize != GPUCA_WARP_SIZE) { + if (deviceProp.warpSize != GPUCA_WARP_SIZE) { throw std::runtime_error("Invalid warp size on GPU"); } - mBlockCount = cudaDeviceProp.multiProcessorCount; + mBlockCount = deviceProp.multiProcessorCount; + mMaxThreads = std::max(mMaxThreads, deviceProp.maxThreadsPerBlock * mBlockCount); +#ifndef __HIPCC__ // CUDA mWarpSize = 32; - mMaxThreads = std::max(mMaxThreads, cudaDeviceProp.maxThreadsPerBlock * mBlockCount); - mDeviceName = cudaDeviceProp.name; +#else // HIP + mWarpSize = 64; +#endif + mDeviceName = deviceProp.name; mDeviceName += " (CUDA GPU)"; - if (cudaDeviceProp.major < 3) { + if (deviceProp.major < 3) { GPUError("Unsupported CUDA Device"); return (1); } #ifdef GPUCA_USE_TEXTURES - if (GPUCA_SLICE_DATA_MEMORY * NSLICES > (size_t)cudaDeviceProp.maxTexture1DLinear) { - GPUError("Invalid maximum texture size of device: %lld < %lld\n", (long long int)cudaDeviceProp.maxTexture1DLinear, (long long int)(GPUCA_SLICE_DATA_MEMORY * NSLICES)); + if (GPUCA_SLICE_DATA_MEMORY * NSLICES > (size_t)deviceProp.maxTexture1DLinear) { + GPUError("Invalid maximum texture size of device: %lld < %lld\n", (long long int)deviceProp.maxTexture1DLinear, (long long int)(GPUCA_SLICE_DATA_MEMORY * NSLICES)); return (1); } #endif #ifndef GPUCA_NO_CONSTANT_MEMORY - if (gGPUConstantMemBufferSize > cudaDeviceProp.totalConstMem) { - GPUError("Insufficient constant memory available on GPU %d < %d!", (int)cudaDeviceProp.totalConstMem, (int)gGPUConstantMemBufferSize); + if (gGPUConstantMemBufferSize > deviceProp.totalConstMem) { + GPUError("Insufficient constant memory available on GPU %d < %d!", (int)deviceProp.totalConstMem, (int)gGPUConstantMemBufferSize); return (1); } #endif +#ifndef __HIPCC__ // CUDA if (contextCreated == 0 && GPUFailedMsgI(cudaInitDevice(mDeviceId, 0, 0))) { +#else // HIP + if (contextCreated == 0 && GPUFailedMsgI(hipSetDevice(mDeviceId))) { +#endif GPUError("Could not set CUDA Device!"); return (1); } +#ifndef __HIPCC__ // CUDA if (GPUFailedMsgI(cudaDeviceSetLimit(cudaLimitStackSize, GPUCA_GPU_STACK_SIZE))) { GPUError("Error setting CUDA stack size"); GPUFailedMsgI(cudaDeviceReset()); @@ -280,9 +312,15 @@ int GPUReconstructionCUDA::InitDevice_Runtime() GPUFailedMsgI(cudaDeviceReset()); return (1); } +#else // HIP + if (GPUFailedMsgI(hipSetDeviceFlags(hipDeviceScheduleBlockingSync))) { + GPUError("Could not set HIP Device flags!"); + return (1); + } +#endif if (mDeviceMemorySize == 1 || mDeviceMemorySize == 2) { - mDeviceMemorySize = std::max(0, devMemory[mDeviceId] - REQUIRE_FREE_MEMORY_RESERVED_PER_SM * cudaDeviceProp.multiProcessorCount); // Take all GPU memory but some reserve + mDeviceMemorySize = std::max(0, devMemory[mDeviceId] - REQUIRE_FREE_MEMORY_RESERVED_PER_SM * deviceProp.multiProcessorCount); // Take all GPU memory but some reserve if (mDeviceMemorySize >= RESERVE_EXTRA_MEM_THRESHOLD) { mDeviceMemorySize -= RESERVE_EXTRA_MEM_OFFSET; } @@ -291,10 +329,10 @@ int GPUReconstructionCUDA::InitDevice_Runtime() mDeviceMemorySize = mDeviceMemorySize * 2 / 3; // Leave 1/3 of GPU memory for event display } - if (mDeviceMemorySize > cudaDeviceProp.totalGlobalMem || GPUFailedMsgI(cudaMalloc(&mDeviceMemoryBase, mDeviceMemorySize))) { + if (mDeviceMemorySize > deviceProp.totalGlobalMem || GPUFailedMsgI(cudaMalloc(&mDeviceMemoryBase, mDeviceMemorySize))) { size_t free, total; GPUFailedMsg(cudaMemGetInfo(&free, &total)); - GPUError("CUDA Memory Allocation Error (trying %lld bytes, %lld available on GPU, %lld free)", (long long int)mDeviceMemorySize, (long long int)cudaDeviceProp.totalGlobalMem, (long long int)free); + GPUError("CUDA Memory Allocation Error (trying %lld bytes, %lld available on GPU, %lld free)", (long long int)mDeviceMemorySize, (long long int)deviceProp.totalGlobalMem, (long long int)free); GPUFailedMsgI(cudaDeviceReset()); return (1); } @@ -321,20 +359,22 @@ int GPUReconstructionCUDA::InitDevice_Runtime() } } +#ifndef __HIPCC__ // CUDA dummyInitKernel<<>>(mDeviceMemoryBase); +#else // HIP + hipLaunchKernelGGL(HIP_KERNEL_NAME(dummyInitKernel), dim3(mBlockCount), dim3(256), 0, 0, mDeviceMemoryBase); +#endif #ifndef GPUCA_ALIROOT_LIB if (mProcessingSettings.rtc.enable) { - if (genRTC()) { - throw std::runtime_error("Runtime compilation failed"); - } + genAndLoadRTC(); } #if defined(GPUCA_KERNEL_COMPILE_MODE) && GPUCA_KERNEL_COMPILE_MODE == 1 else { -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNL(x_class, ...) \ mInternals->kernelModules.emplace_back(std::make_unique()); \ - GPUFailedMsg(cuModuleLoadData(mInternals->kernelModules.back().get(), GPUCA_M_CAT3(_binary_cuda_kernel_module_fatbin_krnl_, GPUCA_M_KRNL_NAME(x_class), _fatbin_start))); -#include "GPUReconstructionKernels.h" + GPUFailedMsg(cuModuleLoadData(mInternals->kernelModules.back().get(), GPUCA_M_CAT3(_binary_cuda_kernel_module_fatbin_krnl_, GPUCA_M_KRNL_NAME(x_class), GPUCA_M_CAT(PER_KERNEL_OBJECT_EXT, _start)))); +#include "GPUReconstructionKernelList.h" #undef GPUCA_KRNL loadKernelModules(true, false); } @@ -345,8 +385,13 @@ int GPUReconstructionCUDA::InitDevice_Runtime() runConstantRegistrators(); devPtrConstantMem = mDeviceConstantMemList[0]; for (unsigned int i = 0; i < mInternals->kernelModules.size(); i++) { - CUdeviceptr tmp; - GPUFailedMsg(cuModuleGetGlobal(&tmp, nullptr, *mInternals->kernelModules[i], "gGPUConstantMemBuffer")); +#ifndef __HIPCC__ + CUdeviceptr tmp; // CUDA has a custom type, that initializes to zero and cannot be initialized with nullptr +#else + CUdeviceptr tmp = nullptr; // HIP just uses void* +#endif + size_t tmpSize = 0; + GPUFailedMsg(cuModuleGetGlobal(&tmp, &tmpSize, *mInternals->kernelModules[i], "gGPUConstantMemBuffer")); mDeviceConstantMemList.emplace_back((void*)tmp); } #else @@ -354,7 +399,7 @@ int GPUReconstructionCUDA::InitDevice_Runtime() #endif mDeviceConstantMem = (GPUConstantMem*)devPtrConstantMem; - GPUInfo("CUDA Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %lld / %lld bytes host / global memory, Stack frame %d, Constant memory %lld)", mDeviceId, cudaDeviceProp.name, cudaDeviceProp.clockRate, cudaDeviceProp.multiProcessorCount, (long long int)mHostMemorySize, (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); + GPUInfo("CUDA Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %lld / %lld bytes host / global memory, Stack frame %d, Constant memory %lld)", mDeviceId, deviceProp.name, deviceProp.clockRate, deviceProp.multiProcessorCount, (long long int)mHostMemorySize, (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); } else { GPUReconstructionCUDA* master = dynamic_cast(mMaster); mDeviceId = master->mDeviceId; @@ -374,7 +419,11 @@ int GPUReconstructionCUDA::InitDevice_Runtime() for (unsigned int i = 0; i < mEvents.size(); i++) { cudaEvent_t* events = (cudaEvent_t*)mEvents[i].data(); for (unsigned int j = 0; j < mEvents[i].size(); j++) { +#ifndef __HIPCC__ // CUDA if (GPUFailedMsgI(cudaEventCreate(&events[j]))) { +#else + if (GPUFailedMsgI(hipEventCreateWithFlags(&events[j], hipEventBlockingSync))) { +#endif GPUError("Error creating event"); GPUFailedMsgI(cudaDeviceReset()); return 1; @@ -385,6 +434,27 @@ int GPUReconstructionCUDA::InitDevice_Runtime() return (0); } +void GPUReconstructionCUDA::genAndLoadRTC() +{ + std::string filename = ""; + unsigned int nCompile = 0; + if (genRTC(filename, nCompile)) { + throw std::runtime_error("Runtime compilation failed"); + } + for (unsigned int i = 0; i < nCompile; i++) { + if (mProcessingSettings.rtc.runTest != 2) { + mInternals->kernelModules.emplace_back(std::make_unique()); + GPUFailedMsg(cuModuleLoad(mInternals->kernelModules.back().get(), (filename + "_" + std::to_string(i) + mRtcBinExtension).c_str())); + } + remove((filename + "_" + std::to_string(i) + mRtcSrcExtension).c_str()); + remove((filename + "_" + std::to_string(i) + mRtcBinExtension).c_str()); + } + if (mProcessingSettings.rtc.runTest == 2) { + return; + } + loadKernelModules(mProcessingSettings.rtc.compilePerKernel); +} + int GPUReconstructionCUDA::ExitDevice_Runtime() { // Uninitialize CUDA @@ -410,6 +480,10 @@ int GPUReconstructionCUDA::ExitDevice_Runtime() } GPUFailedMsgI(cudaFreeHost(mHostMemoryBase)); + for (unsigned int i = 0; i < mInternals->kernelModules.size(); i++) { + GPUFailedMsg(cuModuleUnload(*mInternals->kernelModules[i])); + } + GPUFailedMsgI(cudaDeviceReset()); GPUInfo("CUDA Uninitialized"); } @@ -419,7 +493,7 @@ int GPUReconstructionCUDA::ExitDevice_Runtime() return (0); } -size_t GPUReconstructionCUDA::GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev, deviceEvent* evList, int nEvents) +size_t GPUReconstructionCUDA::GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev, deviceEvent* evList, int nEvents) { if (mProcessingSettings.debugLevel >= 3) { stream = -1; @@ -432,17 +506,17 @@ size_t GPUReconstructionCUDA::GPUMemCpy(void* dst, const void* src, size_t size, nEvents = 0; } for (int k = 0; k < nEvents; k++) { - GPUFailedMsg(cudaStreamWaitEvent(mInternals->Streams[stream], ((cudaEvent_t*)evList)[k], 0)); + GPUFailedMsg(cudaStreamWaitEvent(mInternals->Streams[stream], evList[k].get(), 0)); } GPUFailedMsg(cudaMemcpyAsync(dst, src, size, toGPU == -2 ? cudaMemcpyDeviceToDevice : toGPU ? cudaMemcpyHostToDevice : cudaMemcpyDeviceToHost, mInternals->Streams[stream])); } if (ev) { - GPUFailedMsg(cudaEventRecord(*(cudaEvent_t*)ev, mInternals->Streams[stream == -1 ? 0 : stream])); + GPUFailedMsg(cudaEventRecord(ev->get(), mInternals->Streams[stream == -1 ? 0 : stream])); } return size; } -size_t GPUReconstructionCUDA::TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) +size_t GPUReconstructionCUDA::TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent* ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) { if (!(res->Type() & GPUMemoryResource::MEMORY_GPU)) { if (mProcessingSettings.debugLevel >= 4) { @@ -456,7 +530,7 @@ size_t GPUReconstructionCUDA::TransferMemoryInternal(GPUMemoryResource* res, int return GPUMemCpy(dst, src, res->Size(), stream, toGPU, ev, evList, nEvents); } -size_t GPUReconstructionCUDA::WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream, deviceEvent ev) +size_t GPUReconstructionCUDA::WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream, deviceEvent* ev) { for (unsigned int i = 0; i < 1 + mDeviceConstantMemList.size(); i++) { void* basePtr = i ? mDeviceConstantMemList[i - 1] : mDeviceConstantMem; @@ -470,17 +544,17 @@ size_t GPUReconstructionCUDA::WriteToConstantMemory(size_t offset, const void* s } } if (ev && stream != -1) { - GPUFailedMsg(cudaEventRecord(*(cudaEvent_t*)ev, mInternals->Streams[stream])); + GPUFailedMsg(cudaEventRecord(ev->get(), mInternals->Streams[stream])); } return size; } void GPUReconstructionCUDA::ReleaseEvent(deviceEvent ev) {} -void GPUReconstructionCUDA::RecordMarker(deviceEvent ev, int stream) { GPUFailedMsg(cudaEventRecord(*(cudaEvent_t*)ev, mInternals->Streams[stream])); } +void GPUReconstructionCUDA::RecordMarker(deviceEvent ev, int stream) { GPUFailedMsg(cudaEventRecord(ev.get(), mInternals->Streams[stream])); } std::unique_ptr GPUReconstructionCUDA::GetThreadContext() { - GPUFailedMsgI(cudaSetDevice(mDeviceId)); + GPUFailedMsg(cudaSetDevice(mDeviceId)); return std::unique_ptr(new GPUThreadContext); } @@ -490,21 +564,21 @@ void GPUReconstructionCUDA::SynchronizeStream(int stream) { GPUFailedMsg(cudaStr void GPUReconstructionCUDA::SynchronizeEvents(deviceEvent* evList, int nEvents) { for (int i = 0; i < nEvents; i++) { - GPUFailedMsg(cudaEventSynchronize(((cudaEvent_t*)evList)[i])); + GPUFailedMsg(cudaEventSynchronize(evList[i].get())); } } void GPUReconstructionCUDA::StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents) { for (int i = 0; i < nEvents; i++) { - GPUFailedMsg(cudaStreamWaitEvent(mInternals->Streams[stream], ((cudaEvent_t*)evList)[i], 0)); + GPUFailedMsg(cudaStreamWaitEvent(mInternals->Streams[stream], evList[i].get(), 0)); } } bool GPUReconstructionCUDA::IsEventDone(deviceEvent* evList, int nEvents) { for (int i = 0; i < nEvents; i++) { - cudaError_t retVal = cudaEventSynchronize(((cudaEvent_t*)evList)[i]); + cudaError_t retVal = cudaEventSynchronize(evList[i].get()); if (retVal == cudaErrorNotReady) { return false; } @@ -519,10 +593,10 @@ int GPUReconstructionCUDA::GPUDebug(const char* state, int stream, bool force) cudaError cuErr; cuErr = cudaGetLastError(); if (cuErr != cudaSuccess) { - GPUError("Cuda Error %s while running kernel (%s) (Stream %d)", cudaGetErrorString(cuErr), state, stream); + GPUError("CUDA Error %s while running kernel (%s) (Stream %d)", cudaGetErrorString(cuErr), state, stream); return (1); } - if (force == false && mProcessingSettings.debugLevel <= 0) { + if (!force && mProcessingSettings.debugLevel <= 0) { return (0); } if (GPUFailedMsgI(stream == -1 ? cudaDeviceSynchronize() : cudaStreamSynchronize(mInternals->Streams[stream]))) { @@ -535,18 +609,6 @@ int GPUReconstructionCUDA::GPUDebug(const char* state, int stream, bool force) return (0); } -int GPUReconstructionCUDA::PrepareTextures() -{ -#ifdef GPUCA_USE_TEXTURES - cudaChannelFormatDesc channelDescu2 = cudaCreateChannelDesc(); - size_t offset; - GPUFailedMsg(cudaBindTexture(&offset, &gAliTexRefu2, mProcessorsShadow->tpcTrackers[0].Data().Memory(), &channelDescu2, NSLICES * GPUCA_SLICE_DATA_MEMORY)); - cudaChannelFormatDesc channelDescu = cudaCreateChannelDesc(); - GPUFailedMsg(cudaBindTexture(&offset, &gAliTexRefu, mProcessorsShadow->tpcTrackers[0].Data().Memory(), &channelDescu, NSLICES * GPUCA_SLICE_DATA_MEMORY)); -#endif - return (0); -} - int GPUReconstructionCUDA::registerMemoryForGPU_internal(const void* ptr, size_t size) { return GPUFailedMsgI(cudaHostRegister((void*)ptr, size, cudaHostRegisterDefault)); @@ -557,16 +619,6 @@ int GPUReconstructionCUDA::unregisterMemoryForGPU_internal(const void* ptr) return GPUFailedMsgI(cudaHostUnregister((void*)ptr)); } -void GPUReconstructionCUDA::startGPUProfiling() -{ - GPUFailedMsg(cudaProfilerStart()); -} - -void GPUReconstructionCUDA::endGPUProfiling() -{ - GPUFailedMsg(cudaProfilerStop()); -} - void GPUReconstructionCUDABackend::PrintKernelOccupancies() { int maxBlocks = 0, threads = 0, suggestedBlocks = 0, nRegs = 0, sMem = 0; @@ -580,33 +632,72 @@ void GPUReconstructionCUDABackend::PrintKernelOccupancies() } } -int GPUReconstructionCUDA::loadKernelModules(bool perKernel, bool perSingleMulti) +void GPUReconstructionCUDA::loadKernelModules(bool perKernel, bool perSingleMulti) { - int j = 0; -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) \ + unsigned int j = 0; +#define GPUCA_KRNL(...) \ + GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, __VA_ARGS__) \ j += !perSingleMulti; -#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) \ - mInternals->getRTCkernelNum(mInternals->kernelFunctions.size()); \ - mInternals->kernelFunctions.emplace_back(new CUfunction); \ - mInternals->kernelNames.emplace_back(GPUCA_M_STR(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class)))); \ - GPUFailedMsg(cuModuleGetFunction(mInternals->kernelFunctions.back().get(), *mInternals->kernelModules[perKernel ? (j += perSingleMulti) : 0], GPUCA_M_STR(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))))); -#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) \ - mInternals->getRTCkernelNum(mInternals->kernelFunctions.size()); \ - mInternals->kernelFunctions.emplace_back(new CUfunction); \ - mInternals->kernelNames.emplace_back(GPUCA_M_STR(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi))); \ - GPUFailedMsg(cuModuleGetFunction(mInternals->kernelFunctions.back().get(), *mInternals->kernelModules[perKernel ? (j += perSingleMulti) : 0], GPUCA_M_STR(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)))); -#include "GPUReconstructionKernels.h" +#define GPUCA_KRNL_LOAD_single(x_class, ...) \ + getRTCkernelNum(mInternals->kernelFunctions.size()); \ + mInternals->kernelFunctions.emplace_back(new CUfunction); \ + mInternals->kernelNames.emplace_back(GPUCA_M_STR(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class)))); \ + if (mProcessingSettings.debugLevel >= 3) { \ + GPUInfo("Loading kernel %s (j = %u)", GPUCA_M_STR(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))), j); \ + } \ + GPUFailedMsg(cuModuleGetFunction(mInternals->kernelFunctions.back().get(), *mInternals->kernelModules[perKernel ? j : 0], GPUCA_M_STR(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))))); \ + j += perSingleMulti; +#define GPUCA_KRNL_LOAD_multi(x_class, ...) \ + getRTCkernelNum(mInternals->kernelFunctions.size()); \ + mInternals->kernelFunctions.emplace_back(new CUfunction); \ + mInternals->kernelNames.emplace_back(GPUCA_M_STR(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi))); \ + if (mProcessingSettings.debugLevel >= 3) { \ + GPUInfo("Loading kernel %s (j = %u)", GPUCA_M_STR(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)), j); \ + } \ + GPUFailedMsg(cuModuleGetFunction(mInternals->kernelFunctions.back().get(), *mInternals->kernelModules[perKernel ? j : 0], GPUCA_M_STR(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)))); \ + j += perSingleMulti; +#include "GPUReconstructionKernelList.h" #undef GPUCA_KRNL #undef GPUCA_KRNL_LOAD_single #undef GPUCA_KRNL_LOAD_multi - for (unsigned int i = 0; i < mInternals->kernelNames.size(); i++) { - if (mProcessingSettings.debugLevel >= 3) { - GPUInfo("Loaded module for kernel %s", mInternals->kernelNames[i].c_str()); - } + if (j != mInternals->kernelModules.size()) { + GPUFatal("Did not load all kernels (%u < %u)", j, (unsigned int)mInternals->kernelModules.size()); } - return 0; } +#ifndef __HIPCC__ // CUDA +int GPUReconstructionCUDA::PrepareTextures() +{ +#ifdef GPUCA_USE_TEXTURES + cudaChannelFormatDesc channelDescu2 = cudaCreateChannelDesc(); + size_t offset; + GPUFailedMsg(cudaBindTexture(&offset, &gAliTexRefu2, mProcessorsShadow->tpcTrackers[0].Data().Memory(), &channelDescu2, NSLICES * GPUCA_SLICE_DATA_MEMORY)); + cudaChannelFormatDesc channelDescu = cudaCreateChannelDesc(); + GPUFailedMsg(cudaBindTexture(&offset, &gAliTexRefu, mProcessorsShadow->tpcTrackers[0].Data().Memory(), &channelDescu, NSLICES * GPUCA_SLICE_DATA_MEMORY)); +#endif + return (0); +} + +void GPUReconstructionCUDA::startGPUProfiling() +{ + GPUFailedMsg(cudaProfilerStart()); +} + +void GPUReconstructionCUDA::endGPUProfiling() +{ + GPUFailedMsg(cudaProfilerStop()); +} +#else // HIP +void* GPUReconstructionHIP::getGPUPointer(void* ptr) +{ + void* retVal = nullptr; + GPUFailedMsg(hipHostGetDevicePointer(&retVal, ptr, 0)); + return retVal; +} +#endif // __HIPCC__ + +namespace GPUCA_NAMESPACE::gpu +{ template class GPUReconstructionKernels; +} diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h index d847e0af5c4b6..8a483adb3353a 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDA.h @@ -16,6 +16,8 @@ #define GPURECONSTRUCTIONCUDA_H #include "GPUReconstructionDeviceBase.h" +#include +#include #ifdef _WIN32 extern "C" __declspec(dllexport) GPUCA_NAMESPACE::gpu::GPUReconstruction* GPUReconstruction_Create_CUDA(const GPUCA_NAMESPACE::gpu::GPUSettingsDeviceBackend& cfg); @@ -42,14 +44,19 @@ class GPUReconstructionCUDABackend : public GPUReconstructionDeviceBase void PrintKernelOccupancies() override; template - int runKernelBackend(krnlSetup& _xyz, Args... args); + int runKernelBackend(const krnlSetupArgs& args); template - void runKernelBackendInternal(krnlSetup& _xyz, const Args&... args); + void runKernelBackendInternal(const krnlSetupTime& _xyz, const Args&... args); template - const krnlProperties getKernelPropertiesBackend(); + gpu_reconstruction_kernels::krnlProperties getKernelPropertiesBackend(); template class backendInternal; + template + static int getRTCkernelNum(int k = -1); + + void getRTCKernelCalls(std::vector& kernels); + GPUReconstructionCUDAInternals* mInternals; }; @@ -65,31 +72,37 @@ class GPUReconstructionCUDA : public GPUReconstructionKernels GetThreadContext() override; - bool CanQueryMaxMemory() override { return true; } void SynchronizeGPU() override; int GPUDebug(const char* state = "UNKNOWN", int stream = -1, bool force = false) override; void SynchronizeStream(int stream) override; void SynchronizeEvents(deviceEvent* evList, int nEvents = 1) override; void StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents = 1) override; bool IsEventDone(deviceEvent* evList, int nEvents = 1) override; - - int PrepareTextures() override; int registerMemoryForGPU_internal(const void* ptr, size_t size) override; int unregisterMemoryForGPU_internal(const void* ptr) override; - void startGPUProfiling() override; - void endGPUProfiling() override; - size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, deviceEvent ev = nullptr) override; - size_t TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) override; - size_t GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override; + size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, deviceEvent* ev = nullptr) override; + size_t TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent* ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) override; + size_t GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override; void ReleaseEvent(deviceEvent ev) override; void RecordMarker(deviceEvent ev, int stream) override; void GetITSTraits(std::unique_ptr* trackerTraits, std::unique_ptr* vertexerTraits, std::unique_ptr* timeFrame) override; +#ifndef __HIPCC__ // CUDA + bool CanQueryMaxMemory() override { return true; } + int PrepareTextures() override; + void startGPUProfiling() override; + void endGPUProfiling() override; +#else // HIP + void* getGPUPointer(void* ptr) override; +#endif + private: - int genRTC(); - int loadKernelModules(bool perKernel, bool perSingleMulti = true); + int genRTC(std::string& filename, unsigned int& nCompile); + void genAndLoadRTC(); + void loadKernelModules(bool perKernel, bool perSingleMulti = true); + const char *mRtcSrcExtension = ".src", *mRtcBinExtension = ".o"; }; } // namespace gpu diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cxx similarity index 70% rename from GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cu rename to GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cxx index 9e11d4dcc17bb..9c2bcacc2ae43 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAGenRTC.cxx @@ -13,18 +13,19 @@ /// \author David Rohr #define GPUCA_GPUCODE_HOSTONLY +#ifdef WITH_OPENMP #include -#include -#include -#include "GPUReconstructionCUDADef.h" +#endif #include "GPUReconstructionCUDA.h" -#include "GPUReconstructionCUDAInternals.h" #include "GPUParamRTC.h" #include "GPUDefMacros.h" #include #ifdef GPUCA_HAVE_O2HEADERS #include "Framework/SHA1.h" #endif +#include +#include +#include using namespace GPUCA_NAMESPACE::gpu; @@ -34,28 +35,22 @@ QGET_LD_BINARY_SYMBOLS(GPUReconstructionCUDArtc_src); QGET_LD_BINARY_SYMBOLS(GPUReconstructionCUDArtc_command); #endif -int GPUReconstructionCUDA::genRTC() +int GPUReconstructionCUDA::genRTC(std::string& filename, unsigned int& nCompile) { #ifndef GPUCA_ALIROOT_LIB std::string rtcparam = GPUParamRTC::generateRTCCode(param(), mProcessingSettings.rtc.optConstexpr); - std::string filename = "/tmp/o2cagpu_rtc_"; + if (filename == "") { + filename = "/tmp/o2cagpu_rtc_"; + } filename += std::to_string(getpid()); filename += "_"; filename += std::to_string(rand()); std::vector kernels; + getRTCKernelCalls(kernels); std::string kernelsall; -#undef GPUCA_KRNL_REG -#define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) kernels.emplace_back(GPUCA_M_STR(GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward))); -#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) kernels.emplace_back(GPUCA_M_STR(GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward))); -#include "GPUReconstructionKernels.h" -#undef GPUCA_KRNL -#undef GPUCA_KRNL_LOAD_single -#undef GPUCA_KRNL_LOAD_multi for (unsigned int i = 0; i < kernels.size(); i++) { - kernelsall += kernels[i]; + kernelsall += kernels[i] + "\n"; } #ifdef GPUCA_HAVE_O2HEADERS @@ -68,13 +63,29 @@ int GPUReconstructionCUDA::genRTC() } #endif - unsigned int nCompile = mProcessingSettings.rtc.compilePerKernel ? kernels.size() : 1; + nCompile = mProcessingSettings.rtc.compilePerKernel ? kernels.size() : 1; bool cacheLoaded = false; + int fd = 0; if (mProcessingSettings.rtc.cacheOutput) { + if (mProcessingSettings.RTCcacheFolder != ".") { + std::filesystem::create_directories(mProcessingSettings.RTCcacheFolder); + } #ifndef GPUCA_HAVE_O2HEADERS throw std::runtime_error("Cannot use RTC cache without O2 headers"); #else - FILE* fp = fopen("rtc.cuda.cache", "rb"); + if (mProcessingSettings.rtc.cacheMutex) { + mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + fd = open((mProcessingSettings.RTCcacheFolder + "/cache.lock").c_str(), O_RDWR | O_CREAT | O_CLOEXEC, mask); + if (fd == -1) { + throw std::runtime_error("Error opening rtc cache mutex lock file"); + } + fchmod(fd, mask); + if (lockf(fd, F_LOCK, 0)) { + throw std::runtime_error("Error locking rtc cache mutex file"); + } + } + + FILE* fp = fopen((mProcessingSettings.RTCcacheFolder + "/rtc.cuda.cache").c_str(), "rb"); char sharead[20]; if (fp) { size_t len; @@ -82,36 +93,37 @@ int GPUReconstructionCUDA::genRTC() if (fread(sharead, 1, 20, fp) != 20) { throw std::runtime_error("Cache file corrupt"); } - if (memcmp(sharead, shasource, 20)) { + if (!mProcessingSettings.rtc.ignoreCacheValid && memcmp(sharead, shasource, 20)) { GPUInfo("Cache file content outdated (source)"); break; } if (fread(sharead, 1, 20, fp) != 20) { throw std::runtime_error("Cache file corrupt"); } - if (memcmp(sharead, shaparam, 20)) { + if (!mProcessingSettings.rtc.ignoreCacheValid && memcmp(sharead, shaparam, 20)) { GPUInfo("Cache file content outdated (param)"); break; } if (fread(sharead, 1, 20, fp) != 20) { throw std::runtime_error("Cache file corrupt"); } - if (memcmp(sharead, shacmd, 20)) { + if (!mProcessingSettings.rtc.ignoreCacheValid && memcmp(sharead, shacmd, 20)) { GPUInfo("Cache file content outdated (commandline)"); break; } if (fread(sharead, 1, 20, fp) != 20) { throw std::runtime_error("Cache file corrupt"); } - if (memcmp(sharead, shakernels, 20)) { + if (!mProcessingSettings.rtc.ignoreCacheValid && memcmp(sharead, shakernels, 20)) { GPUInfo("Cache file content outdated (kernel definitions)"); break; } GPUSettingsProcessingRTC cachedSettings; + static_assert(std::is_trivially_copyable_v == true, "GPUSettingsProcessingRTC must be POD"); if (fread(&cachedSettings, sizeof(cachedSettings), 1, fp) != 1) { throw std::runtime_error("Cache file corrupt"); } - if (memcmp(&cachedSettings, &mProcessingSettings.rtc, sizeof(cachedSettings))) { + if (!mProcessingSettings.rtc.ignoreCacheValid && memcmp(&cachedSettings, &mProcessingSettings.rtc, sizeof(cachedSettings))) { GPUInfo("Cache file content outdated (rtc parameters)"); break; } @@ -124,7 +136,7 @@ int GPUReconstructionCUDA::genRTC() if (fread(buffer.data(), 1, len, fp) != len) { throw std::runtime_error("Cache file corrupt"); } - FILE* fp2 = fopen((filename + "_" + std::to_string(i) + ".cubin").c_str(), "w+b"); + FILE* fp2 = fopen((filename + "_" + std::to_string(i) + mRtcBinExtension).c_str(), "w+b"); if (fp2 == nullptr) { throw std::runtime_error("Cannot open tmp file"); } @@ -147,12 +159,15 @@ int GPUReconstructionCUDA::genRTC() } HighResTimer rtcTimer; rtcTimer.ResetStart(); -#pragma omp parallel for + std::string baseCommand = getenv("O2_GPU_RTC_OVERRIDE_CMD") ? std::string(getenv("O2_GPU_RTC_OVERRIDE_CMD")) : std::string(_binary_GPUReconstructionCUDArtc_command_start, _binary_GPUReconstructionCUDArtc_command_len); +#ifdef WITH_OPENMP +#pragma omp parallel for schedule(dynamic, 1) +#endif for (unsigned int i = 0; i < nCompile; i++) { if (mProcessingSettings.debugLevel >= 3) { - printf("Compiling %s\n", (filename + "_" + std::to_string(i) + ".cu").c_str()); + printf("Compiling %s\n", (filename + "_" + std::to_string(i) + mRtcSrcExtension).c_str()); } - FILE* fp = fopen((filename + "_" + std::to_string(i) + ".cu").c_str(), "w+b"); + FILE* fp = fopen((filename + "_" + std::to_string(i) + mRtcSrcExtension).c_str(), "w+b"); if (fp == nullptr) { throw std::runtime_error("Error opening file"); } @@ -167,8 +182,13 @@ int GPUReconstructionCUDA::genRTC() throw std::runtime_error("Error writing file"); } fclose(fp); - std::string command = std::string(_binary_GPUReconstructionCUDArtc_command_start, _binary_GPUReconstructionCUDArtc_command_len); - command += " -cubin -c " + filename + "_" + std::to_string(i) + ".cu -o " + filename + "_" + std::to_string(i) + ".cubin"; + std::string command = baseCommand; + command += " -c " + filename + "_" + std::to_string(i) + mRtcSrcExtension + " -o " + filename + "_" + std::to_string(i) + mRtcBinExtension; + if (mProcessingSettings.debugLevel < 0) { + command += " &> /dev/null"; + } else if (mProcessingSettings.debugLevel < 2) { + command += " > /dev/null"; + } if (mProcessingSettings.debugLevel >= 3) { printf("Running command %s\n", command.c_str()); } @@ -184,7 +204,7 @@ int GPUReconstructionCUDA::genRTC() } #ifdef GPUCA_HAVE_O2HEADERS if (mProcessingSettings.rtc.cacheOutput) { - FILE* fp = fopen("rtc.cuda.cache", "w+b"); + FILE* fp = fopen((mProcessingSettings.RTCcacheFolder + "/rtc.cuda.cache").c_str(), "w+b"); if (fp == nullptr) { throw std::runtime_error("Cannot open cache file for writing"); } @@ -200,7 +220,7 @@ int GPUReconstructionCUDA::genRTC() std::vector buffer; for (unsigned int i = 0; i < nCompile; i++) { - FILE* fp2 = fopen((filename + "_" + std::to_string(i) + ".cubin").c_str(), "rb"); + FILE* fp2 = fopen((filename + "_" + std::to_string(i) + mRtcBinExtension).c_str(), "rb"); if (fp2 == nullptr) { throw std::runtime_error("Cannot open cuda module file"); } @@ -222,32 +242,13 @@ int GPUReconstructionCUDA::genRTC() } #endif } - - for (unsigned int i = 0; i < nCompile; i++) { - mInternals->kernelModules.emplace_back(std::make_unique()); - GPUFailedMsg(cuModuleLoad(mInternals->kernelModules.back().get(), (filename + "_" + std::to_string(i) + ".cubin").c_str())); - remove((filename + "_" + std::to_string(i) + ".cu").c_str()); - remove((filename + "_" + std::to_string(i) + ".cubin").c_str()); + if (mProcessingSettings.rtc.cacheOutput && mProcessingSettings.rtc.cacheMutex) { + if (lockf(fd, F_ULOCK, 0)) { + throw std::runtime_error("Error unlocking RTC cache mutex file"); + } + close(fd); } - loadKernelModules(mProcessingSettings.rtc.compilePerKernel); - #endif return 0; } - -template -int GPUReconstructionCUDAInternals::getRTCkernelNum(int k) -{ - static int num = k; - if (num < 0) { - throw std::runtime_error("Invalid kernel"); - } - return num; -} - -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ - template int GPUReconstructionCUDAInternals::getRTCkernelNum(int k); \ - template int GPUReconstructionCUDAInternals::getRTCkernelNum(int k); -#include "GPUReconstructionKernels.h" -#undef GPUCA_KRNL diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h index fa099ebb474cc..246677b4b9647 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAInternals.h @@ -36,9 +36,6 @@ struct GPUReconstructionCUDAInternals { std::vector kernelNames; // names of kernels cudaStream_t Streams[GPUCA_MAX_STREAMS]; // Pointer to array of CUDA Streams - template - static int getRTCkernelNum(int k = -1); - static void getArgPtrs(const void** pArgs) {} template static void getArgPtrs(const void** pArgs, const T& arg, const Args&... args) @@ -51,11 +48,11 @@ struct GPUReconstructionCUDAInternals { class GPUDebugTiming { public: - GPUDebugTiming(bool d, void** t, cudaStream_t* s, GPUReconstruction::krnlSetup& x, GPUReconstructionCUDABackend* r) : mDeviceTimers(t), mStreams(s), mXYZ(x), mRec(r), mDo(d) + GPUDebugTiming(bool d, gpu_reconstruction_kernels::deviceEvent* t, cudaStream_t* s, const gpu_reconstruction_kernels::krnlSetupTime& x, GPUReconstructionCUDABackend* r) : mDeviceTimers(t), mStreams(s), mXYZ(x), mRec(r), mDo(d) { if (mDo) { if (mDeviceTimers) { - mRec->GPUFailedMsg(cudaEventRecord((cudaEvent_t)mDeviceTimers[0], mStreams[mXYZ.x.stream])); + mRec->GPUFailedMsg(cudaEventRecord(mDeviceTimers[0].get(), mStreams[mXYZ.x.stream])); } else { mTimer.ResetStart(); } @@ -63,12 +60,12 @@ class GPUDebugTiming } ~GPUDebugTiming() { - if (mDo) { + if (mDo && mXYZ.t == 0.) { if (mDeviceTimers) { - mRec->GPUFailedMsg(cudaEventRecord((cudaEvent_t)mDeviceTimers[1], mStreams[mXYZ.x.stream])); - mRec->GPUFailedMsg(cudaEventSynchronize((cudaEvent_t)mDeviceTimers[1])); + mRec->GPUFailedMsg(cudaEventRecord(mDeviceTimers[1].get(), mStreams[mXYZ.x.stream])); + mRec->GPUFailedMsg(cudaEventSynchronize(mDeviceTimers[1].get())); float v; - mRec->GPUFailedMsg(cudaEventElapsedTime(&v, (cudaEvent_t)mDeviceTimers[0], (cudaEvent_t)mDeviceTimers[1])); + mRec->GPUFailedMsg(cudaEventElapsedTime(&v, mDeviceTimers[0].get(), mDeviceTimers[1].get())); mXYZ.t = v * 1.e-3f; } else { mRec->GPUFailedMsg(cudaStreamSynchronize(mStreams[mXYZ.x.stream])); @@ -78,9 +75,9 @@ class GPUDebugTiming } private: - GPUReconstruction::deviceEvent* mDeviceTimers; + gpu_reconstruction_kernels::deviceEvent* mDeviceTimers; cudaStream_t* mStreams; - GPUReconstruction::krnlSetup& mXYZ; + const gpu_reconstruction_kernels::krnlSetupTime& mXYZ; GPUReconstructionCUDABackend* mRec; HighResTimer mTimer; bool mDo; diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAKernels.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAKernels.cu index 70b6b7fc77693..ecf44b6407d3c 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAKernels.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAKernels.cu @@ -33,17 +33,14 @@ __global__ void gGPUConstantMemBuffer_dummy(int* p) { *p = *(int*)&gGPUConstantM #endif template <> -void GPUReconstructionCUDABackend::runKernelBackendInternal(krnlSetup& _xyz, void* const& ptr, unsigned long const& size) +inline void GPUReconstructionCUDABackend::runKernelBackendInternal(const krnlSetupTime& _xyz, void* const& ptr, unsigned long const& size) { - GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); GPUFailedMsg(cudaMemsetAsync(ptr, 0, size, mInternals->Streams[_xyz.x.stream])); } template -void GPUReconstructionCUDABackend::runKernelBackendInternal(krnlSetup& _xyz, const Args&... args) +inline void GPUReconstructionCUDABackend::runKernelBackendInternal(const krnlSetupTime& _xyz, const Args&... args) { -#ifndef __HIPCC__ // CUDA version - GPUDebugTiming timer(mProcessingSettings.deviceTimers && mProcessingSettings.debugLevel > 0, (void**)mDebugEvents, mInternals->Streams, _xyz, this); #if !defined(GPUCA_KERNEL_COMPILE_MODE) || GPUCA_KERNEL_COMPILE_MODE != 1 if (!mProcessingSettings.rtc.enable) { backendInternal::runKernelBackendMacro(_xyz, this, args...); @@ -61,91 +58,101 @@ void GPUReconstructionCUDABackend::runKernelBackendInternal(krnlSetup& _xyz, con pArgs[arg_offset] = &y.start; GPUReconstructionCUDAInternals::getArgPtrs(&pArgs[arg_offset + 1 + (y.num > 1)], args...); if (y.num <= 1) { - GPUFailedMsg(cuLaunchKernel(*mInternals->kernelFunctions[mInternals->getRTCkernelNum()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); + GPUFailedMsg(cuLaunchKernel(*mInternals->kernelFunctions[getRTCkernelNum()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); } else { pArgs[arg_offset + 1] = &y.num; - GPUFailedMsg(cuLaunchKernel(*mInternals->kernelFunctions[mInternals->getRTCkernelNum()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); - } - } - if (mProcessingSettings.checkKernelFailures) { - if (GPUDebug(GetKernelName(), _xyz.x.stream, true)) { - throw std::runtime_error("Kernel Failure"); + GPUFailedMsg(cuLaunchKernel(*mInternals->kernelFunctions[getRTCkernelNum()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); } } -#else // HIP version - if (mProcessingSettings.deviceTimers && mProcessingSettings.debugLevel > 0) { - backendInternal::runKernelBackendMacro(_xyz, this, (hipEvent_t*)&mDebugEvents->DebugStart, (hipEvent_t*)&mDebugEvents->DebugStop, args...); - GPUFailedMsg(hipEventSynchronize((hipEvent_t)mDebugEvents->DebugStop)); - float v; - GPUFailedMsg(hipEventElapsedTime(&v, (hipEvent_t)mDebugEvents->DebugStart, (hipEvent_t)mDebugEvents->DebugStop)); - _xyz.t = v * 1.e-3f; - } else { - backendInternal::runKernelBackendMacro(_xyz, this, nullptr, nullptr, args...); - } -#endif } template -int GPUReconstructionCUDABackend::runKernelBackend(krnlSetup& _xyz, Args... args) +int GPUReconstructionCUDABackend::runKernelBackend(const krnlSetupArgs& args) { - auto& x = _xyz.x; - auto& z = _xyz.z; + auto& x = args.s.x; + auto& z = args.s.z; if (z.evList) { for (int k = 0; k < z.nEvents; k++) { GPUFailedMsg(cudaStreamWaitEvent(mInternals->Streams[x.stream], ((cudaEvent_t*)z.evList)[k], 0)); } } - runKernelBackendInternal(_xyz, args...); + { + GPUDebugTiming timer(mProcessingSettings.deviceTimers && mProcessingSettings.debugLevel > 0, (deviceEvent*)mDebugEvents, mInternals->Streams, args.s, this); + std::apply([this, &args](auto&... vals) { this->runKernelBackendInternal(args.s, vals...); }, args.v); + } GPUFailedMsg(cudaGetLastError()); + if (mProcessingSettings.checkKernelFailures) { + if (GPUDebug(GetKernelName(), args.s.x.stream, true)) { + throw std::runtime_error("Kernel Failure"); + } + } if (z.ev) { GPUFailedMsg(cudaEventRecord(*(cudaEvent_t*)z.ev, mInternals->Streams[x.stream])); } return 0; } +#undef GPUCA_KRNL_REG +#define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) + #if defined(GPUCA_KERNEL_COMPILE_MODE) && GPUCA_KERNEL_COMPILE_MODE == 1 -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_PROP(x_class, x_attributes) \ - template int GPUReconstructionCUDABackend::runKernelBackend(krnlSetup & _xyz GPUCA_M_STRIP(x_arguments)); +#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward, x_types) \ + GPUCA_KRNL_PROP(x_class, x_attributes) \ + template int GPUReconstructionCUDABackend::runKernelBackend(const krnlSetupArgs& args); #else #if defined(GPUCA_KERNEL_COMPILE_MODE) && GPUCA_KERNEL_COMPILE_MODE == 2 #define GPUCA_KRNL_DEFONLY #endif -#undef GPUCA_KRNL_REG -#define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_PROP(x_class, x_attributes) \ - GPUCA_KRNL_WRAP(GPUCA_KRNL_, x_class, x_attributes, x_arguments, x_forward) \ - template int GPUReconstructionCUDABackend::runKernelBackend(krnlSetup & _xyz GPUCA_M_STRIP(x_arguments)); +#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward, x_types) \ + GPUCA_KRNL_PROP(x_class, x_attributes) \ + GPUCA_KRNL_WRAP(GPUCA_KRNL_, x_class, x_attributes, x_arguments, x_forward, x_types) \ + template int GPUReconstructionCUDABackend::runKernelBackend(const krnlSetupArgs& args); #ifndef __HIPCC__ // CUDA version -#define GPUCA_KRNL_CALL_single(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNL_CALL_single(x_class, ...) \ GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))<<mInternals->Streams[x.stream]>>>(GPUCA_CONSMEM_CALL y.start, args...); -#define GPUCA_KRNL_CALL_multi(x_class, x_attributes, x_arguments, x_forward) \ +#define GPUCA_KRNL_CALL_multi(x_class, ...) \ GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)<<mInternals->Streams[x.stream]>>>(GPUCA_CONSMEM_CALL y.start, y.num, args...); #else // HIP version #undef GPUCA_KRNL_CUSTOM #define GPUCA_KRNL_CUSTOM(args) GPUCA_M_STRIP(args) -#undef GPUCA_KRNL_BACKEND_XARGS -#define GPUCA_KRNL_BACKEND_XARGS hipEvent_t *debugStartEvent, hipEvent_t *debugStopEvent, -#define GPUCA_KRNL_CALL_single(x_class, x_attributes, x_arguments, x_forward) \ - if (debugStartEvent == nullptr) { \ - hipLaunchKernelGGL(HIP_KERNEL_NAME(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))), dim3(x.nBlocks), dim3(x.nThreads), 0, me->mInternals->Streams[x.stream], GPUCA_CONSMEM_CALL y.start, args...); \ - } else { \ - hipExtLaunchKernelGGL(HIP_KERNEL_NAME(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))), dim3(x.nBlocks), dim3(x.nThreads), 0, me->mInternals->Streams[x.stream], *debugStartEvent, *debugStopEvent, 0, GPUCA_CONSMEM_CALL y.start, args...); \ - } -#define GPUCA_KRNL_CALL_multi(x_class, x_attributes, x_arguments, x_forward) \ - if (debugStartEvent == nullptr) { \ - hipLaunchKernelGGL(HIP_KERNEL_NAME(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)), dim3(x.nBlocks), dim3(x.nThreads), 0, me->mInternals->Streams[x.stream], GPUCA_CONSMEM_CALL y.start, y.num, args...); \ - } else { \ - hipExtLaunchKernelGGL(HIP_KERNEL_NAME(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)), dim3(x.nBlocks), dim3(x.nThreads), 0, me->mInternals->Streams[x.stream], *debugStartEvent, *debugStopEvent, 0, GPUCA_CONSMEM_CALL y.start, y.num, args...); \ - } +#define GPUCA_KRNL_CALL_single(x_class, ...) \ + hipLaunchKernelGGL(HIP_KERNEL_NAME(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))), dim3(x.nBlocks), dim3(x.nThreads), 0, me->mInternals->Streams[x.stream], GPUCA_CONSMEM_CALL y.start, args...); +#define GPUCA_KRNL_CALL_multi(x_class, ...) \ + hipLaunchKernelGGL(HIP_KERNEL_NAME(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)), dim3(x.nBlocks), dim3(x.nThreads), 0, me->mInternals->Streams[x.stream], GPUCA_CONSMEM_CALL y.start, y.num, args...); #endif // __HIPCC__ #endif -#include "GPUReconstructionKernels.h" +#include "GPUReconstructionKernelList.h" #undef GPUCA_KRNL +template +int GPUReconstructionCUDABackend::getRTCkernelNum(int k) +{ + static int num = k; + if (num < 0) { + throw std::runtime_error("Invalid kernel"); + } + return num; +} + +#define GPUCA_KRNL(x_class, ...) \ + template int GPUReconstructionCUDABackend::getRTCkernelNum(int k); \ + template int GPUReconstructionCUDABackend::getRTCkernelNum(int k); +#include "GPUReconstructionKernelList.h" +#undef GPUCA_KRNL + +void GPUReconstructionCUDABackend::getRTCKernelCalls(std::vector& kernels) +{ +#define GPUCA_KRNL(...) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, __VA_ARGS__) +#define GPUCA_KRNL_LOAD_single(...) kernels.emplace_back(GPUCA_M_STR(GPUCA_KRNLGPU_SINGLE(__VA_ARGS__))); +#define GPUCA_KRNL_LOAD_multi(...) kernels.emplace_back(GPUCA_M_STR(GPUCA_KRNLGPU_MULTI(__VA_ARGS__))); +#include "GPUReconstructionKernelList.h" +#undef GPUCA_KRNL +#undef GPUCA_KRNL_LOAD_single +#undef GPUCA_KRNL_LOAD_multi +} + #ifndef GPUCA_NO_CONSTANT_MEMORY static GPUReconstructionDeviceBase::deviceConstantMemRegistration registerConstSymbol([]() { void* retVal = nullptr; diff --git a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAkernel.template.cu b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAkernel.template.cu index 9442c58c6e880..c22b873961e09 100644 --- a/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAkernel.template.cu +++ b/GPU/GPUTracking/Base/cuda/GPUReconstructionCUDAkernel.template.cu @@ -16,9 +16,9 @@ #include "GPUReconstructionCUDAIncludes.h" #include "GPUReconstructionCUDADef.h" #define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward); -#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward); +#define GPUCA_KRNL(...) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, __VA_ARGS__) +#define GPUCA_KRNL_LOAD_single(...) GPUCA_KRNLGPU_SINGLE(__VA_ARGS__); +#define GPUCA_KRNL_LOAD_multi(...) GPUCA_KRNLGPU_MULTI(__VA_ARGS__); #include "GPUReconstructionKernelMacros.h" // clang-format off diff --git a/GPU/GPUTracking/Base/hip/CMakeLists.txt b/GPU/GPUTracking/Base/hip/CMakeLists.txt index da732b00104fd..cadbe788e46a7 100644 --- a/GPU/GPUTracking/Base/hip/CMakeLists.txt +++ b/GPU/GPUTracking/Base/hip/CMakeLists.txt @@ -11,30 +11,127 @@ set(MODULE GPUTrackingHIP) -# Setting flags as a global option for all HIP targets. -set(CMAKE_HIP_FLAGS "${CMAKE_HIP_FLAGS} -fno-gpu-rdc") +# -------------------------------- Options ------------------------------------------------------- +# set(GPUCA_HIP_HIPIFY_FROM_CUDA 0) # Use local HIP source files + +# -------------------------------- Status Message ------------------------------------------------------- if(DEFINED HIP_AMDGPUTARGET) set(TMP_TARGET "(GPU Target ${HIP_AMDGPUTARGET})") endif() - message(STATUS "Building GPUTracking with HIP support ${TMP_TARGET}") -set(SRCS GPUReconstructionHIP.hip GPUReconstructionHIPKernels.hip) -set(HDRS GPUReconstructionHIP.h GPUReconstructionHIPInternals.h GPUReconstructionHIPIncludes.h HIPThrustHelpers.h) +# -------------------------------- Optionally hipify from CUDA (default) ------------------------------------------------------- +if(NOT DEFINED GPUCA_HIP_HIPIFY_FROM_CUDA OR "${GPUCA_HIP_HIPIFY_FROM_CUDA}") + set(GPUCA_HIP_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/hipify) + file(MAKE_DIRECTORY ${GPUCA_HIP_SOURCE_DIR}) + set(GPUCA_HIP_FILE_LIST GPUReconstructionCUDA.cu GPUReconstructionCUDAExternalProvider.cu GPUReconstructionCUDA.h GPUReconstructionCUDAInternals.h GPUReconstructionCUDAkernel.template.cu CUDAThrustHelpers.h GPUReconstructionCUDADef.h GPUReconstructionCUDAGenRTC.cxx GPUReconstructionCUDAKernels.cu GPUReconstructionCUDArtc.cu) + set(GPUCA_HIP_LOCAL_FILE_LIST GPUReconstructionHIPIncludes.h) + set(HIP_SOURCES "") + foreach(file ${GPUCA_HIP_FILE_LIST}) + get_filename_component(ABS_CUDA_SORUCE ../cuda/${file} ABSOLUTE) + get_filename_component(CUDA_SOURCE ${file} NAME) + string(REPLACE ".cu" ".hip" HIP_SOURCE1 ${CUDA_SOURCE}) + string(REPLACE "CUDA" "HIP" HIP_SOURCE ${HIP_SOURCE1}) + add_custom_command( + OUTPUT ${GPUCA_HIP_SOURCE_DIR}/${HIP_SOURCE} + COMMAND ${hip_HIPIFY_PERL_EXECUTABLE} --quiet-warnings ${ABS_CUDA_SORUCE} | sed -e 's/CUDA/HIP/g' -e 's/cuda/hip/g' > ${GPUCA_HIP_SOURCE_DIR}/${HIP_SOURCE} + DEPENDS ${ABS_CUDA_SORUCE} + COMMENT "Hippifying ${HIP_SOURCE}" + ) + list(APPEND HIP_SOURCES "${GPUCA_HIP_SOURCE_DIR}/${HIP_SOURCE}") + endforeach() + foreach(file ${GPUCA_HIP_LOCAL_FILE_LIST}) + get_filename_component(ABS_SORUCE ${file} ABSOLUTE) + get_filename_component(HIP_SOURCE ${file} NAME) + add_custom_command( + OUTPUT ${GPUCA_HIP_SOURCE_DIR}/${HIP_SOURCE} + COMMAND cp ${ABS_SORUCE} ${GPUCA_HIP_SOURCE_DIR}/${HIP_SOURCE} + DEPENDS ${ABS_SORUCE} + COMMENT "Copying ${HIP_SOURCE}" + ) + list(APPEND HIP_SOURCES "${GPUCA_HIP_SOURCE_DIR}/${HIP_SOURCE}") + endforeach() + + add_custom_target(${MODULE}_HIPIFIED_CHK COMMAND diff -u ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIPkernel.template.hip ${CMAKE_CURRENT_SOURCE_DIR}/GPUReconstructionHIPkernel.template.hip DEPENDS ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIPkernel.template.hip ${CMAKE_CURRENT_SOURCE_DIR}/GPUReconstructionHIPkernel.template.hip) +else() + get_filename_component(GPUCA_HIP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} ABSOLUTE) +endif() + +set(SRCS ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIP.hip ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIPKernels.hip) +set(SRCS_CXX ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIPGenRTC.cxx) +set(HDRS ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIP.h ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIPInternals.h ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIPDef.h ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIPIncludes.h ${GPUCA_HIP_SOURCE_DIR}/HIPThrustHelpers.h) + +# -------------------------------- Prepare RTC ------------------------------------------------------- +if(NOT ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") + enable_language(ASM) + if(ALIGPU_BUILD_TYPE STREQUAL "O2") + set(defineIncludeSrc "O2::${MODULE}") + else() + set(defineIncludeSrc "${MODULE}") + endif() + set(GPU_RTC_DEFINES "-D$,$-D>") + set(GPU_RTC_INCLUDES "-I$,EXCLUDE,^/usr/include/?>,$-I>" + -I${CMAKE_SOURCE_DIR}/Detectors/Base/src + -I${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src + ) + if(ALIGPU_BUILD_TYPE STREQUAL "O2") + set(GPU_RTC_INCLUDES ${GPU_RTC_INCLUDES} "-I$,EXCLUDE,^/usr/include/?>,$-I>") + endif() + + # build flags to use for RTC + set(GPU_RTC_FLAGS "${CMAKE_HIP_FLAGS} ${CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -std=c++${CMAKE_HIP_STANDARD}") + set(GPU_RTC_FLAGS_SEPARATED "${GPU_RTC_FLAGS}") + separate_arguments(GPU_RTC_FLAGS_SEPARATED) + + # convenience variables + if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") + get_filename_component(GPUDIR ${CMAKE_SOURCE_DIR}/../ ABSOLUTE) + else() + set(GPUDIR ${CMAKE_SOURCE_DIR}/GPU/GPUTracking) + endif() + + set(GPU_RTC_SRC ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIPrtc.hip) + set(GPU_RTC_BIN ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionHIPrtc) + + # cmake-format: off + add_custom_command( + OUTPUT ${GPU_RTC_BIN}.src + COMMAND cat ${GPUDIR}/Base/hip/GPUReconstructionHIPIncludes.h > ${GPU_RTC_BIN}.src + COMMAND ${CMAKE_CXX_COMPILER} ${GPU_RTC_DEFINES} ${GPU_RTC_INCLUDES} -std=c++${CMAKE_HIP_STANDARD} -D__HIPCC__ -D__HIP_DEVICE_COMPILE__ -x c++ -E ${GPU_RTC_SRC} >> ${GPU_RTC_BIN}.src + MAIN_DEPENDENCY ${GPU_RTC_SRC} + IMPLICIT_DEPENDS CXX ${GPU_RTC_SRC} + COMMAND_EXPAND_LISTS + COMMENT "Preparing HIP RTC source file ${GPU_RTC_BIN}.src" + ) + create_binary_resource(${GPU_RTC_BIN}.src ${GPU_RTC_BIN}.src.o) + + add_custom_command( + OUTPUT ${GPU_RTC_BIN}.command + COMMAND echo -n "${hip_HIPCC_EXECUTABLE} ${GPU_RTC_FLAGS_SEPARATED} ${GPU_RTC_DEFINES} --genco" > ${GPU_RTC_BIN}.command + COMMAND_EXPAND_LISTS + VERBATIM + COMMENT "Preparing HIP RTC command file ${GPU_RTC_BIN}.command" + ) + create_binary_resource(${GPU_RTC_BIN}.command ${GPU_RTC_BIN}.command.o) + + set(SRCS ${SRCS} ${GPU_RTC_BIN}.src.o ${GPU_RTC_BIN}.command.o) +endif() +# -------------------------------- End RTC ------------------------------------------------------- if(ALIGPU_BUILD_TYPE STREQUAL "O2") + set(TMP_BASELIB O2::GPUTracking) o2_add_library( ${MODULE} SOURCES ${SRCS} - PUBLIC_LINK_LIBRARIES O2::GPUTracking O2::ITStrackingHIP hip::host hip::device hip::hipcub roc::rocthrust - PUBLIC_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src - ${CMAKE_SOURCE_DIR}/Detectors/Base/src - ${CMAKE_SOURCE_DIR}/DataFormats/Reconstruction/src + PUBLIC_LINK_LIBRARIES ${TMP_BASELIB} O2::ITStrackingHIP + PRIVATE_INCLUDE_DIRECTORIES + ${CMAKE_SOURCE_DIR}/Detectors/Base/src + ${CMAKE_SOURCE_DIR}/Detectors/TRD/base/src + ${CMAKE_SOURCE_DIR}/DataFormats/Reconstruction/src + ${GPUCA_HIP_SOURCE_DIR} TARGETVARNAME targetName) - target_compile_definitions( - ${targetName} PUBLIC GPUCA_GPULIBRARY=HIP - $) + target_compile_definitions(${targetName} PUBLIC $) install(FILES ${HDRS} DESTINATION include/GPU) @@ -46,43 +143,131 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") endif() if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") + set(targetName "Ali${MODULE}") + set(TMP_BASELIB AliGPUTracking) if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 14) message(FATAL_ERROR "HIP support needs at least C++14") endif() - add_definitions(-DGPUCA_GPULIBRARY=HIP) # Generate the dictionary get_directory_property(incdirs INCLUDE_DIRECTORIES) - generate_dictionary("Ali${MODULE}" "" "GPUReconstructionHIP.h" "${incdirs} .") + generate_dictionary("${targetName}" "" "${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIP.h" "${incdirs} .") # Generate the ROOT map Dependecies - generate_rootmap("Ali${MODULE}" "" "") + generate_rootmap("${targetName}" "" "") # Add a library to the project using the specified source files - add_library_tested(Ali${MODULE} SHARED ${SRCS} G__Ali${MODULE}.cxx) + add_library_tested(${targetName} SHARED ${SRCS}) + set(SRCS_CXX ${SRCS_CXX} G__${targetName}.cxx) # CMake HIP language feature will parse hip flags to everything that is linked to hip libraries, so add the ROOT dictionary file here + target_link_libraries(${targetName} PUBLIC ${TMP_BASELIB}) + # ROOT Cannot load this library, so we have to remove it from the list - list(REMOVE_ITEM ALILIBSTESTED Ali${MODULE}) + list(REMOVE_ITEM ALILIBSTESTED ${targetName}) set(ALILIBSTESTED ${ALILIBSTESTED} CACHE INTERNAL "ALILIBSTESTED") - # HIP run-time and driver - target_link_libraries(Ali${MODULE} PUBLIC AliGPUTracking hip::host hip::device hip::hipcub roc::rocthrust) - - # Additional compilation flags - set_target_properties(Ali${MODULE} PROPERTIES COMPILE_FLAGS "") - # Installation - install(TARGETS Ali${MODULE} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib) + install(TARGETS ${targetName} ARCHIVE DESTINATION lib LIBRARY DESTINATION lib) install(FILES ${HDRS} DESTINATION include) - set(targetName "Ali${MODULE}") + include_directories(${GPUCA_HIP_SOURCE_DIR}) endif() if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") - add_definitions(-DGPUCA_GPULIBRARY=HIP) - add_library(${MODULE} SHARED ${SRCS}) - target_link_libraries(${MODULE} GPUTracking hip::host hip::device hip::hipcub roc::rocthrust) set(targetName "${MODULE}") + set(TMP_BASELIB GPUTracking) + add_library(${MODULE} SHARED ${SRCS}) + target_link_libraries(${MODULE} PUBLIC ${TMP_BASELIB}) install(TARGETS GPUTrackingHIP) + include_directories(${GPUCA_HIP_SOURCE_DIR}) +endif() + +add_library(${MODULE}_CXX OBJECT ${SRCS_CXX}) # Adding a C++ library for the .cxx code of the HIP library, such that it does not link to HIP libraries, and CMake HIP Language doesn't add HIP compile flags. +target_compile_definitions(${MODULE}_CXX PRIVATE $) +target_include_directories(${MODULE}_CXX PRIVATE $) +target_link_libraries(${targetName} PRIVATE ${MODULE}_CXX) + +if(NOT DEFINED GPUCA_HIP_HIPIFY_FROM_CUDA OR "${GPUCA_HIP_HIPIFY_FROM_CUDA}") + add_custom_target(${MODULE}_HIPIFIED DEPENDS ${HIP_SOURCES} ${MODULE}_HIPIFIED_CHK) + add_dependencies(${targetName} ${MODULE}_HIPIFIED) + add_dependencies(${MODULE}_CXX ${MODULE}_HIPIFIED) endif() +# Setting target architecture and adding GPU libraries +target_link_libraries(${targetName} PRIVATE hip::host hip::device hip::hipcub roc::rocthrust) set_target_hip_arch(${targetName}) + +if(OpenMP_CXX_FOUND) + # Must be private, depending libraries might be compiled by compiler not understanding -fopenmp + target_compile_definitions(${MODULE}_CXX PRIVATE WITH_OPENMP) + target_link_libraries(${MODULE}_CXX PRIVATE OpenMP::OpenMP_CXX) +endif() + +# Special handling of GPU kernels in case of per-kernel compilation / RDC +if(NOT DEFINED GPUCA_HIP_COMPILE_MODE) + if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") + set(GPUCA_HIP_COMPILE_MODE "onefile") + else() + set(GPUCA_HIP_COMPILE_MODE "perkernel") + endif() +endif() +if(GPUCA_HIP_COMPILE_MODE STREQUAL "onefile") + target_compile_definitions(${targetName} PRIVATE GPUCA_KERNEL_COMPILE_MODE=0) +elseif(GPUCA_HIP_COMPILE_MODE STREQUAL "perkernel") + #add_library(GPUTrackingHIPKernels OBJECT $,REPLACE,[^A-Za-z0-9]+,_>,PREPEND,${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_>,APPEND,.cu>, >) + #set_property(TARGET GPUTrackingHIPKernels PROPERTY HIP_FATBIN_COMPILATION ON) + add_subdirectory(per_kernel) + target_compile_options(GPUTrackingHIPKernels PRIVATE $<$:-fno-gpu-rdc>) + target_link_options(GPUTrackingHIPKernels PRIVATE $<$:-fno-gpu-rdc>) + target_compile_definitions(${targetName} PRIVATE GPUCA_KERNEL_COMPILE_MODE=1) + target_compile_definitions(GPUTrackingHIPKernels PRIVATE $) + target_include_directories(GPUTrackingHIPKernels PRIVATE $) + if(NOT DEFINED GPUCA_HIP_HIPIFY_FROM_CUDA OR "${GPUCA_HIP_HIPIFY_FROM_CUDA}") + add_dependencies(GPUTrackingHIPKernels ${MODULE}_HIPIFIED) + endif() + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/hip_kernel_module_fatbin) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/GPUTrackingHIPKernelModules.o + COMMAND cp -u $ ${CMAKE_CURRENT_BINARY_DIR}/hip_kernel_module_fatbin/ + COMMAND ${CMAKE_LINKER} --relocatable --format binary --output ${CMAKE_CURRENT_BINARY_DIR}/GPUTrackingHIPKernelModules.o $>,PREPEND,${CMAKE_CURRENT_BINARY_DIR}/hip_kernel_module_fatbin/>,${CMAKE_CURRENT_BINARY_DIR}> + DEPENDS GPUTrackingHIPKernels $ + COMMENT "Compiling fatbin kernels ${CMAKE_CURRENT_BINARY_DIR}/GPUTrackingHIPKernelModules.o" + VERBATIM + COMMAND_EXPAND_LISTS + ) + target_sources(${targetName} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/GPUTrackingHIPKernelModules.o) + set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/GPUTrackingHIPKernelModules.o PROPERTIES EXTERNAL_OBJECT true GENERATED true) + + # Disable all non-deterministic floating point to make TPC track model encoding / decoding precise + set_source_files_properties(${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_GPUTPCCompressionKernels_step0attached.hip + ${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_GPUTPCCompressionKernels_step1unattached.hip + ${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_GPUTPCDecompressionKernels_step0attached.hip + ${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_GPUTPCDecompressionKernels_step1unattached.hip + TARGET_DIRECTORY ${targetName} + PROPERTIES + COMPILE_FLAGS "${GPUCA_CXX_NO_FAST_MATH_FLAGS}" + COMPILE_DEFINITIONS "GPUCA_NO_FAST_MATH") +elseif(GPUCA_HIP_COMPILE_MODE STREQUAL "rdc") + message(FATAL_ERROR "HIP RDC compilation of GPUReconstruction ios not yet working!") + target_compile_definitions(${targetName} PRIVATE GPUCA_KERNEL_COMPILE_MODE=2) + target_compile_options(${targetName} PRIVATE $<$:-fgpu-rdc>) + target_link_options(${targetName} PRIVATE $<$:-fgpu-rdc>) + target_sources(${targetName} PRIVATE $,REPLACE,[^A-Za-z0-9]+,_>,PREPEND,${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_>,APPEND,.hip>, >) +else() + message(FATAL_ERROR "Invalid compile mode") +endif() +if(NOT GPUCA_HIP_COMPILE_MODE STREQUAL "rdc") + target_compile_options(${targetName} PRIVATE $<$:-fno-gpu-rdc>) + target_link_options(${targetName} PRIVATE $<$:-fno-gpu-rdc>) +endif() + +if(ALIGPU_BUILD_TYPE STREQUAL "O2" OR CONFIG_O2_EXTENSIONS) + add_library(GPUTrackingHIPExternalProvider OBJECT ${GPUCA_HIP_SOURCE_DIR}/GPUReconstructionHIPExternalProvider.hip) + add_library(O2::GPUTrackingHIPExternalProvider ALIAS GPUTrackingHIPExternalProvider) + target_compile_options(GPUTrackingHIPExternalProvider PRIVATE $<$:-fgpu-rdc>) + target_link_options(GPUTrackingHIPExternalProvider PRIVATE $<$:-fgpu-rdc>) + target_compile_definitions(GPUTrackingHIPExternalProvider PRIVATE $) + target_include_directories(GPUTrackingHIPExternalProvider PRIVATE $) + if(NOT DEFINED GPUCA_HIP_HIPIFY_FROM_CUDA OR "${GPUCA_HIP_HIPIFY_FROM_CUDA}") + add_dependencies(GPUTrackingHIPExternalProvider ${MODULE}_HIPIFIED) + endif() +endif() diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h deleted file mode 100644 index 9db69a09a4d34..0000000000000 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.h +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUReconstructionHIP.h -/// \author David Rohr - -#ifndef GPURECONSTRUCTIONHIP_H -#define GPURECONSTRUCTIONHIP_H - -#include "GPUReconstructionDeviceBase.h" - -#ifdef _WIN32 -extern "C" __declspec(dllexport) GPUCA_NAMESPACE::gpu::GPUReconstruction* GPUReconstruction_Create_HIP(const GPUCA_NAMESPACE::gpu::GPUSettingsDeviceBackend& cfg); -#else -extern "C" GPUCA_NAMESPACE::gpu::GPUReconstruction* GPUReconstruction_Create_HIP(const GPUCA_NAMESPACE::gpu::GPUSettingsDeviceBackend& cfg); -#endif - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -struct GPUReconstructionHIPInternals; - -class GPUReconstructionHIPBackend : public GPUReconstructionDeviceBase -{ - public: - ~GPUReconstructionHIPBackend() override; - static int GPUFailedMsgAI(const long long int error, const char* file, int line); - void GPUFailedMsgA(const long long int error, const char* file, int line); - - protected: - GPUReconstructionHIPBackend(const GPUSettingsDeviceBackend& cfg); - - int InitDevice_Runtime() override; - int ExitDevice_Runtime() override; - void UpdateAutomaticProcessingSettings() override; - - std::unique_ptr GetThreadContext() override; - void SynchronizeGPU() override; - int GPUDebug(const char* state = "UNKNOWN", int stream = -1, bool force = false) override; - void SynchronizeStream(int stream) override; - void SynchronizeEvents(deviceEvent* evList, int nEvents = 1) override; - void StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents = 1) override; - bool IsEventDone(deviceEvent* evList, int nEvents = 1) override; - int registerMemoryForGPU_internal(const void* ptr, size_t size) override; - int unregisterMemoryForGPU_internal(const void* ptr) override; - void* getGPUPointer(void* ptr) override; - - size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, deviceEvent ev = nullptr) override; - size_t TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) override; - size_t GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override; - void ReleaseEvent(deviceEvent ev) override; - void RecordMarker(deviceEvent ev, int stream) override; - - void GetITSTraits(std::unique_ptr* trackerTraits, std::unique_ptr* vertexerTraits, std::unique_ptr* timeFrame) override; - - void PrintKernelOccupancies() override; - - template - int runKernelBackend(krnlSetup& _xyz, Args... args); - template - void runKernelBackendInternal(krnlSetup& _xyz, const Args&... args); - template - const krnlProperties getKernelPropertiesBackend(); - template - class backendInternal; - - private: - GPUReconstructionHIPInternals* mInternals; -}; - -using GPUReconstructionHIP = GPUReconstructionKernels; -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip b/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip deleted file mode 100644 index 2bccd69e75b40..0000000000000 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIP.hip +++ /dev/null @@ -1,484 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUReconstructionHIP.hip.cxx -/// \author David Rohr - -#define GPUCA_GPUCODE_HOSTONLY -#include "GPUReconstructionHIPIncludes.h" - -#include "GPUDef.h" - -#include "GPUReconstructionHIP.h" -#include "GPUReconstructionHIPInternals.h" -#include "HIPThrustHelpers.h" -#include "GPUReconstructionIncludes.h" - -using namespace GPUCA_NAMESPACE::gpu; - -__global__ void dummyInitKernel(void*) {} - -#include "GPUReconstructionIncludesITS.h" - -GPUReconstructionHIPBackend::GPUReconstructionHIPBackend(const GPUSettingsDeviceBackend& cfg) : GPUReconstructionDeviceBase(cfg, sizeof(GPUReconstructionDeviceBase)) -{ - if (mMaster == nullptr) { - mInternals = new GPUReconstructionHIPInternals; - } - mDeviceBackendSettings.deviceType = DeviceType::HIP; -} - -GPUReconstructionHIPBackend::~GPUReconstructionHIPBackend() -{ - Exit(); // Make sure we destroy everything (in particular the ITS tracker) before we exit - if (mMaster == nullptr) { - delete mInternals; - } -} - -int GPUReconstructionHIPBackend::GPUFailedMsgAI(const long long int error, const char* file, int line) -{ - // Check for HIP Error and in the case of an error display the corresponding error string - if (error == hipSuccess) { - return (0); - } - GPUError("HIP Error: %lld / %s (%s:%d)", error, hipGetErrorString((hipError_t)error), file, line); - return 1; -} - -void GPUReconstructionHIPBackend::GPUFailedMsgA(const long long int error, const char* file, int line) -{ - if (GPUFailedMsgAI(error, file, line)) { - static bool runningCallbacks = false; - if (IsInitialized() && runningCallbacks == false) { - runningCallbacks = true; - CheckErrorCodes(false, true); - } - throw std::runtime_error("HIP Failure"); - } -} - -GPUReconstruction* GPUReconstruction_Create_HIP(const GPUSettingsDeviceBackend& cfg) { return new GPUReconstructionHIP(cfg); } - -void GPUReconstructionHIPBackend::GetITSTraits(std::unique_ptr* trackerTraits, std::unique_ptr* vertexerTraits, std::unique_ptr* timeFrame) -{ - if (trackerTraits) { - trackerTraits->reset(new o2::its::TrackerTraitsGPU); - } - if (vertexerTraits) { - vertexerTraits->reset(new o2::its::VertexerTraitsGPU); - } - if (timeFrame) { - timeFrame->reset(new o2::its::gpu::TimeFrameGPU); - } -} - -void GPUReconstructionHIPBackend::UpdateAutomaticProcessingSettings() -{ - GPUCA_GPUReconstructionUpdateDefaults(); -} - -int GPUReconstructionHIPBackend::InitDevice_Runtime() -{ - if (mMaster == nullptr) { - hipDeviceProp_t hipDeviceProp; - int count, bestDevice = -1; - double bestDeviceSpeed = -1, deviceSpeed; - if (GPUFailedMsgI(hipGetDeviceCount(&count))) { - GPUError("Error getting HIP Device Count"); - return (1); - } - if (mProcessingSettings.debugLevel >= 2) { - GPUInfo("Available HIP devices:"); - } - std::vector devicesOK(count, false); - std::vector devMemory(count, 0); - bool contextCreated = false; - for (int i = 0; i < count; i++) { - if (mProcessingSettings.debugLevel >= 4) { - GPUInfo("Examining device %d", i); - } - size_t free, total; - if (GPUFailedMsgI(hipSetDevice(i))) { - if (mProcessingSettings.debugLevel >= 4) { - GPUWarning("Couldn't create context for device %d. Skipping it.", i); - } - continue; - } - contextCreated = true; - if (GPUFailedMsgI(hipMemGetInfo(&free, &total))) { - if (mProcessingSettings.debugLevel >= 4) { - GPUWarning("Error obtaining HIP memory info about device %d! Skipping it.", i); - } - GPUFailedMsg(hipDeviceReset()); - continue; - } - if (count > 1) { - GPUFailedMsg(hipDeviceReset()); - contextCreated = false; - } - if (mProcessingSettings.debugLevel >= 4) { - GPUInfo("Obtained current memory usage for device %d", i); - } - if (GPUFailedMsgI(hipGetDeviceProperties(&hipDeviceProp, i))) { - continue; - } - if (mProcessingSettings.debugLevel >= 4) { - GPUInfo("Obtained device properties for device %d", i); - } - int deviceOK = true; - const char* deviceFailure = ""; - - deviceSpeed = (double)hipDeviceProp.multiProcessorCount * (double)hipDeviceProp.clockRate * (double)hipDeviceProp.warpSize * (double)hipDeviceProp.major * (double)hipDeviceProp.major; - if (mProcessingSettings.debugLevel >= 2) { - GPUImportant("Device %s%2d: %s (Rev: %d.%d - Mem %lld)%s %s", deviceOK ? " " : "[", i, hipDeviceProp.name, hipDeviceProp.major, hipDeviceProp.minor, (long long int)hipDeviceProp.totalGlobalMem, deviceOK ? " " : " ]", deviceOK ? "" : deviceFailure); - } - if (!deviceOK) { - continue; - } - devicesOK[i] = true; - if (deviceSpeed > bestDeviceSpeed) { - bestDevice = i; - bestDeviceSpeed = deviceSpeed; - } else { - if (mProcessingSettings.debugLevel >= 2 && mProcessingSettings.deviceNum < 0) { - GPUInfo("Skipping: Speed %f < %f\n", deviceSpeed, bestDeviceSpeed); - } - } - } - bool noDevice = false; - if (bestDevice == -1) { - GPUWarning("No %sHIP Device available, aborting HIP Initialisation (Required mem: %lld)", count ? "appropriate " : "", (long long int)mDeviceMemorySize); - noDevice = true; - } else if (mProcessingSettings.deviceNum > -1) { - if (mProcessingSettings.deviceNum >= (signed)count) { - GPUWarning("Requested device ID %d does not exist", mProcessingSettings.deviceNum); - noDevice = true; - } else if (!devicesOK[mProcessingSettings.deviceNum]) { - GPUWarning("Unsupported device requested (%d)", mProcessingSettings.deviceNum); - noDevice = true; - } else { - bestDevice = mProcessingSettings.deviceNum; - } - } - if (noDevice) { - if (contextCreated) { - GPUFailedMsgI(hipDeviceReset()); - } - return (1); - } - mDeviceId = bestDevice; - - GPUFailedMsgI(hipGetDeviceProperties(&hipDeviceProp, mDeviceId)); - - if (mProcessingSettings.debugLevel >= 2) { - GPUInfo("Using HIP Device %s with Properties:", hipDeviceProp.name); - GPUInfo("\ttotalGlobalMem = %lld", (unsigned long long int)hipDeviceProp.totalGlobalMem); - GPUInfo("\tsharedMemPerBlock = %lld", (unsigned long long int)hipDeviceProp.sharedMemPerBlock); - GPUInfo("\tregsPerBlock = %d", hipDeviceProp.regsPerBlock); - GPUInfo("\twarpSize = %d", hipDeviceProp.warpSize); - GPUInfo("\tmaxThreadsPerBlock = %d", hipDeviceProp.maxThreadsPerBlock); - GPUInfo("\tmaxThreadsDim = %d %d %d", hipDeviceProp.maxThreadsDim[0], hipDeviceProp.maxThreadsDim[1], hipDeviceProp.maxThreadsDim[2]); - GPUInfo("\tmaxGridSize = %d %d %d", hipDeviceProp.maxGridSize[0], hipDeviceProp.maxGridSize[1], hipDeviceProp.maxGridSize[2]); - GPUInfo("\ttotalConstMem = %lld", (unsigned long long int)hipDeviceProp.totalConstMem); - GPUInfo("\tmajor = %d", hipDeviceProp.major); - GPUInfo("\tminor = %d", hipDeviceProp.minor); - GPUInfo("\tclockRate = %d", hipDeviceProp.clockRate); - GPUInfo("\tmemoryClockRate = %d", hipDeviceProp.memoryClockRate); - GPUInfo("\tmultiProcessorCount = %d", hipDeviceProp.multiProcessorCount); - GPUInfo(" "); - } - if (hipDeviceProp.warpSize != GPUCA_WARP_SIZE) { - throw std::runtime_error("Invalid warp size on GPU"); - } - mBlockCount = hipDeviceProp.multiProcessorCount; - mMaxThreads = std::max(mMaxThreads, hipDeviceProp.maxThreadsPerBlock * mBlockCount); - mWarpSize = 64; - mDeviceName = hipDeviceProp.name; - mDeviceName += " (HIP GPU)"; - - if (hipDeviceProp.major < 3) { - GPUError("Unsupported HIP Device"); - return (1); - } -#ifndef GPUCA_NO_CONSTANT_MEMORY - if (gGPUConstantMemBufferSize > hipDeviceProp.totalConstMem) { - GPUError("Insufficient constant memory available on GPU %d < %d!", (int)hipDeviceProp.totalConstMem, (int)gGPUConstantMemBufferSize); - return (1); - } -#endif - - if (contextCreated == 0 && GPUFailedMsgI(hipSetDevice(mDeviceId))) { - GPUError("Could not set HIP Device!"); - return (1); - } - if (GPUFailedMsgI(hipSetDeviceFlags(hipDeviceScheduleBlockingSync))) { - GPUError("Could not set HIP Device!"); - return (1); - } - - /*if (GPUFailedMsgI(hipDeviceSetLimit(hipLimitStackSize, GPUCA_GPU_STACK_SIZE))) - { - GPUError("Error setting HIP stack size"); - GPUFailedMsgI(hipDeviceReset()); - return(1); - }*/ - - if (mDeviceMemorySize > hipDeviceProp.totalGlobalMem || GPUFailedMsgI(hipMalloc(&mDeviceMemoryBase, mDeviceMemorySize))) { - size_t free, total; - GPUFailedMsg(hipMemGetInfo(&free, &total)); - GPUError("HIP Memory Allocation Error (trying %lld bytes, %lld available on GPU, %lld free)", (long long int)mDeviceMemorySize, (long long int)hipDeviceProp.totalGlobalMem, (long long int)free); - GPUFailedMsgI(hipDeviceReset()); - return (1); - } - if (GPUFailedMsgI(hipHostMalloc(&mHostMemoryBase, mHostMemorySize))) { - GPUError("Error allocating Page Locked Host Memory (trying %lld bytes)", (long long int)mHostMemorySize); - GPUFailedMsgI(hipDeviceReset()); - return (1); - } - if (mProcessingSettings.debugLevel >= 1) { - GPUInfo("Memory ptrs: GPU (%lld bytes): %p - Host (%lld bytes): %p", (long long int)mDeviceMemorySize, mDeviceMemoryBase, (long long int)mHostMemorySize, mHostMemoryBase); - memset(mHostMemoryBase, 0, mHostMemorySize); - if (GPUFailedMsgI(hipMemset(mDeviceMemoryBase, 0xDD, mDeviceMemorySize))) { - GPUError("Error during HIP memset"); - GPUFailedMsgI(hipDeviceReset()); - return (1); - } - } - - for (int i = 0; i < mNStreams; i++) { - if (GPUFailedMsgI(hipStreamCreate(&mInternals->Streams[i]))) { - GPUError("Error creating HIP Stream"); - GPUFailedMsgI(hipDeviceReset()); - return (1); - } - } - - void* devPtrConstantMem; -#ifndef GPUCA_NO_CONSTANT_MEMORY - runConstantRegistrators(); - devPtrConstantMem = mDeviceConstantMemList[0]; -#else - if (GPUFailedMsgI(hipMalloc(&devPtrConstantMem, gGPUConstantMemBufferSize))) { - GPUError("HIP Memory Allocation Error"); - GPUFailedMsgI(hipDeviceReset()); - return (1); - } -#endif - mDeviceConstantMem = (GPUConstantMem*)devPtrConstantMem; - - hipLaunchKernelGGL(HIP_KERNEL_NAME(dummyInitKernel), dim3(mBlockCount), dim3(256), 0, 0, mDeviceMemoryBase); - GPUInfo("HIP Initialisation successfull (Device %d: %s (Frequency %d, Cores %d), %lld / %lld bytes host / global memory, Stack frame %d, Constant memory %lld)", mDeviceId, hipDeviceProp.name, hipDeviceProp.clockRate, hipDeviceProp.multiProcessorCount, (long long int)mHostMemorySize, (long long int)mDeviceMemorySize, (int)GPUCA_GPU_STACK_SIZE, (long long int)gGPUConstantMemBufferSize); - } else { - GPUReconstructionHIPBackend* master = dynamic_cast(mMaster); - mDeviceId = master->mDeviceId; - mBlockCount = master->mBlockCount; - mWarpSize = master->mWarpSize; - mMaxThreads = master->mMaxThreads; - mDeviceName = master->mDeviceName; - mDeviceConstantMem = master->mDeviceConstantMem; - mInternals = master->mInternals; - GPUFailedMsgI(hipSetDevice(mDeviceId)); - GPUInfo("HIP Initialized from master"); - } - for (unsigned int i = 0; i < mEvents.size(); i++) { - hipEvent_t* events = (hipEvent_t*)mEvents[i].data(); - for (unsigned int j = 0; j < mEvents[i].size(); j++) { - if (GPUFailedMsgI(hipEventCreateWithFlags(&events[j], hipEventBlockingSync))) { - GPUError("Error creating event"); - GPUFailedMsgI(hipDeviceReset()); - return 1; - } - } - } - - return (0); -} - -int GPUReconstructionHIPBackend::ExitDevice_Runtime() -{ - // Uninitialize HIP - GPUFailedMsgI(hipSetDevice(mDeviceId)); - SynchronizeGPU(); - unregisterRemainingRegisteredMemory(); - - for (unsigned int i = 0; i < mEvents.size(); i++) { - hipEvent_t* events = (hipEvent_t*)mEvents[i].data(); - for (unsigned int j = 0; j < mEvents[i].size(); j++) { - GPUFailedMsgI(hipEventDestroy(events[j])); - } - } - - if (mMaster == nullptr) { - GPUFailedMsgI(hipFree(mDeviceMemoryBase)); - -#ifdef GPUCA_NO_CONSTANT_MEMORY - GPUFailedMsgI(hipFree(mDeviceConstantMem)); -#endif - - for (int i = 0; i < mNStreams; i++) { - GPUFailedMsgI(hipStreamDestroy(mInternals->Streams[i])); - } - - GPUFailedMsgI(hipHostFree(mHostMemoryBase)); - GPUFailedMsgI(hipDeviceReset()); - GPUInfo("HIP Uninitialized"); - } - mHostMemoryBase = nullptr; - mDeviceMemoryBase = nullptr; - - /*if (GPUFailedMsgI(hipDeviceReset())) { // No longer doing this, another thread might use the GPU - GPUError("Could not uninitialize GPU"); - return (1); - }*/ - - return (0); -} - -size_t GPUReconstructionHIPBackend::GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev, deviceEvent* evList, int nEvents) -{ - if (mProcessingSettings.debugLevel >= 3) { - stream = -1; - } - if (stream == -1) { - SynchronizeGPU(); - GPUFailedMsg(hipMemcpy(dst, src, size, toGPU ? hipMemcpyHostToDevice : hipMemcpyDeviceToHost)); - } else { - if (evList == nullptr) { - nEvents = 0; - } - for (int k = 0; k < nEvents; k++) { - GPUFailedMsg(hipStreamWaitEvent(mInternals->Streams[stream], ((hipEvent_t*)evList)[k], 0)); - } - GPUFailedMsg(hipMemcpyAsync(dst, src, size, toGPU == -2 ? hipMemcpyDeviceToDevice : toGPU ? hipMemcpyHostToDevice : hipMemcpyDeviceToHost, mInternals->Streams[stream])); - } - if (ev) { - GPUFailedMsg(hipEventRecord(*(hipEvent_t*)ev, mInternals->Streams[stream == -1 ? 0 : stream])); - } - return size; -} - -size_t GPUReconstructionHIPBackend::TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) -{ - if (!(res->Type() & GPUMemoryResource::MEMORY_GPU)) { - if (mProcessingSettings.debugLevel >= 4) { - GPUInfo("Skipped transfer of non-GPU memory resource: %s", res->Name()); - } - return 0; - } - if (mProcessingSettings.debugLevel >= 3 && (strcmp(res->Name(), "ErrorCodes") || mProcessingSettings.debugLevel >= 4)) { - GPUInfo("Copying to %s: %s - %lld bytes", toGPU ? "GPU" : "Host", res->Name(), (long long int)res->Size()); - } - return GPUMemCpy(dst, src, res->Size(), stream, toGPU, ev, evList, nEvents); -} - -size_t GPUReconstructionHIPBackend::WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream, deviceEvent ev) -{ - for (unsigned int i = 0; i < 1 + mDeviceConstantMemList.size(); i++) { - void* basePtr = i ? mDeviceConstantMemList[i - 1] : mDeviceConstantMem; - if (basePtr == nullptr || (i && basePtr == (void*)mDeviceConstantMem)) { - continue; - } - if (stream == -1) { - GPUFailedMsg(hipMemcpy(((char*)basePtr) + offset, src, size, hipMemcpyHostToDevice)); - } else { - GPUFailedMsg(hipMemcpyAsync(((char*)basePtr) + offset, src, size, hipMemcpyHostToDevice, mInternals->Streams[stream])); - } - } - if (ev && stream != -1) { - GPUFailedMsg(hipEventRecord(*(hipEvent_t*)ev, mInternals->Streams[stream])); - } - return size; -} - -void GPUReconstructionHIPBackend::ReleaseEvent(deviceEvent ev) {} - -void GPUReconstructionHIPBackend::RecordMarker(deviceEvent ev, int stream) { GPUFailedMsg(hipEventRecord(*(hipEvent_t*)ev, mInternals->Streams[stream])); } - -std::unique_ptr GPUReconstructionHIPBackend::GetThreadContext() -{ - GPUFailedMsg(hipSetDevice(mDeviceId)); - return std::unique_ptr(new GPUThreadContext); -} - -void GPUReconstructionHIPBackend::SynchronizeGPU() { GPUFailedMsg(hipDeviceSynchronize()); } - -void GPUReconstructionHIPBackend::SynchronizeStream(int stream) { GPUFailedMsg(hipStreamSynchronize(mInternals->Streams[stream])); } - -void GPUReconstructionHIPBackend::SynchronizeEvents(deviceEvent* evList, int nEvents) -{ - for (int i = 0; i < nEvents; i++) { - GPUFailedMsg(hipEventSynchronize(((hipEvent_t*)evList)[i])); - } -} - -void GPUReconstructionHIPBackend::StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents) -{ - for (int i = 0; i < nEvents; i++) { - GPUFailedMsg(hipStreamWaitEvent(mInternals->Streams[stream], ((hipEvent_t*)evList)[i], 0)); - } -} - -bool GPUReconstructionHIPBackend::IsEventDone(deviceEvent* evList, int nEvents) -{ - for (int i = 0; i < nEvents; i++) { - hipError_t retVal = hipEventSynchronize(((hipEvent_t*)evList)[i]); - if (retVal == hipErrorNotReady) { - return false; - } - GPUFailedMsg(retVal); - } - return (true); -} - -int GPUReconstructionHIPBackend::GPUDebug(const char* state, int stream, bool force) -{ - // Wait for HIP-Kernel to finish and check for HIP errors afterwards, in case of debugmode - hipError_t hipErr; - hipErr = hipGetLastError(); - if (hipErr != hipSuccess) { - GPUError("HIP Error %s while running kernel (%s) (Stream %d)", hipGetErrorString(hipErr), state, stream); - return (1); - } - if (!force && mProcessingSettings.debugLevel <= 0) { - return (0); - } - if (GPUFailedMsgI(hipDeviceSynchronize())) { - GPUError("HIP Error while synchronizing (%s) (Stream %d)", state, stream); - return (1); - } - if (mProcessingSettings.debugLevel >= 3) { - GPUInfo("GPU Sync Done"); - } - return (0); -} - -int GPUReconstructionHIPBackend::registerMemoryForGPU_internal(const void* ptr, size_t size) -{ - return GPUFailedMsgI(hipHostRegister((void*)ptr, size, hipHostRegisterDefault)); -} - -int GPUReconstructionHIPBackend::unregisterMemoryForGPU_internal(const void* ptr) -{ - return GPUFailedMsgI(hipHostUnregister((void*)ptr)); -} - -void* GPUReconstructionHIPBackend::getGPUPointer(void* ptr) -{ - void* retVal = nullptr; - GPUFailedMsg(hipHostGetDevicePointer(&retVal, ptr, 0)); - return retVal; -} - -void GPUReconstructionHIPBackend::PrintKernelOccupancies() -{ - -} diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIPDef.h b/GPU/GPUTracking/Base/hip/GPUReconstructionHIPDef.h deleted file mode 100644 index 516a8ec8c51a7..0000000000000 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIPDef.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUReconstructionCUDDef.h -/// \author David Rohr - -#ifndef O2_GPU_GPURECONSTRUCTIONHIPDEF_H -#define O2_GPU_GPURECONSTRUCTIONHIPDEF_H - -#ifndef __HIPCC__ // HIP -#define GPUCA_UNROLL(optCu, optHi) GPUCA_M_UNROLL_##optCu -#define GPUdic(optCu, optHi) GPUCA_GPUdic_select_##optCu() -#else -#define GPUCA_UNROLL(optCu, optHi) GPUCA_M_UNROLL_##optHi -#define GPUdic(optCu, optHi) GPUCA_GPUdic_select_##optHi() -#endif - -#include "GPUDef.h" - -#ifndef GPUCA_NO_CONSTANT_MEMORY -#define GPUCA_CONSMEM_PTR -#define GPUCA_CONSMEM_CALL -#define GPUCA_CONSMEM (gGPUConstantMemBuffer.v) -#else -#define GPUCA_CONSMEM_PTR const GPUConstantMem *gGPUConstantMemBuffer, -#define GPUCA_CONSMEM_CALL me->mDeviceConstantMem, -#define GPUCA_CONSMEM ((GPUConstantMem&)(*gGPUConstantMemBuffer)) -#endif -#define GPUCA_KRNL_BACKEND_CLASS GPUReconstructionHIPBackend - -#endif diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIPInternals.h b/GPU/GPUTracking/Base/hip/GPUReconstructionHIPInternals.h deleted file mode 100644 index 7903cdd936c5c..0000000000000 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIPInternals.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUReconstructionHIPInternals.h -/// \author David Rohr - -// All HIP-header related stuff goes here, so we can run CING over GPUReconstructionHIP - -#ifndef GPURECONSTRUCTIONHIPINTERNALS_H -#define GPURECONSTRUCTIONHIPINTERNALS_H - -#include -#include "GPULogging.h" -#include -#include -#include - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ -#define GPUFailedMsg(x) GPUFailedMsgA(x, __FILE__, __LINE__) -#define GPUFailedMsgI(x) GPUFailedMsgAI(x, __FILE__, __LINE__) - -struct GPUReconstructionHIPInternals { - std::vector> kernelModules; // module for RTC compilation - std::vector> kernelFunctions; // vector of ptrs to RTC kernels - std::vector kernelNames; // names of kernels - hipStream_t Streams[GPUCA_MAX_STREAMS]; // Pointer to array of HIP Streams - - template - static int getRTCkernelNum(int k = -1); - - static void getArgPtrs(const void** pArgs) {} - template - static void getArgPtrs(const void** pArgs, const T& arg, const Args&... args) - { - *pArgs = &arg; - getArgPtrs(pArgs + 1, args...); - } -}; - -class GPUDebugTiming -{ - public: - GPUDebugTiming(bool d, void** t, hipStream_t* s, GPUReconstruction::krnlSetup& x, GPUReconstructionHIPBackend* r) : mDeviceTimers(t), mStreams(s), mXYZ(x), mRec(r), mDo(d) - { - if (mDo) { - if (mDeviceTimers) { - mRec->GPUFailedMsg(hipEventRecord((hipEvent_t)mDeviceTimers[0], mStreams[mXYZ.x.stream])); - } else { - mTimer.ResetStart(); - } - } - } - ~GPUDebugTiming() - { - if (mDo) { - if (mDeviceTimers) { - mRec->GPUFailedMsg(hipEventRecord((hipEvent_t)mDeviceTimers[1], mStreams[mXYZ.x.stream])); - mRec->GPUFailedMsg(hipEventSynchronize((hipEvent_t)mDeviceTimers[1])); - float v; - mRec->GPUFailedMsg(hipEventElapsedTime(&v, (hipEvent_t)mDeviceTimers[0], (hipEvent_t)mDeviceTimers[1])); - mXYZ.t = v * 1.e-3f; - } else { - mRec->GPUFailedMsg(hipStreamSynchronize(mStreams[mXYZ.x.stream])); - mXYZ.t = mTimer.GetCurrentElapsedTime(); - } - } - } - - private: - GPUReconstruction::deviceEvent* mDeviceTimers; - hipStream_t* mStreams; - GPUReconstruction::krnlSetup& mXYZ; - GPUReconstructionHIPBackend* mRec; - HighResTimer mTimer; - bool mDo; -}; - -static_assert(std::is_convertible::value, "HIP event type incompatible to deviceEvent"); - -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#endif diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIPKernels.hip b/GPU/GPUTracking/Base/hip/GPUReconstructionHIPKernels.hip deleted file mode 100644 index de7587ee8a5e5..0000000000000 --- a/GPU/GPUTracking/Base/hip/GPUReconstructionHIPKernels.hip +++ /dev/null @@ -1,156 +0,0 @@ -#include "hip/hip_runtime.h" -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file GPUReconstructionHIPKernels.cu -/// \author David Rohr - -#include "GPUReconstructionHIPDef.h" -#include "GPUReconstructionHIPIncludes.h" - -#include "GPUReconstructionHIP.h" -#include "GPUReconstructionHIPInternals.h" -#include "HIPThrustHelpers.h" - -using namespace GPUCA_NAMESPACE::gpu; - -#ifdef GPUCA_USE_TEXTURES -texture gAliTexRefu2; -texture gAliTexRefu; -#endif - -#include "GPUReconstructionIncludesDeviceAll.h" - -#if defined(__HIPCC__) && defined(GPUCA_HAS_GLOBAL_SYMBOL_CONSTANT_MEM) -__global__ void gGPUConstantMemBuffer_dummy(int* p) { *p = *(int*)&gGPUConstantMemBuffer; } -#endif - -template <> -void GPUReconstructionHIPBackend::runKernelBackendInternal(krnlSetup& _xyz, void* const& ptr, unsigned long const& size) -{ - GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); - GPUFailedMsg(hipMemsetAsync(ptr, 0, size, mInternals->Streams[_xyz.x.stream])); -} - -template -void GPUReconstructionHIPBackend::runKernelBackendInternal(krnlSetup& _xyz, const Args&... args) -{ -#ifndef __HIPCC__ // HIP version - GPUDebugTiming timer(mProcessingSettings.deviceTimers && mProcessingSettings.debugLevel > 0, (void**)mDebugEvents, mInternals->Streams, _xyz, this); -#if !defined(GPUCA_KERNEL_COMPILE_MODE) || GPUCA_KERNEL_COMPILE_MODE != 1 - if (!mProcessingSettings.rtc.enable) { - backendInternal::runKernelBackendMacro(_xyz, this, args...); - } else -#endif - { - auto& x = _xyz.x; - auto& y = _xyz.y; - const void* pArgs[sizeof...(Args) + 3]; // 3 is max: cons mem + y.start + y.num - int arg_offset = 0; -#ifdef GPUCA_NO_CONSTANT_MEMORY - arg_offset = 1; - pArgs[0] = &mDeviceConstantMem; -#endif - pArgs[arg_offset] = &y.start; - GPUReconstructionHIPInternals::getArgPtrs(&pArgs[arg_offset + 1 + (y.num > 1)], args...); - if (y.num <= 1) { - GPUFailedMsg(hipModuleLaunchKernel(*mInternals->kernelFunctions[mInternals->getRTCkernelNum()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); - } else { - pArgs[arg_offset + 1] = &y.num; - GPUFailedMsg(hipModuleLaunchKernel(*mInternals->kernelFunctions[mInternals->getRTCkernelNum()], x.nBlocks, 1, 1, x.nThreads, 1, 1, 0, mInternals->Streams[x.stream], (void**)pArgs, nullptr)); - } - } - if (mProcessingSettings.checkKernelFailures) { - if (GPUDebug(GetKernelName(), _xyz.x.stream, true)) { - throw std::runtime_error("Kernel Failure"); - } - } -#else // HIP version - if (mProcessingSettings.deviceTimers && mProcessingSettings.debugLevel > 0) { - backendInternal::runKernelBackendMacro(_xyz, this, (hipEvent_t*)&mDebugEvents->DebugStart, (hipEvent_t*)&mDebugEvents->DebugStop, args...); - GPUFailedMsg(hipEventSynchronize((hipEvent_t)mDebugEvents->DebugStop)); - float v; - GPUFailedMsg(hipEventElapsedTime(&v, (hipEvent_t)mDebugEvents->DebugStart, (hipEvent_t)mDebugEvents->DebugStop)); - _xyz.t = v * 1.e-3f; - } else { - backendInternal::runKernelBackendMacro(_xyz, this, nullptr, nullptr, args...); - } -#endif -} - -template -int GPUReconstructionHIPBackend::runKernelBackend(krnlSetup& _xyz, Args... args) -{ - auto& x = _xyz.x; - auto& z = _xyz.z; - if (z.evList) { - for (int k = 0; k < z.nEvents; k++) { - GPUFailedMsg(hipStreamWaitEvent(mInternals->Streams[x.stream], ((hipEvent_t*)z.evList)[k], 0)); - } - } - runKernelBackendInternal(_xyz, args...); - GPUFailedMsg(hipGetLastError()); - if (z.ev) { - GPUFailedMsg(hipEventRecord(*(hipEvent_t*)z.ev, mInternals->Streams[x.stream])); - } - return 0; -} - -#if defined(GPUCA_KERNEL_COMPILE_MODE) && GPUCA_KERNEL_COMPILE_MODE == 1 -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_PROP(x_class, x_attributes) \ - template int GPUReconstructionHIPBackend::runKernelBackend(krnlSetup & _xyz GPUCA_M_STRIP(x_arguments)); -#else -#if defined(GPUCA_KERNEL_COMPILE_MODE) && GPUCA_KERNEL_COMPILE_MODE == 2 -#define GPUCA_KRNL_DEFONLY -#endif - -#undef GPUCA_KRNL_REG -#define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_PROP(x_class, x_attributes) \ - GPUCA_KRNL_WRAP(GPUCA_KRNL_, x_class, x_attributes, x_arguments, x_forward) \ - template int GPUReconstructionHIPBackend::runKernelBackend(krnlSetup & _xyz GPUCA_M_STRIP(x_arguments)); -#ifndef __HIPCC__ // HIP version -#define GPUCA_KRNL_CALL_single(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))<<mInternals->Streams[x.stream]>>>(GPUCA_CONSMEM_CALL y.start, args...); -#define GPUCA_KRNL_CALL_multi(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)<<mInternals->Streams[x.stream]>>>(GPUCA_CONSMEM_CALL y.start, y.num, args...); -#else // HIP version -#undef GPUCA_KRNL_CUSTOM -#define GPUCA_KRNL_CUSTOM(args) GPUCA_M_STRIP(args) -#undef GPUCA_KRNL_BACKEND_XARGS -#define GPUCA_KRNL_BACKEND_XARGS hipEvent_t *debugStartEvent, hipEvent_t *debugStopEvent, -#define GPUCA_KRNL_CALL_single(x_class, x_attributes, x_arguments, x_forward) \ - if (debugStartEvent == nullptr) { \ - hipLaunchKernelGGL(HIP_KERNEL_NAME(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))), dim3(x.nBlocks), dim3(x.nThreads), 0, me->mInternals->Streams[x.stream], GPUCA_CONSMEM_CALL y.start, args...); \ - } else { \ - hipExtLaunchKernelGGL(HIP_KERNEL_NAME(GPUCA_M_CAT(krnl_, GPUCA_M_KRNL_NAME(x_class))), dim3(x.nBlocks), dim3(x.nThreads), 0, me->mInternals->Streams[x.stream], *debugStartEvent, *debugStopEvent, 0, GPUCA_CONSMEM_CALL y.start, args...); \ - } -#define GPUCA_KRNL_CALL_multi(x_class, x_attributes, x_arguments, x_forward) \ - if (debugStartEvent == nullptr) { \ - hipLaunchKernelGGL(HIP_KERNEL_NAME(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)), dim3(x.nBlocks), dim3(x.nThreads), 0, me->mInternals->Streams[x.stream], GPUCA_CONSMEM_CALL y.start, y.num, args...); \ - } else { \ - hipExtLaunchKernelGGL(HIP_KERNEL_NAME(GPUCA_M_CAT3(krnl_, GPUCA_M_KRNL_NAME(x_class), _multi)), dim3(x.nBlocks), dim3(x.nThreads), 0, me->mInternals->Streams[x.stream], *debugStartEvent, *debugStopEvent, 0, GPUCA_CONSMEM_CALL y.start, y.num, args...); \ - } -#endif // __HIPCC__ -#endif - -#include "GPUReconstructionKernels.h" -#undef GPUCA_KRNL - -#ifndef GPUCA_NO_CONSTANT_MEMORY -static GPUReconstructionDeviceBase::deviceConstantMemRegistration registerConstSymbol([]() { - void* retVal = nullptr; - GPUReconstructionHIP::GPUFailedMsgI(hipGetSymbolAddress(&retVal, HIP_SYMBOL(gGPUConstantMemBuffer))); - return retVal; -}); -#endif diff --git a/GPU/GPUTracking/Base/hip/GPUReconstructionHIPkernel.template.hip b/GPU/GPUTracking/Base/hip/GPUReconstructionHIPkernel.template.hip new file mode 100644 index 0000000000000..0ecaf7a83b18c --- /dev/null +++ b/GPU/GPUTracking/Base/hip/GPUReconstructionHIPkernel.template.hip @@ -0,0 +1,32 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \file GPUReconstructionHIPkernel.cu +/// \author David Rohr + +#define GPUCA_GPUCODE_COMPILEKERNELS +#include "GPUReconstructionHIPIncludes.h" +#include "GPUReconstructionHIPDef.h" +#define GPUCA_KRNL_REG(args) __launch_bounds__(GPUCA_M_MAX2_3(GPUCA_M_STRIP(args))) +#define GPUCA_KRNL(...) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, __VA_ARGS__) +#define GPUCA_KRNL_LOAD_single(...) GPUCA_KRNLGPU_SINGLE(__VA_ARGS__); +#define GPUCA_KRNL_LOAD_multi(...) GPUCA_KRNLGPU_MULTI(__VA_ARGS__); +#include "GPUReconstructionKernelMacros.h" + +// clang-format off +@O2_GPU_KERNEL_TEMPLATE_FILES@ +// clang-format on + +extern "C" { +// clang-format off +@O2_GPU_KERNEL_TEMPLATE_REPLACE@ +// clang-format on +} diff --git a/GPU/GPUTracking/Base/hip/HIPThrustHelpers.h b/GPU/GPUTracking/Base/hip/HIPThrustHelpers.h deleted file mode 100644 index dc532bddbebb0..0000000000000 --- a/GPU/GPUTracking/Base/hip/HIPThrustHelpers.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019-2020 CERN and copyright holders of ALICE O2. -// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. -// All rights not expressly granted are reserved. -// -// This software is distributed under the terms of the GNU General Public -// License v3 (GPL Version 3), copied verbatim in the file "COPYING". -// -// In applying this license CERN does not waive the privileges and immunities -// granted to it by virtue of its status as an Intergovernmental Organization -// or submit itself to any jurisdiction. - -/// \file HIPThrustHelpers.h -/// \author David Rohr - -#ifndef GPU_HIPTHRUSTHELPERS_H -#define GPU_HIPTHRUSTHELPERS_H - -#include "GPULogging.h" -#include -#include - -namespace GPUCA_NAMESPACE -{ -namespace gpu -{ - -class ThrustVolatileAsyncAllocator -{ - public: - typedef char value_type; - - ThrustVolatileAsyncAllocator(GPUReconstruction* r) : mRec(r) {} - char* allocate(std::ptrdiff_t n) { return (char*)mRec->AllocateVolatileDeviceMemory(n); } - - void deallocate(char* ptr, size_t) {} - - private: - GPUReconstruction* mRec; -}; - -} // namespace gpu -} // namespace GPUCA_NAMESPACE - -#ifndef __HIPCC__ -// Override synchronize call at end of thrust algorithm running on stream, just don't run hipStreamSynchronize -namespace thrust -{ -namespace hip_cub -{ - -typedef thrust::hip_cub::execution_policy thrustStreamPolicy; -template <> -__host__ __device__ inline hipError_t synchronize(thrustStreamPolicy& policy) -{ -#ifndef GPUCA_GPUCODE_DEVICE - // Do not synchronize! - return hipSuccess; -#else - return synchronize_stream(derived_cast(policy)); -#endif -} - -} // namespace hip_cub -} // namespace thrust -#endif // __HIPCC__ - -#endif // GPU_HIPTHRUSTHELPERS_H diff --git a/GPU/GPUTracking/Base/hip/per_kernel/CMakeLists.txt b/GPU/GPUTracking/Base/hip/per_kernel/CMakeLists.txt new file mode 100644 index 0000000000000..3aba296d9cc4a --- /dev/null +++ b/GPU/GPUTracking/Base/hip/per_kernel/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +add_library(GPUTrackingHIPKernels OBJECT $,REPLACE,[^A-Za-z0-9]+,_>,PREPEND,${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_>,APPEND,.hip.cxx>, >) +set(CMAKE_CXX_COMPILER ${hip_HIPCC_EXECUTABLE}) +set(CMAKE_CXX_FLAGS "${GPU_RTC_FLAGS} --genco") +unset(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}) diff --git a/GPU/GPUTracking/Base/opencl-common/CMakeLists.txt b/GPU/GPUTracking/Base/opencl-common/CMakeLists.txt index deaa94265d1b0..5e49b7a81a85b 100644 --- a/GPU/GPUTracking/Base/opencl-common/CMakeLists.txt +++ b/GPU/GPUTracking/Base/opencl-common/CMakeLists.txt @@ -21,9 +21,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") PUBLIC_LINK_LIBRARIES OpenCL::OpenCL O2::GPUTracking TARGETVARNAME targetName) - target_compile_definitions( - ${targetName} PRIVATE GPUCA_GPULIBRARY=OCL - $) + target_compile_definitions(${targetName} PRIVATE $) # the compile_defitions are not propagated automatically on purpose (they are # declared PRIVATE) so we are not leaking them outside of the GPU** # directories @@ -32,8 +30,6 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") endif() if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") - add_definitions(-DGPUCA_GPULIBRARY=OCL) - # Generate the dictionary get_directory_property(incdirs INCLUDE_DIRECTORIES) generate_dictionary("Ali${MODULE}" "" "GPUReconstructionOCL.h" "${incdirs} .") @@ -53,7 +49,6 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") endif() if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") - add_definitions(-DGPUCA_GPULIBRARY=OCL) add_library(${MODULE} SHARED ${SRCS}) target_link_libraries(${MODULE} GPUTracking OpenCL) target_include_directories(${MODULE} PUBLIC ${CMAKE_CURRENT_LIST_DIR}) diff --git a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cl b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cl index 08555ce71ad2d..6c89b2e6a4710 100644 --- a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cl +++ b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cl @@ -32,9 +32,6 @@ #define local __local #define constant __constant #define private __private - //#include //Use -finclude-default-header instead! current clang libclc.h is incompatible to SPIR-V - typedef __SIZE_TYPE__ size_t; //BUG: OpenCL C++ does not declare placement new - void* operator new (size_t size, void *ptr); #undef global #undef local #undef constant @@ -104,12 +101,12 @@ // if (gpu_mem != pTracker.GPUParametersConst()->gpumem) return; //TODO! -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_SINGLE(x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNLGPU_MULTI(x_class, x_attributes, x_arguments, x_forward) +#define GPUCA_KRNL(...) GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, __VA_ARGS__) +#define GPUCA_KRNL_LOAD_single(...) GPUCA_KRNLGPU_SINGLE(__VA_ARGS__) +#define GPUCA_KRNL_LOAD_multi(...) GPUCA_KRNLGPU_MULTI(__VA_ARGS__) #define GPUCA_CONSMEM_PTR GPUglobal() char *gpu_mem, GPUconstant() MEM_CONSTANT(GPUConstantMem) * pConstant, #define GPUCA_CONSMEM (*pConstant) -#include "GPUReconstructionKernels.h" +#include "GPUReconstructionKernelList.h" #undef GPUCA_KRNL #undef GPUCA_KRNL_LOAD_single #undef GPUCA_KRNL_LOAD_multi diff --git a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cxx b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cxx index 5cb85694fac1d..3d6d083f4a87e 100644 --- a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cxx +++ b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.cxx @@ -32,9 +32,9 @@ using namespace GPUCA_NAMESPACE::gpu; return (1); \ } -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) GPUCA_KRNL_PROP(x_class, x_attributes) +#define GPUCA_KRNL(x_class, x_attributes, ...) GPUCA_KRNL_PROP(x_class, x_attributes) #define GPUCA_KRNL_BACKEND_CLASS GPUReconstructionOCL -#include "GPUReconstructionKernels.h" +#include "GPUReconstructionKernelList.h" #undef GPUCA_KRNL GPUReconstructionOCL::GPUReconstructionOCL(const GPUSettingsDeviceBackend& cfg) : GPUReconstructionDeviceBase(cfg, sizeof(GPUReconstructionDeviceBase)) @@ -393,7 +393,7 @@ int GPUReconstructionOCL::ExitDevice_Runtime() return (0); } -size_t GPUReconstructionOCL::GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev, deviceEvent* evList, int nEvents) +size_t GPUReconstructionOCL::GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev, deviceEvent* evList, int nEvents) { if (evList == nullptr) { nEvents = 0; @@ -405,16 +405,16 @@ size_t GPUReconstructionOCL::GPUMemCpy(void* dst, const void* src, size_t size, SynchronizeGPU(); } if (toGPU == -2) { - GPUFailedMsg(clEnqueueCopyBuffer(mInternals->command_queue[stream == -1 ? 0 : stream], mInternals->mem_gpu, mInternals->mem_gpu, (char*)src - (char*)mDeviceMemoryBase, (char*)dst - (char*)mDeviceMemoryBase, size, nEvents, (cl_event*)evList, (cl_event*)ev)); + GPUFailedMsg(clEnqueueCopyBuffer(mInternals->command_queue[stream == -1 ? 0 : stream], mInternals->mem_gpu, mInternals->mem_gpu, (char*)src - (char*)mDeviceMemoryBase, (char*)dst - (char*)mDeviceMemoryBase, size, nEvents, evList->getEventList(), ev->getEventList())); } else if (toGPU) { - GPUFailedMsg(clEnqueueWriteBuffer(mInternals->command_queue[stream == -1 ? 0 : stream], mInternals->mem_gpu, stream == -1, (char*)dst - (char*)mDeviceMemoryBase, size, src, nEvents, (cl_event*)evList, (cl_event*)ev)); + GPUFailedMsg(clEnqueueWriteBuffer(mInternals->command_queue[stream == -1 ? 0 : stream], mInternals->mem_gpu, stream == -1, (char*)dst - (char*)mDeviceMemoryBase, size, src, nEvents, evList->getEventList(), ev->getEventList())); } else { - GPUFailedMsg(clEnqueueReadBuffer(mInternals->command_queue[stream == -1 ? 0 : stream], mInternals->mem_gpu, stream == -1, (char*)src - (char*)mDeviceMemoryBase, size, dst, nEvents, (cl_event*)evList, (cl_event*)ev)); + GPUFailedMsg(clEnqueueReadBuffer(mInternals->command_queue[stream == -1 ? 0 : stream], mInternals->mem_gpu, stream == -1, (char*)src - (char*)mDeviceMemoryBase, size, dst, nEvents, evList->getEventList(), ev->getEventList())); } return size; } -size_t GPUReconstructionOCL::TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) +size_t GPUReconstructionOCL::TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent* ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) { if (!(res->Type() & GPUMemoryResource::MEMORY_GPU)) { if (mProcessingSettings.debugLevel >= 4) { @@ -428,26 +428,26 @@ size_t GPUReconstructionOCL::TransferMemoryInternal(GPUMemoryResource* res, int return GPUMemCpy(dst, src, res->Size(), stream, toGPU, ev, evList, nEvents); } -size_t GPUReconstructionOCL::WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream, deviceEvent ev) +size_t GPUReconstructionOCL::WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream, deviceEvent* ev) { if (stream == -1) { SynchronizeGPU(); } - GPUFailedMsg(clEnqueueWriteBuffer(mInternals->command_queue[stream == -1 ? 0 : stream], mInternals->mem_constant, stream == -1, offset, size, src, 0, nullptr, (cl_event*)ev)); + GPUFailedMsg(clEnqueueWriteBuffer(mInternals->command_queue[stream == -1 ? 0 : stream], mInternals->mem_constant, stream == -1, offset, size, src, 0, nullptr, ev->getEventList())); return size; } -void GPUReconstructionOCL::ReleaseEvent(deviceEvent ev) { GPUFailedMsg(clReleaseEvent(*(cl_event*)ev)); } +void GPUReconstructionOCL::ReleaseEvent(deviceEvent ev) { GPUFailedMsg(clReleaseEvent(ev.get())); } -void GPUReconstructionOCL::RecordMarker(deviceEvent ev, int stream) { GPUFailedMsg(clEnqueueMarkerWithWaitList(mInternals->command_queue[stream], 0, nullptr, (cl_event*)ev)); } +void GPUReconstructionOCL::RecordMarker(deviceEvent ev, int stream) { GPUFailedMsg(clEnqueueMarkerWithWaitList(mInternals->command_queue[stream], 0, nullptr, ev.getEventList())); } -int GPUReconstructionOCL::DoStuckProtection(int stream, void* event) +int GPUReconstructionOCL::DoStuckProtection(int stream, deviceEvent event) { if (mProcessingSettings.stuckProtection) { cl_int tmp = 0; for (int i = 0; i <= mProcessingSettings.stuckProtection / 50; i++) { usleep(50); - clGetEventInfo(*(cl_event*)event, CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(tmp), &tmp, nullptr); + clGetEventInfo(event.get(), CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(tmp), &tmp, nullptr); if (tmp == CL_COMPLETE) { break; } @@ -471,12 +471,12 @@ void GPUReconstructionOCL::SynchronizeGPU() void GPUReconstructionOCL::SynchronizeStream(int stream) { GPUFailedMsg(clFinish(mInternals->command_queue[stream])); } -void GPUReconstructionOCL::SynchronizeEvents(deviceEvent* evList, int nEvents) { GPUFailedMsg(clWaitForEvents(nEvents, (cl_event*)evList)); } +void GPUReconstructionOCL::SynchronizeEvents(deviceEvent* evList, int nEvents) { GPUFailedMsg(clWaitForEvents(nEvents, evList->getEventList())); } void GPUReconstructionOCL::StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents) { if (nEvents) { - GPUFailedMsg(clEnqueueMarkerWithWaitList(mInternals->command_queue[stream], nEvents, (cl_event*)evList, nullptr)); + GPUFailedMsg(clEnqueueMarkerWithWaitList(mInternals->command_queue[stream], nEvents, evList->getEventList(), nullptr)); } } @@ -484,7 +484,7 @@ bool GPUReconstructionOCL::IsEventDone(deviceEvent* evList, int nEvents) { cl_int eventdone; for (int i = 0; i < nEvents; i++) { - GPUFailedMsg(clGetEventInfo(((cl_event*)evList)[i], CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(eventdone), &eventdone, nullptr)); + GPUFailedMsg(clGetEventInfo(evList[i].get(), CL_EVENT_COMMAND_EXECUTION_STATUS, sizeof(eventdone), &eventdone, nullptr)); if (eventdone != CL_COMPLETE) { return false; } diff --git a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.h b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.h index 2a97296afcbbe..d5562e14a3577 100644 --- a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.h +++ b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCL.h @@ -42,16 +42,16 @@ class GPUReconstructionOCL : public GPUReconstructionDeviceBase void GPUFailedMsgA(const long int error, const char* file, int line); void SynchronizeGPU() override; - int DoStuckProtection(int stream, void* event) override; + int DoStuckProtection(int stream, deviceEvent event) override; int GPUDebug(const char* state = "UNKNOWN", int stream = -1, bool force = false) override; void SynchronizeStream(int stream) override; void SynchronizeEvents(deviceEvent* evList, int nEvents = 1) override; void StreamWaitForEvents(int stream, deviceEvent* evList, int nEvents = 1) override; bool IsEventDone(deviceEvent* evList, int nEvents = 1) override; - size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, deviceEvent ev = nullptr) override; - size_t TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) override; - size_t GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override; + size_t WriteToConstantMemory(size_t offset, const void* src, size_t size, int stream = -1, deviceEvent* ev = nullptr) override; + size_t TransferMemoryInternal(GPUMemoryResource* res, int stream, deviceEvent* ev, deviceEvent* evList, int nEvents, bool toGPU, const void* src, void* dst) override; + size_t GPUMemCpy(void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) override; void ReleaseEvent(deviceEvent ev) override; void RecordMarker(deviceEvent ev, int stream) override; @@ -64,9 +64,9 @@ class GPUReconstructionOCL : public GPUReconstructionDeviceBase template unsigned int FindKernel(int num); template - int runKernelBackendCommon(krnlSetup& _xyz, K& k, const Args&... args); + int runKernelBackendInternal(const krnlSetupTime& _xyz, K& k, const Args&... args); template - const krnlProperties getKernelPropertiesBackend(); + gpu_reconstruction_kernels::krnlProperties getKernelPropertiesBackend(); GPUReconstructionOCLInternals* mInternals; }; diff --git a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCLInternals.h b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCLInternals.h index 87d4d0169dcee..2f8a70ec6b2b1 100644 --- a/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCLInternals.h +++ b/GPU/GPUTracking/Base/opencl-common/GPUReconstructionOCLInternals.h @@ -173,7 +173,7 @@ struct GPUReconstructionOCLInternals { }; template -int GPUReconstructionOCL::runKernelBackendCommon(krnlSetup& _xyz, K& k, const Args&... args) +inline int GPUReconstructionOCL::runKernelBackendInternal(const krnlSetupTime& _xyz, K& k, const Args&... args) { auto& x = _xyz.x; auto& y = _xyz.y; diff --git a/GPU/GPUTracking/Base/opencl/CMakeLists.txt b/GPU/GPUTracking/Base/opencl/CMakeLists.txt index 34e848c10efa5..1ad9041f70997 100644 --- a/GPU/GPUTracking/Base/opencl/CMakeLists.txt +++ b/GPU/GPUTracking/Base/opencl/CMakeLists.txt @@ -61,11 +61,11 @@ add_custom_command( -- "-D$,$-D>" "-I$,EXCLUDE,^/usr>,INCLUDE,${OPENCL_HEADER_FILTER}>,$-I>" - -DGPUCA_GPULIBRARY=OCL1 -x clc++ MAIN_DEPENDENCY ${CL_SRC} IMPLICIT_DEPENDS CXX ${CL_SRC} - COMMAND_EXPAND_LISTS) + COMMAND_EXPAND_LISTS + COMMENT "Compiling OpenCL1 CL source file ${CL_SRC}") create_binary_resource(${CL_BIN} ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.o) @@ -79,9 +79,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") PUBLIC_LINK_LIBRARIES O2::GPUTrackingOpenCLCommon TARGETVARNAME targetName) - target_compile_definitions( - ${targetName} PRIVATE GPUCA_GPULIBRARY=OCL1 - $) + target_compile_definitions(${targetName} PRIVATE $) # the compile_defitions are not propagated automatically on purpose (they are # declared PRIVATE) so we are not leaking them outside of the GPU** # directories @@ -90,8 +88,6 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") endif() if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") - add_definitions(-DGPUCA_GPULIBRARY=OCL1) - # Generate the dictionary get_directory_property(incdirs INCLUDE_DIRECTORIES) generate_dictionary("Ali${MODULE}" "" "GPUReconstructionOCL1.h" "${incdirs} .") @@ -110,7 +106,6 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") endif() if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") - add_definitions(-DGPUCA_GPULIBRARY=OCL1) add_library(${MODULE} SHARED ${SRCS}) target_link_libraries(${MODULE} GPUTrackingOpenCLCommon) install(TARGETS ${MODULE}) diff --git a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.cxx b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.cxx index 1c1f655f395d9..02a230fd69d2a 100644 --- a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.cxx +++ b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.cxx @@ -37,10 +37,10 @@ GPUReconstructionOCL1Backend::GPUReconstructionOCL1Backend(const GPUSettingsDevi } template -int GPUReconstructionOCL1Backend::runKernelBackend(krnlSetup& _xyz, const Args&... args) +int GPUReconstructionOCL1Backend::runKernelBackend(const krnlSetupArgs& args) { - cl_kernel k = _xyz.y.num > 1 ? getKernelObject() : getKernelObject(); - return runKernelBackendCommon(_xyz, k, args...); + cl_kernel k = args.s.y.num > 1 ? getKernelObject() : getKernelObject(); + return std::apply([this, &args, &k](auto&... vals) { return runKernelBackendInternal(args.s, k, vals...); }, args.v); } template @@ -65,17 +65,17 @@ int GPUReconstructionOCL1Backend::GetOCLPrograms() } #define GPUCA_OPENCL1 -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) \ - if (AddKernel(false)) { \ - return 1; \ +#define GPUCA_KRNL(...) \ + GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, __VA_ARGS__) +#define GPUCA_KRNL_LOAD_single(x_class, ...) \ + if (AddKernel(false)) { \ + return 1; \ } -#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) \ - if (AddKernel(true)) { \ - return 1; \ +#define GPUCA_KRNL_LOAD_multi(x_class, ...) \ + if (AddKernel(true)) { \ + return 1; \ } -#include "GPUReconstructionKernels.h" +#include "GPUReconstructionKernelList.h" #undef GPUCA_KRNL #undef GPUCA_OPENCL1 #undef GPUCA_KRNL_LOAD_single diff --git a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.h b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.h index 00727ffd74a6b..c91a52d533b7a 100644 --- a/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.h +++ b/GPU/GPUTracking/Base/opencl/GPUReconstructionOCL1.h @@ -36,7 +36,7 @@ class GPUReconstructionOCL1Backend : public GPUReconstructionOCL GPUReconstructionOCL1Backend(const GPUSettingsDeviceBackend& cfg); template - int runKernelBackend(krnlSetup& _xyz, const Args&... args); + int runKernelBackend(const krnlSetupArgs& args); template S& getKernelObject(); diff --git a/GPU/GPUTracking/Base/opencl2/CMakeLists.txt b/GPU/GPUTracking/Base/opencl2/CMakeLists.txt index f9c0570d3f63c..ec2a4446142c8 100644 --- a/GPU/GPUTracking/Base/opencl2/CMakeLists.txt +++ b/GPU/GPUTracking/Base/opencl2/CMakeLists.txt @@ -33,7 +33,6 @@ set(OCL_DEFINECL "-D$ ${CL_BIN}.src MAIN_DEPENDENCY ${CL_SRC} IMPLICIT_DEPENDS CXX ${CL_SRC} - COMMAND_EXPAND_LISTS) + COMMAND_EXPAND_LISTS + COMMENT "Preparing OpenCL2 CL source file for run time compilation") create_binary_resource(${CL_BIN}.src ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.src.o) set(SRCS ${SRCS} ${CMAKE_CURRENT_BINARY_DIR}/GPUReconstructionOCLCode.src.o) @@ -81,9 +83,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") PUBLIC_LINK_LIBRARIES O2::GPUTrackingOpenCLCommon TARGETVARNAME targetName) - target_compile_definitions( - ${targetName} PRIVATE GPUCA_GPULIBRARY=OCL2 - $) + target_compile_definitions(${targetName} PRIVATE $) # the compile_defitions are not propagated automatically on purpose (they are # declared PRIVATE) so we are not leaking them outside of the GPU** # directories @@ -92,8 +92,6 @@ if(ALIGPU_BUILD_TYPE STREQUAL "O2") endif() if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") - add_definitions(-DGPUCA_GPULIBRARY=OCL2) - # Generate the dictionary get_directory_property(incdirs INCLUDE_DIRECTORIES) generate_dictionary("Ali${MODULE}" "" "GPUReconstructionOCL2.h" "${incdirs} .") @@ -113,7 +111,6 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") endif() if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") - add_definitions(-DGPUCA_GPULIBRARY=OCL2) add_library(${MODULE} SHARED ${SRCS}) target_link_libraries(${MODULE} GPUTrackingOpenCLCommon) install(TARGETS ${MODULE}) diff --git a/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.cxx b/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.cxx index 00c4c74816df4..2c27694b8b111 100644 --- a/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.cxx +++ b/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.cxx @@ -39,10 +39,10 @@ GPUReconstructionOCL2Backend::GPUReconstructionOCL2Backend(const GPUSettingsDevi } template -int GPUReconstructionOCL2Backend::runKernelBackend(krnlSetup& _xyz, const Args&... args) +int GPUReconstructionOCL2Backend::runKernelBackend(const krnlSetupArgs& args) { - cl_kernel k = _xyz.y.num > 1 ? getKernelObject() : getKernelObject(); - return runKernelBackendCommon(_xyz, k, args...); + cl_kernel k = args.s.y.num > 1 ? getKernelObject() : getKernelObject(); + return std::apply([this, &args, &k](auto&... vals) { return runKernelBackendInternal(args.s, k, vals...); }, args.v); } template @@ -95,17 +95,17 @@ int GPUReconstructionOCL2Backend::GetOCLPrograms() return 1; } -#define GPUCA_KRNL(x_class, x_attributes, x_arguments, x_forward) \ - GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, x_class, x_attributes, x_arguments, x_forward) -#define GPUCA_KRNL_LOAD_single(x_class, x_attributes, x_arguments, x_forward) \ - if (AddKernel(false)) { \ - return 1; \ +#define GPUCA_KRNL(...) \ + GPUCA_KRNL_WRAP(GPUCA_KRNL_LOAD_, __VA_ARGS__) +#define GPUCA_KRNL_LOAD_single(x_class, ...) \ + if (AddKernel(false)) { \ + return 1; \ } -#define GPUCA_KRNL_LOAD_multi(x_class, x_attributes, x_arguments, x_forward) \ - if (AddKernel(true)) { \ - return 1; \ +#define GPUCA_KRNL_LOAD_multi(x_class, ...) \ + if (AddKernel(true)) { \ + return 1; \ } -#include "GPUReconstructionKernels.h" +#include "GPUReconstructionKernelList.h" #undef GPUCA_KRNL #undef GPUCA_KRNL_LOAD_single #undef GPUCA_KRNL_LOAD_multi diff --git a/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.h b/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.h index c9d31f20c8b3b..237838a90ca33 100644 --- a/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.h +++ b/GPU/GPUTracking/Base/opencl2/GPUReconstructionOCL2.h @@ -36,7 +36,7 @@ class GPUReconstructionOCL2Backend : public GPUReconstructionOCL GPUReconstructionOCL2Backend(const GPUSettingsDeviceBackend& cfg); template - int runKernelBackend(krnlSetup& _xyz, const Args&... args); + int runKernelBackend(const krnlSetupArgs& args); template S& getKernelObject(); diff --git a/GPU/GPUTracking/CMakeLists.txt b/GPU/GPUTracking/CMakeLists.txt index ee0ce3d69fc3b..6266d4962b88e 100644 --- a/GPU/GPUTracking/CMakeLists.txt +++ b/GPU/GPUTracking/CMakeLists.txt @@ -10,10 +10,11 @@ # or submit itself to any jurisdiction. set(MODULE GPUTracking) +cmake_minimum_required(VERSION 3.27 FATAL_ERROR) -# set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}} -O0") # to uncomment if needed, tired of typing this... +# set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -O0") # to uncomment if needed, tired of typing this... -if(NOT ${GPUCA_NO_FAST_MATH} AND NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") +if(NOT "${GPUCA_NO_FAST_MATH}" AND NOT CMAKE_BUILD_TYPE_UPPER STREQUAL "DEBUG") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math") endif() @@ -21,9 +22,10 @@ include(cmake/helpers.cmake) if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") if(ENABLE_CUDA OR ENABLE_OPENCL1 OR ENABLE_OPENCL2 OR ENABLE_HIP) - cmake_minimum_required(VERSION 3.13 FATAL_ERROR) include(FeatureSummary) find_package(O2GPU) + else() + include("cmake/kernel_helpers.cmake") endif() else() if((ALIGPU_BUILD_TYPE STREQUAL "Standalone" AND BUILD_EVENT_DISPLAY) OR (ALIGPU_BUILD_TYPE STREQUAL "O2" AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND TARGET AliceO2::DebugGUI AND OPENGL_FOUND AND GLFW_FOUND)) @@ -113,6 +115,7 @@ set(HDRS_INSTALL Base/GPUReconstructionIncludes.h Base/GPUReconstructionIncludesITS.h Base/GPUReconstructionKernelMacros.h + Base/GPUReconstructionKernels.h DataCompression/GPUTPCClusterRejection.h DataCompression/GPUTPCCompressionKernels.inc DataCompression/TPCClusterDecompressor.inc @@ -257,7 +260,7 @@ endif() file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly) file(GENERATE - OUTPUT include_gpu_onthefly/GPUReconstructionKernels.h + OUTPUT include_gpu_onthefly/GPUReconstructionKernelList.h INPUT Base/GPUReconstructionKernels.template.h ) file(GENERATE @@ -271,7 +274,7 @@ file(GENERATE if(NOT ALIGPU_BUILD_TYPE STREQUAL "O2") include_directories(${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly) endif() -set(HDRS_INSTALL ${HDRS_INSTALL} ${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly/GPUReconstructionKernels.h) +set(HDRS_INSTALL ${HDRS_INSTALL} ${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly/GPUReconstructionKernelList.h) include(kernels.cmake) # Optional sources depending on optional dependencies @@ -452,6 +455,7 @@ if(ALIGPU_BUILD_TYPE STREQUAL "ALIROOT") ${SRCS_NO_CINT} ${SRCS_NO_H} ${SRCS_DATATYPES} + ${SRCS_DATATYPE_HEADERS} G__Ali${MODULE}.cxx) target_link_libraries(Ali${MODULE} ${LIBDEPS}) @@ -478,7 +482,7 @@ endif() # Main CMake part for Standalone if(ALIGPU_BUILD_TYPE STREQUAL "Standalone") - add_library(${MODULE} SHARED ${SRCS} ${SRCS_NO_CINT} ${SRCS_NO_H} ${SRCS_DATATYPES}) + add_library(${MODULE} SHARED ${SRCS} ${SRCS_NO_CINT} ${SRCS_NO_H} ${SRCS_DATATYPES} ${SRCS_DATATYPE_HEADERS}) set(targetName ${MODULE}) add_library(O2::${MODULE} ALIAS ${MODULE}) install(TARGETS ${MODULE}) @@ -516,6 +520,8 @@ if(OpenMP_CXX_FOUND) target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) endif() +target_compile_options(${targetName} PRIVATE -Wno-instantiation-after-specialization) + # Add CMake recipes for GPU Tracking librararies if(CUDA_ENABLED OR OPENCL1_ENABLED OR OPENCL2_ENABLED OR HIP_ENABLED) if(CMAKE_SYSTEM_NAME MATCHES Darwin) diff --git a/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.cxx b/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.cxx index 54d6db3768ad2..3891e72a97243 100644 --- a/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.cxx +++ b/GPU/GPUTracking/DataCompression/AliHLTTPCClusterStatComponent.cxx @@ -467,7 +467,7 @@ int AliHLTTPCClusterStatComponent::DoEvent(const AliHLTComponentEventData& evtDa if (ip != 0) { int rowType = padrow < 64 ? 0 : (padrow < 128 ? 2 : 1); - prop.Update(xyz[1], xyz[2], rowType, *mSliceParam, 0, 0, nullptr, false); + prop.Update(xyz[1], xyz[2], rowType, *mSliceParam, 0, 0, nullptr, false, slice > 18, -1.f, 0.f, 0.f); } } if (hitsUsed) { diff --git a/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx b/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx index 5dd874582fd26..3fcd4853573e0 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx +++ b/GPU/GPUTracking/DataCompression/GPUTPCCompressionKernels.cxx @@ -44,7 +44,7 @@ GPUdii() void GPUTPCCompressionKernels::Thread processors.param.rec.tpc.rejectQPtB5 || trk.MergedLooper(); unsigned int nClustersStored = 0; CompressedClustersPtrs& GPUrestrict() c = compressor.mPtrs; - unsigned int lastRow = 0, lastSlice = 0; // BUG: These should be unsigned char, but then CUDA breaks + unsigned char lastRow = 0, lastSlice = 0; GPUTPCCompressionTrackModel track; float zOffset = 0; for (int k = trk.NClusters() - 1; k >= 0; k--) { @@ -338,7 +338,6 @@ GPUdi() bool GPUTPCCompressionGatherKernels::isAlignedTo(const S* ptr) } else { return reinterpret_cast(ptr) % alignof(T) == 0; } - return false; // BUG: Cuda complains about missing return value with constexpr if } template <> diff --git a/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.cxx b/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.cxx index 7f9afcae8127f..69b0d70f9ea88 100644 --- a/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.cxx +++ b/GPU/GPUTracking/DataCompression/GPUTPCCompressionTrackModel.cxx @@ -91,7 +91,7 @@ GPUd() int GPUTPCCompressionTrackModel::Propagate(float x, float alpha) if (alpha != mAlpha && !mTrk.Rotate(alpha, t0, GPUCA_MAX_SIN_PHI)) { return 2; } - int retVal = !mTrk.TransportToX(x, t0, mParam->constBz, GPUCA_MAX_SIN_PHI); + int retVal = !mTrk.TransportToX(x, t0, mParam->bzCLight, GPUCA_MAX_SIN_PHI); // GPUInfo("Propagated to: x %f y %f z %f alpha %f qPt %f", x, mTrk.Y(), mTrk.Z(), alpha, mTrk.QPt()); return retVal; } @@ -100,7 +100,7 @@ GPUd() int GPUTPCCompressionTrackModel::Filter(float y, float z, int iRow) { mTrk.ConstrainSinPhi(); float err2Y, err2Z; - GPUTPCTracker::GetErrors2Seeding(*mParam, iRow, mTrk, 0.f, err2Y, err2Z); + GPUTPCTracker::GetErrors2Seeding(*mParam, iRow, mTrk, -1.f, err2Y, err2Z); int retVal = !mTrk.Filter(y, z, err2Y, err2Z, GPUCA_MAX_SIN_PHI, false); // GPUInfo("Filtered with %f %f: y %f z %f qPt %f", y, z, mTrk.Y(), mTrk.Z(), mTrk.QPt()); return retVal; @@ -126,7 +126,7 @@ GPUd() void GPUTPCCompressionTrackModel::Init(float x, float y, float z, float a mP[4] = (qPt - 127.f) * (20.f / 127.f); resetCovariance(); mNDF = -5; - mBz = param.constBz; + mBz = param.bzCLight; float pti = CAMath::Abs(mP[4]); if (pti < 1.e-4f) { pti = 1.e-4f; // set 10.000 GeV momentum for straight track diff --git a/GPU/GPUTracking/DataTypes/GPUO2FakeClasses.h b/GPU/GPUTracking/DataTypes/GPUO2FakeClasses.h index 9a1db75b11185..073d5e74c21ae 100644 --- a/GPU/GPUTracking/DataTypes/GPUO2FakeClasses.h +++ b/GPU/GPUTracking/DataTypes/GPUO2FakeClasses.h @@ -38,6 +38,8 @@ class TrackTPC }; class CalibdEdxContainer { + public: + static bool isDead(int slice, int row, int pad) { return false; } }; struct ClusterNative { GPUd() static float getTime() { return 0.f; } diff --git a/GPU/GPUTracking/DataTypes/GPUSettings.h b/GPU/GPUTracking/DataTypes/GPUSettings.h index 655c5a127789f..0d0f932c95e88 100644 --- a/GPU/GPUTracking/DataTypes/GPUSettings.h +++ b/GPU/GPUTracking/DataTypes/GPUSettings.h @@ -54,12 +54,12 @@ class GPUSettings // Settings describing the global run parameters struct GPUSettingsGRP { // All new members must be sizeof(int) resp. sizeof(float) for alignment reasons! - float solenoidBz = -5.00668f; // solenoid field strength - int constBz = 0; // for test-MC events with constant Bz - int homemadeEvents = 0; // Toy-MC events - int continuousMaxTimeBin = 0; // 0 for triggered events, -1 for default of 23ms - int needsClusterer = 0; // Set to true if the data requires the clusterizer - int doCompClusterDecode = 0; // Set to true if the data contains compressed TPC clusters + float solenoidBzNominalGPU = -5.00668f; // solenoid field strength + int constBz = 0; // for test-MC events with constant Bz + int homemadeEvents = 0; // Toy-MC events + int continuousMaxTimeBin = 0; // 0 for triggered events, -1 for default of 23ms + int needsClusterer = 0; // Set to true if the data requires the clusterizer + int doCompClusterDecode = 0; // Set to true if the data contains compressed TPC clusters }; // Parameters of the current time frame diff --git a/GPU/GPUTracking/DataTypes/GPUTPCClusterOccupancyMap.cxx b/GPU/GPUTracking/DataTypes/GPUTPCClusterOccupancyMap.cxx index b0ea414f9ff87..96c288d86b23d 100644 --- a/GPU/GPUTracking/DataTypes/GPUTPCClusterOccupancyMap.cxx +++ b/GPU/GPUTracking/DataTypes/GPUTPCClusterOccupancyMap.cxx @@ -19,6 +19,9 @@ using namespace GPUCA_NAMESPACE::gpu; GPUd() unsigned int GPUTPCClusterOccupancyMapBin::getNBins(const GPUParam& param) { + if (param.rec.tpc.occupancyMapTimeBins == 0) { + return 0; + } unsigned int maxTimeBin = param.par.continuousTracking ? param.par.continuousMaxTimeBin : TPC_MAX_TIME_BIN_TRIGGERED; return (maxTimeBin + param.rec.tpc.occupancyMapTimeBins) / param.rec.tpc.occupancyMapTimeBins; // Not -1, since maxTimeBin is allowed } diff --git a/GPU/GPUTracking/Definitions/GPULogging.h b/GPU/GPUTracking/Definitions/GPULogging.h index d913df6f2982a..eff71f0fb5178 100644 --- a/GPU/GPUTracking/Definitions/GPULogging.h +++ b/GPU/GPUTracking/Definitions/GPULogging.h @@ -25,6 +25,14 @@ #define GPUAlarm(...) #define GPUError(...) #define GPUFatal(...) +#elif defined(GPUCA_GPUCODE_DEVICE) && !defined(GPUCA_GPU_DEBUG_PRINT) + // Compile-time disable for performance-reasons + #define GPUInfo(...) + #define GPUImportant(...) + #define GPUWarning(...) + #define GPUAlarm(...) + #define GPUError(...) + #define GPUFatal(...) #elif defined(GPUCA_STANDALONE) && !defined(GPUCA_GPUCODE_DEVICE) && !defined(GPUCA_NO_FMT) #include #define GPUInfo(string, ...) \ diff --git a/GPU/GPUTracking/Definitions/GPUSettingsList.h b/GPU/GPUTracking/Definitions/GPUSettingsList.h index 05551419b9352..b5d5bb5d1edc5 100644 --- a/GPU/GPUTracking/Definitions/GPUSettingsList.h +++ b/GPU/GPUTracking/Definitions/GPUSettingsList.h @@ -42,20 +42,24 @@ AddOptionRTC(hitSearchArea2, float, 2.f, "", 0, "square of maximum search road o AddOptionRTC(neighboursSearchArea, float, 3.f, "", 0, "area in cm for the search of neighbours, only used if searchWindowDZDR = 0") AddOptionRTC(clusterError2CorrectionY, float, 1.f, "", 0, "correction (multiplicative) for the squared cluster error during tracking") AddOptionRTC(clusterError2CorrectionZ, float, 1.f, "", 0, "correction (multiplicative) for the squared cluster error during tracking") -AddOptionRTC(clusterError2AdditionalY, float, 0.f, "", 0, "correction (additive) for the squared cluster error during tracking") -AddOptionRTC(clusterError2AdditionalZ, float, 0.f, "", 0, "correction (additive) for the squared cluster error during tracking") +AddOptionRTC(clusterError2AdditionalY, float, 0.f, "", 0, "correction (additive) for the squared cluster error during track fitting") +AddOptionRTC(clusterError2AdditionalZ, float, 0.f, "", 0, "correction (additive) for the squared cluster error during track fitting") +AddOptionRTC(clusterError2AdditionalYSeeding, float, 0.f, "", 0, "correction (additive) for the squared cluster error during track seeding") +AddOptionRTC(clusterError2AdditionalZSeeding, float, 0.f, "", 0, "correction (additive) for the squared cluster error during track seeding") AddOptionRTC(clusterRejectChi2TolleranceY, float, 1.f, "", 0, "Multiplicative factor multiplied onto chi2 in Y direction for cluster rejection check during track fit") AddOptionRTC(clusterRejectChi2TolleranceZ, float, 1.f, "", 0, "Multiplicative factor multiplied onto chi2 in Z direction for cluster rejection check during track fit") -AddOptionRTC(clusterErrorOccupancyScaler, float, 0.f, "", 0, "Scaling factor applied to occupancy histogram bin in cluster error estimation") -AddOptionRTC(clusterErrorChargeScaler, float, 0.f, "", 0, "Scaling factor applied to cluster charge bin in cluster error estimation") +AddOptionRTC(clusterErrorOccupancyScaler, float, 9.95e-04f, "", 0, "Scaling factor applied to occupancy histogram bin in cluster error estimation") +AddOptionRTC(clusterErrorChargeScaler, float, 20.f, "", 0, "Scaling factor applied to cluster charge in cluster error estimation") AddOptionRTC(sysClusErrorNormIFCCE, float, 1.f, "", 0, "Systematic cluster error parameterization IFCCE clInner[0]") AddOptionRTC(sysClusErrorSlopeIFCCE, float, 1.f / 5.f, "", 0, "Systematic cluster error parameterization IFCCE clInner[1]") AddOptionRTC(sysClusErrorIFCCEZRegion, float, -5.f, "", 0, "Systematic cluster error parameterization IFCCE z Region") AddOptionRTC(sysClusErrorslopeIFCCEZ, float, 1.f / 2.0f, "", 0, "Systematic cluster error parameterization IFCCE z Region Sigma Inverse") -AddOptionRTC(sysClusErrorNormIFC, float, 0.f, "", 0, "Systematic cluster error parameterization IFC normalization") -AddOptionRTC(sysClusErrorSlopeIFC, float, 0.f, "", 0, "Systematic cluster error parameterization IFC slope") +AddOptionRTC(sysClusErrorNormIFC, float, 0.5f, "", 0, "Systematic cluster error parameterization IFC normalization") +AddOptionRTC(sysClusErrorSlopeIFC, float, 0.2f, "", 0, "Systematic cluster error parameterization IFC slope") AddOptionRTC(sysClusErrorMinDist, float, 2.f, "", 0, "Systematic cluster error parameterization IFC Minimum Distance") AddOptionRTC(sysClusErrorMaskError, float, 5.f, "", 0, "Systematic cluster error parameterization IFC Large Error for masking") +AddOptionRTC(sysClusErrorC12Norm, float, 5.3333333e-06f, "", 0, "Systematic cluster for Sector C1/2 normalization") +AddOptionRTC(sysClusErrorC12Box, float, 1.1e-05f, "", 0, "Systematic cluster for Sector C1/2 box size") AddOptionRTC(minNClustersTrackSeed, int, -1, "", 0, "required min number of clusters on the track after track following (before merging)") AddOptionRTC(minNClustersFinalTrack, int, -1, "", 0, "required min number of clusters on the final track") AddOptionRTC(searchWindowDZDR, float, 2.5f, "", 0, "Use DZDR window for seeding instead of neighboursSearchArea") @@ -79,8 +83,8 @@ AddOptionRTC(minTrackdEdxMax, float, 20.0f, "", 0, "min accepted dEdxMaxTPC of t AddOptionRTC(minTrackdEdxMax2Tot, float, 0.67f, "", 0, "min accepted dEdxMaxTPC/dEdxTotTPC of the track") AddOptionRTC(extraClusterErrorEdgeY2, float, 0.35f, "", 0, "Additive extra cluster error for Y2 if edge flag set") AddOptionRTC(extraClusterErrorEdgeZ2, float, 0.15f, "", 0, "Additive extra cluster error for Z2 if edge flag set") -AddOptionRTC(extraClusterErrorSingleY2, float, 0.2f, "", 0, "Additive extra cluster error for Y2 if edge single set") -AddOptionRTC(extraClusterErrorSingleZ2, float, 0.2f, "", 0, "Additive extra cluster error for Z2 if edge single set") +AddOptionRTC(extraClusterErrorSingleY2, float, 0.04f, "", 0, "Additive extra cluster error for Y2 if single set") +AddOptionRTC(extraClusterErrorSingleZ2, float, 0.04f, "", 0, "Additive extra cluster error for Z2 if single set") AddOptionRTC(extraClusterErrorSplitPadSharedSingleY2, float, 0.03f, "", 0, "Additive extra cluster error for Y2 if splitpad, shared, or single set") AddOptionRTC(extraClusterErrorFactorSplitPadSharedSingleY2, float, 3.0f, "", 0, "Multiplicative extra cluster error for Y2 if splitpad, shared, or single set") AddOptionRTC(extraClusterErrorSplitTimeSharedSingleZ2, float, 0.03f, "", 0, "Additive extra cluster error for Z2 if splittime, shared, or single set") @@ -94,11 +98,12 @@ AddOptionRTC(trackMergerFactor2ZT, float, 1.5f * 1.5f, "", 0, "factor2ZT for tra AddOptionRTC(trackMergerFactor2K, float, 2.0f * 2.0f, "", 0, "factor2K for track merging") AddOptionRTC(trackMergerFactor2General, float, 3.5f * 3.5f, "", 0, "General factor for track merging") AddOptionRTC(rejectEdgeClustersMargin, float, 0.f, "", 0, "Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y") +AddOptionRTC(rejectEdgeClustersSigmaMargin, float, 0.f, "", 0, "Margin factor for trackSigmaY when rejecting edge clusters based on uncorrected track Y") AddOptionRTC(maxTimeBinAboveThresholdIn1000Bin, unsigned short, 500, "", 0, "Except pad from cluster finding if total number of charges in a fragment is above this baseline (disable = 0)") AddOptionRTC(maxConsecTimeBinAboveThreshold, unsigned short, 200, "", 0, "Except pad from cluster finding if number of consecutive charges in a fragment is above this baseline (disable = 0)") AddOptionRTC(noisyPadSaturationThreshold, unsigned short, 700, "", 0, "Threshold where a timebin is considered saturated, disabling the noisy pad check for that pad") -AddOptionRTC(occupancyMapTimeBins, unsigned short, 100, "", 0, "Number of timebins per histogram bin of occupancy map (0 = disable occupancy map)") -AddOptionRTC(occupancyMapTimeBinsAverage, unsigned short, 2, "", 0, "Number of timebins +/- to use for the averaging") +AddOptionRTC(occupancyMapTimeBins, unsigned short, 16, "", 0, "Number of timebins per histogram bin of occupancy map (0 = disable occupancy map)") +AddOptionRTC(occupancyMapTimeBinsAverage, unsigned short, 0, "", 0, "Number of timebins +/- to use for the averaging") AddOptionRTC(trackFitCovLimit, unsigned short, 1000, "", 0, "Abort fit when y/z cov exceed the limit") AddOptionRTC(addErrorsCECrossing, unsigned char, 0, "", 0, "Add additional custom track errors when crossing CE, 0 = no custom errors but att 0.5 to sigma_z^2, 1 = only to cov diagonal, 2 = preserve correlations") AddOptionRTC(trackMergerMinPartHits, unsigned char, 10, "", 0, "Minimum hits of track part during track merging") @@ -165,7 +170,6 @@ AddOptionRTC(maxChi2Red, float, 99.f, "", 0, "maximum chi2 per attached tracklet AddOptionRTC(applyDeflectionCut, unsigned char, 0, "", 0, "Set to 1 to enable tracklet selection based on deflection") AddOptionRTC(stopTrkAfterNMissLy, unsigned char, 6, "", 0, "Abandon track following after N layers without a TRD match") AddOptionRTC(nTrackletsMin, unsigned char, 3, "", 0, "Tracks with less attached tracklets are discarded after the tracking") -AddOptionRTC(useExternalO2DefaultPropagator, unsigned char, 0, "", 0, "Use the default instance of the o2::Propagator, instead of the GPU Reconstruciton one with GPU B field") AddOptionRTC(matCorrType, unsigned char, 2, "", 0, "Material correction to use: 0 - none, 1 - TGeo, 2 - matLUT") AddOptionRTC(pileupFwdNBC, unsigned char, 80, "", 0, "Post-trigger Pile-up integration time in BCs") AddOptionRTC(pileupBwdNBC, unsigned char, 80, "", 0, "Pre-trigger Pile-up integration time in BCs") @@ -177,7 +181,7 @@ AddOptionRTC(maxTrackQPtB5, float, 1.f / GPUCA_MIN_TRACK_PTB5_DEFAULT, "", 0, "r AddOptionRTC(nonConsecutiveIDs, char, false, "", 0, "Non-consecutive cluster IDs as in HLT, disables features that need access to slice data in TPC merger") AddOptionRTC(fwdTPCDigitsAsClusters, unsigned char, 0, "", 0, "Forward TPC digits as clusters (if they pass the ZS threshold)") AddOptionRTC(bz0Pt10MeV, unsigned char, 60, "", 0, "Nominal Pt to set when bz = 0 (in 10 MeV)") -AddOptionRTC(fitInProjections, char, -1, "", 0, "Fit in projection, -1 to enable for all but passes but the first one") +AddOptionRTC(fitInProjections, char, -1, "", 0, "Fit in projection, -1 to enable full fit for all but passes but the first one") AddOptionRTC(fitPropagateBzOnly, char, -1, "", 0, "Propagate using Bz only for n passes") AddOptionRTC(useMatLUT, char, 0, "", 0, "Use material lookup table for TPC refit") AddOptionRTC(trackingRefitGPUModel, char, 1, "", 0, "Use GPU track model for the Global Track Refit") @@ -187,12 +191,16 @@ AddSubConfig(GPUSettingsRecTRD, trd) AddHelp("help", 'h') EndConfig() +#ifndef __OPENCL__ // Settings steering the processing once the device was selected, only available on the host BeginSubConfig(GPUSettingsProcessingRTC, rtc, configStandalone.proc, "RTC", 0, "Processing settings", proc_rtc) AddOption(cacheOutput, bool, false, "", 0, "Cache RTC compilation results") AddOption(optConstexpr, bool, true, "", 0, "Replace constant variables by static constexpr expressions") AddOption(compilePerKernel, bool, true, "", 0, "Run one RTC compilation per kernel") AddOption(enable, bool, false, "", 0, "Use RTC to optimize GPU code") +AddOption(runTest, int, 0, "", 0, "Do not run the actual benchmark, but just test RTC compilation (1 full test, 2 test only compilation)") +AddOption(cacheMutex, bool, true, "", 0, "Use a file lock to serialize access to the cache folder") +AddOption(ignoreCacheValid, bool, false, "", 0, "If set, allows to use RTC cached code files even if they are not valid for the current source code / parameters") AddHelp("help", 'h') EndConfig() @@ -211,7 +219,7 @@ AddOption(globalInitMutex, bool, false, "", 0, "Use global mutex to synchronize AddOption(stuckProtection, int, 0, "", 0, "Timeout in us, When AMD GPU is stuck, just continue processing and skip tracking, do not crash or stall the chain") AddOption(trdNCandidates, int, 3, "", 0, "Number of branching track candidates for single input track during propagation") AddOption(trdTrackModelO2, bool, false, "", 0, "Use O2 track model instead of GPU track model for TRD tracking") -AddOption(debugLevel, int, -1, "debug", 'd', "Set debug level (-1 = silend)") +AddOption(debugLevel, int, -1, "debug", 'd', "Set debug level (-1 = silent)") AddOption(allocDebugLevel, int, 0, "allocDebug", 0, "Some debug output for memory allocations (without messing with normal debug level)") AddOption(debugMask, int, 262143, "", 0, "Mask for debug output dumps to file") AddOption(checkKernelFailures, bool, false, "", 0, "Synchronize after each kernel call and identify failing kernels") @@ -261,11 +269,9 @@ AddOption(clearO2OutputFromGPU, bool, false, "", 0, "Free the GPU memory used fo AddOption(ignoreNonFatalGPUErrors, bool, false, "", 0, "Continue running after having received non fatal GPU errors, e.g. abort due to overflow") AddOption(tpcIncreasedMinClustersPerRow, unsigned int, 0, "", 0, "Impose a minimum buffer size for the clustersPerRow during TPC clusterization") AddOption(noGPUMemoryRegistration, bool, false, "", 0, "Do not register input / output memory for GPU dma transfer") -AddOption(useInternalO2Propagator, bool, false, "", 0, "Uses an internal (in GPUChainTracking) version of o2::Propagator, which internal b-field, matlut, etc.") -AddOption(internalO2PropagatorGPUField, bool, true, "", 0, "Makes the internal O2 propagator use the fast GPU polynomial b field approximation") +AddOption(o2PropagatorUseGPUField, bool, true, "", 0, "Makes the internal O2 propagator use the fast GPU polynomial b field approximation") AddOption(calibObjectsExtraMemorySize, unsigned int, 10u * 1024 * 1024, "", 0, "Extra spare memory added for calibration object buffer, to allow fow updates with larger objects") AddOption(fastTransformObjectsMinMemorySize, unsigned int, 400u * 1024 * 1024, "", 0, "Extra spare memory added for calibration object buffer, to allow fow updates with larger objects") -AddOption(lateO2PropagatorProvisioning, bool, false, "", 0, "The user will provide the o2 propagator at runtime before processing the first event, it will not be available at init") AddOption(lateO2MatLutProvisioningSize, unsigned int, 0u, "", 0, "Memory size to reserve for late provisioning of matlut table") AddOption(throttleAlarms, bool, false, "", 0, "Throttle rate at which alarms are sent to the InfoLogger in online runs") AddOption(outputSanityCheck, bool, false, "", 0, "Run some simple sanity checks finding errors in the output") @@ -273,11 +279,13 @@ AddOption(tpcSingleSector, int, -1, "", 0, "Restrict TPC processing to a single AddOption(tpcDownscaledEdx, unsigned char, 0, "", 0, "If != 0, downscale dEdx processing (if enabled) to x %") AddOption(tpcMaxAttachedClustersPerSectorRow, unsigned int, 51000, "", 0, "Maximum number of TPC attached clusters which can be decoded per SectorRow") AddOption(tpcUseOldCPUDecoding, bool, false, "", 0, "Enable old CPU-based TPC decoding") +AddOption(RTCcacheFolder, std::string, "./rtccache/", "", 0, "Folder in which the cache file is stored") AddVariable(eventDisplay, GPUCA_NAMESPACE::gpu::GPUDisplayFrontendInterface*, nullptr) AddSubConfig(GPUSettingsProcessingRTC, rtc) AddSubConfig(GPUSettingsProcessingParam, param) AddHelp("help", 'h') EndConfig() +#endif // __OPENCL__ #ifndef GPUCA_GPUCODE_DEVICE // Light settings concerning the event display (can be changed without rebuilding vertices) @@ -465,7 +473,7 @@ AddOption(cpuAffinity, int, -1, "", 0, "Pin CPU affinity to this CPU core", min( AddOption(fifoScheduler, bool, false, "", 0, "Use FIFO realtime scheduler", message("Setting FIFO scheduler: %s")) AddOption(fpe, bool, true, "", 0, "Trap on floating point exceptions") AddOption(flushDenormals, bool, true, "", 0, "Enable FTZ and DAZ (Flush all denormals to zero)") -AddOption(solenoidBz, float, -1e6f, "", 0, "Field strength of solenoid Bz in kGaus") +AddOption(solenoidBzNominalGPU, float, -1e6f, "", 0, "Field strength of solenoid Bz in kGaus") AddOption(constBz, bool, false, "", 0, "Force constand Bz") AddOption(overrideMaxTimebin, bool, false, "", 0, "Override max time bin setting for continuous data with max time bin in time frame") AddOption(encodeZS, int, -1, "", 0, "Zero-Suppress TPC data", def(1)) @@ -502,7 +510,7 @@ EndConfig() //Settings for the O2 workfllow #if !defined(QCONFIG_PARSER_CXX) && (defined(GPUCA_O2_LIB) || defined(GPUCA_O2_INTERFACE)) BeginSubConfig(GPUSettingsO2, global, configStandalone, "O2", 0, "O2 workflow settings", global) -AddOption(solenoidBz, float, -1e6f, "", 0, "solenoid field strength") +AddOption(solenoidBzNominalGPU, float, -1e6f, "", 0, "Field strength of solenoid Bz in kGaus") AddOption(constBz, bool, false, "", 0, "force constant Bz for tests") AddOption(continuousMaxTimeBin, int, 0, "", 0, "maximum time bin of continuous data, 0 for triggered events, -1 for default of 23ms") AddOption(deviceType, std::string, "CPU", "", 0, "Device type, CPU | CUDA | HIP | OCL1 | OCL2") diff --git a/GPU/GPUTracking/GPUTrackingLinkDef_Standalone.h b/GPU/GPUTracking/GPUTrackingLinkDef_Standalone.h index b2cb2105a1df9..a7b91cc37ba4a 100644 --- a/GPU/GPUTracking/GPUTrackingLinkDef_Standalone.h +++ b/GPU/GPUTracking/GPUTrackingLinkDef_Standalone.h @@ -22,5 +22,11 @@ #pragma link off all functions; #pragma link C++ class o2::tpc::ClusterNative + ; +#pragma link C++ class o2::tpc::TrackTPC + ; +#pragma link C++ class o2::track::TrackParametrization < float> + ; +#pragma link C++ class o2::track::TrackParametrizationWithError < float> + ; +#pragma link C++ class o2::dataformats::RangeReference < unsigned int, unsigned short> + ; +#pragma link C++ class o2::tpc::dEdxInfo + ; +#pragma link C++ class o2::track::PID + ; #endif diff --git a/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.cxx b/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.cxx index 00f0d17365e5d..d85a4a9a183fb 100644 --- a/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.cxx +++ b/GPU/GPUTracking/Global/AliHLTGPUDumpComponent.cxx @@ -486,7 +486,7 @@ int AliHLTGPUDumpComponent::DoEvent(const AliHLTComponentEventData& evtData, con fRec->DumpSettings(); } - sprintf(filename, GPUCA_EVDUMP_FILE ".%d.dump", nEvent++); + snprintf(filename, 256, GPUCA_EVDUMP_FILE ".%d.dump", nEvent++); fChain->DumpData(filename); return (0); } diff --git a/GPU/GPUTracking/Global/GPUChain.h b/GPU/GPUTracking/Global/GPUChain.h index 00a02558ec8f1..21245a415a5cd 100644 --- a/GPU/GPUTracking/Global/GPUChain.h +++ b/GPU/GPUTracking/Global/GPUChain.h @@ -31,10 +31,10 @@ class GPUChain using GeneralStep = GPUReconstruction::GeneralStep; using InOutPointerType = GPUReconstruction::InOutPointerType; using GeometryType = GPUReconstruction::GeometryType; - using krnlRunRange = GPUReconstruction::krnlRunRange; - using krnlExec = GPUReconstruction::krnlExec; - using krnlEvent = GPUReconstruction::krnlEvent; - using deviceEvent = GPUReconstruction::deviceEvent; + using krnlRunRange = gpu_reconstruction_kernels::krnlRunRange; + using krnlExec = gpu_reconstruction_kernels::krnlExec; + using krnlEvent = gpu_reconstruction_kernels::krnlEvent; + using deviceEvent = gpu_reconstruction_kernels::deviceEvent; static constexpr krnlRunRange krnlRunRangeNone{0, -1}; static constexpr krnlEvent krnlEventNone = krnlEvent{nullptr, nullptr, 0}; @@ -86,10 +86,10 @@ class GPUChain inline GPUSettingsProcessing& ProcessingSettings() { return mRec->mProcessingSettings; } inline void SynchronizeStream(int stream) { mRec->SynchronizeStream(stream); } inline void SynchronizeEvents(deviceEvent* evList, int nEvents = 1) { mRec->SynchronizeEvents(evList, nEvents); } - inline void SynchronizeEventAndRelease(deviceEvent* ev, bool doGPU = true) + inline void SynchronizeEventAndRelease(deviceEvent& ev, bool doGPU = true) { if (doGPU) { - SynchronizeEvents(ev); + SynchronizeEvents(&ev); ReleaseEvent(ev); } } @@ -120,16 +120,16 @@ class GPUChain inline void ResetHelperThreads(int helpers) { mRec->ResetHelperThreads(helpers); } inline int GPUDebug(const char* state = "UNKNOWN", int stream = -1) { return mRec->GPUDebug(state, stream); } // nEvents is forced to 0 if evList == nullptr - inline void TransferMemoryResourceToGPU(RecoStep step, GPUMemoryResource* res, int stream = -1, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { timeCpy(step, true, &GPUReconstructionCPU::TransferMemoryResourceToGPU, res, stream, ev, evList, nEvents); } - inline void TransferMemoryResourceToHost(RecoStep step, GPUMemoryResource* res, int stream = -1, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { timeCpy(step, false, &GPUReconstructionCPU::TransferMemoryResourceToHost, res, stream, ev, evList, nEvents); } + inline void TransferMemoryResourceToGPU(RecoStep step, GPUMemoryResource* res, int stream = -1, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { timeCpy(step, true, &GPUReconstructionCPU::TransferMemoryResourceToGPU, res, stream, ev, evList, nEvents); } + inline void TransferMemoryResourceToHost(RecoStep step, GPUMemoryResource* res, int stream = -1, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { timeCpy(step, false, &GPUReconstructionCPU::TransferMemoryResourceToHost, res, stream, ev, evList, nEvents); } inline void TransferMemoryResourcesToGPU(RecoStep step, GPUProcessor* proc, int stream = -1, bool all = false) { timeCpy(step, true, &GPUReconstructionCPU::TransferMemoryResourcesToGPU, proc, stream, all); } inline void TransferMemoryResourcesToHost(RecoStep step, GPUProcessor* proc, int stream = -1, bool all = false) { timeCpy(step, false, &GPUReconstructionCPU::TransferMemoryResourcesToHost, proc, stream, all); } - inline void TransferMemoryResourceLinkToGPU(RecoStep step, short res, int stream = -1, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { timeCpy(step, true, &GPUReconstructionCPU::TransferMemoryResourceLinkToGPU, res, stream, ev, evList, nEvents); } - inline void TransferMemoryResourceLinkToHost(RecoStep step, short res, int stream = -1, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { timeCpy(step, false, &GPUReconstructionCPU::TransferMemoryResourceLinkToHost, res, stream, ev, evList, nEvents); } + inline void TransferMemoryResourceLinkToGPU(RecoStep step, short res, int stream = -1, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { timeCpy(step, true, &GPUReconstructionCPU::TransferMemoryResourceLinkToGPU, res, stream, ev, evList, nEvents); } + inline void TransferMemoryResourceLinkToHost(RecoStep step, short res, int stream = -1, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { timeCpy(step, false, &GPUReconstructionCPU::TransferMemoryResourceLinkToHost, res, stream, ev, evList, nEvents); } // Todo: retrieve step from proc, move kernelClass->GetStep to retrieve it from GetProcessor - inline void WriteToConstantMemory(RecoStep step, size_t offset, const void* src, size_t size, int stream = -1, deviceEvent ev = nullptr) { timeCpy(step, true, &GPUReconstructionCPU::WriteToConstantMemory, offset, src, size, stream, ev); } - inline void GPUMemCpy(RecoStep step, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { timeCpy(step, toGPU, &GPUReconstructionCPU::GPUMemCpy, dst, src, size, stream, toGPU, ev, evList, nEvents); } - inline void GPUMemCpyAlways(RecoStep step, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) + inline void WriteToConstantMemory(RecoStep step, size_t offset, const void* src, size_t size, int stream = -1, deviceEvent* ev = nullptr) { timeCpy(step, true, &GPUReconstructionCPU::WriteToConstantMemory, offset, src, size, stream, ev); } + inline void GPUMemCpy(RecoStep step, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { timeCpy(step, toGPU, &GPUReconstructionCPU::GPUMemCpy, dst, src, size, stream, toGPU, ev, evList, nEvents); } + inline void GPUMemCpyAlways(RecoStep step, void* dst, const void* src, size_t size, int stream, int toGPU, deviceEvent* ev = nullptr, deviceEvent* evList = nullptr, int nEvents = 1) { if (toGPU == -1) { memcpy(dst, src, size); @@ -161,7 +161,7 @@ class GPUChain template inline std::unique_ptr ReadFlatObjectFromFile(const char* file) { - return std::move(mRec->ReadFlatObjectFromFile(file)); + return mRec->ReadFlatObjectFromFile(file); } template inline void DumpStructToFile(const T* obj, const char* file) @@ -171,28 +171,28 @@ class GPUChain template inline std::unique_ptr ReadStructFromFile(const char* file) { - return std::move(mRec->ReadStructFromFile(file)); + return mRec->ReadStructFromFile(file); } template inline void ReadStructFromFile(const char* file, T* obj) { mRec->ReadStructFromFile(file, obj); } - template - inline int runKernel(const krnlExec& x, const krnlRunRange& y = krnlRunRangeNone, const krnlEvent& z = krnlEventNone, Args&&... args) + template + inline int runKernel(gpu_reconstruction_kernels::krnlSetup&& setup, Args&&... args) { - return mRec->runKernel(x, y, z, std::forward(args)...); + return mRec->runKernel(std::forward(setup), std::forward(args)...); } template - const GPUReconstruction::krnlProperties getKernelProperties() + gpu_reconstruction_kernels::krnlProperties getKernelProperties() { return mRec->getKernelProperties(); } - template + template HighResTimer& getKernelTimer(RecoStep step, int num = 0, size_t addMemorySize = 0) { - return mRec->getKernelTimer(step, num, addMemorySize); + return mRec->getKernelTimer(step, num, addMemorySize); } template HighResTimer& getTimer(const char* name, int num = -1) @@ -225,7 +225,7 @@ class GPUChain inline GPUChain* GetNextChainInQueue() { return mRec->GetNextChainInQueue(); } virtual int PrepareTextures() { return 0; } - virtual int DoStuckProtection(int stream, void* event) { return 0; } + virtual int DoStuckProtection(int stream, deviceEvent event) { return 0; } template bool DoDebugAndDump(RecoStep step, int mask, T& processor, S T::*func, Args&&... args) diff --git a/GPU/GPUTracking/Global/GPUChainITS.cxx b/GPU/GPUTracking/Global/GPUChainITS.cxx index 127bef6d92537..9e62b480bcac9 100644 --- a/GPU/GPUTracking/Global/GPUChainITS.cxx +++ b/GPU/GPUTracking/Global/GPUChainITS.cxx @@ -90,7 +90,6 @@ o2::its::TimeFrame* GPUChainITS::GetITSTimeframe() mFrameworkAllocator.reset(new o2::its::GPUFrameworkExternalAllocator); mFrameworkAllocator->setReconstructionFramework(rec()); mITSTimeFrame->setExternalAllocator(mFrameworkAllocator.get()); - LOGP(info, "GPUChainITS is giving me allocator: {}", (void*)mFrameworkAllocator.get()); } #endif return mITSTimeFrame.get(); diff --git a/GPU/GPUTracking/Global/GPUChainTracking.cxx b/GPU/GPUTracking/Global/GPUChainTracking.cxx index 4c540b235af71..bd1cd9859cbd2 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.cxx +++ b/GPU/GPUTracking/Global/GPUChainTracking.cxx @@ -264,10 +264,6 @@ bool GPUChainTracking::ValidateSteps() GPUError("Cannot run TPC ZS Decoder without mapping object. (tpczslinkmapping.dump missing?)"); return false; } - if ((GetRecoSteps() & GPUDataTypes::RecoStep::Refit) && !param().rec.trackingRefitGPUModel && ((processors()->calibObjects.o2Propagator == nullptr && !ProcessingSettings().internalO2PropagatorGPUField) || processors()->calibObjects.matLUT == nullptr)) { - GPUError("Cannot run refit with o2 track model without o2 propagator"); - return false; - } return true; } @@ -335,22 +331,14 @@ bool GPUChainTracking::ValidateSettings() GPUError("TRD tracking can only run on GPU TPC tracks if the createO2Output setting does not suppress them"); return false; } - if ((GetRecoStepsGPU() & RecoStep::TRDTracking) && (param().rec.trd.useExternalO2DefaultPropagator || !GetProcessingSettings().internalO2PropagatorGPUField)) { - GPUError("Cannot use TRD tracking on GPU with external default o2::Propagator or without GPU polynomial field map"); + if ((((GetRecoStepsGPU() & RecoStep::TRDTracking) && !GetProcessingSettings().trdTrackModelO2) || ((GetRecoStepsGPU() & RecoStep::Refit) && !param().rec.trackingRefitGPUModel)) && (!GetProcessingSettings().o2PropagatorUseGPUField || processors()->calibObjects.matLUT == nullptr)) { + GPUError("Cannot use TRD tracking or Refit on GPU without GPU polynomial field map or matlut table"); return false; } } return true; } -int GPUChainTracking::EarlyConfigure() -{ - if (GetProcessingSettings().useInternalO2Propagator) { - SetDefaultInternalO2Propagator(GetProcessingSettings().internalO2PropagatorGPUField); - } - return 0; -} - int GPUChainTracking::Init() { const auto& threadContext = GetThreadContext(); @@ -470,7 +458,6 @@ void GPUChainTracking::UpdateGPUCalibObjects(int stream, const GPUCalibObjectsCo if (processors()->calibObjects.o2Propagator && (ptrMask == nullptr || ptrMask->o2Propagator)) { memcpy((void*)mFlatObjectsShadow.mCalibObjects.o2Propagator, (const void*)processors()->calibObjects.o2Propagator, sizeof(*processors()->calibObjects.o2Propagator)); mFlatObjectsShadow.mCalibObjects.o2Propagator->setGPUField(&processorsDevice()->param.polynomialField); - mFlatObjectsShadow.mCalibObjects.o2Propagator->setBz(param().bzkG); mFlatObjectsShadow.mCalibObjects.o2Propagator->setMatLUT(mFlatObjectsShadow.mCalibObjects.matLUT); } #endif @@ -565,10 +552,9 @@ void* GPUChainTracking::GPUTrackingFlatObjects::SetPointersFlatObjects(void* mem if (mChainTracking->processors()->calibObjects.trdGeometry) { computePointerWithAlignment(mem, mCalibObjects.trdGeometry, 1); } - if (mChainTracking->processors()->calibObjects.o2Propagator) { - computePointerWithAlignment(mem, mCalibObjects.o2Propagator, 1); - } else if (mChainTracking->GetProcessingSettings().internalO2PropagatorGPUField) { - computePointerWithAlignment(mem, dummyPtr, sizeof(*mCalibObjects.o2Propagator)); + computePointerWithAlignment(mem, mCalibObjects.o2Propagator, 1); + if (!mChainTracking->processors()->calibObjects.o2Propagator) { + mCalibObjects.o2Propagator = nullptr; // Always reserve memory for o2::Propagator, since it may be propagatred only during run() not during init(). } #endif if (!mChainTracking->mUpdateNewCalibObjects) { @@ -642,7 +628,7 @@ int GPUChainTracking::DoQueuedUpdates(int stream, bool updateSlave) if (mNewCalibValues->newSolenoidField || mNewCalibValues->newContinuousMaxTimeBin) { grp = std::make_unique(mRec->GetGRPSettings()); if (mNewCalibValues->newSolenoidField) { - grp->solenoidBz = mNewCalibValues->solenoidField; + grp->solenoidBzNominalGPU = mNewCalibValues->solenoidField; } if (mNewCalibValues->newContinuousMaxTimeBin) { grp->continuousMaxTimeBin = mNewCalibValues->continuousMaxTimeBin; @@ -657,6 +643,11 @@ int GPUChainTracking::DoQueuedUpdates(int stream, bool updateSlave) retVal = 1; } if (mUpdateNewCalibObjects) { +#ifdef GPUCA_HAVE_O2HEADERS + if (mNewCalibObjects->o2Propagator && ((mNewCalibObjects->o2Propagator->getGPUField() != nullptr) ^ GetProcessingSettings().o2PropagatorUseGPUField)) { + GPUFatal("GPU magnetic field for propagator requested, but received an O2 propagator without GPU field"); + } +#endif void* const* pSrc = (void* const*)mNewCalibObjects.get(); void** pDst = (void**)&processors()->calibObjects; for (unsigned int i = 0; i < sizeof(processors()->calibObjects) / sizeof(void*); i++) { @@ -689,6 +680,9 @@ int GPUChainTracking::DoQueuedUpdates(int stream, bool updateSlave) int GPUChainTracking::RunChain() { + if ((((GetRecoSteps() & RecoStep::TRDTracking) && !GetProcessingSettings().trdTrackModelO2) || ((GetRecoSteps() & RecoStep::Refit) && !param().rec.trackingRefitGPUModel)) && processors()->calibObjects.o2Propagator == nullptr) { + GPUFatal("Cannot run TRD tracking or refit with o2 track model without o2 propagator"); // This check must happen during run, since o2::Propagator cannot be available during init + } if (GetProcessingSettings().ompAutoNThreads && !mRec->IsGPU()) { mRec->SetNOMPThreads(-1); } @@ -776,9 +770,11 @@ int GPUChainTracking::RunChain() } } +#ifdef GPUCA_HAVE_O2HEADERS if (GetProcessingSettings().trdTrackModelO2 ? runRecoStep(RecoStep::TRDTracking, &GPUChainTracking::RunTRDTracking) : runRecoStep(RecoStep::TRDTracking, &GPUChainTracking::RunTRDTracking)) { return 1; } +#endif if (runRecoStep(RecoStep::Refit, &GPUChainTracking::RunRefit)) { return 1; @@ -988,15 +984,6 @@ void GPUChainTracking::ClearErrorCodes(bool cpuOnly) } } -void GPUChainTracking::SetDefaultInternalO2Propagator(bool useGPUField) -{ -#ifdef GPUCA_HAVE_O2HEADERS - o2::base::Propagator* prop = param().GetDefaultO2Propagator(useGPUField); - prop->setMatLUT(processors()->calibObjects.matLUT); - SetO2Propagator(prop); -#endif -} - void GPUChainTracking::SetUpdateCalibObjects(const GPUCalibObjectsConst& obj, const GPUNewCalibValues& vals) { std::lock_guard lk(mMutexUpdateCalib); @@ -1023,3 +1010,13 @@ const o2::base::Propagator* GPUChainTracking::GetDeviceO2Propagator() { return (mRec->IsGPU() ? processorsShadow() : processors())->calibObjects.o2Propagator; } + +void GPUChainTracking::SetO2Propagator(const o2::base::Propagator* prop) +{ + processors()->calibObjects.o2Propagator = prop; +#ifdef GPUCA_HAVE_O2HEADERS + if ((prop->getGPUField() != nullptr) ^ GetProcessingSettings().o2PropagatorUseGPUField) { + GPUFatal("GPU magnetic field for propagator requested, but received an O2 propagator without GPU field"); + } +#endif +} diff --git a/GPU/GPUTracking/Global/GPUChainTracking.h b/GPU/GPUTracking/Global/GPUChainTracking.h index b7e0c678ce9d8..89f2ecd10f65f 100644 --- a/GPU/GPUTracking/Global/GPUChainTracking.h +++ b/GPU/GPUTracking/Global/GPUChainTracking.h @@ -77,7 +77,6 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega void RegisterPermanentMemoryAndProcessors() override; void RegisterGPUProcessors() override; int Init() override; - int EarlyConfigure() override; int PrepareEvent() override; int Finalize() override; int RunChain() override; @@ -188,11 +187,10 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega void SetTRDGeometry(std::unique_ptr&& geo); void SetMatLUT(const o2::base::MatLayerCylSet* lut) { processors()->calibObjects.matLUT = lut; } void SetTRDGeometry(const o2::trd::GeometryFlat* geo) { processors()->calibObjects.trdGeometry = geo; } - void SetO2Propagator(const o2::base::Propagator* prop) { processors()->calibObjects.o2Propagator = prop; } + void SetO2Propagator(const o2::base::Propagator* prop); void SetCalibObjects(const GPUCalibObjectsConst& obj) { processors()->calibObjects = obj; } void SetCalibObjects(const GPUCalibObjects& obj) { memcpy((void*)&processors()->calibObjects, (const void*)&obj, sizeof(obj)); } void SetUpdateCalibObjects(const GPUCalibObjectsConst& obj, const GPUNewCalibValues& vals); - void SetDefaultInternalO2Propagator(bool useGPUField); void LoadClusterErrors(); void SetSubOutputControl(int i, GPUOutputControl* v) { mSubOutputControls[i] = v; } void SetFinalInputCallback(std::function v) { mWaitForFinalInputs = v; } @@ -218,10 +216,10 @@ class GPUChainTracking : public GPUChain, GPUReconstructionHelpers::helperDelega struct eventStruct // Must consist only of void* ptr that will hold the GPU event ptrs! { - void* slice[NSLICES]; // TODO: Proper type for events - void* stream[GPUCA_MAX_STREAMS]; - void* init; - void* single; + deviceEvent slice[NSLICES]; + deviceEvent stream[GPUCA_MAX_STREAMS]; + deviceEvent init; + deviceEvent single; }; struct outputQueueEntry { diff --git a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx index 37e0c523c021a..c26968513611a 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingClusterizer.cxx @@ -390,22 +390,22 @@ void GPUChainTracking::RunTPCClusterizer_compactPeaks(GPUTPCClusterFinder& clust for (unsigned int i = 1; i < nSteps; i++) { counts.push_back(tmpCount); if (i == 1) { - runKernel(GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, i, stage); + runKernel({GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}}, i, stage); } else { - runKernel(GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, i, tmpCount); + runKernel({GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}}, i, tmpCount); } tmpCount = (tmpCount + clusterer.mScanWorkGroupSize - 1) / clusterer.mScanWorkGroupSize; } - runKernel(GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, nSteps, tmpCount); + runKernel({GetGrid(tmpCount, clusterer.mScanWorkGroupSize, lane), {iSlice}}, nSteps, tmpCount); for (unsigned int i = nSteps - 1; i > 1; i--) { tmpCount = counts[i - 1]; - runKernel(GetGrid(tmpCount - clusterer.mScanWorkGroupSize, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, i, clusterer.mScanWorkGroupSize, tmpCount); + runKernel({GetGrid(tmpCount - clusterer.mScanWorkGroupSize, clusterer.mScanWorkGroupSize, lane), {iSlice}}, i, clusterer.mScanWorkGroupSize, tmpCount); } } - runKernel(GetGrid(count, clusterer.mScanWorkGroupSize, lane), {iSlice}, {}, 1, stage, in, out); + runKernel({GetGrid(count, clusterer.mScanWorkGroupSize, lane), {iSlice}}, 1, stage, in, out); } else { auto& nOut = stage ? clusterer.mPmemory->counters.nClusters : clusterer.mPmemory->counters.nPeaks; auto& nIn = stage ? clusterer.mPmemory->counters.nPeaks : clusterer.mPmemory->counters.nPositions; @@ -706,12 +706,12 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) using ChargeMapType = decltype(*clustererShadow.mPchargeMap); using PeakMapType = decltype(*clustererShadow.mPpeakMap); - runKernel(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {}, clustererShadow.mPchargeMap, TPCMapMemoryLayout::items(GetProcessingSettings().overrideClusterizerFragmentLen) * sizeof(ChargeMapType)); - runKernel(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {}, clustererShadow.mPpeakMap, TPCMapMemoryLayout::items(GetProcessingSettings().overrideClusterizerFragmentLen) * sizeof(PeakMapType)); + runKernel({GetGridAutoStep(lane, RecoStep::TPCClusterFinding)}, clustererShadow.mPchargeMap, TPCMapMemoryLayout::items(GetProcessingSettings().overrideClusterizerFragmentLen) * sizeof(ChargeMapType)); + runKernel({GetGridAutoStep(lane, RecoStep::TPCClusterFinding)}, clustererShadow.mPpeakMap, TPCMapMemoryLayout::items(GetProcessingSettings().overrideClusterizerFragmentLen) * sizeof(PeakMapType)); if (fragment.index == 0) { - runKernel(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {}, clustererShadow.mPpadIsNoisy, TPC_PADS_IN_SECTOR * sizeof(*clustererShadow.mPpadIsNoisy)); + runKernel({GetGridAutoStep(lane, RecoStep::TPCClusterFinding)}, clustererShadow.mPpadIsNoisy, TPC_PADS_IN_SECTOR * sizeof(*clustererShadow.mPpadIsNoisy)); } - DoDebugAndDump(RecoStep::TPCClusterFinding, 262144, clusterer, &GPUTPCClusterFinder::DumpChargeMap, *mDebugFile, "Zeroed Charges", doGPU); + DoDebugAndDump(RecoStep::TPCClusterFinding, 262144, clusterer, &GPUTPCClusterFinder::DumpChargeMap, *mDebugFile, "Zeroed Charges"); if (doGPU) { if (mIOPtrs.tpcZS && mCFContext->nPagesSector[iSlice] && mCFContext->zsVersion != -1) { @@ -743,10 +743,10 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) if (GetProcessingSettings().tpcSingleSector == -1 || GetProcessingSettings().tpcSingleSector == (int)iSlice) { if (not mIOPtrs.tpcZS) { - runKernel(GetGrid(1, lane), {iSlice}, {}, mIOPtrs.tpcZS == nullptr); + runKernel({GetGrid(1, lane), {iSlice}}, mIOPtrs.tpcZS == nullptr); TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); } else if (propagateMCLabels) { - runKernel(GetGrid(1, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}, mIOPtrs.tpcZS == nullptr); + runKernel({GetGrid(1, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}}, mIOPtrs.tpcZS == nullptr); TransferMemoryResourceLinkToGPU(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); } } @@ -762,13 +762,13 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) break; case ZSVersionRowBased10BitADC: case ZSVersionRowBased12BitADC: - runKernel(GetGridBlk(nBlocks, lane), {iSlice}, {}, firstHBF); + runKernel({GetGridBlk(nBlocks, lane), {iSlice}}, firstHBF); break; case ZSVersionLinkBasedWithMeta: - runKernel(GetGridBlk(nBlocks, lane), {iSlice}, {}, firstHBF); + runKernel({GetGridBlk(nBlocks, lane), {iSlice}}, firstHBF); break; case ZSVersionDenseLinkBased: - runKernel(GetGridBlk(nBlocks, lane), {iSlice}, {}, firstHBF); + runKernel({GetGridBlk(nBlocks, lane), {iSlice}}, firstHBF); break; } TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); @@ -797,14 +797,14 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) continue; } if (!mIOPtrs.tpcZS) { - runKernel(GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}, {}); + runKernel({GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}}); } - if (DoDebugAndDump(RecoStep::TPCClusterFinding, 262144, clusterer, &GPUTPCClusterFinder::DumpDigits, *mDebugFile)) { - clusterer.DumpChargeMap(*mDebugFile, "Charges", doGPU); + if (DoDebugAndDump(RecoStep::TPCClusterFinding, 262144 << 1, clusterer, &GPUTPCClusterFinder::DumpDigits, *mDebugFile)) { + clusterer.DumpChargeMap(*mDebugFile, "Charges"); } if (propagateMCLabels) { - runKernel(GetGrid(clusterer.mPmemory->counters.nDigitsInFragment, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}); + runKernel({GetGrid(clusterer.mPmemory->counters.nDigitsInFragment, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}}); } bool checkForNoisyPads = (rec()->GetParam().rec.tpc.maxTimeBinAboveThresholdIn1000Bin > 0) || (rec()->GetParam().rec.tpc.maxConsecTimeBinAboveThreshold > 0); @@ -814,15 +814,17 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) if (checkForNoisyPads) { int nBlocks = TPC_PADS_IN_SECTOR / GPUTPCCFCheckPadBaseline::PadsPerCacheline; - runKernel(GetGridBlk(nBlocks, lane), {iSlice}, {}); + runKernel({GetGridBlk(nBlocks, lane), {iSlice}}); } - runKernel(GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}, {}); - DoDebugAndDump(RecoStep::TPCClusterFinding, 262144, clusterer, &GPUTPCClusterFinder::DumpPeaks, *mDebugFile); + runKernel({GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}}); + if (DoDebugAndDump(RecoStep::TPCClusterFinding, 262144 << 2, clusterer, &GPUTPCClusterFinder::DumpPeaks, *mDebugFile)) { + clusterer.DumpPeakMap(*mDebugFile, "Peaks"); + } RunTPCClusterizer_compactPeaks(clusterer, clustererShadow, 0, doGPU, lane); TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); - DoDebugAndDump(RecoStep::TPCClusterFinding, 262144, clusterer, &GPUTPCClusterFinder::DumpPeaksCompacted, *mDebugFile); + DoDebugAndDump(RecoStep::TPCClusterFinding, 262144 << 2, clusterer, &GPUTPCClusterFinder::DumpPeaksCompacted, *mDebugFile); } GPUCA_OPENMP(parallel for if(!doGPU && GetProcessingSettings().ompKernels != 1) num_threads(mRec->SetAndGetNestedLoopOmpFactor(!doGPU, GetProcessingSettings().nTPCClustererLanes))) for (int lane = 0; lane < maxLane; lane++) { @@ -835,13 +837,15 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) if (clusterer.mPmemory->counters.nPeaks == 0) { continue; } - runKernel(GetGrid(clusterer.mPmemory->counters.nPeaks, lane), {iSlice}, {}); - runKernel(GetGrid(clusterer.mPmemory->counters.nPeaks, lane), {iSlice}, {}); - DoDebugAndDump(RecoStep::TPCClusterFinding, 262144, clusterer, &GPUTPCClusterFinder::DumpSuppressedPeaks, *mDebugFile); + runKernel({GetGrid(clusterer.mPmemory->counters.nPeaks, lane), {iSlice}}); + runKernel({GetGrid(clusterer.mPmemory->counters.nPeaks, lane), {iSlice}}); + if (DoDebugAndDump(RecoStep::TPCClusterFinding, 262144 << 3, clusterer, &GPUTPCClusterFinder::DumpSuppressedPeaks, *mDebugFile)) { + clusterer.DumpPeakMap(*mDebugFile, "Suppressed Peaks"); + } RunTPCClusterizer_compactPeaks(clusterer, clustererShadow, 1, doGPU, lane); TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mMemoryId, lane); - DoDebugAndDump(RecoStep::TPCClusterFinding, 262144, clusterer, &GPUTPCClusterFinder::DumpSuppressedPeaksCompacted, *mDebugFile); + DoDebugAndDump(RecoStep::TPCClusterFinding, 262144 << 3, clusterer, &GPUTPCClusterFinder::DumpSuppressedPeaksCompacted, *mDebugFile); } GPUCA_OPENMP(parallel for if(!doGPU && GetProcessingSettings().ompKernels != 1) num_threads(mRec->SetAndGetNestedLoopOmpFactor(!doGPU, GetProcessingSettings().nTPCClustererLanes))) for (int lane = 0; lane < maxLane; lane++) { @@ -853,7 +857,7 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } if (fragment.index == 0) { - runKernel(GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {nullptr, transferRunning[lane] == 1 ? &mEvents->stream[lane] : nullptr}, clustererShadow.mPclusterInRow, GPUCA_ROW_COUNT * sizeof(*clustererShadow.mPclusterInRow)); + runKernel({GetGridAutoStep(lane, RecoStep::TPCClusterFinding), krnlRunRangeNone, {nullptr, transferRunning[lane] == 1 ? &mEvents->stream[lane] : nullptr}}, clustererShadow.mPclusterInRow, GPUCA_ROW_COUNT * sizeof(*clustererShadow.mPclusterInRow)); transferRunning[lane] = 2; } @@ -861,16 +865,16 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) continue; } - runKernel(GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}, {}); - DoDebugAndDump(RecoStep::TPCClusterFinding, 262144, clusterer, &GPUTPCClusterFinder::DumpChargeMap, *mDebugFile, "Split Charges", doGPU); + runKernel({GetGrid(clusterer.mPmemory->counters.nPositions, lane), {iSlice}}); + DoDebugAndDump(RecoStep::TPCClusterFinding, 262144 << 4, clusterer, &GPUTPCClusterFinder::DumpChargeMap, *mDebugFile, "Split Charges"); - runKernel(GetGrid(clusterer.mPmemory->counters.nClusters, lane), {iSlice}, {}, 0); + runKernel({GetGrid(clusterer.mPmemory->counters.nClusters, lane), {iSlice}}, 0); if (doGPU && propagateMCLabels) { TransferMemoryResourceLinkToHost(RecoStep::TPCClusterFinding, clusterer.mScratchId, lane); if (doGPU) { SynchronizeStream(lane); } - runKernel(GetGrid(clusterer.mPmemory->counters.nClusters, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}, 1); + runKernel({GetGrid(clusterer.mPmemory->counters.nClusters, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}}, 1); } if (GetProcessingSettings().debugLevel >= 3) { GPUInfo("Sector %02d Fragment %02d Lane %d: Found clusters: digits %u peaks %u clusters %u", iSlice, fragment.index, lane, (int)clusterer.mPmemory->counters.nPositions, (int)clusterer.mPmemory->counters.nPeaks, (int)clusterer.mPmemory->counters.nClusters); @@ -878,9 +882,8 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) TransferMemoryResourcesToHost(RecoStep::TPCClusterFinding, &clusterer, lane); laneHasData[lane] = true; - if (DoDebugAndDump(RecoStep::TPCClusterFinding, 262144, clusterer, &GPUTPCClusterFinder::DumpCountedPeaks, *mDebugFile)) { - clusterer.DumpClusters(*mDebugFile); - } + // Include clusters in default debug mask, exclude other debug output by default + DoDebugAndDump(RecoStep::TPCClusterFinding, 131072, clusterer, &GPUTPCClusterFinder::DumpClusters, *mDebugFile); } mRec->SetNestedLoopOmpFactor(1); } @@ -899,7 +902,7 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) if (laneHasData[lane]) { anyLaneHasData = true; if (buildNativeGPU && GetProcessingSettings().tpccfGatherKernel) { - runKernel(GetGridBlk(GPUCA_ROW_COUNT, mRec->NStreams() - 1), {iSlice}, {}, &mInputsShadow->mPclusterNativeBuffer[nClsTotal]); + runKernel({GetGridBlk(GPUCA_ROW_COUNT, mRec->NStreams() - 1), {iSlice}}, &mInputsShadow->mPclusterNativeBuffer[nClsTotal]); } for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { if (nClsTotal + clusterer.mPclusterInRow[j] > mInputsHost->mNClusterNative) { @@ -917,9 +920,9 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) nClsTotal += clusterer.mPclusterInRow[j]; } if (transferRunning[lane]) { - ReleaseEvent(&mEvents->stream[lane], doGPU); + ReleaseEvent(mEvents->stream[lane], doGPU); } - RecordMarker(&mEvents->stream[lane], mRec->NStreams() - 1); + RecordMarker(mEvents->stream[lane], mRec->NStreams() - 1); transferRunning[lane] = 1; } @@ -928,9 +931,9 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) continue; } - runKernel(GetGrid(GPUCA_ROW_COUNT, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}); + runKernel({GetGrid(GPUCA_ROW_COUNT, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}}); GPUTPCCFMCLabelFlattener::setGlobalOffsetsAndAllocate(clusterer, mcLinearLabels); - runKernel(GetGrid(GPUCA_ROW_COUNT, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}, {}, &mcLinearLabels); + runKernel({GetGrid(GPUCA_ROW_COUNT, lane, GPUReconstruction::krnlDeviceType::CPU), {iSlice}}, &mcLinearLabels); clusterer.clearMCMemory(); assert(propagateMCLabels ? mcLinearLabels.header.size() == nClsTotal : true); } @@ -957,7 +960,7 @@ int GPUChainTracking::RunTPCClusterizer(bool synchronizeOutput) } for (int i = 0; i < GetProcessingSettings().nTPCClustererLanes; i++) { if (transferRunning[i]) { - ReleaseEvent(&mEvents->stream[i], doGPU); + ReleaseEvent(mEvents->stream[i], doGPU); } } diff --git a/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx b/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx index 08dc74bbe7ad0..4c99523da8f1d 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingCompression.cxx @@ -36,7 +36,7 @@ int GPUChainTracking::RunTPCCompression() GPUTPCCompression& CompressorShadow = doGPU ? processorsShadow()->tpcCompressor : Compressor; const auto& threadContext = GetThreadContext(); if (mPipelineFinalizationCtx && GetProcessingSettings().doublePipelineClusterizer) { - RecordMarker(&mEvents->single, 0); + RecordMarker(mEvents->single, 0); } if (ProcessingSettings().tpcCompressionGatherMode == 3) { @@ -46,13 +46,13 @@ int GPUChainTracking::RunTPCCompression() new (Compressor.mMemory) GPUTPCCompression::memory; WriteToConstantMemory(myStep, (char*)&processors()->tpcCompressor - (char*)processors(), &CompressorShadow, sizeof(CompressorShadow), 0); TransferMemoryResourcesToGPU(myStep, &Compressor, 0); - runKernel(GetGridAutoStep(0, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone, CompressorShadow.mClusterStatus, Compressor.mMaxClusters * sizeof(CompressorShadow.mClusterStatus[0])); - runKernel(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); - runKernel(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAutoStep(0, RecoStep::TPCCompression), CompressorShadow.mClusterStatus, Compressor.mMaxClusters * sizeof(CompressorShadow.mClusterStatus[0])); + runKernel(GetGridAuto(0)); + runKernel(GetGridAuto(0)); TransferMemoryResourcesToHost(myStep, &Compressor, 0); #ifdef GPUCA_TPC_GEOMETRY_O2 if (mPipelineFinalizationCtx && GetProcessingSettings().doublePipelineClusterizer) { - SynchronizeEventAndRelease(&mEvents->single); + SynchronizeEventAndRelease(mEvents->single); ((GPUChainTracking*)GetNextChainInQueue())->RunTPCClusterizer_prepare(false); ((GPUChainTracking*)GetNextChainInQueue())->mCFContext->ptrClusterNativeSave = processorsShadow()->ioPtrs.clustersNative; } @@ -98,25 +98,25 @@ int GPUChainTracking::RunTPCCompression() constexpr unsigned int nBlocksMulti = 1 + 2 * 200; switch (ProcessingSettings().tpcCompressionGatherModeKernel) { case 0: - runKernel(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression)); getKernelTimer(RecoStep::TPCCompression, 0, outputSize); break; case 1: - runKernel(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression)); getKernelTimer(RecoStep::TPCCompression, 0, outputSize); break; case 2: - runKernel(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression)); getKernelTimer(RecoStep::TPCCompression, 0, outputSize); break; case 3: - runKernel(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridBlkStep(nBlocksDefault, outputStream, RecoStep::TPCCompression)); getKernelTimer(RecoStep::TPCCompression, 0, outputSize); break; case 4: static_assert((nBlocksMulti & 1) && nBlocksMulti >= 3); - runKernel(GetGridBlkStep(nBlocksMulti, outputStream, RecoStep::TPCCompression), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridBlkStep(nBlocksMulti, outputStream, RecoStep::TPCCompression)); getKernelTimer(RecoStep::TPCCompression, 0, outputSize); break; default: @@ -124,7 +124,7 @@ int GPUChainTracking::RunTPCCompression() return 1; } if (ProcessingSettings().tpcCompressionGatherMode == 3) { - RecordMarker(&mEvents->stream[outputStream], outputStream); + RecordMarker(mEvents->stream[outputStream], outputStream); char* deviceFlatPts = (char*)Compressor.mOutput->qTotU; if (GetProcessingSettings().doublePipeline) { const size_t blockSize = CAMath::nextMultipleOf<1024>(copySize / 30); @@ -189,7 +189,7 @@ int GPUChainTracking::RunTPCCompression() } mIOPtrs.tpcCompressedClusters = Compressor.mOutputFlat; if (ProcessingSettings().tpcCompressionGatherMode == 3) { - SynchronizeEventAndRelease(&mEvents->stream[outputStream]); + SynchronizeEventAndRelease(mEvents->stream[outputStream]); mRec->ReturnVolatileDeviceMemory(); } @@ -303,8 +303,8 @@ int GPUChainTracking::RunTPCDecompression() inputGPU.timeA = cmprClsHost.timeA; inputGPU.padA = cmprClsHost.padA; - runKernel(GetGridAutoStep(inputStream, RecoStep::TPCDecompression), krnlRunRangeNone, krnlEventNone, DecompressorShadow.mNativeClustersIndex, NSLICES * GPUCA_ROW_COUNT * sizeof(DecompressorShadow.mNativeClustersIndex[0])); - runKernel(GetGridAuto(inputStream), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAutoStep(inputStream, RecoStep::TPCDecompression), DecompressorShadow.mNativeClustersIndex, NSLICES * GPUCA_ROW_COUNT * sizeof(DecompressorShadow.mNativeClustersIndex[0])); + runKernel(GetGridAuto(inputStream)); mInputsHost->mNClusterNative = mInputsShadow->mNClusterNative = cmprClsHost.nAttachedClusters + cmprClsHost.nUnattachedClusters; AllocateRegisteredMemory(mInputsHost->mResourceClusterNativeOutput, mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::clustersNative)]); @@ -344,9 +344,9 @@ int GPUChainTracking::RunTPCDecompression() mClusterNativeAccess->clustersLinear = mInputsHost->mPclusterNativeOutput; mClusterNativeAccess->setOffsetPtrs(); - runKernel(GetGridAuto(inputStream), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(inputStream)); if (GetProcessingSettings().deterministicGPUReconstruction || GetProcessingSettings().debugLevel >= 4) { - runKernel(GetGridAutoStep(inputStream, RecoStep::TPCDecompression), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAutoStep(inputStream, RecoStep::TPCDecompression)); } SynchronizeStream(inputStream); GPUMemCpy(RecoStep::TPCDecompression, (void*)mInputsHost->mPclusterNativeOutput, (void*)mInputsShadow->mPclusterNativeBuffer, sizeof(mInputsShadow->mPclusterNativeBuffer[0]) * mIOPtrs.clustersNative->nClustersTotal, inputStream, false); diff --git a/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx b/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx index 6cc0f9f12ecf3..da167ca9731bf 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingDebugAndProfiling.cxx @@ -32,7 +32,7 @@ int GPUChainTracking::PrepareProfile() #ifdef GPUCA_TRACKLET_CONSTRUCTOR_DO_PROFILE char* tmpMem = (char*)mRec->AllocateUnmanagedMemory(PROFILE_MAX_SIZE, GPUMemoryResource::MEMORY_GPU); processorsShadow()->tpcTrackers[0].mStageAtSync = tmpMem; - runKernel({BlockCount(), ThreadCount(), -1}, nullptr, krnlRunRangeNone, krnlEventNone, tmpMem, PROFILE_MAX_SIZE); + runKernel({{BlockCount(), ThreadCount(), -1}}, tmpMem, PROFILE_MAX_SIZE); #endif return 0; } @@ -189,7 +189,7 @@ void GPUChainTracking::PrepareDebugOutput() WriteToConstantMemory(RecoStep::NoRecoStep, (char*)&processors()->debugOutput - (char*)processors(), &processorsShadow()->debugOutput, sizeof(processors()->debugOutput), -1); memset(processors()->debugOutput.memory(), 0, processors()->debugOutput.memorySize() * sizeof(processors()->debugOutput.memory()[0])); } - runKernel({BlockCount(), ThreadCount(), 0, RecoStep::TPCSliceTracking}, krnlRunRangeNone, {}, (mRec->IsGPU() ? processorsShadow() : processors())->debugOutput.memory(), processorsShadow()->debugOutput.memorySize() * sizeof(processors()->debugOutput.memory()[0])); + runKernel({{BlockCount(), ThreadCount(), 0, RecoStep::TPCSliceTracking}}, (mRec->IsGPU() ? processorsShadow() : processors())->debugOutput.memory(), processorsShadow()->debugOutput.memorySize() * sizeof(processors()->debugOutput.memory()[0])); #endif } diff --git a/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx b/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx index 2509c5f5a0f3f..185de2f804acf 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingMerger.cxx @@ -28,18 +28,18 @@ void GPUChainTracking::RunTPCTrackingMerger_MergeBorderTracks(char withinSlice, GPUTPCGMMerger& MergerShadow = doGPUall ? processorsShadow()->tpcMerger : Merger; if (GetProcessingSettings().deterministicGPUReconstruction) { unsigned int nBorderTracks = withinSlice == 1 ? NSLICES : (2 * NSLICES); - runKernel({nBorderTracks, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 0); + runKernel({{nBorderTracks, -WarpSize(), 0, deviceType}}, 0); } unsigned int n = withinSlice == -1 ? NSLICES / 2 : NSLICES; if (GetProcessingSettings().alternateBorderSort && (!mRec->IsGPU() || doGPUall)) { TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResMemory(), 0, &mEvents->init); - RecordMarker(&mEvents->single, 0); + RecordMarker(mEvents->single, 0); for (unsigned int i = 0; i < n; i++) { int stream = i % mRec->NStreams(); - runKernel(GetGridAuto(stream, deviceType), krnlRunRangeNone, {nullptr, stream && i < (unsigned int)mRec->NStreams() ? &mEvents->single : nullptr}, i, withinSlice, mergeMode); + runKernel({GetGridAuto(stream, deviceType), krnlRunRangeNone, {nullptr, stream && i < (unsigned int)mRec->NStreams() ? &mEvents->single : nullptr}}, i, withinSlice, mergeMode); } - ReleaseEvent(&mEvents->single); - SynchronizeEventAndRelease(&mEvents->init); + ReleaseEvent(mEvents->single); + SynchronizeEventAndRelease(mEvents->init); for (unsigned int i = 0; i < n; i++) { int stream = i % mRec->NStreams(); int n1, n2; @@ -48,28 +48,28 @@ void GPUChainTracking::RunTPCTrackingMerger_MergeBorderTracks(char withinSlice, Merger.MergeBorderTracksSetup(n1, n2, b1, b2, jSlice, i, withinSlice, mergeMode); gputpcgmmergertypes::GPUTPCGMBorderRange* range1 = MergerShadow.BorderRange(i); gputpcgmmergertypes::GPUTPCGMBorderRange* range2 = MergerShadow.BorderRange(jSlice) + *processors()->tpcTrackers[jSlice].NTracks(); - runKernel({1, -WarpSize(), stream, deviceType}, krnlRunRangeNone, krnlEventNone, range1, n1, 0); - runKernel({1, -WarpSize(), stream, deviceType}, krnlRunRangeNone, krnlEventNone, range2, n2, 1); + runKernel({{1, -WarpSize(), stream, deviceType}}, range1, n1, 0); + runKernel({{1, -WarpSize(), stream, deviceType}}, range2, n2, 1); deviceEvent* e = nullptr; int ne = 0; if (i == n - 1) { // Synchronize all execution on stream 0 with the last kernel ne = std::min(n, mRec->NStreams()); for (int j = 1; j < ne; j++) { - RecordMarker(&mEvents->slice[j], j); + RecordMarker(mEvents->slice[j], j); } e = &mEvents->slice[1]; ne--; stream = 0; } - runKernel(GetGridAuto(stream, deviceType), krnlRunRangeNone, {nullptr, e, ne}, i, withinSlice, mergeMode); + runKernel({GetGridAuto(stream, deviceType), krnlRunRangeNone, {nullptr, e, ne}}, i, withinSlice, mergeMode); } } else { for (unsigned int i = 0; i < n; i++) { - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i, withinSlice, mergeMode); + runKernel(GetGridAuto(0, deviceType), i, withinSlice, mergeMode); } - runKernel({2 * n, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 0, withinSlice, mergeMode); + runKernel({{2 * n, -WarpSize(), 0, deviceType}}, 0, withinSlice, mergeMode); for (unsigned int i = 0; i < n; i++) { - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i, withinSlice, mergeMode); + runKernel(GetGridAuto(0, deviceType), i, withinSlice, mergeMode); } } DoDebugAndDump(RecoStep::TPCMerging, 2048, doGPUall, Merger, &GPUTPCGMMerger::DumpMergeRanges, *mDebugFile, withinSlice, mergeMode); @@ -78,11 +78,11 @@ void GPUChainTracking::RunTPCTrackingMerger_MergeBorderTracks(char withinSlice, void GPUChainTracking::RunTPCTrackingMerger_Resolve(char useOrigTrackParam, char mergeAll, GPUReconstruction::krnlDeviceType deviceType) { - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, useOrigTrackParam, mergeAll); + runKernel(GetGridAuto(0, deviceType)); + runKernel(GetGridAuto(0, deviceType)); + runKernel(GetGridAuto(0, deviceType)); + runKernel(GetGridAuto(0, deviceType)); + runKernel(GetGridAuto(0, deviceType), useOrigTrackParam, mergeAll); } int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) @@ -117,64 +117,64 @@ int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) } if (GetProcessingSettings().deterministicGPUReconstruction) { - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, 1); + runKernel(GetGridAuto(0, deviceType), 1); } for (unsigned int i = 0; i < NSLICES; i++) { - runKernel({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, i); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i); + runKernel({{1, -WarpSize(), 0, deviceType}}, i); + runKernel(GetGridAuto(0, deviceType), i); + runKernel(GetGridAuto(0, deviceType), i); } if (GetProcessingSettings().deterministicGPUReconstruction) { - runKernel({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, NSLICES); - runKernel({GPUCA_NSLICES, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 0); + runKernel({{1, -WarpSize(), 0, deviceType}}, NSLICES); + runKernel({{GPUCA_NSLICES, -WarpSize(), 0, deviceType}}, 0); } for (unsigned int i = 0; i < NSLICES; i++) { - runKernel({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, NSLICES + i); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, i); + runKernel({{1, -WarpSize(), 0, deviceType}}, NSLICES + i); + runKernel(GetGridAuto(0, deviceType), i); } - runKernel({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 2 * NSLICES); + runKernel({{1, -WarpSize(), 0, deviceType}}, 2 * NSLICES); if (GetProcessingSettings().deterministicGPUReconstruction) { - runKernel({GPUCA_NSLICES, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 1); + runKernel({{GPUCA_NSLICES, -WarpSize(), 0, deviceType}}, 1); } DoDebugAndDump(RecoStep::TPCMerging, 2048, doGPUall, Merger, &GPUTPCGMMerger::DumpSliceTracks, *mDebugFile); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, false); - runKernel({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), NSLICES * sizeof(*MergerShadowAll.TmpCounter())); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType), false); + runKernel({{1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}}, MergerShadowAll.TmpCounter(), NSLICES * sizeof(*MergerShadowAll.TmpCounter())); + runKernel(GetGridAuto(0, deviceType)); RunTPCTrackingMerger_MergeBorderTracks(1, 0, deviceType); RunTPCTrackingMerger_Resolve(0, 1, deviceType); DoDebugAndDump(RecoStep::TPCMerging, 2048, doGPUall, Merger, &GPUTPCGMMerger::DumpMergedWithinSlices, *mDebugFile); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, false); - runKernel({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); - runKernel(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), krnlRunRangeNone, krnlEventNone, 2, 3, 0); + runKernel(GetGridAuto(0, deviceType), false); + runKernel({{1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); + runKernel(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), 2, 3, 0); RunTPCTrackingMerger_MergeBorderTracks(0, 0, deviceType); RunTPCTrackingMerger_Resolve(0, 1, deviceType); - runKernel({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); - runKernel(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), krnlRunRangeNone, krnlEventNone, 0, 1, 0); + runKernel({{1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); + runKernel(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), 0, 1, 0); RunTPCTrackingMerger_MergeBorderTracks(0, 0, deviceType); RunTPCTrackingMerger_Resolve(0, 1, deviceType); - runKernel({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); - runKernel(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), krnlRunRangeNone, krnlEventNone, 0, 1, 1); + runKernel({{1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); + runKernel(GetGridBlk(std::max(2u, numBlocks), 0, deviceType), 0, 1, 1); RunTPCTrackingMerger_MergeBorderTracks(0, -1, deviceType); RunTPCTrackingMerger_Resolve(0, 1, deviceType); DoDebugAndDump(RecoStep::TPCMerging, 2048, doGPUall, Merger, &GPUTPCGMMerger::DumpMergedBetweenSlices, *mDebugFile); - runKernel({1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); + runKernel({{1, -WarpSize(), 0, deviceType, RecoStep::TPCMerging}}, MergerShadowAll.TmpCounter(), 2 * NSLICES * sizeof(*MergerShadowAll.TmpCounter())); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); + runKernel(GetGridAuto(0, deviceType)); if (GetProcessingSettings().deterministicGPUReconstruction) { - runKernel({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 1); - runKernel({1, -WarpSize(), 0, deviceType}, krnlRunRangeNone, krnlEventNone, 1); + runKernel({{1, -WarpSize(), 0, deviceType}}, 1); + runKernel({{1, -WarpSize(), 0, deviceType}}, 1); } DoDebugAndDump(RecoStep::TPCMerging, 2048, doGPUall, Merger, &GPUTPCGMMerger::DumpCollected, *mDebugFile); if (param().rec.tpc.mergeCE) { - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone, true); + runKernel(GetGridAuto(0, deviceType), true); RunTPCTrackingMerger_MergeBorderTracks(-1, 1, deviceType); RunTPCTrackingMerger_MergeBorderTracks(-1, 2, deviceType); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); DoDebugAndDump(RecoStep::TPCMerging, 2048, doGPUall, Merger, &GPUTPCGMMerger::DumpMergeCE, *mDebugFile); } int waitForTransfer = 0; @@ -184,9 +184,9 @@ int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) } if (GetProcessingSettings().mergerSortTracks) { - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); CondWaitEvent(waitForTransfer, &mEvents->single); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); } unsigned int maxId = param().rec.nonConsecutiveIDs ? Merger.Memory()->nOutputTrackClusters : Merger.NMaxClusters(); @@ -194,13 +194,13 @@ int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) throw std::runtime_error("mNMaxClusters too small"); } if (!param().rec.nonConsecutiveIDs) { - runKernel({numBlocks, -ThreadCount(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.SharedCount(), maxId * sizeof(*MergerShadowAll.SharedCount())); - runKernel({numBlocks, -ThreadCount(), 0, deviceType, RecoStep::TPCMerging}, krnlRunRangeNone, {}, MergerShadowAll.ClusterAttachment(), maxId * sizeof(*MergerShadowAll.ClusterAttachment())); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel({{numBlocks, -ThreadCount(), 0, deviceType, RecoStep::TPCMerging}}, MergerShadowAll.SharedCount(), maxId * sizeof(*MergerShadowAll.SharedCount())); + runKernel({{numBlocks, -ThreadCount(), 0, deviceType, RecoStep::TPCMerging}}, MergerShadowAll.ClusterAttachment(), maxId * sizeof(*MergerShadowAll.ClusterAttachment())); + runKernel(GetGridAuto(0, deviceType)); CondWaitEvent(waitForTransfer, &mEvents->single); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); + runKernel(GetGridAuto(0, deviceType)); + runKernel(GetGridAuto(0, deviceType)); } DoDebugAndDump(RecoStep::TPCMerging, 2048, doGPUall, Merger, &GPUTPCGMMerger::DumpFitPrepare, *mDebugFile); @@ -208,7 +208,7 @@ int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) if (doGPUall) { CondWaitEvent(waitForTransfer, &mEvents->single); if (waitForTransfer) { - ReleaseEvent(&mEvents->single); + ReleaseEvent(mEvents->single); } } else if (doGPU) { TransferMemoryResourcesToGPU(RecoStep::TPCMerging, &Merger, 0); @@ -221,12 +221,12 @@ int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) mOutputQueue.clear(); } - runKernel(doGPU ? GetGrid(Merger.NOutputTracks(), 0) : GetGridAuto(0), krnlRunRangeNone, krnlEventNone, GetProcessingSettings().mergerSortTracks ? 1 : 0); + runKernel(doGPU ? GetGrid(Merger.NOutputTracks(), 0) : GetGridAuto(0), GetProcessingSettings().mergerSortTracks ? 1 : 0); if (param().rec.tpc.retryRefit == 1) { - runKernel(GetGridAuto(0), krnlRunRangeNone, krnlEventNone, -1); + runKernel(GetGridAuto(0), -1); } if (param().rec.tpc.looperInterpolationInExtraPass) { - runKernel(GetGridAuto(0), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0)); } if (doGPU && !doGPUall) { TransferMemoryResourcesToHost(RecoStep::TPCMerging, &Merger, 0); @@ -234,24 +234,24 @@ int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) } DoDebugAndDump(RecoStep::TPCMerging, 2048, Merger, &GPUTPCGMMerger::DumpRefit, *mDebugFile); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); if (!param().rec.nonConsecutiveIDs) { - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); + runKernel(GetGridAuto(0, deviceType)); } if (param().rec.tpc.mergeLoopersAfterburner) { - runKernel(doGPUall ? GetGrid(Merger.NOutputTracks(), 0, deviceType) : GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(doGPUall ? GetGrid(Merger.NOutputTracks(), 0, deviceType) : GetGridAuto(0, deviceType)); if (doGPU) { TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResMemory(), 0); SynchronizeStream(0); // TODO: could probably synchronize on an event after runKernel } - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); - runKernel(doGPUall ? GetGrid(Merger.Memory()->nLooperMatchCandidates, 0, deviceType) : GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); + runKernel(doGPUall ? GetGrid(Merger.Memory()->nLooperMatchCandidates, 0, deviceType) : GetGridAuto(0, deviceType)); } DoDebugAndDump(RecoStep::TPCMerging, 2048, doGPUall, Merger, &GPUTPCGMMerger::DumpFinal, *mDebugFile); if (doGPUall) { - RecordMarker(&mEvents->single, 0); + RecordMarker(mEvents->single, 0); auto* waitEvent = &mEvents->single; if (GetProcessingSettings().keepDisplayMemory || GetProcessingSettings().createO2Output <= 1 || mFractionalQAEnabled) { if (!(GetProcessingSettings().keepDisplayMemory || GetProcessingSettings().createO2Output <= 1)) { @@ -277,7 +277,7 @@ int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResOutputState(), outputStream, nullptr, waitEvent); waitEvent = nullptr; } - ReleaseEvent(&mEvents->single); + ReleaseEvent(mEvents->single); } else { TransferMemoryResourcesToGPU(RecoStep::TPCMerging, &Merger, 0); } @@ -298,11 +298,11 @@ int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) mRec->PushNonPersistentMemory(qStr2Tag("TPCMERG2")); AllocateRegisteredMemory(Merger.MemoryResOutputO2Scratch()); WriteToConstantMemory(RecoStep::TPCMerging, (char*)&processors()->tpcMerger - (char*)processors(), &MergerShadow, sizeof(MergerShadow), 0); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResMemory(), 0, &mEvents->single); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); mRec->ReturnVolatileDeviceMemory(); - SynchronizeEventAndRelease(&mEvents->single, doGPUall); + SynchronizeEventAndRelease(mEvents->single, doGPUall); if (GetProcessingSettings().clearO2OutputFromGPU) { mRec->AllocateVolatileDeviceMemory(0); // make future device memory allocation volatile @@ -310,17 +310,17 @@ int GPUChainTracking::RunTPCTrackingMerger(bool synchronizeOutput) AllocateRegisteredMemory(Merger.MemoryResOutputO2(), mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracksO2)]); AllocateRegisteredMemory(Merger.MemoryResOutputO2Clus(), mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracksO2ClusRefs)]); WriteToConstantMemory(RecoStep::TPCMerging, (char*)&processors()->tpcMerger - (char*)processors(), &MergerShadow, sizeof(MergerShadow), 0); - runKernel(GetGridAuto(0, deviceType), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, deviceType)); if (GetProcessingSettings().runMC && mIOPtrs.clustersNative && mIOPtrs.clustersNative->clustersMCTruth) { AllocateRegisteredMemory(Merger.MemoryResOutputO2MC(), mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcTracksO2Labels)]); TransferMemoryResourcesToHost(RecoStep::TPCMerging, &Merger, -1, true); - runKernel(GetGridAuto(0, GPUReconstruction::krnlDeviceType::CPU), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridAuto(0, GPUReconstruction::krnlDeviceType::CPU)); } else if (doGPUall) { - RecordMarker(&mEvents->single, 0); + RecordMarker(mEvents->single, 0); TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResOutputO2(), outputStream, nullptr, &mEvents->single); TransferMemoryResourceLinkToHost(RecoStep::TPCMerging, Merger.MemoryResOutputO2Clus(), outputStream); - ReleaseEvent(&mEvents->single); + ReleaseEvent(mEvents->single); } mRec->PopNonPersistentMemory(RecoStep::TPCMerging, qStr2Tag("TPCMERG2")); } diff --git a/GPU/GPUTracking/Global/GPUChainTrackingRefit.cxx b/GPU/GPUTracking/Global/GPUChainTrackingRefit.cxx index 782d45587fbde..4d1b7e821479e 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingRefit.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingRefit.cxx @@ -34,9 +34,9 @@ int GPUChainTracking::RunRefit() WriteToConstantMemory(RecoStep::Refit, (char*)&processors()->trackingRefit - (char*)processors(), &RefitShadow, sizeof(RefitShadow), 0); //TransferMemoryResourcesToGPU(RecoStep::Refit, &Refit, 0); if (param().rec.trackingRefitGPUModel) { - runKernel(GetGrid(mIOPtrs.nMergedTracks, 0), krnlRunRangeNone); + runKernel(GetGrid(mIOPtrs.nMergedTracks, 0)); } else { - runKernel(GetGrid(mIOPtrs.nMergedTracks, 0), krnlRunRangeNone); + runKernel(GetGrid(mIOPtrs.nMergedTracks, 0)); } //TransferMemoryResourcesToHost(RecoStep::Refit, &Refit, 0); SynchronizeStream(0); diff --git a/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx b/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx index dbd497551f8bc..221d722878d1d 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingSliceTracker.cxx @@ -31,7 +31,7 @@ int GPUChainTracking::GlobalTracking(unsigned int iSlice, int threadId, bool syn } GPUReconstruction::krnlDeviceType deviceType = GetProcessingSettings().fullMergerOnGPU ? GPUReconstruction::krnlDeviceType::Auto : GPUReconstruction::krnlDeviceType::CPU; - runKernel(GetGridBlk(256, iSlice % mRec->NStreams(), deviceType), {iSlice}); + runKernel({GetGridBlk(256, iSlice % mRec->NStreams(), deviceType), {iSlice}}); if (GetProcessingSettings().fullMergerOnGPU) { TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, processors()->tpcTrackers[iSlice].MemoryResCommon(), iSlice % mRec->NStreams()); } @@ -145,23 +145,28 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() return (2); } - if (param().rec.tpc.occupancyMapTimeBins) { + int streamOccMap = mRec->NStreams() - 1; + if (param().rec.tpc.occupancyMapTimeBins || param().rec.tpc.sysClusErrorC12Norm) { AllocateRegisteredMemory(mInputsHost->mResourceOccupancyMap, mSubOutputControls[GPUTrackingOutputs::getIndex(&GPUTrackingOutputs::tpcOccupancyMap)]); + } + if (param().rec.tpc.occupancyMapTimeBins) { ReleaseEvent(mEvents->init); - auto* ptr = doGPU ? mInputsShadow->mTPCClusterOccupancyMap : mInputsHost->mTPCClusterOccupancyMap; + unsigned int* ptr = doGPU ? mInputsShadow->mTPCClusterOccupancyMap : mInputsHost->mTPCClusterOccupancyMap; auto* ptrTmp = (GPUTPCClusterOccupancyMapBin*)mRec->AllocateVolatileMemory(GPUTPCClusterOccupancyMapBin::getTotalSize(param()), doGPU); - int streamOccMap = mRec->NStreams() - 1; - runKernel(GetGridAutoStep(streamOccMap, RecoStep::TPCSliceTracking), krnlRunRangeNone, {}, ptrTmp, GPUTPCClusterOccupancyMapBin::getTotalSize(param())); - runKernel(GetGridBlk(GPUCA_NSLICES * GPUCA_ROW_COUNT, streamOccMap), krnlRunRangeNone, krnlEventNone, ptrTmp); - runKernel(GetGridBlk(GPUTPCClusterOccupancyMapBin::getNBins(param()), streamOccMap), krnlRunRangeNone, krnlEventNone, ptrTmp, ptr); + runKernel(GetGridAutoStep(streamOccMap, RecoStep::TPCSliceTracking), ptrTmp, GPUTPCClusterOccupancyMapBin::getTotalSize(param())); + runKernel(GetGridBlk(GPUCA_NSLICES * GPUCA_ROW_COUNT, streamOccMap), ptrTmp); + runKernel(GetGridBlk(GPUTPCClusterOccupancyMapBin::getNBins(param()), streamOccMap), ptrTmp, ptr + 2); mRec->ReturnVolatileMemory(); + mInputsHost->mTPCClusterOccupancyMap[1] = param().rec.tpc.occupancyMapTimeBins * 0x10000 + param().rec.tpc.occupancyMapTimeBinsAverage; if (doGPU) { - TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, mInputsHost->mResourceOccupancyMap, streamOccMap, &mEvents->init); + GPUMemCpy(RecoStep::TPCSliceTracking, mInputsHost->mTPCClusterOccupancyMap + 2, mInputsShadow->mTPCClusterOccupancyMap + 2, sizeof(*ptr) * GPUTPCClusterOccupancyMapBin::getNBins(mRec->GetParam()), streamOccMap, false, &mEvents->init); } else { TransferMemoryResourceLinkToGPU(RecoStep::TPCSliceTracking, mInputsHost->mResourceOccupancyMap, streamOccMap, &mEvents->init); } - mRec->UpdateParamOccupancyMap(mInputsHost->mTPCClusterOccupancyMap, mInputsShadow->mTPCClusterOccupancyMap, streamOccMap); } + unsigned int& occupancyTotal = *mInputsHost->mTPCClusterOccupancyMap; + occupancyTotal = CAMath::Float2UIntRn(mRec->MemoryScalers()->nTPCHits / (mIOPtrs.settingsTF && mIOPtrs.settingsTF->hasNHBFPerTF ? mIOPtrs.settingsTF->nHBFPerTF : 128)); + mRec->UpdateParamOccupancyMap(param().rec.tpc.occupancyMapTimeBins ? mInputsHost->mTPCClusterOccupancyMap + 2 : nullptr, param().rec.tpc.occupancyMapTimeBins ? mInputsShadow->mTPCClusterOccupancyMap + 2 : nullptr, occupancyTotal, streamOccMap); int streamMap[NSLICES]; @@ -177,7 +182,7 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() } if (doSliceDataOnGPU) { TransferMemoryResourcesToGPU(RecoStep::TPCSliceTracking, &trk, useStream); - runKernel(GetGridBlk(GPUCA_ROW_COUNT, useStream), {iSlice}, {nullptr, streamInit[useStream] ? nullptr : &mEvents->init}); + runKernel({GetGridBlk(GPUCA_ROW_COUNT, useStream), {iSlice}, {nullptr, streamInit[useStream] ? nullptr : &mEvents->init}}); streamInit[useStream] = true; } else if (!doGPU || iSlice % (GetProcessingSettings().nDeviceHelperThreads + 1) == 0) { if (ReadEvent(iSlice, 0)) { @@ -197,7 +202,7 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() } } if (GetProcessingSettings().deterministicGPUReconstruction) { - runKernel(GetGridBlk(GPUCA_ROW_COUNT, useStream), {iSlice}); + runKernel({GetGridBlk(GPUCA_ROW_COUNT, useStream), {iSlice}}); } if (!doGPU && trk.CheckEmptySlice() && GetProcessingSettings().debugLevel == 0) { continue; @@ -220,7 +225,7 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() if (GetProcessingSettings().keepDisplayMemory && !doSliceDataOnGPU) { memset((void*)trk.Data().HitWeights(), 0, trkShadow.Data().NumberOfHitsPlusAlign() * sizeof(*trkShadow.Data().HitWeights())); } else { - runKernel(GetGridAutoStep(useStream, RecoStep::TPCSliceTracking), krnlRunRangeNone, {}, trkShadow.Data().HitWeights(), trkShadow.Data().NumberOfHitsPlusAlign() * sizeof(*trkShadow.Data().HitWeights())); + runKernel(GetGridAutoStep(useStream, RecoStep::TPCSliceTracking), trkShadow.Data().HitWeights(), trkShadow.Data().NumberOfHitsPlusAlign() * sizeof(*trkShadow.Data().HitWeights())); } // Copy Data to GPU Global Memory @@ -231,7 +236,7 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() throw std::runtime_error("memcpy failure"); } - runKernel(GetGridBlk(GPUCA_ROW_COUNT, useStream), {iSlice}, {nullptr, streamInit[useStream] ? nullptr : &mEvents->init}); + runKernel({GetGridBlk(GPUCA_ROW_COUNT, useStream), {iSlice}, {nullptr, streamInit[useStream] ? nullptr : &mEvents->init}}); streamInit[useStream] = true; if (GetProcessingSettings().keepDisplayMemory) { @@ -242,17 +247,17 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() } } - runKernel(GetGridBlk(GPUCA_ROW_COUNT - 2, useStream), {iSlice}); + runKernel({GetGridBlk(GPUCA_ROW_COUNT - 2, useStream), {iSlice}}); DoDebugAndDump(RecoStep::TPCSliceTracking, 4, trk, &GPUTPCTracker::DumpLinks, *mDebugFile, 1); - runKernel(GetGridBlk(GPUCA_ROW_COUNT - 6, useStream), {iSlice}); + runKernel({GetGridBlk(GPUCA_ROW_COUNT - 6, useStream), {iSlice}}); #ifdef GPUCA_SORT_STARTHITS_GPU if (doGPU) { - runKernel(GetGridAuto(useStream), {iSlice}); + runKernel({GetGridAuto(useStream), {iSlice}}); } #endif if (GetProcessingSettings().deterministicGPUReconstruction) { - runKernel(GetGrid(1, 1, useStream), {iSlice}); + runKernel({GetGrid(1, 1, useStream), {iSlice}}); } DoDebugAndDump(RecoStep::TPCSliceTracking, 32, trk, &GPUTPCTracker::DumpStartHits, *mDebugFile); @@ -263,7 +268,7 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() } if (!(doGPU || GetProcessingSettings().debugLevel >= 1) || GetProcessingSettings().trackletConstructorInPipeline) { - runKernel(GetGridAuto(useStream), {iSlice}); + runKernel({GetGridAuto(useStream), {iSlice}}); DoDebugAndDump(RecoStep::TPCSliceTracking, 128, trk, &GPUTPCTracker::DumpTrackletHits, *mDebugFile); if (GetProcessingSettings().debugMask & 256 && GetProcessingSettings().deterministicGPUReconstruction < 2) { trk.DumpHitWeights(*mDebugFile); @@ -271,10 +276,10 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() } if (!(doGPU || GetProcessingSettings().debugLevel >= 1) || GetProcessingSettings().trackletSelectorInPipeline) { - runKernel(GetGridAuto(useStream), {iSlice}); - runKernel({1, -ThreadCount(), useStream}, {iSlice}, {}, 1); + runKernel({GetGridAuto(useStream), {iSlice}}); + runKernel({{1, -ThreadCount(), useStream}, {iSlice}}, 1); if (GetProcessingSettings().deterministicGPUReconstruction) { - runKernel(GetGrid(1, 1, useStream), {iSlice}); + runKernel({GetGrid(1, 1, useStream), {iSlice}}); } TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, trk.MemoryResCommon(), useStream, &mEvents->slice[iSlice]); streamMap[iSlice] = useStream; @@ -290,7 +295,7 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() } if (doGPU || GetProcessingSettings().debugLevel >= 1) { - ReleaseEvent(&mEvents->init); + ReleaseEvent(mEvents->init); if (!doSliceDataOnGPU) { WaitForHelperThreads(); } @@ -300,13 +305,13 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() SynchronizeGPU(); } else { for (int i = 0; i < mRec->NStreams(); i++) { - RecordMarker(&mEvents->stream[i], i); + RecordMarker(mEvents->stream[i], i); } - runKernel(GetGridAuto(0), krnlRunRangeNone, {&mEvents->single, mEvents->stream, mRec->NStreams()}); + runKernel({GetGridAuto(0), krnlRunRangeNone, {&mEvents->single, mEvents->stream, mRec->NStreams()}}); for (int i = 0; i < mRec->NStreams(); i++) { - ReleaseEvent(&mEvents->stream[i]); + ReleaseEvent(mEvents->stream[i]); } - SynchronizeEventAndRelease(&mEvents->single); + SynchronizeEventAndRelease(mEvents->single); } if (GetProcessingSettings().debugLevel >= 4) { @@ -329,11 +334,11 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() if (GetProcessingSettings().debugLevel >= 3) { GPUInfo("Running TPC Tracklet selector (Stream %d, Slice %d to %d)", useStream, iSlice, iSlice + runSlices); } - runKernel(GetGridAuto(useStream), {iSlice, runSlices}); - runKernel({1, -ThreadCount(), useStream}, {iSlice}, {}, runSlices); + runKernel({GetGridAuto(useStream), {iSlice, runSlices}}); + runKernel({{1, -ThreadCount(), useStream}, {iSlice}}, runSlices); for (unsigned int k = iSlice; k < iSlice + runSlices; k++) { if (GetProcessingSettings().deterministicGPUReconstruction) { - runKernel(GetGrid(1, 1, useStream), {k}); + runKernel({GetGrid(1, 1, useStream), {k}}); } TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, processors()->tpcTrackers[k].MemoryResCommon(), useStream, &mEvents->slice[k]); streamMap[k] = useStream; @@ -365,7 +370,7 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() SynchronizeEvents(&mEvents->slice[iSlice]); } while (tmpSlice < NSLICES && (tmpSlice == iSlice || IsEventDone(&mEvents->slice[tmpSlice]))) { - ReleaseEvent(&mEvents->slice[tmpSlice]); + ReleaseEvent(mEvents->slice[tmpSlice]); if (*processors()->tpcTrackers[tmpSlice].NTracks() > 0) { TransferMemoryResourceLinkToHost(RecoStep::TPCSliceTracking, processors()->tpcTrackers[tmpSlice].MemoryResOutput(), streamMap[tmpSlice], &mEvents->slice[tmpSlice]); } else { @@ -446,7 +451,7 @@ int GPUChainTracking::RunTPCTrackingSlices_internal() } for (unsigned int iSlice = 0; iSlice < NSLICES; iSlice++) { if (transferRunning[iSlice]) { - ReleaseEvent(&mEvents->slice[iSlice]); + ReleaseEvent(mEvents->slice[iSlice]); } } } else { @@ -500,7 +505,7 @@ int GPUChainTracking::ReadEvent(unsigned int iSlice, int threadId) if (GetProcessingSettings().debugLevel >= 5) { GPUInfo("Running ReadEvent for slice %d on thread %d\n", iSlice, threadId); } - runKernel({GetGridAuto(0, GPUReconstruction::krnlDeviceType::CPU)}, {iSlice}); + runKernel({{GetGridAuto(0, GPUReconstruction::krnlDeviceType::CPU)}, {iSlice}}); if (GetProcessingSettings().debugLevel >= 5) { GPUInfo("Finished ReadEvent for slice %d on thread %d\n", iSlice, threadId); } diff --git a/GPU/GPUTracking/Global/GPUChainTrackingTRD.cxx b/GPU/GPUTracking/Global/GPUChainTrackingTRD.cxx index 2fcd7f1d5ed17..8e27de9511af4 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingTRD.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingTRD.cxx @@ -20,6 +20,7 @@ #include "GPUTRDTrack.h" #include "GPUTRDTracker.h" #include "GPUTrackingInputProvider.h" +#include "GPUTRDTrackerKernels.h" #include "utils/strtag.h" using namespace GPUCA_NAMESPACE::gpu; @@ -28,6 +29,7 @@ using namespace o2::trd; template int GPUChainTracking::RunTRDTracking() { +#ifndef GPUCA_ALIROOT_LIB if (!processors()->trdTrackerGPU.IsInitialized()) { return 1; } @@ -127,6 +129,7 @@ int GPUChainTracking::RunTRDTracking() } mRec->PopNonPersistentMemory(RecoStep::TRDTracking, qStr2Tag("TRDTRACK")); +#endif // GPUCA_ALIROOT_LIB return 0; } @@ -183,7 +186,7 @@ int GPUChainTracking::DoTRDGPUTracking(T* externalInstance) } TransferMemoryResourcesToGPU(RecoStep::TRDTracking, Tracker, useStream); - runKernel(GetGridAuto(useStream), krnlRunRangeNone, krnlEventNone, externalInstance ? Tracker : nullptr); + runKernel(GetGridAuto(useStream), externalInstance ? Tracker : nullptr); TransferMemoryResourcesToHost(RecoStep::TRDTracking, Tracker, useStream); SynchronizeStream(useStream); @@ -195,8 +198,8 @@ int GPUChainTracking::DoTRDGPUTracking(T* externalInstance) } template int GPUChainTracking::RunTRDTracking(); -template int GPUChainTracking::RunTRDTracking(); template int GPUChainTracking::DoTRDGPUTracking(GPUTRDTrackerGPU*); template int GPUChainTracking::DoTRDGPUTracking(GPUTRDTracker*); +template int GPUChainTracking::RunTRDTracking(); template int GPUChainTracking::DoTRDGPUTracking(GPUTRDTracker*); template int GPUChainTracking::DoTRDGPUTracking(GPUTRDTrackerGPU*); diff --git a/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx b/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx index bda2d226c69d8..7c8b77d9fe36c 100644 --- a/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx +++ b/GPU/GPUTracking/Global/GPUChainTrackingTransformation.cxx @@ -72,7 +72,7 @@ int GPUChainTracking::ConvertNativeToClusterData() WriteToConstantMemory(RecoStep::TPCConversion, (char*)&processors()->tpcConverter - (char*)processors(), &convertShadow, sizeof(convertShadow), 0); TransferMemoryResourcesToGPU(RecoStep::TPCConversion, &convert, 0); - runKernel(GetGridBlk(NSLICES * GPUCA_ROW_COUNT, 0), krnlRunRangeNone, krnlEventNone); + runKernel(GetGridBlk(NSLICES * GPUCA_ROW_COUNT, 0)); TransferMemoryResourcesToHost(RecoStep::TPCConversion, &convert, 0); SynchronizeStream(0); diff --git a/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx b/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx index bd066ce100a36..bf6cd029a981b 100644 --- a/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx +++ b/GPU/GPUTracking/Global/GPUTrackingInputProvider.cxx @@ -79,7 +79,7 @@ void* GPUTrackingInputProvider::SetPointersInputTRD(void* mem) void* GPUTrackingInputProvider::SetPointersTPCOccupancyMap(void* mem) { if (mHoldTPCOccupancyMap) { - computePointerWithAlignment(mem, mTPCClusterOccupancyMap, GPUTPCClusterOccupancyMapBin::getNBins(mRec->GetParam())); + computePointerWithAlignment(mem, mTPCClusterOccupancyMap, (mRec->GetParam().rec.tpc.occupancyMapTimeBins ? GPUTPCClusterOccupancyMapBin::getNBins(mRec->GetParam()) + 1 : 0) + 1); // +1 for total occupancy estimator, +1 for sanity check information } return mem; } @@ -99,6 +99,6 @@ void GPUTrackingInputProvider::SetMaxData(const GPUTrackingInOutPointers& io) { mHoldTPCZS = io.tpcZS && (mRec->GetRecoStepsGPU() & GPUDataTypes::RecoStep::TPCClusterFinding); mHoldTPCClusterNative = (io.tpcZS || io.tpcPackedDigits || io.clustersNative || io.tpcCompressedClusters) && (mRec->IsGPU() || io.tpcCompressedClusters); - mHoldTPCOccupancyMap = (io.tpcZS || io.tpcPackedDigits || io.clustersNative || io.tpcCompressedClusters) && mRec->GetParam().rec.tpc.occupancyMapTimeBins; + mHoldTPCOccupancyMap = (io.tpcZS || io.tpcPackedDigits || io.clustersNative || io.tpcCompressedClusters) && (mRec->GetParam().rec.tpc.occupancyMapTimeBins || mRec->GetParam().rec.tpc.sysClusErrorC12Norm); mHoldTPCClusterNativeOutput = io.tpcZS || io.tpcPackedDigits || io.tpcCompressedClusters; } diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.cxx b/GPU/GPUTracking/Interface/GPUO2Interface.cxx index d1e4734d45334..429a58ad65dd4 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.cxx +++ b/GPU/GPUTracking/Interface/GPUO2Interface.cxx @@ -260,3 +260,8 @@ const o2::base::Propagator* GPUO2Interface::GetDeviceO2Propagator(int iThread) c { return mCtx[iThread].mChain->GetDeviceO2Propagator(); } + +void GPUO2Interface::UseGPUPolynomialFieldInPropagator(o2::base::Propagator* prop) const +{ + prop->setGPUField(&mCtx[0].mRec->GetParam().polynomialField); +} diff --git a/GPU/GPUTracking/Interface/GPUO2Interface.h b/GPU/GPUTracking/Interface/GPUO2Interface.h index fe8ea37812c41..ae48775396fe4 100644 --- a/GPU/GPUTracking/Interface/GPUO2Interface.h +++ b/GPU/GPUTracking/Interface/GPUO2Interface.h @@ -42,8 +42,6 @@ namespace o2::tpc { struct ClusterNativeAccess; struct ClusterNative; -template -class CalDet; } // namespace o2::tpc namespace o2::its @@ -84,6 +82,7 @@ class GPUO2Interface void GetITSTraits(o2::its::TrackerTraits*& trackerTraits, o2::its::VertexerTraits*& vertexerTraits, o2::its::TimeFrame*& timeFrame); const o2::base::Propagator* GetDeviceO2Propagator(int iThread = 0) const; + void UseGPUPolynomialFieldInPropagator(o2::base::Propagator* prop) const; // Updates all calibration objects that are != nullptr in newCalib int UpdateCalibration(const GPUCalibObjectsConst& newCalib, const GPUNewCalibValues& newVals, unsigned int iThread = 0); diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx index da625dd704ab6..bbd0d16c943f9 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfigurableParam.cxx @@ -53,7 +53,7 @@ using namespace o2::gpu; #undef AddHelp #undef AddShortcut -GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam_internal() +GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam(GPUO2InterfaceConfiguration& obj) { #define BeginNamespace(name) #define EndNamespace() @@ -98,29 +98,29 @@ GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam_internal() #undef AddHelp #undef AddShortcut - configProcessing = proc; - configReconstruction = rec; - configDisplay = display; - configQA = QA; + obj.configProcessing = proc; + obj.configReconstruction = rec; + obj.configDisplay = display; + obj.configQA = QA; if (global.continuousMaxTimeBin) { - configGRP.continuousMaxTimeBin = global.continuousMaxTimeBin; + obj.configGRP.continuousMaxTimeBin = global.continuousMaxTimeBin; } else { - configGRP.continuousMaxTimeBin = global.tpcTriggeredMode ? 0 : -1; + obj.configGRP.continuousMaxTimeBin = global.tpcTriggeredMode ? 0 : -1; } - if (global.solenoidBz > -1e6f) { - configGRP.solenoidBz = global.solenoidBz; + if (global.solenoidBzNominalGPU > -1e6f) { + obj.configGRP.solenoidBzNominalGPU = global.solenoidBzNominalGPU; } if (global.constBz) { - configGRP.constBz = global.constBz; + obj.configGRP.constBz = global.constBz; } if (global.gpuDisplayfilterMacro != "") { - configDisplay.filterMacros.emplace_back(global.gpuDisplayfilterMacro); + obj.configDisplay.filterMacros.emplace_back(global.gpuDisplayfilterMacro); } - if (configReconstruction.tpc.trackReferenceX == 1000.f) { - configReconstruction.tpc.trackReferenceX = 83.f; + if (obj.configReconstruction.tpc.trackReferenceX == 1000.f) { + obj.configReconstruction.tpc.trackReferenceX = 83.f; } - configDeviceBackend.deviceType = GPUDataTypes::GetDeviceType(global.deviceType.c_str()); - configDeviceBackend.forceDeviceType = global.forceDeviceType; + obj.configDeviceBackend.deviceType = GPUDataTypes::GetDeviceType(global.deviceType.c_str()); + obj.configDeviceBackend.forceDeviceType = global.forceDeviceType; return global; } diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx index 10535c9b1283f..54477f550b3d4 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.cxx @@ -19,7 +19,7 @@ using namespace o2::gpu; GPUSettingsO2 GPUO2InterfaceConfiguration::ReadConfigurableParam() { - return ReadConfigurableParam_internal(); + return ReadConfigurableParam(*this); } void GPUO2InterfaceConfiguration::PrintParam() diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h index 2d062c1422c40..0427d6d14c996 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceConfiguration.h @@ -98,11 +98,10 @@ struct GPUO2InterfaceConfiguration { GPUCalibObjectsConst configCalib; GPUSettingsO2 ReadConfigurableParam(); + static GPUSettingsO2 ReadConfigurableParam(GPUO2InterfaceConfiguration& obj); void PrintParam(); private: - friend class GPUReconstruction; - GPUSettingsO2 ReadConfigurableParam_internal(); void PrintParam_internal(); }; diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx index e8e15381e8501..f81da3b52ad1b 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.cxx @@ -13,20 +13,30 @@ /// \author David Rohr #include "GPUO2InterfaceRefit.h" +#include "GPUO2InterfaceUtils.h" #include "DataFormatsTPC/ClusterNative.h" #include "DataFormatsTPC/TrackTPC.h" #include "GPUParam.h" #include "GPUTPCGMMergedTrackHit.h" #include "GPUTrackingRefit.h" #include "CorrectionMapsHelper.h" +#include "GPUTPCClusterOccupancyMap.h" using namespace o2::gpu; using namespace o2::tpc; -void GPUO2InterfaceRefit::fillSharedClustersMap(const ClusterNativeAccess* cl, const gsl::span trks, const TPCClRefElem* trackRef, unsigned char* shmap) +void GPUO2InterfaceRefit::fillSharedClustersAndOccupancyMap(const ClusterNativeAccess* cl, const gsl::span trks, const TPCClRefElem* trackRef, unsigned char* shmap, unsigned int* ocmap, unsigned int nHbfPerTf, const GPUParam* param) { if (!cl || (!shmap && cl->nClustersTotal > 0)) { - throw std::runtime_error("Must provide clusters access and preallocated recepient for shared map"); + throw std::runtime_error("Must provide clusters access and preallocated buffer for shared map"); + } + std::unique_ptr tmpParam; + if (param == nullptr) { + tmpParam = GPUO2InterfaceUtils::getFullParam(0.f, nHbfPerTf); + param = tmpParam.get(); + } + if ((param->rec.tpc.occupancyMapTimeBins || param->rec.tpc.sysClusErrorC12Norm) && ocmap && !nHbfPerTf) { + throw std::runtime_error("Must provide nHbfPerTf for occupancy map"); } memset(shmap, 0, sizeof(char) * cl->nClustersTotal); for (unsigned int i = 0; i < trks.size(); i++) { @@ -35,25 +45,89 @@ void GPUO2InterfaceRefit::fillSharedClustersMap(const ClusterNativeAccess* cl, c shmap[idx] = shmap[idx] ? 2 : 1; } } + std::vector tmp; + unsigned int* binmap = nullptr; + if (ocmap && nHbfPerTf) { + tmp.resize(param->rec.tpc.occupancyMapTimeBinsAverage ? GPUTPCClusterOccupancyMapBin::getNBins(*param) : 0, 0); + binmap = param->rec.tpc.occupancyMapTimeBinsAverage ? tmp.data() : (ocmap + 2); + *ocmap = cl->nClustersTotal / nHbfPerTf; + if (param->rec.tpc.occupancyMapTimeBins) { + ocmap[1] = param->rec.tpc.occupancyMapTimeBins * 0x10000 + param->rec.tpc.occupancyMapTimeBinsAverage; + } + } + for (unsigned int i = 0; i < cl->nClustersTotal; i++) { shmap[i] = (shmap[i] > 1 ? GPUTPCGMMergedTrackHit::flagShared : 0) | cl->clustersLinear[i].getFlags(); + if (binmap) { + binmap[(unsigned int)(cl->clustersLinear[i].getTime() / param->rec.tpc.occupancyMapTimeBins)]++; + } + } + + if (ocmap && nHbfPerTf && param->rec.tpc.occupancyMapTimeBinsAverage) { + for (unsigned int bin = 0; bin < GPUTPCClusterOccupancyMapBin::getNBins(*param); bin++) { + int binmin = CAMath::Max(0, bin - param->rec.tpc.occupancyMapTimeBinsAverage); + int binmax = CAMath::Min(GPUTPCClusterOccupancyMapBin::getNBins(*param), bin + param->rec.tpc.occupancyMapTimeBinsAverage + 1); + unsigned int sum = 0; + for (int i = binmin; i < binmax; i++) { + sum += binmap[i]; + } + sum /= binmax - binmin; + ocmap[2 + bin] = sum; + } } } -GPUO2InterfaceRefit::GPUO2InterfaceRefit(const ClusterNativeAccess* cl, const CorrectionMapsHelper* trans, float bz, const TPCClRefElem* trackRef, const unsigned char* sharedmap, const std::vector* trks, o2::base::Propagator* p) : mParam(new GPUParam) +size_t GPUO2InterfaceRefit::fillOccupancyMapGetSize(unsigned int nHbfPerTf, const GPUParam* param) { + std::unique_ptr tmpParam; + if (param == nullptr) { + tmpParam = GPUO2InterfaceUtils::getFullParam(0.f, nHbfPerTf); + param = tmpParam.get(); + } + if ((param->rec.tpc.occupancyMapTimeBins || param->rec.tpc.sysClusErrorC12Norm) && !nHbfPerTf) { + throw std::runtime_error("nHbfPerTf must not be zero for creation of the occupancy map"); + } + if (param->rec.tpc.occupancyMapTimeBins) { + return (GPUTPCClusterOccupancyMapBin::getNBins(*param) + 2) * sizeof(unsigned int); + } else if (param->rec.tpc.sysClusErrorC12Norm) { + return sizeof(unsigned int); + } else { + return 0; + } +} + +GPUO2InterfaceRefit::GPUO2InterfaceRefit(const ClusterNativeAccess* cl, const CorrectionMapsHelper* trans, float bzNominalGPU, const TPCClRefElem* trackRef, unsigned int nHbfPerTf, const unsigned char* sharedmap, const unsigned int* occupancymap, int occupancyMapSize, const std::vector* trks, o2::base::Propagator* p) +{ + mParam = GPUO2InterfaceUtils::getFullParam(bzNominalGPU, nHbfPerTf); + size_t expectedSharedMapSize = nHbfPerTf ? fillOccupancyMapGetSize(nHbfPerTf, mParam.get()) : 0; if (cl->nClustersTotal) { if (sharedmap == nullptr && trks == nullptr) { throw std::runtime_error("Must provide either shared cluster map or vector of tpc tracks to build the map"); } + if ((sharedmap == nullptr) ^ (expectedSharedMapSize && occupancymap == nullptr)) { + throw std::runtime_error("Must provide either both shared cluster map and occupancy map or none of them"); + } if (sharedmap == nullptr) { mSharedMap.resize(cl->nClustersTotal); sharedmap = mSharedMap.data(); - fillSharedClustersMap(cl, *trks, trackRef, mSharedMap.data()); + mOccupancyMap.resize(expectedSharedMapSize / sizeof(*mOccupancyMap.data())); + occupancymap = mOccupancyMap.data(); + fillSharedClustersAndOccupancyMap(cl, *trks, trackRef, mSharedMap.data(), mOccupancyMap.data(), nHbfPerTf, mParam.get()); } } + if (occupancymap && occupancyMapSize > sizeof(*occupancymap) && occupancymap[1] != (mParam->rec.tpc.occupancyMapTimeBins * 0x10000 + mParam->rec.tpc.occupancyMapTimeBinsAverage)) { + throw std::runtime_error("Occupancy map has invalid paramters occupancyMapTimeBins and occupancyMapTimeBinsAverage"); + } + if (occupancyMapSize != -1 && nHbfPerTf && (size_t)occupancyMapSize != expectedSharedMapSize) { + throw std::runtime_error("Received occupancy map of wrong size, most likely --configKeyValues or HBperTF of map creator and map consumer are different"); + } mRefit = std::make_unique(); - mParam->SetDefaults(bz); + if (occupancymap) { + mParam->occupancyTotal = *occupancymap; + if (mParam->rec.tpc.occupancyMapTimeBins) { + mParam->occupancyMap = occupancymap + 2; + } + } mRefit->SetGPUParam(mParam.get()); mRefit->SetClusterStateArray(sharedmap); mRefit->SetPropagator(p); @@ -62,10 +136,9 @@ GPUO2InterfaceRefit::GPUO2InterfaceRefit(const ClusterNativeAccess* cl, const Co mRefit->SetFastTransformHelper(trans); } -void GPUO2InterfaceRefit::updateCalib(const CorrectionMapsHelper* trans, float bz) +void GPUO2InterfaceRefit::updateCalib(const CorrectionMapsHelper* trans, float bzNominalGPU) { - mParam->SetDefaults(bz); - mRefit->SetGPUParam(mParam.get()); + mParam->UpdateBzOnly(bzNominalGPU); mRefit->SetFastTransformHelper(trans); } @@ -74,7 +147,6 @@ int GPUO2InterfaceRefit::RefitTrackAsTrackParCov(o2::tpc::TrackTPC& trk, bool ou int GPUO2InterfaceRefit::RefitTrackAsGPU(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2, bool outward, bool resetCov) { return mRefit->RefitTrackAsGPU(trk, clusRef, time0, chi2, outward, resetCov); } int GPUO2InterfaceRefit::RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2, bool outward, bool resetCov) { return mRefit->RefitTrackAsTrackParCov(trk, clusRef, time0, chi2, outward, resetCov); } void GPUO2InterfaceRefit::setIgnoreErrorsAtTrackEnds(bool v) { mRefit->mIgnoreErrorsOnTrackEnds = v; } -void GPUO2InterfaceRefit::setGPUTrackFitInProjections(bool v) { mParam->rec.fitInProjections = v; } void GPUO2InterfaceRefit::setTrackReferenceX(float v) { mParam->rec.tpc.trackReferenceX = v; } GPUO2InterfaceRefit::~GPUO2InterfaceRefit() = default; diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.h b/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.h index 6ae70f61b714c..4437e51121163 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceRefit.h @@ -68,25 +68,33 @@ class GPUO2InterfaceRefit // - In any case: Cluster Native access structure (cl), TPC Fast Transformation helper instance (trans), solenoid field (bz), TPC Track hit references (trackRef) // - Either the shared cluster map (sharedmap) or the vector of tpc tracks (trks) to build the shared cluster map internally // - o2::base::Propagator (p) in case RefitTrackAsTrackParCov is to be used + // - In case the --configKeyValues defining GPUParam settings require an occupancy map for TPC error estimation, the map must either be provided as occupancymap, or nHbfPerTf must be set non-zero - GPUO2InterfaceRefit(const o2::tpc::ClusterNativeAccess* cl, const o2::gpu::CorrectionMapsHelper* trans, float bz, const o2::tpc::TPCClRefElem* trackRef, const unsigned char* sharedmap = nullptr, const std::vector* trks = nullptr, o2::base::Propagator* p = nullptr); + GPUO2InterfaceRefit(const o2::tpc::ClusterNativeAccess* cl, const o2::gpu::CorrectionMapsHelper* trans, float bzNominalGPU, const o2::tpc::TPCClRefElem* trackRef, unsigned int nHbfPerTf = 0, const unsigned char* sharedmap = nullptr, const unsigned int* occupancymap = nullptr, int occupancyMapSize = -1, const std::vector* trks = nullptr, o2::base::Propagator* p = nullptr); ~GPUO2InterfaceRefit(); int RefitTrackAsGPU(o2::tpc::TrackTPC& trk, bool outward = false, bool resetCov = false); int RefitTrackAsTrackParCov(o2::tpc::TrackTPC& trk, bool outward = false, bool resetCov = false); int RefitTrackAsGPU(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false); int RefitTrackAsTrackParCov(o2::track::TrackParCov& trk, const o2::tpc::TrackTPCClusRef& clusRef, float time0, float* chi2 = nullptr, bool outward = false, bool resetCov = false); - void setGPUTrackFitInProjections(bool v = true); void setTrackReferenceX(float v); void setIgnoreErrorsAtTrackEnds(bool v); - void updateCalib(const o2::gpu::CorrectionMapsHelper* trans, float bz); + void updateCalib(const o2::gpu::CorrectionMapsHelper* trans, float bzNominalGPU); + auto getParam() const { return mParam.get(); } - static void fillSharedClustersMap(const o2::tpc::ClusterNativeAccess* cl, const gsl::span trks, const o2::tpc::TPCClRefElem* trackRef, unsigned char* shmap); + // To create shared cluster maps and occupancy maps. + // param is an optional parameter to override the param object, by default a default object from --configKeyValues is used. + // If the param object / default object requires an occupancy map, an occupancy map ptr and nHbfPerTf value must be provided. + // You can use the function fillOccupancyMapGetSize(...) to get the required size of the occupancy map. If 0 is returned, no map is required. + // Providing only the shmap ptr but no ocmap ptr will create only the shared map, but no occupancy map. + static void fillSharedClustersAndOccupancyMap(const o2::tpc::ClusterNativeAccess* cl, const gsl::span trks, const o2::tpc::TPCClRefElem* trackRef, unsigned char* shmap, unsigned int* ocmap = nullptr, unsigned int nHbfPerTf = 0, const GPUParam* param = nullptr); + static size_t fillOccupancyMapGetSize(unsigned int nHbfPerTf, const GPUParam* param = nullptr); private: std::unique_ptr mRefit; std::unique_ptr mParam; std::vector mSharedMap; + std::vector mOccupancyMap; }; } // namespace o2::gpu diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.cxx b/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.cxx index e974704ea9d0b..cc4254f7156cf 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.cxx +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.cxx @@ -77,3 +77,39 @@ void GPUO2InterfaceUtils::GPUReconstructionZSDecoder::DecodePage(std::vectorversion](outputBuffer, page, tfFirstOrbit, triggerBC); } + +std::unique_ptr GPUO2InterfaceUtils::getFullParam(float solenoidBz, unsigned int nHbfPerTf, std::unique_ptr* pConfiguration, std::unique_ptr* pO2Settings, bool* autoMaxTimeBin) +{ + std::unique_ptr retVal = std::make_unique(); + std::unique_ptr tmpConfig; + if (!pConfiguration) { + tmpConfig = std::make_unique(); + pConfiguration = &tmpConfig; + } else if (!*pConfiguration) { + *pConfiguration = std::make_unique(); + } + (*pConfiguration)->configGRP.solenoidBzNominalGPU = solenoidBz; + if (pO2Settings && *pO2Settings) { + **pO2Settings = (*pConfiguration)->ReadConfigurableParam(); + } else if (pO2Settings) { + *pO2Settings = std::make_unique((*pConfiguration)->ReadConfigurableParam()); + } else { + (*pConfiguration)->ReadConfigurableParam(); + } + if (nHbfPerTf == 0) { + nHbfPerTf = 256; + } + if (autoMaxTimeBin) { + *autoMaxTimeBin = (*pConfiguration)->configGRP.continuousMaxTimeBin == -1; + } + if ((*pConfiguration)->configGRP.continuousMaxTimeBin == -1) { + (*pConfiguration)->configGRP.continuousMaxTimeBin = (nHbfPerTf * o2::constants::lhc::LHCMaxBunches + 2 * o2::tpc::constants::LHCBCPERTIMEBIN - 2) / o2::tpc::constants::LHCBCPERTIMEBIN; + } + retVal->SetDefaults(&(*pConfiguration)->configGRP, &(*pConfiguration)->configReconstruction, &(*pConfiguration)->configProcessing, nullptr); + return retVal; +} + +std::shared_ptr GPUO2InterfaceUtils::getFullParamShared(float solenoidBz, unsigned int nHbfPerTf, std::unique_ptr* pConfiguration, std::unique_ptr* pO2Settings, bool* autoMaxTimeBin) +{ + return std::move(getFullParam(solenoidBz, nHbfPerTf, pConfiguration, pO2Settings, autoMaxTimeBin)); +} diff --git a/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.h b/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.h index d8672f515c06e..c375f4d646a00 100644 --- a/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.h +++ b/GPU/GPUTracking/Interface/GPUO2InterfaceUtils.h @@ -15,8 +15,8 @@ #ifndef GPUO2INTERFACEUTILS_H #define GPUO2INTERFACEUTILS_H -#include "GPUO2Interface.h" #include +#include namespace o2 { @@ -25,12 +25,21 @@ namespace raw { class RawFileWriter; } // namespace raw +namespace tpc +{ +class CalibdEdxContainer; +class Digit; +template +class CalDet; +} // namespace tpc } // namespace o2 namespace o2::gpu { struct GPUParam; struct GPUO2InterfaceConfiguration; +struct GPUSettingsO2; +struct TPCPadGainCalib; class GPUO2InterfaceUtils { public: @@ -41,6 +50,13 @@ class GPUO2InterfaceUtils static void RunZSEncoder(const S& in, std::unique_ptr* outBuffer, unsigned int* outSizes, o2::raw::RawFileWriter* raw, const o2::InteractionRecord* ir, int version, bool verify, float threshold = 0.f, bool padding = false, std::function&)> digitsFilter = nullptr); template static void RunZSEncoder(const S& in, std::unique_ptr* outBuffer, unsigned int* outSizes, o2::raw::RawFileWriter* raw, const o2::InteractionRecord* ir, GPUO2InterfaceConfiguration& config, int version, bool verify, bool padding = false, std::function&)> digitsFilter = nullptr); + template + static float getNominalGPUBz(T& src) + { + return (5.00668f / 30000.f) * src.getL3Current(); + } + static std::unique_ptr getFullParam(float solenoidBz, unsigned int nHbfPerTf = 0, std::unique_ptr* pConfiguration = nullptr, std::unique_ptr* pO2Settings = nullptr, bool* autoMaxTimeBin = nullptr); + static std::shared_ptr getFullParamShared(float solenoidBz, unsigned int nHbfPerTf = 0, std::unique_ptr* pConfiguration = nullptr, std::unique_ptr* pO2Settings = nullptr, bool* autoMaxTimeBin = nullptr); // Return owning pointer class GPUReconstructionZSDecoder { diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx index 5c46d01b200bb..9f7e359d1630b 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMerger.cxx @@ -657,7 +657,7 @@ GPUd() void GPUTPCGMMerger::MergeSlicesPrepareStep2(int nBlocks, int nThreads, i //* prepare slice tracks for merging with next/previous/same sector //* each track transported to the border line - float fieldBz = Param().constBz; + float fieldBz = Param().bzCLight; float dAlpha = Param().par.dAlpha / 2; float x0 = 0; @@ -829,9 +829,8 @@ struct MergeBorderTracks_compMin { }; template <> -void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal(krnlSetup& _xyz, GPUTPCGMBorderRange* const& range, int const& N, int const& cmpMax) +inline void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal(const krnlSetupTime& _xyz, GPUTPCGMBorderRange* const& range, int const& N, int const& cmpMax) { - GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); thrust::device_ptr p(range); ThrustVolatileAsyncAllocator alloc(this); if (cmpMax) { @@ -1021,7 +1020,7 @@ GPUd() void GPUTPCGMMerger::MergeWithinSlicesPrepare(int nBlocks, int nThreads, GPUTPCGMSliceTrack& track = mSliceTrackInfos[itr]; int iSlice = track.Slice(); GPUTPCGMBorderTrack b; - if (track.TransportToX(this, x0, Param().constBz, b, maxSin)) { + if (track.TransportToX(this, x0, Param().bzCLight, b, maxSin)) { b.SetTrackID(itr); CADEBUG(printf("WITHIN SLICE %d Track %d - ", iSlice, itr); for (int i = 0; i < 5; i++) { printf("%8.3f ", b.Par()[i]); } printf(" - "); for (int i = 0; i < 5; i++) { printf("%8.3f ", b.Cov()[i]); } printf("\n")); b.SetNClusters(track.NClusters()); @@ -1359,7 +1358,7 @@ GPUd() void GPUTPCGMMerger::MergeCEFill(const GPUTPCGMSliceTrack* track, const G for (int attempt = 0; attempt < 2; attempt++) { GPUTPCGMBorderTrack b; const float x0 = Param().tpcGeometry.Row2X(attempt == 0 ? 63 : cls.row); - if (track->TransportToX(this, x0, Param().constBz, b, GPUCA_MAX_SIN_PHI_LOW)) { + if (track->TransportToX(this, x0, Param().bzCLight, b, GPUCA_MAX_SIN_PHI_LOW)) { b.SetTrackID(itr); b.SetNClusters(mOutputTracks[itr].NClusters()); if (CAMath::Abs(b.Cov()[4]) >= 0.5f) { @@ -1847,7 +1846,7 @@ GPUd() void GPUTPCGMMerger::CollectMergedTracks(int nBlocks, int nThreads, int i GPUTPCGMBorderTrack b; const float toX = Param().par.earlyTpcTransform ? clXYZ[0].x : Param().tpcGeometry.Row2X(cl[0].row); - if (p2.TransportToX(this, toX, Param().constBz, b, GPUCA_MAX_SIN_PHI, false)) { + if (p2.TransportToX(this, toX, Param().bzCLight, b, GPUCA_MAX_SIN_PHI, false)) { p1.X() = toX; p1.Y() = b.Par()[0]; p1.Z() = b.Par()[1]; @@ -1933,9 +1932,8 @@ struct GPUTPCGMMergerSortTracks_comp { }; template <> -void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal(krnlSetup& _xyz) +inline void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal(const krnlSetupTime& _xyz) { - GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); thrust::device_ptr trackSort((unsigned int*)mProcessorsShadow->tpcMerger.TrackOrderProcess()); ThrustVolatileAsyncAllocator alloc(this); thrust::sort(GPUCA_THRUST_NAMESPACE::par(alloc).on(mInternals->Streams[_xyz.x.stream]), trackSort, trackSort + processors()->tpcMerger.NOutputTracks(), GPUTPCGMMergerSortTracks_comp(mProcessorsShadow->tpcMerger.OutputTracks())); @@ -1963,9 +1961,8 @@ struct GPUTPCGMMergerSortTracksQPt_comp { }; template <> -void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal(krnlSetup& _xyz) +inline void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal(const krnlSetupTime& _xyz) { - GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); thrust::device_ptr trackSort((unsigned int*)mProcessorsShadow->tpcMerger.TrackSort()); ThrustVolatileAsyncAllocator alloc(this); thrust::sort(GPUCA_THRUST_NAMESPACE::par(alloc).on(mInternals->Streams[_xyz.x.stream]), trackSort, trackSort + processors()->tpcMerger.NOutputTracks(), GPUTPCGMMergerSortTracksQPt_comp(mProcessorsShadow->tpcMerger.OutputTracks())); @@ -2189,9 +2186,8 @@ struct GPUTPCGMMergerMergeLoopers_comp { }; template <> -void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal(krnlSetup& _xyz) +inline void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal(const krnlSetupTime& _xyz) { - GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); thrust::device_ptr params(mProcessorsShadow->tpcMerger.LooperCandidates()); ThrustVolatileAsyncAllocator alloc(this); thrust::sort(GPUCA_THRUST_NAMESPACE::par(alloc).on(mInternals->Streams[_xyz.x.stream]), params, params + processors()->tpcMerger.Memory()->nLooperMatchCandidates, GPUTPCGMMergerMergeLoopers_comp()); diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx index 04b9676dc61ee..19d56b62ba490 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergerDump.cxx @@ -360,8 +360,9 @@ void GPUTPCGMMerger::DebugStreamerUpdate(int iTrk, int ihit, float xx, float yy, auto uncorrectedYZ = StreamerUncorrectedZY(cluster.slice, cluster.row, track, prop); float invCharge = 1.f / clusterNative.qMax; int iRow = cluster.row; - float scaledMult = (time >= 0.f ? Param().GetScaledMult(time) / Param().tpcGeometry.Row2X(iRow) : 0.f); + float unscaledMult = (time >= 0.f ? Param().GetUnscaledMult(time) / Param().tpcGeometry.Row2X(iRow) : 0.f); const float clAlpha = Param().Alpha(cluster.slice); + unsigned int occupancyTotal = Param().occupancyTotal; o2::utils::DebugStreamer::instance()->getStreamer("debug_update_track", "UPDATE") << o2::utils::DebugStreamer::instance()->getUniqueTreeName("tree_update_track").data() << "iTrk=" << iTrk << "ihit=" << ihit @@ -376,10 +377,11 @@ void GPUTPCGMMerger::DebugStreamerUpdate(int iTrk, int ihit, float xx, float yy, << "refit=" << refit << "retVal=" << retVal << "occupancyBins=" << occupancyBins + << "occupancyTotal=" << occupancyTotal << "trackUncorrectedYZ=" << uncorrectedYZ << "avgInvCharge=" << avgInvCharge << "invCharge=" << invCharge - << "scaledMultiplicity=" << scaledMult + << "unscaledMultiplicity=" << unscaledMult << "alpha=" << clAlpha << "iRow=" << iRow << "posY=" << posY diff --git a/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.cxx b/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.cxx index ec26f927806d5..1a9f9c536565e 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMMergerGPU.cxx @@ -12,6 +12,7 @@ /// \file GPUTPCGMMergerGPU.cxx /// \author David Rohr +#if !defined(GPUCA_GPUCODE) || !defined(GPUCA_ALIROOT_LIB) // GPU Merger was not available for Run 2 #include "GPUTPCGMMergerGPU.h" #include "GPUCommonAlgorithm.h" #if defined(WITH_OPENMP) && !defined(GPUCA_GPUCODE) @@ -217,3 +218,4 @@ GPUdii() void GPUTPCGMMergerMergeLoopers::Thread<2>(int nBlocks, int nThreads, i { merger.MergeLoopersMain(nBlocks, nThreads, iBlock, iThread); } +#endif // !defined(GPUCA_GPUCODE) || !defined(GPUCA_ALIROOT_LIB) diff --git a/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx b/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx index 066fac4bf2d89..616a6b70b435a 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMO2Output.cxx @@ -102,9 +102,8 @@ struct GPUTPCGMO2OutputSort_comp { }; template <> -void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal(krnlSetup& _xyz) +inline void GPUCA_KRNL_BACKEND_CLASS::runKernelBackendInternal(const krnlSetupTime& _xyz) { - GPUDebugTiming timer(mProcessingSettings.debugLevel, nullptr, mInternals->Streams, _xyz, this); thrust::device_ptr trackSort(mProcessorsShadow->tpcMerger.TrackSortO2()); ThrustVolatileAsyncAllocator alloc(this); thrust::sort(GPUCA_THRUST_NAMESPACE::par(alloc).on(mInternals->Streams[_xyz.x.stream]), trackSort, trackSort + processors()->tpcMerger.NOutputTracksTPCO2(), GPUTPCGMO2OutputSort_comp()); diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx index 4ea7302494554..2362213d52fb0 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.cxx @@ -603,18 +603,21 @@ GPUd() void GPUTPCGMPropagator::GetErr2(float& GPUrestrict() err2Y, float& GPUre GetErr2(err2Y, err2Z, param, mT0.GetSinPhi(), mT0.DzDs(), posZ, mT->GetX(), mT->GetY(), iRow, clusterState, sector, time, avgCharge, charge, mSeedingErrors); } -GPUd() void GPUTPCGMPropagator::GetErr2(float& GPUrestrict() err2Y, float& GPUrestrict() err2Z, const GPUParam& GPUrestrict() param, float snp, float tgl, float posZ, float x, float y, int iRow, short clusterState, char sector, float time, float avgCharge, float charge, bool seedingErrors) +GPUd() void GPUTPCGMPropagator::GetErr2(float& GPUrestrict() err2Y, float& GPUrestrict() err2Z, const GPUParam& GPUrestrict() param, float snp, float tgl, float posZ, float trackX, float trackY, int iRow, short clusterState, char sector, float time, float avgCharge, float charge, bool seedingErrors) { #ifndef GPUCA_TPC_GEOMETRY_O2 if (seedingErrors) { - param.GetClusterErrorsSeeding2(sector, iRow, posZ, snp, tgl, time, avgCharge, charge, err2Y, err2Z); + param.GetClusterErrorsSeeding2(sector, iRow, posZ, snp, tgl, time, err2Y, err2Z); } else #endif { param.GetClusterErrors2(sector, iRow, posZ, snp, tgl, time, avgCharge, charge, err2Y, err2Z); } param.UpdateClusterError2ByState(clusterState, err2Y, err2Z); - float statErr2 = param.GetSystematicClusterErrorIFC2(x, y, posZ, sector >= (GPUCA_NSLICES / 2)); + float statErr2 = param.GetSystematicClusterErrorIFC2(trackX, trackY, posZ, sector >= (GPUCA_NSLICES / 2)); + if (sector >= GPUCA_NSLICES / 2 + 1 && sector <= GPUCA_NSLICES / 2 + 2) { + statErr2 += param.GetSystematicClusterErrorC122(trackX, trackY, sector); + } err2Y += statErr2; err2Z += statErr2; } @@ -657,14 +660,14 @@ GPUd() int GPUTPCGMPropagator::Update(float posY, float posZ, int iRow, const GP { float err2Y, err2Z; GetErr2(err2Y, err2Z, param, posZ, iRow, clusterState, sector, time, avgInvCharge, invCharge); - GPUCA_DEBUG_STREAMER_CHECK(debugVals->err2Y = err2Y; debugVals->err2Z = err2Z;); + GPUCA_DEBUG_STREAMER_CHECK(if (debugVals) { debugVals->err2Y = err2Y; debugVals->err2Z = err2Z; }); if (rejectChi2 >= rejectInterFill) { if (rejectChi2 == rejectInterReject && inter->errorY < (GPUCA_MERGER_INTERPOLATION_ERROR_TYPE)0) { rejectChi2 = rejectDirect; } else { int retVal = InterpolateReject(param, posY, posZ, clusterState, rejectChi2, inter, err2Y, err2Z); - GPUCA_DEBUG_STREAMER_CHECK(debugVals->retVal = retVal;); + GPUCA_DEBUG_STREAMER_CHECK(if (debugVals) { debugVals->retVal = retVal; }); if (retVal) { return retVal; } diff --git a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h index 615e90a0d524a..f84e6fa413e31 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h +++ b/GPU/GPUTracking/Merger/GPUTPCGMPropagator.h @@ -142,7 +142,7 @@ class GPUTPCGMPropagator GPUd() void GetBxByBz(float Alpha, float X, float Y, float Z, float B[3]) const; GPUd() void GetErr2(float& err2Y, float& err2Z, const GPUParam& param, float posZ, int iRow, short clusterState, char sector, float time, float avgCharge, float charge) const; - GPUd() static void GetErr2(float& err2Y, float& err2Z, const GPUParam& param, float snp, float tgl, float posZ, float x, float y, int iRow, short clusterState, char sector, float time, float avgCharge, float charge, bool seedingErrors); + GPUd() static void GetErr2(float& err2Y, float& err2Z, const GPUParam& param, float snp, float tgl, float posZ, float trackX, float trackY, int iRow, short clusterState, char sector, float time, float avgCharge, float charge, bool seedingErrors); GPUd() float GetAlpha() const { return mAlpha; } GPUd() void SetAlpha(float v) { mAlpha = v; } diff --git a/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.cxx b/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.cxx index c05c42b45b823..b6f2c72a209e0 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMSliceTrack.cxx @@ -118,7 +118,7 @@ GPUd() bool GPUTPCGMSliceTrack::FilterErrors(const GPUTPCGMMerger* merger, int i const int N = 3; - float bz = -merger->Param().constBz; + float bz = -merger->Param().bzCLight; float k = mParam.mQPt * bz; float dx = (1.f / N) * (lastX - mParam.mX); @@ -130,7 +130,7 @@ GPUd() bool GPUTPCGMSliceTrack::FilterErrors(const GPUTPCGMMerger* merger, int i merger->Param().GetClusterErrors2(iSlice, 0, mParam.mZ, mParam.mSinPhi, mParam.mDzDs, -1.f, 0.f, 0.f, mParam.mC0, mParam.mC2); // TODO: provide correct time and row #ifndef GPUCA_TPC_GEOMETRY_O2 float C0a, C2a; - merger->Param().GetClusterErrorsSeeding2(iSlice, 0, mParam.mZ, mParam.mSinPhi, mParam.mDzDs, -1.f, 0.f, 0.f, C0a, C2a); + merger->Param().GetClusterErrorsSeeding2(iSlice, 0, mParam.mZ, mParam.mSinPhi, mParam.mDzDs, -1.f, C0a, C2a); if (C0a > mParam.mC0) { mParam.mC0 = C0a; } @@ -190,7 +190,7 @@ GPUd() bool GPUTPCGMSliceTrack::FilterErrors(const GPUTPCGMMerger* merger, int i merger->Param().GetClusterErrors2(iSlice, 0, mParam.mZ, mParam.mSinPhi, mParam.mDzDs, -1.f, 0.f, 0.f, err2Y, err2Z); // TODO: Provide correct time / row #ifndef GPUCA_TPC_GEOMETRY_O2 float C0a, C2a; - merger->Param().GetClusterErrorsSeeding2(iSlice, 0, mParam.mZ, mParam.mSinPhi, mParam.mDzDs, -1.f, 0.f, 0.f, C0a, C2a); + merger->Param().GetClusterErrorsSeeding2(iSlice, 0, mParam.mZ, mParam.mSinPhi, mParam.mDzDs, -1.f, C0a, C2a); if (C0a > err2Y) { err2Y = C0a; } diff --git a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx index b33f8ca852b7a..5473814610be0 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGMTrackParam.cxx @@ -57,11 +57,11 @@ using namespace GPUCA_NAMESPACE::gpu; using namespace o2::tpc; -static constexpr float kDeg2Rad = M_PI / 180.f; -static constexpr float kSectAngle = 2 * M_PI / 18.f; - GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iTrk, GPUTPCGMMergedTrackHit* GPUrestrict() clusters, GPUTPCGMMergedTrackHitXYZ* GPUrestrict() clustersXYZ, int& GPUrestrict() N, int& GPUrestrict() NTolerated, float& GPUrestrict() Alpha, int attempt, float maxSinPhi, gputpcgmmergertypes::GPUTPCOuterParam* GPUrestrict() outerParam) { + static constexpr float kDeg2Rad = M_PI / 180.f; + CADEBUG(static constexpr float kSectAngle = 2 * M_PI / 18.f); + const GPUParam& GPUrestrict() param = merger->Param(); GPUdEdx dEdx; @@ -323,7 +323,7 @@ GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iT } #endif GPUCA_DEBUG_STREAMER_CHECK(GPUTPCGMPropagator::DebugStreamerVals debugVals;); - if (merger->Param().rec.tpc.rejectEdgeClustersInTrackFit && uncorrectedY > -1e6f && merger->Param().rejectEdgeClusterByY(uncorrectedY, cluster.row)) { // uncorrectedY > -1e6f implies allowModification + if (merger->Param().rec.tpc.rejectEdgeClustersInTrackFit && uncorrectedY > -1e6f && merger->Param().rejectEdgeClusterByY(uncorrectedY, cluster.row, CAMath::Sqrt(mC[0]))) { // uncorrectedY > -1e6f implies allowModification retVal = GPUTPCGMPropagator::updateErrorEdgeCluster; } else { const float time = merger->GetConstantMem()->ioPtrs.clustersNative ? merger->GetConstantMem()->ioPtrs.clustersNative->clustersLinear[cluster.num].getTime() : -1.f; @@ -425,6 +425,9 @@ GPUd() bool GPUTPCGMTrackParam::Fit(GPUTPCGMMerger* GPUrestrict() merger, int iT GPUdni() void GPUTPCGMTrackParam::MoveToReference(GPUTPCGMPropagator& prop, const GPUParam& param, float& Alpha) { + static constexpr float kDeg2Rad = M_PI / 180.f; + static constexpr float kSectAngle = 2 * M_PI / 18.f; + if (param.rec.tpc.trackReferenceX <= 500) { GPUTPCGMTrackParam save = *this; float saveAlpha = Alpha; @@ -635,6 +638,7 @@ GPUd() float GPUTPCGMTrackParam::AttachClusters(const GPUTPCGMMerger* GPUrestric GPUd() bool GPUTPCGMTrackParam::AttachClustersPropagate(const GPUTPCGMMerger* GPUrestrict() Merger, int slice, int lastRow, int toRow, int iTrack, bool goodLeg, GPUTPCGMPropagator& GPUrestrict() prop, bool inFlyDirection, float maxSinPhi, bool dodEdx) { + static constexpr float kSectAngle = 2 * M_PI / 18.f; if (Merger->Param().rec.tpc.disableRefitAttachment & 2) { return dodEdx; } @@ -735,6 +739,7 @@ GPUdii() void GPUTPCGMTrackParam::RefitLoop(const GPUTPCGMMerger* GPUrestrict() template GPUdic(0, 1) int GPUTPCGMTrackParam::FollowCircle(const GPUTPCGMMerger* GPUrestrict() Merger, GPUTPCGMPropagator& GPUrestrict() prop, int slice, int iRow, int iTrack, float toAlpha, float toX, float toY, int toSlice, int toRow, bool inFlyDirection, bool phase2) { + static constexpr float kSectAngle = 2 * M_PI / 18.f; if (Merger->Param().rec.tpc.disableRefitAttachment & 4) { return 1; } @@ -838,6 +843,8 @@ GPUdic(0, 1) int GPUTPCGMTrackParam::FollowCircle(const GPUTPCGMMerger* GPUrestr template GPUdni() void GPUTPCGMTrackParam::AttachClustersMirror(const GPUTPCGMMerger* GPUrestrict() Merger, int slice, int iRow, int iTrack, float toY, GPUTPCGMPropagator& GPUrestrict() prop, bool phase2) { + static constexpr float kSectAngle = 2 * M_PI / 18.f; + if (Merger->Param().rec.tpc.disableRefitAttachment & 8) { return; } diff --git a/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.cxx b/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.cxx index 52a498299892f..cc6e7b5f81efc 100644 --- a/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.cxx +++ b/GPU/GPUTracking/Merger/GPUTPCGlobalMergerComponent.cxx @@ -294,7 +294,7 @@ int GPUTPCGlobalMergerComponent::Configure(const char* cdbEntry, const char* cha GPUSettingsGRP grp; GPUSettingsRec rec; GPUSettingsProcessing devProc; - grp.solenoidBz = fSolenoidBz; + grp.solenoidBzNominalGPU = fSolenoidBz; if (fClusterErrorCorrectionY > 1.e-4) { rec.tpc.clusterError2CorrectionY = fClusterErrorCorrectionY * fClusterErrorCorrectionY; } diff --git a/GPU/GPUTracking/Merger/macros/checkPropagation.C b/GPU/GPUTracking/Merger/macros/checkPropagation.C index 052eda76484c3..bdceb8fde999f 100644 --- a/GPU/GPUTracking/Merger/macros/checkPropagation.C +++ b/GPU/GPUTracking/Merger/macros/checkPropagation.C @@ -66,8 +66,8 @@ int checkPropagation() for (int i = 0; i < 3; i++) { char* s = i == 0 ? "X" : (i == 1 ? "Y" : "Z"); char name[1024], title[1024]; - sprintf(name, "hDiff%s", s); - sprintf(title, "Propagation Difference in %s", s); + snprintf(name, 1024, "hDiff%s", s); + snprintf(title, 1024, "Propagation Difference in %s", s); hDiff[i] = new TH1F(name, title, 1000, -20., 20.); hDiff[i]->GetXaxis()->SetTitle("Propagation difference [um]"); } diff --git a/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx b/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx index 0d8198db95fd3..6f8450385ea54 100644 --- a/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx +++ b/GPU/GPUTracking/Refit/GPUTrackingRefit.cxx @@ -249,8 +249,12 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) int lastSector = -1, currentSector = -1, currentRow = -1; short clusterState = 0, nextState = 0; int nFitted = 0; + float sumInvSqrtCharge = 0.f; + int nAvgCharge = 0; + for (int i = start; i != stop; i += cl ? 0 : direction) { float x = 0, y = 0, z = 0, charge = 0; // FIXME: initialization unneeded, but GCC incorrectly produces uninitialized warnings otherwise + float time = 0.f, invCharge = 0.f, invSqrtCharge = 0.f; // Same here... int clusters = 0; while (true) { if (!cl) { @@ -292,6 +296,9 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) currentSector = sector; charge = cl->qTot; clusterState = nextState; + time = cl->getTime(); + invSqrtCharge = CAMath::InvSqrt(cl->qMax); + invCharge = (1.f / cl->qMax); } else { float xx, yy, zz; mPfastTransformHelper->Transform(sector, row, cl->getPad(), cl->getTime(), xx, yy, zz, tOffset); @@ -320,6 +327,9 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) CADEBUG(printf("\tMerged Hit Row %3d: Cluster Alpha %8.3f %3d, X %8.3f - Y %8.3f, Z %8.3f - State %d\n", row, mPparam->Alpha(sector), (int)sector, x, y, z, (int)clusterState)); } + float invAvgCharge = (sumInvSqrtCharge += invSqrtCharge) / ++nAvgCharge; + invAvgCharge *= invAvgCharge; + if constexpr (std::is_same_v) { if (prop.PropagateToXAlpha(x, mPparam->Alpha(currentSector), !outward)) { IgnoreErrors(trk.GetSinPhi()); @@ -341,7 +351,7 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) } CADEBUG(printf("\t%21sPropaga Alpha %8.3f , X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f (%7.2f), SP %5.2f (%5.2f) --- Res %8.3f %8.3f --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f - YPt %8.3f\n", "", prop.GetAlpha(), x, trk.Par()[0], trk.Par()[1], trk.Par()[4], prop.GetQPt0(), trk.Par()[2], prop.GetSinPhi0(), trk.Par()[0] - y, trk.Par()[1] - z, sqrtf(trk.Cov()[0]), sqrtf(trk.Cov()[2]), sqrtf(trk.Cov()[5]), sqrtf(trk.Cov()[14]), trk.Cov()[10])); lastSector = sector; - if (prop.Update(y, z, row, *mPparam, clusterState, 0, nullptr, true, sector, -1.f, 0.f, 0.f)) { // TODO: Use correct time, avgCharge + if (prop.Update(y, z, row, *mPparam, clusterState, 0, nullptr, true, sector, time, invAvgCharge, invCharge)) { IgnoreErrors(trk.GetSinPhi()); return -3; } @@ -374,7 +384,7 @@ GPUd() int GPUTrackingRefit::RefitTrack(T& trkX, bool outward, bool resetCov) CADEBUG(printf("\t%21sPropaga Alpha %8.3f , X %8.3f - Y %8.3f, Z %8.3f - QPt %7.2f (%7.2f), SP %5.2f (%5.2f) --- Res %8.3f %8.3f --- Cov sY %8.3f sZ %8.3f sSP %8.3f sPt %8.3f - YPt %8.3f\n", "", trk.getAlpha(), x, trk.getParams()[0], trk.getParams()[1], trk.getParams()[4], trk.getParams()[4], trk.getParams()[2], trk.getParams()[2], trk.getParams()[0] - y, trk.getParams()[1] - z, sqrtf(trk.getCov()[0]), sqrtf(trk.getCov()[2]), sqrtf(trk.getCov()[5]), sqrtf(trk.getCov()[14]), trk.getCov()[10])); gpu::gpustd::array p = {y, z}; gpu::gpustd::array c = {0, 0, 0}; - GPUTPCGMPropagator::GetErr2(c[0], c[2], *mPparam, getPar(trk)[2], getPar(trk)[3], z, x, y, currentRow, clusterState, sector, -1.f, 0.f, 0.f, false); // Use correct time / avergage cluster charge + GPUTPCGMPropagator::GetErr2(c[0], c[2], *mPparam, getPar(trk)[2], getPar(trk)[3], z, x, y, currentRow, clusterState, sector, time, invAvgCharge, invCharge, false); TrackParCovChi2 += trk.getPredictedChi2(p, c); if (!trk.update(p, c)) { IgnoreErrors(trk.getSnp()); @@ -429,9 +439,4 @@ void GPUTrackingRefit::SetPtrsFromGPUConstantMem(const GPUConstantMem* v, MEM_CO mPmatLUT = v->calibObjects.matLUT; mPparam = p ? p : &v->param; } - -void GPUTrackingRefit::SetPropagatorDefault() -{ - mPpropagator = mPparam->GetDefaultO2Propagator(false); -} #endif diff --git a/GPU/GPUTracking/Refit/GPUTrackingRefit.h b/GPU/GPUTracking/Refit/GPUTrackingRefit.h index 3bd169ef57ded..ece3444668c07 100644 --- a/GPU/GPUTracking/Refit/GPUTrackingRefit.h +++ b/GPU/GPUTracking/Refit/GPUTrackingRefit.h @@ -63,7 +63,6 @@ class GPUTrackingRefit void SetClusterStateArray(const unsigned char* v) { mPclusterState = v; } void SetPtrsFromGPUConstantMem(const GPUConstantMem* v, MEM_CONSTANT(GPUParam) * p = nullptr); void SetPropagator(const o2::base::Propagator* v) { mPpropagator = v; } - void SetPropagatorDefault(); void SetClusterNative(const o2::tpc::ClusterNativeAccess* v) { mPclusterNative = v; } void SetTrackHits(const GPUTPCGMMergedTrackHit* v) { mPtrackHits = v; } void SetTrackHitReferences(const unsigned int* v) { mPtrackHitReferences = v; } diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx index 72e60673c68c5..9ce30210b975a 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCGlobalTracking.cxx @@ -51,7 +51,7 @@ GPUd() int GPUTPCGlobalTracking::PerformGlobalTrackingRun(GPUTPCTracker& tracker GPUTPCTrackLinearisation t0(tParam); do { rowIndex += direction; - if (!tParam.TransportToX(tracker.Row(rowIndex).X(), t0, tracker.Param().constBz, GPUCA_MAX_SIN_PHI)) { + if (!tParam.TransportToX(tracker.Row(rowIndex).X(), t0, tracker.Param().bzCLight, GPUCA_MAX_SIN_PHI)) { return 0; // Reuse t0 linearization until we are in the next sector } // GPUInfo("Transported X %f Y %f Z %f SinPhi %f DzDs %f QPt %f SignCosPhi %f (MaxY %f)", tParam.X(), tParam.Y(), tParam.Z(), tParam.SinPhi(), tParam.DzDs(), tParam.QPt(), tParam.SignCosPhi(), Row(rowIndex).MaxY()); @@ -61,7 +61,7 @@ GPUd() int GPUTPCGlobalTracking::PerformGlobalTrackingRun(GPUTPCTracker& tracker } while (CAMath::Abs(tParam.Y()) > tracker.Row(rowIndex).MaxY()); float err2Y, err2Z; - tracker.GetErrors2Seeding(rowIndex, tParam.Z(), tParam.SinPhi(), tParam.DzDs(), -1.f, 0.f, 0.f, err2Y, err2Z); // TODO: Use correct time for multiplicity part of error estimation + tracker.GetErrors2Seeding(rowIndex, tParam.Z(), tParam.SinPhi(), tParam.DzDs(), -1.f, err2Y, err2Z); // TODO: Use correct time for multiplicity part of error estimation if (tParam.GetCov(0) < err2Y) { tParam.SetCov(0, err2Y); } @@ -93,7 +93,7 @@ GPUd() int GPUTPCGlobalTracking::PerformGlobalTrackingRun(GPUTPCTracker& tracker if (rowHit != CALINK_INVAL && rowHit != CALINK_DEAD_CHANNEL) { // GPUInfo("New track: entry %d, row %d, hitindex %d", i, rowIndex, mTrackletRowHits[rowIndex * tracker.CommonMemory()->nTracklets]); tracker.TrackHits()[hitId + i].Set(rowIndex, rowHit); - // if (i == 0) tParam.TransportToX(Row(rowIndex).X(), Param().constBz(), GPUCA_MAX_SIN_PHI); //Use transport with new linearisation, we have changed the track in between - NOT needed, fitting will always start at outer end of global track! + // if (i == 0) tParam.TransportToX(Row(rowIndex).X(), Param().bzCLight(), GPUCA_MAX_SIN_PHI); //Use transport with new linearisation, we have changed the track in between - NOT needed, fitting will always start at outer end of global track! i++; } rowIndex++; diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTracker.h b/GPU/GPUTracking/SliceTracker/GPUTPCTracker.h index c02ae069e0115..9e35800d13517 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTracker.h +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTracker.h @@ -108,22 +108,22 @@ class GPUTPCTracker : public GPUProcessor } MEM_CLASS_PRE2() - GPUdi() static void GetErrors2Seeding(const MEM_CONSTANT(GPUParam) & param, char sector, int iRow, const MEM_LG2(GPUTPCTrackParam) & t, float time, float avgCharge, float charge, float& ErrY2, float& ErrZ2) + GPUdi() static void GetErrors2Seeding(const MEM_CONSTANT(GPUParam) & param, char sector, int iRow, const MEM_LG2(GPUTPCTrackParam) & t, float time, float& ErrY2, float& ErrZ2) { - // param.GetClusterErrors2(sector, iRow, param.GetContinuousTracking() != 0. ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), time, avgCharge, ErrY2, ErrZ2); - param.GetClusterErrorsSeeding2(sector, iRow, param.par.continuousTracking != 0.f ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), time, avgCharge, charge, ErrY2, ErrZ2); + // param.GetClusterErrors2(sector, iRow, param.GetContinuousTracking() != 0. ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), time, 0.f, 0.f, ErrY2, ErrZ2); + param.GetClusterErrorsSeeding2(sector, iRow, param.par.continuousTracking != 0.f ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), time, ErrY2, ErrZ2); } MEM_CLASS_PRE2() - GPUdi() void GetErrors2Seeding(int iRow, const MEM_LG2(GPUTPCTrackParam) & t, float time, float avgCharge, float charge, float& ErrY2, float& ErrZ2) const + GPUdi() void GetErrors2Seeding(int iRow, const MEM_LG2(GPUTPCTrackParam) & t, float time, float& ErrY2, float& ErrZ2) const { - // Param().GetClusterErrors2(mISlice, iRow, Param().GetContinuousTracking() != 0. ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), time, avgCharge, ErrY2, ErrZ2); - Param().GetClusterErrorsSeeding2(mISlice, iRow, Param().par.continuousTracking != 0.f ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), time, avgCharge, charge, ErrY2, ErrZ2); + // Param().GetClusterErrors2(mISlice, iRow, Param().GetContinuousTracking() != 0. ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), time, 0.f, 0.f, ErrY2, ErrZ2); + Param().GetClusterErrorsSeeding2(mISlice, iRow, Param().par.continuousTracking != 0.f ? 125.f : t.Z(), t.SinPhi(), t.DzDs(), time, ErrY2, ErrZ2); } - GPUdi() void GetErrors2Seeding(int iRow, float z, float sinPhi, float DzDs, float time, float avgCharge, float charge, float& ErrY2, float& ErrZ2) const + GPUdi() void GetErrors2Seeding(int iRow, float z, float sinPhi, float DzDs, float time, float& ErrY2, float& ErrZ2) const { - // Param().GetClusterErrors2(mISlice, iRow, Param().GetContinuousTracking() != 0. ? 125.f : z, sinPhi, DzDs, time, avgCharge, ErrY2, ErrZ2); - Param().GetClusterErrorsSeeding2(mISlice, iRow, Param().par.continuousTracking != 0.f ? 125.f : z, sinPhi, DzDs, time, avgCharge, charge, ErrY2, ErrZ2); + // Param().GetClusterErrors2(mISlice, iRow, Param().GetContinuousTracking() != 0. ? 125.f : z, sinPhi, DzDs, time, 0.f, 0.f, ErrY2, ErrZ2); + Param().GetClusterErrorsSeeding2(mISlice, iRow, Param().par.continuousTracking != 0.f ? 125.f : z, sinPhi, DzDs, time, ErrY2, ErrZ2); } void SetupCommonMemory(); diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.cxx index b86e576641b15..7b62a43a7c627 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackerComponent.cxx @@ -373,7 +373,7 @@ int GPUTPCTrackerComponent::ConfigureSlices() GPUSettingsGRP grp; GPUSettingsProcessing devProc; - grp.solenoidBz = fSolenoidBz; + grp.solenoidBzNominalGPU = fSolenoidBz; grp.continuousMaxTimeBin = 0; // triggered events if (mNeighboursSearchArea > 0) { rec.tpc.neighboursSearchArea = mNeighboursSearchArea; diff --git a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx index 871022aa3c615..79623c6f66c32 100644 --- a/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx +++ b/GPU/GPUTracking/SliceTracker/GPUTPCTrackletConstructor.cxx @@ -183,7 +183,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int tParam.SetSignCosPhi(dx); tParam.SetDzDs(dz * ri); float err2Y, err2Z; - tracker.GetErrors2Seeding(iRow, tParam, -1.f, 0.f, 0.f, err2Y, err2Z); // Use correct time + tracker.GetErrors2Seeding(iRow, tParam, -1.f, err2Y, err2Z); // Use correct time tParam.SetCov(0, err2Y); tParam.SetCov(2, err2Z); } @@ -196,13 +196,13 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int cosPhi = dx * ri; } CADEBUG(printf("%14s: FIT TRACK ROW %3d X %8.3f -", "", iRow, tParam.X()); for (int i = 0; i < 5; i++) { printf(" %8.3f", tParam.Par()[i]); } printf(" -"); for (int i = 0; i < 15; i++) { printf(" %8.3f", tParam.Cov()[i]); } printf("\n")); - if (!tParam.TransportToX(x, sinPhi, cosPhi, tracker.Param().constBz, GPUCA_MAX_SIN_PHI)) { + if (!tParam.TransportToX(x, sinPhi, cosPhi, tracker.Param().bzCLight, GPUCA_MAX_SIN_PHI)) { rowHit = CALINK_INVAL; break; } CADEBUG(printf("%5s hits %3d: FIT PROP ROW %3d X %8.3f -", "", r.mNHits, iRow, tParam.X()); for (int i = 0; i < 5; i++) { printf(" %8.3f", tParam.Par()[i]); } printf(" -"); for (int i = 0; i < 15; i++) { printf(" %8.3f", tParam.Cov()[i]); } printf("\n")); float err2Y, err2Z; - tracker.GetErrors2Seeding(iRow, tParam.GetZ(), sinPhi, tParam.GetDzDs(), -1.f, 0.f, 0.f, err2Y, err2Z); // TODO: Use correct time + tracker.GetErrors2Seeding(iRow, tParam.GetZ(), sinPhi, tParam.GetDzDs(), -1.f, err2Y, err2Z); // TODO: Use correct time if (r.mNHits >= 10) { const float sErr2 = tracker.Param().GetSystematicClusterErrorIFC2(x, tParam.GetY(), tParam.GetZ(), tracker.ISlice() >= 18); @@ -269,7 +269,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int #if !defined(__OPENCL__) || defined(__OPENCLCPP__) { float tmpY, tmpZ; - if (!tParam.GetPropagatedYZ(tracker.Param().constBz, x, tmpY, tmpZ)) { + if (!tParam.GetPropagatedYZ(tracker.Param().bzCLight, x, tmpY, tmpZ)) { r.mGo = 0; rowHit = CALINK_INVAL; break; @@ -280,7 +280,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int #endif CADEBUG(printf("%14s: SEA TRACK ROW %3d X %8.3f -", "", iRow, tParam.X()); for (int i = 0; i < 5; i++) { printf(" %8.3f", tParam.Par()[i]); } printf(" -"); for (int i = 0; i < 15; i++) { printf(" %8.3f", tParam.Cov()[i]); } printf("\n")); - if (!tParam.TransportToX(x, tParam.SinPhi(), tParam.GetCosPhi(), tracker.Param().constBz, GPUCA_MAX_SIN_PHI_LOW)) { + if (!tParam.TransportToX(x, tParam.SinPhi(), tParam.GetCosPhi(), tracker.Param().bzCLight, GPUCA_MAX_SIN_PHI_LOW)) { r.mGo = 0; rowHit = CALINK_INVAL; break; @@ -303,14 +303,14 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int tracker.GetConstantMem()->calibObjects.fastTransformHelper->InverseTransformYZtoNominalYZ(tracker.ISlice(), iRow, yUncorrected, zUncorrected, yUncorrected, zUncorrected); #endif - if (tracker.Param().rec.tpc.rejectEdgeClustersInSeeding && tracker.Param().rejectEdgeClusterByY(yUncorrected, iRow)) { + if (tracker.Param().rec.tpc.rejectEdgeClustersInSeeding && tracker.Param().rejectEdgeClusterByY(yUncorrected, iRow, CAMath::Sqrt(tParam.Err2Y()))) { rowHit = CALINK_INVAL; break; } calink best = CALINK_INVAL; float err2Y, err2Z; - tracker.GetErrors2Seeding(iRow, *((MEM_LG2(GPUTPCTrackParam)*)&tParam), -1.f, 0.f, 0.f, err2Y, err2Z); // TODO: Use correct time + tracker.GetErrors2Seeding(iRow, *((MEM_LG2(GPUTPCTrackParam)*)&tParam), -1.f, err2Y, err2Z); // TODO: Use correct time if (r.mNHits >= 10) { const float sErr2 = tracker.Param().GetSystematicClusterErrorIFC2(x, tParam.GetY(), tParam.GetZ(), tracker.ISlice() >= 18); err2Y += sErr2; @@ -412,7 +412,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::UpdateTracklet(int /*nBlocks*/, int const float z1 = row1.Grid().ZMin() + hh1.y * row1.HstepZ(); const float z2 = row2.Grid().ZMin() + hh2.y * row2.HstepZ(); float oldOffset = tParam.ZOffset(); - tParam.ShiftZ(z1, z2, tracker.Param().tpcGeometry.Row2X(r.mFirstRow), tracker.Param().tpcGeometry.Row2X(r.mLastRow), tracker.Param().constBz, tracker.Param().rec.tpc.defaultZOffsetOverR); + tParam.ShiftZ(z1, z2, tracker.Param().tpcGeometry.Row2X(r.mFirstRow), tracker.Param().tpcGeometry.Row2X(r.mLastRow), tracker.Param().bzCLight, tracker.Param().rec.tpc.defaultZOffsetOverR); r.mLastZ -= tParam.ZOffset() - oldOffset; CADEBUG(printf("Shifted z from %f to %f\n", oldOffset, tParam.ZOffset())); } @@ -464,7 +464,7 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::DoTracklet(GPUconstantref() MEM_GLO #if !defined(__OPENCL__) || defined(__OPENCLCPP__) { float tmpY, tmpZ; - if (tParam.GetPropagatedYZ(tracker.Param().constBz, x, tmpY, tmpZ)) { + if (tParam.GetPropagatedYZ(tracker.Param().bzCLight, x, tmpY, tmpZ)) { if (tracker.ISlice() < GPUCA_NSLICES / 2 ? (tmpZ < 0) : (tmpZ > 0)) { tmpZ = 0; } else if (tracker.ISlice() < GPUCA_NSLICES / 2 ? (tmpZ > GPUTPCGeometry::TPCLength()) : (tmpZ < -GPUTPCGeometry::TPCLength())) { @@ -477,10 +477,10 @@ GPUdic(2, 1) void GPUTPCTrackletConstructor::DoTracklet(GPUconstantref() MEM_GLO } } #endif - if ((r.mGo = (tParam.TransportToX(x, tracker.Param().constBz, GPUCA_MAX_SIN_PHI) && tParam.Filter(r.mLastY, r.mLastZ, tParam.Err2Y() * 0.5f, tParam.Err2Z() * 0.5f, GPUCA_MAX_SIN_PHI_LOW, true)))) { + if ((r.mGo = (tParam.TransportToX(x, tracker.Param().bzCLight, GPUCA_MAX_SIN_PHI) && tParam.Filter(r.mLastY, r.mLastZ, tParam.Err2Y() * 0.5f, tParam.Err2Z() * 0.5f, GPUCA_MAX_SIN_PHI_LOW, true)))) { CADEBUG(printf("%14s: SEA BACK ROW %3d X %8.3f -", "", iRow, tParam.X()); for (int i = 0; i < 5; i++) { printf(" %8.3f", tParam.Par()[i]); } printf(" -"); for (int i = 0; i < 15; i++) { printf(" %8.3f", tParam.Cov()[i]); } printf("\n")); float err2Y, err2Z; - tracker.GetErrors2Seeding(r.mEndRow, tParam, -1.f, 0.f, 0.f, err2Y, err2Z); // TODO: Use correct time + tracker.GetErrors2Seeding(r.mEndRow, tParam, -1.f, err2Y, err2Z); // TODO: Use correct time if (tParam.GetCov(0) < err2Y) { tParam.SetCov(0, err2Y); } diff --git a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx index 17d99bf1d9fe5..92199f06a5f68 100644 --- a/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx +++ b/GPU/GPUTracking/Standalone/Benchmark/standalone.cxx @@ -282,7 +282,7 @@ int SetupReconstruction() printf("Error reading event config file\n"); return 1; } - printf("Read event settings from dir %s (solenoidBz: %f, home-made events %d, constBz %d, maxTimeBin %d)\n", filename, rec->GetGRPSettings().solenoidBz, (int)rec->GetGRPSettings().homemadeEvents, (int)rec->GetGRPSettings().constBz, rec->GetGRPSettings().continuousMaxTimeBin); + printf("Read event settings from dir %s (solenoidBz: %f, home-made events %d, constBz %d, maxTimeBin %d)\n", filename, rec->GetGRPSettings().solenoidBzNominalGPU, (int)rec->GetGRPSettings().homemadeEvents, (int)rec->GetGRPSettings().constBz, rec->GetGRPSettings().continuousMaxTimeBin); if (configStandalone.testSyncAsync) { recAsync->ReadSettings(filename); } @@ -297,15 +297,15 @@ int SetupReconstruction() GPUSettingsGRP grp = rec->GetGRPSettings(); GPUSettingsRec recSet; GPUSettingsProcessing procSet; - memcpy((void*)&recSet, (void*)&configStandalone.rec, sizeof(GPUSettingsRec)); - memcpy((void*)&procSet, (void*)&configStandalone.proc, sizeof(GPUSettingsProcessing)); + recSet = configStandalone.rec; + procSet = configStandalone.proc; GPURecoStepConfiguration steps; if (configStandalone.eventGenerator) { grp.homemadeEvents = true; } - if (configStandalone.solenoidBz != -1e6f) { - grp.solenoidBz = configStandalone.solenoidBz; + if (configStandalone.solenoidBzNominalGPU != -1e6f) { + grp.solenoidBzNominalGPU = configStandalone.solenoidBzNominalGPU; } if (configStandalone.constBz) { grp.constBz = true; @@ -424,11 +424,6 @@ int SetupReconstruction() } } -#ifdef GPUCA_HAVE_O2HEADERS - procSet.useInternalO2Propagator = true; - procSet.internalO2PropagatorGPUField = true; -#endif - rec->SetSettings(&grp, &recSet, &procSet, &steps); if (configStandalone.proc.doublePipeline) { recPipeline->SetSettings(&grp, &recSet, &procSet, &steps); @@ -464,6 +459,22 @@ int SetupReconstruction() } } +#ifdef GPUCA_HAVE_O2HEADERS + o2::base::Propagator* prop = nullptr; + prop = o2::base::Propagator::Instance(true); + prop->setGPUField(&rec->GetParam().polynomialField); + prop->setNominalBz(rec->GetParam().bzkG); + prop->setMatLUT(chainTracking->GetMatLUT()); + chainTracking->SetO2Propagator(prop); + if (chainTrackingAsync) { + chainTrackingAsync->SetO2Propagator(prop); + } + if (chainTrackingPipeline) { + chainTrackingPipeline->SetO2Propagator(prop); + } + procSet.o2PropagatorUseGPUField = true; +#endif + if (rec->Init()) { printf("Error initializing GPUReconstruction!\n"); return 1; @@ -852,7 +863,7 @@ int main(int argc, char** argv) } if (configStandalone.dumpEvents) { char fname[1024]; - sprintf(fname, "event.%d.dump", nEventsProcessed); + snprintf(fname, 1024, "event.%d.dump", nEventsProcessed); chainTracking->DumpData(fname); if (nEventsProcessed == 0) { rec->DumpSettings(); diff --git a/GPU/GPUTracking/Standalone/cmake/prepare.sh b/GPU/GPUTracking/Standalone/cmake/prepare.sh index 3565e2ec6dfdb..826cdb5efb56c 100755 --- a/GPU/GPUTracking/Standalone/cmake/prepare.sh +++ b/GPU/GPUTracking/Standalone/cmake/prepare.sh @@ -11,6 +11,6 @@ else fi eval "`alienv shell-helper`" alienv load O2/latest -for i in Vc boost fmt CMake ms_gsl Clang; do +for i in Vc boost fmt CMake ms_gsl Clang ninja; do source sw/$ALIARCH/$i/latest/etc/profile.d/init.sh -done \ No newline at end of file +done diff --git a/GPU/GPUTracking/Standalone/tools/testCL.sh b/GPU/GPUTracking/Standalone/tools/testCL.sh index 923070503437f..0257830d8942d 100755 --- a/GPU/GPUTracking/Standalone/tools/testCL.sh +++ b/GPU/GPUTracking/Standalone/tools/testCL.sh @@ -20,7 +20,7 @@ INCLUDES="-I${GPU_DIR}/. -I${GPU_DIR}/DataTypes -I${GPU_DIR}/Definitions -I${GPU -I${O2_DIR}/Detectors/TRD/base/include -I${O2_DIR}/Detectors/TRD/base/src -I${O2_DIR}/Detectors/ITSMFT/ITS/tracking/include -I${O2_DIR}/Detectors/ITSMFT/ITS/tracking/cuda/include -I${O2_DIR}/Common/Constants/include \ -I${O2_DIR}/DataFormats/common/include -I${O2_DIR}/DataFormats/Detectors/Common/include -I${O2_DIR}/DataFormats/Detectors/TRD/include -I${O2_DIR}/DataFormats/Reconstruction/include -I${O2_DIR}/DataFormats/Reconstruction/src \ -I${O2_DIR}/Detectors/Raw/include" -DEFINES="-DGPUCA_STANDALONE -DGPUCA_GPULIBRARY=OCL -DNDEBUG -D__OPENCLCPP__ -DGPUCA_HAVE_O2HEADERS -DGPUCA_TPC_GEOMETRY_O2" +DEFINES="-DGPUCA_STANDALONE -DNDEBUG -D__OPENCLCPP__ -DGPUCA_HAVE_O2HEADERS -DGPUCA_TPC_GEOMETRY_O2" FLAGS="-Xclang -fdenormal-fp-math-f32=ieee -cl-mad-enable -cl-no-signed-zeros -ferror-limit=1000 -Dcl_clang_storage_class_specifiers" echo Test1 - Preprocess @@ -52,4 +52,3 @@ echo clang-ocl -O3 -cl-std=clc++ -mcpu=gfx906 $FLAGS $INCLUDES $DEFINES -o test- clang-ocl -O3 -cl-std=clc++ -mcpu=gfx906 $FLAGS $INCLUDES $DEFINES -o test-clang-ocl.o ${GPU_DIR}/Base/opencl-common/GPUReconstructionOCL.cl rm -f test-clang-ocl.o.* if [ $? != 0 ]; then exit 1; fi - diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.cxx index 3fa5b2ac265eb..18fffd46d707f 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFDeconvolution.cxx @@ -50,7 +50,8 @@ GPUdii() void GPUTPCCFDeconvolution::deconvolutionImpl(int nBlocks, int nThreads ushort partId = ll; ushort in3x3 = 0; - partId = CfUtils::partition(smem, ll, iamPeak, SCRATCH_PAD_WORK_GROUP_SIZE, &in3x3); + bool exclude3x3 = iamPeak || !pos.valid(); + partId = CfUtils::partition(smem, ll, exclude3x3, SCRATCH_PAD_WORK_GROUP_SIZE, &in3x3); if (partId < in3x3) { smem.posBcast1[partId] = pos; @@ -74,7 +75,7 @@ GPUdii() void GPUTPCCFDeconvolution::deconvolutionImpl(int nBlocks, int nThreads } ushort in5x5 = 0; - partId = CfUtils::partition(smem, partId, peakCount > 0 && !iamPeak, in3x3, &in5x5); + partId = CfUtils::partition(smem, partId, peakCount > 0 && !exclude3x3, in3x3, &in5x5); if (partId < in5x5) { smem.posBcast1[partId] = pos; @@ -99,7 +100,7 @@ GPUdii() void GPUTPCCFDeconvolution::deconvolutionImpl(int nBlocks, int nThreads peakCount *= -1; } - if (iamDummy) { + if (iamDummy || !pos.valid()) { return; } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.cxx index fc8a2fcf20d4e..cc7e0daed1476 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFPeakFinder.cxx @@ -121,5 +121,7 @@ GPUd() void GPUTPCCFPeakFinder::findPeaksImpl(int nBlocks, int nThreads, int iBl isPeakPredicate[idx] = peak; - peakMap[pos] = (uchar(charge > calib.tpc.cfInnerThreshold) << 1) | peak; + if (pos.valid()) { + peakMap[pos] = (uchar(charge > calib.tpc.cfInnerThreshold) << 1) | peak; + } } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.cxx index 2477593600812..f4489146f583d 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.cxx @@ -24,106 +24,101 @@ using namespace GPUCA_NAMESPACE::gpu::tpccf; template <> GPUdii() void GPUTPCCFStreamCompaction::Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer, int iBuf, int stage) { - int nElems = compactionElems(clusterer, stage); - nativeScanUpStartImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, clusterer.mPisPeak, clusterer.mPbuf + (iBuf - 1) * clusterer.mBufSize, clusterer.mPbuf + iBuf * clusterer.mBufSize, nElems); -} + int nElems = CompactionElems(clusterer, stage); -GPUdii() void GPUTPCCFStreamCompaction::nativeScanUpStartImpl(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, - const uchar* predicate, - int* sums, - int* incr, int nElems) -{ - int idx = get_global_id(0); + const auto* predicate = clusterer.mPisPeak; + auto* scanOffset = clusterer.GetScanBuffer(iBuf); + + int iThreadGlobal = get_global_id(0); int pred = 0; - if (idx < nElems) { - pred = predicate[idx]; + if (iThreadGlobal < nElems) { + pred = predicate[iThreadGlobal]; } - int scanRes = CfUtils::blockPredicateSum(smem, pred); + int nElemsInBlock = CfUtils::blockPredicateSum(smem, pred); - int lid = get_local_id(0); - int lastItem = get_local_size(0) - 1; - int gid = get_group_id(0); - - if (lid == lastItem) { - incr[gid] = scanRes; + int lastThread = nThreads - 1; + if (iThread == lastThread) { + scanOffset[iBlock] = nElemsInBlock; } } template <> GPUdii() void GPUTPCCFStreamCompaction::Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer, int iBuf, int nElems) { - nativeScanUpImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, clusterer.mPbuf + (iBuf - 1) * clusterer.mBufSize, clusterer.mPbuf + iBuf * clusterer.mBufSize, nElems); -} - -GPUdii() void GPUTPCCFStreamCompaction::nativeScanUpImpl(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, - int* sums, - int* incr, int nElems) -{ - int idx = get_global_id(0); - int scanRes = work_group_scan_inclusive_add((idx < nElems) ? sums[idx] : 0); - - /* DBGPR_2("ScanUp: idx = %d, res = %d", idx, scanRes); */ - - sums[idx] = scanRes; + auto* scanOffset = clusterer.GetScanBuffer(iBuf - 1); + auto* scanOffsetNext = clusterer.GetScanBuffer(iBuf); - int lid = get_local_id(0); - int lastItem = get_local_size(0) - 1; - int gid = get_group_id(0); + int iThreadGlobal = get_global_id(0); + int offsetInBlock = work_group_scan_inclusive_add((iThreadGlobal < nElems) ? scanOffset[iThreadGlobal] : 0); - /* DBGPR_1("ScanUp: idx = %d", idx); */ + // TODO: This write isn't needed?? + scanOffset[iThreadGlobal] = offsetInBlock; - if (lid == lastItem) { - incr[gid] = scanRes; + int lastThread = nThreads - 1; + if (iThread == lastThread) { + scanOffsetNext[iBlock] = offsetInBlock; } } template <> GPUdii() void GPUTPCCFStreamCompaction::Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer, int iBuf, int nElems) { - nativeScanTopImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, clusterer.mPbuf + (iBuf - 1) * clusterer.mBufSize, nElems); -} + int iThreadGlobal = get_global_id(0); + int* scanOffset = clusterer.GetScanBuffer(iBuf - 1); -GPUdii() void GPUTPCCFStreamCompaction::nativeScanTopImpl(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, int* incr, int nElems) -{ - int idx = get_global_id(0); + bool inBounds = (iThreadGlobal < nElems); - /* DBGPR_1("ScanTop: idx = %d", idx); */ + int offsetInBlock = work_group_scan_inclusive_add(inBounds ? scanOffset[iThreadGlobal] : 0); - int scanRes = work_group_scan_inclusive_add((idx < nElems) ? incr[idx] : 0); - incr[idx] = scanRes; + if (inBounds) { + scanOffset[iThreadGlobal] = offsetInBlock; + } } template <> -GPUdii() void GPUTPCCFStreamCompaction::Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer, int iBuf, unsigned int offset, int nElems) +GPUdii() void GPUTPCCFStreamCompaction::Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& /*smem*/, processorType& clusterer, int iBuf, unsigned int offset, int nElems) { - nativeScanDownImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, clusterer.mPbuf + (iBuf - 1) * clusterer.mBufSize, clusterer.mPbuf + iBuf * clusterer.mBufSize, offset, nElems); -} + int iThreadGlobal = get_global_id(0) + offset; -GPUdii() void GPUTPCCFStreamCompaction::nativeScanDownImpl(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, - int* sums, - const int* incr, - unsigned int offset, int nElems) -{ - int gid = get_group_id(0); - int idx = get_global_id(0) + offset; + int* scanOffsetPrev = clusterer.GetScanBuffer(iBuf - 1); + const int* scanOffset = clusterer.GetScanBuffer(iBuf); - int shift = incr[gid]; + int shift = scanOffset[iBlock]; - if (idx < nElems) { - sums[idx] += shift; + if (iThreadGlobal < nElems) { + scanOffsetPrev[iThreadGlobal] += shift; } } template <> GPUdii() void GPUTPCCFStreamCompaction::Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer, int iBuf, int stage, ChargePos* in, ChargePos* out) { - unsigned int nElems = compactionElems(clusterer, stage); + unsigned int nElems = CompactionElems(clusterer, stage); SizeT bufferSize = (stage) ? clusterer.mNMaxClusters : clusterer.mNMaxPeaks; - compactImpl(get_num_groups(0), get_local_size(0), get_group_id(0), get_local_id(0), smem, in, out, clusterer.mPisPeak, clusterer.mPbuf + (iBuf - 1) * clusterer.mBufSize, clusterer.mPbuf + iBuf * clusterer.mBufSize, nElems, bufferSize); + + unsigned int iThreadGlobal = get_global_id(0); + + const auto* predicate = clusterer.mPisPeak; + const auto* scanOffset = clusterer.GetScanBuffer(iBuf); + + bool iAmDummy = (iThreadGlobal >= nElems); + + int pred = (iAmDummy) ? 0 : predicate[iThreadGlobal]; + int offsetInBlock = CfUtils::blockPredicateScan(smem, pred); + + SizeT globalOffsetOut = offsetInBlock; + if (iBlock > 0) { + globalOffsetOut += scanOffset[iBlock - 1]; + } + + if (pred && globalOffsetOut < bufferSize) { + out[globalOffsetOut] = in[iThreadGlobal]; + } + unsigned int lastId = get_global_size(0) - 1; - if ((unsigned int)get_global_id(0) == lastId) { - SizeT nFinal = clusterer.mPbuf[lastId]; + if (iThreadGlobal == lastId) { + SizeT nFinal = globalOffsetOut + pred; if (nFinal > bufferSize) { clusterer.raiseError(stage ? GPUErrors::ERROR_CF_CLUSTER_OVERFLOW : GPUErrors::ERROR_CF_PEAK_OVERFLOW, clusterer.mISlice, nFinal, bufferSize); nFinal = bufferSize; @@ -136,42 +131,7 @@ GPUdii() void GPUTPCCFStreamCompaction::Thread= nElems); - - int pred = (iAmDummy) ? 0 : predicate[idx]; - int scanRes = CfUtils::blockPredicateScan(smem, pred); - - SizeT compIdx = scanRes; - if (gid) { - compIdx += incr[gid - 1]; - } - - // SizeT tgtIdx = compIdx - 1; - SizeT tgtIdx = compIdx; - if (pred && tgtIdx < bufferSize) { - out[tgtIdx] = in[idx]; - } - - if (idx == lastItem) { - newIdx[idx] = compIdx; // TODO: Eventually, we can just return the last value, no need to store to memory - } -} - -GPUdii() int GPUTPCCFStreamCompaction::compactionElems(processorType& clusterer, int stage) +GPUdii() int GPUTPCCFStreamCompaction::CompactionElems(processorType& clusterer, int stage) { return (stage) ? clusterer.mPmemory->counters.nPeaks : clusterer.mPmemory->counters.nPositions; } diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h index 8a2d3034db95c..207c9075ba444 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCCFStreamCompaction.h @@ -55,24 +55,7 @@ class GPUTPCCFStreamCompaction : public GPUKernelTemplate GPUd() static void Thread(int nBlocks, int nThreads, int iBlock, int iThread, GPUSharedMemory& smem, processorType& clusterer, Args... args); private: - static GPUd() void nativeScanUpStartImpl(int, int, int, int, GPUSharedMemory&, - const uchar*, int*, int*, - int); - - static GPUd() void nativeScanUpImpl(int, int, int, int, GPUSharedMemory&, - int*, int*, int); - - static GPUd() void nativeScanTopImpl(int, int, int, int, GPUSharedMemory&, - int*, int); - - static GPUd() void nativeScanDownImpl(int, int, int, int, GPUSharedMemory&, - int*, const int*, unsigned int, int); - - static GPUd() void compactImpl(int, int, int, int, GPUSharedMemory&, - const ChargePos*, ChargePos*, - const uchar*, int*, const int*, - int, tpccf::SizeT); - static GPUd() int compactionElems(processorType& clusterer, int stage); + static GPUd() int CompactionElems(processorType& clusterer, int stage); }; } // namespace GPUCA_NAMESPACE::gpu diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h index 4cdd05802694c..ca89053797a47 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinder.h @@ -116,6 +116,8 @@ class GPUTPCClusterFinder : public GPUProcessor int* mPbuf = nullptr; Memory* mPmemory = nullptr; + GPUdi() int* GetScanBuffer(int iBuf) const { return mPbuf + iBuf * mBufSize; } + o2::dataformats::ConstMCTruthContainerView const* mPinputLabels = nullptr; unsigned int* mPlabelsInRow = nullptr; unsigned int mPlabelsHeaderGlobalOffset = 0; @@ -141,12 +143,12 @@ class GPUTPCClusterFinder : public GPUProcessor #ifndef GPUCA_GPUCODE void DumpDigits(std::ostream& out); - void DumpChargeMap(std::ostream& out, std::string_view, bool doGPU); + void DumpChargeMap(std::ostream& out, std::string_view); + void DumpPeakMap(std::ostream& out, std::string_view); void DumpPeaks(std::ostream& out); void DumpPeaksCompacted(std::ostream& out); void DumpSuppressedPeaks(std::ostream& out); void DumpSuppressedPeaksCompacted(std::ostream& out); - void DumpCountedPeaks(std::ostream& out); void DumpClusters(std::ostream& out); #endif }; diff --git a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderDump.cxx b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderDump.cxx index de8583f8cd9e7..389209d9bb884 100644 --- a/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderDump.cxx +++ b/GPU/GPUTracking/TPCClusterFinder/GPUTPCClusterFinderDump.cxx @@ -22,23 +22,29 @@ using namespace GPUCA_NAMESPACE::gpu::tpccf; void GPUTPCClusterFinder::DumpDigits(std::ostream& out) { - out << "\nClusterer - Digits - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << mPmemory->counters.nPositions << "\n"; + const auto nPositions = mPmemory->counters.nPositions; + + out << "\nClusterer - Digits - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << nPositions << "\n"; out << std::hex; for (size_t i = 0; i < mPmemory->counters.nPositions; i++) { - out << mPpositions[i].time() << " " << mPpositions[i].gpad << '\n'; + const auto& pos = mPpositions[i]; + out << pos.time() << " " << pos.gpad << '\n'; } out << std::dec; } -void GPUTPCClusterFinder::DumpChargeMap(std::ostream& out, std::string_view title, bool doGPU) +void GPUTPCClusterFinder::DumpChargeMap(std::ostream& out, std::string_view title) { out << "\nClusterer - " << title << " - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; Array2D map(mPchargeMap); out << std::hex; - for (TPCFragmentTime i = 0; i < TPC_MAX_FRAGMENT_LEN_PADDED(mRec->GetProcessingSettings().overrideClusterizerFragmentLen); i++) { + TPCFragmentTime start = 0; + TPCFragmentTime end = TPC_MAX_FRAGMENT_LEN_PADDED(mRec->GetProcessingSettings().overrideClusterizerFragmentLen); + + for (TPCFragmentTime i = start; i < end; i++) { int zeros = 0; for (GlobalPad j = 0; j < TPC_NUM_OF_PADS; j++) { ushort q = map[{j, i}]; @@ -61,11 +67,47 @@ void GPUTPCClusterFinder::DumpChargeMap(std::ostream& out, std::string_view titl out << std::dec; } +void GPUTPCClusterFinder::DumpPeakMap(std::ostream& out, std::string_view title) +{ + out << "\nClusterer - " << title << " - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; + + Array2D map(mPpeakMap); + + out << std::hex; + + TPCFragmentTime start = 0; + TPCFragmentTime end = TPC_MAX_FRAGMENT_LEN_PADDED(mRec->GetProcessingSettings().overrideClusterizerFragmentLen); + + for (TPCFragmentTime i = start; i < end; i++) { + int zeros = 0; + + out << i << ":"; + for (GlobalPad j = 0; j < TPC_NUM_OF_PADS; j++) { + uchar q = map[{j, i}]; + zeros += (q == 0); + if (q != 0) { + if (zeros > 0) { + out << " z" << zeros; + zeros = 0; + } + + out << " p" << int{q}; + } + } + if (zeros > 0) { + out << " z" << zeros; + } + out << '\n'; + } + + out << std::dec; +} + void GPUTPCClusterFinder::DumpPeaks(std::ostream& out) { out << "\nClusterer - Peaks - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; for (unsigned int i = 0; i < mPmemory->counters.nPositions; i++) { - out << (int)mPisPeak[i] << " "; + out << int{mPisPeak[i]}; if ((i + 1) % 100 == 0) { out << "\n"; } @@ -74,17 +116,23 @@ void GPUTPCClusterFinder::DumpPeaks(std::ostream& out) void GPUTPCClusterFinder::DumpPeaksCompacted(std::ostream& out) { - out << "\nClusterer - Compacted Peaks - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << mPmemory->counters.nPeaks << "\n"; - for (size_t i = 0; i < mPmemory->counters.nPeaks; i++) { - out << mPpeakPositions[i].time() << ", " << (int)mPpeakPositions[i].pad() << ", " << (int)mPpeakPositions[i].row() << "\n"; + const auto nPeaks = mPmemory->counters.nPeaks; + + out << "\nClusterer - Compacted Peaks - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << nPeaks << "\n"; + for (size_t i = 0; i < nPeaks; i++) { + const auto& pos = mPpeakPositions[i]; + out << pos.time() << " " << int{pos.pad()} << " " << int{pos.row()} << "\n"; } } void GPUTPCClusterFinder::DumpSuppressedPeaks(std::ostream& out) { - out << "\nClusterer - NoiseSuppression - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << mISlice << "\n"; - for (unsigned int i = 0; i < mPmemory->counters.nPeaks; i++) { - out << (int)mPisPeak[i] << " "; + const auto& fragment = mPmemory->fragment; + const auto nPeaks = mPmemory->counters.nPeaks; + + out << "\nClusterer - NoiseSuppression - Slice " << mISlice << " - Fragment " << fragment.index << mISlice << "\n"; + for (unsigned int i = 0; i < nPeaks; i++) { + out << int{mPisPeak[i]}; if ((i + 1) % 100 == 0) { out << "\n"; } @@ -93,17 +141,13 @@ void GPUTPCClusterFinder::DumpSuppressedPeaks(std::ostream& out) void GPUTPCClusterFinder::DumpSuppressedPeaksCompacted(std::ostream& out) { - out << "\nClusterer - Noise Suppression Peaks Compacted - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << ": " << mPmemory->counters.nClusters << "\n"; - for (size_t i = 0; i < mPmemory->counters.nClusters; i++) { - out << i << ": " << mPfilteredPeakPositions[i].time() << ", " << (int)mPfilteredPeakPositions[i].pad() << ", " << (int)mPfilteredPeakPositions[i].row() << "\n"; - } -} + const auto& fragment = mPmemory->fragment; + const auto nPeaks = mPmemory->counters.nClusters; -void GPUTPCClusterFinder::DumpCountedPeaks(std::ostream& out) -{ - out << "\nClusterer - Peak Counts - Slice " << mISlice << " - Fragment " << mPmemory->fragment.index << "\n"; - for (int i = 0; i < GPUCA_ROW_COUNT; i++) { - out << i << ": " << mPclusterInRow[i] << "\n"; + out << "\nClusterer - Noise Suppression Peaks Compacted - Slice " << mISlice << " - Fragment " << fragment.index << ": " << nPeaks << "\n"; + for (size_t i = 0; i < nPeaks; i++) { + const auto& peak = mPfilteredPeakPositions[i]; + out << peak.time() << " " << int{peak.pad()} << " " << int{peak.row()} << "\n"; } } @@ -113,15 +157,15 @@ void GPUTPCClusterFinder::DumpClusters(std::ostream& out) for (int i = 0; i < GPUCA_ROW_COUNT; i++) { size_t N = mPclusterInRow[i]; - out << "Row: " << i << ": " << N << "\n"; - std::vector sortedCluster(N); - tpc::ClusterNative* row = &mPclusterByRow[i * mNMaxClusterPerRow]; - std::copy(row, &row[N], sortedCluster.begin()); + const tpc::ClusterNative* row = &mPclusterByRow[i * mNMaxClusterPerRow]; + std::vector sortedCluster; + sortedCluster.insert(sortedCluster.end(), row, row + N); std::sort(sortedCluster.begin(), sortedCluster.end()); + out << "Row: " << i << ": " << N << "\n"; for (const auto& cl : sortedCluster) { - out << std::hex << cl.timeFlagsPacked << std::dec << ", " << cl.padPacked << ", " << (int)cl.sigmaTimePacked << ", " << (int)cl.sigmaPadPacked << ", " << cl.qMax << ", " << cl.qTot << "\n"; + out << std::hex << cl.timeFlagsPacked << std::dec << " " << cl.padPacked << " " << int{cl.sigmaTimePacked} << " " << int{cl.sigmaPadPacked} << " " << cl.qMax << " " << cl.qTot << "\n"; } } } diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h b/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h index f8a3cf6236a32..8915408c63f87 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDInterfaces.h @@ -49,19 +49,19 @@ class trackInterface : public AliExternalTrackParam { public: - trackInterface() : AliExternalTrackParam(){}; - trackInterface(const trackInterface& param) : AliExternalTrackParam(param){}; - trackInterface(const AliExternalTrackParam& param) CON_DELETE; - trackInterface(const AliHLTExternalTrackParam& param) : AliExternalTrackParam() + trackInterface() : AliExternalTrackParam(){}; + trackInterface(const trackInterface& param) : AliExternalTrackParam(param){}; + trackInterface(const AliExternalTrackParam& param) CON_DELETE; + trackInterface(const AliHLTExternalTrackParam& param) : AliExternalTrackParam() { float paramTmp[5] = {param.fY, param.fZ, param.fSinPhi, param.fTgl, param.fq1Pt}; Set(param.fX, param.fAlpha, paramTmp, param.fC); } - trackInterface(const GPUTPCGMMergedTrack& trk) : AliExternalTrackParam() + trackInterface(const GPUTPCGMMergedTrack& trk) : AliExternalTrackParam() { Set(trk.GetParam().GetX(), trk.GetAlpha(), trk.GetParam().GetPar(), trk.GetParam().GetCov()); } - trackInterface(const gputpcgmmergertypes::GPUTPCOuterParam& param) : AliExternalTrackParam() + trackInterface(const gputpcgmmergertypes::GPUTPCOuterParam& param) : AliExternalTrackParam() { Set(param.X, param.alpha, param.P, param.C); } diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx index 240e1c519649a..09db87f154319 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.cxx @@ -289,26 +289,19 @@ void GPUTRDTracker_t::StartDebugging() #endif //! GPUCA_GPUCODE template <> -GPUdi() const GPUTRDPropagatorGPU::propagatorParam* GPUTRDTracker_t::getPropagatorParam(bool externalDefaultO2Propagator) +GPUdi() const GPUTRDPropagatorGPU::propagatorParam* GPUTRDTracker_t::getPropagatorParam() { return &Param().polynomialField; } template -GPUdi() const typename PROP::propagatorParam* GPUTRDTracker_t::getPropagatorParam(bool externalDefaultO2Propagator) +GPUdi() const typename PROP::propagatorParam* GPUTRDTracker_t::getPropagatorParam() { -#ifdef GPUCA_GPUCODE - return GetConstantMem()->calibObjects.o2Propagator; -#elif defined GPUCA_ALIROOT_LIB +#if defined GPUCA_ALIROOT_LIB return nullptr; #else -#ifdef GPUCA_HAVE_O2HEADERS - if (externalDefaultO2Propagator) { - return o2::base::Propagator::Instance(); - } -#endif -#endif return GetConstantMem()->calibObjects.o2Propagator; +#endif } template @@ -410,7 +403,7 @@ GPUd() void GPUTRDTracker_t::DoTrackingThread(int iTrk, int thread return; } } - PROP prop(getPropagatorParam(Param().rec.trd.useExternalO2DefaultPropagator)); + PROP prop(getPropagatorParam()); mTracks[iTrk].setChi2(Param().rec.trd.penaltyChi2); // TODO check if this should not be higher auto trkStart = mTracks[iTrk]; for (int iColl = 0; iColl < nCollisionIds; ++iColl) { diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h index cb0f57d87d2f0..da1d294b679a6 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTracker.h @@ -155,7 +155,7 @@ class GPUTRDTracker_t : public GPUProcessor GPUd() void DumpTracks(); // utility - GPUd() const typename PROP::propagatorParam* getPropagatorParam(bool externalDefaultO2Propagator); + GPUd() const typename PROP::propagatorParam* getPropagatorParam(); protected: float* mR; // radial position of each TRD chamber, alignment taken into account, radial spread within chambers < 7mm diff --git a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.cxx b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.cxx index acf586c3b7fb5..9ee57e9578e99 100644 --- a/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.cxx +++ b/GPU/GPUTracking/TRDTracking/GPUTRDTrackerComponent.cxx @@ -185,7 +185,7 @@ int GPUTRDTrackerComponent::DoInit(int argc, const char** argv) iResult = ReadConfigurationString(arguments.Data()); GPUSettingsGRP cfgGRP; - cfgGRP.solenoidBz = GetBz(); + cfgGRP.solenoidBzNominalGPU = GetBz(); GPUSettingsRec cfgRec; GPUSettingsProcessing cfgDeviceProcessing; GPURecoStepConfiguration cfgRecoStep; diff --git a/GPU/GPUTracking/cmake/helpers.cmake b/GPU/GPUTracking/cmake/helpers.cmake index e74e5290d5b00..8d8cf592d8295 100644 --- a/GPU/GPUTracking/cmake/helpers.cmake +++ b/GPU/GPUTracking/cmake/helpers.cmake @@ -18,7 +18,7 @@ function(create_binary_resource RESOURCE OUTPUTFILE) add_custom_command( OUTPUT ${OUTPUTFILE} COMMAND ${CMAKE_LINKER} --relocatable --format binary --output ${OUTPUTFILE} ${input-file-rel} - DEPENDS ${RESOURCE} + DEPENDS ${input-file-rel} COMMENT "Adding binary resource ${input-file-rel}" VERBATIM ) diff --git a/GPU/GPUTracking/cmake/kernel_helpers.cmake b/GPU/GPUTracking/cmake/kernel_helpers.cmake index 55f9ac6ded458..30fe2850ff3eb 100644 --- a/GPU/GPUTracking/cmake/kernel_helpers.cmake +++ b/GPU/GPUTracking/cmake/kernel_helpers.cmake @@ -17,7 +17,7 @@ define_property(TARGET PROPERTY O2_GPU_KERNELS) define_property(TARGET PROPERTY O2_GPU_KERNEL_NAMES) define_property(TARGET PROPERTY O2_GPU_KERNEL_INCLUDES) define_property(TARGET PROPERTY O2_GPU_KERNEL_FILES) -set(O2_GPU_KERNEL_WRAPPER_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/include_gpu_onthefly") +set(O2_GPU_KERNEL_WRAPPER_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/GPU/include_gpu_onthefly") file(MAKE_DIRECTORY ${O2_GPU_KERNEL_WRAPPER_FOLDER}) set(O2_GPU_BASE_DIR "${CMAKE_CURRENT_LIST_DIR}/../") function(o2_gpu_add_kernel kernel_name kernel_files kernel_bounds kernel_type) @@ -28,6 +28,7 @@ function(o2_gpu_add_kernel kernel_name kernel_files kernel_bounds kernel_type) list(LENGTH ARGV n) set(OPT1 "") set(OPT2 "") + set(OPT3 "") if(${n} GREATER 4) math(EXPR n "${n} - 1") foreach(i RANGE 4 ${n} 2) @@ -39,6 +40,7 @@ function(o2_gpu_add_kernel kernel_name kernel_files kernel_bounds kernel_type) string(APPEND OPT1 ",${ARGV${i}} ${ARGV${j}}") string(APPEND OPT2 ",${ARGV${j}}") endif() + string(APPEND OPT3 ",${ARGV${i}}") endforeach() endif() if(kernel_bounds MATCHES "^LB") @@ -54,7 +56,7 @@ function(o2_gpu_add_kernel kernel_name kernel_files kernel_bounds kernel_type) set(TMP_PRE "#ifdef GPUCA_KRNL_NOOCL1\n") set(TMP_POST "#endif\n") endif() - set(TMP_KERNEL "GPUCA_KRNL${TMP_BOUNDS}((${kernel_name}), (${kernel_type}), (${OPT1}), (${OPT2}))\n") + set(TMP_KERNEL "GPUCA_KRNL${TMP_BOUNDS}((${kernel_name}), (${kernel_type}), (${OPT1}), (${OPT2}), (${OPT3}))\n") separate_arguments(kernel_files NATIVE_COMMAND ${kernel_files}) list(GET kernel_files 0 TMP_KERNEL_CLASS_FILE) if (TMP_KERNEL_CLASS_FILE STREQUAL "=") @@ -65,7 +67,7 @@ function(o2_gpu_add_kernel kernel_name kernel_files kernel_bounds kernel_type) set_property(TARGET O2_GPU_KERNELS APPEND PROPERTY O2_GPU_KERNEL_INCLUDES "${TMP_KERNEL_CLASS_FILE}") set_property(TARGET O2_GPU_KERNELS APPEND PROPERTY O2_GPU_KERNEL_FILES "${TMP_KERNEL_CLASS_FILE}.cxx") # add_custom_command OUTPUT option does not support target-dependend generator expressions, thus this workaround - + set(O2_GPU_KERNEL_TEMPLATE_FILES "GPUConstantMem.h") list(LENGTH kernel_files n) if(n GREATER 1) @@ -81,15 +83,22 @@ function(o2_gpu_add_kernel kernel_name kernel_files kernel_bounds kernel_type) endif() list(APPEND O2_GPU_KERNEL_TEMPLATE_FILES "${TMP_KERNEL_CLASS_FILE}.cxx") list(REMOVE_DUPLICATES O2_GPU_KERNEL_TEMPLATE_FILES) + list(FILTER O2_GPU_KERNEL_TEMPLATE_FILES EXCLUDE REGEX "^-$") list(TRANSFORM O2_GPU_KERNEL_TEMPLATE_FILES APPEND "\"") list(TRANSFORM O2_GPU_KERNEL_TEMPLATE_FILES PREPEND "#include \"") list(JOIN O2_GPU_KERNEL_TEMPLATE_FILES "\n" O2_GPU_KERNEL_TEMPLATE_FILES) - + + string(REPLACE ", " "_" TMP_FILENAME "${kernel_name}") if(CUDA_ENABLED) - string(REPLACE ", " "_" TMP_FILENAME "${kernel_name}") - set(TMP_FILENAME "${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_${TMP_FILENAME}.cu") + set(TMP_FILENAMEA "${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_${TMP_FILENAME}.cu") + set(O2_GPU_KERNEL_TEMPLATE_REPLACE "${TMP_KERNEL}") + configure_file(${O2_GPU_BASE_DIR}/Base/cuda/GPUReconstructionCUDAkernel.template.cu ${TMP_FILENAMEA}) + endif() + + if(HIP_ENABLED) + set(TMP_FILENAMEA "${O2_GPU_KERNEL_WRAPPER_FOLDER}/krnl_${TMP_FILENAME}.hip.cxx") set(O2_GPU_KERNEL_TEMPLATE_REPLACE "${TMP_KERNEL}") - configure_file(${O2_GPU_BASE_DIR}/Base/cuda/GPUReconstructionCUDAkernel.template.cu ${TMP_FILENAME}) + configure_file(${O2_GPU_BASE_DIR}/Base/hip/GPUReconstructionHIPkernel.template.hip ${TMP_FILENAMEA}) endif() endfunction() @@ -97,7 +106,9 @@ function(o2_gpu_kernel_file_list list) define_property(TARGET PROPERTY O2_GPU_KERNELS_FILE_LIST_${list}) list(LENGTH ARGV n) if(2 GREATER ${n}) - message(FATAL_ERROR "File list must contain at least one file") + set_property(TARGET O2_GPU_KERNELS PROPERTY O2_GPU_KERNELS_FILE_LIST_${list} "-") + return() + # message(FATAL_ERROR "File list must contain at least one file") endif() if(list MATCHES "[^A-Z0-9_]") message(FATAL_ERROR "Invalid character in file list name ${list}") @@ -109,7 +120,9 @@ function(o2_gpu_kernel_file_list list) if(NOT TMP_SUB_FILE_LIST) message(FATAL_ERROR "Invalid file list ${ARGV${i}}") endif() - list(APPEND TMP_FILE_LIST ${TMP_SUB_FILE_LIST}) + if(NOT TMP_SUB_FILE_LIST STREQUAL "-") + list(APPEND TMP_FILE_LIST ${TMP_SUB_FILE_LIST}) + endif() else() list(APPEND TMP_FILE_LIST ${ARGV${i}}) set_property(TARGET O2_GPU_KERNELS APPEND PROPERTY O2_GPU_KERNEL_FILES "${ARGV${i}}") diff --git a/GPU/GPUTracking/display/CMakeLists.txt b/GPU/GPUTracking/display/CMakeLists.txt index 1150a885d567b..8e91f570c93dd 100644 --- a/GPU/GPUTracking/display/CMakeLists.txt +++ b/GPU/GPUTracking/display/CMakeLists.txt @@ -73,22 +73,26 @@ if(GPUCA_EVENT_DISPLAY_VULKAN) OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-client-protocol.h COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/ COMMAND ${O2GPUWayland_SCANNER} client-header ${O2GPUWayland_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-client-protocol.h - MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml) + MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml + COMMENT "Preparing Wayland xdg-shell-client-protocol.h") add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-protocol.c COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/ COMMAND ${O2GPUWayland_SCANNER} private-code ${O2GPUWayland_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-protocol.c - MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml) + MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml + COMMENT "Preparing Wayland xdg-shell-protocol.c") add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-client-protocol.h COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/ COMMAND ${O2GPUWayland_SCANNER} client-header ${O2GPUWayland_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-client-protocol.h - MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml) + MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml + COMMENT "Preparing Wayland xdg-decoration-client-protocol.h") add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-protocol.c COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/ COMMAND ${O2GPUWayland_SCANNER} private-code ${O2GPUWayland_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-protocol.c - MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml) + MAIN_DEPENDENCY ${O2GPUWayland_PROTOCOLS_DIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml + COMMENT "Preparing Wayland xdg-decoration-protocol.c") set_property(SOURCE GPUDisplayFrontendWayland.cxx ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-protocol.c APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-shell-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/xdg-decoration-client-protocol.h) set_property(SOURCE GPUDisplayFrontendWayland.cxx APPEND PROPERTY INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}/xdg-gen/) diff --git a/GPU/GPUTracking/display/GPUDisplay.cxx b/GPU/GPUTracking/display/GPUDisplay.cxx index b620e3f8c8d01..bae8da5a6bf01 100644 --- a/GPU/GPUTracking/display/GPUDisplay.cxx +++ b/GPU/GPUTracking/display/GPUDisplay.cxx @@ -2215,11 +2215,11 @@ void GPUDisplay::DrawGLScene_internal(float animateTime, bool renderToMixBuffer) double fpstime = mTimerFPS.GetCurrentElapsedTime(); char info[1024]; float fps = (double)mFramesDoneFPS / fpstime; - sprintf(info, - "FPS: %6.2f (Slice: %d, 1:Clusters %d, 2:Prelinks %d, 3:Links %d, 4:Seeds %d, 5:Tracklets %d, 6:Tracks %d, 7:GTracks %d, 8:Merger %d) (%d frames, %d draw calls) " - "(X %1.2f Y %1.2f Z %1.2f / R %1.2f Phi %1.1f Theta %1.1f) / Yaw %1.1f Pitch %1.1f Roll %1.1f)", - fps, mCfgL.drawSlice, mCfgL.drawClusters, mCfgL.drawInitLinks, mCfgL.drawLinks, mCfgL.drawSeeds, mCfgL.drawTracklets, mCfgL.drawTracks, mCfgL.drawGlobalTracks, mCfgL.drawFinal, mFramesDone, mNDrawCalls, mXYZ[0], mXYZ[1], mXYZ[2], mRPhiTheta[0], mRPhiTheta[1] * 180 / CAMath::Pi(), - mRPhiTheta[2] * 180 / CAMath::Pi(), mAngle[1] * 180 / CAMath::Pi(), mAngle[0] * 180 / CAMath::Pi(), mAngle[2] * 180 / CAMath::Pi()); + snprintf(info, 1024, + "FPS: %6.2f (Slice: %d, 1:Clusters %d, 2:Prelinks %d, 3:Links %d, 4:Seeds %d, 5:Tracklets %d, 6:Tracks %d, 7:GTracks %d, 8:Merger %d) (%d frames, %d draw calls) " + "(X %1.2f Y %1.2f Z %1.2f / R %1.2f Phi %1.1f Theta %1.1f) / Yaw %1.1f Pitch %1.1f Roll %1.1f)", + fps, mCfgL.drawSlice, mCfgL.drawClusters, mCfgL.drawInitLinks, mCfgL.drawLinks, mCfgL.drawSeeds, mCfgL.drawTracklets, mCfgL.drawTracks, mCfgL.drawGlobalTracks, mCfgL.drawFinal, mFramesDone, mNDrawCalls, mXYZ[0], mXYZ[1], mXYZ[2], mRPhiTheta[0], mRPhiTheta[1] * 180 / CAMath::Pi(), + mRPhiTheta[2] * 180 / CAMath::Pi(), mAngle[1] * 180 / CAMath::Pi(), mAngle[0] * 180 / CAMath::Pi(), mAngle[2] * 180 / CAMath::Pi()); if (fpstime > 1.) { if (mPrintInfoText & 2) { GPUInfo("%s", info); @@ -2242,7 +2242,7 @@ void GPUDisplay::DrawGLScene_internal(float animateTime, bool renderToMixBuffer) std::vector pixels = mBackend->getPixels(); char tmpFileName[48]; if (mAnimateScreenshot) { - sprintf(tmpFileName, "mAnimation%d_%05d.bmp", mAnimationExport, mAnimationFrame); + snprintf(tmpFileName, 48, "mAnimation%d_%05d.bmp", mAnimationExport, mAnimationFrame); } DoScreenshot(mAnimateScreenshot ? tmpFileName : mScreenshotFile.c_str(), pixels); } diff --git a/GPU/GPUTracking/display/GPUDisplayKeys.cxx b/GPU/GPUTracking/display/GPUDisplayKeys.cxx index f66256fb1e63a..7b5ab3a060255 100644 --- a/GPU/GPUTracking/display/GPUDisplayKeys.cxx +++ b/GPU/GPUTracking/display/GPUDisplayKeys.cxx @@ -348,7 +348,7 @@ void GPUDisplay::HandleKey(unsigned char key) } else if (key == 't') { static int nScreenshot = 1; char fname[32]; - sprintf(fname, "screenshot%d.bmp", nScreenshot++); + snprintf(fname, 32, "screenshot%d.bmp", nScreenshot++); mRequestScreenshot = true; mScreenshotFile = fname; SetInfo("Taking screenshot (%s)", fname); diff --git a/GPU/GPUTracking/kernels.cmake b/GPU/GPUTracking/kernels.cmake index 8bdb543230ab6..d4f5ca93e9def 100644 --- a/GPU/GPUTracking/kernels.cmake +++ b/GPU/GPUTracking/kernels.cmake @@ -17,15 +17,21 @@ o2_gpu_kernel_file_list(TPCTRACKER ERRORS GPUTPCTrackParam.cxx GPUTPCTrack.cxx G o2_gpu_kernel_file_list(TPCTRACKLETCONS GPUTPCTrackletConstructor.cxx) o2_gpu_kernel_file_list(TPCSLICEDATA TPCTRACKER GPUTPCSliceData.cxx) o2_gpu_kernel_file_list(TPCOCCUPANCY GPUTPCClusterOccupancyMap.cxx) +if(ALIGPU_BUILD_TYPE STREQUAL "O2" OR CONFIG_O2_EXTENSIONS) o2_gpu_kernel_file_list(TPCDEDX GPUdEdx.cxx) -o2_gpu_kernel_file_list(TPCMERGER ERRORS GPUTPCGMMerger.cxx GPUTPCGMSliceTrack.cxx GPUTPCGMTrackParam.cxx GPUTPCGMPhysicalTrackModel.cxx GPUTPCGMPropagator.cxx) o2_gpu_kernel_file_list(MATLUT MatLayerCylSet.cxx MatLayerCyl.cxx Ray.cxx) +o2_gpu_kernel_file_list(TPCMERGER ERRORS GPUTPCGMMerger.cxx GPUTPCGMSliceTrack.cxx GPUTPCGMTrackParam.cxx GPUTPCGMPhysicalTrackModel.cxx GPUTPCGMPropagator.cxx) o2_gpu_kernel_file_list(O2PROPAGATOR TrackParametrization.cxx TrackParametrizationWithError.cxx Propagator.cxx TrackLTIntegral.cxx) o2_gpu_kernel_file_list(TPCCOMPRESSION GPUTPCCompressionTrackModel.cxx) o2_gpu_kernel_file_list(TPCDECOMPRESSION GPUTPCCompressionTrackModel.cxx ERRORS) o2_gpu_kernel_file_list(TPCCLUSTERFINDER ERRORS ClusterAccumulator.cxx) o2_gpu_kernel_file_list(TRDTRACKER GPUTRDTrack.cxx GPUTRDTracker.cxx GPUTRDTrackletWord.cxx GeometryBase.cxx) o2_gpu_kernel_file_list(GLOBALREFIT TPCMERGER O2PROPAGATOR MATLUT GPUTrackingRefit.cxx) +else() +o2_gpu_kernel_file_list(TPCDEDX) +o2_gpu_kernel_file_list(MATLUT) +o2_gpu_kernel_file_list(TPCMERGER) +endif() o2_gpu_add_kernel("GPUTPCNeighboursFinder" "= TPCTRACKER" LB_OCL1 single) o2_gpu_add_kernel("GPUTPCNeighboursCleaner" "= TPCTRACKER" LB_OCL1 single) diff --git a/GPU/GPUTracking/qa/GPUQA.cxx b/GPU/GPUTracking/qa/GPUQA.cxx index 95de3f3430e52..f4978a80801ab 100644 --- a/GPU/GPUTracking/qa/GPUQA.cxx +++ b/GPU/GPUTracking/qa/GPUQA.cxx @@ -1742,46 +1742,61 @@ void GPUQA::RunQA(bool matchOnly, const std::vector* tracksEx if (!clNative || !mTracking || !mTracking->mIOPtrs.mergedTrackHitAttachment || !mTracking->mIOPtrs.mergedTracks) { throw std::runtime_error("Cannot dump non o2::tpc::clusterNative clusters, need also hit attachmend and GPU tracks"); } - static auto cldump = GPUROOTDump::getNew("cluster", "track", "trackHit", "attach", "extState", "x", "y", "z", "sector", "row", "nEv", "clusterTree"); unsigned int clid = 0; for (unsigned int i = 0; i < GPUChainTracking::NSLICES; i++) { for (unsigned int j = 0; j < GPUCA_ROW_COUNT; j++) { for (unsigned int k = 0; k < mClNative->nClusters[i][j]; k++) { const auto& cl = mClNative->clusters[i][j][k]; unsigned int attach = mTracking->mIOPtrs.mergedTrackHitAttachment[clid]; - GPUTPCGMMergedTrack trk; - GPUTPCGMMergedTrackHit trkHit; - memset((void*)&trk, 0, sizeof(trk)); - memset((void*)&trkHit, 0, sizeof(trkHit)); float x = 0, y = 0, z = 0; if (attach & gputpcgmmergertypes::attachFlagMask) { unsigned int track = attach & gputpcgmmergertypes::attachTrackMask; - trk = mTracking->mIOPtrs.mergedTracks[track]; - for (unsigned int l = 0; l < trk.NClusters(); l++) { - const auto& tmp = mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef() + l]; - if (tmp.num == clid) { - trkHit = tmp; - break; - } - } + const auto& trk = mTracking->mIOPtrs.mergedTracks[track]; mTracking->GetTPCTransformHelper()->Transform(i, j, cl.getPad(), cl.getTime(), x, y, z, trk.GetParam().GetTZOffset()); mTracking->GetParam().Slice2Global(i, x, y, z, &x, &y, &z); } - unsigned int extState = mTracking->mIOPtrs.mergedTrackHitStates ? mTracking->mIOPtrs.mergedTrackHitStates[clid] : 0; - cldump.Fill(cl, trk, trkHit, attach, extState, x, y, z, i, j, mNEvents - 1); + if (mConfig.dumpToROOT >= 2) { + GPUTPCGMMergedTrack trk; + GPUTPCGMMergedTrackHit trkHit; + memset((void*)&trk, 0, sizeof(trk)); + memset((void*)&trkHit, 0, sizeof(trkHit)); + if (attach & gputpcgmmergertypes::attachFlagMask) { + unsigned int track = attach & gputpcgmmergertypes::attachTrackMask; + trk = mTracking->mIOPtrs.mergedTracks[track]; + for (unsigned int l = 0; l < trk.NClusters(); l++) { + const auto& tmp = mTracking->mIOPtrs.mergedTrackHits[trk.FirstClusterRef() + l]; + if (tmp.num == clid) { + trkHit = tmp; + break; + } + } + } + static auto cldump = GPUROOTDump::getNew("cluster", "track", "trackHit", "attach", "extState", "x", "y", "z", "sector", "row", "nEv", "clusterTree"); + cldump.Fill(cl, trk, trkHit, attach, extState, x, y, z, i, j, mNEvents - 1); + } else { + static auto cldump = GPUROOTDump::getNew("cluster", "attach", "extState", "x", "y", "z", "sector", "row", "nEv", "clusterTree"); + cldump.Fill(cl, attach, extState, x, y, z, i, j, mNEvents - 1); + } clid++; } } } - static auto trkdump = GPUROOTDump::getNew("nEv", "tracks"); + static auto trkdump = GPUROOTDump::getNew("nEv", "track", "tracksTree"); for (unsigned int i = 0; i < mTracking->mIOPtrs.nMergedTracks; i++) { if (mTracking->mIOPtrs.mergedTracks[i].OK()) { trkdump.Fill(mNEvents - 1, mTracking->mIOPtrs.mergedTracks[i]); } } + + if (mTracking && mTracking->GetProcessingSettings().createO2Output) { + static auto o2trkdump = GPUROOTDump::getNew("nEv", "track", "tracksO2Tree"); + for (unsigned int i = 0; i < mTracking->mIOPtrs.nOutputTracksTPCO2; i++) { + o2trkdump.Fill(mNEvents - 1, mTracking->mIOPtrs.outputTracksTPCO2[i]); + } + } } mTrackingScratchBuffer.clear(); mTrackingScratchBuffer.shrink_to_fit(); diff --git a/GPU/GPUTracking/qa/GPUQA.h b/GPU/GPUTracking/qa/GPUQA.h index d5fef788c099c..79580a737cdf2 100644 --- a/GPU/GPUTracking/qa/GPUQA.h +++ b/GPU/GPUTracking/qa/GPUQA.h @@ -57,6 +57,7 @@ class GPUQA void* AllocateScratchBuffer(size_t nBytes) { return nullptr; } static bool QAAvailable() { return false; } static bool IsInitialized() { return false; } + void UpdateChain(GPUChainTracking* chain) {} }; } // namespace gpu } // namespace GPUCA_NAMESPACE diff --git a/GPU/GPUTracking/qa/genEvents.cxx b/GPU/GPUTracking/qa/genEvents.cxx index 68cbd43a94d52..280a1eb025479 100644 --- a/GPU/GPUTracking/qa/genEvents.cxx +++ b/GPU/GPUTracking/qa/genEvents.cxx @@ -106,9 +106,9 @@ void genEvents::InitEventGenerator() for (int j = 0; j < 2; j++) { char name[1024], title[1024]; - sprintf(name, "clError%s%d", (j == 0 ? "Y" : "Z"), i); + snprintf(name, 1024, "clError%s%d", (j == 0 ? "Y" : "Z"), i); - sprintf(title, "Cluster %s Error for rows %s", (j == 0 ? "Y" : "Z"), rows[i]); + snprintf(title, 1024, "Cluster %s Error for rows %s", (j == 0 ? "Y" : "Z"), rows[i]); mClusterError[i][j] = new TH1F(name, title, 1000, 0., .7); mClusterError[i][j]->GetXaxis()->SetTitle("Cluster Error [cm]"); diff --git a/GPU/GPUTracking/utils/timer.cxx b/GPU/GPUTracking/utils/timer.cxx index 7f0330ba03287..f3b108fc6f159 100644 --- a/GPU/GPUTracking/utils/timer.cxx +++ b/GPU/GPUTracking/utils/timer.cxx @@ -75,6 +75,13 @@ void HighResTimer::Stop() double EndTime = 0; EndTime = GetTime(); ElapsedTime += EndTime - StartTime; + StartTime = 0; +} + +void HighResTimer::Abort() +{ + StartTime = 0.; + running = 0; } void HighResTimer::StopAndStart(HighResTimer& startTimer) @@ -86,6 +93,7 @@ void HighResTimer::StopAndStart(HighResTimer& startTimer) double EndTime = 0; EndTime = GetTime(); ElapsedTime += EndTime - StartTime; + StartTime = 0; startTimer.StartTime = EndTime; startTimer.running = 1; } diff --git a/GPU/GPUTracking/utils/timer.h b/GPU/GPUTracking/utils/timer.h index f7738bf64e365..3816f49f3024d 100644 --- a/GPU/GPUTracking/utils/timer.h +++ b/GPU/GPUTracking/utils/timer.h @@ -22,6 +22,7 @@ class HighResTimer ~HighResTimer() = default; void Start(); void Stop(); + void Abort(); void Reset(); void ResetStart(); double GetElapsedTime(); diff --git a/GPU/TPCFastTransformation/CMakeLists.txt b/GPU/TPCFastTransformation/CMakeLists.txt index 7e14943f313e3..b338e1492cc6c 100644 --- a/GPU/TPCFastTransformation/CMakeLists.txt +++ b/GPU/TPCFastTransformation/CMakeLists.txt @@ -81,7 +81,7 @@ if(${ALIGPU_BUILD_TYPE} STREQUAL "O2") SOURCES test/testMultivarPolynomials.cxx ENVIRONMENT O2_ROOT=${CMAKE_BINARY_DIR}/stage LABELS gpu - CONFIGURATIONS RelWithDebInfo Release MinRelSize) + CONFIGURATIONS RelWithDebInfo Release MinSizeRel) foreach(m SplineDemo.C diff --git a/GPU/Workflow/CMakeLists.txt b/GPU/Workflow/CMakeLists.txt index 51494b1a1703e..aa725168b9db2 100644 --- a/GPU/Workflow/CMakeLists.txt +++ b/GPU/Workflow/CMakeLists.txt @@ -26,7 +26,8 @@ o2_add_library(GPUWorkflow O2::TPCReaderWorkflow O2::DataFormatsGlobalTracking O2::DataFormatsTRD - PRIVATE_LINK_LIBRARIES O2::GPUTracking) + PRIVATE_LINK_LIBRARIES O2::GPUTracking + O2::ITSTrackingInterface) o2_add_executable(reco-workflow COMPONENT_NAME gpu diff --git a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h index 60567adc73e3d..17f88d0417979 100644 --- a/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h +++ b/GPU/Workflow/include/GPUWorkflow/GPUWorkflowSpec.h @@ -58,9 +58,8 @@ class GeometryFlat; namespace its { -class Tracker; -class Vertexer; class TimeFrame; +class ITSTrackingInterface; } // namespace its namespace itsmft @@ -128,7 +127,6 @@ class GPURecoWorkflowSpec : public o2::framework::Task int lumiScaleType = 0; // 0=off, 1=CTP, 2=TPC scalers bool outputErrorQA = false; bool runITSTracking = false; - int itsTrackingMode = 0; // 0=sync, 1=async, 2=cosmics bool itsOverrBeamEst = false; bool tpcTriggerHandling = false; }; @@ -211,8 +209,7 @@ class GPURecoWorkflowSpec : public o2::framework::Task std::unique_ptr mQA; std::vector mClusterOutputIds; std::vector mTPCSectors; - std::unique_ptr mITSTracker; - std::unique_ptr mITSVertexer; + std::unique_ptr mITSTrackingInterface; std::unique_ptr mPipeline; o2::its::TimeFrame* mITSTimeFrame = nullptr; std::vector mRegionInfos; @@ -235,8 +232,6 @@ class GPURecoWorkflowSpec : public o2::framework::Task bool mITSGeometryCreated = false; bool mTRDGeometryCreated = false; bool mPropagatorInstanceCreated = false; - bool mITSRunVertexer = false; - bool mITSCosmicsProcessing = false; }; } // end namespace gpu diff --git a/GPU/Workflow/src/GPUWorkflowITS.cxx b/GPU/Workflow/src/GPUWorkflowITS.cxx index 8d3270eafd54b..5f6ec171d27c1 100644 --- a/GPU/Workflow/src/GPUWorkflowITS.cxx +++ b/GPU/Workflow/src/GPUWorkflowITS.cxx @@ -10,397 +10,47 @@ // or submit itself to any jurisdiction. /// @file GPUWorkflowITS.cxx -/// @author David Rohr +/// @author David Rohr, Matteo Concas #include "GPUWorkflow/GPUWorkflowSpec.h" -#include "Headers/DataHeader.h" #include "Framework/WorkflowSpec.h" // o2::framework::mergeInputs -#include "Framework/DataRefUtils.h" -#include "Framework/DataSpecUtils.h" -#include "Framework/DeviceSpec.h" #include "Framework/ControlService.h" #include "Framework/ConfigParamRegistry.h" -#include "Framework/InputRecordWalker.h" -#include "Framework/SerializationMethods.h" -#include "Framework/Logger.h" -#include "Framework/CallbackService.h" #include "Framework/CCDBParamSpec.h" -#include "DataFormatsTPC/TPCSectorHeader.h" -#include "DataFormatsTPC/ClusterNative.h" -#include "DataFormatsTPC/CompressedClusters.h" -#include "DataFormatsTPC/Helpers.h" -#include "DataFormatsTPC/ZeroSuppression.h" -#include "DataFormatsTPC/RawDataTypes.h" -#include "DataFormatsTPC/WorkflowHelper.h" -#include "DataFormatsGlobalTracking/TrackTuneParams.h" -#include "TPCReconstruction/TPCTrackingDigitsPreCheck.h" -#include "TPCReconstruction/TPCFastTransformHelperO2.h" -#include "DataFormatsTPC/Digit.h" -#include "TPCFastTransform.h" -#include "DetectorsBase/MatLayerCylSet.h" -#include "DetectorsBase/Propagator.h" -#include "DetectorsBase/GeometryManager.h" -#include "DetectorsRaw/HBFUtils.h" -#include "DetectorsBase/GRPGeomHelper.h" -#include "CommonUtils/NameConf.h" -#include "TPCBase/RDHUtils.h" -#include "GPUO2InterfaceConfiguration.h" -#include "GPUO2InterfaceQA.h" -#include "GPUO2Interface.h" -#include "CalibdEdxContainer.h" -#include "GPUNewCalibValues.h" -#include "TPCPadGainCalib.h" -#include "TPCZSLinkMapping.h" -#include "display/GPUDisplayInterface.h" -#include "TPCBase/Sector.h" -#include "TPCBase/Utils.h" -#include "TPCBase/CDBInterface.h" -#include "TPCCalibration/VDriftHelper.h" -#include "CorrectionMapsHelper.h" -#include "TPCCalibration/CorrectionMapsLoader.h" -#include "SimulationDataFormat/ConstMCTruthContainer.h" -#include "SimulationDataFormat/MCCompLabel.h" -#include "Algorithm/Parser.h" -#include "DataFormatsGlobalTracking/RecoContainer.h" -#include "DataFormatsTRD/RecoInputContainer.h" -#include "TRDBase/Geometry.h" -#include "TRDBase/GeometryFlat.h" -#include "ITSBase/GeometryTGeo.h" -#include "CommonUtils/VerbosityConfig.h" -#include "CommonUtils/DebugStreamer.h" -#include -#include // for make_shared -#include -#include -#include -#include -#include -#include -#include -#include -#include "GPUReconstructionConvert.h" -#include "DetectorsRaw/RDHUtils.h" -#include -#include -#include -#include -#include -#include -#include "ITStracking/TimeFrame.h" -#include "ITStracking/Tracker.h" -#include "ITStracking/TrackerTraits.h" -#include "ITStracking/Vertexer.h" -#include "ITStracking/VertexerTraits.h" -#include "DataFormatsITSMFT/TopologyDictionary.h" -#include "ITSMFTBase/DPLAlpideParam.h" -#include "DataFormatsCalibration/MeanVertexObject.h" -#include "DataFormatsITSMFT/ROFRecord.h" -#include "DataFormatsITSMFT/PhysTrigger.h" -#include "CommonDataFormat/IRFrame.h" -#include "ITSReconstruction/FastMultEst.h" -#include "ITSReconstruction/FastMultEstConfig.h" - -using namespace o2::framework; -using namespace o2::header; -using namespace o2::gpu; -using namespace o2::base; -using namespace o2::dataformats; +#include "ITStracking/TrackingInterface.h" namespace o2::gpu { int GPURecoWorkflowSpec::runITSTracking(o2::framework::ProcessingContext& pc) { - using Vertex = o2::dataformats::Vertex>; - mITSTimeFrame->setDevicePropagator(mGPUReco->GetDeviceO2Propagator()); - LOGP(info, "GPUChainITS is giving me device propagator: {}", (void*)mGPUReco->GetDeviceO2Propagator()); - - auto compClusters = pc.inputs().get>("compClusters"); - gsl::span patterns = pc.inputs().get>("patterns"); - gsl::span physTriggers; - std::vector fromTRD; - if (mSpecConfig.itsTriggerType == 2) { // use TRD triggers - o2::InteractionRecord ir{0, pc.services().get().firstTForbit}; - auto trdTriggers = pc.inputs().get>("phystrig"); - for (const auto& trig : trdTriggers) { - if (trig.getBCData() >= ir && trig.getNumberOfTracklets()) { - ir = trig.getBCData(); - fromTRD.emplace_back(o2::itsmft::PhysTrigger{ir, 0}); - } - } - physTriggers = gsl::span(fromTRD.data(), fromTRD.size()); - } else if (mSpecConfig.itsTriggerType == 1) { // use Phys triggers from ITS stream - physTriggers = pc.inputs().get>("phystrig"); - } - - auto rofsinput = pc.inputs().get>("ROframes"); - - auto& rofs = pc.outputs().make>(Output{"ITS", "ITSTrackROF", 0}, rofsinput.begin(), rofsinput.end()); - auto& irFrames = pc.outputs().make>(Output{"ITS", "IRFRAMES", 0}); - irFrames.reserve(rofs.size()); - - const auto& alpParams = o2::itsmft::DPLAlpideParam::Instance(); // RS: this should come from CCDB - int nBCPerTF = alpParams.roFrameLengthInBC; - - LOG(info) << "ITSTracker pulled " << compClusters.size() << " clusters, " << rofs.size() << " RO frames"; - - const dataformats::MCTruthContainer* labels = nullptr; - gsl::span mc2rofs; - if (mSpecConfig.processMC) { - labels = pc.inputs().get*>("itsmclabels").release(); - // get the array as read-only span, a snapshot is sent forward - pc.outputs().snapshot(Output{"ITS", "ITSTrackMC2ROF", 0}, pc.inputs().get>("ITSMC2ROframes")); - LOG(info) << labels->getIndexedSize() << " MC label objects , in " << mc2rofs.size() << " MC events"; - } - - auto& allClusIdx = pc.outputs().make>(Output{"ITS", "TRACKCLSID", 0}); - auto& allTracks = pc.outputs().make>(Output{"ITS", "TRACKS", 0}); - auto& vertROFvec = pc.outputs().make>(Output{"ITS", "VERTICESROF", 0}); - auto& vertices = pc.outputs().make>(Output{"ITS", "VERTICES", 0}); - - // MC - static pmr::vector dummyMCLabTracks, dummyMCLabVerts; - auto& allTrackLabels = mSpecConfig.processMC ? pc.outputs().make>(Output{"ITS", "TRACKSMCTR", 0}) : dummyMCLabTracks; - auto& allVerticesLabels = mSpecConfig.processMC ? pc.outputs().make>(Output{"ITS", "VERTICESMCTR", 0}) : dummyMCLabVerts; - - std::uint32_t roFrame = 0; - - bool continuous = o2::base::GRPGeomHelper::instance().getGRPECS()->isDetContinuousReadOut(o2::detectors::DetID::ITS); - LOG(info) << "ITSTracker RO: continuous=" << continuous; - - if (mSpecConfig.itsOverrBeamEst) { - mITSTimeFrame->setBeamPosition(mMeanVertex->getX(), - mMeanVertex->getY(), - mMeanVertex->getSigmaY2(), - mITSTracker->getParameters()[0].LayerResolution[0], - mITSTracker->getParameters()[0].SystErrorY2[0]); - } - - mITSTracker->setBz(o2::base::Propagator::Instance()->getNominalBz()); - - gsl::span::iterator pattIt = patterns.begin(); - - gsl::span rofspan(rofs); - mITSTimeFrame->loadROFrameData(rofspan, compClusters, pattIt, mITSDict, labels); - pattIt = patterns.begin(); - std::vector savedROF; - auto logger = [&](std::string s) { LOG(info) << s; }; - auto fatalLogger = [&](std::string s) { LOG(fatal) << s; }; - auto errorLogger = [&](std::string s) { LOG(error) << s; }; - - o2::its::FastMultEst multEst; // mult estimator - std::vector processingMask; - int cutVertexMult{0}, cutRandomMult = int(rofs.size()) - multEst.selectROFs(rofs, compClusters, physTriggers, processingMask); - mITSTimeFrame->setMultiplicityCutMask(processingMask); - float vertexerElapsedTime{0.f}; - if (mITSRunVertexer) { - // Run seeding vertexer - vertROFvec.reserve(rofs.size()); - vertexerElapsedTime = mITSVertexer->clustersToVerticesHybrid(logger); - } else { // cosmics - mITSTimeFrame->resetRofPV(); - } - const auto& multEstConf = o2::its::FastMultEstConfig::Instance(); // parameters for mult estimation and cuts - for (auto iRof{0}; iRof < rofspan.size(); ++iRof) { - std::vector vtxVecLoc; - auto& vtxROF = vertROFvec.emplace_back(rofspan[iRof]); - vtxROF.setFirstEntry(vertices.size()); - if (mITSRunVertexer) { - auto vtxSpan = mITSTimeFrame->getPrimaryVertices(iRof); - vtxROF.setNEntries(vtxSpan.size()); - bool selROF = vtxSpan.size() == 0; - for (auto iV{0}; iV < vtxSpan.size(); ++iV) { - auto& v = vtxSpan[iV]; - if (multEstConf.isVtxMultCutRequested() && !multEstConf.isPassingVtxMultCut(v.getNContributors())) { - continue; // skip vertex of unwanted multiplicity - } - selROF = true; - vertices.push_back(v); - if (mSpecConfig.processMC) { - auto vLabels = mITSTimeFrame->getPrimaryVerticesLabels(iRof)[iV]; - allVerticesLabels.reserve(allVerticesLabels.size() + vLabels.size()); - std::copy(vLabels.begin(), vLabels.end(), std::back_inserter(allVerticesLabels)); - } - } - if (processingMask[iRof] && !selROF) { // passed selection in clusters and not in vertex multiplicity - LOG(debug) << fmt::format("ROF {} rejected by the vertex multiplicity selection [{},{}]", - iRof, - multEstConf.cutMultVtxLow, - multEstConf.cutMultVtxHigh); - processingMask[iRof] = selROF; - cutVertexMult++; - } - } else { // cosmics - vtxVecLoc.emplace_back(Vertex()); - vtxVecLoc.back().setNContributors(1); - vtxROF.setNEntries(vtxVecLoc.size()); - for (auto& v : vtxVecLoc) { - vertices.push_back(v); - } - mITSTimeFrame->addPrimaryVertices(vtxVecLoc); - } - } - LOG(info) << fmt::format(" - rejected {}/{} ROFs: random/mult.sel:{} (seed {}), vtx.sel:{}", cutRandomMult + cutVertexMult, rofspan.size(), cutRandomMult, multEst.lastRandomSeed, cutVertexMult); - LOG(info) << fmt::format(" - Vertex seeding total elapsed time: {} ms for {} vertices found in {} ROFs", vertexerElapsedTime, mITSTimeFrame->getPrimaryVerticesNum(), rofspan.size()); - - if (mSpecConfig.itsOverrBeamEst) { - LOG(info) << fmt::format(" - Beam position set to: {}, {} from meanvertex object", mITSTimeFrame->getBeamX(), mITSTimeFrame->getBeamY()); - } else { - LOG(info) << fmt::format(" - Beam position computed for the TF: {}, {}", mITSTimeFrame->getBeamX(), mITSTimeFrame->getBeamY()); - } - if (mITSCosmicsProcessing && compClusters.size() > 1500 * rofspan.size()) { - LOG(error) << "Cosmics processing was requested with an average detector occupancy exceeding 1.e-7, skipping TF processing."; - } else { - - mITSTimeFrame->setMultiplicityCutMask(processingMask); - // Run CA tracker - if (!mSpecConfig.itsTrackingMode) { - mITSTracker->clustersToTracksHybrid(logger, errorLogger); - } else { - mITSTracker->clustersToTracksHybrid(logger, fatalLogger); - } - size_t totTracks{mITSTimeFrame->getNumberOfTracks()}, totClusIDs{mITSTimeFrame->getNumberOfUsedClusters()}; - allTracks.reserve(totTracks); - allClusIdx.reserve(totClusIDs); - - if (mITSTimeFrame->hasBogusClusters()) { - LOG(warning) << fmt::format(" - The processed timeframe had {} clusters with wild z coordinates, check the dictionaries", mITSTimeFrame->hasBogusClusters()); - } - - for (unsigned int iROF{0}; iROF < rofs.size(); ++iROF) { - auto& rof{rofs[iROF]}; - auto& tracks = mITSTimeFrame->getTracks(iROF); - auto number{tracks.size()}; - auto first{allTracks.size()}; - int offset = -rof.getFirstEntry(); // cluster entry!!! - rof.setFirstEntry(first); - rof.setNEntries(number); - - if (processingMask[iROF]) { - irFrames.emplace_back(rof.getBCData(), rof.getBCData() + nBCPerTF - 1).info = tracks.size(); - } - - allTrackLabels.reserve(mITSTimeFrame->getTracksLabel(iROF).size()); // should be 0 if not MC - std::copy(mITSTimeFrame->getTracksLabel(iROF).begin(), mITSTimeFrame->getTracksLabel(iROF).end(), std::back_inserter(allTrackLabels)); - // Some conversions that needs to be moved in the tracker internals - for (unsigned int iTrk{0}; iTrk < tracks.size(); ++iTrk) { - auto& trc{tracks[iTrk]}; - trc.setFirstClusterEntry(allClusIdx.size()); // before adding tracks, create final cluster indices - int ncl = trc.getNumberOfClusters(), nclf = 0; - for (int ic = o2::its::TrackITSExt::MaxClusters; ic--;) { // track internally keeps in->out cluster indices, but we want to store the references as out->in!!! - auto clid = trc.getClusterIndex(ic); - if (clid >= 0) { - allClusIdx.push_back(clid); - nclf++; - } - } - assert(ncl == nclf); - allTracks.emplace_back(trc); - } - } - LOGP(info, "ITSTracker pushed {} tracks and {} vertices", allTracks.size(), vertices.size()); - if (mSpecConfig.processMC) { - LOGP(info, "ITSTracker pushed {} track labels", allTrackLabels.size()); - LOGP(info, "ITSTracker pushed {} vertex labels", allVerticesLabels.size()); - } - } + LOGP(debug, "GPUChainITS is giving me device propagator: {}", (void*)mGPUReco->GetDeviceO2Propagator()); + mITSTrackingInterface->run(pc); return 0; } -void GPURecoWorkflowSpec::initFunctionITS(InitContext& ic) +void GPURecoWorkflowSpec::initFunctionITS(o2::framework::InitContext& ic) { o2::its::VertexerTraits* vtxTraits = nullptr; o2::its::TrackerTraits* trkTraits = nullptr; + mITSTrackingInterface = std::make_unique(mSpecConfig.processMC, + mSpecConfig.itsTriggerType, + mSpecConfig.itsOverrBeamEst); mGPUReco->GetITSTraits(trkTraits, vtxTraits, mITSTimeFrame); - mITSVertexer = std::make_unique(vtxTraits); - mITSTracker = std::make_unique(trkTraits); - mITSVertexer->adoptTimeFrame(*mITSTimeFrame); - mITSTracker->adoptTimeFrame(*mITSTimeFrame); - mITSRunVertexer = true; - mITSCosmicsProcessing = false; - std::vector trackParams; - - if (mSpecConfig.itsTrackingMode == 1) { - trackParams.resize(3); - for (auto& param : trackParams) { - param.ZBins = 64; - param.PhiBins = 32; - param.CellsPerClusterLimit = 1.e3f; - param.TrackletsPerClusterLimit = 1.e3f; - } - trackParams[1].TrackletMinPt = 0.2f; - trackParams[1].CellDeltaTanLambdaSigma *= 2.; - trackParams[2].TrackletMinPt = 0.1f; - trackParams[2].CellDeltaTanLambdaSigma *= 4.; - trackParams[2].MinTrackLength = 4; - LOG(info) << "Initializing tracker in async. phase reconstruction with " << trackParams.size() << " passes"; - } else if (mSpecConfig.itsTrackingMode == 0) { - trackParams.resize(1); - trackParams[0].ZBins = 64; - trackParams[0].PhiBins = 32; - trackParams[0].MinTrackLength = 4; - LOG(info) << "Initializing tracker in sync. phase reconstruction with " << trackParams.size() << " passes"; - } else if (mSpecConfig.itsTrackingMode == 2) { - mITSCosmicsProcessing = true; - mITSRunVertexer = false; - trackParams.resize(1); - trackParams[0].MinTrackLength = 4; - trackParams[0].CellDeltaTanLambdaSigma *= 10; - trackParams[0].PhiBins = 4; - trackParams[0].ZBins = 16; - trackParams[0].PVres = 1.e5f; - trackParams[0].MaxChi2ClusterAttachment = 60.; - trackParams[0].MaxChi2NDF = 40.; - trackParams[0].TrackletsPerClusterLimit = 100.; - trackParams[0].CellsPerClusterLimit = 100.; - LOG(info) << "Initializing tracker in reconstruction for cosmics with " << trackParams.size() << " passes"; - } - - for (auto& params : trackParams) { - params.CorrType = o2::base::PropagatorImpl::MatCorrType::USEMatCorrLUT; - } - mITSTracker->setParameters(trackParams); + mITSTrackingInterface->setTraitsFromProvider(vtxTraits, trkTraits, mITSTimeFrame); + mITSTrackingInterface->initialise(); } -void GPURecoWorkflowSpec::finaliseCCDBITS(ConcreteDataMatcher& matcher, void* obj) +void GPURecoWorkflowSpec::finaliseCCDBITS(o2::framework::ConcreteDataMatcher& matcher, void* obj) { - if (matcher == ConcreteDataMatcher("ITS", "CLUSDICT", 0)) { - LOG(info) << "cluster dictionary updated"; - mITSDict = (const o2::itsmft::TopologyDictionary*)obj; - return; - } - // Note: strictly speaking, for Configurable params we don't need finaliseCCDB check, the singletons are updated at the CCDB fetcher level - if (matcher == ConcreteDataMatcher("ITS", "ALPIDEPARAM", 0)) { - LOG(info) << "Alpide param updated"; - const auto& par = o2::itsmft::DPLAlpideParam::Instance(); - par.printKeyValues(); - return; - } - if (matcher == ConcreteDataMatcher("GLO", "MEANVERTEX", 0)) { - LOGP(info, "mean vertex acquired"); - if (obj) { - mMeanVertex = (const o2::dataformats::MeanVertexObject*)obj; - } - return; - } + mITSTrackingInterface->finaliseCCDB(matcher, obj); } -bool GPURecoWorkflowSpec::fetchCalibsCCDBITS(ProcessingContext& pc) +bool GPURecoWorkflowSpec::fetchCalibsCCDBITS(o2::framework::ProcessingContext& pc) { - static bool initOnceDone = false; - if (!initOnceDone) { // this params need to be queried only once - initOnceDone = true; - pc.inputs().get("itscldict"); // just to trigger the finaliseCCDB - pc.inputs().get*>("itsalppar"); - mITSVertexer->getGlobalConfiguration(); - mITSTracker->getGlobalConfiguration(); - if (mSpecConfig.itsOverrBeamEst) { - pc.inputs().get("meanvtx"); - } - } + mITSTrackingInterface->updateTimeDependentParams(pc); return false; } - } // namespace o2::gpu diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 91cade4e9d621..af65de4ce5c48 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -52,6 +52,7 @@ #include "GPUO2InterfaceConfiguration.h" #include "GPUO2InterfaceQA.h" #include "GPUO2Interface.h" +#include "GPUO2InterfaceUtils.h" #include "CalibdEdxContainer.h" #include "GPUNewCalibValues.h" #include "TPCPadGainCalib.h" @@ -75,8 +76,7 @@ #include "CommonUtils/DebugStreamer.h" #include "GPUReconstructionConvert.h" #include "DetectorsRaw/RDHUtils.h" -#include "ITStracking/Tracker.h" -#include "ITStracking/Vertexer.h" +#include "ITStracking/TrackingInterface.h" #include "GPUWorkflowInternal.h" // #include "Framework/ThreadPool.h" @@ -97,6 +97,7 @@ #include #include #include +#include using namespace o2::framework; using namespace o2::header; @@ -133,7 +134,7 @@ void GPURecoWorkflowSpec::init(InitContext& ic) GPUO2InterfaceConfiguration& config = *mConfig.get(); // Create configuration object and fill settings - mConfig->configGRP.solenoidBz = 0; + mConfig->configGRP.solenoidBzNominalGPU = 0; mTFSettings->hasSimStartOrbit = 1; auto& hbfu = o2::raw::HBFUtils::Instance(); mTFSettings->simStartOrbit = hbfu.getFirstIRofTF(o2::InteractionRecord(0, hbfu.orbitFirstSampled)).orbit; @@ -152,7 +153,7 @@ void GPURecoWorkflowSpec::init(InitContext& ic) mConfig->configProcessing.doublePipeline = 1; } - mAutoSolenoidBz = mConfParam->solenoidBz == -1e6f; + mAutoSolenoidBz = mConfParam->solenoidBzNominalGPU == -1e6f; mAutoContinuousMaxTimeBin = mConfig->configGRP.continuousMaxTimeBin == -1; if (mAutoContinuousMaxTimeBin) { mConfig->configGRP.continuousMaxTimeBin = (256 * o2::constants::lhc::LHCMaxBunches + 2 * o2::tpc::constants::LHCBCPERTIMEBIN - 2) / o2::tpc::constants::LHCBCPERTIMEBIN; @@ -271,7 +272,7 @@ void GPURecoWorkflowSpec::init(InitContext& ic) mConfig->configCalib.trdGeometry = mTRDGeometry.get(); } - mConfig->configProcessing.internalO2PropagatorGPUField = true; + mConfig->configProcessing.o2PropagatorUseGPUField = true; if (mConfParam->printSettings) { mConfig->PrintParam(); @@ -320,11 +321,11 @@ void GPURecoWorkflowSpec::init(InitContext& ic) mode_t mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; fd = open("/tmp/o2_gpu_memlock_mutex.lock", O_RDWR | O_CREAT | O_CLOEXEC, mask); if (fd == -1) { - throw std::runtime_error("Error opening lock file"); + throw std::runtime_error("Error opening memlock mutex lock file"); } fchmod(fd, mask); if (lockf(fd, F_LOCK, 0)) { - throw std::runtime_error("Error locking file"); + throw std::runtime_error("Error locking memlock mutex file"); } } std::chrono::time_point start, end; @@ -341,7 +342,7 @@ void GPURecoWorkflowSpec::init(InitContext& ic) } if (mConfParam->mutexMemReg) { if (lockf(fd, F_ULOCK, 0)) { - throw std::runtime_error("Error unlocking file"); + throw std::runtime_error("Error unlocking memlock mutex file"); } close(fd); } @@ -374,11 +375,6 @@ void GPURecoWorkflowSpec::finaliseCCDB(o2::framework::ConcreteDataMatcher& match mGRPGeomUpdated = true; return; } - if (matcher == ConcreteDataMatcher("ITS", "GEOMTGEO", 0)) { - LOG(info) << "ITS GeomtetryTGeo loaded from ccdb"; - o2::its::GeometryTGeo::adopt((o2::its::GeometryTGeo*)obj); - return; - } } template @@ -683,21 +679,23 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) using outputBufferUninitializedVector = std::decay_t>(Output{"", "", 0}))>; using outputBufferType = std::pair>, outputDataType*>; std::vector outputBuffers(GPUInterfaceOutputs::count(), {std::nullopt, nullptr}); + std::unordered_set outputsCreated; - auto setOutputAllocator = [this, &outputBuffers, &outputRegions, &pc](const char* name, bool condition, GPUOutputControl& region, auto&& outputSpec, size_t offset = 0) { + auto setOutputAllocator = [this, &outputBuffers, &outputRegions, &pc, &outputsCreated](const char* name, bool condition, GPUOutputControl& region, auto&& outputSpec, size_t offset = 0) { if (condition) { auto& buffer = outputBuffers[outputRegions.getIndex(region)]; if (mConfParam->allocateOutputOnTheFly) { - region.allocator = [this, name, &buffer, &pc, outputSpec = std::move(outputSpec), offset](size_t size) -> void* { + region.allocator = [this, name, &buffer, &pc, outputSpec = std::move(outputSpec), offset, &outputsCreated](size_t size) -> void* { size += offset; if (mVerbosity) { - LOG(info) << "ALLOCATING " << size << " bytes for " << std::get(outputSpec).template as() << "/" << std::get(outputSpec).template as() << "/" << std::get<2>(outputSpec); + LOG(info) << "ALLOCATING " << size << " bytes for " << name << ": " << std::get(outputSpec).template as() << "/" << std::get(outputSpec).template as() << "/" << std::get<2>(outputSpec); } std::chrono::time_point start, end; if (mVerbosity) { start = std::chrono::high_resolution_clock::now(); } buffer.first.emplace(pc.outputs().make>(std::make_from_tuple(outputSpec), size)); + outputsCreated.insert(name); if (mVerbosity) { end = std::chrono::high_resolution_clock::now(); std::chrono::duration elapsed_seconds = end - start; @@ -710,6 +708,7 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) buffer.first.emplace(pc.outputs().make>(std::make_from_tuple(outputSpec), mConfParam->outputBufferSize)); region.ptrBase = (buffer.second = buffer.first->get().data()) + offset; region.size = buffer.first->get().size() - offset; + outputsCreated.insert(name); } } }; @@ -847,10 +846,6 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) } } - if (mConfig->configReconstruction.tpc.occupancyMapTimeBins == 0) { - pc.outputs().make>({gDataOriginTPC, "TPCOCCUPANCYMAP", 0}, 0u); - } - std::unique_ptr tmpEmptyClNative; if (createEmptyOutput) { memset(&ptrs, 0, sizeof(ptrs)); @@ -976,7 +971,10 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) pc.outputs().snapshot({gDataOriginGPU, "ERRORQA", 0}, mErrorQA); mErrorQA.clear(); // FIXME: This is a race condition once we run multi-threaded! } - if (mSpecConfig.tpcTriggerHandling && !mSpecConfig.caClusterer) { + if (mSpecConfig.outputSharedClusterMap && !outputsCreated.contains("TPCOCCUPANCYMAP")) { + pc.outputs().make>({gDataOriginTPC, "TPCOCCUPANCYMAP", 0}, 0u); + } + if (mSpecConfig.tpcTriggerHandling && !outputsCreated.contains("TRIGGERWORDS")) { pc.outputs().make>(Output{gDataOriginTPC, "TRIGGERWORDS", 0}, 0u); } mTimer->Stop(); @@ -1001,7 +999,8 @@ void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc, c if (mAutoSolenoidBz) { newCalibValues.newSolenoidField = true; - newCalibValues.solenoidField = mConfig->configGRP.solenoidBz = (5.00668f / 30000.f) * GRPGeomHelper::instance().getGRPMagField()->getL3Current(); + newCalibValues.solenoidField = mConfig->configGRP.solenoidBzNominalGPU = GPUO2InterfaceUtils::getNominalGPUBz(*GRPGeomHelper::instance().getGRPMagField()); + // Propagator::Instance()->setBz(newCalibValues.solenoidField); // Take value from o2::Propagator::UpdateField from GRPGeomHelper LOG(info) << "Updating solenoid field " << newCalibValues.solenoidField; } if (mAutoContinuousMaxTimeBin) { @@ -1013,8 +1012,8 @@ void GPURecoWorkflowSpec::doCalibUpdates(o2::framework::ProcessingContext& pc, c if (!mPropagatorInstanceCreated) { newCalibObjects.o2Propagator = mConfig->configCalib.o2Propagator = Propagator::Instance(); - if (mAutoSolenoidBz) { - Propagator::Instance()->setBz(newCalibValues.solenoidField); + if (mConfig->configProcessing.o2PropagatorUseGPUField) { + mGPUReco->UseGPUPolynomialFieldInPropagator(Propagator::Instance()); } mPropagatorInstanceCreated = true; } diff --git a/GPU/Workflow/src/O2GPUDPLDisplay.cxx b/GPU/Workflow/src/O2GPUDPLDisplay.cxx index b334296dd4413..4d3510391046d 100644 --- a/GPU/Workflow/src/O2GPUDPLDisplay.cxx +++ b/GPU/Workflow/src/O2GPUDPLDisplay.cxx @@ -22,6 +22,7 @@ #include "ITSBase/GeometryTGeo.h" #include "DetectorsBase/Propagator.h" #include "GPUO2InterfaceDisplay.h" +#include "GPUO2InterfaceUtils.h" #include "GPUO2InterfaceConfiguration.h" #include "TPCFastTransform.h" #include "TPCReconstruction/TPCFastTransformHelperO2.h" @@ -62,7 +63,7 @@ void O2GPUDPLDisplaySpec::init(InitContext& ic) { GRPGeomHelper::instance().setRequest(mGGR); mConfig.reset(new GPUO2InterfaceConfiguration); - mConfig->configGRP.solenoidBz = 0; + mConfig->configGRP.solenoidBzNominalGPU = 0; mConfParam.reset(new GPUSettingsO2(mConfig->ReadConfigurableParam())); mFastTransformHelper.reset(new o2::tpc::CorrectionMapsLoader()); @@ -113,7 +114,7 @@ void O2GPUDPLDisplaySpec::run(ProcessingContext& pc) if (mGRPGeomUpdated) { mGRPGeomUpdated = false; - mConfig->configGRP.solenoidBz = 5.00668f * grp->getL3Current() / 30000.; + mConfig->configGRP.solenoidBzNominalGPU = GPUO2InterfaceUtils::getNominalGPUBz(*grp); if (mAutoContinuousMaxTimeBin) { mConfig->configGRP.continuousMaxTimeBin = (mTFSettings->nHBFPerTF * o2::constants::lhc::LHCMaxBunches + 2 * o2::tpc::constants::LHCBCPERTIMEBIN - 2) / o2::tpc::constants::LHCBCPERTIMEBIN; } diff --git a/GPU/Workflow/src/gpu-reco-workflow.cxx b/GPU/Workflow/src/gpu-reco-workflow.cxx index 9e610331a3aa3..aef7694ac5de7 100644 --- a/GPU/Workflow/src/gpu-reco-workflow.cxx +++ b/GPU/Workflow/src/gpu-reco-workflow.cxx @@ -107,6 +107,7 @@ enum struct ioType { Digits, SendClustersPerSector, ITSClusters, ITSTracks, + MeanVertex, TPCTriggers }; static const std::unordered_map InputMap{ @@ -117,7 +118,9 @@ static const std::unordered_map InputMap{ {"compressed-clusters-root", ioType::CompClustROOT}, {"compressed-clusters-ctf", ioType::CompClustCTF}, {"trd-tracklets", ioType::TRDTracklets}, - {"its-clusters", ioType::ITSClusters}}; + {"its-clusters", ioType::ITSClusters}, + {"its-mean-vertex", ioType::MeanVertex}, +}; static const std::unordered_map OutputMap{ {"clusters", ioType::Clusters}, @@ -183,6 +186,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) cfg.enableDoublePipeline = cfgc.options().get("enableDoublePipeline"); cfg.tpcDeadMapSources = cfgc.options().get("tpc-deadMap-sources"); cfg.runITSTracking = isEnabled(outputTypes, ioType::ITSTracks); + cfg.itsOverrBeamEst = isEnabled(inputTypes, ioType::MeanVertex); Inputs ggInputs; auto ggRequest = std::make_shared(false, true, false, true, true, o2::base::GRPGeomRequest::Aligned, ggInputs, true); diff --git a/Generators/CMakeLists.txt b/Generators/CMakeLists.txt index ec9e7af0756e2..3f6509b7db408 100644 --- a/Generators/CMakeLists.txt +++ b/Generators/CMakeLists.txt @@ -32,6 +32,7 @@ o2_add_library(Generators src/TriggerExternalParam.cxx src/TriggerParticleParam.cxx src/BoxGunParam.cxx + src/BoxGenerator.cxx src/QEDGenParam.cxx src/GenCosmicsParam.cxx src/GeneratorFactory.cxx @@ -80,6 +81,7 @@ set(headers include/Generators/GeneratorTParticle.h include/Generators/GeneratorTParticleParam.h include/Generators/GeneratorService.h + include/Generators/BoxGenerator.h ) if(pythia_FOUND) diff --git a/Generators/include/Generators/BoxGenerator.h b/Generators/include/Generators/BoxGenerator.h new file mode 100644 index 0000000000000..4198a1ac4ccb3 --- /dev/null +++ b/Generators/include/Generators/BoxGenerator.h @@ -0,0 +1,113 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author Sandro Wenzel - April 2024 + +#ifndef ALICEO2_EVENTGEN_BOX +#define ALICEO2_EVENTGEN_BOX + +#include "Generators/Generator.h" +#include "TParticle.h" +#include + +namespace o2::eventgen +{ + +/* + * A simple mono-pdg "BoxGenerator". Or particle gun. + * Re-implements FairBoxGenerator for more convenient O2-processing. + */ +class BoxGenerator : public Generator +{ + public: + BoxGenerator() = default; + BoxGenerator(int pdgid, int mult = 1); + + BoxGenerator(int pdgid, + int mult, + double etamin, + double etamax, + double pmin, + double pmax, + double phimin, + double phimax) : mPDG{pdgid}, mMult{mult} + { + SetEtaRange(etamin, etamax); + SetPRange(pmin, pmax); + SetPhiRange(phimin, phimax); + } + + void SetPRange(Double32_t pmin = 0, Double32_t pmax = 10) + { + mPMin = pmin; + mPMax = pmax; + mPRangeIsSet = true; + } + + void SetPhiRange(double phimin = 0, double phimax = 360) + { + mPhiMin = phimin; + mPhiMax = phimax; + } + + void SetEtaRange(double etamin = -5, double etamax = 5) + { + mEtaMin = etamin; + mEtaMax = etamax; + mEtaRangeIsSet = true; + } + + /// generates a single particle conforming to particle gun parameters + TParticle sampleParticle() const; + + /// implements the main O2 generator interfaces + bool generateEvent() override + { + mEvent.clear(); + for (int i = 0; i < mMult; ++i) { + mEvent.push_back(sampleParticle()); + } + return true; + } + bool importParticles() override + { + mParticles.clear(); + std::copy(mEvent.begin(), mEvent.end(), std::back_insert_iterator(mParticles)); + return true; + } + + private: + double mPtMin{0.}, mPtMax{0.}; // Transverse momentum range [GeV] + double mPhiMin{0.}, mPhiMax{360.}; // Azimuth angle range [degree] + double mEtaMin{0.}, mEtaMax{0.}; // Pseudorapidity range in lab system + double mYMin{0.}, mYMax{0.}; // Rapidity range in lab system + double mPMin{0.}, mPMax{0.}; // Momentum range in lab system + double mThetaMin{0.}, mThetaMax{0.}; // Polar angle range in lab system [degree] + double mEkinMin{0.}, mEkinMax{0.}; // Kinetic Energy range in lab system [GeV] + + int mPDG{0}; + int mMult{1}; + + bool mEtaRangeIsSet{false}; // True if eta range is set + bool mYRangeIsSet{false}; // True if rapidity range is set + bool mThetaRangeIsSet{false}; // True if theta range is set + bool mCosThetaIsSet{false}; // True if uniform distribution in + // cos(theta) is set (default -> not set) + bool mPtRangeIsSet{false}; // True if transverse momentum range is set + bool mPRangeIsSet{false}; // True if abs.momentum range is set + bool mEkinRangeIsSet{false}; // True if kinetic energy range is set + + std::vector mEvent; // internal event container +}; + +} // namespace o2::eventgen + +#endif diff --git a/Generators/include/Generators/Generator.h b/Generators/include/Generators/Generator.h index 3b3e056efe3ae..a488e31ace2b9 100644 --- a/Generators/include/Generators/Generator.h +++ b/Generators/include/Generators/Generator.h @@ -71,8 +71,8 @@ class Generator : public FairGenerator Bool_t ReadEvent(FairPrimaryGenerator* primGen) final; /** methods to override **/ - virtual Bool_t generateEvent() = 0; - virtual Bool_t importParticles() = 0; + virtual Bool_t generateEvent() = 0; // generates event (in structure internal to generator) + virtual Bool_t importParticles() = 0; // fills the mParticles vector (transfer from generator state) /** setters **/ void setMomentumUnit(double val) { mMomentumUnit = val; }; diff --git a/Generators/include/Generators/GeneratorFromFile.h b/Generators/include/Generators/GeneratorFromFile.h index b75279cf3319f..42656baddd402 100644 --- a/Generators/include/Generators/GeneratorFromFile.h +++ b/Generators/include/Generators/GeneratorFromFile.h @@ -88,11 +88,15 @@ class GeneratorFromO2Kine : public o2::eventgen::Generator TFile* mEventFile = nullptr; //! the file containing the persistent events TBranch* mEventBranch = nullptr; //! the branch containing the persistent events + TBranch* mMCHeaderBranch = nullptr; //! branch containing MC event headers int mEventCounter = 0; int mEventsAvailable = 0; bool mSkipNonTrackable = true; //! whether to pass non-trackable (decayed particles) to the MC stack bool mContinueMode = false; //! whether we want to continue simulation of previously inhibited tracks bool mRoundRobin = false; //! whether we want to take events from file in a round robin fashion + + std::unique_ptr mOrigMCEventHeader; //! the MC event header of the original file + ClassDefOverride(GeneratorFromO2Kine, 2); }; diff --git a/Generators/src/BoxGenerator.cxx b/Generators/src/BoxGenerator.cxx new file mode 100644 index 0000000000000..478934d98c621 --- /dev/null +++ b/Generators/src/BoxGenerator.cxx @@ -0,0 +1,78 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// \author Sandro Wenzel - April 2024 + +#include "Generators/BoxGenerator.h" +#include "TRandom.h" +#include "TDatabasePDG.h" + +using namespace o2::eventgen; + +double GetPDGMass(int pdg) +{ + static TDatabasePDG* pid = TDatabasePDG::Instance(); + TParticlePDG* p = pid->GetParticle(pdg); + if (p != nullptr) { + // LOG(info) << this->ClassName() << ": particle with PDG =" << GetPDGType() << " Found"; + return p->Mass(); // fPDGMass = p->Mass(); + } + // LOG(warn) << "pdg not known"; + return 0.; +} + +TParticle o2::eventgen::BoxGenerator::sampleParticle() const +{ + // Primary particles are distributed uniformly along + // those kinematics variables which were limitted by setters. + // if SetCosTheta() function is used, the distribution will be uniform in + // cos(theta) + + static double mass = GetPDGMass(mPDG); + + double pabs = 0, phi, pt = 0, theta = 0, eta, y, mt, px, py, pz = 0; + phi = gRandom->Uniform(mPhiMin, mPhiMax) * TMath::DegToRad(); + if (mPRangeIsSet) { + pabs = gRandom->Uniform(mPMin, mPMax); + } else if (mPtRangeIsSet) { + pt = gRandom->Uniform(mPtMin, mPtMax); + } + if (mThetaRangeIsSet) { + if (mCosThetaIsSet) { + theta = acos(gRandom->Uniform(cos(mThetaMin * TMath::DegToRad()), cos(mThetaMax * TMath::DegToRad()))); + } else { + theta = gRandom->Uniform(mThetaMin, mThetaMax) * TMath::DegToRad(); + } + } else if (mEtaRangeIsSet) { + eta = gRandom->Uniform(mEtaMin, mEtaMax); + theta = 2 * TMath::ATan(TMath::Exp(-eta)); + } else if (mYRangeIsSet) { + y = gRandom->Uniform(mYMin, mYMax); + mt = TMath::Sqrt(mass * mass + pt * pt); + pz = mt * TMath::SinH(y); + } + + if (mThetaRangeIsSet || mEtaRangeIsSet) { + if (mPRangeIsSet) { + pz = pabs * TMath::Cos(theta); + pt = pabs * TMath::Sin(theta); + } else if (mPtRangeIsSet) { + pz = pt / TMath::Tan(theta); + } + } + px = pt * TMath::Cos(phi); + py = pt * TMath::Sin(phi); + + double vx = 0., vy = 0., vz = 0.; + double etot = TMath::Sqrt(px * px + py * py + pz * pz + mass * mass); + return TParticle(mPDG, 1 /*status*/, -1 /* mother1 */, -1 /* mother2 */, + -1 /* daughter1 */, -1 /* daughter2 */, px, py, pz, etot, vx, vy, vz, 0. /*time*/); +} diff --git a/Generators/src/Generator.cxx b/Generators/src/Generator.cxx index 99a00f154c268..530e418add7c4 100644 --- a/Generators/src/Generator.cxx +++ b/Generators/src/Generator.cxx @@ -75,19 +75,23 @@ Bool_t /** generate event **/ if (!generateEvent()) { + LOG(error) << "ReadEvent failed in generateEvent"; return kFALSE; } /** import particles **/ if (!importParticles()) { + LOG(error) << "ReadEvent failed in importParticles"; return kFALSE; } if (mSubGeneratorsIdToDesc.empty() && mSubGeneratorId > -1) { + LOG(error) << "ReadEvent failed because no SubGenerator description given"; return kFALSE; } if (!mSubGeneratorsIdToDesc.empty() && mSubGeneratorId < 0) { + LOG(error) << "ReadEvent failed because SubGenerator description given but sub-generator not set"; return kFALSE; } @@ -102,6 +106,7 @@ Bool_t /** add tracks **/ if (!addTracks(primGen)) { + LOG(error) << "ReadEvent failed in addTracks"; return kFALSE; } diff --git a/Generators/src/GeneratorFromFile.cxx b/Generators/src/GeneratorFromFile.cxx index 39fd809ac5560..069c92ec86c70 100644 --- a/Generators/src/GeneratorFromFile.cxx +++ b/Generators/src/GeneratorFromFile.cxx @@ -181,8 +181,14 @@ GeneratorFromO2Kine::GeneratorFromO2Kine(const char* name) if (mEventBranch) { mEventsAvailable = mEventBranch->GetEntries(); LOG(info) << "Found " << mEventsAvailable << " events in this file"; - return; } + mMCHeaderBranch = tree->GetBranch("MCEventHeader."); + if (mMCHeaderBranch) { + LOG(info) << "Found " << mMCHeaderBranch->GetEntries() << " event-headers"; + } else { + LOG(warn) << "No MCEventHeader branch found in kinematics input file"; + } + return; } LOG(error) << "Problem reading events from file " << name; } @@ -223,6 +229,13 @@ bool GeneratorFromO2Kine::importParticles() mEventBranch->SetAddress(&tracks); mEventBranch->GetEntry(mEventCounter); + if (mMCHeaderBranch) { + o2::dataformats::MCEventHeader* mcheader = nullptr; + mMCHeaderBranch->SetAddress(&mcheader); + mMCHeaderBranch->GetEntry(mEventCounter); + mOrigMCEventHeader.reset(mcheader); + } + for (auto& t : *tracks) { // in case we do not want to continue, take only primaries @@ -281,11 +294,17 @@ void GeneratorFromO2Kine::updateHeader(o2::dataformats::MCEventHeader* eventHead { /** update header **/ - // put information about input file and event number of the current event + // we forward the original header information if any + if (mOrigMCEventHeader.get()) { + eventHeader->copyInfoFrom(*mOrigMCEventHeader.get()); + } + // we forward also the original basic vertex information contained in FairMCEventHeader + static_cast(*eventHeader) = static_cast(*mOrigMCEventHeader.get()); - eventHeader->putInfo("generator", "generatorFromO2Kine"); - eventHeader->putInfo("inputFile", mEventFile->GetName()); - eventHeader->putInfo("inputEventNumber", mEventCounter - 1); + // put additional information about input file and event number of the current event + eventHeader->putInfo("forwarding-generator", "generatorFromO2Kine"); + eventHeader->putInfo("forwarding-generator_inputFile", mEventFile->GetName()); + eventHeader->putInfo("forwarding-generator_inputEventNumber", mEventCounter - 1); } } // namespace eventgen diff --git a/Generators/src/GeneratorsLinkDef.h b/Generators/src/GeneratorsLinkDef.h index 35e77febee172..537b012cee2b2 100644 --- a/Generators/src/GeneratorsLinkDef.h +++ b/Generators/src/GeneratorsLinkDef.h @@ -73,4 +73,6 @@ #pragma link C++ class o2::eventgen::GeneratorFileOrCmdParam + ; #pragma link C++ class o2::conf::ConfigurableParamHelper < o2::eventgen::GeneratorFileOrCmdParam> + ; +#pragma link C++ class o2::eventgen::BoxGenerator + ; + #endif diff --git a/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx index 0adb9eb0a90df..2e888166d16fc 100644 --- a/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/HMPIDDigitizerSpec.cxx @@ -34,7 +34,6 @@ using namespace o2::framework; using SubSpecificationType = o2::framework::DataAllocator::SubSpecificationType; - namespace o2 { namespace hmpid @@ -102,34 +101,32 @@ class HMPIDDPLDigitizerTask : public o2::base::BaseDPLDigitizer // try to start new readout cycle by setting the trigger time auto triggeraccepted = mDigitizer.setTriggerTime(irecords[collID].getTimeNS()); if (triggeraccepted) { - flushDigitsAndLabels(); // flush previous readout cycle - } - auto withinactivetime = mDigitizer.setEventTime(irecords[collID].getTimeNS()); - if (withinactivetime) { - // for each collision, loop over the constituents event and source IDs - // (background signal merging is basically taking place here) - for (auto& part : eventParts[collID]) { - mDigitizer.setEventID(part.entryID); - mDigitizer.setSrcID(part.sourceID); - - // get the hits for this event and this source - std::vector hits; - context->retrieveHits(mSimChains, "HMPHit", part.sourceID, part.entryID, &hits); - LOG(info) << "For collision " << collID << " eventID " << part.entryID << " found HMP " << hits.size() << " hits "; - - mDigitizer.setLabelContainer(&mLabels); - mLabels.clear(); - mDigits.clear(); - - mDigitizer.process(hits, mDigits); + auto withinactivetime = mDigitizer.setEventTime(irecords[collID].getTimeNS()); + if (withinactivetime) { + // for each collision, loop over the constituents event and source IDs + // (background signal merging is basically taking place here) + for (auto& part : eventParts[collID]) { + mDigitizer.setEventID(part.entryID); + mDigitizer.setSrcID(part.sourceID); + + // get the hits for this event and this source + std::vector hits; + context->retrieveHits(mSimChains, "HMPHit", part.sourceID, part.entryID, &hits); + LOG(info) << "For collision " << collID << " eventID " << part.entryID << " found HMP " << hits.size() << " hits "; + + mDigitizer.setLabelContainer(&mLabels); + mLabels.clear(); + mDigits.clear(); + + mDigitizer.process(hits, mDigits); + } + + flushDigitsAndLabels(); // flush previous readout cycle + } else { + LOG(info) << "COLLISION " << collID << "FALLS WITHIN A DEAD TIME"; } - - } else { - LOG(info) << "COLLISION " << collID << "FALLS WITHIN A DEAD TIME"; } } - // final flushing step; getting everything not yet written out - flushDigitsAndLabels(); // send out to next stage pc.outputs().snapshot(Output{"HMP", "DIGITS", 0}, digitsAccum); diff --git a/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx index 187c24f962c1f..2cd17ba16f5d5 100644 --- a/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/MCHDigitizerSpec.cxx @@ -45,7 +45,7 @@ namespace mch class MCHDPLDigitizerTask : public o2::base::BaseDPLDigitizer { public: - MCHDPLDigitizerTask() : o2::base::BaseDPLDigitizer(o2::base::InitServices::GEOM) {} + MCHDPLDigitizerTask() : o2::base::BaseDPLDigitizer(o2::base::InitServices::FIELD | o2::base::InitServices::GEOM) {} void initDigitizerTask(framework::InitContext& ic) override { diff --git a/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx b/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx index 523c1f2cf6af7..a30294a240fb0 100644 --- a/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx +++ b/Steer/DigitizerWorkflow/src/SimpleDigitizerWorkflow.cxx @@ -228,6 +228,18 @@ void customize(std::vector& policies) policies.push_back({"prompt-for-simreader", matcher, DispatchOp::WhenReady}); } +void setTimingInfoInHeaders(o2::header::DataHeader& dh, o2::framework::DataProcessingHeader& dph) +{ + const auto& hbfu = o2::raw::HBFUtils::Instance(); + const auto offset = int64_t(hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).orbit); + const auto increment = int64_t(hbfu.nHBFPerTF); + const auto startTime = hbfu.startTime; + const auto orbitFirst = hbfu.orbitFirst; + dh.firstTForbit = offset + increment * dh.tfCounter; + dh.runNumber = hbfu.runNumber; + dph.creation = startTime + (dh.firstTForbit - orbitFirst) * o2::constants::lhc::LHCOrbitMUS * 1.e-3; +} + void customize(std::vector& policies) { // we customize the time information sent in DPL headers @@ -239,17 +251,10 @@ void customize(std::vector& policies) // simple linear enumeration from already updated HBFUtils (set via config key values) service.set( [](o2::header::DataHeader& dh, o2::framework::DataProcessingHeader& dph) { - const auto& hbfu = o2::raw::HBFUtils::Instance(); - const auto offset = int64_t(hbfu.getFirstIRofTF({0, hbfu.orbitFirstSampled}).orbit); - const auto increment = int64_t(hbfu.nHBFPerTF); - const auto startTime = hbfu.startTime; - const auto orbitFirst = hbfu.orbitFirst; - dh.firstTForbit = offset + increment * dh.tfCounter; - LOG(info) << "Setting firstTForbit to " << dh.firstTForbit; - dh.runNumber = hbfu.runNumber; - LOG(info) << "Setting runNumber to " << dh.runNumber; - dph.creation = startTime + (dh.firstTForbit - orbitFirst) * o2::constants::lhc::LHCOrbitMUS * 1.e-3; - LOG(info) << "Setting timeframe creation time to " << dph.creation; + setTimingInfoInHeaders(dh, dph); + LOG(info) << "Setting DPL-header firstTForbit to " << dh.firstTForbit; + LOG(info) << "Setting DPL-header runNumber to " << dh.runNumber; + LOG(info) << "Setting DPL-header timeframe creation time to " << dph.creation; }); }} // end of struct ); @@ -486,7 +491,13 @@ WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) // init on a high level, the time for the CCDB queries // we expect that digitizers do not play with the manager themselves // this will only be needed until digitizers take CCDB objects via DPL mechanism - o2::ccdb::BasicCCDBManager::instance().setTimestamp(hbfu.startTime); + + // fix the timestamp for CCDB manager in the same way as for DPL-CCDB-fetcher + o2::header::DataHeader dh; + o2::framework::DataProcessingHeader dph; + setTimingInfoInHeaders(dh, dph); + LOG(info) << "Setting timestamp of BasicCCDBManager to " << dph.creation; + o2::ccdb::BasicCCDBManager::instance().setTimestamp(dph.creation); // activate caching o2::ccdb::BasicCCDBManager::instance().setCaching(true); // this is asking the manager to check validity only locally - no further query to server done diff --git a/Steer/src/O2MCApplication.cxx b/Steer/src/O2MCApplication.cxx index 64fe2281ed1b5..e06faaf26bd63 100644 --- a/Steer/src/O2MCApplication.cxx +++ b/Steer/src/O2MCApplication.cxx @@ -351,6 +351,22 @@ void addSpecialParticles() // f2(1270) (PDG: width = 185 MeV) TVirtualMC::GetMC()->DefineParticle(225, "f2_1270", kPTNeutron, 1.275, 0.0, 3.558e-24, "Hadron", 0.185, 4, 1, 1, 0, 0, 1, 0, 0, kTRUE); + // f1(1285) (PDG: width = 24.20 MeV) Spin/Parity might not be correct + TVirtualMC::GetMC()->DefineParticle(20223, "f1_1285", kPTNeutron, 1.28210, 0.0, 1e-24, "Hadron", 0.02420, 3, 1, 0, 0, 0, 0, 0, 1, kTRUE); + // f1(1420) (PDG: width = 54 MeV) Spin/Parity might not be correct + TVirtualMC::GetMC()->DefineParticle(20333, "f1_1420", kPTNeutron, 1.42640, 0.0, 1e-24, "Hadron", 0.05490, 3, 1, 0, 0, 0, 0, 0, 1, kTRUE); + + // Glueball hunting family + // Their life times are not known, so we set them to 1e-24 + // f0(1370) (PDG: width = 200-500 MeV) Spin/Parity might not be correct + TVirtualMC::GetMC()->DefineParticle(10221, "f0_1370", kPTNeutron, 1.37, 0.0, 1e-24, "Hadron", 0.2, 1, 1, 1, 0, 0, 1, 0, 0, kTRUE); + // f0(1500) (PDG: width = 112 MeV) Spin/Parity might not be correct + TVirtualMC::GetMC()->DefineParticle(9030221, "f0_1500", kPTNeutron, 1.506, 0.0, 1e-24, "Hadron", 0.112, 0, 1, 1, 0, 0, 1, 0, 0, kTRUE); + // f0(1710) (PDG: width = 139 MeV) Spin/Parity might not be correct + TVirtualMC::GetMC()->DefineParticle(10331, "f0_1710", kPTNeutron, 1.71, 0.0, 1e-24, "Hadron", 0.139, 1, 1, 1, 0, 0, 1, 0, 0, kTRUE); + // f2(1525) (PDG: width = 73 MeV) Spin/Parity might not be correct + TVirtualMC::GetMC()->DefineParticle(335, "f2_1525", kPTNeutron, 1.525, 0.0, 1e-24, "Hadron", 0.073, 5, 1, 1, 0, 0, 1, 0, 0, kTRUE); + // Xi_0(1820) TVirtualMC::GetMC()->DefineParticle(123324, "Xi_0_1820", kPTNeutron, 1.8234, 0.0, 2.742550e-23, "Hadron", 0.024, 3, -1, 0, 1, 1, 0, 0, 1, kTRUE); TVirtualMC::GetMC()->DefineParticle(-123324, "Xi_0_Bar_1820", kPTNeutron, 1.8234, 0.0, 2.742550e-23, "Hadron", 0.024, 3, -1, 0, 1, -1, 0, 0, -1, kTRUE); @@ -1135,78 +1151,153 @@ void addSpecialParticles() TVirtualMC::GetMC()->SetDecayMode(225, bratio, mode); + // Define the 2-body phase space decay for the resonances: f0(1500), f2(1525), f0(1710 + for (Int_t kz = 0; kz < 6; kz++) { + bratio[kz] = 0.; + mode[kz][0] = 0; + mode[kz][1] = 0; + mode[kz][2] = 0; + } + bratio[0] = 100.; + mode[0][0] = 310; // K0s + mode[0][1] = 310; // K0s + + TVirtualMC::GetMC()->SetDecayMode(9030221, bratio, mode); // f0(1500) + TVirtualMC::GetMC()->SetDecayMode(335, bratio, mode); // f2(1525) + TVirtualMC::GetMC()->SetDecayMode(10331, bratio, mode); // f0(1710) + TVirtualMC::GetMC()->SetDecayMode(10221, bratio, mode); // f0(1370) + + // Define the 3-body phase space decay for the resonances: f1(1285), f1(1420) + for (Int_t kz = 0; kz < 6; kz++) { + bratio[kz] = 0.; + mode[kz][0] = 0; + mode[kz][1] = 0; + mode[kz][2] = 0; + } + + bratio2[0] = 50.; + mode[0][0] = 310; // K0s + mode[0][1] = -321; // anti-K + mode[0][2] = 211; // pion+ + + bratio2[1] = 50.; + mode[1][0] = 310; // K0s + mode[1][1] = 321; // K + mode[1][2] = -211; // pion- + + TVirtualMC::GetMC()->SetDecayMode(20223, bratio2, mode); // f1(1285) + TVirtualMC::GetMC()->SetDecayMode(20333, bratio2, mode); // f1(1420) + // Lambda1520/Lambda1520bar - TVirtualMC::GetMC()->DefineParticle(3124, "Lambda1520", kPTNeutron, 1.5195, 0.0, 4.22e-23, "Hadron", 0.0156, 3, -1, 0, 0, 0, 0, 0, 1, kTRUE); - TVirtualMC::GetMC()->DefineParticle(-3124, "Lambda1520bar", kPTNeutron, 1.5195, 0.0, 4.22e-23, "Hadron", 0.0156, 3, -1, 0, 0, 0, 0, 0, -1, kTRUE); + TVirtualMC::GetMC()->DefineParticle(102134, "Lambda1520", kPTNeutron, 1.5195, 0.0, 4.22e-23, "Hadron", 0.0156, 3, -1, 0, 0, 0, 0, 0, 1, kTRUE); + TVirtualMC::GetMC()->DefineParticle(-102134, "Lambda1520bar", kPTNeutron, 1.5195, 0.0, 4.22e-23, "Hadron", 0.0156, 3, -1, 0, 0, 0, 0, 0, -1, kTRUE); // Lambda1520 decay modes + Int_t lmode[9][3]; + Float_t lbratio[9]; + for (Int_t kz = 0; kz < 9; kz++) { + lbratio[kz] = 0.; + lmode[kz][0] = 0; + lmode[kz][1] = 0; + lmode[kz][2] = 0; + } // L(1520) -> p K- - bratio[0] = 0.223547; - mode[0][0] = 2212; - mode[0][1] = -321; + lbratio[0] = 0.229944; + lmode[0][0] = 2212; + lmode[0][1] = -321; // L(1520) -> n K0 - bratio[1] = 0.223547; - mode[1][0] = 2112; - mode[1][1] = -311; + lbratio[1] = 0.229944; + lmode[1][0] = 2112; + lmode[1][1] = -311; // L(1520) -> Sigma+ pi- - bratio[2] = 0.139096; - mode[2][0] = 3222; - mode[2][1] = -211; + lbratio[2] = 0.143076; + lmode[2][0] = 3222; + lmode[2][1] = -211; // L(1520) -> Sigma0 pi0 - bratio[3] = 0.139096; - mode[3][0] = 3212; - mode[3][1] = 111; + lbratio[3] = 0.143076; + lmode[3][0] = 3212; + lmode[3][1] = 111; // L(1520) -> Sigma- pi+ - bratio[4] = 0.139096; - mode[4][0] = 3112; - mode[4][1] = 211; + lbratio[4] = 0.143076; + lmode[4][0] = 3112; + lmode[4][1] = 211; + + // L(1520) -> Sigma*- pi+ + lbratio[5] = 0.034066; + lmode[5][0] = 3114; + lmode[5][1] = 211; + + // L(1520) -> Sigma*0 pi0 + lbratio[6] = 0.034066; + lmode[6][0] = 3214; + lmode[6][1] = 111; - // The other decay modes are neglected - bratio[5] = 0.; - mode[5][0] = 0; - mode[5][1] = 0; + // L(1520) -> Sigma*+ pi- + lbratio[7] = 0.034066; + lmode[7][0] = 3224; + lmode[7][1] = -211; - TVirtualMC::GetMC()->SetDecayMode(3124, bratio, mode); + // L(1520) -> Lambda gamma + lbratio[8] = 0.008687; + lmode[8][0] = 3122; + lmode[8][1] = 22; + + TVirtualMC::GetMC()->SetDecayMode(102134, lbratio, lmode); // Lambda1520bar decay modes // L(1520)bar -> p- K+ - bratio[0] = 0.223547; - mode[0][0] = -2212; - mode[0][1] = 321; + lbratio[0] = 0.229944; + lmode[0][0] = -2212; + lmode[0][1] = 321; // L(1520)bar -> nbar K0bar - bratio[1] = 0.223547; - mode[1][0] = -2112; - mode[1][1] = 311; + lbratio[1] = 0.229944; + lmode[1][0] = -2112; + lmode[1][1] = 311; // L(1520)bar -> Sigmabar- pi+ - bratio[2] = 0.139096; - mode[2][0] = -3222; - mode[2][1] = 211; + lbratio[2] = 0.143076; + lmode[2][0] = -3222; + lmode[2][1] = 211; // L(1520)bar -> Sigma0bar pi0 - bratio[3] = 0.139096; - mode[3][0] = -3212; - mode[3][1] = 111; + lbratio[3] = 0.143076; + lmode[3][0] = -3212; + lmode[3][1] = 111; // L(1520)bar -> Sigmabar+ pi- - bratio[4] = 0.139096; - mode[4][0] = -3112; - mode[4][1] = -211; - - // The other decay modes are neglected - bratio[5] = 0.; - mode[5][0] = 0; - mode[5][1] = 0; - - TVirtualMC::GetMC()->SetDecayMode(-3124, bratio, mode); + lbratio[4] = 0.143076; + lmode[4][0] = -3112; + lmode[4][1] = -211; + + // L(1520)bar -> anti-Sigma*- pi- + lbratio[5] = 0.034066; + lmode[5][0] = -3114; + lmode[5][1] = -211; + + // L(1520)bar -> anti-Sigma*0 pi0 + lbratio[6] = 0.034066; + lmode[6][0] = -3214; + lmode[6][1] = 111; + + // L(1520)bar -> anti-Sigma*+ pi+ + lbratio[7] = 0.034066; + lmode[7][0] = -3224; + lmode[7][1] = 211; + + // L(1520)bar -> Anti-Lambda gamma + lbratio[8] = 0.008687; + lmode[8][0] = -3122; + lmode[8][1] = 22; + + TVirtualMC::GetMC()->SetDecayMode(-102134, lbratio, lmode); // -------------------------------------------------------------------- diff --git a/Utilities/EPNMonitoring/src/EPNstderrMonitor.cxx b/Utilities/EPNMonitoring/src/EPNstderrMonitor.cxx index 57d8bab96e398..b0b0f96ad9af3 100644 --- a/Utilities/EPNMonitoring/src/EPNstderrMonitor.cxx +++ b/Utilities/EPNMonitoring/src/EPNstderrMonitor.cxx @@ -126,7 +126,7 @@ void EPNMonitor::sendLog(const std::string& file, const std::string& message) mLoggerContext->setField(InfoLogger::InfoLoggerContext::FieldName::Facility, ("stderr/" + file).substr(0, 31)); mLoggerContext->setField(InfoLogger::InfoLoggerContext::FieldName::Run, mRunNumber != 0 ? std::to_string(mRunNumber) : "unspecified"); static const InfoLogger::InfoLogger::InfoLoggerMessageOption opt = {InfoLogger::InfoLogger::Severity::Error, 3, InfoLogger::InfoLogger::undefinedMessageOption.errorCode, InfoLogger::InfoLogger::undefinedMessageOption.sourceFile, InfoLogger::InfoLogger::undefinedMessageOption.sourceLine}; - mLogger->log(opt, *mLoggerContext, "stderr: %s", message.c_str()); + mLogger->log(opt, *mLoggerContext, "stderr: %s", file == "SYSLOG" ? (std::string("[GLOBAL SYSLOG]: ") + message).c_str() : message.c_str()); } else { printf("stderr: %s: %s\n", file.c_str(), message.c_str()); } diff --git a/Utilities/Mergers/include/Mergers/IntegratingMerger.h b/Utilities/Mergers/include/Mergers/IntegratingMerger.h index 2fedcda0f3b44..8a6cecc437d1e 100644 --- a/Utilities/Mergers/include/Mergers/IntegratingMerger.h +++ b/Utilities/Mergers/include/Mergers/IntegratingMerger.h @@ -55,6 +55,7 @@ class IntegratingMerger : public framework::Task void endOfStream(framework::EndOfStreamContext& eosContext) override; private: + void finishCycle(framework::DataAllocator& outputs); void publishIntegral(framework::DataAllocator& allocator); void publishMovingWindow(framework::DataAllocator& allocator); static void merge(ObjectStore& mMergedDelta, ObjectStore&& other); diff --git a/Utilities/Mergers/src/FullHistoryMerger.cxx b/Utilities/Mergers/src/FullHistoryMerger.cxx index a2836e63732e0..2ed05d46c0e8a 100644 --- a/Utilities/Mergers/src/FullHistoryMerger.cxx +++ b/Utilities/Mergers/src/FullHistoryMerger.cxx @@ -90,6 +90,7 @@ void FullHistoryMerger::run(framework::ProcessingContext& ctx) void FullHistoryMerger::endOfStream(framework::EndOfStreamContext& eosContext) { + mergeCache(); publish(eosContext.outputs()); } diff --git a/Utilities/Mergers/src/IntegratingMerger.cxx b/Utilities/Mergers/src/IntegratingMerger.cxx index f935628ff94b5..749becd463a5d 100644 --- a/Utilities/Mergers/src/IntegratingMerger.cxx +++ b/Utilities/Mergers/src/IntegratingMerger.cxx @@ -69,31 +69,37 @@ void IntegratingMerger::run(framework::ProcessingContext& ctx) } if (ctx.inputs().isValid("timer-publish")) { - mCyclesSinceReset++; + finishCycle(ctx.outputs()); + } +} - if (mConfig.publishMovingWindow.value == PublishMovingWindow::Yes) { - publishMovingWindow(ctx.outputs()); - } +void IntegratingMerger::finishCycle(DataAllocator& outputs) +{ + mCyclesSinceReset++; - if (!std::holds_alternative(mMergedObjectLastCycle)) { - merge(mMergedObjectIntegral, std::move(mMergedObjectLastCycle)); - } - mMergedObjectLastCycle = std::monostate{}; - mTotalDeltasMerged += mDeltasMerged; + if (mConfig.publishMovingWindow.value == PublishMovingWindow::Yes) { + publishMovingWindow(outputs); + } - publishIntegral(ctx.outputs()); + if (!std::holds_alternative(mMergedObjectLastCycle)) { + merge(mMergedObjectIntegral, std::move(mMergedObjectLastCycle)); + } + mMergedObjectLastCycle = std::monostate{}; + mTotalDeltasMerged += mDeltasMerged; - if (mConfig.mergedObjectTimespan.value == MergedObjectTimespan::LastDifference || - mConfig.mergedObjectTimespan.value == MergedObjectTimespan::NCycles && mConfig.mergedObjectTimespan.param == mCyclesSinceReset) { - clear(); - } + publishIntegral(outputs); - mCollector->send({mTotalDeltasMerged, "total_deltas_merged"}, monitoring::DerivedMetricMode::RATE); - mCollector->send({mDeltasMerged, "deltas_merged_since_last_publication"}); - mCollector->send({mCyclesSinceReset, "cycles_since_reset"}); - mDeltasMerged = 0; + if (mConfig.mergedObjectTimespan.value == MergedObjectTimespan::LastDifference || + mConfig.mergedObjectTimespan.value == MergedObjectTimespan::NCycles && mConfig.mergedObjectTimespan.param == mCyclesSinceReset) { + clear(); } + + mCollector->send({mTotalDeltasMerged, "total_deltas_merged"}, monitoring::DerivedMetricMode::RATE); + mCollector->send({mDeltasMerged, "deltas_merged_since_last_publication"}); + mCollector->send({mCyclesSinceReset, "cycles_since_reset"}); + mDeltasMerged = 0; } + void IntegratingMerger::merge(ObjectStore& target, ObjectStore&& other) { if (std::holds_alternative(target)) { @@ -121,7 +127,7 @@ void IntegratingMerger::merge(ObjectStore& target, ObjectStore&& other) void IntegratingMerger::endOfStream(framework::EndOfStreamContext& eosContext) { - publishIntegral(eosContext.outputs()); + finishCycle(eosContext.outputs()); } // I am not calling it reset(), because it does not have to be performed during the FairMQs reset. diff --git a/Utilities/Mergers/test/common.h b/Utilities/Mergers/test/common.h index e85e256cd513a..c2726959bb8ac 100644 --- a/Utilities/Mergers/test/common.h +++ b/Utilities/Mergers/test/common.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace o2::mergers::test { @@ -22,6 +23,26 @@ inline auto to_span(const TH1F& histo) { return gsl::span(histo.GetArray(), histo.GetSize()); } + +void registerCallbacksForTestFailure(framework::CallbackService& cb, std::shared_ptr success) +{ + cb.set([success](framework::EndOfStreamContext& ctx) { + if (*success == false) { + LOG(fatal) << "Received an EndOfStream without having received the expected object"; + } + }); + cb.set([success]() { + if (*success == false) { + LOG(fatal) << "STOP transition without having received the expected object"; + } + }); + cb.set([success](framework::ServiceRegistryRef) { + if (*success == false) { + LOG(fatal) << "EXIT transition without having received the expected object"; + } + }); +} + } // namespace o2::mergers::test namespace std diff --git a/Utilities/Mergers/test/customTopologyCommon.h b/Utilities/Mergers/test/customTopologyCommon.h index 13c745d6f8a91..6233cb53bd215 100644 --- a/Utilities/Mergers/test/customTopologyCommon.h +++ b/Utilities/Mergers/test/customTopologyCommon.h @@ -24,6 +24,7 @@ #include #include #include +#include "common.h" void customize(std::vector& policies) { @@ -109,9 +110,12 @@ class CustomMergerTestGenerator }, Outputs{}, AlgorithmSpec{ - AlgorithmSpec::InitCallback{[expectedResult = mExpectedResult](InitContext&) { + AlgorithmSpec::InitCallback{[expectedResult = mExpectedResult](InitContext& initContext) { + auto success = std::make_shared(false); + mergers::test::registerCallbacksForTestFailure(initContext.services().get(), success); + return AlgorithmSpec::ProcessCallback{ - [expectedResult, numberOfCalls = 0, numberOfObjects = 0, numberOfMovingWindows = 0, lastObjectValue = 0, retries = 5](ProcessingContext& processingContext) mutable { + [expectedResult, numberOfCalls = 0, numberOfObjects = 0, numberOfMovingWindows = 0, lastObjectValue = 0, retries = 5, success](ProcessingContext& processingContext) mutable { numberOfCalls++; if (processingContext.inputs().isValid("custom")) { @@ -139,7 +143,10 @@ class CustomMergerTestGenerator if (lastObjectValue != expectedResult) { LOG(fatal) << "got wrong secret from object: " << lastObjectValue << ", expected: " << expectedResult; } + return; } + LOG(info) << "Received the expected objects, test successful"; + *success = true; } }}; }}}}); @@ -154,12 +161,17 @@ class CustomMergerTestGenerator }, Outputs{}, AlgorithmSpec{ - AlgorithmSpec::InitCallback{[expectedResult = mExpectedResult](InitContext&) { + AlgorithmSpec::InitCallback{[expectedResult = mExpectedResult](InitContext& initContext) { + auto success = std::make_shared(false); + mergers::test::registerCallbacksForTestFailure(initContext.services().get(), success); + return AlgorithmSpec::ProcessCallback{ - [expectedResult, retryNumber = 0, numberOfRetries = 5](ProcessingContext& processingContext) mutable { + [expectedResult, retryNumber = 0, numberOfRetries = 5, success](ProcessingContext& processingContext) mutable { const auto obj = processingContext.inputs().get("custom"); if (obj->getSecret() == expectedResult) { + LOG(info) << "Received the expected object, test successful"; + *success = true; processingContext.services().get().readyToQuit(QuitRequest::All); return; } diff --git a/Utilities/Mergers/test/histosTopologyCommon.h b/Utilities/Mergers/test/histosTopologyCommon.h index 7c713b3409747..d2305e3f6e6f2 100644 --- a/Utilities/Mergers/test/histosTopologyCommon.h +++ b/Utilities/Mergers/test/histosTopologyCommon.h @@ -71,6 +71,7 @@ class HistosMergerTestGenerator "histo", "histo", histoBinsCount, histoMin, histoMax); histo.Fill(5); histo.Fill(producerIdx); + processingContext.services().get().endOfStream(); processingContext.services().get().readyToQuit(QuitRequest::Me); })}}); } @@ -103,14 +104,19 @@ class HistosMergerTestGenerator Inputs{{"histo", origin, description, 0, Lifetime::Sporadic}}, Outputs{}, AlgorithmSpec{ - AlgorithmSpec::InitCallback{[expectedResult = mExpectedResult](InitContext&) { + AlgorithmSpec::InitCallback{[expectedResult = mExpectedResult](InitContext& initContext) { + auto success = std::make_shared(false); + mergers::test::registerCallbacksForTestFailure(initContext.services().get(), success); + // reason for this crude retry is that multiple layers are not synchronized between each other and publish on their own timers, // number of retries is chosen arbitrarily as we need to retry at least twice - return AlgorithmSpec::ProcessCallback{[expectedResult, retryNumber = 1, retries = 5](ProcessingContext& processingContext) mutable { + return AlgorithmSpec::ProcessCallback{[expectedResult, retryNumber = 1, retries = 5, success](ProcessingContext& processingContext) mutable { const auto histo = processingContext.inputs().get("histo"); LOG(info) << "RETRY: " << retryNumber << ": comparing: " << std::to_string(histo) << " to the expected: " << std::to_string(expectedResult); if (std::equal(expectedResult.begin(), expectedResult.end(), histo->GetArray(), histo->GetArray() + histo->GetSize())) { + LOG(info) << "Received the expected object, test successful"; + *success = true; processingContext.services().get().readyToQuit(QuitRequest::All); return; } diff --git a/Utilities/Mergers/test/test_MergerTopologyHistosFullHistory.cxx b/Utilities/Mergers/test/test_MergerTopologyHistosFullHistory.cxx index d08f6ee077edf..5ac18f998d444 100644 --- a/Utilities/Mergers/test/test_MergerTopologyHistosFullHistory.cxx +++ b/Utilities/Mergers/test/test_MergerTopologyHistosFullHistory.cxx @@ -32,7 +32,7 @@ WorkflowSpec defineDataProcessing(ConfigContext const&) const auto mergersInputs = generator.generateHistoProducers(specs, producersCount); - generator.generateMergers(specs, mergersInputs, InputObjectsTimespan::LastDifference); + generator.generateMergers(specs, mergersInputs, InputObjectsTimespan::FullHistory); generator.generateChecker(specs); diff --git a/Utilities/Mergers/test/vectorTopologyCommon.h b/Utilities/Mergers/test/vectorTopologyCommon.h index d98576fd094f1..34dcc8515a04a 100644 --- a/Utilities/Mergers/test/vectorTopologyCommon.h +++ b/Utilities/Mergers/test/vectorTopologyCommon.h @@ -127,15 +127,20 @@ class VectorMergerTestGenerator Inputs{{"vec", origin, description, 0, Lifetime::Sporadic}}, Outputs{}, AlgorithmSpec{ - AlgorithmSpec::InitCallback{[expectedResult = mExpectedResult](InitContext&) { + AlgorithmSpec::InitCallback{[expectedResult = mExpectedResult](InitContext& initContext) { + auto success = std::make_shared(false); + mergers::test::registerCallbacksForTestFailure(initContext.services().get(), success); + // reason for this crude retry is that multiple layers are not synchronized between each other and publish on their own timers. // number of retries was chosen a bit randomly, as we need to have at least 2 runs through this function because of publish // timers inside of the mergers - return AlgorithmSpec::ProcessCallback{[expectedResult, retryNumber = 1, retries = 5](ProcessingContext& processingContext) mutable { + return AlgorithmSpec::ProcessCallback{[expectedResult, retryNumber = 1, retries = 5, success](ProcessingContext& processingContext) mutable { const auto vectorOfHistos = processingContext.inputs().get*>("vec"); LOG(info) << "RETRY: " << retryNumber << ": comparing: " << std::to_string(vectorOfHistos) << " to the expected: " << std::to_string(expectedResult); if (vectorOfHistos == expectedResult) { + LOG(info) << "Received the expected object, test successful"; + *success = true; processingContext.services().get().readyToQuit(QuitRequest::All); return; } diff --git a/cmake/O2AddHipifiedExecutable.cmake b/cmake/O2AddHipifiedExecutable.cmake index dc633ec0cafff..c7354fd989e76 100644 --- a/cmake/O2AddHipifiedExecutable.cmake +++ b/cmake/O2AddHipifiedExecutable.cmake @@ -24,7 +24,6 @@ function(o2_add_hipified_executable baseTargetName) "SOURCES;PUBLIC_LINK_LIBRARIES;JOB_POOL") # Process each .cu file to generate a .hip file - set(HIPIFY_EXECUTABLE "/opt/rocm/bin/hipify-perl") set(HIP_SOURCES) foreach(file ${A_SOURCES}) @@ -38,8 +37,9 @@ function(o2_add_hipified_executable baseTargetName) add_custom_command( OUTPUT ${OUTPUT_HIP_FILE} - COMMAND ${HIPIFY_EXECUTABLE} --quiet-warnings ${ABS_CUDA_SORUCE} | sed '1{/\#include \"hip\\/hip_runtime.h\"/d}' > ${OUTPUT_HIP_FILE} + COMMAND ${hip_HIPIFY_PERL_EXECUTABLE} --quiet-warnings ${ABS_CUDA_SORUCE} > ${OUTPUT_HIP_FILE} DEPENDS ${file} + COMMENT "Hippifying ${HIP_SOURCE}" ) set_source_files_properties(${OUTPUT_HIP_FILE} PROPERTIES diff --git a/cmake/O2AddHipifiedLibrary.cmake b/cmake/O2AddHipifiedLibrary.cmake index 24652344343be..a9d8602bf87e3 100644 --- a/cmake/O2AddHipifiedLibrary.cmake +++ b/cmake/O2AddHipifiedLibrary.cmake @@ -24,7 +24,6 @@ function(o2_add_hipified_library baseTargetName) ) # Process each .cu file to generate a .hip file - set(HIPIFY_EXECUTABLE "/opt/rocm/bin/hipify-perl") set(HIP_SOURCES) foreach(file ${A_SOURCES}) @@ -38,8 +37,9 @@ function(o2_add_hipified_library baseTargetName) add_custom_command( OUTPUT ${OUTPUT_HIP_FILE} - COMMAND ${HIPIFY_EXECUTABLE} --quiet-warnings ${ABS_CUDA_SORUCE} | sed '1{/\#include \"hip\\/hip_runtime.h\"/d}' > ${OUTPUT_HIP_FILE} + COMMAND ${hip_HIPIFY_PERL_EXECUTABLE} --quiet-warnings ${ABS_CUDA_SORUCE} > ${OUTPUT_HIP_FILE} DEPENDS ${file} + COMMENT "Hippifying ${HIP_SOURCE}" ) set_source_files_properties(${OUTPUT_HIP_FILE} PROPERTIES diff --git a/cmake/O2BuildSanityChecks.cmake b/cmake/O2BuildSanityChecks.cmake index 887b490ecfb90..37bde528ffa1e 100644 --- a/cmake/O2BuildSanityChecks.cmake +++ b/cmake/O2BuildSanityChecks.cmake @@ -26,5 +26,6 @@ function(o2_build_sanity_checks) if(NOT CMAKE_BUILD_TYPE) message(WARNING "CMAKE_BUILD_TYPE not set : will use Debug") set(CMAKE_BUILD_TYPE Debug) + set(CMAKE_BUILD_TYPE_UPPER DEBUG) endif() endfunction() diff --git a/cmake/O2RootMacroExclusionList.cmake b/cmake/O2RootMacroExclusionList.cmake index 84b03472b365c..e079ea8cc6909 100644 --- a/cmake/O2RootMacroExclusionList.cmake +++ b/cmake/O2RootMacroExclusionList.cmake @@ -60,7 +60,8 @@ list(APPEND O2_ROOT_MACRO_EXCLUSION_LIST macro/load_all_libs.C macro/putCondition.C macro/rootlogon.C - Detectors/FIT/FT0/calibration/macros/makeChannelOffsetCalibObjectInCCDB.C) + Detectors/FIT/FT0/calibration/macros/makeChannelOffsetCalibObjectInCCDB.C + Detectors/Upgrades/ALICE3/macros/ALICE3Field.C) if(NOT BUILD_SIMULATION) diff --git a/dependencies/FindO2GPU.cmake b/dependencies/FindO2GPU.cmake index d90eaa077dbd8..52d3276c2ec85 100644 --- a/dependencies/FindO2GPU.cmake +++ b/dependencies/FindO2GPU.cmake @@ -25,6 +25,9 @@ string(TOUPPER "${ENABLE_CUDA}" ENABLE_CUDA) string(TOUPPER "${ENABLE_OPENCL1}" ENABLE_OPENCL1) string(TOUPPER "${ENABLE_OPENCL2}" ENABLE_OPENCL2) string(TOUPPER "${ENABLE_HIP}" ENABLE_HIP) +if(NOT DEFINED CMAKE_BUILD_TYPE_UPPER) + string(TOUPPER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_UPPER) +endif() if(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET STREQUAL "default") set(CUDA_COMPUTETARGET 86 89) @@ -35,10 +38,10 @@ if(HIP_AMDGPUTARGET AND HIP_AMDGPUTARGET STREQUAL "default") endif() function(set_target_cuda_arch target) - if(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET STREQUAL "86") + if(CUDA_COMPUTETARGET AND (CUDA_COMPUTETARGET MATCHES "86" OR CUDA_COMPUTETARGET MATCHES "89")) message(STATUS "Using optimized CUDA settings for Ampere GPU") target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_AMPERE) - elseif(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET STREQUAL "75") + elseif(CUDA_COMPUTETARGET AND CUDA_COMPUTETARGET MATCHES "75") message(STATUS "Using optimized CUDA settings for Turing GPU") target_compile_definitions(${target} PUBLIC GPUCA_GPUTYPE_TURING) else() @@ -66,7 +69,7 @@ endfunction() STRING(REGEX REPLACE "\-std=[^ ]*" "" O2_GPU_CMAKE_CXX_FLAGS_NOSTD "${CMAKE_CXX_FLAGS}") # Need to strip c++17 imposed by alidist defaults if(ENABLE_CUDA) - set(CMAKE_CUDA_STANDARD 17) + set(CMAKE_CUDA_STANDARD ${CMAKE_CXX_STANDARD}) set(CMAKE_CUDA_STANDARD_REQUIRED TRUE) include(CheckLanguage) check_language(CUDA) @@ -108,19 +111,21 @@ if(ENABLE_CUDA) endif() endif() if(CMAKE_CUDA_COMPILER) - set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Xcompiler \"${O2_GPU_CMAKE_CXX_FLAGS_NOSTD}\" --expt-relaxed-constexpr --extended-lambda --allow-unsupported-compiler -Xptxas -v") + set(CMAKE_CUDA_FLAGS "-Xcompiler \"${O2_GPU_CMAKE_CXX_FLAGS_NOSTD}\" ${CMAKE_CUDA_FLAGS} --expt-relaxed-constexpr --extended-lambda --allow-unsupported-compiler -Xptxas -v -Xcompiler -Wno-attributes") if(CMAKE_CUDA_COMPILER_VERSION VERSION_GREATER_EQUAL "12.3") - string(APPEND CMAKE_CUDA_FLAGS " -Xcudafe --diag_suppress=20257") + string(APPEND CMAKE_CUDA_FLAGS " -Xcudafe --diag_suppress=20257") # TODO: Cleanup endif() - set(CMAKE_CUDA_FLAGS_DEBUG "${CMAKE_CUDA_FLAGS_DEBUG} -lineinfo -Xcompiler \"${CMAKE_CXX_FLAGS_DEBUG}\" -Xptxas -O0 -Xcompiler -O0") - if(NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") - set(CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}} -Xcompiler \"${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}\" -Xptxas -O4 -Xcompiler -O4") + set(CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "-Xcompiler \"${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}\" ${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}") + if(CMAKE_BUILD_TYPE_UPPER STREQUAL "DEBUG") + set(CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -lineinfo -Xptxas -O0 -Xcompiler -O0") + else() + set(CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -Xptxas -O4 -Xcompiler -O4") endif() set(GPUCA_CUDA_NO_FAST_MATH_FLAGS "--ftz=false --prec-div=true --prec-sqrt=true --fmad false") if(DEFINED GPUCA_NO_FAST_MATH AND "${GPUCA_NO_FAST_MATH}") - set(CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}} ${GPUCA_CUDA_NO_FAST_MATH_FLAGS}") - elseif(NOT CMAKE_BUILD_TYPE STREQUAL "DEBUG") - set(CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE}} -use_fast_math --ftz=true")# + set(CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} ${GPUCA_CUDA_NO_FAST_MATH_FLAGS}") + elseif(NOT CMAKE_BUILD_TYPE_UPPER STREQUAL "DEBUG") + set(CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CUDA_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -use_fast_math --ftz=true")# endif() if(CMAKE_CXX_FLAGS MATCHES "(^| )-Werror( |$)") set(CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS} -Werror=cross-execution-space-call") @@ -170,12 +175,6 @@ if(ENABLE_OPENCL2) if(LLVM_FOUND) find_package(Clang) endif() - if(DEFINED ENV{ROCM_PATH}) - get_filename_component(ROCM_ROOT "$ENV{ROCM_PATH}" ABSOLUTE) - else() - set(ROCM_ROOT "/opt/rocm") - endif() - find_program(ROCM_AGENT_ENUMERATOR rocm_agent_enumerator PATHS "${ROCM_ROOT}/bin") if (GPUCA_OPENCL_CLANGBIN) set(LLVM_CLANG ${GPUCA_OPENCL_CLANGBIN}) execute_process(COMMAND "which" "/usr/lib/llvm/15/bin/clang-15" OUTPUT_VARIABLE TMP_LLVM_SPIRV_PATH COMMAND_ERROR_IS_FATAL ANY) @@ -211,52 +210,64 @@ endif() # Detect and enable HIP if(ENABLE_HIP) - set(CMAKE_HIP_STANDARD 17) - set(CMAKE_HIP_STANDARD_REQUIRED TRUE) - if(HIP_AMDGPUTARGET) - set(AMDGPU_TARGETS "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) - set(GPU_TARGETS "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) - set(CMAKE_HIP_ARCHITECTURES "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) - endif() - if(EXISTS "/opt/rocm/lib/cmake" AND (NOT DEFINED CMAKE_PREFIX_PATH OR NOT ${CMAKE_PREFIX_PATH} MATCHES "rocm") AND (NOT ENV{CMAKE_PREFIX_PATH} MATCHES "rocm")) - set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH};/opt/rocm/lib/cmake") + if("$ENV{CMAKE_PREFIX_PATH}" MATCHES "rocm") + set(CMAKE_HIP_STANDARD ${CMAKE_CXX_STANDARD}) + set(CMAKE_HIP_STANDARD_REQUIRED TRUE) + if(HIP_AMDGPUTARGET) + set(AMDGPU_TARGETS "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) + set(GPU_TARGETS "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) + set(CMAKE_HIP_ARCHITECTURES "${HIP_AMDGPUTARGET}" CACHE STRING "AMD GPU targets to compile for" FORCE) + endif() + set(TMP_ROCM_DIR_LIST $ENV{CMAKE_PREFIX_PATH}) + string(REPLACE ":" ";" TMP_ROCM_DIR_LIST "${TMP_ROCM_DIR_LIST}") + list(FILTER TMP_ROCM_DIR_LIST INCLUDE REGEX rocm) + list(POP_FRONT TMP_ROCM_DIR_LIST TMP_ROCM_DIR) + get_filename_component(TMP_ROCM_DIR ${TMP_ROCM_DIR}/../../ ABSOLUTE) if (NOT DEFINED CMAKE_HIP_COMPILER) - set(CMAKE_HIP_COMPILER "/opt/rocm/llvm/bin/clang++") + set(CMAKE_HIP_COMPILER "${TMP_ROCM_DIR}/llvm/bin/clang++") + if(NOT EXISTS ${CMAKE_HIP_COMPILER}) + unset(CMAKE_HIP_COMPILER) + endif() endif() - if (NOT DEFINED HIP_CLANG_PATH) - set(HIP_CLANG_PATH "/opt/rocm/llvm/bin") + include(CheckLanguage) + check_language(HIP) + find_package(hip) + find_package(hipcub) + find_package(rocprim) + find_package(rocthrust) + find_program(hip_HIPIFY_PERL_EXECUTABLE "hipify-perl") + if(NOT hip_HIPIFY_PERL_EXECUTABLE) + find_program(hip_HIPIFY_PERL_EXECUTABLE "hipify-perl" HINTS "${TMP_ROCM_DIR}/bin") endif() - endif() - include(CheckLanguage) - check_language(HIP) - find_package(hip) - find_package(hipcub) - find_package(rocprim) - find_package(rocthrust) - find_program(hip_HIPIFY_PERL_EXECUTABLE "hipify-perl") - if(NOT hip_HIPIFY_PERL_EXECUTABLE) - find_program(hip_HIPIFY_PERL_EXECUTABLE "hipify-perl" HINTS "/opt/rocm/bin") - endif() - if(ENABLE_HIP STREQUAL "AUTO") - set_package_properties(hip PROPERTIES TYPE OPTIONAL) - set_package_properties(hipcub PROPERTIES TYPE OPTIONAL) - set_package_properties(rocprim PROPERTIES TYPE OPTIONAL) - set_package_properties(rocthrust PROPERTIES TYPE OPTIONAL) - else() - set_package_properties(hip PROPERTIES TYPE REQUIRED) - set_package_properties(hipcub PROPERTIES TYPE REQUIRED) - set_package_properties(rocprim PROPERTIES TYPE REQUIRED) - set_package_properties(rocthrust PROPERTIES TYPE REQUIRED) - endif() - if (CMAKE_HIP_COMPILER) - enable_language(HIP) - message(STATUS "HIP language enabled: ${CMAKE_HIP_COMPILER}") + if(ENABLE_HIP STREQUAL "AUTO") + set_package_properties(hip PROPERTIES TYPE OPTIONAL) + set_package_properties(hipcub PROPERTIES TYPE OPTIONAL) + set_package_properties(rocprim PROPERTIES TYPE OPTIONAL) + set_package_properties(rocthrust PROPERTIES TYPE OPTIONAL) + else() + set_package_properties(hip PROPERTIES TYPE REQUIRED) + set_package_properties(hipcub PROPERTIES TYPE REQUIRED) + set_package_properties(rocprim PROPERTIES TYPE REQUIRED) + set_package_properties(rocthrust PROPERTIES TYPE REQUIRED) + if(NOT hip_HIPIFY_PERL_EXECUTABLE) + message(FATAL_ERROR "Could not find hipify-perl command") + endif() + endif() + if (CMAKE_HIP_COMPILER) + enable_language(HIP) + message(STATUS "HIP language enabled: ${CMAKE_HIP_COMPILER}") + endif() + elseif(NOT ENABLE_HIP STREQUAL "AUTO") + message(FATAL_ERROR "HIP requested, but CMAKE_PREFIX_PATH env variable does not contain rocm folder!") endif() if(hip_FOUND AND hipcub_FOUND AND rocthrust_FOUND AND rocprim_FOUND AND hip_HIPCC_EXECUTABLE AND hip_HIPIFY_PERL_EXECUTABLE) set(HIP_ENABLED ON) set_target_properties(roc::rocthrust PROPERTIES IMPORTED_GLOBAL TRUE) message(STATUS "HIP Found (${hip_HIPCC_EXECUTABLE} version ${hip_VERSION})") set(O2_HIP_CMAKE_CXX_FLAGS "-fgpu-defer-diag -mllvm -amdgpu-enable-lower-module-lds=false -Wno-invalid-command-line-argument -Wno-unused-command-line-argument -Wno-invalid-constexpr -Wno-ignored-optimization-argument -Wno-unused-private-field -Wno-pass-failed") + if(hip_VERSION VERSION_GREATER_EQUAL "6.0") + set(O2_HIP_CMAKE_CXX_FLAGS "${O2_HIP_CMAKE_CXX_FLAGS} -mllvm -amdgpu-legacy-sgpr-spill-lowering=true") # TODO: Cleanup + endif() set(O2_HIP_CMAKE_LINK_FLAGS "-Wno-pass-failed") string(REGEX REPLACE "(gfx1[0-9]+;?)" "" CMAKE_HIP_ARCHITECTURES "${CMAKE_HIP_ARCHITECTURES}") # ROCm currently doesn’t support integrated graphics if(HIP_AMDGPUTARGET) @@ -267,14 +278,19 @@ if(ENABLE_HIP) set(CMAKE_HIP_ARCHITECTURES "${HIP_AMDGPUTARGET}") # If GPU build is enforced we override autodetection endif() if(NOT DEFINED GPUCA_NO_FAST_MATH OR NOT ${GPUCA_NO_FAST_MATH}) - set(O2_HIP_CMAKE_CXX_FLAGS "${O2_HIP_CMAKE_CXX_FLAGS} -fgpu-flush-denormals-to-zero") # -ffast-math disabled, since apparently it leads to miscompilation and crashes in FollowLooper kernel + set(O2_HIP_CMAKE_CXX_FLAGS "${O2_HIP_CMAKE_CXX_FLAGS} -fgpu-flush-denormals-to-zero -ffast-math") endif() if (CMAKE_CXX_COMPILER MATCHES "bin/c\\+\\+\$" AND NOT CMAKE_CXX_COMPILER MATCHES "^/usr/bin") string(REGEX REPLACE "(.*)bin/c\\+\\+\$" "\\1" HIP_GCC_TOOLCHAIN_PATH "${CMAKE_CXX_COMPILER}") - set(O2_HIP_CMAKE_CXX_FLAGS "${O2_HIP_CMAKE_CXX_FLAGS} --gcc-toolchain=${HIP_GCC_TOOLCHAIN_PATH}") # -ffast-math disabled, since apparently it leads to miscompilation and crashes in FollowLooper kernel + set(O2_HIP_CMAKE_CXX_FLAGS "${O2_HIP_CMAKE_CXX_FLAGS} --gcc-toolchain=${HIP_GCC_TOOLCHAIN_PATH}") endif() set(CMAKE_HIP_FLAGS "${O2_GPU_CMAKE_CXX_FLAGS_NOSTD} ${CMAKE_HIP_FLAGS} ${O2_HIP_CMAKE_CXX_FLAGS}") - set(CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}} ${CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE}}") + set(CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} ${CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}") + if(CMAKE_BUILD_TYPE_UPPER STREQUAL "DEBUG") + set(CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -O0 -ggdb") + else() + set(CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_HIP_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -O3") + endif() else() set(HIP_ENABLED OFF) endif() @@ -297,7 +313,7 @@ if(ENABLE_HIP) if (NOT hip_HIPIFY_PERL_EXECUTABLE) message(WARNING "hipify-perl executable not found") endif() - message(FATAL_ERROR "HIP requested with HIP_PATH=${HIP_PATH} but some of the above packages are not found") + message(FATAL_ERROR "HIP requested but some of the above packages are not found") endif() endif() diff --git a/dependencies/FindONNXRuntime.cmake b/dependencies/FindONNXRuntime.cmake new file mode 100644 index 0000000000000..b783c2e1c7bf3 --- /dev/null +++ b/dependencies/FindONNXRuntime.cmake @@ -0,0 +1,23 @@ +# Copyright 2019-2020 CERN and copyright holders of ALICE O2. +# See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +# All rights not expressly granted are reserved. +# +# This software is distributed under the terms of the GNU General Public +# License v3 (GPL Version 3), copied verbatim in the file "COPYING". +# +# In applying this license CERN does not waive the privileges and immunities +# granted to it by virtue of its status as an Intergovernmental Organization +# or submit itself to any jurisdiction. + +find_package(ONNXRuntime::ONNXRuntime CONFIG) +if (ONNXRuntime::ONNXRuntime_FOUND) + set(onnxruntime_FOUND 1) + add_library(onnxruntime::onnxruntime ALIAS ONNXRuntime::ONNXRuntime) +endif() + +if (NOT ONNXRuntime::ONNXRuntime_FOUND) + find_package(onnxruntime CONFIG) + if (onnxruntime_FOUND) + add_library(ONNXRuntime::ONNXRuntime ALIAS onnxruntime::onnxruntime) + endif() +endif() diff --git a/dependencies/O2CompileFlags.cmake b/dependencies/O2CompileFlags.cmake index 7fe9019701efe..08dd388cbdf36 100644 --- a/dependencies/O2CompileFlags.cmake +++ b/dependencies/O2CompileFlags.cmake @@ -69,9 +69,14 @@ endif() string(JOIN " " CMAKE_C_WARNINGS "-Wno-unknown-warning-option" ${O2_C_ENABLED_WARNINGS} ${O2_C_ENABLED_WARNINGS_NO_ERROR}) string(JOIN " " CMAKE_CXX_WARNINGS "-Wno-unknown-warning-option" ${O2_CXX_ENABLED_WARNINGS} ${O2_CXX_ENABLED_WARNINGS_NO_ERROR}) -set(CMAKE_CXX_FLAGS_COVERAGE "-g -O2 -fprofile-arcs -ftest-coverage") +string(REGEX MATCH "-O[0-9]+" CMAKE_FLAGS_OPT_VALUE "${CMAKE_CXX_FLAGS}") +if(NOT CMAKE_FLAGS_OPT_VALUE OR CMAKE_FLAGS_OPT_VALUE STREQUAL "-O0" OR CMAKE_FLAGS_OPT_VALUE STREQUAL "-O1") + set(CMAKE_FLAGS_OPT_VALUE "-O2") # Release builds should not decrease the -O level below something requested externally via CXXFLAGS +endif() + +set(CMAKE_CXX_FLAGS_COVERAGE "-g ${CMAKE_FLAGS_OPT_VALUE} -fprofile-arcs -ftest-coverage") set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE}") -set(CMAKE_Fortran_FLAGS_COVERAGE "-g -O2 -fprofile-arcs -ftest-coverage") +set(CMAKE_Fortran_FLAGS_COVERAGE "-g ${CMAKE_FLAGS_OPT_VALUE} -fprofile-arcs -ftest-coverage") set(CMAKE_LINK_FLAGS_COVERAGE "--coverage -fprofile-arcs -fPIC") MARK_AS_ADVANCED( @@ -81,9 +86,9 @@ MARK_AS_ADVANCED( CMAKE_LINK_FLAGS_COVERAGE) # Options to enable the thread sanitizer -set(CMAKE_CXX_FLAGS_THREADSANITIZER "-g -O2 -fsanitize=thread -fPIC") +set(CMAKE_CXX_FLAGS_THREADSANITIZER "-g ${CMAKE_FLAGS_OPT_VALUE} -fsanitize=thread -fPIC") set(CMAKE_C_FLAGS_THREADSANITIZER "${CMAKE_CXX_FLAGS_THREADSANITIZER}") -set(CMAKE_Fortran_FLAGS_THREADSANITIZER "-g -O2 -fsanitize=thread -fPIC") +set(CMAKE_Fortran_FLAGS_THREADSANITIZER "-g ${CMAKE_FLAGS_OPT_VALUE} -fsanitize=thread -fPIC") set(CMAKE_LINK_FLAGS_THREADSANITIZER "-fsanitize=thread -fPIC") MARK_AS_ADVANCED( @@ -92,38 +97,32 @@ MARK_AS_ADVANCED( CMAKE_Fortran_FLAGS_THREADSANITIZER CMAKE_LINK_FLAGS_THREADSANITIZER) -#Check the compiler and set the compile and link flags -IF (NOT CMAKE_BUILD_TYPE) - Message(STATUS "Set BuildType to DEBUG") - set(CMAKE_BUILD_TYPE Debug) -ENDIF (NOT CMAKE_BUILD_TYPE) - IF(ENABLE_CASSERT) #For the CI, we want to have assertions enabled - set(CMAKE_CXX_FLAGS_RELEASE "-O2") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_FLAGS_OPT_VALUE}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_FLAGS_OPT_VALUE} -g") ELSE() - set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -DNDEBUG") - if (CMAKE_BUILD_TYPE STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE STREQUAL "RELWITHDEBINFO") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_FLAGS_OPT_VALUE} -DNDEBUG") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_FLAGS_OPT_VALUE} -g -DNDEBUG") + if (CMAKE_BUILD_TYPE_UPPER STREQUAL "RELEASE" OR CMAKE_BUILD_TYPE_UPPER STREQUAL "RELWITHDEBINFO") set(FAIR_MIN_SEVERITY "detail") endif() ENDIF() IF(ENABLE_THREAD_SAFETY_ANALYSIS) - set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}} -Werror=thread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS") + set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -Werror=thread-safety -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS") ENDIF() -set(CMAKE_C_FLAGS_RELEASE "-O2") -set(CMAKE_Fortran_FLAGS_RELEASE "-O2") -set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g") -set(CMAKE_Fortran_FLAGS_RELWITHDEBINFO "-O2 -g") +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_FLAGS_OPT_VALUE}") +set(CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_FLAGS_OPT_VALUE}") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_FLAGS_OPT_VALUE} -g") +set(CMAKE_Fortran_FLAGS_RELWITHDEBINFO "${CMAKE_FLAGS_OPT_VALUE} -g") # make sure Debug build not optimized (does not seem to work without CACHE + FORCE) set(CMAKE_CXX_FLAGS_DEBUG "-g -O0" CACHE STRING "Debug mode build flags" FORCE) set(CMAKE_C_FLAGS_DEBUG "-g -O0" CACHE STRING "Debug mode build flags" FORCE) set(CMAKE_Fortran_FLAGS_DEBUG "-g -O0" CACHE STRING "Debug mode build flags" FORCE) -set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}} ${CMAKE_CXX_WARNINGS}") -set(CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE}} ${CMAKE_C_WARNINGS}") +set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} ${CMAKE_CXX_WARNINGS}") +set(CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} ${CMAKE_C_WARNINGS}") if(APPLE) elseif(UNIX) @@ -131,13 +130,19 @@ elseif(UNIX) endif() if(ENABLE_TIME_TRACE) - set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}} -ftime-trace") + set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -ftime-trace") endif() if(DEFINED ENV{O2_CXXFLAGS_OVERRIDE}) - set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}} $ENV{O2_CXXFLAGS_OVERRIDE}") + set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} $ENV{O2_CXXFLAGS_OVERRIDE}") message(STATUS "Setting CXXFLAGS Override $ENV{O2_CXXFLAGS_OVERRIDE}") endif() +if(GPUCA_NO_FAST_MATH_WHOLEO2) + set(GPUCA_NO_FAST_MATH 1) + add_definitions(-DGPUCA_NO_FAST_MATH) + set(CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -fno-fast-math -ffp-contract=off") + set(CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPER} "${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UPPER}} -fno-fast-math -ffp-contract=off") +endif() -message(STATUS "Using build type: ${CMAKE_BUILD_TYPE} - CXXFLAGS: ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}") +message(STATUS "Using build type: ${CMAKE_BUILD_TYPE} - CXXFLAGS: ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE_UPPER}}") diff --git a/doc/README.md b/doc/README.md index 68520ab356009..6ceae4b7d365e 100644 --- a/doc/README.md +++ b/doc/README.md @@ -11,6 +11,7 @@ This module contains the documentation pages. * \subpage refdocCMakeInstructions * \subpage refdocModernCMakeMigration * \subpage refdocCodeOrganization +* \subpage refdocDebugging * \subpage refdocDetectorSimulation * \subpage refdocDoxygenInstructions * \subpage refdocManPages diff --git a/doc/doxyfile-with-graphs.in b/doc/doxyfile-with-graphs.in index d60d01d5bcb59..75f18b7c54e72 100644 --- a/doc/doxyfile-with-graphs.in +++ b/doc/doxyfile-with-graphs.in @@ -83,6 +83,7 @@ MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_FILES = YES SHOW_NAMESPACES = YES +SHOW_EXAMPLES = NO FILE_VERSION_FILTER = LAYOUT_FILE = CITE_BIB_FILES = @@ -109,7 +110,7 @@ EXCLUDE = .git/ \ html-docs/ \ doxygen cmake config gconfig geometry input parameters .svn vis EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = G__* ClassImp build_* +EXCLUDE_PATTERNS = G__* ClassImp build_* CHANGELOG* EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = diff --git a/doc/doxyfile.in b/doc/doxyfile.in index 08b7d37770b20..1e89f1ac1d958 100644 --- a/doc/doxyfile.in +++ b/doc/doxyfile.in @@ -83,6 +83,7 @@ MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_FILES = YES SHOW_NAMESPACES = YES +SHOW_EXAMPLES = NO FILE_VERSION_FILTER = LAYOUT_FILE = CITE_BIB_FILES = @@ -109,7 +110,7 @@ EXCLUDE = .git/ \ html-docs/ \ doxygen cmake config gconfig geometry input parameters .svn vis EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = G__* ClassImp build_* +EXCLUDE_PATTERNS = G__* ClassImp build_* CHANGELOG* EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = diff --git a/macro/build_geometry.C b/macro/build_geometry.C index 3b33f3c3ddfee..3712f6bf85a93 100644 --- a/macro/build_geometry.C +++ b/macro/build_geometry.C @@ -165,7 +165,7 @@ void build_geometry(FairRunSim* run = nullptr) #ifdef ENABLE_UPGRADES // upgraded beampipe at the interaction point (IP) if (isActivated("A3IP")) { - run->AddModule(new o2::passive::Alice3Pipe("A3IP", "Alice 3 beam pipe", !isActivated("TRK"), !isActivated("FT3"), 1.8f, 0.08f, 1000.f, 3.7f, 0.08f, 76.f)); + run->AddModule(new o2::passive::Alice3Pipe("A3IP", "Alice 3 beam pipe", !isActivated("TRK"), !isActivated("FT3"), 1.8f, 0.08f, 1000.f, 5.6f, 0.08f, 76.f)); } // the absorber diff --git a/macro/runTPCRefit.C b/macro/runTPCRefit.C index ab1b141d86143..02c79a8b369ed 100644 --- a/macro/runTPCRefit.C +++ b/macro/runTPCRefit.C @@ -87,7 +87,7 @@ int runTPCRefit(TString trackFile = "tpctracks.root", TString clusterFile = "tpc std::cout << "Error reading clusters (code " << retVal << ")\n"; return 1; } - GPUO2InterfaceRefit refit(&clusterIndex, &transHelper, bz, trackHitRefs->data(), nullptr, tracks, prop); + GPUO2InterfaceRefit refit(&clusterIndex, &transHelper, bz, trackHitRefs->data(), 0, nullptr, nullptr, -1, tracks, prop); //refit.setGPUTrackFitInProjections(false); // Enable full 3D fit without assuming y and Z are uncorrelated for (unsigned int i = 0; i < tracks->size(); i++) { TrackTPC trk = (*tracks)[i]; diff --git a/prodtests/full-system-test/aggregator-workflow.sh b/prodtests/full-system-test/aggregator-workflow.sh index e3317d760730e..2812c6da76817 100755 --- a/prodtests/full-system-test/aggregator-workflow.sh +++ b/prodtests/full-system-test/aggregator-workflow.sh @@ -76,6 +76,7 @@ if [[ "${GEN_TOPO_VERBOSE:-}" == "1" ]]; then echo "CALIB_FT0_TIMEOFFSET = $CALIB_FT0_TIMEOFFSET" 1>&2 echo "CALIB_ITS_DEADMAP_TIME = $CALIB_ITS_DEADMAP_TIME" 1>&2 echo "CALIB_MFT_DEADMAP_TIME = $CALIB_MFT_DEADMAP_TIME" 1>&2 + echo "CALIB_RCT_UPDATER = ${CALIB_RCT_UPDATER:-}" 1>&2 fi # beamtype dependent settings @@ -191,6 +192,10 @@ fi # calibrations for AGGREGATOR_TASKS == BARREL_TF if [[ $AGGREGATOR_TASKS == BARREL_TF ]] || [[ $AGGREGATOR_TASKS == ALL ]]; then + # RCT updater + if [[ ${CALIB_RCT_UPDATER:-} == 1 ]]; then + add_W o2-rct-updater-workflow "--ccdb-server $CCDB_POPULATOR_UPLOAD_PATH" + fi # PrimaryVertex if [[ $CALIB_PRIMVTX_MEANVTX == 1 ]]; then : ${TFPERSLOTS_MEANVTX:=55000} @@ -248,7 +253,7 @@ if [[ $AGGREGATOR_TASKS == BARREL_SPORADIC ]] || [[ $AGGREGATOR_TASKS == ALL ]]; add_W o2-tpc-calibrator-dedx "--min-entries-sector 3000 --min-entries-1d 200 --min-entries-2d 10000" fi if [[ $CALIB_TPC_RESPADGAIN == 1 ]]; then - add_W o2-tpc-calibrator-gainmap-tracks "--tf-per-slot 10000 --store-RMS-CCDB true" + add_W o2-tpc-calibrator-gainmap-tracks "--tf-per-slot 200000 --store-RMS-CCDB true" fi # TOF if [[ $CALIB_TOF_INTEGRATEDCURR == 1 ]]; then diff --git a/prodtests/full-system-test/dpl-workflow.sh b/prodtests/full-system-test/dpl-workflow.sh index abffdb7c37512..a5d0b290e11a5 100755 --- a/prodtests/full-system-test/dpl-workflow.sh +++ b/prodtests/full-system-test/dpl-workflow.sh @@ -5,7 +5,6 @@ set -o pipefail # Abort in case any variable is not bound if [[ ${IGNORE_UNBOUND_VARIABLES:-} != 1 ]]; then set -u; fi - # --------------------------------------------------------------------------------------------------------------------- # Get this script's directory and load common settings : ${GEN_TOPO_MYDIR:=$(dirname $(realpath $0))} @@ -124,7 +123,7 @@ if [[ $SYNCMODE == 1 ]]; then PVERTEXING_CONFIG_KEY+="pvertexer.meanVertexExtraErrConstraint=0.3;" # for calibration relax the constraint if [[ $SYNCRAWMODE == 1 ]]; then # add extra tolerance in sync mode to account for eventual time misalignment - PVERTEXING_CONFIG_KEY+="pvertexer.timeMarginVertexTime=1.3;" + PVERTEXING_CONFIG_KEY+="pvertexer.timeMarginVertexTime=2.5;" if [[ -z $ITSEXTRAERR ]]; then # in sync mode account for ITS residual misalignment ERRIB="100e-8" ERROB="100e-8" @@ -141,6 +140,8 @@ if [[ $SYNCMODE == 1 ]]; then else if [[ $BEAMTYPE == "pp" ]]; then ITS_CONFIG_KEY+="ITSVertexerParam.phiCut=0.5;ITSVertexerParam.clusterContributorsCut=3;ITSVertexerParam.tanLambdaCut=0.2;" + elif [[ $BEAMTYPE == "PbPb" ]]; then + ITS_CONFIG_KEY+="ITSVertexerParam.lowMultBeamDistCut=0;ITSCATrackerParam.nROFsPerIterations=12;ITSCATrackerParam.perPrimaryVertexProcessing=true;" fi fi [[ $CTFINPUT == 1 ]] && GPU_CONFIG_KEY+="GPU_proc.tpcInputWithClusterRejection=1;" @@ -319,6 +320,7 @@ if has_detector_calib PHS && workflow_has_parameter CALIB; then fi [[ ${O2_GPU_DOUBLE_PIPELINE:-$EPNSYNCMODE} == 1 ]] && GPU_CONFIG+=" --enableDoublePipeline" +[[ ${O2_GPU_RTC:-0} == 1 ]] && GPU_CONFIG_KEY+="GPU_proc_rtc.enable=1;GPU_proc_rtc.cacheOutput=1;GPU_proc.RTCcacheFolder=/var/tmp/o2_gpu_rtc_cache;" ( workflow_has_parameter AOD || [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output o2-emcal-cell-writer-workflow ) && has_detector EMC && RAW_EMC_SUBSPEC=" --subspecification 1 " has_detector_reco MID && has_detector_matching MCHMID && MFTMCHConf="FwdMatching.useMIDMatch=true;" || MFTMCHConf="FwdMatching.useMIDMatch=false;" @@ -345,6 +347,7 @@ fi [[ $RUNTYPE != "COSMICS" ]] && [[ $RUNTYPE != "TECHNICAL" ]] && has_detectors_reco ITS && has_detector_matching PRIMVTX && [[ ! -z "$VERTEXING_SOURCES" ]] && EVE_CONFIG+=" --primary-vertex-mode" [[ $SYNCRAWMODE == 1 ]] && [[ -z ${CONFIG_EXTRA_PROCESS_o2_trd_global_tracking:-} ]] && CONFIG_EXTRA_PROCESS_o2_trd_global_tracking='GPU_rec_trd.maxChi2=25;GPU_rec_trd.penaltyChi2=20;GPU_rec_trd.extraRoadY=4;GPU_rec_trd.extraRoadZ=10;GPU_rec_trd.applyDeflectionCut=0;GPU_rec_trd.trkltResRPhiIdeal=1' [[ $SYNCRAWMODE == 1 ]] && [[ -z ${ARGS_EXTRA_PROCESS_o2_phos_reco_workflow:-} ]] && ARGS_EXTRA_PROCESS_o2_phos_reco_workflow='--presamples 2 --fitmethod semigaus' +[[ $SYNCRAWMODE == 1 ]] && [[ $BEAMTYPE == "PbPb" ]] && [[ -z ${CONFIG_EXTRA_PROCESS_o2_calibration_emcal_channel_calib_workflow:-} ]] && CONFIG_EXTRA_PROCESS_o2_calibration_emcal_channel_calib_workflow='EMCALCalibParams.selectedClassMasks=C0TVX-NONE-NOPF-EMC:c0tvxtsc-b-nopf-emc:C0TVXTCE-B-NOPF-EMC;EMCALCalibParams.fractionEvents_bc=0.3' # --------------------------------------------------------------------------------------------------------------------- # Start of workflow command generation @@ -355,6 +358,9 @@ WORKFLOW= # Make sure we start with an empty workflow # --------------------------------------------------------------------------------------------------------------------- # Input workflow INPUT_DETECTOR_LIST=$WORKFLOW_DETECTORS +: ${GLOBAL_READER_OPTIONS:=} +: ${GLOBAL_READER_NEEDS_PV:=} +: ${GLOBAL_READER_NEEDS_SV:=} if [[ ! -z ${WORKFLOW_DETECTORS_USE_GLOBAL_READER_TRACKS} ]] || [[ ! -z ${WORKFLOW_DETECTORS_USE_GLOBAL_READER_CLUSTERS} ]]; then for i in ${WORKFLOW_DETECTORS_USE_GLOBAL_READER_TRACKS//,/ }; do export INPUT_DETECTOR_LIST=$(echo $INPUT_DETECTOR_LIST | sed -e "s/,$i,/,/g" -e "s/^$i,//" -e "s/,$i"'$'"//" -e "s/^$i"'$'"//") @@ -363,8 +369,9 @@ if [[ ! -z ${WORKFLOW_DETECTORS_USE_GLOBAL_READER_TRACKS} ]] || [[ ! -z ${WORKFL export INPUT_DETECTOR_LIST=$(echo $INPUT_DETECTOR_LIST | sed -e "s/,$i,/,/g" -e "s/^$i,//" -e "s/,$i"'$'"//" -e "s/^$i"'$'"//") done - GLOBAL_READER_OPTIONS= has_detector ITS && SYNCMODE==1 && GLOBAL_READER_OPTIONS+=" --ir-frames-its" + [[ $GLOBAL_READER_NEEDS_PV == 1 ]] && GLOBAL_READER_OPTIONS+=" --primary-vertices" + [[ $GLOBAL_READER_NEEDS_SV == 1 ]] && GLOBAL_READER_OPTIONS+=" --secondary-vertices" if [[ ! -z ${TIMEFRAME_RATE_LIMIT:-} ]] && [[ $TIMEFRAME_RATE_LIMIT != 0 ]]; then HBFINI_OPTIONS=" --hbfutils-config o2_tfidinfo.root,upstream " @@ -381,6 +388,7 @@ if [[ ! -z ${WORKFLOW_DETECTORS_USE_GLOBAL_READER_TRACKS} ]] || [[ ! -z ${WORKFL has_detector MCH && has_detector_from_global_reader MCH && add_W o2-mch-clusters-reader-workflow "$HBFINI_OPTIONS" "" 0 has_detector MCH && has_detector_from_global_reader MCH && add_W o2-mch-preclusters-reader-workflow "$HBFINI_OPTIONS" "" 0 has_detector TRD && has_detector_from_global_reader TRD && add_W o2-trd-digit-reader-workflow "$DISABLE_MC --digit-subspec 0 --disable-trigrec $HBFINI_OPTIONS" + has_detector TRD && has_detector_from_global_reader TRD && [[ ! -z "$TRD_SOURCES" ]] && has_detector_from_global_reader_tracks "$(echo "$TRD_SOURCES" | cut -d',' -f1)-TRD" && add_W o2-trd-calib-reader-workflow "--trd-calib-infile trdcaliboutput.root $HBFINI_OPTIONS" has_detector TOF && has_detector_from_global_reader TOF && add_W o2-tof-reco-workflow "$DISABLE_MC --input-type digits --output-type NONE $HBFINI_OPTIONS" fi @@ -510,9 +518,9 @@ fi has_detector_reco ITS && ! has_detector_from_global_reader ITS && add_W o2-its-reco-workflow "--trackerCA $ITS_CONFIG $DISABLE_MC $DISABLE_DIGIT_CLUSTER_INPUT $DISABLE_ROOT_OUTPUT --pipeline $(get_N its-tracker ITS REST 1 ITSTRK),$(get_N its-clusterer ITS REST 1 ITSCL)" "$ITS_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR" has_detector_reco FT0 && ! has_detector_from_global_reader FT0 && add_W o2-ft0-reco-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --pipeline $(get_N ft0-reconstructor FT0 REST 1)" has_detector_reco TRD && ! has_detector_from_global_reader TRD && add_W o2-trd-tracklet-transformer "--disable-irframe-reader $DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TRD_FILTER_CONFIG --pipeline $(get_N TRDTRACKLETTRANSFORMER TRD REST 1 TRDTRKTRANS)" -has_detectors_reco ITS TPC && has_detector_matching ITSTPC && add_W o2-tpcits-match-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $SEND_ITSTPC_DTGL $TPC_CORR_OPT --nthreads $ITSTPC_THREADS --pipeline $(get_N itstpc-track-matcher MATCH REST $ITSTPC_THREADS TPCITS)" "$ITSTPC_CONFIG_KEY;$INTERACTION_TAG_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR;$TPC_CORR_KEY" -has_detector_reco TRD && [[ ! -z "$TRD_SOURCES" ]] && add_W o2-trd-global-tracking "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TRD_CONFIG $TRD_FILTER_CONFIG $TPC_CORR_OPT --track-sources $TRD_SOURCES --pipeline $(get_N trd-globaltracking_TPC_ITS-TPC_ TRD REST 1 TRDTRK),$(get_N trd-globaltracking_TPC_FT0_ITS-TPC_ TRD REST 1 TRDTRK),$(get_N trd-globaltracking_TPC_FT0_ITS-TPC_CTP_ TRD REST 1 TRDTRK)" "$TRD_CONFIG_KEY;$INTERACTION_TAG_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR;$TPC_CORR_KEY" -has_detector_reco TOF && [[ ! -z "$TOF_SOURCES" ]] && add_W o2-tof-matcher-workflow "$TOF_MATCH_OPT $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TPC_CORR_OPT ${TOFMATCH_THREADS:+--tof-lanes ${TOFMATCH_THREADS}} --track-sources $TOF_SOURCES --pipeline $(get_N tof-matcher TOF REST 1 TOFMATCH)" "$ITSMFT_STROBES;$ITSEXTRAERR;$TPC_CORR_KEY" +has_detectors_reco ITS TPC && ! has_detector_from_global_reader_tracks ITS-TPC && has_detector_matching ITSTPC && add_W o2-tpcits-match-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $SEND_ITSTPC_DTGL $TPC_CORR_OPT --nthreads $ITSTPC_THREADS --pipeline $(get_N itstpc-track-matcher MATCH REST $ITSTPC_THREADS TPCITS)" "$ITSTPC_CONFIG_KEY;$INTERACTION_TAG_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR;$TPC_CORR_KEY" +has_detector_reco TRD && [[ ! -z "$TRD_SOURCES" ]] && ! has_detector_from_global_reader_tracks "$(echo "$TRD_SOURCES" | cut -d',' -f1)-TRD" && add_W o2-trd-global-tracking "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TRD_CONFIG $TRD_FILTER_CONFIG $TPC_CORR_OPT --track-sources $TRD_SOURCES --pipeline $(get_N trd-globaltracking_TPC_ITS-TPC_ TRD REST 1 TRDTRK),$(get_N trd-globaltracking_TPC_FT0_ITS-TPC_ TRD REST 1 TRDTRK),$(get_N trd-globaltracking_TPC_FT0_ITS-TPC_CTP_ TRD REST 1 TRDTRK)" "$TRD_CONFIG_KEY;$INTERACTION_TAG_CONFIG_KEY;$ITSMFT_STROBES;$ITSEXTRAERR;$TPC_CORR_KEY" +has_detector_reco TOF && [[ ! -z "$TOF_SOURCES" ]] && ! has_detector_from_global_reader_tracks "$(echo "$TOF_SOURCES" | cut -d',' -f1)-TOF" && add_W o2-tof-matcher-workflow "$TOF_MATCH_OPT $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC $TPC_CORR_OPT ${TOFMATCH_THREADS:+--tof-lanes ${TOFMATCH_THREADS}} --track-sources $TOF_SOURCES --pipeline $(get_N tof-matcher TOF REST 1 TOFMATCH)" "$ITSMFT_STROBES;$ITSEXTRAERR;$TPC_CORR_KEY" has_detectors TPC && [[ -z "$DISABLE_ROOT_OUTPUT" && "${SKIP_TPC_CLUSTERSTRACKS_OUTPUT:-}" != 1 ]] && ! has_detector_from_global_reader TPC && add_W o2-tpc-reco-workflow "--input-type pass-through --output-type clusters,tpc-triggers,tracks,send-clusters-per-sector $DISABLE_MC" # --------------------------------------------------------------------------------------------------------------------- @@ -524,9 +532,9 @@ has_detector FDD && ! has_detector_from_global_reader FDD && has_processing_step has_detector FV0 && ! has_detector_from_global_reader FV0 && has_processing_step FV0_RECO && add_W o2-fv0-reco-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC" has_detector ZDC && ! has_detector_from_global_reader ZDC && has_processing_step ZDC_RECO && add_W o2-zdc-digits-reco "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC" has_detector HMP && ! has_detector_from_global_reader HMP && has_processing_step HMP_RECO && add_W o2-hmpid-digits-to-clusters-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT --pipeline $(get_N HMP-Clusterization HMP REST 1 HMPCLUS)" -has_detector HMP && has_detector_matching HMP && ! has_detector_from_global_reader_tracks HMP && has_processing_step HMP_RECO && add_W o2-hmpid-matcher-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --track-sources ${HMP_SOURCES:-all} --pipeline $(get_N hmp-matcher HMP REST 1 HMPMATCH)" -has_detectors_reco MCH MID && has_detector_matching MCHMID && add_W o2-muon-tracks-matcher-workflow "$DISABLE_ROOT_INPUT $DISABLE_MC $DISABLE_ROOT_OUTPUT --pipeline $(get_N muon-track-matcher MATCH REST 1)" -has_detectors_reco MFT MCH && has_detector_matching MFTMCH && add_W o2-globalfwd-matcher-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --pipeline $(get_N globalfwd-track-matcher MATCH REST 1 FWDMATCH)" "$MFTMCHConf" +has_detector HMP && [[ ! -z "$HMP_SOURCES" ]] && has_detector_matching HMP && ! has_detector_from_global_reader_tracks HMP && add_W o2-hmpid-matcher-workflow "$DISABLE_DIGIT_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --track-sources $HMP_SOURCES --pipeline $(get_N hmp-matcher HMP REST 1 HMPMATCH)" +has_detectors_reco MCH MID && has_detector_matching MCHMID && ! has_detector_from_global_reader_tracks "MCH-MID" && add_W o2-muon-tracks-matcher-workflow "$DISABLE_ROOT_INPUT $DISABLE_MC $DISABLE_ROOT_OUTPUT --pipeline $(get_N muon-track-matcher MATCH REST 1)" +has_detectors_reco MFT MCH && has_detector_matching MFTMCH && ! has_detector_from_global_reader_tracks "MFT-MCH" && add_W o2-globalfwd-matcher-workflow "$DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $DISABLE_MC --pipeline $(get_N globalfwd-track-matcher MATCH REST 1 FWDMATCH)" "$MFTMCHConf" # --------------------------------------------------------------------------------------------------------------------- # Reconstruction workflows needed only in case QC or CALIB was requested @@ -554,10 +562,10 @@ has_detector_reco MCH && ( [[ -z "$DISABLE_ROOT_OUTPUT" ]] || needs_root_output # always run vertexing if requested and if there are some sources, but in cosmic mode we work in pass-trough mode (create record for non-associated tracks) ( [[ $BEAMTYPE == "cosmic" ]] || ! has_detector_reco ITS) && PVERTEX_CONFIG+=" --skip" -has_detector_matching PRIMVTX && [[ ! -z "$VERTEXING_SOURCES" ]] && add_W o2-primary-vertexing-workflow "$DISABLE_MC $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $PVERTEX_CONFIG --pipeline $(get_N primary-vertexing MATCH REST 1 PRIMVTX),$(get_N pvertex-track-matching MATCH REST 1 PRIMVTXMATCH)" "${PVERTEXING_CONFIG_KEY};${INTERACTION_TAG_CONFIG_KEY};" +has_detector_matching PRIMVTX && [[ ! -z "$VERTEXING_SOURCES" ]] && [[ $GLOBAL_READER_NEEDS_PV != 1 ]] && add_W o2-primary-vertexing-workflow "$DISABLE_MC $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $PVERTEX_CONFIG --pipeline $(get_N primary-vertexing MATCH REST 1 PRIMVTX),$(get_N pvertex-track-matching MATCH REST 1 PRIMVTXMATCH)" "${PVERTEXING_CONFIG_KEY};${INTERACTION_TAG_CONFIG_KEY};" if [[ $BEAMTYPE != "cosmic" ]] && has_detectors_reco ITS && has_detector_matching SECVTX && [[ ! -z "$SVERTEXING_SOURCES" ]]; then - add_W o2-secondary-vertexing-workflow "$DISABLE_MC $STRTRACKING $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $TPC_CORR_OPT --vertexing-sources $SVERTEXING_SOURCES --threads $SVERTEX_THREADS --pipeline $(get_N secondary-vertexing MATCH REST $SVERTEX_THREADS SECVTX)" "$TPC_CORR_KEY" + [[ $GLOBAL_READER_NEEDS_SV != 1 ]] && add_W o2-secondary-vertexing-workflow "$DISABLE_MC $STRTRACKING $DISABLE_ROOT_INPUT $DISABLE_ROOT_OUTPUT $TPC_CORR_OPT --vertexing-sources $SVERTEXING_SOURCES --threads $SVERTEX_THREADS --pipeline $(get_N secondary-vertexing MATCH REST $SVERTEX_THREADS SECVTX)" "$TPC_CORR_KEY" SECTVTX_ON="1" else SECTVTX_ON="0" @@ -625,8 +633,8 @@ workflow_has_parameter AOD && [[ ! -z "$AOD_SOURCES" ]] && add_W o2-aod-producer # extra workflows in case we want to extra ITS/MFT info for dead channel maps to then go to CCDB for MC : ${ALIEN_JDL_PROCESSITSDEADMAP:=} : ${ALIEN_JDL_PROCESSMFTDEADMAP:=} -[[ $ALIEN_JDL_PROCESSITSDEADMAP == 1 ]] && has_detector ITS && add_W o2-itsmft-deadmap-builder-workflow " --local-output --output-dir . --source clusters --tf-sampling 1000" -[[ $ALIEN_JDL_PROCESSMFTDEADMAP == 1 ]] && has_detector MFT && add_W o2-itsmft-deadmap-builder-workflow " --runmft --local-output --output-dir . --source clusters --tf-sampling 1000" +[[ $ALIEN_JDL_PROCESSITSDEADMAP == 1 ]] && has_detector ITS && add_W o2-itsmft-deadmap-builder-workflow " --local-output --output-dir . --source clusters --tf-sampling 350" +[[ $ALIEN_JDL_PROCESSMFTDEADMAP == 1 ]] && has_detector MFT && add_W o2-itsmft-deadmap-builder-workflow " --runmft --local-output --output-dir . --source clusters --tf-sampling 350" # --------------------------------------------------------------------------------------------------------------------- diff --git a/prodtests/full-system-test/start_tmux.sh b/prodtests/full-system-test/start_tmux.sh index e56514196afe3..22b0ce2ddcd2a 100755 --- a/prodtests/full-system-test/start_tmux.sh +++ b/prodtests/full-system-test/start_tmux.sh @@ -97,19 +97,16 @@ fi FST_SLEEP0=0 FST_SLEEP1=0 -FST_SLEEP2=45 +FST_SLEEP2=30 if [[ -z $SHM_MANAGER_SHMID ]]; then rm -f /dev/shm/*fmq* if [[ `ls /dev/shm/*fmq* 2> /dev/null | wc -l` != "0" ]]; then echo "FMQ SHM files left which cannot be deleted, please clean up!" exit 1 fi -else - FST_SLEEP0=0 - FST_SLEEP1=0 - FST_SLEEP2=30 fi [[ ! -z $FST_TMUX_DD_WAIT ]] && FST_SLEEP2=$FST_TMUX_DD_WAIT +[[ ${O2_GPU_RTC:-0} == 1 ]] && FST_SLEEP2=60 if workflow_has_parameter CALIB_PROXIES; then CALIB_COMMAND="$GEN_TOPO_MYDIR/aggregator-workflow.sh" diff --git a/prodtests/full_system_test.sh b/prodtests/full_system_test.sh index f1c40f4194143..e429ee7ad078b 100755 --- a/prodtests/full_system_test.sh +++ b/prodtests/full_system_test.sh @@ -50,7 +50,7 @@ GPUMEMSIZE=${GPUMEMSIZE:-6000000000} # Size of GPU memory to use in case ENABBLE NTIMEFRAMES=${NTIMEFRAMES:-1} # Number of time frames to process TFDELAY=${TFDELAY:-100} # Delay in seconds between publishing time frames [[ -z ${NOMCLABELS+x} ]] && NOMCLABELS="--disable-mc" -O2SIMSEED=${O2SIMSEED:--1} +O2SIMSEED=${O2SIMSEED:-0} SPLITTRDDIGI=${SPLITTRDDIGI:-1} DIGITDOWNSCALINGTRD=${DIGITDOWNSCALINGTRD:-1000} NHBPERTF=${NHBPERTF:-128} @@ -140,8 +140,8 @@ taskwrapper sim.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} --seed $O2SIMSEED if [[ $DO_EMBEDDING == 1 ]]; then taskwrapper embed.log o2-sim ${FST_BFIELD+--field=}${FST_BFIELD} -j $NJOBS --run ${RUNNUMBER} -n $NEvents -g pythia8pp -e ${FST_MC_ENGINE} -o sig --configKeyValues ${FST_EMBEDDING_CONFIG} --embedIntoFile o2sim_Kine.root fi -taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents ${DIGIQED} ${NOMCLABELS} --sims ${SIM_SOURCES} --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} ${DIGITOPT} --configKeyValues "\"${DIGITOPTKEY}\"" --interactionRate $FST_COLRATE -[[ $SPLITTRDDIGI == "1" ]] && taskwrapper digiTRD.log o2-sim-digitizer-workflow -n $NEvents ${NOMCLABELS} --onlyDet TRD --trd-digit-downscaling ${DIGITDOWNSCALINGTRD} --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} --incontext collisioncontext.root --configKeyValues "\"${DIGITOPTKEYTRD}\"" +taskwrapper digi.log o2-sim-digitizer-workflow -n $NEvents ${DIGIQED} ${NOMCLABELS} --sims ${SIM_SOURCES} --tpc-lanes $((NJOBS < 36 ? NJOBS : 36)) --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} ${DIGITOPT} --configKeyValues "\"${DIGITOPTKEY}\"" --interactionRate $FST_COLRATE --early-forward-policy always +[[ $SPLITTRDDIGI == "1" ]] && taskwrapper digiTRD.log o2-sim-digitizer-workflow -n $NEvents ${NOMCLABELS} --onlyDet TRD --trd-digit-downscaling ${DIGITDOWNSCALINGTRD} --shm-segment-size $SHMSIZE ${GLOBALDPLOPT} --incontext collisioncontext.root --configKeyValues "\"${DIGITOPTKEYTRD}\"" --early-forward-policy always touch digiTRD.log_done if [[ "0$GENERATE_ITSMFT_DICTIONARIES" == "01" ]]; then diff --git a/run/O2HitMerger.h b/run/O2HitMerger.h index a819f0b8cb146..543aa9f48cae7 100644 --- a/run/O2HitMerger.h +++ b/run/O2HitMerger.h @@ -75,6 +75,8 @@ #include #include #include +#include +#include #endif #include @@ -1005,6 +1007,14 @@ void O2HitMerger::initDetInstances() mDetectorInstances[i] = std::move(std::make_unique(true)); counter++; } + if (i == DetID::MI3) { + mDetectorInstances[i] = std::move(std::make_unique(true)); + counter++; + } + if (i == DetID::ECL) { + mDetectorInstances[i] = std::move(std::make_unique(true)); + counter++; + } #endif } if (counter != DetID::nDetectors) { diff --git a/run/O2SimDevice.h b/run/O2SimDevice.h index 1d1b769bcb5fd..07f7e9f82e249 100644 --- a/run/O2SimDevice.h +++ b/run/O2SimDevice.h @@ -205,6 +205,28 @@ class O2SimDevice final : public fair::mq::Device reproducibleSim = false; } + // Mainly for debugging reasons, we allow to transport + // a specific event + eventpart. This allows to reproduce and debug bugs faster, once + // we know in which precise chunk they occur. The expected format for the environment variable + // is "eventnum:partid". + auto eventselection = getenv("O2SIM_RESTRICT_EVENTPART"); + int focus_on_event = -1; + int focus_on_part = -1; + if (eventselection) { + auto splitString = [](const std::string& str) { + std::pair parts; + size_t pos = str.find(':'); + if (pos != std::string::npos) { + parts.first = str.substr(0, pos); + parts.second = str.substr(pos + 1); + } + return parts; + }; + auto p = splitString(eventselection); + focus_on_event = std::atoi(p.first.c_str()); + focus_on_part = std::atoi(p.second.c_str()); + } + fair::mq::MessagePtr request(requestchannel.NewSimpleMessage(PrimaryChunkRequest{workerID, -1, counter++})); // <-- don't need content; channel means -> give primaries fair::mq::Parts reply; @@ -252,14 +274,22 @@ class O2SimDevice final : public fair::mq::Device } if (goon) { - mVMCApp->setPrimaries(chunk->mParticles); auto info = chunk->mSubEventInfo; - mVMCApp->setSubEventInfo(&info); - LOG(info) << workerStr() << " Processing " << chunk->mParticles.size() << " primary particles " << "for event " << info.eventID << "/" << info.maxEvents << " " << "part " << info.part << "/" << info.nparts; + + if (eventselection == nullptr || (focus_on_event == info.eventID && focus_on_part == info.part)) { + mVMCApp->setPrimaries(chunk->mParticles); + } else { + // nothing to transport here + mVMCApp->setPrimaries(std::vector{}); + LOG(info) << workerStr() << " This chunk will be skipped"; + } + + mVMCApp->setSubEventInfo(&info); + if (reproducibleSim) { LOG(info) << workerStr() << " Setting seed for this sub-event to " << chunk->mSubEventInfo.seed; gRandom->SetSeed(chunk->mSubEventInfo.seed); diff --git a/run/SimExamples/README.md b/run/SimExamples/README.md index 13386d0baed97..5615848202fca 100644 --- a/run/SimExamples/README.md +++ b/run/SimExamples/README.md @@ -15,11 +15,14 @@ * \subpage refrunSimExamplesHepMC * \subpage refrunSimExamplesHepMC_STARlight * \subpage refrunSimExamplesJet_Embedding_Pythia8 -* \subpage refrunSimExamplesStepMonitoringSimple1 +* \subpage refrunSimExamplesMcTracksToAOD +* \subpage refrunSimExamplesMcTracksToAOD +* \subpage refrunSimExamplesPythia * \subpage refrunSimExamplesForceDecay_Lambda_Neutron_Dalitz * \subpage refrunSimExamplesJustPrimaryKinematics * \subpage refrunSimExamplesSelective_Transport * \subpage refrunSimExamplesSelective_Transport_pi0 +* \subpage refrunSimExamplesStepMonitoringSimple1 * \subpage refrunSimExamplesCustom_EventInfo * \subpage refrunSimExamplesMCTrackToDPL * \subpage refrunSimExamplesTParticle diff --git a/run/SimExamples/Selective_Transport_pi0/Readme.md b/run/SimExamples/Selective_Transport_pi0/Readme.md index 56df617faafd9..77dc700ed455e 100644 --- a/run/SimExamples/Selective_Transport_pi0/Readme.md +++ b/run/SimExamples/Selective_Transport_pi0/Readme.md @@ -1,3 +1,7 @@ + + This is a simulation example showing how to run simulation and selectively transport particles through the detector geometry according to configurable settings and how to use the external event trigger mechanism on generators. diff --git a/run/dpl_eventgen.cxx b/run/dpl_eventgen.cxx index b1929482041b0..66dd1c8342990 100644 --- a/run/dpl_eventgen.cxx +++ b/run/dpl_eventgen.cxx @@ -101,8 +101,8 @@ struct GeneratorTask { } // report number of TFs injected for the rate limiter to work - pc.services().get().send(o2::monitoring::Metric{(uint64_t)tfCounter, "df-sent"}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL)); ++tfCounter; + pc.services().get().send(o2::monitoring::Metric{(uint64_t)tfCounter, "df-sent"}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL)); bool time_expired = false; if (ttl > 0) { timer.Stop(); diff --git a/run/o2sim_hepmc_publisher.cxx b/run/o2sim_hepmc_publisher.cxx index ec049a44439a1..bf40abacb134f 100644 --- a/run/o2sim_hepmc_publisher.cxx +++ b/run/o2sim_hepmc_publisher.cxx @@ -148,8 +148,8 @@ struct O2simHepmcPublisher { } // report number of TFs injected for the rate limiter to work - pc.services().get().send(o2::monitoring::Metric{(uint64_t)tfCounter, "df-sent"}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL)); ++tfCounter; + pc.services().get().send(o2::monitoring::Metric{(uint64_t)tfCounter, "df-sent"}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL)); if (eos || (maxEvents > 0 && eventCounter == maxEvents)) { pc.services().get().endOfStream(); pc.services().get().readyToQuit(QuitRequest::Me); diff --git a/run/o2sim_kine_publisher.cxx b/run/o2sim_kine_publisher.cxx index 83f82fd69cca3..f72dd6eebaaf0 100644 --- a/run/o2sim_kine_publisher.cxx +++ b/run/o2sim_kine_publisher.cxx @@ -49,8 +49,8 @@ struct O2simKinePublisher { ++eventCounter; } // report number of TFs injected for the rate limiter to work - pc.services().get().send(o2::monitoring::Metric{(uint64_t)tfCounter, "df-sent"}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL)); ++tfCounter; + pc.services().get().send(o2::monitoring::Metric{(uint64_t)tfCounter, "df-sent"}.addTag(o2::monitoring::tags::Key::Subsystem, o2::monitoring::tags::Value::DPL)); if (eventCounter >= nEvents) { pc.services().get().endOfStream(); pc.services().get().readyToQuit(QuitRequest::Me);