00001 #include <algorithm>
00002 #include <iomanip>
00003 #include <iostream>
00004 #include <sstream>
00005 #include <fstream>
00006 #include <cstring>
00007 #include <string>
00008 #include <vector>
00009
00010 #include <boost/bind.hpp>
00011
00012 #include <xercesc/sax2/Attributes.hpp>
00013 #include <xercesc/dom/DOM.hpp>
00014
00015 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00016 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00017 #include "FWCore/Utilities/interface/Exception.h"
00018 #include "FWCore/Utilities/interface/TimeOfDay.h"
00019
00020 #include "GeneratorInterface/LHEInterface/interface/LHEReader.h"
00021 #include "GeneratorInterface/LHEInterface/interface/LHERunInfo.h"
00022 #include "GeneratorInterface/LHEInterface/interface/LHEEvent.h"
00023
00024 #include "Utilities/StorageFactory/interface/IOTypes.h"
00025 #include "Utilities/StorageFactory/interface/Storage.h"
00026 #include "Utilities/StorageFactory/interface/StorageFactory.h"
00027
00028 #include "XMLUtils.h"
00029
00030 XERCES_CPP_NAMESPACE_USE
00031
00032 namespace lhef {
00033
00034 static void logFileAction(char const* msg, std::string const& fileName) {
00035 edm::LogAbsolute("fileAction") << std::setprecision(0) << edm::TimeOfDay() << msg << fileName;
00036 edm::FlushMessageLog();
00037 }
00038
00039
00040 class LHEReader::Source {
00041 public:
00042 Source() {}
00043 virtual ~Source() {}
00044 virtual XMLDocument *createReader(XMLDocument::Handler &handler) = 0;
00045 };
00046
00047 class LHEReader::FileSource : public LHEReader::Source {
00048 public:
00049 FileSource(const std::string &fileURL)
00050 {
00051 Storage *storage =
00052 StorageFactory::get()->open(fileURL,
00053 IOFlags::OpenRead);
00054
00055 if (!storage)
00056 throw cms::Exception("FileOpenError")
00057 << "Could not open LHE file \""
00058 << fileURL << "\" for reading"
00059 << std::endl;
00060
00061 fileStream.reset(new StorageWrap(storage));
00062 }
00063
00064 ~FileSource() {}
00065
00066 XMLDocument *createReader(XMLDocument::Handler &handler)
00067 { return new XMLDocument(fileStream, handler); }
00068
00069 private:
00070 std::auto_ptr<StorageWrap> fileStream;
00071 };
00072
00073 class LHEReader::StringSource : public LHEReader::Source {
00074 public:
00075 StringSource(const std::string &inputs)
00076 {
00077 if (inputs == "")
00078 throw cms::Exception("StreamOpenError")
00079 << "Empty LHE file string name \""
00080 << std::endl;
00081
00082 std::stringstream * tmpis = new std::stringstream(inputs);
00083 fileStream.reset(tmpis);
00084 }
00085
00086 ~StringSource() {}
00087
00088 XMLDocument *createReader(XMLDocument::Handler &handler)
00089 { return new XMLDocument(fileStream, handler); }
00090
00091 private:
00092 std::auto_ptr<std::istream> fileStream;
00093 };
00094
00095 class LHEReader::XMLHandler : public XMLDocument::Handler {
00096 public:
00097 XMLHandler() :
00098 impl(0), gotObject(kNone), mode(kNone),
00099 xmlHeader(0), headerOk(false) {}
00100 ~XMLHandler()
00101 { if (xmlHeader) xmlHeader->release(); }
00102
00103 enum Object {
00104 kNone = 0,
00105 kHeader,
00106 kInit,
00107 kComment,
00108 kEvent
00109 };
00110
00111 void reset() { headerOk = false; }
00112
00113 protected:
00114 void startElement(const XMLCh *const uri,
00115 const XMLCh *const localname,
00116 const XMLCh *const qname,
00117 const Attributes &attributes);
00118
00119 void endElement(const XMLCh *const uri,
00120 const XMLCh *const localname,
00121 const XMLCh *const qname);
00122
00123 void characters(const XMLCh *const data, const unsigned int length);
00124 void comment(const XMLCh *const data, const unsigned int length);
00125
00126 private:
00127 friend class LHEReader;
00128
00129 DOMImplementation *impl;
00130 std::string buffer;
00131 Object gotObject;
00132 Object mode;
00133 DOMDocument *xmlHeader;
00134 std::vector<DOMElement*> xmlNodes;
00135 bool headerOk;
00136 std::vector<LHERunInfo::Header> headers;
00137 };
00138
00139 static void attributesToDom(DOMElement *dom, const Attributes &attributes)
00140 {
00141 for(unsigned int i = 0; i < attributes.getLength(); i++) {
00142 const XMLCh *name = attributes.getQName(i);
00143 const XMLCh *value = attributes.getValue(i);
00144
00145 dom->setAttribute(name, value);
00146 }
00147 }
00148
00149 static void fillHeader(LHERunInfo::Header &header, const char *data,
00150 int len = -1)
00151 {
00152 const char *end = len >= 0 ? (data + len) : 0;
00153 while(*data && (!end || data < end)) {
00154 std::size_t len = std::strcspn(data, "\r\n");
00155 if (end && data + len > end)
00156 len = end - data;
00157 if (data[len] == '\r' && data[len + 1] == '\n')
00158 len += 2;
00159 else if (data[len])
00160 len++;
00161 header.addLine(std::string(data, len));
00162 data += len;
00163 }
00164 }
00165
00166 void LHEReader::XMLHandler::startElement(const XMLCh *const uri,
00167 const XMLCh *const localname,
00168 const XMLCh *const qname,
00169 const Attributes &attributes)
00170 {
00171 std::string name((const char*)XMLSimpleStr(qname));
00172
00173 if (!headerOk) {
00174 if (name != "LesHouchesEvents")
00175 throw cms::Exception("InvalidFormat")
00176 << "LHE file has invalid header" << std::endl;
00177 headerOk = true;
00178 return;
00179 }
00180
00181 if (mode == kHeader) {
00182 DOMElement *elem = xmlHeader->createElement(qname);
00183 attributesToDom(elem, attributes);
00184 xmlNodes.back()->appendChild(elem);
00185 xmlNodes.push_back(elem);
00186 return;
00187 } else if (mode != kNone)
00188 throw cms::Exception("InvalidFormat")
00189 << "LHE file has invalid format" << std::endl;
00190
00191 if (name == "header") {
00192 if (!impl)
00193 impl = DOMImplementationRegistry::getDOMImplementation(
00194 XMLUniStr("Core"));
00195 xmlHeader = impl->createDocument(0, qname, 0);
00196 xmlNodes.resize(1);
00197 xmlNodes[0] = xmlHeader->getDocumentElement();
00198 mode = kHeader;
00199 } if (name == "init")
00200 mode = kInit;
00201 else if (name == "event")
00202 mode = kEvent;
00203
00204 if (mode == kNone)
00205 throw cms::Exception("InvalidFormat")
00206 << "LHE file has invalid format" << std::endl;
00207
00208 buffer.clear();
00209 }
00210
00211 void LHEReader::XMLHandler::endElement(const XMLCh *const uri,
00212 const XMLCh *const localname,
00213 const XMLCh *const qname)
00214 {
00215 if (mode) {
00216 if (mode == kHeader && xmlNodes.size() > 1) {
00217 xmlNodes.resize(xmlNodes.size() - 1);
00218 return;
00219 } else if (mode == kHeader) {
00220 std::auto_ptr<DOMWriter> writer(
00221 static_cast<DOMImplementationLS*>(
00222 impl)->createDOMWriter());
00223 writer->setEncoding(XMLUniStr("UTF-8"));
00224
00225 for(DOMNode *node = xmlNodes[0]->getFirstChild();
00226 node; node = node->getNextSibling()) {
00227 XMLSimpleStr buffer(
00228 writer->writeToString(*node));
00229
00230 std::string type;
00231 const char *p, *q;
00232 DOMElement *elem;
00233
00234 switch(node->getNodeType()) {
00235 case DOMNode::ELEMENT_NODE:
00236 elem = static_cast<DOMElement*>(node);
00237 type = (const char*)XMLSimpleStr(
00238 elem->getTagName());
00239 p = std::strchr((const char*)buffer,
00240 '>') + 1;
00241 q = std::strrchr(p, '<');
00242 break;
00243 case DOMNode::COMMENT_NODE:
00244 type = "";
00245 p = buffer + 4;
00246 q = buffer + strlen(buffer) - 3;
00247 break;
00248 default:
00249 type = "<>";
00250 p = buffer +
00251 std::strspn(buffer, " \t\r\n");
00252 if (!*p)
00253 continue;
00254 q = p + strlen(p);
00255 }
00256
00257 LHERunInfo::Header header(type);
00258 fillHeader(header, p, q - p);
00259 headers.push_back(header);
00260 }
00261
00262 xmlHeader->release();
00263 xmlHeader = 0;
00264 }
00265
00266 if (gotObject != kNone)
00267 throw cms::Exception("InvalidState")
00268 << "Unexpected pileup in"
00269 " LHEReader::XMLHandler::endElement"
00270 << std::endl;
00271
00272 gotObject = mode;
00273 mode = kNone;
00274 }
00275 }
00276
00277 void LHEReader::XMLHandler::characters(const XMLCh *const data_,
00278 const unsigned int length)
00279 {
00280 if (mode == kHeader) {
00281 DOMText *text = xmlHeader->createTextNode(data_);
00282 xmlNodes.back()->appendChild(text);
00283 return;
00284 }
00285
00286 if (XMLSimpleStr::isAllSpaces(data_, length))
00287 return;
00288
00289 unsigned int offset = 0;
00290 while(offset < length && XMLSimpleStr::isSpace(data_[offset]))
00291 offset++;
00292
00293 XMLSimpleStr data(data_ + offset);
00294
00295 if (mode == kNone)
00296 throw cms::Exception("InvalidFormat")
00297 << "LHE file has invalid format" << std::endl;
00298
00299 buffer.append(data);
00300 }
00301
00302 void LHEReader::XMLHandler::comment(const XMLCh *const data_,
00303 const unsigned int length)
00304 {
00305 if (mode == kHeader) {
00306 DOMComment *comment = xmlHeader->createComment(data_);
00307 xmlNodes.back()->appendChild(comment);
00308 return;
00309 }
00310
00311 XMLSimpleStr data(data_);
00312
00313 LHERunInfo::Header header;
00314 fillHeader(header, data);
00315 headers.push_back(header);
00316 }
00317
00318 LHEReader::LHEReader(const edm::ParameterSet ¶ms) :
00319 fileURLs(params.getUntrackedParameter< std::vector<std::string> >("fileNames")),
00320 strName(""),
00321 firstEvent(params.getUntrackedParameter<unsigned int>("skipEvents", 0)),
00322 maxEvents(params.getUntrackedParameter<int>("limitEvents", -1)),
00323 curIndex(0), handler(new XMLHandler())
00324 {
00325 }
00326
00327 LHEReader::LHEReader(const std::vector<std::string> &fileNames,
00328 unsigned int firstEvent) :
00329 fileURLs(fileNames), strName(""), firstEvent(firstEvent), maxEvents(-1),
00330 curIndex(0), handler(new XMLHandler())
00331 {
00332 }
00333
00334 LHEReader::LHEReader(const std::string &inputs,
00335 unsigned int firstEvent) :
00336 strName(inputs), firstEvent(firstEvent), maxEvents(-1),
00337 curIndex(0), handler(new XMLHandler())
00338 {
00339 }
00340
00341 LHEReader::~LHEReader()
00342 {
00343 }
00344
00345 boost::shared_ptr<LHEEvent> LHEReader::next()
00346 {
00347
00348 while(curDoc.get() || curIndex < fileURLs.size() || (fileURLs.size() == 0 && strName != "" ) ) {
00349 if (!curDoc.get()) {
00350 if ( fileURLs.size() > 0 ) {
00351 logFileAction(" Initiating request to open LHE file ", fileURLs[curIndex]);
00352 curSource.reset(new FileSource(fileURLs[curIndex]));
00353 logFileAction(" Successfully opened LHE file ", fileURLs[curIndex]);
00354 ++curIndex;
00355 } else if ( strName != "" ) {
00356 curSource.reset(new StringSource(strName));
00357 }
00358 handler->reset();
00359 curDoc.reset(curSource->createReader(*handler));
00360 curRunInfo.reset();
00361 }
00362
00363 XMLHandler::Object event = handler->gotObject;
00364 handler->gotObject = XMLHandler::kNone;
00365
00366 std::istringstream data;
00367 if (event != XMLHandler::kNone) {
00368 data.str(handler->buffer);
00369 handler->buffer.clear();
00370 }
00371
00372 switch(event) {
00373 case XMLHandler::kNone:
00374 if (!curDoc->parse()) {
00375 curDoc.reset();
00376 logFileAction(" Closed LHE file ", fileURLs[curIndex - 1]);
00377 }
00378 break;
00379
00380 case XMLHandler::kHeader:
00381 break;
00382
00383 case XMLHandler::kInit:
00384 curRunInfo.reset(new LHERunInfo(data));
00385
00386 std::for_each(handler->headers.begin(),
00387 handler->headers.end(),
00388 boost::bind(&LHERunInfo::addHeader,
00389 curRunInfo.get(), _1));
00390 handler->headers.clear();
00391 break;
00392
00393 case XMLHandler::kComment:
00394 break;
00395
00396 case XMLHandler::kEvent:
00397 if (!curRunInfo.get())
00398 throw cms::Exception("InvalidState")
00399 << "Got LHE event without"
00400 " initialization." << std::endl;
00401
00402 if (firstEvent > 0) {
00403 firstEvent--;
00404 continue;
00405 }
00406
00407 if (maxEvents == 0)
00408 return boost::shared_ptr<LHEEvent>();
00409 else if (maxEvents > 0)
00410 maxEvents--;
00411
00412 return boost::shared_ptr<LHEEvent>(
00413 new LHEEvent(curRunInfo, data));
00414 }
00415 }
00416
00417 return boost::shared_ptr<LHEEvent>();
00418 }
00419
00420 }
00421