Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 10:51:38

0001 #include "DetectorDescription/Core/interface/DDLogicalPart.h"
0002 
0003 #include <ostream>
0004 
0005 #include "DetectorDescription/Core/interface/DDMaterial.h"
0006 #include "DetectorDescription/Core/interface/DDSolid.h"
0007 #include "DetectorDescription/Core/interface/LogicalPart.h"
0008 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0009 
0010 class DDValue;
0011 
0012 void DD_NC(const DDName& n) {
0013   auto& ns = LPNAMES::instance()[n.name()];
0014 
0015   bool alreadyIn(false);
0016   for (const auto& p : ns) {
0017     if (p.ns() == n.ns()) {
0018       alreadyIn = true;
0019       break;
0020     }
0021   }
0022   if (!alreadyIn) {
0023     ns.emplace_back(n);
0024   }
0025 }
0026 
0027 std::ostream& operator<<(std::ostream& os, const DDLogicalPart& part) {
0028   DDBase<DDName, DDI::LogicalPart*>::def_type defined(part.isDefined());
0029   if (defined.first) {
0030     os << *(defined.first) << " ";
0031     if (defined.second) {
0032       part.rep().stream(os);
0033     } else {
0034       os << "* logicalpart not defined * ";
0035     }
0036   } else {
0037     os << "* logicalpart not declared * ";
0038   }
0039   return os;
0040 }
0041 
0042 // =================================================================================
0043 
0044 /** 
0045    In order to use an uninitialized reference object one has to assign
0046    to it an initialized object of the same class.
0047       
0048    Example: 
0049    \code 
0050       DDLogicalPart world;  // uninitialized (anonymous) reference object
0051       world = DDLogicalPart(DDName("CMS","cms.xml"));  
0052       // now world refers to an initialized object, which in turn is not
0053       // necessarily defined yet.
0054    \endcode
0055 */
0056 // now inlined...
0057 
0058 /** One has to distinguish two cases:
0059   
0060       \par The object which should be referred to has already been defined ...
0061        ... using the constructor:
0062        \code DDLogicalPart(const DDName &, const DDMaterial, 
0063        const DDSolid, bool sens)\endcode
0064        This will be the case for example after XML has been parsed. The XML parser calls the constructor 
0065        described below and thus registers a new object using DDName to identify it uniquely. The 
0066        using this constructor one fetches the reference object. Assigning to this reference object
0067        invalidates the object being refered before (and redirects all reference objects using the same value
0068        of their DDName already in use to the newly assigned reference object).
0069       \par The object which should be referred to has not yet been defined 
0070        In this case this constructor registeres a valid object. But this object is not
0071        yet defined (i.e. no material nor a solid has been attached to it). Nevertheless
0072        the reference object can be used (copied ...) everywhere. If, at a later stage,
0073        a defined reference object with the same DDName is created, all already existing reference objects
0074        become references to this newly created reference object (one definition rule).
0075        
0076        Example:
0077        
0078        \code 
0079        ... // code for DDMaterial (material) definition and DDSolid (solid) defintion goes here
0080        DDName detName("Detector","logparts"); // define a unique  name
0081        DDLogicalPart detDeclaration(detName); // detName-corresponding object not defined yet!
0082        std::vector<DDLogicalPart> vec; 
0083        vec.emplace_back(det);  // use reference object in a std::vector
0084        // now define ad detName-corresponding object (it will be internally registered) 
0085        DDLogicalPart detDefinition(detName, material, solid, false); 
0086        // now also vec[0] automatically becomes a reference to detDefinition!
0087        // both got  
0088        \endcode 
0089 */
0090 DDLogicalPart::DDLogicalPart(const DDName& name) : DDBase<DDName, std::unique_ptr<DDI::LogicalPart> >() {
0091   create(name);
0092   DD_NC(name);
0093 }
0094 
0095 /** 
0096    An object representing a logicalpart uniquely identified by its DDName \a name
0097    will be created. If reference objects of the same \a name already exist, they
0098    will refere to the newly created object. DDMaterial \a material and DDSolid \a solid
0099    are themselves reference objects to a material and solid specification. The need
0100    not be defined yet as long as they were constructed using unique DDName-objects.
0101       
0102    This constructor is intended to be called by the \b XML \b parsing software, not
0103    by the DDD user. It decouples the input technologies (i.e. XML) and forms the transition
0104    to the runtime DDD representation.
0105    However, it could also be used for 'programming' a detector description.
0106 */
0107 DDLogicalPart::DDLogicalPart(const DDName& ddname,
0108                              const DDMaterial& material,
0109                              const DDSolid& solid,
0110                              DDEnums::Category cat)
0111     : DDBase<DDName, std::unique_ptr<DDI::LogicalPart> >() {
0112   create(ddname, std::make_unique<DDI::LogicalPart>(material, solid, cat));
0113   DD_NC(ddname);
0114 }
0115 
0116 DDEnums::Category DDLogicalPart::category() const { return rep().category(); }
0117 
0118 const DDMaterial& DDLogicalPart::material() const { return rep().material(); }
0119 
0120 const DDSolid& DDLogicalPart::solid() const { return rep().solid(); }
0121 
0122 /**
0123  The method will only return specific data attached to a DDLogicalPart. 
0124  If DDL-XML is used to define specific data, the path-attribute of <PartSelector> addressing only
0125  LogicalParts only consists of a "//" and the name of the LogicalPart (or a regexp for the name):
0126  \code
0127    <SpecPar name="Color">
0128     <PartSelector path="//BarrelDetector"/>
0129     <PartSelector path="//ForwardSector1.*Cable."/>
0130     <Parameter name="rgb" value="0.5"/>
0131     <Parameter name="rgb" value="0.1+0.2"/>
0132     <Parameter name="rgb" value="[colors:blue1]/>
0133     <Parameter name="visible" value="true"/>
0134    </SpecPar>
0135  \endcode 
0136  The above XML assigns specific data to a DDLogicalPart with name "BarrelDetector" and to all
0137  DDLogicalParts whose names match the regexp "ForwardSector1.*Cable.", e.g. "ForwardSector123abCable7"
0138  Two parameters are attached as specific data: "rgb" - a std::vector of three values, and 
0139  "visible" - a std::vector of one value.
0140  
0141  The method DDLogicalPart::specifics() now returns a std::vector<const DDsvalues_type *> V which
0142  correspond to these two values. Every entry in V comes from a different <SpecPar> tag.
0143  In our example above, V would have size 1, e.g. V.size() == 1.
0144  
0145  A <Paramter> is std::mapped to DDValue. 'value' of <Parameter> is kept as a std::string and as a double.
0146  If the std::string does not evaluate correctly to double, 0 is the assigned.
0147  
0148  Here's the code to retrieve the 'rgb' Parameter:
0149  \code
0150    void someFunc(DDLogicalPart aLp) {
0151 
0152      // want to know, whether the specific parameter 'Color' is attached to aLp
0153 
0154      // each <SpecPar> for this LogicalPart will create one entry in the result_type std::vector
0155      // each entry in the result_type std::vector contains all Paramters defined in one SpecPar-tag
0156      // We assume now, that we have only one SpecPar ...
0157      typedef std::vector<const DDsvalues_type *> result_type;
0158      result_type result = aLp.specifics();
0159      if (result.size()==1) {
0160        DDValue val("Color");
0161        bool foundIt=false;
0162        foundIt = DDfetch(result[0],val) // DDfetch is a utility function to retrieve values from a DDsvalues_type*
0163       if (foundIt) { // val contains the result
0164         const std::vector<std::string> & strVec = val.std::string();
0165        // strVec[0] == "0.5"
0166        // strVec[1] == "0.1+0.2"
0167        const std::vector<double> & dblVec = val.doubles(); 
0168        // dblVec[0] == double value of Constant 'red' 0.5
0169 ... 
0170       // do something here ...
0171      }
0172    } 
0173  \endcode
0174 */
0175 std::vector<const DDsvalues_type*> DDLogicalPart::specifics() const {
0176   std::vector<const DDsvalues_type*> result;
0177   rep().specificsV(result);
0178   return result;
0179 }
0180 
0181 DDsvalues_type DDLogicalPart::mergedSpecifics() const {
0182   DDsvalues_type result;
0183   rep().mergedSpecificsV(result);
0184   return result;
0185 }
0186 
0187 // for internal use only
0188 void DDLogicalPart::addSpecifics(const std::pair<const DDPartSelection*, const DDsvalues_type*>& s) {
0189   rep().addSpecifics(s);
0190 }
0191 
0192 void DDLogicalPart::removeSpecifics(const std::pair<DDPartSelection*, DDsvalues_type*>& s) { rep().removeSpecifics(s); }
0193 
0194 bool DDLogicalPart::hasDDValue(const DDValue& v) const { return rep().hasDDValue(v); }
0195 
0196 // finds out whether a DDLogicalPart is registered & already valid (initialized)
0197 // - returns (true,""), if so; result holds the corresponding DDLogicalPart
0198 // - returns (false,"some status message") otherwise
0199 // - nm corresponds to a regular expression, but will be anchored ( ^regexp$ )
0200 // - ns corresponds to a regular expression, but will be anchored ( ^regexp$ )
0201 #include <regex.h>
0202 #include <cstddef>
0203 
0204 namespace {
0205   struct Regex {
0206     explicit Regex(const std::string& s) : m_ok(false), me(s) {
0207       size_t p = me.find('.');
0208       m_ok = p != std::string::npos;
0209       if (m_ok) {
0210         if (p > 0) {
0211           m_range.first = me.substr(0, p);
0212           m_range.second = m_range.first + "{";  // '{' is 'z'+1
0213         }
0214         me = "^" + me + "$";
0215         regcomp(&m_regex, me.c_str(), 0);
0216       }
0217     }
0218 
0219     ~Regex(void) {
0220       if (m_ok)
0221         regfree(&m_regex);
0222     }
0223 
0224     bool empty(void) const { return me.empty(); }
0225 
0226     bool notRegex(void) const { return !m_ok; }
0227 
0228     const std::string& value(void) const { return me; }
0229 
0230     bool match(const std::string& s) const {
0231       if (m_ok)
0232         return !regexec(&m_regex, s.c_str(), 0, nullptr, 0);
0233       else
0234         return me == s;
0235     }
0236 
0237     const std::pair<std::string, std::string>& range(void) const { return m_range; }
0238 
0239   private:
0240     bool m_ok;
0241     regex_t m_regex;
0242     std::string me;
0243     // range of me in a collating sequence
0244     std::pair<std::string, std::string> m_range;
0245   };
0246 }  // namespace
0247 
0248 std::pair<bool, std::string> DDIsValid(const std::string& ns,
0249                                        const std::string& nm,
0250                                        std::vector<DDLogicalPart>& result,
0251                                        bool doRegex) {
0252   if (!doRegex) {
0253     DDName ddnm(nm, ns);
0254     result.emplace_back(DDLogicalPart(ddnm));
0255     return std::make_pair(true, "");
0256   }
0257   std::string status;
0258   Regex aRegex(nm);
0259   Regex aNsRegex(ns);
0260   bool emptyNs = aNsRegex.empty();
0261 
0262   // THIS IS THE SLOW PART: I have to compare every namespace & name of every
0263   // logical part with a regex-comparison .... a linear search always through the
0264   // full range of logical parts!!!!
0265   /*
0266     Algorithm description:
0267     x. empty nm and ns argument of method means: use all matching regex ^.*$
0268     a. iterate over all logical part names, match against regex for names
0269     b. iterate over all namespaces of names found in a & match against regex for namespaces   
0270   */
0271   LPNAMES::value_type::const_iterator bn(LPNAMES::instance().begin()), ed(LPNAMES::instance().end());
0272   typedef std::vector<LPNAMES::value_type::const_iterator> Candidates;
0273   Candidates candidates;
0274   if (aRegex.notRegex()) {
0275     LPNAMES::value_type::const_iterator it = LPNAMES::instance().find(aRegex.value());
0276     if (it != ed)
0277       candidates.emplace_back(it);
0278   } else {
0279     if (!aRegex.range().first.empty()) {
0280       bn = LPNAMES::instance().lower_bound(aRegex.range().first);
0281       ed = LPNAMES::instance().upper_bound(aRegex.range().second);
0282     }
0283     for (LPNAMES::value_type::const_iterator it = bn; it != ed; ++it)
0284       if (aRegex.match(it->first))
0285         candidates.emplace_back(it);
0286   }
0287   for (const auto& it : candidates) {
0288     //if (doit)  edm::LogInfo("DDLogicalPart") << "rgx: " << aName << ' ' << it->first << ' ' << doit << std::endl;
0289     std::vector<DDName>::size_type sz = it->second.size();  // no of 'compatible' namespaces
0290     if (emptyNs && (sz == 1)) {                             // accept all logical parts in all the namespaces
0291       result.emplace_back(it->second[0]);
0292       //std::vector<DDName>::const_iterator nsIt(it->second.begin()), nsEd(it->second.end());
0293       //for(; nsIt != nsEd; ++nsIt) {
0294       //   result.emplace_back(DDLogicalPart(*nsIt));
0295       //   edm::LogInfo("DDLogicalPart") << "DDD-WARNING: multiple namespaces match (in SpecPars PartSelector): " << *nsIt << std::endl;
0296       //}
0297     } else if (!emptyNs) {  // only accept matching namespaces
0298       std::vector<DDName>::const_iterator nsit(it->second.begin()), nsed(it->second.end());
0299       for (; nsit != nsed; ++nsit) {
0300         //edm::LogInfo("DDLogicalPart") << "comparing " << aNs << " with " << *nsit << std::endl;
0301         bool another_doit = aNsRegex.match(nsit->ns());
0302         if (another_doit) {
0303           //temp.emplace_back(std::make_pair(it->first,*nsit));
0304           result.emplace_back(DDLogicalPart(*nsit));
0305         }
0306       }
0307     } else {  // emtpyNs and sz>1 -> error, too ambigous
0308       std::string message = "DDLogicalPart-name \"" + it->first + "\" matching regex \"" + nm +
0309                             "\" has been found at least in following namespaces:\n";
0310       std::vector<DDName>::const_iterator vit = it->second.begin();
0311       for (; vit != it->second.end(); ++vit) {
0312         message += vit->ns();
0313         message += " ";
0314       }
0315       message += "\nQualify the name with a regexp for the namespace, i.e \".*:name-regexp\" !";
0316       return std::make_pair(false, message);
0317     }
0318   }
0319   bool flag = true;
0320   std::string message;
0321 
0322   // check whether the found logical-parts are also defined (i.e. have material, solid ...)
0323   if (!result.empty()) {
0324     std::vector<DDLogicalPart>::const_iterator lpit(result.begin()), lped(result.end());
0325     for (; lpit != lped; ++lpit) {
0326       // std::cout << "VI- " << std::string(lpit->name()) << std::endl;
0327       if (!lpit->isDefined().second) {
0328         message = message + "LogicalPart " + lpit->name().fullname() + " not (yet) defined!\n";
0329         flag = false;
0330       }
0331     }
0332   } else {
0333     flag = false;
0334     message = "No regex-match for namespace=" + ns + "  name=" + nm + "\n";
0335   }
0336 
0337   return std::make_pair(flag, message);
0338 }
0339 
0340 const std::vector<std::pair<const DDPartSelection*, const DDsvalues_type*> >& DDLogicalPart::attachedSpecifics(
0341     void) const {
0342   return rep().attachedSpecifics();
0343 }