Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2026-10-15 08:26:12

0001 #include "TpcConditionsReco.h"
0002 #include "TpcConditions.h"
0003 
0004 #include <ffamodules/CDBInterface.h>
0005 
0006 #include <cdbobjects/CDBTTree.h>
0007 
0008 #include <ffarawobjects/Gl1Packet.h>
0009 
0010 #include <fun4all/Fun4AllReturnCodes.h>
0011 
0012 #include <phool/PHCompositeNode.h>
0013 #include <phool/PHDataNode.h>
0014 #include <phool/PHNodeIterator.h>
0015 #include <phool/getClass.h>
0016 
0017 #include <phool/recoConsts.h>
0018 
0019 #include <algorithm>
0020 #include <cstddef>
0021 #include <cstdint>
0022 #include <iostream>
0023 #include <iterator>
0024 #include <string>
0025 #include <vector>
0026 
0027 //  This namespace organizes Charles' "Undamaged GEM List"
0028 //  into vectors for simpler consumption later.
0029 namespace
0030 {
0031   const std::vector<std::string> SR1 = {
0032       "S_01_R1_G4_IMon",
0033       "S_04_R1_G4_IMon",
0034       "S_05_R1_G4_IMon",
0035       "S_10_R1_G4_IMon"};
0036 
0037   const std::vector<std::string> SR2 = {
0038       "S_01_R2_G4_IMon",
0039       "S_02_R2_G4_IMon",
0040       "S_07_R2_G4_IMon",
0041       "S_09_R2_G4_IMon",
0042       "S_10_R2_G4_IMon",
0043       "S_12_R2_G4_IMon"};
0044 
0045   const std::vector<std::string> SR3 = {
0046       "S_08_R3_G4_IMon",
0047       "S_09_R3_G4_IMon",
0048       "S_10_R3_G4_IMon",
0049   };
0050 
0051   const std::vector<std::string> NR1 = {
0052       "N_03_R1_G4_IMon",
0053       "N_04_R1_G4_IMon",
0054       "N_06_R1_G4_IMon",
0055       "N_07_R1_G4_IMon",
0056       "N_08_R1_G4_IMon",
0057       "N_10_R1_G4_IMon",
0058       "N_11_R1_G4_IMon",
0059       "N_12_R1_G4_IMon"};
0060 
0061   const std::vector<std::string> NR2 = {
0062       "N_02_R2_G4_IMon",
0063       "N_04_R2_G4_IMon",
0064       "N_05_R2_G4_IMon",
0065       "N_09_R2_G4_IMon",
0066       "N_10_R2_G4_IMon",
0067       "N_11_R2_G4_IMon",
0068       "N_12_R2_G4_IMon"};
0069 
0070   const std::vector<std::string> NR3 = {
0071       "N_02_R3_G4_IMon",
0072       "N_10_R3_G4_IMon"};
0073 
0074   const std::vector<std::string> SOUTH = []()
0075   {
0076     std::vector<std::string> v;
0077     v.insert(v.end(), SR1.begin(), SR1.end());
0078     v.insert(v.end(), SR2.begin(), SR2.end());
0079     v.insert(v.end(), SR3.begin(), SR3.end());
0080     return v;
0081   }();
0082 
0083   const std::vector<std::string> NORTH = []()
0084   {
0085     std::vector<std::string> v;
0086     v.insert(v.end(), NR1.begin(), NR1.end());
0087     v.insert(v.end(), NR2.begin(), NR2.end());
0088     v.insert(v.end(), NR3.begin(), NR3.end());
0089     return v;
0090   }();
0091 
0092   const std::vector<std::string> ALL = []()
0093   {
0094     std::vector<std::string> v;
0095     v.insert(v.end(), SOUTH.begin(), SOUTH.end());
0096     v.insert(v.end(), NORTH.begin(), NORTH.end());
0097     return v;
0098   }();
0099 }  // namespace
0100 
0101 TpcConditionsReco::TpcConditionsReco(const std::string &name)
0102   : SubsysReco(name)
0103 {
0104 }
0105 
0106 TpcConditionsReco::~TpcConditionsReco()
0107 {
0108   delete m_tree;
0109 }
0110 
0111 float TpcConditionsReco::get_AverageMedianCurrent(
0112     const std::vector<std::string> &channels)
0113 {
0114   if (m_bco_to_channel.empty())
0115   {
0116     return 0.0F;
0117   }
0118 
0119   double sum = 0.0;
0120 
0121   for (const auto &entry : m_bco_to_channel)
0122   {
0123     sum += get_MedianCurrent(entry.second, channels);
0124   }
0125 
0126   return static_cast<float>(sum / static_cast<double>(m_bco_to_channel.size()));
0127 }
0128 
0129 float TpcConditionsReco::get_InterpolatedMedianCurrent(const uint64_t bco, const std::vector<std::string> &channels)
0130 {
0131   if (m_bco_to_channel.empty())
0132   {
0133     return 0.0F;
0134   }
0135 
0136   if (m_bco_to_channel.size() == 1)
0137   {
0138     return get_MedianCurrent(m_bco_to_channel.begin()->second, channels);
0139   }
0140 
0141   const auto first = m_bco_to_channel.begin();
0142   const auto last = std::prev(m_bco_to_channel.end());
0143 
0144   if (bco <= first->first)
0145   {
0146     return get_MedianCurrent(first->second, channels);
0147   }
0148 
0149   if (bco >= last->first)
0150   {
0151     return get_MedianCurrent(last->second, channels);
0152   }
0153 
0154   const auto right = m_bco_to_channel.upper_bound(bco);
0155   const auto left = std::prev(right);
0156 
0157   const double x1 = static_cast<double>(left->first);
0158   const double x2 = static_cast<double>(right->first);
0159   const double y1 = get_MedianCurrent(left->second, channels);
0160   const double y2 = get_MedianCurrent(right->second, channels);
0161 
0162   const double h1 = x2 - x1;
0163   const double d1 = (y2 - y1) / h1;
0164 
0165   double m1 = d1;
0166   double m2 = d1;
0167 
0168   if (left != m_bco_to_channel.begin())
0169   {
0170     const auto left2 = std::prev(left);
0171     const double x0 = static_cast<double>(left2->first);
0172     const double y0 = get_MedianCurrent(left2->second, channels);
0173     const double h0 = x1 - x0;
0174     const double d0 = (y1 - y0) / h0;
0175 
0176     if (d0 * d1 > 0.0)
0177     {
0178       const double w1 = 2.0 * h1 + h0;
0179       const double w2 = h1 + 2.0 * h0;
0180       m1 = (w1 + w2) / (w1 / d0 + w2 / d1);
0181     }
0182     else
0183     {
0184       m1 = 0.0;
0185     }
0186   }
0187 
0188   const auto right2 = std::next(right);
0189   if (right2 != m_bco_to_channel.end())
0190   {
0191     const double x3 = static_cast<double>(right2->first);
0192     const double y3 = get_MedianCurrent(right2->second, channels);
0193     const double h2 = x3 - x2;
0194     const double d2 = (y3 - y2) / h2;
0195 
0196     if (d1 * d2 > 0.0)
0197     {
0198       const double w1 = 2.0 * h2 + h1;
0199       const double w2 = h2 + 2.0 * h1;
0200       m2 = (w1 + w2) / (w1 / d1 + w2 / d2);
0201     }
0202     else
0203     {
0204       m2 = 0.0;
0205     }
0206   }
0207 
0208   const double t = (static_cast<double>(bco) - x1) / h1;
0209   const double t2 = t * t;
0210   const double t3 = t2 * t;
0211 
0212   return static_cast<float>(
0213       (2.0 * t3 - 3.0 * t2 + 1.0) * y1 +
0214       (t3 - 2.0 * t2 + t) * h1 * m1 +
0215       (-2.0 * t3 + 3.0 * t2) * y2 +
0216       (t3 - t2) * h1 * m2);
0217 }
0218 
0219 void TpcConditionsReco::fillConditions(int channel)
0220 {
0221   m_conditions->set_Temperature(m_tree->GetFloatValue(channel, "gas_temperature"));
0222   m_conditions->set_Pressure(m_tree->GetFloatValue(channel, "gas_pressure"));
0223   m_conditions->set_FieldOK(m_tree->GetFloatValue(channel, "FieldOK") != 0.0);
0224   m_conditions->set_GainOK(m_tree->GetFloatValue(channel, "GainOK") != 0.0);
0225 
0226   m_conditions->set_LoadCurrent(get_MedianCurrent(channel, ALL));
0227   m_conditions->set_LoadNorth(get_MedianCurrent(channel, NORTH));
0228   m_conditions->set_LoadSouth(get_MedianCurrent(channel, SOUTH));
0229   m_conditions->set_LoadSR1(get_MedianCurrent(channel, SR1));
0230   m_conditions->set_LoadSR2(get_MedianCurrent(channel, SR2));
0231   m_conditions->set_LoadSR3(get_MedianCurrent(channel, SR3));
0232   m_conditions->set_LoadNR1(get_MedianCurrent(channel, NR1));
0233   m_conditions->set_LoadNR2(get_MedianCurrent(channel, NR2));
0234   m_conditions->set_LoadNR3(get_MedianCurrent(channel, NR3));
0235 }
0236 
0237 int TpcConditionsReco::InitRun(PHCompositeNode *topNode)
0238 {
0239   std::cout << "TpcConditionsReco::InitRun(PHCompositeNode *topNode) Initializing"
0240             << std::endl;
0241 
0242   PHNodeIterator iter(topNode);
0243   PHCompositeNode *parNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "PAR"));
0244 
0245   if (!parNode)
0246   {
0247     parNode = new PHCompositeNode("PAR");
0248     topNode->addNode(parNode);
0249   }
0250 
0251   m_conditions = findNode::getClass<TpcConditions>(topNode, "TpcConditions");
0252   if (!m_conditions)
0253   {
0254     m_conditions = new TpcConditions();
0255     auto *conditionsNode = new PHDataNode<TpcConditions>(m_conditions, "TpcConditions", "Data");
0256     parNode->addNode(conditionsNode);
0257   }
0258 
0259   m_conditions->set_ConditionsAvailable(false);
0260 
0261   delete m_tree;
0262   m_tree = nullptr;
0263   m_bco_to_channel.clear();
0264 
0265   Gl1Packet *gl1 = findNode::getClass<Gl1Packet>(topNode, "GL1RAWHIT");
0266   if (!gl1)
0267   {
0268     gl1 = findNode::getClass<Gl1Packet>(topNode, "GL1Packet");
0269   }
0270 
0271   if (!gl1)
0272   {
0273     std::cout << "TpcConditionsReco::InitRun - could not find GL1 packet"
0274               << std::endl;
0275     m_conditions->set_ConditionsAvailable(false);
0276     return Fun4AllReturnCodes::EVENT_OK;
0277   }
0278 
0279   const int64_t rawBco = gl1->lValue(0, "BCO");
0280 
0281   if (rawBco <= 0)
0282   {
0283     std::cout << "TpcConditionsReco::InitRun - invalid GL1 BCO "
0284               << rawBco << std::endl;
0285     m_conditions->set_ConditionsAvailable(false);
0286     return Fun4AllReturnCodes::EVENT_OK;
0287   }
0288 
0289   const uint64_t targetBco = static_cast<uint64_t>(rawBco);
0290 
0291   std::cout << " targetBCO = " << targetBco << std::endl;
0292 
0293   // Get the TPC conditions payload from CDB
0294   std::string calibdir = CDBInterface::instance()->getUrl("TPC_CONDITIONS");
0295 
0296   if (calibdir.empty())
0297   {
0298     std::cout << "TpcConditionsReco::InitRun - WARNING: "
0299               << "TPC_CONDITIONS not available for this run; "
0300               << "continuing without TPC conditions"
0301               << std::endl;
0302     return Fun4AllReturnCodes::EVENT_OK;
0303   }
0304 
0305   m_tree = new CDBTTree(calibdir);
0306   m_tree->LoadCalibrations();
0307 
0308   // Build the BCO -> CDBTTree channel lookup
0309   m_bco_to_channel.clear();
0310   for (unsigned int channel = 0;
0311        channel < m_tree->GetUInt64EntryMap().size();
0312        ++channel)
0313   {
0314     uint64_t bco = m_tree->GetUInt64Value(channel, "bco");
0315     m_bco_to_channel[bco] = channel;
0316   }
0317 
0318   if (m_bco_to_channel.empty())
0319   {
0320     std::cout << "TpcConditionsReco::InitRun - WARNING: "
0321               << "TPC_CONDITIONS contains no BCO entries; "
0322               << "continuing without TPC conditions"
0323               << std::endl;
0324     return Fun4AllReturnCodes::EVENT_OK;
0325   }
0326 
0327   m_conditions->set_AverageLoadCurrent(get_AverageMedianCurrent(ALL));
0328   m_conditions->set_AverageLoadNorth(get_AverageMedianCurrent(NORTH));
0329   m_conditions->set_AverageLoadSouth(get_AverageMedianCurrent(SOUTH));
0330 
0331   m_conditions->set_AverageLoadSR1(get_AverageMedianCurrent(SR1));
0332   m_conditions->set_AverageLoadSR2(get_AverageMedianCurrent(SR2));
0333   m_conditions->set_AverageLoadSR3(get_AverageMedianCurrent(SR3));
0334 
0335   m_conditions->set_AverageLoadNR1(get_AverageMedianCurrent(NR1));
0336   m_conditions->set_AverageLoadNR2(get_AverageMedianCurrent(NR2));
0337   m_conditions->set_AverageLoadNR3(get_AverageMedianCurrent(NR3));
0338 
0339   if (!m_bco_to_channel.empty())
0340   {
0341     recoConsts *rc = recoConsts::instance();
0342     const int segment = rc->get_IntFlag("RUNSEGMENT");
0343 
0344     // Find closest stored conditions BCO.
0345     auto upper = m_bco_to_channel.upper_bound(targetBco);
0346     auto selected = upper;
0347 
0348     if (upper == m_bco_to_channel.end())
0349     {
0350       selected = std::prev(m_bco_to_channel.end());
0351     }
0352     else if (upper != m_bco_to_channel.begin())
0353     {
0354       auto lower = std::prev(upper);
0355 
0356       if ((targetBco - lower->first) <= (upper->first - targetBco))
0357       {
0358         selected = lower;
0359       }
0360     }
0361 
0362     const auto first = m_bco_to_channel.begin();
0363     const auto last = std::prev(m_bco_to_channel.end());
0364     const auto middle = std::next(
0365         m_bco_to_channel.begin(),
0366         static_cast<long>(m_bco_to_channel.size() / 2));
0367 
0368     std::cout << "R1 conditions:"
0369               << "\n  FIRST  BCO=" << first->first
0370               << " NR1=" << get_MedianCurrent(first->second, NR1)
0371               << " SR1=" << get_MedianCurrent(first->second, SR1)
0372               << "\n  MIDDLE BCO=" << middle->first
0373               << " NR1=" << get_MedianCurrent(middle->second, NR1)
0374               << " SR1=" << get_MedianCurrent(middle->second, SR1)
0375               << "\n  LAST   BCO=" << last->first
0376               << " NR1=" << get_MedianCurrent(last->second, NR1)
0377               << " SR1=" << get_MedianCurrent(last->second, SR1)
0378               << "\n  AVERAGE NR1=" << m_conditions->get_AverageLoadNR1()
0379               << " SR1=" << m_conditions->get_AverageLoadSR1()
0380               << std::endl;
0381 
0382     fillConditions(selected->second);
0383 
0384     // GEM load currents are evaluated smoothly at the actual segment BCO.
0385     m_conditions->set_LoadCurrent(get_InterpolatedMedianCurrent(targetBco, ALL));
0386     m_conditions->set_LoadNorth(get_InterpolatedMedianCurrent(targetBco, NORTH));
0387     m_conditions->set_LoadSouth(get_InterpolatedMedianCurrent(targetBco, SOUTH));
0388 
0389     m_conditions->set_LoadSR1(get_InterpolatedMedianCurrent(targetBco, SR1));
0390     m_conditions->set_LoadSR2(get_InterpolatedMedianCurrent(targetBco, SR2));
0391     m_conditions->set_LoadSR3(get_InterpolatedMedianCurrent(targetBco, SR3));
0392 
0393     m_conditions->set_LoadNR1(get_InterpolatedMedianCurrent(targetBco, NR1));
0394     m_conditions->set_LoadNR2(get_InterpolatedMedianCurrent(targetBco, NR2));
0395     m_conditions->set_LoadNR3(get_InterpolatedMedianCurrent(targetBco, NR3));
0396 
0397     std::cout << "TpcConditionsReco::InitRun - segment " << segment
0398               << ", target BCO " << targetBco
0399               << ", nearest conditions BCO " << selected->first
0400               << ", interpolated LoadNR1 " << m_conditions->get_LoadNR1()
0401               << ", interpolated LoadSR1 " << m_conditions->get_LoadSR1()
0402               << std::endl;
0403   }
0404 
0405   m_conditions->set_ConditionsAvailable(true);
0406   return Fun4AllReturnCodes::EVENT_OK;
0407 }
0408 
0409 int TpcConditionsReco::process_event(PHCompositeNode *topNode)
0410 {
0411   if (!m_tree || m_bco_to_channel.empty())
0412   {
0413     return Fun4AllReturnCodes::EVENT_OK;
0414   }
0415 
0416   // Get the current event BCO
0417   Gl1Packet *gl1 = findNode::getClass<Gl1Packet>(topNode, "GL1RAWHIT");
0418   if (!gl1)
0419   {
0420     std::cout << "TpcConditionsReco::process_event - "
0421               << "could not find GL1RAWHIT node"
0422               << std::endl;
0423     m_conditions->set_ConditionsAvailable(false);
0424     return Fun4AllReturnCodes::EVENT_OK;
0425   }
0426 
0427   uint64_t bco = gl1->getBCO();
0428 
0429   auto iter = m_bco_to_channel.upper_bound(bco);
0430 
0431   if (iter == m_bco_to_channel.begin())
0432   {
0433     iter = m_bco_to_channel.begin();
0434   }
0435   else
0436   {
0437     --iter;
0438   }
0439 
0440   int channel = iter->second;
0441 
0442   m_conditions->set_Temperature(m_tree->GetFloatValue(channel, "gas_temperature"));
0443   m_conditions->set_Pressure(m_tree->GetFloatValue(channel, "gas_pressure"));
0444   m_conditions->set_FieldOK(m_tree->GetFloatValue(channel, "FieldOK") != 0.0);
0445   m_conditions->set_GainOK(m_tree->GetFloatValue(channel, "GainOK") != 0.0);
0446 
0447   m_conditions->set_LoadCurrent(get_InterpolatedMedianCurrent(bco, ALL));
0448   m_conditions->set_LoadNorth(get_InterpolatedMedianCurrent(bco, NORTH));
0449   m_conditions->set_LoadSouth(get_InterpolatedMedianCurrent(bco, SOUTH));
0450 
0451   m_conditions->set_LoadSR1(get_InterpolatedMedianCurrent(bco, SR1));
0452   m_conditions->set_LoadSR2(get_InterpolatedMedianCurrent(bco, SR2));
0453   m_conditions->set_LoadSR3(get_InterpolatedMedianCurrent(bco, SR3));
0454 
0455   m_conditions->set_LoadNR1(get_InterpolatedMedianCurrent(bco, NR1));
0456   m_conditions->set_LoadNR2(get_InterpolatedMedianCurrent(bco, NR2));
0457   m_conditions->set_LoadNR3(get_InterpolatedMedianCurrent(bco, NR3));
0458 
0459   m_conditions->set_ConditionsAvailable(true);
0460 
0461   // Do or die
0462   if (m_conditions->get_ConditionsAvailable() &&
0463       (!m_conditions->get_FieldOK() ||
0464        !m_conditions->get_GainOK()))
0465   {
0466     return Fun4AllReturnCodes::ABORTEVENT;
0467   }
0468 
0469   return Fun4AllReturnCodes::EVENT_OK;
0470 }
0471 
0472 float TpcConditionsReco::get_MedianCurrent(
0473     int channel,
0474     const std::vector<std::string> &channels)
0475 {
0476   std::vector<float> currents;
0477   currents.reserve(channels.size());
0478 
0479   for (const auto &name : channels)
0480   {
0481     currents.push_back(m_tree->GetFloatValue(channel, name));
0482   }
0483 
0484   std::sort(currents.begin(), currents.end());
0485 
0486   const size_t n = currents.size();
0487 
0488   if (n % 2)
0489   {
0490     return currents[n / 2];
0491   }
0492 
0493   return 0.5F * (currents[n / 2 - 1] + currents[n / 2]);
0494 }