CMS 3D CMS Logo

SiStripLorentzAnglePCLHarvester.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: CalibTracker/SiStripLorentzAnglePCLHarvester
4 // Class: SiStripLorentzAnglePCLHarvester
5 //
9 //
10 // Original Author: mmusich
11 // Created: Sat, 29 May 2021 14:46:19 GMT
12 //
13 //
14 
15 // system includes
16 #include <fmt/format.h>
17 #include <fmt/printf.h>
18 #include <fstream>
19 #include <iostream>
20 #include <numeric>
21 #include <sstream>
22 #include <string>
23 #include <vector>
24 
25 // user includes
46 
47 //------------------------------------------------------------------------------
49 public:
51  ~SiStripLorentzAnglePCLHarvester() override = default;
52  void beginRun(const edm::Run&, const edm::EventSetup&) override;
53 
55 
56 private:
58  void endRun(const edm::Run&, const edm::EventSetup&) override;
59  std::string getStem(const std::string& histoName, bool isFolder);
60 
61  // es tokens
65 
69 
70  // member data
71 
74 
75  const bool debug_;
77 
79  const std::vector<double> fitRange_;
81  float theMagField_{0.f};
82 
83  static constexpr float teslaToInverseGeV_ = 2.99792458e-3f;
84  std::pair<double, double> theFitRange_{0., 0.};
85 
87  std::unique_ptr<TrackerTopology> theTrackerTopology_;
88  std::unique_ptr<TkDetMap> tkDetMap_;
89 
90  // ancillary struct to store the input / output LA
91  struct LATkMap {
92  LATkMap() : hInputLA(nullptr), hOutputLA(nullptr) {}
93  LATkMap(std::unique_ptr<TkHistoMap>&& input, std::unique_ptr<TkHistoMap>&& output)
95 
96  void fill(uint32_t id, float inputLA, float outputLA) {
97  hInputLA->fill(id, inputLA);
98  hOutputLA->fill(id, outputLA);
99  }
100 
101  void beautify() {
102  const auto& allInputMaps = hInputLA->getAllMaps();
103  // set colz
104  for (size_t i = 1; i < allInputMaps.size(); i++) {
105  hInputLA->getMap(i)->setOption("colz");
106  hOutputLA->getMap(i)->setOption("colz");
107  }
108  }
109 
110  std::unique_ptr<TkHistoMap> hInputLA, hOutputLA;
111  };
112 
114 };
115 
116 //------------------------------------------------------------------------------
118  : geomEsToken_(esConsumes<edm::Transition::BeginRun>()),
119  topoEsTokenBR_(esConsumes<edm::Transition::BeginRun>()),
120  topoEsTokenER_(esConsumes<edm::Transition::EndRun>()),
121  tkDetMapTokenER_(esConsumes<edm::Transition::EndRun>()),
122  latencyToken_(esConsumes<edm::Transition::BeginRun>()),
123  siStripLAEsToken_(esConsumes<edm::Transition::BeginRun>()),
124  magneticFieldToken_(esConsumes<edm::Transition::BeginRun>()),
125  mismatchedBField_{false},
126  mismatchedLatency_{false},
127  debug_(iConfig.getParameter<bool>("debugMode")),
128  dqmDir_(iConfig.getParameter<std::string>("dqmDir")),
129  fitRange_(iConfig.getParameter<std::vector<double>>("fitRange")),
130  recordName_(iConfig.getParameter<std::string>("record")) {
131  // initialize the fit range
132  if (fitRange_.size() == 2) {
133  theFitRange_.first = fitRange_[0];
134  theFitRange_.second = fitRange_[1];
135  } else {
136  throw cms::Exception("SiStripLorentzAnglePCLHarvester") << "Too many fit range parameters specified";
137  }
138 
139  // first ensure DB output service is available
141  if (!poolDbService.isAvailable())
142  throw cms::Exception("SiStripLorentzAnglePCLHarvester") << "PoolDBService required";
143 }
144 
145 //------------------------------------------------------------------------------
147  // geometry
148  const TrackerGeometry* geom = &iSetup.getData(geomEsToken_);
149  const TrackerTopology* tTopo = &iSetup.getData(topoEsTokenBR_);
150 
151  const MagneticField* magField = &iSetup.getData(magneticFieldToken_);
153 
154  // B-field value
155  // inverseBzAtOriginInGeV() returns the inverse of field z component for this map in GeV
156  // for the conversion please consult https://github.com/cms-sw/cmssw/blob/master/MagneticField/Engine/src/MagneticField.cc#L17
157  // theInverseBzAtOriginInGeV = 1.f / (at0z * 2.99792458e-3f);
158  // ==> at0z = 1.f / (theInverseBzAtOriginInGeV * 2.99792458e-3f)
159 
161 
162  if (iHists_.bfield_.empty()) {
164  } else {
166  mismatchedBField_ = true;
167  }
168  }
169 
170  const SiStripLatency* apvlat = &iSetup.getData(latencyToken_);
171  if (iHists_.apvmode_.empty()) {
173  } else {
175  mismatchedLatency_ = true;
176  }
177  }
178 
179  auto dets = geom->detsTIB();
180  dets.insert(dets.end(), geom->detsTID().begin(), geom->detsTID().end());
181  dets.insert(dets.end(), geom->detsTOB().begin(), geom->detsTOB().end());
182  dets.insert(dets.end(), geom->detsTEC().begin(), geom->detsTEC().end());
183 
184  for (auto det : dets) {
185  auto detid = det->geographicalId().rawId();
186  const StripGeomDetUnit* stripDet = dynamic_cast<const StripGeomDetUnit*>(geom->idToDet(det->geographicalId()));
187  if (stripDet) {
190  }
191  }
192 }
193 
194 //------------------------------------------------------------------------------
196  if (!theTrackerTopology_) {
197  theTrackerTopology_ = std::make_unique<TrackerTopology>(isetup.getData(topoEsTokenER_));
198  }
199  if (!tkDetMap_) {
200  tkDetMap_ = std::make_unique<TkDetMap>(isetup.getData(tkDetMapTokenER_));
201  }
202 }
203 
204 //------------------------------------------------------------------------------
206  if (mismatchedBField_) {
207  throw cms::Exception("SiStripLorentzAnglePCLHarvester") << "Trying to harvest runs with different B-field values!";
208  }
209 
210  if (mismatchedLatency_) {
211  throw cms::Exception("SiStripLorentzAnglePCLHarvester") << "Trying to harvest runs with diffent APV modes!";
212  }
213 
214  // go in the right directory
215  iGetter.cd();
216  std::string bvalue = (iHists_.bfield_ == "3.8") ? "B-ON" : "B-OFF";
217  std::string folderToHarvest = fmt::format("{}/{}_{}", dqmDir_, bvalue, iHists_.apvmode_);
218  edm::LogPrint(moduleDescription().moduleName()) << "Harvesting in " << folderToHarvest;
219  iGetter.setCurrentFolder(folderToHarvest);
220 
221  // fill in the module types
222  iHists_.nlayers_["TIB"] = 4;
223  iHists_.nlayers_["TOB"] = 6;
224  iHists_.modtypes_.push_back("s");
225  iHists_.modtypes_.push_back("a");
226 
227  std::vector<std::string> MEtoHarvest = {"tanthcosphtrk_nstrip",
228  "thetatrk_nstrip",
229  "tanthcosphtrk_var2",
230  "tanthcosphtrk_var3",
231  "thcosphtrk_var2",
232  "thcosphtrk_var3"};
233 
234  // prepare the histograms to be harvested
235  for (auto& layers : iHists_.nlayers_) {
236  std::string subdet = layers.first;
237  for (int l = 1; l <= layers.second; ++l) {
238  for (auto& t : iHists_.modtypes_) {
239  // do not fill stereo where there aren't
240  if (l > 2 && t == "s")
241  continue;
242  std::string locationtype = Form("%s_L%d%s", subdet.c_str(), l, t.c_str());
243  for (const auto& toHarvest : MEtoHarvest) {
244  const char* address = Form(
245  "%s/%s/L%d/%s_%s", folderToHarvest.c_str(), subdet.c_str(), l, locationtype.c_str(), toHarvest.c_str());
246 
247  LogDebug(moduleDescription().moduleName()) << "harvesting at: " << address << std::endl;
248 
249  iHists_.h2_[Form("%s_%s", locationtype.c_str(), toHarvest.c_str())] = iGetter.get(address);
250  if (iHists_.h2_[Form("%s_%s", locationtype.c_str(), toHarvest.c_str())] == nullptr) {
252  << "could not retrieve: " << Form("%s_%s", locationtype.c_str(), toHarvest.c_str());
253  }
254  }
255  }
256  }
257  }
258 
259  // book the summary output histograms
260  iBooker.setCurrentFolder(fmt::format("{}Harvesting/LorentzAngleMaps", dqmDir_));
261 
262  // Define a lambda function to extract the second element and add it to the accumulator
263  auto sumValues = [](int accumulator, const std::pair<std::string, int>& element) {
264  return accumulator + element.second;
265  };
266 
267  // Use std::accumulate to sum the values
268  int totalLayers = std::accumulate(iHists_.nlayers_.begin(), iHists_.nlayers_.end(), 0, sumValues);
269 
270  // Lambda expression to set bin labels for a TH2F histogram
271  auto setHistoLabels = [](TH2F* histogram, const std::map<std::string, int>& nlayers) {
272  // Set common options
273  histogram->SetOption("colz1"); // don't fill empty bins
274  histogram->SetStats(false);
275  histogram->GetYaxis()->SetLabelSize(0.05);
276  histogram->GetXaxis()->SetLabelSize(0.05);
277 
278  // Set bin labels for the X-axis
279  histogram->GetXaxis()->SetBinLabel(1, "r-#phi");
280  histogram->GetXaxis()->SetBinLabel(2, "stereo");
281 
282  // Set bin labels for the Y-axis
283  int binCounter = 1;
284  for (const auto& subdet : {"TIB", "TOB"}) {
285  for (int layer = 1; layer <= nlayers.at(subdet); ++layer) {
286  std::string label = Form("%s L%d", subdet, layer);
287  histogram->GetYaxis()->SetBinLabel(binCounter++, label.c_str());
288  }
289  }
290  histogram->GetXaxis()->LabelsOption("h");
291  };
292 
293  std::string d_name = "h2_byLayerSiStripLA";
294  std::string d_text = "SiStrip tan#theta_{LA}/B;module type (r-#phi/stereo);layer number;tan#theta_{LA}/B [1/T]";
296  iBooker.book2D(d_name.c_str(), d_text.c_str(), 2, -0.5, 1.5, totalLayers, -0.5, totalLayers - 0.5);
297 
298  setHistoLabels(iHists_.h2_byLayerLA_->getTH2F(), iHists_.nlayers_);
299 
300  d_name = "h2_byLayerSiStripLADiff";
301  d_text = "SiStrip #Delta#mu_{H}/#mu_{H};module type (r-#phi/stereo);ladder number;#Delta#mu_{H}/#mu_{H} [%%]";
303  iBooker.book2D(d_name.c_str(), d_text.c_str(), 2, -0.5, 1.5, totalLayers, -0.5, totalLayers - 0.5);
304 
305  setHistoLabels(iHists_.h2_byLayerDiff_->getTH2F(), iHists_.nlayers_);
306 
307  // prepare the profiles
308  for (const auto& ME : iHists_.h2_) {
309  if (!ME.second)
310  continue;
311  // draw colored 2D plots
312  ME.second->setOption("colz");
313  TProfile* hp = (TProfile*)ME.second->getTH2F()->ProfileX();
314  iBooker.setCurrentFolder(folderToHarvest + "/" + getStem(ME.first, /* isFolder = */ true));
315  iHists_.p_[hp->GetName()] = iBooker.bookProfile(hp->GetName(), hp);
316  iHists_.p_[hp->GetName()]->setAxisTitle(ME.second->getAxisTitle(2), 2);
317  delete hp;
318  }
319 
320  if (iHists_.p_.empty()) {
321  edm::LogError(moduleDescription().moduleName()) << "None of the input histograms could be retrieved. Aborting";
322  return;
323  }
324 
325  std::map<std::string, std::pair<double, double>> LAMap_;
326 
327  // do the fits
328  for (const auto& prof : iHists_.p_) {
329  //fit only this type of profile
330  if ((prof.first).find("thetatrk_nstrip") != std::string::npos) {
331  // Create the TF1 function
332 
333  // fitting range (take full axis by default)
334  double low = prof.second->getAxisMin(1);
335  double high = prof.second->getAxisMax(1);
336  if (theFitRange_.first > theFitRange_.second) {
337  low = theFitRange_.first;
338  high = theFitRange_.second;
339  }
340 
341  TF1* fitFunc = new TF1("fitFunc", siStripLACalibration::fitFunction, low, high, 3);
342 
343  // Fit the function to the data
344  prof.second->getTProfile()->Fit(fitFunc, "F"); // "F" option performs a least-squares fit
345 
346  // Get the fit results
347  Double_t a_fit = fitFunc->GetParameter(0);
348  Double_t thetaL_fit = fitFunc->GetParameter(1);
349  Double_t b_fit = fitFunc->GetParameter(2);
350 
351  Double_t a_fitError = fitFunc->GetParError(0);
352  Double_t thetaL_fitError = fitFunc->GetParError(1);
353  Double_t b_fitError = fitFunc->GetParError(2);
354 
355  if (debug_) {
357  << prof.first << " fit result: "
358  << " a=" << a_fit << " +/ " << a_fitError << " theta_L=" << thetaL_fit << " +/- " << thetaL_fitError
359  << " b=" << b_fit << " +/- " << b_fitError;
360  }
361 
362  LAMap_[getStem(prof.first, /* isFolder = */ false)] = std::make_pair(thetaL_fit, thetaL_fitError);
363  }
364  }
365 
366  if (debug_) {
367  for (const auto& element : LAMap_) {
369  << element.first << " thetaLA = " << element.second.first << "+/-" << element.second.second;
370  }
371  }
372 
373  // now prepare the output LA
374  std::shared_ptr<SiStripLorentzAngle> OutLorentzAngle = std::make_shared<SiStripLorentzAngle>();
375 
376  bool isPayloadChanged{false};
377  std::vector<std::pair<int, int>> treatedIndices;
378  for (const auto& loc : iHists_.moduleLocationType_) {
379  if (debug_) {
380  edm::LogInfo(moduleDescription().moduleName()) << "modId: " << loc.first << " " << loc.second;
381  }
382 
383  if (!(loc.second).empty() && theMagField_ != 0.f) {
384  OutLorentzAngle->putLorentzAngle(loc.first, std::abs(LAMap_[loc.second].first / theMagField_));
385  } else {
386  OutLorentzAngle->putLorentzAngle(loc.first, iHists_.la_db_[loc.first]);
387  }
388 
389  // if the location is not assigned (e.g. TID or TEC) continue
390  if ((loc.second).empty()) {
391  continue;
392  }
393 
394  const auto& index2D = siStripLACalibration::locationTypeIndex(loc.second);
395  LogDebug("SiStripLorentzAnglePCLHarvester")
396  << loc.first << " : " << loc.second << " index: " << index2D.first << "-" << index2D.second << std::endl;
397 
398  // check if the location exists, otherwise throw!
399  if (index2D != std::make_pair(-1, -1)) {
400  // Check if index2D is in treatedIndices
401  // Do not fill the control plots more than necessary (i.e. 1 entry per "partition")
402  auto it = std::find(treatedIndices.begin(), treatedIndices.end(), index2D);
403  if (it == treatedIndices.end()) {
404  // control plots
405  LogTrace("SiStripLorentzAnglePCLHarvester") << "accepted " << loc.first << " : " << loc.second << " bin ("
406  << index2D.first << "," << index2D.second << ")";
407 
408  const auto& outputLA = OutLorentzAngle->getLorentzAngle(loc.first);
409  const auto& inputLA = currentLorentzAngle_->getLorentzAngle(loc.first);
410 
411  LogTrace("SiStripLorentzAnglePCLHarvester") << "inputLA: " << inputLA << " outputLA: " << outputLA;
412 
413  iHists_.h2_byLayerLA_->setBinContent(index2D.first, index2D.second, outputLA);
414 
415  float deltaMuHoverMuH = (inputLA != 0.f) ? (inputLA - outputLA) / inputLA : 0.f;
416  iHists_.h2_byLayerDiff_->setBinContent(index2D.first, index2D.second, deltaMuHoverMuH * 100.f);
417  treatedIndices.emplace_back(index2D);
418 
419  // Check if the delta is different from zero
420  // and if the output LA is not zero (during B=0T running)
421  // If none of the locations has a non-zero diff
422  // will not write out the payload.
423  if (deltaMuHoverMuH != 0.f && outputLA != 0.f) {
424  isPayloadChanged = true;
425  LogDebug("SiStripLorentzAnglePCLHarvester")
426  << "accepted " << loc.first << " : " << loc.second << " bin (" << index2D.first << "," << index2D.second
427  << ") " << deltaMuHoverMuH;
428  } else {
429  edm::LogWarning("SiStripLorentzAnglePCLHarvester")
430  << "Discarded " << loc.first << " : " << loc.second << " bin (" << index2D.first << "," << index2D.second
431  << ") | delta muH/muH = " << deltaMuHoverMuH << " [1/T], output muH = " << outputLA << " [1/T]";
432  }
433  } // if the index has not been treated already
434  } else {
435  throw cms::Exception("SiStripLorentzAnglePCLHarvester")
436  << "Trying to fill an inexistent module location from " << loc.second << "!";
437  } //
438  } // ends loop on location types
439 
440  // book the TkDetMaps
441  const auto tkDetMapFolderIn = (fmt::format("{}Harvesting/TkDetMaps_LAInput", dqmDir_));
442  const auto tkDetMapFolderOut = (fmt::format("{}Harvesting/TkDetMaps_LAOutput", dqmDir_));
444  std::make_unique<TkHistoMap>(tkDetMap_.get(), iBooker, tkDetMapFolderIn, "inputLorentzAngle", 0, false, true),
445  std::make_unique<TkHistoMap>(tkDetMap_.get(), iBooker, tkDetMapFolderOut, "outputLorentzAngle", 0, false, true));
446 
447  // fill the TkDetMaps
448  for (const auto& loc : iHists_.moduleLocationType_) {
449  const auto& outputLA = OutLorentzAngle->getLorentzAngle(loc.first);
450  const auto& inputLA = currentLorentzAngle_->getLorentzAngle(loc.first);
451  h_modulesLA.fill(loc.first, inputLA, outputLA);
452  }
453 
454  // set colz to the output maps
456 
457  if (isPayloadChanged) {
458  // fill the DB object record
460  if (mydbservice.isAvailable()) {
461  try {
462  mydbservice->writeOneIOV(*OutLorentzAngle, mydbservice->currentTime(), recordName_);
463  } catch (const cond::Exception& er) {
464  edm::LogError("SiStripLorentzAngleDB") << er.what();
465  } catch (const std::exception& er) {
466  edm::LogError("SiStripLorentzAngleDB") << "caught std::exception " << er.what();
467  }
468  } else {
469  edm::LogError("SiStripLorentzAngleDB") << "Service is unavailable!";
470  }
471  } else {
472  edm::LogPrint("SiStripLorentzAngleDB")
473  << "****** WARNING ******\n* " << __PRETTY_FUNCTION__
474  << "\n* There is no new valid measurement to append!\n* Will NOT update the DB!\n*********************";
475  }
476 }
477 
478 //------------------------------------------------------------------------------
480  std::vector<std::string> tokens;
481 
483  // Create a string stream from the input string
484  std::istringstream iss(histoName);
485 
487  while (std::getline(iss, token, '_')) {
488  // Add each token to the vector
489  tokens.push_back(token);
490  }
491 
492  if (isFolder) {
493  output = tokens[0] + "/" + tokens[1];
494  output.pop_back();
495  } else {
496  output = tokens[0] + "_" + tokens[1];
497  }
498  return output;
499 }
500 
501 //------------------------------------------------------------------------------
504  desc.setComment("Harvester module of the SiStrip Lorentz Angle PCL monitoring workflow");
505  desc.add<bool>("debugMode", false)->setComment("determines if it's in debug mode");
506  desc.add<std::string>("dqmDir", "AlCaReco/SiStripLorentzAngle")->setComment("the directory of PCL Worker output");
507  desc.add<std::vector<double>>("fitRange", {0., 0.})->setComment("range of depths to perform the LA fit");
508  desc.add<std::string>("record", "SiStripLorentzAngleRcd")->setComment("target DB record");
509  descriptions.addWithDefaultLabel(desc);
510 }
511 
void addWithDefaultLabel(ParameterSetDescription const &psetDescription)
ESGetTokenH3DDVariant esConsumes(std::string const &Record, edm::ConsumesCollector &)
Definition: DeDxTools.cc:283
Base exception class for the object to relational access.
Definition: Exception.h:11
const edm::ESGetToken< TrackerGeometry, TrackerDigiGeometryRecord > geomEsToken_
T const & getData(const ESGetToken< T, R > &iToken) const noexcept(false)
Definition: EventSetup.h:119
void beginRun(const edm::Run &, const edm::EventSetup &) override
virtual void setCurrentFolder(std::string const &fullpath)
Definition: DQMStore.cc:36
ModuleDescription const & moduleDescription() const
double fitFunction(double *x, double *par)
Log< level::Error, false > LogError
std::pair< int, int > locationTypeIndex(const std::string &locType)
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:19
#define LogTrace(id)
static std::string const input
Definition: EdmProvDump.cc:50
float inverseBzAtOriginInGeV() const
The inverse of field z component for this map in GeV.
Definition: MagneticField.h:52
Definition: ME.h:11
char const * label
std::map< std::string, dqm::reco::MonitorElement * > p_
SiStripLorentzAngleCalibrationHistograms iHists_
std::map< std::string, dqm::reco::MonitorElement * > h2_
MonitorElement * bookProfile(TString const &name, TString const &title, int nchX, double lowX, double highX, int, double lowY, double highY, char const *option="s", FUNC onbooking=NOOP())
Definition: DQMStore.h:408
const std::string fieldAsString(const float &inputField)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
Hash writeOneIOV(const T &payload, Time_t time, const std::string &recordName)
Transition
Definition: Transition.h:12
static void fillDescriptions(edm::ConfigurationDescriptions &)
double f[11][100]
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
std::unique_ptr< TrackerTopology > theTrackerTopology_
const std::string apvModeAsString(const SiStripLatency *latency)
Log< level::Warning, true > LogPrint
Log< level::Info, false > LogInfo
const edm::ESGetToken< TrackerTopology, TrackerTopologyRcd > topoEsTokenBR_
float getLorentzAngle(const uint32_t &) const
void fill(uint32_t id, float inputLA, float outputLA)
std::string getStem(const std::string &histoName, bool isFolder)
const edm::ESGetToken< MagneticField, IdealMagneticFieldRecord > magneticFieldToken_
virtual void setBinContent(int binx, double content)
set content of bin (1-D)
MonitorElement * book2D(TString const &name, TString const &title, int nchX, double lowX, double highX, int nchY, double lowY, double highY, FUNC onbooking=NOOP())
Definition: DQMStore.h:221
void dqmEndJob(DQMStore::IBooker &, DQMStore::IGetter &) override
const SiStripLorentzAngle * currentLorentzAngle_
virtual MonitorElement * get(std::string const &fullpath) const
Definition: DQMStore.cc:712
SiStripLorentzAnglePCLHarvester(const edm::ParameterSet &)
void endRun(const edm::Run &, const edm::EventSetup &) override
HLT enums.
~SiStripLorentzAnglePCLHarvester() override=default
bool isAvailable() const
Definition: Service.h:40
Definition: output.py:1
Log< level::Warning, false > LogWarning
char const * what() const noexcept override
Definition: Exception.cc:107
LATkMap(std::unique_ptr< TkHistoMap > &&input, std::unique_ptr< TkHistoMap > &&output)
const edm::ESGetToken< TkDetMap, TrackerTopologyRcd > tkDetMapTokenER_
std::string moduleLocationType(const uint32_t &mod, const TrackerTopology *tTopo)
Generates a module location type string based on the detector ID and topology information.
def move(src, dest)
Definition: eostools.py:511
const edm::ESGetToken< SiStripLorentzAngle, SiStripLorentzAngleDepRcd > siStripLAEsToken_
Definition: Run.h:45
const edm::ESGetToken< TrackerTopology, TrackerTopologyRcd > topoEsTokenER_
#define LogDebug(id)
const edm::ESGetToken< SiStripLatency, SiStripLatencyRcd > latencyToken_