diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,75 +1,76 @@ Makefile$ Makefile\.in$ \.deps$ \.libs$ \.l[ao]$ \.so$ \.so\. \.o$ ~$ \.orig$ ^include/.done-all-links$ ^lib/.done-all-links$ ^src/.*\.(run|tex|out|log|rpo|spc|top|dump|dot|aux|pdf|ps|png|svg|hepmc)$ ^src/.done-all-links$ +^src/thepeg-config$ ^autom4te.cache$ ^config.thepeg$ ^config.log$ ^config.status$ ^configure$ ^Config/config.h$ ^Config/config.h.in$ ^Config/config.sub$ ^Config/depcomp$ ^Config/install-sh$ ^Config/compile$ ^Config/missing$ ^Config/stamp-h.$ ^Config/ar-lib$ ^Config/config.guess$ ^Config/test-driver$ ^Doc/fixinterfaces.pl$ ^include/ThePEG$ ^Doc/MakeDocs.in$ ^Doc/refman.conf$ ^Doc/refman.h$ ^Doc/refman-html$ ^Doc/AllInterfaces.h$ ^Doc/MoreInterfaces.h$ ^Doc/ThePEG-refman.tag$ ^java/.*\.(java|class)$ ^java/ThePEG$ ^java/ThePEG.jar$ ^java/thepeg.sh$ ^java/thepeg$ ^PDF/.done-all-links$ ^lib/ThePEGDefaults.rpo$ ^lib/Makefile.common ^lib/Makefile.dist$ ^src/runThePEG$ ^src/setupThePEG$ ^aclocal.m4$ ^libtool$ ^INSTALL$ ^src/TestDecayMode.in$ ^ThePEG.*\.tar\.(bz2|gz)$ ^src/runThePEG.bin$ ^src/setupThePEG.bin$ ^ThePEG-default.kdev4$ ^src/SimpleLEP.cmp$ ^Repository/versionstamp.inc$ ^Repository/repository_test(.log|.trs)?$ ^Repository/test-suite.log$ ^Repository/tests/.dirstamp$ # added by aHg on Wed Jan 13 13:27:00 2016 syntax: glob Config/LWH.h PDF/done-all-links include/done-all-links lib/done-all-links src/done-all-links # added by aHg on Tue Oct 11 14:21:42 2016 syntax: glob Config/ThePEG_Qty.h diff --git a/Analysis/FactoryBase.cc b/Analysis/FactoryBase.cc --- a/Analysis/FactoryBase.cc +++ b/Analysis/FactoryBase.cc @@ -1,195 +1,195 @@ // -*- C++ -*- // // FactoryBase.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the FactoryBase class. // #include "FactoryBase.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Config/algorithm.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "AIDA_helper.h" using namespace ThePEG; FactoryBase::FactoryBase() : theFilename(""), theSuffix("aida"), theStoreType("xml"), theAnalysisFactory(0), theTree(0), theHistogramFactory(0), theDataSetFactory(0) {} FactoryBase::FactoryBase(const FactoryBase & x) : Interfaced(x), theFilename(x.theFilename), theSuffix(x.theSuffix), theStoreType(x.theStoreType), theAnalysisFactory(0), theTree(0), theHistogramFactory(0), theDataSetFactory(0) {} FactoryBase::~FactoryBase() {} FactoryBase::DataFiller::~DataFiller() { int N = v.size()/(3*dset->dimension()); for ( int i = 0; i < N; ++i ) { AIDA::IDataPoint * p = dset->addPoint(); for ( int j = 0; j < p->dimension(); ++j ) { p->coordinate(j)->setValue(v.front()); v.pop_front(); p->coordinate(j)->setErrorPlus(v.front()); v.pop_front(); p->coordinate(j)->setErrorMinus(v.front()); v.pop_front(); } } } void FactoryBase::clear() { if ( theTree ) delete theTree; if ( theAnalysisFactory ) delete theAnalysisFactory; theHistogramFactory = 0; theDataSetFactory = 0; theTree = 0; theAnalysisFactory = 0; } void FactoryBase::dofinish() { Interfaced::dofinish(); - for_each(clients, mem_fun(&InterfacedBase::finish)); + for_each(clients, mem_fn(&InterfacedBase::finish)); tree().commit(); clear(); } void FactoryBase::doinitrun() { Interfaced::doinitrun(); string file = filename(); if ( file == "" ) file = generator()->filename(); else if ( file[0] != '/' ) file = generator()->path() + "/" + file; file += "." + suffix(); theTree = analysisFactory().createTreeFactory()->create (file, storeType(), false, true); theTree->setOverwrite(false); theHistogramFactory = analysisFactory().createHistogramFactory(tree()); theDataSetFactory = analysisFactory().createDataPointSetFactory(tree()); } void FactoryBase::persistentOutput(PersistentOStream & os) const { os << theFilename << theSuffix << theStoreType; } void FactoryBase::persistentInput(PersistentIStream & is, int) { clear(); is >> theFilename >> theSuffix >> theStoreType; } AbstractClassDescription FactoryBase::initFactoryBase; // Definition of the static class description member. void FactoryBase::Init() { static ClassDocumentation documentation ("There is no documentation for the FactoryBase class"); static Parameter interfaceFilename ("Filename", "Together with Suffix, the name of the file " "where the resulting histograms will be stored. If empty, the run-name " "provided by the current EventGenerator will be used instead.", &FactoryBase::theFilename, "", true, false); static Parameter interfaceSuffix ("Suffix", "Together with Filename, the name of the file " "where the resulting histograms will be stored.", &FactoryBase::theSuffix, "aida", true, false); static Parameter interfaceStoreType ("StoreType", "The format in which the histograms are stored in the output file. " "The allowed values depend on the actual AIDA implementation used.", &FactoryBase::theStoreType, "xml", true, false); } AIDA::ITree & FactoryBase::tree() const { return *theTree; } AIDA::IHistogramFactory & FactoryBase::histogramFactory() const { return *theHistogramFactory; } AIDA::IDataPointSetFactory & FactoryBase::dataSetFactory() const { return *theDataSetFactory; } void FactoryBase::mkdir(const string & path) { tree().mkdir(path); } void FactoryBase::mkdirs(const string & path) { tree().mkdirs(path); } void FactoryBase::cd(const string & path) { tree().cd(path); } FactoryBase::tH1DPtr FactoryBase::createHistogram1D(const string & path, int nb, double lo, double up) { return histogramFactory().createHistogram1D(path, nb, lo, up); } FactoryBase::tH1DPtr FactoryBase::createHistogram1D(const string & path, const string & title, int nb, double lo, double up) { return histogramFactory().createHistogram1D(path, title, nb, lo, up); } FactoryBase::tH1DPtr FactoryBase::createHistogram1D(const string & path, const string & title, const std::vector & edges) { return histogramFactory().createHistogram1D(path, title, edges); } FactoryBase::tH2DPtr FactoryBase::createHistogram2D(const string & path, int nbx, double xlo, double xup, int nby, double ylo, double yup) { return histogramFactory().createHistogram2D(path, nbx, xlo, xup, nby, ylo, yup); } FactoryBase::tH2DPtr FactoryBase::createHistogram2D(const string & path, const string & title, int nbx, double xlo, double xup, int nby, double ylo, double yup) { return histogramFactory().createHistogram2D(path, title, nbx, xlo, xup, nby, ylo, yup); } FactoryBase::tH2DPtr FactoryBase::createHistogram2D(const string & path, const string & title, const std::vector & xedges, const std::vector & yedges) { return histogramFactory().createHistogram2D(path, title, xedges, yedges); } FactoryBase::DataFiller FactoryBase::createDataSet(const string & path, const string & title, int dim) { return DataFiller(dataSetFactory().create(path, title, dim)); } void FactoryBase::registerClient(tIPtr client) { initrun(); clients.insert(client); } diff --git a/Analysis/LWH/DataPointSet.h b/Analysis/LWH/DataPointSet.h --- a/Analysis/LWH/DataPointSet.h +++ b/Analysis/LWH/DataPointSet.h @@ -1,372 +1,370 @@ // -*- C++ -*- // // DataPointSet.h is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef LWH_DataPointSet_H #define LWH_DataPointSet_H // // This is the declaration of the DataPointSet class representing // #include #include #include #include #include "AIDataPointSet.h" #include "ManagedObject.h" #include "DataPoint.h" namespace LWH { using namespace AIDA; /** * An DataPointSet represents a binned histogram axis. A 1D Histogram would have * one DataPointSet representing the X axis, while a 2D Histogram would have two * axes representing the X and Y DataPointSet. */ class DataPointSet: public IDataPointSet, public ManagedObject { public: /** * Standard constructor takes the dimension, \a D, of the data * points as argument. */ DataPointSet(int D): dim(D) {} /** * Destructor. */ virtual ~DataPointSet() {} /** * Not implemented in LWH. will throw an exception. */ IAnnotation & annotation() { throw std::runtime_error("LWH cannot handle annotations"); } /** * Not implemented in LWH. will throw an exception. */ const IAnnotation & annotation() const { throw std::runtime_error("LWH cannot handle annotations"); } /** * Get the data set's title. * @return The data set's title. */ std::string title() const { return theTitle; } /** * Get the data set's title. * @return The data set's title. */ std::string name() const { return theTitle; } /** * Set the data set's title. * @param title The title. * @return false If title cannot be changed. */ bool setTitle(const std::string & title) { theTitle = title; return true; } /** * Get the dimension of the IDataPoints that can be stored in the set. * @return The dimension of the IDataPoints storable in the set. * */ int dimension() const { return dim; } /** * Remove all the IDataPoints in the set. * After this the IDataPointSet is as just created. */ void clear() { dset.clear(); } /** * Get the current size of the IDataPointSet, i.e. the number * of IDataPoints contained in the set. * @return The size of the IDataPointSet. */ int size() const { return dset.size(); } /** * Get the IDataPoint at a give index in the set. * @param index The IDataPoint index. * @return The corresponding IDataPoint. */ IDataPoint * point(int index) { return &(dset[index]); } /** * Set the values and errors of a given coordinate all at once. If * this method is called on an empty IDataPointSet, a number of * points equal to the size of the arrays provided is created; if * the IDataPointSet is not empty the dimension of the array must * match with the size of the IDataPointSet. * @param coord The coordinate's index * @param val The array of the values for the given coordinate * @param err The array with the symmetric errors. * @return false if an illegal coordinate is provided or if there is * a mismatch between the size of the array and the size of the * IDataPointSet. */ bool setCoordinate(int coord, const std::vector & val, const std::vector & err) { return setCoordinate(coord, val, err, err); } /** * Set the values and errors of a given coordinate all at once. If * this method is called on an empty IDataPointSet, a number of * points equal to the size of the arrays provided is created; if * the IDataPointSet is not empty the dimension of the array must * match with the size of the IDataPointSet. * @param coord The coordinate's index * @param val The array of the values for the given coordinate * @param errp The array with the plus errors. * @param errm The array with the minus errors. * @return false if an illegal coordinate is provided or if there is * a mismatch between the size of the array and the size of the * IDataPointSet. * */ bool setCoordinate(int coord, const std::vector & val, const std::vector & errp, const std::vector & errm) { if ( coord < 0 || coord >= dimension() ) return false; if ( val.size() != dset.size() || errp.size() != dset.size() || errm.size() != dset.size() ) return false; for ( int i = 0, N = val.size(); i < N; ++i ) { dset[i].coordinate(coord)->setValue(val[i]); dset[i].coordinate(coord)->setErrorPlus(errp[i]); dset[i].coordinate(coord)->setErrorMinus(errm[i]); } return true; } /** * Return the data point at the given index. * @return 0 if index is out of range. */ const IDataPoint * point(int index) const { if ( index < 0 || unsigned(index) >= dset.size() ) return 0; return &(dset[index]); } /** * Add a new empty IDataPoint at the end of the set. * @return The newly added point. */ IDataPoint * addPoint() { dset.push_back(DataPoint(dimension())); return &(dset.back()); } /** * Add a copy of an IDataPoint at the end of the set. * @param point The IDataPoint to be added. * @return false If the point has the wrong dimension or * if the point cannot be added. */ bool addPoint(const IDataPoint & point) { if ( dimension() && dimension() != point.dimension() ) return false; dset.push_back(DataPoint(point)); return true; } /** * Remove the IDataPoint at a given index. * @param index The index of the IDataPoint to be removed. * @return false If the index is < 0 or >= size(). */ bool removePoint(int index) { if ( index < 0 || unsigned(index) >= dset.size() ) return false; dset.erase(dset.begin() + index); return true; } /** * Get the lower value for a give axis. * @param coord The coordinate of the axis. * @return The lower edge of the corresponding axis. * If coord < 0 or coord >= dimension(), or if the * set is empty NaN is returned. */ double lowerExtent(int coord) const { if ( dset.empty() ) return std::numeric_limits::quiet_NaN(); if ( coord < 0 || coord >= dimension() ) return std::numeric_limits::quiet_NaN(); double low = dset[0].coordinate(coord)->value(); for ( int i = 1, N = dset.size(); i < N; ++i ) low = std::min(low, dset[i].coordinate(coord)->value()); return low; } /** * Get the upper value for a give axis. * @param coord The coordinate of the axis. * @return The upper edge of the corresponding axis. * If coord < 0 or coord >= dimension(), or if the set * is empty NaN is returned. */ double upperExtent(int coord) const { if ( dset.empty() ) return std::numeric_limits::quiet_NaN(); if ( coord < 0 || coord >= dimension() ) return std::numeric_limits::quiet_NaN(); double upp = dset[0].coordinate(coord)->value(); for ( int i = 1, N = dset.size(); i < N; ++i ) upp = std::max(upp, dset[i].coordinate(coord)->value()); return upp; } /** * Scales the values and the errors of all the measurements * of each point by a given factor. * @param scale The scale factor. * @return false If an illegal scaleFactor is provided. */ bool scale(double scale) { for ( int i = 0, N = dset.size(); i < N; ++i ) for ( int j = 0, M = dset[i].dimension(); j < M; ++j ) { IMeasurement * m = dset[i].coordinate(j); m->setValue(m->value()*scale); m->setErrorPlus(m->errorPlus()*scale); m->setErrorMinus(m->errorPlus()*scale); } return true; } /** * Scales the values of all the measurements * of each point by a given factor. * @param scale The scale factor. * @return false If an illegal scaleFactor is provided. */ bool scaleValues(double scale) { for ( int i = 0, N = dset.size(); i < N; ++i ) for ( int j = 0, M = dset[i].dimension(); j < M; ++j ) { IMeasurement * m = dset[i].coordinate(j); m->setValue(m->value()*scale); } return true; } /** * Scales the errors of all the measurements * of each point by a given factor. * @param scale The scale factor. * @return false If an illegal scaleFactor is provided. */ bool scaleErrors(double scale) { for ( int i = 0, N = dset.size(); i < N; ++i ) for ( int j = 0, M = dset[i].dimension(); j < M; ++j ) { IMeasurement * m = dset[i].coordinate(j); m->setErrorPlus(m->errorPlus()*scale); m->setErrorMinus(m->errorPlus()*scale); } return true; } /** * Not implemented in LWH. * @return null pointer always. */ void * cast(const std::string &) const { return 0; } /** * Write out the data set in the AIDA xml format. */ bool writeXML(std::ostream & os, std::string path, std::string name) { os << " \n"; for ( int d = 0; d < dimension(); ++d ) os << " \n"; for ( int i = 0, N = size(); i < N; ++i ) { os << " \n"; for ( int j = 0, M = dimension(); j < M; ++j ) os << " coordinate(j)->value() << "\" errorPlus=\"" << point(i)->coordinate(j)->errorPlus() << "\" errorMinus=\"" << point(i)->coordinate(j)->errorMinus() << "\"/>\n"; os << " \n"; } os << " " << std::endl; return true; } /** * Write out the data set in a flat text file suitable for * eg. gnuplot to read. The coloums are layed out as 'x1 x2 ... xn * dx1+ dx2+ ... dxn+ dx1- dx2- ... dxn-'. */ bool writeFLAT(std::ostream & os, std::string path, std::string name) { os << "# " << path << "/" << name << " " << size() << " \"" << title() << " \" dimension " << dimension() << std::endl; for ( int i = 0, N = size(); i < N; ++i ) { for ( int j = 0, M = dimension(); j < M; ++j ) os << point(i)->coordinate(j)->value() << " "; for ( int j = 0, M = dimension(); j < M; ++j ) os << point(i)->coordinate(j)->errorPlus() << " "; for ( int j = 0, M = dimension(); j < M; ++j ) os << point(i)->coordinate(j)->errorMinus() << " "; os << std::endl; } os << std::endl; return true; } private: /** The title */ std::string theTitle; /** * The included data points. */ std::vector dset; /** * The dimension of the points in this set. */ unsigned int dim; - /** dummy pointer to non-existen annotation. */ - IAnnotation * anno; }; } #endif /* LWH_DataPointSet_H */ diff --git a/Analysis/LWH/Histogram1D.h b/Analysis/LWH/Histogram1D.h --- a/Analysis/LWH/Histogram1D.h +++ b/Analysis/LWH/Histogram1D.h @@ -1,523 +1,520 @@ // -*- C++ -*- // // Histogram1D.h is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef LWH_Histogram1D_H #define LWH_Histogram1D_H // // This is the declaration of the Histogram1D class. // #include "AIHistogram1D.h" #include "ManagedObject.h" #include "Axis.h" #include "VariAxis.h" #include #include namespace LWH { using namespace AIDA; /** * User level interface to 1D Histogram. */ class Histogram1D: public IHistogram1D, public ManagedObject { public: /** HistFactory is a friend. */ friend class HistogramFactory; public: /** * Standard constructor. */ Histogram1D(int n, double lo, double up) : fax(new Axis(n, lo, up)), vax(0), sum(n + 2), sumw(n + 2), sumw2(n + 2), sumxw(n + 2), sumx2w(n + 2) { ax = fax; } /** * Standard constructor for variable bin width. */ Histogram1D(const std::vector & edges) : fax(0), vax(new VariAxis(edges)), sum(edges.size() + 1), sumw(edges.size() + 1), sumw2(edges.size() + 1), sumxw(edges.size() + 1), sumx2w(edges.size() + 1) { ax = vax; } /** * Copy constructor. */ Histogram1D(const Histogram1D & h) : IBaseHistogram(h), IHistogram(h), IHistogram1D(h), ManagedObject(h), fax(0), vax(0), sum(h.sum), sumw(h.sumw), sumw2(h.sumw2), sumxw(h.sumxw), sumx2w(h.sumx2w) { const VariAxis * hvax = dynamic_cast(h.ax); if ( vax ) ax = vax = new VariAxis(*hvax); else ax = fax = new Axis(dynamic_cast(*h.ax)); } /// Destructor. virtual ~Histogram1D() { delete ax; } /** * Get the Histogram's title. * @return The Histogram's title. */ std::string title() const { return theTitle; } /** * Get the Histogram's title. * @return The Histogram's title. */ std::string name() const { return theTitle; } /** * Set the histogram title. * @param title The title. * @return false If title cannot be changed. */ bool setTitle(const std::string & title) { theTitle = title; return true; } /** * Not implemented in LWH. will throw an exception. */ IAnnotation & annotation() { throw std::runtime_error("LWH cannot handle annotations"); } /** * Not implemented in LWH. will throw an exception. */ const IAnnotation & annotation() const { throw std::runtime_error("LWH cannot handle annotations"); } /** * Get the Histogram's dimension. * @return The Histogram's dimension. */ int dimension() const { return 1; } /** * Reset the Histogram; as if just created. * @return false If something goes wrong. */ bool reset() { sum = std::vector(ax->bins() + 2); sumw = std::vector(ax->bins() + 2); sumxw = std::vector(ax->bins() + 2); sumx2w = std::vector(ax->bins() + 2); sumw2 = std::vector(ax->bins() + 2); return true; } /** * Get the number of in-range entries in the Histogram. * @return The number of in-range entries. * */ int entries() const { int si = 0; for ( int i = 2; i < ax->bins() + 2; ++i ) si += sum[i]; return si; } /** * Sum of the entries in all the IHistogram's bins, * i.e in-range bins, UNDERFLOW and OVERFLOW. * This is equivalent to the number of times the * method fill was invoked. * @return The sum of all the entries. */ int allEntries() const { return entries() + extraEntries(); } /** * Number of entries in the UNDERFLOW and OVERFLOW bins. * @return The number of entries outside the range of the IHistogram. */ int extraEntries() const { return sum[0] + sum[1]; } /** * Number of equivalent entries, * i.e. SUM[ weight ] ^ 2 / SUM[ weight^2 ] * @return The number of equivalent entries. */ double equivalentBinEntries() const { double sw = 0.0; double sw2 = 0.0; for ( int i = 2; i < ax->bins() + 2; ++i ) { sw += sumw[i]; sw2 += sumw2[i]; } return sw2/(sw*sw); } /** * Sum of in-range bin heights in the IHistogram, * UNDERFLOW and OVERFLOW bins are excluded. * @return The sum of the in-range bins heights. * */ double sumBinHeights() const { double sw = 0.0; for ( int i = 2; i < ax->bins() + 2; ++i ) sw += sumw[i]; return sw; } /** * Sum of the heights of all the IHistogram's bins, * i.e in-range bins, UNDERFLOW and OVERFLOW. * @return The sum of all the bins heights. */ double sumAllBinHeights() const { return sumBinHeights() + sumExtraBinHeights(); } /** * Sum of heights in the UNDERFLOW and OVERFLOW bins. * @return The sum of the heights of the out-of-range bins. */ double sumExtraBinHeights() const { return sumw[0] + sumw[1]; } /** * Minimum height of the in-range bins, * i.e. not considering the UNDERFLOW and OVERFLOW bins. * @return The minimum height among the in-range bins. */ double minBinHeight() const { double minw = sumw[2]; for ( int i = 3; i < ax->bins() + 2; ++i ) minw = std::min(minw, sumw[i]); return minw; } /** * Maximum height of the in-range bins, * i.e. not considering the UNDERFLOW and OVERFLOW bins. * @return The maximum height among the in-range bins. */ double maxBinHeight() const{ double maxw = sumw[2]; for ( int i = 3; i < ax->bins() + 2; ++i ) maxw = std::max(maxw, sumw[i]); return maxw; } /** * Fill the IHistogram1D with a value and the * corresponding weight. * @param x The value to be filled in. * @param weight The corresponding weight (by default 1). * @return false If the weight is <0 or >1 (?). */ bool fill(double x, double weight = 1.) { int i = ax->coordToIndex(x) + 2; ++sum[i]; sumw[i] += weight; sumxw[i] += x*weight; sumx2w[i] += x*x*weight; sumw2[i] += weight*weight; return weight >= 0 && weight <= 1; } /** * The weighted mean of a bin. * @param index The bin number (0...N-1) or OVERFLOW or UNDERFLOW. * @return The mean of the corresponding bin. */ double binMean(int index) const { int i = index + 2; return sumw[i] != 0.0? sumxw[i]/sumw[i]: ( vax? vax->binMidPoint(index): fax->binMidPoint(index) ); }; /** * The weighted RMS of a bin. * @param index The bin number (0...N-1) or OVERFLOW or UNDERFLOW. * @return The RMS of the corresponding bin. */ double binRms(int index) const { int i = index + 2; return sumw[i] == 0.0 || sum[i] < 2? ax->binWidth(index): std::sqrt(std::max(sumw[i]*sumx2w[i] - sumxw[i]*sumxw[i], 0.0))/sumw[i]; }; /** * Number of entries in the corresponding bin (ie the number of * times fill was called for this bin). * @param index The bin number (0...N-1) or OVERFLOW or UNDERFLOW. * @return The number of entries in the corresponding bin. */ int binEntries(int index) const { return sum[index + 2]; } /** * Total height of the corresponding bin (ie the sum of the weights * in this bin). * @param index The bin number (0...N-1) or OVERFLOW or UNDERFLOW. * @return The height of the corresponding bin. */ double binHeight(int index) const { return sumw[index + 2]; } /** * The error of a given bin. * @param index The bin number (0...N-1) or OVERFLOW or UNDERFLOW. * @return The error on the corresponding bin. * */ double binError(int index) const { return std::sqrt(sumw2[index + 2]); } /** * The mean of the whole IHistogram1D. * @return The mean of the IHistogram1D. */ double mean() const { double s = 0.0; double sx = 0.0; for ( int i = 2; i < ax->bins() + 2; ++i ) { s += sumw[i]; sx += sumxw[i]; } return s != 0.0? sx/s: 0.0; } /** * The RMS of the whole IHistogram1D. * @return The RMS if the IHistogram1D. */ double rms() const { double s = 0.0; double sx = 0.0; double sx2 = 0.0; for ( int i = 2; i < ax->bins() + 2; ++i ) { s += sumw[i]; sx += sumxw[i]; sx2 += sumx2w[i]; } return s != 0.0? std::sqrt(std::max(s*sx2 - sx*sx, 0.0))/s: ax->upperEdge() - ax->lowerEdge(); } /** * Get the x axis of the IHistogram1D. * @return The x coordinate IAxis. */ const IAxis & axis() const { return *ax; } /** * Get the bin number corresponding to a given coordinate along the * x axis. This is a convenience method, equivalent to * axis().coordToIndex(coord). * @param coord The coordinalte along the x axis. * @return The corresponding bin number. */ int coordToIndex(double coord) const { return ax->coordToIndex(coord); } /** * Add to this Histogram1D the contents of another IHistogram1D. * @param h The Histogram1D to be added to this IHistogram1D. * @return false If the IHistogram1Ds binnings are incompatible. */ bool add(const Histogram1D & h) { if ( ax->upperEdge() != h.ax->upperEdge() || ax->lowerEdge() != h.ax->lowerEdge() || ax->bins() != h.ax->bins() ) return false; for ( int i = 0; i < ax->bins() + 2; ++i ) { sum[i] += h.sum[i]; sumw[i] += h.sumw[i]; sumxw[i] += h.sumxw[i]; sumx2w[i] += h.sumx2w[i]; sumw2[i] += h.sumw2[i]; } return true; } /** * Add to this IHistogram1D the contents of another IHistogram1D. * @param hist The IHistogram1D to be added to this IHistogram1D. * @return false If the IHistogram1Ds binnings are incompatible. */ bool add(const IHistogram1D & hist) { return add(dynamic_cast(hist)); } /** * Scale the contents of this histogram with the given factor. * @param s the scaling factor to use. */ bool scale(double s) { for ( int i = 0; i < ax->bins() + 2; ++i ) { sumw[i] *= s; sumxw[i] *= s; sumx2w[i] *= s; sumw2[i] *= s*s; } return true; } /** * Scale the given histogram so that the integral over all bins * (including overflow) gives \a intg. This function also corrects * for the bin-widths, which means that it should only be run once * for each histogram. Further rescaling must be done with the * scale(double) function. */ void normalize(double intg) { double oldintg = sumAllBinHeights(); if ( oldintg == 0.0 ) return; for ( int i = 0; i < ax->bins() + 2; ++i ) { double fac = intg/oldintg; if ( i >= 2 ) fac /= (ax->binUpperEdge(i - 2) - ax->binLowerEdge(i - 2)); sumw[i] *= fac; sumxw[i] *= fac; sumx2w[i] *= fac; sumw2[i] *= fac*fac; } } /** * Return the integral over the histogram bins assuming it has been * normalize()d. */ double integral() const { double intg = sumw[0] + sumw[1]; for ( int i = 2; i < ax->bins() + 2; ++i ) intg += sumw[i]*(ax->binUpperEdge(i - 2) - ax->binLowerEdge(i - 2)); return intg; } /** * Not implemented in LWH. * @return null pointer always. */ void * cast(const std::string &) const { return 0; } /** * Write out the histogram in the AIDA xml format. */ bool writeXML(std::ostream & os, std::string path, std::string name) { os << " \n upperEdge() << "\" numberOfBins=\"" << ax->bins() << "\" min=\"" << ax->lowerEdge() << "\" direction=\"x\""; if ( vax ) { os << ">\n"; for ( int i = 0, N = ax->bins() - 1; i < N; ++i ) os << " binUpperEdge(i) << "\"/>\n"; os << " \n"; } else { os << "/>\n"; } os << " \n \n \n \n"; for ( int i = 0; i < ax->bins() + 2; ++i ) if ( sum[i] ) { os << " \n"; } os << " \n " << std::endl; return true; } /** * Write out the histogram in a flat text file suitable for * eg. gnuplot to read. The coloums are layed out as 'x w w2 n'. */ bool writeFLAT(std::ostream & os, std::string path, std::string name) { os << "# " << path << "/" << name << " " << ax->lowerEdge() << " " << ax->bins() << " " << ax->upperEdge() << " \"" << title() << " \"" << std::endl; for ( int i = 2; i < ax->bins() + 2; ++i ) os << 0.5*(ax->binLowerEdge(i - 2) + ax->binUpperEdge(i - 2)) << " " << sumw[i] << " " << sqrt(sumw2[i]) << " " << sum[i] << std::endl; os << std::endl; return true; } private: /** The title */ std::string theTitle; /** The axis. */ IAxis * ax; /** Pointer (possibly null) to a axis with fixed bin width. */ Axis * fax; /** Pointer (possibly null) to a axis with fixed bin width. */ VariAxis * vax; /** The counts. */ std::vector sum; /** The weights. */ std::vector sumw; /** The squared weights. */ std::vector sumw2; /** The weighted x-values. */ std::vector sumxw; /** The weighted x-square-values. */ std::vector sumx2w; - /** dummy pointer to non-existen annotation. */ - IAnnotation * anno; - }; } #endif /* LWH_Histogram1D_H */ diff --git a/Analysis/NLORivetAnalysis.cc b/Analysis/NLORivetAnalysis.cc --- a/Analysis/NLORivetAnalysis.cc +++ b/Analysis/NLORivetAnalysis.cc @@ -1,310 +1,310 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the NLORivetAnalysis class. // #include #include "NLORivetAnalysis.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Vectors/HepMCConverter.h" #include "ThePEG/Config/HepMCHelper.h" #include "ThePEG/EventRecord/Event.h" #include "ThePEG/EventRecord/SubProcess.h" #include "ThePEG/EventRecord/SubProcessGroup.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "Rivet/AnalysisHandler.hh" #include "Rivet/Tools/Logging.hh" using namespace ThePEG; NLORivetAnalysis::NLORivetAnalysis() - : _remnantId(82), _format(1),_unitchoice(), - _geneventPrecision(16), debug(false), _rivet(), _nevent(0) {} + : _remnantId(82),_unitchoice(), + debug(false), _rivet(), _nevent(0) {} namespace { // Special anonymous function for creating a genEvent. HepMC::GenEvent * makeEvent(tEventPtr event, tSubProPtr sub, long no, long remnantId, Energy eUnit, Length lUnit, CrossSection xsec, CrossSection xsecErr) { // generate beam particles const PPair& beam = event->incoming(); HepMC::GenParticlePtr b1 = HepMCTraits::newParticle(beam.first->momentum(),beam.first->id(), 1,eUnit); HepMC::GenParticlePtr b2 = HepMCTraits::newParticle(beam.second->momentum(),beam.second->id(), 1,eUnit); // generate remnants HepMC::GenParticlePtr r1 = HepMCTraits::newParticle(beam.first->momentum() - sub->incoming().first->momentum(), remnantId,1,eUnit); HepMC::GenParticlePtr r2 = HepMCTraits::newParticle(beam.second->momentum() - sub->incoming().second->momentum(), remnantId,1,eUnit); // generate outgoing particles vector outgoing; for ( ParticleVector::const_iterator p = sub->outgoing().begin(); p != sub->outgoing().end(); ++p ) { outgoing.push_back(HepMCTraits::newParticle((**p).momentum(),(**p).id(), 1,eUnit)); } // generate one blob vertex HepMC::GenVertexPtr vertex = HepMCTraits::newVertex(); HepMCTraits::addIncoming(*vertex,b1); HepMCTraits::addIncoming(*vertex,b2); HepMCTraits::addOutgoing(*vertex,r1); HepMCTraits::addOutgoing(*vertex,r2); for ( vector::const_iterator p = outgoing.begin(); p != outgoing.end(); ++p ) HepMCTraits::addOutgoing(*vertex,*p); HepMC::GenEvent * ev = HepMCTraits::newEvent(no,event->weight()*sub->groupWeight(), event->optionalWeights()); HepMCTraits::setUnits(*ev,eUnit,lUnit); HepMCTraits::setBeamParticles(*ev,b1,b2); HepMCTraits::addVertex(*ev,vertex); HepMCTraits::setCrossSection(*ev,xsec/picobarn, xsecErr/picobarn); return ev; } } void NLORivetAnalysis::analyze(ThePEG::tEventPtr event, long ieve, int loop, int state) { Energy eUnit; Length lUnit; switch (_unitchoice) { default: eUnit = GeV; lUnit = millimeter; break; case 1: eUnit = MeV; lUnit = millimeter; break; case 2: eUnit = GeV; lUnit = centimeter; break; case 3: eUnit = MeV; lUnit = centimeter; break; } tcEHPtr eh = dynamic_ptr_cast(event->primaryCollision()->handler()); assert(eh); CrossSection xsec = eh->integratedXSec(); CrossSection xsecErr = eh->integratedXSecErr(); tSubProPtr sub = event->primarySubProcess(); Ptr::tptr grp = dynamic_ptr_cast::tptr>(sub); AnalysisHandler::analyze(event, ieve, loop, state); // Rotate to CMS, extract final state particles and call analyze(particles). // convert to hepmc HepMC::GenEvent * hepmc = makeEvent(event,sub,_nevent,_remnantId,eUnit,lUnit,xsec,xsecErr); CurrentGenerator::Redirect stdout(cout); if(_rivet){ #if ThePEG_RIVET_VERSION == 1 _rivet->analyze(*hepmc); #elif ThePEG_RIVET_VERSION > 1 try { _rivet->analyze(*hepmc); } catch (const YODA::Exception & e) { Throw() << "Warning: Rivet/Yoda got the exception: "<< e.what()<<"\n" << Exception::warning; } #else #error "Unknown ThePEG_RIVET_VERSION" #endif } // delete hepmc event delete hepmc; if ( grp ) { for ( SubProcessVector::const_iterator s = grp->dependent().begin(); s != grp->dependent().end(); ++s ) { hepmc = makeEvent(event,*s,_nevent,_remnantId,eUnit,lUnit,xsec,xsecErr); if ( _rivet ){ #if ThePEG_RIVET_VERSION == 1 _rivet->analyze(*hepmc); #elif ThePEG_RIVET_VERSION > 1 try { _rivet->analyze(*hepmc); } catch (const YODA::Exception & e) { Throw() << "Warning: Rivet/Yoda got the exception: "<< e.what()<<"\n" << Exception::warning; } #else #error "Unknown ThePEG_RIVET_VERSION" #endif } // delete hepmc event delete hepmc; } } ++_nevent; } ThePEG::IBPtr NLORivetAnalysis::clone() const { return new_ptr(*this); } ThePEG::IBPtr NLORivetAnalysis::fullclone() const { return new_ptr(*this); } void NLORivetAnalysis::persistentOutput(ThePEG::PersistentOStream & os) const { os << _analyses << filename << debug; } void NLORivetAnalysis::persistentInput(ThePEG::PersistentIStream & is, int) { is >> _analyses >> filename >> debug; } ThePEG::ClassDescription NLORivetAnalysis::initNLORivetAnalysis; // Definition of the static class description member. void NLORivetAnalysis::Init() { static ThePEG::ClassDocumentation documentation ("The NLORivetAnalysis class is a simple class to allow analyses" " from the Rivet library to be called from ThePEG"); static ThePEG::ParVector interfaceAnalyses ("Analyses", "The names of the Rivet analyses to use", &NLORivetAnalysis::_analyses, -1, "", "","" "", false, false, ThePEG::Interface::nolimits); static Parameter interfaceRemnantId ("RemnantId", "Set the PDG id to be used for remnants.", &NLORivetAnalysis::_remnantId, 82, 0, 0, false, false, Interface::nolimits); static Parameter interfaceFilename ("Filename", #if ThePEG_RIVET_VERSION == 1 "The name of the file where the AIDA histograms are put. If empty, " "the run name will be used instead. '.aida' will in any case be " "appended to the file name.", #elif ThePEG_RIVET_VERSION > 1 "The name of the file where the YODA histograms are put. If empty, " "the run name will be used instead. '.yoda' will in any case be " "appended to the file name.", #else #error "Unknown ThePEG_RIVET_VERSION" #endif &NLORivetAnalysis::filename, "", true, false); static Switch interfaceDebug ("Debug", "Enable debug information from Rivet", &NLORivetAnalysis::debug, false, true, false); static SwitchOption interfaceDebugNo (interfaceDebug, "No", "Disable debug information.", false); static SwitchOption interfaceDebugYes (interfaceDebug, "Yes", "Enable debug information from Rivet.", true); interfaceAnalyses.rank(10); } void NLORivetAnalysis::dofinish() { AnalysisHandler::dofinish(); if( _nevent > 0 && _rivet ) { CurrentGenerator::Redirect stdout(cout); #if ThePEG_RIVET_VERSION > 2 _rivet->setCrossSection(make_pair(generator()->integratedXSec()/picobarn, generator()->integratedXSecErr()/picobarn)); #else _rivet->setCrossSection(generator()->integratedXSec()/picobarn); #endif _rivet->finalize(); string fname = filename; #if ThePEG_RIVET_VERSION == 1 if ( fname.empty() ) fname = generator()->path() + "/" + generator()->runName() + ".aida"; #elif ThePEG_RIVET_VERSION > 1 if ( fname.empty() ) fname = generator()->path() + "/" + generator()->runName() + ".yoda"; #else #error "Unknown ThePEG_RIVET_VERSION" #endif _rivet->writeData(fname); } delete _rivet; _rivet = nullptr; } void NLORivetAnalysis::doinit() { AnalysisHandler::doinit(); if(_analyses.empty()) throw ThePEG::Exception() << "Must have at least one analysis loaded in " << "NLORivetAnalysis::doinitrun()" << ThePEG::Exception::runerror; // check that analysis list is available _rivet = new Rivet::AnalysisHandler; //(fname); _rivet->addAnalyses(_analyses); if ( _rivet->analysisNames().size() != _analyses.size() ) { throw ThePEG::Exception() << "Rivet could not find all requested analyses.\n" << "Use 'rivet --list-analyses' to check availability.\n" << ThePEG::Exception::runerror; } delete _rivet; _rivet = 0; } void NLORivetAnalysis::doinitrun() { AnalysisHandler::doinitrun(); // create NLORivet analysis handler CurrentGenerator::Redirect stdout(cout); _rivet = new Rivet::AnalysisHandler; //(fname); _rivet->addAnalyses(_analyses); // check that analysis list is still available if ( _rivet->analysisNames().size() != _analyses.size() ) { throw ThePEG::Exception() << "Rivet could not find all requested analyses.\n" << "Use 'rivet --list-analyses' to check availability.\n" << ThePEG::Exception::runerror; } if ( debug ) Rivet::Log::setLevel("Rivet",Rivet::Log::DEBUG); } diff --git a/Analysis/NLORivetAnalysis.h b/Analysis/NLORivetAnalysis.h --- a/Analysis/NLORivetAnalysis.h +++ b/Analysis/NLORivetAnalysis.h @@ -1,216 +1,206 @@ // -*- C++ -*- #ifndef THEPEG_NLORivetAnalysis_H #define THEPEG_NLORivetAnalysis_H // // This is the declaration of the NLORivetAnalysis class. // #include "ThePEG/Handlers/AnalysisHandler.h" #include "Rivet/AnalysisHandler.hh" namespace ThePEG { /** * Here is the documentation of the NLORivetAnalysis class. * * @see \ref NLORivetAnalysisInterfaces "The interfaces" * defined for NLORivetAnalysis. */ class NLORivetAnalysis: public ThePEG::AnalysisHandler { public: /** * The default constructor. */ NLORivetAnalysis(); public: /** @name Virtual functions required by the AnalysisHandler class. */ //@{ /** * Analyze a given Event. Note that a fully generated event * may be presented several times, if it has been manipulated in * between. The default version of this function will call transform * to make a lorentz transformation of the whole event, then extract * all final state particles and call analyze(tPVector) of this * analysis object and those of all associated analysis objects. The * default version will not, however, do anything on events which * have not been fully generated, or have been manipulated in any * way. * @param event pointer to the Event to be analyzed. * @param ieve the event number. * @param loop the number of times this event has been presented. * If negative the event is now fully generated. * @param state a number different from zero if the event has been * manipulated in some way since it was last presented. */ virtual void analyze(ThePEG::tEventPtr event, long ieve, int loop, int state); //@} public: /** @name Functions used by the persistent I/O system. */ //@{ /** * Function used to write out object persistently. * @param os the persistent output stream written to. */ void persistentOutput(ThePEG::PersistentOStream & os) const; /** * Function used to read in object persistently. * @param is the persistent input stream read from. * @param version the version number of the object when written. */ void persistentInput(ThePEG::PersistentIStream & is, int version); //@} /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual ThePEG::IBPtr clone() const; /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual ThePEG::IBPtr fullclone() const; //@} protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object. Called in the read phase. */ virtual void doinit(); /** * Initialize this object. Called in the run phase just before * a run begins. */ virtual void doinitrun(); /** * Finalize this object. Called in the run phase just after a * run has ended. Used eg. to write out statistics. */ virtual void dofinish(); //@} private: /** * The static object used to initialize the description of this class. * Indicates that this is a concrete class with persistent data. */ static ThePEG::ClassDescription initNLORivetAnalysis; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ NLORivetAnalysis & operator=(const NLORivetAnalysis &) = delete; private: /** * The PDG ID to be used for remnants */ long _remnantId; /** - * The HepMC format - */ - int _format; - - /** * Selector for the choice of units */ int _unitchoice; /** - * Choice of output precision in GenEvent format - */ - unsigned int _geneventPrecision; - - /** * The Analyses to use */ vector _analyses; /** * The base name of the output file. */ string filename; /** * Enable debugging information from NLORivet */ bool debug; /** * The NLORivetAnalysisHandler */ Rivet::AnalysisHandler * _rivet; /** * Event count */ unsigned long _nevent; }; } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of NLORivetAnalysis. */ template <> struct BaseClassTrait { /** Typedef of the first base class of NLORivetAnalysis. */ typedef AnalysisHandler NthBase; }; /** This template specialization informs ThePEG about the name of * the NLORivetAnalysis class and the shared object where it is defined. */ template <> struct ClassTraits : public ClassTraitsBase { /** Return a platform-independent class name */ static string className() { return "ThePEG::NLORivetAnalysis"; } /** * The name of a file containing the dynamic library where the class * NLORivetAnalysis is implemented. It may also include several, space-separated, * libraries if the class NLORivetAnalysis depends on other classes (base classes * excepted). In this case the listed libraries will be dynamically * linked in the order they are specified. */ static string library() { return "RivetAnalysis.so"; } }; /** @endcond */ } #endif /* THEPEG_NLORivetAnalysis_H */ diff --git a/Config/std.h b/Config/std.h --- a/Config/std.h +++ b/Config/std.h @@ -1,187 +1,188 @@ // -*- C++ -*- // // std.h is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef ThePEG_std_H #define ThePEG_std_H /** \file * This file introduces a number of std:: classes into * the ThePEG namespace. Also introduces some useful functions for * standard library classes. * * Do not make changes in this file. If you want to use alternatives * to the std:: classes in ThePEG, edit a copy of this * file and include it in an alternative config file which can be * included in the main ThePEG.h config file using the macro * ThePEG_ALTERNATE_CONFIG. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace std { /** @cond TRAITSPECIALIZATIONS */ /** * This specialization of the std::less class is needed in order to be * able use put pointers to type_info objects as keys in maps and * sets. */ template <> struct less : public binary_function { /** * This is the function called when comparing two pointers to * type_info. */ bool operator()(const type_info * x, const type_info * y) const { return x->before(*y); } }; /** @endcond */ } namespace ThePEG { using std::array; using std::deque; using std::stack; using std::vector; using std::multiset; using std::set; using std::map; using std::list; using std::multimap; using std::pair; using std::make_pair; using std::less; using std::string; using std::type_info; using std::exception; using std::range_error; using std::ios; using std::ostream; using std::istream; using std::ofstream; using std::ifstream; using std::ostringstream; using std::istringstream; using std::cin; using std::cout; using std::cerr; using std::endl; using std::flush; using std::setprecision; using std::setw; using std::swap; using std::min; using std::max; +using std::mem_fn; using std::mem_fun; using std::sqrt; //using std::pow; using std::abs; using std::atan2; using std::isfinite; /** Powers - standard or non-standard */ template inline constexpr double pow(double x, ExponentT p) { return std::pow(x,double(p)); } /** Square root of an integer. */ inline double sqrt(int x) { return std::sqrt(double(x)); } /** factorial */ inline constexpr long double factorial(unsigned int n) { return (n < 2) ? 1.0 : n * factorial(n - 1); } /** Check if a given object is a part of a container. */ template inline bool member(const Container & c, const Key & k) { return c.find(k) != c.end(); } /** Check if a given object is a part of a vector. */ template inline bool member(const vector & v, const Key & k) { for ( typename vector::const_iterator i = v.begin(); i != v.end(); ++i ) if ( *i == k ) return true; return false; // return find(v.begin(), v.end(), k) != v.end(); } /** Return an insert iterator for a given container. */ template inline std::insert_iterator inserter(Cont & c) { return std::insert_iterator(c, c.end()); } /** Return an insert iterator for a given vector. Overrides the * general version. */ template inline std::back_insert_iterator< vector > inserter(vector & v) { return back_inserter(v); } /** Return an insert iterator for a given vector. Overrides the * general version. */ template inline std::back_insert_iterator< deque > inserter(deque & v) { return back_inserter(v); } /** Stream manipulator setting an ostream to left-adjust its ouput. */ inline ostream& left(ostream& os) { os.setf(ios::left, ios::adjustfield); return os; } /** Stream manipulator setting an ostream to right-adjust its ouput. */ inline ostream& right(ostream& os) { os.setf(ios::right, ios::adjustfield); return os; } } /** Macro for declaring a set. */ #define ThePEG_DECLARE_SET(VALTYPE,NAME) \ /** A set of VALTYPE. */ \ typedef set > NAME /** Macro for declaring a multiset. */ #define ThePEG_DECLARE_MULTISET(VALTYPE,NAME) \ /** A multiset of VALTYPE. */ \ typedef multiset > NAME /** Macro for declaring a map. */ #define ThePEG_DECLARE_MAP(KEYTYPE,VALTYPE,NAME) \ /** A map of VALTYPE indexed by KEYTYPE. */ \ typedef map > NAME #endif /* ThePEG_std_H */ diff --git a/Cuts/Cuts.cc b/Cuts/Cuts.cc --- a/Cuts/Cuts.cc +++ b/Cuts/Cuts.cc @@ -1,663 +1,663 @@ // -*- C++ -*- // // Cuts.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the Cuts class. // #include "Cuts.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/PDT/ParticleData.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/EventRecord/SubProcess.h" #include "ThePEG/EventRecord/Collision.h" #include "ThePEG/EventRecord/TmpTransform.h" #include "ThePEG/Utilities/UtilityBase.h" #include "ThePEG/Utilities/HoldFlag.h" #include "ThePEG/Utilities/Debug.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Config/algorithm.h" using namespace ThePEG; Cuts::Cuts(Energy MhatMin) : theSMax(ZERO), theY(0), theCurrentSHat(-1.0*GeV2), theCurrentYHat(0), theMHatMin(MhatMin), theMHatMax(Constants::MaxEnergy), theYHatMin(-Constants::MaxRapidity), theYHatMax(Constants::MaxRapidity), theX1Min(0.0), theX1Max(1.0), theX2Min(0.0), theX2Max(1.0), theScaleMin(ZERO), theScaleMax(Constants::MaxEnergy2), theSubMirror(false), theCutWeight(1.0), theLastCutWeight(1.0) {} Cuts::~Cuts() {} IBPtr Cuts::clone() const { return new_ptr(*this); } IBPtr Cuts::fullclone() const { return new_ptr(*this); } void Cuts::doinitrun() { Interfaced::doinitrun(); if ( Debug::level ) { describe(); - for_each(theOneCuts, mem_fun(&OneCutBase::describe)); - for_each(theTwoCuts, mem_fun(&TwoCutBase::describe)); - for_each(theMultiCuts, mem_fun(&MultiCutBase::describe)); + for_each(theOneCuts, mem_fn(&OneCutBase::describe)); + for_each(theTwoCuts, mem_fn(&TwoCutBase::describe)); + for_each(theMultiCuts, mem_fn(&MultiCutBase::describe)); } } void Cuts::describe() const { CurrentGenerator::log() << fullName() << ":\n" << "MHat = " << theMHatMin/GeV << " .. " << theMHatMax/GeV << " GeV\n" << "Scale = " << theScaleMin/GeV2 << " .. " << theScaleMax/GeV2 << " GeV2\n" << "YHat = " << theYHatMin << " .. " << theYHatMax << '\n' << "X1 = " << theX1Min << " .. " << theX1Max << '\n' << "X2 = " << theX2Min << " .. " << theX2Max << "\n\n"; if ( theJetFinder ) theJetFinder->describe(); } void Cuts::initialize(Energy2 smax, double Y) { theSMax = smax; theMHatMax = min(theMHatMax, sqrt(smax)); theY = Y; theSubMirror = false; } void Cuts::initEvent() { theCurrentSHat = -1.0*GeV2; theCurrentYHat = 0.0; theSubMirror = false; } bool Cuts::initSubProcess(Energy2 shat, double yhat, bool mirror) const { theCutWeight = 1.0; theLastCutWeight = 1.0; theSubMirror = mirror; theCurrentSHat = shat; theCurrentYHat = yhat; if ( shat <= sHatMin() || shat > sHatMax()*(1.0 + 1000.0*Constants::epsilon) ) { theCutWeight = 0.0; return false; } if ( yhat <= yHatMin() || yhat >= yHatMax() ) { theCutWeight = 0.0; return false; } double x1 = min(1.0, sqrt(shat/SMax())*exp(yhat)); if ( x1 <= x1Min() || x1 > x1Max() ) { theCutWeight = 0.0; return false; } double x2 = min(1.0, sqrt(shat/SMax())*exp(-yhat)); if ( x2 <= x2Min() || x2 > x2Max() ) { theCutWeight = 0.0; return false; } return true; } bool Cuts::passCuts(const tcPDVector & ptype, const vector & p, tcPDPtr t1, tcPDPtr t2) const { if ( subMirror() ) { vector pmir = p; for ( int i = 0, N = pmir.size(); i < N; ++i ) pmir[i].setZ(-pmir[i].z()); swap(t1,t2); HoldFlag<> nomir(theSubMirror, false); return passCuts(ptype, pmir, t1, t2); } bool pass = true; theCutWeight = 1.0; theLastCutWeight = 1.0; if ( jetFinder() ) { if ( ptype.size() > jetFinder()->minOutgoing() ) { vector jets; tcPDVector jettype; if ( !jetFinder()->restrictConsitutents() ) { jets = p; jettype = ptype; } else { tcPDVector::const_iterator pd = ptype.begin(); vector::const_iterator pm = p.begin(); for ( ; pd != ptype.end(); ++pd, ++pm ) { if ( pm->rapidity() > jetFinder()->constituentRapidityRange().first && pm->rapidity() < jetFinder()->constituentRapidityRange().second ) { jets.push_back(*pm); jettype.push_back(*pd); } } } if ( jetFinder()->cluster(jettype,jets,this,t1,t2) ){ return passCuts(jettype,jets,t1,t2); } } } for ( int i = 0, N = p.size(); i < N; ++i ) for ( int j = 0, M = theOneCuts.size(); j < M; ++j ) { pass &= theOneCuts[j]->passCuts(this, ptype[i], p[i]); theCutWeight *= theLastCutWeight; theLastCutWeight = 1.0; if ( !pass ) { theCutWeight = 0.0; return false; } } for ( int i1 = 0, N1 = p.size() - 1; i1 < N1; ++i1 ) for ( int i2 = i1 + 1, N2 = p.size(); i2 < N2; ++i2 ) for ( int j = 0, M = theTwoCuts.size(); j < M; ++j ) { pass &= theTwoCuts[j]->passCuts(this, ptype[i1], ptype[i2], p[i1], p[i2]); theCutWeight *= theLastCutWeight; theLastCutWeight = 1.0; if ( !pass ) { theCutWeight = 0.0; return false; } } for ( int j = 0, M = theMultiCuts.size(); j < M; ++j ) { pass &= theMultiCuts[j]->passCuts(this, ptype, p); theCutWeight *= theLastCutWeight; theLastCutWeight = 1.0; if ( !pass ) { theCutWeight = 0.0; return false; } } if ( t1 ) { LorentzMomentum p1(ZERO, ZERO, 0.5*sqrt(currentSHat()), 0.5*sqrt(currentSHat())); for ( int i = 0, N = p.size(); i < N; ++i ) for ( int j = 0, M = theTwoCuts.size(); j < M; ++j ) { pass &= theTwoCuts[j]->passCuts(this, t1, ptype[i], p1, p[i], true, false); theCutWeight *= theLastCutWeight; theLastCutWeight = 1.0; if ( !pass ) { theCutWeight = 0.0; return false; } } } if ( t2 ) { LorentzMomentum p2(ZERO, ZERO, -0.5*sqrt(currentSHat()), 0.5*sqrt(currentSHat())); for ( int i = 0, N = p.size(); i < N; ++i ) for ( int j = 0, M = theTwoCuts.size(); j < M; ++j ) { pass &= theTwoCuts[j]->passCuts(this, ptype[i], t2, p[i], p2, false, true); theCutWeight *= theLastCutWeight; theLastCutWeight = 1.0; if ( !pass ) { theCutWeight = 0.0; return false; } } } return pass; } bool Cuts::passCuts(const tcPVector & p, tcPDPtr t1, tcPDPtr t2) const { tcPDVector ptype(p.size()); vector mom(p.size()); for ( int i = 0, N = p.size(); i < N; ++i ) { ptype[i] = p[i]->dataPtr(); mom[i] = p[i]->momentum(); } return passCuts(ptype, mom, t1, t2); } bool Cuts::passCuts(const SubProcess & sub) const { if ( !passCuts(tcPVector(sub.outgoing().begin(), sub.outgoing().end()), sub.incoming().first->dataPtr(), sub.incoming().second->dataPtr()) ) return false; return true; } bool Cuts::passCuts(const Collision & coll) const { tSubProPtr sub = coll.primarySubProcess(); LorentzMomentum phat = sub->incoming().first->momentum() + sub->incoming().second->momentum(); if ( !initSubProcess(phat.m2(), phat.rapidity()) ) return false; TmpTransform tmp(sub, Utilities::getBoostToCM(sub->incoming())); if ( !passCuts(*sub) ) return false; return true; } Energy2 Cuts::minS(const tcPDVector & pv) const { Energy2 mins = ZERO; for ( int i = 0, N = theMultiCuts.size(); i < N; ++i ) mins = max(mins, theMultiCuts[i]->minS(pv)); return mins; } Energy2 Cuts::maxS(const tcPDVector & pv) const { Energy2 maxs = SMax(); for ( int i = 0, N = theMultiCuts.size(); i < N; ++i ) maxs = min(maxs, theMultiCuts[i]->maxS(pv)); return maxs; } Energy2 Cuts::minSij(tcPDPtr pi, tcPDPtr pj) const { Energy2 mins = ZERO; for ( int i = 0, N = theTwoCuts.size(); i < N; ++i ) mins = max(mins, theTwoCuts[i]->minSij(pi, pj)); if ( mins > ZERO ) return mins; mins = sqr(pi->massMin() + pj->massMin()); mins = max(mins, sqr(minKTClus(pi, pj))/4.0); mins = max(mins, minDurham(pi, pj)*currentSHat()/2.0); mins = max(mins, minKT(pi)*minKT(pj)*minDeltaR(pi, pj)/4.0); return mins; } Energy2 Cuts::minTij(tcPDPtr pi, tcPDPtr po) const { Energy2 mint = ZERO; for ( int i = 0, N = theTwoCuts.size(); i < N; ++i ) mint = max(mint, theTwoCuts[i]->minTij(pi, po)); if ( mint > ZERO ) return mint; mint = max(mint, sqr(minKT(po))); return mint; } double Cuts::minDeltaR(tcPDPtr pi, tcPDPtr pj) const { double mindr = 0.0; for ( int i = 0, N = theTwoCuts.size(); i < N; ++i ) mindr = max(mindr, theTwoCuts[i]->minDeltaR(pi, pj)); return mindr; } Energy Cuts::minKTClus(tcPDPtr pi, tcPDPtr pj) const { Energy minkt = ZERO; for ( int i = 0, N = theTwoCuts.size(); i < N; ++i ) minkt = max(minkt, theTwoCuts[i]->minKTClus(pi, pj)); return minkt; } double Cuts::minDurham(tcPDPtr pi, tcPDPtr pj) const { double y = 0.0; for ( int i = 0, N = theTwoCuts.size(); i < N; ++i ) y = max(y, theTwoCuts[i]->minDurham(pi, pj)); return y; } Energy Cuts::minKT(tcPDPtr p) const { Energy minkt = ZERO; for ( int i = 0, N = theOneCuts.size(); i < N; ++i ) minkt = max(minkt, theOneCuts[i]->minKT(p)); if ( minkt > ZERO ) return minkt; minkt = minKTClus(p, tcPDPtr()); return minkt; } double Cuts::minEta(tcPDPtr p) const { double mineta = -Constants::MaxRapidity; for ( int i = 0, N = theOneCuts.size(); i < N; ++i ) mineta = max(mineta, theOneCuts[i]->minEta(p)); return mineta; } double Cuts::maxEta(tcPDPtr p) const { double maxeta = Constants::MaxRapidity; for ( int i = 0, N = theOneCuts.size(); i < N; ++i ) maxeta = min(maxeta, theOneCuts[i]->maxEta(p)); return maxeta; } double Cuts::minYStar(tcPDPtr p) const { if ( currentSHat() < ZERO ) return -Constants::MaxRapidity; if ( subMirror() ) { HoldFlag<> nomir(theSubMirror, false); return -maxYStar(p); } double etamin = minEta(p); double ytot = Y() + currentYHat(); if ( etamin > 0.0 ) { Energy minkt = minKT(p); Energy maxm = p->massMax(); return asinh(minkt*sinh(etamin)/sqrt(sqr(minkt) + sqr(maxm))) - ytot; } else { return etamin - ytot; } } double Cuts::maxYStar(tcPDPtr p) const { if ( currentSHat() < ZERO ) return Constants::MaxRapidity; if ( subMirror() ) { HoldFlag<> nomir(theSubMirror, false); return -minYStar(p); } double etamax = maxEta(p); double ytot = Y() + currentYHat(); if ( etamax > 0.0 ) { return etamax - ytot; } else { Energy minkt = minKT(p); Energy maxm = p->massMax(); return asinh(minkt*sinh(etamax)/sqrt(sqr(minkt) + sqr(maxm))) - ytot; } } double Cuts::minRapidityMax(tcPDPtr p) const { double minRapidityMax = -Constants::MaxRapidity; for ( int i = 0, N = theOneCuts.size(); i < N; ++i ) minRapidityMax = max(minRapidityMax, theOneCuts[i]->minRapidityMax(p)); return minRapidityMax; } double Cuts::maxRapidityMin(tcPDPtr p) const { double maxRapidityMin = Constants::MaxRapidity; for ( int i = 0, N = theOneCuts.size(); i < N; ++i ) maxRapidityMin = min(maxRapidityMin, theOneCuts[i]->maxRapidityMin(p)); return maxRapidityMin; } void Cuts::persistentOutput(PersistentOStream & os) const { os << ounit(theSMax, GeV2) << theY << ounit(theCurrentSHat, GeV2) << theCurrentYHat << ounit(theMHatMin, GeV) << ounit(theMHatMax, GeV) << theYHatMin << theYHatMax << theX1Min << theX1Max << theX2Min << theX2Max << ounit(theScaleMin, GeV2) << ounit(theScaleMax, GeV2) << theOneCuts << theTwoCuts << theMultiCuts << theJetFinder << theSubMirror << theCutWeight << theLastCutWeight << theFuzzyTheta; } void Cuts::persistentInput(PersistentIStream & is, int) { is >> iunit(theSMax, GeV2) >> theY >> iunit(theCurrentSHat, GeV2) >> theCurrentYHat >> iunit(theMHatMin, GeV) >> iunit(theMHatMax, GeV) >> theYHatMin >> theYHatMax >> theX1Min >> theX1Max >> theX2Min >> theX2Max >> iunit(theScaleMin, GeV2) >> iunit(theScaleMax, GeV2) >> theOneCuts >> theTwoCuts >> theMultiCuts >> theJetFinder >> theSubMirror >> theCutWeight >> theLastCutWeight >> theFuzzyTheta; } ClassDescription Cuts::initCuts; // Definition of the static class description member. Energy Cuts::maxMHatMin() const { return theMHatMax; } Energy Cuts::minMHatMax() const { return theMHatMin; } Energy2 Cuts::maxScaleMin() const { return theScaleMax; } Energy2 Cuts::minScaleMax() const { return theScaleMin; } double Cuts::maxYHatMin() const { return theYHatMax; } double Cuts::minYHatMax() const { return theYHatMin; } double Cuts::maxX1Min() const { return theX1Max; } double Cuts::minX1Max() const { return theX1Min; } double Cuts::maxX2Min() const { return theX2Max; } double Cuts::minX2Max() const { return theX2Min; } void Cuts::Init() { typedef double (ThePEG::Cuts::*IGFN)() const; typedef void (ThePEG::Cuts::*ISFN)(double); static ClassDocumentation documentation ("Cuts is a class for implementing kinematical cuts in ThePEG. The " "class itself only implements cuts on the total momentum of the hard " "sub-process, implemented as minimum and maximum values of \\f$x_1\\f$ " "and \\f$x_2\\f$ (or \\f$\\hat{s}\\f$ and \\f$\\hat{y}\\f$. Further cuts " "can be implemented either by inheriting from this base class, in which " "the virtual cut() function should be overridden, or by assigning " "objects of class OneCutBase, TwoCutBase and MultiCutBase defining " "cuts on single particles, pairs of particles and groups of " "particles respectively."); static Parameter interfaceMHatMin ("MHatMin", "The minimum allowed value of \\f$\\sqrt{\\hat{s}}\\f$.", &Cuts::theMHatMin, GeV, 2.0*GeV, ZERO, Constants::MaxEnergy, true, false, Interface::limited, 0, 0, 0, &Cuts::maxMHatMin, 0); interfaceMHatMin.setHasDefault(false); static Parameter interfaceMHatMax ("MHatMax", "The maximum allowed value of \\f$\\sqrt{\\hat{s}}\\f$.", &Cuts::theMHatMax, GeV, 100.0*GeV, ZERO, ZERO, true, false, Interface::lowerlim, 0, 0, &Cuts::minMHatMax, 0, 0); interfaceMHatMax.setHasDefault(false); static Parameter interfaceScaleMin ("ScaleMin", "The minimum allowed value of the scale to be used in PDFs and " "coupling constants.", &Cuts::theScaleMin, GeV2, ZERO, ZERO, Constants::MaxEnergy2, true, false, Interface::limited, 0, 0, 0, &Cuts::maxScaleMin, 0); interfaceScaleMin.setHasDefault(false); static Parameter interfaceScaleMax ("ScaleMax", "The maximum allowed value of the scale to be used in PDFs and " "coupling constants.", &Cuts::theScaleMax, GeV2, 10000.0*GeV2, ZERO, ZERO, true, false, Interface::lowerlim, 0, 0, &Cuts::minScaleMax, 0, 0); interfaceScaleMax.setHasDefault(false); static Parameter interfaceYHatMin ("YHatMin", "The minimum value of the rapidity of the hard sub-process " "(wrt. the rest system of the colliding particles).", &Cuts::theYHatMin, -10.0, 0.0, Constants::MaxRapidity, true, false, Interface::upperlim, (ISFN)0, (IGFN)0, (IGFN)0, &Cuts::maxYHatMin, (IGFN)0); interfaceYHatMin.setHasDefault(false); static Parameter interfaceYHatMax ("YHatMax", "The maximum value of the rapidity of the hard sub-process " "(wrt. the rest system of the colliding particles).", &Cuts::theYHatMax, 10.0, -Constants::MaxRapidity, 0.0, true, false, Interface::lowerlim, (ISFN)0, (IGFN)0, &Cuts::minYHatMax, (IGFN)0, (IGFN)0); interfaceYHatMax.setHasDefault(false); static Parameter interfaceX1Min ("X1Min", "The minimum value of the positive light-cone fraction of the hard " "sub-process.", &Cuts::theX1Min, 0.0, 0.0, 1.0, true, false, Interface::limited, (ISFN)0, (IGFN)0, (IGFN)0, &Cuts::maxX1Min, (IGFN)0); interfaceX1Min.setHasDefault(false); static Parameter interfaceX1Max ("X1Max", "The maximum value of the positive light-cone fraction of the hard " "sub-process.", &Cuts::theX1Max, 0.0, 0.0, 1.0, true, false, Interface::limited, (ISFN)0, (IGFN)0, &Cuts::minX1Max, (IGFN)0, (IGFN)0); interfaceX1Max.setHasDefault(false); static Parameter interfaceX2Min ("X2Min", "The minimum value of the negative light-cone fraction of the hard " "sub-process.", &Cuts::theX2Min, 0.0, 0.0, 1.0, true, false, Interface::limited, (ISFN)0, (IGFN)0, (IGFN)0, &Cuts::maxX2Min, (IGFN)0); interfaceX2Min.setHasDefault(false); static Parameter interfaceX2Max ("X2Max", "The maximum value of the negative light-cone fraction of the hard " "sub-process.", &Cuts::theX2Max, 0.0, 0.0, 1.0, true, false, Interface::limited, (ISFN)0, (IGFN)0, &Cuts::minX2Max, (IGFN)0, (IGFN)0); interfaceX2Max.setHasDefault(false); static RefVector interfaceOneCuts ("OneCuts", "The objects defining cuts on single outgoing partons from the " "hard sub-process.", &Cuts::theOneCuts, -1, true, false, true, false, false); static RefVector interfaceTwoCuts ("TwoCuts", "The objects defining cuts on pairs of particles in the " "hard sub-process.", &Cuts::theTwoCuts, -1, true, false, true, false, false); static RefVector interfaceMultiCuts ("MultiCuts", "The objects defining cuts on sets of outgoing particles from the " "hard sub-process.", &Cuts::theMultiCuts, -1, true, false, true, false, false); static Reference interfaceJetFinder ("JetFinder", "Set a JetFinder object used to define cuts on the" "level of reconstructed jets as needed for higher order corrections.", &Cuts::theJetFinder, false, false, true, true, false); static Reference interfaceFuzzy ("Fuzzy", "The fuzziness to be applied to cuts (may not be supported by all cut objects).", &Cuts::theFuzzyTheta, false, false, true, true, false); interfaceX1Min.rank(10); interfaceX1Max.rank(9); interfaceX2Min.rank(8); interfaceX2Max.rank(7); interfaceMHatMin.rank(6); interfaceMHatMax.rank(5); interfaceYHatMin.rank(4); interfaceYHatMax.rank(3); interfaceOneCuts.rank(2); interfaceTwoCuts.rank(1); } double Cuts::yHatMin() const { return theX1Min > 0.0 && theX2Max > 0.0? max(theYHatMin, 0.5*log(theX1Min/theX2Max)): theYHatMin; } double Cuts::yHatMax() const { return theX1Max > 0.0 && theX2Min > 0.0? min(theYHatMax, 0.5*log(theX1Max/theX2Min)): theYHatMax; } bool Cuts::yHat(double y) const { return y > yHatMin() && y < yHatMax(); } double Cuts::x1Min() const { return max(theX1Min, (theMHatMin/sqrt(SMax()))*exp(theYHatMin)); } double Cuts::x1Max() const { return min(theX1Max, (theMHatMax/sqrt(SMax()))*exp(theYHatMax)); } bool Cuts::x1(double x) const { return x > x1Min() && x <= x1Max(); } double Cuts::x2Min() const { return max(theX2Min, (theMHatMin/sqrt(SMax()))/exp(theYHatMax)); } double Cuts::x2Max() const { return min(theX2Max, (theMHatMax/sqrt(SMax()))/exp(theYHatMin)); } bool Cuts::x2(double x) const { return x > x2Min() && x <= x2Max(); } template vector::transient_const_pointer> Cuts::oneCutObjects() const { typedef typename Ptr::transient_const_pointer tcPtr; vector ret; for ( int i = 0, N = theOneCuts.size(); i < N; ++i ) if ( dynamic_ptr_cast(theOneCuts[i]) ) ret.push_back(dynamic_ptr_cast(theOneCuts[i])); return ret; } template vector::transient_const_pointer> Cuts::twoCutObjects() const { typedef typename Ptr::transient_const_pointer tcPtr; vector ret; for ( int i = 0, N = theTwoCuts.size(); i < N; ++i ) if ( dynamic_ptr_cast(theTwoCuts[i]) ) ret.push_back(dynamic_ptr_cast(theTwoCuts[i])); return ret; } template vector::transient_const_pointer> Cuts::multiCutObjects() const { typedef typename Ptr::transient_const_pointer tcPtr; vector ret; for ( int i = 0, N = theMultiCuts.size(); i < N; ++i ) if ( dynamic_ptr_cast(theMultiCuts[i]) ) ret.push_back(dynamic_ptr_cast(theMultiCuts[i])); return ret; } diff --git a/EventRecord/Particle.cc b/EventRecord/Particle.cc --- a/EventRecord/Particle.cc +++ b/EventRecord/Particle.cc @@ -1,524 +1,525 @@ // -*- C++ -*- // // Particle.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined member functions of // the Particle class. // #include "Particle.h" #include "ThePEG/EventRecord/Step.h" #include "ThePEG/EventRecord/Event.h" #include "ThePEG/EventRecord/ColourLine.h" #include "ThePEG/Utilities/Rebinder.h" #include "ThePEG/Config/algorithm.h" #include "ThePEG/EventRecord/ParticleTraits.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include #include #include #ifdef ThePEG_TEMPLATES_IN_CC_FILE #include "Particle.tcc" #endif using namespace ThePEG; Particle::ParticleRep::ParticleRep(const ParticleRep & p) : theParents(p.theParents), theChildren(p.theChildren), thePrevious(p.thePrevious), theNext(p.theNext), theBirthStep(p.theBirthStep), theVertex(p.theVertex), theLifeLength(p.theLifeLength), theScale(p.theScale), theVetoScale(p.theVetoScale), theNumber(p.theNumber), theExtraInfo(p.theExtraInfo.size()) { if ( p.theColourInfo ) theColourInfo = dynamic_ptr_cast(p.theColourInfo->clone()); if ( p.theSpinInfo ) theSpinInfo = dynamic_ptr_cast(p.theSpinInfo->clone()); for ( int i = 0, N = p.theExtraInfo.size(); i < N; ++i ) theExtraInfo[i] = p.theExtraInfo[i]->clone(); } Particle::Particle(const Particle & p) - : Base(p), theData(p.theData), theMomentum(p.theMomentum), theRep(p.theRep) { + : Base(p), theData(p.theData), theMomentum(p.theMomentum), + theRep(p.theRep), theStatus(p.theStatus) { if ( p.theRep ) { theRep = new ParticleRep(*p.theRep); theRep->theParents.clear(); } } Particle::~Particle() { if ( theRep ) { if ( colourLine() ) colourLine()->removeColoured(this); if ( antiColourLine() ) antiColourLine()->removeAntiColoured(this); delete theRep; } theRep = 0; theData = cEventPDPtr(); } void Particle::initFull() { if ( theRep ) return; theRep = new ParticleRep; Energy width = data().generateWidth(mass()); if ( width > ZERO ) { Time lifetime = data().generateLifeTime(mass(), width); theRep->theLifeLength.setTau(lifetime); theRep->theLifeLength. setVect((momentum().vect()*(lifetime / max(mass(), Constants::epsilon*GeV)))); theRep->theLifeLength.rescaleEnergy(); } } PPtr Particle::clone() const { return ptr_new(*this); } void Particle::rebind(const EventTranslationMap & trans) { for ( ParticleVector::iterator pit = rep().theChildren.begin(); pit != rep().theChildren.end(); ++pit ) *pit = trans.translate(*pit); for ( tParticleVector::iterator pit = rep().theParents.begin(); pit != rep().theParents.end(); ++pit ) *pit = trans.translate(*pit); rep().thePrevious = trans.translate(rep().thePrevious); rep().theNext = trans.translate(rep().theNext); if ( hasColourInfo() ) colourInfo()->rebind(trans); if ( spinInfo() ) spinInfo()->rebind(trans); rep().theBirthStep = trans.translate(rep().theBirthStep); for ( EIVector::const_iterator ie = rep().theExtraInfo.begin(); ie != rep().theExtraInfo.end(); ++ie ) (**ie).rebind(trans); } tParticleSet Particle::siblings() const { tParticleSet theSiblings; for ( tParticleVector::const_iterator pit = parents().begin(); pit != parents().end(); ++pit ) theSiblings.insert((*pit)->children().begin(), (*pit)->children().end()); theSiblings.erase(const_cast(this)); return theSiblings; } void Particle::colourNeighbour(tPPtr p, bool anti) { tColinePtr line = colourLine(!anti); if ( !line ) line = ColourLine::create(this, !anti); line->addColoured(p, anti); } void Particle::outgoingColour(tPPtr p, bool anti) { tColinePtr line = colourLine(anti); if ( !line ) line = ColourLine::create(this, anti); line->addColoured(p, anti); } tPPtr Particle::incomingColour(bool anti) const { if ( !hasColourInfo() ) return tPPtr(); tColinePtr line = colourLine(anti); if ( !line ) return tPPtr(); for ( int i = 0, N = parents().size(); i < N; ++i ) if ( parents()[i]->hasColourLine(line, anti) ) return parents()[i]; return tPPtr(); } tPPtr Particle::outgoingColour(bool anti) const { if ( !hasColourInfo() ) return tPPtr(); tColinePtr line = colourLine(anti); if ( !line ) return tPPtr(); for ( int i = 0, N = children().size(); i < N; ++i ) if ( children()[i]->hasColourLine(line, anti) ) return children()[i]; return tPPtr(); } LorentzPoint Particle::labVertex() const { LorentzPoint r(rep().theBirthStep && rep().theBirthStep->collision()? vertex() + rep().theBirthStep->collision()->vertex(): vertex()); return r; } void Particle::setLabVertex(const LorentzPoint & p) { rep().theVertex = ( rep().theBirthStep && rep().theBirthStep->collision()? p - rep().theBirthStep->collision()->vertex() : p ); } void Particle::transform(const LorentzRotation & r) { if ( hasRep() && spinInfo() ) spinInfo()->transform(momentum(), r); theMomentum.transform(r); if ( !hasRep() ) return; rep().theVertex.transform(r); rep().theLifeLength.transform(r); } void Particle::deepTransform(const LorentzRotation & r) { transform(r); if ( !theRep ) return; for ( int i = 0, N = children().size(); i < N; ++i ) rep().theChildren[i]->deepTransform(r); if ( rep().theNext ) rep().theNext->deepTransform(r); } void Particle::rotateX(double a) { LorentzRotation r; r.rotateX(a); transform(r); } void Particle::deepRotateX(double a) { LorentzRotation r; r.rotateX(a); deepTransform(r); } void Particle::rotateY(double a) { LorentzRotation r; r.rotateY(a); transform(r); } void Particle::deepRotateY(double a) { LorentzRotation r; r.rotateY(a); deepTransform(r); } void Particle::rotateZ(double a) { LorentzRotation r; r.rotateZ(a); transform(r); } void Particle::deepRotateZ(double a) { LorentzRotation r; r.rotateZ(a); deepTransform(r); } void Particle::rotate(double a, const Axis & axis) { LorentzRotation r; r.rotate(a, axis); transform(r); } void Particle::deepRotate(double a, const Axis & axis) { LorentzRotation r; r.rotate(a, axis); deepTransform(r); } string Particle::outputFormat = "%n3%s10 %i7 %p[,]0 %c(,) %^^0%vv0 %>>0%<>0 %l{,}0\n" " %x10.3%y10.3%z10.3%e10.3%m10.3\n"; int getNumber(string::const_iterator & pos, int def) { if ( !isdigit(*pos) ) return def; def = *pos++ - '0'; while ( isdigit(*pos) ) def = 10*def + *pos++ - '0'; return def; } void writePrecision(ostream & os, string::const_iterator & pos, int defw, int defp, double x) { defw = getNumber(pos, defw); if ( *pos == '.' ) defp = getNumber(++pos, defp); int oldp = os.precision(); os << setprecision(defp) << setw(defw) << x << setprecision(oldp); } void writeStringAdjusted(ostream & os, bool left, int w, string str) { while ( !left && w-- > int(str.size()) ) os << ' '; os << str; while ( left && w-- > int(str.size()) ) os << ' '; } template void writeParticleRanges(ostream & os, const Container & co, char sep, int w) { set cnum; for ( typename Container::const_iterator it = co.begin(); it != co.end(); ++it) cnum.insert((**it).number()); bool elipsis = false; int last = -10; for ( set::iterator it = cnum.begin(); it != cnum.end(); ++it) { int n = *it; int next = 0; set::iterator itn = it; if ( ++itn != cnum.end() ) next = *itn; bool writeit = true; bool writesep = false; if ( elipsis && ( n != last + 1 || n != next - 1 ) ) elipsis = false; else if ( !elipsis && n == last + 1 && n == next -1 ) { os << ".."; elipsis = true; writeit = false; } else if ( elipsis && n == last + 1 && n == next -1 ) writeit = false; else if ( it != cnum.begin() ) writesep = true; if ( writeit ) { if ( writesep ) os << sep; os << setw(w) << n; } last = n; } } ostream & ThePEG::operator<<(ostream & os, const Particle & p) { return p.print(os, p.birthStep()); } ostream & Particle::print(ostream & os, tcStepPtr step) const { if ( !step ) step = birthStep(); tCollPtr coll = step? step->collision(): tCollPtr(); tEventPtr event = coll? coll->event(): tEventPtr(); string::const_iterator pos = Particle::outputFormat.begin(); ios::fmtflags saveflags = os.setf(ios::fixed, ios::floatfield); while ( pos != Particle::outputFormat.end() ) { if ( *pos == '%' && ++pos != Particle::outputFormat.end() ) { bool left = false; if ( *pos == '-' ) { left = true; os.setf(ios::left, ios::adjustfield); ++pos; } else { os.setf(ios::right, ios::adjustfield); } char mark; char open; char close; char sep; int w; string str; string fill; if ( pos == Particle::outputFormat.end() ) break; bool fullColour = false; switch ( *pos ) { case 'n': os << setw(getNumber(++pos, 3)) << number(); break; case 'i': os << setw(getNumber(++pos, 8)) << id(); break; case 's': writeStringAdjusted(os, left, getNumber(++pos, 8), PDGName()); break; case 'x': writePrecision(os, ++pos, 10, 3, momentum().x()/GeV); break; case 'y': writePrecision(os, ++pos, 10, 3, momentum().y()/GeV); break; case 'z': writePrecision(os, ++pos, 10, 3, momentum().z()/GeV); break; case 'e': writePrecision(os, ++pos, 10, 3, momentum().e()/GeV); break; case 'm': writePrecision(os, ++pos, 10, 3, momentum().mass()/GeV); break; case 'P': fullColour = true; [[fallthrough]]; case 'p': open = *++pos; sep = *++pos; close = *++pos; w = getNumber(++pos, 0); if ( parents().empty() ) break; if ( open ) os << open; writeParticleRanges(os, parents(), sep, w); if ( fullColour && hasColourInfo() && ( incomingColour() || incomingAntiColour() ) ) { if ( close ) os << open; if ( incomingColour() ) os << "+" << incomingColour()->number(); if ( incomingAntiColour() ) os << "-" << incomingAntiColour()->number(); if ( close ) os << close; } if ( close ) os << close; break; case 'l': open = *++pos; sep = *++pos; close = *++pos; w = getNumber(++pos, 0); if ( hasColourInfo() && ( colourLine() || antiColourLine() ) && event) { if ( open ) os << open; vector clines = colourInfo()->colourLines(); for ( int i = 0, N = clines.size(); i < N; ++i ) { if ( i > 0 && sep ) os << sep; clines[i]->write(os, event, false); } vector aclines = colourInfo()->antiColourLines(); for ( int i = 0, N = aclines.size(); i < N; ++i ) { if ( ( i > 0 || clines.size() ) && sep ) os << sep; aclines[i]->write(os, event, true); } if ( close ) os << close; } break; case 'C': fullColour = true; [[fallthrough]]; case 'c': open = *++pos; sep = *++pos; close = *++pos; w = getNumber(++pos, 0); if ( children().empty() ) break; if ( open ) os << open; writeParticleRanges(os, children(), sep, w); if ( fullColour && hasColourInfo() && ( outgoingColour() || outgoingAntiColour() ) ) { if ( close ) os << open; if ( outgoingColour() ) os << "+" << outgoingColour()->number(); if ( outgoingAntiColour() ) os << "-" << outgoingAntiColour()->number(); if ( close ) os << close; } if ( close ) os << close; break; case '>': mark = *++pos; w = getNumber(++pos, 0); if ( hasColourInfo() && step && step->colourNeighbour(this) ) { os << setw(w-1) << step->colourNeighbour(this)->number() << mark; } break; case '<': mark = *++pos; w = getNumber(++pos, 0); if ( hasColourInfo() && step && step->antiColourNeighbour(this) ) { int n = step->antiColourNeighbour(this)->number(); ostringstream oss; oss << mark << n; writeStringAdjusted(os, left, w, oss.str()); } break; case 'v': mark = *++pos; w = getNumber(++pos, 0); if ( next() ) { if ( left && mark ) os << mark; os << setw(w) << next()->number(); if ( !left && mark ) os << mark; } break; case '^': mark = *++pos; w = getNumber(++pos, 0); if ( previous() ) { if ( left && mark ) os << mark; os << setw(w) << previous()->number(); if ( !left && mark ) os << mark; } break; case 'd': switch ( *++pos ) { case 'x': writePrecision(os, ++pos, 10, 3, lifeLength().x()/mm); break; case 'y': writePrecision(os, ++pos, 10, 3, lifeLength().y()/mm); break; case 'z': writePrecision(os, ++pos, 10, 3, lifeLength().z()/mm); break; case 't': writePrecision(os, ++pos, 10, 3, lifeLength().e()/mm); break; case 'T': writePrecision(os, ++pos, 10, 3, lifeLength().tau()/mm); break; } break; case 'V': switch ( *++pos ) { case 'x': writePrecision(os, ++pos, 10, 3, vertex().x()/mm); break; case 'y': writePrecision(os, ++pos, 10, 3, vertex().y()/mm); break; case 'z': writePrecision(os, ++pos, 10, 3, vertex().z()/mm); break; case 't': writePrecision(os, ++pos, 10, 3, vertex().e()/mm); break; } break; case 'L': switch ( *++pos ) { case 'x': writePrecision(os, ++pos, 10, 3, labVertex().x()/mm); break; case 'y': writePrecision(os, ++pos, 10, 3, labVertex().y()/mm); break; case 'z': writePrecision(os, ++pos, 10, 3, labVertex().z()/mm); break; case 't': writePrecision(os, ++pos, 10, 3, labVertex().e()/mm); break; } break; default: os << *pos++; } } else { if ( pos != Particle::outputFormat.end() ) os << *pos++; } } os.flags(saveflags); return os; } void Particle::debugme() const { cerr << *this; EventRecordBase::debugme(); } void Particle::persistentOutput(PersistentOStream & os) const { EventConfig::putParticleData(os, theData); - os << ounit(theMomentum, GeV) << bool( theRep != 0 ); + os << ounit(theMomentum, GeV) << theStatus << bool( theRep != 0 ); if ( !theRep ) return; os << rep().theParents << rep().theChildren << rep().thePrevious << rep().theNext << rep().theBirthStep << ounit(rep().theVertex, mm) << ounit(rep().theLifeLength, mm) << ounit(rep().theScale, GeV2) << ounit(rep().theVetoScale, GeV2) << rep().theNumber << rep().theDecayMode << rep().theColourInfo << rep().theSpinInfo << rep().theExtraInfo; } void Particle::persistentInput(PersistentIStream & is, int) { bool readRep; EventConfig::getParticleData(is, theData); - is >> iunit(theMomentum, GeV) >> readRep; + is >> iunit(theMomentum, GeV) >> theStatus >> readRep; if ( !readRep ) return; if ( !hasRep() ) theRep = new ParticleRep; is >> rep().theParents >> rep().theChildren >> rep().thePrevious >> rep().theNext >> rep().theBirthStep >> iunit(rep().theVertex, mm) >> iunit(rep().theLifeLength, mm) >> iunit(rep().theScale, GeV2) >> iunit(rep().theVetoScale, GeV2) >> rep().theNumber >> rep().theDecayMode >> rep().theColourInfo >> rep().theSpinInfo >> rep().theExtraInfo; } ClassDescription Particle::initParticle; void Particle::Init() {} diff --git a/EventRecord/Particle.h b/EventRecord/Particle.h --- a/EventRecord/Particle.h +++ b/EventRecord/Particle.h @@ -1,1180 +1,1195 @@ // -*- C++ -*- // // Particle.h is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef ThePEG_Particle_H #define ThePEG_Particle_H // This is the decalaration of the Particle class. #include "EventConfig.h" #include "ThePEG/Vectors/Lorentz5Vector.h" #include "ThePEG/Vectors/LorentzRotation.h" #include "ThePEG/Utilities/ClassDescription.h" #include "ThePEG/EventRecord/MultiColour.h" #include "ThePEG/EventRecord/SpinInfo.h" #include "ThePEG/PDT/ParticleData.h" namespace ThePEG { /** * The Particle class is used to describe an instance of a * particle. Properties of the corresponding particle type can be * accessed through a pointer to a ParticleData object. * * A Particle object contains pointers to other particles, such as a * list of parents and a list of children. It may also contain a * pointer to the previous or next instance of the same physical * particle if the properties of a given particle has been changed * during the generation. Coloured particles contains pointers to * ColourLine defining the colour connections to other particles. * * The Particle also has a pointer to the Step object where it was * first introduced in the Event. * * When printing a particle the format of the output is governed by * the static outputFormat string. When a particle is sent * to an ostream, the format string is written but with * keys prefixed by the \% character replaced with * infromation about the particle as follows:
\%\% is * replaced by a singel \%
\%C sets a flag so * that subsequent output of children and parents etc. will contain * colour information.
\%n is replaced by the particles * number in a fied ow width
\%s is replaced by the name * of the particle
\%i is replaced by the id number of * the particle type
\%x, \%y, \%z, \%e, \%m is replaced by * the x-, y-, z-, energy- and mass-component of the particles * momentum respectively
\%dx, \%dy, \%dz, \%dt, \%dT is * replaced by the x-, y-, z-, time- and invariant time-component of * the particles lifeLength respectively
\%Vx, \%Vy, \%Vz, * \%Vt is replaced by the x-, y-, z- and time-component of the * creation point relative to the vertex of the * collision.
\%Lx, \%Ly, \%Lz, \%Lt is replaced by the x-, * y-, z- and time-component of the creation point in the current * lab-system.
\%p[,] is replaced by a list (of numbers) * of the particles parents enclosed by [ and ] * and separated by ,, The parent from which the particle * inherits its (anti-) colour is marked by a (-)+
* \%c(,) is replaced by a list (of numbers) of the * particles children enclosed by ( and ) and * separated by ,, The child which inherits the particles * (anti-) colour is marked by a (-)+
\%> is replaced * by the number of the colour neighbor
\%< is * replaced by the number of the anti-colour neighbor
* \%^ is replaced by the number of the previous instance of * the same physical particle
\%v is replaced by the * number of the next instance of the same physical particle.
* \%l{,} is replaced by the indices of the colour lines to * which this particle is connected enclosed by { and * } and separated by ,, The line corresponding * to the (anti-) colour of the particle is prefixed by a (-)+ * * @see Event * @see Collision * @see Step * @see SubProcess * @see Lorentz5Vector * @see ColourLine * @see ColourBase */ class Particle: public EventRecordBase { public: /** Most of the Event classes are friends with each other. */ friend class Event; /** Most of the Event classes are friends with each other. */ friend class Collision; /** Most of the Event classes are friends with each other. */ friend class Step; /** Most of the Event classes are friends with each other. */ friend class SubProcess; /** ParticleData needs to be a friend. */ friend class ParticleData; struct ParticleRep; public: /** * Standard Constructor. Note that the default constructor is * private - there is no particle without a pointer to a * ParticleData object. */ - Particle(tcEventPDPtr newData) : theData(newData), theRep(0) {} + Particle(tcEventPDPtr newData) : theData(newData), theRep(0), theStatus(0) {} /** * Copy constructor. */ Particle(const Particle &); /** * Destructor. */ virtual ~Particle(); //@} /** @name Functions relating to ancestry of particles. */ //@{ /** * Returns true if and only if this particle has decayed. */ bool decayed() const { return hasRep() && !rep().theChildren.empty(); } /** * The list of decay products. */ const ParticleVector & children() const { static const ParticleVector null; return hasRep() ? rep().theChildren : null; } /** * Add a child (the childs parent pointer will be set accordingly). */ void addChild(tPPtr c) { rep().theChildren.push_back(c); (c->rep()).theParents.push_back(this); } /** * Remove the given child from the list of children of this particle * (the corresponding parent pointer of the child will also be * removed). */ void abandonChild(tPPtr child) { removeChild(child); child->removeParent(this); } /** * The list of parent particles. */ const tParticleVector & parents() const { static const tParticleVector null; return hasRep() ? rep().theParents : null; } /** * Return a set of neighboring particles coming from the same decay * as this one. The return value is a newly recalculated set * every time. It must be stored to be used further, do not directly call * e.g. siblings().begin() or siblings().end()! */ tParticleSet siblings() const; /** * Undo the decay of this particle, removing all children (and * grand children ...) from the event record */ void undecay() { if ( hasRep() ) { rep().theChildren.clear(); rep().theNext = tPPtr(); } } /** * If this particle has decayed set the corresponding decay mode. */ void decayMode(tDMPtr dm) { rep().theDecayMode = dm; } /** * If this particle has decayed get the corresponding decay mode. */ tDMPtr decayMode() const { return hasRep() ? rep().theDecayMode : tDMPtr(); } /** * Next instance. Pointer to another instance of the same * physical particle in later steps. */ tPPtr next() const { return hasRep() ? rep().theNext : PPtr(); } /** * Previous instance. Pointer to another instance of the same * physical particle in earlier steps. */ tPPtr previous() const { return hasRep() ? rep().thePrevious : tPPtr(); } /** * Original instance. If there exists another previous instance of * this particle return this instance (recursively). */ tcPPtr original() const { return previous() ? tcPPtr(previous()->original()) : tcPPtr(this); } /** * Original instance. If there exists another previous instance of * this particle return this instance (recursively). */ tPPtr original() { return previous() ? previous()->original() : tPPtr(this); } /** * Final instance. If there exists another subsequent instance of * this particle return this instance (recursively). */ tcPPtr final() const { return next() ? tcPPtr(next()->final()) : tcPPtr(this); } /** * Final instance. If there exists another subsequent instance of * this particle return this instance (recursively). */ tPPtr final() { return next() ? next()->final() : tPPtr(this); } //@} /** @name Relations to the Event and Step. */ //@{ /** * Get the first Step object where this particle occurred. */ tStepPtr birthStep() const { return hasRep() ? rep().theBirthStep : tStepPtr(); } /** * Get the order-number for this particle in the current event. */ int number() const { return hasRep() ? rep().theNumber : 0; } + + /** + * Get the status code of the particle + */ + int status() const { return theStatus; } + + /** + * Set the status code of the particle + */ + void status(int n) { theStatus = n; } //@} /** @name Access the underlying ParticleData object. */ //@{ /** * Access the ParticleData object of this particle type */ const ParticleDataClass & data() const { return *theData; } /** * Access the ParticleData object of this particle type */ tcEventPDPtr dataPtr() const { return theData; } /** * Return the PDG name of this particle. */ const string & PDGName() const { return data().PDGName(); } /** * Return the PDG id number of this particle. */ long id() const { return data().id(); } //@} /** @name Functions to access the momentum. */ //@{ /** * Return the momentum of this particle. */ const Lorentz5Momentum & momentum() const { return theMomentum; } /** * Set the 3-momentum of this particle. The energy is set to be * consistent with the mass. */ void set3Momentum(const Momentum3 & p) { theMomentum.setVect(p); theMomentum.rescaleEnergy(); } /** * Set the momentum of this particle. Afterwards, the underlying * Lorentz5Momentum may have inconsistent mass. */ void setMomentum(const LorentzMomentum & p) { theMomentum = p; } /** * Set the momentum and mass. */ void set5Momentum(const Lorentz5Momentum & p) { theMomentum = p; } /** * Acces the mass of this particle. */ Energy mass() const { return momentum().mass(); } /** * Acces the mass of this particle type. */ Energy nominalMass() const { return data().mass(); } /** * Get the scale at which this particle is considered resolved. */ Energy2 scale() const { return hasRep() ? rep().theScale : -1.0*GeV2; } /** * Set the scale at which this particle is considered resolved. */ void scale(Energy2 q2) { rep().theScale = q2; } /** * Get the scale above which this particle should * not radiate. */ Energy2 vetoScale() const { return hasRep() ? rep().theVetoScale : -1.0*GeV2; } /** * Set the scale above which this particle should * not radiate. */ void vetoScale(Energy2 q2) { rep().theVetoScale = q2; } /** * Return the transverse mass (squared), calculated from the energy * and the longitudinal momentum. */ Energy2 mt2() const { return sqr(momentum().t()) - sqr(momentum().z()); } /** * Return the transverse mass (squared), calculated from the energy * and the longitudinal momentum. */ Energy mt() const { return sqrt(mt2()); } /** * Return the transverse mass (squared), calculated from the mass * and the transverse momentum. */ Energy2 perpmass2() const { return momentum().perp2() + momentum().mass2(); } /** * Return the transverse mass (squared), calculated from the mass * and the transverse momentum. */ Energy perpmass() const { return sqrt(perpmass2()); } /** * Return the (pseudo) rapidity. */ double rapidity() const { return ( Pplus() > ZERO && Pminus() > ZERO )? 0.5*log(Pplus()/Pminus()) : Constants::MaxFloat; } /** * Return the (pseudo) rapidity. */ double eta() const { Energy rho = momentum().rho(); return rho > abs(momentum().z())? 0.5*log((rho+momentum().z())/(rho-momentum().z())) : Constants::MaxFloat; } /** * Return the positive and negative light-cone momenta. */ Energy Pplus() const { return momentum().plus(); } /** * Return the positive and negative light-cone momenta. */ Energy Pminus() const { return momentum().minus(); } //@} /** @name Functions to access the position. */ //@{ /** * The creation vertex of this particle. The point is given * relative to the collision vertex. */ const LorentzPoint & vertex() const { static const LorentzPoint null; return hasRep() ? rep().theVertex : null; } /** * The creation vertex of this particle. The absolute * position in the lab is given. */ LorentzPoint labVertex() const; /** * The decay vertex of this particle. The point is given * relative to the collision vertex. */ LorentzPoint decayVertex() const { return vertex() + lifeLength(); } /** * The decay vertex of this particle. The absolute * position in the lab is given. */ LorentzPoint labDecayVertex() const { return labVertex() + lifeLength(); } /** * The life time/length. Return the Lorentz vector connecting the * creation to the decay vertes. */ const Lorentz5Distance & lifeLength() const { static const Lorentz5Distance null; return hasRep() ? rep().theLifeLength : null; } /** * Set the creation vertex relative to the collision vertex. */ void setVertex(const LorentzPoint & p) { rep().theVertex = p; } /** * Set the creation vertex in the lab frame of this particle. */ void setLabVertex(const LorentzPoint &); /** * Set the life length of this particle. The life time will be * automatically rescaled to be consistent with the invariant * distance. */ void setLifeLength(const Distance & d) { rep().theLifeLength.setVect(d); rep().theLifeLength.rescaleEnergy(); } /** * Set the life time/length of a particle. The invariant distance * may become inconsistent. */ void setLifeLength(const LorentzDistance & d) { rep().theLifeLength = d; } /** * Set the life time/length of a particle. */ void setLifeLength(const Lorentz5Distance & d) { rep().theLifeLength = d; } /** * The invariant life time of this particle. */ Time lifeTime() const { return lifeLength().m(); } //@} /** @name Functions for (Lorentz) transformations. */ //@{ /** * Do Lorentz transformations on this particle. */ void transform(const LorentzRotation & r); /** * Do Lorentz transformations on this particle. \a bx, \a by and \a * bz are the boost vector components. */ void boost(double bx, double by, double bz) { transform(LorentzRotation(Boost(bx, by, bz))); } /** * Do Lorentz transformations on this particle. \a b is the boost * vector. */ void boost(const Boost & b) { transform(LorentzRotation(b)); } /** * Rotate around the x-axis. */ void rotateX(double a); /** * Rotate around the y-axis. */ void rotateY(double a); /** * Rotate around the z-axis. */ void rotateZ(double a); /** * Rotate around the given \a axis. */ void rotate(double a, const Axis & axis); /** * Mirror in the xy-plane. */ void mirror() { theMomentum.setZ(-theMomentum.z()); } /** * Do Lorentz transformations on this particle and its decendants. */ void deepTransform(const LorentzRotation & r); /** * Do Lorentz transformations on this particle and its * decendants. \a bx, \a by and \a bz are the boost vector * components. */ void deepBoost(double bx, double by, double bz) { deepTransform(LorentzRotation(Boost(bx, by, bz))); } /** * Do Lorentz transformations on this particle and its * decendants. \a b is the boost vector. */ void deepBoost(const Boost & b) { deepTransform(LorentzRotation(b)); } /** * Rotate this particle and its decendants around the x-axis. */ void deepRotateX(double a); /** * Rotate this particle and its decendants around the y-axis. */ void deepRotateY(double a); /** * Rotate this particle and its decendants around the z-axis. */ void deepRotateZ(double a); /** * Rotate this particle and its decendants around the given \a axis. */ void deepRotate(double a, const Axis & axis); //@} /** @name Functions controlling possible mass/momentum inconsistencies. */ //@{ /** * Return the relative inconsistency in the mass component. */ double massError() const { return theMomentum.massError(); } /** * Return the relative inconsistency in the energy component. */ double energyError() const { return theMomentum.energyError(); } /** * Return the relative inconsistency in the spatial components. */ double rhoError() const { return theMomentum.rhoError(); } /** * Rescale energy, so that the invariant length/mass of the * LorentzVector agrees with the current one. */ void rescaleEnergy() { theMomentum.rescaleEnergy(); } /** * Rescale spatial component, so that the invariant length/mass of * the LorentzVector agrees with the current one. */ void rescaleRho() { theMomentum.rescaleRho(); } /** * Set the invariant length/mass member, so that it agrees with the * invariant length/mass of the LorentzVector. */ void rescaleMass() { theMomentum.rescaleMass(); } //@} /** @name Acces incormation about colour connections */ //@{ /** * True if this particle has colour information. To determine if * this particle is actually coloured, the coloured(), hasColour() or * hasAntiColour() methods should be used instead. */ bool hasColourInfo() const { return hasRep() && rep().theColourInfo; } /** * Return the colour lines to which this particles anti-colour is * connected. */ tColinePtr antiColourLine() const { return hasColourInfo() ? colourInfo()->antiColourLine() : tColinePtr(); } /** * Return the colour lines to which this particles (\a anti-)colour * is connected. */ tColinePtr colourLine(bool anti = false) const { if ( anti ) return antiColourLine(); return hasColourInfo() ? colourInfo()->colourLine() : tColinePtr(); } /** * Return true if the particle is connected to the given (\a anti-) * colour \a line. */ bool hasColourLine(tcColinePtr line, bool anti = false) const { return hasColourInfo() ? colourInfo()->hasColourLine(line, anti) : false; } /** * Return true if the particle is connected to the given anti-colour * \a line. */ bool hasAntiColourLine(tcColinePtr line) const { return hasColourLine(line, true); } /** * True if this particle type is not a colour singlet. */ bool coloured() const { return data().coloured(); } /** * True if this particle type carries (\a anti-)colour. */ bool hasColour(bool anti = false) const { return data().hasColour(anti); } /** * True if this particle type carries anti-colour. */ bool hasAntiColour() const { return data().hasAntiColour(); } /** * Get the ColourBase object. */ tcCBPtr colourInfo() const { return hasRep() ? rep().theColourInfo : CBPtr(); } /** * Get the ColourBase object. */ tCBPtr colourInfo() { if ( !rep().theColourInfo ) { switch(theData->iColour()) { case PDT::Colour6: case PDT::Colour6bar: rep().theColourInfo = new_ptr(MultiColour()); break; default: rep().theColourInfo = new_ptr(ColourBase()); } } return rep().theColourInfo; } /** * Set the ColourBase object. */ void colourInfo(tCBPtr c) { rep().theColourInfo = c; } /** * Get a pointer to the colour neighbor. Returns a particle in the * range \a first to \a last which colour is connected to the same * line as this particles anti-colour. If \a anti is true return * antiColourNeighbour(). */ template typename std::iterator_traits::value_type colourNeighbour(Iterator first, Iterator last, bool anti = false) const; /** * Get a pointer to the anti-colour neighbor. Returns a particle in * the range \a first to \a last which anti-colour is * connected to the same line as this particles colour. */ template typename std::iterator_traits::value_type antiColourNeighbour(Iterator first, Iterator last) const { return colourNeighbour(first, last, true); } /** * Set the colour neighbor. Connects the given particles colour to * the same colour line as this particles anti-colour. If \a anti is * true call antiColourNeighbour(tPPtr). */ void colourNeighbour(tPPtr, bool anti = false); /** * Set the anti-colour neighbor. Connects the given particles * anti-colour to the same colour line as this particles colour. */ void antiColourNeighbour(tPPtr p) { colourNeighbour(p, true); } /** * Connect colour. Create a colour line connecting to it this * particles colour and the given particles anti-colour. */ void antiColourConnect(tPPtr neighbour) { colourConnect(neighbour, true); } /** * Connect colour. Create a colour line connecting to it this * particles anti-colour and the given particles colour. If \a anti * is true call antiColourConnect(tPPtr). */ void colourConnect(tPPtr neighbour, bool anti = false) { colourNeighbour(neighbour, anti); } /** * Incoming colour. Return the parent particle which colour is * connected to the same colour line as this particle. If \a anti is * true return incomingAntiColour(). */ tPPtr incomingColour(bool anti = false) const; /** * Incoming anti-colour. Return the parent particle which * anti-colour is connected to the same colour line as this * particle. */ tPPtr incomingAntiColour() const { return incomingColour(true); } /** * Set incoming colour. Connect this particles colour to the same * colour line as the given particle. If \a anti * is true call incomingAntiColour(tPPtr). */ void incomingColour(tPPtr p, bool anti = false) { p->outgoingColour(this, anti); } /** * Set incoming anti-colour. Connect this particles anti colour to * the same colour line as the given particle. */ void incomingAntiColour(tPPtr p) { p->outgoingColour(this, true); } /** * Outgoing colour. Return the daughter particle which colour is * connected to the same colour line as this particle. If \a anti is * true return outgoingAntiColour(). */ tPPtr outgoingColour(bool anti = false) const; /** * Outgoing anti-colour. Return the daughter particle which * anti-colour is connected to the same colour line as this * particle. */ tPPtr outgoingAntiColour() const { return outgoingColour(true); } /** * Set outgoing colour. Connect this particles colour to the same * colour line as the given particle. If \a anti * is true call outgoingAntiColour(tPPtr). */ void outgoingColour(tPPtr, bool anti = false); /** * Set outgoing anti-colour. Connect this particles anti-colour to * the same colour line as the given particle. */ void outgoingAntiColour(tPPtr p) { outgoingColour(p, true); } /** * Specify colour flow. Calls outgoingColour(tPPtr,bool). */ void colourFlow(tPPtr child, bool anti = false) { outgoingColour(child, anti); } /** * Specify anticolour flow. Calls outgoingAntiColour(tPPtr,bool). */ void antiColourFlow(tPPtr child) { colourFlow(child, true); } /** * Remove all colour information; */ void resetColour() { if ( hasColourInfo() ) rep().theColourInfo = CBPtr(); } //@} /** @name Functions to access spin. */ //@{ /** * Return the Spin object. */ tcSpinPtr spinInfo() const { return hasRep() ? rep().theSpinInfo : SpinPtr(); } /** * Return the Spin object. */ tSpinPtr spinInfo() { return hasRep() ? rep().theSpinInfo : SpinPtr(); } /** * Set the Spin object. */ void spinInfo(tSpinPtr s) { rep().theSpinInfo = s; } //@} /** @name Accessing user-defined information. */ //@{ /** * Access user-defined information as a vector of EventInfoBase pointers. */ const EIVector & getInfo() const { static const EIVector null; return hasRep() ? rep().theExtraInfo : null; } /** * Access user-defined information as a vector of EventInfoBase pointers. */ EIVector & getInfo() { return rep().theExtraInfo; } //@} public: /** @name Accessing user-defined information. */ //@{ /** * True if this particle has instantiated the object with * information other than type and momentum. */ bool hasRep() const { return theRep; } /** * If this particle has only a type and momentum, instantiate the * rest of the information. */ void initFull(); //@} public: /** @name Input and output functions. */ //@{ /** * Standard function for writing to a persistent stream. */ void persistentOutput(PersistentOStream &) const; /** * Standard function for reading from a persistent stream. */ void persistentInput(PersistentIStream &, int); //@} /** * Print particle info to a stream \a os. The \a step is used to * access information about colour neighbors and other struff. */ ostream & print(ostream & os, tcStepPtr step = tcStepPtr()) const; /** * Print a range of particles. */ template static void PrintParticles(ostream & os, Iterator first, Iterator last, tcStepPtr step = tcStepPtr()); /** * Print a container of particles. */ template static inline void PrintParticles(ostream & os, const Cont & c, tcStepPtr step = tcStepPtr()) { PrintParticles(os, c.begin(), c.end(), step); } /** * Standard Init function. @see Base::Init(). */ static void Init(); /** * Specify how to print particles. The format string is analogous to * the one used by eg. the unix 'date' command as described above. */ static string outputFormat; private: /** * Standard clone function. */ virtual PPtr clone() const; /** * Rebind to cloned objects. When an Event is cloned, a shallow * copy is done first, then all Particles etc, are * cloned, and finally this method is used to see to that the * pointers in the cloned Particle points to the cloned objects. */ virtual void rebind(const EventTranslationMap &); /** * Set the order-number for this particle in the current event. */ void number(int n) { rep().theNumber = n; } /** * Remove the given particle from the list of children. */ void removeChild(tPPtr c) { if ( hasRep() ) rep().theChildren.erase(remove(rep().theChildren.begin(), rep().theChildren.end(), c), rep().theChildren.end()); } /** * Remove the given particle from the list of parents. */ void removeParent(tPPtr p) { if ( hasRep() ) rep().theParents.erase(remove(rep().theParents.begin(), rep().theParents.end(), p), rep().theParents.end()); } /** * Set the mass of this particle. */ void mass(Energy m) { theMomentum.setMass(m); } /** * Set the invaiant life time of this particle. */ void lifeTime(Length t) { rep().theLifeLength.setTau(t); } /** * Return a reference to the bulk information of this particle. if * no ParticleRep object exists, one is created. */ ParticleRep & rep() { if ( !hasRep() ) initFull(); return *theRep; } /** * Return a reference to the bulk information of this particle. if * no ParticleRep object exists, we return the default values. */ const ParticleRep & rep() const { static const ParticleRep null; return hasRep() ? *theRep : null; } /** * The pointer to the ParticleData object */ cEventPDPtr theData; /** * The momentum. */ Lorentz5Momentum theMomentum; /** * The rest of the information in this particle is only instantiated * if needed. */ ParticleRep * theRep; + /** + * The status code of the particle + */ + int theStatus; + public: /** * This class is used internally in the Particle class to represent * information besides momentum and type. A corresponding object * will only be instantiated if needed to save memory and time when * temporarily creating particles. */ struct ParticleRep { /** * Default constructor. */ ParticleRep() : theScale(-1.0*GeV2), theVetoScale(-1.0*GeV2), theNumber(0) {} /** * Copy constructor. */ ParticleRep(const ParticleRep &); /** * The pointers to the parents. */ tParticleVector theParents; /** * The pointers to the children. */ ParticleVector theChildren; /** * The pointer to the previous instance. */ tPPtr thePrevious; /** * The pointer to the next instance. */ PPtr theNext; /** * If this particle has decayed this is the pointer to the * corresponding decay mode. */ tDMPtr theDecayMode; /** * The pointer to the first step where this particle occurred. */ tStepPtr theBirthStep; /** * The creation point. */ LorentzPoint theVertex; /** * The life time/length. */ Lorentz5Distance theLifeLength; /** * the resolution scale. */ Energy2 theScale; /** * the veto scale. */ Energy2 theVetoScale; /** * The order-number for this particle in the current event. */ int theNumber; /** * A pointer to the colour information object. */ CBPtr theColourInfo; /** * Spin information */ SpinPtr theSpinInfo; /** * Additional used-defined information. */ EIVector theExtraInfo; }; public: /** * Print out debugging information for this object on std::cerr. To * be called from within a debugger via the debug() function. */ virtual void debugme() const; protected: /** * Private default constructor must only be used by the * PersistentIStream class via the ClassTraits class. */ - Particle() : theRep(0) {} + Particle() : theRep(0), theStatus(0) {} /** * The ClassTraits class must be a friend to be able to * use the private default constructor. */ friend struct ClassTraits; private: /** * Private and non-existent assignment. */ Particle & operator=(const Particle &) = delete; /** * Describe concrete class with persistent data. */ static ClassDescription initParticle; }; /** * Write a Particle object to a stream. */ ostream & operator<<(ostream &, const Particle &); /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base class of Particle. */ template <> struct BaseClassTrait: public ClassTraitsType { /** Typedef of the first base class of Collision. */ typedef EventRecordBase NthBase; }; /** This template specialization informs ThePEG about the name of * the Particle class and how to create it. */ template <> struct ClassTraits: public ClassTraitsBase { /** Return a platform-independent class name */ static string className() { return "ThePEG::Particle"; } /** Create a Particle object. */ static TPtr create() { return TPtr::Create(Particle()); } }; /** @endcond */ } #ifndef ThePEG_TEMPLATES_IN_CC_FILE #include "Particle.tcc" #endif #endif /* ThePEG_Particle_H */ diff --git a/Helicity/Vertex/AbstractSSSSVertex.cc b/Helicity/Vertex/AbstractSSSSVertex.cc --- a/Helicity/Vertex/AbstractSSSSVertex.cc +++ b/Helicity/Vertex/AbstractSSSSVertex.cc @@ -1,32 +1,26 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the AbstractSSSSVertex class. // #include "AbstractSSSSVertex.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" using namespace ThePEG; using namespace Helicity; // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractNoPIOClass describeThePEGAbstractSSSSVertex("ThePEG::AbstractSSSSVertex", "libThePEG.so"); void AbstractSSSSVertex::Init() { static ClassDocumentation documentation ("The AbstractSSSSVertex class is the base class for all " "scalar-scalar-scalar-scalar interactions"); } -ScalarWaveFunction AbstractSSSSVertex::evaluate(Energy2,int, tcPDPtr, - const ScalarWaveFunction & , - const ScalarWaveFunction & , - const ScalarWaveFunction & ) { - assert(false); -} diff --git a/Helicity/Vertex/AbstractSSSSVertex.h b/Helicity/Vertex/AbstractSSSSVertex.h --- a/Helicity/Vertex/AbstractSSSSVertex.h +++ b/Helicity/Vertex/AbstractSSSSVertex.h @@ -1,88 +1,88 @@ // -*- C++ -*- #ifndef HELICITY_AbstractSSSSVertex_H #define HELICITY_AbstractSSSSVertex_H // // This is the declaration of the AbstractSSSSVertex class. // #include "VertexBase.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "AbstractSSSSVertex.fh" namespace ThePEG { namespace Helicity { /** * The AbstractSSSSVertex class is the base class for all scalar-scalar-scalar * interactions in ThePEG */ class AbstractSSSSVertex: public VertexBase { public: /** * Default constructor */ AbstractSSSSVertex() : VertexBase(VertexType::SSSS) {} /** * Members to calculate the helicity amplitude expressions for vertices * and off-shell particles. */ //@{ /** * Evaluate the vertex. * @param q2 The scale \f$q^2\f$ for the coupling at the vertex. * @param sca1 The wavefunction for the first scalar. * @param sca2 The wavefunction for the second scalar. * @param sca3 The wavefunction for the third scalar. * @param sca4 The wavefunction for the fourth scalar. */ virtual Complex evaluate(Energy2 q2,const ScalarWaveFunction & sca1, const ScalarWaveFunction & sca2, const ScalarWaveFunction & sca3, const ScalarWaveFunction & sca4) = 0; /** * Evaluate the off-shell scalar coming from the vertex. * @param q2 The scale \f$q^2\f$ for the coupling at the vertex. * @param iopt Option of the shape of the Breit-Wigner for the off-shell scalar. * @param out The ParticleData pointer for the off-shell scalar. * @param sca1 The wavefunction for the first scalar. * @param sca2 The wavefunction for the second scalar. * @param sca3 The wavefunction for the third scalar. */ virtual ScalarWaveFunction evaluate(Energy2 q2,int iopt, tcPDPtr out, const ScalarWaveFunction & sca1, const ScalarWaveFunction & sca2, - const ScalarWaveFunction & sca3); + const ScalarWaveFunction & sca3)=0; //@} public: /** * The standard Init function used to initialize the interfaces. * Called exactly once for each class by the class description system * before the main function starts or * when this class is dynamically loaded. */ static void Init(); private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ AbstractSSSSVertex & operator=(const AbstractSSSSVertex &) = delete; }; } } namespace ThePEG { } #endif /* HELICITY_AbstractSSSSVertex_H */ diff --git a/PDF/PartonExtractor.cc b/PDF/PartonExtractor.cc --- a/PDF/PartonExtractor.cc +++ b/PDF/PartonExtractor.cc @@ -1,653 +1,654 @@ // -*- C++ -*- // // PartonExtractor.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the PartonExtractor class. // #include "PartonExtractor.h" #include "ThePEG/Handlers/XComb.h" #include "ThePEG/Cuts/Cuts.h" #include "ThePEG/PDF/NoPDF.h" #include "ThePEG/PDF/RemnantHandler.h" #include "ThePEG/PDF/BeamParticleData.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/EventRecord/Step.h" #include "ThePEG/EventRecord/SubProcess.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "ThePEG/Utilities/UtilityBase.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/PDT/EnumParticles.h" using namespace ThePEG; PartonExtractor::PartonExtractor() : theMaxTries(100), flatSHatY(false) {} PartonExtractor::~PartonExtractor() {} IBPtr PartonExtractor::clone() const { return new_ptr(*this); } IBPtr PartonExtractor::fullclone() const { return new_ptr(*this); } PartonPairVec PartonExtractor:: getPartons(Energy maxEnergy, const cPDPair & incoming, const Cuts & kc) const { PartonPairVec result; PartonVector first; PDFCuts cuts1(kc, true, maxEnergy); PBPtr p1 = new_ptr(PartonBin(PDPtr(), PBPtr(), incoming.first, PDFPtr(), cuts1)); addPartons(p1, cuts1, theFirstPDF, first); PartonVector second; PDFCuts cuts2(kc, false, maxEnergy); PBPtr p2 = new_ptr(PartonBin(PDPtr(), PBPtr(), incoming.second, PDFPtr(), cuts2)); addPartons(p2, cuts2, theSecondPDF, second); for ( PartonVector::iterator it1 = first.begin(); it1 != first.end(); ++it1 ) for ( PartonVector::iterator it2 = second.begin(); it2 != second.end(); ++it2 ) result.push_back(PBPair(*it1, *it2)); // We add the original parton bins as well to avoid them being // deleted. result.push_back(PBPair(p1, p2)); return result; } void PartonExtractor:: addPartons(tPBPtr incoming, const PDFCuts & cuts, tcPDFPtr pdf, PartonVector & pbins) const { if(!pdf) pdf = getPDF(incoming->parton()); if ( dynamic_ptr_cast::tcp>(pdf) || incoming->parton() == incoming->particle() ) { pbins.push_back(incoming); return; } cPDVector partons = pdf->partons(incoming->parton()); for ( int i = 0, N = partons.size(); i < N; ++i ) { PBPtr pb = new_ptr(PartonBin(incoming->parton(), incoming, partons[i], pdf, cuts)); incoming->addOutgoing(pb); addPartons(pb, cuts, PDFPtr(), pbins); } } tcPDFPtr PartonExtractor::getPDF(tcPDPtr particle) const { for ( vector::const_iterator it = theSpecialDensities.begin(); it != theSpecialDensities.end(); ++it ) if ( (**it).canHandle(particle) ) return *it; Ptr::tcp p = dynamic_ptr_cast::tcp>(particle); if ( !p || !p->pdf() ) return noPDF(); return p->pdf(); } void PartonExtractor::select(tXCombPtr newXComb) { theLastXComb = newXComb; } tPBIPtr PartonExtractor::partonBinInstance(tcPPtr p) const { PartonBinInstanceMap::const_iterator it = partonBinInstances().find(p); return it == partonBinInstances().end()? PBIPtr(): it->second; } void PartonExtractor:: colourConnect(tPPtr particle, tPPtr parton, const tPVector & remnants) const { // Sorry cannot handle coloured resolved particles. if ( particle->coloured() ) throw RemColException(*this); // First connect the loose colour line from the extacted parton. if ( parton->hasColour() ) findConnect(parton->colourLine(), parton, true, remnants.rbegin(), remnants.rend()); // First connect the loose anti-colour line from the extacted parton. if ( parton->hasAntiColour() ) findConnect(parton->antiColourLine(), parton, false, remnants.begin(), remnants.end()); // Go through the rest of the remnants and create new colour lines // if needed. Go through it forwards and backwards to catch possible // inconsistencies. for ( tPVector::const_iterator it = remnants.begin(); it != remnants.end(); ++it ) { if ( (**it).hasAntiColour() && !(**it).antiColourLine() ) findConnect(ColourLine::create(*it, true), *it, false, it + 1, remnants.end()); } for ( tPVector::const_reverse_iterator it = remnants.rbegin(); it != remnants.rend(); ++it ) { if ( (**it).hasColour() && !(**it).colourLine() ) findConnect(ColourLine::create(*it), *it, true, it + 1, remnants.rend()); } } Energy2 PartonExtractor::newScale() { return lastScale(); } pair PartonExtractor::nDims(const PBPair & pbins) { // if photon from a lepton or proton generate scale bool genscale[2]={false,false}; for(unsigned int ix=0;ix<2;++ix) { PBPtr bin = ix==0 ? pbins.first : pbins.second; if (!bin || !bin->particle() || !bin->parton()) continue; if(bin->pdf()->partons(bin->particle()).size()==1 && bin->particle()->id()!=bin->parton()->id()) genscale[ix]=true; } return make_pair(pbins.first ->nDim(genscale[0]), pbins.second->nDim(genscale[1])); } void PartonExtractor::prepare(const PBIPair & pbins) { partonBinInstances().clear(); pbins.first->prepare(); pbins.second->prepare(); } void PartonExtractor::updatePartonBinInstances(const PBIPair & pbins) { partonBinInstances().clear(); tPBIPtr current = pbins.first; while ( current->incoming() ) { partonBinInstances()[current->parton()] = current; current = current->incoming(); } current = pbins.second; while ( current->incoming() ) { partonBinInstances()[current->parton()] = current; current = current->incoming(); } } bool PartonExtractor:: generateL(const PBIPair & pbins, const double * r1, const double * r2) { Direction<0> dir(true); generateL(*pbins.first, r1); dir.reverse(); generateL(*pbins.second, r2); if ( !flatSHatY || pbins.first->hasPoleIn1() || pbins.second->hasPoleIn1() ) return true; Energy2 shmax = lastCuts().sHatMax(); Energy2 shmin = lastCuts().sHatMin(); Energy2 sh = shmin*pow(shmax/shmin, *r1); double ymax = lastCuts().yHatMax(); double ymin = lastCuts().yHatMin(); double km = log(shmax/shmin); ymax = min(ymax, log(lastCuts().x1Max()*sqrt(lastS()/sh))); ymin = max(ymin, -log(lastCuts().x2Max()*sqrt(lastS()/sh))); double y = ymin + (*r2)*(ymax - ymin); double l1 = 0.5*log(lastS()/sh) - y; double l2 = 0.5*log(lastS()/sh) + y; pbins.first->li(l1 - pbins.first->l() + pbins.first->li()); pbins.first->l(l1); pbins.first->jacobian(km*(ymax - ymin)); pbins.second->li(l2 - pbins.second->l() + pbins.second->li()); pbins.second->l(l2); pbins.second->jacobian(1.0); return ( pbins.first->li() >= 0.0 && pbins.second->li() >= 0.0 ); } Energy2 PartonExtractor:: generateSHat(Energy2, const PBIPair & pbins, const double * r1, const double * r2, bool haveMEPartons) { Direction<0> dir(true); if(pbins.first->bin()->pdfDim()<=1) pbins.first->scale(-lastScale()); if ( !generate(*pbins.first, r1, lastSHat(), pbins.first->getFirst()->parton()->momentum(), haveMEPartons) ) return -1.0*GeV2; dir.reverse(); if(pbins.second->bin()->pdfDim()<=1) pbins.second->scale(-lastScale()); if ( !generate(*pbins.second, r2, lastSHat(), pbins.second->getFirst()->parton()->momentum(), haveMEPartons) ) return -1.0*GeV2; return (pbins.first->parton()->momentum() + pbins.second->parton()->momentum()).m2(); } void PartonExtractor:: generateL(PartonBinInstance & pb, const double * r) { if ( !pb.incoming() ) return; pb.parton(pb.partonData()->produceParticle(Lorentz5Momentum())); generateL(*pb.incoming(), r + pb.bin()->pdfDim() + pb.bin()->remDim()); pb.particle(pb.incoming()->parton()); if ( pb.li() >= 0 ) return; double jac = 1.0; if ( pb.bin()->pdfDim() ) pb.li(pb.pdf()->flattenL(pb.particleData(), pb.partonData(), pb.bin()->cuts(), *r++, jac)); pb.scale(-1.0*GeV2); if ( pb.bin()->pdfDim() > 1 ) pb.scale(pb.pdf()->flattenScale(pb.particleData(), pb.partonData(), pb.bin()->cuts(), pb.li(), *r++, jac) *pb.bin()->cuts().scaleMaxL(pb.li())); pb.jacobian(jac); pb.l(pb.incoming()->l() + pb.li()); } bool PartonExtractor:: generate(PartonBinInstance & pb, const double * r, Energy2 shat, const Lorentz5Momentum & first, bool haveMEPartons) { if ( !pb.incoming() ) return true; if ( !generate(*pb.incoming(), r + pb.bin()->pdfDim() + pb.bin()->remDim(), shat/pb.xi(), first) ) return false; pb.remnantWeight(1.0); - pb.parton()->setMomentum + pb.parton()->set5Momentum (pb.remnantHandler()->generate(pb, r + pb.bin()->pdfDim(), pb.scale(), shat, pb.particle()->momentum(),haveMEPartons)); if ( pb.remnantWeight() <= 0.0 ) return false; partonBinInstances()[pb.parton()] = &pb; return true; } void PartonExtractor:: constructRemnants(const PBIPair & pbins, tSubProPtr sub, tStepPtr step) const { partonBinInstances().clear(); LorentzMomentum k1 = pbins.first->parton()->momentum(); LorentzMomentum k2 = pbins.second->parton()->momentum(); LorentzMomentum Ph = k1 + k2; LorentzMomentum Phold = Ph; LorentzRotation Rh = Utilities::getBoostToCM(make_pair(k1, k2)); bool pickside = rndbool(); if ( pickside && pbins.first->incoming() ) { Direction<0> dir(true); constructRemnants(*pbins.first, Ph, k2); construct(*pbins.first, step, false); } if ( pbins.second->incoming() ) { Direction<0> dir(false); constructRemnants(*pbins.second, Ph, pbins.first->parton()->momentum()); construct(*pbins.second, step, false); } if ( (!pickside) && pbins.first->incoming() ) { Direction<0> dir(true); constructRemnants(*pbins.first, Ph, pbins.second->parton()->momentum()); construct(*pbins.first, step, false); } // LorentzRotation rot = Utilities::transformToMomentum(Phold, Ph); k1 = pbins.first->parton()->momentum(); k2 = pbins.second->parton()->momentum(); LorentzRotation rot = Utilities::getBoostFromCM(make_pair(k1, k2))*Rh; Utilities::transform(sub->outgoing(), rot); Utilities::transform(sub->intermediates(), rot); Ph = k1 + k2; if ( abs(Ph.m2() - Phold.m2())/Phold.m2() > 0.000001 ) cerr << Ph.m2()/GeV2 << " was (" << Phold.m2()/GeV2 << ")" << endl; } void PartonExtractor:: constructRemnants(PartonBinInstance & pb, LorentzMomentum & Ph, const LorentzMomentum & k) const { LorentzMomentum P = pb.particle()->momentum(); DVector r = UseRandom::rndvec(pb.bin()->remDim()); if ( r.empty() ) r.push_back(0.0); pb.parton()->setMomentum(pb.remnantHandler()-> generate(pb, &r[0], pb.scale(), Ph.m2(), P)); if ( pb.remnantWeight() <= 0.0 ) throw Veto(); pb.remnantHandler()->boostRemnants(pb); LorentzMomentum Pr = Utilities::sumMomentum(pb.remnants()); transformRemnants(Ph, Pr, k, pb.particle()->momentum()); pb.parton()->setMomentum(pb.particle()->momentum() - Pr); try { Utilities::setMomentum(pb.remnants().begin(), pb.remnants().end(), static_cast(Pr)); } catch ( ThePEG::Exception & e) { throw e; } catch ( ThePEG::Veto ) { throw; } catch ( std::exception & e ) { throw Exception() << "Caught non-ThePEG exception " << e.what() << "in " << "PartonExtractor::constructRemnants" << Exception::eventerror; } partonBinInstances()[pb.parton()] = &pb; if ( !pb.incoming()->incoming() ) return; // We get here if we need to construct remnants recursively. LorentzMomentum Phnew = Ph + Pr; constructRemnants(*pb.incoming(), Phnew, k); LorentzRotation rot = Utilities::transformToMomentum(Ph + Pr, Phnew); Utilities::transform(pb.remnants(), rot); Ph.transform(rot); } LorentzRotation PartonExtractor:: boostRemnants(PBIPair & bins, LorentzMomentum k1, LorentzMomentum k2, bool side1, bool side2) const { if ( !side1 && !side2 ) return LorentzRotation(); LorentzMomentum P1 = bins.first? LorentzMomentum(bins.first->parton()->momentum()): k1; LorentzMomentum Pr1; if ( side1 ) { P1 = bins.first->particle()->momentum(); Pr1 = Utilities::sumMomentum(bins.first->remnants()); } LorentzMomentum P2 = bins.second? LorentzMomentum(bins.second->parton()->momentum()): k2; LorentzMomentum Pr2; if ( side2 ) { P2 = bins.second->particle()->momentum(); Pr2 = Utilities::sumMomentum(bins.second->remnants()); } LorentzRotation Rh = Utilities::getBoostToCM(make_pair(k1, k2)); LorentzMomentum Ph = k1 + k2; // LorentzMomentum Phold = Ph; bool otherside = rndbool(); if ( otherside && side2 ){ Direction<0> dir(false); transformRemnants(Ph, Pr2, k1, P2); k2 = P2 - Pr2; } if ( side1 ){ Direction<0> dir(true); transformRemnants(Ph, Pr1, k2, P1); k1 = P1 - Pr1; } if ( side2 && !otherside ) { Direction<0> dir(false); transformRemnants(Ph, Pr2, k1, P2); k2 = P2 - Pr2; } if ( bins.first ) { if ( bins.first->remnants().size() == 1 ) bins.first->remnants()[0]->setMomentum(Pr1); else Utilities::setMomentum(bins.first->remnants().begin(), bins.first->remnants().end(), static_cast(Pr1)); bins.first->parton()->setMomentum(k1); } if ( bins.second ) { if ( bins.second->remnants().size() == 1 ) bins.second->remnants()[0]->setMomentum(Pr2); else Utilities::setMomentum(bins.second->remnants().begin(), bins.second->remnants().end(), static_cast(Pr2)); bins.second->parton()->setMomentum(k2); } Rh.transform(Utilities::getBoostFromCM(make_pair(k1, k2))); // LorentzMomentum phh = Rh*Phold; return Rh; // return Utilities::transformToMomentum(Phold, Ph); } void PartonExtractor:: transformRemnants(LorentzMomentum & Ph, LorentzMomentum & Pr, const LorentzMomentum & k, const LorentzMomentum & P) const { // don't do this for very soft remnants, as // we may run into numerical troubles; threshold // needs to become a parameter at some point if ( Pr.vect().mag2()/k.vect().mag2() < 1e-10 && sqr(Pr.e()/k.e()) < 1e-10 ) return; TransverseMomentum pt = Pr; try { if ( Direction<0>::pos() ) SimplePhaseSpace::CMS(Pr, Ph, (P + k).m2(), 1.0, 0.0); else SimplePhaseSpace::CMS(Ph, Pr, (k + P).m2(), 1.0, 0.0); LorentzRotation rpt; if ( sqr(Pr.z()) > ZERO ) rpt.rotateY(asin(pt.pt()/Pr.z())); rpt.rotateZ(pt.phi()); rpt = Direction<0>::pos()? Utilities::getBoostFromCM(make_pair(P, k))*rpt: Utilities::getBoostFromCM(make_pair(k, P))*rpt; Ph.transform(rpt); Pr.transform(rpt); } catch ( ImpossibleKinematics & e ) {} } double PartonExtractor::fullFn(const PBIPair & pbins, Energy2 scale, pair noLastPDF) { if(pbins.first->bin()->pdfDim()<=1) pbins.first->scale(scale); if(pbins.second->bin()->pdfDim()<=1) pbins.second->scale(scale); return fullFn(*pbins.first,noLastPDF.first)*fullFn(*pbins.second,noLastPDF.second); } double PartonExtractor::fullFn(const PartonBinInstance & pb, bool noLastPDF) { if ( !pb.incoming() ) return 1.0; if (noLastPDF) return fullFn(*pb.incoming(),false) * pb.jacobian() * pb.remnantWeight() * exp(-pb.li()); return fullFn(*pb.incoming(),false) * pb.jacobian() * pb.remnantWeight() * pb.pdf()->xfl(pb.particleData(), pb.partonData(), pb.scale(), pb.li(), pb.incoming()->scale()); } void PartonExtractor:: construct(const PBIPair & pbins, tStepPtr step) const { // if a long chain we need to break some mother/child relationships if(pbins.first->incoming()) { if(pbins.first->incoming()->incoming()) { if(!pbins.first->parton()->parents().empty()) { tParticleVector parents=pbins.first->parton()->parents(); tPPtr parton = pbins.first->parton(); for(unsigned int ix=0;ixabandonChild(parton); } } } if(pbins.second->incoming()) { if(pbins.second->incoming()->incoming()) { if(!pbins.second->parton()->parents().empty()) { tParticleVector parents=pbins.second->parton()->parents(); tPPtr parton = pbins.second->parton(); for(unsigned int ix=0;ixabandonChild(parton); } } } Direction<0> dir(true); construct(*pbins.first, step); dir.reverse(); construct(*pbins.second, step); } void PartonExtractor:: construct(PartonBinInstance & pb, tStepPtr step, bool boost) const { if ( !pb.incoming() ) return; if ( boost ) pb.remnantHandler()->boostRemnants(pb); if ( pb.incoming()->incoming() ) { step->insertIntermediate(pb.particle(),pb.incoming()->particle(),pb.parton()); } tPVector rem(pb.remnants().begin(), pb.remnants().end()); if ( !step->addDecayProduct(pb.particle(), rem.begin(), rem.end(), false) ) {} colourConnect(pb.particle(), pb.parton(), rem); construct(*pb.incoming(), step); } PBIPair PartonExtractor::newRemnants(tPPair oldp, tPPair newp, tStepPtr step) { PBIPair pb; Direction<0> dir(true); pb.first = newRemnants(partonBinInstance(oldp.first), newp.first, newp.second->momentum()); dir.reverse(); pb.second = newRemnants(partonBinInstance(oldp.second), newp.second, newp.first->momentum()); addNewRemnants(partonBinInstance(oldp.first), pb.first, step); addNewRemnants(partonBinInstance(oldp.second), pb.second, step); return pb; } PBIPtr PartonExtractor:: newRemnants(tPBIPtr oldpb, tPPtr newp, const LorentzMomentum & k) { if ( ! oldpb || !oldpb->incoming() ) return oldpb; Energy2 shat = (k + newp->momentum()).m2(); // Loop over all possible PartonBin sisters to find the one // corresponding to the newly extracted parton. const PartonBin::PBVector & sisters = oldpb->incoming()->bin()->outgoing(); for ( int i = 0, N = sisters.size(); i < N; ++i ) if ( sisters[i]->parton() == newp->dataPtr() ) { // Setup necessary info in new PartonBinInstance object. PBIPtr newpb = new_ptr(PartonBinInstance(sisters[i], oldpb->incoming())); newpb->particle(oldpb->particle()); newpb->parton(newp); newpb->li(log(oldpb->particle()->momentum().dirPlus()/ newp->momentum().dirPlus())); newpb->l(oldpb->l() - oldpb->li() + newpb->li()); Energy2 sc = -newp->scale(); newpb->scale(newp->scale()); if ( oldpb->incoming()->incoming() ) sc = -newpb->particle()->momentum().m2(); // Now we can construct the new remnants. newpb->remnantWeight(1.0); if ( !newpb->remnantHandler()-> recreateRemnants(*newpb, oldpb->parton(), newp, newpb->li(), sc, shat, newpb->particle()->momentum()) ) throw Veto(); if ( newpb->remnantWeight() <= 0.0 ) throw Veto(); return newpb; } throw Veto(); } void PartonExtractor:: addNewRemnants(tPBIPtr oldpb, tPBIPtr newpb, tStepPtr step) { if ( oldpb == newpb ) return; if ( oldpb->parton() != newpb->parton() ) { step->removeDecayProduct(newpb->particle(), oldpb->parton()); if ( !step->addDecayProduct(newpb->particle(), newpb->parton()) ) throw Veto(); } tPVector rem(newpb->remnants().begin(), newpb->remnants().end()); colourConnect(newpb->particle(), newpb->parton(), rem); partonBinInstances()[newpb->parton()] = newpb; if ( !step->addDecayProduct(oldpb->remnants().begin(), oldpb->remnants().end(), rem.begin(), rem.end()) ) throw Veto(); } void PartonExtractor::persistentOutput(PersistentOStream & os) const { os << theLastXComb << theSpecialDensities << theNoPDF << theMaxTries << flatSHatY << theFirstPDF << theSecondPDF; } void PartonExtractor::persistentInput(PersistentIStream & is, int) { is >> theLastXComb >> theSpecialDensities >> theNoPDF >> theMaxTries >> flatSHatY >> theFirstPDF >> theSecondPDF; } ClassDescription PartonExtractor::initPartonExtractor; void PartonExtractor::Init() { static ClassDocumentation documentation ("There is no documentation for the ThePEG::PartonExtractor class"); static RefVector interfaceSpecialDensities ("SpecialDensities", "A list of parton density objects to be used for incoming particles " "overriding possible densities given for particles of the " "BeamParticleData class.", &PartonExtractor::theSpecialDensities, 0, false, false, true, false); static Reference interfaceNoPDF ("NoPDF", "A fixed reference to a NoPDF object to be used for particles without " "substructure.", &PartonExtractor::theNoPDF, true, true, true, false); static Parameter interfaceMaxTries ("MaxTries", "The maximum number of attempts allowed when trying to generate " "remnants.", &PartonExtractor::theMaxTries, 100, 1, 1000, false, false, true); static Switch interfaceFlatSHatY ("FlatSHatY", "The possibility to override the l-generation in the PDFs and generate " "a flat distribution in \\f$\\log(\\hat{s})\\f$ and \\f$y\\f$. This only " "applies if the parton densities do not have poles in \\f$x=1\\f$.", &PartonExtractor::flatSHatY, false, false, false); static SwitchOption interfaceFlatSHatY0 (interfaceFlatSHatY, "Off", "Use the l-generation defined by the PDFs", false); static SwitchOption interfaceFlatSHatY1 (interfaceFlatSHatY, "On", "Generate flat rapidity and \\f$\\log(\\hat{s})\\f$", true); static SwitchOption interfaceFlatSHatNo (interfaceFlatSHatY, "No", "Use the l-generation defined by the PDFs", false); static SwitchOption interfaceFlatSHatYes (interfaceFlatSHatY, "Yes", "Generate flat rapidity and \\f$\\log(\\hat{s})\\f$", true); static Reference interfaceFirstPDF ("FirstPDF", "PDF to override the default PDF for the first beam particle", &PartonExtractor::theFirstPDF, false, false, true, true, false); static Reference interfaceSecondPDF ("SecondPDF", "PDF to override the default PDF for the second beam particle", &PartonExtractor::theSecondPDF, false, false, true, true, false); } RemColException::RemColException(const PartonExtractor & pe) { theMessage << "Parton extractor '" << pe.name() << "' failed to connect " << "the colours of the outgoing partons and the remnants."; severity(maybeabort); } void PartonExtractor::dofinish() { - partonBinInstances().clear(); + // Only clear partonBinInstances if we have a lastXCombPtr + if(lastXCombPtr()) partonBinInstances().clear(); HandlerBase::dofinish(); } diff --git a/PDT/QuarksToHadronsDecayer.cc b/PDT/QuarksToHadronsDecayer.cc --- a/PDT/QuarksToHadronsDecayer.cc +++ b/PDT/QuarksToHadronsDecayer.cc @@ -1,235 +1,236 @@ // -*- C++ -*- // // QuarksToHadronsDecayer.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the QuarksToHadronsDecayer class. // #include "QuarksToHadronsDecayer.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/PDT/StandardMatchers.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" using namespace ThePEG; QuarksToHadronsDecayer::~QuarksToHadronsDecayer() {} IBPtr QuarksToHadronsDecayer::clone() const { return new_ptr(*this); } IBPtr QuarksToHadronsDecayer::fullclone() const { return new_ptr(*this); } bool QuarksToHadronsDecayer::accept(const DecayMode & dm) const { int col = 0; int acol = 0; if ( !dm.productMatchers().empty() ) { for ( MatcherMSet::const_iterator it = dm.productMatchers().begin(); it != dm.productMatchers().end(); ++it ) { - if ( typeid(**it) == typeid(MatchLightQuark) ) ++col; - else if ( typeid(**it) == typeid(MatchLightAntiQuark) ) ++acol; + const auto & tmp=**it; + if ( typeid(tmp) == typeid(MatchLightQuark) ) ++col; + else if ( typeid(tmp) == typeid(MatchLightAntiQuark) ) ++acol; else return false; } if ( col != 1 || col != acol ) return false; } if ( dm.orderedProducts().size() + col + acol < 2 || !dm.cascadeProducts().empty() || dm.wildProductMatcher() ) return false; for ( int i = 0, N = dm.orderedProducts().size(); i < N; ++i ) { if ( DiquarkMatcher::Check(*dm.orderedProducts()[i]) ) { if ( i + 1 != N ) return false; if ( dm.orderedProducts()[i]->id() < 0 ) ++col; else ++acol; } if ( QuarkMatcher::Check(*dm.orderedProducts()[i]) ) { if ( dm.orderedProducts()[i]->id() > 0 ) ++col; else ++acol; } } if ( acol != col || col < 1 || col > 2 ) return false; return true; } PVector QuarksToHadronsDecayer::decay(const DecayMode & dm, const Particle & parent) const { PVector children; tcPDVector quarks; if ( !dm.productMatchers().empty() ) { tcPDPtr pd = getParticleData(flavourGenerator()->selectQuark()); quarks.push_back(pd); quarks.push_back(pd->CC()); } Energy summq = ZERO; Energy summp = ZERO; tPDVector prods = dm.orderedProducts(); for ( int i = 0, N = prods.size(); i < N; ++i ) if ( QuarkMatcher::Check(*prods[i]) || DiquarkMatcher::Check(*prods[i])) { quarks.push_back(prods[i]); summq += quarks.back()->mass(); } else { children.push_back(prods[i]->produceParticle()); summp += children.back()->mass(); } Energy summh = ZERO; PVector hadrons; if ( !quarks.empty() ) do { hadrons = getHadrons(getN(parent.mass(), summq, quarks.size()), quarks); summh = ZERO; for ( int i = 0, N = hadrons.size(); i < N; ++i ) summh += hadrons[i]->mass(); } while ( hadrons.empty() || summp + summh >= parent.mass() ); children.insert(children.end(), hadrons.begin(), hadrons.end()); distribute(parent, children); finalBoost(parent, children); setScales(parent, children); return children; } int QuarksToHadronsDecayer::getN(Energy m0, Energy summq, int Nq) const { int Nh = fixedN(); if ( Nh >= 2 ) return Nh; double c = c1()*log((m0 - summq)/c2()) + c3(); if ( c < 0.0 ) return minN(); while ( true ) { using namespace Constants; Nh = int(0.5 + double(Nq)/4.0 + c + sqrt(-2.0*c*log(max(1.0e-10, rnd())))*sin(2.0*pi*rnd())); if ( Nh >= minN() ) return Nh; } } PVector QuarksToHadronsDecayer:: getHadrons(int Nh, tcPDVector quarks) const { PVector hadrons; Nh -= quarks.size()/2; while ( Nh-- > 0 ) { int i = irnd(quarks.size() - 1); tcPDPair hq = flavourGenerator()->alwaysGenerateHadron(quarks[i]); hadrons.push_back(hq.first->produceParticle()); quarks[i] = hq.second; } if ( DiquarkMatcher::Check(*quarks[0]) && DiquarkMatcher::Check(*quarks[1]) ) return PVector(); tcPDPtr h = flavourGenerator()->alwaysGetHadron(quarks[0], quarks[1]); hadrons.push_back(h->produceParticle()); if ( quarks.size() <= 2 ) return hadrons; if ( DiquarkMatcher::Check(*quarks[2]) && DiquarkMatcher::Check(*quarks[3]) ) return PVector(); h = flavourGenerator()->alwaysGetHadron(quarks[2], quarks[3]); hadrons.push_back(h->produceParticle()); return hadrons; } void QuarksToHadronsDecayer:: distribute(const Particle & parent, PVector & children) const { do { try { SimplePhaseSpace::CMSn(children, parent.mass()); } catch ( ImpossibleKinematics & e) { children.clear(); return; } } while ( reweight(parent, children) < rnd() ); } double QuarksToHadronsDecayer:: reweight(const Particle &, const PVector &) const { return 1.0; } void QuarksToHadronsDecayer::persistentOutput(PersistentOStream & os) const { os << theFixedN << theMinN << theC1 << ounit(theC2,GeV) << theC3 << theFlavourGenerator; } void QuarksToHadronsDecayer::persistentInput(PersistentIStream & is, int) { is >> theFixedN >> theMinN >> theC1 >> iunit(theC2,GeV) >> theC3 >> theFlavourGenerator; } ClassDescription QuarksToHadronsDecayer::initQuarksToHadronsDecayer; // Definition of the static class description member. void QuarksToHadronsDecayer::Init() { static ClassDocumentation documentation ("This class decays particles to nq (2 or 4) quarks which then are " "decayes to hadrons according to phase space. The number of final " "hadrons can either be given by a fixed number or as a Gaussian " "multiplicity distribution centered around c+nq/4+c3 and a width " "sqrt(c), where c = c1 log((m - summ)/c2), m is the mass of the " "decaying particle, summ the sum of the quark masses and ci real " "parameters."); static Parameter interfaceFixedN ("FixedN", "The fixed number of hadrons to be produced. If less than 2, the " "number is instead given by a gaussian multiplicity distribution.", &QuarksToHadronsDecayer::theFixedN, 0, 0, 10, true, false, true); static Parameter interfaceMinN ("MinN", "The minimum hadrons to be produced.", &QuarksToHadronsDecayer::theMinN, 2, 2, 10, true, false, true); static Parameter interfaceC1 ("C1", "The c1 parameter of the gaussian multiplicity distribution centered " "around c1 log((m - summ)/c2) +c3.", &QuarksToHadronsDecayer::theC1, 4.5, 0.0, 10.0, true, false, true); static Parameter interfaceC2 ("C2", "The c2 parameter of the gaussian multiplicity distribution centered " "around c1 log((m - summ)/c2) +c3.", &QuarksToHadronsDecayer::theC2, GeV, 0.7*GeV, ZERO, 10.0*GeV, true, false, true); static Parameter interfaceC3 ("C3", "The c3 parameter of the gaussian multiplicity distribution centered " "around c1 log((m - summ)/c2) +c3.", &QuarksToHadronsDecayer::theC3, 0.0, 0.0, 10.0, true, false, true); static Reference interfaceFlavourGenerator ("FlavourGenerator", "The object in charge of generating hadrons spieces from given quark " "flavours.", &QuarksToHadronsDecayer::theFlavourGenerator, true, false, true, false, true); interfaceFixedN.rank(10); interfaceMinN.rank(9); interfaceFlavourGenerator.rank(8); interfaceMinN.setHasDefault(false);; } diff --git a/Persistency/PersistentOStream.cc b/Persistency/PersistentOStream.cc --- a/Persistency/PersistentOStream.cc +++ b/Persistency/PersistentOStream.cc @@ -1,169 +1,170 @@ // -*- C++ -*- // // PersistentOStream.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the PersistentOStream class. // #include "PersistentOStream.h" #include "ThePEG/Utilities/DynamicLoader.h" #include namespace ThePEG { PersistentOStream::PersistentOStream(ostream & os, const vector & libs) : theOStream(&os), badState(false), allocStream(false) { init(libs); } PersistentOStream::PersistentOStream(string file, const vector & libs) : badState(false), allocStream(true) { // if ( file[0] == '|' ) // theOStream = new opfstream(file.substr(1).c_str()); // else if ( file.substr(file.length()-3, file.length()) == ".gz" ) // theOStream = new opfstream(string("gzip > " + file).c_str()); // else theOStream = new ofstream(file.c_str()); if ( theOStream ) init(libs); else setBadState(); } void PersistentOStream::init(const vector & libs) { operator<<(string("ThePEG version 1 Database")); operator<<(version); operator<<(subVersion); *this << DynamicLoader::appendedPaths(); *this << DynamicLoader::prependedPaths(); vector libraries; for ( int i = 0, N = libs.size(); i < N; ++i ) libraries.push_back(DynamicLoader::dlnameversion(libs[i])); *this << libraries; } PersistentOStream::~PersistentOStream() { if ( allocStream ) delete theOStream; } void PersistentOStream:: putObjectPart(tcBPtr obj, const ClassDescriptionBase * db) { ClassDescriptionBase::DescriptionVector::const_iterator bit = db->descriptions().begin(); while ( bit != db->descriptions().end() ) { putObjectPart(obj, *bit++); endBase(); } db->output(obj, *this); } PersistentOStream & PersistentOStream::outputPointer(tcBPtr obj) { if ( !good() ) return *this; if ( !obj ) return operator<<(0); // It it's the null pointer, just print a zero. int oid = 0; const ClassDescriptionBase * desc = 0; try { // Check if the object has been written before. In that case just write // out it's number ObjectMap::const_iterator oit = writtenObjects.find(obj); if ( oit != writtenObjects.end() ) { *this << oit->second; return *this; } // This object hasn't been written before so we write it out, beginning // with a number, then the class information, and finally let it write // itself on the stream. beginObject(); oid = writtenObjects.size()+1; writtenObjects[obj] = oid; *this << oid; desc = writeClassId(obj); *this << obj->uniqueId; putObjectPart(obj, desc); endObject(); } catch (Exception & e) { e.handle(); string classname = ""; if ( desc ) classname = desc->name(); throw WriteError() << "While writing object number " << oid << " of class " << classname << ":\n" << e.message() << Exception::runerror; setBadState(); } catch (...) { setBadState(); } checkState(); return *this; } const ClassDescriptionBase * PersistentOStream::writeClassId(tcBPtr obj) { - const ClassDescriptionBase * db = DescriptionList::find(typeid(*obj)); + const auto & tmp=*obj; + const ClassDescriptionBase * db = DescriptionList::find(typeid(tmp)); if ( !db ) { throw MissingClass() << "PersistentOStream could not find the ClassDescription object " - << "corresponding to the class " << typeid(*obj).name() + << "corresponding to the class " << typeid(tmp).name() << ". Please check that the class has a properly instantiated " << "ClassDescription object." << Exception::runerror; } writeClassDescription(db); return db; } void PersistentOStream:: writeClassDescription(const ClassDescriptionBase * db) { // If objects of this class has been written out before, just write // the corresponding number ClassMap::iterator cit = writtenClasses.find(db); if ( cit != writtenClasses.end() ) { operator<<(cit->second); return; } // This class hasn't been written before, so append it to the list of // written classes and assign a number to it, before writing the string // containing the information int cid = writtenClasses.size(); writtenClasses[db] = cid; operator<<(cid); operator<<(db->name()); operator<<(db->version()); operator<<(DynamicLoader::dlnameversion(db->library())); // Now write its base classes or a zero if the base class is PersistentBase. operator<<(db->descriptions().size()); DescriptionVector::const_iterator bit = db->descriptions().begin(); while ( bit != db->descriptions().end() ) writeClassDescription(*bit++); } PersistentOStream & PersistentOStream::flush() { #ifdef _LIBCPP_VERSION typedef ObjectMap::const_iterator Iterator; #else typedef ObjectMap::iterator Iterator; #endif Iterator it = writtenObjects.begin(); while ( it != writtenObjects.end() ) { Iterator it2 = it++; if ( (*it2).second > lastSavedObject.top() ) writtenObjects.erase(it2); } os().flush(); return *this; } } diff --git a/Repository/BaseRepository.cc b/Repository/BaseRepository.cc --- a/Repository/BaseRepository.cc +++ b/Repository/BaseRepository.cc @@ -1,977 +1,986 @@ // -*- C++ -*- // // BaseRepository.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the BaseRepository class. // // macro is passed in from -D compile flag #ifndef THEPEG_PKGDATADIR #error Makefile.am needs to define THEPEG_PKGDATADIR #endif #include "BaseRepository.h" #include "ThePEG/Config/algorithm.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/InterfaceBase.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Command.h" #include "ThePEG/Utilities/ClassDescription.h" #include "ThePEG/Utilities/DescriptionList.h" #include "ThePEG/Utilities/HoldFlag.h" #include "ThePEG/Utilities/TypeInfo.h" #include "ThePEG/Utilities/DynamicLoader.h" #include "ThePEG/Utilities/StringUtils.h" #include "ThePEG/Utilities/Throw.h" #include "ThePEG/PDT/DecayMode.h" #ifdef ThePEG_TEMPLATES_IN_CC_FILE #include "BaseRepository.tcc" #endif using namespace ThePEG; ostream *& BaseRepository::coutp() { static ostream * theCout = &std::cout; return theCout; } ostream *& BaseRepository::cerrp() { static ostream * theCerr = &std::cerr; return theCerr; } ostream *& BaseRepository::clogp() { static ostream * theClog = &std::clog; return theClog; } bool & BaseRepository::updating() { static bool theBool = false; return theBool; } ObjectMap & BaseRepository::objects() { static ObjectMap theObjectMap; return theObjectMap; } ObjectSet & BaseRepository::allObjects() { static ObjectSet theObjectSet; return theObjectSet; } BaseRepository::TypeInterfaceMap & BaseRepository::interfaces() { static TypeInterfaceMap theInterfaceMap; return theInterfaceMap; } BaseRepository::TypeDocumentationMap & BaseRepository::documentations() { static TypeDocumentationMap theDocumentationMap; return theDocumentationMap; } BaseRepository::DirectorySet & BaseRepository::directories() { static DirectorySet theDirectories = {"/"}; return theDirectories; } vector & BaseRepository::globalLibraries() { static vector theGlobalLibraries; return theGlobalLibraries; } stack & BaseRepository::currentReadDirStack() { static stack theCurrentReadDirStack; if ( theCurrentReadDirStack.empty() ) theCurrentReadDirStack.push(""); return theCurrentReadDirStack; } vector & BaseRepository::readDirs() { // macro is passed in from -D compile flag static vector theReadDirs(1, THEPEG_PKGDATADIR); return theReadDirs; } const vector & BaseRepository::listReadDirs() { return BaseRepository::readDirs(); } void BaseRepository::prependReadDir(string dir) { readDirs().insert(readDirs().begin(), dir); } void BaseRepository::prependReadDir(const std::vector& dirs) { readDirs().insert(readDirs().begin(), dirs.begin(), dirs.end()); } void BaseRepository::appendReadDir(string dir) { readDirs().push_back(dir); } void BaseRepository::appendReadDir(const std::vector& dirs) { readDirs().insert(readDirs().end(), dirs.begin(), dirs.end()); } BaseRepository::StringVector & BaseRepository::directoryStack() { static StringVector theDirectoryStack(1, "/"); return theDirectoryStack; } void BaseRepository::Register(const InterfaceBase & ib, const type_info & i) { const ClassDescriptionBase * db = DescriptionList::find(i); if ( db ) interfaces()[db].insert(&ib); } void BaseRepository:: Register(const ClassDocumentationBase & cd, const type_info & i) { const ClassDescriptionBase * db = DescriptionList::find(i); if ( db ) documentations()[db] = &cd; } void BaseRepository::Register(IBPtr ip, string newName) { DirectoryAppend(newName); ip->name(newName); Register(ip); } void BaseRepository::Register(IBPtr ip) { if ( !ip || member(allObjects(), ip) ) return; if ( member(objects(), ip->fullName()) ) throw RepoNameExistsException(ip->fullName()); objects()[ip->fullName()] = ip; allObjects().insert(ip); ip->clear(); ip->update(); ip->touch(); } void BaseRepository::DirectoryAppend(string & name) { if ( name == "." ) name = directoryStack().back(); if ( name[0] != '/' ) name = directoryStack().back() + name; } void BaseRepository::CreateDirectory(string name) { DirectoryAppend(name); if ( name[name.size()-1] != '/' ) name += "/"; if ( member(directories(), name) ) return; directories().insert(name); name = name.substr(0, name.size() - 1); name = name.substr(0, name.rfind('/')); if ( name.size() ) CreateDirectory(name); } void BaseRepository::CheckObjectDirectory(string name) { if ( name[name.size() - 1] != '/' ) name = name.substr(0, name.rfind('/') + 1); CheckDirectory(name); } void BaseRepository::CheckDirectory(string name) { DirectoryAppend(name); if ( name[name.size()-1] != '/' ) name += "/"; if ( member(directories(), name) ) return; throw RepositoryNoDirectory(name); } void BaseRepository::ChangeDirectory(string name) { DirectoryAppend(name); if ( name[name.size()-1] != '/' ) name += "/"; if ( member(directories(), name) ) { directoryStack().back() = name; return; } throw RepositoryNoDirectory(name); } void BaseRepository::PushDirectory(string name) { DirectoryAppend(name); if ( name[name.size()-1] != '/' ) name += "/"; if ( member(directories(), name) ) { directoryStack().push_back(name); return; } throw RepositoryNoDirectory(name); } void BaseRepository::PopDirectory() { if ( directoryStack().size() > 1 ) directoryStack().pop_back(); } IBPtr BaseRepository::GetPointer(string name) { ObjectMap::iterator it = objects().find(name); return it == objects().end()? IBPtr(): it->second; } IVector BaseRepository::SearchDirectory(string name, string className) { IVector ret; DirectoryAppend(name); const ClassDescriptionBase * cdb = 0; if ( className.size() ) { cdb = DescriptionList::find(className); if ( !cdb ) return ret; } if ( name[name.size()-1] != '/' ) name += "/"; string::size_type size = name.size(); for ( ObjectMap::const_iterator i = objects().begin(); i != objects().end(); ++i ) { - if ( cdb && !DescriptionList::find(typeid(*(i->second)))->isA(*cdb) ) + const auto & tmp=(*(i->second)); + if ( cdb && !DescriptionList::find(typeid(tmp))->isA(*cdb) ) continue; if ( i->first.substr(0, size) == name ) ret.push_back(i->second); } return ret; } IVector BaseRepository::GetObjectsReferringTo(IBPtr obj) { IVector ret; for ( ObjectMap::const_iterator i = objects().begin(); i != objects().end(); ++i ) { if ( obj == i->second ) continue; IVector ov = DirectReferences(i->second); if ( member(ov, obj) ) ret.push_back(i->second); } return ret; } IVector BaseRepository::DirectReferences(IBPtr obj) { IVector ov = obj->getReferences(); - InterfaceMap interfaceMap = getInterfaces(typeid(*obj)); + const auto & tmp=*obj; + InterfaceMap interfaceMap = getInterfaces(typeid(tmp)); for ( InterfaceMap::iterator iit = interfaceMap.begin(); iit != interfaceMap.end(); ++iit ) { IVector ovi = iit->second->getReferences(*obj); ov.insert(ov.end(), ovi.begin(), ovi.end()); } return ov; } void BaseRepository:: addReferences(tIBPtr obj, ObjectSet & refs) { if ( !obj ) return; refs.insert(obj); IVector ov = obj->getReferences(); for ( IVector::const_iterator it = ov.begin(); it != ov.end(); ++it ) if ( !member(refs, *it) ) addReferences(*it, refs); - InterfaceMap interfaceMap = getInterfaces(typeid(*obj)); + const auto & tmp=*obj; + InterfaceMap interfaceMap = getInterfaces(typeid(tmp)); for ( InterfaceMap::iterator iit = interfaceMap.begin(); iit != interfaceMap.end(); ++iit ) { IVector ov = iit->second->getReferences(*obj); for ( IVector::const_iterator it = ov.begin(); it != ov.end(); ++it ) if ( !member(refs, *it) ) addReferences(*it, refs); } } void BaseRepository:: addInterfaces(const ClassDescriptionBase & db, InterfaceMap & interfaceMap, bool all) { for ( ClassDescriptionBase::DescriptionVector::const_iterator it = db.descriptions().begin(); it != db.descriptions().end(); ++it ) if ( *it ) addInterfaces(**it, interfaceMap, all); TypeInterfaceMap::const_iterator cit = interfaces().find(&db); if ( cit == interfaces().end() ) return; for ( InterfaceSet::const_iterator iit = (cit->second).begin(); iit != (cit->second).end(); ++iit ) { string n = (**iit).name(); while ( all && member(interfaceMap, n) ) n = "+" + n; interfaceMap[n] = *iit; } } InterfaceMap BaseRepository::getInterfaces(const type_info & ti, bool all) { InterfaceMap interfaceMap; const ClassDescriptionBase * db = DescriptionList::find(ti); if ( !db ) return interfaceMap; addInterfaces(*db, interfaceMap, all); return interfaceMap; } void BaseRepository:: rebind(InterfacedBase & i, const TranslationMap & trans, const IVector & defaults) { InterfaceMap interfaceMap = getInterfaces(typeid(i), true); for ( InterfaceMap::iterator iit = interfaceMap.begin(); iit != interfaceMap.end(); ++iit ) iit->second->rebind(i, trans, defaults); i.rebind(trans); } void BaseRepository::update() { - for_each(allObjects(), mem_fun(&InterfacedBase::update)); + for_each(allObjects(), std::mem_fn(&InterfacedBase::update)); clearAll(allObjects()); } template bool overlap(const Set1 & s1, const Set2 & s2) { typename Set1::const_iterator i1 = s1.begin(); typename Set2::const_iterator i2 = s2.begin(); while ( i1 != s1.end() && i2 != s2.end() ) { if ( *i1 == *i2 ) return true; if ( *i1 < *i2 ) { i1 = s1.lower_bound(*i2); if ( *i1 == *i2 ) return true; ++i1; } else { i2 = s2.lower_bound(*i1); if ( *i1 == *i2 ) return true; ++i2; } } return false; } void BaseRepository::remove(tIBPtr ip) { ObjectMap::iterator it = objects().find(ip->fullName()); if ( it == objects().end() || ip != it->second ) return; objects().erase(it); allObjects().erase(ip); } string BaseRepository::remove(const ObjectSet & rmset) { ObjectSet refset; for ( ObjectSet::const_iterator oi = rmset.begin(); oi != rmset.end(); ++oi ) { IVector ov = GetObjectsReferringTo(*oi); refset.insert(ov.begin(), ov.end()); } for ( ObjectSet::iterator oi = rmset.begin(); oi != rmset.end(); ++oi ) refset.erase(*oi); if ( refset.empty() ) { for ( ObjectSet::iterator oi = rmset.begin(); oi != rmset.end(); ++oi ) remove(*oi); return ""; } string ret = "Error: cannot remove the objects because the following " "objects refers to some of them:\n"; for ( ObjectSet::iterator oi = refset.begin(); oi != refset.end(); ++oi ) ret += (**oi).fullName() + "\n"; return ret; } void BaseRepository::rename(tIBPtr ip, string newName) { ObjectSet::iterator it = allObjects().find(ip); if ( it == allObjects().end() ) { Register(ip, newName); return; } ObjectMap::iterator mit = objects().find(ip->fullName()); if ( mit == objects().end() || mit->second != ip ) throw RepoNameException(ip->fullName()); objects().erase(mit); ip->name(newName); while ( member(objects(), ip->fullName()) ) ip->name(ip->fullName() + "#"); objects()[ip->fullName()] = ip; } const InterfaceBase * BaseRepository::FindInterface(IBPtr ip, string name) { - InterfaceMap imap = getInterfaces(typeid(*ip), false); + const auto & tmp=*ip; + InterfaceMap imap = getInterfaces(typeid(tmp), false); InterfaceMap::iterator it = imap.find(name); return it == imap.end()? 0: it->second; } const ClassDocumentationBase * BaseRepository::getDocumentation(tcIBPtr ip) { + const auto & tmp=*ip; TypeDocumentationMap::const_iterator cdoc = - documentations().find(DescriptionList::find(typeid(*ip))); + documentations().find(DescriptionList::find(typeid(tmp))); return cdoc != documentations().end()? cdoc->second: 0; } string BaseRepository::getModelDescription(tcIBPtr ip) { const ClassDocumentationBase * cd = getDocumentation(ip); return cd? cd->modelDescription(): string(""); } string BaseRepository::getModelReferences(tcIBPtr ip) { const ClassDocumentationBase * cd = getDocumentation(ip); return cd? cd->modelReferences(): string(""); } IBPtr BaseRepository::TraceObject(string path) { DirectoryAppend(path); string::size_type colon = path.find(':'); IBPtr ip = GetPointer(path.substr(0, colon)); if ( !ip ) { // Do special check if this is a decay mode. string name = path.substr(0, colon); string::size_type slash = name.rfind('/'); if ( slash != string::npos ) name = name.substr(slash + 1); if ( name.find("->") != string::npos && name[name.length() - 1] == ';' ) { vector save; DMPtr dm = DecayMode::constructDecayMode(name, &save); if ( dm ) ip = dynamic_ptr_cast(GetPointer(path.substr(0, slash + 1) + dm->tag())); if ( ip ) Throw() << "Warning: rewriting DecayMode name '" << path.substr(0, colon).substr(slash + 1) << "' to '" << ip->name() << Exception::warning; } } while ( colon != string::npos ) { if ( !ip ) throw RepositoryNotFound(path); path = path.substr(colon+1); colon = path.find(':'); string::size_type bra = path.find('['); const InterfaceBase * ifb = FindInterface(ip, path.substr(0, min(colon, bra))); const ReferenceBase * rb = dynamic_cast(ifb); if ( rb ) { ip = rb->get(*ip); continue; } const RefVectorBase * rvb = dynamic_cast(ifb); if ( rvb ) { unsigned int place = 0; if ( bra < colon ) { string::size_type ket = path.find(']'); place = atoi(path.substr(bra + 1,ket - bra - 1).c_str()); } IVector iv = rvb->get(*ip); if ( place >= iv.size() ) throw RepositoryNotFound(path); ip = iv[place]; continue; } const CommandBase * cb = dynamic_cast(ifb); if ( cb ) { string::size_type ket = path.find(']'); string newobj = cb->cmd(*ip, path.substr(bra + 1,ket - bra - 1)); ip = GetPointer(newobj); continue; } throw RepositoryNotFound(path); } if ( !ip ) throw RepositoryNotFound(path); return ip; } IBPtr BaseRepository::getObjectFromNoun(string noun) { string::size_type colon = noun.rfind(':'); return TraceObject(noun.substr(0, colon)); } string BaseRepository::getInterfaceFromNoun(string noun) { string::size_type colon = noun.rfind(':'); string interface = noun.substr(colon+1); string::size_type bra = interface.find('['); if ( bra != string::npos ) return interface.substr(0, bra); else return interface; } string BaseRepository::getPosArgFromNoun(string noun) { string::size_type colon = noun.rfind(':'); string interface = noun.substr(colon+1); string::size_type bra = interface.find('['); if ( bra != string::npos ) { string::size_type ket = interface.find(']'); return interface.substr(bra + 1,ket - bra - 1); } return ""; } string BaseRepository:: GetInterfacedBaseClasses(const ClassDescriptionBase * cdb) { if ( !cdb || cdb->name() == "ThePEG::Interfaced" || cdb->name() == "ThePEG::InterfacedBase" ) return ""; string ret = cdb->name() + "\n"; for ( int i = 0, N = cdb->descriptions().size(); i < N; ++i ) ret += GetInterfacedBaseClasses(cdb->descriptions()[i]); return ret; } struct InterfaceOrder { bool operator()(const InterfaceBase * x, const InterfaceBase * y) const { return x->rank() > y->rank() || ( x->rank() == y->rank() && x->name() < y->name() ); } }; void BaseRepository::readSetup(tIBPtr ip, istream & is) { ip->setup(is); } string BaseRepository::exec(string command, ostream &) { string verb = StringUtils::car(command); command = StringUtils::cdr(command); if ( verb.empty() || verb[0] == '#' ) return ""; try { if ( verb == "DISABLEREADONLY" ) { InterfaceBase::NoReadOnly = true; return ""; } if ( verb == "ENABLEREADONLY" ) { InterfaceBase::NoReadOnly = false; return ""; } if ( verb == "cd" || verb == "pushd" || verb == "mkdir") { string dir = StringUtils::car(command); if ( verb == "cd" ) ChangeDirectory(dir); else if ( verb == "pushd" ) PushDirectory(dir); else CreateDirectory(dir); return ""; } if ( verb == "popd" ) { PopDirectory(); return ""; } if ( verb == "pwd" ) return directoryStack().back(); if ( verb == "dirs" ) { string ret; for ( StringVector::reverse_iterator it = directoryStack().rbegin(); it != directoryStack().rend(); ++it ) ret += *it; return ret; } if ( verb == "cp" || verb == "mv" ) { string oldname = StringUtils::car(command); DirectoryAppend(oldname); IBPtr obj = GetPointer(oldname); if ( !obj ) return "Error: No object named '" + oldname + "' available."; command = StringUtils::cdr(command); string newname = StringUtils::car(command); DirectoryAppend(newname); if ( newname[newname.size() - 1] == '/' ) newname += obj->name(); if ( verb == "cp" ) obj = obj->fullclone(); rename(obj, newname); return ""; } if ( verb == "check" ) { string name = StringUtils::car(command); if ( directories().find(name) != directories().end() ) return name; if ( objects().find(name) != objects().end() ) return name; return "Not found"; } if ( verb == "ls" ) { string className; string dir = StringUtils::car(command); if ( dir.size() ) { PushDirectory(dir); command = StringUtils::cdr(command); className = StringUtils::car(command); } string ret; string thisdir = directoryStack().back(); for ( DirectorySet::iterator it = directories().begin(); it != directories().end(); ++it ) { string d = *it; if ( d.size() <= thisdir.size() ) continue; string d0 = d.substr(0, thisdir.size()); string d1 = d.substr(thisdir.size()); if ( d0 == thisdir && d1.find('/') == d1.size() - 1 ) { if ( className.size() && SearchDirectory(d, className).empty() ) continue; ret += (dir.size()? d: d1) + "\n"; } } for ( ObjectMap::iterator it = objects().begin(); it != objects().end(); ++it ) { if ( className.size() ) { const ClassDescriptionBase * cdb = DescriptionList::find(className); + const auto & tmp=*(it->second); if ( cdb && - !DescriptionList::find(typeid(*(it->second)))->isA(*cdb) ) + !DescriptionList::find(typeid(tmp))->isA(*cdb) ) continue; } if ( thisdir + it->second->name() == it->first ) ret += (dir.size()? it->first: it->second->name()) + '\n'; } if ( dir.size() ) PopDirectory(); return ret; } if ( verb == "library" ) { string library = StringUtils::car(command); if ( library.empty() ) return "Error: No library specified."; if ( !DynamicLoader::load(library) ) return "Error: Could not load library " + library + "\n - " + DynamicLoader::lastErrorMessage; return ""; } if ( verb == "globallibrary" ) { string library = StringUtils::car(command); if ( library.empty() ) return "Error: No library specified."; if ( !DynamicLoader::load(library) ) return "Error: Could not load library " + library + "\n - " + DynamicLoader::lastErrorMessage; globalLibraries().push_back(library); return ""; } if ( verb == "rmgloballibrary" ) { string library = StringUtils::car(command); if ( library.empty() ) return "Error: No library specified."; vector::iterator it; while ( (it = find(globalLibraries(), library)) != globalLibraries().end() ) globalLibraries().erase(it); return ""; } if ( verb == "appendpath" ) { string path = StringUtils::car(command); if ( !path.empty() ) DynamicLoader::appendPath(path); return ""; } if ( verb == "lspaths" ) { string paths; for ( int i = 0, N = DynamicLoader::allPaths().size(); i < N; ++i ) paths += DynamicLoader::allPaths()[i] + "\n"; return paths; } if ( verb == "prependpath" ) { string path = StringUtils::car(command); if ( !path.empty() ) DynamicLoader::prependPath(path); return ""; } if ( verb == "create" ) { string className = StringUtils::car(command); command = StringUtils::cdr(command); string name = StringUtils::car(command); const ClassDescriptionBase * db = DescriptionList::find(className); command = StringUtils::cdr(command); while ( !db && command.length() ) { string library = StringUtils::car(command); command = StringUtils::cdr(command); DynamicLoader::load(library); db = DescriptionList::find(className); } if ( !db ) { string msg = "Error: " + className + ": No such class found."; if ( !DynamicLoader::lastErrorMessage.empty() ) msg += "\nerror message from dynamic loader:\n" + DynamicLoader::lastErrorMessage; return msg; } IBPtr obj = dynamic_ptr_cast(db->create()); if ( !obj ) return "Error: Could not create object of class "+className; if ( name.empty() ) return "Error: No name specified."; Register(obj, name); return ""; } if ( verb == "setup" ) { string name = StringUtils::car(command); DirectoryAppend(name); IBPtr obj = GetPointer(name); if ( !obj ) return "Error: Could not find object named " + name; istringstream is(StringUtils::cdr(command)); readSetup(obj, is); return ""; } if ( verb == "rm" ) { ObjectSet rmset; while ( !command.empty() ) { string name = StringUtils::car(command); DirectoryAppend(name); IBPtr obj = GetPointer(name); if ( !obj ) return "Error: Could not find object named " + name; rmset.insert(obj); command = StringUtils::cdr(command); } return remove(rmset); } if ( verb == "rmdir" || verb == "rrmdir" ) { string dir = StringUtils::car(command); DirectoryAppend(dir); if ( dir[dir.size() - 1] != '/' ) dir += '/'; if ( !member(directories(), dir) ) return verb == "rmdir"? "Error: No such directory.": ""; IVector ov = SearchDirectory(dir); if ( ov.size() && verb == "rmdir" ) return "Error: Cannot remove a non-empty directory. " "(Use rrmdir do remove all object and subdirectories.)"; ObjectSet rmset(ov.begin(), ov.end()); string ret = remove(rmset); if ( !ret.empty() ) return ret; StringVector dirs(directories().begin(), directories().end()); for ( int i = 0, N = dirs.size(); i < N; ++ i ) if ( dirs[i].substr(0, dir.size()) == dir ) directories().erase(dirs[i]); for ( int i = 0, N = directoryStack().size(); i < N; ++i ) if ( directoryStack()[i].substr(0, dir.size()) == dir ) directoryStack()[i] = '/'; return ""; } if ( verb == "rcp" ) { string name = StringUtils::car(command); DirectoryAppend(name); string newName = StringUtils::car(StringUtils::cdr(command)); if ( newName.empty() ) return "Error: No destination directory specified."; DirectoryAppend(newName); CreateDirectory(newName); if ( newName[newName.size() - 1] != '/' ) newName += '/'; IBPtr obj = GetPointer(name); if ( name[name.size() - 1] != '/' ) name += '/'; IVector ov = SearchDirectory(name); ov.push_back(obj); if ( ov.empty() ) return "Error: No such object or directory."; ObjectSet toclone; for ( IVector::iterator i = ov.begin(); i != ov.end(); ++i ) { toclone.insert(*i); addReferences(*i, toclone); } for ( ObjectSet::iterator i = toclone.begin(); i != toclone.end(); ++i ) Register((**i).clone(), newName + (**i).name()); return ""; } if ( verb == "rebind" ) { // For all objects in the repository, replace any references to // the first object given with references to the second // object. The two objects will change names IBPtr ip1 = TraceObject(StringUtils::car(command)); string newname = StringUtils::car(StringUtils::cdr(command)); DirectoryAppend(newname); IBPtr ip2 = GetPointer(newname); if ( !ip2 ) { ip2 = ip1->fullclone(); rename(ip2, newname); } TranslationMap trans; trans[ip1] = ip2; IVector objs = GetObjectsReferringTo(ip1); for ( int i = 0, N = objs.size(); i < N; ++i ) rebind(*objs[i], trans, IVector()); } if ( verb == "doxygendump" ) { string spacename = StringUtils::car(command); command = StringUtils::cdr(command); string filename = StringUtils::car(command); ofstream os(filename.c_str()); for ( TypeDocumentationMap::const_iterator it = documentations().begin(); it != documentations().end(); ++it ) { const ClassDescriptionBase & db = *(it->first); string classname = db.name(); if ( classname.substr(0, spacename.length()) != spacename ) continue; string briefname = classname.substr(spacename.length()); os << "/** \\page " << briefname << "Interfaces " << "Interfaces defined for the " << classname << " class.\n\n" << "\\par Brief class description:\n"; string doc = it->second->documentation(); if ( doc.substr(0,25) == "There is no documentation" ) os << "See " << classname << "\n\n"; else os << doc << "
See also " << classname << "\n\n"; TypeInterfaceMap::const_iterator isit = interfaces().find(it->first); if ( isit == interfaces().end() || isit->second.empty() ) { os << "There are no interfaces declared for this class.\n\n"; } else { const InterfaceSet & ints = isit->second; for ( InterfaceSet::const_iterator iit = ints.begin(); iit != ints.end(); ++iit ) (**iit).doxygenDescription(os); } string baserefs = ""; int nbases = 0; for ( int ib = 0, N = db.descriptions().size(); ib < N; ++ib ) { if ( documentations().find(db.descriptions()[ib]) == documentations().end() ) continue; const ClassDescriptionBase & bdb = *db.descriptions()[ib]; if ( nbases ) baserefs += " and "; string briefname = bdb.name().substr(bdb.name().rfind("::") + 2); baserefs += "\\ref " + briefname + "Interfaces \"" + bdb.name() + "\""; ++nbases; } if ( nbases == 1 ) os << "
There may be interfaces inherited from the " << baserefs << " class."; else if ( nbases > 1 ) os << "
There may be interfaces inherited from the " << "following classes: " << baserefs << "."; os << "\n\n*/\n\n"; } return ""; } if ( verb == "mset" || verb == "msetdef" || verb == "minsert" || verb == "mdo" || verb == "mget" || verb == "mdef" || verb == "mmin" || verb == "mmax" || verb == "merase" || verb == "msend" ) { if ( verb == "msend" ) verb = "mdo"; string dir = StringUtils::car(command); command = StringUtils::cdr(command); string className = StringUtils::car(command); command = StringUtils::cdr(command); string interface = StringUtils::car(command); string arguments = StringUtils::cdr(command); string::size_type bra = interface.find('['); if ( bra != string::npos ) { string::size_type ket = interface.find(']'); arguments = interface.substr(bra + 1,ket - bra - 1) + " " + arguments; interface = interface.substr(0, bra); } IVector ov = SearchDirectory(dir, className); if ( ov.empty() ) return "Error: no matching objects found."; string ret; verb = verb.substr(1); for ( IVector::size_type i = 0; i < ov.size(); ++i ) { const InterfaceBase * ifb = FindInterface(ov[i], interface); if ( !ifb ) continue; string mess = ifb->exec(*ov[i], verb, arguments); if ( !mess.empty() ) ret += ov[i]->fullName() + ": " + mess + "\n"; } return ret.substr(0, ret.size() - 1); } if ( verb == "set" || verb == "setdef" || verb == "insert" || verb == "do" || verb == "get" || verb == "def" || verb == "min" || verb == "max" || verb == "describe" || verb == "fulldescribe" || verb == "erase" || verb == "clear" || verb == "send" || verb == "newdef" ) { if ( verb == "send" ) verb = "do"; if ( verb == "newdef" && !InterfaceBase::NoReadOnly ) return "Error: The default value of an interface is a read-only " "entity. Use the command 'DISABLEREADONLY' to override."; string noun = StringUtils::car(command); string arguments = getPosArgFromNoun(noun) + " " + StringUtils::cdr(command); IBPtr ip = getObjectFromNoun(noun); const InterfaceBase * ifb = FindInterface(ip, getInterfaceFromNoun(noun)); if ( !ifb && verb != "describe" && verb != "fulldescribe" ) { string ret = "Error: The interface '" + noun + "' was not found.\n"; ret += "Valid interfaces:\n"; - InterfaceMap imap = getInterfaces(typeid(*ip)); + const auto & tmp=*ip; + InterfaceMap imap = getInterfaces(typeid(tmp)); for ( InterfaceMap::iterator it = imap.begin(); it != imap.end(); ++it ) ret += "* " + it->second->name() + "\n"; return ret; } if ( verb == "describe" ) { if ( ifb ) return ifb->description(); - const ClassDescriptionBase * cd = DescriptionList::find(typeid(*ip)); + const auto & tmp=*ip; + const ClassDescriptionBase * cd = DescriptionList::find(typeid(tmp)); string ret = "Object '" + ip->name() + "' of class '" + cd->name() + "':\n"; TypeDocumentationMap::const_iterator cdoc = documentations().find(cd); if ( cdoc != documentations().end() ) ret += cdoc->second->documentation() + "\n"; ret +="Interfaces:\n"; - InterfaceMap imap = getInterfaces(typeid(*ip)); + InterfaceMap imap = getInterfaces(typeid(tmp)); for ( InterfaceMap::iterator it = imap.begin(); it != imap.end(); ++it ) ret += "* " + it->second->name() + "\n"; return ret; } else if ( verb == "fulldescribe" ) { if ( ifb ) return ifb->fullDescription(*ip); ostringstream ret; - const ClassDescriptionBase * cd = DescriptionList::find(typeid(*ip)); + const auto & tmp=*ip; + const ClassDescriptionBase * cd = DescriptionList::find(typeid(tmp)); TypeDocumentationMap::const_iterator cdoc = documentations().find(cd); ret << ip->fullName() << endl << cd->name() << endl; if ( cdoc != documentations().end() ) ret << cdoc->second->documentation() << endl; ret << "Interfaces:" << endl; - InterfaceMap imap = getInterfaces(typeid(*ip)); + InterfaceMap imap = getInterfaces(typeid(tmp)); typedef set InterfaceSet; InterfaceSet iset; for ( InterfaceMap::iterator it = imap.begin(); it != imap.end(); ++it ) iset.insert(it->second); double rank = 1.0; for ( InterfaceSet::iterator it = iset.begin(); it != iset.end(); ++it ) { if ( rank >= 0.0 && (**it).rank() < 0.0 ) ret << "0" << endl; rank = (**it).rank(); ret << (**it).type() << " " << (**it).name() << endl; } return ret.str(); } else return ifb->exec(*ip, verb, arguments); } if ( verb == "baseclasses" ) { string className = StringUtils::car(command); const ClassDescriptionBase * cdb = 0; if ( className.size() ) { cdb = DescriptionList::find(className); if ( !cdb ) return "Error: no class '" + className + "' found."; } return GetInterfacedBaseClasses(cdb); } if ( verb == "describeclass" ) { string className = StringUtils::car(command); const ClassDescriptionBase * cdb = 0; if ( className.size() ) { cdb = DescriptionList::find(className); if ( !cdb ) return "Error: no class '" + className + "' found."; } TypeDocumentationMap::const_iterator cdoc = documentations().find(cdb); if ( cdoc != documentations().end() ) return cdoc->second->documentation() + "\n"; else return ""; } if ( verb == "lsclass" ) { string className = StringUtils::car(command); const ClassDescriptionBase * cdb = 0; if ( className.size() ) { cdb = DescriptionList::find(className); if ( !cdb ) return "Error: no class '" + className + "' found."; } vector classes; if ( cdb && !cdb->abstract() ) classes.push_back(cdb); for ( DescriptionList::DescriptionMap::const_iterator it = DescriptionList::all().begin(); it != DescriptionList::all().end(); ++it ) { if ( it->second == cdb || it->second->abstract() ) continue; if ( cdb && !it->second->isA(*cdb) ) continue; classes.push_back(it->second); } if ( classes.empty() ) return "Error: no classes found."; string ret; for ( int i = 0, N = classes.size(); i < N; ++i ) ret += classes[i]->name() + "\n"; return ret; } } catch (const Exception & e) { e.handle(); return "Error: " + e.message(); } return "Error: Unrecognized command '" + verb + "'."; } BadClassClone::BadClassClone(const InterfacedBase & o) { theMessage << "Could not clone the object '" << o.name() << "' of class '" << TypeInfo::name(o) << "' because the class does not" << " implement a working 'clone' method."; severity(abortnow); } BadClone::BadClone(const InterfacedBase & o) { theMessage << "Could not clone the object '" << o.name() << "' of class '" << TypeInfo::name(o) << "' because the clone method threw an unknown exception."; severity(abortnow); } RepoNameException::RepoNameException(string name) { theMessage << "The object '" << name << "' is present in the Repository but " << "under a different name. This means that the name of the " << "object has been illegally changed outside of the Repository."; severity(abortnow); } RepoNameExistsException::RepoNameExistsException(string name) { theMessage << "The object '" << name << "' was not created as another object with that name already exists."; severity(warning); } RepositoryNoDirectory::RepositoryNoDirectory(string name) { theMessage << "The directory '" << name << "' does not exist."; severity(warning); } RepositoryNotFound::RepositoryNotFound(string name) { theMessage << "There was no object named '" << name << "' in the repository."; severity(warning); } RepositoryClassMisMatch:: RepositoryClassMisMatch(const InterfacedBase & o, string name) { theMessage << "The requested object '" << o.fullName() << "' was not of the " << "specified type (" << name << ")."; severity(warning); } diff --git a/Repository/BaseRepository.h b/Repository/BaseRepository.h --- a/Repository/BaseRepository.h +++ b/Repository/BaseRepository.h @@ -1,583 +1,583 @@ // -*- C++ -*- // // BaseRepository.h is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef ThePEG_BaseRepository_H #define ThePEG_BaseRepository_H // This is the declaration of the BaseRepository class. #include "ThePEG/Config/ThePEG.h" #include "BaseRepository.xh" #include "ThePEG/Interface/InterfaceBase.fh" #include "ThePEG/Interface/ClassDocumentation.fh" #include "ThePEG/Interface/InterfacedBase.h" #include "ThePEG/Utilities/ClassDescription.fh" namespace ThePEG { /** * BaseRepository is a purely static class which keeps a set of * InterfacedBase objects indexed by their name. The objects and their * names are divided up in a tree-like structure inspired by the Unix * file system. * * The InterfacedBase objects may be manipulated using InterfaceBase * objects. This may be done directly or via a simple command * interface using the exec() method. * * RepositoryBase is closely related to the Repository sub-class. The * division may seem unnecessary, but the idea is that BaseRepository * is a general repository for administrating and manipulating a set * of InterfacedBase objects, while the Repository adds on utilites * which are special to ThePEG where the objects are Interfaced (a * sub-class of InterfacedBase). * * @see Repository * @see InterfacedBase * @see InterfaceBase * @see Interfaced * */ class BaseRepository { public: /** A set of strings. */ typedef StringSet DirectorySet; /** A vector of character strings. */ typedef vector StringVector; /** A set of pointers to InterfaceBase objects. */ typedef set InterfaceSet; /** A map of sets of IterfaceBase objects indexed by pointers to ClassDescriptionBase objects. */ typedef map TypeInterfaceMap; /** A map of ClassDocumentationBase objects indexed by pointers to ClassDescriptionBase objects. */ typedef map TypeDocumentationMap; public: /** * Interpret the command in \a cmd and return possible * messages. This is the main function for the command-line * interface. The syntax is described elsewhere. The ostream * argument is currently unused. */ static string exec(string cmd, ostream &); /** @name Functions for adding and deleting objects and interfaces. */ //@{ /** * Register an interface. This is called automatically in the * InterfaceBase constructor and should never be called explicitly. */ static void Register(const InterfaceBase &, const type_info &); /** * Register a class documentation. This is called automatically in * the ClassDocumentationBase constructor and should never be called * explicitly. */ static void Register(const ClassDocumentationBase &, const type_info &); /** * Register a new object using the its current name. If the object * is already in the repository, nothing happens. If another object * already exists with the same name, the new object will have * #'s appended to its name to make it unique. */ static void Register(IBPtr); /** * Register a new object giving it a new \a name. If the object is * already in the repository, nothing happens. If another object * already exists with the same name, the new object will have * #'s appended to its name to make it unique. */ static void Register(IBPtr, string name); /** * Remove the given object from the repository. If the object was * not present nothing will happen. */ static void remove(tIBPtr); /** * Remove objects. Remove the objects in \a rmset if there are no * other objects in the repository referring to them, otherwise * return an error message and the names of the objects refering to * them separated by new-line characters. */ static string remove(const ObjectSet & rmset); /** * Rename a given \a object. Syntacticly the same as * remove(object); Register(object, newName);. */ static void rename(tIBPtr object, string newName); //@} /** @name Access the directory stack. */ //@{ /** * Create a new directory with the given name. If the given name * starts with a / the name is assumed to be an absolute * path, otherwise it is assumed to be a path relative to the * current directory. */ static void CreateDirectory(string); /** * Check if directory exixts. Check if the name given as argument * corresponds to an existing directory. If the argument string does * not end in a / it is assumed to be the name of an * object in a directory, and only the directory part of the name is * checked. If the given name starts with a / the name * is assumed to be an absolute path, otherwise it is assumed to be * a path relative to the current directory. * * @throws RepositoryNoDirectory if the correspinding directory is * non-existent. */ static void CheckObjectDirectory(string); /** * Check if directory exixts. Check if the name given as argument * corresponds to an existing directory. If the given name starts * with a / the name is assumed to be an absolute path, * otherwise it is assumed to be a path relative to the current * directory. * * @throws RepositoryNoDirectory if the correspinding directory is * non-existent. */ static void CheckDirectory(string); /** * Return the absolute path. If the given name starts with a * / the name is assumed to be an absolute path already, * otherwise it is assumed to be a path relative to the current * directory, and the absolute path is constructed. */ static void DirectoryAppend(string &); /** * Set the current directory to \a name. \a name can be aither a * relative or absolute path. The new directory replaces the * previous current directory on the directory stack. * * @throws RepositoryNoDirectory if the directory is non-existent. */ static void ChangeDirectory(string name); /** * Set the current directory to \a name. \a name can be aither a * relative or absolute path. The new directory is pushed onto the * directory stack. * * @throws RepositoryNoDirectory if the directory is non-existent. */ static void PushDirectory(string name); /** * Pop the directory stack. Leave the current directory and set the * directory which is on top of the popped directory stack. */ static void PopDirectory(); /** * A list of all globally loaded libraries. */ static vector & globalLibraries(); //@} /** @name Information on where to read input files. */ //@{ protected: /** * The stack of directories used by the "read" command. */ static stack & currentReadDirStack(); /** * List of directories to search for files for the "read" command. */ static vector & readDirs(); public: /** * Access to list of directories to search for files for the "read" command. */ static const vector & listReadDirs(); /** * Add a directory to readDirs(). */ static void prependReadDir(string); /** * Add a string vector with directories to readDirs(). */ static void prependReadDir(const std::vector& dirs); /** * Add a directory to readDirs(). */ static void appendReadDir(string); /** * Add a string vector with directories to readDirs(). */ static void appendReadDir(const std::vector& dirs); //@} /** @name Access objects in the repository. */ //@{ /** * Return a reference counted pointer to the given object. This * currently not needed when ThePEG is used with the * ThePEG::Pointer::RCPtr class of pointers. */ template static typename Ptr::pointer GetPtr(const T &); /** * Return a pointer of the specified type to an object with the * given name. If such an object does not exist, GetPtr will return * a null pointer. */ template static PtrType GetPtr(string); /** * Return a pointer of the specified type to an object with the * given name. If such an object does not exist an exception will be * thrown. * @throws RepositoryNotFound if the object was not found. * @throws RepositoryClassMisMatch if the object exists but is of * the wrong class. */ template static PtrType GetObject(string); /** * Return a pointer to an object with the given name or null if no * such object exists. */ static IBPtr GetPointer(string); /** * Return all objects in the directory \a name. Optionally only return * objects of class \a className or of a sub-class thereof. */ static IVector SearchDirectory(string name, string className = ""); /** * Find an object. If the \a name does not begin with '/', the * current directory is prepended. If the string is on the form * object:interface (or * object:interface[i]) and interface * corresponds to an Reference (or RefVector) interface, the * corresponding referenced object is returned. (also * object:interface:interface is allowed etc.) */ static IBPtr TraceObject(string name); /** * Return a string containing the name of the given class * description and its base classes, one on each line. */ static string GetInterfacedBaseClasses(const ClassDescriptionBase * cdb); /** * Get an object. Decompose a string of the form * object:interface or * object:vector-interface[pos]. Retrun a pointer to * the corresponding object. */ static IBPtr getObjectFromNoun(string noun); //@} /** @name Access references between object in the repository. */ //@{ /** * Get referring objects. Return all object which refers to the * given object through a Reference of RefVector interface. */ static IVector GetObjectsReferringTo(IBPtr); /** * Get direct references. Return all objects the given object refers * to directly through a Reference of RefVector interface. */ static IVector DirectReferences(IBPtr); /** * Get all references. If \a obj contains references to other objects, * either through a Reference or RefVector interface or through the * virtual getReferences member function, add these to refs. Do the * same to the references recursively. */ static void addReferences(tIBPtr obj, ObjectSet & refs); //@} /** @name Access the interfaces of the objects in the repository. */ //@{ /** * Get interfaces. Return the interfaces defined for the * InterfacedBase class with the given type_info, \a ti, mapped to * their name. If several interfaces with the same name exists only * the one which correspond to the most derived class will be given, * except if \a all is true in which case all interfaces are given * (prefixed by '+'s to become unique). */ static InterfaceMap getInterfaces(const type_info & ti, bool all = true); /** * Return an interface with the given \a name to the given \a object. */ static const InterfaceBase * FindInterface(IBPtr object, string name); /** * Get an interface name. Decompose a string of the form * object:interface or * object:vector-interface[pos]. Return the interface * name (without the [pos]). */ static string getInterfaceFromNoun(string noun); /** * Get interface index. Decompose a string of the form * object:interface or * object:vector-interface[pos]. Return the * pos part or empty string if not present. */ static string getPosArgFromNoun(string noun); /** * Return a list of the interfaces which do not have their default * values for the given objects. */ template static vector< pair > getNonDefaultInterfaces(const Cont &); //@} /** @name Manipulate objects in the repository. */ //@{ /** * Call the InterfacedBase::update() function of all objects. */ static void update(); /** * Clear the InterfacedBase::touched() flag in all objects in the * given container. */ template static void clearAll(const Cont & c) { - for_each(c, mem_fun(&InterfacedBase::clear)); + for_each(c, mem_fn(&InterfacedBase::clear)); } /** * Set the status of all objects in the given container to * InterfacedBase::uninitialized. */ template static void resetAll(const Cont & c) { - for_each(c, mem_fun(&InterfacedBase::reset)); + for_each(c, mem_fn(&InterfacedBase::reset)); } /** * Setup an object. Execute the InterfacedBase::readSetup() method * of \a ip with the stream \a is as argument. */ static void readSetup(tIBPtr ip, istream & is); /** * Lock the given object. Locked objects cannot be * changed through an interface. */ static void lock(tIBPtr ip) { ip->lock(); } /** * Unlock the given object. Locked objects cannot be changed through * an interface. */ static void unlock(tIBPtr ip) { ip->unlock(); } //@} /** @name Access the documentation of objects. */ //@{ /** * Return the class documentation of a given object */ static const ClassDocumentationBase * getDocumentation(tcIBPtr ip); /** * Get the description for the model implemented in the class of the * given object. */ static string getModelDescription(tcIBPtr ip); /** * Get the references for the model implemented in the class of the * given object. */ static string getModelReferences(tcIBPtr ip); //@} /** @name Manipulate the output streams of the repository. */ //@{ /** * Set the standard output stream */ static void cout(ostream & os) { coutp() = &os; } /** * Get the standard output stream */ static ostream & cout() { return *coutp(); } /** * Set the standard error stream */ static void cerr(ostream & os) { cerrp() = &os; } /** * Get the standard error stream */ static ostream & cerr() { return *cerrp(); } /** * Set the standard log stream */ static void clog(ostream & os) { clogp() = &os; } /** * Get the standard log stream */ static ostream & clog() { return *clogp(); } //@} protected: /** @name Access standard InterfacedBase functions. */ //@{ /** * Return a clone of the given object. Calls the * InterfacedBase::clone() function of \a t and casts the resulting * pointer to the correct type. */ template static typename Ptr::pointer clone(const T & t); /** * Return a clone of the given object. Calls the * InterfacedBase::fullclone() function of \a t and casts the * resulting pointer to the correct type. */ template static typename Ptr::pointer fullclone(const T & t); /** * Rebind references. For all objects directly referenced by \a obj, * replace them with the translation found in \a trans. If \a obj has a * Reference or a member of a RefVector interface which is null, and * the corresponding interface has the RefInterfaceBase::defaultIfNull() flag set, * translate the null pointer to the first acceptable object in * defaults. */ static void rebind(InterfacedBase & obj, const TranslationMap & trans, const IVector & defaults); //@} /** * Add interfaces to the given map for the class with the given * class description. Recursively do the same with the base classes. */ static void addInterfaces(const ClassDescriptionBase &, InterfaceMap &, bool all = true); /** @name Functions containing the static instances of objects used by the repository. */ //@{ /** * All InterfacedBase objects mapped to their name. */ static ObjectMap & objects(); /** * All InterfacedBase objects. */ static ObjectSet & allObjects(); /** * Sets of InterfaceBase objects mapped to the class description of * the class for which they are defined. */ static TypeInterfaceMap & interfaces(); /** * Sets of ClassDocumentationBase objects mapped to the class * description of the class for which they are defined. */ static TypeDocumentationMap & documentations(); /** * All defined directories. */ static DirectorySet & directories(); /** * The current directory stack. */ static StringVector & directoryStack(); /** * Flag to say if we are in the middle of an update procedure. */ static bool & updating(); /** * The current current standard output stream. */ static ostream *& coutp(); /** * The current current standard error stream. */ static ostream *& cerrp(); /** * The current current standard log stream. */ static ostream *& clogp(); //@} }; } #ifndef ThePEG_TEMPLATES_IN_CC_FILE #include "BaseRepository.tcc" #endif #endif /* ThePEG_BaseRepository_H */ diff --git a/Repository/EventGenerator.cc b/Repository/EventGenerator.cc --- a/Repository/EventGenerator.cc +++ b/Repository/EventGenerator.cc @@ -1,1415 +1,1415 @@ // -*- C++ -*- // // EventGenerator.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the EventGenerator class. // #include "EventGenerator.h" #include "EventGenerator.xh" #include "ThePEG/Handlers/EventHandler.h" #include "Repository.h" #include "ThePEG/Utilities/HoldFlag.h" #include "ThePEG/Utilities/Debug.h" #include "ThePEG/Utilities/DebugItem.h" #include "ThePEG/Interface/Interfaced.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Command.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/PDT/ParticleData.h" #include "ThePEG/PDT/MatcherBase.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/StandardModel/StandardModelBase.h" #include "ThePEG/Repository/Strategy.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "ThePEG/Handlers/AnalysisHandler.h" #include "ThePEG/Analysis/FactoryBase.h" #include "ThePEG/Handlers/EventManipulator.h" #include "ThePEG/Handlers/LuminosityFunction.h" #include "ThePEG/MatrixElement/MEBase.h" #include "ThePEG/EventRecord/Event.h" #include "ThePEG/Handlers/SubProcessHandler.h" #include "ThePEG/Handlers/CascadeHandler.h" #include "ThePEG/Handlers/HadronizationHandler.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Config/algorithm.h" #include "ThePEG/Utilities/DynamicLoader.h" #include #include "ThePEG/Repository/Main.h" #include #ifdef ThePEG_TEMPLATES_IN_CC_FILE #include "EventGenerator.tcc" #endif using namespace ThePEG; namespace { volatile sig_atomic_t THEPEG_SIGNAL_STATE = 0; } // signal handler function // very restricted in what it is allowed do // without causing undefined behaviour extern "C" { void thepegSignalHandler(int id) { THEPEG_SIGNAL_STATE=id; signal(id,SIG_DFL); } } void EventGenerator::checkSignalState() { if (THEPEG_SIGNAL_STATE) { log() << "Caught signal " << THEPEG_SIGNAL_STATE << ". Exiting ..." << std::endl; finalize(); exit(0); } } EventGenerator::EventGenerator() : thePath("."), theNumberOfEvents(1000), theQuickSize(7000), preinitializing(false), ieve(0), weightSum(0.0), theDebugLevel(0), logNonDefault(-1), printEvent(0), dumpPeriod(0), keepAllDumps(false), debugEvent(0), maxWarnings(10), maxErrors(10), theCurrentRandom(0), theCurrentGenerator(0), useStdout(false), theIntermediateOutput(false) {} EventGenerator::EventGenerator(const EventGenerator & eg) : Interfaced(eg), theDefaultObjects(eg.theDefaultObjects), theLocalParticles(eg.theLocalParticles), theStandardModel(eg.theStandardModel), theStrategy(eg.theStrategy), theRandom(eg.theRandom), theEventHandler(eg.theEventHandler), theAnalysisHandlers(eg.theAnalysisHandlers), theHistogramFactory(eg.theHistogramFactory), theEventManipulator(eg.theEventManipulator), thePath(eg.thePath), theRunName(eg.theRunName), theNumberOfEvents(eg.theNumberOfEvents), theObjects(eg.theObjects), theObjectMap(eg.theObjectMap), theParticles(eg.theParticles), theQuickParticles(eg.theQuickParticles), theQuickSize(eg.theQuickSize), preinitializing(false), theMatchers(eg.theMatchers), usedObjects(eg.usedObjects), ieve(eg.ieve), weightSum(eg.weightSum), theDebugLevel(eg.theDebugLevel), logNonDefault(eg.logNonDefault), printEvent(eg.printEvent), dumpPeriod(eg.dumpPeriod), keepAllDumps(eg.keepAllDumps), debugEvent(eg.debugEvent), maxWarnings(eg.maxWarnings), maxErrors(eg.maxErrors), theCurrentRandom(0), theCurrentGenerator(0), theCurrentEventHandler(eg.theCurrentEventHandler), theCurrentStepHandler(eg.theCurrentStepHandler), useStdout(eg.useStdout), theIntermediateOutput(eg.theIntermediateOutput) {} EventGenerator::~EventGenerator() { if ( theCurrentRandom ) delete theCurrentRandom; if ( theCurrentGenerator ) delete theCurrentGenerator; } IBPtr EventGenerator::clone() const { return new_ptr(*this); } IBPtr EventGenerator::fullclone() const { return new_ptr(*this); } tcEventPtr EventGenerator::currentEvent() const { return eventHandler()->currentEvent(); } CrossSection EventGenerator::histogramScale() const { return eventHandler()->histogramScale(); } CrossSection EventGenerator::integratedXSec() const { return eventHandler()->integratedXSec(); } CrossSection EventGenerator::integratedXSecErr() const { return eventHandler()->integratedXSecErr(); } void EventGenerator::setSeed(long seed) { random().setSeed(seed); ostringstream s; s << seed; const InterfaceBase * ifb = BaseRepository::FindInterface(theRandom, "Seed"); ifb->exec(*theRandom, "set", s.str()); } void EventGenerator::setup(string newRunName, ObjectSet & newObjects, ParticleMap & newParticles, MatcherSet & newMatchers) { HoldFlag debug(Debug::level, Debug::isset? Debug::level: theDebugLevel); theRunName = newRunName; theObjects.swap(newObjects); theParticles.swap(newParticles); theMatchers.swap(newMatchers); theObjectMap.clear(); for ( ObjectSet::const_iterator it = objects().begin(); it != objects().end(); ++it ) theObjectMap[(**it).fullName()] = *it; UseRandom currentRandom(theRandom); CurrentGenerator currentGenerator(this); // Force update of all objects and then reset. touch(); - for_each(theObjects, mem_fun(&InterfacedBase::touch)); + for_each(theObjects, mem_fn(&InterfacedBase::touch)); update(); - for_each(theObjects, mem_fun(&InterfacedBase::update)); + for_each(theObjects, mem_fn(&InterfacedBase::update)); clear(); BaseRepository::clearAll(theObjects); init(); } IBPtr EventGenerator::getPointer(string name) const { ObjectMap::const_iterator it = objectMap().find(name); if ( it == objectMap().end() ) return IBPtr(); else return it->second; } void EventGenerator::openOutputFiles() { if ( !useStdout ) { logfile().open((filename() + ".log").c_str()); theOutFileName = filename() + ".out"; outfile().open(theOutFileName.c_str()); outfile().close(); theOutStream.str(""); } out() << Repository::banner() << endl; log() << Repository::banner() << endl; } void EventGenerator::closeOutputFiles() { flushOutputFile(); if ( !useStdout ) logfile().close(); } void EventGenerator::flushOutputFile() { if ( !useStdout ) { outfile().open(theOutFileName.c_str(), ios::out|ios::app); outfile() << theOutStream.str(); outfile().close(); } else BaseRepository::cout() << theOutStream.str(); theOutStream.str(""); } void EventGenerator::doinit() { HoldFlag debug(Debug::level, Debug::isset? Debug::level: theDebugLevel); // First initialize base class and random number generator. Interfaced::doinit(); random().init(); // Make random generator and this available in standard static // classes. UseRandom useRandom(theRandom); CurrentGenerator currentGenerator(this); // First initialize all objects which have requested this by // implementing a InterfacedBase::preInitialize() function which // returns true. while ( true ) { HoldFlag hold(preinitializing, true); ObjectSet preinits; for ( ObjectSet::iterator it = objects().begin(); it != objects().end(); ++it ) if ( (**it).preInitialize() && (**it).state() == InterfacedBase::uninitialized ) preinits.insert(*it); if ( preinits.empty() ) break; - for_each(preinits, mem_fun(&InterfacedBase::init)); + for_each(preinits, std::mem_fn(&InterfacedBase::init)); } // Initialize the quick access to particles. theQuickParticles.clear(); theQuickParticles.resize(2*theQuickSize); for ( ParticleMap::const_iterator pit = theParticles.begin(); pit != theParticles.end(); ++pit ) if ( abs(pit->second->id()) < theQuickSize ) theQuickParticles[pit->second->id()+theQuickSize] = pit->second; // Then call the init method for all objects. Start with the // standard model and the strategy. standardModel()->init(); if ( strategy() ) strategy()->init(); eventHandler()->init(); // initialize particles first for(ParticleMap::const_iterator pit = particles().begin(); pit != particles().end(); ++pit) pit->second->init(); - for_each(objects(), mem_fun(&InterfacedBase::init)); + for_each(objects(), std::mem_fn(&InterfacedBase::init)); // Then initialize the Event Handler calculating initial cross // sections and stuff. eventHandler()->initialize(); } void EventGenerator::doinitrun() { HoldFlag debug(Debug::level, Debug::isset? Debug::level: theDebugLevel); signal(SIGHUP, thepegSignalHandler); signal(SIGINT, thepegSignalHandler); signal(SIGTERM,thepegSignalHandler); currentEventHandler(eventHandler()); Interfaced::doinitrun(); random().initrun(); // Then call the init method for all objects. Start with the // standard model and the strategy. standardModel()->initrun(); if ( strategy() ) { strategy()->initrun(); if ( ! strategy()->versionstring().empty() ) { out() << ">> " << strategy()->versionstring() << '\n' << endl; log() << ">> " << strategy()->versionstring() << '\n' << endl; } } // initialize particles first for(ParticleMap::const_iterator pit = particles().begin(); pit != particles().end(); ++pit) { pit->second->initrun(); } eventHandler()->initrun(); - for_each(objects(), mem_fun(&InterfacedBase::initrun)); + for_each(objects(), std::mem_fn(&InterfacedBase::initrun)); if ( logNonDefault > 0 || ( ThePEG_DEBUG_LEVEL && logNonDefault == 0 ) ) { vector< pair > changed = Repository::getNonDefaultInterfaces(objects()); if ( changed.size() ) { log() << string(78, '=') << endl << "The following interfaces have non-default values (default):" << endl << string(78, '-') << endl; for ( int i = 0, N = changed.size(); i < N; ++i ) { log() << changed[i].first->fullName() << ":" << changed[i].second->name() << " = " << changed[i].second->exec(*changed[i].first, "notdef", "") << endl; } log() << string(78,'=') << endl; } } weightSum = 0.0; } PDPtr EventGenerator::getParticleData(PID id) const { long newId = id; if ( abs(newId) < theQuickSize && theQuickParticles.size() ) return theQuickParticles[newId+theQuickSize]; ParticleMap::const_iterator it = theParticles.find(newId); if ( it == theParticles.end() ) return PDPtr(); return it->second; } PPtr EventGenerator::getParticle(PID newId) const { tcPDPtr pd = getParticleData(newId); if ( !pd ) return PPtr(); return pd->produceParticle(); } void EventGenerator::finalize() { UseRandom currentRandom(theRandom); CurrentGenerator currentGenerator(this); finish(); finally(); } void EventGenerator::dofinish() { HoldFlag debug(Debug::level, Debug::isset? Debug::level: theDebugLevel); // first write out statistics from the event handler. eventHandler()->statistics(out()); // Call the finish method for all other objects. - for_each(objects(), mem_fun(&InterfacedBase::finish)); + for_each(objects(), std::mem_fn(&InterfacedBase::finish)); if ( theExceptions.empty() ) { log() << "No exceptions reported in this run.\n"; } else { log() << "\nThe following exception classes were reported in this run:\n"; for ( ExceptionMap::iterator it = theExceptions.begin(); it != theExceptions.end(); ++it ) { string severity; switch ( it->first.second ) { case Exception::info : severity="info"; break; case Exception::warning : severity="warning"; break; case Exception::setuperror : severity="setuperror"; break; case Exception::eventerror : severity="eventerror"; break; case Exception::runerror : severity="runerror"; break; case Exception::maybeabort : severity="maybeabort"; break; case Exception::abortnow : severity="abortnow"; break; default : severity="unknown"; } log() << it->first.first << ' ' << severity << " (" << it->second << " times)\n"; } } theExceptions.clear(); const string & msg = theMiscStream.str(); if ( ! msg.empty() ) { log() << endl << "Miscellaneous output from modules to the standard output:\n\n" << msg; theMiscStream.str(""); } flushOutputFile(); } void EventGenerator::finally() { generateReferences(); closeOutputFiles(); if ( theCurrentRandom ) delete theCurrentRandom; if ( theCurrentGenerator ) delete theCurrentGenerator; theCurrentRandom = 0; theCurrentGenerator = 0; } void EventGenerator::initialize(bool initOnly) { UseRandom currentRandom(theRandom); CurrentGenerator currentGenerator(this); doInitialize(initOnly); } bool EventGenerator::loadMain(string file) { initialize(); UseRandom currentRandom(theRandom); CurrentGenerator currentGenerator(this); Main::eventGenerator(this); bool ok = DynamicLoader::load(file); finish(); finally(); return ok; } void EventGenerator::go(long next, long maxevent, bool tics) { UseRandom currentRandom(theRandom); CurrentGenerator currentGenerator(this); doGo(next, maxevent, tics); } EventPtr EventGenerator::shoot() { static DebugItem debugfpu("ThePEG::FPU", 1); if ( debugfpu ) Debug::unmaskFpuErrors(); UseRandom currentRandom(theRandom); CurrentGenerator currentGenerator(this); checkSignalState(); EventPtr event = doShoot(); if ( event ) weightSum += event->weight(); DebugItem::tic(); return event; } EventPtr EventGenerator::doShoot() { EventPtr event; if ( N() >= 0 && ++ieve > N() ) return event; HoldFlag debug(Debug::level, Debug::isset? Debug::level: theDebugLevel); do { int state = 0; int loop = 1; eventHandler()->clearEvent(); try { do { // Generate a full event or part of an event if ( eventHandler()->empty() ) event = eventHandler()->generateEvent(); else event = eventHandler()->continueEvent(); if ( eventHandler()->empty() ) loop = -loop; // Analyze the possibly uncomplete event for ( AnalysisVector::iterator it = analysisHandlers().begin(); it != analysisHandlers().end(); ++it ) (**it).analyze(event, ieve, loop, state); // Manipulate the current event, possibly deleting some steps // and telling the event handler to redo them. if ( manipulator() ) state = manipulator()->manipulate(eventHandler(), event); // If the event was not completed, continue generation and continue. loop = abs(loop) + 1; } while ( !eventHandler()->empty() ); } catch (Exception & ex) { if ( logException(ex, eventHandler()->currentEvent()) ) throw; } catch (...) { event = eventHandler()->currentEvent(); if ( event ) log() << *event; else log() << "An exception occurred before any event object was created!"; log() << endl; if ( ThePEG_DEBUG_LEVEL ) dump(); throw; } if ( ThePEG_DEBUG_LEVEL ) { if ( ( ThePEG_DEBUG_LEVEL == Debug::printEveryEvent || ieve < printEvent ) && event ) log() << *event; if ( debugEvent > 0 && ieve + 1 >= debugEvent ) Debug::level = Debug::full; } } while ( !event ); // If scheduled, dump a clean state between events if ( ThePEG_DEBUG_LEVEL && dumpPeriod > 0 && ieve%dumpPeriod == 0 ) { eventHandler()->clearEvent(); eventHandler()->clean(); dump(); } return event; } EventPtr EventGenerator::doGenerateEvent(tEventPtr e) { if ( N() >= 0 && ++ieve > N() ) return EventPtr(); EventPtr event = e; try { event = eventHandler()->generateEvent(e); } catch (Exception & ex) { if ( logException(ex, eventHandler()->currentEvent()) ) throw; } catch (...) { event = eventHandler()->currentEvent(); if ( !event ) event = e; log() << *event << endl; dump(); throw; } return event; } EventPtr EventGenerator::doGenerateEvent(tStepPtr s) { if ( N() >= 0 && ++ieve > N() ) return EventPtr(); EventPtr event; try { event = eventHandler()->generateEvent(s); } catch (Exception & ex) { if ( logException(ex, eventHandler()->currentEvent()) ) throw; } catch (...) { event = eventHandler()->currentEvent(); if ( event ) log() << *event << endl; dump(); throw; } return event; } EventPtr EventGenerator::generateEvent(Event & e) { UseRandom currentRandom(theRandom); CurrentGenerator currentGenerator(this); EventPtr event = doGenerateEvent(tEventPtr(&e)); if ( event ) weightSum += event->weight(); return event; } EventPtr EventGenerator::generateEvent(Step & s) { UseRandom currentRandom(theRandom); CurrentGenerator currentGenerator(this); EventPtr event = doGenerateEvent(tStepPtr(&s)); if ( event ) weightSum += event->weight(); return event; } Energy EventGenerator::maximumCMEnergy() const { tcEHPtr eh = eventHandler(); return eh->lumiFnPtr()? eh->lumiFn().maximumCMEnergy(): ZERO; } void EventGenerator::doInitialize(bool initOnly) { if ( !initOnly ) openOutputFiles(); init(); if ( !initOnly ) initrun(); if ( !ThePEG_DEBUG_LEVEL ) Exception::noabort = true; } void EventGenerator::doGo(long next, long maxevent, bool tics) { if ( maxevent >= 0 ) N(maxevent); if ( next >= 0 ) { if ( tics ) cerr << "event> " << setw(9) << "init\r" << flush; initialize(); ieve = next-1; } else { openOutputFiles(); } if ( tics ) tic(); try { while ( shoot() ) { if ( tics ) tic(); } } catch ( ... ) { finish(); throw; } finish(); finally(); } void EventGenerator::tic(long currev, long totev) const { if ( !currev ) currev = ieve; if ( !totev ) totev = N(); long i = currev; long n = totev; bool skip = currev%(max(totev/100, 1L)); if ( i > n/2 ) i = n-i; while ( skip && i >= 10 && !(i%10) ) i /= 10; if ( i == 1 || i == 2 || i == 5 ) skip = false; if (!theIntermediateOutput) { //default if ( skip ) return; cerr << "event> " << setw(8) << currev << " " << setw(8) << totev << "\r"; } else if (theIntermediateOutput) { if ( skip && currev%10000!=0) return; cerr << "event> " << setw(9) << right << currev << "/" << totev << "; xs = " << integratedXSec()/picobarn << " pb +- " << integratedXSecErr()/picobarn << " pb" << endl; } cerr.flush(); if ( currev == totev ) cerr << endl; } void EventGenerator::dump() const { if ( dumpPeriod > -1 ) { string dumpfile; if ( keepAllDumps ) { ostringstream number; number << ieve; dumpfile = filename() + "-" + number.str() + ".dump"; } else dumpfile = filename() + ".dump"; PersistentOStream file(dumpfile, globalLibraries()); file << tcEGPtr(this); } } void EventGenerator::use(const Interfaced & i) { IBPtr ip = getPtr(i); if ( ip ) usedObjects.insert(ip); } void EventGenerator::generateReferences() { typedef map StringMap; StringMap references; // First get all model descriptions and model references from the // used objects. Put them in a map indexed by the description to // avoid duplicates. for ( ObjectSet::iterator it = usedObjects.begin(); it != usedObjects.end(); ++it ) { if ( *it == strategy() ) continue; string desc = Repository::getModelDescription(*it); if ( desc.empty() ) continue; if ( dynamic_ptr_cast(*it) ) desc = "A " + desc; else if ( dynamic_ptr_cast(*it) ) desc = "B " + desc; else if ( dynamic_ptr_cast(*it) ) desc = "C " + desc; else if ( dynamic_ptr_cast(*it) ) desc = "D " + desc; else if ( dynamic_ptr_cast(*it) ) desc = "E " + desc; else if ( dynamic_ptr_cast(*it) ) desc = "F " + desc; else if ( dynamic_ptr_cast(*it) ) desc = "Y " + desc; else if ( dynamic_ptr_cast(*it) ) desc = "Z " + desc; else if ( dynamic_ptr_cast::const_pointer>(*it) ) desc = "G " + desc; else desc = "H " + desc; references[desc] = Repository::getModelReferences(*it); } // Now get the main strategy description which should put first and // remove it from the map. string stratdesc; string stratref; if ( strategy() ) { stratdesc = Repository::getModelDescription(strategy()); stratref = Repository::getModelReferences(strategy()); references.erase(stratdesc); } // Open the file and write out an appendix header if ( !useStdout ) reffile().open((filename() + ".tex").c_str()); ref() << "\\documentclass{article}\n" << "\\usepackage{graphics}\n" << "\\begin{document}\n" << "\\appendix\n" << "\\section[xxx]{\\textsc{ThePEG} version " << Repository::version() << " \\cite{ThePEG} Run Information}\n" << "Run name: \\textbf{" << runName() << "}:\\\\\n"; if ( !stratdesc.empty() ) ref() << "This run was generated using " << stratdesc << " and the following models:\n"; else ref() << "The following models were used:\n"; ref() << "\\begin{itemize}\n"; // Write out all descriptions. for ( StringMap::iterator it = references.begin(); it != references.end(); ++it ) ref() << "\\item " << it->first.substr(2) << endl; // Write out thebibliography header and all references. ref() << "\\end{itemize}\n\n" << "\\begin{thebibliography}{99}\n" << "\\bibitem{ThePEG} L.~L\\\"onnblad, " << "Comput.~Phys.~Commun.\\ {\\bf 118} (1999) 213.\n"; if ( !stratref.empty() ) ref() << stratref << '\n'; for ( StringMap::iterator it = references.begin(); it != references.end(); ++it ) ref() << it->second << '\n'; ref() << "\\end{thebibliography}\n" << "\\end{document}" << endl; if ( !useStdout ) reffile().close(); } void EventGenerator::strategy(StrategyPtr s) { theStrategy = s; } int EventGenerator::count(const Exception & ex) { return ++theExceptions[make_pair(StringUtils::typeName(typeid(ex)), ex.severity())]; } void EventGenerator::printException(const Exception & ex) { switch ( ex.severity() ) { case Exception::info: log() << "* An information"; break; case Exception::warning: log() << "* A warning"; break; case Exception::setuperror: log() << "** A setup"; break; case Exception::eventerror: log() << "** An event"; break; case Exception::runerror: log() << "*** An run"; break; case Exception::maybeabort: case Exception::abortnow: log() << "**** A serious"; break; default: log() << "**** An unknown"; break; } if ( ieve > 0 ) log() << " exception of type " << StringUtils::typeName(typeid(ex)) << " occurred while generating event number " << ieve << ": \n" << ex.message() << endl; else log() << " exception occurred in the initialization of " << name() << ": \n" << ex.message() << endl; if ( ex.severity() == Exception::eventerror ) log() << "The event will be discarded." << endl; } void EventGenerator::logWarning(const Exception & ex) { if ( ex.severity() != Exception::info && ex.severity() != Exception::warning ) throw ex; ex.handle(); int c = count(ex); if ( c > maxWarnings ) return; printException(ex); if ( c == maxWarnings ) log() << "No more warnings of this kind will be reported." << endl; } bool EventGenerator:: logException(const Exception & ex, tcEventPtr event) { bool noEvent = !event; ex.handle(); int c = count(ex); if ( c <= maxWarnings ) { printException(ex); if ( c == maxWarnings ) log() << "No more warnings of this kind will be reported." << endl; } if ( ex.severity() == Exception::info || ex.severity() == Exception::warning ) { ex.handle(); return false; } if ( ex.severity() == Exception::eventerror ) { if ( c < maxErrors || maxErrors <= 0 ) { ex.handle(); if ( ThePEG_DEBUG_LEVEL > 0 && !noEvent ) log() << *event; return false; } if ( c > maxErrors ) printException(ex); log() << "Too many (" << c << ") exceptions of this kind has occurred. " "Execution will be stopped.\n"; } else { log() << "This exception is too serious. Execution will be stopped.\n"; } if ( !noEvent ) log() << *event; else log() << "An exception occurred before any event object was created!\n"; dump(); return true; } struct MatcherOrdering { bool operator()(tcPMPtr m1, tcPMPtr m2) const { return m1->name() < m2->name() || ( m1->name() == m2->name() && m1->fullName() < m2->fullName() ); } }; struct ObjectOrdering { bool operator()(tcIBPtr i1, tcIBPtr i2) const { return i1->fullName() < i2->fullName(); } }; void EventGenerator::persistentOutput(PersistentOStream & os) const { set match(theMatchers.begin(), theMatchers.end()); set usedset(usedObjects.begin(), usedObjects.end()); os << theDefaultObjects << theLocalParticles << theStandardModel << theStrategy << theRandom << theEventHandler << theAnalysisHandlers << theHistogramFactory << theEventManipulator << thePath << theRunName << theNumberOfEvents << theObjectMap << theParticles << theQuickParticles << theQuickSize << match << usedset << ieve << weightSum << theDebugLevel << logNonDefault << printEvent << dumpPeriod << keepAllDumps << debugEvent << maxWarnings << maxErrors << theCurrentEventHandler << theCurrentStepHandler << useStdout << theIntermediateOutput << theMiscStream.str() << Repository::listReadDirs(); } void EventGenerator::persistentInput(PersistentIStream & is, int) { string dummy; vector readdirs; theGlobalLibraries = is.globalLibraries(); is >> theDefaultObjects >> theLocalParticles >> theStandardModel >> theStrategy >> theRandom >> theEventHandler >> theAnalysisHandlers >> theHistogramFactory >> theEventManipulator >> thePath >> theRunName >> theNumberOfEvents >> theObjectMap >> theParticles >> theQuickParticles >> theQuickSize >> theMatchers >> usedObjects >> ieve >> weightSum >> theDebugLevel >> logNonDefault >> printEvent >> dumpPeriod >> keepAllDumps >> debugEvent >> maxWarnings >> maxErrors >> theCurrentEventHandler >> theCurrentStepHandler >> useStdout >> theIntermediateOutput >> dummy >> readdirs; theMiscStream.str(dummy); theMiscStream.seekp(0, std::ios::end); theObjects.clear(); for ( ObjectMap::iterator it = theObjectMap.begin(); it != theObjectMap.end(); ++it ) theObjects.insert(it->second); Repository::appendReadDir(readdirs); } void EventGenerator::setLocalParticles(PDPtr pd, int) { localParticles()[pd->id()] = pd; } void EventGenerator::insLocalParticles(PDPtr pd, int) { localParticles()[pd->id()] = pd; } void EventGenerator::delLocalParticles(int place) { ParticleMap::iterator it = localParticles().begin(); while ( place-- && it != localParticles().end() ) ++it; if ( it != localParticles().end() ) localParticles().erase(it); } vector EventGenerator::getLocalParticles() const { vector ret; for ( ParticleMap::const_iterator it = localParticles().begin(); it != localParticles().end(); ++it ) ret.push_back(it->second); return ret; } void EventGenerator::setPath(string newPath) { if ( std::system(("mkdir -p " + newPath).c_str()) ) throw EGNoPath(newPath); if ( std::system(("touch " + newPath + "/.ThePEG").c_str()) ) throw EGNoPath(newPath); if ( std::system(("rm -f " + newPath + "/.ThePEG").c_str()) ) throw EGNoPath(newPath); thePath = newPath; } string EventGenerator::defPath() const { char * env = std::getenv("ThePEG_RUN_DIR"); if ( env ) return string(env); return string("."); } ostream & EventGenerator::out() { return theOutStream; } ostream & EventGenerator::log() { return logfile().is_open()? logfile(): BaseRepository::cout(); } ostream & EventGenerator::ref() { return reffile().is_open()? reffile(): BaseRepository::cout(); } string EventGenerator::doSaveRun(string runname) { runname = StringUtils::car(runname); if ( runname.empty() ) runname = theRunName; if ( runname.empty() ) runname = name(); EGPtr eg = Repository::makeRun(this, runname); string file = eg->filename() + ".run"; PersistentOStream os(file); os << eg; if ( !os ) return "Error: Save failed! (I/O error)"; return ""; } string EventGenerator::doMakeRun(string runname) { runname = StringUtils::car(runname); if ( runname.empty() ) runname = theRunName; if ( runname.empty() ) runname = name(); Repository::makeRun(this, runname); return ""; } bool EventGenerator::preinitRegister(IPtr obj, string fullname) { if ( !preinitializing ) throw InitException() << "Tried to register a new object in the initialization of an " << "EventGenerator outside of the pre-initialization face. " << "The preinitRegister() can only be called from a doinit() function " << "in an object for which preInitialize() returns true."; if ( objectMap().find(fullname) != objectMap().end() ) return false; obj->name(fullname); objectMap()[fullname] = obj; objects().insert(obj); obj->theGenerator = this; PDPtr pd = dynamic_ptr_cast(obj); if ( pd ) theParticles[pd->id()] = pd; PMPtr pm = dynamic_ptr_cast(obj); if ( pm ) theMatchers.insert(pm); return true; } bool EventGenerator::preinitRemove(IPtr obj) { bool deleted=true; if(theObjects.find(obj)!=theObjects.end()) { theObjects.erase(obj); } else deleted = false; if(theObjectMap.find(obj->fullName())!=theObjectMap.end()) theObjectMap.erase(obj->fullName()); else deleted = false; return deleted; } IPtr EventGenerator:: preinitCreate(string classname, string fullname, string libraries) { if ( !preinitializing ) throw InitException() << "Tried to create a new object in the initialization of an " << "EventGenerator outside of the pre-initialization face. " << "The preinitCreate() can only be called from a doinit() function " << "in an object for which preInitialize() returns true."; if ( objectMap().find(fullname) != objectMap().end() ) return IPtr(); const ClassDescriptionBase * db = DescriptionList::find(classname); while ( !db && libraries.length() ) { string library = StringUtils::car(libraries); libraries = StringUtils::cdr(libraries); DynamicLoader::load(library); db = DescriptionList::find(classname); } if ( !db ) return IPtr(); IPtr obj = dynamic_ptr_cast(db->create()); if ( !obj ) return IPtr(); if ( !preinitRegister(obj, fullname) ) return IPtr(); return obj; } string EventGenerator:: preinitInterface(IPtr obj, string ifcname, string cmd, string value) { if ( !preinitializing ) throw InitException() << "Tried to manipulate an external object in the initialization of an " << "EventGenerator outside of the pre-initialization face. " << "The preinitSet() can only be called from a doinit() function " << "in an object for which preInitialize() returns true."; if ( !obj ) return "Error: No object found."; const InterfaceBase * ifc = Repository::FindInterface(obj, ifcname); if ( !ifc ) return "Error: No such interface found."; try { return ifc->exec(*obj, cmd, value); } catch ( const InterfaceException & ex) { ex.handle(); return "Error: " + ex.message(); } } string EventGenerator:: preinitInterface(IPtr obj, string ifcname, int index, string cmd, string value) { ostringstream os; os << index; return preinitInterface(obj, ifcname, cmd, os.str() + " " + value); } string EventGenerator:: preinitInterface(string fullname, string ifcname, string cmd, string value) { return preinitInterface(getObject(fullname), ifcname, cmd, value); } string EventGenerator:: preinitInterface(string fullname, string ifcname, int index, string cmd, string value) { return preinitInterface(getObject(fullname), ifcname, index, cmd, value); } tDMPtr EventGenerator::findDecayMode(string tag) const { for ( ObjectSet::const_iterator it = objects().begin(); it != objects().end(); ++it ) { tDMPtr dm = dynamic_ptr_cast(*it); if ( dm && dm->tag() == tag ) return dm; } return tDMPtr(); } tDMPtr EventGenerator::preinitCreateDecayMode(string tag) { return constructDecayMode(tag); } DMPtr EventGenerator::constructDecayMode(string & tag) { DMPtr rdm; DMPtr adm; int level = 0; string::size_type end = 0; while ( end < tag.size() && ( tag[end] != ']' || level ) ) { switch ( tag[end++] ) { case '[': ++level; break; case ']': --level; break; } } rdm = findDecayMode(tag.substr(0,end)); if ( rdm ) return rdm; string::size_type next = tag.find("->"); if ( next == string::npos ) return rdm; if ( tag.find(';') == string::npos ) return rdm; tPDPtr pd = getObject(tag.substr(0,next)); if ( !pd ) pd = findParticle(tag.substr(0,next)); if ( !pd ) return rdm; rdm = ptr_new(); rdm->parent(pd); if ( pd->CC() ) { adm = ptr_new(); adm->parent(pd->CC()); rdm->theAntiPartner = adm; adm->theAntiPartner = rdm; } bool error = false; tag = tag.substr(next+2); tPDPtr lastprod; bool dolink = false; do { switch ( tag[0] ) { case '[': { tag = tag.substr(1); tDMPtr cdm = constructDecayMode(tag); if ( cdm ) rdm->addCascadeProduct(cdm); else error = true; } break; case '=': dolink = true; [[fallthrough]]; case ',': case ']': tag = tag.substr(1); break; case '?': { next = min(tag.find(','), tag.find(';')); tPMPtr pm = findMatcher(tag.substr(1,next-1)); if ( pm ) rdm->addProductMatcher(pm); else error = true; tag = tag.substr(next); } break; case '!': { next = min(tag.find(','), tag.find(';')); tPDPtr pd = findParticle(tag.substr(1,next-1)); if ( pd ) rdm->addExcluded(pd); else error = true; tag = tag.substr(next); } break; case '*': { next = min(tag.find(','), tag.find(';')); tPMPtr pm = findMatcher(tag.substr(1,next-1)); if ( pm ) rdm->setWildMatcher(pm); else error = true; tag = tag.substr(next); } break; default: { next = min(tag.find('='), min(tag.find(','), tag.find(';'))); tPDPtr pdp = findParticle(tag.substr(0,next)); if ( pdp ) rdm->addProduct(pdp); else error = true; tag = tag.substr(next); if ( dolink && lastprod ) { rdm->addLink(lastprod, pdp); dolink = false; } lastprod = pdp; } break; } } while ( tag[0] != ';' && tag.size() ); if ( tag[0] != ';' || error ) { return DMPtr(); } tag = tag.substr(1); DMPtr ndm = findDecayMode(rdm->tag()); if ( ndm ) return ndm; pd->addDecayMode(rdm); if ( !preinitRegister(rdm, pd->fullName() + "/" + rdm->tag()) ) return DMPtr(); if ( adm ) { preinitRegister(adm, pd->CC()->fullName() + "/" + adm->tag()); rdm->CC(adm); adm->CC(rdm); } return rdm; } tPDPtr EventGenerator::findParticle(string pdgname) const { for ( ParticleMap::const_iterator it = particles().begin(); it != particles().end(); ++it ) if ( it->second->PDGName() == pdgname ) return it->second; return tPDPtr(); } tPMPtr EventGenerator::findMatcher(string name) const { for ( MatcherSet::const_iterator it = matchers().begin(); it != matchers().end(); ++it ) if ( (**it).name() == name ) return *it; return tPMPtr(); } ClassDescription EventGenerator::initEventGenerator; void EventGenerator::Init() { static ClassDocumentation documentation ("This is the main class used to administer an event generation run. " "The actual generation of each event is handled by the assigned " "EventHandler object. When the event generator" "is properly set up it can be initialized with the command " "MakeRun and/or saved to a file with the command " "SaveRun. If saved to a file, the event generator " "can be read into another program to produce events. The file can also " "be read into the runThePEG program where a number of events " "determined by the parameter NumberOfEvents is " "generated with each event analysed by the list of assigned " "AnalysisHandlers."); static Reference interfaceStandardModel ("StandardModelParameters", "The ThePEG::StandardModelBase object to be used to access standard " "model parameters in this run.", &EventGenerator::theStandardModel, false, false, true, false); static Reference interfaceEventHandler ("EventHandler", "The ThePEG::EventHandler object to be used to generate the " "individual events in this run.", &EventGenerator::theEventHandler, false, false, true, false); static RefVector interfaceAnalysisHandlers ("AnalysisHandlers", "ThePEG::AnalysisHandler objects to be used to analyze the produced " "events in this run.", &EventGenerator::theAnalysisHandlers, 0, true, false, true, false); static Reference interfaceHistogramFactory ("HistogramFactory", "An associated factory object for handling histograms to be used by " "AnalysisHandlers.", &EventGenerator::theHistogramFactory, true, false, true, true, true); static Reference interfaceEventManip ("EventManipulator", "An ThePEG::EventManipulator called each time the generation of an " "event is stopped. The ThePEG::EventManipulator object is able to " "manipulate the generated event, as opposed to an " "ThePEG::AnalysisHandler which may only look at the event.", &EventGenerator::theEventManipulator, true, false, true, true); static RefVector interfaceLocalParticles ("LocalParticles", "Special versions of ThePEG::ParticleData objects to be used " "in this run. Note that to delete an object, its number in the list " "should be given, rather than its id number.", 0, 0, false, false, true, false, &EventGenerator::setLocalParticles, &EventGenerator::insLocalParticles, &EventGenerator::delLocalParticles, &EventGenerator::getLocalParticles); static RefVector interfaceDefaultObjects ("DefaultObjects", "A vector of pointers to default objects. In a ThePEG::Reference or " "ThePEG::RefVector interface with the defaultIfNull() flag set, if a " "null pointer is encountered this vector is gone through until an " "acceptable object is found in which case the null pointer is replaced " "by a pointer to this object.", &EventGenerator::theDefaultObjects, 0, true, false, true, false, false); static Reference interfaceStrategy ("Strategy", "An ThePEG::Strategy with additional ThePEG::ParticleData objects to " "be used in this run.", &EventGenerator::theStrategy, false, false, true, true); static Reference interfaceRandomGenerator ("RandomNumberGenerator", "An ThePEG::RandomGenerator object which should typically interaface to " "a CLHEP Random object. This will be the default random number generator " "for the run, but individual objects may use their own random generator " "if they wish.", &EventGenerator::theRandom, true, false, true, false); static Parameter interfacePath ("Path", "The directory where the output files are put.", &EventGenerator::thePath, ".", true, false, &EventGenerator::setPath, 0, &EventGenerator::defPath); interfacePath.directoryType(); static Parameter interfaceRunName ("RunName", "The name of this run. This name will be used in the output filenames. " "The files wil be placed in the directory specified by the " "Path parameter" "If empty the name of the event generator will be used instead.", &EventGenerator::theRunName, "", true, false, 0, 0, &EventGenerator::name); static Parameter interfaceNumberOfEvents ("NumberOfEvents", "The number of events to be generated in this run. If less than zero, " "the number of events is unlimited", &EventGenerator::theNumberOfEvents, 1000, -1, Constants::MaxInt, true, false, Interface::lowerlim); static Parameter interfaceDebugLevel ("DebugLevel", "The level of debug information sent out to the log file in the run. " "Level 0 only gives a limited ammount of warnings and error messages. " "Level 1 will print the first few events. " "Level 5 will print every event. " "Level 9 will print every step in every event.", &EventGenerator::theDebugLevel, 0, 0, 9, true, false, true); static Parameter interfacePrintEvent ("PrintEvent", "If the debug level is above zero, print the first 'PrintEvent' events.", &EventGenerator::printEvent, 0, 0, 1000, true, false, Interface::lowerlim); static Parameter interfaceDumpPeriod ("DumpPeriod", "If the debug level is above zero, dump the full state of the run every " "'DumpPeriod' events. Set it to -1 to disable dumping even in the case of errors.", &EventGenerator::dumpPeriod, 0, -1, Constants::MaxInt, true, false, Interface::lowerlim); static Switch interfaceKeepAllDumps ("KeepAllDumps", "Whether all dump files should be kept, labelled by event number.", &EventGenerator::keepAllDumps, false, true, false); static SwitchOption interfaceKeepAllDumpsYes (interfaceKeepAllDumps, "Yes", "Keep all dump files, labelled by event number.", true); static SwitchOption interfaceKeepAllDumpsNo (interfaceKeepAllDumps, "No", "Keep only the latest dump file.", false); static Parameter interfaceDebugEvent ("DebugEvent", "If the debug level is above zero, step up to the highest debug level " "befor event number 'DebugEvent'.", &EventGenerator::debugEvent, 0, 0, Constants::MaxInt, true, false, Interface::lowerlim); static Parameter interfaceMaxWarnings ("MaxWarnings", "The maximum number of warnings of each type which will be printed.", &EventGenerator::maxWarnings, 10, 1, 100, true, false, Interface::lowerlim); static Parameter interfaceMaxErrors ("MaxErrors", "The maximum number of errors of each type which will be tolerated. " "If more errors are reported, the run will be aborted.", &EventGenerator::maxErrors, 10, -1, 100000, true, false, Interface::lowerlim); static Parameter interfaceQuickSize ("QuickSize", "The max absolute id number of particle data objects which are accessed " "quickly through a vector indexed by the id number.", &EventGenerator::theQuickSize, 7000, 0, 50000, true, false, Interface::lowerlim); static Command interfaceSaveRun ("SaveRun", "Isolate, initialize and save this event generator to a file, from which " "it can be read in and run in another program. If an agument is given " "this is used as the run name, otherwise the run name is taken from the " "RunName parameter.", &EventGenerator::doSaveRun, true); static Command interfaceMakeRun ("MakeRun", "Isolate and initialize this event generator and give it a run name. " "If no argument is given, the run name is taken from the " "RunName parameter.", &EventGenerator::doMakeRun, true); interfaceEventHandler.rank(11.0); interfaceSaveRun.rank(10.0); interfaceMakeRun.rank(9.0); interfaceRunName.rank(8.0); interfaceNumberOfEvents.rank(7.0); interfaceAnalysisHandlers.rank(6.0); static Switch interfaceUseStdout ("UseStdout", "Redirect the logging and output to stdout instead of files.", &EventGenerator::useStdout, false, true, false); static SwitchOption interfaceUseStdoutYes (interfaceUseStdout, "Yes", "Use stdout instead of log files.", true); static SwitchOption interfaceUseStdoutNo (interfaceUseStdout, "No", "Use log files.", false); static Switch interfaceLogNonDefault ("LogNonDefault", "Controls the printout of important interfaces which has been changed from their default values.", &EventGenerator::logNonDefault, -1, true, false); static SwitchOption interfaceLogNonDefaultYes (interfaceLogNonDefault, "Yes", "Always print changed interfaces.", 1); static SwitchOption interfaceLogNonDefaultOnDebug (interfaceLogNonDefault, "OnDebug", "Only print changed interfaces if debugging is turned on.", 0); static SwitchOption interfaceLogNonDefaultNo (interfaceLogNonDefault, "No", "Don't print changed interfaces.", -1); interfaceLogNonDefault.setHasDefault(false); static Switch interfaceIntermediateOutput ("IntermediateOutput", "Modified event number count with the number of events processed so far, " "which updates at least every 10000 events, together with the corresponding " "intermediate estimate for the cross section plus the integration error.", &EventGenerator::theIntermediateOutput, false, true, false); static SwitchOption interfaceIntermediateOutputYes (interfaceIntermediateOutput, "Yes", "Show the modified event number count with the number of events processed so far, " "plus further information on the intermediate cross section estimate.", true); static SwitchOption interfaceIntermediateOutputNo (interfaceIntermediateOutput, "No", "Show the usual event number count with the number of events processed so far, " "but no further information on the intermediate cross section estimate.", false); } EGNoPath::EGNoPath(string path) { theMessage << "Cannot set the directory path for output files to '" << path << "' because the directory did not exist and could not be " << "created."; severity(warning); } diff --git a/Repository/MultiEventGenerator.cc b/Repository/MultiEventGenerator.cc --- a/Repository/MultiEventGenerator.cc +++ b/Repository/MultiEventGenerator.cc @@ -1,347 +1,347 @@ // -*- C++ -*- // // MultiEventGenerator.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the MultiEventGenerator class. // #include "MultiEventGenerator.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Command.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Repository/BaseRepository.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/Rebinder.h" #include "ThePEG/EventRecord/Event.h" #include "ThePEG/Config/algorithm.h" #include "ThePEG/Utilities/StringUtils.h" #include "ThePEG/Handlers/EventHandler.h" #include "ThePEG/Repository/CurrentGenerator.h" #include using namespace ThePEG; MultiEventGenerator::~MultiEventGenerator() {} IBPtr MultiEventGenerator::clone() const { return new_ptr(*this); } IBPtr MultiEventGenerator::fullclone() const { return new_ptr(*this); } string MultiEventGenerator::removeInterface(string cmd) { string noun = StringUtils::car(cmd); IBPtr ip = BaseRepository::getObjectFromNoun(noun); const InterfaceBase * ifb = BaseRepository:: FindInterface(ip, BaseRepository::getInterfaceFromNoun(noun)); string posarg = BaseRepository::getPosArgFromNoun(noun); for ( string::size_type i = 0; i < theObjects.size(); ++i ) { if ( theObjects[i] == ip && theInterfaces[i] == ifb->name() && thePosArgs[i] == posarg ) { theObjects.erase(theObjects.begin() + i); theInterfaces.erase(theInterfaces.begin() + i); thePosArgs.erase(thePosArgs.begin() + i); theValues.erase(theValues.begin() + i); return ""; } } return "No such object/interface defined for this MultiEventGenerator."; } string MultiEventGenerator::addInterface(string cmd) { return addInterface(cmd, false); } string MultiEventGenerator::addRndInterface(string cmd) { return addInterface(cmd, true); } string MultiEventGenerator::addInterface(string cmd, bool rnd) { breakThePEG(); string noun = StringUtils::car(cmd); IBPtr ip = BaseRepository::getObjectFromNoun(noun); const InterfaceBase * ifb = BaseRepository:: FindInterface(ip, BaseRepository::getInterfaceFromNoun(noun)); string posarg = BaseRepository::getPosArgFromNoun(noun); cmd = StringUtils::cdr(cmd); if ( cmd.empty() ) return "Error: empty argument list."; string ret; string oldvalue = ifb->exec(*ip, "get", posarg); StringVector args; try { if ( rnd ) { do { args.push_back(StringUtils::car(cmd)); cmd = StringUtils::cdr(cmd); } while ( !cmd.empty() ); if ( args.size() < 3 ) return "Error: Argument list should be 'N min max mean width'."; int N = atoi(args[0].c_str()); string vmin = args[1]; string vmax = args[2]; string vmean = "0"; if ( args.size() > 3 ) vmean = args[3]; string vwidth = "0"; if ( args.size() > 4 ) vwidth = args[4]; string arg = "RND " + vmin + " " + vmax + " " + vmean + " " + vwidth; args = vector(N, arg); ifb->exec(*ip, "set", vmin); ifb->exec(*ip, "set", vmax); ifb->exec(*ip, "set", posarg + " " + oldvalue); } else { do { args.push_back(StringUtils::car(cmd, ",")); cmd = StringUtils::cdr(cmd, ","); } while ( !cmd.empty() ); for ( string::size_type i = 0; i < args.size(); ++i ) ifb->exec(*ip, "set", args[i]); } } catch (const Exception & e) { e.handle(); ret = "Error: " + e.message(); } ifb->exec(*ip, "set", posarg + " " + oldvalue); if ( !ret.empty() ) return ret; for ( string::size_type i = 0; i < theObjects.size(); ++i ) { if ( theObjects[i] == ip && theInterfaces[i] == ifb->name() && thePosArgs[i] == posarg ) { if ( rnd || theValues[i][0].substr(0,3) == "RND" ) theValues[i] = args; else theValues[i].insert(theValues[i].end(), args.begin(), args.end()); return ""; } } theObjects.push_back(ip); theInterfaces.push_back(ifb->name()); thePosArgs.push_back(posarg); theValues.push_back(args); return ""; } void MultiEventGenerator::addTag(string tag) { if ( tag[0] == '#' ) { string::size_type dash = tag.find('-'); if ( dash == string::npos ) firstSubrun = lastSubrun = atoi(tag.substr(1).c_str()); else { firstSubrun = atoi(tag.substr(1, dash - 1).c_str()); lastSubrun = atoi(tag.substr(dash + 1).c_str()); } } EventGenerator::addTag(tag); } void MultiEventGenerator::doGo(long next, long maxevent, bool tics) { if ( theObjects.empty() || next < 0 ) { EventGenerator::doGo(next, maxevent, tics); return; } if ( maxevent >= 0 ) N(maxevent); vector interfaces; long nargs = 1; for ( string::size_type i = 0; i < theObjects.size(); ++i ) { nargs *= theValues[i].size(); interfaces.push_back(BaseRepository::FindInterface(theObjects[i], theInterfaces[i])); } if ( theSeparateRandom ) { theSeparateRandom->init(); theSeparateRandom->initrun(); const InterfaceBase * ifb = BaseRepository::FindInterface(theSeparateRandom, "Seed"); ifb->exec(*theSeparateRandom, "set", "0"); } openOutputFiles(); string baseName = runName(); if ( tics ) tic(next - 1, nargs*N()); for ( long iargs = 0; iargs < nargs; ++iargs ) { ostringstream subname; subname << baseName << ":" << iargs + 1; runName(subname.str()); string head = heading(iargs, interfaces, baseName); if ( ( firstSubrun > 0 && iargs + 1 < firstSubrun ) || ( lastSubrun > 0 && iargs + 1 > lastSubrun ) ) { if ( theSeparateRandom ) { // This is needed to ensure the same random settings for a // given sub-run irrespectively if previous sub-runs have been // included or not. theSeparateRandom->reset(); theSeparateRandom->init(); theSeparateRandom->initrun(); } continue; } log() << head; out() << head; reset(); - for_each(objects(), mem_fun(&InterfacedBase::reset)); + for_each(objects(), mem_fn(&InterfacedBase::reset)); init(); initrun(); ieve = next-1; try { while ( shoot() ) { if ( tics ) tic(ieve + iargs*N(), nargs*N()); } } catch ( ... ) { finish(); throw; } finish(); } runName(baseName); finally(); } string MultiEventGenerator:: heading(long iargs, const vector & interfaces, string baseName) const { ostringstream os; long div = 1; if ( iargs > 0 ) os << endl; os << ">> " << baseName << " sub-run number " << iargs + 1 << " using the following interface values:" << endl; for ( string::size_type i = 0; i < theObjects.size(); ++i ) { long iarg = (iargs/div)%theValues[i].size(); string sval = theValues[i][iarg]; if ( theValues[i][iarg].substr(0,3) == "RND" ) { double vmin, vmax, vmean, vwidth; istringstream is(theValues[i][iarg].substr(3)); is >> vmin >> vmax >> vmean >> vwidth; double val = randomArg().rnd(vmin, vmax); if ( vwidth > 0.0 ) do { val = randomArg().rndGauss(vwidth, vmean); } while ( val < vmin || val > vmax ); ostringstream ssv; ssv << val; sval = ssv.str(); } interfaces[i]->exec(*theObjects[i], "set", thePosArgs[i] + " " + sval); os << " set " << theObjects[i]->name() << ":" << theInterfaces[i]; if ( !thePosArgs[i].empty() ) os << "[" << thePosArgs[i] << "]"; os << " " << sval << endl; div *= theValues[i].size(); } os << endl; return os.str(); } void MultiEventGenerator::persistentOutput(PersistentOStream & os) const { os << theObjects << theInterfaces << thePosArgs << theValues << firstSubrun << lastSubrun << theSeparateRandom; } void MultiEventGenerator::persistentInput(PersistentIStream & is, int) { is >> theObjects >> theInterfaces >> thePosArgs >> theValues >> firstSubrun >> lastSubrun >> theSeparateRandom; } IVector MultiEventGenerator::getReferences() { IVector ret = EventGenerator::getReferences(); ret.insert(ret.end(), theObjects.begin(), theObjects.end()); return ret; } void MultiEventGenerator::rebind(const TranslationMap & trans) { for ( string::size_type i = 0; i < theObjects.size(); ++i ) theObjects[i] = trans.translate(theObjects[i]); EventGenerator::rebind(trans); } ClassDescription MultiEventGenerator::initMultiEventGenerator; // Definition of the static class description member. void MultiEventGenerator::Init() { static ClassDocumentation documentation ("The ThePEG::MultiEventGenerator class is derived from the " "ThePEG::EventGenerator and is capable of making " "several runs with a pre-defined set of parameter and switch values."); static Command interfaceAddInterface ("AddInterface", "If arguments are given on the form 'object-name:interface-name arg1, " "arg2, arg3' or 'object-name:vectorinterface-name[pos] arg1, arg2, arg3' " "the generator will be run three times with the corresonding interface of " "the given object set to arg1, arg2, arg3 in each run respectively. If " "another interface with e.g. 4 different arguments, the generator will " "be run 12 times once for each combination of arguments. If called with " "an object and interface wich has already been given in a previous call, " "the new arguments will be added to the previously specified list without " "checking if any argument is doubled.", &MultiEventGenerator::addInterface); static Command interfaceAddRndInterface ("AddRndInterface", "If arguments are given on the form 'object-name:interface-name N min max " "mean width'"" or 'object-name:vectorinterface-name[pos] N min max mean width' " "the generator will be run N times with the corresonding interface of " "the given object set to a random value between min and max according to a " "Gaussian distribution with the given mean and width (if the width is absent " "or zero a flat distribution between min and max will be used instead) . If " "another interface with e.g. 4 different arguments, the generator will " "be run N*4 times once for each combination of arguments and the specified " "interface will get a new random value each time.. If called with " "an object and interface wich has already been given in a previous call to " "AddInterface or AddRndInterface " "the previous call will be ignored.", &MultiEventGenerator::addRndInterface); static Command interfaceRemoveInterface ("RemoveInterface", "If arguments are given on the form 'object-name:interface-name' and " "the same interface and object was previously with an " "AddInterface}, the corresponding arguments are " "removed and the interfaced will be left unchanged during the generation.", &MultiEventGenerator::removeInterface); static Reference interfaceSeparateRandom ("SeparateRandom", "A separate random number generator used for AddRndInterface" " to ensure reproducible sequences of interface values. If null, the standard " "random generator will be used instead.", &MultiEventGenerator::theSeparateRandom, true, false, true, true, false); interfaceAddInterface.rank(10.7); interfaceRemoveInterface.rank(10.5); } diff --git a/Repository/Repository.cc b/Repository/Repository.cc --- a/Repository/Repository.cc +++ b/Repository/Repository.cc @@ -1,1131 +1,1131 @@ // -*- C++ -*- // // Repository.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the Repository class. // // macro is passed in from -D compile flag #ifndef THEPEG_PKGLIBDIR #error Makefile.am needs to define THEPEG_PKGLIBDIR #endif #include "Repository.h" #include "ThePEG/Utilities/Rebinder.h" #include "ThePEG/Handlers/EventHandler.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Repository/Strategy.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/Debug.h" #include "ThePEG/Config/algorithm.h" #include "ThePEG/Utilities/DynamicLoader.h" #include "ThePEG/Utilities/StringUtils.h" #include #include #include // readline options taken from // http://autoconf-archive.cryp.to/vl_lib_readline.html // Copyright © 2008 Ville Laurikari // Copying and distribution of this file, with or without // modification, are permitted in any medium without royalty provided // the copyright notice and this notice are preserved. #ifdef HAVE_LIBREADLINE # if defined(HAVE_READLINE_READLINE_H) # include # elif defined(HAVE_READLINE_H) # include # else extern "C" char *readline (const char *); # endif #endif #ifdef HAVE_READLINE_HISTORY # if defined(HAVE_READLINE_HISTORY_H) # include # elif defined(HAVE_HISTORY_H) # include # else extern "C" void add_history (const char *); # endif #endif using namespace ThePEG; ParticleMap & Repository::defaultParticles() { static ParticleMap theMap; return theMap; } ParticleDataSet & Repository::particles() { static ParticleDataSet theSet; return theSet; } MatcherSet & Repository::matchers() { static MatcherSet theSet; return theSet; } Repository::GeneratorMap & Repository::generators() { static GeneratorMap theMap;; return theMap; } string & Repository::currentFileName() { static string theCurrentFileName; return theCurrentFileName; } int & Repository::exitOnError() { static int exitonerror = 0; return exitonerror; } void Repository::cleanup() { generators().clear(); } void Repository::Register(IBPtr ip) { BaseRepository::Register(ip); registerParticle(dynamic_ptr_cast(ip)); registerMatcher(dynamic_ptr_cast(ip)); } void Repository::Register(IBPtr ip, string newName) { DirectoryAppend(newName); BaseRepository::Register(ip, newName); registerParticle(dynamic_ptr_cast(ip)); registerMatcher(dynamic_ptr_cast(ip)); } void Repository::registerParticle(tPDPtr pd) { if ( !pd ) return; if ( !member(particles(), pd) ) { particles().insert(pd); CreateDirectory(pd->fullName()); } if ( pd->id() == 0 ) return; if ( !member(defaultParticles(), pd->id()) ) defaultParticles()[pd->id()] = pd; for ( MatcherSet::iterator it = matchers().begin(); it != matchers().end(); ++it) (*it)->addPIfMatch(pd); } void Repository::registerMatcher(tPMPtr pm) { if ( !pm || member(matchers(), pm) ) return; pm->addPIfMatchFrom(particles()); for ( MatcherSet::iterator it = matchers().begin(); it != matchers().end(); ++it) { (*it)->addMIfMatch(pm); pm->addMIfMatch(*it); } matchers().insert(pm); } tPDPtr Repository::findParticle(string name) { tPDPtr pd; string path = name; DirectoryAppend(path); pd = dynamic_ptr_cast(GetPointer(path)); if ( pd ) return pd; for ( ParticleMap::iterator pit = defaultParticles().begin(); pit != defaultParticles().end(); ++pit ) if ( pit->second->PDGName() == name ) return pit->second; for ( ParticleDataSet::iterator pit = particles().begin(); pit != particles().end(); ++pit ) if ( (**pit).PDGName() == name ) return *pit; return pd; } tPMPtr Repository::findMatcher(string name) { for ( MatcherSet::iterator mit = matchers().begin(); mit != matchers().end(); ++mit ) if ( name == (**mit).name() ) return *mit; return tPMPtr(); } void Repository::saveRun(string EGname, string name, string filename) { EGPtr eg = BaseRepository::GetObject(EGname); EGPtr run = makeRun(eg, name); PersistentOStream os(filename, globalLibraries()); if ( ThePEG_DEBUG_ITEM(3) ) clog() << "Saving event generator '" << name << "'... " << flush; os << run; if ( ThePEG_DEBUG_ITEM(3) ) clog() << "done" << endl; } EGPtr Repository::makeRun(tEGPtr eg, string name) { // Clone all objects relevant for the EventGenerator. This is // the EventGenerator itself, all particles and all particle // matchers. 'localObject' is the set of all object refered to by // the generator particles and matcher and in the end these are // cloned as well. // Clone all Particle matchers if ( ThePEG_DEBUG_ITEM(3) ) clog() << "Making event generator '" << name << "':" << endl << "Updating all objects... " << flush; if ( ThePEG_DEBUG_ITEM(3) ) clog() << "done\nCloning matchers and particles... " << flush; MatcherSet localMatchers; ObjectSet localObjects; ObjectSet clonedObjects; TranslationMap trans; for ( MatcherSet::iterator mit = matchers().begin(); mit != matchers().end(); ++mit ) { PMPtr pm = clone(**mit); pm->clear(); trans[*mit] = pm; localMatchers.insert(pm); clonedObjects.insert(pm); localObjects.insert(*mit); addReferences(*mit, localObjects); } // Clone the particles. But only the ones which should be // used. First select the localParticles of the EventGenerator, then // add particles from the strategy of the EventGenerator which have // not already been selected. Finally add particles from the global // default if no default directories has been specified in the // strategy which have not already been selected. PDVector allParticles; for ( ParticleMap::const_iterator pit = eg->localParticles().begin(); pit != eg->localParticles().end(); ++pit ) allParticles.push_back(pit->second); if ( eg->strategy() ) { tcStrategyPtr strat = eg->strategy(); for ( ParticleMap::const_iterator pit = strat->particles().begin(); pit != strat->particles().end(); ++pit ) allParticles.push_back(pit->second); vector pdirs; if ( eg->strategy()->localParticlesDir().length() ) pdirs.push_back(eg->strategy()->localParticlesDir()); pdirs.insert(pdirs.end(), eg->strategy()->defaultParticlesDirs().begin(), eg->strategy()->defaultParticlesDirs().end()); for ( int i = 0, N = pdirs.size(); i < N; ++i ) { string dir = pdirs[i]; for ( ParticleDataSet::iterator pit = particles().begin(); pit != particles().end(); ++pit ) if ( (**pit).fullName().substr(0, dir.length()) == dir ) allParticles.push_back(*pit); } } if ( !eg->strategy() || eg->strategy()->defaultParticlesDirs().empty() ) for ( ParticleMap::iterator pit = defaultParticles().begin(); pit != defaultParticles().end(); ++pit ) allParticles.push_back(pit->second); for ( ParticleDataSet::iterator pit = particles().begin(); pit != particles().end(); ++pit ) allParticles.push_back(*pit); ParticleMap localParticles; set pdgnames; for ( PDVector::iterator pit = allParticles.begin(); pit != allParticles.end(); ++pit ) { ParticleMap::iterator it = localParticles.find((**pit).id()); if ( it == localParticles.end() ) { PDPtr pd = clone(**pit); trans[*pit] = pd; localParticles[pd->id()] = pd; clonedObjects.insert(pd); localObjects.insert(*pit); addReferences(*pit, localObjects); if ( pdgnames.find(pd->PDGName()) != pdgnames.end() ) std::cerr << "Using duplicate PDGName " << pd->PDGName() << " for a new particle.\n This can cause problems and is not " << "recommended.\n If this second particle is a new particle " << "in a BSM Model we recommend you change the name of the particle.\n"; else pdgnames.insert(pd->PDGName()); } else { trans[*pit] = it->second; } } if ( ThePEG_DEBUG_ITEM(3) ) clog() << "done\nCloning other objects... " << flush; // Clone the OldEventGenerator object to be used: localObjects.insert(eg); addReferences(eg, localObjects); EGPtr egrun = clone(*eg); clonedObjects.insert(egrun); trans[eg] = egrun; for ( ObjectSet::iterator it = localObjects.begin(); it != localObjects.end(); ++it ) { if ( member(trans.map(), *it) ) continue; IBPtr ip = clone(**it); trans[*it] = ip; clonedObjects.insert(ip); } if ( ThePEG_DEBUG_ITEM(3) ) clog() << "done\nRebind references... " << flush; IVector defaults; trans.translate(inserter(defaults), eg->defaultObjects().begin(), eg->defaultObjects().end()); if ( eg->strategy() ) trans.translate(inserter(defaults), eg->strategy()->defaultObjects().begin(), eg->strategy()->defaultObjects().end()); for ( ObjectSet::iterator it = clonedObjects.begin(); it != clonedObjects.end(); ++it ) { dynamic_cast(**it).theGenerator = egrun; rebind(**it, trans, defaults); } // Now, dependencies may have changed, so we do a final round of // updates. if ( ThePEG_DEBUG_ITEM(3) ) clog() << "done\nUpdating cloned objects... " << flush; if ( ThePEG_DEBUG_ITEM(3) ) clog() << "done\nInitializing... " << flush; clonedObjects.erase(egrun); egrun->setup(name, clonedObjects, localParticles, localMatchers); if ( ThePEG_DEBUG_ITEM(3) ) clog() << "done" << endl; generators()[name] = egrun; return egrun; } PDPtr Repository::defaultParticle(PID id) { ParticleMap::iterator pit = defaultParticles().find(id); return pit == defaultParticles().end()? PDPtr(): pit->second; } void Repository::defaultParticle(tPDPtr pdp) { if ( pdp ) defaultParticles()[pdp->id()] = pdp; } struct ParticleOrdering { bool operator()(tcPDPtr p1, tcPDPtr p2) const { return abs(p1->id()) > abs(p2->id()) || ( abs(p1->id()) == abs(p2->id()) && p1->id() > p2->id() ) || ( p1->id() == p2->id() && p1->fullName() > p2->fullName() ); } }; struct MatcherOrdering { bool operator()(tcPMPtr m1, tcPMPtr m2) const { return m1->name() < m2->name() || ( m1->name() == m2->name() && m1->fullName() < m2->fullName() ); } }; struct InterfaceOrdering { bool operator()(tcIBPtr i1, tcIBPtr i2) const { return i1->fullName() < i2->fullName(); } }; void Repository::save(string filename) { if ( ThePEG_DEBUG_ITEM(3) ) clog() << "saving '" << filename << "'... " << flush; PersistentOStream os(filename, globalLibraries()); set part(particles().begin(), particles().end()); set match(matchers().begin(), matchers().end()); os << objects().size(); for ( ObjectMap::iterator it = objects().begin(); it != objects().end(); ++it ) os << it->second; os << defaultParticles() << part << match << generators() << directories() << directoryStack() << globalLibraries() << readDirs(); if ( ThePEG_DEBUG_ITEM(3) ) clog() << "(" << objects().size() << " objects in " << directories().size() << " directories) done" << endl; } string Repository::load(string filename) { if ( ThePEG_DEBUG_ITEM(3) ) clog() << "loading '" << filename << "'... " << flush; currentFileName() = filename; PersistentIStream * is = new PersistentIStream(filename); if ( !*is ) { delete is; // macro is passed in from -D compile flag string fullpath = string(THEPEG_PKGLIBDIR) + '/' + filename; is = new PersistentIStream(fullpath); if ( !*is ) { delete is; return "Error: Could not find repository '" + filename + "'."; } } *is >> allObjects() >> defaultParticles() >> particles() >> matchers() >> generators() >> directories() >> directoryStack() >> globalLibraries() >> readDirs(); delete is; objects().clear(); for ( ObjectSet::iterator it = allObjects().begin(); it != allObjects().end(); ++it ) objects()[(**it).fullName()] = *it; if ( ThePEG_DEBUG_ITEM(3) ) clog() << "(" << objects().size() << " objects in " << directories().size() << " directories) done\nUpdating... " << flush; BaseRepository::resetAll(allObjects()); BaseRepository::update(); if ( ThePEG_DEBUG_ITEM(3) ) clog() << "done" << endl; return ""; } void Repository::stats(ostream & os) { os << "number of objects: " << setw(6) << objects().size() << endl; os << "number of objects (all): " << setw(6) << allObjects().size() << endl; os << "number of particles: " << setw(6) << particles().size() << endl; os << "number of matchers: " << setw(6) << matchers().size() << endl; } string Repository::read(string filename, ostream & os) { ifstream is; string file = filename; if ( file[0] == '/' ) { if ( ThePEG_DEBUG_LEVEL > 1 ) os << "(= trying to open " << file << " =)" << endl; is.open(file.c_str()); } else { vector dirs(readDirs().rbegin(), readDirs().rend()); dirs.push_back(currentReadDirStack().top()); if ( ThePEG_DEBUG_LEVEL > 1 ) { os << "(= search path order =)\n(== "; std::copy(dirs.rbegin(), dirs.rend(), std::ostream_iterator(os, " ==)\n(== ")); os << ")" << endl; } while ( dirs.size() ) { string dir = dirs.back(); if ( dir != "" && dir[dir.length() -1] != '/' ) dir += '/'; file = dir + filename; is.clear(); if ( ThePEG_DEBUG_LEVEL > 1 ) os << "(= trying to open " << file << " =)" << endl; is.open(file.c_str()); if ( is ) break; if ( ThePEG_DEBUG_LEVEL > 1 ) os << "(= no, try next search path =)" << endl; dirs.pop_back(); } } if ( !is ) { return "Error: Could not find input file '" + filename + "'"; } if ( ThePEG_DEBUG_LEVEL > 1 ) os << "(= yes =)" << endl; const string dir = StringUtils::dirname(file); if ( ThePEG_DEBUG_LEVEL > 1 ) os << "(= pushing <" << dir << "> to stack =)" << endl; currentReadDirStack().push(dir); try { Repository::read(is, os); if ( ThePEG_DEBUG_LEVEL > 1 ) os << "(= popping <" << currentReadDirStack().top() << "> from stack =)" << endl; currentReadDirStack().pop(); } catch ( ... ) { if ( ThePEG_DEBUG_LEVEL > 1 ) os << "(= popping <" << currentReadDirStack().top() << "> from stack =)" << endl; currentReadDirStack().pop(); throw; } return ""; } string Repository:: modifyEventGenerator(EventGenerator & eg, string filename, ostream & os, bool initOnly) { ObjectSet objs = eg.objects(); objs.insert(&eg); for ( ObjectSet::iterator it = objs.begin(); it != objs.end(); ++it ) { string name = (**it).fullName(); if ( name.rfind('/') != string::npos ) CreateDirectory(name.substr(0, name.rfind('/') + 1)); objects()[name] = *it; allObjects().insert(*it); } string msg = read(filename, os); if ( !msg.empty() ) return msg; - for_each(objs, mem_fun(&InterfacedBase::reset)); + for_each(objs, mem_fn(&InterfacedBase::reset)); eg.initialize(initOnly); if ( !generators().empty() ) msg += "Warning: new generators were initialized while modifying " + eg.fullName() + ".\n"; return msg; } void Repository::resetEventGenerator(EventGenerator & eg) { ObjectSet objs = eg.objects(); objs.insert(&eg); for ( ObjectSet::iterator it = objs.begin(); it != objs.end(); ++it ) { string name = (**it).fullName(); if ( name.rfind('/') != string::npos ) CreateDirectory(name.substr(0, name.rfind('/') + 1)); objects()[name] = *it; allObjects().insert(*it); } - for_each(objs, mem_fun(&InterfacedBase::reset)); + for_each(objs, mem_fn(&InterfacedBase::reset)); eg.initialize(true); } void Repository::execAndCheckReply(string line, ostream & os) { string reply = exec(line, os); if ( reply.size() ) os << reply; if ( reply.size() && reply[reply.size()-1] != '\n' ) os << endl; if ( exitOnError() && reply.size() >= 7 && reply.substr(0, 7) == "Error: " ) exit(exitOnError()); } void Repository::read(istream & is, ostream & os, string prompt) { #ifdef HAVE_LIBREADLINE if ( &is == &std::cin ) { char * line_read = 0; do { if ( line_read ) { free(line_read); line_read = 0; } line_read = readline(prompt.c_str()); if ( line_read && *line_read ) { string line = line_read; while ( !line.empty() && line[line.size() - 1] == '\\' ) { line[line.size() - 1] = ' '; char * cont_read = readline("... "); if ( cont_read ) { line += cont_read; free(cont_read); } } if ( prompt.empty() && ThePEG_DEBUG_LEVEL > 0 ) os << "(" << line << ")" << endl; #ifdef HAVE_READLINE_HISTORY add_history(line.c_str()); #endif // HAVE_READLINE_HISTORY execAndCheckReply(line, os); } } while ( line_read ); } else { #endif // HAVE_LIBREADLINE string line; if ( prompt.size() ) os << prompt; while ( getline(is, line) ) { while ( !line.empty() && line[line.size() - 1] == '\\' ) { line[line.size() - 1] = ' '; string cont; if ( prompt.size() ) os << "... "; getline(is, cont); line += cont; } if ( prompt.empty() && ThePEG_DEBUG_LEVEL > 0 ) os << "(" << line << ")" << endl; execAndCheckReply(line, os); if ( prompt.size() ) os << prompt; } #ifdef HAVE_LIBREADLINE } #endif if ( prompt.size() ) os << endl; } string Repository::copyParticle(tPDPtr p, string newname) { DirectoryAppend(newname); string newdir = newname.substr(0, newname.rfind('/')+1); newname =newname.substr(newname.rfind('/')+1); if ( newname.empty() ) newname = p->name(); if ( GetPointer(newdir + newname) ) return "Error: Cannot create particle " + newdir + newname + ". Object already exists."; if ( p->CC() && GetPointer(newdir + p->CC()->name()) ) return "Error: Cannot create anti-particle " + newdir + newname + ". Object already exists."; PDPtr pd = p->pdclone(); Register(pd, newdir + newname); pd->theDecaySelector.clear(); pd->theDecayModes.clear(); pd->isStable = true; if ( p->CC() ) { PDPtr apd = p->CC()->pdclone(); Register(apd, newdir + apd->name()); apd->theDecaySelector.clear(); apd->theDecayModes.clear(); apd->isStable = true; pd->theAntiPartner = apd; apd->theAntiPartner = pd; pd->syncAnti = p->syncAnti; apd->syncAnti = p->CC()->syncAnti; } HoldFlag<> dosync(pd->syncAnti, true); for ( DecaySet::const_iterator it = p->theDecayModes.begin(); it != p->theDecayModes.end(); ++it ) pd->addDecayMode(*it); return ""; } void Repository::remove(tIBPtr ip) { ObjectMap::iterator it = objects().find(ip->fullName()); if ( it == objects().end() || ip != it->second ) return; objects().erase(it); allObjects().erase(ip); if ( dynamic_ptr_cast(ip) ) { particles().erase(dynamic_ptr_cast(ip)); defaultParticles().erase(dynamic_ptr_cast(ip)->id()); } if ( dynamic_ptr_cast(ip) ) matchers().erase(dynamic_ptr_cast(ip)); } string Repository::remove(const ObjectSet & rmset) { ObjectSet refset; for ( ObjectMap::const_iterator i = objects().begin(); i != objects().end(); ++i ) { if ( member(rmset, i->second) ) continue; IVector ov = DirectReferences(i->second); for ( int j = 0, M = ov.size(); j < M; ++j ) if ( member(rmset, ov[j]) ) { refset.insert(i->second); break; } } if ( refset.empty() ) { for ( ObjectSet::iterator oi = rmset.begin(); oi != rmset.end(); ++oi ) remove(*oi); return ""; } string ret = "Error: cannot remove the objects because the following " "objects refers to some of them:\n"; for ( ObjectSet::iterator oi = refset.begin(); oi != refset.end(); ++oi ) ret += (**oi).fullName() + "\n"; return ret; } string Repository::exec(string command, ostream & os) { string cpcmd = command; try { string verb = StringUtils::car(command); command = StringUtils::cdr(command); if ( verb == "help" ) { help(command, os); return ""; } if ( verb == "rm" ) { ObjectSet rmset; while ( !command.empty() ) { string name = StringUtils::car(command); DirectoryAppend(name); IBPtr obj = GetPointer(name); if ( !obj ) return "Error: Could not find object named " + name; rmset.insert(obj); command = StringUtils::cdr(command); } return remove(rmset); } if ( verb == "rmdir" || verb == "rrmdir" ) { string dir = StringUtils::car(command); DirectoryAppend(dir); if ( dir[dir.size() - 1] != '/' ) dir += '/'; if ( !member(directories(), dir) ) return verb == "rmdir"? "Error: No such directory.": ""; IVector ov = SearchDirectory(dir); if ( ov.size() && verb == "rmdir" ) return "Error: Cannot remove a non-empty directory. " "(Use rrmdir do remove all object and subdirectories.)"; ObjectSet rmset(ov.begin(), ov.end()); string ret = remove(rmset); if ( !ret.empty() ) return ret; StringVector dirs(directories().begin(), directories().end()); for ( int i = 0, N = dirs.size(); i < N; ++ i ) if ( dirs[i].substr(0, dir.size()) == dir ) directories().erase(dirs[i]); for ( int i = 0, N = directoryStack().size(); i < N; ++i ) if ( directoryStack()[i].substr(0, dir.size()) == dir ) directoryStack()[i] = '/'; return ""; } if ( verb == "cp" ) { string name = StringUtils::car(command); DirectoryAppend(name); tPDPtr p = dynamic_ptr_cast(GetPointer(name)); if ( p ) return copyParticle(p, StringUtils::cdr(command)); return BaseRepository::exec(cpcmd, os); } if ( verb == "setup" ) { string name = StringUtils::car(command); DirectoryAppend(name); IBPtr obj = GetPointer(name); if ( !obj ) return "Error: Could not find object named " + name; istringstream is(StringUtils::cdr(command)); readSetup(obj, is); // A particle may have been registered before but under the wrong id(). PDPtr pd = dynamic_ptr_cast(obj); if(pd) registerParticle(pd); return ""; } if ( verb == "decaymode" ) { string tag = StringUtils::car(command); DMPtr dm = DecayMode::constructDecayMode(tag); if ( !dm ) return "Error: Could not create decay mode from the tag " + StringUtils::car(command); istringstream is(StringUtils::cdr(command)); readSetup(dm, is); if ( !dm->CC() ) return ""; if ( dm->CC()->parent()->synchronized() ) { dm->CC()->synchronize(); return ""; } if ( !dm->CC()->decayer() ) return FindInterface(dm, "Decayer")-> exec(*dm->CC(), "set", dm->decayer()->fullName()); return ""; } if ( verb == "makeanti" ) { string name = StringUtils::car(command); DirectoryAppend(name); tPDPtr p = dynamic_ptr_cast(GetPointer(name)); if ( !p ) return "Error: No particle named " + name; name = StringUtils::car(StringUtils::cdr(command)); DirectoryAppend(name); tPDPtr ap = dynamic_ptr_cast(GetPointer(name)); if ( !ap ) return "Error: No particle named " + name; ParticleData::antiSetup(PDPair(p, ap)); return ""; } if ( verb == "read" ) { // remember directory we're in string cwd = directoryStack().back(); string filename = StringUtils::car(command); string msg = read(filename, os); // Return to the original directory, so that // calling 'read' in an input file will not change the // repository directory you're in ChangeDirectory(cwd); return msg; } if ( verb == "load" ) { return load(StringUtils::car(command)); } if ( verb == "save" ) { save(StringUtils::car(command)); return ""; } if ( verb == "lsruns" ) { string ret; for ( GeneratorMap::iterator ieg = generators().begin(); ieg != generators().end(); ++ieg ) ret += ieg->first + "\n"; return ret; } if ( verb == "makerun" ) { string runname = StringUtils::car(command); string generator = StringUtils::car(StringUtils::cdr(command)); DirectoryAppend(generator); EGPtr eg = BaseRepository::GetObject(generator); makeRun(eg, runname); return ""; } if ( verb == "rmrun" ) { string runname = StringUtils::car(command); generators().erase(runname); return ""; } if ( verb == "saverun" || verb == "saverunfile" || verb == "run" ) { string runname = StringUtils::car(command); string generator = StringUtils::car(StringUtils::cdr(command)); DirectoryAppend(generator); GeneratorMap::iterator ieg = generators().find(runname); EGPtr eg; if ( ieg == generators().end() ) { eg = BaseRepository::GetObject(generator); eg = makeRun(eg, runname); } else eg = ieg->second; if ( !eg ) return "Error: Could not create/find run named'" + runname + "'."; if ( verb == "run" ) eg->go(); else if ( verb == "saverunfile" ) { string file = generator; PersistentOStream os(file, globalLibraries()); os << eg; if ( !os ) return "Save failed! (I/O error)"; } else { string file = eg->filename() + ".run"; PersistentOStream os(file, globalLibraries()); os << eg; if ( !os ) return "Save failed! (I/O error)"; } return ""; } if ( verb == "removerun" ) { string runname = StringUtils::car(command); GeneratorMap::iterator ieg = generators().find(runname); if ( ieg != generators().end() ) { generators().erase(ieg); return ""; } else return "Error: No run named '" + runname + "' available."; } if ( verb == "create" ) { string className = StringUtils::car(command); command = StringUtils::cdr(command); string name = StringUtils::car(command); const ClassDescriptionBase * db = DescriptionList::find(className); command = StringUtils::cdr(command); while ( !db && command.length() ) { string library = StringUtils::car(command); command = StringUtils::cdr(command); DynamicLoader::load(library); db = DescriptionList::find(className); } if ( !db ) { string msg = "Error: " + className + ": No such class found."; if ( !DynamicLoader::lastErrorMessage.empty() ) msg += "\nerror message from dynamic loader:\n" + DynamicLoader::lastErrorMessage; return msg; } IBPtr obj = dynamic_ptr_cast(db->create()); if ( !obj ) return "Error: Could not create object of this class class."; if ( name.empty() ) return "Error: No name specified."; Register(obj, name); return ""; } if ( verb == "defaultparticle" ) { while ( !command.empty() ) { string name = StringUtils::car(command); DirectoryAppend(name); tPDPtr p = dynamic_ptr_cast(GetPointer(name)); if ( !p ) return "Error: No particle named " + name; defaultParticle(p); command = StringUtils::cdr(command); } return ""; } if ( verb == "EXITONERROR" ) { exitOnError() = 1; return ""; } } catch (const Exception & e) { e.handle(); return "Error: " + e.message(); } return BaseRepository::exec(cpcmd, os); } void Repository::help(string cmd, ostream & os) { cmd = StringUtils::car(cmd); if ( cmd == "cd" ) os << "Usage: cd " << endl << "Set the current directory to ." << endl; else if ( cmd == "mkdir" ) os << "Usage: mkdir " << endl << "Create a new directory called with the given path name." << endl; else if ( cmd == "rmdir" ) os << "Usage: rmdir " << endl << "Remove an empty directory." << endl; else if ( cmd == "rrmdir" ) os << "Usage: rrmdir " << endl << "Remove a directory and everything that is in it recursively." << endl << "Will only succeed if no other objects refers to the ones to " << "be deleted." << endl; else if ( cmd == "cp" ) os << "Usage: cp " << endl << "Copy the given object to a new object with the given name." << endl; else if ( cmd == "setup" ) os << "Usage: setup ..." << endl << "Tell a given object to read information given by the arguments." << endl; else if ( cmd == "decaymode" ) os << "Usage: decaymode " << endl << "Construct a decay mode from the given decay tag. The resulting " << "object will be inserted in the directory with the same path as " << "the decaying particle object. The given brancing fraction will " << "be set as well as the given decayer object. If the mode should " << "be switched on by default 1(on) should be specified (otherwise " << "0(off))." << endl; else if ( cmd == "makeanti" ) os << "Usage: makeanti " << endl << "Indicate that the two given particle objects are eachothers " << "anti-partnets." << endl; else if ( cmd == "read" ) os << "Usage: read " << endl << "Read more commands from the given file. The file name can be " << "given relative to the current directory in the shell, or " << "relative to standard directories, or as an absolute path." << endl; else if ( cmd == "load" ) os << "Usage: load " << endl << "Discard everything in the reopsitory and read in a completely " << "new repository from the given file." << endl; else if ( cmd == "save" ) os << "Usage: save " << endl << "Save the complete repository to the given file." << endl; else if ( cmd == "lsruns" ) os << "Usage: lsruns" << endl << "List the run names of all initialized event generators." << endl; else if ( cmd == "makerun" ) os << "Usage: makerun " << endl << "Initialize the given event generator and assign a run name." << endl; else if ( cmd == "rmrun" ) os << "Usage: rmrun " << endl << "Remove the initialized event generator given by the run name." << endl; else if ( cmd == "saverun" ) os << "Usage: saverun " << endl << "Initialize the given event generator and assign a run name " << "and save it to a file named .run" << endl; else if ( cmd == "run" ) os << "Usage: run " << endl << "Run the initialized event generator given b the run name." << endl; else if ( cmd == "create" ) os << "Usage: create {}" << endl << "Create an object of the given class and assign the given name. " << "Optionally supply a dynamically loaded library where the class " << "is included." << endl; else if ( cmd == "pushd" ) os << "Usage: pushd " << endl << "Set the current directory to , but keep the previous " << "working directory on the directory stack." << endl; else if ( cmd == "popd" ) os << "Usage: popd" << endl << "Leave the current working directory and set the current " << "directory to the previous one on the directory stack." << endl; else if ( cmd == "pwd" ) os << "Usage: pwd" << endl << "Print the current working directory." << endl; else if ( cmd == "dirs" ) os << "Usage: dirs" << endl << " Print the contents of the directory stack." << endl; else if ( cmd == "mv" ) os << "Usage: mv " << endl << "Rename the given object to a new path name." << endl; else if ( cmd == "ls" ) os << "Usage: ls {}" << endl << "List the objects and subdirectories in the current or given " << "directory." << endl; else if ( cmd == "library" ) os << "Usage: library " << endl << "Make new classes available to the repository by dynamically " << "linking the given library." << endl; else if ( cmd == "globallibrary" ) os << "Usage: globallibrary " << endl << "Make new classes available to the repository by dynamically " << "linking the given library. If this repository is saved and read " << "in again, this library will be linked in from the beginning." << endl; else if ( cmd == "rmgloballibrary" ) os << "Usage: rmgloballibrary " << endl << "Remove a dynamic library previously added with globallibrary." << endl; else if ( cmd == "appendpath" ) os << "Usage: appendpath " << endl << "Add a search path for dynamic libraries to the end of the " << "search list." << endl; else if ( cmd == "lspaths" ) os << "Usage: lspaths" << endl << "List search paths for dynamic libraries." << endl; else if ( cmd == "prependpath" ) os << "Usage: prependpath " << endl << "Add a search path for dynamic libraries to the beginning of the " << "search list." << endl; else if ( cmd == "doxygendump" ) os << "Usage: doxygendump " << endl << "Extract doxygen documentation of all loaded classes in the " << "given name space and weite it to a file.." << endl; else if ( cmd == "mset" || cmd == "minsert" || cmd == "mdo" ) os << "Usage: " << cmd << " " << endl << "Recursively find in the given directory all objects of the " << "given class and call '" << cmd.substr(1) << "' with the given value for the given interface." << endl; else if ( cmd == "msetdef" || cmd == "mget" || cmd == "mdef" || cmd == "mmin" || cmd == "mmax" || cmd == "merase" ) os << "Usage: " << cmd << " " << endl << "Recursively find in the given directory all objects of the given " << "class and call '" << cmd.substr(1) << "' for the given interface." << endl; else if ( cmd == "set" ) os << "Usage: set : " << endl << "Set the interface for the given object to the given value." << endl; else if ( cmd == "setdef" ) os << "Usage: setdef :" << endl << "Set the interface for the given object to its default value." << endl; else if ( cmd == "insert" ) os << "Usage: insert : " << endl << "Insert a value in the vector interface of the given object." << endl; else if ( cmd == "erase" ) os << "Usage: erase :" << endl << "Erase a value from the vector interface of the given object." << endl; else if ( cmd == "do" ) os << "Usage: do : " << endl << "Call the command interface of the given object with the " << "given arguments." << endl; else if ( cmd == "get" ) os << "Usage: get :" << endl << "Print the value of the interface of the given object." << endl; else if ( cmd == "def" ) os << "Usage: def :" << endl << "Print the default value of the interface of the given object." << endl; else if ( cmd == "min" ) os << "Usage: min :" << endl << "Print the minimum value of the interface of the given object." << endl; else if ( cmd == "max" ) os << "Usage: max :" << endl << "Print the maximum value of the interface of the given object." << endl; else if ( cmd == "describe" ) os << "Usage: describe {:}" << endl << "Describe the given object or an interface of the object." << endl; else if ( cmd == "lsclass" ) os << "Usage: lsclass" << endl << "List all classes available in the repository." << endl; else if ( cmd == "all" ) { os << "Available commands:" << endl << "* cd, mkdir, rmdir, rrmdir, pwd, cp, mv, rm, pushd, popd, dirs, ls:\n" << " Manipulate the repository structure. Analogous to unix " << "shell commands." << endl << "* create, setup, decaymode makeanti:\n" << " Create or setup an object." << endl << "* set, get, insert, erase, do, detdef, def, min, max, describe\n" << " mset, minsert, mdo, msetdef, mdef, mmin, mmax, merase:\n" << " Manipulate interfaces to objects." << endl << "* makerun, saverun, run, lsruns, rmrun:\n" << " Create and handle initialized event genrators which can be run." << endl << "* read, load, library globallibrary, rmgloballibrary,\n" << " appendpath, prependpath, lspaths, doxygendump:\n" << " Handle files external files and libraries." << endl; os << "Do 'help syntax' for help on syntax." << endl << "Do 'help ' for help on a particular command." << endl; } else if ( cmd == "syntax" ) os << "* = '/' | | /" << endl << " = | / | :\n" << " Analogous to a unix file structure, an object can be " << "specified with an\n absolute path or a path relative to " << "the current directory." << endl << "* = |[]" << endl << " An interface can be a parameter (floating point, integer or " << "string),\n a switch (integer, possibly named), a reference to " << "another object in the\n repository or a command which takes " << "an arbitrary string as argument.\n There are also vector interfaces " << "of parameters and references for which\n an index must be supplied." << endl; else { if ( !cmd.empty() ) os << "No command '" << cmd << "' found." << endl; os << "Common commands:" << endl << "* cd, mkdir, rmdir, pwd, cp, mv, rm:\n" << " Manipulate the repository structure. Analogous to unix " << "shell commands." << endl << "* create, setup:\n" << " Create an object." << endl << "set, get, insert, erase, do:\n" << " Manipulate interfaces to objects." << endl << "* makerun, saverun, run, lsruns:\n" << " Create and handle initialized event genrators which can be run." << endl; os << "Do 'help all' for a complete list of commands." << endl << "Do 'help syntax' for help on syntax." << endl << "Do 'help ' for help on a particular command." << endl; } } Repository::Repository() { ++ninstances; } Repository::~Repository() { --ninstances; if ( ninstances <= 0 ) { generators().clear(); } } int Repository::ninstances = 0; namespace { static string version_ = #include "versionstamp.inc" ""; } string Repository::version() { return ::version_; } string Repository::banner() { const auto now = std::chrono::system_clock::now(); const auto now_c = std::chrono::system_clock::to_time_t(now); string time = ">>>> " ; time += StringUtils::stripws(string(std::ctime(&now_c))) + ' '; time += string(max(0,74 - int(time.size())), ' '); time += "<<<<"; string line = ">>>> Toolkit for HEP Event Generation - " + Repository::version() + ' '; line += string(max(0,78 - int(line.size())), '<'); string block = string(78, '>') + '\n' + line + '\n' + time + '\n' + string(78, '<') + '\n'; return block; } diff --git a/Utilities/SimplePhaseSpace.cc b/Utilities/SimplePhaseSpace.cc --- a/Utilities/SimplePhaseSpace.cc +++ b/Utilities/SimplePhaseSpace.cc @@ -1,112 +1,116 @@ // -*- C++ -*- // // SimplePhaseSpace.cc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #include "SimplePhaseSpace.h" #ifdef ThePEG_TEMPLATES_IN_CC_FILE #include "SimplePhaseSpace.tcc" #endif using namespace ThePEG; Energy SimplePhaseSpace::getMagnitude(Energy2 s, Energy m1, Energy m2) { const Energy2 eps = 10.0*s*Constants::epsilon; if ( m1 < ZERO && sqr(m1) < eps ) m1 = ZERO; if ( m2 < ZERO && sqr(m2) < eps ) m2 = ZERO; if ( m1 >= ZERO && m2 >= ZERO ) { Energy2 aa = s - sqr(m1+m2); if ( aa < ZERO && aa > -eps ) return ZERO; if ( aa < ZERO ) throw ImpossibleKinematics(); return 0.5*sqrt(aa*(s-sqr(m1-m2))/s); } - Energy2 m12 = m1 < ZERO? -sqr(m1): sqr(m1); - Energy2 m22 = m2 < ZERO? -sqr(m2): sqr(m2); - Energy2 r2 = 0.25*(sqr(m12) + sqr(m22 - s) -2.0*m12*(m22 + s))/s; - if ( r2 < ZERO || r2 + m12 < ZERO || r2 + m22 < ZERO ) - throw ImpossibleKinematics(); - return sqrt(r2); + if ( m1 >= ZERO && m2 < ZERO ) { + return sqrt(sqr(m2)+sqr(s-sqr(m1)-sqr(m2))/(4.*s)); + } + if ( m1 < ZERO && m2 >= ZERO ) { + return sqrt(sqr(m1)+sqr(s-sqr(m1)-sqr(m2))/(4.*s)); + } + if ( m1 < ZERO && m2 < ZERO ) { + return sqrt(sqr(m1)+sqr(s-sqr(m1)+sqr(m2))/(4.*s)); + } + return ZERO; } // Energy SimplePhaseSpace::checkMagnitude(Energy2 s, Energy m1, Energy m2) // { // if ( s < ZERO ) return -1.0*GeV; // const Energy2 eps = 10.0*s*Constants::epsilon; // if ( m1 < ZERO && sqr(m1) < eps ) m1 = ZERO; // if ( m2 < ZERO && sqr(m2) < eps ) m2 = ZERO; // if ( m1 >= ZERO && m2 >= ZERO ) { // Energy2 aa = s - sqr(m1+m2); // if ( aa < ZERO && aa > -eps ) return ZERO; // if ( aa < ZERO ) return -1.0*GeV; // return 0.5*sqrt(aa*(s-sqr(m1-m2))/s); // } // Energy2 m12 = m1 < ZERO? -sqr(m1): sqr(m1); // Energy2 m22 = m2 < ZERO? -sqr(m2): sqr(m2); // Energy2 r2 = 0.25*(sqr(m12) + sqr(m22 - s) -2.0*m12*(m22 + s))/s; // if ( r2 < ZERO || r2 + m12 < ZERO || r2 + m22 < ZERO ) // return -1.0*GeV; // return sqrt(r2); // } vector SimplePhaseSpace:: CMSn(Energy m0, const vector & m) { using Constants::pi; // Setup constants. int Np = m.size(); vector ret(Np); Energy summ = std::accumulate(m.begin(), m.end(), Energy()); if ( summ >= m0 ) throw ImpossibleKinematics(); while ( true ) { // First get an ordered list of random numbers. vector rndv(Np); rndv[0] = 1.0; rndv.back() = 0.0; for ( int i = 1; i < Np - 1; ++i ) rndv[i] = UseRandom::rnd(); std::sort(rndv.begin() + 1, rndv.end() - 1, std::greater()); // Now setup masses of subsystems. vector sm(Np); Energy tmass = m0 - summ; Energy tmp = summ; for ( int i = 0; i < Np; ++i ) { sm[i] = rndv[i]*tmass + tmp; tmp -= m[i]; } // Now the magnitude of all the momenta can be calculated. This // gives the weight. double weight = 1.0; vector p(Np); p[Np - 1] = getMagnitude(sqr(sm[Np - 2]), m[Np -2], sm[Np - 1]); for ( int i = Np - 2; i >= 0; --i ) weight *= (p[i] = getMagnitude(sqr(sm[i]), m[i], sm[i + 1]))/sm[i]; if ( weight > UseRandom::rnd() ) continue; // Now we just have to generate the angles. ret[Np - 1] = LorentzMomentum(ZERO, ZERO, ZERO, m[Np - 1]); for ( int i = Np - 2; i >= 0; --i ) { Momentum3 p3 = polar3Vector(p[i], 2.0*UseRandom::rnd() - 1.0, 2.0*pi*UseRandom::rnd()); ret[i] = LorentzMomentum(-p3, sqrt(sqr(p[i]) + sqr(m[i]))); if ( i == Np -2 ) { ret[Np - 1] = LorentzMomentum(p3, sqrt(sqr(m[Np - 1]) + p3.mag2())); } else { Boost bv = p3*(1.0/sqrt(sqr(p[i]) + sqr(sm[i + 1]))); if ( bv.mag2() >= 1.0 ) throw ImpossibleKinematics(); LorentzRotation r(bv); for ( int j = i + 1; j < Np; ++j ) ret[j]*=r.one(); } } return ret; } } diff --git a/Utilities/SimplePhaseSpace.tcc b/Utilities/SimplePhaseSpace.tcc --- a/Utilities/SimplePhaseSpace.tcc +++ b/Utilities/SimplePhaseSpace.tcc @@ -1,136 +1,141 @@ // -*- C++ -*- // // SimplePhaseSpace.tcc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined templated member // functions of the SimplePhaseSpace class. // namespace ThePEG { template void SimplePhaseSpace::CMS(PType & p1, PType & p2, Energy2 s) { typedef ParticleTraits Traits; - Energy z = getMagnitude(s, Traits::mass(p1), Traits::mass(p2)); - Traits::set3Momentum(p1, Momentum3(ZERO, ZERO, z)); - Traits::set3Momentum(p2, Momentum3(ZERO, ZERO, -z)); + Energy m1 = Traits::mass(p1); Energy m2 = Traits::mass(p2); + Energy z = getMagnitude(s, m1, m2); + Energy2 m12 = m1 >= ZERO ? sqr(m1) : -sqr(m1); + Energy2 m22 = m2 >= ZERO ? sqr(m2) : -sqr(m2); + Energy2 c1 = (s+m12-m22); + Energy2 c2 = (s-m12+m22); + Traits::set5Momentum(p1, Lorentz5Momentum(ZERO, ZERO, z, (c1 > ZERO ? 1. : -1.) * 0.5*sqrt(sqr(c1)/s), m1)); + Traits::set5Momentum(p2, Lorentz5Momentum(ZERO, ZERO, -z, (c2 > ZERO ? 1. : -1.) * 0.5*sqrt(sqr(c2)/s), m2)); } template void SimplePhaseSpace::CMS(Energy2 s, PType & p1, PType & p2) { CMS(p1, p2, s, 2.0*UseRandom::rnd() - 1.0, Constants::twopi*UseRandom::rnd()); } template void SimplePhaseSpace::CMS(PType & p1, PType & p2, Energy2 s, double cthe, double phi) { typedef ParticleTraits Traits; Energy r = getMagnitude(s, Traits::mass(p1), Traits::mass(p2)); double sthe = sqrt(1.0-sqr(cthe)); Momentum3 p(r*sthe*cos(phi), r*sthe*sin(phi), r*cthe); Traits::set3Momentum(p1, p); Traits::set3Momentum(p2, -p); } template void SimplePhaseSpace:: CMS(PType & p1, PType & p2, PType & p3, Energy2 s, double x1, double x3) { CMS(p1, p2, p3, s, x1, x3, Constants::twopi*UseRandom::rnd(), acos(2.0*UseRandom::rnd() - 1.0), Constants::twopi*UseRandom::rnd()); } template void SimplePhaseSpace:: CMS(PType & p1, PType & p2, PType & p3, Energy2 s, double x1, double x3, double phii, double the, double phi) { typedef ParticleTraits Traits; Energy Etot = sqrt(s); Energy m1 = Traits::mass(p1); Energy m2 = Traits::mass(p2); Energy m3 = Traits::mass(p3); Energy e1 = 0.5*x1*Etot; Energy e3 = 0.5*x3*Etot; Energy e2 = Etot - e1 - e3; if ( e1 < m1 || e2 < m2 || e3 < m3 ) throw ImpossibleKinematics(); Energy r1 = sqrt(sqr(e1)-sqr(m1)); Energy r2 = sqrt(sqr(e2)-sqr(m2)); Energy r3 = sqrt(sqr(e3)-sqr(m3)); Traits::set3Momentum(p1, Momentum3(ZERO, ZERO, r1)); double cthe2 = (sqr(r3)-sqr(r2)-sqr(r1))/(2.0*r2*r1); double cthe3 = (sqr(r2)-sqr(r3)-sqr(r1))/(2.0*r3*r1); if ( abs(cthe2) > 1.0 || abs(cthe3) > 1.0 ) throw ImpossibleKinematics(); double sthe2 = sqrt(1.0-sqr(cthe2)); Energy px = r2*sthe2*cos(phii); Energy py = r2*sthe2*sin(phii); Traits::set3Momentum(p2, Momentum3(px, py, r2*cthe2)); Traits::set3Momentum(p3, Momentum3(-px, -py, r3*cthe3)); if ( the == 0.0 && phi == 0.0 ) return; LorentzRotation r; r.rotateZ(phi); r.rotateX(the); Traits::transform(p1, r); Traits::transform(p2, r); Traits::transform(p3, r); } template void SimplePhaseSpace:: CMS(PType & p1, PType & p2, Energy2 s, Energy2 t, double phi, const PType & p0) { typedef ParticleTraits Traits; Energy r = getMagnitude(s, Traits::mass(p1), Traits::mass(p2)); Energy e = sqrt(sqr(r) + sqr(Traits::mass(p1))); Energy r0 = Traits::momentum(p0).rho(); Energy e0 = Traits::momentum(p0).e(); double cthe = (t + sqr(e - e0) + sqr(r) + sqr(r0))/(2.0*r*r0); if ( abs(cthe) > 1.0 ) throw ImpossibleKinematics(); double sthe = sqrt(1.0-sqr(cthe)); Momentum3 p(r*sthe*cos(phi), r*sthe*sin(phi), r*cthe); Traits::set3Momentum(p1, p); Traits::set3Momentum(p2, -p); if ( Traits::momentum(p0).perp2() > ZERO ) { LorentzRotation r; r.rotateX(Traits::momentum(p0).theta()); r.rotateZ(Traits::momentum(p0).phi()); Traits::transform(p1, r); Traits::transform(p2, r); } } template void SimplePhaseSpace::CMSn(Container & particles, Energy m0) { typedef typename Container::value_type PType; typedef typename Container::iterator Iterator; if ( particles.size() == 2 ) { Iterator it = particles.begin(); PType & p1 = *it++; PType & p2 = *it; CMS(sqr(m0), p1, p2); return; } typedef ParticleTraits Traits; vector masses(particles.size()); int j = 0; for ( Iterator i = particles.begin();i != particles.end(); ++i, ++j ) masses[j] = Traits::mass(*i); vector p = CMSn(m0, masses); j = 0; for ( Iterator i = particles.begin();i != particles.end(); ++i, ++j ) Traits::set5Momentum(*i, p[j]); } } diff --git a/Vectors/HepMCConverter.tcc b/Vectors/HepMCConverter.tcc --- a/Vectors/HepMCConverter.tcc +++ b/Vectors/HepMCConverter.tcc @@ -1,337 +1,337 @@ // -*- C++ -*- // // HepMCConverter.tcc is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 1999-2017 Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // // // This is the implementation of the non-inlined, non-templated member // functions of the HepMCConverter class. // #include "ThePEG/StandardModel/StandardModelBase.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/EventRecord/StandardSelectors.h" #include "ThePEG/EventRecord/Collision.h" #include "ThePEG/EventRecord/Step.h" #include "ThePEG/EventRecord/SubProcess.h" #include "ThePEG/Handlers/XComb.h" #include "ThePEG/Handlers/EventHandler.h" #include "ThePEG/PDF/PartonExtractor.h" #include "ThePEG/PDF/PDF.h" #include "ThePEG/PDT/StandardMatchers.h" #include "ThePEG/Utilities/Throw.h" namespace ThePEG { template typename HepMCConverter::GenEvent * HepMCConverter:: convert(const Event & ev, bool nocopies, Energy eunit, Length lunit) { HepMCConverter converter(ev, nocopies, eunit, lunit); return converter.geneve; } template void HepMCConverter:: convert(const Event & ev, GenEvent & gev, bool nocopies) { HepMCConverter converter(ev, gev, nocopies, Traits::momentumUnit(gev), Traits::lengthUnit(gev)); } template void HepMCConverter:: convert(const Event & ev, GenEvent & gev, bool nocopies, Energy eunit, Length lunit) { HepMCConverter converter(ev, gev, nocopies, eunit, lunit); } template HepMCConverter:: HepMCConverter(const Event & ev, bool nocopies, Energy eunit, Length lunit) : energyUnit(eunit), lengthUnit(lunit) { geneve = Traits::newEvent(ev.number(), ev.weight(), ev.optionalWeights()); init(ev, nocopies); } template HepMCConverter:: HepMCConverter(const Event & ev, GenEvent & gev, bool nocopies, Energy eunit, Length lunit) : energyUnit(eunit), lengthUnit(lunit) { geneve = &gev; Traits::resetEvent(geneve, ev.number(), ev.weight(), ev.optionalWeights()); init(ev, nocopies); } struct ParticleOrderNumberCmp { bool operator()(tcPPtr a, tcPPtr b) const { return a->number() < b->number(); } }; template void HepMCConverter::init(const Event & ev, bool nocopies) { if ( lengthUnit != millimeter && lengthUnit != centimeter ) Throw() << "Length unit used for HepMC::GenEvent was not MM nor CM." << Exception::runerror; if ( energyUnit != GeV && energyUnit != MeV ) Throw() << "Momentum unit used for HepMC::GenEvent was not GEV nor MEV." << Exception::runerror; Traits::setUnits(*geneve, energyUnit, lengthUnit); tcEHPtr eh; if ( ev.primaryCollision() && ( eh = dynamic_ptr_cast(ev.primaryCollision()->handler()) ) ) { // Get general event info if present. Traits::setScaleAndAlphas(*geneve, eh->lastScale(), eh->lastAlphaS(),eh->lastAlphaEM(), energyUnit); } // Extract all particles and order them. tcPVector all; ev.select(back_inserter(all), SelectAll()); stable_sort(all.begin(), all.end(), ParticleOrderNumberCmp()); vertices.reserve(all.size()*2); // Create GenParticle's and map them to the ThePEG particles. for ( int i = 0, N = all.size(); i < N; ++i ) { tcPPtr p = all[i]; if ( nocopies && p->next() ) continue; if ( pmap.find(p) != pmap.end() ) continue; pmap[p] = createParticle(p); if ( !p->children().empty() || p->next() ) { // If the particle has children it should have a decay vertex: vertices.push_back(Vertex()); decv[p] = &vertices.back(); vertices.back().in.insert(p); } if ( !p->parents().empty() || p->previous() || (p->children().empty() && !p->next()) ) { // If the particle has parents it should have a production // vertex. If neither parents or children it should still have a // dummy production vertex. vertices.push_back(Vertex()); prov[p] = &vertices.back(); vertices.back().out.insert(p); } } // Now go through the the particles again, and join the vertices. for ( int i = 0, N = all.size(); i < N; ++i ) { tcPPtr p = all[i]; if ( nocopies ) { if ( p->next() ) continue; for ( int i = 0, N = p->children().size(); i < N; ++i ) join(p, p->children()[i]->final()); tcPPtr pp = p; while ( pp->parents().empty() && pp->previous() ) pp = pp->previous(); for ( int i = 0, N = pp->parents().size(); i < N; ++i ) join(pp->parents()[i]->final(), p); } else { for ( int i = 0, N = p->children().size(); i < N; ++i ) join(p, p->children()[i]); if ( p->next() ) join(p, p->next()); for ( int i = 0, N = p->parents().size(); i < N; ++i ) join(p->parents()[i], p); if ( p->previous() ) join(p->previous(), p); } } // Time to create the GenVertex's for ( typename VertexMap::iterator it = prov.begin(); it != prov.end(); ++it ) if ( !member(vmap, it->second) ) vmap[it->second] = createVertex(it->second); for ( typename VertexMap::iterator it = decv.begin(); it != decv.end(); ++it ) if ( !member(vmap, it->second) ) vmap[it->second] = createVertex(it->second); // Now find the primary signal process vertex defined to be the // decay vertex of the first parton coming into the primary hard // sub-collision. tSubProPtr sub = ev.primarySubProcess(); if ( sub && sub->incoming().first ) { const Vertex * prim = decv[sub->incoming().first]; Traits::setSignalProcessVertex(*geneve, vmap[prim]); vmap.erase(prim); } // Then add the rest of the vertices. for ( typename GenVertexMap::iterator it = vmap.begin(); it != vmap.end(); ++it ) Traits::addVertex(*geneve, it->second); // and the incoming beam particles Traits::setBeamParticles(*geneve,pmap[ev.incoming().first], pmap[ev.incoming().second]); // and the PDF info setPdfInfo(ev); // and the cross section info Traits::setCrossSection(*geneve, eh->integratedXSec()/picobarn, eh->integratedXSecErr()/picobarn); for ( int i = 0, N = all.size(); i < N; ++i ) { tcPPtr p = all[i]; if ( pmap.find(p) == pmap.end() ) continue; GenParticlePtrT gp = pmap[p]; if ( p->hasColourInfo() ) { // Check if the particle is connected to colour lines, in which // case the lines are mapped to an integer and set in the // GenParticle's Flow info. tcColinePtr l; if ( (l = p->colourLine()) ) { if ( !member(flowmap, l) ) flowmap[l] = flowmap.size() + 500; Traits::setColourLine(*gp, 1, flowmap[l]); } if ( (l = p->antiColourLine()) ) { if ( !member(flowmap, l) ) flowmap[l] = flowmap.size() + 500; Traits::setColourLine(*gp, 2, flowmap[l]); } } if ( p->spinInfo() && p->spinInfo()->hasPolarization() ) { DPair pol = p->spinInfo()->polarization(); Traits::setPolarization(*gp, pol.first, pol.second); } } } template typename HepMCConverter::GenParticlePtrT HepMCConverter::createParticle(tcPPtr p) const { int status = 1; size_t nChildren = p->children().size(); if ( nChildren > 0 || p->next() ) status = 11; if ( nChildren > 1 ) { long id = p->data().id(); if ( BaryonMatcher::Check(id) || MesonMatcher::Check(id) || id == ParticleID::muminus || id == ParticleID::muplus || id == ParticleID::tauminus || id == ParticleID::tauplus ) { bool child = false; for(unsigned int ix=0;ixchildren()[ix]->id()==id) { child = true; break; } } if ( !child ) { if(p->data().widthCut()!=ZERO) { if(p->mass() <= p->data().massMax() && p->mass() >= p->data().massMin() ) status = 2; } else { status = 2; } } } } GenParticlePtrT gp = - Traits::newParticle(p->momentum(), p->id(), status, energyUnit); + Traits::newParticle(p->momentum(), p->id(), p->status() ? p->status() : status, energyUnit); if ( p->spinInfo() && p->spinInfo()->hasPolarization() ) { DPair pol = p->spinInfo()->polarization(); Traits::setPolarization(*gp, pol.first, pol.second); } return gp; } template void HepMCConverter::join(tcPPtr parent, tcPPtr child) { Vertex * dec = decv[parent]; Vertex * pro = prov[child]; if ( !pro || !dec ) Throw() << "Found a reference to a ThePEG::Particle which was not in the Event." << Exception::eventerror; if ( pro == dec ) return; while ( !pro->in.empty() ) { dec->in.insert(*(pro->in.begin())); decv[*(pro->in.begin())] = dec; pro->in.erase(pro->in.begin()); } while ( !pro->out.empty() ) { dec->out.insert(*(pro->out.begin())); prov[*(pro->out.begin())] = dec; pro->out.erase(pro->out.begin()); } } template typename HepMCConverter::GenVertexPtrT HepMCConverter::createVertex(Vertex * v) { if ( !v ) Throw() << "Found internal null Vertex." << Exception::abortnow; GenVertexPtrT gv = Traits::newVertex(); // We assume that the vertex position is the average of the decay // vertices of all incoming and the creation vertices of all // outgoing particles in the lab. Note that this will probably not // be useful information for very small distances. LorentzPoint p; for ( tcParticleSet::iterator it = v->in.begin(); it != v->in.end(); ++it ) { p += (**it).labDecayVertex(); Traits::addIncoming(*gv, pmap[*it]); } for ( tcParticleSet::iterator it = v->out.begin(); it != v->out.end(); ++it ) { p += (**it).labVertex(); Traits::addOutgoing(*gv, pmap[*it]); } p /= double(v->in.size() + v->out.size()); Traits::setPosition(*gv, p, lengthUnit); return gv; } template void HepMCConverter::setPdfInfo(const Event & e) { // ids of the partons going into the primary sub process tSubProPtr sub = e.primarySubProcess(); int id1 = sub->incoming().first ->id(); int id2 = sub->incoming().second->id(); // get the event handler tcEHPtr eh = dynamic_ptr_cast(e.handler()); // get the values of x double x1 = eh->lastX1(); double x2 = eh->lastX2(); // get the pdfs pair pdfs; pdfs.first = eh->pdf(sub->incoming().first ); pdfs.second = eh->pdf(sub->incoming().second); // get the scale Energy2 scale = eh->lastScale(); // get the values of the pdfs double xf1 = pdfs.first.xfx(sub->incoming().first->dataPtr(), scale, x1); double xf2 = pdfs.second.xfx(sub->incoming().second->dataPtr(), scale, x2); Traits::setPdfInfo(*geneve, id1, id2, x1, x2, sqrt(scale/GeV2), xf1, xf2); } } diff --git a/Vectors/LorentzVector.h b/Vectors/LorentzVector.h --- a/Vectors/LorentzVector.h +++ b/Vectors/LorentzVector.h @@ -1,765 +1,765 @@ // -*- C++ -*- // // LorentzVector.h is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 2006-2017 David Grellscheid, Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef ThePEG_LorentzVector_H #define ThePEG_LorentzVector_H /** * @file LorentzVector.h contains the LorentzVector class. Lorentz * vectors can be created with any unit type as template parameter. * All basic mathematical operations are supported, as well as a * subset of the CLHEP LorentzVector functionality. */ #include "LorentzVector.fh" #include "ThePEG/Utilities/Direction.h" #include "ThePEG/Utilities/UnitIO.h" #include "LorentzRotation.h" #include "ThreeVector.h" /// Debug helper function #ifdef NDEBUG #define ERROR_IF(condition,message) if (false) {} #else #define ERROR_IF(condition,message) \ if ( condition ) throw ThePEG::Exception( (message) , ThePEG::Exception::eventerror) #endif namespace ThePEG { template class LorentzVector; /** * A 4-component Lorentz vector. It can be created with any unit type * as template parameter. All basic mathematical operations are * supported, as well as a subset of the CLHEP LorentzVector * functionality. */ template class LorentzVector { private: /// Value squared using Value2 = decltype(sqr(std::declval())); public: /** @name Constructors. */ //@{ LorentzVector() : theX(), theY(), theZ(), theT() {} LorentzVector(Value x, Value y, Value z, Value t) : theX(x), theY(y), theZ(z), theT(t) {} LorentzVector(const ThreeVector & v, Value t) : theX(v.x()), theY(v.y()), theZ(v.z()), theT(t) {} template LorentzVector(const LorentzVector & v) : theX(v.x()), theY(v.y()), theZ(v.z()), theT(v.t()) {} //@} /// Assignment operator template LorentzVector & operator=(const LorentzVector & b) { setX(b.x()); setY(b.y()); setZ(b.z()); setT(b.t()); return *this; } public: /// @name Component access methods. //@{ Value x() const { return theX; } Value y() const { return theY; } Value z() const { return theZ; } Value t() const { return theT; } Value e() const { return t(); } //@} /// @name Component set methods. //@{ void setX(Value x) { theX = x; } void setY(Value y) { theY = y; } void setZ(Value z) { theZ = z; } void setT(Value t) { theT = t; } void setE(Value e) { setT(e); } //@} public: /// Access to the 3-component part. ThreeVector vect() const { return ThreeVector(x(),y(),z()); } /// Cast to the 3-component part. operator ThreeVector() const { return vect(); } /// Set the 3-component part. void setVect(const ThreeVector & p) { theX = p.x(); theY = p.y(); theZ = p.z(); } public: /// The complex conjugate vector. LorentzVector conjugate() const { return LorentzVector(conj(x()),conj(y()),conj(z()),conj(t())); } /// Squared magnitude \f$x^\mu\,x_\mu=t^2 - \vec{x}^2\f$. Value2 m2() const { return (t()-z())*(t()+z()) - sqr(x()) - sqr(y()); } /// Squared magnitude with another vector Value2 m2(const LorentzVector & a) const { Value tt(a.t()+t()),zz(a.z()+z()); return (tt-zz)*(tt+zz)-sqr(a.x()+x())-sqr(a.y()+y()); } /// Magnitude (signed) \f$\pm\sqrt{|t^2 - \vec{x}^2|}\f$. Value m() const { Value2 tmp = m2(); return tmp < Value2() ? -Value(sqrt(-tmp)) : Value(sqrt(tmp)); } /// Transverse mass squared \f$t^2-z^2\f$. Value2 mt2() const { return (t()-z())*(t()+z()); } /// Transverse mass (signed) \f$\pm\sqrt{|t^2 - z^2|}\f$. Value mt() const { Value2 tmp = mt2(); return tmp < Value2() ? -Value(sqrt(-tmp)) : Value(sqrt(tmp)); } /// Squared transverse component of the spatial vector \f$x^2+y^2\f$. Value2 perp2() const { return sqr(x()) + sqr(y()); } /// Transverse component of the spatial vector \f$\pm\sqrt{x^2 + y^2}\f$. Value perp() const { return sqrt(perp2()); } /** * Squared transverse component of the spatial vector with respect to the * given axis. */ template Value2 perp2(const ThreeVector & p) const { return vect().perp2(p); } /** * Transverse component of the spatial vector with respect to the * given axis. */ template Value perp(const ThreeVector & p) const { return vect().perp(p); } /// Transverse energy squared. Value2 et2() const { Value2 pt2 = vect().perp2(); return pt2 == Value2() ? Value2() : e()*e() * pt2/(pt2+z()*z()); } /// Transverse energy (signed). Value et() const { Value2 etet = et2(); return e() < Value() ? -sqrt(etet) : sqrt(etet); } /// Transverse energy squared with respect to the given axis. Value2 et2(const ThreeVector & v) const { Value2 pt2 = vect().perp2(v); Value pv = vect().dot(v.unit()); return pt2 == Value2() ? Value2() : e()*e() * pt2/(pt2+pv*pv); } /// Transverse energy with respect to the given axis (signed). Value et(const ThreeVector & v) const { Value2 etet = et2(v); return e() < Value() ? -sqrt(etet) : sqrt(etet); } /// @name Spherical coordinates for the spatial part. //@{ /// Radius squared. Value2 rho2() const { return sqr(x()) + sqr(y()) + sqr(z()); } /// Radius. Value rho() const { return sqrt(rho2()); } /// Set new radius. void setRho(Value newRho) { Value oldRho = rho(); if (oldRho == Value()) return; double factor = newRho / oldRho; setX(x()*factor); setY(y()*factor); setZ(z()*factor); } /// Polar angle. double theta() const { assert(!(x() == Value() && y() == Value() && z() == Value())); return atan2(perp(),z()); } /// Cosine of the polar angle. double cosTheta() const { Value ptot = rho(); assert( ptot > Value() ); return z() / ptot; } /// Azimuthal angle. double phi() const { return atan2(y(),x()) ; } //@} /// Pseudorapidity of spatial part. double eta() const { Value m = rho(); if ( m == Value() ) return 0.0; Value pt = max(Constants::epsilon*m, perp()); double rap = log((m + abs(z()))/pt); return z() > ZERO? rap: -rap; } /// Spatial angle with another vector. double angle(const LorentzVector & w) const { return vect().angle(w.vect()); } /// Rapidity \f$\frac{1}{2}\ln\frac{t+z}{t-z} \f$ double rapidity() const { if ( z() == ZERO ) return 0.0; ERROR_IF(t() <= ZERO, "Tried to take rapidity of negative-energy Lorentz vector"); Value pt = sqrt(max(sqr(t()*Constants::epsilon), perp2() + m2())); double rap = log((t() + abs(z()))/pt); return z() > ZERO? rap: -rap; } /// Rapidity with respect to another vector double rapidity(const Axis & ref) const { double r = ref.mag2(); ERROR_IF(r == 0,"A zero vector used as reference to LorentzVector rapidity"); Value vdotu = vect().dot(ref)/sqrt(r); if ( vdotu == ZERO ) return 0.0; ERROR_IF(t() <= ZERO, "Tried to take rapidity of negative-energy Lorentz vector"); Value pt = sqrt(max(sqr(t()*Constants::epsilon), perp2(ref) + m2())); double rap = log((t() + abs(z()))/pt); return z() > ZERO? rap: -rap; } /** * Boost from reference frame into this vector's rest * frame: \f$\frac{\vec{x}}{t}\f$. */ Boost boostVector() const { if (t() == Value()) { if (rho2() == Value2()) return Boost(); else ERROR_IF(true,"boostVector computed for LorentzVector with t=0 -- infinite result"); } // result will make analytic sense but is physically meaningless ERROR_IF(m2() <= Value2(),"boostVector computed for a non-timelike LorentzVector"); return vect() * (1./t()); } /** * Boost from reference frame into this vector's rest * frame: \f$-\frac{\vec{x}}{t}\f$. */ Boost findBoostToCM() const { return -boostVector(); } /// Returns the positive light-cone component \f$t + z\f$. Value plus() const { return t() + z(); } /// Returns the negative light-cone component \f$t - z\f$. Value minus() const { return t() - z(); } /// Are two vectors nearby, using Euclidean measure \f$t^2 + |\vec{x}|^2\f$? bool isNear(const LorentzVector & w, double epsilon) const { Value2 limit = abs(vect().dot(w.vect())); limit += 0.25 * sqr( t() + w.t() ); limit *= sqr(epsilon); Value2 delta = (vect() - w.vect()).mag2(); delta += sqr( t() - w.t() ); return (delta <= limit); } /// Rotate the vector. Resets \f$x^\mu\rightarrow\mathsf{M}^\mu_\nu x^\nu\f$. LorentzVector & transform(const SpinOneLorentzRotation & m) { return *this = m.operator*(*this); } /// Rotate the vector. Resets \f$x^\mu\rightarrow\mathsf{M}^\mu_\nu x^\nu\f$. LorentzVector & operator*=(const SpinOneLorentzRotation & m) { return transform(m); } /// Dot product with metric \f$(+,-,-,-)\f$ template - auto dot(const LorentzVector & a) const -> decltype(t() * a.t()) + auto dot(const LorentzVector & a) const -> decltype(this->t() * a.t()) { return t() * a.t() - ( x() * a.x() + y() * a.y() + z() * a.z() ); } public: /** * Apply boost. * * @param bx Component x of the boost. * @param by Component y of the boost. * @param bz Component z of the boost. * @param gamma Optional gamma parameter for higher numerical * accuracy. The user has to ensure consistency. If not given, it * will be calculated as \f$\gamma=1/\sqrt{1-\beta^2}\f$. * */ LorentzVector & boost(double bx, double by, double bz, double gamma=-1.) { const double b2 = bx*bx + by*by + bz*bz; if ( b2 == 0.0 ) return *this; if ( gamma < 0.0 ) { gamma = 1.0 / sqrt(1.0 - b2); } const Value bp = bx*x() + by*y() + bz*z(); const double gamma2 = (gamma - 1.0)/b2; setX(x() + gamma2*bp*bx + gamma*bx*t()); setY(y() + gamma2*bp*by + gamma*by*t()); setZ(z() + gamma2*bp*bz + gamma*bz*t()); setT(gamma*(t() + bp)); return *this; } /** * Apply boost. * * @param b Three-vector giving the boost. * * @param gamma Optional gamma parameter for higher numerical * accuracy. The user has to ensure consistency. If not given, it * will be calculated as \f$\gamma=1/\sqrt{1-\beta^2}\f$. * */ LorentzVector & boost(Boost b, double gamma=-1.) { return boost(b.x(), b.y(), b.z(),gamma); } /** * Apply rotation around the x-axis. * * @param phi Angle in radians. */ LorentzVector & rotateX (double phi) { double sinphi = sin(phi); double cosphi = cos(phi); Value ty = y() * cosphi - z() * sinphi; theZ = z() * cosphi + y() * sinphi; theY = ty; return *this; } /** * Apply rotation around the y-axis. * * @param phi Angle in radians. */ LorentzVector & rotateY (double phi) { double sinphi = sin(phi); double cosphi = cos(phi); Value tz = z() * cosphi - x() * sinphi; theX = x() * cosphi + z() * sinphi; theZ = tz; return *this; } /** * Apply rotation around the z-axis. * * @param phi Angle in radians. */ LorentzVector & rotateZ (double phi) { double sinphi = sin(phi); double cosphi = cos(phi); Value tx = x() * cosphi - y() * sinphi; theY = y() * cosphi + x() * sinphi; theX = tx; return *this; } /** * Rotate the reference frame to a new z-axis. */ LorentzVector & rotateUz (const Axis & axis) { Axis ax = axis.unit(); double u1 = ax.x(); double u2 = ax.y(); double u3 = ax.z(); double up = u1*u1 + u2*u2; if (up>0) { up = sqrt(up); Value px = x(), py = y(), pz = z(); setX( (u1*u3*px - u2*py)/up + u1*pz ); setY( (u2*u3*px + u1*py)/up + u2*pz ); setZ( -up*px + u3*pz ); } else if (u3 < 0.) { setX(-x()); setZ(-z()); } return *this; } /** * Apply a rotation. * @param angle Rotation angle in radians. * @param axis Rotation axis. */ template LorentzVector & rotate(double angle, const ThreeVector & axis) { if (angle == 0.0) return *this; const U ll = axis.mag(); assert( ll > U() ); const double sa = sin(angle), ca = cos(angle); const double dx = axis.x()/ll, dy = axis.y()/ll, dz = axis.z()/ll; const Value xx = x(), yy = y(), zz = z(); setX((ca+(1-ca)*dx*dx) * xx +((1-ca)*dx*dy-sa*dz) * yy +((1-ca)*dx*dz+sa*dy) * zz ); setY(((1-ca)*dy*dx+sa*dz) * xx +(ca+(1-ca)*dy*dy) * yy +((1-ca)*dy*dz-sa*dx) * zz ); setZ(((1-ca)*dz*dx-sa*dy) * xx +((1-ca)*dz*dy+sa*dx) * yy +(ca+(1-ca)*dz*dz) * zz ); return *this; } public: /// @name Mathematical assignment operators. //@{ LorentzVector & operator+=(const LorentzVector > & a) { theX += a.x(); theY += a.y(); theZ += a.z(); theT += a.t(); return *this; } template LorentzVector & operator+=(const LorentzVector & a) { theX += a.x(); theY += a.y(); theZ += a.z(); theT += a.t(); return *this; } LorentzVector & operator-=(const LorentzVector > & a) { theX -= Complex(a.x()); theY -= Complex(a.y()); theZ -= Complex(a.z()); theT -= Complex(a.t()); return *this; } template LorentzVector & operator-=(const LorentzVector & a) { theX -= a.x(); theY -= a.y(); theZ -= a.z(); theT -= a.t(); return *this; } LorentzVector & operator*=(double a) { theX *= a; theY *= a; theZ *= a; theT *= a; return *this; } LorentzVector & operator/=(double a) { theX /= a; theY /= a; theZ /= a; theT /= a; return *this; } //@} private: /// @name Vector components //@{ Value theX; Value theY; Value theZ; Value theT; //@} }; /// @name Basic mathematical operations //@{ template inline LorentzVector operator/(const LorentzVector & v, Value a) { return LorentzVector(v.x()/a, v.y()/a, v.z()/a, v.t()/a); } inline LorentzVector operator/(const LorentzVector & v, Complex a) { return LorentzVector(v.x()/a, v.y()/a, v.z()/a, v.t()/a); } template inline LorentzVector operator-(const LorentzVector & v) { return LorentzVector(-v.x(),-v.y(),-v.z(),-v.t()); } template inline LorentzVector operator+(LorentzVector a, const LorentzVector & b) { return a += b; } template inline LorentzVector operator-(LorentzVector a, const LorentzVector & b) { return a -= b; } template inline LorentzVector operator*(const LorentzVector & a, double b) { return LorentzVector(a.x()*b, a.y()*b, a.z()*b, a.t()*b); } template inline LorentzVector operator*(double b, LorentzVector a) { return a *= b; } template inline auto operator*(ValueB a, const LorentzVector & v) -> LorentzVector { return {a*v.x(), a*v.y(), a*v.z(), a*v.t()}; } template inline auto operator*(const LorentzVector & v, ValueB b) -> LorentzVector { return b*v; } template inline auto operator/(const LorentzVector & v, ValueB b) -> LorentzVector { return {v.x()/b, v.y()/b, v.z()/b, v.t()/b}; } //@} /// @name Scalar product with metric \f$(+,-,-,-)\f$ //@{ template inline auto operator*(const LorentzVector & a, const LorentzVector & b) -> decltype(a.dot(b)) { return a.dot(b); } //@} /// Equality template inline bool operator==(const LorentzVector & a, const LorentzVector & b) { return a.x() == b.x() && a.y() == b.y() && a.z() == b.z() && a.t() == b.t(); } /// Stream output. Format \f$(x,y,z;t)\f$. inline ostream & operator<< (ostream & os, const LorentzVector & v) { return os << "(" << v.x() << "," << v.y() << "," << v.z() << ";" << v.t() << ")"; } /** Return the positive light-cone component. Or negative if the * current Direction<0> is reversed. */ template inline Value dirPlus(const LorentzVector & p) { return Direction<0>::pos()? p.plus(): p.minus(); } /** Return the negative light-cone component. Or positive if the * current Direction<0> is reversed. */ template inline Value dirMinus(const LorentzVector & p) { return Direction<0>::neg()? p.plus(): p.minus(); } /** Return the component along the positive z-axis. Or the negative * z-axis if the current Direction<0> is reversed. */ template inline Value dirZ(const LorentzVector & p) { return Direction<0>::dir()*p.z(); } /** Return the polar angle wrt. the positive z-axis. Or the negative * z-axis if the current Direction<0> is reversed. */ template inline double dirTheta(const LorentzVector & p) { return Direction<0>::pos()? p.theta(): Constants::pi - p.theta(); } /** Return the cosine of the polar angle wrt. the positive z-axis. Or * the negative z-axis if the current Direction<0> is reversed. */ template inline double dirCosTheta(const LorentzVector & p) { return Direction<0>::pos()? p.cosTheta(): -p.cosTheta(); } /** Get the boost vector for the LorentzVector. If the current * Direction<0> is reversed, so is the z-component. */ template inline ThreeVector dirBoostVector(const LorentzVector & p) { ThreeVector b(p.boostVector()); if ( Direction<0>::neg() ) b.setZ(-b.z()); return b; } /** Create a LorentzVector giving its light-cone and transverse * components. */ template inline LorentzVector lightCone(Value plus, Value minus, Value x, Value y) { LorentzVector r(x, y, 0.5*(plus-minus), 0.5*(plus+minus)); return r; } /** Create a LorentzVector giving its light-cone components. */ template inline LorentzVector lightCone(Value plus, Value minus) { // g++-3.3 has a problem with using Value() directly // gcc-bug c++/3650, fixed in 3.4 static const Value zero = Value(); LorentzVector r(zero, zero, 0.5*(plus-minus), 0.5*(plus+minus)); return r; } } // delayed header inclusion to break inclusion loop: // LorentzVec -> Transverse -> Lorentz5Vec -> LorentzVec #include "Transverse.h" namespace ThePEG { /** Create a LorentzVector giving its light-cone and transverse * components. */ template inline LorentzVector lightCone(Value plus, Value minus, Transverse pt) { LorentzVector r(pt.x(), pt.y(), 0.5*(plus-minus), 0.5*(plus+minus)); return r; } /** Create a LorentzVector giving its light-cone and transverse * components. If the current Direction<0> is reversed, so is the * z-component. */ template inline LorentzVector lightConeDir(Value plus, Value minus, Value x = Value(), Value y = Value()) { LorentzVector r(x, y, Direction<0>::dir()*0.5*(plus - minus), 0.5*(plus + minus)); return r; } /** Create a LorentzVector giving its light-cone and transverse * components. If the current Direction<0> is reversed, so is the * z-component. */ template inline LorentzVector lightConeDir(Value plus, Value minus, Transverse pt) { LorentzVector r(pt.x(), pt.y(), Direction<0>::dir()*0.5*(plus - minus), 0.5*(plus + minus)); return r; } /** Output a LorentzVector with units to a stream. */ template void ounitstream(OStream & os, const LorentzVector & p, UnitT & u) { os << ounit(p.x(), u) << ounit(p.y(), u) << ounit(p.z(), u) << ounit(p.e(), u); } /** Input a LorentzVector with units from a stream. */ template void iunitstream(IStream & is, LorentzVector & p, UnitT & u) { Value x, y, z, e; is >> iunit(x, u) >> iunit(y, u) >> iunit(z, u) >> iunit(e, u); p = LorentzVector(x, y, z, e); } } #undef ERROR_IF #endif /* ThePEG_LorentzVector_H */ diff --git a/Vectors/ThreeVector.h b/Vectors/ThreeVector.h --- a/Vectors/ThreeVector.h +++ b/Vectors/ThreeVector.h @@ -1,421 +1,421 @@ // -*- C++ -*- // // ThreeVector.h is a part of ThePEG - Toolkit for HEP Event Generation // Copyright (C) 2006-2017 David Grellscheid, Leif Lonnblad // // ThePEG is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef ThePEG_ThreeVector_H #define ThePEG_ThreeVector_H /** * @file ThreeVector.h contains the ThreeVector class. ThreeVector can be * created with any unit type as template parameter. All basic * mathematical operations are supported, as well as a subset of the * CLHEP Vector3 functionality. */ #include "ThreeVector.fh" #include "ThePEG/Config/ThePEG.h" #include "ThePEG/Utilities/UnitIO.h" #include #include namespace ThePEG { /** * A 3-component vector. It can be created with any unit type * as template parameter. All basic mathematical operations are * supported, as well as a subset of the CLHEP Vector3 * functionality. */ template class ThreeVector { private: /// Value squared using Value2 = decltype(sqr(std::declval())); public: /** @name Constructors. */ //@{ ThreeVector() : theX(), theY(), theZ() {} ThreeVector(Value x, Value y, Value z) : theX(x), theY(y), theZ(z) {} template ThreeVector(const ThreeVector & v) : theX(v.x()), theY(v.y()), theZ(v.z()) {} //@} public: /// @name Component access methods. //@{ Value x() const { return theX; } Value y() const { return theY; } Value z() const { return theZ; } //@} /// @name Component set methods. //@{ void setX(Value x) { theX = x; } void setY(Value y) { theY = y; } void setZ(Value z) { theZ = z; } //@} public: /// Squared magnitude \f$x^2+y^2+z^2\f$. Value2 mag2() const { return sqr(x()) + sqr(y()) + sqr(z()); } /// Magnitude \f$\sqrt{x^2+y^2+z^2}\f$. Value mag() const { return sqrt(mag2()); } /// Squared transverse component \f$x^2+y^2\f$. Value2 perp2() const { return sqr(x()) + sqr(y()); } /// Transverse component \f$\sqrt{x^2+y^2}\f$. Value perp() const { return sqrt(perp2()); } /// Dot product. template auto dot(const ThreeVector & a) const - -> decltype(x()*a.x()) + -> decltype(this->x()*a.x()) { return x()*a.x() + y()*a.y() + z()*a.z(); } /// Squared transverse component with respect to the given axis. template Value2 perp2(const ThreeVector & p) const { const auto pMag2 = p.mag2(); assert( pMag2 > ZERO ); auto ss = this->dot(p); Value2 ret = mag2() - sqr(ss)/pMag2; if ( ret <= ZERO ) ret = ZERO; return ret; } /// Transverse component with respect to the given axis. template Value perp(const ThreeVector & p) const { return sqrt(perp2(p)); } /// @name Spherical coordinates. //@{ /// Polar angle. double theta() const { assert(!(x() == ZERO && y() == ZERO && z() == ZERO)); return atan2(perp(),z()); } /// Azimuthal angle. double phi() const { return atan2(y(),x()); } /// Set the polar angle. void setTheta(double th) { double ma = mag(); double ph = phi(); setX(ma*sin(th)*cos(ph)); setY(ma*sin(th)*sin(ph)); setZ(ma*cos(th)); } /// Set the azimuthal angle. void setPhi(double ph) { double xy = perp(); setX(xy*cos(ph)); setY(xy*sin(ph)); } //@} /// Parallel vector with unit length. ThreeVector unit() const { Value2 mg2 = mag2(); assert(mg2 > ZERO); Value mg = sqrt(mg2); return {x()/mg, y()/mg, z()/mg}; } /// Orthogonal vector. ThreeVector orthogonal() const { Value xx = abs(x()); Value yy = abs(y()); Value zz = abs(z()); using TVec = ThreeVector; if (xx < yy) { return xx < zz ? TVec{ZERO,z(),-y()} : TVec{y(),-x(),ZERO}; } else { return yy < zz ? TVec{-z(),ZERO,x()} : TVec{y(),-x(),ZERO}; } } /// Azimuthal angle difference, brought into the range \f$(-\pi,\pi]\f$. template double deltaPhi (const ThreeVector & v2) const { double dphi = v2.phi() - phi(); if ( dphi > Constants::pi ) { dphi -= Constants::twopi; } else if ( dphi <= -Constants::pi ) { dphi += Constants::twopi; } return dphi; } /** * Apply a rotation. * @param angle Rotation angle in radians. * @param axis Rotation axis. */ template ThreeVector & rotate(double angle, const ThreeVector & axis) { if (angle == 0.0) return *this; const U ll = axis.mag(); assert( ll > ZERO ); const double sa = sin(angle), ca = cos(angle); const double dx = axis.x()/ll, dy = axis.y()/ll, dz = axis.z()/ll; const Value xx = x(), yy = y(), zz = z(); setX((ca+(1-ca)*dx*dx) * xx +((1-ca)*dx*dy-sa*dz) * yy +((1-ca)*dx*dz+sa*dy) * zz ); setY(((1-ca)*dy*dx+sa*dz) * xx +(ca+(1-ca)*dy*dy) * yy +((1-ca)*dy*dz-sa*dx) * zz ); setZ(((1-ca)*dz*dx-sa*dy) * xx +((1-ca)*dz*dy+sa*dx) * yy +(ca+(1-ca)*dz*dz) * zz ); return *this; } /** * Rotate the reference frame to a new z-axis. */ ThreeVector & rotateUz (const Axis & axis) { Axis ax = axis.unit(); double u1 = ax.x(); double u2 = ax.y(); double u3 = ax.z(); double up = u1*u1 + u2*u2; if (up>0) { up = sqrt(up); Value px = x(), py = y(), pz = z(); setX( (u1*u3*px - u2*py)/up + u1*pz ); setY( (u2*u3*px + u1*py)/up + u2*pz ); setZ( -up*px + u3*pz ); } else if (u3 < 0.) { setX(-x()); setZ(-z()); } return *this; } /** * Rotate from a reference frame to the z-axis. */ ThreeVector & rotateUzBack (const Axis & axis) { Axis ax = axis.unit(); double u1 = ax.x(); double u2 = ax.y(); double u3 = ax.z(); double up = u1*u1 + u2*u2; if (up>0) { up = sqrt(up); Value px = x(), py = y(), pz = z(); setX( ( u1*u3*px + u2*u3*py)/up - up*pz ); setY( (-u2*px + u1*py)/up ); setZ( u1*px + u2*py + u3*pz ); } else if (u3 < 0.) { setX(-x()); setZ(-z()); } return *this; } /// Vector cross-product template auto cross(const ThreeVector & a) const - -> ThreeVector + -> ThreeVectory()*a.z())> { return { y()*a.z()-z()*a.y(), -x()*a.z()+z()*a.x(), x()*a.y()-y()*a.x() }; } public: /// @name Comparison operators. //@{ bool operator==(const ThreeVector & a) const { return (theX == a.x() && theY == a.y() && theZ == a.z()); } bool operator!=(const ThreeVector & a) const { return !(*this == a); } bool almostEqual(const ThreeVector & a, double threshold = 1e-04) const { return ((std::abs(theX - a.x()) < threshold) && (std::abs(theY - a.y()) < threshold) && (std::abs(theZ - a.z()) < threshold)); } bool almostUnequal(const ThreeVector & a, double threshold = 1e-04) const { return ! this->almostEqual(a, threshold); } //@} public: /// @name Mathematical assignment operators. //@{ ThreeVector & operator+=(const ThreeVector & a) { theX += a.x(); theY += a.y(); theZ += a.z(); return *this; } ThreeVector & operator-=(const ThreeVector & a) { theX -= a.x(); theY -= a.y(); theZ -= a.z(); return *this; } ThreeVector & operator*=(double a) { theX *= a; theY *= a; theZ *= a; return *this; } ThreeVector & operator/=(double a) { theX /= a; theY /= a; theZ /= a; return *this; } //@} /// Cosine of the azimuthal angle between two vectors. template double cosTheta(const ThreeVector & q) const { auto ptot = mag()*q.mag(); assert( ptot > ZERO ); double arg = dot(q)/ptot; if (arg > 1.0) arg = 1.0; else if(arg < -1.0) arg = -1.0; return arg; } /// Angle between two vectors. template double angle(const ThreeVector & v) const { return acos(cosTheta(v)); } private: /// @name Vector components //@{ Value theX; Value theY; Value theZ; //@} }; /// Stream output. Format \f$(x,y,z)\f$. inline ostream & operator<< (ostream & os, const ThreeVector & v) { return os << '(' << v.x() << ',' << v.y() << ',' << v.z() << ')'; } /// @name Basic mathematical operations //@{ template inline ThreeVector operator+(ThreeVector a, const ThreeVector & b) { return a += b; } template inline ThreeVector operator-(ThreeVector a, const ThreeVector & b) { return a -= b; } template inline ThreeVector operator-(const ThreeVector & v) { return {-v.x(),-v.y(),-v.z()}; } template inline ThreeVector operator*(ThreeVector v, double a) { return v *= a; } template inline ThreeVector operator*(double a, ThreeVector v) { return v *= a; } template inline auto operator*(ValueB a, ThreeVector v) -> ThreeVector { return {a*v.x(), a*v.y(), a*v.z()}; } template inline auto operator*(ThreeVector v, ValueB a) -> ThreeVector { return {v.x()*a, v.y()*a, v.z()*a}; } //@} /// Vector dot product. template inline auto operator*(const ThreeVector & a, const ThreeVector & b) -> decltype(a.x()*b.x()) { return a.dot(b); } /// A parallel vector with unit length. template ThreeVector unitVector(const ThreeVector & v) { return v.unit(); } /** Output a ThreeVector with units to a stream. */ template void ounitstream(OStream & os, const ThreeVector & p, UT & u) { os << ounit(p.x(), u) << ounit(p.y(), u) << ounit(p.z(), u); } /** Input a ThreeVector with units from a stream. */ template void iunitstream(IStream & is, ThreeVector & p, UT & u) { Value x, y, z; is >> iunit(x, u) >> iunit(y, u) >> iunit(z, u); p = ThreeVector(x, y, z); } } #endif /* ThePEG_ThreeVector_H */ diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1,174 +1,175 @@ dnl Process this file with autoconf to produce a configure script. -AC_PREREQ([2.59]) -AC_INIT([ThePEG],[devel],[http://www.thep.lu.se/ThePEG/],[ThePEG]) +AC_PREREQ([2.69]) +AC_INIT([ThePEG],[2.2.0],[http://www.thep.lu.se/ThePEG/],[ThePEG]) AC_CONFIG_AUX_DIR([Config]) AC_CONFIG_MACRO_DIR([m4]) THEPEG_LIBTOOL_VERSION_INFO(29,0,0) AC_CONFIG_SRCDIR([EventRecord/SubProcess.h]) AC_CONFIG_HEADERS([Config/config.h]) AC_CANONICAL_HOST case "${host}" in *-darwin[[0156]].*) AC_MSG_ERROR([ThePEG requires OS X 10.3 or later]) ;; *-darwin7.*) if test "x$MACOSX_DEPLOYMENT_TARGET" != "x10.3"; then AC_MSG_ERROR( [Please export the MACOSX_DEPLOYMENT_TARGET variable, set to 10.3]) fi ;; esac AC_LANG(C++) AM_INIT_AUTOMAKE([1.9 gnu dist-bzip2 subdir-objects -Wall]) dnl also include std-options once --version and --help exist m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) dnl Checks for C++ compiler. Handle C++11 flags. AC_PROG_CXX AX_CXX_COMPILE_STDCXX([11],[noext],[mandatory]) dnl check for unistd AC_CHECK_HEADER([unistd.h],[], [AC_MSG_ERROR([ThePEG needs "unistd.h". Check your system is POSIX-compliant.])]) dnl Checks for programs. AC_PROG_INSTALL AC_PROG_MAKE_SET AC_PROG_LN_S LT_PREREQ([2.2]) LT_INIT([disable-static dlopen pic-only]) VL_LIB_READLINE THEPEG_CHECK_GSL THEPEG_SEARCH_LHAPDF THEPEG_CHECK_HEPMC THEPEG_CHECK_RIVET FASTJET_CHECK_FASTJET AX_CHECK_ZLIB dnl AX_CHECK_BZ2LIB THEPEG_DEFINE_ENVDEFAULT(ThePEG_GZREAD_FILE,GZREAD_FILE,gunzip -c,[The command which, taking the name of a gzipped file as argument, unzips it and prints it to stdout. Default is "gunzip -c"]) THEPEG_DEFINE_ENVDEFAULT(ThePEG_GZWRITE_FILE,GZWRITE_FILE,[gzip -c > ],[The command which, taking the name of a gzipped file as argument, reads stdin, zips it and writes it to the file. Default is "gzip -c > ".]) THEPEG_DEFINE_ENVDEFAULT(ThePEG_BZ2READ_FILE,BZ2READ_FILE,bunzip2 -c,[The command which, taking the name of a bzipped file as argument, unzips it and prints it to stdout. Default is "bunzip2 -c".]) THEPEG_DEFINE_ENVDEFAULT(ThePEG_BZ2WRITE_FILE,BZ2WRITE_FILE,[bzip2 -c > ],[The command which, taking the name of a bzipped file as argument, reads stdin, zips it and writes it to the file. Default is "bzip2 -c > ".]) THEPEG_CHECK_EXPM1 THEPEG_CHECK_LOG1P THEPEG_CHECK_DLOPEN AX_COMPILER_VENDOR case "${ax_cv_cxx_compiler_vendor}" in clang) case "${host}" in *linux*) AC_MSG_WARN([ ***************************************************************************** clang/LLVM ignores the CPU floating-point environment. All floating point exception trapping will be disabled. *****************************************************************************]) ;; esac esac THEPEG_CHECK_FPUCONTROL THEPEG_CHECK_FENV AM_CPPFLAGS="-I\$(top_builddir)/include \$(GSLINCLUDE)" case "${ax_cv_cxx_compiler_vendor}" in gnu) AM_CXXFLAGS="-pedantic -Wall -W" ;; clang) AM_CXXFLAGS="-pedantic -Wall -Wno-overloaded-virtual -Wno-unused-function" dnl -Wno-unneeded-internal-declaration ;; intel) AM_CXXFLAGS="-strict-ansi -Wall -wd13000,1418,981,444,383,1599,1572,2259,980" ;; esac AC_SUBST(AM_CPPFLAGS) AC_SUBST(AM_CXXFLAGS) dnl do an actual capability check on ld instead of this workaround case "${host}" in *-darwin*) ;; *) AM_LDFLAGS="-Wl,--enable-new-dtags" ;; esac AC_SUBST(AM_LDFLAGS) THEPEG_EMPTY_SUBST AC_PATH_PROG(PERL, perl) AC_ARG_WITH(javagui, [ --with-javagui Compile and install the java-based GUI.]) if test "x$with_javagui" != "xno"; then THEPEG_HAS_JAVA([1.4], [], [with_javagui=no; AC_MSG_NOTICE([Java GUI disabled])]) fi AM_CONDITIONAL([JAVAGUI], [test "x$with_javagui" != "xno"]) AC_CONFIG_FILES([Helicity/Makefile Helicity/WaveFunction/Makefile Helicity/Vertex/Makefile Helicity/Vertex/Scalar/Makefile Helicity/Vertex/Vector/Makefile Helicity/Vertex/Tensor/Makefile Utilities/Makefile include/Makefile Interface/Makefile LesHouches/Makefile Vectors/Makefile PDT/Makefile PDF/Makefile Persistency/Makefile Config/Makefile Handlers/Makefile MatrixElement/Makefile Pointer/Makefile lib/Makefile lib/Makefile.common.install src/Makefile +src/thepeg-config ACDC/Makefile Repository/Makefile EventRecord/Makefile StandardModel/Makefile Cuts/Makefile Analysis/Makefile Doc/Makefile Doc/MakeDocs.in Doc/refman.h Doc/refman.conf java/Makefile Makefile]) AC_CONFIG_FILES([Doc/fixinterfaces.pl],[chmod +x Doc/fixinterfaces.pl]) BOOST_REQUIRE([1.41],[AC_SUBST([BOOST_NOT_FOUND],[true])]) BOOST_TEST() THEPEG_BOOST_UNIT_TEST THEPEG_OVERVIEW AC_CONFIG_COMMANDS([summary],[cat config.thepeg]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,143 +1,145 @@ AUTOMAKE_OPTIONS = -Wno-portability bin_PROGRAMS = setupThePEG runThePEG EXTRA_PROGRAMS = runEventLoop +bin_SCRIPTS = thepeg-config + EXTRA_DIST = testpdfs .check-local.sh myLDADD = $(top_builddir)/lib/libThePEG.la myLDFLAGS = -export-dynamic runThePEG_SOURCES = runThePEG.cc runThePEG_LDADD = $(myLDADD) $(GSLLIBS) runThePEG_LDFLAGS = $(AM_LDFLAGS) $(myLDFLAGS) runEventLoop_SOURCES = runEventLoop.cc runEventLoop_LDADD = -lHepMC $(myLDADD) $(GSLLIBS) runEventLoop_LDFLAGS = $(AM_LDFLAGS) $(myLDFLAGS) setupThePEG_SOURCES = setupThePEG.cc setupThePEG_LDADD = $(myLDADD) $(GSLLIBS) setupThePEG_LDFLAGS = $(AM_LDFLAGS) $(myLDFLAGS) setupThePEG_CPPFLAGS = $(AM_CPPFLAGS) \ -DTHEPEG_PKGLIBDIR="\"$(pkglibdir)\"" if USELHAPDF pkglib_LTLIBRARIES = TestLHAPDF.la TestLHAPDF_la_SOURCES = TestLHAPDF.cc TestLHAPDF.h TestLHAPDF_la_LDFLAGS = $(AM_LDFLAGS) -module $(LIBTOOLVERSIONINFO) endif dist_pkgdata_DATA = SimpleLEP.in ThePEGDefaults.in ThePEGParticles.in debugItems.txt TestLHAPDF.in MultiLEP.in rpodir = $(pkglibdir) nodist_rpo_DATA = ThePEGDefaults.rpo CLEANFILES = SimpleLEP.log SimpleLEP.out SimpleLEP.run SimpleLEP.tex \ MultiLEP.log MultiLEP.out MultiLEP.run MultiLEP.tex \ ThePEGDefaults.rpo .done-all-links \ TestLHAPDF.log TestLHAPDF.out TestLHAPDF.run TestLHAPDF.tex \ .runThePEG.timer.TestLHAPDF.run SimpleLEP.dump MultiLEP.dump save: mkdir -p save cp *.log *.out *.run *.tex *.rpo save valgrind: valgrind --leak-check=full --num-callers=25 --track-fds=yes --freelist-vol=100000000 --leak-resolution=med --trace-children=yes ./setupThePEG -r ThePEGDefaults.rpo SimpleLEP.in &> /tmp/valgrind.out valgrind --leak-check=full --num-callers=25 --track-fds=yes --freelist-vol=100000000 --leak-resolution=med --trace-children=yes ./runThePEG SimpleLEP.run >> /tmp/valgrind.out 2>&1 INPUTFILES = ThePEGDefaults.in ThePEGParticles.in \ SimpleLEP.in SimpleLEP.mod MultiLEP.in TestLHAPDF.in .done-all-links: @EMPTY@ifdef SHOWCOMMAND for file in $(INPUTFILES); do \ if test ! -f $$file; then $(LN_S) $(srcdir)/$$file $$file; fi; done echo "stamp" > .done-all-links @EMPTY@else @echo "sym-linking input files files..." @for file in $(INPUTFILES); do \ if test ! -f $$file; then $(LN_S) $(srcdir)/$$file $$file; fi; done @echo "stamp" > .done-all-links @EMPTY@endif ThePEGDefaults.rpo: .done-all-links setupThePEG ThePEGDefaults.in ThePEGParticles.in ./setupThePEG --init --exitonerror -L../lib -r ThePEGDefaults.rpo ThePEGDefaults.in cd ../lib; rm -f ThePEGDefaults.rpo; $(LN_S) -f ../src/ThePEGDefaults.rpo . check-local: ThePEGDefaults.rpo @$(srcdir)/.check-local.sh if USELHAPDF LHAPATH=$(srcdir)/testpdfs ./setupThePEG --exitonerror -r ThePEGDefaults.rpo TestLHAPDF.in LHAPATH=$(srcdir)/testpdfs time ./runThePEG -d 1 -x .libs/TestLHAPDF.so TestLHAPDF.run endif SimpleLEP.run: .done-all-links setupThePEG ThePEGDefaults.rpo SimpleLEP.in ./setupThePEG --exitonerror -r ThePEGDefaults.rpo SimpleLEP.in SimpleLEP.out: runThePEG SimpleLEP.run time ./runThePEG -d 0 SimpleLEP.run MultiLEP.run: .done-all-links setupThePEG ThePEGDefaults.rpo MultiLEP.in ./setupThePEG --exitonerror -r ThePEGDefaults.rpo MultiLEP.in MultiLEP.out: runThePEG MultiLEP.run time ./runThePEG -d 0 MultiLEP.run if USELHAPDF TestLHAPDF.run: .done-all-links setupThePEG ThePEGDefaults.rpo TestLHAPDF.in TestLHAPDF.la LHAPATH=$(srcdir)/testpdfs ./setupThePEG --exitonerror -r ThePEGDefaults.rpo TestLHAPDF.in TestLHAPDF.out: runThePEG TestLHAPDF.run LHAPATH=$(srcdir)/testpdfs time ./runThePEG -d 1 -x .libs/TestLHAPDF.so TestLHAPDF.run endif install-exec-hook: cd $(DESTDIR)$(pkglibdir); \ rm -f setupThePEG-$(VERSION) runThePEG-$(VERSION); \ cp $(DESTDIR)$(bindir)/setupThePEG setupThePEG-$(VERSION); \ cp $(DESTDIR)$(bindir)/runThePEG runThePEG-$(VERSION) install-data-hook: rm -f $(DESTDIR)$(pkglibdir)/ThePEGDefaults.rpo ./setupThePEG --init --exitonerror -L$(DESTDIR)$(pkglibdir) -r $(DESTDIR)$(pkglibdir)/ThePEGDefaults.rpo $(DESTDIR)$(pkgdatadir)/ThePEGDefaults.in if USELHAPDF # LHAPATH=$(srcdir)/testpdfs ./setupThePEG --init --exitonerror -r $(DESTDIR)$(pkglibdir)/ThePEGDefaults.rpo -o $(DESTDIR)$(pkglibdir)/ThePEGDefaults.rpo endif cd $(DESTDIR)$(pkglibdir); \ if test -n "$(DESTDIR)"; \ then sed -i.bak -e "s@$(DESTDIR)@@g" ThePEGDefaults.rpo; \ rm -f ThePEGDefaults.rpo.bak; \ fi ; \ cp ThePEGDefaults.rpo ThePEGDefaults-$(VERSION).rpo uninstall-local: cd $(DESTDIR)$(pkglibdir); \ rm -f setupThePEG-$(VERSION) runThePEG-$(VERSION) ThePEGDefaults-$(VERSION).rpo installcheck-local: $(mkdir_p) _test_thepeg_installation_ cd _test_thepeg_installation_; \ $(DESTDIR)$(bindir)/setupThePEG --exitonerror $(DESTDIR)$(pkgdatadir)/SimpleLEP.in; \ mv SimpleLEP.out SimpleLEP.cmp; \ $(DESTDIR)$(bindir)/runThePEG SimpleLEP.run; \ diff SimpleLEP.out SimpleLEP.cmp; \ mv SimpleLEP.out SimpleLEP.cmp; \ $(DESTDIR)$(bindir)/runThePEG --resume SimpleLEP.dump; \ diff SimpleLEP.out SimpleLEP.cmp; \ $(DESTDIR)$(bindir)/setupThePEG --exitonerror $(DESTDIR)$(pkgdatadir)/MultiLEP.in; \ $(DESTDIR)$(bindir)/runThePEG MultiLEP.run; if USELHAPDF export LHAPATH=$$(pwd)/$(srcdir)/testpdfs; cd _test_thepeg_installation_; \ $(DESTDIR)$(bindir)/setupThePEG --exitonerror $(DESTDIR)$(pkgdatadir)/TestLHAPDF.in; \ $(DESTDIR)$(bindir)/runThePEG -x $(DESTDIR)$(pkglibdir)/TestLHAPDF.so TestLHAPDF.run endif rm -rf _test_thepeg_installation_ %.run: %.in .done-all-links ThePEGDefaults.rpo ./setupThePEG --exitonerror -L .libs -r ../lib/ThePEGDefaults.rpo $< %.out: %.run time ./runThePEG -d 0 $< diff --git a/src/thepeg-config.in b/src/thepeg-config.in new file mode 100644 --- /dev/null +++ b/src/thepeg-config.in @@ -0,0 +1,62 @@ +#! /usr/bin/env bash +# @configure_input@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datarootdir=@datarootdir@ + +tmp=$(echo $* | egrep -- '--\|-\') +if test $# -eq 0 || test -n "$tmp"; then + echo "thepeg-config: configuration tool for the ThePEG event generator framework" + echo " http://projects.hepforge.org/thepeg/" + echo + echo "Usage: `basename $0` [Option]" + echo "Options:" + echo " --help | -h : show this help message" + echo " --prefix : show the installation prefix (cf. autoconf)" + echo " --datadir : show the path to the directory containing shared data" + echo " --libdir : show the path to the directory containing the libraries" + echo " --includedir : show the path to the directory containing the headers" + echo " --cppflags : show the required CPPFLAGS for building against ThePEG" + echo " --ldflags : show the required LDFLAGS for linking against ThePEG" + echo " --ldlibs : show the required libraries for linking against ThePEG" + echo " --rivet-include : show the path to the directory containing the Rivet headers" + echo " --fastjet-include : show the path to the directory containing the FastJet headers" + echo " --rivet-libs : show the required libraries for linking against Rivet" + echo " --fastjet-libs : show the required libraries for linking against FastJet" + + echo +fi + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo $prefix + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo @datadir@/@PACKAGE_TARNAME@ + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo @libdir@/@PACKAGE_TARNAME@ + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo @includedir@ + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo -I@includedir@ @BOOST_CPPFLAGS@ @GSLINCLUDE@ + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo @LDFLAGS@ + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo @LIBS@ + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo @RIVETINCLUDE@ + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo @FASTJETINCLUDE@ + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo @RIVETLIBS@ + +tmp=$(echo "$*" | egrep -- '--\') +test -n "$tmp" && echo @FASTJETLIBS@