CMS 3D CMS Logo

HGCalWaferValidation.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: Validation/HGCalValidation
4 // Class: HGCalWaferValidation
5 //
20 //
21 // Original Author: Imran Yusuff
22 // Created: Thu, 27 May 2021 19:47:08 GMT
23 //
24 // Additional Author(s): Yulun Miao
25 /*
26  Changelog:
27 
28  Wed, 17 Nov 2021 21:04:10 UTC by Yulun Miao:
29 
30  * Use the l or h preceding the thickness to determine the type of flat file
31  * Unified partial wafer information to HGCalTypes.h to allow cross-compare
32 
33  Tue, 14 Dmr 2021 by Imran Yusuff:
34 
35  * Further tidying the code
36  * Now uses the first line of the flat file to determine flat file type (single number means new format)
37  * Separate out shape and rotation matching operation into functions
38  * Fixed validation for D86 geometry (especially in rotation for type-3 layers)
39 */
40 
41 // system include files
42 #include <memory>
43 
44 // user include files
47 
50 
55 
59 
60 #include <fstream>
61 #include <regex>
62 
63 //
64 // class declaration
65 //
66 
67 // If the analyzer does not use TFileService, please remove
68 // the template argument to the base class so the class inherits
69 // from edm::one::EDAnalyzer<>
70 // This will improve performance in multithreaded jobs.
71 
73 public:
74  explicit HGCalWaferValidation(const edm::ParameterSet&);
75  ~HGCalWaferValidation() override = default;
76 
77  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
78 
79 private:
80  // This is MessageLogger logging category
81  const std::string logcat = "HGCalWaferValidation";
82 
83  // wafer coordinate is (layer, u, v), used as index for map
84  using WaferCoord = std::tuple<int, int, int>;
85 
86  std::string strWaferCoord(const WaferCoord& coord);
87 
88  // mapping of wafer shape codes: DD / old format -> new format (LD/HD)
89  using WaferShapeMap = std::map<std::string, int>;
90 
92  {"a", HGCalTypes::WaferHalf},
93  {"am", HGCalTypes::WaferHalf2},
94  {"b", HGCalTypes::WaferFive},
95  {"bm", HGCalTypes::WaferFive2},
97  {"d", HGCalTypes::WaferSemi},
98  {"dm", HGCalTypes::WaferSemi2},
100  {"gm", HGCalTypes::WaferChopTwoM}};
101 
103  {"1", HGCalTypes::WaferHalf},
104  {"2", HGCalTypes::WaferHalf},
105  {"3", HGCalTypes::WaferSemi},
106  {"4", HGCalTypes::WaferSemi},
107  {"5", HGCalTypes::WaferFive},
108  {"6", HGCalTypes::WaferThree}};
109 
111  {"1", HGCalTypes::WaferHalf2},
113  {"3", HGCalTypes::WaferSemi2},
114  {"4", HGCalTypes::WaferSemi2},
115  {"5", HGCalTypes::WaferFive2}};
116 
117  bool DDFindHGCal(DDCompactView::GraphWalker& walker, std::string targetName);
120  bool isThicknessMatched(const int geoThickClass, const int fileThickness);
121  bool isRotationMatched(
122  const bool isNewFile, const int layer, const int fileShapeCode, const int geoRotCode, const int fileRotCode);
123 
124  void beginJob() override;
125  void analyze(const edm::Event&, const edm::EventSetup&) override;
126  void endJob() override;
127 
128  // ----------member data ---------------------------
129  // module parameters
131 
132  // information from newer flat file header
133  unsigned int layerCount_;
134  std::vector<int> layerTypes_;
135 
136  // struct to hold wafer information from DD in map
137  struct WaferInfo {
139  double x;
140  double y;
142  int rotCode;
143  std::string waferName; // TEMPORARY
144  };
145 
146  // EDM token to access DD
148 
149  // map holding all wafer properties from DD
150  std::map<WaferCoord, struct WaferInfo> waferData_;
151 
152  // boolean map to keep track of unaccounted DD wafers (not in flat file)
153  std::map<WaferCoord, bool> waferValidated_;
154 };
155 
156 //
157 // constants, enums and typedefs
158 //
159 
160 //
161 // static data member definitions
162 //
163 
164 //
165 // constructors and destructor
166 //
168  : geometryFileName_(iConfig.getParameter<edm::FileInPath>("GeometryFileName")) {
169  viewToken_ = esConsumes<DDCompactView, IdealGeometryRecord>();
170  //now do what ever initialization is needed
171 }
172 
173 //
174 // member functions
175 //
176 
177 // convert WaferCoord tuple to string representation (i.e. for printing)
179  std::stringstream ss;
180  ss << "(" << std::get<0>(coord) << "," << std::get<1>(coord) << "," << std::get<2>(coord) << ")";
181  return ss.str();
182 }
183 
184 // ----- find HGCal entry among the DD -----
186  if (walker.current().first.name().name() == targetName) {
187  // target found
188  return true;
189  }
190  if (walker.firstChild()) {
191  do {
192  if (DDFindHGCal(walker, targetName))
193  // target inside child
194  return true;
195  } while (walker.nextSibling());
196  walker.parent();
197  }
198  return false;
199 }
200 
201 // ----- find the next wafer, then process the wafer layer -----
203  if (walker.current().first.name().fullname().rfind("hgcalwafer:", 0) == 0) {
204  // first wafer found. Now process the entire layer of wafers.
205  ProcessWaferLayer(walker);
206  return;
207  }
208  if (walker.firstChild()) {
209  do {
210  DDFindWafers(walker);
211  } while (walker.nextSibling());
212  walker.parent();
213  }
214 }
215 
216 // ----- process the layer of wafers -----
218  int waferLayer = 0; // layer numbers in DD are assumed to be sequential from 1
219  waferLayer++;
220  edm::LogVerbatim(logcat) << "ProcessWaferLayer: Processing layer " << waferLayer;
221  do {
222  if (walker.current().first.name().fullname().rfind("hgcalwafer:", 0) == 0) {
223  auto wafer = walker.current();
224  const std::string waferName(walker.current().first.name().fullname());
225  //edm::LogVerbatim(logcat) << " " << waferName; // DEBUG: in case wafer name info is needed
226  const int copyNo = wafer.second->copyno();
227  // extract DD layer properties
228  const int waferType = HGCalTypes::getUnpackedType(copyNo);
229  const int waferU = HGCalTypes::getUnpackedU(copyNo);
230  const int waferV = HGCalTypes::getUnpackedV(copyNo);
231  const WaferCoord waferCoord(waferLayer, waferU, waferV); // map index
232  // build struct of DD wafer properties
233  struct WaferInfo waferInfo;
234  waferInfo.waferName = waferName; //TEMPORARY
235  waferInfo.thickClass = waferType;
236  waferInfo.x = wafer.second->translation().x();
237  waferInfo.y = wafer.second->translation().y();
238  const std::string waferNameData =
239  std::regex_replace(waferName,
240  std::regex("(HGCal[EH]E)(Wafer[01])(Fine|Coarse[12])([a-z]*)([0-9]*)"),
241  "$1 $2-$3 $4 $5",
242  std::regex_constants::format_no_copy);
243  std::stringstream ss(waferNameData);
244  std::string EEorHE;
245  std::string typeStr;
246  std::string shapeStr;
247  std::string rotStr;
248  ss >> EEorHE >> typeStr >> shapeStr >> rotStr;
249  // assume rotational symmetry of full-sized wafers
250  if (shapeStr.empty())
251  shapeStr = "F";
252  if (rotStr.empty())
253  rotStr = "0";
254  const int rotCode(std::stoi(rotStr));
255  //edm::LogVerbatim(logcat) << "rotStr " << rotStr << " rotCode " << rotCode;
256 
257  // convert shape code to wafer types defined in HGCalTypes.h
258  waferInfo.shapeCode = waferShapeMapDD.at(shapeStr);
259 
260  waferInfo.rotCode = rotCode;
261  // populate the map
262  waferData_[waferCoord] = waferInfo;
263  waferValidated_[waferCoord] = false;
264  }
265  } while (walker.nextSibling());
266 }
267 
268 // ------------ check if wafer thickness in geo matches in file (true = is a match) ------------
269 bool HGCalWaferValidation::isThicknessMatched(const int geoThickClass, const int fileThickness) {
270  if (geoThickClass == 0 && fileThickness == 120)
271  return true;
272  if (geoThickClass == 1 && fileThickness == 200)
273  return true;
274  if (geoThickClass == 2 && fileThickness == 300)
275  return true;
276  return false;
277 }
278 
279 // ------------ check if wafer rotation in geo matches in file (true = is a match) ------------
281  const bool isNewFile, const int layer, const int fileShapeCode, const int geoRotCode, const int fileRotCode) {
282  if (fileShapeCode != HGCalTypes::WaferFull && geoRotCode == fileRotCode)
283  return true;
284  if (fileShapeCode == HGCalTypes::WaferFull) {
285  if (isNewFile && layerTypes_[layer - 1] == 3) { // this array is index-0 based
286  if ((geoRotCode + 1) % 2 == fileRotCode % 2)
287  return true;
288  } else {
289  if (geoRotCode % 2 == fileRotCode % 2)
290  return true;
291  }
292  }
293  return false;
294 }
295 
296 // ------------ method called for each event ------------
298  using namespace edm;
299 
300  // Get the CMS DD
301  auto viewH = iSetup.getHandle(viewToken_);
302 
303  if (!viewH.isValid()) {
304  edm::LogPrint(logcat) << "Error obtaining geometry handle!";
305  return;
306  }
307 
308  edm::LogVerbatim(logcat) << "Root is : " << viewH->root();
309  edm::LogVerbatim(logcat) << std::endl;
310 
311  // find HGCalEE
312  auto eeWalker = viewH->walker();
313  const bool eeFound = DDFindHGCal(eeWalker, "HGCalEE");
314  if (eeFound) {
315  edm::LogVerbatim(logcat) << "HGCalEE found!";
316  edm::LogVerbatim(logcat) << "name = " << eeWalker.current().first.name().name();
317  edm::LogVerbatim(logcat) << "fullname = " << eeWalker.current().first.name().fullname();
318  } else {
319  edm::LogPrint(logcat) << "HGCalEE not found!";
320  }
321  edm::LogVerbatim(logcat) << std::endl;
322 
323  // find HGCalHEsil
324  auto hesilWalker = viewH->walker();
325  const bool hesilFound = DDFindHGCal(hesilWalker, "HGCalHEsil");
326  if (hesilFound) {
327  edm::LogVerbatim(logcat) << "HGCalHEsil found!";
328  edm::LogVerbatim(logcat) << "name = " << hesilWalker.current().first.name().name();
329  edm::LogVerbatim(logcat) << "fullname = " << hesilWalker.current().first.name().fullname();
330  } else {
331  edm::LogPrint(logcat) << "HGCalHEsil not found!";
332  }
333  edm::LogVerbatim(logcat) << std::endl;
334 
335  // find HGCalHEmix
336  auto hemixWalker = viewH->walker();
337  const bool hemixFound = DDFindHGCal(hemixWalker, "HGCalHEmix");
338  if (hemixFound) {
339  edm::LogVerbatim(logcat) << "HGCalHEmix found!";
340  edm::LogVerbatim(logcat) << "name = " << hemixWalker.current().first.name().name();
341  edm::LogVerbatim(logcat) << "fullname = " << hemixWalker.current().first.name().fullname();
342  } else {
343  edm::LogPrint(logcat) << "HGCalHEmix not found!";
344  }
345  edm::LogVerbatim(logcat) << std::endl;
346 
347  // give up if no HGCal found at all
348  if (!(eeFound || hesilFound || hemixFound)) {
349  edm::LogPrint(logcat) << "Nothing found. Giving up.";
350  return;
351  }
352 
353  // Now walk the HGCalEE walker to find the first wafer on each layer and process them
354  edm::LogVerbatim(logcat) << "Calling DDFindWafers(eeWalker);";
355  DDFindWafers(eeWalker);
356 
357  // Walk the HGCalHEsilwalker to find the first wafer on each layer and process them
358  edm::LogVerbatim(logcat) << "Calling DDFindWafers(hesilWalker);";
359  DDFindWafers(hesilWalker);
360 
361  // Walk the HGCalHEmix walker to find the first wafer on each layer and process them
362  edm::LogVerbatim(logcat) << "Calling DDFindWafers(hemixWalker);";
363  DDFindWafers(hemixWalker);
364 
365  // Confirm all the DD wafers have been read
366  edm::LogVerbatim(logcat) << "Number of wafers read from DD: " << waferData_.size();
367 
368  // Now open the geometry text file
370  edm::LogVerbatim(logcat) << "Opening geometry text file: " << fileName;
371  std::ifstream geoTxtFile(fileName);
372 
373  if (!geoTxtFile) {
374  edm::LogPrint(logcat) << "Cannot open geometry text file.";
375  return;
376  }
377 
378  // total processed counter
379  int nTotalProcessed = 0;
380 
381  // geometry error counters
382  int nMissing = 0;
383  int nThicknessError = 0;
384  int nPosXError = 0;
385  int nPosYError = 0;
386  int nShapeError = 0;
387  int nRotError = 0;
388  int nUnaccounted = 0;
389 
391 
392  // find out if this file is an old file or a new file
393  std::getline(geoTxtFile, buf);
394  std::stringstream ss(buf);
395  std::vector<std::string> first_tokens;
396  while (ss >> buf)
397  if (!buf.empty())
398  first_tokens.push_back(buf);
399 
400  const bool isNewFile(first_tokens.size() == 1);
401 
402  if (isNewFile) {
403  edm::LogVerbatim(logcat) << "Text file is of newer version.";
404  layerCount_ = std::stoi(buf);
405  std::getline(geoTxtFile, buf);
406  std::stringstream layerTypesSS(buf);
407  while (layerTypesSS >> buf)
408  if (!buf.empty())
409  layerTypes_.push_back(std::stoi(buf));
410  if (layerTypes_.size() != layerCount_)
411  edm::LogWarning(logcat) << "Number of layer types does not tally with layer count.";
412 
413  // TEMP: make sure reading is correct
414  edm::LogVerbatim(logcat) << "layerCount = " << layerCount_;
415  for (unsigned i = 0; i < layerTypes_.size(); i++) {
416  edm::LogVerbatim(logcat) << " layerType " << i + 1 << " = " << layerTypes_[i]; // 1-based
417  }
418  } else {
419  layerCount_ = 0;
420  // rewind back
421  geoTxtFile.clear();
422  geoTxtFile.seekg(0);
423  }
424 
425  // process each line on the text file
426  while (std::getline(geoTxtFile, buf)) {
427  std::stringstream ss(buf);
428  std::vector<std::string> tokens;
429  while (ss >> buf)
430  if (!buf.empty())
431  tokens.push_back(buf);
432  if (tokens.size() != 8)
433  continue;
434 
435  nTotalProcessed++;
436 
437  // extract wafer info from a textfile line
438  const int waferLayer(std::stoi(tokens[0]));
439  const std::string waferShapeStr(tokens[1]);
440  const std::string waferDensityStr(isNewFile ? tokens[2].substr(0, 1) : "");
441  const int waferThickness(isNewFile ? std::stoi(tokens[2].substr(1)) : std::stoi(tokens[2]));
442  const double waferX(std::stod(tokens[3]));
443  const double waferY(std::stod(tokens[4]));
444  const int waferRotCode(std::stoi(tokens[5]));
445  const int waferU(std::stoi(tokens[6]));
446  const int waferV(std::stoi(tokens[7]));
447  const int waferShapeCode(isNewFile ? (waferDensityStr == "l" ? waferShapeMapLD.at(waferShapeStr)
448  : waferDensityStr == "h" ? waferShapeMapHD.at(waferShapeStr)
450  : waferShapeMapDD.at(waferShapeStr));
451 
452  // map index for crosschecking with DD
453  const WaferCoord waferCoord(waferLayer, waferU, waferV);
454 
455  // now check for (and report) wafer data disagreements
456 
457  if (waferData_.find(waferCoord) == waferData_.end()) {
458  nMissing++;
459  edm::LogVerbatim(logcat) << "MISSING: " << strWaferCoord(waferCoord);
460  continue;
461  }
462 
463  const struct WaferInfo waferInfo = waferData_[waferCoord];
464  waferValidated_[waferCoord] = true;
465 
466  if (!isThicknessMatched(waferInfo.thickClass, waferThickness)) {
467  nThicknessError++;
468  edm::LogVerbatim(logcat) << "THICKNESS ERROR: " << strWaferCoord(waferCoord);
469  }
470 
471  // it seems that wafer x-coords relative to their layer plane are mirrored...
472  if (fabs(-waferInfo.x - waferX) > 0.015) { // assuming this much tolerance
473  nPosXError++;
474  edm::LogVerbatim(logcat) << "POSITION x ERROR: " << strWaferCoord(waferCoord);
475  }
476 
477  if (fabs(waferInfo.y - waferY) > 0.015) { // assuming this much tolerance
478  nPosYError++;
479  edm::LogVerbatim(logcat) << "POSITION y ERROR: " << strWaferCoord(waferCoord);
480  }
481 
482  if (waferInfo.shapeCode != waferShapeCode || waferShapeCode == HGCalTypes::WaferOut) {
483  nShapeError++;
484  edm::LogVerbatim(logcat) << "SHAPE ERROR: " << strWaferCoord(waferCoord) << " ( " << waferInfo.shapeCode
485  << " != " << waferDensityStr << waferShapeCode << " ) name=" << waferInfo.waferName;
486  }
487 
488  if (!isRotationMatched(isNewFile, std::get<0>(waferCoord), waferShapeCode, waferInfo.rotCode, waferRotCode)) {
489  nRotError++;
490  edm::LogVerbatim(logcat) << "ROTATION ERROR: " << strWaferCoord(waferCoord) << " ( " << waferInfo.rotCode
491  << " != " << waferRotCode << " (" << waferShapeCode
492  << ") ) name=" << waferInfo.waferName;
493  }
494  }
495 
496  geoTxtFile.close();
497 
498  // Find unaccounted DD wafers
499  for (auto const& accounted : waferValidated_) {
500  if (!accounted.second) {
501  nUnaccounted++;
502  edm::LogVerbatim(logcat) << "UNACCOUNTED: " << strWaferCoord(accounted.first);
503  }
504  }
505 
506  // Print out error counts
507  edm::LogVerbatim(logcat) << std::endl;
508  edm::LogVerbatim(logcat) << "*** ERROR COUNTS ***";
509  edm::LogVerbatim(logcat) << "Missing : " << nMissing;
510  edm::LogVerbatim(logcat) << "Thickness error : " << nThicknessError;
511  edm::LogVerbatim(logcat) << "Pos-x error : " << nPosXError;
512  edm::LogVerbatim(logcat) << "Pos-y error : " << nPosYError;
513  edm::LogVerbatim(logcat) << "Shape error : " << nShapeError;
514  edm::LogVerbatim(logcat) << "Rotation error : " << nRotError;
515  edm::LogVerbatim(logcat) << "Unaccounted : " << nUnaccounted;
516  edm::LogVerbatim(logcat) << std::endl;
517  edm::LogVerbatim(logcat) << "Total wafers processed from geotxtfile = " << nTotalProcessed;
518  edm::LogVerbatim(logcat) << std::endl;
519 
520  // Issue a LogPrint (warning) if there is at least one wafer errors
521  if (nMissing > 0 || nThicknessError > 0 || nPosXError > 0 || nPosYError > 0 || nShapeError > 0 || nRotError > 0 ||
522  nUnaccounted > 0) {
523  edm::LogPrint(logcat) << "There are at least one wafer error.";
524  }
525 }
526 
527 // ------------ method called once each job just before starting event loop ------------
529  // please remove this method if not needed
530 }
531 
532 // ------------ method called once each job just after ending the event loop ------------
534  // please remove this method if not needed
535 }
536 
537 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
539  //The following says we do not know what parameters are allowed so do no validation
540  // Please change this to state exactly what you do use, even if it is no parameters
542  desc.add<edm::FileInPath>("GeometryFileName",
543  edm::FileInPath("Validation/HGCalValidation/data/geomnew_corrected_360.txt"));
544  descriptions.add("hgcalWaferValidation", desc);
545 }
546 
547 //define this as a plug-in
std::map< WaferCoord, struct WaferInfo > waferData_
Log< level::Info, true > LogVerbatim
const WaferShapeMap waferShapeMapHD
static constexpr int32_t WaferHalf2
Definition: HGCalTypes.h:43
void ProcessWaferLayer(DDCompactView::GraphWalker &walker)
static constexpr int32_t WaferFive2
Definition: HGCalTypes.h:44
bool DDFindHGCal(DDCompactView::GraphWalker &walker, std::string targetName)
const WaferShapeMap waferShapeMapDD
static int32_t getUnpackedU(int id)
Definition: HGCalTypes.cc:16
int32_t waferU(const int32_t index)
std::map< std::string, int > WaferShapeMap
int32_t waferLayer(const int32_t index)
const std::string logcat
static constexpr int32_t WaferOut
Definition: HGCalTypes.h:56
static constexpr int32_t WaferThree
Definition: HGCalTypes.h:42
static int32_t getUnpackedV(int id)
Definition: HGCalTypes.cc:22
static constexpr int32_t WaferSemi2
Definition: HGCalTypes.h:41
std::tuple< int, int, int > WaferCoord
const WaferShapeMap waferShapeMapLD
~HGCalWaferValidation() override=default
static constexpr int32_t WaferFull
Definition: HGCalTypes.h:35
int iEvent
Definition: GenABIO.cc:224
static constexpr int32_t WaferHalf
Definition: HGCalTypes.h:39
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
result_type parent()
Definition: GraphWalker.h:130
void analyze(const edm::Event &, const edm::EventSetup &) override
std::vector< int > layerTypes_
bool isThicknessMatched(const int geoThickClass, const int fileThickness)
static int32_t getUnpackedType(int id)
Definition: HGCalTypes.cc:14
result_type firstChild()
Definition: GraphWalker.h:108
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
bool isRotationMatched(const bool isNewFile, const int layer, const int fileShapeCode, const int geoRotCode, const int fileRotCode)
Log< level::Warning, true > LogPrint
ESHandle< T > getHandle(const ESGetToken< T, R > &iToken) const
Definition: EventSetup.h:130
result_type nextSibling()
Definition: GraphWalker.h:119
static constexpr int32_t WaferChopTwoM
Definition: HGCalTypes.h:38
edm::ESGetToken< DDCompactView, IdealGeometryRecord > viewToken_
void add(std::string const &label, ParameterSetDescription const &psetDescription)
std::map< WaferCoord, bool > waferValidated_
HLT enums.
std::string strWaferCoord(const WaferCoord &coord)
int32_t waferV(const int32_t index)
edm::FileInPath geometryFileName_
const std::string & fullPath() const
Definition: FileInPath.cc:144
static constexpr int32_t WaferFive
Definition: HGCalTypes.h:36
void DDFindWafers(DDCompactView::GraphWalker &walker)
static constexpr int32_t WaferSemi
Definition: HGCalTypes.h:40
HGCalWaferValidation(const edm::ParameterSet &)
value_type current() const
Definition: GraphWalker.h:86
static constexpr int32_t WaferChopTwo
Definition: HGCalTypes.h:37