00001 #include "DataFormats/Provenance/interface/BranchDescription.h"
00002 #include "DataFormats/Provenance/interface/ModuleDescription.h"
00003 #include "FWCore/Utilities/interface/Exception.h"
00004 #include "FWCore/Utilities/interface/FriendlyName.h"
00005 #include "FWCore/Utilities/interface/WrappedClassName.h"
00006 #include <ostream>
00007 #include <sstream>
00008 #include <stdlib.h>
00009
00010
00011
00012
00013
00014
00015 namespace edm {
00016 BranchDescription::Transients::Transients() :
00017 moduleDescriptionID_(),
00018 productIDtoAssign_(),
00019 branchName_(),
00020 wrappedName_(),
00021 produced_(false),
00022 present_(true),
00023 transient_(false),
00024 type_(),
00025 splitLevel_(),
00026 basketSize_() {
00027 }
00028
00029 BranchDescription::BranchDescription() :
00030 branchType_(InEvent),
00031 moduleLabel_(),
00032 processName_(),
00033 branchID_(),
00034 productID_(),
00035 fullClassName_(),
00036 friendlyClassName_(),
00037 productInstanceName_(),
00038 psetIDs_(),
00039 processConfigurationIDs_(),
00040 branchAliases_(),
00041 transients_()
00042 {
00043
00044 }
00045
00046 BranchDescription::BranchDescription(
00047 BranchType const& branchType,
00048 std::string const& mdLabel,
00049 std::string const& procName,
00050 std::string const& name,
00051 std::string const& fName,
00052 std::string const& pin,
00053 ModuleDescription const& modDesc,
00054 std::set<std::string> const& aliases) :
00055 branchType_(branchType),
00056 moduleLabel_(mdLabel),
00057 processName_(procName),
00058 branchID_(),
00059 productID_(),
00060 fullClassName_(name),
00061 friendlyClassName_(fName),
00062 productInstanceName_(pin),
00063 psetIDs_(),
00064 processConfigurationIDs_(),
00065 branchAliases_(aliases),
00066 transients_()
00067 {
00068 present() = true;
00069 produced() = true;
00070 moduleDescriptionID() = modDesc.id();
00071 psetIDs_.insert(modDesc.parameterSetID());
00072 processConfigurationIDs_.insert(modDesc.processConfigurationID());
00073 init();
00074 }
00075
00076
00077
00078 BranchDescription::BranchDescription(
00079 BranchType const& branchType,
00080 std::string const& mdLabel,
00081 std::string const& procName,
00082 std::string const& name,
00083 std::string const& fName,
00084 std::string const& pin,
00085 ModuleDescriptionID const& mdID,
00086 std::set<ParameterSetID> const& psIDs,
00087 std::set<ProcessConfigurationID> const& procConfigIDs,
00088 std::set<std::string> const& aliases) :
00089 branchType_(branchType),
00090 moduleLabel_(mdLabel),
00091 processName_(procName),
00092 branchID_(),
00093 productID_(),
00094 fullClassName_(name),
00095 friendlyClassName_(fName),
00096 productInstanceName_(pin),
00097 psetIDs_(psIDs),
00098 processConfigurationIDs_(procConfigIDs),
00099 branchAliases_(aliases),
00100 transients_()
00101 {
00102 present() = true;
00103 produced() = true;
00104 moduleDescriptionID() = mdID;
00105 init();
00106 }
00107
00108 void
00109 BranchDescription::init() const {
00110 if (!branchName().empty()) {
00111 return;
00112 }
00113 throwIfInvalid_();
00114
00115 char const underscore('_');
00116 char const period('.');
00117
00118 if (friendlyClassName_.find(underscore) != std::string::npos) {
00119 throw cms::Exception("IllegalCharacter") << "Class name '" << friendlyClassName()
00120 << "' contains an underscore ('_'), which is illegal in the name of a product.\n";
00121 }
00122
00123 if (moduleLabel_.find(underscore) != std::string::npos) {
00124 throw cms::Exception("IllegalCharacter") << "Module label '" << moduleLabel()
00125 << "' contains an underscore ('_'), which is illegal in a module label.\n";
00126 }
00127
00128 if (productInstanceName_.find(underscore) != std::string::npos) {
00129 throw cms::Exception("IllegalCharacter") << "Product instance name '" << productInstanceName()
00130 << "' contains an underscore ('_'), which is illegal in a product instance name.\n";
00131 }
00132
00133 if (processName_.find(underscore) != std::string::npos) {
00134 throw cms::Exception("IllegalCharacter") << "Process name '" << processName()
00135 << "' contains an underscore ('_'), which is illegal in a process name.\n";
00136 }
00137
00138 branchName().reserve(friendlyClassName().size() +
00139 moduleLabel().size() +
00140 productInstanceName().size() +
00141 processName().size() + 4);
00142 branchName() += friendlyClassName();
00143 branchName() += underscore;
00144 branchName() += moduleLabel();
00145 branchName() += underscore;
00146 branchName() += productInstanceName();
00147 branchName() += underscore;
00148 branchName() += processName();
00149 branchName() += period;
00150
00151 if (!branchID_.isValid()) {
00152 branchID_.setID(branchName());
00153 }
00154
00155 ROOT::Reflex::Type t = ROOT::Reflex::Type::ByName(fullClassName());
00156 ROOT::Reflex::PropertyList p = t.Properties();
00157 transient() = (p.HasProperty("persistent") ? p.PropertyAsString("persistent") == std::string("false") : false);
00158
00159 wrappedName() = wrappedClassName(fullClassName());
00160 type() = ROOT::Reflex::Type::ByName(wrappedName());
00161 ROOT::Reflex::PropertyList wp = type().Properties();
00162 if (wp.HasProperty("splitLevel")) {
00163 splitLevel() = strtol(wp.PropertyAsString("splitLevel").c_str(), 0, 0);
00164 if (splitLevel() < 0) {
00165 throw cms::Exception("IllegalSplitLevel") << "' An illegal ROOT split level of " <<
00166 splitLevel() << " is specified for class " << wrappedName() << ".'\n";
00167 }
00168 ++splitLevel();
00169 } else {
00170 splitLevel() = invalidSplitLevel;
00171 }
00172 if (wp.HasProperty("basketSize")) {
00173 basketSize() = strtol(wp.PropertyAsString("basketSize").c_str(), 0, 0);
00174 if (basketSize() <= 0) {
00175 throw cms::Exception("IllegalBasketSize") << "' An illegal ROOT basket size of " <<
00176 basketSize() << " is specified for class " << wrappedName() << "'.\n";
00177 }
00178 } else {
00179 basketSize() = invalidBasketSize;
00180 }
00181 }
00182
00183 ParameterSetID const&
00184 BranchDescription::psetID() const {
00185 assert(!psetIDs().empty());
00186 if (psetIDs().size() != 1) {
00187 throw cms::Exception("Ambiguous")
00188 << "Your application requires all events on Branch '" << branchName()
00189 << "'\n to have the same provenance. This file has events with mixed provenance\n"
00190 << "on this branch. Use a different input file.\n";
00191 }
00192 return *psetIDs().begin();
00193 }
00194
00195 void
00196 BranchDescription::merge(BranchDescription const& other) {
00197 psetIDs_.insert(other.psetIDs().begin(), other.psetIDs().end());
00198 processConfigurationIDs_.insert(other.processConfigurationIDs().begin(), other.processConfigurationIDs().end());
00199 branchAliases_.insert(other.branchAliases().begin(), other.branchAliases().end());
00200 present() = present() || other.present();
00201 if (splitLevel() == invalidSplitLevel) splitLevel() = other.splitLevel();
00202 if (basketSize() == invalidBasketSize) basketSize() = other.basketSize();
00203 }
00204
00205 void
00206 BranchDescription::write(std::ostream& os) const {
00207 os << "Branch Type = " << branchType() << std::endl;
00208 os << "Process Name = " << processName() << std::endl;
00209 os << "ModuleLabel = " << moduleLabel() << std::endl;
00210 os << "Branch ID = " << branchID() << '\n';
00211 os << "Class Name = " << fullClassName() << '\n';
00212 os << "Friendly Class Name = " << friendlyClassName() << '\n';
00213 os << "Product Instance Name = " << productInstanceName() << std::endl;
00214 }
00215
00216 void throwExceptionWithText(const char* txt)
00217 {
00218 edm::Exception e(edm::errors::LogicError);
00219 e << "Problem using an incomplete BranchDescription\n"
00220 << txt
00221 << "\nPlease report this error to the FWCore developers";
00222 throw e;
00223 }
00224
00225 void
00226 BranchDescription::throwIfInvalid_() const
00227 {
00228 if (branchType_ >= edm::NumBranchTypes)
00229 throwExceptionWithText("Illegal BranchType detected");
00230
00231 if (moduleLabel_.empty())
00232 throwExceptionWithText("Module label is not allowed to be empty");
00233
00234 if (processName_.empty())
00235 throwExceptionWithText("Process name is not allowed to be empty");
00236
00237 if (fullClassName_.empty())
00238 throwExceptionWithText("Full class name is not allowed to be empty");
00239
00240 if (friendlyClassName_.empty())
00241 throwExceptionWithText("Friendly class name is not allowed to be empty");
00242
00243 if (produced() && !moduleDescriptionID().isValid())
00244 throwExceptionWithText("Invalid ModuleDescriptionID detected");
00245 }
00246
00247 void
00248 BranchDescription::updateFriendlyClassName() {
00249 friendlyClassName_ = friendlyname::friendlyName(fullClassName());
00250 }
00251
00252 bool
00253 operator<(BranchDescription const& a, BranchDescription const& b) {
00254 if (a.processName() < b.processName()) return true;
00255 if (b.processName() < a.processName()) return false;
00256 if (a.fullClassName() < b.fullClassName()) return true;
00257 if (b.fullClassName() < a.fullClassName()) return false;
00258 if (a.friendlyClassName() < b.friendlyClassName()) return true;
00259 if (b.friendlyClassName() < a.friendlyClassName()) return false;
00260 if (a.productInstanceName() < b.productInstanceName()) return true;
00261 if (b.productInstanceName() < a.productInstanceName()) return false;
00262 if (a.moduleLabel() < b.moduleLabel()) return true;
00263 if (b.moduleLabel() < a.moduleLabel()) return false;
00264 if (a.branchType() < b.branchType()) return true;
00265 if (b.branchType() < a.branchType()) return false;
00266 if (a.branchID() < b.branchID()) return true;
00267 if (b.branchID() < a.branchID()) return false;
00268 if (a.psetIDs() < b.psetIDs()) return true;
00269 if (b.psetIDs() < a.psetIDs()) return false;
00270 if (a.processConfigurationIDs() < b.processConfigurationIDs()) return true;
00271 if (b.processConfigurationIDs() < a.processConfigurationIDs()) return false;
00272 if (a.branchAliases() < b.branchAliases()) return true;
00273 if (b.branchAliases() < a.branchAliases()) return false;
00274 if (a.present() < b.present()) return true;
00275 if (b.present() < a.present()) return false;
00276 return false;
00277 }
00278
00279 bool
00280 combinable(BranchDescription const& a, BranchDescription const& b) {
00281 return
00282 (a.branchType() == b.branchType()) &&
00283 (a.processName() == b.processName()) &&
00284 (a.fullClassName() == b.fullClassName()) &&
00285 (a.friendlyClassName() == b.friendlyClassName()) &&
00286 (a.productInstanceName() == b.productInstanceName()) &&
00287 (a.moduleLabel() == b.moduleLabel()) &&
00288 (a.branchID() == b.branchID());
00289 }
00290
00291 bool
00292 operator==(BranchDescription const& a, BranchDescription const& b) {
00293 return combinable(a, b) &&
00294 (a.present() == b.present()) &&
00295 (a.psetIDs() == b.psetIDs()) &&
00296 (a.processConfigurationIDs() == b.processConfigurationIDs()) &&
00297 (a.branchAliases() == b.branchAliases());
00298 }
00299
00300 std::string
00301 match(BranchDescription const& a, BranchDescription const& b,
00302 std::string const& fileName,
00303 BranchDescription::MatchMode m) {
00304 std::ostringstream differences;
00305 if (a.branchName() != b.branchName()) {
00306 differences << "Branch name '" << b.branchName() << "' does not match '" << a.branchName() << "'.\n";
00307
00308
00309
00310
00311
00312 }
00313 if (a.branchType() != b.branchType()) {
00314 differences << "Branch '" << b.branchName() << "' is a(n) '" << b.branchType() << "' branch\n";
00315 differences << " in file '" << fileName << "', but a(n) '" << a.branchType() << "' branch in previous files.\n";
00316 }
00317 if (a.branchID() != b.branchID()) {
00318 differences << "Branch '" << b.branchName() << "' has a branch ID of '" << b.branchID() << "'\n";
00319 differences << " in file '" << fileName << "', but '" << a.branchID() << "' in previous files.\n";
00320 }
00321 if (a.fullClassName() != b.fullClassName()) {
00322 differences << "Products on branch '" << b.branchName() << "' have type '" << b.fullClassName() << "'\n";
00323 differences << " in file '" << fileName << "', but '" << a.fullClassName() << "' in previous files.\n";
00324 }
00325 if (b.present() && !a.present()) {
00326 differences << "Branch '" << a.branchName() << "' was dropped in previous files but is present in '" << fileName << "'.\n";
00327 }
00328 if (m == BranchDescription::Strict) {
00329 if (b.psetIDs().size() > 1) {
00330 differences << "Branch '" << b.branchName() << "' uses more than one parameter set in file '" << fileName << "'.\n";
00331 } else if (a.psetIDs().size() > 1) {
00332 differences << "Branch '" << a.branchName() << "' uses more than one parameter set in previous files.\n";
00333 } else if (a.psetIDs() != b.psetIDs()) {
00334 differences << "Branch '" << b.branchName() << "' uses different parameter sets in file '" << fileName << "'.\n";
00335 differences << " than in previous files.\n";
00336 }
00337
00338 if (b.processConfigurationIDs().size() > 1) {
00339 differences << "Branch '" << b.branchName() << "' uses more than one process configuration in file '" << fileName << "'.\n";
00340 } else if (a.processConfigurationIDs().size() > 1) {
00341 differences << "Branch '" << a.branchName() << "' uses more than one process configuration in previous files.\n";
00342 } else if (a.processConfigurationIDs() != b.processConfigurationIDs()) {
00343 differences << "Branch '" << b.branchName() << "' uses different process configurations in file '" << fileName << "'.\n";
00344 differences << " than in previous files.\n";
00345 }
00346 }
00347 return differences.str();
00348 }
00349 }