From 262656472a478f7d6ed62268ee14d44901deb751 Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Wed, 8 Feb 2023 11:32:54 +0100 Subject: [PATCH 1/4] TPC: Adding streamer for FastTransform in reconstruction SpaceCharge: adding option to use analytical formula for corrections and distortions - adding simple default analytical distortions/corrections - add streamer in digitizer DebugStreamer: Allow writing out streams in parallel --- Common/Utils/CMakeLists.txt | 2 +- .../Utils/include/CommonUtils/DebugStreamer.h | 50 ++++-- Common/Utils/src/DebugStreamer.cxx | 53 ++++-- .../macro/createTPCSpaceChargeCorrection.C | 65 +++++++ Detectors/TPC/simulation/src/Digitizer.cxx | 18 +- .../include/TPCSpaceCharge/SpaceCharge.h | 63 ++++++- .../TPCSpaceCharge/SpaceChargeHelpers.h | 69 ++++++++ Detectors/TPC/spacecharge/src/SpaceCharge.cxx | 162 +++++++++++++++--- .../spacecharge/src/TPCSpacechargeLinkDef.h | 2 + GPU/TPCFastTransformation/TPCFastTransform.h | 35 +++- GPU/Workflow/src/GPUWorkflowSpec.cxx | 11 ++ .../src/TPCDigitizerSpec.cxx | 1 + 12 files changed, 472 insertions(+), 59 deletions(-) diff --git a/Common/Utils/CMakeLists.txt b/Common/Utils/CMakeLists.txt index a0155ffc61f3d..4e43116b279a1 100644 --- a/Common/Utils/CMakeLists.txt +++ b/Common/Utils/CMakeLists.txt @@ -25,7 +25,7 @@ o2_add_library(CommonUtils src/IRFrameSelector.cxx src/DebugStreamer.cxx PUBLIC_LINK_LIBRARIES ROOT::Hist ROOT::Tree Boost::iostreams O2::CommonDataFormat O2::Headers - FairLogger::FairLogger O2::MathUtils) + FairLogger::FairLogger O2::MathUtils TBB::tbb) o2_target_root_dictionary(CommonUtils HEADERS include/CommonUtils/TreeStream.h diff --git a/Common/Utils/include/CommonUtils/DebugStreamer.h b/Common/Utils/include/CommonUtils/DebugStreamer.h index 4cce9354dc4ed..d6df63a38fcec 100644 --- a/Common/Utils/include/CommonUtils/DebugStreamer.h +++ b/Common/Utils/include/CommonUtils/DebugStreamer.h @@ -21,6 +21,7 @@ #include "CommonUtils/ConfigurableParamHelper.h" #if defined(DEBUG_STREAMER) #include "CommonUtils/TreeStreamRedirector.h" +#include #endif #endif @@ -29,10 +30,12 @@ namespace o2::utils /// struct defining the flags which can be used to check if a certain debug streamer is used enum StreamFlags { - streamdEdx = 1 << 0, ///< stream corrections and cluster properties used for the dE/dx - streamDigitFolding = 1 << 1, ///< stream ion tail and saturatio information - streamDigits = 1 << 2, ///< stream digit information - streamITCorr = 1 << 4, ///< stream ion tail correction information + streamdEdx = 1 << 0, ///< stream corrections and cluster properties used for the dE/dx + streamDigitFolding = 1 << 1, ///< stream ion tail and saturatio information + streamDigits = 1 << 2, ///< stream digit information + streamFastTransform = 1 << 3, ///< stream tpc fast transform + streamITCorr = 1 << 4, ///< stream ion tail correction information + streamDistortionsSC = 1 << 5, ///< stream distortions applied in the TPC space-charge class (used for example in the tpc digitizer) }; #if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) @@ -59,16 +62,33 @@ class DebugStreamer // CPU implementation of the class #if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) && defined(DEBUG_STREAMER) public: + /// default constructor + DebugStreamer(); + /// set the streamer i.e. create the output file and set up the streamer /// \param outFile output file name without .root suffix /// \param option RECREATE or UPDATE - void setStreamer(const char* outFile, const char* option); + /// \param id unique id for given streamer (i.e. for defining unique streamers for each thread) + void setStreamer(const char* outFile, const char* option, const size_t id = getCPUID()); /// \return returns if the streamer is set - bool isStreamerSet() const { return mTreeStreamer ? true : false; } + /// \param id unique id of streamer + bool isStreamerSet(const size_t id = getCPUID()) const { return getStreamerPtr(id); } + + /// flush TTree for given ID to disc + /// \param id unique id of streamer + void flush(const size_t id); + + /// flush all TTrees to disc + void flush(); + + /// \return returns streamer object for given id + /// \param id unique id of streamer + o2::utils::TreeStreamRedirector& getStreamer(const size_t id = getCPUID()) { return *(mTreeStreamer[id]); } /// \return returns streamer object - o2::utils::TreeStreamRedirector& getStreamer() { return *mTreeStreamer; } + /// \param id unique id of streamer + o2::utils::TreeStreamRedirector* getStreamerPtr(const size_t id = getCPUID()) const; /// \return returns streamer level i.e. what will be written to file static StreamFlags getStreamFlags() { return ParameterDebugStreamer::Instance().StreamLevel; } @@ -77,11 +97,13 @@ class DebugStreamer static size_t getCPUID(); /// \return returns number of trees in the streamer - int getNTrees() const; + /// \param id unique id of streamer + int getNTrees(const size_t id = getCPUID()) const; /// \return returns an unique branch name which is not already written in the file /// \param tree name of the tree for which to get a unique tree name - std::string getUniqueTreeName(const char* tree) const; + /// \param id unique id of streamer + std::string getUniqueTreeName(const char* tree, const size_t id = getCPUID()) const; /// set directly the debug level static void setStreamFlags(const StreamFlags streamFlags) { o2::conf::ConfigurableParam::setValue("DebugStreamerParam", "StreamLevel", static_cast(streamFlags)); } @@ -102,7 +124,9 @@ class DebugStreamer static void mergeTrees(const char* inpFile, const char* outFile, const char* option = "fast"); private: - std::unique_ptr mTreeStreamer; ///< streamer which is used for the debugging + using StreamersPerFlag = tbb::concurrent_unordered_map>; + StreamersPerFlag mTreeStreamer; ///< streamer which is used for the debugging + #else // empty implementation of the class for GPU or when the debug streamer is not build for CPU @@ -126,14 +150,16 @@ class DebugStreamer } }; - GPUd() StreamerDummy getStreamer() const { return StreamerDummy{}; }; + GPUd() StreamerDummy getStreamer(const int id = 0) const { return StreamerDummy{}; }; template - GPUd() StreamerDummy getUniqueTreeName(Type) const + GPUd() StreamerDummy getUniqueTreeName(Type, const int id = 0) const { return StreamerDummy{}; } + GPUd() void flush() const {}; + #endif }; diff --git a/Common/Utils/src/DebugStreamer.cxx b/Common/Utils/src/DebugStreamer.cxx index 3ff0082144e4e..3020a2f4d2175 100644 --- a/Common/Utils/src/DebugStreamer.cxx +++ b/Common/Utils/src/DebugStreamer.cxx @@ -21,32 +21,65 @@ O2ParamImpl(o2::utils::ParameterDebugStreamer); #if !defined(GPUCA_GPUCODE) && !defined(GPUCA_STANDALONE) && defined(DEBUG_STREAMER) -void o2::utils::DebugStreamer::setStreamer(const char* outFile, const char* option) +o2::utils::DebugStreamer::DebugStreamer() { - if (!isStreamerSet()) { - ROOT::EnableThreadSafety(); - mTreeStreamer = std::make_unique(fmt::format("{}_{}.root", outFile, getCPUID()).data(), option); + ROOT::EnableThreadSafety(); +} + +void o2::utils::DebugStreamer::setStreamer(const char* outFile, const char* option, const size_t id) +{ + if (!isStreamerSet(id)) { + mTreeStreamer[id] = std::make_unique(fmt::format("{}_{}.root", outFile, id).data(), option); + } +} + +void o2::utils::DebugStreamer::flush(const size_t id) +{ + if (isStreamerSet(id)) { + mTreeStreamer[id].reset(); + } +} + +void o2::utils::DebugStreamer::flush() +{ + for (const auto& pair : mTreeStreamer) { + flush(pair.first); } } -std::string o2::utils::DebugStreamer::getUniqueTreeName(const char* tree) const { return fmt::format("{}_{}", tree, getNTrees()); } +std::string o2::utils::DebugStreamer::getUniqueTreeName(const char* tree, const size_t id) const { return fmt::format("{}_{}", tree, getNTrees(id)); } size_t o2::utils::DebugStreamer::getCPUID() { return std::hash{}(std::this_thread::get_id()); } -int o2::utils::DebugStreamer::getNTrees() const { return mTreeStreamer->GetFile()->GetListOfKeys()->GetEntries(); } +o2::utils::TreeStreamRedirector* o2::utils::DebugStreamer::getStreamerPtr(const size_t id) const +{ + auto it = mTreeStreamer.find(id); + if (it != mTreeStreamer.end()) { + return (it->second).get(); + } else { + return nullptr; + } +} + +int o2::utils::DebugStreamer::getNTrees(const size_t id) const { return isStreamerSet(id) ? getStreamerPtr(id)->GetFile()->GetListOfKeys()->GetEntries() : -1; } void o2::utils::DebugStreamer::mergeTrees(const char* inpFile, const char* outFile, const char* option) { TFile fInp(inpFile, "READ"); - TList list; + std::unordered_map lists; for (TObject* keyAsObj : *fInp.GetListOfKeys()) { const auto key = dynamic_cast(keyAsObj); - list.Add((TTree*)fInp.Get(key->GetName())); + TTree* tree = (TTree*)fInp.Get(key->GetName()); + // perform simple check on the number of entries to merge only TTree with same content (ToDo: Do check on name of branches) + const int entries = tree->GetListOfBranches()->GetEntries(); + lists[entries].Add(tree); } TFile fOut(outFile, "RECREATE"); - auto tree = TTree::MergeTrees(&list, option); - fOut.WriteObject(tree, "tree"); + for (auto& list : lists) { + auto tree = TTree::MergeTrees(&list.second, option); + fOut.WriteObject(tree, tree->GetName()); + } } void o2::utils::DebugStreamer::enableStream(const StreamFlags streamFlag) diff --git a/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C b/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C index cba9c5c7aff6f..d8e9f1c5e2c38 100644 --- a/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C +++ b/Detectors/TPC/reconstruction/macro/createTPCSpaceChargeCorrection.C @@ -54,6 +54,8 @@ std::unique_ptr spaceCharge; void getGlobalSpaceChargeCorrection(const int roc, double x, double y, double z, double& dx, double& dy, double& dz); +void getLocalSpaceChargeCorrection(const int roc, int irow, double y, double z, + double& dx, double& dy, double& dz); void initSpaceCharge(const char* histoFileName, const char* histoName); void DumpFlatObjectToFile(const TPCFastTransform* obj, const char* file); @@ -98,6 +100,56 @@ void createTPCSpaceChargeCorrection( } } +/// Creates TPCFastTransform object for TPC space-charge correction, stores it in a file and provides a debug tree if requested +/// \param outputFileName name of the output file to store the TPCFastTransform object in +/// \param debug create debug tree comparing original corrections and spline interpolations from TPCFastTransform (1 = on the spline interpolation grid, 2 = on the original lookup table grid) +void createTPCSpaceChargeCorrectionAnalytical( + const char* outputFileName = "tpctransform.root", + const int debug = 0) +{ + SC::setGrid(nZ, nR, nPhi); + + // initialize space-charge object + spaceCharge = std::make_unique(); + + // default analytical formulas for distortions and corrections + AnalyticalDistCorr formula; + formula.initDefault(); + /* + set custom distortions and corrections here. e.g. + TFormula mDistZ{"mDlZ", "z * 11"}; + formula.mDlZFormula = mDistZ; + */ + + spaceCharge->setDistortionsCorrectionsAnalytical(formula); + spaceCharge->setUseAnalyticalDistCorr(true); + + // dumping the space-charge object to file to apply it during the TPC digitizer simulation + TFile fSC("distortions_analytical.root", "RECREATE"); + spaceCharge->dumpAnalyticalCorrectionsDistortions(fSC); + + TPCFastTransformHelperO2::instance()->setLocalSpaceChargeCorrection(getLocalSpaceChargeCorrection); + + std::unique_ptr fastTransform(TPCFastTransformHelperO2::instance()->create(0)); + fastTransform->writeToFile(outputFileName, "ccdb_object"); + + if (debug > 0) { + const o2::gpu::TPCFastTransformGeo& geo = fastTransform->getGeometry(); + utils::TreeStreamRedirector pcstream(TString::Format("fastTransformUnitTest_debug%d_gridsize%d-%d-%d.root", debug, nPhi, nR, nZ).Data(), "recreate"); + switch (debug) { + case 1: + debugInterpolation(pcstream, geo, fastTransform.get()); + break; + case 2: + debugGridpoints(pcstream, geo, fastTransform.get()); + break; + default: + printf("Debug option %d is not implemented. Debug tree will be empty.", debug); + } + pcstream.Close(); + } +} + /// Initialize calculation of original correction lookup tables /// \param histoFileName path and name to the root file containing input space-charge density histograms /// \param histoName name of the input space-charge density histogram @@ -131,6 +183,19 @@ void getGlobalSpaceChargeCorrection(const int roc, double x, double y, double z, spaceCharge->getCorrections(x, y, z, side, dx, dy, dz); } +/// Function to get corrections from original lookup tables +/// \param XYZ array with x, y and z position +/// \param dXdYdZ array with correction dx, dy and dz +void getLocalSpaceChargeCorrection(const int roc, int irow, double y, double z, + double& dx, double& dy, double& dz) +{ + Side side = roc < 18 ? Side::A : Side::C; + float x = o2::tpc::TPCFastTransformHelperO2::instance()->getGeometry().getRowInfo(irow).x; + dx = spaceCharge->getDistortionsCorrectionsAnalytical().getCorrectionsLX(x, y, z, side); + dy = spaceCharge->getDistortionsCorrectionsAnalytical().getCorrectionsLY(x, y, z, side); + dz = spaceCharge->getDistortionsCorrectionsAnalytical().getCorrectionsLZ(x, y, z, side); +} + /// Save TPCFastTransform to a file /// \param obj TPCFastTransform object to store /// \param file output file name diff --git a/Detectors/TPC/simulation/src/Digitizer.cxx b/Detectors/TPC/simulation/src/Digitizer.cxx index ec343d5bd5bd1..9378859199a1d 100644 --- a/Detectors/TPC/simulation/src/Digitizer.cxx +++ b/Detectors/TPC/simulation/src/Digitizer.cxx @@ -163,6 +163,13 @@ void Digitizer::flush(std::vector& digits, { SAMPAProcessing& sampaProcessing = SAMPAProcessing::instance(); mDigitContainer.fillOutputContainer(digits, labels, commonModeOutput, mSector, sampaProcessing.getTimeBinFromTime(mEventTime - mOutputDigitTimeOffset), mIsContinuous, finalFlush); + // flushing debug output to file + using Streamer = o2::utils::DebugStreamer; + if (Streamer::checkStream(o2::utils::StreamFlags::streamDistortionsSC)) { + if (((finalFlush && mIsContinuous) || (!mIsContinuous)) && mSpaceCharge) { + mSpaceCharge->flushStreamer(); + } + } } void Digitizer::setUseSCDistortions(SC::SCDistortionType distortionType, const TH3* hisInitialSCDensity) @@ -190,10 +197,13 @@ void Digitizer::setUseSCDistortions(TFile& finp) if (!mSpaceCharge) { mSpaceCharge = std::make_unique(); } - mSpaceCharge->setGlobalDistortionsFromFile(finp, Side::A); - mSpaceCharge->setGlobalDistortionsFromFile(finp, Side::C); - mSpaceCharge->setGlobalCorrectionsFromFile(finp, Side::A); - mSpaceCharge->setGlobalCorrectionsFromFile(finp, Side::C); + + // in case analytical distortions are loaded from file they are applied + mSpaceCharge->setAnalyticalCorrectionsDistortionsFromFile(finp); + if (!mSpaceCharge->getUseAnalyticalDistCorr()) { + mSpaceCharge->setGlobalDistortionsFromFile(finp, Side::A); + mSpaceCharge->setGlobalDistortionsFromFile(finp, Side::C); + } } void Digitizer::setStartTime(double time) diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h index 38a6bcb8f7f97..f685155e9965d 100644 --- a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceCharge.h @@ -26,6 +26,7 @@ #include "TPCSpaceCharge/DataContainer3D.h" #include "TPCSpaceCharge/SpaceChargeParameter.h" #include "DataFormatsTPC/Defs.h" +#include "CommonUtils/DebugStreamer.h" class TH3; class TH3D; @@ -64,7 +65,7 @@ class SpaceCharge /// \param omegaTau \omega \tau value /// \param t1 value for t1 /// \param t2 value for t2 - SpaceCharge(const DataT omegaTau = 0.32f, const DataT t1 = 1, const DataT t2 = 1) { setOmegaTauT1T2(omegaTau, t1, t2); }; + SpaceCharge(const DataT omegaTau = 0.32f, const DataT t1 = 1, const DataT t2 = 1); /// \param nZVertices number of vertices of the grid in z direction /// \param nRVertices number of vertices of the grid in z direction @@ -333,6 +334,15 @@ class SpaceCharge /// \param corrZ returns corrections in z direction void getCorrections(const DataT x, const DataT y, const DataT z, const Side side, DataT& corrX, DataT& corrY, DataT& corrZ) const; + /// get the analytical global corrections for given coordinate + /// \param x global x coordinate + /// \param y global y coordinate + /// \param z global z coordinate + /// \param corrX returns corrections in x direction + /// \param corrY returns corrections in y direction + /// \param corrZ returns corrections in z direction + void getCorrectionsAnalytical(const DataT x, const DataT y, const DataT z, const Side side, DataT& corrX, DataT& corrY, DataT& corrZ) const { getDistortionsCorrectionsAnalytical(x, y, z, side, corrX, corrY, corrZ, false); } + /// get the local distortions for given coordinate /// \param z global z coordinate /// \param r global r coordinate @@ -414,6 +424,27 @@ class SpaceCharge /// \param distZ returns distortion in z direction void getDistortions(const DataT x, const DataT y, const DataT z, const Side side, DataT& distX, DataT& distY, DataT& distZ) const; + /// get the global distortions for given coordinate for a possible analytical formula if it was specified + /// \param x global x coordinate + /// \param y global y coordinate + /// \param z global z coordinate + /// \param distX returns distortion in x direction + /// \param distY returns distortion in y direction + /// \param distZ returns distortion in z direction + void getDistortionsAnalytical(const DataT x, const DataT y, const DataT z, const Side side, DataT& distX, DataT& distY, DataT& distZ) const { getDistortionsCorrectionsAnalytical(x, y, z, side, distX, distY, distZ, true); } + + /// set distortions and corrections by an analytical formula + void setDistortionsCorrectionsAnalytical(const AnalyticalDistCorr& formula) { mAnaDistCorr = formula; } + + /// \return returns analytical distortions/corrections + const auto& getDistortionsCorrectionsAnalytical() const& { return mAnaDistCorr; } + + /// setting usage of the analytical formula for the distortions and corrections + void setUseAnalyticalDistCorr(const bool useAna) { mUseAnaDistCorr = useAna; } + + /// \return returns if the analytical formula will be used in the distortElectron() and getCorrections() function + bool getUseAnalyticalDistCorr() const { return mUseAnaDistCorr; } + /// convert x and y coordinates from cartesian to the radius in polar coordinates static DataT getRadiusFromCartesian(const DataT x, const DataT y) { return std::sqrt(x * x + y * y); } @@ -821,6 +852,14 @@ class SpaceCharge template int dumpGlobalDistortions(TFile& outf, const Side side) const; + /// write analytical corrections and distortions to file + /// \param outf output file where the analytical corrections and distortions will be written to + int dumpAnalyticalCorrectionsDistortions(TFile& outf) const; + + /// set analytical corrections and distortions from file + /// \param inpf input file where the analytical corrections and distortions are stored + void setAnalyticalCorrectionsDistortionsFromFile(TFile& inpf); + /// set global distortions from root file /// \param inpf input file where the global distortions are stored /// \side side of the TPC @@ -914,6 +953,9 @@ class SpaceCharge /// \return returns max threads static int getOMPMaxThreads(); + /// write output of streamer to file + void flushStreamer() { mStreamer.flush(); } + private: inline static auto& mParamGrid = ParameterSpaceCharge::Instance(); /// mInterpolatorLocalDist[FNSIDES]{{mLocalDistdR[Side::A], mLocalDistdZ[Side::A], mLocalDistdRPhi[Side::A], mGrid3D[Side::A], Side::A}, {mLocalDistdR[Side::C], mLocalDistdZ[Side::C], mLocalDistdRPhi[Side::C], mGrid3D[Side::C], Side::C}}; /// mInterpolatorLocalVecDist[FNSIDES]{{mLocalVecDistdR[Side::A], mLocalVecDistdZ[Side::A], mLocalVecDistdRPhi[Side::A], mGrid3D[Side::A], Side::A}, {mLocalVecDistdR[Side::C], mLocalVecDistdZ[Side::C], mLocalVecDistdRPhi[Side::C], mGrid3D[Side::C], Side::C}}; /// mInterpolatorEField[FNSIDES]{{mElectricFieldEr[Side::A], mElectricFieldEz[Side::A], mElectricFieldEphi[Side::A], mGrid3D[Side::A], Side::A}, {mElectricFieldEr[Side::C], mElectricFieldEz[Side::C], mElectricFieldEphi[Side::C], mGrid3D[Side::C], Side::C}}; /// mAnaDistCorr; + bool mUseAnaDistCorr{false}; ///< flag if analytical distortions will be used in the distortElectron() and getCorrections() function + o2::utils::DebugStreamer mStreamer; ///& potentialFunc, const GEMstack stack, const bool bottom, const Side side, const bool outerFrame = false); - ClassDefNV(SpaceCharge, 2); + void getDistortionsCorrectionsAnalytical(const DataT x, const DataT y, const DataT z, const Side side, DataT& distX, DataT& distY, DataT& distZ, const bool dist) const; + + ClassDefNV(SpaceCharge, 3); }; /// @@ -1189,7 +1236,7 @@ template int SpaceCharge::dumpElectricFields(TFile& outf, const Side side) const { if (!mIsEfieldSet[side]) { - LOGP(warning, "============== E-Fields are not set! returning ==============\n"); + LOGP(info, "============== E-Fields are not set! returning ==============\n"); return 0; } const std::string sideName = getSideName(side); @@ -1215,7 +1262,7 @@ template int SpaceCharge::dumpGlobalDistortions(TFile& outf, const Side side) const { if (!mIsGlobalDistSet[side]) { - LOGP(warning, "============== global distortions are not set! returning ==============\n"); + LOGP(info, "============== global distortions are not set! returning ==============\n"); return 0; } const std::string sideName = getSideName(side); @@ -1241,7 +1288,7 @@ template int SpaceCharge::dumpGlobalCorrections(TFile& outf, const Side side) const { if (!mIsGlobalCorrSet[side]) { - LOGP(warning, "============== global corrections are not set! returning ==============\n"); + LOGP(info, "============== global corrections are not set! returning ==============\n"); return 0; } const std::string sideName = getSideName(side); @@ -1267,7 +1314,7 @@ template int SpaceCharge::dumpLocalCorrections(TFile& outf, const Side side) const { if (!mIsLocalCorrSet[side]) { - LOGP(warning, "============== local corrections are not set! returning ==============\n"); + LOGP(info, "============== local corrections are not set! returning ==============\n"); return 0; } const std::string sideName = getSideName(side); @@ -1297,7 +1344,7 @@ template int SpaceCharge::dumpLocalDistortions(TFile& outf, const Side side) const { if (!mIsLocalDistSet[side]) { - LOGP(warning, "============== local distortions are not set! returning ==============\n"); + LOGP(info, "============== local distortions are not set! returning ==============\n"); return 0; } const std::string sideName = getSideName(side); @@ -1312,7 +1359,7 @@ template int SpaceCharge::dumpLocalDistCorrVectors(TFile& outf, const Side side) const { if (!mIsLocalVecDistSet[side]) { - LOGP(warning, "============== local distortion vectors are not set! returning ==============\n"); + LOGP(info, "============== local distortion vectors are not set! returning ==============\n"); return 0; } const std::string sideName = getSideName(side); diff --git a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeHelpers.h b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeHelpers.h index 69ece20ef9878..11391caec0836 100644 --- a/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeHelpers.h +++ b/Detectors/TPC/spacecharge/include/TPCSpaceCharge/SpaceChargeHelpers.h @@ -22,6 +22,7 @@ #include #include "TPCSpaceCharge/TriCubic.h" #include "DataFormatsTPC/Defs.h" +#include "TFormula.h" namespace o2 { @@ -131,6 +132,74 @@ class AnalyticalFields o2::tpc::Side mSide{o2::tpc::Side::A}; ///< side of the TPC. Since the absolute value is taken during the calculations the choice of the side is arbitrary. }; +/// struct for containing simple analytical distortions (as function of local coordinates) and the resulting corrections +template +class AnalyticalDistCorr +{ + public: + DataT getDistortionsLX(const DataT lx, const DataT ly, const DataT lz, const Side side) const { return mDlXFormula.Eval(lx, ly, lz, side); }; + DataT getCorrectionsLX(const DataT lx, const DataT ly, const DataT lz, const Side side) const { return mClXFormula.Eval(lx, ly, lz, side); }; + DataT getDistortionsLY(const DataT lx, const DataT ly, const DataT lz, const Side side) const { return mDlYFormula.Eval(lx, ly, lz, side); }; + DataT getCorrectionsLY(const DataT lx, const DataT ly, const DataT lz, const Side side) const { return mClYFormula.Eval(lx, ly, lz, side); }; + DataT getDistortionsLZ(const DataT lx, const DataT ly, const DataT lz, const Side side) const { return mDlZFormula.Eval(lx, ly, lz, side); }; + DataT getCorrectionsLZ(const DataT lx, const DataT ly, const DataT lz, const Side side) const { return mClZFormula.Eval(lx, ly, lz, side); }; + + /// set default analytical formulas for distortions and corrections + void initDefault() + { + mDlXFormula = TFormula{"mDlX", "(254.5 - x) / 50"}; ///< analytical distortions in lx as a function of lx + mClXFormula = TFormula{"mClX", "(x * 50 - 254.5) / 49 - x"}; ///< analytical corrections in lx as a function of lx + mDlYFormula = TFormula{"mDlY", "2 + 0.01 * x"}; ///< analytical distortions in ly as a function of lx + mClYFormula = TFormula{"mClY", "-(2 + 0.01 * (x + (x * 50 - 254.5) / 49 - x))"}; ///< analytical correction in ly as a function of lx + mDlZFormula = TFormula{"mDlZ", "z / 50"}; ///< analytical correction in lz as a function of lz + mClZFormula = TFormula{"mClZ", "z * 50 / 51 - z"}; ///< analytical correction in lz as a function of lz + } + + /// check if all formulas are valid + bool isValid() const { return mDlXFormula.IsValid() && mClXFormula.IsValid() && mDlYFormula.IsValid() && mClYFormula.IsValid() && mDlZFormula.IsValid() && mClZFormula.IsValid(); } + + /// const DataT dlX = (TPCParameters::OFCRADIUS - lx) / 50; // (171 -> 0) / 50 = 3.42 cn + /// return dlX; + TFormula mDlXFormula{}; ///< analytical distortions in lx as a function of lx + + /// analytical correction in lx as a function of lx + /// distorted point: lx_2 = lx_1 + mDlX(lx_1) + /// lx_2 = lx_1 + (TPCParameters::OFCRADIUS - lx) / 50); + /// lx_2 * 50 = lx_1 * 50 + TPCParameters::OFCRADIUS - lx + /// lx_2 * 50 - TPCParameters::OFCRADIUS = lx_1 * 49 + /// lx_2 * 50 - TPCParameters::OFCRADIUS / 49 = lx_1 + /// correction: dCorrX = lx_2 - lx_1 + /// + /// const DataT lx2 = (lx * 50 - TPCParameters::OFCRADIUS) / 49; + /// return lx2 - lx; + TFormula mClXFormula{}; ///< analytical corrections in lx as a function of lx + + /// const DataT dlY = 2 + 0.01 * lx; + /// return dlY; + TFormula mDlYFormula{}; ///< analytical distortions in ly as a function of lx + + /// const DataT dlX_1 = lx + mClX(lx, 0, 0, Side::A); // corrected point (original point without distortion) + /// return -mDlY(dlX_1, 0, 0, Side::A); // distortion at original point + TFormula mClYFormula{}; ///< analytical correction in ly as a function of lx + + /// const DataT dlZ = lz / 50; + /// return dlZ; + TFormula mDlZFormula{}; ///< analytical correction in lz as a function of lz + + /// lz_2 = lz_1 + mDlZ(lz_1) + /// lz_2 = lz_1 + lz_1 / 50 + /// lz_2 = lz_1 * (1 + 1/50) + /// lz_2 / (1 + 1/50) = lz_1 + /// lz_2 * 50 / 51 = lz_1 + /// + /// const DataT lz2 = lz * 50 / 51.; + /// const DataT diffZ = lz2 - lz; + /// return diffZ; + TFormula mClZFormula{}; ///< analytical correction in lz as a function of lz + + ClassDefNV(AnalyticalDistCorr, 1); +}; + /// /// This class gives tricubic interpolation of the electric fields and can be used to calculate the distortions/corrections. /// The electric fields have to be calculated by the poisson solver or given by the analytical formula. diff --git a/Detectors/TPC/spacecharge/src/SpaceCharge.cxx b/Detectors/TPC/spacecharge/src/SpaceCharge.cxx index 395f0f7268873..93a110db3f8a3 100644 --- a/Detectors/TPC/spacecharge/src/SpaceCharge.cxx +++ b/Detectors/TPC/spacecharge/src/SpaceCharge.cxx @@ -27,6 +27,7 @@ #include "CommonUtils/TreeStreamRedirector.h" #include "TPCBase/CalDet.h" #include "TPCBase/Painter.h" +#include "MathUtils/Utils.h" #include #include @@ -35,6 +36,7 @@ #include "TH2F.h" #include "TGraph.h" #include "TCanvas.h" +#include "TROOT.h" #if defined(WITH_OPENMP) || defined(_OPENMP) #include @@ -47,6 +49,13 @@ templateClassImp(o2::tpc::SpaceCharge); using namespace o2::tpc; +template +SpaceCharge::SpaceCharge(const DataT omegaTau, const DataT t1, const DataT t2) +{ + ROOT::EnableThreadSafety(); + setOmegaTauT1T2(omegaTau, t1, t2); +}; + template void SpaceCharge::setGrid(const unsigned short nZVertices, const unsigned short nRVertices, const unsigned short nPhiVertices) { @@ -228,7 +237,6 @@ void SpaceCharge::setPotentialBoundaryGEMFrameAlongR(const std::function< const auto radiusStart = std::sqrt(std::pow(GEMFrameParameters::LENGTHFRAMEIROCBOTTOM / 2, 2) + std::pow(GEMFrameParameters::POSBOTTOM[0], 2)); const auto rStart = getNearestRVertex(radiusStart, side); const int verticesPerSector = mParamGrid.NPhiVertices / SECTORSPERSIDE; - const Mapper& mapper = Mapper::instance(); const auto& regInf = Mapper::instance().getPadRegionInfo(0); const float localYEdgeIROC = regInf.getPadsInRowRegion(0) / 2 * regInf.getPadWidth(); @@ -1304,6 +1312,31 @@ void SpaceCharge::distortElectron(GlobalPosition3D& point) const // get the distortions for input coordinate getDistortions(point.X(), point.Y(), point.Z(), side, distX, distY, distZ); + using Streamer = o2::utils::DebugStreamer; + if (Streamer::checkStream(o2::utils::StreamFlags::streamDistortionsSC)) { + auto& streamer = (const_cast*>(this))->mStreamer; + streamer.setStreamer("debug_distortions", "UPDATE"); + + GlobalPosition3D pos(point); + float phi = std::atan2(pos.Y(), pos.X()); + if (phi < 0.) { + phi += TWOPI; + } + unsigned char secNum = std::floor(phi / SECPHIWIDTH); + const Sector sector(secNum + (pos.Z() < 0) * SECTORSPERSIDE); + LocalPosition3D lPos = Mapper::GlobalToLocal(pos, sector); + + streamer.getStreamer() << streamer.getUniqueTreeName("tree").data() + << "pos=" << pos + << "lPos=" << lPos + << "phi=" << phi + << "secNum=" << secNum + << "distX=" << distX + << "distY=" << distY + << "distZ=" << distZ + << "\n"; + } + // set distorted coordinates point.SetXYZ(point.X() + distX, point.Y() + distY, point.Z() + distZ); } @@ -1377,20 +1410,24 @@ void SpaceCharge::getCorrectionsCyl(const std::vector& z, const st template void SpaceCharge::getCorrections(const DataT x, const DataT y, const DataT z, const Side side, DataT& corrX, DataT& corrY, DataT& corrZ) const { - // convert cartesian to polar - const DataT radius = getRadiusFromCartesian(x, y); - const DataT phi = getPhiFromCartesian(x, y); + if (mUseAnaDistCorr) { + getCorrectionsAnalytical(x, y, z, side, corrX, corrY, corrZ); + } else { + // convert cartesian to polar + const DataT radius = getRadiusFromCartesian(x, y); + const DataT phi = getPhiFromCartesian(x, y); - DataT corrR{}; - DataT corrRPhi{}; - getCorrectionsCyl(z, radius, phi, side, corrZ, corrR, corrRPhi); + DataT corrR{}; + DataT corrRPhi{}; + getCorrectionsCyl(z, radius, phi, side, corrZ, corrR, corrRPhi); - // Calculate corrected position - const DataT radiusCorr = radius + corrR; - const DataT phiCorr = phi + corrRPhi / radius; + // Calculate corrected position + const DataT radiusCorr = radius + corrR; + const DataT phiCorr = phi + corrRPhi / radius; - corrX = getXFromPolar(radiusCorr, phiCorr) - x; // difference between corrected and original x coordinate - corrY = getYFromPolar(radiusCorr, phiCorr) - y; // difference between corrected and original y coordinate + corrX = getXFromPolar(radiusCorr, phiCorr) - x; // difference between corrected and original x coordinate + corrY = getYFromPolar(radiusCorr, phiCorr) - y; // difference between corrected and original y coordinate + } } template @@ -1488,20 +1525,73 @@ void SpaceCharge::getDistortionsCyl(const std::vector& z, const st template void SpaceCharge::getDistortions(const DataT x, const DataT y, const DataT z, const Side side, DataT& distX, DataT& distY, DataT& distZ) const { - // convert cartesian to polar - const DataT radius = getRadiusFromCartesian(x, y); - const DataT phi = getPhiFromCartesian(x, y); + if (mUseAnaDistCorr) { + getDistortionsAnalytical(x, y, z, side, distX, distY, distZ); + } else { + // convert cartesian to polar + const DataT radius = getRadiusFromCartesian(x, y); + const DataT phi = getPhiFromCartesian(x, y); - DataT distR{}; - DataT distRPhi{}; - getDistortionsCyl(z, radius, phi, side, distZ, distR, distRPhi); + DataT distR{}; + DataT distRPhi{}; + getDistortionsCyl(z, radius, phi, side, distZ, distR, distRPhi); - // Calculate distorted position - const DataT radiusDist = radius + distR; - const DataT phiDist = phi + distRPhi / radius; + // Calculate distorted position + const DataT radiusDist = radius + distR; + const DataT phiDist = phi + distRPhi / radius; - distX = getXFromPolar(radiusDist, phiDist) - x; // difference between distorted and original x coordinate - distY = getYFromPolar(radiusDist, phiDist) - y; // difference between distorted and original y coordinate + distX = getXFromPolar(radiusDist, phiDist) - x; // difference between distorted and original x coordinate + distY = getYFromPolar(radiusDist, phiDist) - y; // difference between distorted and original y coordinate + } +} + +template +void SpaceCharge::getDistortionsCorrectionsAnalytical(const DataT x, const DataT y, const DataT z, const Side side, DataT& distX, DataT& distY, DataT& distZ, const bool dist) const +{ + const GlobalPosition3D pos(x, y, z); + float phi = std::atan2(pos.Y(), pos.X()); + if (phi < 0.) { + phi += TWOPI; + } + const unsigned char secNum = std::floor(phi / SECPHIWIDTH); + const Sector sector(secNum + (pos.Z() < 0) * SECTORSPERSIDE); + const LocalPosition3D lPos = Mapper::GlobalToLocal(pos, sector); + + // convert dlx and dlY to r, rPhi + const DataT dlX = dist ? mAnaDistCorr.getDistortionsLX(lPos.X(), lPos.Y(), lPos.Z(), side) : mAnaDistCorr.getCorrectionsLX(lPos.X(), lPos.Y(), lPos.Z(), side); + const DataT dlY = dist ? mAnaDistCorr.getDistortionsLY(lPos.X(), lPos.Y(), lPos.Z(), side) : mAnaDistCorr.getCorrectionsLY(lPos.X(), lPos.Y(), lPos.Z(), side); + const DataT dlZ = dist ? mAnaDistCorr.getDistortionsLZ(lPos.X(), lPos.Y(), lPos.Z(), side) : mAnaDistCorr.getCorrectionsLZ(lPos.X(), lPos.Y(), lPos.Z(), side); + + // convert distortios in local coordinates to global coordinates + // distorted local position + const LocalPosition3D lPosDist(lPos.X() + dlX, lPos.Y() + dlY, lPos.Z() + dlZ); + + // calc global position + const auto globalPosDist = Mapper::LocalToGlobal(lPosDist, sector); + distX = globalPosDist.X() - x; + distY = globalPosDist.Y() - y; + distZ = globalPosDist.Z() - z; + + using Streamer = o2::utils::DebugStreamer; + if (Streamer::checkStream(o2::utils::StreamFlags::streamDistortionsSC)) { + auto& streamer = (const_cast*>(this))->mStreamer; + streamer.setStreamer("debug_distortions_analytical", "UPDATE"); + float dlXTmp = dlX; + float dlYTmp = dlY; + float dlZTmp = dlZ; + auto posTmp = pos; + auto lPosTmp = lPos; + streamer.getStreamer() << streamer.getUniqueTreeName("tree_ana").data() + << "pos=" << posTmp + << "lPos=" << lPosTmp + << "dlX=" << dlXTmp + << "dlY=" << dlYTmp + << "dlZ=" << dlZTmp + << "distX=" << distX + << "distY=" << distY + << "distZ=" << distZ + << "\n"; + } } template @@ -1879,6 +1969,32 @@ void SpaceCharge::normalizeHistoQVEps0(TH3& histoIonsPhiRZ) } } +template +int SpaceCharge::dumpAnalyticalCorrectionsDistortions(TFile& outf) const +{ + if (!mAnaDistCorr.isValid()) { + LOGP(info, "============== analytical functions are not set! returning ==============\n"); + return 0; + } + bool isOK = outf.WriteObject(&mAnaDistCorr, "analyticalDistCorr"); + return isOK; +} + +template +void SpaceCharge::setAnalyticalCorrectionsDistortionsFromFile(TFile& inpf) +{ + const bool containsFormulas = inpf.GetListOfKeys()->Contains("analyticalDistCorr"); + if (!containsFormulas) { + LOGP(info, "============== analytical functions are not stored! returning ==============\n"); + return; + } + LOGP(info, "Using analytical corrections and distortions"); + setUseAnalyticalDistCorr(true); + AnalyticalDistCorr* form = (AnalyticalDistCorr*)inpf.Get("analyticalDistCorr"); + mAnaDistCorr = *form; + delete form; +} + using DataTD = double; template class o2::tpc::SpaceCharge; diff --git a/Detectors/TPC/spacecharge/src/TPCSpacechargeLinkDef.h b/Detectors/TPC/spacecharge/src/TPCSpacechargeLinkDef.h index 316bc1dd86256..87e01393ae45c 100644 --- a/Detectors/TPC/spacecharge/src/TPCSpacechargeLinkDef.h +++ b/Detectors/TPC/spacecharge/src/TPCSpacechargeLinkDef.h @@ -43,4 +43,6 @@ #pragma link C++ class o2::tpc::NumericalFields < float> + ; #pragma link C++ class o2::tpc::DistCorrInterpolator < float> + ; #pragma link C++ class o2::tpc::GridProperties < float> + ; +#pragma link C++ class o2::tpc::AnalyticalDistCorr < double> + ; +#pragma link C++ class o2::tpc::AnalyticalDistCorr < float> + ; #endif diff --git a/GPU/TPCFastTransformation/TPCFastTransform.h b/GPU/TPCFastTransformation/TPCFastTransform.h index 84188d8bbee31..1075904f2bb71 100644 --- a/GPU/TPCFastTransformation/TPCFastTransform.h +++ b/GPU/TPCFastTransformation/TPCFastTransform.h @@ -21,6 +21,7 @@ #include "TPCFastTransformGeo.h" #include "TPCFastSpaceChargeCorrection.h" #include "GPUCommonMath.h" +#include "CommonUtils/DebugStreamer.h" #if !defined(GPUCA_GPUCODE) #include @@ -115,6 +116,9 @@ class TPCFastTransform : public FlatObject ~TPCFastTransform() CON_DEFAULT; #endif + /// write output of streamer to file + void flushStreamer() { mStreamer.flush(); } + /// _____________ FlatObject functionality, see FlatObject class for description ____________ /// Memory alignment @@ -331,9 +335,10 @@ class TPCFastTransform : public FlatObject /// Correction of (x,u,v) with tricubic interpolator on a regular grid TPCSlowSpaceChargeCorrection* mCorrectionSlow{nullptr}; ///< reference space charge corrections + o2::utils::DebugStreamer mStreamer; ///(this))->mStreamer; + streamer.setStreamer("debug_fasttransform", "UPDATE"); + + float ly, lz; + getGeometry().convUVtoLocal(slice, u, v, ly, lz); + + float gx, gy, gz; + getGeometry().convLocalToGlobal(slice, x, ly, lz, gx, gy, gz); + + streamer.getStreamer() << streamer.getUniqueTreeName("tree").data() + << "dx=" << dx + << "du=" << du + << "dv=" << dv + << "v=" << v + << "u=" << u + << "row=" << row + << "slice=" << slice + << "ly=" << ly + << "lz=" << lz + << "lx=" << x + << "gx=" << gx + << "gy=" << gy + << "gz=" << gz + << "\n"; + } + x += dx; u += du; v += dv; diff --git a/GPU/Workflow/src/GPUWorkflowSpec.cxx b/GPU/Workflow/src/GPUWorkflowSpec.cxx index 039dc98981fdf..974b297c1761a 100644 --- a/GPU/Workflow/src/GPUWorkflowSpec.cxx +++ b/GPU/Workflow/src/GPUWorkflowSpec.cxx @@ -626,6 +626,17 @@ void GPURecoWorkflowSpec::run(ProcessingContext& pc) int retVal = mTracker->RunTracking(&ptrs, &outputRegions); + // flushing debug output to file + using Streamer = o2::utils::DebugStreamer; + if (Streamer::checkStream(o2::utils::StreamFlags::streamFastTransform)) { + if (mFastTransform) { + mFastTransform->flushStreamer(); + } + if (mFastTransformNew) { + mFastTransformNew->flushStreamer(); + } + } + // setting TPC calibration objects storeUpdatedCalibsTPCPtrs(); diff --git a/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx b/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx index dfe504d367fcc..f220004165ae8 100644 --- a/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx +++ b/Steer/DigitizerWorkflow/src/TPCDigitizerSpec.cxx @@ -139,6 +139,7 @@ class TPCDPLDigitizerTask : public BaseDPLDigitizer } if (readSpaceCharge[0].size() != 0) { // use pre-calculated space-charge object if (std::filesystem::exists(readSpaceCharge[0])) { + LOGP(info, "Reading space-charge object from file {}", readSpaceCharge[0].data()); TFile fileSC(readSpaceCharge[0].data(), "READ"); mDigitizer.setUseSCDistortions(fileSC); } else { From c0558af909a4cbb8b8f96163e5686793398488eb Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Thu, 9 Feb 2023 14:15:12 +0100 Subject: [PATCH 2/4] Adding additional output to streamer --- GPU/TPCFastTransformation/TPCFastTransform.h | 24 ++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/GPU/TPCFastTransformation/TPCFastTransform.h b/GPU/TPCFastTransformation/TPCFastTransform.h index 1075904f2bb71..c6ebc8ea3c380 100644 --- a/GPU/TPCFastTransformation/TPCFastTransform.h +++ b/GPU/TPCFastTransformation/TPCFastTransform.h @@ -501,7 +501,21 @@ GPUdi() void TPCFastTransform::Transform(int slice, int row, float pad, float ti float gx, gy, gz; getGeometry().convLocalToGlobal(slice, x, ly, lz, gx, gy, gz); + float lyT, lzT; + float uCorr = u + du; + float vCorr = v + dv; + float lxT = x + dx; + getGeometry().convUVtoLocal(slice, uCorr, vCorr, lyT, lzT); + + float invYZtoX; + InverseTransformYZtoX(slice, row, ly, lz, invYZtoX); + + float YZtoNominalY; + float YZtoNominalZ; + InverseTransformYZtoNominalYZ(slice, row, ly, lz, YZtoNominalY, YZtoNominalZ); + streamer.getStreamer() << streamer.getUniqueTreeName("tree").data() + // corrections in x, u, v << "dx=" << dx << "du=" << du << "dv=" << dv @@ -509,12 +523,22 @@ GPUdi() void TPCFastTransform::Transform(int slice, int row, float pad, float ti << "u=" << u << "row=" << row << "slice=" << slice + // original local coordinates << "ly=" << ly << "lz=" << lz << "lx=" << x + // corrected local coordinated + << "lxT=" << lxT + << "lyT=" << lyT + << "lzT=" << lzT + // global uncorrected coordinates << "gx=" << gx << "gy=" << gy << "gz=" << gz + // some transformations which are applied + << "invYZtoX=" << invYZtoX + << "YZtoNominalY=" << YZtoNominalY + << "YZtoNominalZ=" << YZtoNominalZ << "\n"; } From 0d625ba7ca0f476dd243c3819d8286af88b109bc Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Thu, 9 Feb 2023 17:28:55 +0100 Subject: [PATCH 3/4] Adding additional streamer --- GPU/TPCFastTransformation/TPCFastTransform.h | 37 +++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/GPU/TPCFastTransformation/TPCFastTransform.h b/GPU/TPCFastTransformation/TPCFastTransform.h index c6ebc8ea3c380..c14809c2753c8 100644 --- a/GPU/TPCFastTransformation/TPCFastTransform.h +++ b/GPU/TPCFastTransformation/TPCFastTransform.h @@ -514,7 +514,7 @@ GPUdi() void TPCFastTransform::Transform(int slice, int row, float pad, float ti float YZtoNominalZ; InverseTransformYZtoNominalYZ(slice, row, ly, lz, YZtoNominalY, YZtoNominalZ); - streamer.getStreamer() << streamer.getUniqueTreeName("tree").data() + streamer.getStreamer() << streamer.getUniqueTreeName("tree_Transform").data() // corrections in x, u, v << "dx=" << dx << "du=" << du @@ -720,6 +720,22 @@ GPUdi() void TPCFastTransform::InverseTransformYZtoX(int slice, int row, float y ref->mCorrection.getCorrectionInvCorrectedX(slice, row, u, v, xr); x = (x - xr) * scale + xr; } + + using Streamer = o2::utils::DebugStreamer; + if (Streamer::checkStream(o2::utils::StreamFlags::streamFastTransform)) { + auto& streamer = (const_cast(this))->mStreamer; + streamer.setStreamer("debug_fasttransform", "UPDATE"); + streamer.getStreamer() << streamer.getUniqueTreeName("tree_InverseTransformYZtoX").data() + << "slice=" << slice + << "row=" << row + << "scale=" << scale + << "y=" << y + << "z=" << z + << "x=" << x + << "v=" << v + << "u=" << u + << "\n"; + } } GPUdi() void TPCFastTransform::InverseTransformYZtoNominalYZ(int slice, int row, float y, float z, float& ny, float& nz, const TPCFastTransform* ref, float scale) const @@ -735,6 +751,25 @@ GPUdi() void TPCFastTransform::InverseTransformYZtoNominalYZ(int slice, int row, vn = (vn - vnr) * scale + vnr; } getGeometry().convUVtoLocal(slice, un, vn, ny, nz); + + using Streamer = o2::utils::DebugStreamer; + if (Streamer::checkStream(o2::utils::StreamFlags::streamFastTransform)) { + auto& streamer = (const_cast(this))->mStreamer; + streamer.setStreamer("debug_fasttransform", "UPDATE"); + streamer.getStreamer() << streamer.getUniqueTreeName("tree_InverseTransformYZtoNominalYZ").data() + << "slice=" << slice + << "row=" << row + << "scale=" << scale + << "y=" << y + << "z=" << z + << "ny=" << ny + << "nz=" << nz + << "u=" << u + << "v=" << v + << "un=" << un + << "vn=" << vn + << "\n"; + } } } // namespace gpu From 59e017ca250ed30e3dd3022f6880febf20328d52 Mon Sep 17 00:00:00 2001 From: Matthias Kleiner Date: Fri, 10 Feb 2023 13:40:53 +0100 Subject: [PATCH 4/4] Fixing compiling on GPU --- GPU/TPCFastTransformation/TPCFastTransform.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/TPCFastTransformation/TPCFastTransform.h b/GPU/TPCFastTransformation/TPCFastTransform.h index c14809c2753c8..5d302a0760cbd 100644 --- a/GPU/TPCFastTransformation/TPCFastTransform.h +++ b/GPU/TPCFastTransformation/TPCFastTransform.h @@ -117,7 +117,7 @@ class TPCFastTransform : public FlatObject #endif /// write output of streamer to file - void flushStreamer() { mStreamer.flush(); } + GPUd() void flushStreamer() { mStreamer.flush(); } /// _____________ FlatObject functionality, see FlatObject class for description ____________