Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-06-16 01:49:45

0001 /****************************************************************************
0002 *
0003 * This is a part of TOTEM offline software.
0004 * Authors:
0005 *   Maciej Wróbel (wroblisko@gmail.com)
0006 *   Jan Kašpar (jan.kaspar@cern.ch)
0007 *   Marcin Borratynski (mborratynski@gmail.com)
0008 *   Seyed Mohsen Etesami (setesami@cern.ch)
0009 *   Laurent Forthomme
0010 ****************************************************************************/
0011 
0012 #include "FWCore/Framework/interface/MakerMacros.h"
0013 #include "FWCore/Framework/interface/SourceFactory.h"
0014 #include "FWCore/Framework/interface/ModuleFactory.h"
0015 #include "FWCore/Framework/interface/ESHandle.h"
0016 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0017 #include "FWCore/Framework/interface/ESProducer.h"
0018 #include "FWCore/Framework/interface/EventSetupRecordIntervalFinder.h"
0019 #include "FWCore/Framework/interface/ESProducts.h"
0020 #include "FWCore/Framework/interface/SourceFactory.h"
0021 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0022 
0023 #include "DataFormats/CTPPSDetId/interface/TotemRPDetId.h"
0024 #include "DataFormats/CTPPSDetId/interface/CTPPSDiamondDetId.h"
0025 #include "DataFormats/CTPPSDetId/interface/TotemTimingDetId.h"
0026 
0027 #include "CondFormats/DataRecord/interface/TotemReadoutRcd.h"
0028 #include "CondFormats/PPSObjects/interface/TotemDAQMapping.h"
0029 #include "CondFormats/PPSObjects/interface/TotemAnalysisMask.h"
0030 #include "CondFormats/PPSObjects/interface/TotemFramePosition.h"
0031 #include "Utilities/Xerces/interface/Xerces.h"
0032 #include "Utilities/Xerces/interface/XercesStrUtils.h"
0033 
0034 #include <xercesc/parsers/XercesDOMParser.hpp>
0035 #include <xercesc/dom/DOM.hpp>
0036 #include <xercesc/sax/HandlerBase.hpp>
0037 #include <xercesc/util/XMLString.hpp>
0038 #include <xercesc/util/PlatformUtils.hpp>
0039 
0040 #include <memory>
0041 #include <sstream>
0042 
0043 //#define DEBUG 1
0044 
0045 //----------------------------------------------------------------------------------------------------
0046 
0047 using namespace std;
0048 
0049 /**
0050  * \brief Loads TotemDAQMapping and TotemAnalysisMask from two XML files.
0051  **/
0052 class TotemDAQMappingESSourceXML : public edm::ESProducer, public edm::EventSetupRecordIntervalFinder {
0053 public:
0054   static const std::string tagVFAT;
0055   static const std::string tagChannel;
0056   static const std::string tagAnalysisMask;
0057 
0058   /// Common position tags
0059   static const std::string tagArm;
0060 
0061   /// RP XML tags
0062   static const std::string tagRPStation;
0063   static const std::string tagRPPot;
0064   static const std::string tagRPPlane;
0065 
0066   /// COMMON Chip XML tags
0067   static const std::string tagChip1;
0068   static const std::string tagChip2;
0069 
0070   /// diamond specific tags
0071   static const std::string tagDiamondPlane;
0072   static const std::string tagDiamondCh;
0073 
0074   /// totem timing specific tags
0075   static const std::string tagSampicBoard;
0076   static const std::string tagSampicCh;
0077   static const std::string tagTotemTimingCh;
0078   static const std::string tagTotemTimingPlane;
0079 
0080   TotemDAQMappingESSourceXML(const edm::ParameterSet &);
0081   ~TotemDAQMappingESSourceXML() override;
0082 
0083   edm::ESProducts<std::unique_ptr<TotemDAQMapping>, std::unique_ptr<TotemAnalysisMask>> produce(const TotemReadoutRcd &);
0084 
0085 private:
0086   unsigned int verbosity;
0087 
0088   /// label of the CTPPS sub-system
0089   string subSystemName;
0090 
0091   //subdetector id for sampic
0092   unsigned int sampicSubDetId;
0093 
0094   /// the mapping files
0095   std::vector<std::string> mappingFileNames;
0096 
0097   struct ConfigBlock {
0098     /// validity interval
0099     edm::EventRange validityRange;
0100 
0101     /// the mapping files
0102     std::vector<std::string> mappingFileNames;
0103 
0104     /// the mask files
0105     std::vector<std::string> maskFileNames;
0106   };
0107 
0108   vector<ConfigBlock> configuration;
0109 
0110   /// index of the current block in 'configuration' array
0111   unsigned int currentBlock;
0112 
0113   /// flag whether the 'currentBlock' index is valid
0114   bool currentBlockValid;
0115 
0116   /// enumeration of XML node types
0117   enum NodeType {
0118     nUnknown,
0119     nSkip,
0120     nTop,
0121     nArm,
0122     nRPStation,
0123     nRPPot,
0124     nRPPlane,
0125     nDiamondPlane,
0126     nChip,
0127     nDiamondCh,
0128     nChannel,
0129     nSampicBoard,
0130     nSampicChannel,
0131     nTotemTimingPlane,
0132     nTotemTimingCh
0133   };
0134 
0135   /// whether to parse a mapping of a mask XML
0136   enum ParseType { pMapping, pMask };
0137 
0138   /// parses XML file
0139   void ParseXML(ParseType,
0140                 const string &file,
0141                 const std::unique_ptr<TotemDAQMapping> &,
0142                 const std::unique_ptr<TotemAnalysisMask> &);
0143 
0144   /// recursive method to extract RP-related information from the DOM tree
0145   void ParseTreeRP(ParseType,
0146                    xercesc::DOMNode *,
0147                    NodeType,
0148                    unsigned int parentID,
0149                    const std::unique_ptr<TotemDAQMapping> &,
0150                    const std::unique_ptr<TotemAnalysisMask> &);
0151 
0152   /// recursive method to extract RP-related information from the DOM tree
0153   void ParseTreeDiamond(ParseType,
0154                         xercesc::DOMNode *,
0155                         NodeType,
0156                         unsigned int parentID,
0157                         const std::unique_ptr<TotemDAQMapping> &,
0158                         const std::unique_ptr<TotemAnalysisMask> &);
0159 
0160   /// recursive method to extract RP-related information from the DOM tree
0161   void ParseTreeTotemTiming(ParseType,
0162                             xercesc::DOMNode *,
0163                             NodeType,
0164                             unsigned int parentID,
0165                             const std::unique_ptr<TotemDAQMapping> &,
0166                             const std::unique_ptr<TotemAnalysisMask> &);
0167 
0168 private:
0169   /// adds the path prefix, if needed
0170   string CompleteFileName(const string &fn);
0171 
0172   /// returns true iff the node is of the given name
0173   bool Test(xercesc::DOMNode *node, const std::string &name) {
0174     return !(name.compare(cms::xerces::toString(node->getNodeName())));
0175   }
0176 
0177   /// determines node type
0178   NodeType GetNodeType(xercesc::DOMNode *);
0179 
0180   /// returns the content of the node
0181   string GetNodeContent(xercesc::DOMNode *parent) { return string(cms::xerces::toString(parent->getTextContent())); }
0182 
0183   /// returns the value of the node
0184   string GetNodeValue(xercesc::DOMNode *node) { return cms::xerces::toString(node->getNodeValue()); }
0185 
0186   /// extracts VFAT's DAQ channel from XML attributes
0187   TotemFramePosition ChipFramePosition(xercesc::DOMNode *chipnode);
0188 
0189   void GetChannels(xercesc::DOMNode *n, std::set<unsigned char> &channels);
0190 
0191   bool RPNode(NodeType type) {
0192     return ((type == nArm) || (type == nRPStation) || (type == nRPPot) || (type == nRPPlane) || (type == nChip));
0193   }
0194 
0195   bool DiamondNode(NodeType type) {
0196     return ((type == nArm) || (type == nRPStation) || (type == nRPPot) || (type == nDiamondPlane) ||
0197             (type == nDiamondCh));
0198   }
0199 
0200   bool TotemTimingNode(NodeType type) {
0201     return ((type == nArm) || (type == nRPStation) || (type == nRPPot) || (type == nSampicBoard) ||
0202             (type == nSampicChannel) || (type == nTotemTimingPlane) || (type == nTotemTimingCh));
0203   }
0204 
0205   bool CommonNode(NodeType type) { return ((type == nChip) || (type == nArm)); }
0206 
0207 protected:
0208   /// sets infinite validity of this data
0209   void setIntervalFor(const edm::eventsetup::EventSetupRecordKey &,
0210                       const edm::IOVSyncValue &,
0211                       edm::ValidityInterval &) override;
0212 };
0213 
0214 //----------------------------------------------------------------------------------------------------
0215 
0216 using namespace std;
0217 using namespace edm;
0218 using namespace xercesc;
0219 
0220 const string TotemDAQMappingESSourceXML::tagVFAT = "vfat";
0221 const string TotemDAQMappingESSourceXML::tagChannel = "channel";
0222 const string TotemDAQMappingESSourceXML::tagAnalysisMask = "analysisMask";
0223 
0224 // common XML position tags
0225 const string TotemDAQMappingESSourceXML::tagArm = "arm";
0226 
0227 // common XML Chip tags
0228 const string TotemDAQMappingESSourceXML::tagChip1 = "vfat";
0229 const string TotemDAQMappingESSourceXML::tagChip2 = "test_vfat";
0230 
0231 // specific RP XML tags
0232 const string TotemDAQMappingESSourceXML::tagRPStation = "station";
0233 const string TotemDAQMappingESSourceXML::tagRPPot = "rp_detector_set";
0234 const string TotemDAQMappingESSourceXML::tagRPPlane = "rp_plane";
0235 
0236 // specific tags for diamond
0237 const string TotemDAQMappingESSourceXML::tagDiamondPlane = "rp_plane_diamond";
0238 const string TotemDAQMappingESSourceXML::tagDiamondCh = "diamond_channel";
0239 
0240 // specific tags for totem timing
0241 const string TotemDAQMappingESSourceXML::tagSampicBoard = "rp_sampic_board";
0242 const string TotemDAQMappingESSourceXML::tagSampicCh = "rp_sampic_channel";
0243 const string TotemDAQMappingESSourceXML::tagTotemTimingCh = "timing_channel";
0244 const string TotemDAQMappingESSourceXML::tagTotemTimingPlane = "timing_plane";
0245 
0246 //----------------------------------------------------------------------------------------------------
0247 
0248 TotemDAQMappingESSourceXML::TotemDAQMappingESSourceXML(const edm::ParameterSet &conf)
0249     : verbosity(conf.getUntrackedParameter<unsigned int>("verbosity", 0)),
0250       subSystemName(conf.getUntrackedParameter<string>("subSystem")),
0251       sampicSubDetId(conf.getParameter<unsigned int>("sampicSubDetId")),
0252       currentBlock(0),
0253       currentBlockValid(false) {
0254   for (const auto &it : conf.getParameter<vector<ParameterSet>>("configuration")) {
0255     ConfigBlock b;
0256     b.validityRange = it.getParameter<EventRange>("validityRange");
0257     b.mappingFileNames = it.getParameter<vector<string>>("mappingFileNames");
0258     b.maskFileNames = it.getParameter<vector<string>>("maskFileNames");
0259     configuration.push_back(b);
0260   }
0261 
0262   setWhatProduced(this, subSystemName);
0263   findingRecord<TotemReadoutRcd>();
0264 }
0265 
0266 //----------------------------------------------------------------------------------------------------
0267 
0268 void TotemDAQMappingESSourceXML::setIntervalFor(const edm::eventsetup::EventSetupRecordKey &key,
0269                                                 const edm::IOVSyncValue &iosv,
0270                                                 edm::ValidityInterval &oValidity) {
0271   LogVerbatim("TotemDAQMappingESSourceXML") << ">> TotemDAQMappingESSourceXML::setIntervalFor(" << key.name() << ")";
0272 
0273   LogVerbatim("TotemDAQMappingESSourceXML")
0274       << "    run=" << iosv.eventID().run() << ", event=" << iosv.eventID().event();
0275 
0276   currentBlockValid = false;
0277   for (unsigned int idx = 0; idx < configuration.size(); ++idx) {
0278     const auto &bl = configuration[idx];
0279 
0280     edm::EventRange range = bl.validityRange;
0281 
0282     // If "<run>:min" is specified in python config, it is translated into event <run>:0:1.
0283     // However, the truly minimal event id often found in data is <run>:0:0. Therefore the
0284     // adjustment below is needed.
0285     if (range.startEventID().luminosityBlock() == 0 && range.startEventID().event() == 1)
0286       range = edm::EventRange(edm::EventID(range.startEventID().run(), 0, 0), range.endEventID());
0287 
0288     if (edm::contains(range, iosv.eventID())) {
0289       currentBlockValid = true;
0290       currentBlock = idx;
0291 
0292       const IOVSyncValue begin(range.startEventID());
0293       const IOVSyncValue end(range.endEventID());
0294       oValidity = edm::ValidityInterval(begin, end);
0295 
0296       LogVerbatim("TotemDAQMappingESSourceXML") << "    block found: index=" << currentBlock << ", interval=("
0297                                                 << range.startEventID() << " - " << range.endEventID() << ")";
0298 
0299       return;
0300     }
0301   }
0302 
0303   if (!currentBlockValid) {
0304     throw cms::Exception("TotemDAQMappingESSourceXML::setIntervalFor")
0305         << "No configuration for event " << iosv.eventID();
0306   }
0307 }
0308 
0309 //----------------------------------------------------------------------------------------------------
0310 
0311 TotemDAQMappingESSourceXML::~TotemDAQMappingESSourceXML() {}
0312 
0313 //----------------------------------------------------------------------------------------------------
0314 
0315 string TotemDAQMappingESSourceXML::CompleteFileName(const string &fn) {
0316   FileInPath fip(fn);
0317   return fip.fullPath();
0318 }
0319 
0320 //----------------------------------------------------------------------------------------------------
0321 
0322 edm::ESProducts<std::unique_ptr<TotemDAQMapping>, std::unique_ptr<TotemAnalysisMask>>
0323 TotemDAQMappingESSourceXML::produce(const TotemReadoutRcd &) {
0324   assert(currentBlockValid);
0325 
0326   auto mapping = std::make_unique<TotemDAQMapping>();
0327   auto mask = std::make_unique<TotemAnalysisMask>();
0328 
0329   // initialize Xerces
0330   cms::concurrency::xercesInitialize();
0331 
0332   // load mapping files
0333   for (const auto &fn : configuration[currentBlock].mappingFileNames)
0334     ParseXML(pMapping, CompleteFileName(fn), mapping, mask);
0335 
0336   // load mask files
0337   for (const auto &fn : configuration[currentBlock].maskFileNames)
0338     ParseXML(pMask, CompleteFileName(fn), mapping, mask);
0339 
0340   // release Xerces
0341   cms::concurrency::xercesTerminate();
0342 
0343   // commit the products
0344   return edm::es::products(std::move(mapping), std::move(mask));
0345 }
0346 
0347 //----------------------------------------------------------------------------------------------------
0348 
0349 void TotemDAQMappingESSourceXML::ParseXML(ParseType pType,
0350                                           const string &file,
0351                                           const std::unique_ptr<TotemDAQMapping> &mapping,
0352                                           const std::unique_ptr<TotemAnalysisMask> &mask) {
0353   unique_ptr<XercesDOMParser> parser(new XercesDOMParser());
0354   parser->parse(file.c_str());
0355 
0356   DOMDocument *domDoc = parser->getDocument();
0357 
0358   if (!domDoc)
0359     throw cms::Exception("TotemDAQMappingESSourceXML::ParseXML")
0360         << "Cannot parse file `" << file << "' (domDoc = NULL).";
0361 
0362   DOMElement *elementRoot = domDoc->getDocumentElement();
0363 
0364   if (!elementRoot)
0365     throw cms::Exception("TotemDAQMappingESSourceXML::ParseXML") << "File `" << file << "' is empty.";
0366 
0367   ParseTreeRP(pType, elementRoot, nTop, 0, mapping, mask);
0368 
0369   ParseTreeDiamond(pType, elementRoot, nTop, 0, mapping, mask);
0370 
0371   ParseTreeTotemTiming(pType, elementRoot, nTop, 0, mapping, mask);
0372 }
0373 
0374 //-----------------------------------------------------------------------------------------------------------
0375 
0376 void TotemDAQMappingESSourceXML::ParseTreeRP(ParseType pType,
0377                                              xercesc::DOMNode *parent,
0378                                              NodeType parentType,
0379                                              unsigned int parentID,
0380                                              const std::unique_ptr<TotemDAQMapping> &mapping,
0381                                              const std::unique_ptr<TotemAnalysisMask> &mask) {
0382 #ifdef DEBUG
0383   printf(">> TotemDAQMappingESSourceXML::ParseTreeRP(%s, %u, %u)\n",
0384          cms::xerces::toString(parent->getNodeName()),
0385          parentType,
0386          parentID);
0387 #endif
0388 
0389   DOMNodeList *children = parent->getChildNodes();
0390 
0391   for (unsigned int i = 0; i < children->getLength(); i++) {
0392     DOMNode *n = children->item(i);
0393     if (n->getNodeType() != DOMNode::ELEMENT_NODE)
0394       continue;
0395 
0396     NodeType type = GetNodeType(n);
0397 
0398 #ifdef DEBUG
0399     printf("\tname = %s, type = %u\n", cms::xerces::toString(n->getNodeName()), type);
0400 #endif
0401 
0402     // structure control
0403     if (!RPNode(type))
0404       continue;
0405 
0406     NodeType expectedParentType;
0407     switch (type) {
0408       case nArm:
0409         expectedParentType = nTop;
0410         break;
0411       case nRPStation:
0412         expectedParentType = nArm;
0413         break;
0414       case nRPPot:
0415         expectedParentType = nRPStation;
0416         break;
0417       case nRPPlane:
0418         expectedParentType = nRPPot;
0419         break;
0420       case nChip:
0421         expectedParentType = nRPPlane;
0422         break;
0423       case nChannel:
0424         expectedParentType = nChip;
0425         break;
0426       default:
0427         expectedParentType = nUnknown;
0428         break;
0429     }
0430 
0431     if (expectedParentType != parentType) {
0432       throw cms::Exception("TotemDAQMappingESSourceXML")
0433           << "Node " << cms::xerces::toString(n->getNodeName()) << " not allowed within "
0434           << cms::xerces::toString(parent->getNodeName()) << " block.\n";
0435     }
0436 
0437     // parse tag attributes
0438     unsigned int id = 0, hw_id = 0;
0439     bool id_set = false, hw_id_set = false;
0440     bool fullMask = false;
0441     DOMNamedNodeMap *attr = n->getAttributes();
0442 
0443     for (unsigned int j = 0; j < attr->getLength(); j++) {
0444       DOMNode *a = attr->item(j);
0445 
0446       if (!strcmp(cms::xerces::toString(a->getNodeName()).c_str(), "id")) {
0447         sscanf(cms::xerces::toString(a->getNodeValue()).c_str(), "%u", &id);
0448         id_set = true;
0449       }
0450 
0451       if (!strcmp(cms::xerces::toString(a->getNodeName()).c_str(), "hw_id")) {
0452         sscanf(cms::xerces::toString(a->getNodeValue()).c_str(), "%x", &hw_id);
0453         hw_id_set = true;
0454       }
0455 
0456       if (!strcmp(cms::xerces::toString(a->getNodeName()).c_str(), "full_mask"))
0457         fullMask = (strcmp(cms::xerces::toString(a->getNodeValue()).c_str(), "no") != 0);
0458     }
0459 
0460     // content control
0461     if (!id_set)
0462       throw cms::Exception("TotemDAQMappingESSourceXML::ParseTreeRP")
0463           << "id not given for element `" << cms::xerces::toString(n->getNodeName()) << "'";
0464 
0465     if (!hw_id_set && type == nChip && pType == pMapping)
0466       throw cms::Exception("TotemDAQMappingESSourceXML::ParseTreeRP")
0467           << "hw_id not given for element `" << cms::xerces::toString(n->getNodeName()) << "'";
0468 
0469     if (type == nRPPlane && id > 9)
0470       throw cms::Exception("TotemDAQMappingESSourceXML::ParseTreeRP")
0471           << "Plane IDs range from 0 to 9. id = " << id << " is invalid.";
0472 
0473 #ifdef DEBUG
0474     printf("\tID found: 0x%x\n", id);
0475 #endif
0476 
0477     // store mapping data
0478     if (pType == pMapping && type == nChip) {
0479       const TotemFramePosition &framepos = ChipFramePosition(n);
0480       TotemVFATInfo vfatInfo;
0481       vfatInfo.hwID = hw_id;
0482 
0483       const unsigned int armIdx = (parentID / 1000) % 10;
0484       const unsigned int stIdx = (parentID / 100) % 10;
0485       const unsigned int rpIdx = (parentID / 10) % 10;
0486       const unsigned int plIdx = parentID % 10;
0487 
0488       vfatInfo.symbolicID.symbolicID = TotemRPDetId(armIdx, stIdx, rpIdx, plIdx, id);
0489 
0490       mapping->insert(framepos, vfatInfo);
0491 
0492       continue;
0493     }
0494 
0495     // store mask data
0496     if (pType == pMask && type == nChip) {
0497       const unsigned int armIdx = (parentID / 1000) % 10;
0498       const unsigned int stIdx = (parentID / 100) % 10;
0499       const unsigned int rpIdx = (parentID / 10) % 10;
0500       const unsigned int plIdx = parentID % 10;
0501 
0502       TotemSymbID symbId;
0503       symbId.symbolicID = TotemRPDetId(armIdx, stIdx, rpIdx, plIdx, id);
0504 
0505       TotemVFATAnalysisMask am;
0506       am.fullMask = fullMask;
0507       GetChannels(n, am.maskedChannels);
0508 
0509       mask->insert(symbId, am);
0510 
0511       continue;
0512     }
0513 
0514     // recursion (deeper in the tree)
0515     ParseTreeRP(pType, n, type, parentID * 10 + id, mapping, mask);
0516   }
0517 }
0518 
0519 //----------------------------------------------------------------------------------------------------
0520 
0521 void TotemDAQMappingESSourceXML::ParseTreeDiamond(ParseType pType,
0522                                                   xercesc::DOMNode *parent,
0523                                                   NodeType parentType,
0524                                                   unsigned int parentID,
0525                                                   const std::unique_ptr<TotemDAQMapping> &mapping,
0526                                                   const std::unique_ptr<TotemAnalysisMask> &mask) {
0527 #ifdef DEBUG
0528   printf(">> TotemDAQMappingESSourceXML::ParseTreeDiamond(%s, %u, %u)\n",
0529          cms::xerces::toString(parent->getNodeName()),
0530          parentType,
0531          parentID);
0532 #endif
0533 
0534   DOMNodeList *children = parent->getChildNodes();
0535 
0536   for (unsigned int i = 0; i < children->getLength(); i++) {
0537     DOMNode *n = children->item(i);
0538     if (n->getNodeType() != DOMNode::ELEMENT_NODE)
0539       continue;
0540 
0541     NodeType type = GetNodeType(n);
0542 #ifdef DEBUG
0543     printf("\tname = %s, type = %u\n", cms::xerces::toString(n->getNodeName()), type);
0544 #endif
0545 
0546     // structure control
0547     if (!DiamondNode(type))
0548       continue;
0549 
0550     NodeType expectedParentType;
0551     switch (type) {
0552       case nArm:
0553         expectedParentType = nTop;
0554         break;
0555       case nRPStation:
0556         expectedParentType = nArm;
0557         break;
0558       case nRPPot:
0559         expectedParentType = nRPStation;
0560         break;
0561       case nDiamondPlane:
0562         expectedParentType = nRPPot;
0563         break;
0564       case nDiamondCh:
0565         expectedParentType = nDiamondPlane;
0566         break;
0567       default:
0568         expectedParentType = nUnknown;
0569         break;
0570     }
0571 
0572     if (expectedParentType != parentType) {
0573       throw cms::Exception("TotemDAQMappingESSourceXML")
0574           << "Node " << cms::xerces::toString(n->getNodeName()) << " not allowed within "
0575           << cms::xerces::toString(parent->getNodeName()) << " block.\n";
0576     }
0577 
0578     // parse tag attributes
0579     unsigned int id = 0, hw_id = 0;
0580     bool id_set = false, hw_id_set = false;
0581     DOMNamedNodeMap *attr = n->getAttributes();
0582 
0583     for (unsigned int j = 0; j < attr->getLength(); j++) {
0584       DOMNode *a = attr->item(j);
0585 
0586       if (!strcmp(cms::xerces::toString(a->getNodeName()).c_str(), "id")) {
0587         sscanf(cms::xerces::toString(a->getNodeValue()).c_str(), "%u", &id);
0588         id_set = true;
0589       }
0590 
0591       if (!strcmp(cms::xerces::toString(a->getNodeName()).c_str(), "hw_id")) {
0592         sscanf(cms::xerces::toString(a->getNodeValue()).c_str(), "%x", &hw_id);
0593         hw_id_set = true;
0594       }
0595     }
0596 
0597     // content control
0598     if (!id_set)
0599       throw cms::Exception("TotemDAQMappingESSourceXML::ParseTreeDiamond")
0600           << "id not given for element `" << cms::xerces::toString(n->getNodeName()) << "'";
0601 
0602     if (!hw_id_set && type == nDiamondCh && pType == pMapping)
0603       throw cms::Exception("TotemDAQMappingESSourceXML::ParseTreeDiamond")
0604           << "hw_id not given for element `" << cms::xerces::toString(n->getNodeName()) << "'";
0605 
0606     if (type == nDiamondPlane && id > 3)
0607       throw cms::Exception("TotemDAQMappingESSourceXML::ParseTreeDiamond")
0608           << "Plane IDs range from 0 to 3. id = " << id << " is invalid.";
0609 
0610 #ifdef DEBUG
0611     printf("\tID found: 0x%x\n", id);
0612 #endif
0613 
0614     // store mapping data
0615     if (pType == pMapping && type == nDiamondCh) {
0616       const TotemFramePosition &framepos = ChipFramePosition(n);
0617 
0618       TotemVFATInfo vfatInfo;
0619       vfatInfo.hwID = hw_id;
0620 
0621       if (type == nDiamondCh) {
0622         unsigned int ArmNum = (parentID / 10000) % 10;
0623         unsigned int StationNum = (parentID / 1000) % 10;
0624         unsigned int RpNum = (parentID / 100) % 10;
0625         unsigned int PlaneNum = (parentID % 100);
0626 
0627         vfatInfo.symbolicID.symbolicID = CTPPSDiamondDetId(ArmNum, StationNum, RpNum, PlaneNum, id);
0628       }
0629 
0630       mapping->insert(framepos, vfatInfo);
0631 
0632       continue;
0633     }
0634 
0635     unsigned int childId;
0636     if (pType == pMapping && type == nDiamondPlane)
0637       childId = parentID * 100 + id;
0638     else
0639       childId = parentID * 10 + id;
0640 
0641     ParseTreeDiamond(pType, n, type, childId, mapping, mask);
0642   }
0643 }
0644 
0645 //----------------------------------------------------------------------------------------------------
0646 
0647 void TotemDAQMappingESSourceXML::ParseTreeTotemTiming(ParseType pType,
0648                                                       xercesc::DOMNode *parent,
0649                                                       NodeType parentType,
0650                                                       unsigned int parentID,
0651                                                       const std::unique_ptr<TotemDAQMapping> &mapping,
0652                                                       const std::unique_ptr<TotemAnalysisMask> &mask) {
0653   DOMNodeList *children = parent->getChildNodes();
0654 
0655   // Fill map hwId -> TotemTimingPlaneChannelPair
0656   for (unsigned int i = 0; i < children->getLength(); i++) {
0657     DOMNode *child = children->item(i);
0658     if ((child->getNodeType() != DOMNode::ELEMENT_NODE) || (GetNodeType(child) != nTotemTimingCh))
0659       continue;
0660 
0661     int plane = -1;
0662     DOMNamedNodeMap *attr = parent->getAttributes();
0663     for (unsigned int j = 0; j < attr->getLength(); j++) {
0664       DOMNode *a = attr->item(j);
0665 
0666       if (!strcmp(cms::xerces::toString(a->getNodeName()).c_str(), "id"))
0667         sscanf(cms::xerces::toString(a->getNodeValue()).c_str(), "%d", &plane);
0668     }
0669 
0670     int channel = -1;
0671     unsigned int hwId = 0;
0672     attr = child->getAttributes();
0673     for (unsigned int j = 0; j < attr->getLength(); j++) {
0674       DOMNode *a = attr->item(j);
0675 
0676       if (!strcmp(cms::xerces::toString(a->getNodeName()).c_str(), "id"))
0677         sscanf(cms::xerces::toString(a->getNodeValue()).c_str(), "%d", &channel);
0678       if (!strcmp(cms::xerces::toString(a->getNodeName()).c_str(), "hwId"))
0679         sscanf(cms::xerces::toString(a->getNodeValue()).c_str(), "%x", &hwId);
0680     }
0681 
0682     mapping->totemTimingChannelMap[(uint8_t)hwId] = TotemDAQMapping::TotemTimingPlaneChannelPair(plane, channel);
0683   }
0684 
0685   for (unsigned int i = 0; i < children->getLength(); i++) {
0686     DOMNode *n = children->item(i);
0687     if (n->getNodeType() != DOMNode::ELEMENT_NODE)
0688       continue;
0689 
0690     NodeType type = GetNodeType(n);
0691 
0692     // structure control
0693     if (!TotemTimingNode(type))
0694       continue;
0695 
0696     NodeType expectedParentType;
0697     switch (type) {
0698       case nArm:
0699         expectedParentType = nTop;
0700         break;
0701       case nRPStation:
0702         expectedParentType = nArm;
0703         break;
0704       case nRPPot:
0705         expectedParentType = nRPStation;
0706         break;
0707       case nSampicBoard:
0708         expectedParentType = nRPPot;
0709         break;
0710       case nSampicChannel:
0711         expectedParentType = nSampicBoard;
0712         break;
0713       case nTotemTimingPlane:
0714         expectedParentType = nRPPot;
0715         break;
0716       case nTotemTimingCh:
0717         expectedParentType = nTotemTimingPlane;
0718         break;
0719       default:
0720         expectedParentType = nUnknown;
0721         break;
0722     }
0723 
0724     if (expectedParentType != parentType) {
0725       throw cms::Exception("TotemDAQMappingESSourceXML")
0726           << "Node " << cms::xerces::toString(n->getNodeName()) << " not allowed within "
0727           << cms::xerces::toString(parent->getNodeName()) << " block.\n";
0728     }
0729 
0730     // parse tag attributes
0731     unsigned int id = 0;
0732     bool id_set = false;
0733     DOMNamedNodeMap *attr = n->getAttributes();
0734 
0735     for (unsigned int j = 0; j < attr->getLength(); j++) {
0736       DOMNode *a = attr->item(j);
0737 
0738       if (!strcmp(cms::xerces::toString(a->getNodeName()).c_str(), "id")) {
0739         sscanf(cms::xerces::toString(a->getNodeValue()).c_str(), "%u", &id);
0740         id_set = true;
0741       }
0742     }
0743 
0744     // content control
0745     if (!id_set)
0746       throw cms::Exception("TotemDAQMappingESSourceXML::ParseTreeTotemTiming")
0747           << "id not given for element `" << cms::xerces::toString(n->getNodeName()) << "'";
0748     if (type == nSampicBoard && id > 5)
0749       throw cms::Exception("TotemDAQMappingESSourceXML::ParseTreeTotemTiming")
0750           << "SampicBoard IDs range from 0 to 5. id = " << id << " is invalid.";
0751 
0752     // store mapping data
0753     if (pType == pMapping && type == nSampicChannel) {
0754       const TotemFramePosition &framepos = ChipFramePosition(n);
0755 
0756       TotemVFATInfo vfatInfo;
0757       unsigned int ArmNum = (parentID / 10000) % 10;
0758       unsigned int StationNum = (parentID / 1000) % 10;
0759       unsigned int RpNum = (parentID / 100) % 10;
0760 
0761       vfatInfo.symbolicID.symbolicID = TotemTimingDetId(ArmNum,
0762                                                         StationNum,
0763                                                         RpNum,
0764                                                         0,
0765                                                         TotemTimingDetId::ID_NOT_SET,
0766                                                         sampicSubDetId);  //Dynamical: it is encoded in the frame
0767 
0768       mapping->insert(framepos, vfatInfo);
0769 
0770       continue;
0771     }
0772 
0773     unsigned int childId;
0774     if (pType == pMapping && type == nSampicBoard)
0775       childId = parentID * 100 + id;
0776     else
0777       childId = parentID * 10 + id;
0778 
0779     ParseTreeTotemTiming(pType, n, type, childId, mapping, mask);
0780   }
0781 }
0782 
0783 //----------------------------------------------------------------------------------------------------
0784 
0785 TotemFramePosition TotemDAQMappingESSourceXML::ChipFramePosition(xercesc::DOMNode *chipnode) {
0786   TotemFramePosition fp;
0787   unsigned char attributeFlag = 0;
0788 
0789   DOMNamedNodeMap *attr = chipnode->getAttributes();
0790   for (unsigned int j = 0; j < attr->getLength(); j++) {
0791     DOMNode *a = attr->item(j);
0792     if (fp.setXMLAttribute(
0793             cms::xerces::toString(a->getNodeName()), cms::xerces::toString(a->getNodeValue()), attributeFlag) > 1) {
0794       throw cms::Exception("TotemDAQMappingESSourceXML")
0795           << "Unrecognized tag `" << cms::xerces::toString(a->getNodeName()) << "' or incompatible value `"
0796           << cms::xerces::toString(a->getNodeValue()) << "'.";
0797     }
0798   }
0799 
0800   if (!fp.checkXMLAttributeFlag(attributeFlag)) {
0801     throw cms::Exception("TotemDAQMappingESSourceXML")
0802         << "Wrong/incomplete DAQ channel specification (attributeFlag = " << attributeFlag << ").";
0803   }
0804 
0805   return fp;
0806 }
0807 
0808 //----------------------------------------------------------------------------------------------------
0809 
0810 TotemDAQMappingESSourceXML::NodeType TotemDAQMappingESSourceXML::GetNodeType(xercesc::DOMNode *n) {
0811   // common node types
0812   if (Test(n, tagArm))
0813     return nArm;
0814   if (Test(n, tagChip1))
0815     return nChip;
0816   if (Test(n, tagChip2))
0817     return nChip;
0818 
0819   // RP node types
0820   if (Test(n, tagRPStation))
0821     return nRPStation;
0822   if (Test(n, tagRPPot))
0823     return nRPPot;
0824   if (Test(n, tagRPPlane))
0825     return nRPPlane;
0826 
0827   //diamond specifics
0828   if (Test(n, tagDiamondCh))
0829     return nDiamondCh;
0830   if (Test(n, tagDiamondPlane))
0831     return nDiamondPlane;
0832 
0833   //totem timing specifics
0834   if (Test(n, tagSampicBoard))
0835     return nSampicBoard;
0836   if (Test(n, tagSampicCh))
0837     return nSampicChannel;
0838   if (Test(n, tagTotemTimingCh))
0839     return nTotemTimingCh;
0840   if (Test(n, tagTotemTimingPlane))
0841     return nTotemTimingPlane;
0842 
0843   // for backward compatibility
0844   if (Test(n, "trigger_vfat"))
0845     return nSkip;
0846 
0847   throw cms::Exception("TotemDAQMappingESSourceXML::GetNodeType")
0848       << "Unknown tag `" << cms::xerces::toString(n->getNodeName()) << "'.\n";
0849 }
0850 
0851 //----------------------------------------------------------------------------------------------------
0852 
0853 void TotemDAQMappingESSourceXML::GetChannels(xercesc::DOMNode *n, set<unsigned char> &channels) {
0854   DOMNodeList *children = n->getChildNodes();
0855   for (unsigned int i = 0; i < children->getLength(); i++) {
0856     DOMNode *n = children->item(i);
0857     if (n->getNodeType() != DOMNode::ELEMENT_NODE || !Test(n, "channel"))
0858       continue;
0859 
0860     DOMNamedNodeMap *attr = n->getAttributes();
0861     bool idSet = false;
0862     for (unsigned int j = 0; j < attr->getLength(); j++) {
0863       DOMNode *a = attr->item(j);
0864 
0865       if (!strcmp(cms::xerces::toString(a->getNodeName()).c_str(), "id")) {
0866         unsigned int id = 0;
0867         sscanf(cms::xerces::toString(a->getNodeValue()).c_str(), "%u", &id);
0868         channels.insert(id);
0869         idSet = true;
0870         break;
0871       }
0872     }
0873 
0874     if (!idSet) {
0875       throw cms::Exception("TotemDAQMappingESSourceXML::GetChannels") << "Channel tags must have an `id' attribute.";
0876     }
0877   }
0878 }
0879 
0880 //----------------------------------------------------------------------------------------------------
0881 
0882 DEFINE_FWK_EVENTSETUP_SOURCE(TotemDAQMappingESSourceXML);