Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 11:56:07

0001 /// \file
0002 ///
0003 /// $Date: 2010/11/29 20:41:55 $
0004 /// $Revision: 1.11 $
0005 ///
0006 /// $Author: wmtan $
0007 /// \author Frederic Ronga - CERN-PH-CMG
0008 
0009 #include <string>
0010 #include <iostream>
0011 #include <sstream>
0012 #include <cstdlib>
0013 
0014 // Framework
0015 #include "FWCore/Utilities/interface/Exception.h"
0016 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0017 
0018 // Alignment
0019 #include "Alignment/CommonAlignment/interface/MisalignmentScenarioBuilder.h"
0020 #include "Alignment/CommonAlignment/interface/Alignable.h"
0021 
0022 //______________________________________________________________________________
0023 MisalignmentScenarioBuilder::MisalignmentScenarioBuilder(AlignableObjectId::Geometry geometry)
0024     : alignableObjectId_(geometry) {}
0025 
0026 //__________________________________________________________________________________________________
0027 // Call for each alignable the more general version with its appropriate level name.
0028 void MisalignmentScenarioBuilder::decodeMovements_(const edm::ParameterSet& pSet, const align::Alignables& alignables) {
0029   // first create a map with one align::Alignables per type (=levelName)
0030   using AlignablesMap = std::map<std::string, align::Alignables>;
0031   AlignablesMap alisMap;
0032   for (align::Alignables::const_iterator iA = alignables.begin(); iA != alignables.end(); ++iA) {
0033     const std::string& levelName = alignableObjectId_.idToString((*iA)->alignableObjectId());
0034     alisMap[levelName].push_back(*iA);  // either first entry of new level or add to an old one
0035   }
0036 
0037   // Now call the more general version for each entry in the map.
0038   //
0039   // There is a hack to ensure that strip components are called in the same order
0040   // as in old version of TrackerScenarioBuilder (TIB,TID,TOB,TEC) while
0041   // std::map seems to order alphabetically (TECEndcap,TIBHalfBarrel,TIDEndcap,TOBHalfBarrel).
0042   // Order matters due to random sequence. If scenarios are allowed to change
0043   // 'numerically', remove this comment and the lines marked with 'HACK'.
0044   const AlignablesMap::iterator itTec = alisMap.find("TECEndcap");  // HACK
0045   for (AlignablesMap::iterator it = alisMap.begin(); it != alisMap.end(); ++it) {
0046     if (it == itTec)
0047       continue;  // HACK
0048     this->decodeMovements_(pSet, it->second, it->first);
0049   }
0050   if (itTec != alisMap.end())
0051     this->decodeMovements_(pSet, itTec->second, itTec->first);  // HACK
0052 }
0053 
0054 //__________________________________________________________________________________________________
0055 // Decode nested parameter sets: this is the tricky part... Recursively called on components
0056 void MisalignmentScenarioBuilder::decodeMovements_(const edm::ParameterSet& pSet,
0057                                                    const align::Alignables& alignables,
0058                                                    const std::string& levelName) {
0059   indent_ += " ";  // For indented output!
0060 
0061   // Retrieve parameters for all components at this level
0062   std::ostringstream name;
0063   name << levelName << "s";
0064   edm::ParameterSet globalParameters = this->getParameterSet_(name.str(), pSet);
0065   if (!globalParameters.empty()) {
0066     LogDebug("PrintParameters") << indent_ << " *** " << levelName << ": found "
0067                                 << globalParameters.getParameterNames().size() << " global parameters" << std::endl;
0068   }
0069 
0070   // Propagate down parameters from upper level
0071   this->propagateParameters_(pSet, name.str(), globalParameters);
0072   LogDebug("PrintParameters") << indent_ << " global parameter is now:" << std::endl;
0073   this->printParameters_(globalParameters, true);
0074 
0075   // Loop on alignables
0076   int iComponent = 0;  // physical numbering starts at 1...
0077   for (align::Alignables::const_iterator iter = alignables.begin(); iter != alignables.end(); ++iter) {
0078     iComponent++;
0079 
0080     // Check for special parameters -> merge with global
0081     name.str("");
0082     name << levelName << iComponent;
0083 
0084     edm::ParameterSet localParameters = this->getParameterSet_(levelName, iComponent, pSet);
0085     LogDebug("PrintParameters") << indent_ << " ** " << name.str() << ": found "
0086                                 << localParameters.getParameterNames().size() << " local parameters" << std::endl;
0087     this->mergeParameters_(localParameters, globalParameters);
0088 
0089     // Retrieve and apply parameters
0090     LogDebug("PrintParameters") << indent_ << " parameters to apply:" << std::endl;
0091     this->printParameters_(localParameters, true);
0092     if (theModifier.modify((*iter), localParameters)) {
0093       theModifierCounter++;
0094       LogDebug("PrintParameters") << indent_ << "Movements applied to " << name.str();
0095     }
0096 
0097     // Apply movements to components
0098     std::vector<std::string> parameterSetNames;
0099     localParameters.getParameterSetNames(parameterSetNames, true);
0100     if ((*iter)->size() > 0 && !parameterSetNames.empty())
0101       // Has components and remaining parameter sets
0102       this->decodeMovements_(localParameters, (*iter)->components());
0103   }
0104 
0105   indent_ = indent_.substr(0, indent_.length() - 1);
0106 }
0107 
0108 //__________________________________________________________________________________________________
0109 // Merge two sets of parameters into one. The local set overrides the global one
0110 // A recursive merging is done on parameter sets.
0111 void MisalignmentScenarioBuilder::mergeParameters_(edm::ParameterSet& localSet,
0112                                                    const edm::ParameterSet& globalSet) const {
0113   indent_ += " ";
0114 
0115   // Loop on globalSet. Add to localSet all non-existing parameters
0116   std::vector<std::string> globalParameterNames = globalSet.getParameterNames();
0117   for (std::vector<std::string>::iterator iter = globalParameterNames.begin(); iter != globalParameterNames.end();
0118        iter++) {
0119     if (globalSet.existsAs<edm::ParameterSet>(*iter)) {
0120       // This is a parameter set: check it
0121       edm::ParameterSet subLocalSet = this->getParameterSet_((*iter), localSet);
0122       if (subLocalSet.empty()) {
0123         // No local subset exists: just insert it
0124         localSet.copyFrom(globalSet, (*iter));
0125       } else {
0126         // Merge with local subset and replace
0127         this->mergeParameters_(subLocalSet, globalSet.getParameter<edm::ParameterSet>(*iter));
0128         localSet.addParameter<edm::ParameterSet>((*iter), subLocalSet);
0129       }
0130     } else {
0131       // If (*iter) exists, (silently...) not replaced:
0132       localSet.copyFrom(globalSet, (*iter));
0133     }
0134   }
0135 
0136   indent_ = indent_.substr(0, indent_.length() - 1);
0137 }
0138 
0139 //__________________________________________________________________________________________________
0140 // Propagates some parameters from upper level.
0141 // Parameter sets are also propagated down (if name different from global name) or merged down.
0142 void MisalignmentScenarioBuilder::propagateParameters_(const edm::ParameterSet& pSet,
0143                                                        const std::string& globalName,
0144                                                        edm::ParameterSet& subSet) const {
0145   indent_ += " ";  // For indented output!
0146 
0147   // Propagate some given parameters
0148   std::vector<std::string> parameterNames = pSet.getParameterNames();
0149   for (std::vector<std::string>::iterator iter = parameterNames.begin(); iter != parameterNames.end(); ++iter) {
0150     if (theModifier.isPropagated(*iter)) {  // like 'distribution', 'scale', etc.
0151       LogDebug("PropagateParameters") << indent_ << " - adding parameter " << (*iter) << std::endl;
0152       subSet.copyFrom(pSet, (*iter));  // If existing, is not replaced.
0153     }
0154   }
0155 
0156   // Propagate all tracked parameter sets
0157   std::vector<std::string> pSetNames;
0158   if (pSet.getParameterSetNames(pSetNames, true) > 0) {
0159     for (std::vector<std::string>::const_iterator it = pSetNames.begin(); it != pSetNames.end(); ++it) {
0160       const std::string rootName = this->rootName_(*it);
0161       const std::string globalRoot(this->rootName_(globalName));
0162       if (rootName.compare(0, rootName.length(), globalRoot) == 0) {
0163         // Parameter for this level: skip
0164         LogDebug("PropagateParameters") << indent_ << " - skipping PSet " << (*it) << " from global " << globalName
0165                                         << std::endl;
0166       } else if (this->isTopLevel_(*it)) {
0167         // Top-level parameters should not be propagated
0168         LogDebug("PropagateParameters") << indent_ << " - skipping top-level PSet " << (*it) << " global " << globalName
0169                                         << std::endl;
0170 
0171       } else if (!this->possiblyPartOf(*it, globalRoot)) {
0172         // (*it) is a part of the detector that does not fit to globalName
0173         LogDebug("PropagateParameters") << indent_ << " - skipping PSet " << (*it) << " not fitting into global "
0174                                         << globalName << std::endl;
0175 
0176       } else if (alignableObjectId_.stringToId(rootName) == align::invalid) {
0177         // Parameter is not known!
0178         throw cms::Exception("BadConfig") << "Unknown parameter set name " << rootName;
0179       } else {
0180         // Pass down any other: in order to merge PSets, create dummy PSet
0181         // only containing this PSet and merge it recursively.
0182         LogDebug("PropagateParameters") << indent_ << " - adding PSet " << (*it) << " global " << globalName
0183                                         << std::endl;
0184         edm::ParameterSet m_subSet;
0185         m_subSet.addParameter<edm::ParameterSet>((*it), pSet.getParameter<edm::ParameterSet>(*it));
0186         this->mergeParameters_(subSet, m_subSet);
0187       }
0188     }
0189   }
0190 
0191   indent_ = indent_.substr(0, indent_.length() - 1);
0192 }
0193 
0194 //__________________________________________________________________________________________________
0195 // Get parameter set corresponding to given name.
0196 // Return empty parameter set if does not exist.
0197 edm::ParameterSet MisalignmentScenarioBuilder::getParameterSet_(const std::string& name,
0198                                                                 const edm::ParameterSet& pSet) const {
0199   edm::ParameterSet result;
0200 
0201   // Get list of parameter set names and retrieve requested one
0202   std::vector<std::string> parameterSetNames;
0203   if (this->hasParameter_(name, pSet)) {
0204     result = pSet.getParameter<edm::ParameterSet>(name);
0205   }
0206 
0207   return result;
0208 }
0209 
0210 //__________________________________________________________________________________________________
0211 // Get parameter set corresponding to given level name and number.
0212 // Return empty parameter set if does not exist.
0213 edm::ParameterSet MisalignmentScenarioBuilder::getParameterSet_(const std::string& levelName,
0214                                                                 int iComponent,
0215                                                                 const edm::ParameterSet& pSet) const {
0216   edm::ParameterSet result;
0217   unsigned int nFittingPsets = 0;
0218 
0219   // Get list of parameter set names and look for requested one
0220   std::vector<std::string> pNames = pSet.getParameterNames();
0221   for (std::vector<std::string>::iterator iter = pNames.begin(); iter != pNames.end(); ++iter) {
0222     if (iter->find(levelName) != 0)
0223       continue;  // parameter not starting with levelName
0224 
0225     const std::string numberString(*iter, levelName.size());
0226     //    if (numberString.empty() || numberString == "s") { // "s" only left means we have e.g. 'TOBs'
0227     if (numberString.empty()) {  // check on "s" not needed, see below
0228       continue;                  // nothing left in levelName to be iComponent...
0229     }
0230     // now look for numbers (separated by '_', tolerating '__' or ending with '_')
0231     size_t lastPos = 0;
0232     size_t pos = numberString.find_first_of('_', lastPos);
0233     while (std::string::npos != pos || std::string::npos != lastPos) {
0234       const std::string digit(numberString.substr(lastPos, pos - lastPos));
0235 
0236       bool isDigit = !digit.empty();
0237       for (std::string::const_iterator dIt = digit.begin(); dIt != digit.end(); ++dIt) {
0238         if (!isdigit(*dIt))
0239           isDigit = false;  // check all 'letters' to be a digit
0240       }
0241       if (!isDigit) {
0242         if (lastPos != 0) {  // do not throw if e.g. after 'TOB' ('Det') you find only 's' (Unit<n>)
0243           throw cms::Exception("BadConfig")
0244               << "[MisalignmentScenarioBuilder::getParameterSet_] "
0245               << "Expect only numbers, separated by '_' after " << levelName << " in " << *iter << std::endl;
0246         }
0247         break;
0248       }
0249 
0250       if (atoi(digit.c_str()) == iComponent) {
0251         ++nFittingPsets;
0252         LogDebug("getParameterSet_") << indent_ << "found " << *iter << " matching " << levelName << iComponent;
0253         result = pSet.getParameter<edm::ParameterSet>(*iter);
0254         break;
0255       }
0256       lastPos = numberString.find_first_not_of('_', pos);
0257       pos = numberString.find_first_of('_', lastPos);
0258     }
0259   }  // end loop on names of parameters in pSet
0260 
0261   if (nFittingPsets > 1) {
0262     throw cms::Exception("BadConfig") << "[MisalignmentScenarioBuilder::getParameterSet_] "
0263                                       << "Found " << nFittingPsets << " PSet for " << levelName << " " << iComponent
0264                                       << "." << std::endl;
0265   }
0266 
0267   return result;
0268 }
0269 
0270 //__________________________________________________________________________________________________
0271 bool MisalignmentScenarioBuilder::hasParameter_(const std::string& name, const edm::ParameterSet& pSet) const {
0272   // Get list of parameter set names and look for requested one
0273   std::vector<std::string> names = pSet.getParameterNames();
0274 
0275   return (std::find(names.begin(), names.end(), name) != names.end());
0276 }
0277 
0278 //__________________________________________________________________________________________________
0279 // Print parameter set. If showPsets is 'false', do not print PSets
0280 void MisalignmentScenarioBuilder::printParameters_(const edm::ParameterSet& pSet, const bool showPsets) const {
0281   std::vector<std::string> parameterNames = pSet.getParameterNames();
0282   for (std::vector<std::string>::iterator iter = parameterNames.begin(); iter != parameterNames.end(); ++iter) {
0283     if (showPsets || !pSet.existsAs<edm::ParameterSet>(*iter)) {
0284       //       LogTrace("PrintParameters") << indent_ << "   " << (*iter) << " = "
0285       //                  << pSet.retrieve( *iter ).toString() << std::endl;
0286       // From Bill Tannenbaum:
0287       // You can use
0288       //   pset.getParameterAsString(aString).
0289       // This function was added with the new tag.
0290       //   However, there is a possible complication if the parameter in question is
0291       //   itself a ParameterSet or a vector of ParameterSets.  In the new format, a
0292       //   ParameterSet cannot be converted to a string until its ID is calculated,
0293       //   which happens when it is registered.  So, if you get error messages about
0294       //   not being able to convert an unregistered ParameterSet to a string, you can
0295       //   do one of two things:
0296       // A) You can use ParameterSet::dump() to print the parameter set, instead of
0297       //    getParameterAsString().  This does not require registering.  I'm not sure of
0298       //    the exact format of the dump output (Rick wrote this, I think).
0299       // OR
0300       // B) You can use ParameterSet::registerIt() to register the parameter set
0301       //    before calling getParameterAsString().
0302       //
0303       // In either case, you can use existsAs to determine which parameters are
0304       // themselves parameter sets or vectors of parameter sets.
0305       //
0306       // Note that in the new parameter set format, ParameterSet::toString() does not
0307       // write out nested parameter sets by value.  It writes them out by
0308       // "reference", i.e it writes the ID.
0309     }
0310   }
0311 }
0312 
0313 //__________________________________________________________________________________________________
0314 bool MisalignmentScenarioBuilder::isTopLevel_(const std::string& parameterSetName) const {
0315   // Get root name (strip last character[s])
0316   std::string root = this->rootName_(parameterSetName);
0317 
0318   // tracker stuff treated in overwriting TrackerScenarioBuilder::isTopLevel_(..)
0319   if (root == "DTSector")
0320     return true;
0321   else if (root == "CSCSector")
0322     return true;
0323   else if (root == "Muon")
0324     return true;
0325 
0326   return false;
0327 }
0328 
0329 //__________________________________________________________________________________________________
0330 bool MisalignmentScenarioBuilder::possiblyPartOf(const std::string& /*sub*/, const std::string& /*large*/) const {
0331   return true;  // possibly overwrite in specific class
0332 }
0333 
0334 //__________________________________________________________________________________________________
0335 // Get root name of parameter set (e.g. return 'Rod' from 'Rods' or 'Rod1')
0336 const std::string MisalignmentScenarioBuilder::rootName_(const std::string& parameterSetName) const {
0337   std::string result{parameterSetName};  // Initialise to full string
0338 
0339   // Check if string ends with 's'
0340   const auto lastChar = parameterSetName.length() - 1;
0341   if (parameterSetName[lastChar] == 's') {
0342     result = parameterSetName.substr(0, lastChar);
0343   } else {
0344     // Otherwise, look for numbers at the end
0345     // (assumes that numbers at the end are not part of the name)
0346     for (auto ichar = lastChar; ichar != 0; --ichar) {
0347       if (!isdigit(parameterSetName[ichar])) {
0348         result = parameterSetName.substr(0, ichar + 1);
0349         break;  // Stop at first non-digit
0350       }
0351     }
0352   }
0353 
0354   LogDebug("PrintParameters") << "Name was " << parameterSetName << ", root is " << result;
0355 
0356   return result;
0357 }