diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -1,27 +1,28 @@ 168ae2110e964d62fbc1331a1c2e095952a67748 release-2-5-2 3abb4fa42e20e332796c2572334c2d77204cd0e0 release-2-4-2 4796ca080aafd5daa3b7349b015cb1df944428a2 release-2-5-0 76da042f056eb153981b4d005d5474ffb90a5e88 release-2-4-1 81a684a558413c69df314365eabf09893ffd43d8 release-2-6-0 bd75cd00d99f4bdbaed992daf98f0a73c0f91e9b release-2-4-0 ff6ecc8d49ce10299303b050394bd5cb5837f1c3 release-2-5-1 d0389f5453b2c210923e1adc7b872b18269de668 release-2-6-1 f8998033021185942533b824607285feb3fbd2dc release-2-6-1a cead23e428b9aacaf2d709e722624e54f844498b release-2-6-1b 191db4655439045f912cb21bd905e729d59ec7bc release-2-6-2 edb538156e9c3d64bb842934b4cebf0126aeb9ea release-2-6-3 eb4a104591859ecac18746b1ad54d6aa0c2a5d1a release-2-7-0 568971ac5b3c1d044c9259f2280a8304fc5a62e9 trunk-before-QED 6e3edb6cfeb4ee48687eb4eb3d016026fc59d602 trunk-after-QED 633abb80b571aa23088957df60e9b0000bbb8a22 release-2-7-1 1bdde095d2346c15ee548e5406a96f0fc6d6e0f1 beforeHQ a0f9fb821396092bdbeee532bcb0bd624f58335b before_MB_merge 270c1e6b34aa7f758f1d9868c4d3e1ec4bf4e709 herwig-7-0-0 6e0f198c1c2603ecd1a0b6cfe40105cda4bd58c5 herwig-7-0-1 566c1de845a8070559cda45b1bdb40afa18cb2cc herwig-7-0-2 f5c4aa956880f2def763ebd57de7b5bfa55cb1db herwig-7-0-3 65282dedfc2e4bec184e68678dbf4c553c968f38 herwig-7-0-4 541e7790b65ed423c86780bf66ec30e6b99b5a18 herwig-7-1-0 dd35a1c12d57c047169e8c5fb18644972d49c6ac herwig-7-1-1 0d651b079756b63713e32a1341d81e4dfc7eeb7b herwig-7-1-2 4b97934bc41c861c4be04f563ffa68a94a982560 herwig-7-1-3 +97aca5398cfa1f3273804f03fa96fa0fa23eca61 herwig-7-1-4 diff --git a/AUTHORS b/AUTHORS --- a/AUTHORS +++ b/AUTHORS @@ -1,56 +1,56 @@ ================================================================================ -Herwig 7.1.3 +Herwig 7.1.4 ================================================================================ Please contact for any queries. -------------------------------------------------------------------------------- Herwig is actively developed by: -------------------------------------------------------------------------------- Johannes Bellm Stefan Gieseke David Grellscheid Patrick Kirchgaeßer Graeme Nail Andreas Papaefstathiou Simon Plätzer Radek Podskubka Michael Rauch Christian Reuschle Peter Richardson Mike Seymour Andrzej Siödmok Stephen Webster -------------------------------------------------------------------------------- Former authors are: -------------------------------------------------------------------------------- Ken Arnold Manuel Bähr Luca d'Errico Martyn Gigg Nadine Fischer Keith Hamilton Marco A. Harrendorf Seyi Latunde-Dada Frashër Loshaj Daniel Rauch Alberto Ribon Christian Röhr Pavel Růžička Peter Schichtel Alex Schofield Thomas Schuh Alexander Sherstnev Philip Stephens Martin Stoll Louise Suter Jon Tully Bryan Webber Alix Wilcock David Winn Benedikt Zimmermann diff --git a/Contrib/AlpGen/AlpGenHandler.cc b/Contrib/AlpGen/AlpGenHandler.cc --- a/Contrib/AlpGen/AlpGenHandler.cc +++ b/Contrib/AlpGen/AlpGenHandler.cc @@ -1,1392 +1,1392 @@ #include "AlpGenHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" #include "Herwig/PDF/HwRemDecayer.h" #include #include "ThePEG/Utilities/Throw.h" -#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "fastjet/PseudoJet.hh" #include "fastjet/ClusterSequence.hh" #include "gsl/gsl_rng.h" #include "gsl/gsl_randist.h" using namespace Herwig; bool recordEntry(PPtr i,PPtr j) { return (i->number()number()); } bool pTsortFunction(PPtr i,PPtr j) { return (i->momentum().perp2()>j->momentum().perp2()); } bool ETsortFunction(pair i,pair j) { return (i.first>j.first); } bool isMomLessThanEpsilon(Lorentz5Momentum p,Energy epsilon) { return (abs(p.x())> alphaS_ >> ncy_ >> ncphi_ >> ihvy_ >> nph_ >> nh_ >> iunit(etclusmean_,GeV) >> rclus_ >> etaclmax_ >> rclusfactor_ >> ihrd_ >> njets_ >> drjmin_ >> highestMultiplicity_ >> ycmax_ >> ycmin_ >> jetAlgorithm_ >> vetoIsTurnedOff_ >> inputIsNLO_ >> highestNLOMultiplicity_ >> etclusfixed_ >> cphcal_ >> sphcal_ >> cthcal_ >> sthcal_ >> iunit(epsetclus_,GeV); } ClassDescription AlpGenHandler::initAlpGenHandler; // Definition of the static class description member. void AlpGenHandler::Init() { static ClassDocumentation documentation ("The AlpGenHandler class performs MEPS merging " "using the MLM procedure."); static Reference interfaceShowerAlpha ("ShowerAlpha", "The object calculating the strong coupling constant", &AlpGenHandler::alphaS_, false, false, true, false, false); static Parameter interfaceNoCellsInRapidity ("NoCellsInRapidity", "The number of cells spanning the rapidity interval of " "the calorimeter", &AlpGenHandler::ncy_, 100, 1, 10000, false, false, Interface::limited); static Parameter interfaceNoCellsInPhi ("NoCellsInPhi", "The number of cells spanning the phi interval of " "the calorimeter", &AlpGenHandler::ncphi_, 60, 1, 10000, false, false, Interface::limited); static Parameter interfaceihvy ("ihvy", "heavy flavour in WQQ,ZQQ,2Q etc (4=c, 5=b, 6=t)", &AlpGenHandler::ihvy_, -999, -999, 7, false, false, Interface::limited); static Parameter interfacenph ("nph", "Number of photons in the AlpGen process", &AlpGenHandler::nph_, -999, -999, 7, false, false, Interface::limited); static Parameter interfacenh ("nh", "Number of higgses in the AlpGen process", &AlpGenHandler::nph_, -999, -999, 7, false, false, Interface::limited); static Parameter interfaceETClus ("ETClus", "The ET threshold defining a jet in the merging procedure", &AlpGenHandler::etclusmean_, GeV, 20*GeV, 0*GeV, 14000*GeV, false, false, Interface::limited); static Parameter interfaceRClus ("RClus", "The cone size used to define a jet in the merging procedure", &AlpGenHandler::rclus_, 0.4, 0.0, 4.0, false, false, Interface::limited); static Parameter interfaceEtaClusMax ("EtaClusMax", "The maximum |eta| used to define a jet in the merging procedure", &AlpGenHandler::etaclmax_, 5.0, 0.0, 15.0, false, false, Interface::limited); static Parameter interfaceRClusFactor ("RClusFactor", "The prefactor for RClus used to define the jet-parton matching " "distance", &AlpGenHandler::rclusfactor_, 1.5, 0.0, 4.0, false, false, Interface::limited); static Parameter interfaceihrd ("ihrd", "The AlpGen hard process code", &AlpGenHandler::ihrd_, -999, 0, 10000, false, false, Interface::limited); static Parameter interfacenjets ("njets", "The number of light jets in the AlpGen process (i.e. the " "extra ones)", &AlpGenHandler::njets_, -999, 0, 10000, false, false, Interface::limited); static Parameter interfacedrjmin ("drjmin", "Mimimum parton-parton R-sep used for generation.", &AlpGenHandler::drjmin_, 0.7, 0.0, 4.0, false, false, Interface::limited); static Parameter interfacehighestMultiplicity ("highestMultiplicity", "If true it indicates that this is the highest multiplicity input " "ME-level configuration to be processed.", &AlpGenHandler::highestMultiplicity_, 0, 0, 1, false, false, Interface::limited); static Parameter interfacehighestNLOMultiplicity ("highestNLOMultiplicity", "If true it indicates that this is the highest NLO multiplicity input " "ME-level configuration to be processed.", &AlpGenHandler::highestNLOMultiplicity_, 0, 0, 1, false, false, Interface::limited); static Parameter interfaceETClusFixed ("ETClusFixed", "If false, indicates that the jet merging scale, etclus_ is allowed to vary" "according to epsetclus_", &AlpGenHandler::etclusfixed_, 1, 0, 1, false, false, Interface::limited); static Parameter interfaceEpsilonETClus ("EpsilonETClus", "The ET threshold defining a jet in the merging procedure", &AlpGenHandler::epsetclus_, GeV, 2.5*GeV, 0*GeV, 100.0*GeV, false, false, Interface::limited); static Switch interfaceJetAlgorithm ("JetAlgorithm", "Determines the jet algorithm for finding jets in parton-jet " "matching in the MLM procedure.", &AlpGenHandler::jetAlgorithm_, 2, false, false); static SwitchOption AntiKt (interfaceJetAlgorithm, "AntiKt", "The anti-kt jet algorithm.", -1); static SwitchOption CambridgeAachen (interfaceJetAlgorithm, "CambridgeAachen", "The Cambridge-Aachen jet algorithm.", 0); static SwitchOption Kt (interfaceJetAlgorithm, "Kt", "The Kt jet algorithm.", 1); static SwitchOption GetJet (interfaceJetAlgorithm, "GetJet", "Calorimeter-based GetJet algorithm (default).", 2); static Switch interfaceVetoIsTurnedOff ("VetoIsTurnedOff", "Allows the vetoing mechanism to be switched off.", &AlpGenHandler::vetoIsTurnedOff_, false, false, false); static SwitchOption VetoingIsOn (interfaceVetoIsTurnedOff, "VetoingIsOn", "The MLM merging veto mechanism is switched ON.", false); static SwitchOption VetoingIsOff (interfaceVetoIsTurnedOff, "VetoingIsOff", "The MLM merging veto mechanism is switched OFF.", true); static Switch interfaceInputIsNLO ("InputIsNLO", "Signals whether the input LH file is tree-level accurate " "or contains NLO (Powheg) events.", &AlpGenHandler::inputIsNLO_, false, false, false); static SwitchOption InputIsNotNLO (interfaceInputIsNLO, "InputIsNotNLO", "The input LH events have tree-level accuracy.", false); static SwitchOption InputIsNLO (interfaceInputIsNLO, "InputIsNLO", "The input LH events have NLO accuracy.", true); } void AlpGenHandler::dofinish() { ShowerHandler::dofinish(); } void AlpGenHandler::doinit() { //print error if HardProcID is not set in input file if(ihrd_ == -999) { cout << "Error: AlpGenHandler:ihrd not set!" << endl; exit(1); } ShowerHandler::doinit(); // Compute calorimeter edges in rapidity for GetJet algorithm. ycmax_=etaclmax_+rclus_; ycmin_=-ycmax_; // Initialise calorimeter. calini_m(); } // Throws a veto according to MLM strategy ... when we finish writing it. bool AlpGenHandler::showerHardProcessVeto() const { if(vetoIsTurnedOff_) return false; // Skip veto for processes in which merging is not implemented: if(ihrd_==7||ihrd_==8||ihrd_==13) { ostringstream wstring; wstring << "AlpGenHandler::showerHardProcessVeto() - warning." << "MLM merging not implemented for AlpGen " << "processes 4Q (ihrd=7), QQh (ihrd=8), " << "(single) top (ihrd=13) \n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); return false; } // Fill preshowerISPs_ pair and preshowerFSPs_ particle pointer vector. getPreshowerParticles(); // Fill showeredISHs_, showeredISPs and showeredRems pairs, as well as // showeredFSPs_ particle pointer vector. getShoweredParticles(); // Turn on some screen output debugging: 0 = none ---> 5 = very verbose. doSanityChecks(0); // Dimensions of each calorimter cell in y and phi. dely_ = (ycmax_-ycmin_)/double(ncy_); delphi_ = 2*M_PI/double(ncphi_); // Fill partonsToMatch_ with only those pre-shower partons intended to // used in jet-parton matching and fill particlesToCluster_ using only // those final state particles (post-shower) which are supposed to go // in the jet clustering used to do merging. partonsToMatch_ = preshowerFSPs_; particlesToCluster_ = showeredFSPs_ ; // <--- TO DO: add remnants in here ??? // Filter out all but the 'extra' light-parton progenitors and their // associated final state particles. caldel_m(); double prob(1); //if etclusfixed_ then set the etclus_ to the fixed chosen value if(etclusfixed_) { etclus_ = etclusmean_; } else { //else, if we wish to vary etclus_, we use the probability distribution //choose a probability between 0 and 1 prob = rnd(); etclus_ = etclusran_(prob); } if(jetAlgorithm_==2) { // If using GetJet fill the calorimeter cells now from particlesToCluster_ calsim_m(); // Make jets from the calorimeter blobs. getjet_m(rclus_,etclus_,etaclmax_); } else { // Cluster particlesToCluster_ into jets with FastJet. getFastJets(rclus_,etclus_,etaclmax_); } // If there are less jets than partons then parton-jet matching is // bound to fail: reject the event already. Also, if the input is // an NLO event file it will 99.5% of the time contain a number of // light partons in the F.S. equal to that in the real emission // process in the NLO calculation, moreover, it has already // effectively merged njets_-1 and njets jet events. So in that // case we do not reject events on the grounds they have jet // multiplicity less than partonsToMatch_.size() but rather less // jets than partonsToMatch.size()-1; such events are better // described by the lower-by-one-unit (partonsToMatch_.size()-1) // of multiplicity NLO event file, or the lower-by-two-units // (partonsToMatch_.size()-2) of multiplicity LO event file. // If it is not jet production apply rejection criterion as above. if(ihrd_!=9) { if(!inputIsNLO_) { if(pjet_.size() < partonsToMatch_.size()) return true; } else { if(pjet_.size() < partonsToMatch_.size()-1) return true; } // Otherwise, in the case of jet production allow the lowest // contributing multiplicity process (just at NLO), namely, // dijet production, to give rise to 1-jet and even 0-jet // events, since these can contribute to, for example, the // inclusive jet cross section i.e. in this case the rejection // is only applied in the case of the next-to-lowest multiplicity // processes (>2 parton events at LO and >3 parton events at NLO). } else { if(!inputIsNLO_) { // KH - March 5th // Removed the following line giving special treatment // also to the LO events, to maintain consistency with // the fortran algorithm, at least for now. So now jet // production at LO is being treated the same as all // other processes. // if(partonsToMatch_.size()==2 && pjet_.size()<2) return false; if(pjet_.size() < partonsToMatch_.size()) return true; } else { if(partonsToMatch_.size()<=3 && pjet_.size()<2) return false; if(pjet_.size() < partonsToMatch_.size()-1) return true; } } // Sort partonsToMatch_ from high to low pT. sort(partonsToMatch_.begin(),partonsToMatch_.end(),pTsortFunction); // Match light progenitors to jets. vector jetToPartonMap(pjet_.size(),-999); Energy etmin(777e100*GeV); // If the input is NLO events then don't do any jet-parton matching! if(!inputIsNLO_) { // For each parton, starting with the hardest one ... for(unsigned int ixx=0; ixx=0) { jetToPartonMap[jetIndexForDRmin]=ixx; if(ixx==0||etjet_[jetIndexForDRmin]partonsToMatch_.size() && !inputIsNLO_) return true; if(inputIsNLO_) { if(!highestNLOMultiplicity_) { if(pjet_.size()>partonsToMatch_.size()-1) return true; } else { if(!highestMultiplicity_&&pjet_.size()>partonsToMatch_.size()) return true; } } // Veto events where matched jets are softer than non-matched ones, // in the inclusive (highestMultiplicity_ = true) mode, unless we // are dealing with NLO input events. if(highestMultiplicity_ && !inputIsNLO_ ) { for(unsigned int ixx=0; ixxid())==4||abs(partonsToMatch_[jxx]->id())==5)) continue; if(partonJetDeltaR(partonsToMatch_[jxx],pjet_[ixx])etmin) return true; } } } // Otherwise we accept the event ... return false; } /* Function that returns the R distance between a particle and a jet. */ double AlpGenHandler::partonJetDeltaR(ThePEG::tPPtr partonptr, LorentzMomentum jetmom) const { LorentzMomentum partonmom(partonptr->momentum()); // Calculate DY, DPhi and then DR double DY(partonmom.eta()-jetmom.eta()); double DPhi(partonmom.phi()-jetmom.phi()); if(DPhi>M_PI) DPhi=2*M_PI-DPhi; double DR(sqrt(sqr(DY)+sqr(DPhi))); return DR; } // Initialize calorimeter for calsim_m and getjet_m. Note that // because initialization is separte calsim_m can be called more // than once to simulate pileup of several events. void AlpGenHandler::calini_m() const { // Making sure arrays are clear before filling; cphcal_.clear(); sphcal_.clear(); cthcal_.clear(); sthcal_.clear(); // Fill array holding phi values of calorimeter cell centres. double deltaPhi(2*M_PI/ncphi_); for(unsigned int iphi=1; iphi<=ncphi_; iphi++) { double phi(deltaPhi*(iphi-0.5)); // Goes phi~=0 to phi~=2*pi (iphi=0--->ncphi). cphcal_.push_back(cos(phi)); // ==> goes from +1 ---> +1 (iphi=0--->ncphi). sphcal_.push_back(sin(phi)); // ==> goes 0 -> 1 -> 0 -> -1 -> 0 (iphi=0--->ncphi). } // Fill array holding theta values of calorimeter cell centres in Y. double deltaY((ycmax_-ycmin_)/double(ncy_)); for(unsigned int iy=1; iy<=ncy_; iy++) { double Y(deltaY*(iy-0.5)+ycmin_); double th(2*atan(exp(-Y))); // Goes bwds th~=pi to fwds th~=0 (iy=0--->ncy). cthcal_.push_back(cos(th)); // ==> goes from -1 ---> +1 (iy=0--->ncy). sthcal_.push_back(sin(th)); // ==> goes from 0 ---> +1 ---> 0 (iy=0--->ncy). } return; } // Get FastJets void AlpGenHandler::getFastJets(double rjet, Energy ejcut, double etajcut) const { vector particlesToCluster; for(unsigned int ipar=0; iparmomentum().eta()); if(y>=ycmin_&&y<=ycmax_) { int absId(abs(particlesToCluster_[ipar]->id())); // If it's not a lepton / top / photon it may go in the jet finder. if(!(absId>=11&&absId<=16) && absId!=6 && absId!=22) { // input particles into fastjet pseudojet fastjet::PseudoJet p(particlesToCluster_[ipar]->momentum().x()/GeV, particlesToCluster_[ipar]->momentum().y()/GeV, particlesToCluster_[ipar]->momentum().z()/GeV, particlesToCluster_[ipar]->momentum().e()/GeV); p.set_user_index(ipar); particlesToCluster.push_back(p); } } } fastjet::RecombinationScheme recombinationScheme = fastjet::E_scheme; fastjet::Strategy strategy = fastjet::Best; double R(rjet); fastjet::JetDefinition theJetDefinition; switch (jetAlgorithm_) { case -1: theJetDefinition=fastjet::JetDefinition(fastjet::antikt_algorithm, R, recombinationScheme, strategy); break; case 0: theJetDefinition=fastjet::JetDefinition(fastjet::cambridge_algorithm, R, recombinationScheme, strategy); break; case 1: theJetDefinition=fastjet::JetDefinition(fastjet::kt_algorithm, R, recombinationScheme, strategy); break; default: theJetDefinition=fastjet::JetDefinition(fastjet::cambridge_algorithm, R, recombinationScheme, strategy); break; } fastjet::ClusterSequence fastjetEvent(particlesToCluster,theJetDefinition); vector inclusiveJets = fastjetEvent.inclusive_jets(); inclusiveJets = fastjet::sorted_by_pt(inclusiveJets); // Fill the array of jet momenta for the rest of the veto procedure. pjet_.clear(); pjet_.resize(inclusiveJets.size()); etjet_.clear(); etjet_.resize(inclusiveJets.size()); for(unsigned int ffj=0; ffjetajcut) { pjet_.erase(pjet_.begin()+fj); etjet_.erase(etjet_.begin()+fj); fj--; } // Sort jets from high to low ET. vector > etjet_pjet; for(unsigned int ixx=0; ixxmomentum().eta()); if(y>=ycmin_&&y<=ycmax_) { int absId(abs(particlesToCluster_[ipar]->id())); // If it's not a lepton / top / photon it goes in the calorimeter. if(!(absId>=11&&absId<=16) && absId!=6 && absId!=22) { double phi(atan2(particlesToCluster_[ipar]->momentum().y()/GeV, particlesToCluster_[ipar]->momentum().x()/GeV)); if(phi<0) phi+=2*M_PI; unsigned int iy(int((y-ycmin_)/dely_)); unsigned int iphi(int(phi/delphi_)); et_[iy][iphi]+=particlesToCluster_[ipar]->momentum().e()*sthcal_[iy]; } } } return; } // Find highest remaining cell > etstop and sum surrounding cells // with -- delta(y)^2+delta(phi)^2 < Rjet^2 , ET>eccut. Keep sets // with ET>ejcut and abs(eta)=etstop) { // Find the cell with the highest ET from // those not already assigned to a jet. etmax=0*GeV; int iymx(0), iphimx(0); for(unsigned int iphi=0; iphietmax&&jetIdx_[iy][iphi]<0) { etmax = et_[iy][iphi]; iymx = iy; iphimx = iphi; } // If the remaining cell with the highest ET has ET < etstop, stop. if(etmax(ncy_*ncphi_)) { cout << "AlpGenHandler::getjet_m() - Fatal error." << endl; cout << "We found " << ipass << " calo cells with the highest ET so" << "far\nbut the calorimeter only has " << ncy_*ncphi_ << " " << "cells in it!" << endl; exit(10); } // Add a jet vector (may get deleted if jet fails ET / eta cuts). etjet_.push_back(0*GeV); pjet_.push_back(Lorentz5Momentum(0.*GeV,0.*GeV,0.*GeV,0.*GeV,0.*GeV)); // Loop over all calo cells in range iphimx +/- nphi1 (inclusive) // wrapping round in azimuth if required. for(unsigned int iphi1=0; iphi1<=2*nphi1; iphi1++) { int iphix(iphimx-nphi1+iphi1); if(iphix<0) iphix += ncphi_; if(iphix>=int(ncphi_)) iphix -= ncphi_; // Loop over all calo cells in range iymx +/- ny1 (inclusive). for(unsigned int iy1=0; iy1<=2*ny1; iy1++) { int iyx(iymx-ny1+iy1); // If the cell is outside the calorimeter OR if it was already // associated to a jet then skip to the next loop. if(iyx>=0&&iyx=eccut) { Energy ECell(et_[iyx][iphix]/sthcal_[iyx]); pjet_.back()+=LorentzMomentum(ECell*sthcal_[iyx]*cphcal_[iphix], // px ECell*sthcal_[iyx]*sphcal_[iphix], // py ECell*cthcal_[iyx],ECell); // pz, E. // N.B. This is the same reln as in ThePEG between phi and x,y. etjet_.back()+=et_[iyx][iphix]; jetIdx_[iyx][iphix] = pjet_.size()-1; // Identify cell with this jet. } } } } // Compute the current jet's mass. pjet_.back().rescaleMass(); // Throw the jet away if it's ET is less than ejcut. if(etjet_.back()etajcut) { pjet_.pop_back(); etjet_.pop_back(); } } // Sort jets from high to low ET. vector > etjet_pjet; for(unsigned int ixx=0; ixxchildren()); for (unsigned int ixx=0; ixxchildren().size()==0) tmpList_.push_back(theChildren[ixx]); else getDescendents(theChildren[ixx]); return; } void AlpGenHandler::caldel_m() const { preshowerFSPsToDelete_.clear(); showeredFSPsToDelete_.clear(); for(unsigned int ixx=0; ixxparents()[0]->id())==23|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==ihvy_&&ixx<2) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparents()[0]->id())==23|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparents()[0]->id())==23|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24|| abs(preshowerFSPs_[ixx]->id())==22|| abs(preshowerFSPs_[ixx]->id())==25) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparents()[0]->id())==6|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); } if(abs(preshowerFSPs_[ixx]->parents()[0]->id())==6) { getDescendents(preshowerFSPs_[ixx]->parents()[0]); for(unsigned int jxx=0; jxxid())==ihvy_&&ixx<2) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==4&&ixx<1)|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==25) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| (abs(preshowerFSPs_[ixx]->id())==ihvy_&&ixx==(preshowerFSPs_.size()-(2+nph_+1)))|| (abs(preshowerFSPs_[ixx]->id())==ihvy_&&ixx==(preshowerFSPs_.size()-(2+nph_+2)))|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==6|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| (abs(preshowerFSPs_[ixx]->id())==ihvy_&&ixx<2)) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparticlesToCluster_.size()) { throw Exception() << "AlpGenHandler::caldel_m() - ERROR!\n" << "No. of ME level partons to be matched to jets = " << partonsToMatch_.size() << "\n" << "No. of showered particles to build jets from = " << particlesToCluster_.size() << "\n" << "There should be at least as many partons to\n" << "cluster as there are partons to match to.\n" << Exception::eventerror; } // Acid test. unsigned int tmpUnsignedInt(njets_); if(!inputIsNLO_&&partonsToMatch_.size()!=tmpUnsignedInt) { for(unsigned int ixx=0; ixxid())>=6&& abs(partonsToMatch_[ixx]->id())!=21) throw Exception() << "AlpGenHandler::caldel_m() - ERROR!\n" << "Found a parton to match to which is not a quark or gluon!" << *partonsToMatch_[ixx] << "\n" << Exception::eventerror; } throw Exception() << "AlpGenHandler::caldel_m() - ERROR!\n" << "No. of ME level partons to be matched to jets = " << partonsToMatch_.size() << "\n" << "No. of light jets (njets) in AlpGen process = " << njets_ << "\n" << "These should be equal." << "\n" << Exception::eventerror; } return; } // This looks for all descendents of a top up to but not including // the W and b children. void AlpGenHandler::getTopRadiation(PPtr theParticle) const { ParticleVector theChildren(theParticle->children()); for (unsigned int ixx=0; ixxchildren().size()==0) tmpList_.push_back(theChildren[ixx]); else if(abs(theChildren[ixx]->id())==5||abs(theChildren[ixx]->id())==24) return; else getTopRadiation(theChildren[ixx]); return; } void AlpGenHandler::caldel_hvq() const { // Fill partonsToMatch_ with only those pre-shower partons intended to // be used in heavy-quark-jet matching and fill particlesToCluster_ using // only those final state particles (post-shower) which are supposed // in the heavy-quark-jet clustering used to do merging. To begin with // these are made from the corresponding sets of particles that were // omitted from the initial jet-parton matching run. partonsToMatch_ = preshowerFSPsToDelete_; particlesToCluster_.resize(showeredFSPsToDelete_.size()); for(unsigned int ixx=0; ixxid())<4||abs(partonsToMatch_[ixx]->id())>6) { preshowerFSPsToDelete_.push_back(partonsToMatch_[ixx]); tmpList_.clear(); getDescendents(partonsToMatch_[ixx]); for(unsigned int jxx=0; jxxid())==5&& partonsToMatch_[ixx]->parents().size()>0&& abs(partonsToMatch_[ixx]->parents()[0]->id())==6) { preshowerFSPsToDelete_.push_back(partonsToMatch_[ixx]); tmpList_.clear(); getDescendents(partonsToMatch_[ixx]); for(unsigned int jxx=0; jxxparents().size()>0&& (abs(partonsToMatch_[ixx]->parents()[0]->id())==23|| abs(partonsToMatch_[ixx]->parents()[0]->id())==24|| abs(partonsToMatch_[ixx]->parents()[0]->id())==25)) { preshowerFSPsToDelete_.push_back(partonsToMatch_[ixx]); tmpList_.clear(); getDescendents(partonsToMatch_[ixx]); for(unsigned int jxx=0; jxxsubProcess()->intermediates()); for(unsigned int ixx=0; ixxid())==6) { partonsToMatch_.push_back(intermediates[ixx]); tmpList_.clear(); getTopRadiation(partonsToMatch_.back()); for(unsigned int jxx=0; jxxid())>=4&&abs(partonsToMatch_[ixx]->id())<=6) { theProgenitor = partonsToMatch_[ixx]; // Follow the heavy quark line down to where it stops branching. while(theProgenitor->children().size()>0) { theLastProgenitor = theProgenitor; for(unsigned int jxx=0; jxxchildren().size(); jxx++) { if(theProgenitor->children()[jxx]->id()==theProgenitor->id()) theProgenitor=theProgenitor->children()[jxx]; } // If the progenitor had children but none of them had // the same particle id as it, then it must have undergone // a decay rather than a branching, i.e. it is the end of // the evolution line, so, if(theProgenitor==theLastProgenitor) break; } evolvedHeavyQuarks.push_back(theProgenitor); } } // Now delete the evolved heavy quark from the particlesToCluster. for(unsigned int ixx=0; ixxsubProcess()->incoming(); // LH file final-state partICLEs: preshowerFSPs_ = lastXCombPtr()->subProcess()->outgoing(); return; } void AlpGenHandler::getShoweredParticles() const { // Post-shower initial-state hadrons: showeredISHs_ = eventHandler()->currentEvent()->incoming(); // Post-shower initial-state partons: for(unsigned int ixx=0; ixx<(showeredISHs_.first)->children().size(); ixx++) if(((showeredISHs_.first)->children()[ixx]->id())<6|| ((showeredISHs_.first)->children()[ixx]->id())==21) showeredISPs_.first=(showeredISHs_.first)->children()[ixx]; for(unsigned int ixx=0; ixx<(showeredISHs_.second)->children().size(); ixx++) if(((showeredISHs_.second)->children()[ixx]->id())<6|| ((showeredISHs_.second)->children()[ixx]->id())==21) showeredISPs_.second=(showeredISHs_.second)->children()[ixx]; // Post-shower final-state partICLEs plus remnants (to be removed later): showeredFSPs_ = eventHandler()->currentEvent()->getFinalState(); // Post-shower final-state remnants: for(unsigned int ixx=0; ixxPDGName()=="Rem:p+"|| showeredFSPs_[ixx]->PDGName()=="Rem:pbar-") { if(showeredFSPs_[ixx]->parents()[0]->parents()[0]== showeredISHs_.first) showeredRems_.first=showeredFSPs_[ixx]; else if(showeredFSPs_[ixx]->parents()[0]->parents()[0]== showeredISHs_.second) showeredRems_.second=showeredFSPs_[ixx]; } } // Now delete found remnants from the showeredFSPs vector for consistency. for(unsigned int ixx=0; ixxPDGName()=="Rem:p+") showeredFSPs_.erase(showeredFSPs_.begin()+ixx); for(unsigned int ixx=0; ixxPDGName()=="Rem:pbar-") showeredFSPs_.erase(showeredFSPs_.begin()+ixx); sort(showeredFSPs_.begin(),showeredFSPs_.end(),recordEntry); return; } void AlpGenHandler::doSanityChecks(int debugLevel) const { // When checking momentum conservation in the form // p_in - p_out, any momentum component bigger / less // than + / - epsilon will result in the p_in - p_out // vector being flagged as "non-null", triggering a // warning that momentum conservation is violated. Energy epsilon(0.5*GeV); if(debugLevel>=5) epsilon=1e-9*GeV; // Print out what was found for the incoming and outgoing // partons in the lastXCombPtr regardless. if(debugLevel>=5) { cout << "\n\n\n\n"; cout << "****************************************************" << endl; cout << " The following are the hard subprocess momenta from " << "\n" << " lastXCombPtr and should be basically identical to " << "\n" << " the input LH file momenta." << "\n\n"; cout << " Incoming particles:" << "\n" << *(preshowerISPs_.first) << "\n" << *(preshowerISPs_.second) << endl; cout << " Outgoing particles:" << endl; for(unsigned int ixx=0; ixx=5) { cout << "\n\n"; cout << "****************************************************" << endl; cout << " The following are the particles left at the end of" << "\n" << " the showering step." << "\n\n"; cout << " Incoming hadrons:" << "\n" << *(showeredISHs_.first) << "\n" << *(showeredISHs_.second) << endl; cout << " Incoming partons:" << "\n" << *(showeredISPs_.first) << "\n" << *(showeredISPs_.second) << endl; cout << " Outgoing partons:" << endl; for(unsigned int ixx=0; ixx=4) { Lorentz5Momentum tmpMom; tmpMom += showeredISPs_.first->momentum(); tmpMom += showeredISPs_.second->momentum(); for(unsigned int ixx=0; ixxmomentum(); if(!isMomLessThanEpsilon(tmpMom,epsilon)) cout << "Total parton mom.in - total parton mom.out = " << tmpMom/GeV << endl; tmpMom = showeredISHs_.first->momentum() - showeredRems_.first->momentum() -showeredISPs_.first->momentum(); if(!isMomLessThanEpsilon(tmpMom,epsilon)) cout << "First p_hadron-p_remnant-p_incoming " << tmpMom/GeV << endl; tmpMom = showeredISHs_.second->momentum() - showeredRems_.second->momentum()-showeredISPs_.second->momentum(); if(!isMomLessThanEpsilon(tmpMom,epsilon)) cout << "Second p_hadron-p_remnant-p_incoming " << tmpMom/GeV << endl; } // Check if what we found to be the remnant is consistent with // what we identified as the parent incoming hadron i.e. p+ // goes with Rem:p+ and pbar- goes with Rem:pbar-. if(debugLevel>=0) { string tmpString; tmpString=showeredRems_.first->PDGName(); tmpString=tmpString.substr(tmpString.find_first_of(":")+1, string::npos); if(showeredISHs_.first->PDGName()!=tmpString) { cout << "AlpGenHandler::showerHardProcessVeto" << "\n" << "Fatal error in pairing of remnant and parent hadron." << "\n" << "Remnant = " << *(showeredRems_.first) << "\n" << "Parent hadron = " << *(showeredISHs_.first) << endl; cout << showeredISHs_.first->PDGName() << endl; cout << tmpString << endl; } tmpString=showeredRems_.second->PDGName(); tmpString=tmpString.substr(tmpString.find_first_of(":")+1, string::npos); if(showeredISHs_.second->PDGName()!=tmpString) { cout << "AlpGenHandler::showerHardProcessVeto" << "\n" << "Fatal error in pairing of remnant and parent hadron." << "\n" << "Remnant = " << *(showeredRems_.second) << "\n" << "Parent hadron = " << *(showeredISHs_.second) << endl; cout << showeredISHs_.second->PDGName() << endl; cout << tmpString << endl; } } return; } void AlpGenHandler::printMomVec(vector momVec) { cout << "\n\n"; // Label columns. printf("%5s %9s %9s %9s %9s %9s %9s %9s %9s %9s\n", "jet #", "px","py","pz","E", "eta","phi","pt","et","mass"); // Print out the details for each jet for (unsigned int ixx=0; ixx #include "ThePEG/Utilities/Throw.h" -#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "fastjet/PseudoJet.hh" #include "fastjet/ClusterSequence.hh" #include "gsl/gsl_rng.h" #include "gsl/gsl_randist.h" #include using namespace Herwig; using namespace ThePEG; bool recordEntry(PPtr i,PPtr j) { return (i->number()number()); } bool pTsortFunction(PPtr i,PPtr j) { return (i->momentum().perp2()>j->momentum().perp2()); } bool ETsortFunction(pair i,pair j) { return (i.first>j.first); } bool isMomLessThanEpsilon(Lorentz5Momentum p,Energy epsilon) { return (abs(p.x())> alphaS_ >> ncy_ >> ncphi_ >> ihvy_ >> nph_ >> nh_ >> iunit(etclusmean_,GeV) >> rclus_ >> etaclmax_ >> rclusfactor_ >> ihrd_ >> njets_ >> drjmin_ >> highestMultiplicity_ >> ycmax_ >> ycmin_ >> jetAlgorithm_ >> vetoIsTurnedOff_ >> vetoSoftThanMatched_ >> etclusfixed_ >> cphcal_ >> sphcal_ >> cthcal_ >> sthcal_ >> iunit(epsetclus_,GeV) >> vetoHeavyQ_ >> mergemode_ >> hpdetect_ >> vetoHeavyFlavour_; } ClassDescription FxFxHandler::initFxFxHandler; // Definition of the static class description member. void FxFxHandler::Init() { static ClassDocumentation documentation ("The FxFxHandler class performs MEPS merging " "using the MLM procedure."); static Reference interfaceShowerAlpha ("ShowerAlpha", "The object calculating the strong coupling constant", &FxFxHandler::alphaS_, false, false, true, false, false); static Parameter interfaceihvy ("ihvy", "heavy flavour in WQQ,ZQQ,2Q etc (4=c, 5=b, 6=t)", &FxFxHandler::ihvy_, -999, -999, 7, false, false, Interface::limited); static Parameter interfacenph ("nph", "Number of photons in the AlpGen process", &FxFxHandler::nph_, -999, -999, 7, false, false, Interface::limited); static Parameter interfacenh ("nh", "Number of higgses in the AlpGen process", &FxFxHandler::nph_, -999, -999, 7, false, false, Interface::limited); static Parameter interfaceETClus ("ETClus", "The ET threshold defining a jet in the merging procedure", &FxFxHandler::etclusmean_, GeV, 20*GeV, 0*GeV, 14000*GeV, false, false, Interface::limited); static Parameter interfaceRClus ("RClus", "The cone size used to define a jet in the merging procedure", &FxFxHandler::rclus_, 0.4, 0.0, 4.0, false, false, Interface::limited); static Parameter interfaceEtaClusMax ("EtaClusMax", "The maximum |eta| used to define a jet in the merging procedure", &FxFxHandler::etaclmax_, 5.0, 0.0, 15.0, false, false, Interface::limited); static Parameter interfaceRClusFactor ("RClusFactor", "The prefactor for RClus used to define the jet-parton matching " "distance", &FxFxHandler::rclusfactor_, 1.5, 0.0, 4.0, false, false, Interface::limited); static Parameter interfaceihrd ("ihrd", "The hard process code", &FxFxHandler::ihrd_, -999, 0, 10000, false, false, Interface::limited); static Parameter interfacenjetsmax ("njetsmax", "The number of light jets in the maximum-multiplicity process", &FxFxHandler::njets_, -999, 0, 10000, false, false, Interface::limited); static Parameter interfacedrjmin ("drjmin", "Mimimum parton-parton R-sep used for generation.", &FxFxHandler::drjmin_, 0.7, 0.0, 4.0, false, false, Interface::limited); static Parameter interfacehighestMultiplicity ("highestMultiplicity", "If true it indicates that this is the highest multiplicity input " "ME-level configuration to be processed.", &FxFxHandler::highestMultiplicity_, 0, 0, 1, false, false, Interface::limited); static Parameter interfaceETClusFixed ("ETClusFixed", "If false, indicates that the jet merging scale, etclus_ is allowed to vary" "according to epsetclus_", &FxFxHandler::etclusfixed_, 1, 0, 1, false, false, Interface::limited); static Parameter interfaceEpsilonETClus ("EpsilonETClus", "The ET threshold defining a jet in the merging procedure", &FxFxHandler::epsetclus_, GeV, 2.5*GeV, 0*GeV, 100.0*GeV, false, false, Interface::limited); static Switch interfaceJetAlgorithm ("JetAlgorithm", "Determines the jet algorithm for finding jets in parton-jet " "matching in the MLM procedure.", &FxFxHandler::jetAlgorithm_, 1, false, false); static SwitchOption AntiKt (interfaceJetAlgorithm, "AntiKt", "The anti-kt jet algorithm.", -1); static SwitchOption CambridgeAachen (interfaceJetAlgorithm, "CambridgeAachen", "The Cambridge-Aachen jet algorithm.", 0); static SwitchOption Kt (interfaceJetAlgorithm, "Kt", "The Kt jet algorithm.", 1); static Switch interfaceMergeMode ("MergeMode", "The choice of merging mode", &FxFxHandler::mergemode_, 0, false, false); static SwitchOption FxFx (interfaceMergeMode, "FxFx", "FxFx merging.", 0); static SwitchOption Tree (interfaceMergeMode, "Tree", "Tree-level merging.", 1); static SwitchOption TreeMG (interfaceMergeMode, "TreeMG5", "Tree-level merging using the MadGraph pt clustering information.", 2); static Switch interfaceHardProcessDetection ("HardProcessDetection", "The choice of merging mode", &FxFxHandler::hpdetect_, true, false, false); static SwitchOption Automatic (interfaceHardProcessDetection, "Automatic", "Automatically determine which particles to include in the merging.", true); static SwitchOption Manual (interfaceHardProcessDetection, "Manual", "Use the ihrd code to determine which particles to include in the merging.", false); static Switch interfaceVetoIsTurnedOff ("VetoIsTurnedOff", "Allows the vetoing mechanism to be switched off.", &FxFxHandler::vetoIsTurnedOff_, false, false, false); static SwitchOption VetoingIsOn (interfaceVetoIsTurnedOff, "VetoingIsOn", "The MLM merging veto mechanism is switched ON.", false); static SwitchOption VetoingIsOff (interfaceVetoIsTurnedOff, "VetoingIsOff", "The MLM merging veto mechanism is switched OFF.", true); static Switch interfaceVetoHeavyFlavour ("VetoHeavyFlavour", "Allows the heavy flavour vetoing mechanism to be switched off.", &FxFxHandler::vetoHeavyFlavour_, false, false, false); static SwitchOption HeavyFVetoingIsOn (interfaceVetoHeavyFlavour, "Yes", "The MLM merging veto mechanism for heavy flavour is switched ON.", true); static SwitchOption HeavyFVetoingIsOff (interfaceVetoHeavyFlavour, "No", "The MLM merging veto mechanism for heavy flavour is switched OFF.", false); static Switch interfaceHeavyQVeto ("HeavyQVeto", "Allows the vetoing mechanism on the heavy quark products to be switched off.", &FxFxHandler::vetoHeavyQ_, false, false, false); static SwitchOption HQVetoingIsOn (interfaceHeavyQVeto, "Yes", "The MLM merging veto on Heavy quark decay produts mechanism is switched ON.", true); static SwitchOption HQVetoingIsOff (interfaceHeavyQVeto, "No", "The MLM merging veto on Heavy quark decay products mechanism is switched OFF.", false); static Switch interfaceVetoSoftThanMatched ("VetoSoftThanMatched", "Allows the vetoing mechanism to be switched off.", &FxFxHandler::vetoSoftThanMatched_, false, false, false); static SwitchOption VetoSoftIsOn (interfaceVetoSoftThanMatched, "VetoSoftIsOn", "The vetoing of highest-mult. events with jets softer than matched ones is ON", true); static SwitchOption VetoSoftIsOff (interfaceVetoSoftThanMatched, "VetoSoftIsOff", "The vetoing of highest-mult. events with jets softer than matched ones is OFF.", false); } void FxFxHandler::dofinish() { QTildeShowerHandler::dofinish(); } void FxFxHandler::doinit() { //print error if HardProcID is not set in input file if(ihrd_ == -999 && !hpdetect_) { cout << "Error: FxFxHandler:ihrd not set and FxFx:HardProcessDetection set to Manual!" << endl; exit(1); } QTildeShowerHandler::doinit(); // Compute calorimeter edges in rapidity for GetJet algorithm. ycmax_=etaclmax_+rclus_; ycmin_=-ycmax_; } // Throws a veto according to MLM strategy ... when we finish writing it. bool FxFxHandler::showerHardProcessVeto() const { int debug_mode = 0; if(vetoIsTurnedOff_) { // cout << "Vetoing is turned OFF." << endl; return false; } //if(debug_mode) { cout << "debug_mode = " << 5 << endl; } // Skip veto for processes in which merging is not implemented: if(ihrd_==7||ihrd_==8||ihrd_==13) { ostringstream wstring; wstring << "FxFxHandler::showerHardProcessVeto() - warning." << "MLM merging not implemented " << "processes 4Q (ihrd=7), QQh (ihrd=8), " << "(single) top (ihrd=13) \n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); return false; } // Fill preshowerISPs_ pair and preshowerFSPs_ particle pointer vector. getPreshowerParticles(); // Fill showeredISHs_, showeredISPs and showeredRems pairs, as well as // showeredFSPs_ particle pointer vector. getShoweredParticles(); // Turn on some screen output debugging: 0 = none ---> 5 = very verbose. doSanityChecks(debug_mode); // Dimensions of each calorimter cell in y and phi. dely_ = (ycmax_-ycmin_)/double(ncy_); delphi_ = 2*M_PI/double(ncphi_); // Fill partonsToMatch_ with only those pre-shower partons intended to // used in jet-parton matching and fill particlesToCluster_ using only // those final state particles (post-shower) which are supposed to go // in the jet clustering used to do merging. partonsToMatch_ = preshowerFSPs_; particlesToCluster_ = showeredFSPs_ ; // Filter out all but the 'extra' light-parton progenitors and their // associated final state particles. if(mergemode_ == 0 || mergemode_ == 1) { caldel_m(); } else if(mergemode_ == 2) { caldel_mg(); } double prob(1); //if etclusfixed_ then set the etclus_ to the fixed chosen value if(etclusfixed_) { etclus_ = etclusmean_; } else { //else, if we wish to vary etclus_, we use the probability distribution //choose a probability between 0 and 1 prob = rnd(); etclus_ = etclusran_(prob); } // Cluster particlesToCluster_ into jets with FastJet. getFastJets(rclus_,etclus_,etaclmax_); if(mergemode_ == 0) { // Get npLO_ and npNLO_ for FxFx matching getnpFxFx(); // print the npXLO_ values obtained // cout << "HANDLER:\t\t\t\t" << npLO_ << "\t\t" << npNLO_ << endl; //FxFx modifications start here. // Sort partonsToMatch_ from high to low pT. sort(partonsToMatch_.begin(),partonsToMatch_.end(),pTsortFunction); // Count the number of jets. int njets_found(pjet_.size()); // If the number of jets found is not equal to the number of partons in the Born // (i.e., the number of partons in the S-event, or one less than the number of partons in an H-event), // the jets cannot be matched and the event has to be rejected. The number of partons in the Born is written in the event file with a name “npNLO” // if there are no jets to match and no jets have been found, do not veto. if(njets_found == 0 && npNLO_ == 0) { /*cout << "njets_found = " << njets_found << " and npNLO = " << npNLO_ << ", accepting" << endl;*/ return false; } //if the number of jets is smaller than npNLO -> reject the event. if(njets_found < npNLO_) { /*cout << "njets_found = " << njets_found << " and npNLO = " << npNLO_ << ", rejecting" << endl;*/ return true; } // For the maximum-multiplicity sample, the number of jets obtained does not have to be exactly equal to npNLO, it may also be larger; if(njets_found > npNLO_ && npNLO_ != njets_) { /*cout << "njets_found = " << njets_found << " and npNLO = " << npNLO_ << ", rejecting" << endl;*/ return true; } // Create the matrix-element jets. // Cluster also the partons at the hard-matrix element level into jets with the same algorithm as above, // but without the requirement of a minimal pT on the jets (or set it very small). // By construction, for S-events you should find exactly npNLO jets, while for the H-events it is either npNLO or npNLO+1. // Cluster partonsToMatch_ into jets with FastJet. getFastJetsToMatch(rclus_,0*GeV,etaclmax_); int me_njets_found(pjetME_.size()); // cout << "number of ME jets found = " << me_njets_found << "partons to match: " << partonsToMatch_.size() << endl; // Match light progenitors to jets. vector jetToPartonMap(pjetME_.size(),-999); Energy etmin(777e100*GeV); // Match the jets. // Try to match the “npNLO” hardest jets created post-shower with any of the jets pre-shower. Two jets are matched if the distance between them is smaller than 1.5*DeltaR. // If not all the npNLO hardest shower jets are matched the event has to be rejected. // Note that if the current event does not belong to the maximum multiplicity sample, this means that all the shower jets need to be matched, because the requirement above already rejects // events that do not have npNLO shower jets. // For those events, at the level of the matrix elements there can either be npNLO or npNLO+1 matrix-element jets, depending on S- or H-events and the kinematics of those partons. // Still only the shower jets need to be matched, so an event should not be rejected if a matrix-element jet cannot be matched. // For each parton, starting with the hardest one ... for(unsigned int ixx=0; ixx=0) { jetToPartonMap[jetIndexForDRmin]=ixx; if(ixx==0||etjet_[jetIndexForDRmin]id())==4||abs(partonsToMatch_[jxx]->id())==5)) continue; if(partonJetDeltaR(partonsToMatch_[jxx],pjet_[ixx])id())==4||abs(partonsToMatch_[jxx]->id())==5)) continue; if(partonJetDeltaR(partonsToMatch_[jxx],pjet_[ixx])etmin) return true; } } } } // Otherwise we accept the event ... return false; } /* Function that returns the R distance between a particle and a jet. */ double FxFxHandler::partonJetDeltaR(ThePEG::tPPtr partonptr, LorentzMomentum jetmom) const { LorentzMomentum partonmom(partonptr->momentum()); // Calculate DY, DPhi and then DR double DY(partonmom.eta()-jetmom.eta()); double DPhi(partonmom.phi()-jetmom.phi()); if(DPhi>M_PI) DPhi=2*M_PI-DPhi; double DR(sqrt(sqr(DY)+sqr(DPhi))); return DR; } double FxFxHandler::partonJetDeltaR(LorentzMomentum jetmom1, LorentzMomentum jetmom2) const { // Calculate DY, DPhi and then DR double DY(jetmom1.eta()-jetmom2.eta()); double DPhi(jetmom1.phi()-jetmom2.phi()); if(DPhi>M_PI) DPhi=2*M_PI-DPhi; double DR(sqrt(sqr(DY)+sqr(DPhi))); return DR; } // Get FastJets void FxFxHandler::getFastJets(double rjet, Energy ejcut, double etajcut) const { vector particlesToCluster; for(unsigned int ipar=0; iparmomentum().eta()); if(y>=ycmin_&&y<=ycmax_) { int absId(abs(particlesToCluster_[ipar]->id())); // If it's not a lepton / top / photon it may go in the jet finder. if(!(absId>=11&&absId<=16) && absId!=6 && absId!=22) { // input particles into fastjet pseudojet fastjet::PseudoJet p(particlesToCluster_[ipar]->momentum().x()/GeV, particlesToCluster_[ipar]->momentum().y()/GeV, particlesToCluster_[ipar]->momentum().z()/GeV, particlesToCluster_[ipar]->momentum().e()/GeV); p.set_user_index(ipar); particlesToCluster.push_back(p); } } } fastjet::RecombinationScheme recombinationScheme = fastjet::E_scheme; fastjet::Strategy strategy = fastjet::Best; double R(rjet); fastjet::JetDefinition theJetDefinition; switch (jetAlgorithm_) { case -1: theJetDefinition=fastjet::JetDefinition(fastjet::antikt_algorithm, R, recombinationScheme, strategy); break; case 0: theJetDefinition=fastjet::JetDefinition(fastjet::cambridge_algorithm, R, recombinationScheme, strategy); break; case 1: theJetDefinition=fastjet::JetDefinition(fastjet::kt_algorithm, R, recombinationScheme, strategy); break; default: theJetDefinition=fastjet::JetDefinition(fastjet::cambridge_algorithm, R, recombinationScheme, strategy); break; } fastjet::ClusterSequence fastjetEvent(particlesToCluster,theJetDefinition); vector inclusiveJets = fastjetEvent.inclusive_jets(); inclusiveJets = fastjet::sorted_by_pt(inclusiveJets); // Fill the array of jet momenta for the rest of the veto procedure. pjet_.clear(); pjet_.resize(inclusiveJets.size()); etjet_.clear(); etjet_.resize(inclusiveJets.size()); for(unsigned int ffj=0; ffjetajcut) { pjet_.erase(pjet_.begin()+fj); etjet_.erase(etjet_.begin()+fj); fj--; } // Sort jets from high to low ET. vector > etjet_pjet; for(unsigned int ixx=0; ixx particlesToCluster; for(unsigned int ipar=0; iparmomentum().eta()); if(y>=ycmin_&&y<=ycmax_) { int absId(abs(partonsToMatch_[ipar]->id())); // If it's not a lepton / top / photon it may go in the jet finder. if(!(absId>=11&&absId<=16) && absId!=6 && absId!=22) { // input particles into fastjet pseudojet fastjet::PseudoJet p(partonsToMatch_[ipar]->momentum().x()/GeV, partonsToMatch_[ipar]->momentum().y()/GeV, partonsToMatch_[ipar]->momentum().z()/GeV, partonsToMatch_[ipar]->momentum().e()/GeV); p.set_user_index(ipar); particlesToCluster.push_back(p); } } } fastjet::RecombinationScheme recombinationScheme = fastjet::E_scheme; fastjet::Strategy strategy = fastjet::Best; double R(rjet); fastjet::JetDefinition theJetDefinition; switch (jetAlgorithm_) { case -1: theJetDefinition=fastjet::JetDefinition(fastjet::antikt_algorithm, R, recombinationScheme, strategy); break; case 0: theJetDefinition=fastjet::JetDefinition(fastjet::cambridge_algorithm, R, recombinationScheme, strategy); break; case 1: theJetDefinition=fastjet::JetDefinition(fastjet::kt_algorithm, R, recombinationScheme, strategy); break; default: theJetDefinition=fastjet::JetDefinition(fastjet::cambridge_algorithm, R, recombinationScheme, strategy); break; } fastjet::ClusterSequence fastjetEvent(particlesToCluster,theJetDefinition); vector inclusiveJets = fastjetEvent.inclusive_jets(); inclusiveJets = fastjet::sorted_by_pt(inclusiveJets); // Fill the array of jet momenta for the rest of the veto procedure. pjetME_.clear(); pjetME_.resize(inclusiveJets.size()); for(unsigned int ffj=0; ffjchildren()); for (unsigned int ixx=0; ixxchildren().size()==0) tmpList_.push_back(theChildren[ixx]); else getDescendents(theChildren[ixx]); return; } void FxFxHandler::caldel_m() const { preshowerFSPsToDelete_.clear(); showeredFSPsToDelete_.clear(); hvqfound = false; if(hpdetect_ && mergemode_!=2) { for(unsigned int ixx=0; ixxparents()[0]->id())==6) { hvqfound = true; // cout << "preshowerFSPs_[ixx]->id() = " << preshowerFSPs_[ixx]->id() << " " << preshowerFSPs_[ixx]->momentum().perp2() << endl; preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]->parents()[0]); for(unsigned int jxx=0; jxxid() = " << tmpList_[jxx]->id() << " " << tmpList_[jxx]->momentum().perp2() << endl; showeredFSPsToDelete_.push_back(tmpList_[jxx]); } continue; } /* Exclude the v.bosons and any children they may have produced from the jet parton matching. */ if( (abs(preshowerFSPs_[ixx]->parents()[0]->id())==23|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24|| abs(preshowerFSPs_[ixx]->id())==22|| abs(preshowerFSPs_[ixx]->id())==25|| (abs(preshowerFSPs_[ixx]->id()) < 17 && abs(preshowerFSPs_[ixx]->id()) > 10)) && (abs(preshowerFSPs_[ixx]->parents()[0]->id())!=6)) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==5&&ixx<2) { hvqfound = true; preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparents()[0]->id())==23|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==ihvy_&&ixx<2) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparents()[0]->id())==23|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparents()[0]->id())==23|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24|| abs(preshowerFSPs_[ixx]->id())==22|| abs(preshowerFSPs_[ixx]->id())==25) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparents()[0]->id())==6|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { // cout << "preshowerFSPs_[ixx]->id() = " << preshowerFSPs_[ixx]->id() << " " << preshowerFSPs_[ixx]->momentum().perp2() << endl; preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); } if(abs(preshowerFSPs_[ixx]->parents()[0]->id())==6) { getDescendents(preshowerFSPs_[ixx]->parents()[0]); for(unsigned int jxx=0; jxxid() = " << tmpList_[jxx]->id() << " " << tmpList_[jxx]->momentum().perp2() << endl; showeredFSPsToDelete_.push_back(tmpList_[jxx]); } } if(ixx==preshowerFSPs_.size()-1&&preshowerFSPsToDelete_.size()!=6) { throw Exception() << "FxFxHandler::caldel_m() - ERROR!\n" << "2Q process should have 6 particles to omit from" << "jet-parton matching for ihvy=" << ihvy_ << "." << Exception::eventerror; } } else { if(abs(preshowerFSPs_[ixx]->id())==ihvy_&&ixx<2) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==4&&ixx<1)|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==25) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| (abs(preshowerFSPs_[ixx]->id())==ihvy_&&ixx==(preshowerFSPs_.size()-(2+nph_+1)))|| (abs(preshowerFSPs_[ixx]->id())==ihvy_&&ixx==(preshowerFSPs_.size()-(2+nph_+2)))|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==6|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| (abs(preshowerFSPs_[ixx]->id())==ihvy_&&ixx<2)) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid() << " with parent " << preshowerFSPsToDelete_[ixx]->parents()[0]->id() << endl; // " energy = " << preshowerFSPsToDelete_[ixx]->momentum().e()*GeV << endl; partonsToMatch_.erase(partonsToMatch_.begin()+jxx); break; } } } //cout << "partonsToMatch_.size() (AFTER) = " << partonsToMatch_.size() << endl; //cout << "deleting showeredFSPs" << endl; for(unsigned int ixx=0; ixxid() << " with parent " << showeredFSPsToDelete_[ixx]->parents()[0]->id() << endl; //" energy = " << preshowerFSPsToDelete_[ixx]->momentum().e()*GeV << endl; particlesToCluster_.erase(particlesToCluster_.begin()+jxx); break; } } } // Sanity check! if(partonsToMatch_.size()>particlesToCluster_.size()) { throw Exception() << "FxFxHandler::caldel_m() - ERROR!\n" << "No. of ME level partons to be matched to jets = " << partonsToMatch_.size() << "\n" << "No. of showered particles to build jets from = " << particlesToCluster_.size() << "\n" << "There should be at least as many partons to\n" << "cluster as there are partons to match to.\n" << Exception::eventerror; } // cout << "partonsToMatch_.size() (AFTER2) = " << partonsToMatch_.size() << endl; // Acid test. /* unsigned int tmpUnsignedInt(njets_); if(!inputIsNLO_&&partonsToMatch_.size()!=tmpUnsignedInt) { for(unsigned int ixx=0; ixxid())>=6&& abs(partonsToMatch_[ixx]->id())!=21) throw Exception() << "FxFxHandler::caldel_m() - ERROR!\n" << "Found a parton to match to which is not a quark or gluon!" << *partonsToMatch_[ixx] << "\n" << Exception::eventerror; } throw Exception() << "FxFxHandler::caldel_m() - ERROR!\n" << "No. of ME level partons to be matched to jets = " << partonsToMatch_.size() << "\n" << "No. of light jets (njets) in AlpGen process = " << njets_ << "\n" << "These should be equal." << "\n" << Exception::eventerror; } */ //cout << "partonsToMatch_.size() (AFTER3) = " << partonsToMatch_.size() << endl; return; } // This looks for all descendents of a top up to but not including // the W and b children. void FxFxHandler::getTopRadiation(PPtr theParticle) const { ParticleVector theChildren(theParticle->children()); for (unsigned int ixx=0; ixxchildren().size()==0) tmpList_.push_back(theChildren[ixx]); else if(abs(theChildren[ixx]->id())==5||abs(theChildren[ixx]->id())==24) return; else getTopRadiation(theChildren[ixx]); return; } void FxFxHandler::caldel_mg() const { preshowerFSPsToDelete_.clear(); showeredFSPsToDelete_.clear(); /* * Get the MadGraph clustering information * from the Les Houches event tags */ ptclust_.clear(); getptclust(); //for(unsigned int izz = 0; izzid() << endl; partonsToMatch_.erase(partonsToMatch_.begin()+jxx); break; } } } for(unsigned int ixx=0; ixxid() << " with parent " << showeredFSPsToDelete_[ixx]->parents()[0]->id() << endl; //" energy = " << preshowerFSPsToDelete_[ixx]->momentum().e()*GeV << endl; particlesToCluster_.erase(particlesToCluster_.begin()+jxx); break; } } } // Sanity check! if(partonsToMatch_.size()>particlesToCluster_.size()) { throw Exception() << "FxFxHandler::caldel_m() - ERROR!\n" << "No. of ME level partons to be matched to jets = " << partonsToMatch_.size() << "\n" << "No. of showered particles to build jets from = " << particlesToCluster_.size() << "\n" << "There should be at least as many partons to\n" << "cluster as there are partons to match to.\n" << Exception::eventerror; } } void FxFxHandler::caldel_hvq() const { // Fill partonsToMatch_ with only those pre-shower partons intended to // be used in heavy-quark-jet matching and fill particlesToCluster_ using // only those final state particles (post-shower) which are supposed // in the heavy-quark-jet clustering used to do merging. To begin with // these are made from the corresponding sets of particles that were // omitted from the initial jet-parton matching run. partonsToMatch_ = preshowerFSPsToDelete_; particlesToCluster_.resize(showeredFSPsToDelete_.size()); for(unsigned int ixx=0; ixxid())<4||abs(partonsToMatch_[ixx]->id())>6) { preshowerFSPsToDelete_.push_back(partonsToMatch_[ixx]); tmpList_.clear(); getDescendents(partonsToMatch_[ixx]); for(unsigned int jxx=0; jxxid())==5&& partonsToMatch_[ixx]->parents().size()>0&& abs(partonsToMatch_[ixx]->parents()[0]->id())==6) { preshowerFSPsToDelete_.push_back(partonsToMatch_[ixx]); tmpList_.clear(); getDescendents(partonsToMatch_[ixx]); for(unsigned int jxx=0; jxxparents().size()>0&& (abs(partonsToMatch_[ixx]->parents()[0]->id())==23|| abs(partonsToMatch_[ixx]->parents()[0]->id())==24|| abs(partonsToMatch_[ixx]->parents()[0]->id())==25)) { preshowerFSPsToDelete_.push_back(partonsToMatch_[ixx]); tmpList_.clear(); getDescendents(partonsToMatch_[ixx]); for(unsigned int jxx=0; jxxsubProcess()->intermediates()); for(unsigned int ixx=0; ixxid())==6) { partonsToMatch_.push_back(intermediates[ixx]); tmpList_.clear(); getTopRadiation(partonsToMatch_.back()); for(unsigned int jxx=0; jxxid())>=4&&abs(partonsToMatch_[ixx]->id())<=6) { theProgenitor = partonsToMatch_[ixx]; // Follow the heavy quark line down to where it stops branching. while(theProgenitor->children().size()>0) { theLastProgenitor = theProgenitor; for(unsigned int jxx=0; jxxchildren().size(); jxx++) { if(theProgenitor->children()[jxx]->id()==theProgenitor->id()) theProgenitor=theProgenitor->children()[jxx]; } // If the progenitor had children but none of them had // the same particle id as it, then it must have undergone // a decay rather than a branching, i.e. it is the end of // the evolution line, so, if(theProgenitor==theLastProgenitor) break; } evolvedHeavyQuarks.push_back(theProgenitor); } } // Now delete the evolved heavy quark from the particlesToCluster. for(unsigned int ixx=0; ixx optionalEventWeights = eventHandler()->currentEvent()->optionalWeights(); // loop over the optional weights and find np values for (map::const_iterator it=optionalEventWeights.begin(); it!=optionalEventWeights.end(); ++it){ // split the line boost::split( SplitVec, it->first, boost::is_any_of(" ") ); // if np is found, store the information if(SplitVec[0] == "np") { npLO_ = atof(SplitVec[1].c_str()); npNLO_ = atof(SplitVec[2].c_str()); } } return; } // get hadron COM energy void FxFxHandler::getECOM() const { split_vector_type SplitVec; // pull the optional weights from the current event map optionalEventWeights = eventHandler()->currentEvent()->optionalWeights(); // loop over the optional weights and find np values for (map::const_iterator it=optionalEventWeights.begin(); it!=optionalEventWeights.end(); ++it){ // split the line boost::split( SplitVec, it->first, boost::is_any_of(" ") ); // if np is found, store the information if(SplitVec[0] == "ecom") { ECOM_ = it->second; } } return; } // get pt_clust information void FxFxHandler::getptclust() const { split_vector_type SplitVec; // pull the optional weights from the current event map optionalEventWeights = eventHandler()->currentEvent()->optionalWeights(); // loop over the optional weights and find np values string str_eq = "="; string str_quote = "\""; int countptc_(0); for (map::const_iterator it=optionalEventWeights.begin(); it!=optionalEventWeights.end(); ++it){ // split the line double wgtid = it->second; //cout << "wgtdid = " << wgtid << endl; if(wgtid == -333) { // cout << "it->first for -333 = " << it->first << endl; boost::split( SplitVec, it->first, boost::is_any_of(" ") ); // if np is found, store the information double ptclust(0.); string stringtohandle(""); for(unsigned int i_ = 0; i_ < SplitVec.size(); ++i_) { if(SplitVec[i_].find("pt_clust_") != std::string::npos) { //cout << "pt_clust_ found in " << SplitVec[i_] << endl; countptc_++; // cout << "SplitVec[i_] = " << SplitVec[i_] << endl; stringtohandle = SplitVec[i_]; stringtohandle.erase(0,10); erase_substr(stringtohandle,str_eq); erase_substr(stringtohandle,str_quote); // cout << "stringtohandle = " << stringtohandle << endl; ptclust = atof(stringtohandle.c_str()); ptclust_.push_back(ptclust); } } } } return; } void FxFxHandler::getPreshowerParticles() const { // LH file initial-state partons: preshowerISPs_ = lastXCombPtr()->subProcess()->incoming(); // LH file final-state partICLEs: preshowerFSPs_ = lastXCombPtr()->subProcess()->outgoing(); return; } void FxFxHandler::getShoweredParticles() const { // Post-shower initial-state hadrons: showeredISHs_ = eventHandler()->currentEvent()->incoming(); // Post-shower initial-state partons: for(unsigned int ixx=0; ixx<(showeredISHs_.first)->children().size(); ixx++) if(((showeredISHs_.first)->children()[ixx]->id())<6|| ((showeredISHs_.first)->children()[ixx]->id())==21) showeredISPs_.first=(showeredISHs_.first)->children()[ixx]; for(unsigned int ixx=0; ixx<(showeredISHs_.second)->children().size(); ixx++) if(((showeredISHs_.second)->children()[ixx]->id())<6|| ((showeredISHs_.second)->children()[ixx]->id())==21) showeredISPs_.second=(showeredISHs_.second)->children()[ixx]; // Post-shower final-state partICLEs plus remnants (to be removed later): showeredFSPs_ = eventHandler()->currentEvent()->getFinalState(); // Post-shower final-state remnants: for(unsigned int ixx=0; ixxPDGName()=="Rem:p+"|| showeredFSPs_[ixx]->PDGName()=="Rem:pbar-") { if(showeredFSPs_[ixx]->parents()[0]->parents()[0]== showeredISHs_.first) showeredRems_.first=showeredFSPs_[ixx]; else if(showeredFSPs_[ixx]->parents()[0]->parents()[0]== showeredISHs_.second) showeredRems_.second=showeredFSPs_[ixx]; } } // Now delete found remnants from the showeredFSPs vector for consistency. for(unsigned int ixx=0; ixxPDGName()=="Rem:p+") showeredFSPs_.erase(showeredFSPs_.begin()+ixx); for(unsigned int ixx=0; ixxPDGName()=="Rem:pbar-") showeredFSPs_.erase(showeredFSPs_.begin()+ixx); sort(showeredFSPs_.begin(),showeredFSPs_.end(),recordEntry); return; } void FxFxHandler::doSanityChecks(int debugLevel) const { // When checking momentum conservation in the form // p_in - p_out, any momentum component bigger / less // than + / - epsilon will result in the p_in - p_out // vector being flagged as "non-null", triggering a // warning that momentum conservation is violated. Energy epsilon(0.5*GeV); if(debugLevel>=5) epsilon=1e-9*GeV; // Print out what was found for the incoming and outgoing // partons in the lastXCombPtr regardless. if(debugLevel>=5) { cout << "\n\n\n\n"; cout << "****************************************************" << endl; cout << " The following are the hard subprocess momenta from " << "\n" << " lastXCombPtr and should be basically identical to " << "\n" << " the input LH file momenta." << "\n\n"; cout << " Incoming particles:" << "\n" << *(preshowerISPs_.first) << "\n" << *(preshowerISPs_.second) << endl; cout << " Outgoing particles:" << endl; for(unsigned int ixx=0; ixx=5) { cout << "\n\n"; cout << "****************************************************" << endl; cout << " The following are the particles left at the end of" << "\n" << " the showering step." << "\n\n"; cout << " Incoming hadrons:" << "\n" << *(showeredISHs_.first) << "\n" << *(showeredISHs_.second) << endl; cout << " Incoming partons:" << "\n" << *(showeredISPs_.first) << "\n" << *(showeredISPs_.second) << endl; cout << " Outgoing partons:" << endl; for(unsigned int ixx=0; ixx=4) { Lorentz5Momentum tmpMom; tmpMom += showeredISPs_.first->momentum(); tmpMom += showeredISPs_.second->momentum(); for(unsigned int ixx=0; ixxmomentum(); if(!isMomLessThanEpsilon(tmpMom,epsilon)) cout << "Total parton mom.in - total parton mom.out = " << tmpMom/GeV << endl; tmpMom = showeredISHs_.first->momentum() - showeredRems_.first->momentum() -showeredISPs_.first->momentum(); if(!isMomLessThanEpsilon(tmpMom,epsilon)) cout << "First p_hadron-p_remnant-p_incoming " << tmpMom/GeV << endl; tmpMom = showeredISHs_.second->momentum() - showeredRems_.second->momentum()-showeredISPs_.second->momentum(); if(!isMomLessThanEpsilon(tmpMom,epsilon)) cout << "Second p_hadron-p_remnant-p_incoming " << tmpMom/GeV << endl; } // Check if what we found to be the remnant is consistent with // what we identified as the parent incoming hadron i.e. p+ // goes with Rem:p+ and pbar- goes with Rem:pbar-. if(debugLevel>=0) { string tmpString; tmpString=showeredRems_.first->PDGName(); tmpString=tmpString.substr(tmpString.find_first_of(":")+1, string::npos); if(showeredISHs_.first->PDGName()!=tmpString) { cout << "FxFxHandler::showerHardProcessVeto" << "\n" << "Fatal error in pairing of remnant and parent hadron." << "\n" << "Remnant = " << *(showeredRems_.first) << "\n" << "Parent hadron = " << *(showeredISHs_.first) << endl; cout << showeredISHs_.first->PDGName() << endl; cout << tmpString << endl; } tmpString=showeredRems_.second->PDGName(); tmpString=tmpString.substr(tmpString.find_first_of(":")+1, string::npos); if(showeredISHs_.second->PDGName()!=tmpString) { cout << "FxFxHandler::showerHardProcessVeto" << "\n" << "Fatal error in pairing of remnant and parent hadron." << "\n" << "Remnant = " << *(showeredRems_.second) << "\n" << "Parent hadron = " << *(showeredISHs_.second) << endl; cout << showeredISHs_.second->PDGName() << endl; cout << tmpString << endl; } } return; } void FxFxHandler::printMomVec(vector momVec) { cout << "\n\n"; // Label columns. printf("%5s %9s %9s %9s %9s %9s %9s %9s %9s %9s\n", "jet #", "px","py","pz","E", "eta","phi","pt","et","mass"); // Print out the details for each jet for (unsigned int ixx=0; ixx #include "ThePEG/Utilities/Throw.h" -#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "fastjet/PseudoJet.hh" #include "fastjet/ClusterSequence.hh" #include "gsl/gsl_rng.h" #include "gsl/gsl_randist.h" using namespace Herwig; bool recordEntry(PPtr i,PPtr j) { return (i->number()number()); } bool pTsortFunction(PPtr i,PPtr j) { return (i->momentum().perp2()>j->momentum().perp2()); } bool ETsortFunction(pair i,pair j) { return (i.first>j.first); } bool isMomLessThanEpsilon(Lorentz5Momentum p,Energy epsilon) { return (abs(p.x())> alphaS_ >> ncy_ >> ncphi_ >> ihvy_ >> nph_ >> nh_ >> iunit(etclusmean_,GeV) >> rclus_ >> etaclmax_ >> rclusfactor_ >> ihrd_ >> njets_ >> drjmin_ >> highestMultiplicity_ >> highestNjets_ >> ycmax_ >> ycmin_ >> jetAlgorithm_ >> vetoIsTurnedOff_ >> vetoType_ >> inputIsNLO_ >> highestNLOMultiplicity_ >> etclusfixed_ >> cphcal_ >> sphcal_ >> cthcal_ >> sthcal_ >> iunit(epsetclus_,GeV) >> smoothingtype_; } ClassDescription AlpGenHandlerOL::initAlpGenHandlerOL; // Definition of the static class description member. void AlpGenHandlerOL::Init() { static ClassDocumentation documentation ("The AlpGenHandlerOL class performs MEPS merging " "using the MLM procedure."); static Reference interfaceShowerAlpha ("ShowerAlpha", "The object calculating the strong coupling constant", &AlpGenHandlerOL::alphaS_, false, false, true, false, false); static Parameter interfaceNoCellsInRapidity ("NoCellsInRapidity", "The number of cells spanning the rapidity interval of " "the calorimeter", &AlpGenHandlerOL::ncy_, 100, 1, 10000, false, false, Interface::limited); static Parameter interfaceNoCellsInPhi ("NoCellsInPhi", "The number of cells spanning the phi interval of " "the calorimeter", &AlpGenHandlerOL::ncphi_, 60, 1, 10000, false, false, Interface::limited); static Parameter interfaceihvy ("ihvy", "heavy flavour in WQQ,ZQQ,2Q etc (4=c, 5=b, 6=t)", &AlpGenHandlerOL::ihvy_, -999, -999, 7, false, false, Interface::limited); static Parameter interfacenph ("nph", "Number of photons in the AlpGen process", &AlpGenHandlerOL::nph_, -999, -999, 7, false, false, Interface::limited); static Parameter interfacenh ("nh", "Number of higgses in the AlpGen process", &AlpGenHandlerOL::nh_, -999, -999, 7, false, false, Interface::limited); static Parameter interfaceETClus ("ETClus", "The ET threshold defining a jet in the merging procedure", &AlpGenHandlerOL::etclusmean_, GeV, 20*GeV, 0*GeV, 14000*GeV, false, false, Interface::limited); static Parameter interfaceRClus ("RClus", "The cone size used to define a jet in the merging procedure", &AlpGenHandlerOL::rclus_, 0.4, 0.0, 4.0, false, false, Interface::limited); static Parameter interfaceEtaClusMax ("EtaClusMax", "The maximum |eta| used to define a jet in the merging procedure", &AlpGenHandlerOL::etaclmax_, 5.0, 0.0, 15.0, false, false, Interface::limited); static Parameter interfaceRClusFactor ("RClusFactor", "The prefactor for RClus used to define the jet-parton matching " "distance", &AlpGenHandlerOL::rclusfactor_, 1.5, 0.0, 4.0, false, false, Interface::limited); static Parameter interfaceihrd ("ihrd", "The AlpGen hard process code", &AlpGenHandlerOL::ihrd_, -999, 0, 10000, false, false, Interface::limited); static Parameter interfacenjets ("njets", "The number of light jets in the AlpGen process (i.e. the " "extra ones)", &AlpGenHandlerOL::njets_, -999, 0, 10000, false, false, Interface::limited); static Parameter interfacedrjmin ("drjmin", "Mimimum parton-parton R-sep used for generation.", &AlpGenHandlerOL::drjmin_, 0.7, 0.0, 4.0, false, false, Interface::limited); static Parameter interfacehighestMultiplicity ("highestMultiplicity", "If true it indicates that this is the highest multiplicity input " "ME-level configuration to be processed.", &AlpGenHandlerOL::highestMultiplicity_, 0, 0, 1, false, false, Interface::limited); static Parameter interfacehighestNjets ("highestNjets", "If true it indicates that this is the highest multiplicity input " "ME-level configuration to be processed.", &AlpGenHandlerOL::highestNjets_, 1, 0, 100, false, false, Interface::limited); static Parameter interfacehighestNLOMultiplicity ("highestNLOMultiplicity", "If true it indicates that this is the highest NLO multiplicity input " "ME-level configuration to be processed.", &AlpGenHandlerOL::highestNLOMultiplicity_, 0, 0, 1, false, false, Interface::limited); static Parameter interfaceETClusFixed ("ETClusFixed", "If false, indicates that the jet merging scale, etclus_ is allowed to vary" "according to epsetclus_", &AlpGenHandlerOL::etclusfixed_, 1, 0, 1, false, false, Interface::limited); static Parameter interfaceEpsilonETClus ("EpsilonETClus", "The ET threshold defining a jet in the merging procedure", &AlpGenHandlerOL::epsetclus_, GeV, 2.5*GeV, 0*GeV, 100.0*GeV, false, false, Interface::limited); static Switch interfaceSmoothingType ("SmoothingType", "Determines the kind of smoothing to use ", &AlpGenHandlerOL::smoothingtype_, 0, false, false); static SwitchOption Sine (interfaceSmoothingType, "Sine", "Sinusoidal smoothing.", 0); static SwitchOption Unifnorm (interfaceSmoothingType, "Uniform", "Uniform smoothing.", 1); static Switch interfaceJetAlgorithm ("JetAlgorithm", "Determines the jet algorithm for finding jets in parton-jet " "matching in the MLM procedure.", &AlpGenHandlerOL::jetAlgorithm_, 2, false, false); static SwitchOption AntiKt (interfaceJetAlgorithm, "AntiKt", "The anti-kt jet algorithm.", -1); static SwitchOption CambridgeAachen (interfaceJetAlgorithm, "CambridgeAachen", "The Cambridge-Aachen jet algorithm.", 0); static SwitchOption Kt (interfaceJetAlgorithm, "Kt", "The Kt jet algorithm.", 1); static SwitchOption GetJet (interfaceJetAlgorithm, "GetJet", "Calorimeter-based GetJet algorithm (default).", 2); static Switch interfaceVetoIsTurnedOff ("VetoIsTurnedOff", "Allows the vetoing mechanism to be switched off.", &AlpGenHandlerOL::vetoIsTurnedOff_, false, false, false); static SwitchOption VetoingIsOn (interfaceVetoIsTurnedOff, "VetoingIsOn", "The MLM merging veto mechanism is switched ON.", false); static SwitchOption VetoingIsOff (interfaceVetoIsTurnedOff, "VetoingIsOff", "The MLM merging veto mechanism is switched OFF.", true); static Switch interfaceVetoType ("VetoType", "Allows choosing betwewen the original vetoing mechanism and the one used for OL.", &AlpGenHandlerOL::vetoType_, 1, false, false); static SwitchOption Original (interfaceVetoType, "Original", "The MLM merging veto mechanism in the original form.", 0); static SwitchOption OpenLoops (interfaceVetoType, "OpenLoops", "The MLM merging veto meechanism in the OpenLoops implementation.", 1); static Switch interfaceInputIsNLO ("InputIsNLO", "Signals whether the input LH file is tree-level accurate " "or contains NLO (Powheg) events.", &AlpGenHandlerOL::inputIsNLO_, false, false, false); static SwitchOption InputIsNotNLO (interfaceInputIsNLO, "InputIsNotNLO", "The input LH events have tree-level accuracy.", false); static SwitchOption InputIsNLO (interfaceInputIsNLO, "InputIsNLO", "The input LH events have NLO accuracy.", true); } void AlpGenHandlerOL::dofinish() { ShowerHandler::dofinish(); } void AlpGenHandlerOL::doinit() { //print error if HardProcID is not set in input file if(ihrd_ == -999) { cout << "Error: AlpGenHandlerOL:ihrd not set!" << endl; exit(1); } ShowerHandler::doinit(); // Compute calorimeter edges in rapidity for GetJet algorithm. ycmax_=etaclmax_+rclus_; ycmin_=-ycmax_; // Initialise calorimeter. calini_m(); } // Throws a veto according to MLM strategy ... when we finish writing it. bool AlpGenHandlerOL::showerHardProcessVeto() const { if(vetoIsTurnedOff_) return false; // Skip veto for processes in which merging is not implemented: if(ihrd_==7||ihrd_==8||ihrd_==13) { ostringstream wstring; wstring << "AlpGenHandlerOL::showerHardProcessVeto() - warning." << "MLM merging not implemented for AlpGen " << "processes 4Q (ihrd=7), QQh (ihrd=8), " << "(single) top (ihrd=13) \n"; generator()->logWarning( Exception(wstring.str(), Exception::warning) ); return false; } // Fill preshowerISPs_ pair and preshowerFSPs_ particle pointer vector. getPreshowerParticles(); // Fill showeredISHs_, showeredISPs and showeredRems pairs, as well as // showeredFSPs_ particle pointer vector. getShoweredParticles(); // Turn on some screen output debugging: 0 = none ---> 5 = very verbose. doSanityChecks(0); // Dimensions of each calorimter cell in y and phi. dely_ = (ycmax_-ycmin_)/double(ncy_); delphi_ = 2*M_PI/double(ncphi_); // Fill partonsToMatch_ with only those pre-shower partons intended to // used in jet-parton matching and fill particlesToCluster_ using only // those final state particles (post-shower) which are supposed to go // in the jet clustering used to do merging. partonsToMatch_ = preshowerFSPs_; particlesToCluster_ = showeredFSPs_ ; // <--- TO DO: add remnants in here ??? // Filter out all but the 'extra' light-parton progenitors and their // associated final state particles. caldel_m(); double prob(1); //if etclusfixed_ then set the etclus_ to the fixed chosen value if(etclusfixed_) { etclus_ = etclusmean_; } else { //else, if we wish to vary etclus_, we use the probability distribution //choose a probability between 0 and 1 prob = rnd(); etclus_ = etclusran_(prob); } if(jetAlgorithm_==2) { // If using GetJet fill the calorimeter cells now from particlesToCluster_ calsim_m(); // Make jets from the calorimeter blobs. getjet_m(rclus_,etclus_,etaclmax_); } else { // Cluster particlesToCluster_ into jets with FastJet. getFastJets(rclus_,etclus_,etaclmax_); } // If there are less jets than partons then parton-jet matching is // bound to fail: reject the event already. Also, if the input is // an NLO event file it will 99.5% of the time contain a number of // light partons in the F.S. equal to that in the real emission // process in the NLO calculation, moreover, it has already // effectively merged njets_-1 and njets jet events. So in that // case we do not reject events on the grounds they have jet // multiplicity less than partonsToMatch_.size() but rather less // jets than partonsToMatch.size()-1; such events are better // described by the lower-by-one-unit (partonsToMatch_.size()-1) // of multiplicity NLO event file, or the lower-by-two-units // (partonsToMatch_.size()-2) of multiplicity LO event file. // If it is not jet production apply rejection criterion as above. if(ihrd_!=9) { if(!inputIsNLO_) { if(pjet_.size() < partonsToMatch_.size()) { // cout << "multiplicity: " << partonsToMatch_.size() << " jets: " << pjet_.size() << endl; return true; } } else { if(pjet_.size() < partonsToMatch_.size()-1) return true; } // Otherwise, in the case of jet production allow the lowest // contributing multiplicity process (just at NLO), namely, // dijet production, to give rise to 1-jet and even 0-jet // events, since these can contribute to, for example, the // inclusive jet cross section i.e. in this case the rejection // is only applied in the case of the next-to-lowest multiplicity // processes (>2 parton events at LO and >3 parton events at NLO). } else { if(!inputIsNLO_) { // KH - March 5th // Removed the following line giving special treatment // also to the LO events, to maintain consistency with // the fortran algorithm, at least for now. So now jet // production at LO is being treated the same as all // other processes. // if(partonsToMatch_.size()==2 && pjet_.size()<2) return false; if(pjet_.size() < partonsToMatch_.size()) return true; } else { if(partonsToMatch_.size()<=3 && pjet_.size()<2) return false; if(pjet_.size() < partonsToMatch_.size()-1) return true; } } // Sort partonsToMatch_ from high to low pT. sort(partonsToMatch_.begin(),partonsToMatch_.end(),pTsortFunction); // Match light progenitors to jets. vector jetToPartonMap(pjet_.size(),-999); Energy etmin(777e100*GeV); // If the input is NLO events then don't do any jet-parton matching! if(!inputIsNLO_) { // For each parton, starting with the hardest one ... for(unsigned int ixx=0; ixx=0) { jetToPartonMap[jetIndexForDRmin]=ixx; if(ixx==0||etjet_[jetIndexForDRmin]partonsToMatch_.size() && !inputIsNLO_) { // cout << "multiplicity: " << partonsToMatch_.size() << " jets: " << pjet_.size() << endl; return true; } if(inputIsNLO_) { if(!highestNLOMultiplicity_) { if(pjet_.size()>partonsToMatch_.size()-1) return true; } else { if(!highestMultiplicity_&&pjet_.size()>partonsToMatch_.size()) return true; } } // Veto events where matched jets are softer than non-matched ones, // in the inclusive (highestMultiplicity_ = true) mode, unless we // are dealing with NLO input events. if(highestMultiplicity_ && !inputIsNLO_ ) { for(unsigned int ixx=0; ixxpartonsToMatch_.size() if(partonsToMatch_.size()partonsToMatch_.size() && !inputIsNLO_) { // cout << "multiplicity: " << partonsToMatch_.size() << " jets: " << pjet_.size() << endl; return true; } if(inputIsNLO_) { if(!highestNLOMultiplicity_) { if(pjet_.size()>partonsToMatch_.size()-1) return true; } else { if(partonsToMatch_.size()partonsToMatch_.size()) return true; } } // Veto events where matched jets are softer than non-matched ones, // in the inclusive (highestMultiplicity_ = true) mode, unless we // are dealing with NLO input events. if(partonsToMatch_.size()==highestNjets_ && !inputIsNLO_ ) { // cout << "multiplicity: " << partonsToMatch_.size() << " jets: " << pjet_.size() << endl; for(unsigned int ixx=0; ixxid())==4||abs(partonsToMatch_[jxx]->id())==5)) continue; if(partonJetDeltaR(partonsToMatch_[jxx],pjet_[ixx])etmin) return true; } } } // Otherwise we accept the event ... return false; } /* Function that returns the R distance between a particle and a jet. */ double AlpGenHandlerOL::partonJetDeltaR(ThePEG::tPPtr partonptr, LorentzMomentum jetmom) const { LorentzMomentum partonmom(partonptr->momentum()); // Calculate DY, DPhi and then DR double DY(partonmom.eta()-jetmom.eta()); double DPhi(partonmom.phi()-jetmom.phi()); if(DPhi>M_PI) DPhi=2*M_PI-DPhi; double DR(sqrt(sqr(DY)+sqr(DPhi))); return DR; } // Initialize calorimeter for calsim_m and getjet_m. Note that // because initialization is separte calsim_m can be called more // than once to simulate pileup of several events. void AlpGenHandlerOL::calini_m() const { // Making sure arrays are clear before filling; cphcal_.clear(); sphcal_.clear(); cthcal_.clear(); sthcal_.clear(); // Fill array holding phi values of calorimeter cell centres. double deltaPhi(2*M_PI/ncphi_); for(unsigned int iphi=1; iphi<=ncphi_; iphi++) { double phi(deltaPhi*(iphi-0.5)); // Goes phi~=0 to phi~=2*pi (iphi=0--->ncphi). cphcal_.push_back(cos(phi)); // ==> goes from +1 ---> +1 (iphi=0--->ncphi). sphcal_.push_back(sin(phi)); // ==> goes 0 -> 1 -> 0 -> -1 -> 0 (iphi=0--->ncphi). } // Fill array holding theta values of calorimeter cell centres in Y. double deltaY((ycmax_-ycmin_)/double(ncy_)); for(unsigned int iy=1; iy<=ncy_; iy++) { double Y(deltaY*(iy-0.5)+ycmin_); double th(2*atan(exp(-Y))); // Goes bwds th~=pi to fwds th~=0 (iy=0--->ncy). cthcal_.push_back(cos(th)); // ==> goes from -1 ---> +1 (iy=0--->ncy). sthcal_.push_back(sin(th)); // ==> goes from 0 ---> +1 ---> 0 (iy=0--->ncy). } return; } // Get FastJets void AlpGenHandlerOL::getFastJets(double rjet, Energy ejcut, double etajcut) const { vector particlesToCluster; for(unsigned int ipar=0; iparmomentum().eta()); if(y>=ycmin_&&y<=ycmax_) { int absId(abs(particlesToCluster_[ipar]->id())); // If it's not a lepton / top / photon it may go in the jet finder. if(!(absId>=11&&absId<=16) && absId!=6 && absId!=22) { // input particles into fastjet pseudojet fastjet::PseudoJet p(particlesToCluster_[ipar]->momentum().x()/GeV, particlesToCluster_[ipar]->momentum().y()/GeV, particlesToCluster_[ipar]->momentum().z()/GeV, particlesToCluster_[ipar]->momentum().e()/GeV); p.set_user_index(ipar); particlesToCluster.push_back(p); } } } fastjet::RecombinationScheme recombinationScheme = fastjet::E_scheme; fastjet::Strategy strategy = fastjet::Best; double R(rjet); fastjet::JetDefinition theJetDefinition; switch (jetAlgorithm_) { case -1: theJetDefinition=fastjet::JetDefinition(fastjet::antikt_algorithm, R, recombinationScheme, strategy); break; case 0: theJetDefinition=fastjet::JetDefinition(fastjet::cambridge_algorithm, R, recombinationScheme, strategy); break; case 1: theJetDefinition=fastjet::JetDefinition(fastjet::kt_algorithm, R, recombinationScheme, strategy); break; default: theJetDefinition=fastjet::JetDefinition(fastjet::cambridge_algorithm, R, recombinationScheme, strategy); break; } fastjet::ClusterSequence fastjetEvent(particlesToCluster,theJetDefinition); vector inclusiveJets = fastjetEvent.inclusive_jets(); inclusiveJets = fastjet::sorted_by_pt(inclusiveJets); // Fill the array of jet momenta for the rest of the veto procedure. pjet_.clear(); pjet_.resize(inclusiveJets.size()); etjet_.clear(); etjet_.resize(inclusiveJets.size()); for(unsigned int ffj=0; ffjetajcut) { pjet_.erase(pjet_.begin()+fj); etjet_.erase(etjet_.begin()+fj); fj--; } // Sort jets from high to low ET. vector > etjet_pjet; for(unsigned int ixx=0; ixxmomentum().eta()); if(y>=ycmin_&&y<=ycmax_) { int absId(abs(particlesToCluster_[ipar]->id())); // If it's not a lepton / top / photon it goes in the calorimeter. if(!(absId>=11&&absId<=16) && absId!=6 && absId!=22) { double phi(atan2(particlesToCluster_[ipar]->momentum().y()/GeV, particlesToCluster_[ipar]->momentum().x()/GeV)); if(phi<0) phi+=2*M_PI; unsigned int iy(int((y-ycmin_)/dely_)); unsigned int iphi(int(phi/delphi_)); et_[iy][iphi]+=particlesToCluster_[ipar]->momentum().e()*sthcal_[iy]; } } } return; } // Find highest remaining cell > etstop and sum surrounding cells // with -- delta(y)^2+delta(phi)^2 < Rjet^2 , ET>eccut. Keep sets // with ET>ejcut and abs(eta)=etstop) { // Find the cell with the highest ET from // those not already assigned to a jet. etmax=0*GeV; int iymx(0), iphimx(0); for(unsigned int iphi=0; iphietmax&&jetIdx_[iy][iphi]<0) { etmax = et_[iy][iphi]; iymx = iy; iphimx = iphi; } // If the remaining cell with the highest ET has ET < etstop, stop. if(etmax(ncy_*ncphi_)) { cout << "AlpGenHandlerOL::getjet_m() - Fatal error." << endl; cout << "We found " << ipass << " calo cells with the highest ET so" << "far\nbut the calorimeter only has " << ncy_*ncphi_ << " " << "cells in it!" << endl; exit(10); } // Add a jet vector (may get deleted if jet fails ET / eta cuts). etjet_.push_back(0*GeV); pjet_.push_back(Lorentz5Momentum(0.*GeV,0.*GeV,0.*GeV,0.*GeV,0.*GeV)); // Loop over all calo cells in range iphimx +/- nphi1 (inclusive) // wrapping round in azimuth if required. for(unsigned int iphi1=0; iphi1<=2*nphi1; iphi1++) { int iphix(iphimx-nphi1+iphi1); if(iphix<0) iphix += ncphi_; if(iphix>=int(ncphi_)) iphix -= ncphi_; // Loop over all calo cells in range iymx +/- ny1 (inclusive). for(unsigned int iy1=0; iy1<=2*ny1; iy1++) { int iyx(iymx-ny1+iy1); // If the cell is outside the calorimeter OR if it was already // associated to a jet then skip to the next loop. if(iyx>=0&&iyx=eccut) { Energy ECell(et_[iyx][iphix]/sthcal_[iyx]); pjet_.back()+=LorentzMomentum(ECell*sthcal_[iyx]*cphcal_[iphix], // px ECell*sthcal_[iyx]*sphcal_[iphix], // py ECell*cthcal_[iyx],ECell); // pz, E. // N.B. This is the same reln as in ThePEG between phi and x,y. etjet_.back()+=et_[iyx][iphix]; jetIdx_[iyx][iphix] = pjet_.size()-1; // Identify cell with this jet. } } } } // Compute the current jet's mass. pjet_.back().rescaleMass(); // Throw the jet away if it's ET is less than ejcut. if(etjet_.back()etajcut) { pjet_.pop_back(); etjet_.pop_back(); } } // Sort jets from high to low ET. vector > etjet_pjet; for(unsigned int ixx=0; ixxchildren()); for (unsigned int ixx=0; ixxchildren().size()==0) tmpList_.push_back(theChildren[ixx]); else getDescendents(theChildren[ixx]); return; } void AlpGenHandlerOL::caldel_m() const { preshowerFSPsToDelete_.clear(); showeredFSPsToDelete_.clear(); for(unsigned int ixx=0; ixxparents()[0]->id())==23|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==ihvy_&&ixx<2) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparents()[0]->id())==23|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparents()[0]->id())==23|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24|| abs(preshowerFSPs_[ixx]->id())==22|| abs(preshowerFSPs_[ixx]->id())==25) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparents()[0]->id())==6|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); } if(abs(preshowerFSPs_[ixx]->parents()[0]->id())==6) { getDescendents(preshowerFSPs_[ixx]->parents()[0]); for(unsigned int jxx=0; jxxid())==ihvy_&&ixx<2) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==4&&ixx<1)|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==25) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| (abs(preshowerFSPs_[ixx]->id())==ihvy_&&ixx==(preshowerFSPs_.size()-(2+nph_+1)))|| (abs(preshowerFSPs_[ixx]->id())==ihvy_&&ixx==(preshowerFSPs_.size()-(2+nph_+2)))|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==6|| abs(preshowerFSPs_[ixx]->parents()[0]->id())==24) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxid())==22|| (abs(preshowerFSPs_[ixx]->id())==ihvy_&&ixx<2)) { preshowerFSPsToDelete_.push_back(preshowerFSPs_[ixx]); getDescendents(preshowerFSPs_[ixx]); for(unsigned int jxx=0; jxxparticlesToCluster_.size()) { throw Exception() << "AlpGenHandlerOL::caldel_m() - ERROR!\n" << "No. of ME level partons to be matched to jets = " << partonsToMatch_.size() << "\n" << "No. of showered particles to build jets from = " << particlesToCluster_.size() << "\n" << "There should be at least as many partons to\n" << "cluster as there are partons to match to.\n" << Exception::eventerror; } // Acid test. unsigned int tmpUnsignedInt(njets_); if(!inputIsNLO_&&partonsToMatch_.size()!=tmpUnsignedInt) { for(unsigned int ixx=0; ixxid())>=6&& abs(partonsToMatch_[ixx]->id())!=21) throw Exception() << "AlpGenHandlerOL::caldel_m() - ERROR!\n" << "Found a parton to match to which is not a quark or gluon!" << *partonsToMatch_[ixx] << "\n" << Exception::eventerror; } if(vetoType_==0) { throw Exception() << "AlpGenHandlerOL::caldel_m() - ERROR!\n" << "No. of ME level partons to be matched to jets = " << partonsToMatch_.size() << "\n" << "No. of light jets (njets) in AlpGen process = " << njets_ << "\n" << "These should be equal." << "\n" << Exception::eventerror; } } return; } // This looks for all descendents of a top up to but not including // the W and b children. void AlpGenHandlerOL::getTopRadiation(PPtr theParticle) const { ParticleVector theChildren(theParticle->children()); for (unsigned int ixx=0; ixxchildren().size()==0) tmpList_.push_back(theChildren[ixx]); else if(abs(theChildren[ixx]->id())==5||abs(theChildren[ixx]->id())==24) return; else getTopRadiation(theChildren[ixx]); return; } void AlpGenHandlerOL::caldel_hvq() const { // Fill partonsToMatch_ with only those pre-shower partons intended to // be used in heavy-quark-jet matching and fill particlesToCluster_ using // only those final state particles (post-shower) which are supposed // in the heavy-quark-jet clustering used to do merging. To begin with // these are made from the corresponding sets of particles that were // omitted from the initial jet-parton matching run. partonsToMatch_ = preshowerFSPsToDelete_; particlesToCluster_.resize(showeredFSPsToDelete_.size()); for(unsigned int ixx=0; ixxid())<4||abs(partonsToMatch_[ixx]->id())>6) { preshowerFSPsToDelete_.push_back(partonsToMatch_[ixx]); tmpList_.clear(); getDescendents(partonsToMatch_[ixx]); for(unsigned int jxx=0; jxxid())==5&& partonsToMatch_[ixx]->parents().size()>0&& abs(partonsToMatch_[ixx]->parents()[0]->id())==6) { preshowerFSPsToDelete_.push_back(partonsToMatch_[ixx]); tmpList_.clear(); getDescendents(partonsToMatch_[ixx]); for(unsigned int jxx=0; jxxparents().size()>0&& (abs(partonsToMatch_[ixx]->parents()[0]->id())==23|| abs(partonsToMatch_[ixx]->parents()[0]->id())==24|| abs(partonsToMatch_[ixx]->parents()[0]->id())==25)) { preshowerFSPsToDelete_.push_back(partonsToMatch_[ixx]); tmpList_.clear(); getDescendents(partonsToMatch_[ixx]); for(unsigned int jxx=0; jxxsubProcess()->intermediates()); for(unsigned int ixx=0; ixxid())==6) { partonsToMatch_.push_back(intermediates[ixx]); tmpList_.clear(); getTopRadiation(partonsToMatch_.back()); for(unsigned int jxx=0; jxxid())>=4&&abs(partonsToMatch_[ixx]->id())<=6) { theProgenitor = partonsToMatch_[ixx]; // Follow the heavy quark line down to where it stops branching. while(theProgenitor->children().size()>0) { theLastProgenitor = theProgenitor; for(unsigned int jxx=0; jxxchildren().size(); jxx++) { if(theProgenitor->children()[jxx]->id()==theProgenitor->id()) theProgenitor=theProgenitor->children()[jxx]; } // If the progenitor had children but none of them had // the same particle id as it, then it must have undergone // a decay rather than a branching, i.e. it is the end of // the evolution line, so, if(theProgenitor==theLastProgenitor) break; } evolvedHeavyQuarks.push_back(theProgenitor); } } // Now delete the evolved heavy quark from the particlesToCluster. for(unsigned int ixx=0; ixxsubProcess()->incoming(); // LH file final-state partICLEs: preshowerFSPs_ = lastXCombPtr()->subProcess()->outgoing(); return; } void AlpGenHandlerOL::getShoweredParticles() const { // Post-shower initial-state hadrons: showeredISHs_ = eventHandler()->currentEvent()->incoming(); // Post-shower initial-state partons: for(unsigned int ixx=0; ixx<(showeredISHs_.first)->children().size(); ixx++) if(((showeredISHs_.first)->children()[ixx]->id())<6|| ((showeredISHs_.first)->children()[ixx]->id())==21) showeredISPs_.first=(showeredISHs_.first)->children()[ixx]; for(unsigned int ixx=0; ixx<(showeredISHs_.second)->children().size(); ixx++) if(((showeredISHs_.second)->children()[ixx]->id())<6|| ((showeredISHs_.second)->children()[ixx]->id())==21) showeredISPs_.second=(showeredISHs_.second)->children()[ixx]; // Post-shower final-state partICLEs plus remnants (to be removed later): showeredFSPs_ = eventHandler()->currentEvent()->getFinalState(); // Post-shower final-state remnants: for(unsigned int ixx=0; ixxPDGName()=="Rem:p+"|| showeredFSPs_[ixx]->PDGName()=="Rem:pbar-") { if(showeredFSPs_[ixx]->parents()[0]->parents()[0]== showeredISHs_.first) showeredRems_.first=showeredFSPs_[ixx]; else if(showeredFSPs_[ixx]->parents()[0]->parents()[0]== showeredISHs_.second) showeredRems_.second=showeredFSPs_[ixx]; } } // Now delete found remnants from the showeredFSPs vector for consistency. for(unsigned int ixx=0; ixxPDGName()=="Rem:p+") showeredFSPs_.erase(showeredFSPs_.begin()+ixx); for(unsigned int ixx=0; ixxPDGName()=="Rem:pbar-") showeredFSPs_.erase(showeredFSPs_.begin()+ixx); sort(showeredFSPs_.begin(),showeredFSPs_.end(),recordEntry); return; } void AlpGenHandlerOL::doSanityChecks(int debugLevel) const { // When checking momentum conservation in the form // p_in - p_out, any momentum component bigger / less // than + / - epsilon will result in the p_in - p_out // vector being flagged as "non-null", triggering a // warning that momentum conservation is violated. Energy epsilon(0.5*GeV); if(debugLevel>=5) epsilon=1e-9*GeV; // Print out what was found for the incoming and outgoing // partons in the lastXCombPtr regardless. if(debugLevel>=5) { cout << "\n\n\n\n"; cout << "****************************************************" << endl; cout << " The following are the hard subprocess momenta from " << "\n" << " lastXCombPtr and should be basically identical to " << "\n" << " the input LH file momenta." << "\n\n"; cout << " Incoming particles:" << "\n" << *(preshowerISPs_.first) << "\n" << *(preshowerISPs_.second) << endl; cout << " Outgoing particles:" << endl; for(unsigned int ixx=0; ixx=5) { cout << "\n\n"; cout << "****************************************************" << endl; cout << " The following are the particles left at the end of" << "\n" << " the showering step." << "\n\n"; cout << " Incoming hadrons:" << "\n" << *(showeredISHs_.first) << "\n" << *(showeredISHs_.second) << endl; cout << " Incoming partons:" << "\n" << *(showeredISPs_.first) << "\n" << *(showeredISPs_.second) << endl; cout << " Outgoing partons:" << endl; for(unsigned int ixx=0; ixx=4) { Lorentz5Momentum tmpMom; tmpMom += showeredISPs_.first->momentum(); tmpMom += showeredISPs_.second->momentum(); for(unsigned int ixx=0; ixxmomentum(); if(!isMomLessThanEpsilon(tmpMom,epsilon)) cout << "Total parton mom.in - total parton mom.out = " << tmpMom/GeV << endl; tmpMom = showeredISHs_.first->momentum() - showeredRems_.first->momentum() -showeredISPs_.first->momentum(); if(!isMomLessThanEpsilon(tmpMom,epsilon)) cout << "First p_hadron-p_remnant-p_incoming " << tmpMom/GeV << endl; tmpMom = showeredISHs_.second->momentum() - showeredRems_.second->momentum()-showeredISPs_.second->momentum(); if(!isMomLessThanEpsilon(tmpMom,epsilon)) cout << "Second p_hadron-p_remnant-p_incoming " << tmpMom/GeV << endl; } // Check if what we found to be the remnant is consistent with // what we identified as the parent incoming hadron i.e. p+ // goes with Rem:p+ and pbar- goes with Rem:pbar-. if(debugLevel>=0) { string tmpString; tmpString=showeredRems_.first->PDGName(); tmpString=tmpString.substr(tmpString.find_first_of(":")+1, string::npos); if(showeredISHs_.first->PDGName()!=tmpString) { cout << "AlpGenHandlerOL::showerHardProcessVeto" << "\n" << "Fatal error in pairing of remnant and parent hadron." << "\n" << "Remnant = " << *(showeredRems_.first) << "\n" << "Parent hadron = " << *(showeredISHs_.first) << endl; cout << showeredISHs_.first->PDGName() << endl; cout << tmpString << endl; } tmpString=showeredRems_.second->PDGName(); tmpString=tmpString.substr(tmpString.find_first_of(":")+1, string::npos); if(showeredISHs_.second->PDGName()!=tmpString) { cout << "AlpGenHandlerOL::showerHardProcessVeto" << "\n" << "Fatal error in pairing of remnant and parent hadron." << "\n" << "Remnant = " << *(showeredRems_.second) << "\n" << "Parent hadron = " << *(showeredISHs_.second) << endl; cout << showeredISHs_.second->PDGName() << endl; cout << tmpString << endl; } } return; } void AlpGenHandlerOL::printMomVec(vector momVec) { cout << "\n\n"; // Label columns. printf("%5s %9s %9s %9s %9s %9s %9s %9s %9s %9s\n", "jet #", "px","py","pz","E", "eta","phi","pt","et","mass"); // Print out the details for each jet for (unsigned int ixx=0; ixxparent.mass()) return ParticleVector(); // generate the decay bool cc; _imode = modeNumber(cc,parent.dataPtr(),children); return _modes[_imode]->generate(_generateinter,cc,parent); } void DecayIntegrator::persistentOutput(PersistentOStream & os) const { - os << _modes << _niter << _npoint << _ntry << _photongen << _generateinter; + os << _modes << _niter << _npoint << _ntry << _photongen << _generateinter << ounit(_eps,GeV); } void DecayIntegrator::persistentInput(PersistentIStream & is, int) { - is >> _modes >> _niter >> _npoint >> _ntry >> _photongen >> _generateinter; + is >> _modes >> _niter >> _npoint >> _ntry >> _photongen >> _generateinter >> iunit(_eps,GeV); } // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractClass describeHerwigDecayIntegrator("Herwig::DecayIntegrator", "Herwig.so"); void DecayIntegrator::Init() { - - static RefVector interfaceModes - ("Modes", - "The phase space integration modes.", - &DecayIntegrator::_modes, 0, false, false, true, true); static ClassDocumentation documentation ("The DecayIntegrator class is a base decayer class " "including a multi-channel integrator."); static Parameter interfaceIteration ("Iteration", "Number of iterations for the initialization of the phase space", &DecayIntegrator::_niter, 10, 0, 100, false, false, true); static Parameter interfacePoints ("Points", "number of phase space points to generate in the initialisation.", &DecayIntegrator::_npoint, 10000, 1, 1000000000, false, false, true); static Parameter interfaceNtry ("Ntry", "Number of attempts to generate the decay", &DecayIntegrator::_ntry, 500, 0, 100000, false, false, true); static Reference interfacePhotonGenerator ("PhotonGenerator", "Object responsible for generating photons in the decay.", &DecayIntegrator::_photongen, false, false, true, true, false); static Switch interfaceGenerateIntermediates ("GenerateIntermediates", "Whether or not to include intermediate particles in the output", &DecayIntegrator::_generateinter, false, false, false); static SwitchOption interfaceGenerateIntermediatesNoIntermediates (interfaceGenerateIntermediates, "No", "Don't include the intermediates", false); static SwitchOption interfaceGenerateIntermediatesIncludeIntermediates (interfaceGenerateIntermediates, "Yes", "include the intermediates", true); } // output info on the integrator ostream & Herwig::operator<<(ostream & os, const DecayIntegrator & decay) { os << "The integrator has " << decay._modes.size() << " modes" << endl; for(unsigned int ix=0;ixgenerate(inter,cc,inpart); } // initialization for a run void DecayIntegrator::doinitrun() { HwDecayerBase::doinitrun(); if ( initialize() && Debug::level > 1 ) CurrentGenerator::current().log() << "Start of the initialisation for " << this->name() << "\n"; for(unsigned int ix=0;ix<_modes.size();++ix) { if(!_modes[ix]) continue; _modes[ix]->initrun(); _imode=ix; _modes[ix]->initializePhaseSpace(initialize()); } // CurrentGenerator::current().log() << *this << "\n"; } // add a new mode void DecayIntegrator::addMode(DecayPhaseSpaceModePtr in,double maxwgt, const vector inwgt) const { _modes.push_back(in); if(in) { in->setMaxWeight(maxwgt); in->setWeights(inwgt); in->setIntegrate(_niter,_npoint,_ntry); in->init(); } } // reset the properities of all intermediates void DecayIntegrator::resetIntermediate(tcPDPtr part, Energy mass, Energy width) { if(!part) return; for(unsigned int ix=0,N=_modes.size();ixresetIntermediate(part,mass,width); } } WidthCalculatorBasePtr DecayIntegrator::threeBodyMEIntegrator(const DecayMode &) const { return WidthCalculatorBasePtr(); } // set the code for the partial width void DecayIntegrator::setPartialWidth(const DecayMode & dm, int imode) { vector extid; tcPDPtr cc,cc2; int nfound(0),ifound,nmax(1),id; unsigned int ix(0),iy,N,iz,tmax,nmatched; if(dm.parent()->CC()) nmax=2; if(_modes.size()==0) return; do { if(!_modes[ix]) { ++ix; continue; } cc = _modes[ix]->externalParticles(0)->CC(); tmax = cc ? 1 : 2; for(iz=0;izid()==_modes[ix]->externalParticles(0)->id()&&iz==0) { for(iy=0,N=_modes[ix]->numberofParticles();iyexternalParticles(iy)->id()); } } else if(dm.parent()->id()==_modes[ix]->externalParticles(0)->id()&&iz==1) { for(iy=0,N=_modes[ix]->numberofParticles();iyexternalParticles(iy)->CC(); extid.push_back( cc2 ? cc2->id() : _modes[ix]->externalParticles(iy)->id()); } } else if(cc&&dm.parent()->id()==cc->id()) { for(iy=0,N=_modes[ix]->numberofParticles();iyexternalParticles(iy)->CC(); extid.push_back( cc2 ? cc2->id() : _modes[ix]->externalParticles(iy)->id()); } } // if the parents match if(!extid.empty()) { vector matched(extid.size(),false); bool done; nmatched=0; ParticleMSet::const_iterator pit = dm.products().begin(); do { id=(**pit).id(); done=false; iy=1; do { if(id==extid[iy]&&!matched[iy]) { matched[iy]=true; ++nmatched; done=true; } ++iy; } while(iy=0) _modes[ifound]->setPartialWidth(imode); } ++ix; } while(nfound extid; tcPDPtr cc,cc2; bool found(false); int id; unsigned int ix(0),iy,N,iz,tmax,nmatched; if(_modes.size()==0) return -1; do { if(!_modes[ix]) { ++ix; continue; } cc = _modes[ix]->externalParticles(0)->CC(); tmax=1;if(!cc){++tmax;} for(iz=0;izid()==_modes[ix]->externalParticles(0)->id()&&iz==0) { for(iy=0,N=_modes[ix]->numberofParticles();iyexternalParticles(iy)->id()); } } else if(dm.parent()->id()==_modes[ix]->externalParticles(0)->id()&&iz==1) { for(iy=0,N=_modes[ix]->numberofParticles();iyexternalParticles(iy)->CC(); extid.push_back( cc2 ? cc2->id() : _modes[ix]->externalParticles(iy)->id()); } } else if(cc&&dm.parent()->id()==cc->id()) { for(iy=0,N=_modes[ix]->numberofParticles();iyexternalParticles(iy)->CC(); extid.push_back( cc ? cc->id() : _modes[ix]->externalParticles(iy)->id()); } } // if the parents match if(!extid.empty()) { vector matched(extid.size(),false); bool done; nmatched=0; ParticleMSet::const_iterator pit = dm.products().begin(); do { id=(**pit).id(); done=false; iy=1; do { if(id==extid[iy]&&!matched[iy]) { matched[iy]=true; ++nmatched; done=true; } ++iy; } while(iy(cmodeptr); modeptr->init(); return modeptr->initializePhaseSpace(init,onShell); } // the matrix element to be integrated for the me double DecayIntegrator::threeBodyMatrixElement(const int,const Energy2, const Energy2, const Energy2,const Energy2, const Energy, const Energy, const Energy) const { throw DecayIntegratorError() << "Calling the virtual DecayIntegrator::threeBodyMatrixElement" << "method. This must be overwritten in the classes " << "inheriting from DecayIntegrator where it is needed" << Exception::runerror; } // the differential three body decay rate with one integral performed InvEnergy DecayIntegrator::threeBodydGammads(const int, const Energy2, const Energy2, const Energy, const Energy, const Energy) const { throw DecayIntegratorError() << "Calling the virtual DecayIntegrator::threeBodydGammads()" <<"method. This must be overwritten in the classes " << "inheriting from DecayIntegrator where it is needed" << Exception::runerror; } double DecayIntegrator::oneLoopVirtualME(unsigned int , const Particle &, const ParticleVector &) { throw DecayIntegratorError() << "DecayIntegrator::oneLoopVirtualME() called. This should" << " have been overidden in an inheriting class if it is used" << Exception::runerror; } InvEnergy2 DecayIntegrator::realEmissionME(unsigned int, const Particle &, ParticleVector &, unsigned int, double, double, const LorentzRotation &, const LorentzRotation &) { throw DecayIntegratorError() << "DecayIntegrator::realEmmisionME() called. This should" << " have been overidden in an inheriting class if it is used" << Exception::runerror; } diff --git a/Decay/DecayIntegrator.h b/Decay/DecayIntegrator.h --- a/Decay/DecayIntegrator.h +++ b/Decay/DecayIntegrator.h @@ -1,470 +1,490 @@ // -*- C++ -*- // // DecayIntegrator.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_DecayIntegrator_H #define HERWIG_DecayIntegrator_H // // This is the declaration of the DecayIntegrator class. // #include #include "DecayPhaseSpaceChannel.h" #include #include #include "DecayPhaseSpaceMode.fh" #include "Herwig/PDT/WidthCalculatorBase.fh" #include "Radiation/DecayRadiationGenerator.h" #include "HwDecayerBase.h" #include "DecayIntegrator.fh" namespace Herwig { using namespace ThePEG; /** \ingroup Decay * \class DecayIntegrator * \brief Main class for Decayers implementing multi-channel phase space integration. * \author Peter Richardson * * This class is designed to be the base class for Herwig decays including * the implementation of a multichannel decayer or n-body phase space decays. * * The DecayIntegrator class inherits from ThePEG's Decayer class * and makes use of the DecayPhaseSpaceMode class to specify a number * of decay modes. * * Additional modes can be added using the addMode method. In practice the * phase space channels for a particular mode are usually constructed in the * doinit member of a Decayer and then the modes added to the Decayer. * * For the majority of the decays currently implemented the * phase-space integration has been optimised and the maximum weight set. * If the parameters of the decay model are changed the Initialize interface * can be used to optimise the integration and calculate the maximum weight. * * In classes inheriting from this the me2() member which gives the matrix element * squared must be implemented. This should be combined with the setting of the * phase space channels, and the setting of which channels to use and their * initial weights in the doinit() member. The different decay modes should then * be initialized in the initrun() member if needed. The generate member can then * be called from the decay() member to generate a phase-space configuration for a * decay. * * @see DecayPhaseSpaceMode * @see DecayPhaseSpaceChannel * @see \ref DecayIntegratorInterfaces "The interfaces" * defined for DecayIntegrator. */ class DecayIntegrator: public HwDecayerBase { public: /** * The output operator is a friend, this is mainly for debugging */ friend ostream & operator<<(ostream &, const DecayIntegrator &); /** * and DecayPhaseMode */ friend class DecayPhaseSpaceMode; /** * Enum for the matrix element option */ enum MEOption {Initialize,Calculate,Terminate}; public: /** * Default constructor. */ DecayIntegrator() : _niter(10), _npoint(10000), _ntry(500), _generateinter(false), _imode(-1), - _realME(false), _virtualME(false) {} + _realME(false), _virtualME(false), _eps(ZERO) {} /** * Check if this decayer can perfom the decay for a particular mode. * Uses the modeNumber member but can be overridden * @param parent The decaying particle * @param children The decay products */ virtual bool accept(tcPDPtr parent, const tPDVector & children) const { bool cc; return modeNumber(cc,parent,children)>=0; } /** * For a given decay mode and a given particle instance, perform the * decay and return the decay products. As this is the base class this * is not implemented. * @return The vector of particles produced in the decay. */ virtual ParticleVector decay(const Particle & parent, const tPDVector & children) const; /** * Which of the possible decays is required * @param cc Is this mode the charge conjugate * @param parent The decaying particle * @param children The decay products */ virtual int modeNumber(bool & cc, tcPDPtr parent, const tPDVector & children) const = 0; /** * The mode being used for this decay */ int imode() const {return _imode;} /** * Add a phase-space mode to the list * @param mode The mode being added. * @param maxwgt The maximum weight for the phase space integration. * @param wgts The weights of the different channels in the multichannel approach. */ void addMode(DecayPhaseSpaceModePtr mode,double maxwgt, const vector wgts) const; /** * Return the matrix element squared for a given mode and phase-space channel. * This function is purely virtual and must be implemented in classes inheriting * from DecayIntegrator. * @param ichan The channel we are calculating the matrix element for. * @param part The decaying Particle. * @param decay The particles produced in the decay. * @param opt Option for the calculation of the matrix element * @return The matrix element squared for the phase-space configuration. */ virtual double me2(const int ichan, const Particle & part, const ParticleVector & decay,MEOption opt) const=0; /** * The helicity amplitude matrix element for spin correlations. */ DecayMEPtr ME() const {return _matrixelement;} /** * Specify the \f$1\to2\f$ matrix element to be used in the running width calculation. * @param mecode The code for the matrix element as described * in the GenericWidthGenerator class. * @param coupling The coupling for the matrix element. * @return True or False if this mode can be handled. */ virtual bool twoBodyMEcode(const DecayMode &, int & mecode, double & coupling) const { coupling = 1.; mecode = -1; return false; } /** * Method to return an object to calculate the 3 (or higher body) partial width * @param dm The DecayMode * @return A pointer to a WidthCalculatorBase object capable of calculating the width */ virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const; /** * The matrix element to be integrated for the three-body decays as a function * of the invariant masses of pairs of the outgoing particles. * @param imode The mode for which the matrix element is needed. * @param q2 The scale, \e i.e. the mass squared of the decaying particle. * @param s3 The invariant mass squared of particles 1 and 2, \f$s_3=m^2_{12}\f$. * @param s2 The invariant mass squared of particles 1 and 3, \f$s_2=m^2_{13}\f$. * @param s1 The invariant mass squared of particles 2 and 3, \f$s_1=m^2_{23}\f$. * @param m1 The mass of the first outgoing particle. * @param m2 The mass of the second outgoing particle. * @param m3 The mass of the third outgoing particle. * @return The matrix element */ virtual double threeBodyMatrixElement(const int imode, const Energy2 q2, const Energy2 s3, const Energy2 s2, const Energy2 s1, const Energy m1, const Energy m2, const Energy m3) const; /** * The differential three body decay rate with one integral performed. * @param imode The mode for which the matrix element is needed. * @param q2 The scale, \e i.e. the mass squared of the decaying particle. * @param s The invariant mass which still needs to be integrate over. * @param m1 The mass of the first outgoing particle. * @param m2 The mass of the second outgoing particle. * @param m3 The mass of the third outgoing particle. * @return The differential rate \f$\frac{d\Gamma}{ds}\f$ */ virtual InvEnergy threeBodydGammads(const int imode, const Energy2 q2, const Energy2 s, const Energy m1, const Energy m2, const Energy m3) const; /** * Set the code for the partial width. Finds the partial width in the * GenericWidthGenerator class which corresponds to the decay mode. * @param dm The DecayMode * @param imode The mode. */ void setPartialWidth(const DecayMode & dm, int imode); /** * Finds the phase-space mode corresponding to a given decay mode * @param dm The DecayMode */ int findMode(const DecayMode & dm); /** * Output the setup information for the particle database * @param os The stream to output the information to * @param header Whether or not to output the information for MySQL */ virtual void dataBaseOutput(ofstream & os,bool header) const; + /** + * Access to the epsilon parameter + */ + Energy epsilonPS() const {return _eps;} + public: /** * Members for the generation of QED radiation in the decays */ //@{ /** * Use the DecayRadiationGenerator to generate photons in the decay. * @param p The Particle instance being decayed * @param children The decay products * @return A particle vector containing the decay products after the generation * of photons. */ ParticleVector generatePhotons(const Particle & p,ParticleVector children) { return _photongen->generatePhotons(p,children,this); } /** * check if photons can be generated in the decay */ bool canGeneratePhotons() {return _photongen;} /** * The one-loop virtual correction. * @param imode The mode required. * @param part The decaying particle. * @param products The decay products including the radiated photon. * @return Whether the correction is implemented */ virtual double oneLoopVirtualME(unsigned int imode, const Particle & part, const ParticleVector & products); /** * Whether or not the one loop matrix element is implemented */ bool hasOneLoopME() {return _virtualME;} /** * The real emission matrix element * @param imode The mode required * @param part The decaying particle * @param products The decay products including the radiated photon * @param iemitter The particle which emitted the photon * @param ctheta The cosine of the polar angle between the photon and the * emitter * @param stheta The sine of the polar angle between the photon and the * emitter * @param rot1 Rotation from rest frame to frame for real emission * @param rot2 Rotation to place emitting particle along z */ virtual InvEnergy2 realEmissionME(unsigned int imode, const Particle & part, ParticleVector & products, unsigned int iemitter, double ctheta, double stheta, const LorentzRotation & rot1, const LorentzRotation & rot2); /** * Whether or not the real emission matrix element is implemented */ bool hasRealEmissionME() {return _realME;} //@} 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(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(PersistentIStream & is, int version); //@} /** * Standard Init function used to initialize the interfaces. */ static void Init(); protected: /** * Generate the momenta for the decay * @param inter Generate the intermediates produced in the decay as well as the * final particles. * @param cc Is this the mode defined or its charge conjugate. * @param imode The mode being generated. * @param inpart The decaying particle. * @return The particles produced inthe decay. */ ParticleVector generate(bool inter,bool cc, const unsigned int & imode, const Particle & inpart) const; /** * Set the mode being use for this decay. */ void imode(int in) {_imode=in;} /** * Set the helicity matrix element for the decay. */ void ME(DecayMEPtr in) const { _matrixelement = in;} /** * Reset the properities of all intermediates. * @param part The intermediate particle being reset. * @param mass The mass of the particle. * @param width The width of the particle. */ void resetIntermediate(tcPDPtr part, Energy mass, Energy width); /** * Number of decay modes */ unsigned int numberModes() const {return _modes.size();} /** * Pointer to a mode */ tDecayPhaseSpaceModePtr mode(unsigned int); /** * Pointer to a mode */ tcDecayPhaseSpaceModePtr mode(unsigned int) const; /** * Get whether or not the intermediates are included */ bool generateIntermediates() const {return _generateinter;} /** * Set whether or not the intermediates are included */ void generateIntermediates(bool in) {_generateinter=in;} /** * Initialize the phase-space mode * @param imode The mode * @param init Whether or not to perform the initialization */ Energy initializePhaseSpaceMode(unsigned int imode,bool init, bool onShell=false) const; /** * Whether or not the one loop matrix element is implemented */ void hasOneLoopME(bool in) {_virtualME=in;} /** * Whether or not the real emission matrix element is implemented */ void hasRealEmissionME(bool in) {_realME=in;} + /** + * Set the epsilon parameter + */ + void epsilonPS(Energy in) {_eps=in;} + + /** + * Clear the models + */ + void clearModes() {_modes.clear();} + protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object to the begining of the run phase. */ virtual void doinitrun(); //@} private: /** * Private and non-existent assignment operator. */ DecayIntegrator & operator=(const DecayIntegrator &); private: /** * Number of iterations for th initialization. */ int _niter; /** * Number of points for initialisation */ int _npoint; /** * number of attempts to generate the decay */ int _ntry; /** * List of the decay modes */ mutable vector _modes; /** * Whether to include the intermediates whne outputing the results. */ bool _generateinter; /** * Pointer to the object generating the QED radiation in the decay */ DecayRadiationGeneratorPtr _photongen; /** * mode currently being generated */ mutable int _imode; /** * The helicity matrix element for the current decay */ mutable DecayMEPtr _matrixelement; /** * Whether or not the real photon emission matrix element exists */ bool _realME; /** * Whether or not the one-loop matrix element exists */ bool _virtualME; + + /** + * Epsilon parameter for phase-space integration + */ + Energy _eps; }; /** * Output information on the DecayIntegrator for debugging purposes */ ostream & operator<<(ostream &, const DecayIntegrator &); /** * Exception for this class and those inheriting from it */ class DecayIntegratorError: public Exception {}; } #endif /* HERWIG_DecayIntegrator_H */ diff --git a/Decay/DecayPhaseSpaceChannel.cc b/Decay/DecayPhaseSpaceChannel.cc --- a/Decay/DecayPhaseSpaceChannel.cc +++ b/Decay/DecayPhaseSpaceChannel.cc @@ -1,603 +1,596 @@ // -*- C++ -*- // // DecayPhaseSpaceChannel.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 DecayPhaseSpaceChannel class. // // Author: Peter Richardson // #include "DecayPhaseSpaceChannel.h" #include "ThePEG/Utilities/DescribeClass.h" #include "DecayPhaseSpaceMode.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Switch.h" #include using namespace Herwig; DecayPhaseSpaceChannel::DecayPhaseSpaceChannel(tcDecayPhaseSpaceModePtr in) : _mode(in) {} void DecayPhaseSpaceChannel::persistentOutput(PersistentOStream & os) const { os << _intpart << _jactype << ounit(_intmass,GeV) << ounit(_intwidth,GeV) << ounit(_intmass2,GeV2) << ounit(_intmwidth,GeV2) << _intpower << _intdau1 << _intdau2 << _intext << _mode; } void DecayPhaseSpaceChannel::persistentInput(PersistentIStream & is, int) { is >> _intpart >> _jactype >> iunit(_intmass,GeV) >> iunit(_intwidth,GeV) >> iunit(_intmass2,GeV2) >> iunit(_intmwidth,GeV2) >> _intpower >> _intdau1 >> _intdau2 >> _intext >> _mode; } - + // The following static variable is needed for the type // description system in ThePEG. -DescribeClass +DescribeClass describeHerwigDecayPhaseSpaceChannel("Herwig::DecayPhaseSpaceChannel", "Herwig.so"); void DecayPhaseSpaceChannel::Init() { static RefVector interfaceIntermediateParticles ("IntermediateParticles", "The intermediate particles in the decay chain.", &DecayPhaseSpaceChannel::_intpart, 0, false, false, true, false); - - static ParVector interfacejactype - ("Jacobian", - "The type of Jacobian to use for the intermediate particle", - &DecayPhaseSpaceChannel::_jactype, - 0, 0, 0, 0, 1, false, false, true); - - static ParVector interfaceIntermediatePower - ("IntermediatePower", - "The power to use in the Jacobian", - &DecayPhaseSpaceChannel::_intpower, - 0, 0, 0, -10, 10, false, false, true); - - static ParVector interfaceIntermediateDau1 - ("IntermediateDaughter1", - "First Daughter of the intermediate", - &DecayPhaseSpaceChannel::_intdau1, - 0, 0, 0, -10, 10, false, false, true); - - static ParVector interfaceIntermediateDau2 - ("IntermediateDaughter2", - "Second Daughter of the intermediate", - &DecayPhaseSpaceChannel::_intdau2, - 0, 0, 0, -10, 10, false, false, true); - - static ClassDocumentation documentation - ("The DecayPhaseSpaceChannel class defines a channel" - " for the multichannel integration of the phase space for a decay."); - } // generate the momenta of the external particles vector DecayPhaseSpaceChannel::generateMomenta(const Lorentz5Momentum & pin, const vector & massext) { // integers for loops unsigned int ix,iy,idau[2],iz; // storage of the momenta of the external particles vector pexternal; // and the internal particles vector pinter; // copy the momentum of the incoming particle pexternal.push_back(pin); pinter.push_back(pin); pexternal.resize(_mode->numberofParticles()); pinter.resize(_intpart.size()); // masses of the intermediate particles vector massint(_intpart.size()); massint[0]=pin.mass(); // generate all the decays in the chain Energy lower,upper,lowerb[2]; for(ix=0;ix<_intpart.size();++ix) { idau[0] = abs(_intdau1[ix]); idau[1] = abs(_intdau2[ix]); // if both decay products off-shell if(_intdau1[ix]<0&&_intdau2[ix]<0) { // lower limits on the masses of the two resonances for(iy=0;iy<2;++iy) { lowerb[iy]=ZERO; + bool massless=true; for(iz=0;iz<_intext[idau[iy]].size();++iz) { + if(massext[_intext[idau[iy]][iz]]!=ZERO) massless = false; lowerb[iy]+=massext[_intext[idau[iy]][iz]]; } + if(massless) lowerb[iy] = _mode->epsilonPS(); } // randomize the order if(UseRandom::rnd()<0.5) { // mass of the first resonance upper = massint[ix]-lowerb[1]; lower = lowerb[0]; massint[idau[0]]=generateMass(idau[0],lower,upper); // mass of the second resonance upper = massint[ix]-massint[idau[0]]; lower = lowerb[1]; massint[idau[1]]=generateMass(idau[1],lower,upper); } else { // mass of the second resonance upper = massint[ix]-lowerb[0]; lower = lowerb[1]; massint[idau[1]]=generateMass(idau[1],lower,upper); // mass of the first resonance upper = massint[ix]-massint[idau[1]]; lower = lowerb[0]; massint[idau[0]]=generateMass(idau[0],lower,upper); } // generate the momenta of the decay products twoBodyDecay(pinter[ix],massint[idau[0]],massint[idau[1]], pinter[idau[0]],pinter[idau[1]]); } // only first off-shell else if(_intdau1[ix]<0) { // compute the limits of integration upper = massint[ix]-massext[idau[1]]; lower = ZERO; + bool massless=true; for(iy=0;iy<_intext[idau[0]].size();++iy) { + if(massext[_intext[idau[0]][iy]]!=ZERO) massless = false; lower+=massext[_intext[idau[0]][iy]]; } + if(massless) lower = _mode->epsilonPS(); massint[idau[0]]=generateMass(idau[0],lower,upper); // generate the momenta of the decay products twoBodyDecay(pinter[ix],massint[idau[0]],massext[idau[1]], pinter[idau[0]],pexternal[idau[1]]); } // only second off-shell else if(_intdau2[ix]<0) { // compute the limits of integration upper = massint[ix]-massext[idau[0]]; lower = ZERO; + bool massless=true; for(iy=0;iy<_intext[idau[1]].size();++iy) { + if(massext[_intext[idau[0]][iy]]!=ZERO) massless = false; lower+=massext[_intext[idau[1]][iy]]; } + if(massless) lower = _mode->epsilonPS(); massint[idau[1]]=generateMass(idau[1],lower,upper); // generate the momenta of the decay products twoBodyDecay(pinter[ix],massext[idau[0]],massint[idau[1]], pexternal[idau[0]],pinter[idau[1]]); } // both on-shell else { // generate the momenta of the decay products twoBodyDecay(pinter[ix],massext[idau[0]],massext[idau[1]], pexternal[idau[0]],pexternal[idau[1]]); } } // return the external momenta return pexternal; } // generate the weight for this channel given a phase space configuration double DecayPhaseSpaceChannel::generateWeight(const vector & output) { using Constants::pi; // integers for loops unsigned int ix,iy,idau[2],iz; // include the prefactor due to the weight of the channel double wgt=1.; // work out the masses of the intermediate particles static vector intmass; intmass.clear(); Lorentz5Momentum pinter; for(ix=0;ix<_intpart.size();++ix) { pinter=output[_intext[ix][0]]; for(iz=1;iz<_intext[ix].size();++iz) pinter+=output[_intext[ix][iz]]; pinter.rescaleMass(); intmass.push_back( pinter.mass() ); } Energy2 scale(sqr(intmass[0])); // calculate the terms for each of the decays Energy lower,upper,lowerb[2]; for(ix=0;ix<_intpart.size();++ix) { idau[0] = abs(_intdau1[ix]); idau[1] = abs(_intdau2[ix]); // if both decay products off-shell Energy pcm; if(_intdau1[ix]<0&&_intdau2[ix]<0) { // lower limits on the masses of the two resonances for(iy=0;iy<2;++iy) { lowerb[iy]=ZERO; for(iz=0;iz<_intext[idau[iy]].size();++iz) lowerb[iy]+=output[_intext[idau[iy]][iz]].mass(); } // undo effect of randomising // weight for the first order // contribution of first resonance upper = intmass[ix]-lowerb[1]; lower = lowerb[0]; InvEnergy2 wgta=massWeight(idau[0],intmass[idau[0]],lower,upper); // contribution of second resonance upper = intmass[ix]-intmass[idau[0]]; lower = lowerb[1]; InvEnergy4 wgta2 = wgta*massWeight(idau[1],intmass[idau[1]],lower,upper); // weight for the second order upper = intmass[ix]-lowerb[0]; lower = lowerb[1]; InvEnergy2 wgtb=massWeight(idau[1],intmass[idau[1]],lower,upper); upper = intmass[ix]-intmass[idau[1]]; lower = lowerb[0]; InvEnergy4 wgtb2=wgtb*massWeight(idau[0],intmass[idau[0]],lower,upper); // weight factor wgt *=0.5*sqr(scale)*(wgta2+wgtb2); // factor for the kinematics pcm = Kinematics::pstarTwoBodyDecay(intmass[ix],intmass[idau[0]], intmass[idau[1]]); if(pcm>ZERO) wgt *= intmass[ix]*8.*pi*pi/pcm; else wgt = 0.; } // only first off-shell else if(_intdau1[ix]<0) { // compute the limits of integration upper = intmass[ix]-output[idau[1]].mass(); lower = ZERO; for(iy=0;iy<_intext[idau[0]].size();++iy) lower+=output[_intext[idau[0]][iy]].mass(); wgt *=scale*massWeight(idau[0],intmass[idau[0]],lower,upper); pcm = Kinematics::pstarTwoBodyDecay(intmass[ix],intmass[idau[0]], output[idau[1]].mass()); if(pcm>ZERO) wgt *= intmass[ix]*8.*pi*pi/pcm; else wgt = 0.; } // only second off-shell else if(_intdau2[ix]<0) { // compute the limits of integration upper = intmass[ix]-output[idau[0]].mass(); lower = ZERO; for(iy=0;iy<_intext[idau[1]].size();++iy) lower+=output[_intext[idau[1]][iy]].mass(); wgt *=scale*massWeight(idau[1],intmass[idau[1]],lower,upper); pcm = Kinematics::pstarTwoBodyDecay(intmass[ix],intmass[idau[1]], output[idau[0]].mass()); if(pcm>ZERO) wgt *=intmass[ix]*8.*pi*pi/pcm; else wgt=0.; } // both on-shell else { pcm = Kinematics::pstarTwoBodyDecay(intmass[ix],output[idau[1]].mass(), output[idau[0]].mass()); if(pcm>ZERO) wgt *=intmass[ix]*8.*pi*pi/pcm; else wgt = 0.; } } // finally the overall factor wgt /= pi; // return the answer return wgt; } // output the information to a stream ostream & Herwig::operator<<(ostream & os, const DecayPhaseSpaceChannel & channel) { // output of the external particles os << "Channel for the decay of " << channel._mode->externalParticles(0)->PDGName() << " -> "; for(unsigned int ix=1;ixnumberofParticles();++ix) os << channel._mode->externalParticles(ix)->PDGName() << " "; os << endl; os << "Decay proceeds in following steps "; for(unsigned int ix=0;ixPDGName() << " -> "; if(channel._intdau1[ix]>0) { os << channel._mode->externalParticles(channel._intdau1[ix])->PDGName() << "(" << channel._intdau1[ix]<< ") "; } else { os << channel._intpart[-channel._intdau1[ix]]->PDGName() << "(" << channel._intdau1[ix]<< ") "; } if(channel._intdau2[ix]>0) { os << channel._mode->externalParticles(channel._intdau2[ix])->PDGName() << "(" <PDGName() << "(" <mass()); _intwidth.push_back(_intpart[ix]->width()); _intmass2.push_back(_intpart[ix]->mass()*_intpart[ix]->mass()); _intmwidth.push_back(_intpart[ix]->mass()*_intpart[ix]->width()); } // external particles for each intermediate particle vector temp; _intext.resize(_intpart.size()); // loop over the intermediate particles for(int ix=_intpart.size()-1;ix>=0;--ix) { temp.clear(); // add the first daughter if(_intdau1[ix]>=0) { temp.push_back(_intdau1[ix]); } else { int iy = -_intdau1[ix]; vector::iterator istart=_intext[iy].begin(); vector::iterator iend=_intext[iy].end(); for(;istart!=iend;++istart) temp.push_back(*istart); } // add the second daughter if(_intdau2[ix]>=0) { temp.push_back(_intdau2[ix]); } else { int iy = -_intdau2[ix]; vector::iterator istart=_intext[iy].begin(); vector::iterator iend=_intext[iy].end(); for(;istart!=iend;++istart) temp.push_back(*istart); } _intext[ix]=temp; } // ensure intermediates either have the width set, or // can't possibly be on-shell Energy massmax; if(_mode->testOnShell()) { massmax = _mode->externalParticles(0)->mass(); for(unsigned int ix=1;ix<_mode->numberofParticles();++ix) massmax -= _mode->externalParticles(ix)->mass(); } else { massmax = _mode->externalParticles(0)->massMax(); for(unsigned int ix=1;ix<_mode->numberofParticles();++ix) massmax -= _mode->externalParticles(ix)->massMin(); } for(unsigned int ix=0;ix<_intpart.size();++ix) { if(_intwidth[ix]==ZERO && ix>0 && _jactype[ix]==0 ) { Energy massmin(ZERO); for(unsigned int iy=0;iy<_intext[ix].size();++iy) massmin += _mode->testOnShell() ? _mode->externalParticles(_intext[ix][iy])->mass() : _mode->externalParticles(_intext[ix][iy])->massMin(); // check if can be on-shell if(_intmass[ix]>=massmin&&_intmass[ix]<=massmax+massmin) { string modeout; for(unsigned int iy=0;iy<_mode->numberofParticles();++iy) { modeout += _mode->externalParticles(iy)->PDGName() + " "; } throw InitException() << "Width zero for " << _intpart[ix]->PDGName() << " in DecayPhaseSpaceChannel::doinit() " << modeout << Exception::runerror; } } } } -void DecayPhaseSpaceChannel::doinitrun() { - Interfaced::doinitrun(); +void DecayPhaseSpaceChannel::initrun() { if(!_mode->testOnShell()) return; _intmass.clear(); _intwidth.clear(); _intmass2.clear(); _intmwidth.clear(); // masses and widths of the intermediate particles for(unsigned int ix=0;ix<_intpart.size();++ix) { _intmass.push_back(_intpart[ix]->mass()); _intwidth.push_back(_intpart[ix]->width()); _intmass2.push_back(_intpart[ix]->mass()*_intpart[ix]->mass()); _intmwidth.push_back(_intpart[ix]->mass()*_intpart[ix]->width()); } // ensure intermediates either have the width set, or // can't possibly be on-shell Energy massmax = _mode->externalParticles(0)->massMax(); for(unsigned int ix=1;ix<_mode->numberofParticles();++ix) massmax -= _mode->externalParticles(ix)->massMin(); for(unsigned int ix=0;ix<_intpart.size();++ix) { if(_intwidth[ix]==0.*MeV && ix>0 && _jactype[ix]==0 ) { Energy massmin(0.*GeV); - for(unsigned int iy=0;iy<_intext[ix].size();++iy) + for(unsigned int iy=0;iy<_intext[ix].size();++iy) { massmin += _mode->externalParticles(_intext[ix][iy])->massMin(); + } // check if can be on-shell if(_intmass[ix]>=massmin&&_intmass[ix]<=massmax+massmin) { string modeout; for(unsigned int iy=0;iy<_mode->numberofParticles();++iy) { modeout += _mode->externalParticles(iy)->PDGName() + " "; } throw Exception() << "Width zero for " << _intpart[ix]->PDGName() << " in DecayPhaseSpaceChannel::doinitrun() " << modeout << Exception::runerror; } } } } // generate the final-state particles including the intermediate resonances void DecayPhaseSpaceChannel::generateIntermediates(bool cc, const Particle & in, ParticleVector & out) { // integers for the loops unsigned int ix,iz; // create the particles // incoming particle ParticleVector external; external.push_back(const_ptr_cast(&in)); // outgoing for(ix=0;ixmomentum(); for(iz=1;iz<_intext[ix].size();++iz) pinter+=external[_intext[ix][iz]]->momentum(); pinter.rescaleMass(); respart = (cc&&_intpart[ix]->CC()) ? _intpart[ix]->CC()->produceParticle(pinter) : _intpart[ix] ->produceParticle(pinter); resonance.push_back(respart); } // set up the mother daughter relations for(ix=1;ix<_intpart.size();++ix) { resonance[ix]->addChild( _intdau1[ix]<0 ? resonance[-_intdau1[ix]] : external[_intdau1[ix]]); resonance[ix]->addChild( _intdau2[ix]<0 ? resonance[-_intdau2[ix]] : external[_intdau2[ix]]); if(resonance[ix]->dataPtr()->stable()) resonance[ix]->setLifeLength(Lorentz5Distance()); } // construct the output with the particles in the first step out.push_back( _intdau1[0]>0 ? external[_intdau1[0]] : resonance[-_intdau1[0]]); out.push_back( _intdau2[0]>0 ? external[_intdau2[0]] : resonance[-_intdau2[0]]); } double DecayPhaseSpaceChannel::atanhelper_(int ires, Energy limit) { return atan2( limit*limit-_intmass2[ires], _intmwidth[ires] ); } // return the weight for a given resonance InvEnergy2 DecayPhaseSpaceChannel::massWeight(int ires, Energy moff, Energy lower,Energy upper) { InvEnergy2 wgt = ZERO; if(lower>upper) { throw DecayPhaseSpaceError() << "DecayPhaseSpaceChannel::massWeight not allowed " << ires << " " << _intpart[ires]->id() << " " << moff/GeV << " " << lower/GeV << " " << upper/GeV << Exception::eventerror; } // use a Breit-Wigner if ( _jactype[ires] == 0 ) { double rhomin = atanhelper_(ires,lower); double rhomax = atanhelper_(ires,upper) - rhomin; if ( rhomax != 0.0 ) { Energy2 moff2=moff*moff-_intmass2[ires]; wgt = _intmwidth[ires]/rhomax/(moff2*moff2+_intmwidth[ires]*_intmwidth[ires]); } else { wgt = 1./((sqr(upper)-sqr(lower))*sqr(sqr(moff)-_intmass2[ires])/ (sqr(lower)-_intmass2[ires])/(sqr(upper)-_intmass2[ires])); } } // power law else if(_jactype[ires]==1) { double rhomin = pow(sqr(lower/MeV),_intpower[ires]+1.); double rhomax = pow(sqr(upper/MeV),_intpower[ires]+1.)-rhomin; wgt = (_intpower[ires]+1.)/rhomax*pow(sqr(moff/MeV),_intpower[ires]) /MeV/MeV; } else if(_jactype[ires]==2) { wgt = 1./Constants::pi/_intmwidth[ires]; } else { throw DecayPhaseSpaceError() << "Unknown type of Jacobian in " << "DecayPhaseSpaceChannel::massWeight" << Exception::eventerror; } return wgt; } Energy DecayPhaseSpaceChannel::generateMass(int ires,Energy lower,Energy upper) { static const Energy eps=1e-9*MeV; if(lowerupper) throw DecayPhaseSpaceError() << "DecayPhaseSpaceChannel::generateMass" << " not allowed" << Exception::eventerror; if(abs(lower-upper)/(lower+upper)>2e-10) { lower +=1e-10*(lower+upper); upper -=1e-10*(lower+upper); } else return 0.5*(lower+upper); // use a Breit-Wigner if(_jactype[ires]==0) { if(_intmwidth[ires]!=ZERO) { Energy2 lower2 = sqr(lower); Energy2 upper2 = sqr(upper); double rhomin = atan2((lower2 - _intmass2[ires]),_intmwidth[ires]); double rhomax = atan2((upper2 - _intmass2[ires]),_intmwidth[ires])-rhomin; double rho = rhomin+rhomax*UseRandom::rnd(); Energy2 mass2 = max(lower2,min(upper2,_intmass2[ires]+_intmwidth[ires]*tan(rho))); if(mass2upper-1e-10*(lower+upper)) mass=upper-1e-10*(lower+upper); return mass; } void DecayPhaseSpaceChannel::twoBodyDecay(const Lorentz5Momentum & p, const Energy m1, const Energy m2, Lorentz5Momentum & p1, Lorentz5Momentum & p2 ) { static const double eps=1e-6; double ctheta,phi; Kinematics::generateAngles(ctheta,phi); Axis unitDir1=Kinematics::unitDirection(ctheta,phi); Momentum3 pstarVector; Energy min=p.mass(); if ( min >= m1 + m2 && m1 >= ZERO && m2 >= ZERO ) { pstarVector = unitDir1 * Kinematics::pstarTwoBodyDecay(min,m1,m2); } else if( m1 >= ZERO && m2 >= ZERO && (m1+m2-min)/(min+m1+m2) " << m1/GeV << ' ' << m2/GeV << Exception::eventerror; } p1 = Lorentz5Momentum(m1, pstarVector); p2 = Lorentz5Momentum(m2,-pstarVector); // boost from CM to LAB Boost bv = p.boostVector(); double gammarest = p.e()/p.mass(); p1.boost( bv , gammarest ); p2.boost( bv , gammarest ); } + +bool DecayPhaseSpaceChannel::checkKinematics() { + Energy massmax = _mode->externalParticles(0)->massMax(); + for(unsigned int ix=1;ix<_mode->numberofParticles();++ix) + massmax -= _mode->externalParticles(ix)->massMin(); + for(unsigned int ix=1;ix<_intpart.size();++ix) { + Energy massmin(0.*GeV); + for(unsigned int iy=0;iy<_intext[ix].size();++iy) { + massmin += _mode->externalParticles(_intext[ix][iy])->massMin(); + } + if(_intmass[ix]>=massmin&&_intmass[ix]<=massmax+massmin && + _intwidth[ix]==ZERO) + return false; + } + return true; +} diff --git a/Decay/DecayPhaseSpaceChannel.h b/Decay/DecayPhaseSpaceChannel.h --- a/Decay/DecayPhaseSpaceChannel.h +++ b/Decay/DecayPhaseSpaceChannel.h @@ -1,361 +1,349 @@ // -*- C++ -*- // // DecayPhaseSpaceChannel.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_DecayPhaseSpaceChannel_H #define HERWIG_DecayPhaseSpaceChannel_H // // This is the declaration of the DecayPhaseSpaceChannel class. // #include #include #include #include "DecayPhaseSpaceChannel.fh" #include "DecayIntegrator.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Repository/UseRandom.h" #include "DecayPhaseSpaceMode.fh" namespace Herwig { using namespace ThePEG; /** \ingroup Decay * * This class is designed to store the information needed for a given * phase-space channel for use by the multi-channel phase space decayer * and perform the generation of the phase space for that channel. * * The decay channel is specified as a series of \f$1\to2\f$ decays to either * external particles or other intermediates. For each intermediate * the Jacobian to be used can be either a Breit-Wigner(0) or a power-law * (1). * * The class is then capable of generating a phase-space point using this * channel and computing the weight of a given point for use in a multi-channel * phase space integration using the DecayPhaseSpaceMode class. * * The class is designed so that the phase-space channels can either by specified * using the addIntermediate method directly or via the repository. * (In practice at the moment all the channels are constructed by the relevant decayers * using the former method at the moment.) * * @see DecayPhaseSpaceMode * @see DecayIntegrator * * @author Peter Richardson */ -class DecayPhaseSpaceChannel: public Interfaced { +class DecayPhaseSpaceChannel: public Base { /** * A friend output operator to allow the channel to be outputted for * debugging purposes */ friend ostream & operator<<(ostream &, const DecayPhaseSpaceChannel &); /** * DecayPhaseSpaceMode is a friend to avoid making many of the phase space * generation members public. */ friend class DecayPhaseSpaceMode; public: /** @name Standard constructors and destructors. */ //@{ /** * Default constructor. */ DecayPhaseSpaceChannel() {} /** * Constructor with a pointer to a DecayPhaseSpaceMode. This * is the constructor which should normally be used in decayers. */ DecayPhaseSpaceChannel(tcDecayPhaseSpaceModePtr); //@} public: /** @name Set-up Members */ //@{ /** * Add a new intermediate particle * @param part A pointer to the particle data object for the intermediate. * @param jac The jacobian to be used for the generation of the particle's mass * 0 is a Breit-Wigner and 1 is a power-law * @param power The power to beb used for the mass generation if a power law * mass distribution is chosen. * @param dau1 The first daughter. If this is postive it is the \f$dau1\f$ th * outgoing particle (0 is the incoming particle), if it is negative it is the * \f$|dau1|\f$ intermediate. The intermediates are specified in the order they * are added with 0 being the incoming particle. * @param dau2 The first daughter. If this is postive it is the \f$dau2\f$ th * outgoing particle (0 is the incoming particle), if it is negative it is the * \f$|dau2|\f$ intermediate. The intermediates are specified in the order they * are added with 0 being the incoming particle. */ void addIntermediate(PDPtr part,int jac,double power,int dau1,int dau2) { _intpart.push_back(part); _jactype.push_back(jac); _intpower.push_back(power); _intdau1.push_back(dau1); _intdau2.push_back(dau2); } /** * Reset the properties of an intermediate particle. This member is used * when a Decayer is used a different value for either the mass or width * of a resonace to that in the ParticleData object. This improves the * efficiency of the integration. * @param part A pointer to the particle data object for the intermediate. * @param mass The new mass of the intermediate * @param width The new width of the intermediate. */ void resetIntermediate(tcPDPtr part,Energy mass,Energy width) { if(!part) return; int idin=part->id(); for(unsigned int ix=0;ix<_intpart.size();++ix) { if(_intpart[ix] && _intpart[ix]->id()==idin) { _intmass[ix] =mass;_intwidth[ix]=width; _intmass2[ix]=mass*mass;_intmwidth[ix]=mass*width; } } } /* * Reset the one of the daughters * @param oldp The id of the particle being reset * @param newp The id of the particle replacing it */ void resetDaughter(int oldp, int newp) { for(unsigned int ix=0;ix<_intdau1.size();++ix) { if(_intdau1[ix]==oldp) _intdau1[ix]=newp; } for(unsigned int ix=0;ix<_intdau2.size();++ix) { if(_intdau2[ix]==oldp) _intdau2[ix]=newp; } } + + /** + * Check the kinematics + */ + bool checkKinematics(); //@} protected: /** @name Phase-Space Generation Members */ //@{ /** * Generate the momenta of the external particles. This member uses the masses * of the external particles generated by the DecayPhaseMode class and the * intermediates for the channel to generate the momenta of the decay products. * @param pin The momenta of the decay products. This is outputed by the member. * @param massext The masses of the particles. This is to allow inclusion of * off-shell effects for the external particles. */ vector generateMomenta(const Lorentz5Momentum & pin, const vector & massext); /** * Generate the weight for this channel given a phase space configuration. * This member generates the weight for a given phase space configuration * and is used by the DecayPhaseSpaceMode class to compute the denominator * of the weight in the multi-channel integration. * @param output The momenta of the outgoing particles. */ double generateWeight(const vector & output); /** * Generate the final-state particles including the intermediate resonances. * This method takes the outgoing particles and adds the intermediate particles * specified by this phase-space channel. This is to allow a given set of * intermediates to be specified even when there is interference between different * intermediate states. * @param cc Whether the particles are the mode specified or its charge conjugate. * @param in The incoming particles. * @param out The outgoing particles. * */ void generateIntermediates(bool cc,const Particle & in, ParticleVector & out); /** * Calculate the momenta for a two body decay * The return value indicates success or failure. * @param p The momentum of the decaying particle * @param m1 The mass of the first decay product * @param m2 The mass of the second decay product * @param p1 The momentum of the first decay product * @param p2 The momentum of the second decay product */ void twoBodyDecay(const Lorentz5Momentum & p, const Energy m1, const Energy m2, Lorentz5Momentum & p1, Lorentz5Momentum & p2); //@} 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(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(PersistentIStream & is, int version); //@} /** * Standard Init function used to initialize the interfaces. */ static void Init(); - -protected: - - /** @name Clone Methods. */ - //@{ - /** - * Make a simple clone of this object. - * @return a pointer to the new object. - */ - virtual IBPtr clone() const {return new_ptr(*this);} - /** Make a clone of this object, possibly modifying the cloned object - * to make it sane. - * @return a pointer to the new object. - */ - virtual IBPtr fullclone() const {return new_ptr(*this);} - //@} - -protected: +public: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving and * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ - virtual void doinit(); + virtual void init(); /** * Initialize this object. Called in the run phase just before * a run begins. */ - virtual void doinitrun(); + virtual void initrun(); //@} private: /** * Private and non-existent assignment operator. */ DecayPhaseSpaceChannel & operator=(const DecayPhaseSpaceChannel &); private: /** @name Mass Generation Members */ //@{ /** * Generate the mass of a resonance. * @param ires The resonance to be generated. * @param lower The lower limit on the particle's mass. * @param upper The upper limit on the particle's mass. */ Energy generateMass(int ires,Energy lower,Energy upper); /** * Return the weight for a given resonance. * @param ires The resonance to be generated. * @param moff The mass of the resonance. * @param lower The lower limit on the particle's mass. * @param upper The upper limit on the particle's mass. */ InvEnergy2 massWeight(int ires, Energy moff,Energy lower,Energy upper); //@} private: /** * pointer to the mode */ tcDecayPhaseSpaceModePtr _mode; /** * Pointers to the particle data objects of the intermediate particles */ vector _intpart; /** * The type of jacobian to be used for the intermediates. */ vector _jactype; /** * The mass of the intermediates. */ vector _intmass; /** * The width of the intermediates. */ vector _intwidth; /** * The mass squared of the intermediate particles. */ vector _intmass2; /** * The mass times the width for the intermediate particles. */ vector_intmwidth; /** * The power for the intermediate resonance. */ vector _intpower; /** * The first daughter of the intermediate resonance. */ vector _intdau1; /** * The second daughter of the intermediate resonance. */ vector _intdau2; /** * The external particles that an intermediate particle final decays to. */ vector< vector > _intext; /** * Helper function for the weight calculation. * @param ires The resonance to be generated. * @param limit The limit on the particle's mass. */ double atanhelper_(int ires, Energy limit); }; /** * write the phase space channel to a stream */ ostream & operator<<(ostream &, const DecayPhaseSpaceChannel &); /** * exception for this class and those inheriting from it */ class DecayPhaseSpaceError: public Exception {}; } #endif /* HERWIG_DecayPhaseSpaceChannel_H */ diff --git a/Decay/DecayPhaseSpaceMode.cc b/Decay/DecayPhaseSpaceMode.cc --- a/Decay/DecayPhaseSpaceMode.cc +++ b/Decay/DecayPhaseSpaceMode.cc @@ -1,529 +1,527 @@ // -*- C++ -*- // // DecayPhaseSpaceMode.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 DecayPhaseSpaceMode class. // #include "DecayPhaseSpaceMode.h" #include "ThePEG/Utilities/DescribeClass.h" #include "Herwig/PDT/GenericWidthGenerator.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/RefVector.h" #include "DecayIntegrator.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/EventRecord/HelicityVertex.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/EventRecord/Event.h" #include "ThePEG/Utilities/Debug.h" using namespace Herwig; using namespace ThePEG::Helicity; void DecayPhaseSpaceMode::persistentOutput(PersistentOStream & os) const { os << _integrator << _channels << _channelwgts << _maxweight << _niter << _npoint << _ntry << _extpart << _partial << _widthgen << _massgen - << _testOnShell; + << _testOnShell << ounit(_eps,GeV); } void DecayPhaseSpaceMode::persistentInput(PersistentIStream & is, int) { is >> _integrator >> _channels >> _channelwgts >> _maxweight >> _niter >> _npoint >> _ntry >> _extpart >> _partial >> _widthgen >> _massgen - >> _testOnShell; + >> _testOnShell >> iunit(_eps,GeV); } // The following static variable is needed for the type // description system in ThePEG. -DescribeClass +DescribeClass describeHerwigDecayPhaseSpaceMode("Herwig::DecayPhaseSpaceMode", "Herwig.so"); void DecayPhaseSpaceMode::Init() { static ClassDocumentation documentation ("The DecayPhaseSpaceMode class contains a number of phase space" " channels for the integration of a particular decay mode"); - - static RefVector interfaceChannels - ("Channels", - "The phase space integration channels.", - &DecayPhaseSpaceMode::_channels, 0, false, false, true, true); } // flat phase space generation and weight Energy DecayPhaseSpaceMode::flatPhaseSpace(bool cc, const Particle & inpart, ParticleVector & outpart, bool onShell) const { double wgt(1.); if(outpart.empty()) { outpart.reserve(_extpart.size()-1); for(unsigned int ix=1;ix<_extpart.size();++ix) { if(cc&&_extpart[ix]->CC()) { outpart.push_back((_extpart[ix]->CC())->produceParticle()); } else { outpart.push_back(_extpart[ix]->produceParticle()); } } } // masses of the particles Energy inmass(inpart.mass()); vector mass = externalMasses(inmass,wgt,onShell); // momenta of the particles vector part(outpart.size()); // two body decay assert(outpart.size()==2); double ctheta,phi; Kinematics::generateAngles(ctheta,phi); if(! Kinematics::twoBodyDecay(inpart.momentum(), mass[1], mass[2], ctheta, phi,part[0],part[1])) throw Exception() << "Incoming mass - Outgoing mass negative in " << "DecayPhaseSpaceMode::flatPhaseSpace()" << Exception::eventerror; wgt *= Kinematics::pstarTwoBodyDecay(inmass,mass[1],mass[2])/8./Constants::pi/inmass; outpart[0]->set5Momentum(part[0]); outpart[1]->set5Momentum(part[1]); return wgt*inmass; } // initialise the phase space Energy DecayPhaseSpaceMode::initializePhaseSpace(bool init, bool onShell) { + _integrator->ME(DecayMEPtr()); Energy output(ZERO); // ensure that the weights add up to one if(!_channels.empty()) { double temp=0.; for(unsigned int ix=0;ix<_channels.size();++ix) temp+=_channelwgts[ix]; for(unsigned int ix=0;ix<_channels.size();++ix) _channelwgts[ix]/=temp; } if(!init) return ZERO; // create a particle vector from the particle data one ThePEG::PPtr inpart=_extpart[0]->produceParticle(); ParticleVector particles; // now if using flat phase space _maxweight=0.; double totsum(0.),totsq(0.); InvEnergy pre=1./MeV; Energy prewid; if(_channels.empty()) { double wsum=0.,wsqsum=0.; Energy m0,mmin(ZERO); for(unsigned int ix=1;ix<_extpart.size();++ix) { mmin+=_extpart[ix]->massMin(); } for(int ix=0;ix<_npoint;++ix) { // set the mass of the decaying particle m0 = !onShell ? inpart->dataPtr()->generateMass() : inpart->dataPtr()->mass(); double wgt=0.; if(m0>mmin) { inpart->set5Momentum(Lorentz5Momentum(m0)); // compute the prefactor prewid = (_widthgen&&_partial>=0) ? _widthgen->partialWidth(_partial,inpart->mass()) : inpart->dataPtr()->width(); pre = prewid>ZERO ? 1./prewid : 1./MeV; // generate the weight for this point try { int dummy; wgt = pre*weight(false,dummy,*inpart,particles,true,onShell); } catch (Veto) { wgt=0.; } } if(wgt>_maxweight) _maxweight=wgt; wsum += wgt; wsqsum += sqr(wgt); } wsum=wsum/_npoint; wsqsum=wsqsum/_npoint-sqr(wsum); if(wsqsum<0.) wsqsum=0.; wsqsum=sqrt(wsqsum/_npoint); Energy fact = (_widthgen&&_partial>=0) ? _widthgen->partialWidth(_partial,inpart->nominalMass()) : inpart->dataPtr()->width(); if(fact==ZERO) fact=MeV; // factor for the weight with spin correlations _maxweight *= inpart->dataPtr()->iSpin()==1 ? 1.1 : 1.6; if ( Debug::level > 1 ) { // ouptut the information on the initialisation CurrentGenerator::log() << "Initialized the phase space for the decay " << _extpart[0]->PDGName() << " -> "; for(unsigned int ix=1,N=_extpart.size();ixPDGName() << " "; CurrentGenerator::log() << "\n"; if(fact!=MeV) CurrentGenerator::log() << "The branching ratio is " << wsum << " +/- " << wsqsum << "\n"; CurrentGenerator::log() << "The partial width is " << wsum*fact/MeV << " +/- " << wsqsum*fact/MeV << " MeV\n"; CurrentGenerator::log() << "The partial width is " << wsum*fact/6.58212E-22/MeV << " +/- " << wsqsum*fact/6.58212E-22/MeV<< " s-1\n"; CurrentGenerator::log() << "The maximum weight is " << _maxweight << endl; } output=wsum*fact; } else { for(int iy=0;iy<_niter;++iy) { // zero the maximum weight _maxweight=0.; vector wsum(_channels.size(),0.),wsqsum(_channels.size(),0.); vector nchan(_channels.size(),0); totsum = 0.; totsq = 0.; Energy m0,mmin(ZERO); for(unsigned int ix=1;ix<_extpart.size();++ix) { mmin+=_extpart[ix]->massMin(); } for(int ix=0;ix<_npoint;++ix) { m0 = !onShell ? inpart->dataPtr()->generateMass() : inpart->dataPtr()->mass(); double wgt=0.; int ichan(-1); if(m0>mmin) { inpart->set5Momentum(Lorentz5Momentum(m0)); // compute the prefactor prewid= (_widthgen&&_partial>=0) ? _widthgen->partialWidth(_partial,inpart->mass()) : inpart->dataPtr()->width(); pre = prewid>ZERO ? 1./prewid : 1./MeV; // generate the weight for this point try { wgt = pre*weight(false,ichan,*inpart,particles,true,onShell); } catch (Veto) { wgt=0.; } } if(wgt>_maxweight) _maxweight=wgt; if(ichan>=0) { wsum[ichan] += wgt; wsqsum[ichan] += sqr(wgt); ++nchan[ichan]; } totsum+=wgt; totsq+=wgt*wgt; } totsum=totsum/_npoint; totsq=totsq/_npoint-sqr(totsum); if(totsq<0.) totsq=0.; totsq=sqrt(totsq/_npoint); if ( Debug::level > 1 ) CurrentGenerator::log() << "The branching ratio is " << iy << " " << totsum << " +/- " << totsq << _maxweight << "\n"; // compute the individual terms double total(0.); for(unsigned int ix=0;ix<_channels.size();++ix) { if(nchan[ix]!=0) { wsum[ix]=wsum[ix]/nchan[ix]; wsqsum[ix]=wsqsum[ix]/nchan[ix]; if(wsqsum[ix]<0.) wsqsum[ix]=0.; wsqsum[ix]=sqrt(wsqsum[ix]/nchan[ix]); } else { wsum[ix]=0; wsqsum[ix]=0; } total+=sqrt(wsqsum[ix])*_channelwgts[ix]; } if(total>0.) { double temp; for(unsigned int ix=0;ix<_channels.size();++ix) { temp=sqrt(wsqsum[ix])*_channelwgts[ix]/total; _channelwgts[ix]=temp; } } } // factor for the weight with spin correlations _maxweight*= inpart->dataPtr()->iSpin()==1 ? 1.1 : 1.6; // ouptut the information on the initialisation Energy fact = (_widthgen&&_partial>=0) ? _widthgen->partialWidth(_partial,inpart->nominalMass()) : inpart->dataPtr()->width(); if(fact==ZERO) fact=MeV; if ( Debug::level > 1 ) { CurrentGenerator::log() << "Initialized the phase space for the decay " << _extpart[0]->PDGName() << " -> "; for(unsigned int ix=1,N=_extpart.size();ixPDGName() << " "; CurrentGenerator::log() << "\n"; if(fact!=MeV) CurrentGenerator::log() << "The branching ratio is " << totsum << " +/- " << totsq << "\n"; CurrentGenerator::log() << "The partial width is " << totsum*fact/MeV << " +/- " << totsq*fact/MeV << " MeV\n"; CurrentGenerator::log() << "The partial width is " << totsum*fact/6.58212E-22/MeV << " +/- " << totsq*fact/6.58212E-22/MeV << " s-1\n"; CurrentGenerator::log() << "The maximum weight is " << _maxweight << "\n"; CurrentGenerator::log() << "The weights for the different phase" << " space channels are \n"; for(unsigned int ix=0,N=_channels.size();ix momenta; double wgt(UseRandom::rnd()); // select a channel ichan=-1; do{++ichan;wgt-=_channelwgts[ichan];} while(ichan0.); // generate the momenta if(ichan==int(_channels.size())) { throw DecayIntegratorError() << "DecayPhaseSpaceMode::channelPhaseSpace()" << " failed to select a channel" << Exception::abortnow; } // generate the masses of the external particles double masswgt(1.); vector mass(externalMasses(inpart.mass(),masswgt,onShell)); momenta=_channels[ichan]->generateMomenta(inpart.momentum(),mass); // compute the denominator of the weight wgt=0.; unsigned int ix; for(ix=0;ix<_channels.size();++ix) { wgt+=_channelwgts[ix]*_channels[ix]->generateWeight(momenta); } // now we need to set the momenta of the particles // create the particles if they don't exist if(outpart.empty()) { for(ix=1;ix<_extpart.size();++ix) { if(cc&&_extpart[ix]->CC()) { outpart.push_back((_extpart[ix]->CC())->produceParticle()); } else { outpart.push_back(_extpart[ix]->produceParticle()); } } } // set up the momenta for(ix=0;ixset5Momentum(momenta[ix+1]); // return the weight return wgt!=0. ? inpart.mass()*masswgt/wgt : ZERO; } // generate the decay ParticleVector DecayPhaseSpaceMode::generate(bool intermediates,bool cc, const Particle & inpart) const { _integrator->ME(DecayMEPtr()); // compute the prefactor InvEnergy pre(1./MeV); Energy prewid; if(_widthgen&&_partial>=0) prewid=_widthgen->partialWidth(_partial,inpart.mass()); else prewid=(inpart.dataPtr()->width()); pre = prewid>ZERO ? 1./prewid : 1./MeV; // Particle vector for the output ParticleVector particles; // boosts to/from rest Boost bv =-inpart.momentum().boostVector(); double gammarest = inpart.momentum().e()/inpart.momentum().mass(); LorentzRotation boostToRest( bv,gammarest); LorentzRotation boostFromRest(-bv,gammarest); // construct a new particle which is at rest Particle inrest(inpart); inrest.transform(boostToRest); int ncount(0),ichan; double wgt(0.); unsigned int ix; try { do { wgt=pre*weight(cc,ichan,inrest,particles,ncount==0); ++ncount; if(wgt>_maxweight) { CurrentGenerator::log() << "Resetting max weight for decay " << inrest.PDGName() << " -> "; for(ix=0;ixPDGName(); CurrentGenerator::log() << " " << _maxweight << " " << wgt << " " << inrest.mass()/MeV << "\n"; _maxweight=wgt; } } while(_maxweight*UseRandom::rnd()>wgt&&ncount<_ntry); if(ncount>=_ntry) { CurrentGenerator::log() << "The decay " << inrest.PDGName() << " -> "; for(ix=0;ixPDGName(); CurrentGenerator::log() << " " << _maxweight << " " << _ntry << " is too inefficient for the particle " << inpart << "vetoing the decay \n"; particles.clear(); throw Veto(); } } catch (Veto) { // restore the incoming particle to its original state inrest.transform(boostFromRest); throw Veto(); } // set up the vertex for spin correlations me2(-1,inrest,particles,DecayIntegrator::Terminate); const_ptr_cast(&inpart)->spinInfo(inrest.spinInfo()); constructVertex(inpart,particles); // return if intermediate particles not required if(_channelwgts.empty()||!intermediates) { for(ix=0;ixtransform(boostFromRest); } // find the intermediate particles else { // select the channel _ichannel = selectChannel(inpart,particles); for(ix=0;ixtransform(boostFromRest); // generate the particle vector _channels[_ichannel]->generateIntermediates(cc,inpart,particles); } _integrator->ME(DecayMEPtr()); return particles; } // construct the vertex for spin corrections void DecayPhaseSpaceMode::constructVertex(const Particle & inpart, const ParticleVector & decay) const { // construct the decay vertex VertexPtr vertex(new_ptr(DecayVertex())); DVertexPtr Dvertex(dynamic_ptr_cast(vertex)); // set the incoming particle for the decay vertex (inpart.spinInfo())->decayVertex(vertex); for(unsigned int ix=0;ixspinInfo())->productionVertex(vertex); } // set the matrix element Dvertex->ME(_integrator->ME()); _integrator->ME(DecayMEPtr()); } // output info on the mode ostream & Herwig::operator<<(ostream & os, const DecayPhaseSpaceMode & decay) { os << "The mode has " << decay._channels.size() << " channels\n"; os << "This is a mode for the decay of " << decay._extpart[0]->PDGName() << " to "; for(unsigned int iz=1,N=decay._extpart.size();izPDGName() << " "; } os << "\n"; for(unsigned int ix=0;ix(_extpart[0]->widthGenerator()); for(unsigned int ix=0;ix<_extpart.size();++ix) { assert(_extpart[ix]); _massgen[ix]= dynamic_ptr_cast(_extpart[ix]->massGenerator()); } for(unsigned int ix=0;ix<_channels.size();++ix) { _channels[ix]->init(); } + // set the phase-space cut off + _eps = _integrator->epsilonPS(); } -void DecayPhaseSpaceMode::doinitrun() { +void DecayPhaseSpaceMode::initrun() { // update the mass and width generators if(_extpart[0]->widthGenerator()!=_widthgen) { _widthgen= dynamic_ptr_cast(_extpart[0]->widthGenerator()); } for(unsigned int ix=0;ix<_extpart.size();++ix) { if(_massgen[ix]!=_extpart[ix]->massGenerator()) _massgen[ix] = dynamic_ptr_cast(_extpart[ix]->massGenerator()); } // check the size of the weight vector is the same as the number of channels if(_channelwgts.size()!=numberChannels()) { throw Exception() << "Inconsistent number of channel weights and channels" << " in DecayPhaseSpaceMode " << Exception::abortnow; } for(unsigned int ix=0;ix<_channels.size();++ix) { _channels[ix]->initrun(); } if(_widthgen) const_ptr_cast(_widthgen)->initrun(); tcGenericWidthGeneratorPtr wtemp; for(unsigned int ix=1;ix<_extpart.size();++ix) { wtemp= dynamic_ptr_cast(_extpart[ix]->widthGenerator()); if(wtemp) const_ptr_cast(wtemp)->initrun(); } - Interfaced::doinitrun(); } // generate the masses of the external particles vector DecayPhaseSpaceMode::externalMasses(Energy inmass,double & wgt, bool onShell) const { vector mass(1,inmass); mass.reserve(_extpart.size()); vector notdone; Energy mlow(ZERO); // set masses of stable particles and limits for(unsigned int ix=1;ix<_extpart.size();++ix) { // get the mass of the particle if can't use weight if(onShell) { mass.push_back(_extpart[ix]->mass()); } else if(!_massgen[ix] || _extpart[ix]->stable()) { mass.push_back(_extpart[ix]->generateMass()); mlow+=mass[ix]; } else { mass.push_back(ZERO); notdone.push_back(ix); mlow+=max(_extpart[ix]->mass()-_extpart[ix]->widthLoCut(),ZERO); } } if(mlow>inmass) { - CurrentGenerator::log() << "Decay mode " << _extpart[0]->PDGName() << " -> "; - for(unsigned int ix=1;ix<_extpart.size();++ix) { - CurrentGenerator::log() << _extpart[ix]->PDGName() << " "; - } - CurrentGenerator::log() << "is below threshold in DecayPhaseMode::externalMasses()" - << "the threshold is " << mlow/GeV - << "GeV and the parent mass is " << inmass/GeV - << " GeV\n"; + // if(_integrator->state()==runready) { + // CurrentGenerator::log() << "Decay mode " << _extpart[0]->PDGName() << " -> "; + // for(unsigned int ix=1;ix<_extpart.size();++ix) { + // CurrentGenerator::log() << _extpart[ix]->PDGName() << " "; + // } + // CurrentGenerator::log() << "is below threshold in DecayPhaseMode::externalMasses()" + // << "the threshold is " << mlow/GeV + // << "GeV and the parent mass is " << inmass/GeV + // << " GeV\n"; + // } throw Veto(); } // now we need to generate the masses for the particles we haven't unsigned int iloc; double wgttemp; Energy low=ZERO; for( ;!notdone.empty();) { iloc=long(UseRandom::rnd()*(notdone.size()-1)); low=max(_extpart[notdone[iloc]]->mass()-_extpart[notdone[iloc]]->widthLoCut(),ZERO); mlow-=low; mass[notdone[iloc]]= _massgen[notdone[iloc]]->mass(wgttemp,*_extpart[notdone[iloc]],low,inmass-mlow); assert(mass[notdone[iloc]]>=low&&mass[notdone[iloc]]<=inmass-mlow); wgt *= wgttemp; mlow += mass[notdone[iloc]]; notdone.erase(notdone.begin()+iloc); } return mass; } diff --git a/Decay/DecayPhaseSpaceMode.h b/Decay/DecayPhaseSpaceMode.h --- a/Decay/DecayPhaseSpaceMode.h +++ b/Decay/DecayPhaseSpaceMode.h @@ -1,461 +1,454 @@ // -*- C++ -*- // // DecayPhaseSpaceMode.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_DecayPhaseSpaceMode_H #define HERWIG_DecayPhaseSpaceMode_H // // This is the declaration of the DecayPhaseSpaceMode class. // #include "ThePEG/Interface/Interfaced.h" #include "DecayPhaseSpaceMode.fh" #include "DecayPhaseSpaceChannel.h" #include "Herwig/PDT/GenericWidthGenerator.h" #include "Herwig/PDT/GenericMassGenerator.h" #include #include "DecayIntegrator.h" namespace Herwig { using namespace ThePEG; /** \ingroup Decay * * The DecayPhaseSpaceMode class is designed to store a group * of phase-space channels for use by the DecayIntegrator class to * generate the phase-space for a given decay mode. * * Additional phase-space channels can be added using the addChannel member. * * In practice the modes are usually constructed together with the a number of * DecayPhaseSpaceChannel objects. In classes inheriting from the * DecayIntegrator class. * * @see DecayIntegrator * @see DecayPhaseSpaceChannel * * @author Peter Richardson * */ -class DecayPhaseSpaceMode: public Interfaced { +class DecayPhaseSpaceMode: public Base { /** * A friend operator to allow the mode to be outputted for debugging purposes. */ friend ostream & operator<<(ostream &, const DecayPhaseSpaceMode &); /** * DecayIntegrator is a friend to avoid making many of the phase space * generation members public. */ friend class DecayIntegrator; /** * DecayPhaseSpaceChannel is a friend to avoid making many of the phase space * generation members public */ friend class DecayPhaseSpaceChannel; public: /** @name Standard constructors and destructors. */ //@{ /** * Default constructor. */ DecayPhaseSpaceMode() : _maxweight(0.),_niter(10), _npoint(10000), _ntry(500), _partial(-1), _testOnShell(false), _ichannel(999) {} /** * Constructor with a pointer to a DecayPhaseIntegrator and a vector * of particle data objects for the external particles. This * is the constructor which should normally be used in decayers. * @param in The particle data objects for the external particles * @param intin A pointer to the DecayIntegrator class using this mode. * @param onShell Whether or not to perform tests for zero width on-shell particles */ DecayPhaseSpaceMode(tPDVector in, tcDecayIntegratorPtr intin,bool onShell=false) : _integrator(intin), _maxweight(0.), _niter(10), _npoint(10000), _ntry(500), _extpart(in), _partial(-1), _testOnShell(onShell), _ichannel(999) {} //@} /** * Access to the external particles. * @param ix The external particle required. * @return A pointer to the ParticleData object. */ tcPDPtr externalParticles(int ix) const {return _extpart[ix];} /** * Number of external particles. * @return The number of external particles. */ unsigned int numberofParticles() const {return _extpart.size();} /** * Number of channels * @return The number of channels. */ unsigned int numberChannels() const {return _channels.size();} /** * Add a new channel. * @param channel A pointer to the new DecayPhaseChannel */ void addChannel(DecayPhaseSpaceChannelPtr channel) { channel->init(); _channels.push_back(channel); } /** * Reset the properties of one of the intermediate particles. Only a specific channel * is reset. * @param ichan The channel to reset. * @param part The ParticleData object of the particle to reset * @param mass The mass of the intermediate. * @param width The width of gthe intermediate. */ void resetIntermediate(int ichan, tcPDPtr part, Energy mass, Energy width) { if(!part) return; _channels[ichan]->resetIntermediate(part,mass,width); } /** * Reset the properties of one of the intermediate particles. All the channels * are reset. * @param part The ParticleData object of the particle to reset * @param mass The mass of the intermediate. * @param width The width of gthe intermediate. */ void resetIntermediate(tcPDPtr part, Energy mass, Energy width) { for(unsigned int ix=0,N=_channels.size();ixresetIntermediate(part,mass,width); } /** * Get the maximum weight for the decay. * @return The maximum weight. */ double maxWeight() const {return _maxweight;} /** * Set the maximum weight for the decay. * @param wgt The maximum weight. */ void setMaxWeight(double wgt) const {_maxweight=wgt;} /** * Get the weight for a channel. This is the weight for the multi-channel approach. * @param ichan The channel. * @return The weight for the channel. */ double channelWeight(unsigned int ichan) const {return _channelwgts[ichan];} /** * Set the weights for the different channels. * @param in The weights for the different channels in the multi-channel approach. */ void setWeights(const vector & in) const {_channelwgts=in;} /** * Access to the selected channel */ unsigned int selectedChannel() const {return _ichannel;} /** * test on/off-shell kinematics */ bool testOnShell() const { return _testOnShell; } + /** + * Access to the epsilon parameter + */ + Energy epsilonPS() const {return _eps;} + protected: /** @name Set-up, Initialization and Access Members */ //@{ /** * Initialise the phase space. * @param init Perform the initialization. */ Energy initializePhaseSpace(bool init, bool onShell=false); /** * Set the integration parameters * @param iter The number of iterations to use for initialization. * @param points The number of points to use for each iteration during initialization. * @param ntry The number of tries to generate a decay. */ void setIntegrate(int iter,int points,int ntry) { _niter=iter; _npoint=points; _ntry=ntry; } /** * Set the partial width to use for normalization. This is the partial width * in the WidthGenerator object. * @param in The partial width to use. */ void setPartialWidth(int in) {_partial=in;} //@} /** @name Phase-Space Generation Members */ //@{ /** * Access to the matrix element from the decayer. * @param ichan The channel, this is to allow the matrix element to be used to * select the intermediates * @param inpart The incoming particle. * @param opt The option for what to calculate * @param outpart The outgoing particles. */ double me2(const int ichan ,const Particle & inpart, const ParticleVector &outpart,DecayIntegrator::MEOption opt) const { return _integrator->me2(ichan,inpart,outpart,opt); } /** * Generate the decay. * @param intermediates Whether or not to generate the intermediate particle * in the decay channel. * @param cc Whether we are generating the mode specified or the charge * conjugate mode. * @param inpart The incoming particle. * @return The outgoing particles. */ ParticleVector generate(bool intermediates,bool cc,const Particle & inpart) const; /** * Select which channel to use to output the particles. * @param inpart The incoming particles. * @param outpart The outgoing particles. */ int selectChannel(const Particle & inpart, ParticleVector & outpart) const { // if using flat phase-space don't need to do this if(_channelwgts.empty()) return 0; vector mewgts(_channels.size(),0.0); double total=0.; for(unsigned int ix=0,N=_channels.size();ix0.); return ichan; } /** * Return the weight for a given phase-space point. * @param cc Whether we are generating the mode specified or the charge * conjugate mode. * @param ichan The channel to generate the weight for. * @param in The incoming particle. * @param particles The outgoing particles. * @param first Whether or not this is the first call for initialisation * @return The weight. */ Energy weight(bool cc,int & ichan, const Particle & in, ParticleVector & particles,bool first, bool onShell=false) const { ichan=0; Energy phwgt = (_channels.size()==0) ? flatPhaseSpace(cc,in,particles,onShell) : channelPhaseSpace(cc,ichan,in,particles,onShell); // generate the matrix element return me2(-1,in,particles, first ? DecayIntegrator::Initialize : DecayIntegrator::Calculate)*phwgt; } /** * Return the weight and momenta for a flat phase-space decay. * @param cc Whether we are generating the mode specified or the charge * conjugate mode. * @param inpart The incoming particle. * @param outpart The outgoing particles. * @return The weight. */ Energy flatPhaseSpace(bool cc,const Particle & inpart, ParticleVector & outpart, bool onShell=false) const; /** * Generate a phase-space point using multichannel phase space. * @param cc Whether we are generating the mode specified or the charge * conjugate mode. * @param ichan The channel to generate the weight for. * @param in The incoming particle. * @param particles The outgoing particles. * @return The weight. */ Energy channelPhaseSpace(bool cc,int & ichan, const Particle & in, ParticleVector & particles, bool onShell=false) const; /** * Construct the vertex for spin corrections * @param in The incoming particle. * @param out The outgoing particles. */ void constructVertex(const Particle & in, const ParticleVector & out) const; /** * Generate the masses of the external particles. * @param inmass The mass of the decaying particle. * @param wgt The weight for the masses. * @return The masses. */ vector externalMasses(Energy inmass,double & wgt, bool onShell) const; //@} 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(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(PersistentIStream & is, int version); //@} /** * Standard Init function used to initialize the interfaces. */ static void Init(); protected: - /** @name Clone Methods. */ - //@{ - /** - * Make a simple clone of this object. - * @return a pointer to the new object. - */ - virtual IBPtr clone() const {return new_ptr(*this);} - - /** Make a clone of this object, possibly modifying the cloned object - * to make it sane. - * @return a pointer to the new object. - */ - virtual IBPtr fullclone() const {return new_ptr(*this);} - //@} - -protected: - /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving and * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ - virtual void doinit(); + virtual void init(); /** * Initialize this object to the begining of the run phase. */ - virtual void doinitrun(); + virtual void initrun(); //@} private: /** * Private and non-existent assignment operator. */ DecayPhaseSpaceMode & operator=(const DecayPhaseSpaceMode &); private: /** * pointer to the decayer */ tcDecayIntegratorPtr _integrator; /** * pointers to the phase-space channels */ vector _channels; /** * the weights for the different channels */ mutable vector _channelwgts; /** * the maximum weight for the decay */ mutable double _maxweight; /** * Number of iterations for the initialization. */ int _niter; /** * Number of weights for each iteration of the initialization. */ int _npoint; /** * Number of attempts to generate the decay */ int _ntry; /** * External particles */ tPDVector _extpart; /** * Which of the partial widths of the incoming particle to use */ int _partial; /** * The width generator for the incoming particle. */ cGenericWidthGeneratorPtr _widthgen; /** * The mass generators for the outgoing particles. */ vector _massgen; /** * Whether to check on-shell or off-shell kinematics * in doinit, if on-shell off-shell is tested in initrun */ bool _testOnShell; /** * The selected channel */ mutable unsigned int _ichannel; + /** + * Epsilon parameter for phase-space integration + */ + Energy _eps; + }; /** * The output operator which is used for debugging. */ ostream & operator<<(ostream &, const DecayPhaseSpaceMode &); } #endif /* HERWIG_DecayPhaseSpaceMode_H */ diff --git a/Decay/General/FFSDecayer.cc b/Decay/General/FFSDecayer.cc --- a/Decay/General/FFSDecayer.cc +++ b/Decay/General/FFSDecayer.cc @@ -1,463 +1,465 @@ // -*- C++ -*- // // FFSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 FFSDecayer class. // #include "FFSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr FFSDecayer::clone() const { return new_ptr(*this); } IBPtr FFSDecayer::fullclone() const { return new_ptr(*this); } void FFSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_ .push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertexF_[inter] = AbstractFFVVertexPtr(); outgoingVertexS_[inter] = AbstractVSSVertexPtr(); if(outV[0].at(inter)) { if (outV[0].at(inter)->getName()==VertexType::FFV) outgoingVertexF_[inter] = dynamic_ptr_cast(outV[0].at(inter)); else outgoingVertexS_[inter] = dynamic_ptr_cast(outV[0].at(inter)); } if(outV[1].at(inter)) { if (outV[1].at(inter)->getName()==VertexType::FFV) outgoingVertexF_[inter] = dynamic_ptr_cast(outV[1].at(inter)); else outgoingVertexS_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } } void FFSDecayer::persistentOutput(PersistentOStream & os) const { os << perturbativeVertex_ << vertex_ << incomingVertex_ << outgoingVertexF_ << outgoingVertexS_; } void FFSDecayer::persistentInput(PersistentIStream & is, int) { is >> perturbativeVertex_ >> vertex_ >> incomingVertex_ >> outgoingVertexF_ >> outgoingVertexS_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFFSDecayer("Herwig::FFSDecayer", "Herwig.so"); void FFSDecayer::Init() { static ClassDocumentation documentation ("The FFSDecayer class implements the decay of a fermion to " "a fermion and a scalar."); } double FFSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin0))); //Need to use different barred or unbarred spinors depending on //whether particle is cc or not. int itype[2]; if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0? 0:1; else itype[0] = 2; if(decay[0]->dataPtr()->CC()) itype[1] = decay[0]->id() > 0? 0:1; else itype[1] = 2; bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2)); if(meopt==Initialize) { // spinors and rho if(ferm) { SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_, const_ptr_cast(&inpart), incoming); if(wave_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_, const_ptr_cast(&inpart), incoming); if(wavebar_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave_,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(wavebar_,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar_,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(wave_,decay[0],outgoing,true); } ScalarWaveFunction::constructSpinInfo(decay[1],outgoing,true); } if(ferm) SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[0],outgoing); else SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[0],outgoing); ScalarWaveFunction scal(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int if1 = 0; if1 < 2; ++if1) { for(unsigned int if2 = 0; if2 < 2; ++if2) { if(ferm) (*ME())(if1, if2, 0) = 0.; else (*ME())(if2, if1, 0) = 0.; for(auto vert : vertex_) { if(ferm) (*ME())(if1, if2, 0) += vert->evaluate(scale,wave_[if1],wavebar_[if2],scal); else (*ME())(if2, if1, 0) += vert->evaluate(scale,wave_[if1],wavebar_[if2],scal); } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy FFSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { double mu1(0.),mu2(0.); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; if(outa.first->iSpin() == PDT::Spin1Half) { mu1 = outa.second/inpart.second; mu2 = outb.second/inpart.second; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first); } else { mu1 = outb.second/inpart.second; mu2 = outa.second/inpart.second; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outb.first, outa.first); } double c2 = norm(perturbativeVertex_[0]->norm()); Complex cl = perturbativeVertex_[0]->left(); Complex cr = perturbativeVertex_[0]->right(); double me2 = c2*( (norm(cl) + norm(cr))*(1. + sqr(mu1) - sqr(mu2)) + 2.*mu1*(conj(cl)*cr + conj(cr)*cl).real() ); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second, outb.second); Energy output = me2*pcm/16./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double FFSDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { int iscal (0), iferm (1), iglu (2); // get location of outgoing fermion/scalar if(decay[1]->dataPtr()->iSpin()==PDT::Spin0) swap(iscal,iferm); // work out whether inpart is a fermion or antifermion int itype[2]; if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1; else itype[0] = 2; if(decay[iferm]->dataPtr()->CC()) itype[1] = decay[iferm]->id() > 0 ? 0 : 1; else itype[1] = 2; bool ferm(false); if(itype[0] == itype[1] ) { ferm = itype[0]==0 || (itype[0]==2 && decay[iscal]->id() < 0); } else if(itype[0] == 2) { ferm = itype[1]==0; } else if(itype[1] == 2) { ferm = itype[0]==0; } else if((itype[0] == 1 && itype[1] == 0) || (itype[0] == 0 && itype[1] == 1)) { if(abs(inpart.id())<=16) { ferm = itype[0]==0; } else if(abs(decay[iferm]->id())<=16) { ferm = itype[1]==0; } else { ferm = true; } } else assert(false); if(meopt==Initialize) { // create spinor (bar) for decaying particle if(ferm) { SpinorWaveFunction::calculateWaveFunctions(wave3_, rho3_, const_ptr_cast(&inpart), incoming); if(wave3_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave3_[ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_,rho3_, const_ptr_cast(&inpart), incoming); if(wavebar3_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar3_[ix].conjugate(); } } // setup spin information when needed if(meopt==Terminate) { if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave3_,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(wavebar3_,decay[iferm],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar3_,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(wave3_,decay[iferm],outgoing,true); } ScalarWaveFunction::constructSpinInfo( decay[iscal],outgoing,true); VectorWaveFunction::constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false); return 0.; } // calulate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, PDT::Spin0, PDT::Spin1Half, PDT::Spin1))); // create wavefunctions if (ferm) SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_, decay[iferm],outgoing); else SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[iferm],outgoing); ScalarWaveFunction swave3_(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing); VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(),decay[iglu ]->dataPtr(),10, outgoing)); } } #endif if (! ((incomingVertex_[inter] && (outgoingVertexF_[inter] || outgoingVertexS_[inter])) || (outgoingVertexF_[inter] && outgoingVertexS_[inter]))) throw Exception() << "Invalid vertices for radiation in FFS decay in FFSDecayer::threeBodyME" << Exception::runerror; // sort out colour flows int F(1), S(2); if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[iferm]->dataPtr()->iColour()==PDT::Colour8) swap(F,S); else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar && decay[iscal]->dataPtr()->iColour()==PDT::Colour8) swap(F,S); Complex diag; Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int ifi = 0; ifi < 2; ++ifi) { for(unsigned int ifo = 0; ifo < 2; ++ifo) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming fermion if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); if (ferm) { SpinorWaveFunction spinorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wave3_[ifi], gluon_[2*ig],inpart.mass()); assert(wave3_[ifi].particle()->id()==spinorInter.particle()->id()); diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,spinorInter,wavebar3_[ifo],swave3_); } else { SpinorBarWaveFunction spinorBarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wavebar3_[ifi], gluon_[2*ig],inpart.mass()); assert(wavebar3_[ifi].particle()->id()==spinorBarInter.particle()->id()); diag = 0.; for(auto vertex :vertex_) diag+= vertex->evaluate(scale,wave3_[ifo], spinorBarInter,swave3_); } if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexF_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iferm]->dataPtr(); if(off->CC()) off = off->CC(); if (ferm) { SpinorBarWaveFunction spinorBarInter = outgoingVertexF_[inter]->evaluate(scale,3,off,wavebar3_[ifo], gluon_[2*ig],decay[iferm]->mass()); assert(wavebar3_[ifo].particle()->id()==spinorBarInter.particle()->id()); diag = 0.; for(auto vertex :vertex_) diag+= vertex->evaluate(scale,wave3_[ifi],spinorBarInter,swave3_); } else { SpinorWaveFunction spinorInter = outgoingVertexF_[inter]->evaluate(scale,3,off,wave3_[ifo], gluon_[2*ig],decay[iferm]->mass()); assert(wave3_[ifo].particle()->id()==spinorInter.particle()->id()); diag = 0.; for(auto vertex :vertex_) diag+= vertex->evaluate(scale,spinorInter,wavebar3_[ifi],swave3_); } if(!couplingSet) { gs = abs(outgoingVertexF_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexS_[inter]); // ensure you get correct ougoing particle from first vertex tcPDPtr off = decay[iscal]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig], swave3_,decay[iscal]->mass()); assert(swave3_.particle()->id()==scalarInter.particle()->id()); if (ferm){ diag = 0.; for(auto vertex :vertex_) diag += vertex->evaluate(scale,wave3_[ifi],wavebar3_[ifo],scalarInter); } else { diag = 0.; for(auto vertex :vertex_) diag += vertex->evaluate(scale,wave3_[ifo],wavebar3_[ifi],scalarInter); } if(!couplingSet) { gs = abs(outgoingVertexS_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/FFVCurrentDecayer.cc b/Decay/General/FFVCurrentDecayer.cc --- a/Decay/General/FFVCurrentDecayer.cc +++ b/Decay/General/FFVCurrentDecayer.cc @@ -1,200 +1,202 @@ // -*- C++ -*- // // FFVCurrentDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 FFVCurrentDecayer class. // #include "FFVCurrentDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "ThePEG/StandardModel/StandardModelBase.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using ThePEG::Helicity::VectorWaveFunction; using ThePEG::Helicity::SpinorWaveFunction; using ThePEG::Helicity::SpinorBarWaveFunction; using ThePEG::Helicity::Direction; using ThePEG::Helicity::incoming; using ThePEG::Helicity::outgoing; IBPtr FFVCurrentDecayer::clone() const { return new_ptr(*this); } IBPtr FFVCurrentDecayer::fullclone() const { return new_ptr(*this); } void FFVCurrentDecayer::doinit() { FFVPtr_ = dynamic_ptr_cast(vertex()); GeneralCurrentDecayer::doinit(); } void FFVCurrentDecayer::rebind(const TranslationMap & trans) { FFVPtr_ = trans.translate(FFVPtr_); GeneralCurrentDecayer::rebind(trans); } IVector FFVCurrentDecayer::getReferences() { IVector ret = GeneralCurrentDecayer::getReferences(); ret.push_back(FFVPtr_); return ret; } void FFVCurrentDecayer::persistentOutput(PersistentOStream & os) const { os << FFVPtr_; } void FFVCurrentDecayer::persistentInput(PersistentIStream & is, int) { is >> FFVPtr_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFFVCurrentDecayer("Herwig::FFVCurrentDecayer", "Herwig.so"); void FFVCurrentDecayer::Init() { static ClassDocumentation documentation ("There is no documentation for the FFVCurrentDecayer class"); } double FFVCurrentDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // get the particles for the hadronic curret Energy q; ParticleVector hadpart(decay.begin()+1,decay.end()); // fermion types int itype[2]; if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1; else itype[0] = 2; if(decay[0]->dataPtr()->CC()) itype[1] = decay[0]->id() > 0 ? 0 : 1; else itype[1] = 2; //Need to use different barred or unbarred spinors depending on //whether particle is cc or not. bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2)); if(meopt==Initialize) { // spinors and rho if(ferm) { SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_, const_ptr_cast(&inpart), incoming); if(wave_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_, const_ptr_cast(&inpart), incoming); if(wavebar_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave_,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(wavebar_,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar_,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(wave_,decay[0],outgoing,true); } weakCurrent()->current(mode(),ichan,q,hadpart,meopt); return 0.; } Energy2 scale(sqr(inpart.mass())); if(ferm) SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[0],outgoing); else SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[0],outgoing); // calculate the hadron current vector hadron(weakCurrent()->current(mode(),ichan,q,hadpart,meopt)); // prefactor double pre = sqr(pow(inpart.mass()/q,int(hadpart.size()-2))); // work out the mapping for the hadron vector vector constants(decay.size()+1),ihel(decay.size()+1); vector ispin(decay.size()); int itemp(1); unsigned int hhel,ix(decay.size()); do { --ix; ispin[ix]=decay[ix]->data().iSpin(); itemp*=ispin[ix]; constants[ix]=itemp; } while(ix>0); constants[decay.size()]=1; constants[0]=constants[1]; // compute the matrix element GeneralDecayMEPtr newME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,ispin))); VectorWaveFunction vWave; tcPDPtr vec= inpart.dataPtr()->iCharge()-decay[0]->dataPtr()->iCharge() > 0 ? getParticleData(ParticleID::Wplus) : getParticleData(ParticleID::Wminus); Lorentz5Momentum vmom=inpart.momentum()-decay[0]->momentum(); vmom.rescaleMass(); for(hhel=0;hhel1;--ix) ihel[ix]=(hhel%constants[ix-1])/constants[ix]; vWave=VectorWaveFunction(vmom,vec,hadron[hhel]*UnitRemoval::InvE,outgoing); for(unsigned int if1 = 0; if1 < 2; ++if1) { for(unsigned int if2 = 0; if2 < 2; ++if2) { ihel[0]=if1; ihel[1]=if2; if(!ferm) swap(ihel[0],ihel[1]); (*newME)(ihel) = FFVPtr_->evaluate(scale,wave_[if1],wavebar_[if2],vWave); } } } // store the matrix element ME(newME); // multiply by the CKM element int iq,ia; weakCurrent()->decayModeInfo(mode(),iq,ia); double ckm(1.); if(iq<=6) { if(iq%2==0) ckm = SM().CKM(iq/2-1,(abs(ia)-1)/2); else ckm = SM().CKM(abs(ia)/2-1,(iq-1)/2); } pre /= 0.125*sqr(FFVPtr_->weakCoupling(scale)); double output(0.5*pre*ckm*(ME()->contract(rho_)).real()* sqr(SM().fermiConstant()*UnitRemoval::E2)); return output; } Energy FFVCurrentDecayer::partialWidth(tPDPtr inpart, tPDPtr outa, vector currout) { vector id; id.push_back(inpart->id()); id.push_back(outa->id()); for(unsigned int ix=0;ixid()); bool cc; int mode=modeNumber(cc,id); imode(mode); return initializePhaseSpaceMode(mode,true,true); } diff --git a/Decay/General/FFVDecayer.cc b/Decay/General/FFVDecayer.cc --- a/Decay/General/FFVDecayer.cc +++ b/Decay/General/FFVDecayer.cc @@ -1,456 +1,458 @@ // -*- C++ -*- // // FFVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 FFVDecayer class. // #include "FFVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr FFVDecayer::clone() const { return new_ptr(*this); } IBPtr FFVDecayer::fullclone() const { return new_ptr(*this); } void FFVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_ .push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); if(outV[0].at(inter)) { if (outV[0].at(inter)->getName()==VertexType::FFV) outgoingVertexF_[inter] = dynamic_ptr_cast(outV[0].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[0].at(inter)); } if(outV[1].at(inter)) { if (outV[1].at(inter)->getName()==VertexType::FFV) outgoingVertexF_[inter] = dynamic_ptr_cast(outV[1].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } } void FFVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertexF_ << outgoingVertexV_; } void FFVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertexF_ >> outgoingVertexV_; } double FFVDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half,PDT::Spin1))); // type of process int itype[2]; if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1; else itype[0] = 2; if(decay[0]->dataPtr()->CC()) itype[1] = decay[0]->id() > 0 ? 0 : 1; else itype[1] = 2; //Need to use different barred or unbarred spinors depending on //whether particle is cc or not. bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2)); if(meopt==Initialize) { // spinors and rho if(ferm) { SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_, const_ptr_cast(&inpart), incoming); if(wave_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_, const_ptr_cast(&inpart), incoming); if(wavebar_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave_,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(wavebar_,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar_,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(wave_,decay[0],outgoing,true); } VectorWaveFunction:: constructSpinInfo(vector_,decay[1],outgoing,true,false); } Energy2 scale(sqr(inpart.mass())); if(ferm) SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[0],outgoing); else SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[0],outgoing); bool massless = decay[1]->dataPtr()->mass()==ZERO; VectorWaveFunction:: calculateWaveFunctions(vector_,decay[1],outgoing,massless); for(unsigned int if1 = 0; if1 < 2; ++if1) { for(unsigned int if2 = 0; if2 < 2; ++if2) { for(unsigned int vhel = 0; vhel < 3; ++vhel) { if(massless && vhel == 1) ++vhel; if(ferm) (*ME())(if1, if2,vhel) = 0.; else (*ME())(if2, if1, vhel) = 0.; for(auto vertex : vertex_) { if(ferm) (*ME())(if1, if2,vhel) += vertex->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]); else (*ME())(if2, if1, vhel) += vertex->evaluate(scale,wave_[if1],wavebar_[if2],vector_[vhel]); } } } } double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),decay[1]->dataPtr()); // return the answer return output; } Energy FFVDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { double mu1(outa.second/inpart.second),mu2(outb.second/inpart.second); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; if( outa.first->iSpin() == PDT::Spin1Half) perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first); else { swap(mu1,mu2); perturbativeVertex_[0]->setCoupling(sqr(inpart.second),in, outb.first,outa.first); } Complex cl(perturbativeVertex_[0]->left()),cr(perturbativeVertex_[0]->right()); double me2(0.); if( mu2 > 0. ) { me2 = (norm(cl) + norm(cr))*(1. + sqr(mu1*mu2) + sqr(mu2) - 2.*sqr(mu1) - 2.*sqr(mu2*mu2) + sqr(mu1*mu1)) - 6.*mu1*sqr(mu2)*(conj(cl)*cr + conj(cr)*cl).real(); me2 /= sqr(mu2); } else me2 = 2.*( (norm(cl) + norm(cr))*(sqr(mu1) + 1.) - 4.*mu1*(conj(cl)*cr + conj(cr)*cl).real() ); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second, outb.second); Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm/16./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFFVDecayer("Herwig::FFVDecayer", "Herwig.so"); void FFVDecayer::Init() { static ClassDocumentation documentation ("The FFVDecayer class implements the decay of a fermion to a fermion and a vector boson"); } double FFVDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { int iferm (0), ivect (1), iglu (2); // get location of outgoing lepton/vector if(decay[1]->dataPtr()->iSpin()==PDT::Spin1Half) swap(iferm,ivect); // work out whether inpart is a fermion or antifermion int itype[2]; if(inpart.dataPtr()->CC()) itype[0] = inpart.id() > 0 ? 0 : 1; else itype[0] = 2; if(decay[iferm]->dataPtr()->CC()) itype[1] = decay[iferm]->id() > 0 ? 0 : 1; else itype[1] = 2; bool ferm(itype[0] == 0 || itype[1] == 0 || (itype[0] == 2 && itype[1] == 2 && decay[ivect]->id() < 0)); // no emissions from massive vectors bool massless = decay[ivect]->dataPtr()->mass()==ZERO; if(meopt==Initialize) { // create spinor (bar) for decaying particle if(ferm) { SpinorWaveFunction::calculateWaveFunctions(wave3_, rho3_, const_ptr_cast(&inpart), incoming); if(wave3_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave3_[ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_,rho3_, const_ptr_cast(&inpart), incoming); if(wavebar3_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar3_[ix].conjugate(); } } // setup spin information when needed if(meopt==Terminate) { if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave3_,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(wavebar3_,decay[iferm],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar3_,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(wave3_,decay[iferm],outgoing,true); } VectorWaveFunction::constructSpinInfo(vector3_, decay[ivect],outgoing,true,massless); VectorWaveFunction::constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false); return 0.; } // calulate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, PDT::Spin1Half, PDT::Spin1, PDT::Spin1))); // create wavefunctions if (ferm) SpinorBarWaveFunction::calculateWaveFunctions(wavebar3_, decay[iferm],outgoing); else SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[iferm],outgoing); VectorWaveFunction::calculateWaveFunctions(vector3_, decay[ivect],outgoing,massless); VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true ); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif if (! ((incomingVertex_[inter] && (outgoingVertexF_[inter] || outgoingVertexV_[inter])) || (outgoingVertexF_[inter] && outgoingVertexV_[inter]))) throw Exception() << "Invalid vertices for QCD radiation in FFV decay in FFVDecayer::threeBodyME" << Exception::runerror; // sort out colour flows int F(1), V(2); if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar && decay[ivect]->dataPtr()->iColour()==PDT::Colour8) swap(F,V); else if (decay[ivect]->dataPtr()->iColour()==PDT::Colour3 && decay[iferm]->dataPtr()->iColour()==PDT::Colour8) swap(F,V); Complex diag; Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int ifi = 0; ifi < 2; ++ifi) { for(unsigned int ifo = 0; ifo < 2; ++ifo) { for(unsigned int iv = 0; iv < 3; ++iv) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming fermion if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); if (ferm){ SpinorWaveFunction spinorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wave3_[ifi], gluon_[2*ig],inpart.mass()); assert(wave3_[ifi].particle()->id()==spinorInter.particle()->id()); diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,spinorInter,wavebar3_[ifo],vector3_[iv]); } else { SpinorBarWaveFunction spinorBarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),wavebar3_[ifi], gluon_[2*ig],inpart.mass()); assert(wavebar3_[ifi].particle()->id()==spinorBarInter.particle()->id()); diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ifo], spinorBarInter,vector3_[iv]); } if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexF_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iferm]->dataPtr(); if(off->CC()) off = off->CC(); if (ferm) { SpinorBarWaveFunction spinorBarInter = outgoingVertexF_[inter]->evaluate(scale,3,off,wavebar3_[ifo], gluon_[2*ig],decay[iferm]->mass()); assert(wavebar3_[ifo].particle()->id()==spinorBarInter.particle()->id()); diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ifi],spinorBarInter,vector3_[iv]); } else { SpinorWaveFunction spinorInter = outgoingVertexF_[inter]->evaluate(scale,3,off,wave3_[ifo], gluon_[2*ig],decay[iferm]->mass()); assert(wave3_[ifo].particle()->id()==spinorInter.particle()->id()); diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,spinorInter,wavebar3_[ifi],vector3_[iv]); } if(!couplingSet) { gs = abs(outgoingVertexF_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ivect]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexV_[inter]); // ensure you get correct ougoing particle from first vertex tcPDPtr off = decay[ivect]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig], vector3_[iv],decay[ivect]->mass()); assert(vector3_[iv].particle()->id()==vectorInter.particle()->id()); if (ferm) { diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ifi],wavebar3_[ifo],vectorInter); } else { diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ifo],wavebar3_[ifi],vectorInter); } if(!couplingSet) { gs = abs(outgoingVertexV_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha(S,eM) output *= (4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/FRSDecayer.cc b/Decay/General/FRSDecayer.cc --- a/Decay/General/FRSDecayer.cc +++ b/Decay/General/FRSDecayer.cc @@ -1,189 +1,191 @@ // -*- C++ -*- // // FRSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 FRSDecayer class. // #include "FRSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr FRSDecayer::clone() const { return new_ptr(*this); } IBPtr FRSDecayer::fullclone() const { return new_ptr(*this); } void FRSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map &, const vector > &, map) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } } void FRSDecayer::persistentOutput(PersistentOStream & os) const { os << perturbativeVertex_ << vertex_; } void FRSDecayer::persistentInput(PersistentIStream & is, int) { is >> perturbativeVertex_ >> vertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFRSDecayer("Herwig::FRSDecayer", "Herwig.so"); void FRSDecayer::Init() { static ClassDocumentation documentation ("The FRSDecayer class implements the decay of a fermion to " "a spin-3/2 fermion and a scalar."); } double FRSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { bool ferm = inpart.id() > 0; if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin3Half,PDT::Spin0))); if(meopt==Initialize) { // spinors and rho if(ferm) { SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_, const_ptr_cast(&inpart), incoming); if(wave_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_, const_ptr_cast(&inpart), incoming); if(wavebar_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave_,const_ptr_cast(&inpart),incoming,true); RSSpinorBarWaveFunction::constructSpinInfo(RSwavebar_,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar_,const_ptr_cast(&inpart),incoming,true); RSSpinorWaveFunction::constructSpinInfo(RSwave_,decay[0],outgoing,true); } ScalarWaveFunction::constructSpinInfo(decay[1],outgoing,true); } if(ferm) RSSpinorBarWaveFunction:: calculateWaveFunctions(RSwavebar_,decay[0],outgoing); else RSSpinorWaveFunction:: calculateWaveFunctions(RSwave_ ,decay[0],outgoing); ScalarWaveFunction scal(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int if1 = 0; if1 < 2; ++if1) { for(unsigned int if2 = 0; if2 < 4; ++if2) { (*ME())(if1, if2, 0) = 0.; for(auto vert : vertex_) { if(ferm) (*ME())(if1, if2, 0) += vert->evaluate(scale,wave_[if1],RSwavebar_[if2],scal); else (*ME())(if1, if2, 0) += vert->evaluate(scale,RSwave_[if2],wavebar_[if1],scal); } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // test code // Energy q = inpart.mass(); // Energy m1 = decay[0]->mass(); // Energy m2 = decay[1]->mass(); // Energy2 q2(q*q),m12(m1*m1),m22(m2*m2); // Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2); // Energy pcm(sqrt(pcm2)); // Energy Qp(sqrt((q+m1)*(q+m1)-m22)),Qm(sqrt((q-m1)*(q-m1)-m22)); // double r23(sqrt(2./3.)); // // couplings // Complex left = perturbativeVertex_-> left()*perturbativeVertex_-> norm(); // Complex right = perturbativeVertex_->right()*perturbativeVertex_-> norm(); // complex A1 = 0.5*(left+right)*UnitRemoval::InvE; // complex B1 = 0.5*(right-left)*UnitRemoval::InvE; // complex h1(-2.*r23*pcm*q/m1*Qm*B1); // complex h2( 2.*r23*pcm*q/m1*Qp*A1); // cout << "testing 1/2->3/2 0 " // << output*scale/GeV2 << " " // << real(h1*conj(h1)+h2*conj(h2))/4./GeV2 << " " // << real(h1*conj(h1)+h2*conj(h2))/4./(output*scale) << endl; // return the answer return output; } Energy FRSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy q = inpart.second; Energy m1 = outa.second; Energy m2 = outb.second; Energy2 q2(q*q),m12(m1*m1),m22(m2*m2); Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2); Energy pcm(sqrt(pcm2)); Energy Qp(sqrt((q+m1)*(q+m1)-m22)),Qm(sqrt((q-m1)*(q-m1)-m22)); double r23(sqrt(2./3.)); // couplings tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first, in, outb.first); Complex left = perturbativeVertex_[0]-> left()*perturbativeVertex_[0]-> norm(); Complex right = perturbativeVertex_[0]->right()*perturbativeVertex_[0]-> norm(); complex A1 = 0.5*(left+right)*UnitRemoval::InvE; complex B1 = 0.5*(right-left)*UnitRemoval::InvE; complex h1(-2.*r23*pcm*q/m1*Qm*B1); complex h2( 2.*r23*pcm*q/m1*Qp*A1); double me2 = real(h1*conj(h1)+h2*conj(h2))/4./sqr(inpart.second); Energy output = me2*pcm/8./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } diff --git a/Decay/General/FRVDecayer.cc b/Decay/General/FRVDecayer.cc --- a/Decay/General/FRVDecayer.cc +++ b/Decay/General/FRVDecayer.cc @@ -1,219 +1,221 @@ // -*- C++ -*- // // FRVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 FRVDecayer class. // #include "FRVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr FRVDecayer::clone() const { return new_ptr(*this); } IBPtr FRVDecayer::fullclone() const { return new_ptr(*this); } void FRVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map &, const vector > &, map) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } } void FRVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_; } void FRVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_; } double FRVDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin3Half,PDT::Spin1))); // decaying fermion or antifermion bool ferm = inpart.id() > 0; // initialize if(meopt==Initialize) { // spinors and rho if(ferm) { SpinorWaveFunction ::calculateWaveFunctions(wave_,rho_, const_ptr_cast(&inpart), incoming); if(wave_[0].wave().Type() != SpinorType::u) for(unsigned int ix = 0; ix < 2; ++ix) wave_ [ix].conjugate(); } else { SpinorBarWaveFunction::calculateWaveFunctions(wavebar_,rho_, const_ptr_cast(&inpart), incoming); if(wavebar_[0].wave().Type() != SpinorType::v) for(unsigned int ix = 0; ix < 2; ++ix) wavebar_[ix].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) { SpinorWaveFunction:: constructSpinInfo(wave_,const_ptr_cast(&inpart),incoming,true); RSSpinorBarWaveFunction::constructSpinInfo(RSwavebar_,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(wavebar_,const_ptr_cast(&inpart),incoming,true); RSSpinorWaveFunction::constructSpinInfo(RSwave_,decay[0],outgoing,true); } VectorWaveFunction:: constructSpinInfo(vector_,decay[1],outgoing,true,false); } Energy2 scale(sqr(inpart.mass())); if(ferm) RSSpinorBarWaveFunction:: calculateWaveFunctions(RSwavebar_,decay[0],outgoing); else RSSpinorWaveFunction:: calculateWaveFunctions(RSwave_ ,decay[0],outgoing); bool massless = decay[1]->dataPtr()->mass()==ZERO; VectorWaveFunction:: calculateWaveFunctions(vector_,decay[1],outgoing,massless); // loop over helicities for(unsigned int if1 = 0; if1 < 2; ++if1) { for(unsigned int if2 = 0; if2 < 4; ++if2) { for(unsigned int vhel = 0; vhel < 3; ++vhel) { if(massless && vhel == 1) ++vhel; (*ME())(if1, if2,vhel) = 0.; for(auto vert : vertex_) { if(ferm) (*ME())(if1, if2,vhel) += vert->evaluate(scale,wave_[if1], RSwavebar_[if2],vector_[vhel]); else (*ME())(if1, if2, vhel) += vert->evaluate(scale,RSwave_[if2], wavebar_[if1],vector_[vhel]); } } } } double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // test // Energy m1(inpart.mass()),m2(decay[0]->mass()),m3(decay[1]->mass()); // Energy2 m12(m1*m1),m22(m2*m2),m32(m3*m3); // Energy Qp(sqrt(sqr(m1+m2)-sqr(m3))),Qm(sqrt(sqr(m1-m2)-sqr(m3))); // double r2(sqrt(2.)),r3(sqrt(3.)); // Energy pcm(Kinematics::pstarTwoBodyDecay(m1,m2,m3)); // vector left = perturbativeVertex_-> left(); // vector right = perturbativeVertex_->right(); // Complex A1 = 0.5*(left [0]+right[0])*perturbativeVertex_-> norm(); // Complex B1 = 0.5*(right[0]- left[0])*perturbativeVertex_-> norm(); // complex A2 = 0.5*(left [1]+right[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE; // complex B2 = 0.5*(right[1]- left[1])*perturbativeVertex_-> norm()*UnitRemoval::InvE; // complex A3 = 0.5*(left [2]+right[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2; // complex B3 = 0.5*(right[2]- left[2])*perturbativeVertex_-> norm()*UnitRemoval::InvE2; // complex h1(-2.*Qp*A1),h2(2.*Qm*B1); // complex h3(-2./r3*Qp*(A1-Qm*Qm/m2*A2)); // complex h4( 2./r3*Qm*(B1-Qp*Qp/m2*B2)); // complex h5(ZERO),h6(ZERO); // if(decay[1]->mass()>ZERO) { // h5 = -2.*r2/r3/m2/m3*Qp*(0.5*(m12-m22-m32)*A1+0.5*Qm*Qm*(m1+m2)*A2 // +m12*pcm*pcm*A3); // h6 = 2.*r2/r3/m2/m3*Qm*(0.5*(m12-m22-m32)*B1-0.5*Qp*Qp*(m1-m2)*B2 // +m12*pcm*pcm*B3); // } // cout << "testing 1/2->3/2 1 " << inpart.id() << " " // << output << " " // << 0.25*(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+ // h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.mass()) << " " // << 0.25*(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+ // h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.mass())/output << endl; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(),decay[1]->dataPtr()); // return the answer return output; } Energy FRVDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy m1(inpart.second),m2(outa.second),m3(outb.second); Energy2 m12(m1*m1),m22(m2*m2),m32(m3*m3); Energy Qp(sqrt(sqr(m1+m2)-sqr(m3))),Qm(sqrt(sqr(m1-m2)-sqr(m3))); double r2(sqrt(2.)),r3(sqrt(3.)); Energy pcm(Kinematics::pstarTwoBodyDecay(m1,m2,m3)); // couplings tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first, in, outb.first); vector left = perturbativeVertex_[0]-> left(); vector right = perturbativeVertex_[0]->right(); Complex A1 = 0.5*(left [0]+right[0])*perturbativeVertex_[0]-> norm(); Complex B1 = 0.5*(right[0]- left[0])*perturbativeVertex_[0]-> norm(); complex A2 = 0.5*(left [1]+right[1])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE; complex B2 = 0.5*(right[1]- left[1])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE; complex A3 = 0.5*(left [2]+right[2])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE2; complex B3 = 0.5*(right[2]- left[2])*perturbativeVertex_[0]-> norm()*UnitRemoval::InvE2; complex h1(-2.*Qp*A1),h2(2.*Qm*B1); complex h3(-2./r3*Qp*(A1-Qm*Qm/m2*A2)); complex h4( 2./r3*Qm*(B1-Qp*Qp/m2*B2)); complex h5(ZERO),h6(ZERO); if(outb.second>ZERO) { h5 = -2.*r2/r3/m2/m3*Qp*(0.5*(m12-m22-m32)*A1+0.5*Qm*Qm*(m1+m2)*A2 +m12*pcm*pcm*A3); h6 = 2.*r2/r3/m2/m3*Qm*(0.5*(m12-m22-m32)*B1-0.5*Qp*Qp*(m1-m2)*B2 +m12*pcm*pcm*B3); } double me2 = 0.25*real(h1*conj(h1)+h2*conj(h2)+h3*conj(h3)+ h4*conj(h4)+h5*conj(h5)+h6*conj(h6))/sqr(inpart.second); Energy output = me2*pcm/8./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFRVDecayer("Herwig::FRVDecayer", "Herwig.so"); void FRVDecayer::Init() { static ClassDocumentation documentation ("The FRVDecayer class handles the decay of a fermion to " "a spin-3/2 particle and a vector boson."); } diff --git a/Decay/General/FtoFFFDecayer.cc b/Decay/General/FtoFFFDecayer.cc --- a/Decay/General/FtoFFFDecayer.cc +++ b/Decay/General/FtoFFFDecayer.cc @@ -1,309 +1,311 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the FtoFFFDecayer class. // #include "FtoFFFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Decay/DecayPhaseSpaceMode.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; IBPtr FtoFFFDecayer::clone() const { return new_ptr(*this); } IBPtr FtoFFFDecayer::fullclone() const { return new_ptr(*this); } void FtoFFFDecayer::persistentOutput(PersistentOStream & os) const { os << sca_ << vec_ << ten_; } void FtoFFFDecayer::persistentInput(PersistentIStream & is, int) { is >> sca_ >> vec_ >> ten_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFtoFFFDecayer("Herwig::FtoFFFDecayer", "Herwig.so"); void FtoFFFDecayer::Init() { static ClassDocumentation documentation ("The FtoFFFDecayer class implements the general decay of a fermion to " "three fermions."); } -void FtoFFFDecayer::doinit() { - GeneralThreeBodyDecayer::doinit(); +void FtoFFFDecayer::setupDiagrams(bool kinCheck) { + GeneralThreeBodyDecayer::setupDiagrams(kinCheck); if(outgoing().empty()) return; unsigned int ndiags = getProcessInfo().size(); sca_.resize(ndiags); vec_.resize(ndiags); ten_.resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { TBDiagram current = getProcessInfo()[ix]; tcPDPtr offshell = current.intermediate; if( offshell->CC() ) offshell = offshell->CC(); if(offshell->iSpin() == PDT::Spin0) { AbstractFFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a scalar diagram in FtoFFFDecayer::doinit()" + << "Invalid vertices for a scalar diagram in FtoFFFDecayer::setupDiagrams()" << Exception::runerror; sca_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1) { AbstractFFVVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a vector diagram in FtoFFFDecayer::doinit()" + << "Invalid vertices for a vector diagram in FtoFFFDecayer::setupDiagrams()" << Exception::runerror; vec_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin2) { AbstractFFTVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFTVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a tensor diagram in FtoFFFDecayer::doinit()" + << "Invalid vertices for a tensor diagram in FtoFFFDecayer::setupDiagrams()" << Exception::runerror; ten_[ix] = make_pair(vert1, vert2); } } } double FtoFFFDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming != inpart.id(); // special handling or first/last call const vector > cfactors(getColourFactors()); const vector > nfactors(getLargeNcColourFactors()); const size_t ncf(numberOfFlows()); Energy2 scale(sqr(inpart.mass())); if(meopt==Initialize) { SpinorWaveFunction:: calculateWaveFunctions(inwave_.first,rho_,const_ptr_cast(&inpart), Helicity::incoming); inwave_.second.resize(2); if(inwave_.first[0].wave().Type() == SpinorType::u) { for(unsigned int ix = 0; ix < 2; ++ix) { inwave_.second[ix] = inwave_.first[ix].bar(); inwave_.second[ix].conjugate(); } } else { for(unsigned int ix = 0; ix < 2; ++ix) { inwave_.second[ix] = inwave_.first[ix].bar(); inwave_.first[ix].conjugate(); } } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(inpart.id()<0) SpinorWaveFunction::constructSpinInfo(inwave_.first, const_ptr_cast(&inpart), Helicity::incoming,true); else SpinorBarWaveFunction::constructSpinInfo(inwave_.second, const_ptr_cast(&inpart), Helicity::incoming,true); // outgoing particles for(unsigned int ix = 0; ix < 3; ++ix) { SpinorWaveFunction:: constructSpinInfo(outwave_[ix].first,decay[ix],Helicity::outgoing,true); } } // outgoing particles for(unsigned int ix = 0; ix < 3; ++ix) { SpinorWaveFunction:: calculateWaveFunctions(outwave_[ix].first,decay[ix],Helicity::outgoing); outwave_[ix].second.resize(2); if(outwave_[ix].first[0].wave().Type() == SpinorType::u) { for(unsigned int iy = 0; iy < 2; ++iy) { outwave_[ix].second[iy] = outwave_[ix].first[iy].bar(); outwave_[ix].first[iy].conjugate(); } } else { for(unsigned int iy = 0; iy < 2; ++iy) { outwave_[ix].second[iy] = outwave_[ix].first[iy].bar(); outwave_[ix].second[iy].conjugate(); } } } bool ferm = inpart.id()>0; vector flows(ncf, Complex(0.)),largeflows(ncf, Complex(0.)); static const unsigned int out2[3]={1,0,0},out3[3]={2,2,1}; vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); unsigned int ihel[4]; for(ihel[0] = 0; ihel[0] < 2; ++ihel[0]) { for(ihel[1] = 0; ihel[1] < 2; ++ihel[1]) { for(ihel[2] = 0; ihel[2] < 2; ++ihel[2]) { for(ihel[3] = 0; ihel[3] < 2; ++ihel[3]) { flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag=0; for(vector::const_iterator dit=getProcessInfo().begin(); dit!=getProcessInfo().end();++dit) { if(ichan>=0&&diagramMap()[ichan]!=idiag) { ++idiag; continue; } // the sign from normal ordering double sign = ferm ? 1. : -1; // outgoing wavefunction and NO sign if (dit->channelType==TBDiagram::channel23) sign *= -1.; else if(dit->channelType==TBDiagram::channel13) sign *= 1.; else if(dit->channelType==TBDiagram::channel12) sign *= -1.; else throw Exception() << "Unknown diagram type in FtoFFFDecayer::me2()" << Exception::runerror; // wavefunctions SpinorWaveFunction w0,w3; SpinorBarWaveFunction w1,w2; // incoming wavefunction if(ferm) { w0 = inwave_.first [ihel[0]]; w1 = outwave_[dit->channelType].second[ihel[dit->channelType+1]]; } else { w0 = outwave_[dit->channelType].first [ihel[dit->channelType+1]]; w1 = inwave_.second[ihel[0]]; } if(decay[out2[dit->channelType]]->id()<0&& decay[out3[dit->channelType]]->id()>0) { w2 = outwave_[out3[dit->channelType]].second[ihel[out3[dit->channelType]+1]]; w3 = outwave_[out2[dit->channelType]].first [ihel[out2[dit->channelType]+1]]; sign *= -1.; } else { w2 = outwave_[out2[dit->channelType]].second[ihel[out2[dit->channelType]+1]]; w3 = outwave_[out3[dit->channelType]].first [ihel[out3[dit->channelType]+1]]; } tcPDPtr offshell = dit->intermediate; if(cc&&offshell->CC()) offshell=offshell->CC(); Complex diag(0.); // intermediate scalar if (offshell->iSpin() == PDT::Spin0) { ScalarWaveFunction inters = sca_[idiag].first-> evaluate(scale, widthOption(), offshell, w0, w1); diag = sca_[idiag].second->evaluate(scale,w3,w2,inters); } // intermediate vector else if(offshell->iSpin() == PDT::Spin1) { VectorWaveFunction interv = vec_[idiag].first-> evaluate(scale, widthOption(), offshell, w0, w1); diag = vec_[idiag].second->evaluate(scale,w3,w2,interv); } // intermediate tensor else if(offshell->iSpin() == PDT::Spin2) { TensorWaveFunction intert = ten_[idiag].first-> evaluate(scale, widthOption(), offshell, w0, w1); diag = ten_[idiag].second->evaluate(scale,w3,w2,intert); } // unknown else throw Exception() << "Unknown intermediate in FtoFFFDecayer::me2()" << Exception::runerror; // apply NO sign diag *= sign; // matrix element for the different colour flows if(ichan<0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; } // now add the flows to the me2 with appropriate colour factors for(unsigned int ix = 0; ix < ncf; ++ix) { (*mes[ix])(ihel[0],ihel[1],ihel[2],ihel[3]) = flows[ix]; (*mel[ix])(ihel[0],ihel[1],ihel[2],ihel[3]) = largeflows[ix]; } } } } } double me2(0.); if(ichan<0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix==iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *=UseRandom::rnd(); for(unsigned int ix=0;ixcontract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2; } WidthCalculatorBasePtr FtoFFFDecayer:: threeBodyMEIntegrator(const DecayMode & ) const { vector intype; vector inmass,inwidth; vector inpow,inweights; constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow,*this,0, outgoing()[0]->mass(),outgoing()[1]->mass(),outgoing()[2]->mass(), relativeError())); } diff --git a/Decay/General/FtoFFFDecayer.h b/Decay/General/FtoFFFDecayer.h --- a/Decay/General/FtoFFFDecayer.h +++ b/Decay/General/FtoFFFDecayer.h @@ -1,142 +1,137 @@ // -*- C++ -*- #ifndef HERWIG_FtoFFFDecayer_H #define HERWIG_FtoFFFDecayer_H // // This is the declaration of the FtoFFFDecayer class. // #include "GeneralThreeBodyDecayer.h" #include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h" namespace Herwig { using namespace ThePEG; /** * The FtoFFFDecayer class provides the general matrix elements for the * decay of a (anti)fermion to three (anti)fermions. * * @see \ref FtoFFFDecayerInterfaces "The interfaces" * defined for FtoFFFDecayer. */ class FtoFFFDecayer: public GeneralThreeBodyDecayer { public: /** * Return the matrix element squared for a given mode and phase-space channel * @param ichan The channel we are calculating the matrix element for. * @param part The decaying Particle. * @param decay The particles produced in the decay. * @param meopt Option for the matrix element * @return The matrix element squared for the phase-space configuration. */ virtual double me2(const int ichan, const Particle & part, const ParticleVector & decay, MEOption meopt) const; /** * Method to return an object to calculate the 3 (or higher body) partial width * @param dm The DecayMode * @return A pointer to a WidthCalculatorBase object capable of calculating the width */ virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const; 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(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(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 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 IBPtr fullclone() const; //@} protected: - /** @name Standard Interfaced functions. */ - //@{ /** - * Initialize this object after the setup phase before saving an - * EventGenerator to disk. - * @throws InitException if object could not be initialized properly. + * Set up the diagrams etc */ - virtual void doinit(); - //@} + virtual void setupDiagrams(bool checkKinematics); private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ FtoFFFDecayer & operator=(const FtoFFFDecayer &); private: /** * Store the vector of FFSVertex pairs */ vector > sca_; /** * Store the vector of FFVVertex pairs */ vector > vec_; /** * Store the vector of FFTVertex pairs */ vector > ten_; /** * Spin density matrix */ mutable RhoDMatrix rho_; /** * Spinors for incoming particle */ mutable pair,vector > inwave_; /** * Spinors for outgoing particles */ mutable pair,vector > outwave_[3]; }; } #endif /* HERWIG_FtoFFFDecayer_H */ diff --git a/Decay/General/FtoFVVDecayer.cc b/Decay/General/FtoFVVDecayer.cc --- a/Decay/General/FtoFVVDecayer.cc +++ b/Decay/General/FtoFVVDecayer.cc @@ -1,401 +1,403 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the FtoFVVDecayer class. // #include "FtoFVVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Decay/DecayPhaseSpaceMode.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; IBPtr FtoFVVDecayer::clone() const { return new_ptr(*this); } IBPtr FtoFVVDecayer::fullclone() const { return new_ptr(*this); } void FtoFVVDecayer::persistentOutput(PersistentOStream & os) const { os << sca_ << fer_ << vec_ << ten_; } void FtoFVVDecayer::persistentInput(PersistentIStream & is, int) { is >> sca_ >> fer_ >> vec_ >> ten_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigFtoFVVDecayer("Herwig::FtoFVVDecayer", "Herwig.so"); void FtoFVVDecayer::Init() { static ClassDocumentation documentation ("The FtoFVVDecayer class implements the general decay of a fermion to " "a fermion and a pair of vectors."); } -void FtoFVVDecayer::doinit() { - GeneralThreeBodyDecayer::doinit(); +void FtoFVVDecayer::setupDiagrams(bool kinCheck) { + GeneralThreeBodyDecayer::setupDiagrams(kinCheck); if(outgoing().empty()) return; unsigned int ndiags = getProcessInfo().size(); sca_.resize(ndiags); fer_.resize(ndiags); vec_.resize(ndiags); ten_.resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { TBDiagram current = getProcessInfo()[ix]; tcPDPtr offshell = current.intermediate; if(offshell->iSpin() == PDT::Spin0) { AbstractFFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractVVSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a scalar diagram in FtoFVVDecayer::doinit()" + << "Invalid vertices for a scalar diagram in FtoFVVDecayer::setupDiagrams()" << Exception::runerror; sca_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1Half) { AbstractFFVVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a scalar diagram in FtoFVVDecayer::doinit()" + << "Invalid vertices for a scalar diagram in FtoFVVDecayer::setupDiagrams()" << Exception::runerror; fer_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1) { AbstractFFVVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractVVVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a vector diagram in FtoFVVDecayer::doinit()" + << "Invalid vertices for a vector diagram in FtoFVVDecayer::setupDiagrams()" << Exception::runerror; vec_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin2) { AbstractFFTVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractVVTVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a tensor diagram in FtoFVVDecayer::doinit()" + << "Invalid vertices for a tensor diagram in FtoFVVDecayer::setupDiagrams()" << Exception::runerror; ten_[ix] = make_pair(vert1, vert2); } } } double FtoFVVDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming != inpart.id(); // special handling or first/last call //Set up wave-functions bool ferm( inpart.id() > 0 ); if(meopt==Initialize) { if( ferm ) { SpinorWaveFunction:: calculateWaveFunctions(fwave_,rho_,const_ptr_cast(&inpart), Helicity::incoming); if( fwave_[0].wave().Type() != SpinorType::u ) fwave_[0].conjugate(); if( fwave_[1].wave().Type() != SpinorType::u ) fwave_[1].conjugate(); } else { SpinorBarWaveFunction:: calculateWaveFunctions(fbwave_, rho_, const_ptr_cast(&inpart), Helicity::incoming); if( fbwave_[0].wave().Type() != SpinorType::v ) fbwave_[0].conjugate(); if( fbwave_[1].wave().Type() != SpinorType::v ) fbwave_[1].conjugate(); } + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(ferm) SpinorWaveFunction::constructSpinInfo(fwave_, const_ptr_cast(&inpart), Helicity::incoming,true); else SpinorBarWaveFunction::constructSpinInfo(fbwave_, const_ptr_cast(&inpart), Helicity::incoming,true); int ivec(-1); // outgoing particles for(int ix = 0; ix < 3; ++ix) { tPPtr p = decay[ix]; if( p->dataPtr()->iSpin() == PDT::Spin1Half ) { if( ferm ) { SpinorBarWaveFunction:: constructSpinInfo(fbwave_, p, Helicity::outgoing,true); } else { SpinorWaveFunction:: constructSpinInfo(fwave_ , p, Helicity::outgoing,true); } } else if( p->dataPtr()->iSpin() == PDT::Spin1 ) { if( ivec < 0 ) { ivec = ix; VectorWaveFunction:: constructSpinInfo(vwave_.first , p, Helicity::outgoing, true, false); } else { VectorWaveFunction:: constructSpinInfo(vwave_.second, p, Helicity::outgoing, true, false); } } } return 0.; } // outgoing, keep track of fermion and first occurrence of vector positions int isp(-1), ivec(-1); // outgoing particles pair mass = make_pair(false,false); for(int ix = 0; ix < 3; ++ix) { tPPtr p = decay[ix]; if( p->dataPtr()->iSpin() == PDT::Spin1Half ) { isp = ix; if( ferm ) { SpinorBarWaveFunction:: calculateWaveFunctions(fbwave_, p, Helicity::outgoing); if( fbwave_[0].wave().Type() != SpinorType::u ) fbwave_[0].conjugate(); if( fbwave_[1].wave().Type() != SpinorType::u ) fbwave_[1].conjugate(); } else { SpinorWaveFunction:: calculateWaveFunctions(fwave_, p, Helicity::outgoing); if( fwave_[0].wave().Type() != SpinorType::v ) fwave_[0].conjugate(); if( fwave_[1].wave().Type() != SpinorType::v ) fwave_[1].conjugate(); } } else if( p->dataPtr()->iSpin() == PDT::Spin1 ) { bool massless = p->id() == ParticleID::gamma || p->id() == ParticleID::g; if( ivec < 0 ) { ivec = ix; VectorWaveFunction:: calculateWaveFunctions(vwave_.first , p, Helicity::outgoing, massless); mass.first = massless; } else { VectorWaveFunction:: calculateWaveFunctions(vwave_.second, p, Helicity::outgoing, massless); mass.second = massless; } } } assert(isp >= 0 && ivec >= 0); Energy2 scale(sqr(inpart.mass())); const vector > cfactors(getColourFactors()); const vector > nfactors(getLargeNcColourFactors()); const size_t ncf(numberOfFlows()); vector flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.)); vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, (isp == 0) ? PDT::Spin1Half : PDT::Spin1, (isp == 1) ? PDT::Spin1Half : PDT::Spin1, (isp == 2) ? PDT::Spin1Half : PDT::Spin1))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half, (isp == 0) ? PDT::Spin1Half : PDT::Spin1, (isp == 1) ? PDT::Spin1Half : PDT::Spin1, (isp == 2) ? PDT::Spin1Half : PDT::Spin1))); //Helicity calculation for( unsigned int if1 = 0; if1 < 2; ++if1 ) { for( unsigned int if2 = 0; if2 < 2; ++if2 ) { for( unsigned int iv1 = 0; iv1 < 3; ++iv1 ) { if ( mass.first && iv1 == 1 ) continue; for( unsigned int iv2 = 0; iv2 < 3; ++iv2 ) { if ( mass.second && iv2 == 1 ) continue; flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag(0); for(vector::const_iterator dit = getProcessInfo().begin(); dit != getProcessInfo().end(); ++dit) { // If we are selecting a particular channel if( ichan >= 0 && diagramMap()[ichan] != idiag ) { ++idiag; continue; } tcPDPtr offshell = (*dit).intermediate; if(cc&&offshell->CC()) offshell=offshell->CC(); Complex diag; if( offshell->iSpin() == PDT::Spin1Half ) { // Make sure we connect the correct particles VectorWaveFunction vw1, vw2; if( (*dit).channelType == TBDiagram::channel23 ) { vw1 = vwave_.first[iv1]; vw2 = vwave_.second[iv2]; } else if( (*dit).channelType == TBDiagram::channel12 ) { vw1 = vwave_.second[iv2]; vw2 = vwave_.first[iv1]; } else { if( ivec < isp ) { vw1 = vwave_.second[iv2]; vw2 = vwave_.first[iv1]; } else { vw1 = vwave_.first[iv1]; vw2 = vwave_.second[iv2]; } } if( ferm ) { SpinorWaveFunction inters = fer_[idiag].first->evaluate(scale, widthOption(), offshell, fwave_[if1], vw1); diag = fer_[idiag].second->evaluate(scale, inters, fbwave_[if2], vw2); } else { SpinorBarWaveFunction inters = fer_[idiag].first->evaluate(scale, widthOption(), offshell, fbwave_[if2], vw1); diag = fer_[idiag].second->evaluate(scale, fwave_[if1], inters, vw2); } } else if( offshell->iSpin() == PDT::Spin0 ) { ScalarWaveFunction inters = sca_[idiag].first->evaluate(scale, widthOption(), offshell, fwave_[if1], fbwave_[if2]); diag = sca_[idiag].second->evaluate(scale, vwave_.first[iv1], vwave_.second[iv2], inters); } else if( offshell->iSpin() == PDT::Spin1 ) { VectorWaveFunction interv = vec_[idiag].first->evaluate(scale, widthOption(), offshell, fwave_[if1], fbwave_[if2]); diag = vec_[idiag].second->evaluate(scale, vwave_.first[iv1], vwave_.second[iv2], interv); } else if( offshell->iSpin() == PDT::Spin2 ) { TensorWaveFunction intert = ten_[idiag].first->evaluate(scale, widthOption(), offshell, fwave_[if1], fbwave_[if2]); diag = ten_[idiag].second->evaluate(scale, vwave_.first[iv1], vwave_.second[iv2], intert); } else throw Exception() << "Unknown intermediate in FtoFVVDecayer::me2()" << Exception::runerror; //NO sign if( !ferm ) diag *= -1; if(ichan<0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; }// end diagram loop // now add the flows to the me2 unsigned int h1(if1), h2(if2); if( !ferm ) swap(h1,h2); for(unsigned int ix = 0; ix < ncf; ++ix) { if(isp == 0) { (*mes[ix])(h1, h2, iv1, iv2) = flows[ix]; (*mel[ix])(h1, h2, iv1, iv2) = largeflows[ix]; } else if(isp == 1) { (*mes[ix])(h1, iv1, h2, iv2) = flows[ix]; (*mel[ix])(h1, iv1, h2, iv2) = largeflows[ix]; } else if(isp == 2) { (*mes[ix])(h1, iv1, iv2, h2) = flows[ix]; (*mel[ix])(h1, iv1, h2, iv2) = largeflows[ix]; } } }//v2 }//v1 }//f2 }//f1 //Finally, work out me2. This depends on whether we are selecting channels //or not double me2(0.); if(ichan<0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix==iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *= UseRandom::rnd(); for(unsigned int ix=0;ixcontract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2; } WidthCalculatorBasePtr FtoFVVDecayer:: threeBodyMEIntegrator(const DecayMode & ) const { vector intype; vector inmass,inwidth; vector inpow,inweights; constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow,*this,0, outgoing()[0]->mass(),outgoing()[1]->mass(), outgoing()[2]->mass(),relativeError())); } diff --git a/Decay/General/FtoFVVDecayer.h b/Decay/General/FtoFVVDecayer.h --- a/Decay/General/FtoFVVDecayer.h +++ b/Decay/General/FtoFVVDecayer.h @@ -1,156 +1,151 @@ // -*- C++ -*- #ifndef HERWIG_FtoFVVDecayer_H #define HERWIG_FtoFVVDecayer_H // // This is the declaration of the FtoFVVDecayer class. // #include "GeneralThreeBodyDecayer.h" #include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h" #include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h" #include "ThePEG/Helicity/Vertex/AbstractVVTVertex.h" namespace Herwig { using namespace ThePEG; /** * The FtoFVVDecayer class provides the general matrix elements for the * decay of a fermion to a fermion and two vector bosons. * * @see \ref FtoFVVDecayerInterfaces "The interfaces" * defined for FtoFVVDecayer. */ class FtoFVVDecayer: public GeneralThreeBodyDecayer { public: /** * Return the matrix element squared for a given mode and phase-space channel * @param ichan The channel we are calculating the matrix element for. * @param part The decaying Particle. * @param decay The particles produced in the decay. * @param meopt Option for the calculation of the matrix element * @return The matrix element squared for the phase-space configuration. */ virtual double me2(const int ichan, const Particle & part, const ParticleVector & decay, MEOption meopt) const; /** * Method to return an object to calculate the 3 (or higher body) partial width * @param dm The DecayMode * @return A pointer to a WidthCalculatorBase object capable of calculating the width */ virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const; 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(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(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 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 IBPtr fullclone() const; //@} protected: - /** @name Standard Interfaced functions. */ - //@{ /** - * Initialize this object after the setup phase before saving an - * EventGenerator to disk. - * @throws InitException if object could not be initialized properly. + * Set up the diagrams etc */ - virtual void doinit(); - //@} + virtual void setupDiagrams(bool checkKinematics); private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ FtoFVVDecayer & operator=(const FtoFVVDecayer &); private: /** * Store the vector of scalar intermediates */ vector > sca_; /** * Store the vector for fermion intermediates */ vector > fer_; /** * Store the vector for gauge boson intermediates */ vector > vec_; /** * Store the vector of tensor intermediates */ vector > ten_; /** * Spin density matrix */ mutable RhoDMatrix rho_; /** * Spinor wavefunctions */ mutable vector fwave_; /** * Barred spinor wavefunctions */ mutable vector fbwave_; /** * Vector wavefunctions */ mutable pair, vector > vwave_; }; } #endif /* HERWIG_FtoFVVDecayer_H */ diff --git a/Decay/General/GeneralThreeBodyDecayer.cc b/Decay/General/GeneralThreeBodyDecayer.cc --- a/Decay/General/GeneralThreeBodyDecayer.cc +++ b/Decay/General/GeneralThreeBodyDecayer.cc @@ -1,1028 +1,1053 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the GeneralThreeBodyDecayer class. // #include "GeneralThreeBodyDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "Herwig/Decay/DecayPhaseSpaceMode.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" using namespace Herwig; void GeneralThreeBodyDecayer::persistentOutput(PersistentOStream & os) const { os << incoming_ << outgoing_ << diagrams_ << diagmap_ << colour_ << colourLargeNC_ << nflow_ << widthOpt_ << refTag_ << refTagCC_ << intOpt_ << relerr_; } void GeneralThreeBodyDecayer::persistentInput(PersistentIStream & is, int) { is >> incoming_ >> outgoing_ >> diagrams_ >> diagmap_ >> colour_ >> colourLargeNC_ >> nflow_ >> widthOpt_ >> refTag_ >> refTagCC_ >> intOpt_ >> relerr_; } // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractClass describeHerwigGeneralThreeBodyDecayer("Herwig::GeneralThreeBodyDecayer", "Herwig.so"); void GeneralThreeBodyDecayer::Init() { static ClassDocumentation documentation ("The GeneralThreeBodyDecayer class is the base class for the implementation of" " all three body decays based on spin structures in Herwig."); static Switch interfaceWidthOption ("WidthOption", "Option for the treatment of the widths of the intermediates", &GeneralThreeBodyDecayer::widthOpt_, 1, false, false); static SwitchOption interfaceWidthOptionFixed (interfaceWidthOption, "Fixed", "Use fixed widths", 1); static SwitchOption interfaceWidthOptionRunning (interfaceWidthOption, "Running", "Use running widths", 2); static SwitchOption interfaceWidthOptionZero (interfaceWidthOption, "Zero", "Set the widths to zero", 3); static Switch interfacePartialWidthIntegration ("PartialWidthIntegration", "Switch to control the partial width integration", &GeneralThreeBodyDecayer::intOpt_, 0, false, false); static SwitchOption interfacePartialWidthIntegrationAllPoles (interfacePartialWidthIntegration, "AllPoles", "Include all potential poles", 0); static SwitchOption interfacePartialWidthIntegrationShallowestPole (interfacePartialWidthIntegration, "ShallowestPole", "Only include the shallowest pole", 1); static Parameter interfaceRelativeError ("RelativeError", "The relative error for the GQ integration of the partial width", &GeneralThreeBodyDecayer::relerr_, 1e-2, 1e-10, 1., false, false, Interface::limited); } ParticleVector GeneralThreeBodyDecayer::decay(const Particle & parent, const tPDVector & children) const { // return empty vector if products heavier than parent Energy mout(ZERO); for(tPDVector::const_iterator it=children.begin(); it!=children.end();++it) mout+=(**it).massMin(); if(mout>parent.mass()) return ParticleVector(); // generate the decay bool cc; int imode=modeNumber(cc,parent.dataPtr(),children); // generate the kinematics ParticleVector decay=generate(generateIntermediates(),cc,imode,parent); // make the colour connections colourConnections(parent, decay); // return the answer return decay; } int GeneralThreeBodyDecayer:: modeNumber(bool & cc, tcPDPtr in, const tPDVector & outin) const { assert( !refTag_.empty() && !refTagCC_.empty() ); // check number of outgoing particles if( outin.size() != 3 || abs(in->id()) != abs(incoming_->id()) ) return -1; OrderedParticles testmode(outin.begin(), outin.end()); OrderedParticles::const_iterator dit = testmode.begin(); string testtag(in->name() + "->"); for( unsigned int i = 1; dit != testmode.end(); ++dit, ++i) { testtag += (**dit).name(); if( i != 3 ) testtag += string(","); } if( testtag == refTag_ ) { cc = false; return 0; } else if ( testtag == refTagCC_ ) { cc = true; return 0; } else return -1; } bool GeneralThreeBodyDecayer::setDecayInfo(PDPtr incoming, vector outgoing, const vector & process, double symfac) { // set the member variables from the info supplied incoming_ = incoming; outgoing_ = outgoing; diagrams_ = process; assert( outgoing_.size() == 3 ); // Construct reference tags for testing in modeNumber function OrderedParticles refmode(outgoing_.begin(), outgoing_.end()); OrderedParticles::const_iterator dit = refmode.begin(); refTag_ = incoming_->name() + "->"; for( unsigned int i = 1; dit != refmode.end(); ++dit, ++i) { refTag_ += (**dit).name(); if( i != 3 ) refTag_ += string(","); } //CC-mode refmode.clear(); refTagCC_ = incoming_->CC() ? incoming_->CC()->name() : incoming_->name(); refTagCC_ += "->"; for( unsigned int i = 0; i < 3; ++i ) { if( outgoing_[i]->CC() ) refmode.insert( outgoing_[i]->CC() ); else refmode.insert( outgoing_[i] ); } dit = refmode.begin(); for( unsigned int i = 1; dit != refmode.end(); ++dit , ++i) { refTagCC_ += (**dit).name(); if( i != 3 ) refTagCC_ += string(","); } // check if intermeidates or only four point diagrams bool intermediates(false); for(auto diagram : diagrams_) { if(diagram.intermediate) { intermediates=true; break; } } if(!intermediates) { incoming_= PDPtr(); outgoing_.clear(); generator()->log() << "Only four body diagrams for decay " << refTag_ << " in GeneralThreeBodyDecayer::" << "setDecayInfo(), omitting decay\n"; return false; } // set the colour factors and return the answer if(setColourFactors(symfac)) return true; incoming_= PDPtr(); outgoing_.clear(); return false; } void GeneralThreeBodyDecayer::doinit() { DecayIntegrator::doinit(); if(outgoing_.empty()) return; - // create the phase space integrator - tPDVector extpart(1,incoming_); - extpart.insert(extpart.end(),outgoing_.begin(),outgoing_.end()); - // create the integration channels for the decay - DecayPhaseSpaceModePtr mode(new_ptr(DecayPhaseSpaceMode(extpart,this,true))); - DecayPhaseSpaceChannelPtr newchannel; - // create the phase-space channels for the integration - unsigned int nmode(0); - for(unsigned int ix=0;ixmass() == ZERO || - diagrams_[ix].intermediate->width() == ZERO ) { - jac = 1; - power = -2.0; - } - if(diagrams_[ix].channelType==TBDiagram::channel23) { - newchannel->addIntermediate(extpart[0],0,0.0,-1,1); - newchannel->addIntermediate(diagrams_[ix].intermediate,jac,power, 2,3); - } - else if(diagrams_[ix].channelType==TBDiagram::channel13) { - newchannel->addIntermediate(extpart[0],0,0.0,-1,2); - newchannel->addIntermediate(diagrams_[ix].intermediate,jac,power, 1,3); - } - else if(diagrams_[ix].channelType==TBDiagram::channel12) { - newchannel->addIntermediate(extpart[0],0,0.0,-1,3); - newchannel->addIntermediate(diagrams_[ix].intermediate,jac,power, 1,2); - } - diagmap_.push_back(ix); - mode->addChannel(newchannel); - ++nmode; - } - if(nmode==0) { - string mode = extpart[0]->PDGName() + "->"; - for(unsigned int ix=1;ixPDGName() + " "; - throw Exception() << "No decay channels in GeneralThreeBodyDecayer::" - << "doinit() for " << mode << "\n" << Exception::runerror; - } - // add the mode - vector wgt(nmode,1./double(nmode)); - addMode(mode,1.,wgt); + setupDiagrams(false); +} + +void GeneralThreeBodyDecayer::doinitrun() { + setupDiagrams(true); + DecayIntegrator::doinitrun(); } double GeneralThreeBodyDecayer:: threeBodyMatrixElement(const int imode, const Energy2 q2, const Energy2 s3, const Energy2 s2, const Energy2 s1, const Energy m1, const Energy m2, const Energy m3) const { // calculate the momenta of the outgoing particles Energy m0=sqrt(q2); // energies Energy eout[3] = {0.5*(q2+sqr(m1)-s1)/m0, 0.5*(q2+sqr(m2)-s2)/m0, 0.5*(q2+sqr(m3)-s3)/m0}; // magnitudes of the momenta Energy pout[3] = {sqrt(sqr(eout[0])-sqr(m1)), sqrt(sqr(eout[1])-sqr(m2)), sqrt(sqr(eout[2])-sqr(m3))}; double cos2 = 0.5*(sqr(pout[0])+sqr(pout[1])-sqr(pout[2]))/pout[0]/pout[1]; double cos3 = 0.5*(sqr(pout[0])-sqr(pout[1])+sqr(pout[2]))/pout[0]/pout[2]; double sin2 = sqrt(1.-sqr(cos2)), sin3 = sqrt(1.-sqr(cos3)); Lorentz5Momentum out[3]= {Lorentz5Momentum( ZERO , ZERO , pout[0] , eout[0] , m1), Lorentz5Momentum( pout[1]*sin2 , ZERO , -pout[1]*cos2 , eout[1] , m2), Lorentz5Momentum( -pout[2]*sin3 , ZERO , -pout[2]*cos3 , eout[2] , m3)}; // create the incoming PPtr inpart=mode(imode)->externalParticles(0)-> produceParticle(Lorentz5Momentum(sqrt(q2))); // and outgoing particles ParticleVector decay; for(unsigned int ix=1;ix<4;++ix) decay.push_back(mode(imode)->externalParticles(ix)->produceParticle(out[ix-1])); // return the matrix element return me2(-1,*inpart,decay,Initialize); } double GeneralThreeBodyDecayer::brat(const DecayMode &, const Particle & p, double oldbrat) const { ParticleVector children = p.children(); if( children.size() != 3 || !p.data().widthGenerator() ) return oldbrat; // partial width for this mode Energy scale = p.mass(); Energy pwidth = partialWidth( make_pair(p.dataPtr(), scale), make_pair(children[0]->dataPtr(), children[0]->mass()), make_pair(children[1]->dataPtr(), children[1]->mass()), make_pair(children[2]->dataPtr(), children[2]->mass()) ); Energy width = p.data().widthGenerator()->width(p.data(), scale); return pwidth/width; } Energy GeneralThreeBodyDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb, PMPair outc) const { if(inpart.secondname() + "->"; tag += outgoing_[0]->name() + "," + outgoing_[1]->name() + "," + outgoing_[2]->name() + ";"; DMPtr dm = generator()->findDecayMode(tag); widthCalc_ = threeBodyMEIntegrator(*dm); } return widthCalc_->partialWidth(sqr(inpart.second)); } void GeneralThreeBodyDecayer:: colourConnections(const Particle & parent, const ParticleVector & out) const { // first extract the outgoing particles and intermediate PPtr inter; ParticleVector outgoing; if(!generateIntermediates()) { outgoing=out; } else { // find the diagram unsigned int idiag = diagramMap()[mode(imode())->selectedChannel()]; PPtr child; for(unsigned int ix=0;ixchildren().empty()) child = out[ix]; else inter = out[ix]; } outgoing.resize(3); switch(diagrams_[idiag].channelType) { case TBDiagram::channel23: outgoing[0] = child; outgoing[1] = inter->children()[0]; outgoing[2] = inter->children()[1]; break; case TBDiagram::channel13: outgoing[0] = inter->children()[0]; outgoing[1] = child; outgoing[2] = inter->children()[1]; break; case TBDiagram::channel12: outgoing[0] = inter->children()[0]; outgoing[1] = inter->children()[1]; outgoing[2] = child; break; default: throw Exception() << "unknown diagram type in GeneralThreeBodyDecayer::" << "colourConnections()" << Exception::runerror; } } // extract colour of the incoming and outgoing particles PDT::Colour inColour(parent.data().iColour()); vector outColour; vector singlet,octet,triplet,antitriplet; for(unsigned int ix=0;ixdata().iColour()); switch(outColour.back()) { case PDT::Colour0 : singlet.push_back(ix); break; case PDT::Colour3 : triplet.push_back(ix); break; case PDT::Colour3bar: antitriplet.push_back(ix); break; case PDT::Colour8 : octet.push_back(ix); break; default: throw Exception() << "Unknown colour for particle in GeneralThreeBodyDecayer::" << "colourConnections()" << Exception::runerror; } } // colour neutral decaying particle if ( inColour == PDT::Colour0) { // options are all neutral or triplet/antitriplet+ neutral if(singlet.size()==3) return; else if(singlet.size()==1&&triplet.size()==1&&antitriplet.size()==1) { outgoing[triplet[0]]->antiColourNeighbour(outgoing[antitriplet[0]]); // add intermediate if needed if(inter&&inter->coloured()) { if(inter->dataPtr()->iColour()==PDT::Colour3) outgoing[triplet[0]]->colourLine()->addColoured(inter); else if(inter->dataPtr()->iColour()==PDT::Colour3bar) outgoing[triplet[0]]->colourLine()->addAntiColoured(inter); } } else if(octet.size()==1&&triplet.size()==1&&antitriplet.size()==1) { outgoing[ triplet[0]]->antiColourNeighbour(outgoing[octet[0]]); outgoing[antitriplet[0]]-> colourNeighbour(outgoing[octet[0]]); if(inter&&inter->coloured()) { if(inter->dataPtr()->iColour()==PDT::Colour3) outgoing[antitriplet[0]]->antiColourLine()->addColoured(inter); else if(inter->dataPtr()->iColour()==PDT::Colour3bar) outgoing[ triplet[0]]-> colourLine()->addAntiColoured(inter); else if(inter->dataPtr()->iColour()==PDT::Colour8) { outgoing[antitriplet[0]]->antiColourLine()->addAntiColoured(inter); outgoing[ triplet[0]]-> colourLine()->addColoured(inter); } } } else if(triplet.size()==3) { tColinePtr col[3] = {ColourLine::create(outgoing[0]), ColourLine::create(outgoing[1]), ColourLine::create(outgoing[2])}; col[0]->setSourceNeighbours(col[1],col[2]); } else if(antitriplet.size()==3) { tColinePtr col[3] = {ColourLine::create(outgoing[0],true), ColourLine::create(outgoing[1],true), ColourLine::create(outgoing[2],true)}; col[0]->setSinkNeighbours(col[1],col[2]); } else { string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " " + out[1]->PDGName() + " " + out[2]->PDGName(); throw Exception() << "Unknown colour structure in GeneralThreeBodyDecayer::" << "colourConnections() for singlet decaying particle " << mode << Exception::runerror; } } // colour triplet decaying particle else if( inColour == PDT::Colour3) { if(singlet.size()==2&&triplet.size()==1) { outgoing[triplet[0]]->incomingColour(const_ptr_cast(&parent)); if(inter&&inter->coloured()) outgoing[triplet[0]]->colourLine()->addColoured(inter); } else if(antitriplet.size()==1&&triplet.size()==2) { if(colourFlow()==0) { outgoing[triplet[0]]->incomingColour(const_ptr_cast(&parent)); outgoing[antitriplet[0]]->colourNeighbour(outgoing[triplet[1]]); if(inter&&inter->coloured()) { switch (inter->dataPtr()->iColour()) { case PDT::Colour8: inter->incomingColour(const_ptr_cast(&parent)); outgoing[triplet[1]]->colourLine()->addAntiColoured(inter); break; default: string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " " + out[1]->PDGName() + " " + out[2]->PDGName(); throw Exception() << "Unknown colour for intermediate in " << "GeneralThreeBodyDecayer::" << "colourConnections() for " << "decaying colour triplet " << mode << Exception::runerror; } } } else { outgoing[triplet[1]]->incomingColour(const_ptr_cast(&parent)); outgoing[antitriplet[0]]->colourNeighbour(outgoing[triplet[0]]); if(inter&&inter->coloured()) { switch (inter->dataPtr()->iColour()) { case PDT::Colour8: inter->incomingColour(const_ptr_cast(&parent)); outgoing[triplet[0]]->colourLine()->addAntiColoured(inter); break; default: string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " " + out[1]->PDGName() + " " + out[2]->PDGName(); throw Exception() << "Unknown colour for intermediate in " << "GeneralThreeBodyDecayer::" << "colourConnections() for " << "decaying colour triplet " << mode << Exception::runerror; } } } } else if (singlet.size()==1&&triplet.size()==1&&octet.size()==1) { if(inter) { if(inter->children()[0]->dataPtr()->iColour()==PDT::Colour8 || inter->children()[1]->dataPtr()->iColour()==PDT::Colour8) { inter->incomingColour(const_ptr_cast(&parent)); outgoing[octet[0]]->incomingColour(inter); outgoing[octet[0]]->colourNeighbour(outgoing[triplet[0]]); } else { outgoing[octet[0]]->incomingColour(inter); outgoing[octet[0]]->colourNeighbour(inter); outgoing[triplet[0]]->incomingColour(inter); } } else { outgoing[octet[0]]->incomingColour(const_ptr_cast(&parent)); outgoing[octet[0]]->colourNeighbour(outgoing[triplet[0]]); } } else if (singlet.size()==1&&antitriplet.size()==2) { tColinePtr col[2] = {ColourLine::create(outgoing[antitriplet[0]],true), ColourLine::create(outgoing[antitriplet[1]],true)}; parent.colourLine()->setSinkNeighbours(col[0],col[1]); } else { string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " " + out[1]->PDGName() + " " + out[2]->PDGName(); throw Exception() << "Unknown colour structure in GeneralThreeBodyDecayer::" << "colourConnections() for triplet decaying particle " << mode << Exception::runerror; } } else if( inColour == PDT::Colour3bar) { if(singlet.size()==2&&antitriplet.size()==1) { outgoing[antitriplet[0]]->incomingAntiColour(const_ptr_cast(&parent)); } else if(antitriplet.size()==2&&triplet.size()==1) { if(colourFlow()==0) { outgoing[antitriplet[0]]->incomingAntiColour(const_ptr_cast(&parent)); outgoing[triplet[0]]->antiColourNeighbour(outgoing[antitriplet[1]]); if(inter&&inter->coloured()) { switch (inter->dataPtr()->iColour()) { case PDT::Colour8: inter->incomingAntiColour(const_ptr_cast(&parent)); outgoing[antitriplet[1]]->antiColourLine()->addAntiColoured(inter); break; default: string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " " + out[1]->PDGName() + " " + out[2]->PDGName(); throw Exception() << "Unknown colour for intermediate in" << " GeneralThreeBodyDecayer::" << "colourConnections() for " << "decaying colour antitriplet " << mode << Exception::runerror; } } } else { outgoing[antitriplet[1]]->incomingAntiColour(const_ptr_cast(&parent)); outgoing[triplet[0]]->antiColourNeighbour(outgoing[antitriplet[0]]); if(inter&&inter->coloured()) { switch (inter->dataPtr()->iColour()) { case PDT::Colour8: inter->incomingAntiColour(const_ptr_cast(&parent)); outgoing[antitriplet[0]]->antiColourLine()->addAntiColoured(inter); break; default: string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " " + out[1]->PDGName() + " " + out[2]->PDGName(); throw Exception() << "Unknown colour for intermediate in " << "GeneralThreeBodyDecayer::" << "colourConnections() for " << "decaying colour antitriplet " << mode << Exception::runerror; } } } } else if (singlet.size()==1&&antitriplet.size()==1&&octet.size()==1) { if(inter) { if(inter->children()[0]->dataPtr()->iColour()==PDT::Colour8 || inter->children()[1]->dataPtr()->iColour()==PDT::Colour8) { inter->incomingColour(const_ptr_cast(&parent)); outgoing[octet[0]]->incomingAntiColour(inter); outgoing[octet[0]]->antiColourNeighbour(outgoing[antitriplet[0]]); } else { outgoing[octet[0]]->incomingAntiColour(inter); outgoing[octet[0]]->antiColourNeighbour(inter); outgoing[antitriplet[0]]->incomingAntiColour(inter); } } else { outgoing[octet[0]]->incomingAntiColour(const_ptr_cast(&parent)); outgoing[octet[0]]->antiColourNeighbour(outgoing[antitriplet[0]]); } } else if (singlet.size()==1&&triplet.size()==2) { tColinePtr col[2] = {ColourLine::create(outgoing[triplet[0]]), ColourLine::create(outgoing[triplet[1]])}; parent.antiColourLine()->setSourceNeighbours(col[0],col[1]); } else { string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " " + out[1]->PDGName() + " " + out[2]->PDGName(); throw Exception() << "Unknown colour structure in GeneralThreeBodyDecayer::" << "colourConnections() for anti-triplet decaying particle" << mode << Exception::runerror; } } else if( inColour == PDT::Colour8) { if(triplet.size()==1&&antitriplet.size()==1&&singlet.size()==1) { outgoing[ triplet[0]]->incomingColour (const_ptr_cast(&parent)); outgoing[antitriplet[0]]->incomingAntiColour(const_ptr_cast(&parent)); if(inter&&inter->coloured()) { switch (inter->dataPtr()->iColour()) { case PDT::Colour3: outgoing[triplet[0]]->colourLine()->addColoured(inter); break; case PDT::Colour3bar: outgoing[antitriplet[0]]->antiColourLine()->addAntiColoured(inter); break; default: string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " " + out[1]->PDGName() + " " + out[2]->PDGName(); throw Exception() << "Unknown colour for intermediate" << " in GeneralThreeBodyDecayer::" << "colourConnections() for " << "decaying colour octet " << mode << Exception::runerror; } } } else if(triplet.size()==3) { tColinePtr col[2]; if(colourFlow()==0) { outgoing[0]->incomingColour (const_ptr_cast(&parent)); col[0] = ColourLine::create(outgoing[1]); col[1] = ColourLine::create(outgoing[2]); } else if(colourFlow()==1) { outgoing[1]->incomingColour (const_ptr_cast(&parent)); col[0] = ColourLine::create(outgoing[0]); col[1] = ColourLine::create(outgoing[2]); } else if(colourFlow()==2) { outgoing[2]->incomingColour (const_ptr_cast(&parent)); col[0] = ColourLine::create(outgoing[0]); col[1] = ColourLine::create(outgoing[1]); } else assert(false); parent.antiColourLine()->setSourceNeighbours(col[0],col[1]); } else if(antitriplet.size()==3) { tColinePtr col[2]; if(colourFlow()==0) { outgoing[0]->incomingAntiColour(const_ptr_cast(&parent)); col[0] = ColourLine::create(outgoing[1],true); col[1] = ColourLine::create(outgoing[2],true); } else if(colourFlow()==1) { outgoing[1]->incomingAntiColour(const_ptr_cast(&parent)); col[0] = ColourLine::create(outgoing[0],true); col[1] = ColourLine::create(outgoing[2],true); } else if(colourFlow()==2) { outgoing[2]->incomingAntiColour(const_ptr_cast(&parent)); col[0] = ColourLine::create(outgoing[0],true); col[1] = ColourLine::create(outgoing[1],true); } else assert(false); parent.colourLine()->setSinkNeighbours(col[0],col[1]); } else { string mode = parent.PDGName() + " -> " + out[0]->PDGName() + " " + out[1]->PDGName() + " " + out[2]->PDGName(); throw Exception() << "Unknown colour structure in GeneralThreeBodyDecayer::" << "colourConnections() for octet decaying particle" << mode << Exception::runerror; } } } void GeneralThreeBodyDecayer:: constructIntegratorChannels(vector & intype, vector & inmass, vector & inwidth, vector & inpow, vector & inweights) const { // check if any intermediate photons bool hasPhoton=false; for(unsigned int iy=0;iyid()==ParticleID::gamma) hasPhoton = true; } // loop over channels Energy min = incoming()->mass(); int nchannel(0); pair imin[4]={make_pair(-1,-1.*GeV),make_pair(-1,-1.*GeV), make_pair(-1,-1.*GeV),make_pair(-1,-1.*GeV)}; Energy absmin = -1e20*GeV; int minType = -1; for(unsigned int iy=0;iymass()); Energy dm2(getProcessInfo()[ix].intermediate->mass()); int itype(0); if (getProcessInfo()[ix].channelType==TBDiagram::channel23) { dm1 -= outgoing()[0]->mass(); dm2 -= outgoing()[1]->mass()+outgoing()[2]->mass(); itype = 3; } else if(getProcessInfo()[ix].channelType==TBDiagram::channel13) { dm1 -= outgoing()[1]->mass(); dm2 -= outgoing()[0]->mass()+outgoing()[2]->mass(); itype = 2; } else if(getProcessInfo()[ix].channelType==TBDiagram::channel12) { dm1 -= outgoing()[2]->mass(); dm2 -= outgoing()[0]->mass()+outgoing()[1]->mass(); itype = 1; } if((dm1id()!=ParticleID::gamma) { intype.push_back(itype); inpow.push_back(0.); inmass.push_back(getProcessInfo()[ix].intermediate->mass()); inwidth.push_back(widthOption() ==3 ? ZERO : getProcessInfo()[ix].intermediate->width()); ++nchannel; } else if(getProcessInfo()[ix].intermediate->id()==ParticleID::gamma) { intype.push_back(itype); inpow.push_back(-2.); inmass.push_back(-1.*GeV); inwidth.push_back(-1.*GeV); ++nchannel; } } // physical poles, use them and return if(nchannel>0) { inweights = vector(nchannel,1./double(nchannel)); return; } // use shallowest pole else if(intOpt_==1&&minType>0&&getProcessInfo()[imin[minType].first].intermediate->id()!=ParticleID::gamma) { intype.push_back(minType); inpow.push_back(0.); inmass.push_back(getProcessInfo()[imin[minType].first].intermediate->mass()); inwidth.push_back(widthOption() ==3 ? ZERO : getProcessInfo()[imin[minType].first].intermediate->width()); inweights = vector(1,1.); return; } for(unsigned int ix=1;ix<4;++ix) { if(imin[ix].first>=0) { intype.push_back(ix); if(getProcessInfo()[imin[ix].first].intermediate->id()!=ParticleID::gamma) { inpow.push_back(0.); inmass.push_back(getProcessInfo()[imin[ix].first].intermediate->mass()); inwidth.push_back(widthOption() ==3 ? ZERO : getProcessInfo()[imin[ix].first].intermediate->width()); } else { inpow.push_back(-2.); inmass.push_back(-1.*GeV); inwidth.push_back(-1.*GeV); } ++nchannel; } } inweights = vector(nchannel,1./double(nchannel)); } bool GeneralThreeBodyDecayer::setColourFactors(double symfac) { string name = incoming_->PDGName() + "->"; vector sng,trip,atrip,oct; unsigned int iloc(0); for(vector::const_iterator it = outgoing_.begin(); it != outgoing_.end();++it) { name += (**it).PDGName() + " "; if ((**it).iColour() == PDT::Colour0 ) sng.push_back(iloc) ; else if((**it).iColour() == PDT::Colour3 ) trip.push_back(iloc) ; else if((**it).iColour() == PDT::Colour3bar ) atrip.push_back(iloc); else if((**it).iColour() == PDT::Colour8 ) oct.push_back(iloc) ; ++iloc; } // colour neutral decaying particle if ( incoming_->iColour() == PDT::Colour0) { // options are all neutral or triplet/antitriplet+ neutral if(sng.size()==3) { nflow_ = 1; colour_ = vector(1,DVector(1,1.)); colourLargeNC_ = vector(1,DVector(1,1.)); } else if(sng.size()==1&&trip.size()==1&&atrip.size()==1) { nflow_ = 1; colour_ = vector(1,DVector(1,3.)); colourLargeNC_ = vector(1,DVector(1,3.)); } else if(trip.size()==1&&atrip.size()==1&&oct.size()==1) { nflow_ = 1; colour_ = vector(1,DVector(1,4.)); colourLargeNC_ = vector(1,DVector(1,4.)); } else if( trip.size() == 3 || atrip.size() == 3 ) { nflow_ = 1; colour_ = vector(1,DVector(1,6.)); colourLargeNC_ = vector(1,DVector(1,6.)); for(unsigned int ix=0;ix(1,make_pair(1,sign)); diagrams_[ix].largeNcColourFlow = vector(1,make_pair(1,sign)); } } else { generator()->log() << "Unknown colour flow structure for " << "colour neutral decay " << name << " in GeneralThreeBodyDecayer::" << "setColourFactors(), omitting decay\n"; return false; } } // colour triplet decaying particle else if( incoming_->iColour() == PDT::Colour3) { if(sng.size()==2&&trip.size()==1) { nflow_ = 1; colour_ = vector(1,DVector(1,1.)); colourLargeNC_ = vector(1,DVector(1,1.)); } else if(trip.size()==2&&atrip.size()==1) { nflow_ = 2; colour_.clear(); colour_.resize(2,DVector(2,0.)); colour_[0][0] = 3.; colour_[0][1] = 1.; colour_[1][0] = 1.; colour_[1][1] = 3.; colourLargeNC_.clear(); colourLargeNC_.resize(2,DVector(2,0.)); colourLargeNC_[0][0] = 3.; colourLargeNC_[1][1] = 3.; // sort out the contribution of the different diagrams to the colour // flows for(unsigned int ix=0;ixiColour()==PDT::Colour0) { if(diagrams_[ix].channelType==trip[0]) { diagrams_[ix]. colourFlow = vector(1,make_pair(1,1.)); diagrams_[ix].largeNcColourFlow = vector(1,make_pair(1,1.)); } else { diagrams_[ix].colourFlow = vector(1,make_pair(2,1.)); diagrams_[ix].largeNcColourFlow = vector(1,make_pair(2,1.)); } } // colour octet intermediate else if(diagrams_[ix].intermediate->iColour()==PDT::Colour8) { if(diagrams_[ix].channelType==trip[0]) { vector flow(1,make_pair(2, 0.5 )); diagrams_[ix].largeNcColourFlow = flow; flow.push_back( make_pair(1,-1./6.)); diagrams_[ix].colourFlow=flow; } else { vector flow(1,make_pair(1, 0.5 )); diagrams_[ix].largeNcColourFlow = flow; flow.push_back( make_pair(2,-1./6.)); diagrams_[ix].colourFlow=flow; } } else { generator()->log() << "Unknown colour for the intermediate in " << "triplet -> triplet triplet antitriplet in " << "GeneralThreeBodyDecayer::setColourFactors()" << " for " << name << " omitting decay\n"; return false; } } } else if(trip.size()==1&&oct.size()==1&&sng.size()==1) { nflow_ = 1; colour_ = vector(1,DVector(1,4./3.)); colourLargeNC_ = vector(1,DVector(1,4./3.)); } else if(sng.size()==1&&atrip.size()==2) { nflow_ = 1; colour_ = vector(1,DVector(1,2.)); colourLargeNC_ = vector(1,DVector(1,2.)); } else { generator()->log() << "Unknown colour structure for " << "triplet decay in " << "GeneralThreeBodyDecayer::setColourFactors()" << " for " << name << " omitting decay\n"; return false; } } // colour antitriplet decaying particle else if( incoming_->iColour() == PDT::Colour3bar) { if(sng.size()==2&&atrip.size()==1) { nflow_ = 1; colour_ = vector(1,DVector(1,1.)); colourLargeNC_ = vector(1,DVector(1,1.)); } else if(atrip.size()==2&&trip.size()==1) { nflow_ = 2; colour_.clear(); colour_.resize(2,DVector(2,0.)); colour_[0][0] = 3.; colour_[0][1] = 1.; colour_[1][0] = 1.; colour_[1][1] = 3.; colourLargeNC_.clear(); colourLargeNC_.resize(2,DVector(2,0.)); colourLargeNC_[0][0] = 3.; colourLargeNC_[1][1] = 3.; // sort out the contribution of the different diagrams to the colour // flows for(unsigned int ix=0;ixiColour()==PDT::Colour0) { if(diagrams_[ix].channelType==atrip[0]) { diagrams_[ix]. colourFlow = vector(1,make_pair(1,1.)); diagrams_[ix].largeNcColourFlow = vector(1,make_pair(1,1.)); } else { diagrams_[ix].colourFlow = vector(1,make_pair(2,1.)); diagrams_[ix].largeNcColourFlow = vector(1,make_pair(2,1.)); } } // colour octet intermediate else if(diagrams_[ix].intermediate->iColour()==PDT::Colour8) { if(diagrams_[ix].channelType==atrip[0]) { vector flow(1,make_pair(2, 0.5 )); diagrams_[ix].largeNcColourFlow = flow; flow.push_back( make_pair(1,-1./6.)); diagrams_[ix].colourFlow=flow; } else { vector flow(1,make_pair(1, 0.5 )); diagrams_[ix].largeNcColourFlow = flow; flow.push_back( make_pair(2,-1./6.)); diagrams_[ix].colourFlow=flow; } } else { generator()->log() << "Unknown colour for the intermediate in " << "antitriplet -> antitriplet antitriplet triplet in " << "GeneralThreeBodyDecayer::setColourFactors()" << " for " << name << " omitting decay\n"; return false; } } } else if(atrip.size()==1&&oct.size()==1&&sng.size()==1) { nflow_ = 1; colour_ = vector(1,DVector(1,4./3.)); colourLargeNC_ = vector(1,DVector(1,4./3.)); } else if(sng.size()==1&&trip.size()==2) { nflow_ = 1; colour_ = vector(1,DVector(1,2.)); colourLargeNC_ = vector(1,DVector(1,2.)); } else { generator()->log() << "Unknown colour antitriplet decay in " << "GeneralThreeBodyDecayer::setColourFactors()" << " for " << name << " omitting decay\n"; return false; } } // colour octet particle else if( incoming_->iColour() == PDT::Colour8) { // triplet antitriplet if(trip.size() == 1 && atrip.size() == 1 && sng.size() == 1) { nflow_ = 1; colour_ = vector(1,DVector(1,0.5)); colourLargeNC_ = vector(1,DVector(1,0.5)); } // three (anti)triplets else if(trip.size()==3||atrip.size()==3) { nflow_ = 3; colour_ = vector(3,DVector(3,0.)); colourLargeNC_ = vector(3,DVector(3,0.)); colour_[0][0] = 1.; colour_[1][1] = 1.; colour_[2][2] = 1.; colour_[0][1] = -0.5; colour_[1][0] = -0.5; colour_[0][2] = -0.5; colour_[2][0] = -0.5; colour_[1][2] = -0.5; colour_[2][1] = -0.5; colourLargeNC_ = vector(3,DVector(3,0.)); colourLargeNC_[0][0] = 1.; colourLargeNC_[1][1] = 1.; colourLargeNC_[2][2] = 1.; // sett the factors for the diagrams for(unsigned int ix=0;ixCC()) inter = inter->CC(); unsigned int io[2]={1,2}; double sign = diagrams_[ix].channelType == TBDiagram::channel13 ? -1. : 1.; for(unsigned int iy=0;iy<3;++iy) { if (iy==1) io[0]=0; else if(iy==2) io[1]=1; tPDVector decaylist = diagrams_[ix].vertices.second->search(iy, inter); if(decaylist.empty()) continue; bool found=false; for(unsigned int iz=0;izid()==diagrams_[ix].outgoingPair.first && decaylist[iz+io[1]]->id()==diagrams_[ix].outgoingPair.second) { sign *= 1.; found = true; } else if(decaylist[iz+io[0]]->id()==diagrams_[ix].outgoingPair.second && decaylist[iz+io[1]]->id()==diagrams_[ix].outgoingPair.first ) { sign *= -1.; found = true; } } if(found) { if(iy==1) sign *=-1.; break; } } diagrams_[ix]. colourFlow = vector(1,make_pair(diagrams_[ix].channelType+1,sign)); diagrams_[ix].largeNcColourFlow = vector(1,make_pair(diagrams_[ix].channelType+1,sign)); } } // unknown else { generator()->log() << "Unknown colour octet decay in " << "GeneralThreeBodyDecayer::setColourFactors()" << " for " << name << " omitting decay\n"; return false; } } else if (incoming_->iColour() == PDT::Colour6 ) { generator()->log() << "Unknown colour sextet decay in " << "GeneralThreeBodyDecayer::setColourFactors()" << " for " << name << " omitting decay\n"; return false; } else if (incoming_->iColour() == PDT::Colour6bar ) { generator()->log() << "Unknown colour anti-sextet decay in " << "GeneralThreeBodyDecayer::setColourFactors()" << " for " << name << " omitting decay\n"; return false; } assert(nflow_ != 999); for(unsigned int ix=0;ix 1 ) { generator()->log() << "Mode: " << name << " has colour factors\n"; for(unsigned int ix=0;ixlog() << colour_[ix][iy] << " "; } generator()->log() << "\n"; } for(unsigned int ix=0;ixlog() << "colour flow for diagram : " << ix; for(unsigned int iy=0;iylog() << "(" << diagrams_[ix].colourFlow[iy].first << "," << diagrams_[ix].colourFlow[iy].second << "); "; generator()->log() << "\n"; } } return true; } + +void GeneralThreeBodyDecayer::setupDiagrams(bool kinCheck) { + clearModes(); + // create the phase space integrator + tPDVector extpart(1,incoming_); + extpart.insert(extpart.end(),outgoing_.begin(),outgoing_.end()); + // create the integration channels for the decay + DecayPhaseSpaceModePtr mode(new_ptr(DecayPhaseSpaceMode(extpart,this,true))); + DecayPhaseSpaceChannelPtr newchannel; + // create the phase-space channels for the integration + unsigned int nmode(0); + unsigned int idiag(0); + for(vector::iterator it = diagrams_.begin();it!=diagrams_.end();++it) { + if(it->channelType==TBDiagram::fourPoint|| + it->channelType==TBDiagram::UNDEFINED) { + idiag+=1; + continue; + } + // create the new channel + newchannel=new_ptr(DecayPhaseSpaceChannel(mode)); + int jac = 0; + double power = 0.0; + if ( it->intermediate->mass() == ZERO || + it->intermediate->width() == ZERO ) { + jac = 1; + power = -2.0; + } + if(it->channelType==TBDiagram::channel23) { + newchannel->addIntermediate(extpart[0],0,0.0,-1,1); + newchannel->addIntermediate(it->intermediate,jac,power, 2,3); + } + else if(it->channelType==TBDiagram::channel13) { + newchannel->addIntermediate(extpart[0],0,0.0,-1,2); + newchannel->addIntermediate(it->intermediate,jac,power, 1,3); + } + else if(it->channelType==TBDiagram::channel12) { + newchannel->addIntermediate(extpart[0],0,0.0,-1,3); + newchannel->addIntermediate(it->intermediate,jac,power, 1,2); + } + newchannel->init(); + if(kinCheck&&!newchannel->checkKinematics()) { + generator()->log() << "Erasing diagram " + << *it + << "from three body decay as zero width propagator can be on-shell,\n" + << "hopefully this diagram is zero in your model, but you should check this\n"; + it = diagrams_.erase(it); + if(it == diagrams_.end()) break; + continue; + } + diagmap_.push_back(idiag); + mode->addChannel(newchannel); + ++nmode; + ++idiag; + } + if(nmode==0) { + string mode = extpart[0]->PDGName() + "->"; + for(unsigned int ix=1;ixPDGName() + " "; + throw Exception() << "No decay channels in GeneralThreeBodyDecayer::" + << "doinit() for " << mode << "\n" << Exception::runerror; + } + // // add the mode + vector wgt(nmode,1./double(nmode)); + addMode(mode,1.,wgt); +} diff --git a/Decay/General/GeneralThreeBodyDecayer.h b/Decay/General/GeneralThreeBodyDecayer.h --- a/Decay/General/GeneralThreeBodyDecayer.h +++ b/Decay/General/GeneralThreeBodyDecayer.h @@ -1,321 +1,332 @@ // -*- C++ -*- #ifndef HERWIG_GeneralThreeBodyDecayer_H #define HERWIG_GeneralThreeBodyDecayer_H // // This is the declaration of the GeneralThreeBodyDecayer class. // #include "Herwig/Decay/DecayIntegrator.h" #include "Herwig/Models/General/TBDiagram.h" #include "GeneralThreeBodyDecayer.fh" namespace Herwig { using namespace ThePEG; /** * Here is the documentation of the GeneralThreeBodyDecayer class. * * @see \ref GeneralThreeBodyDecayerInterfaces "The interfaces" * defined for GeneralThreeBodyDecayer. */ class GeneralThreeBodyDecayer: public DecayIntegrator { public: /** A ParticleData ptr and (possible) mass pair.*/ typedef pair PMPair; public: /** * The default constructor. */ GeneralThreeBodyDecayer() : nflow_(999), widthOpt_(1), refTag_(), refTagCC_(), iflow_(999), intOpt_(0), relerr_(1e-2) {} /** @name Virtual functions required by the Decayer class. */ //@{ /** * For a given decay mode and a given particle instance, perform the * decay and return the decay products. As this is the base class this * is not implemented. * @return The vector of particles produced in the decay. */ virtual ParticleVector decay(const Particle & parent, const tPDVector & children) const; /** * Which of the possible decays is required * @param cc Is this mode the charge conjugate * @param parent The decaying particle * @param children The decay products */ virtual int modeNumber(bool & cc, tcPDPtr parent,const tPDVector & children) const; /** * The matrix element to be integrated for the three-body decays as a function * of the invariant masses of pairs of the outgoing particles. * @param imode The mode for which the matrix element is needed. * @param q2 The scale, \e i.e. the mass squared of the decaying particle. * @param s3 The invariant mass squared of particles 1 and 2, \f$s_3=m^2_{12}\f$. * @param s2 The invariant mass squared of particles 1 and 3, \f$s_2=m^2_{13}\f$. * @param s1 The invariant mass squared of particles 2 and 3, \f$s_1=m^2_{23}\f$. * @param m1 The mass of the first outgoing particle. * @param m2 The mass of the second outgoing particle. * @param m3 The mass of the third outgoing particle. * @return The matrix element */ virtual double threeBodyMatrixElement(const int imode, const Energy2 q2, const Energy2 s3, const Energy2 s2, const Energy2 s1, const Energy m1, const Energy m2, const Energy m3) const; /** * Function to return partial Width * @param inpart The decaying particle. * @param outa First decay product. * @param outb Second decay product. * @param outc Third decay product. */ virtual Energy partialWidth(PMPair inpart, PMPair outa, PMPair outb, PMPair outc) const; /** * An overidden member to calculate a branching ratio for a certain * particle instance. * @param dm The DecayMode of the particle * @param p The particle object * @param oldbrat The branching fraction given in the DecayMode object */ virtual double brat(const DecayMode & dm, const Particle & p, double oldbrat) const; //@} /** * Set the diagrams */ bool setDecayInfo(PDPtr incoming,vector outgoing, const vector & process, double symfac); 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(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(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 Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); + + /** + * Initialize this object. Called in the run phase just before + * a run begins. + */ + virtual void doinitrun(); //@} + /** + * Set up the diagrams etc + */ + virtual void setupDiagrams(bool checkKinematics); + protected: /** * Access the TBDiagrams that store the required information * to create the diagrams */ const vector & getProcessInfo() const { return diagrams_; } /** * Incoming particle */ PDPtr incoming() const { return incoming_; } /** * Outgoing particles */ const vector & outgoing() const { return outgoing_; } /** * Number of colour flows */ unsigned int numberOfFlows() const { return nflow_; } /** * Set up the colour factors */ bool setColourFactors(double symfac); /** * Return the matrix of colour factors */ const vector & getColourFactors() const { return colour_; } /** * Return the matrix of colour factors */ const vector & getLargeNcColourFactors() const { return colourLargeNC_; } /** * Get the mapping between the phase-space channel and the diagram */ const vector & diagramMap() const { return diagmap_; } /** * Option for the handling of the widths of the intermediate particles */ unsigned int widthOption() const { return widthOpt_; } /** * Set colour connections * @param parent Parent particle * @param out Particle vector containing particles to * connect colour lines */ void colourConnections(const Particle & parent, const ParticleVector & out) const; /** * Method to construct the channels for the integrator to give the partial width * @param intype Types of the channels * @param inmass Mass for the channels * @param inwidth Width for the channels * @param inpow Power for the channels * @param inweights Weights for the channels */ void constructIntegratorChannels(vector & intype, vector & inmass, vector & inwidth, vector & inpow, vector & inweights) const; /** * Set the colour flow * @param flow The value for the colour flow */ void colourFlow(unsigned int flow) const { iflow_ = flow; } /** * Set the colour flow */ unsigned int const & colourFlow() const { return iflow_; } /** * Relative error for GQ integration */ double relativeError() const {return relerr_;} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ GeneralThreeBodyDecayer & operator=(const GeneralThreeBodyDecayer &); private: /** * Store the incoming particle */ PDPtr incoming_; /** * Outgoing particles */ vector outgoing_; /** * Store the diagrams for the decay */ vector diagrams_; /** * Map between the diagrams and the phase-space channels */ vector diagmap_; /** * Store colour factors for ME calc. */ vector colour_; /** * Store cololur factors for ME calc at large N_c */ vector colourLargeNC_; /** * The number of colourflows. */ unsigned int nflow_; /** * Reference to object to calculate the partial width */ mutable WidthCalculatorBasePtr widthCalc_; /** * Option for the treatment of the widths */ unsigned int widthOpt_; /** * Store a decay tag for this mode that can be tested when * trying to determine whether it can be generated by * this Decayer */ string refTag_; /** * Store a decay tag for the cc-mode that can be tested when * trying to determine whether it can be generated by * this Decayer */ string refTagCC_; /** * The colour flow */ mutable unsigned int iflow_; /** * Option for the construction of the gaussian integrator */ unsigned int intOpt_; /** * Relative error for GQ integration of partial width */ double relerr_; }; } #endif /* HERWIG_GeneralThreeBodyDecayer_H */ diff --git a/Decay/General/SFFDecayer.cc b/Decay/General/SFFDecayer.cc --- a/Decay/General/SFFDecayer.cc +++ b/Decay/General/SFFDecayer.cc @@ -1,491 +1,493 @@ // -*- C++ -*- // // SFFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SFFDecayer class. // #include "SFFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr SFFDecayer::clone() const { return new_ptr(*this); } IBPtr SFFDecayer::fullclone() const { return new_ptr(*this); } void SFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_ .push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } void SFFDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_; } void SFFDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSFFDecayer("Herwig::SFFDecayer", "Herwig.so"); void SFFDecayer::Init() { static ClassDocumentation documentation ("This class implements to decay of a scalar to 2 fermions"); } double SFFDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay,MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin1Half))); // work out which is the fermion and antifermion int iferm(1),ianti(0); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0||itype[1]==1||(itype[0]==2&&itype[1]==2)) swap(iferm,ianti); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart),incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[ianti],outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int ifm = 0; ifm < 2; ++ifm){ for(unsigned int ia = 0; ia < 2; ++ia) { if(iferm > ianti) (*ME())(0, ia, ifm) = 0.; else (*ME())(0, ifm, ia) = 0.; for(auto vert : vertex_) { if(iferm > ianti){ (*ME())(0, ia, ifm) += vert->evaluate(scale,wave_[ia], wavebar_[ifm],swave_); } else { (*ME())(0, ifm, ia) += vert->evaluate(scale,wave_[ia], wavebar_[ifm],swave_); } } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy SFFDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outb.first, outa.first, in); double mu1(outa.second/inpart.second),mu2(outb.second/inpart.second); double c2 = norm(perturbativeVertex_[0]->norm()); Complex al(perturbativeVertex_[0]->left()), ar(perturbativeVertex_[0]->right()); double me2 = -c2*( (norm(al) + norm(ar))*( sqr(mu1) + sqr(mu2) - 1.) + 2.*(ar*conj(al) + al*conj(ar)).real()*mu1*mu2 ); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second, outb.second); Energy output = me2*pcm/(8*Constants::pi); // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double SFFDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { // work out which is the fermion and antifermion int ianti(0), iferm(1), iglu(2); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti); if(itype[0]==2 && itype[1]==1) swap(iferm, ianti); if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(meopt==Initialize) { // create scalar wavefunction for decaying particle ScalarWaveFunction:: calculateWaveFunctions(rho3_,const_ptr_cast(&inpart),incoming); swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); } // setup spin information when needed if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction:: constructSpinInfo(wavebar3_ ,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave3_ ,decay[ianti],outgoing,true); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1Half, PDT::Spin1Half, PDT::Spin1))); // create wavefunctions SpinorBarWaveFunction:: calculateWaveFunctions(wavebar3_, decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[ianti],outgoing); VectorWaveFunction:: calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif // identify fermion and/or anti-fermion vertex AbstractFFVVertexPtr outgoingVertexF; AbstractFFVVertexPtr outgoingVertexA; identifyVertices(iferm, ianti, inpart, decay, outgoingVertexF, outgoingVertexA, inter); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); Energy2 scale(sqr(inpart.mass())); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int ifm = 0; ifm < 2; ++ifm) { for(unsigned int ia = 0; ia < 2; ++ia) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming scalar if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); ScalarWaveFunction scalarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(), gluon_[2*ig],swave3_,inpart.mass()); assert(swave3_.particle()->id()==scalarInter.particle()->id()); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ia], wavebar3_[ifm],scalarInter); for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED)) { assert(outgoingVertexF); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iferm]->dataPtr(); if(off->CC()) off = off->CC(); SpinorBarWaveFunction interS = outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm], gluon_[2*ig],decay[iferm]->mass()); assert(wavebar3_[ifm].particle()->id()==interS.particle()->id()); if(!couplingSet) { gs = abs(outgoingVertexF->norm()); couplingSet = true; } Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ia], interS,swave3_); for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED)) { assert(outgoingVertexA); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ianti]->dataPtr(); if(off->CC()) off = off->CC(); SpinorWaveFunction interS = outgoingVertexA->evaluate(scale,3,off,wave3_[ia], gluon_[2*ig],decay[ianti]->mass()); assert(wave3_[ia].particle()->id()==interS.particle()->id()); if(!couplingSet) { gs = abs(outgoingVertexA->norm()); couplingSet = true; } Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,interS,wavebar3_[ifm],swave3_); for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha(S,EM) output *= (4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } void SFFDecayer::identifyVertices(const int iferm, const int ianti, const Particle & inpart, const ParticleVector & decay, AbstractFFVVertexPtr & outgoingVertexF, AbstractFFVVertexPtr & outgoingVertexA, ShowerInteraction inter) { // QCD if(inter==ShowerInteraction::QCD) { // work out which fermion each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8))) { if(outgoingVertex1_[inter]==outgoingVertex2_[inter]) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) { if(outgoingVertex1_[inter]==outgoingVertex2_[inter]) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr()->iColour()==PDT::Colour3){ if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexF = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexF = outgoingVertex2_[inter]; } else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8) { if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))) { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } else { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } } else if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3bar && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) { if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){ if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar && decay[iferm]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter]; } else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } else if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3) { if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour6 || inpart.dataPtr()->iColour()==PDT::Colour6bar) { if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } if (! ((incomingVertex_[inter] && (outgoingVertexF || outgoingVertexA)) || ( outgoingVertexF && outgoingVertexA))) { throw Exception() << "Invalid vertices for QCD radiation in SFF decay in SFFDecayer::identifyVertices" << Exception::runerror; } } // QED else { if(decay[iferm]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) outgoingVertexF = outgoingVertex1_[inter]; else outgoingVertexF = outgoingVertex2_[inter]; } if(decay[ianti]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))) outgoingVertexA = outgoingVertex1_[inter]; else outgoingVertexA = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/SRFDecayer.cc b/Decay/General/SRFDecayer.cc --- a/Decay/General/SRFDecayer.cc +++ b/Decay/General/SRFDecayer.cc @@ -1,196 +1,198 @@ // -*- C++ -*- // // SRFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SRFDecayer class. // #include "SRFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr SRFDecayer::clone() const { return new_ptr(*this); } IBPtr SRFDecayer::fullclone() const { return new_ptr(*this); } void SRFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map &, const vector > &, map) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_ .push_back(dynamic_ptr_cast (vert)); } } void SRFDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_; } void SRFDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSRFDecayer("Herwig::SRFDecayer", "Herwig.so"); void SRFDecayer::Init() { static ClassDocumentation documentation ("This class implements to decay of a scalar to a spin-3/2 and" " spin-1/2 fermion"); } double SRFDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay,MEOption meopt) const { unsigned int irs=0,ifm=1; if(decay[0]->dataPtr()->iSpin()==PDT::Spin1Half) swap(irs,ifm); if(!ME()) { if(irs==0) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin3Half,PDT::Spin1Half))); else ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin3Half))); } bool ferm = decay[ifm]->id()<0; if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart),incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); if(ferm) { RSSpinorBarWaveFunction:: constructSpinInfo(RSwavebar_,decay[irs],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ifm],outgoing,true); } else { RSSpinorWaveFunction:: constructSpinInfo(RSwave_ ,decay[irs],outgoing,true); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[ifm],outgoing,true); } return 0.; } if(ferm) { RSSpinorBarWaveFunction:: calculateWaveFunctions(RSwavebar_,decay[irs],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[ifm],outgoing); } else { RSSpinorWaveFunction:: calculateWaveFunctions(RSwave_ ,decay[irs],outgoing); SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[ifm],outgoing); } Energy2 scale(sqr(inpart.mass())); for(unsigned int ifm = 0; ifm < 4; ++ifm){ for(unsigned int ia = 0; ia < 2; ++ia) { if(irs==0) { if(ferm) { (*ME())(0, ifm, ia) = 0.; for(auto vert : vertex_) (*ME())(0, ifm, ia) += vert->evaluate(scale,wave_[ia], RSwavebar_[ifm],swave_); } else { (*ME())(0, ifm, ia) = 0.; for(auto vert : vertex_) (*ME())(0, ifm, ia) += vert->evaluate(scale,RSwave_[ifm], wavebar_[ia],swave_); } } else { if(ferm) { (*ME())(0, ia, ifm) = 0.; for(auto vert : vertex_) (*ME())(0, ia, ifm) += vert->evaluate(scale,wave_[ia], RSwavebar_[ifm],swave_); } else { (*ME())(0, ia, ifm) = 0.; for(auto vert : vertex_) (*ME())(0, ia, ifm) += vert->evaluate(scale,RSwave_[ifm], wavebar_[ia],swave_); } } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[irs]->dataPtr(), decay[ifm]->dataPtr()); // return the answer return output; } Energy SRFDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy q = inpart.second; Energy m1 = outa.second, m2 = outb.second; // couplings tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; if(outa.first->iSpin()==PDT::Spin1Half) { swap(m1,m2); perturbativeVertex_[0]->setCoupling(sqr(inpart.second),outb.first, outa.first, in); } else { perturbativeVertex_[0]->setCoupling(sqr(inpart.second),outa.first, outb.first, in); } Complex left = perturbativeVertex_[0]-> left()*perturbativeVertex_[0]-> norm(); Complex right = perturbativeVertex_[0]->right()*perturbativeVertex_[0]-> norm(); complex A1 = 0.5*(left+right)*UnitRemoval::InvE; complex B1 = 0.5*(right-left)*UnitRemoval::InvE; Energy2 q2(q*q),m12(m1*m1),m22(m2*m2); Energy2 pcm2(0.25*(q2*(q2-2.*m12-2.*m22)+(m12-m22)*(m12-m22))/q2); Energy pcm(sqrt(pcm2)); Energy Qp(sqrt(-sqr(m2+m1)+q2)),Qm(sqrt(-sqr(m2-m1)+q2)); double r23(sqrt(2./3.)); complex h1(-2.*r23*pcm*q/m1*Qm*B1); complex h2( 2.*r23*pcm*q/m1*Qp*A1); double me2 = real(h1*conj(h1)+h2*conj(h2))/2./sqr(inpart.second); Energy output = me2*pcm/8./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } diff --git a/Decay/General/SSSDecayer.cc b/Decay/General/SSSDecayer.cc --- a/Decay/General/SSSDecayer.cc +++ b/Decay/General/SSSDecayer.cc @@ -1,410 +1,412 @@ // -*- C++ -*- // // SSSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SSSDecayer class. // #include "SSSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr SSSDecayer::clone() const { return new_ptr(*this); } IBPtr SSSDecayer::fullclone() const { return new_ptr(*this); } void SSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } void SSSDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_; } void SSSDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSSSDecayer("Herwig::SSSDecayer", "Herwig.so"); void SSSDecayer::Init() { static ClassDocumentation documentation ("This class implements the decay of a scalar to 2 scalars."); } double SSSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin0,PDT::Spin0))); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart),incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); for(unsigned int ix=0;ix<2;++ix) ScalarWaveFunction:: constructSpinInfo(decay[ix],outgoing,true); } ScalarWaveFunction s1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing); ScalarWaveFunction s2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); (*ME())(0,0,0) = 0.; for(auto vert : vertex_) { (*ME())(0,0,0) += vert->evaluate(scale,s1,s2,swave_); } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy SSSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0] && !perturbativeVertex_[0]->kinematics()) { Energy2 scale(sqr(inpart.second)); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(scale, in, outa.first, outb.first); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second, outb.second); double c2 = norm(perturbativeVertex_[0]->norm()); Energy pWidth = c2*pcm/8./Constants::pi/scale*UnitRemoval::E2; // colour factor pWidth *= colourFactor(inpart.first,outa.first,outb.first); return pWidth; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double SSSDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { // work out which is the scalar and anti scalar int ianti(0), iscal(1), iglu(2); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0 && itype[1]!=0) swap(ianti, iscal); if(itype[0]==2 && itype[1]==1) swap(ianti, iscal); if(itype[0]==0 && itype[1]==0 && abs(decay[0]->dataPtr()->id())>abs(decay[1]->dataPtr()->id())) swap(iscal, ianti); if(itype[0]==1 && itype[1]==1 && abs(decay[0]->dataPtr()->id())dataPtr()->id())) swap(iscal, ianti); if(meopt==Initialize) { // create scalar wavefunction for decaying particle ScalarWaveFunction::calculateWaveFunctions(rho3_,const_ptr_cast(&inpart),incoming); swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); } // setup spin information when needed if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); ScalarWaveFunction:: constructSpinInfo(decay[iscal],outgoing,true); ScalarWaveFunction:: constructSpinInfo(decay[ianti],outgoing,true); VectorWaveFunction:: constructSpinInfo(gluon_,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin0, PDT::Spin0, PDT::Spin1))); // create wavefunctions ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing); ScalarWaveFunction anti(decay[ianti]->momentum(), decay[ianti]->dataPtr(),outgoing); VectorWaveFunction::calculateWaveFunctions(gluon_,decay[iglu ],outgoing,true); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif AbstractVSSVertexPtr outgoingVertexS; AbstractVSSVertexPtr outgoingVertexA; identifyVertices(iscal, ianti, inpart, decay, outgoingVertexS, outgoingVertexA,inter); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming scalar if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); ScalarWaveFunction scalarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(), gluon_[2*ig],swave3_,inpart.mass()); assert(swave3_.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,scal,anti,scalarInter); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexS); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iscal]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexS->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass()); assert(scal.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,swave3_,anti,scalarInter); if(!couplingSet) { gs = abs(outgoingVertexS->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexA); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ianti]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexA->evaluate(scale,3,off, gluon_[2*ig],anti,decay[ianti]->mass()); assert(anti.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,swave3_,scal,scalarInter); if(!couplingSet) { gs = abs(outgoingVertexA->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } void SSSDecayer::identifyVertices(const int iscal, const int ianti, const Particle & inpart, const ParticleVector & decay, AbstractVSSVertexPtr & outgoingVertexS, AbstractVSSVertexPtr & outgoingVertexA, ShowerInteraction inter){ // QCD if(inter==ShowerInteraction::QCD) { // work out which scalar each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[iscal]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr() ->iColour()==PDT::Colour3){ if(decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexS = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexS = outgoingVertex2_[inter]; } else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } else { outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } } } else if(inpart.dataPtr() ->iColour()==PDT::Colour3bar){ if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar && decay[iscal]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter]; } else if (decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar && decay[iscal]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->dataPtr()->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } } if (! ((incomingVertex_[inter] && (outgoingVertexS || outgoingVertexA)) || ( outgoingVertexS && outgoingVertexA))) throw Exception() << "Invalid vertices for QCD radiation in SSS decay in SSSDecayer::identifyVertices" << Exception::runerror; } // QED else { if(decay[iscal]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iscal]->dataPtr()))) outgoingVertexS = outgoingVertex1_[inter]; else outgoingVertexS = outgoingVertex2_[inter]; } if(decay[ianti]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))) outgoingVertexA = outgoingVertex1_[inter]; else outgoingVertexA = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/SSVDecayer.cc b/Decay/General/SSVDecayer.cc --- a/Decay/General/SSVDecayer.cc +++ b/Decay/General/SSVDecayer.cc @@ -1,366 +1,368 @@ // -*- C++ -*- // // SSVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SSVDecayer class. // #include "SSVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr SSVDecayer::clone() const { return new_ptr(*this); } IBPtr SSVDecayer::fullclone() const { return new_ptr(*this); } void SSVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map fourV) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); fourPointVertex_[inter] = dynamic_ptr_cast(fourV.at(inter)); outgoingVertexS_[inter] = AbstractVSSVertexPtr(); outgoingVertexV_[inter] = AbstractVVVVertexPtr(); if(outV[0].at(inter)) { if (outV[0].at(inter)->getName()==VertexType::VSS) outgoingVertexS_[inter] = dynamic_ptr_cast(outV[0].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[0].at(inter)); } if(outV[1].at(inter)) { if (outV[1].at(inter)->getName()==VertexType::VSS) outgoingVertexS_[inter] = dynamic_ptr_cast(outV[1].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } } void SSVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertexS_ << outgoingVertexV_ << fourPointVertex_; } void SSVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertexS_ >> outgoingVertexV_ >> fourPointVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSSVDecayer("Herwig::SSVDecayer", "Herwig.so"); void SSVDecayer::Init() { static ClassDocumentation documentation ("This implements the decay of a scalar to a vector and a scalar"); } double SSVDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { unsigned int isc(0),ivec(1); if(decay[0]->dataPtr()->iSpin() != PDT::Spin0) swap(isc,ivec); if(!ME()) { if(ivec==1) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin0,PDT::Spin1))); else ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1,PDT::Spin0))); } if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart),incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); ScalarWaveFunction:: constructSpinInfo(decay[isc],outgoing,true); VectorWaveFunction:: constructSpinInfo(vector_,decay[ivec],outgoing,true,false); } VectorWaveFunction:: calculateWaveFunctions(vector_,decay[ivec],outgoing,false); ScalarWaveFunction sca(decay[isc]->momentum(),decay[isc]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); //make sure decay matrix element is in the correct order double output(0.); if(ivec == 0) { for(unsigned int ix = 0; ix < 3; ++ix) { (*ME())(0, ix, 0) = 0.; for(auto vert : vertex_) (*ME())(0, ix, 0) += vert->evaluate(scale,vector_[ix],sca, swave_); } } else { for(unsigned int ix = 0; ix < 3; ++ix) { (*ME())(0, 0, ix) = 0.; for(auto vert : vertex_) (*ME())(0, 0, ix) += vert->evaluate(scale,vector_[ix],sca,swave_); } } output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy SSVDecayer:: partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { double mu1sq(sqr(outa.second/inpart.second)), mu2sq(sqr(outb.second/inpart.second)); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; if(outa.first->iSpin() == PDT::Spin0) { perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outb.first, outa.first,in); } else { swap(mu1sq,mu2sq); perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first, outb.first,in); } double me2(0.); if(mu2sq == 0.) me2 = -2.*mu1sq - 2.; else me2 = ( sqr(mu2sq - mu1sq) - 2.*(mu2sq + mu1sq) + 1. )/mu2sq; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second, outa.second, outb.second); Energy output = pcm*me2*norm(perturbativeVertex_[0]->norm())/8./Constants::pi; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double SSVDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { int iscal (0), ivect (1), iglu (2); // get location of outgoing scalar/vector if(decay[1]->dataPtr()->iSpin()==PDT::Spin0) swap(iscal,ivect); if(meopt==Initialize) { // create scalar wavefunction for decaying particle ScalarWaveFunction::calculateWaveFunctions(rho3_,const_ptr_cast(&inpart),incoming); swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); } // setup spin information when needed if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); ScalarWaveFunction:: constructSpinInfo(decay[iscal],outgoing,true); VectorWaveFunction:: constructSpinInfo(vector3_,decay[ivect],outgoing,true,false); VectorWaveFunction:: constructSpinInfo(gluon_, decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin0, PDT::Spin1, PDT::Spin1))); // create wavefunctions ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing); VectorWaveFunction::calculateWaveFunctions(vector3_,decay[ivect],outgoing,false); VectorWaveFunction::calculateWaveFunctions(gluon_, decay[iglu ],outgoing,true ); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif if (! ((incomingVertex_[inter] && (outgoingVertexS_[inter] || outgoingVertexV_[inter])) || (outgoingVertexS_[inter] && outgoingVertexV_[inter]))) throw Exception() << "Invalid vertices for radiation in SSV decay in SSVDecayer::threeBodyME" << Exception::runerror; // sort out colour flows int S(1), V(2); if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3bar && decay[ivect]->dataPtr()->iColour()==PDT::Colour8) swap(S,V); else if (decay[ivect]->dataPtr()->iColour()==PDT::Colour3 && decay[iscal]->dataPtr()->iColour()==PDT::Colour8) swap(S,V); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv = 0; iv < 3; ++iv) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming scalar if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); ScalarWaveFunction scalarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(), gluon_[2*ig],swave3_,inpart.mass()); assert(swave3_.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv],scal,scalarInter); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexS_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iscal]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass()); assert(scal.particle()->id()==scalarInter.particle()->id()); if(!couplingSet) { gs = abs(outgoingVertexS_[inter]->norm()); couplingSet = true; } Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv],scalarInter,swave3_); for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ivect]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexV_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ivect]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig], vector3_[iv],decay[ivect]->mass()); assert(vector3_[iv].particle()->id()==vectorInter.particle()->id()); if(!couplingSet) { gs = abs(outgoingVertexV_[inter]->norm()); couplingSet = true; } Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectorInter,scal,swave3_); for(unsigned int ix=0;ixevaluate(scale, gluon_[2*ig], vector3_[iv], scal, swave3_); for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/SVVDecayer.cc b/Decay/General/SVVDecayer.cc --- a/Decay/General/SVVDecayer.cc +++ b/Decay/General/SVVDecayer.cc @@ -1,432 +1,434 @@ // -*- C++ -*- // // SVVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SVVDecayer class. // #include "SVVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/Vertex/Scalar/VVSVertex.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr SVVDecayer::clone() const { return new_ptr(*this); } IBPtr SVVDecayer::fullclone() const { return new_ptr(*this); } void SVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } void SVVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_; } void SVVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSVVDecayer("Herwig::SVVDecayer", "Herwig.so"); void SVVDecayer::Init() { static ClassDocumentation documentation ("This implements the decay of a scalar to 2 vector bosons."); } double SVVDecayer::me2(const int , const Particle & inpart, const ParticleVector& decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1,PDT::Spin1))); bool photon[2]; for(unsigned int ix=0;ix<2;++ix) photon[ix] = decay[ix]->mass()==ZERO; if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart),incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: constructSpinInfo(vectors_[ix],decay[ix],outgoing,true,photon[ix]); } for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: calculateWaveFunctions(vectors_[ix],decay[ix],outgoing,photon[ix]); Energy2 scale(sqr(inpart.mass())); unsigned int iv1,iv2; for(iv2 = 0; iv2 < 3; ++iv2) { if( photon[1] && iv2 == 1 ) ++iv2; for(iv1=0;iv1<3;++iv1) { if( photon[0] && iv1 == 1) ++iv1; (*ME())(0, iv1, iv2) = 0.; for(auto vert : vertex_) (*ME())(0, iv1, iv2) += vert->evaluate(scale,vectors_[0][iv1], vectors_[1][iv2],swave_); } } double output = ME()->contract(rho_).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy SVVDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy2 scale(sqr(inpart.second)); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(scale, outa.first , outb.first, in); double mu1sq = sqr(outa.second/inpart.second); double mu2sq = sqr(outb.second/inpart.second); double m1pm2 = mu1sq + mu2sq; double me2(0.); if( mu1sq > 0. && mu2sq > 0.) me2 = ( m1pm2*(m1pm2 - 2.) + 8.*mu1sq*mu2sq + 1.)/4./mu1sq/mu2sq; else if( mu1sq == 0. || mu2sq == 0. ) me2 = 3.; else me2 = 4.; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = norm(perturbativeVertex_[0]->norm())* me2*pcm/(8*Constants::pi)/scale*UnitRemoval::E2; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double SVVDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { if(meopt==Initialize) { // create scalar wavefunction for decaying particle ScalarWaveFunction:: calculateWaveFunctions(rho3_,const_ptr_cast(&inpart),incoming); swave3_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart),incoming,true); VectorWaveFunction:: constructSpinInfo(vectors3_[0],decay[0],outgoing,true,false); VectorWaveFunction:: constructSpinInfo(vectors3_[1],decay[1],outgoing,true,false); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[2],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1, PDT::Spin1, PDT::Spin1))); bool massless[2]; for(unsigned int ix=0;ix<2;++ix) massless[ix] = decay[ix]->mass()!=ZERO; // create wavefunctions VectorWaveFunction::calculateWaveFunctions(vectors3_[0],decay[0],outgoing,massless[0]); VectorWaveFunction::calculateWaveFunctions(vectors3_[1],decay[1],outgoing,massless[1]); VectorWaveFunction::calculateWaveFunctions(gluon_ ,decay[2],outgoing,true); // gauge test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[2]->momentum(), decay[2]->dataPtr(),10, outgoing)); } } #endif // get the outgoing vertices AbstractVVVVertexPtr outgoingVertex1; AbstractVVVVertexPtr outgoingVertex2; identifyVertices(inpart,decay, outgoingVertex1, outgoingVertex2,inter); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv1 = 0; iv1 < 3; ++iv1) { if(massless[0] && iv1==1) continue; for(unsigned int iv2 = 0; iv2 < 3; ++iv2) { if(massless[1] && iv2==1) continue; for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming vector if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); ScalarWaveFunction scalarInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),gluon_[2*ig], swave3_,inpart.mass()); assert(swave3_.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectors3_[0][iv1], vectors3_[1][iv2],scalarInter); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[0]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex1); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[0]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertex1->evaluate(scale,3,off,gluon_[2*ig],vectors3_[0][iv1],decay[0]->mass()); assert(vectors3_[0][iv1].particle()->id()==vectorInter.particle()->id()); Complex diag =0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectorInter,vectors3_[1][iv2],swave3_); if(!couplingSet) { gs = abs(outgoingVertex1->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[1]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex2); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[1]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertex2->evaluate(scale,3,off, gluon_[2*ig],vectors3_[1][iv2],decay[1]->mass()); assert(vectors3_[1][iv2].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectors3_[0][iv1],vectorInter,swave3_); if(!couplingSet) { gs = abs(outgoingVertex2->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } void SVVDecayer::identifyVertices(const Particle & inpart, const ParticleVector & decay, AbstractVVVVertexPtr & outgoingVertex1, AbstractVVVVertexPtr & outgoingVertex2, ShowerInteraction inter) { if(inter==ShowerInteraction::QCD) { // work out which scalar each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[0]->dataPtr()->iColour()==PDT::Colour8 && decay[1]->dataPtr()->iColour()==PDT::Colour8))){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr()->iColour()==PDT::Colour3){ if(decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertex1 = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertex1 = outgoingVertex2_[inter]; } else if (decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[1]->dataPtr()->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } else { outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){ if(decay[1]->dataPtr()->iColour()==PDT::Colour3bar && decay[0]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertex2 = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertex2 = outgoingVertex2_[inter]; } else if (decay[0]->dataPtr()->iColour()==PDT::Colour8 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->dataPtr()->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else { outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } } if (! ((incomingVertex_[inter] && (outgoingVertex1 || outgoingVertex2)) || ( outgoingVertex1 && outgoingVertex2))) throw Exception() << "Invalid vertices for QCD radiation in SVV decay in SVVDecayer::identifyVertices" << Exception::runerror; } else { if(decay[0]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[0]->dataPtr()))) outgoingVertex1 = outgoingVertex1_[inter]; else outgoingVertex1 = outgoingVertex2_[inter]; } if(decay[1]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[1]->dataPtr()))) outgoingVertex2 = outgoingVertex1_[inter]; else outgoingVertex2 = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/StoFFFFDecayer.cc b/Decay/General/StoFFFFDecayer.cc --- a/Decay/General/StoFFFFDecayer.cc +++ b/Decay/General/StoFFFFDecayer.cc @@ -1,1306 +1,1308 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the StoFFFFDecayer class. // #include "StoFFFFDecayer.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Decay/DecayPhaseSpaceMode.h" #include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h" #include "ThePEG/Helicity/Vertex/Scalar/FFSVertex.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG::Helicity; namespace { inline bool isParticle(tPPtr part) { return part->id()>0 && part->dataPtr()->CC(); } inline bool isAntiParticle(tPPtr part) { return part->id()<0 && part->dataPtr()->CC(); } inline bool isMajorana(tPPtr part) { return !part->dataPtr()->CC(); } } IBPtr StoFFFFDecayer::clone() const { return new_ptr(*this); } IBPtr StoFFFFDecayer::fullclone() const { return new_ptr(*this); } void StoFFFFDecayer::persistentOutput(PersistentOStream & os) const { os << firstVVS_ << firstVSS_ << firstSSS_ << firstFFS_ << secondFFV_ << secondFFS_ << thirdFFV_ << thirdFFS_ << sign_; } void StoFFFFDecayer::persistentInput(PersistentIStream & is, int) { is >> firstVVS_ >> firstVSS_ >> firstSSS_ >> firstFFS_ >> secondFFV_ >> secondFFS_ >> thirdFFV_ >> thirdFFS_ >> sign_; } DescribeClass describeStoFFFFDecayer("Herwig::StoFFFFDecayer", "Herwig.so"); void StoFFFFDecayer::Init() { static ClassDocumentation documentation ("The StoFFFFDecayer class performs the 4-fermion " "decays of scalar particles in BSM models"); } void StoFFFFDecayer::doinit() { GeneralFourBodyDecayer::doinit(); unsigned int ndiags = getProcessInfo().size(); firstVVS_ .resize(ndiags); firstVSS_ .resize(ndiags); firstSSS_ .resize(ndiags); firstFFS_ .resize(ndiags); secondFFV_.resize(ndiags); secondFFS_.resize(ndiags); thirdFFV_ .resize(ndiags); thirdFFS_ .resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { const NBDiagram & current = getProcessInfo()[ix]; // first vertex firstVVS_[ix] = dynamic_ptr_cast(current.vertex); firstVSS_[ix] = dynamic_ptr_cast(current.vertex); firstSSS_[ix] = dynamic_ptr_cast(current.vertex); firstFFS_[ix] = dynamic_ptr_cast(current.vertex); // get the other vertices const NBVertex & second = current.vertices.begin()->second.incoming ? current.vertices.begin()->second : (++current.vertices.begin())->second; // get the other vertices const NBVertex & third = current.vertices.begin()->second.incoming ? (++current.vertices.begin())->second : (++second.vertices.begin())->second; // second vertex secondFFV_[ix] = dynamic_ptr_cast(second.vertex); secondFFS_[ix] = dynamic_ptr_cast(second.vertex); // third vertex thirdFFV_ [ix] = dynamic_ptr_cast(third .vertex); thirdFFS_ [ix] = dynamic_ptr_cast(third .vertex); assert( ( firstVVS_[ix] || firstVSS_[ix] || firstSSS_[ix] || firstFFS_[ix] ) && (secondFFV_[ix] || secondFFS_[ix] ) && ( thirdFFV_[ix] || thirdFFS_[ix] )); // NO sign int order = current.channelType[0]*1000+current.channelType[1]*100+ current.channelType[2]*10 +current.channelType[3]; switch(order) { case 1234: case 1342: case 1423: case 2143: case 2314: case 2431: case 3124: case 3241: case 3412: case 4132: case 4213: case 4321: sign_.push_back( 1.); break; case 1243: case 1324: case 1432: case 2134: case 2341: case 2413: case 3142: case 3214: case 3421: case 4123: case 4231: case 4312: sign_.push_back(-1.); break; default: assert(false); } } } double StoFFFFDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming->id() != inpart.id(); // special handling or first/last call const vector > & cfactors(getColourFactors()); const vector > & nfactors(getLargeNcColourFactors()); const size_t ncf(numberOfFlows()); Energy2 scale(sqr(inpart.mass())); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart), Helicity::incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(), Helicity::incoming); + // fix rho if no correlations + fixRho(rho_); } // setup spin info when needed if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart), Helicity::incoming,true); // outgoing particles for(unsigned int ix = 0; ix < 4; ++ix) { SpinorWaveFunction:: constructSpinInfo(outwave_[ix].first,decay[ix],Helicity::outgoing,true); } } // outgoing particles for(unsigned int ix = 0; ix < 4; ++ix) { SpinorWaveFunction:: calculateWaveFunctions(outwave_[ix].first,decay[ix],Helicity::outgoing); outwave_[ix].second.resize(2); if(outwave_[ix].first[0].wave().Type() == SpinorType::u) { for(unsigned int iy = 0; iy < 2; ++iy) { outwave_[ix].second[iy] = outwave_[ix].first[iy].bar(); outwave_[ix].first[iy].conjugate(); } } else { for(unsigned int iy = 0; iy < 2; ++iy) { outwave_[ix].second[iy] = outwave_[ix].first[iy].bar(); outwave_[ix].second[iy].conjugate(); } } } // matrix element for the colour flows vector flows(ncf, Complex(0.)),largeflows(ncf, Complex(0.)); vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); // calculate the matrix element unsigned int ihel[4]; for(ihel[0] = 0; ihel[0] < 2; ++ihel[0]) { for(ihel[1] = 0; ihel[1] < 2; ++ihel[1]) { for(ihel[2] = 0; ihel[2] < 2; ++ihel[2]) { for(ihel[3] = 0; ihel[3] < 2; ++ihel[3]) { flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag=0; for(vector::const_iterator dit=getProcessInfo().begin(); dit!=getProcessInfo().end();++dit) { if(ichan>=0&&diagramMap()[ichan]!=idiag) { ++idiag; continue; } // location of the particles int iloc[4]; for(unsigned int ix=0;ix<4;++ix) iloc[ix] = dit->channelType[ix]-1; // NO sign double sign = sign_[idiag]; // work out the type of topology bool topo = dit->vertices.begin()->second.incoming; const NBVertex & second = topo ? dit->vertices.begin() ->second : (++(dit->vertices.begin()))->second; const NBVertex & third = topo ? (++(dit-> vertices.begin()))->second : (++(second.vertices.begin()))->second; // extract the intermediates tPDPair inter = make_pair(second.incoming, third .incoming); if( inter.second->CC()) inter.second = inter.second->CC(); if(cc&&inter.first ->CC()) inter.first = inter.first ->CC(); if(cc&&inter.second->CC()) inter.second = inter.second->CC(); // value for the diagram Complex diag(0.); // first compute the last part of the diagram VectorWaveFunction offVector2; ScalarWaveFunction offScalar2; // intermediate scalar if(inter.second->iSpin()==PDT::Spin0) { if( (isAntiParticle(decay[iloc[2]]) || isMajorana(decay[iloc[2]])) && (isParticle (decay[iloc[3]]) || isMajorana(decay[iloc[3]])) ) { sign *= -1.; offScalar2 = thirdFFS_[idiag]-> evaluate(scale, widthOption(),inter.second, outwave_[iloc[2]].first [ihel[iloc[2]]], outwave_[iloc[3]].second[ihel[iloc[3]]]); } else { offScalar2 = thirdFFS_[idiag]-> evaluate(scale, widthOption(),inter.second, outwave_[iloc[3]].first [ihel[iloc[3]]], outwave_[iloc[2]].second[ihel[iloc[2]]]); } } // intermediate vector else if(inter.second->iSpin()==PDT::Spin1) { if( (isAntiParticle(decay[iloc[2]]) || isMajorana(decay[iloc[2]])) && (isParticle(decay[iloc[3]])||isMajorana(decay[iloc[3]]))) { sign *= -1.; offVector2 = thirdFFV_[idiag]-> evaluate(scale, widthOption(),inter.second, outwave_[iloc[2]].first [ihel[iloc[2]]], outwave_[iloc[3]].second[ihel[iloc[3]]]); } else { offVector2 = thirdFFV_[idiag]-> evaluate(scale, widthOption(),inter.second, outwave_[iloc[3]].first [ihel[iloc[3]]], outwave_[iloc[2]].second[ihel[iloc[2]]]); } } // unknown else assert(false); // first topology if(topo) { // first intermediate if(inter.first->CC()) inter.first = inter.first->CC(); VectorWaveFunction offVector1; ScalarWaveFunction offScalar1; // intermeidate scalar if(inter.first->iSpin()==PDT::Spin0) { if(decay[iloc[0]]->id()<0&& decay[iloc[1]]->id()>0) { sign *= -1.; offScalar1 = secondFFS_[idiag]-> evaluate(scale, widthOption(),inter.first, outwave_[iloc[0]].first [ihel[iloc[0]]], outwave_[iloc[1]].second[ihel[iloc[1]]]); } else { offScalar1 = secondFFS_[idiag]-> evaluate(scale, widthOption(),inter.first, outwave_[iloc[1]].first [ihel[iloc[1]]], outwave_[iloc[0]].second[ihel[iloc[0]]]); } } // intermediate vector else if(inter.first->iSpin()==PDT::Spin1) { if(decay[iloc[0]]->id()<0&& decay[iloc[1]]->id()>0) { sign *= -1.; offVector1 = secondFFV_[idiag]-> evaluate(scale, widthOption(),inter.first, outwave_[iloc[0]].first [ihel[iloc[0]]], outwave_[iloc[1]].second[ihel[iloc[1]]]); } else { offVector1 = secondFFV_[idiag]-> evaluate(scale, widthOption(),inter.first, outwave_[iloc[1]].first [ihel[iloc[1]]], outwave_[iloc[0]].second[ihel[iloc[0]]]); } } // unknown else assert(false); // put it all together if(inter.first->iSpin()==PDT::Spin0) { if(inter.second->iSpin()==PDT::Spin0) { diag = firstSSS_[idiag]-> evaluate(scale,swave_,offScalar1,offScalar2); } else if(inter.second->iSpin()==PDT::Spin1) { diag = firstVSS_[idiag]-> evaluate(scale,offVector2,offScalar1,swave_); } } else if(inter.first->iSpin()==PDT::Spin1) { if(inter.second->iSpin()==PDT::Spin0) { diag = firstVSS_[idiag]-> evaluate(scale,offVector1,offScalar2,swave_); } else if(inter.second->iSpin()==PDT::Spin1) { diag = firstVVS_[idiag]-> evaluate(scale,offVector1,offVector2,swave_); } } } // second topology else { if(((isAntiParticle(decay[iloc[0]]) || isMajorana(decay[iloc[0]]))&& (isParticle (decay[iloc[1]]) || isMajorana(decay[iloc[1]])))) { sign *= -1.; SpinorWaveFunction inters = firstFFS_[idiag]-> evaluate(scale,widthOption(),inter.first, outwave_[iloc[0]].first [ihel[iloc[0]]],swave_); if(inter.second->iSpin()==PDT::Spin0) { diag = secondFFS_[idiag]-> evaluate(scale,inters,outwave_[iloc[1]].second[ihel[iloc[1]]], offScalar2); } else { diag = secondFFV_[idiag]-> evaluate(scale,inters,outwave_[iloc[1]].second[ihel[iloc[1]]], offVector2); } } else { SpinorBarWaveFunction inters = firstFFS_[idiag]-> evaluate(scale,widthOption(),inter.first, outwave_[iloc[0]].second[ihel[iloc[0]]],swave_); if(inter.second->iSpin()==PDT::Spin0) { diag = secondFFS_[idiag]-> evaluate(scale,outwave_[iloc[1]].first [ihel[iloc[1]]],inters, offScalar2); } else { diag = secondFFV_[idiag]-> evaluate(scale,outwave_[iloc[1]].first [ihel[iloc[1]]],inters, offVector2); } } } // apply NO sign diag *= sign; // matrix element for the different colour flows if(ichan<0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; } // now add the flows to the me2 with appropriate colour factors for(unsigned int ix = 0; ix < ncf; ++ix) { (*mes[ix])(0,ihel[0],ihel[1],ihel[2],ihel[3]) = flows[ix]; (*mel[ix])(0,ihel[0],ihel[1],ihel[2],ihel[3]) = largeflows[ix]; } } } } } double me2(0.); if(ichan<0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix==iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *=UseRandom::rnd(); for(unsigned int ix=0;ixcontract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2*scale*UnitRemoval::InvE2; } // OLD TESTING CODE // extracted from StandardModel.h // public: // virtual void StopCouplings(Energy2 &,tcPDPtr, tcPDPtr, // double &, double &, double &, // Complex &, Complex &, // vector &, vector &, // vector &, // vector &, vector &, // vector &, vector &, // vector &, vector &, // vector > &, vector > &, // vector > &, vector > &, // vector &, vector &, // vector &, vector &, // double &, double &) { // assert(false); // } // extracted from RunningMass.cc // if(id==5) return 4.8787783899999999*GeV; // if(id==15) return 1.7770999999999999*GeV; // extracted from MSSM.h // public: // virtual void StopCouplings(Energy2 &, tcPDPtr, tcPDPtr, // double & g, double & sw, double & cw, // Complex & aL, Complex & aR, // vector & cL, vector & cR, // vector & d, // vector & bL, vector & bR, // vector & kL, vector & kR, // vector & fL, vector & fR, // vector > & eL, vector > & eR, // vector > & gL, vector > & gR, // vector & hL, vector & hR, // vector & lL, vector & lR, // double & ytop, double & ytau); // extracted from MSSM.cc // void MSSM::StopCouplings(Energy2 & scale, tcPDPtr ferm, tcPDPtr anti, double & g, double & sw, double & cw, // Complex & aL, Complex & aR, // vector & cL, vector & cR, // vector & d, // vector & bL, vector & bR, // vector & kL, vector & kR, // vector & fL, vector & fR, // vector > & eL, vector > & eR, // vector > & gL, vector > & gR, // vector & hL, vector & hR, // vector & lL, vector & lR, // double & ytop, double & ytau) { // MixingMatrixPtr stop = stopMix(); // MixingMatrixPtr sbot = sbottomMix(); // MixingMatrixPtr stau = stauMix(); // MixingMatrixPtr neut = neutralinoMix(); // MixingMatrixPtr vmix = charginoVMix(); // MixingMatrixPtr umix = charginoUMix(); // sw = sqrt( sin2ThetaW()); // cw = sqrt(1.-sin2ThetaW()); // g = sqrt(4.0*Constants::pi*alphaEMMZ()/sin2ThetaW()); // Energy mb = mass(scale,getParticleData(ParticleID::b)); // Energy mt = mass(scale,getParticleData(ParticleID::t)); // Energy mw = getParticleData(ParticleID::Wplus)->mass(); // double tb = tanBeta(); // double sb = tb/sqrt(1 + sqr(tb)); // double cb = sqrt(1 - sqr(sb)); // Complex n1prime = (*neut)(0,0)*cw + (*neut)(0,1)*sw; // Complex n2prime = (*neut)(0,1)*cw - (*neut)(0,0)*sw; // double yt = double(mt/mw)/sb/sqrt(2.); // Complex bracketl = 2./ 3.*sw*( conj(n1prime) - sw*conj(n2prime)/cw ); // Complex bracketr = 2./3.*sw*n1prime - n2prime*(-0.5 + 2./3.*sqr(sw))/cw; // ytop = mt/tb/mw; // aL = -yt*conj((*neut)(0,3))*(*stop)(0,0) + sqrt(2.)*(*stop)(0,1)*bracketl; // aR = -yt* (*neut)(0,3) *(*stop)(0,1) - sqrt(2.)*(*stop)(0,0)*bracketr; // cL.resize(2); cR.resize(2); d.resize(2.); // kL.resize(2); kR.resize(2); // bL.resize(2); bR.resize(2); // double yb = double(mb/mw)/cb/sqrt(2.); // bracketl = -1./3.*sw*( conj(n1prime) - sw*conj(n2prime)/cw ); // bracketr = -1./3.*sw*n1prime - n2prime*(0.5 -1./3.*sqr(sw))/cw; // for(unsigned int k=0;k<2;++k) { // cL[k] =-yb*conj((*neut)(0,2))*(*sbot)(k,0) + sqrt(2.)*(*sbot)(k,1)*bracketl; // cR[k] =-yb* (*neut)(0,2) *(*sbot)(k,1) - sqrt(2.)*(*sbot)(k,0)*bracketr; // d[k] = (*stop)(0,0)*(*sbot)(k,0); // bL[k] = mb*conj((*umix)(k,1))/sqrt(2.)/mw/cb*(*stop)(0,0); // bR[k] = -(*vmix)(k,0)*(*stop)(0,0)+mt*(*vmix)(k,1)/sqrt(2.)/mw/sb*(*stop)(0,1); // kR[k] = - (*neut)(0,3)*conj((*vmix)(k,1))/sqrt(2.) // + (*neut)(0,1) *conj((*vmix)(k,0)); // kL[k] = conj((*neut)(0,2))* (*umix)(k,1) /sqrt(2.) // +conj((*neut)(0,1))* (*umix)(k,0) ; // } // fL.resize(2); fR.resize(2); // double qf = ferm->charge()/eplus; // Energy mf = (abs(ferm->id())<5||(abs(ferm->id())>=11&&abs(ferm->id())<=14)) ? ZERO : mass(scale, ferm); // Energy ma = (abs(anti->id())<5||(abs(anti->id())>=11&&abs(anti->id())<=14)) ? ZERO : mass(scale, anti); // fL[0] = 0.; // fR[0] = - sqrt(2.)*(qf*sw*n1prime - n2prime*(-0.5 + qf*sqr(sw))/cw); // fL[1] = + sqrt(2.)*qf*sw*( conj(n1prime) - sw*conj(n2prime)/cw ); // fR[1] = 0.; // eL.resize(2,vector(2,0.)); // eR.resize(2,vector(2,0.)); // for(unsigned int i=0;i<2;++i) { // eR[i][0] = ma*conj((*umix)(i,1))/sqrt(2.)/mw/cb; // eL[i][0] = -(*vmix)(i,0); // eL[i][1] = 0.; // eR[i][1] = 0.; // } // hL.resize(2); hR.resize(2); // double ya = double(ma/mw)/cb/sqrt(2.); // qf =-anti->charge()/eplus; // bracketl = qf*sw*( conj(n1prime) - sw*conj(n2prime)/cw ); // bracketr = qf*sw*n1prime - n2prime*(0.5 +qf*sqr(sw))/cw; // if(abs(anti->id())==ParticleID::tauminus) { // for(unsigned int k=0;k<2;++k) { // hR[k] =-ya*conj((*neut)(0,2))*(*stau)(k,0) + sqrt(2.)*(*stau)(k,1)*bracketl; // hL[k] =-ya* (*neut)(0,2) *(*stau)(k,1) - sqrt(2.)*(*stau)(k,0)*bracketr; // } // } // else { // hR[0] = 0.; // hL[0] = - sqrt(2.)*bracketr; // hR[1] = + sqrt(2.)*bracketl; // hL[1] = 0.; // } // gL.resize(2,vector(2,0.)); // gR.resize(2,vector(2,0.)); // double y = ma/mw/sqrt(2.)/cb; // ytau = ma/mw*tb; // for(unsigned int i=0;i<2;++i) { // if(abs(anti->id())==ParticleID::tauminus) { // for(unsigned int j=0;j<2;++j) { // gL[i][j] = 0.; // gR[i][j] = -(*umix)(i,0)*(*stau)(j,0) + ya*(*stau)(j,1)*(*umix)(i,1); // } // } // else { // gL[i][0] = 0.; // gR[i][0] = -(*umix)(i,0); // gL[i][1] = 0.; // gR[i][1] = 0.; // } // } // double tw = sw/cw; // lL.resize(2); // lR.resize(2); // for(unsigned int j = 0; j < 2; ++j) { // lL[j] = -(conj((*neut)(0, 3)*(*vmix)(j,0) + ((*neut)(0,1) + (*neut)(0,0)*tw)*(*vmix)(j,1)/sqrt(2)))*cb; // lR[j] = -( (*neut)(0, 2)*(*umix)(j,0) - ((*neut)(0,1) + (*neut)(0,0)*tw)*(*umix)(j,1)/sqrt(2) )*sb; // } // } // extracted from SSFFHVertex.cc // if(particle1->id()!=ParticleID::b) theMassLast.first = theMSSM->mass(q2,particle1); // if(particle2->id()!=ParticleID::b) theMassLast.second = theMSSM->mass(q2,particle2); // extracted from FourBodyDecayConstructor.cc // from createDecayMode // unsigned int nferm=0; // tcPDPtr bottom,ferm,anti,chi; // for(OrderedParticles::const_iterator it=diagrams[0].outgoing.begin(); // it!=diagrams[0].outgoing.end();++it) { // if((**it).iSpin()==PDT::Spin1Half) ++nferm; // if(abs((**it).id())==ParticleID::b) // bottom = *it; // else if(abs((**it).id())>1000000) // chi = *it; // else if((**it).id()<0) // anti = *it; // else // ferm = *it; // } // if(!bottom||!chi||!ferm||!anti) return; // if(ferm->id()-abs(anti->id())!=1) return; //if(anti->id()!=ParticleID::tauplus) return; // from decayList // set new_particles; // for(set::iterator it=particles.begin();it!=particles.end();++it) { // if((**it).id()==ParticleID::SUSY_t_1) new_particles.insert(*it); // } // NBodyDecayConstructorBase::DecayList(new_particles); // extracted from StoFFFFDecayer.h // private : // InvEnergy2 stopMatrixElement(const Particle & inpart, // const ParticleVector & decay, // InvEnergy2 me2) const; // #include "Herwig/Models/StandardModel/StandardModel.h" // InvEnergy2 StoFFFFDecayer::stopMatrixElement(const Particle & inpart, // const ParticleVector & decay, // InvEnergy2 me2) const { // // extract the momenta and check the process // bool found[4]={false,false,false,false}; // Lorentz5Momentum pb,pf,pfp,pChi; // double col = 1.; // tcPDPtr ferm,anti; // for(unsigned int ix=0;ixid(); // if(id==ParticleID::b) { // found[0] = true; // pb = decay[ix]->momentum(); // } // else if(id==ParticleID::SUSY_chi_10) { // found[1] = true; // pChi = decay[ix]->momentum(); // } // else if(abs(id)%2==0) { // if(decay[ix]->dataPtr()->coloured()) col = 3.; // found[2] = true; // pf = decay[ix]->momentum(); // ferm = decay[ix]->dataPtr(); // } // else { // found[3] = true; // pfp = decay[ix]->momentum(); // anti = decay[ix]->dataPtr(); // } // } // // check the process // if(!found[0]||!found[1]||!found[2]||!found[3]) return ZERO; // // extract the couplings we need // HwSMPtr model = dynamic_ptr_cast(generator()->standardModel()); // double sw(0.),cw(0.),g(0.); // Energy mb = getParticleData(ParticleID::b)->mass(); // Energy mt = getParticleData(ParticleID::t)->mass(); // Energy mChi = getParticleData(ParticleID::SUSY_chi_10)->mass(); // Energy mw = getParticleData(ParticleID::Wplus)->mass(); // Energy mbt[2] = {getParticleData(ParticleID::SUSY_b_1)->mass(), // getParticleData(ParticleID::SUSY_b_2)->mass()}; // Energy mP[2] = {getParticleData(ParticleID::SUSY_chi_1plus)->mass(), // getParticleData(ParticleID::SUSY_chi_2plus)->mass()}; // Energy msf[2]={ZERO,ZERO}; // tcPDPtr sf = getParticleData(1000000+abs(ferm->id())); // msf[0] = sf->mass(); // sf = getParticleData(2000000+abs(ferm->id())); // msf[1] = sf ? sf->mass() : 1e30*GeV; // Energy msfp[2]={getParticleData(1000000+abs(anti->id()))->mass(), // getParticleData(2000000+abs(anti->id()))->mass()}; // Complex aL(0.),aR(0.); // vector cL,cR,d,bL,bR,kL,kR,fL,fR,hL,hR,lL,lR; // vector > eL,eR,gL,gR; // double ytop,ytau; // Energy2 scale = sqr(inpart.mass()); // model->StopCouplings(scale,ferm,anti,g,sw,cw,aL,aR,cL,cR,d,bL,bR,kL,kR,fL,fR,eL,eR,gL,gR,hL,hR, // lL,lR,ytop,ytau); // // compute the matrix element // Lorentz5Momentum pw = pf+pfp; pw.rescaleMass(); // Lorentz5Momentum ptop = pw+pb; ptop.rescaleMass(); // Lorentz5Momentum ptt = inpart.momentum(); // Lorentz5Momentum pbt = inpart.momentum()-pw; pbt.rescaleMass(); // Lorentz5Momentum pChiP= inpart.momentum()-pb; pb.rescaleMass(); // Lorentz5Momentum psf = pChi+pf;psf.rescaleMass(); // Lorentz5Momentum psfp = pChi+pfp;psfp.rescaleMass(); // Energy2 ptpt = ptop*ptop; // Energy2 pChipfp = pChi*pfp; // Energy2 ptopptop = ptop.m2(); // Energy2 pbpf = pb*pf; // Energy2 pbpfp = pb*pfp; // Energy2 ptoppfp = ptop*pfp; // Energy2 pChipt = pChi*ptop; // Energy2 pChiptt = pChi*ptt; // Energy2 pfpfp = pf*pfp; // Energy2 pChipb = pChi*pb; // Energy2 pChipf = pChi*pf; // Energy2 pttptt = ptt.m2(); // Energy2 pbptt = pb*ptt; // Energy2 pfpptt = pfp*ptt; // Energy2 pfppt = pfp*ptop; // Energy2 pfptt = pf*ptt; // Energy2 ptptt = ptop*ptt; // Energy2 pfpt = pf*ptop; // Energy2 pbpt = pb*ptop; // Energy2 pChiPpChiP=pChiP*pChiP; // Energy2 pChipChiP=pChi*pChiP; // Energy2 pbpChiP = pb*pChiP; // Energy2 pfppChiP = pfp*pChiP; // Energy2 ptpChiP = ptop*pChiP; // Energy2 pttpChiP = ptt*pChiP; // Energy2 pfpChiP = pf*pChiP; // Energy mf = pf.mass(); // Energy mfp = pfp.mass(); // assert(model); // InvEnergy2 pTop = 1./(ptop.m2()-sqr(mt)); // InvEnergy2 pW = 1./(pw .m2()-sqr(mw)); // InvEnergy2 pBT[2] = {1./(pbt.m2()-sqr(mbt[0])),1./(pbt.m2()-sqr(mbt[1]))}; // InvEnergy2 pP[2] = {1./(pChiP.m2()-sqr(mP[0])),1./(pChiP.m2()-sqr(mP[1]))}; // InvEnergy2 pSF [2] = {1./(psf .m2()-sqr(msf [0])),1./(psf .m2()-sqr(msf [1]))}; // if(abs(ferm->id())==ParticleID::nu_e||abs(ferm->id())==ParticleID::nu_mu||abs(ferm->id())==ParticleID::nu_tau) // pSF[1] = ZERO; // InvEnergy2 pSFP[2] = {1./(psfp.m2()-sqr(msfp[0])),1./(psfp.m2()-sqr(msfp[1]))}; // // top squared // InvEnergy2 mett = pow(g,6)*sqr(pTop*pW)* // ( norm(aR) * ( -4.*pChipfp*pbpf*ptopptop + 8.*pChipt*pbpf*ptoppfp ) + // norm(aL) * ( 4.*pChipfp*pbpf*sqr(mt)) // + real(aL*conj(aR)) * ( - 8*pbpf*ptoppfp*mChi*mt ) // ); // // colour factors // mett *=col; // // sbottom squared // complex mebb(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // mebb += pow(g,6)*d[i]*d[j]*pBT[i]*pBT[j]*sqr(pW)* // (pChipb*(cR[i]*cR[j]+cL[i]*cL[j])- mChi*mb*(cL[j]*cR[i]+cL[i]*cR[j]))* // ( - 4*pfpfp*pttptt + 8*pfptt*pfpptt + pfpfp*sqr(mfp) + pfpfp*sqr(mf) // - 4*pfptt*sqr(mfp) - 4*pfpptt*sqr(mf) + 2*sqr(mf)*sqr(mfp) ); // } // } // // colour factors // mebb *=col; // // stop sbottom // complex metb(ZERO); // for(unsigned int i=0;i<2;++i) { // metb += pow(g,6)*d[i]*pTop*pBT[i]*sqr(pW)*cR[i]* // ( // + aR*( - 2*pChipb*pfpfp*ptptt + 2*pChipb*pfpt* // pfpptt + 2*pChipb*pfptt*pfppt + 2*pChipf*pbpfp*ptptt - // 2*pChipf*pbpt*pfpptt - 2*pChipf*pbptt*pfppt - 2*pChipfp // *pbpf*ptptt - 2*pChipfp*pbpt*pfptt + 2*pChipfp*pbptt* // pfpt + 2*pChipt*pbpf*pfpptt + 2*pChipt*pbpfp*pfptt - 2* // pChipt*pbptt*pfpfp + 2*pChiptt*pbpf*pfppt - 2*pChiptt* // pbpfp*pfpt + 2*pChiptt*pbpt*pfpfp) // + aL*mChi*mt*( - 2*pbpf*pfpptt - 2*pbpfp*pfptt + 2*pbptt*pfpfp )); // } // // colour factors // metb *=col; // complex mecc(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // mecc += pow(g,6)*pP[i]*pP[j]*sqr(pW)* // (+ bR[i]*bR[j]*kR[i]*kR[j] * ( 16*pChipb*pChipf*pChipfp + 16*pChipb*pChipf*pfpfp + 16*pChipb*pChipf*sqr(mfp) + 16*pChipf* // pChipfp*pbpf + 16*pChipf*pbpf*pfpfp + 16*pChipf*pbpf*sqr(mfp) + 8*pChipf*pbpfp*sqr(mfp) - 8*pChipf*pbpfp*sqr(mf) - 16*sqr(pChipf)*pbpfp ) // + bR[i]*bR[j]*kL[i]*kL[j] * ( 8*pChipfp*pbpf*mP[i]*mP[j] ) // + bL[i]*bL[j]*kR[i]*kR[j] * ( 8*pChipf*pbpfp*mP[i]*mP[j] ) // + bL[i]*bL[j]*kL[i]*kL[j] * ( 16*pChipb*pChipf*pChipfp + 16*pChipb* // pChipfp*pfpfp + 16*pChipb*pChipfp*sqr(mf) + 16*pChipf* // pChipfp*pbpfp - 8*pChipfp*pbpf*sqr(mfp) + 8*pChipfp*pbpf* // sqr(mf) + 16*pChipfp*pbpfp*pfpfp + 16*pChipfp*pbpfp*sqr(mf) - // 16*sqr(pChipfp)*pbpf ) // + mb*bL[j]*bR[i]*kR[i]*kR[j] * ( - 8*pChipf*pChipfp*mP[j] - 8*pChipf*pfpfp*mP[j] - 8*pChipf*sqr(mfp)*mP[j] ) // + mb*bL[j]*bR[i]*kL[i]*kL[j] * ( - 8*pChipf*pChipfp*mP[i] - 8*pChipfp*pfpfp*mP[i] - 8*pChipfp*sqr(mf)*mP[i] ) // + mb*bL[i]*bR[j]*kR[i]*kR[j] * ( - 8*pChipf*pChipfp*mP[i] - 8*pChipf*pfpfp*mP[i] - 8*pChipf*sqr(mfp)*mP[i] ) // + mb*bL[i]*bR[j]*kL[i]*kL[j] * ( - 8*pChipf*pChipfp*mP[j] - 8*pChipfp*pfpfp*mP[j] - 8*pChipfp*sqr(mf)*mP[j] ) // + mChi*bR[i]*bR[j]*kR[i]*kL[j] * ( - 4*pChipb*pfpfp*mP[j] + 4*pChipf*pbpfp*mP[j] - 4*pChipfp*pbpf*mP[j] - 8*pbpf*pfpfp*mP[j] - 4*pbpf*sqr(mfp)*mP[j] + 4*pbpfp*sqr(mf)*mP[j] ) // + mChi*bR[i]*bR[j]*kL[i]*kR[j] * ( - 4*pChipb*pfpfp*mP[i] + 4*pChipf*pbpfp*mP[i] - 4*pChipfp*pbpf*mP[i] - 8*pbpf*pfpfp*mP[i] - 4* // pbpf*sqr(mfp)*mP[i] + 4*pbpfp*sqr(mf)*mP[i] ) // + mChi*bL[i]*bL[j]*kR[i]*kL[j] * ( - 4*pChipb*pfpfp*mP[i] - 4*pChipf*pbpfp*mP[i] + 4*pChipfp*pbpf*mP[i] + 4*pbpf*sqr(mfp)*mP[i] - 8*pbpfp*pfpfp*mP[i] - 4*pbpfp*sqr(mf)*mP[i] ) // + mChi*bL[i]*bL[j]*kL[i]*kR[j] * ( - 4*pChipb*pfpfp*mP[j] - 4*pChipf*pbpfp*mP[j] + 4*pChipfp*pbpf*mP[j] + 4*pbpf*sqr(mfp)*mP[j] - 8* // pbpfp*pfpfp*mP[j] - 4*pbpfp*sqr(mf)*mP[j] ) // + mChi*mb*bL[j]*bR[i]*kR[i]*kL[j] * ( 8*pChipf*pfpfp + 8*pChipfp* // pfpfp + 4*pfpfp*sqr(mfp) + 4*pfpfp*sqr(mf) + 8*sqr(pfpfp) ) // + mChi*mb*bL[j]*bR[i]*kL[i]*kR[j] * ( 4*pfpfp*mP[i]*mP[j] ) // + mChi*mb*bL[i]*bR[j]*kR[i]*kL[j] * ( 4*pfpfp*mP[i]*mP[j] ) // + mChi*mb*bL[i]*bR[j]*kL[i]*kR[j] * ( 8*pChipf*pfpfp + 8*pChipfp* // pfpfp + 4*pfpfp*sqr(mfp) + 4*pfpfp*sqr(mf) + 8*sqr(pfpfp) ) // + sqr(mChi)*bR[i]*bR[j]*kR[i]*kR[j] * ( - 8*pChipf*pbpfp ) // + sqr(mChi)*bL[i]*bL[j]*kL[i]*kL[j] * ( - 8*pChipfp*pbpf ) // + mChi*sqr(mChi)*mb*bL[j]*bR[i]*kR[i]*kL[j] * ( 4*pfpfp ) // + mChi*sqr(mChi)*mb*bL[i]*bR[j]*kL[i]*kR[j] * ( 4*pfpfp )); // } // } // mecc *=col; // complex metc(ZERO); // for(unsigned int j=0;j<2;++j) { // metc += pow(g,6)*pP[j]*pTop*sqr(pW)/sqrt(2.)*( // + aR*bR[j]*kR[j] * ( - 8*pChipb*pChipf*pbpfp + 8*pChipb*pChipf*pfpfp - 8*pChipb* // pChipfp*pbpf - 8*pChipb*pChipfp*sqr(mf) + 8*pChipb*pbpf*pfpfp - 8*pChipb*pbpfp* // sqr(mf) - 4*pChipb*pfpfp*sqr(mfp) - 4* // pChipb*pfpfp*sqr(mf) - 8*pChipb*sqr(mf)*sqr(mfp) + 8*sqr(pChipb)*pfpfp + 8*pChipf*pChipfp* // pbpf + 8*pChipf*pbpf*pbpfp + 16* // pChipf*pbpf*pfpfp + 16*pChipf*pbpf*sqr(mfp) + 4*pChipf*pbpfp*sqr(mfp) - 4*pChipf*pbpfp* // sqr(mf) - 8*sqr(pChipf)*pbpfp + 4*pChipfp* // pbpf*sqr(mfp) - 4*pChipfp*pbpf*sqr(mf) - 8* // pChipfp*sqr(pbpf) ) // + aR*mb*bL[j]*kR[j] * ( - 4*pChipb*pfpfp*mP[j] - 4*pChipf*pbpfp*mP[j] - 8*pChipf*pfpfp*mP[j] // - 4*pChipf*sqr(mfp)*mP[j] + 4*pChipfp* // pbpf*mP[j] + 4*pChipfp*sqr(mf)*mP[j] ) // + aR*sqr(mb)*bR[j]*kR[j] * ( 8*pChipf*pChipfp + 4*pChipf*sqr(mfp) + 4*pChipfp*sqr(mf) ) // + aR*mChi*bR[j]*kL[j] * ( - 8*pbpf*pbpfp*mP[j] - 8*pbpf*pfpfp*mP[j] - 8*pbpf*sqr(mfp)*mP[j] ) // + aR*mChi*mb*bL[j]*kL[j] * ( 8*sqr(mf)*sqr(mfp) + 8* // pChipf*pbpfp + 8*pChipf*pfpfp + 8* // pChipf*sqr(mfp) + 8*pbpfp*pfpfp + 8* // pbpfp*sqr(mf) + 8*pfpfp*sqr(mfp) + 8*pfpfp* // sqr(mf) + 8*sqr(pfpfp) ) // + aR*sqr(mChi)*bR[j]*kR[j] * ( 8*pbpf*pbpfp + 4 // *pbpf*sqr(mfp) + 4*pbpfp*sqr(mf) ) // + aR*sqr(mChi)*sqr(mb)*bR[j]*kR[j] * ( - 4*pfpfp ) // + aL*mt*bR[j]*kL[j] * ( 8*pChipfp*pbpf*mP[j] ) // + aL*mb*mt*bL[j]*kL[j] * ( - 8*pChipf*pChipfp - 8*pChipfp*pfpfp - 8*pChipfp*sqr(mf) ) // + aL*mChi*mt*bR[j]*kR[j] * ( - 4*pChipb*pfpfp + 4*pChipf*pbpfp - 4*pChipfp*pbpf - 8*pbpf*pfpfp - 4*pbpf*sqr(mfp) + 4*pbpfp*sqr(mf) ) // + aL*mChi*mb*mt*bL[j]*kR[j] * ( 4*pfpfp*mP[j] )); // } // metc *= col; // complex mebc(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // mebc += pow(g,6)*pP[j]*sqr(pW)*d[i]*pBT[i]/sqrt(2.)* // (+ cR[i]*bR[j]*kR[j] * ( - 8*pChipb*pChipf*pfpptt + 4 // *pChipb*pChipf*sqr(mfp) - 8*pChipb* // pChipfp*pfptt + 4*pChipb*pChipfp*sqr(mf) + 8*pChipb*pChiptt*pfpfp + 2*pChipb* // pfpfp*sqr(mfp) + 2*pChipb*pfpfp*sqr(mf) - 4 // *pChipb*pfptt*sqr(mfp) - 4*pChipb*pfpptt*sqr(mf) + 4 // *pChipb*sqr(mf)*sqr(mfp) + 8*pChipf*pbpfp* // pfptt + 2*pChipf*pbpfp*sqr(mfp) - 2* // pChipf*pbpfp*sqr(mf) - 8*pChipf*pbptt*pfpfp - 4*pChipf*pbptt*sqr(mfp) - 8*pChipfp*pbpf* // pfptt - 2*pChipfp*pbpf*sqr(mfp) + 2* // pChipfp*pbpf*sqr(mf) + 4*pChipfp*pbptt*sqr(mf) + 8*pChiptt*pbpf*pfpfp + 4*pChiptt*pbpf* // sqr(mfp) - 4*pChiptt*pbpfp*sqr(mf)) // + cL[i]*bL[j]*kL[j] * ( - 8*pChipb*pChipf*pfpptt + 4 // *pChipb*pChipf*sqr(mfp) - 8*pChipb* // pChipfp*pfptt + 4*pChipb*pChipfp*sqr(mf) + 8*pChipb*pChiptt*pfpfp + 2*pChipb* // pfpfp*sqr(mfp) + 2*pChipb*pfpfp*sqr(mf) - 4 // *pChipb*pfptt*sqr(mfp) - 4*pChipb*pfpptt*sqr(mf) + 4 // *pChipb*sqr(mf)*sqr(mfp) - 8*pChipf*pbpfp* // pfpptt + 2*pChipf*pbpfp*sqr(mfp) - 2* // pChipf*pbpfp*sqr(mf) + 4*pChipf*pbptt*sqr(mfp) + 8*pChipfp*pbpf*pfpptt - 2*pChipfp*pbpf // *sqr(mfp) + 2*pChipfp*pbpf*sqr(mf) - 8* // pChipfp*pbptt*pfpfp - 4*pChipfp*pbptt*sqr(mf) - 4*pChiptt*pbpf*sqr(mfp) + 8*pChiptt* // pbpfp*pfpfp + 4*pChiptt*pbpfp*sqr(mf)) // + mb*cR[i]*bL[j]*kR[j] * ( 4*pChipf*pfpptt*mP[j] - 2*pChipf*sqr(mfp)*mP[j] + 4*pChipfp*pfptt*mP[j] // - 2*pChipfp*sqr(mf)*mP[j] - 4*pChiptt*pfpfp*mP[j] ) // + mb*cL[i]*bR[j]*kL[j] * ( 4*pChipf*pfpptt*mP[j] - 2*pChipf*sqr(mfp)*mP[j] + 4*pChipfp*pfptt*mP[j] // - 2*pChipfp*sqr(mf)*mP[j] - 4*pChiptt*pfpfp*mP[j] ) // + mChi*cR[i]*bR[j]*kL[j] * ( - 4*pbpf*pfpptt*mP[j] + 2*pbpf*sqr(mfp)*mP[j] - 4*pbpfp*pfptt*mP[j] // + 2*pbpfp*sqr(mf)*mP[j] + 4*pbptt*pfpfp*mP[j] ) // + mChi*cL[i]*bL[j]*kR[j] * ( - 4*pbpf*pfpptt*mP[j] + 2*pbpf*sqr(mfp)*mP[j] - 4*pbpfp*pfptt*mP[j] + 2*pbpfp*sqr(mf)*mP[j] + 4*pbptt*pfpfp*mP[j] ) // + mChi*mb*cR[i]*bL[j]*kL[j] * ( - 4*sqr(mf)*sqr(mfp) + 4*pChipf*pfpptt - 2*pChipf*sqr(mfp) + 4*pChipfp*pfptt - 2*pChipfp*sqr(mf) - 4*pChiptt*pfpfp - 2*pfpfp*sqr(mfp) - 2*pfpfp*sqr(mf) + 4*pfptt*sqr(mfp) + 4*pfpptt*sqr(mf) ) // + mChi*mb*cL[i]*bR[j]*kR[j] * ( - 4*sqr(mf)*sqr(mfp) + 4*pChipf*pfpptt - 2*pChipf*sqr(mfp) + 4*pChipfp*pfptt - 2*pChipfp*sqr(mf) - 4*pChiptt*pfpfp - 2*pfpfp*sqr(mfp) - 2*pfpfp*sqr(mf) + 4*pfptt*sqr(mfp) + 4*pfpptt*sqr(mf) ) // + sqr(mChi)*cR[i]*bR[j]*kR[j] * ( 4*pbpf*pfpptt - 2*pbpf*sqr(mfp) + 4*pbpfp*pfptt - 2*pbpfp*sqr(mf) - 4*pbptt*pfpfp ) // + sqr(mChi)*cL[i]*bL[j]*kL[j] * ( 4*pbpf*pfpptt - 2*pbpf*sqr(mfp) + 4*pbpfp*pfptt - 2*pbpfp*sqr(mf) - 4*pbptt*pfpfp )); // } // } // mebc *= col; // complex meff(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int k=0;k<2;++k) { // for(unsigned int l=0;l<2;++l) { // meff += pow(g,6)*pP[i]*pP[j]*pSF[k]*pSF[l]*pChipf*(fR[k]*fR[l]+fL[k]*fL[l])* // ( // + ( eR[i][k]*eR[j][l]*bR[i]*bR[j] + eL[i][k]*eL[j][l]*bL[i]*bL[j] )* ( 4.*pbpfp*mP[i]*mP[j] ) // + ( eR[i][k]*eR[j][l]*bL[i]*bL[j] + eL[i][k]*eL[j][l]*bR[i]*bR[j] )* ( - 4*pbpfp*pChiPpChiP + // 8*pbpChiP*pfppChiP ) // +mb*mP[i]*( eR[i][k]*eR[j][l]*bL[j]*bR[i] + eL[i][k]*eL[j][l]*bL[i]*bR[j] ) * ( - 4*pfppChiP ) // +mb*mP[j]*( eR[i][k]*eR[j][l]*bL[i]*bR[j] + eL[i][k]*eL[j][l]*bL[j]*bR[i] ) * ( - 4*pfppChiP )); // } // } // } // } // meff *= col; // complex mepp(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int k=0;k<2;++k) { // for(unsigned int l=0;l<2;++l) { // mepp += pow(g,6)*pP[i]*pP[j]*pSFP[k]*pSFP[l]*pChipfp*(hR[k]*hR[l]+hL[k]*hL[l])* // ((gR[i][k]*gR[j][l]*bR[i]*bR[j] + gL[i][k]*gL[j][l]*bL[i]*bL[j]) * ( 4*pbpf*mP[i]*mP[j] ) + // (gR[i][k]*gR[j][l]*bL[i]*bL[j] + gL[i][k]*gL[j][l]*bR[i]*bR[j]) * // ( - 4*pbpf*pChiPpChiP + 8*pbpChiP*pfpChiP )); // } // } // } // } // mepp *= col; // complex metf(ZERO); // for(unsigned int j=0;j<2;++j) { // for(unsigned int l=0;l<2;++l) { // metf += pow(g,6)*pTop*pW*pP[j]*pSF[l]* // (+ aR*eL[j][l]*fR[l]*bR[j] * ( 2*pChipb*pfpfp*ptpChiP - 2*pChipb*pfpt*pfppChiP // - 2*pChipb*pfpChiP*pfppt - 2*pChipf*pbpfp*ptpChiP // + 2*pChipf*pbpt*pfppChiP + 2*pChipf*pbpChiP*pfppt // - 2*pChipfp*pbpf*ptpChiP + 2*pChipfp*pbpt*pfpChiP // - 2*pChipfp*pbpChiP*pfpt + 2*pChipt*pbpf*pfppChiP // - 2*pChipt*pbpfp*pfpChiP + 2*pChipt*pbpChiP*pfpfp // + 2*pChipChiP*pbpf*pfppt + 2*pChipChiP*pbpfp*pfpt // - 2*pChipChiP*pbpt*pfpfp ) // + aL*mChi*mt*eL[j][l]*fR[l]*bR[j] * ( - 2*pbpf*pfppChiP + 2*pbpfp*pfpChiP - 2*pbpChiP*pfpfp ) // ); // } // } // metf *= col; // // sbottom sfermion interference // complex mebf(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int l=0;l<2;++l) { // mebf += 2.*pow(g,6)*d[i]*pBT[i]*pW*pP[j]*pSF[l]* // (cR[i]*eL[j][l]*fR[l]*bR[j] * ( pChipb*pfpfp*pttpChiP - pChipb*pfptt*pfppChiP - pChipb*pfpChiP*pfpptt + // pChipf*pbpfp*pttpChiP - pChipf*pbptt*pfppChiP - pChipf*pbpChiP*pfpptt - // pChipfp*pbpf*pttpChiP + pChipfp*pbptt*pfpChiP - pChipfp*pbpChiP*pfptt + // pChiptt*pbpf*pfppChiP - pChiptt*pbpfp*pfpChiP + pChiptt*pbpChiP*pfpfp + // pChipChiP*pbpf*pfpptt + pChipChiP*pbpfp*pfptt - pChipChiP*pbptt*pfpfp) // + mChi*mP[j]*cL[i]*eL[j][l]*fR[l]*bL[j] * ( - pbpf*pfpptt - pbpfp*pfptt + pbptt*pfpfp )); // } // } // } // mebf *= col; // // chi W sfermion interference // complex mecf(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int l=0;l<2;++l) { // mecf -= pow(g,6)*pP[i]*pW*pP[j]*pSF[l]*eL[j][l]*fR[l]/sqrt(2.)* // (+ bR[i]*bR[j]*kR[i] * ( 8*pChipf*pbpfp*pChiPpChiP - 16*pChipf*pbpChiP*pfppChiP ) // + bR[i]*bR[j]*kL[i]*mChi*mP[i] * ( 4*pbpf*pfppChiP - 4*pbpfp*pfpChiP + 4*pbpChiP*pfpfp) // + bL[i]*bL[j]*kR[i]*mP[i]*mP[j] * ( - 8*pChipf*pbpfp ) // + bL[i]*bL[j]*kL[i]*mChi*mP[j] * (-4*pbpf*pfppChiP + 4*pbpfp*pfpChiP + 4*pbpChiP*pfpfp) // ); // } // } // } // mecf *= col; // complex mebp(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int l=0;l<2;++l) { // mebp += pow(g,6)*d[i]*pBT[i]*pW*pP[j]*pSFP[l]* // ( // + cL[i]*gR[j][l]*hL[l]*bL[j] * // ( - 2*pChipb*pfpfp*pttpChiP + 2*pChipb*pfptt*pfppChiP // + 2*pChipb*pfpChiP*pfpptt + 2*pChipf*pbpfp*pttpChiP // - 2*pChipf*pbptt*pfppChiP + 2*pChipf*pbpChiP*pfpptt // - 2*pChipfp*pbpf*pttpChiP + 2*pChipfp*pbptt*pfpChiP // + 2*pChipfp*pbpChiP*pfptt + 2*pChiptt*pbpf*pfppChiP // - 2*pChiptt*pbpfp*pfpChiP - 2*pChiptt*pbpChiP*pfpfp // - 2*pChipChiP*pbpf*pfpptt - 2*pChipChiP*pbpfp*pfptt // + 2*pChipChiP*pbptt*pfpfp) // + mChi*cR[i]*gR[j][l]*hL[l]*bR[j]*mP[j] * // ( 2*pbpf*pfpptt + 2*pbpfp*pfptt - 2*pbptt*pfpfp )); // } // } // } // mebp *= col; // // chi W anti sfermion interference // complex mecp(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int l=0;l<1;++l) { // mecp +=pow(g,6)*pP[i]*pW*pP[j]*pSFP[l]/sqrt(2.)*gR[j][l]*hL[l]* // ( // + bR[i]*bR[j]*kL[i] * ( - 8*pChipfp*pbpf*mP[i]*mP[j] ) // + bL[i]*bL[j]*kL[i] * ( 8*pChipfp*pbpf*pfppChiP + 8*pChipfp*pbpf*pChiPpChiP - 8*pChipfp*pbpfp*pfpChiP - 8*pChipfp*pbpChiP*pfpfp - 16*pChipfp*pbpChiP*pfpChiP) // + mChi*bR[i]*bR[j]*kR[i]*mP[j]*( 4*pbpf*pfppChiP - 4*pbpfp*pfpChiP + 4*pbpChiP*pfpfp) // + mChi*bL[i]*bL[j]*kR[i]*mP[i]*( - 4*pbpf*pfppChiP + 8*pbpfp*pfpfp + 4*pbpfp*pfpChiP + 4*pbpChiP*pfpfp)); // } // } // } // mecp *= col; // // sfermion antisfermion interferences // complex mefp(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // for(unsigned int k=0;k<1;++k) { // for(unsigned int l=0;l<2;++l) { // mefp +=pow(g,6)*pP[i]*pP[j]*pSF[k]*pSFP[l]*fR[k]*gR[j][l]* // ( // + eR[i][k]*hR[l]*bR[i]*bR[j]*mP[i]*mP[j] * // ( 2*pChipb*pfpfp - 2*pChipf*pbpfp - 2*pChipfp*pbpf ) // + eR[i][k]*hR[l]*bL[i]*bL[j]* // ( - 2*pChipb*pfpfp*pChiPpChiP + 2*pChipf*pbpfp*pChiPpChiP // - 4*pChipf*pbpChiP*pfppChiP + 2*pChipfp*pbpf*pChiPpChiP // - 4*pChipfp*pbpChiP*pfpChiP + 4*pChipChiP*pbpChiP*pfpfp) // + eL[i][k]*hL[l]*bL[i]*bL[j]*mChi*mP[i] * // (-2*pbpf*pfppChiP + 2*pbpfp*pfpChiP + 2*pbpChiP*pfpfp ) // + eL[i][k]*hL[l]*bR[i]*bR[j]*mChi*mP[j] * // ( 2*pbpf*pfppChiP - 2*pbpfp*pfpChiP + 2*pbpChiP*pfpfp )); // } // } // } // } // mefp *= col; // // top higgs // Energy mHiggs = getParticleData(ParticleID::Hplus)->mass(); // InvEnergy2 pH = 1./(pw.m2()-sqr(mHiggs)); // InvEnergy2 meht = 0.25*sqr(ytop*ytau)*pow(g,6)*sqr(pTop*pH)*pfpfp* // ( norm(aR) *sqr(mt)*4*pChipb + // norm(aL) * ( - 4*pChipb*ptpt + 8*pChipt*pbpt ) // + real(aL*conj(aR)) * mChi*mt * ( - 8*pbpt )); // // colour factors // meht *=col; // // chargino higgs // complex mehc(ZERO); // for(unsigned int i=0;i<2;++i) { // for(unsigned int j=0;j<2;++j) { // mehc += pow(g,6)*pP[i]*pP[j]*sqr(pH)*sqr(ytau)*pfpfp* // ( + (bR[i]*bR[j]*lR[i]*lR[j]+bL[i]*bL[j]*lL[i]*lL[j])*mP[i]*mP[j]*2*pChipb // + (bR[i]*bR[j]*lL[i]*lL[j]+bL[i]*bL[j]*lR[i]*lR[j])*(-2*pChipb*pChiPpChiP+4*pChipChiP*pbpChiP) // + (bR[i]*bR[j]*lR[i]*lL[j]+bL[i]*bL[j]*lL[i]*lR[j])*mChi*mP[i]*2*pbpChiP // + (bR[i]*bR[j]*lL[i]*lR[j]+bL[i]*bL[j]*lR[i]*lL[j])*mChi*mP[j]*2*pbpChiP); // } // } // // hehbc = // // + cR1*d1*bR2*kR2 * ( 2*pChi.pb*pf.pfp*mP2 ) // // + cL1*d1*bL2*kL2 * ( 2*pChi.pb*pf.pfp*mP2 ) // // + mChi*cR1*d1*bR2*kL2 * ( 2*pb.pChiP*pf.pfp ) // // + mChi*cL1*d1*bL2*kR2 * ( 2*pb.pChiP*pf.pfp ); // // InvEnergy2 meTotal = meff.real()+mecc.real()+2.*mecf.real(); // InvEnergy2 meTotal = abs(mehc.real()); // // if(abs(anti->id())==ParticleID::tauminus) { // // cerr << "testing inter " << (me2-mepp.real()-meff.real())*GeV2 << " " << 2.*mefp.real()*GeV2 // // << " " << 0.5*(me2-mepp.real()-meff.real())/mefp.real() << "\n"; // // cerr << "testing the matrix element " << meTotal*GeV2 << " " // // << me2*GeV2 << " " << meTotal/me2 << "\n"; // // } // return meTotal; // } // extracted from main diagram loop // //\todo remove testing // top // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // sbottom // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // chargino W // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // sneutrino // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()<0)) { // ++idiag; // continue; // } // sneutrino // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()<0)) { // ++idiag; // continue; // } // charged slepton // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()>0)) { // ++idiag; // continue; // } // slepton sneutrino // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // abs(inter.second->id())!=ParticleID::Hplus&& // inter.second->id()>0) && // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // abs(inter.second->id())!=ParticleID::Hplus&& // inter.second->id()<0)) { // ++idiag; // continue; // } // chi W and charged slepton // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Wplus) && // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()>0) ) { // ++idiag; // continue; // } // chi W and sneutrino // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Wplus) && // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()<0) ) { // ++idiag; // continue; // } // top/sbottom interference // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Wplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // top chiW interference // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Wplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // bottom chiW interference // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Wplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Wplus)) { // ++idiag; // continue; // } // top charged slepton // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Wplus) && // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()>0)) { // ++idiag; // continue; // } // top sneutrino // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Wplus) && // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()<0)) { // ++idiag; // continue; // } // ~b sneutrino // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Wplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()<0)) { // ++idiag; // continue; // } // ~b slepton // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Wplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())!=ParticleID::Wplus&& // inter.second->id()>0)) { // ++idiag; // continue; // } // top H // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // sbottom H // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // chargino H // if(!((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // top/sbottom interference // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Hplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // top chiH interference // if(!(abs(inter.first ->id())==ParticleID::t&& // abs(inter.second->id())==ParticleID::Hplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // bottom chiH interference // if(!((abs(inter.first ->id())==ParticleID::SUSY_b_1|| // abs(inter.first ->id())==ParticleID::SUSY_b_2)&& // abs(inter.second->id())==ParticleID::Hplus)&& // !((abs(inter.first ->id())==ParticleID::SUSY_chi_1plus|| // abs(inter.first ->id())==ParticleID::SUSY_chi_2plus)&& // abs(inter.second->id())==ParticleID::Hplus)) { // ++idiag; // continue; // } // all Higgs // if(abs(inter.second->id())==ParticleID::Hplus) { // ++idiag; // continue; // } //reomved from end of me2() //InvEnergy2 output = stopMatrixElement(inpart,decay,me2*UnitRemoval::InvE2); // return output*scale; diff --git a/Decay/General/StoFFVDecayer.cc b/Decay/General/StoFFVDecayer.cc --- a/Decay/General/StoFFVDecayer.cc +++ b/Decay/General/StoFFVDecayer.cc @@ -1,387 +1,389 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the StoFFVDecayer class. // #include "StoFFVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG; using namespace ThePEG::Helicity; IBPtr StoFFVDecayer::clone() const { return new_ptr(*this); } IBPtr StoFFVDecayer::fullclone() const { return new_ptr(*this); } void StoFFVDecayer::persistentOutput(PersistentOStream & os) const { os << sca_ << fer_ << vec_ << RSfer_ << four_; } void StoFFVDecayer::persistentInput(PersistentIStream & is, int) { is >> sca_ >> fer_ >> vec_ >> RSfer_ >> four_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigStoFFVDecayer("Herwig::StoFFVDecayer", "Herwig.so"); void StoFFVDecayer::Init() { static ClassDocumentation documentation ("The StoFFVDecayer class implements the general decay of a scalar to " "a two fermions and a vector."); } WidthCalculatorBasePtr StoFFVDecayer:: threeBodyMEIntegrator(const DecayMode & ) const { vector intype; vector inmass,inwidth; vector inpow,inweights; constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow,*this,0, outgoing()[0]->mass(),outgoing()[1]->mass(), outgoing()[2]->mass(),relativeError())); } -void StoFFVDecayer::doinit() { - GeneralThreeBodyDecayer::doinit(); +void StoFFVDecayer::setupDiagrams(bool kinCheck) { + GeneralThreeBodyDecayer::setupDiagrams(kinCheck); if(outgoing().empty()) return; unsigned int ndiags = getProcessInfo().size(); sca_.resize(ndiags); fer_.resize(ndiags); RSfer_.resize(ndiags); vec_.resize(ndiags); four_.resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { TBDiagram current = getProcessInfo()[ix]; tcPDPtr offshell = current.intermediate; // four point vertex if(!offshell) { four_[ix] = dynamic_ptr_cast(current.vertices.first); continue; } if( offshell->CC() ) offshell = offshell->CC(); if(offshell->iSpin() == PDT::Spin0) { AbstractVSSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a scalar diagram in StoFFVDecayer::doinit()" + << "Invalid vertices for a scalar diagram in StoFFVDecayer::setupDiagrams()" << Exception::runerror; sca_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1Half) { AbstractFFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a fermion diagram in StoFFVDecayer::doinit()" + << "Invalid vertices for a fermion diagram in StoFFVDecayer::setupDiagrams()" << Exception::runerror; fer_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1) { AbstractVVSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a vector diagram in StoFFVDecayer::doinit()" + << "Invalid vertices for a vector diagram in StoFFVDecayer::setupDiagrams()" << Exception::runerror; vec_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin3Half) { AbstractRFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractRFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a RS fermion diagram in StoFFVDecayer::doinit()" + << "Invalid vertices for a RS fermion diagram in StoFFVDecayer::setupDiagrams()" << Exception::runerror; RSfer_[ix] = make_pair(vert1, vert2); } } } double StoFFVDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming != inpart.id(); // special handling or first/last call if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart), Helicity::incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(), Helicity::incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart), Helicity::incoming,true); for(unsigned int ix=0;ixdataPtr()->iSpin()==PDT::Spin1) { VectorWaveFunction::constructSpinInfo(outVector_,decay[ix], Helicity::outgoing,true,false); } else { SpinorWaveFunction:: constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true); } } } unsigned int ivec(0); bool massless(false); for(unsigned int ix = 0; ix < decay.size();++ix) { if(decay[ix]->dataPtr()->iSpin() == PDT::Spin1) { ivec = ix; massless = decay[ivec]->mass()==ZERO; VectorWaveFunction:: calculateWaveFunctions(outVector_, decay[ix], Helicity::outgoing,massless); } else { SpinorWaveFunction:: calculateWaveFunctions(outspin_[ix].first,decay[ix],Helicity::outgoing); outspin_[ix].second.resize(2); // Need a ubar and a v spinor if(outspin_[ix].first[0].wave().Type() == SpinorType::u) { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].first[iy].conjugate(); } } else { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].second[iy].conjugate(); } } } } const vector > cfactors(getColourFactors()); const vector > nfactors(getLargeNcColourFactors()); Energy2 scale(sqr(inpart.mass())); const size_t ncf(numberOfFlows()); vector flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.)); // setup the DecayMatrixElement vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, ivec == 0 ? PDT::Spin1 : PDT::Spin1Half, ivec == 1 ? PDT::Spin1 : PDT::Spin1Half, ivec == 2 ? PDT::Spin1 : PDT::Spin1Half))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, ivec == 0 ? PDT::Spin1 : PDT::Spin1Half, ivec == 1 ? PDT::Spin1 : PDT::Spin1Half, ivec == 2 ? PDT::Spin1 : PDT::Spin1Half))); //the channel possiblities static const unsigned int out2[3] = {1,0,0}, out3[3] = {2,2,1}; for(unsigned int s1 = 0; s1 < 2; ++s1) { for(unsigned int s2 = 0; s2 < 2; ++s2) { for(unsigned int v1 = 0; v1 < 3; ++v1) { if(massless&&v1==1) ++v1; flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag(0); Complex diag; for(vector::const_iterator dit=getProcessInfo().begin(); dit!=getProcessInfo().end();++dit) { // channels if selecting if( ichan >= 0 && diagramMap()[ichan] != idiag ) { ++idiag; continue; } tcPDPtr offshell = dit->intermediate; if(offshell) { if(cc&&offshell->CC()) offshell=offshell->CC(); unsigned int o2(out2[dit->channelType]), o3(out3[dit->channelType]); double sign = (o3 < o2) ? 1. : -1.; // intermediate scalar if(offshell->iSpin() == PDT::Spin0) { ScalarWaveFunction inters = sca_[idiag].first-> evaluate(scale, widthOption(), offshell, outVector_[v1], swave_); unsigned int h1(s1),h2(s2); if(o2 > o3) swap(h1, h2); if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag = -sign*sca_[idiag].second-> evaluate(scale,outspin_[o2].first[h1], outspin_[o3].second[h2],inters); } else { diag = sign*sca_[idiag].second-> evaluate(scale, outspin_[o3].first [h2], outspin_[o2].second[h1],inters); } } // intermediate fermion else if(offshell->iSpin() == PDT::Spin1Half) { int iferm = (decay[o2]->dataPtr()->iSpin() == PDT::Spin1Half) ? o2 : o3; unsigned int h1(s1),h2(s2); if(dit->channelType > iferm) swap(h1, h2); sign = iferm < dit->channelType ? 1. : -1.; if((decay[dit->channelType]->id() < 0 && decay[iferm]->id() > 0 ) || (decay[dit->channelType]->id()*offshell->id()>0)) { SpinorWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].first[h1], swave_); diag = -sign*fer_[idiag].second-> evaluate(scale,inters,outspin_[iferm].second[h2], outVector_[v1]); } else { SpinorBarWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].second[h1],swave_); diag = sign*fer_[idiag].second-> evaluate(scale,outspin_[iferm].first [h2],inters, outVector_[v1]); } } // intermediate vector else if(offshell->iSpin() == PDT::Spin1) { VectorWaveFunction interv = vec_[idiag].first-> evaluate(scale, widthOption(), offshell, outVector_[v1], swave_); unsigned int h1(s1),h2(s2); if(o2 > o3) swap(h1,h2); if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag =-sign*vec_[idiag].second-> evaluate(scale, outspin_[o2].first[h1], outspin_[o3].second[h2], interv); } else { diag = sign*vec_[idiag].second-> evaluate(scale, outspin_[o3].first[h2], outspin_[o2].second[h1], interv); } } // intermediate RS fermion else if(offshell->iSpin() == PDT::Spin3Half) { int iferm = (decay[o2]->dataPtr()->iSpin() == PDT::Spin1Half) ? o2 : o3; unsigned int h1(s1),h2(s2); if(dit->channelType > iferm) swap(h1, h2); sign = iferm < dit->channelType ? 1. : -1.; if((decay[dit->channelType]->id() < 0 && decay[iferm]->id() > 0 ) || (decay[dit->channelType]->id()*offshell->id()>0)) { RSSpinorWaveFunction inters = RSfer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].first[h1], swave_); diag = -sign*RSfer_[idiag].second-> evaluate(scale,inters,outspin_[iferm].second[h2], outVector_[v1]); } else { RSSpinorBarWaveFunction inters = RSfer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].second[h1],swave_); diag = sign*RSfer_[idiag].second-> evaluate(scale,outspin_[iferm].first [h2],inters, outVector_[v1]); } } // unknown else throw Exception() << "Unknown intermediate in StoFFVDecayer::me2()" << Exception::runerror; } else { unsigned int o2 = ivec > 0 ? 0 : 1; unsigned int o3 = ivec < 2 ? 2 : 1; if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag =-four_[idiag]-> evaluate(scale, outspin_[o2].first[s1], outspin_[o3].second[s2], outVector_[v1], swave_); } else { diag = four_[idiag]-> evaluate(scale, outspin_[o3].first[s2], outspin_[o2].second[s1], outVector_[v1], swave_); } } // matrix element for the different colour flows if(ichan < 0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1 != colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; } //end of diagrams // now add the flows to the me2 with appropriate colour factors for(unsigned int ix = 0; ix < ncf; ++ix) { if ( ivec == 0 ) { (*mes[ix])(0, v1, s1, s2) = flows[ix]; (*mel[ix])(0, v1, s1, s2) = largeflows[ix]; } else if( ivec == 1 ) { (*mes[ix])(0, s1, v1, s2) = flows[ix]; (*mel[ix])(0, s1, v1, s2) = largeflows[ix]; } else if( ivec == 2 ) { (*mes[ix])(0, s1, s2, v1) = flows[ix]; (*mel[ix])(0, s1, s2, v1) = largeflows[ix]; } } } } } double me2(0.); if(ichan < 0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix == iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *= UseRandom::rnd(); for(unsigned int ix = 0;ix < pflows.size(); ++ix) { if(ptotal <= pflows[ix]) { colourFlow(ix); ME(mes[ix]); break; } ptotal -= pflows[ix]; } } else { unsigned int iflow = colourFlow(); me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2; } diff --git a/Decay/General/StoFFVDecayer.h b/Decay/General/StoFFVDecayer.h --- a/Decay/General/StoFFVDecayer.h +++ b/Decay/General/StoFFVDecayer.h @@ -1,162 +1,157 @@ // -*- C++ -*- #ifndef THEPEG_StoFFVDecayer_H #define THEPEG_StoFFVDecayer_H // // This is the declaration of the StoFFVDecayer class. // #include "GeneralThreeBodyDecayer.h" #include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h" #include "ThePEG/Helicity/Vertex/AbstractRFVVertex.h" #include "ThePEG/Helicity/Vertex/AbstractRFSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFVSVertex.h" namespace Herwig { using namespace ThePEG; /** * Here is the documentation of the StoFFVDecayer class. * * @see \ref StoFFVDecayerInterfaces "The interfaces" * defined for StoFFVDecayer. */ class StoFFVDecayer: public GeneralThreeBodyDecayer { public: /** * Return the matrix element squared for a given mode and phase-space channel * @param ichan The channel we are calculating the matrix element for. * @param part The decaying Particle. * @param decay The particles produced in the decay. * @param meopt Option for the calculation of the matrix element * @return The matrix element squared for the phase-space configuration. */ virtual double me2(const int ichan, const Particle & part, const ParticleVector & decay, MEOption meopt) const; /** * Method to return an object to calculate the 3 (or higher body) partial width * @param dm The DecayMode * @return A pointer to a WidthCalculatorBase object capable of * calculating the width */ virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const; 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(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(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 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 IBPtr fullclone() const; //@} protected: - /** @name Standard Interfaced functions. */ - //@{ /** - * Initialize this object after the setup phase before saving an - * EventGenerator to disk. - * @throws InitException if object could not be initialized properly. + * Set up the diagrams etc */ - virtual void doinit(); - //@} + virtual void setupDiagrams(bool checkKinematics); private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ StoFFVDecayer & operator=(const StoFFVDecayer &); private: /** * Store the vertices for fermion intrermediate */ vector > fer_; /** * Store the vertices for fermion intrermediate */ vector > RSfer_; /** * Store the vertices for scalar intrermediate */ vector > sca_; /** * Store the vertices for vector intrermediate */ vector > vec_; /** * Store the vertices for 4-point diagrams */ vector four_; /** * Spin density matrix */ mutable RhoDMatrix rho_; /** * Scalar wavefunction */ mutable ScalarWaveFunction swave_; /** * Vector wavefunction */ mutable vector outVector_; /** * Spinor wavefunctions */ mutable pair,vector > outspin_[3]; }; } #endif /* THEPEG_StoFFVDecayer_H */ diff --git a/Decay/General/StoSFFDecayer.cc b/Decay/General/StoSFFDecayer.cc --- a/Decay/General/StoSFFDecayer.cc +++ b/Decay/General/StoSFFDecayer.cc @@ -1,422 +1,424 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the StoSFFDecayer class. // #include "StoSFFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG; using namespace ThePEG::Helicity; IBPtr StoSFFDecayer::clone() const { return new_ptr(*this); } IBPtr StoSFFDecayer::fullclone() const { return new_ptr(*this); } void StoSFFDecayer::persistentOutput(PersistentOStream & os) const { os << sca_ << fer_ << vec_ << ten_ << RSfer_ << four_; } void StoSFFDecayer::persistentInput(PersistentIStream & is, int) { is >> sca_ >> fer_ >> vec_ >> ten_ >> RSfer_ >> four_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigStoSFFDecayer("Herwig::StoSFFDecayer", "Herwig.so"); void StoSFFDecayer::Init() { static ClassDocumentation documentation ("The StoSFFDecayer class implements the general decay of a scalar to " "a scalar and two fermions."); } WidthCalculatorBasePtr StoSFFDecayer:: threeBodyMEIntegrator(const DecayMode & ) const { vector intype; vector inmass,inwidth; vector inpow,inweights; constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow,*this,0, outgoing()[0]->mass(),outgoing()[1]->mass(),outgoing()[2]->mass(), relativeError())); } -void StoSFFDecayer::doinit() { - GeneralThreeBodyDecayer::doinit(); +void StoSFFDecayer::setupDiagrams(bool kinCheck) { + GeneralThreeBodyDecayer::setupDiagrams(kinCheck); if(outgoing().empty()) return; unsigned int ndiags = getProcessInfo().size(); sca_.resize(ndiags); fer_.resize(ndiags); RSfer_.resize(ndiags); vec_.resize(ndiags); ten_.resize(ndiags); four_.resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { TBDiagram current = getProcessInfo()[ix]; tcPDPtr offshell = current.intermediate; // four point vertex if(!offshell) { four_[ix] = dynamic_ptr_cast(current.vertices.first); continue; } if( offshell->CC() ) offshell = offshell->CC(); if(offshell->iSpin() == PDT::Spin0) { AbstractSSSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a scalar diagram in StoSFFDecayer::doinit()" + << "Invalid vertices for a scalar diagram in StoSFFDecayer::setupDiagrams()" << Exception::runerror; sca_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1Half) { AbstractFFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a fermion diagram in StoSFFDecayer::doinit()" + << "Invalid vertices for a fermion diagram in StoSFFDecayer::setupDiagrams()" << Exception::runerror; fer_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1) { AbstractVSSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a vector diagram in StoSFFDecayer::doinit()" + << "Invalid vertices for a vector diagram in StoSFFDecayer::setupDiagrams()" << Exception::runerror; vec_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin2) { AbstractSSTVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFTVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a tensor diagram in StoSFFDecayer::doinit()" + << "Invalid vertices for a tensor diagram in StoSFFDecayer::setupDiagrams()" << Exception::runerror; ten_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin3Half) { AbstractRFSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractRFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a RS fermion diagram in StoSFFDecayer::doinit()" + << "Invalid vertices for a RS fermion diagram in StoSFFDecayer::setupDiagrams()" << Exception::runerror; RSfer_[ix] = make_pair(vert1, vert2); } } } double StoSFFDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming != inpart.id(); // special handling or first/last call if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(rho_,const_ptr_cast(&inpart), Helicity::incoming); swave_ = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(), Helicity::incoming); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { ScalarWaveFunction:: constructSpinInfo(const_ptr_cast(&inpart), Helicity::incoming,true); for(unsigned int ix=0;ixdataPtr()->iSpin()==PDT::Spin0) { ScalarWaveFunction::constructSpinInfo(decay[ix],Helicity::outgoing,true); } else { SpinorWaveFunction:: constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true); } } return 0.; } // get the wavefunctions for all the particles ScalarWaveFunction outScalar; unsigned int isca(0); for(unsigned int ix=0;ixdataPtr()->iSpin()==PDT::Spin0) { isca = ix; outScalar = ScalarWaveFunction(decay[ix]->momentum(), decay[ix]->dataPtr(),Helicity::outgoing); } else { SpinorWaveFunction:: calculateWaveFunctions(outspin_[ix].first,decay[ix],Helicity::outgoing); outspin_[ix].second.resize(2); if(outspin_[ix].first[0].wave().Type() == SpinorType::u) { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].first[iy].conjugate(); } } else { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].second[iy].conjugate(); } } } } const vector > cfactors(getColourFactors()); const vector > nfactors(getLargeNcColourFactors()); Energy2 scale(sqr(inpart.mass())); const size_t ncf(numberOfFlows()); vector flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.)); vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, isca==0 ? PDT::Spin0 : PDT::Spin1Half, isca==1 ? PDT::Spin0 : PDT::Spin1Half, isca==2 ? PDT::Spin0 : PDT::Spin1Half))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin0, isca == 0 ? PDT::Spin0 : PDT::Spin1Half, isca == 1 ? PDT::Spin0 : PDT::Spin1Half, isca == 2 ? PDT::Spin0 : PDT::Spin1Half))); static const unsigned int out2[3]={1,0,0},out3[3]={2,2,1}; for(unsigned int s1 = 0;s1 < 2; ++s1) { for(unsigned int s2 = 0;s2 < 2; ++s2) { flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag(0); for(vector::const_iterator dit = getProcessInfo().begin(); dit != getProcessInfo().end(); ++dit) { // channels if selecting if( ichan >= 0 && diagramMap()[ichan] != idiag ) { ++idiag; continue; } tcPDPtr offshell = dit->intermediate; Complex diag; if(offshell) { if(cc&&offshell->CC()) offshell=offshell->CC(); double sign = out3[dit->channelType] < out2[dit->channelType] ? 1. : -1.; // intermediate scalar if (offshell->iSpin() == PDT::Spin0) { ScalarWaveFunction inters = sca_[idiag].first-> evaluate(scale, widthOption(), offshell, swave_, outScalar); unsigned int h1(s1),h2(s2); if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2); if(decay[out2[dit->channelType]]->id()<0&& decay[out3[dit->channelType]]->id()>0) { diag =-sign*sca_[idiag].second-> evaluate(scale, outspin_[out2[dit->channelType]].first [h1], outspin_[out3[dit->channelType]].second[h2],inters); } else { diag = sign*sca_[idiag].second-> evaluate(scale, outspin_[out3[dit->channelType]].first [h2], outspin_[out2[dit->channelType]].second[h1],inters); } } // intermediate fermion else if(offshell->iSpin() == PDT::Spin1Half) { int iferm = decay[out2[dit->channelType]]->dataPtr()->iSpin()==PDT::Spin1Half ? out2[dit->channelType] : out3[dit->channelType]; unsigned int h1(s1),h2(s2); if(dit->channelType>iferm) swap(h1,h2); sign = ifermchannelType ? 1. : -1.; if((decay[dit->channelType]->id() < 0 &&decay[iferm]->id() > 0 ) || (decay[dit->channelType]->id()*offshell->id()>0)) { SpinorWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].first [h1],swave_); diag = -sign*fer_[idiag].second-> evaluate(scale,inters,outspin_[iferm].second[h2],outScalar); } else { SpinorBarWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].second[h1],swave_); diag = sign*fer_[idiag].second-> evaluate(scale,outspin_[iferm].first [h2],inters,outScalar); } } // intermediate vector else if(offshell->iSpin() == PDT::Spin1) { VectorWaveFunction interv = vec_[idiag].first-> evaluate(scale, widthOption(), offshell, swave_, outScalar); unsigned int h1(s1),h2(s2); if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2); if(decay[out2[dit->channelType]]->id()<0&& decay[out3[dit->channelType]]->id()>0) { diag =-sign*vec_[idiag].second-> evaluate(scale, outspin_[out2[dit->channelType]].first [h1], outspin_[out3[dit->channelType]].second[h2],interv); } else { diag = sign*vec_[idiag].second-> evaluate(scale, outspin_[out3[dit->channelType]].first [h2], outspin_[out2[dit->channelType]].second[h1],interv); } } // intermediate tensor else if(offshell->iSpin() == PDT::Spin2) { TensorWaveFunction intert = ten_[idiag].first-> evaluate(scale, widthOption(), offshell, swave_, outScalar); unsigned int h1(s1),h2(s2); if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2); if(decay[out2[dit->channelType]]->id()<0&& decay[out3[dit->channelType]]->id()>0) { diag =-sign*ten_[idiag].second-> evaluate(scale, outspin_[out2[dit->channelType]].first [h1], outspin_[out3[dit->channelType]].second[h2],intert); } else { diag = sign*ten_[idiag].second-> evaluate(scale, outspin_[out3[dit->channelType]].first [h2], outspin_[out2[dit->channelType]].second[h1],intert); } } // intermediate RS fermion else if(offshell->iSpin() == PDT::Spin3Half) { int iferm = decay[out2[dit->channelType]]->dataPtr()->iSpin()==PDT::Spin1Half ? out2[dit->channelType] : out3[dit->channelType]; unsigned int h1(s1),h2(s2); if(dit->channelType>iferm) swap(h1,h2); sign = ifermchannelType ? 1. : -1.; if((decay[dit->channelType]->id() < 0 &&decay[iferm]->id() > 0 ) || (decay[dit->channelType]->id()*offshell->id()>0)) { RSSpinorWaveFunction inters = RSfer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].first [h1],swave_); diag = -sign*RSfer_[idiag].second-> evaluate(scale,inters,outspin_[iferm].second[h2],outScalar); } else { RSSpinorBarWaveFunction inters = RSfer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].second[h1],swave_); diag = sign*RSfer_[idiag].second-> evaluate(scale,outspin_[iferm].first [h2],inters,outScalar); } } // unknown else throw Exception() << "Unknown intermediate in StoSFFDecayer::me2()" << Exception::runerror; } // four point diagram else { unsigned int o2 = isca > 0 ? 0 : 1; unsigned int o3 = isca < 2 ? 2 : 1; if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag =-four_[idiag]-> evaluate(scale, outspin_[o2].first[s1], outspin_[o3].second[s2], outScalar, swave_); } else { diag = four_[idiag]-> evaluate(scale, outspin_[o3].first[s2], outspin_[o2].second[s1], outScalar, swave_); } } // matrix element for the different colour flows if(ichan < 0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1 != colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; } for(unsigned int ix = 0; ix < ncf; ++ix) { if(isca == 0) { (*mes[ix])(0, 0, s1, s2) = flows[ix]; (*mel[ix])(0, 0, s1, s2) = largeflows[ix]; } else if(isca == 1 ) { (*mes[ix])(0, s1, 0, s2) = flows[ix]; (*mel[ix])(0, s1, 0, s2) = largeflows[ix]; } else if(isca == 2) { (*mes[ix])(0, s1,s2, 0) = flows[ix]; (*mel[ix])(0, s1,s2, 0) = largeflows[ix] ; } } } } double me2(0.); if(ichan < 0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix == iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *= UseRandom::rnd(); for(unsigned int ix = 0;ix < pflows.size(); ++ix) { if(ptotal <= pflows[ix]) { colourFlow(ix); ME(mes[ix]); break; } ptotal -= pflows[ix]; } } else { unsigned int iflow = colourFlow(); me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2; } diff --git a/Decay/General/StoSFFDecayer.h b/Decay/General/StoSFFDecayer.h --- a/Decay/General/StoSFFDecayer.h +++ b/Decay/General/StoSFFDecayer.h @@ -1,163 +1,158 @@ // -*- C++ -*- #ifndef THEPEG_StoSFFDecayer_H #define THEPEG_StoSFFDecayer_H // // This is the declaration of the StoSFFDecayer class. // #include "GeneralThreeBodyDecayer.h" #include "ThePEG/Helicity/Vertex/AbstractSSSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractRFSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractVSSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h" #include "ThePEG/Helicity/Vertex/AbstractSSTVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFSSVertex.h" namespace Herwig { using namespace ThePEG; /** * The StoSFFDecayer class provides the general matrix element for * scalar decays into another scalar and a fermion-antifermion pair. * * @see \ref StoSFFDecayerInterfaces "The interfaces" * defined for StoSFFDecayer. */ class StoSFFDecayer: public GeneralThreeBodyDecayer { public: /** * Return the matrix element squared for a given mode and phase-space channel * @param ichan The channel we are calculating the matrix element for. * @param part The decaying Particle. * @param decay The particles produced in the decay. * @param meopt Option for the calculation of the matrix element * @return The matrix element squared for the phase-space configuration. */ virtual double me2(const int ichan, const Particle & part, const ParticleVector & decay, MEOption meopt) const; /** * Method to return an object to calculate the 3 (or higher body) partial width * @param dm The DecayMode * @return A pointer to a WidthCalculatorBase object capable of calculating the width */ virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const; 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(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(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 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 IBPtr fullclone() const; //@} protected: - /** @name Standard Interfaced functions. */ - //@{ /** - * Initialize this object after the setup phase before saving an - * EventGenerator to disk. - * @throws InitException if object could not be initialized properly. + * Set up the diagrams etc */ - virtual void doinit(); - //@} + virtual void setupDiagrams(bool checkKinematics); private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ StoSFFDecayer & operator=(const StoSFFDecayer &); private: /** * Store the vertices for scalar intermediate */ vector > sca_; /** * Store the vertices for spin-\f$\frac12\f$ fermion intermediate */ vector > fer_; /** * Store the vertices for spin-\f$\frac32\f$ fermion intermediate */ vector > RSfer_; /** * Store the vertices for vector intermediate */ vector > vec_; /** * Store the vertices for tensor intermediate */ vector > ten_; /** * Store the vertices for four point diagrams */ vector four_; /** * Spin density matrix */ mutable RhoDMatrix rho_; /** * Scalar wavefunction */ mutable ScalarWaveFunction swave_; /** * Spinor wavefunctions */ mutable pair,vector > outspin_[3]; }; } #endif /* THEPEG_StoSFFDecayer_H */ diff --git a/Decay/General/TFFDecayer.cc b/Decay/General/TFFDecayer.cc --- a/Decay/General/TFFDecayer.cc +++ b/Decay/General/TFFDecayer.cc @@ -1,351 +1,353 @@ // -*- C++ -*- // // TFFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 TFFDecayer class. // #include "TFFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr TFFDecayer::clone() const { return new_ptr(*this); } IBPtr TFFDecayer::fullclone() const { return new_ptr(*this); } void TFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map &, const vector > & outV, map fourV) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { fourPointVertex_[inter] = dynamic_ptr_cast(fourV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast (outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast (outV[1].at(inter)); } } void TFFDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << outgoingVertex1_ << outgoingVertex2_ << fourPointVertex_; } void TFFDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> outgoingVertex1_ >> outgoingVertex2_ >> fourPointVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTFFDecayer("Herwig::TFFDecayer", "Herwig.so"); void TFFDecayer::Init() { static ClassDocumentation documentation ("The TFFDecayer class implements the decay of a tensor particle " "to 2 fermions "); } double TFFDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { unsigned int iferm(0),ianti(1); if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin1Half,PDT::Spin1Half))); if(decay[0]->id()>=0) swap(iferm,ianti); if(meopt==Initialize) { TensorWaveFunction:: calculateWaveFunctions(tensors_,rho_,const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { TensorWaveFunction:: constructSpinInfo(tensors_,const_ptr_cast(&inpart), incoming,true,false); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[ianti],outgoing); Energy2 scale(sqr(inpart.mass())); unsigned int thel,fhel,ahel; for(thel=0;thel<5;++thel) { for(fhel=0;fhel<2;++fhel) { for(ahel=0;ahel<2;++ahel) { if(iferm > ianti) { (*ME())(thel,fhel,ahel) = 0.; for(auto vert : vertex_) (*ME())(thel,fhel,ahel) += vert->evaluate(scale,wave_[ahel], wavebar_[fhel],tensors_[thel]); } else { (*ME())(thel,ahel,fhel) = 0.; for(auto vert : vertex_) (*ME())(thel,ahel,fhel) += vert->evaluate(scale,wave_[ahel], wavebar_[fhel],tensors_[thel]); } } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy TFFDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy2 scale = sqr(inpart.second); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(scale, in, outa.first, outb.first); double musq = sqr(outa.second/inpart.second); double b = sqrt(1- 4.*musq); double me2 = b*b*(5-2*b*b)*scale/120.*UnitRemoval::InvE2; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm/(8.*Constants::pi); // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double TFFDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { // work out which is the fermion and antifermion int ianti(0), iferm(1), iglu(2); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti); if(itype[0]==2 && itype[1]==1) swap(iferm, ianti); if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(meopt==Initialize) { // create tensor wavefunction for decaying particle TensorWaveFunction:: calculateWaveFunctions(tensors3_, rho3_, const_ptr_cast(&inpart), incoming, false); } // setup spin information when needed if(meopt==Terminate) { TensorWaveFunction:: constructSpinInfo(tensors3_, const_ptr_cast(&inpart),incoming,true, false); SpinorBarWaveFunction:: constructSpinInfo(wavebar3_ ,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave3_ ,decay[ianti],outgoing,true); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin2, PDT::Spin1Half, PDT::Spin1Half, PDT::Spin1))); // create wavefunctions SpinorBarWaveFunction:: calculateWaveFunctions(wavebar3_, decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[ianti],outgoing); VectorWaveFunction:: calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif if (! (outgoingVertex1_[inter] && outgoingVertex2_[inter])) throw Exception() << "Invalid vertices for QCD radiation in TFF decay in TFFDecayer::threeBodyME" << Exception::runerror; // identify fermion and/or anti-fermion vertex AbstractFFVVertexPtr outgoingVertexF = outgoingVertex1_[inter]; AbstractFFVVertexPtr outgoingVertexA = outgoingVertex2_[inter]; if(outgoingVertex1_[inter]!=outgoingVertex2_[inter] && outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->id()))) swap (outgoingVertexF, outgoingVertexA); if(! (inpart.dataPtr()->iColour()==PDT::Colour0)){ throw Exception() << "Invalid vertices for QCD radiation in TFF decay in TFFDecayer::threeBodyME" << Exception::runerror; } Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int it = 0; it < 5; ++it) { for(unsigned int ifm = 0; ifm < 2; ++ifm) { for(unsigned int ia = 0; ia < 2; ++ia) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from outgoing fermion if((decay[iferm]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexF); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iferm]->dataPtr(); if(off->CC()) off = off->CC(); SpinorBarWaveFunction interS = outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm], gluon_[2*ig],decay[iferm]->mass()); assert(wavebar3_[ifm].particle()->id()==interS.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ia], interS,tensors3_[it]); if(!couplingSet) { gs = abs(outgoingVertexF->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexA); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ianti]->dataPtr(); if(off->CC()) off = off->CC(); SpinorWaveFunction interS = outgoingVertexA->evaluate(scale,3,off,wave3_[ia], gluon_[2*ig],decay[ianti]->mass()); assert(wave3_[ia].particle()->id()==interS.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,interS,wavebar3_[ifm],tensors3_[it]); if(!couplingSet) { gs = abs(outgoingVertexA->norm()); couplingSet = true; } for(unsigned int ix=0;ixevaluate(scale, wave3_[ia], wavebar3_[ifm], gluon_[2*ig], tensors3_[it]); for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(s,em) output *= (4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/TSSDecayer.cc b/Decay/General/TSSDecayer.cc --- a/Decay/General/TSSDecayer.cc +++ b/Decay/General/TSSDecayer.cc @@ -1,130 +1,132 @@ // -*- C++ -*- // // TSSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 TSSDecayer class. // #include "TSSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr TSSDecayer::clone() const { return new_ptr(*this); } IBPtr TSSDecayer::fullclone() const { return new_ptr(*this); } void TSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & , const vector > & , map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } } void TSSDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_; } void TSSDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTSSDecayer("Herwig::TSSDecayer", "Herwig.so"); void TSSDecayer::Init() { static ClassDocumentation documentation ("This class implements the decay of a tensor particle into " "2 scalars."); } double TSSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin0,PDT::Spin0))); if(meopt==Initialize) { TensorWaveFunction:: calculateWaveFunctions(tensors_,rho_,const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { TensorWaveFunction:: constructSpinInfo(tensors_,const_ptr_cast(&inpart), incoming,true,false); for(unsigned int ix=0;ix<2;++ix) ScalarWaveFunction:: constructSpinInfo(decay[ix],outgoing,true); return 0.; } ScalarWaveFunction sca1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing); ScalarWaveFunction sca2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int thel=0;thel<5;++thel) { (*ME())(thel,0,0) =0.; for(auto vert : vertex_) (*ME())(thel,0,0) += vert->evaluate(scale,sca1,sca2,tensors_[thel]); } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy TSSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy2 scale(sqr(inpart.second)); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(scale, outa.first, outb.first, in); double musq = sqr(outa.second/inpart.second); double b = sqrt(1. - 4.*musq); double me2 = scale*pow(b,4)/120*UnitRemoval::InvE2; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm/(8.*Constants::pi); // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } diff --git a/Decay/General/TVVDecayer.cc b/Decay/General/TVVDecayer.cc --- a/Decay/General/TVVDecayer.cc +++ b/Decay/General/TVVDecayer.cc @@ -1,338 +1,340 @@ // -*- C++ -*- // // TVVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 TVVDecayer class. // #include "TVVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/TensorWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Helicity/LorentzTensor.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr TVVDecayer::clone() const { return new_ptr(*this); } IBPtr TVVDecayer::fullclone() const { return new_ptr(*this); } void TVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map &, const vector > & outV, map fourV) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { fourPointVertex_[inter] = dynamic_ptr_cast(fourV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast (outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast (outV[1].at(inter)); } } void TVVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << outgoingVertex1_ << outgoingVertex2_ << fourPointVertex_; } void TVVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> outgoingVertex1_ >> outgoingVertex2_ >> fourPointVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTVVDecayer("Herwig::TVVDecayer", "Herwig.so"); void TVVDecayer::Init() { static ClassDocumentation documentation ("This class implements the decay of a tensor to 2 vector bosons"); } double TVVDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin2,PDT::Spin1,PDT::Spin1))); bool photon[2]; for(unsigned int ix=0;ix<2;++ix) photon[ix] = decay[ix]->mass()==ZERO; if(meopt==Initialize) { TensorWaveFunction:: calculateWaveFunctions(tensors_,rho_,const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { TensorWaveFunction:: constructSpinInfo(tensors_,const_ptr_cast(&inpart), incoming,true,false); for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: constructSpinInfo(vectors_[ix],decay[ix],outgoing,true,photon[ix]); return 0.; } for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: calculateWaveFunctions(vectors_[ix],decay[ix],outgoing,photon[ix]); Energy2 scale(sqr(inpart.mass())); unsigned int thel,v1hel,v2hel; for(thel=0;thel<5;++thel) { for(v1hel=0;v1hel<3;++v1hel) { for(v2hel=0;v2hel<3;++v2hel) { (*ME())(thel,v1hel,v2hel) = 0.; for(auto vert : vertex_) (*ME())(thel,v1hel,v2hel) += vert->evaluate(scale, vectors_[0][v1hel], vectors_[1][v2hel], tensors_[thel]); if(photon[1]) ++v2hel; } if(photon[0]) ++v1hel; } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy TVVDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy2 scale(sqr(inpart.second)); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(scale, outa.first, outb.first, in); double mu2 = sqr(outa.second/inpart.second); double b = sqrt(1 - 4.*mu2); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy2 me2; if(outa.second > ZERO && outb.second > ZERO) me2 = scale*(30 - 20.*b*b + 3.*pow(b,4))/120.; else me2 = scale/10.; Energy output = norm(perturbativeVertex_[0]->norm())*me2*pcm /(8.*Constants::pi)*UnitRemoval::InvE2; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double TVVDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { bool massless[2]; for(unsigned int ix=0;ix<2;++ix) massless[ix] = decay[ix]->mass()==ZERO; int iglu(2); if(meopt==Initialize) { // create tensor wavefunction for decaying particle TensorWaveFunction:: calculateWaveFunctions(tensors3_, rho3_, const_ptr_cast(&inpart), incoming, false); } // setup spin information when needed if(meopt==Terminate) { TensorWaveFunction:: constructSpinInfo(tensors3_, const_ptr_cast(&inpart),incoming,true, false); for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: constructSpinInfo(vectors3_[ix],decay[ix ],outgoing,true, massless[ix]); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin2, PDT::Spin1, PDT::Spin1, PDT::Spin1))); // create wavefunctions for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: calculateWaveFunctions(vectors3_[ix],decay[ix ],outgoing,massless[ix]); VectorWaveFunction:: calculateWaveFunctions(gluon_ ,decay[iglu ],outgoing,true); // gauge test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif // work out which vector each outgoing vertex corresponds to if(outgoingVertex1_[inter]!=outgoingVertex2_[inter] && outgoingVertex1_[inter]->isIncoming(getParticleData(decay[1]->id()))) swap(outgoingVertex1_[inter], outgoingVertex2_[inter]); if (! (outgoingVertex1_[inter] && outgoingVertex2_[inter])) throw Exception() << "Invalid vertices for radiation in TVV decay in TVVDecayer::threeBodyME" << Exception::runerror; if( !(!inpart.dataPtr()->coloured() && inter ==ShowerInteraction::QCD) && !(!inpart.dataPtr()->charged() && inter ==ShowerInteraction::QED)) throw Exception() << "Invalid vertices for radiation in TVV decay in TVVDecayer::threeBodyME" << Exception::runerror; Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int it = 0; it < 5; ++it) { for(unsigned int iv0 = 0; iv0 < 3; ++iv0) { for(unsigned int iv1 = 0; iv1 < 3; ++iv1) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from first outgoing vector if((decay[0]->dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[0]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex1_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[0]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectInter = outgoingVertex1_[inter]->evaluate(scale,3,off,gluon_[2*ig], vectors3_[0][iv0],decay[0]->mass()); assert(vectors3_[0][iv0].particle()->PDGName()==vectInter.particle()->PDGName()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectors3_[1][iv1], vectInter,tensors3_[it]); if(!couplingSet) { gs = abs(outgoingVertex1_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[1]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex2_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[1]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectInter = outgoingVertex2_[inter]->evaluate(scale,3,off,vectors3_[1][iv1], gluon_[2*ig],decay[1]->mass()); assert(vectors3_[1][iv1].particle()->PDGName()==vectInter.particle()->PDGName()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectInter,vectors3_[0][iv0], tensors3_[it]); if(!couplingSet) { gs = abs(outgoingVertex2_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixevaluate(scale, vectors3_[0][iv0], vectors3_[1][iv1],gluon_[2*ig], tensors3_[it]); for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(s,em) output *= (4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/VFFDecayer.cc b/Decay/General/VFFDecayer.cc --- a/Decay/General/VFFDecayer.cc +++ b/Decay/General/VFFDecayer.cc @@ -1,470 +1,472 @@ // -*- C++ -*- // // VFFDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 VFFDecayer class. // #include "VFFDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Helicity/Vertex/Vector/FFVVertex.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr VFFDecayer::clone() const { return new_ptr(*this); } IBPtr VFFDecayer::fullclone() const { return new_ptr(*this); } void VFFDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } void VFFDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_; } void VFFDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVFFDecayer("Herwig::VFFDecayer", "Herwig.so"); void VFFDecayer::Init() { static ClassDocumentation documentation ("The VFFDecayer implements the matrix element for the" " decay of a vector to fermion-antifermion pair"); } double VFFDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { int iferm(1),ianti(0); if(decay[0]->id()>0) swap(iferm,ianti); if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_,rho_, const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(vectors_,const_ptr_cast(&inpart), incoming,true,false); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[ianti],outgoing); // compute the matrix element Energy2 scale(inpart.mass()*inpart.mass()); for(unsigned int ifm = 0; ifm < 2; ++ifm) { //loop over fermion helicities for(unsigned int ia = 0; ia < 2; ++ia) {// loop over antifermion helicities for(unsigned int vhel = 0; vhel < 3; ++vhel) {//loop over vector helicities if(iferm > ianti) { (*ME())(vhel, ia, ifm) = 0.; for(auto vert : vertex_) (*ME())(vhel, ia, ifm) += vert->evaluate(scale,wave_[ia], wavebar_[ifm],vectors_[vhel]); } else { (*ME())(vhel,ifm,ia)= 0.; for(auto vert : vertex_) (*ME())(vhel,ifm,ia) += vert->evaluate(scale,wave_[ia], wavebar_[ifm],vectors_[vhel]); } } } } double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy VFFDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { double mu1(outa.second/inpart.second), mu2(outb.second/inpart.second); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), outa.first, outb.first,in); Complex cl(perturbativeVertex_[0]->left()), cr(perturbativeVertex_[0]->right()); double me2 = (norm(cl) + norm(cr))*( sqr(sqr(mu1) - sqr(mu2)) + sqr(mu1) + sqr(mu2) - 2.) - 6.*(cl*conj(cr) + cr*conj(cl)).real()*mu1*mu2; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = -norm(perturbativeVertex_[0]->norm())*me2*pcm / (24.*Constants::pi); // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double VFFDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { // work out which is the fermion and antifermion int ianti(0), iferm(1), iglu(2); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0 && itype[1]!=0) swap(iferm, ianti); if(itype[0]==2 && itype[1]==1) swap(iferm, ianti); if(itype[0]==0 && itype[1]==0 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(itype[0]==1 && itype[1]==1 && decay[0]->dataPtr()->id()dataPtr()->id()) swap(iferm, ianti); if(meopt==Initialize) { // create vector wavefunction for decaying particle VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast(&inpart), incoming, false); } // setup spin information when needed if(meopt==Terminate) { VectorWaveFunction:: constructSpinInfo(vector3_ ,const_ptr_cast(&inpart),outgoing,true,false); SpinorBarWaveFunction:: constructSpinInfo(wavebar3_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave3_ ,decay[ianti],outgoing,true); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin1Half, PDT::Spin1Half, PDT::Spin1))); // create wavefunctions SpinorBarWaveFunction:: calculateWaveFunctions(wavebar3_, decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave3_ , decay[ianti],outgoing); VectorWaveFunction:: calculateWaveFunctions(gluon_ , decay[iglu ],outgoing,true); // gauge invariance test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif // identify fermion and/or anti-fermion vertex AbstractFFVVertexPtr outgoingVertexF; AbstractFFVVertexPtr outgoingVertexA; identifyVertices(iferm, ianti, inpart, decay, outgoingVertexF, outgoingVertexA,inter); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv = 0; iv < 3; ++iv) { for(unsigned int ifm = 0; ifm < 2; ++ifm) { for(unsigned int ia = 0; ia < 2; ++ia) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming vector if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); VectorWaveFunction vectorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv], gluon_[2*ig],inpart.mass()); assert(vector3_[iv].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ia],wavebar3_[ifm],vectorInter); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iferm]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexF); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iferm]->dataPtr(); if(off->CC()) off = off->CC(); SpinorBarWaveFunction interS = outgoingVertexF->evaluate(scale,3,off,wavebar3_[ifm], gluon_[2*ig],decay[iferm]->mass()); assert(wavebar3_[ifm].particle()->id()==interS.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,wave3_[ia], interS,vector3_[iv]); if(!couplingSet) { gs = abs(outgoingVertexF->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexA); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ianti]->dataPtr(); if(off->CC()) off = off->CC(); SpinorWaveFunction interS = outgoingVertexA->evaluate(scale,3,off,wave3_[ia], gluon_[2*ig],decay[ianti]->mass()); assert(wave3_[ia].particle()->id()==interS.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,interS,wavebar3_[ifm],vector3_[iv]); if(!couplingSet) { gs = abs(outgoingVertexA->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif //return output return output; } void VFFDecayer::identifyVertices(const int iferm, const int ianti, const Particle & inpart, const ParticleVector & decay, AbstractFFVVertexPtr & outgoingVertexF, AbstractFFVVertexPtr & outgoingVertexA, ShowerInteraction inter){ // QCD vertices if(inter==ShowerInteraction::QCD) { // work out which fermion each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))){ outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))){ outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))){ outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))){ outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr()->iColour()==PDT::Colour3){ if(decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexF = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexF = outgoingVertex2_[inter]; } else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))){ outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } else { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){ if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar && decay[iferm]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter]; } else if (decay[iferm]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))){ outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour6 || inpart.dataPtr()->iColour()==PDT::Colour6bar) { if (outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) { outgoingVertexF = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexF = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } if (! ((incomingVertex_[inter] && (outgoingVertexF || outgoingVertexA)) || ( outgoingVertexF && outgoingVertexA))) throw Exception() << "Invalid vertices for QCD radiation in VFF decay in VFFDecayer::identifyVertices" << Exception::runerror; } // QED else { if(decay[iferm]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iferm]->dataPtr()))) outgoingVertexF = outgoingVertex1_[inter]; else outgoingVertexF = outgoingVertex2_[inter]; } if(decay[ianti]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))) outgoingVertexA = outgoingVertex1_[inter]; else outgoingVertexA = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/VSSDecayer.cc b/Decay/General/VSSDecayer.cc --- a/Decay/General/VSSDecayer.cc +++ b/Decay/General/VSSDecayer.cc @@ -1,416 +1,418 @@ // -*- C++ -*- // // VSSDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 VSSDecayer class. // #include "VSSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Utilities/Kinematics.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr VSSDecayer::clone() const { return new_ptr(*this); } IBPtr VSSDecayer::fullclone() const { return new_ptr(*this); } void VSSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map ) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } void VSSDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_; } void VSSDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVSSDecayer("Herwig::VSSDecayer", "Herwig.so"); void VSSDecayer::Init() { static ClassDocumentation documentation ("This implements the decay of a vector to 2 scalars"); } double VSSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin0,PDT::Spin0))); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_,rho_, const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(vectors_,const_ptr_cast(&inpart), incoming,true,false); for(unsigned int ix=0;ix<2;++ix) ScalarWaveFunction:: constructSpinInfo(decay[ix],outgoing,true); return 0.; } ScalarWaveFunction sca1(decay[0]->momentum(),decay[0]->dataPtr(),outgoing); ScalarWaveFunction sca2(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int ix=0;ix<3;++ix) { (*ME())(ix,0,0) = 0.; for(auto vert : vertex_) (*ME())(ix,0,0) += vert->evaluate(scale,vectors_[ix],sca1,sca2); } double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy VSSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first); double mu1sq = sqr(outa.second/inpart.second); double mu2sq = sqr(outb.second/inpart.second); double me2 = sqr(mu1sq - mu2sq) - 2.*(mu1sq + mu2sq); Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = -norm(perturbativeVertex_[0]->norm())*me2*pcm / (24.*Constants::pi); // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double VSSDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { // work out which is the scalar and anti-scalar int ianti(0), iscal(1), iglu(2); int itype[2]; for(unsigned int ix=0;ix<2;++ix) { if(decay[ix]->dataPtr()->CC()) itype[ix] = decay[ix]->id()>0 ? 0:1; else itype[ix] = 2; } if(itype[0]==0 && itype[1]!=0) swap(ianti, iscal); if(itype[0]==2 && itype[1]==1) swap(ianti, iscal); if(itype[0]==0 && itype[1]==0 && abs(decay[0]->dataPtr()->id())>abs(decay[1]->dataPtr()->id())) swap(iscal, ianti); if(itype[0]==1 && itype[1]==1 && abs(decay[0]->dataPtr()->id())dataPtr()->id())) swap(iscal, ianti); if(meopt==Initialize) { // create vector wavefunction for decaying particle VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast(&inpart), incoming, false); } // setup spin information when needed if(meopt==Terminate) { VectorWaveFunction:: constructSpinInfo(vector3_ ,const_ptr_cast(&inpart),outgoing,true,false); ScalarWaveFunction::constructSpinInfo( decay[iscal],outgoing,true); ScalarWaveFunction::constructSpinInfo( decay[ianti],outgoing,true); VectorWaveFunction::constructSpinInfo(gluon_,decay[iglu ],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin0, PDT::Spin0, PDT::Spin1))); // create wavefunctions ScalarWaveFunction scal(decay[iscal]->momentum(), decay[iscal]->dataPtr(),outgoing); ScalarWaveFunction anti(decay[ianti]->momentum(), decay[ianti]->dataPtr(),outgoing); VectorWaveFunction::calculateWaveFunctions(gluon_,decay[iglu ],outgoing,true); // gauge test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[iglu ]->momentum(), decay[iglu ]->dataPtr(),10, outgoing)); } } #endif // identify scalar and/or anti-scalar vertex AbstractVSSVertexPtr outgoingVertexS; AbstractVSSVertexPtr outgoingVertexA; identifyVertices(iscal, ianti, inpart, decay, outgoingVertexS, outgoingVertexA,inter); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv = 0; iv < 3; ++iv) { for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming vector if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); VectorWaveFunction vectorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv], gluon_[2*ig],inpart.mass()); assert(vector3_[iv].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectorInter,scal,anti); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[iscal]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexS); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[iscal]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexS->evaluate(scale,3,off,gluon_[2*ig],scal,decay[iscal]->mass()); assert(scal.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv],anti,scalarInter); if(!couplingSet) { gs = abs(outgoingVertexS->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ianti]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexA); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ianti]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexA->evaluate(scale,3,off, gluon_[2*ig],anti,decay[ianti]->mass()); assert(anti.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv],scal,scalarInter); if(!couplingSet) { gs = abs(outgoingVertexA->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } void VSSDecayer::identifyVertices(const int iscal, const int ianti, const Particle & inpart, const ParticleVector & decay, AbstractVSSVertexPtr & outgoingVertexS, AbstractVSSVertexPtr & outgoingVertexA, ShowerInteraction inter){ if(inter==ShowerInteraction::QCD) { // work out which scalar each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[iscal]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8))){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[iscal]->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr()->iColour()==PDT::Colour3){ if(decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexS = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexS = outgoingVertex2_[inter]; } else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour3 && decay[ianti]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[ianti]->dataPtr()->id()))){ outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } else { outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){ if(decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar && decay[iscal]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertexA = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertexA = outgoingVertex2_[inter]; } else if (decay[iscal]->dataPtr()->iColour()==PDT::Colour8 && decay[ianti]->dataPtr()->iColour()==PDT::Colour3bar){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[iscal]->dataPtr()->id()))){ outgoingVertexS = outgoingVertex1_[inter]; outgoingVertexA = outgoingVertex2_[inter]; } else { outgoingVertexS = outgoingVertex2_[inter]; outgoingVertexA = outgoingVertex1_[inter]; } } } if (! ((incomingVertex_[inter] && (outgoingVertexS || outgoingVertexA)) || ( outgoingVertexS && outgoingVertexA))) throw Exception() << "Invalid vertices for QCD radiation in VSS decay in VSSDecayer::identifyVertices" << Exception::runerror; } else { if(decay[iscal]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[iscal]->dataPtr()))) outgoingVertexS = outgoingVertex1_[inter]; else outgoingVertexS = outgoingVertex2_[inter]; } if(decay[ianti]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[ianti]->dataPtr()))) outgoingVertexA = outgoingVertex1_[inter]; else outgoingVertexA = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/VVSDecayer.cc b/Decay/General/VVSDecayer.cc --- a/Decay/General/VVSDecayer.cc +++ b/Decay/General/VVSDecayer.cc @@ -1,313 +1,315 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the VVSDecayer class. // #include "VVSDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr VVSDecayer::clone() const { return new_ptr(*this); } IBPtr VVSDecayer::fullclone() const { return new_ptr(*this); } void VVSDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_.push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertexS_[inter] = AbstractVSSVertexPtr(); outgoingVertexV_[inter] = AbstractVVVVertexPtr(); if(outV[0].at(inter)) { if (outV[0].at(inter)->getName()==VertexType::VSS) outgoingVertexS_[inter] = dynamic_ptr_cast(outV[0].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[0].at(inter)); } if(outV[1].at(inter)) { if (outV[1].at(inter)->getName()==VertexType::VSS) outgoingVertexS_[inter] = dynamic_ptr_cast(outV[1].at(inter)); else outgoingVertexV_[inter] = dynamic_ptr_cast(outV[1].at(inter)); } } } void VVSDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertexS_ << outgoingVertexV_; } void VVSDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertexS_ >> outgoingVertexV_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVVSDecayer("Herwig::VVSDecayer", "Herwig.so"); void VVSDecayer::Init() { static ClassDocumentation documentation ("The VVSDecayer class implements the decay of a vector" " to a vector and a scalar"); } double VVSDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { bool massless = ( decay[0]->id()==ParticleID::gamma || decay[0]->id()==ParticleID::g ); if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin0))); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_[0],rho_, const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(vectors_[0],const_ptr_cast(&inpart), incoming,true,false); VectorWaveFunction:: constructSpinInfo(vectors_[1],decay[0],outgoing,true,massless); ScalarWaveFunction:: constructSpinInfo(decay[1],outgoing,true); return 0.; } VectorWaveFunction:: calculateWaveFunctions(vectors_[1],decay[0],outgoing,massless); ScalarWaveFunction sca(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); Energy2 scale(sqr(inpart.mass())); for(unsigned int in=0;in<3;++in) { for(unsigned int out=0;out<3;++out) { if(massless&&out==1) ++out; (*ME())(in,out,0) = 0.; for(auto vert : vertex_) (*ME())(in,out,0) += vert->evaluate(scale,vectors_[0][in],vectors_[1][out],sca); } } double output=(ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy VVSDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { Energy2 scale(sqr(inpart.second)); double mu1sq = sqr(outa.second/inpart.second); double mu2sq = sqr(outb.second/inpart.second); tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; if( outb.first->iSpin() == PDT::Spin0 ) perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first); else { perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outb.first, outa.first); swap(mu1sq, mu2sq); } double vn = norm(perturbativeVertex_[0]->norm()); if(vn == ZERO || mu1sq == ZERO) return ZERO; double me2 = 2. + 0.25*sqr(1. + mu1sq - mu2sq)/mu1sq; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy output = vn*me2*pcm/(24.*Constants::pi)/scale*UnitRemoval::E2; // colour factor output *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return output; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double VVSDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { unsigned int ivec(0),isca(1); if(decay[ivec]->dataPtr()->iSpin()!=PDT::Spin1) swap(ivec,isca); if(meopt==Initialize) { // create vector wavefunction for decaying particle VectorWaveFunction::calculateWaveFunctions(vectors3_[0], rho3_, const_ptr_cast(&inpart), incoming, false); } if(meopt==Terminate) { VectorWaveFunction:: constructSpinInfo(vectors3_[0] ,const_ptr_cast(&inpart),outgoing,true,false); VectorWaveFunction:: constructSpinInfo(vectors3_[1],decay[ivec],outgoing,true,false); ScalarWaveFunction:: constructSpinInfo(decay[isca],outgoing,true); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[2],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin1, PDT::Spin0, PDT::Spin1))); bool massless= decay[ivec]->mass()!=ZERO; // create wavefunctions VectorWaveFunction::calculateWaveFunctions(vectors3_[1],decay[0],outgoing,massless); ScalarWaveFunction scal(decay[isca]->momentum(), decay[isca]->dataPtr(),outgoing); VectorWaveFunction::calculateWaveFunctions(gluon_ ,decay[2],outgoing,true); // gauge test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[2]->momentum(), decay[2]->dataPtr(),10, outgoing)); } } #endif Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv0 = 0; iv0 < 3; ++iv0) { for(unsigned int iv1 = 0; iv1 < 3; ++iv1) { if(massless && iv1==1) continue; for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming vector if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); VectorWaveFunction vectorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vectors3_[0][iv0], gluon_[2*ig],inpart.mass()); assert(vectors3_[0][iv0].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectorInter,vectors3_[1][iv1],scal); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[ivec]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexV_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[ivec]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertexV_[inter]->evaluate(scale,3,off,gluon_[2*ig],vectors3_[1][iv1],decay[ivec]->mass()); assert(vectors3_[1][iv1].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectors3_[0][iv0],vectorInter,scal); if(!couplingSet) { gs = abs(outgoingVertexV_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[isca]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertexS_[inter]); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[isca]->dataPtr(); if(off->CC()) off = off->CC(); ScalarWaveFunction scalarInter = outgoingVertexS_[inter]->evaluate(scale,3,off,gluon_[2*ig],scal,decay[isca]->mass()); assert(scal.particle()->id()==scalarInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectors3_[0][iv0],vectors3_[1][iv1],scalarInter); if(!couplingSet) { gs = abs(outgoingVertexS_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } diff --git a/Decay/General/VVVDecayer.cc b/Decay/General/VVVDecayer.cc --- a/Decay/General/VVVDecayer.cc +++ b/Decay/General/VVVDecayer.cc @@ -1,441 +1,443 @@ // -*- C++ -*- // // VVVDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 VVVDecayer class. // #include "VVVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Utilities/Kinematics.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; IBPtr VVVDecayer::clone() const { return new_ptr(*this); } IBPtr VVVDecayer::fullclone() const { return new_ptr(*this); } void VVVDecayer::setDecayInfo(PDPtr incoming, PDPair outgoing, vector vertex, map & inV, const vector > & outV, map fourV) { decayInfo(incoming,outgoing); for(auto vert : vertex) { vertex_ .push_back(dynamic_ptr_cast(vert)); perturbativeVertex_ .push_back(dynamic_ptr_cast (vert)); } vector itemp={ShowerInteraction::QCD,ShowerInteraction::QED}; for(auto & inter : itemp) { incomingVertex_[inter] = dynamic_ptr_cast(inV.at(inter)); outgoingVertex1_[inter] = dynamic_ptr_cast(outV[0].at(inter)); outgoingVertex2_[inter] = dynamic_ptr_cast(outV[1].at(inter)); fourPointVertex_[inter] = dynamic_ptr_cast(fourV.at(inter)); } } void VVVDecayer::persistentOutput(PersistentOStream & os) const { os << vertex_ << perturbativeVertex_ << incomingVertex_ << outgoingVertex1_ << outgoingVertex2_ << fourPointVertex_; } void VVVDecayer::persistentInput(PersistentIStream & is, int) { is >> vertex_ >> perturbativeVertex_ >> incomingVertex_ >> outgoingVertex1_ >> outgoingVertex2_ >> fourPointVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVVVDecayer("Herwig::VVVDecayer", "Herwig.so"); void VVVDecayer::Init() { static ClassDocumentation documentation ("The VVVDecayer class implements the decay of a vector boson " "into 2 vector bosons"); } double VVVDecayer::me2(const int , const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1,PDT::Spin1))); bool massless[2]; for(unsigned int ix=0;ix<2;++ix) massless[ix] = (decay[ix]->id()==ParticleID::gamma || decay[ix]->id()==ParticleID::g); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_[0],rho_, const_ptr_cast(&inpart), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(vectors_[0],const_ptr_cast(&inpart), incoming,true,false); for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: constructSpinInfo(vectors_[ix+1],decay[ix],outgoing,true,massless[ix]); return 0.; } for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: calculateWaveFunctions(vectors_[ix+1],decay[ix],outgoing,massless[ix]); Energy2 scale(sqr(inpart.mass())); for(unsigned int iv3=0;iv3<3;++iv3) { for(unsigned int iv2=0;iv2<3;++iv2) { for(unsigned int iv1=0;iv1<3;++iv1) { (*ME())(iv1,iv2,iv3) = 0.; for(auto vert : vertex_) { (*ME())(iv1,iv2,iv3) += vert-> evaluate(scale,vectors_[1][iv2],vectors_[2][iv3],vectors_[0][iv1]); } } } } double output = (ME()->contract(rho_)).real()/scale*UnitRemoval::E2; // colour and identical particle factors output *= colourFactor(inpart.dataPtr(),decay[0]->dataPtr(), decay[1]->dataPtr()); // return the answer return output; } Energy VVVDecayer::partialWidth(PMPair inpart, PMPair outa, PMPair outb) const { if( inpart.second < outa.second + outb.second ) return ZERO; if(perturbativeVertex_.size()==1 && perturbativeVertex_[0]) { tcPDPtr in = inpart.first->CC() ? tcPDPtr(inpart.first->CC()) : inpart.first; perturbativeVertex_[0]->setCoupling(sqr(inpart.second), in, outa.first, outb.first); double mu1(outa.second/inpart.second), mu1sq(sqr(mu1)), mu2(outb.second/inpart.second), mu2sq(sqr(mu2)); double vn = norm(perturbativeVertex_[0]->norm()); if(vn == ZERO || mu1sq == ZERO || mu2sq == ZERO) return ZERO; double me2 = (mu1 - mu2 - 1.)*(mu1 - mu2 + 1.)*(mu1 + mu2 - 1.)*(mu1 + mu2 + 1.) * (sqr(mu1sq) + sqr(mu2sq) + 10.*(mu1sq*mu2sq + mu1sq + mu2sq) + 1.) /4./mu1sq/mu2sq; Energy pcm = Kinematics::pstarTwoBodyDecay(inpart.second,outa.second, outb.second); Energy pWidth = vn*me2*pcm/24./Constants::pi; // colour factor pWidth *= colourFactor(inpart.first,outa.first,outb.first); // return the answer return pWidth; } else { return GeneralTwoBodyDecayer::partialWidth(inpart,outa,outb); } } double VVVDecayer::threeBodyME(const int , const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter, MEOption meopt) { if(meopt==Initialize) { // create vector wavefunction for decaying particle VectorWaveFunction::calculateWaveFunctions(vector3_, rho3_, const_ptr_cast(&inpart), incoming, false); } if(meopt==Terminate) { VectorWaveFunction:: constructSpinInfo(vector3_ ,const_ptr_cast(&inpart),outgoing,true,false); VectorWaveFunction:: constructSpinInfo(vectors3_[0],decay[0],outgoing,true,false); VectorWaveFunction:: constructSpinInfo(vectors3_[1],decay[1],outgoing,true,false); VectorWaveFunction:: constructSpinInfo(gluon_ ,decay[2],outgoing,true,false); return 0.; } // calculate colour factors and number of colour flows unsigned int nflow; vector cfactors = getColourFactors(inpart, decay, nflow); vector ME(nflow,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, PDT::Spin1, PDT::Spin1, PDT::Spin1))); bool massless[2]; for(unsigned int ix=0;ix<2;++ix) massless[ix] = decay[ix]->mass()!=ZERO; // create wavefunctions VectorWaveFunction::calculateWaveFunctions(vectors3_[0],decay[0],outgoing,massless[0]); VectorWaveFunction::calculateWaveFunctions(vectors3_[1],decay[1],outgoing,massless[1]); VectorWaveFunction::calculateWaveFunctions(gluon_ ,decay[2],outgoing,true); // gauge test #ifdef GAUGE_CHECK gluon_.clear(); for(unsigned int ix=0;ix<3;++ix) { if(ix==1) gluon_.push_back(VectorWaveFunction()); else { gluon_.push_back(VectorWaveFunction(decay[2]->momentum(), decay[2]->dataPtr(),10, outgoing)); } } #endif // get the outgoing vertices AbstractVVVVertexPtr outgoingVertex1; AbstractVVVVertexPtr outgoingVertex2; identifyVertices(inpart,decay, outgoingVertex1, outgoingVertex2,inter); Energy2 scale(sqr(inpart.mass())); const GeneralTwoBodyDecayer::CFlow & colourFlow = colourFlows(inpart, decay); double gs(0.); bool couplingSet(false); #ifdef GAUGE_CHECK double total=0.; #endif for(unsigned int iv0 = 0; iv0 < 3; ++iv0) { for(unsigned int iv1 = 0; iv1 < 3; ++iv1) { if(massless[0] && iv1==1) continue; for(unsigned int iv2 = 0; iv2 < 3; ++iv2) { if(massless[1] && iv2==1) continue; for(unsigned int ig = 0; ig < 2; ++ig) { // radiation from the incoming vector if((inpart.dataPtr()->coloured() && inter==ShowerInteraction::QCD) || (inpart.dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(incomingVertex_[inter]); VectorWaveFunction vectorInter = incomingVertex_[inter]->evaluate(scale,3,inpart.dataPtr(),vector3_[iv0], gluon_[2*ig],inpart.mass()); assert(vector3_[iv0].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vectorInter,vectors3_[0][iv1], vectors3_[1][iv2]); if(!couplingSet) { gs = abs(incomingVertex_[inter]->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[0]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex1); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[0]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertex1->evaluate(scale,3,off,gluon_[2*ig],vectors3_[0][iv1],decay[0]->mass()); assert(vectors3_[0][iv1].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv0],vectorInter,vectors3_[1][iv2]); if(!couplingSet) { gs = abs(outgoingVertex1->norm()); couplingSet = true; } for(unsigned int ix=0;ixdataPtr()->coloured() && inter==ShowerInteraction::QCD) || (decay[1]->dataPtr()->charged() && inter==ShowerInteraction::QED) ) { assert(outgoingVertex2); // ensure you get correct outgoing particle from first vertex tcPDPtr off = decay[1]->dataPtr(); if(off->CC()) off = off->CC(); VectorWaveFunction vectorInter = outgoingVertex2->evaluate(scale,3,off, gluon_[2*ig],vectors3_[1][iv2],decay[1]->mass()); assert(vectors3_[1][iv2].particle()->id()==vectorInter.particle()->id()); Complex diag = 0.; for(auto vertex : vertex_) diag += vertex->evaluate(scale,vector3_[iv0],vectors3_[0][iv1],vectorInter); if(!couplingSet) { gs = abs(outgoingVertex2->norm()); couplingSet = true; } for(unsigned int ix=0;ixevaluate(scale,0, vector3_[iv0], vectors3_[0][iv1], vectors3_[1][iv2],gluon_[2*ig]); for(unsigned int ix=0;ixcontract(*ME[iy],rho3_)).real(); } } // divide by alpha_(S,EM) output*=(4.*Constants::pi)/sqr(gs); #ifdef GAUGE_CHECK double ratio = output/total; if(abs(ratio)>1e-20) { generator()->log() << "Test of gauge invariance in decay\n" << inpart << "\n"; for(unsigned int ix=0;ixlog() << *decay[ix] << "\n"; generator()->log() << "Test of gauge invariance " << ratio << "\n"; } #endif // return the answer return output; } void VVVDecayer::identifyVertices(const Particle & inpart, const ParticleVector & decay, AbstractVVVVertexPtr & outgoingVertex1, AbstractVVVVertexPtr & outgoingVertex2, ShowerInteraction inter) { if(inter==ShowerInteraction::QCD) { // work out which scalar each outgoing vertex corresponds to // two outgoing vertices if( inpart.dataPtr() ->iColour()==PDT::Colour0 && ((decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar) || (decay[0]->dataPtr()->iColour()==PDT::Colour8 && decay[1]->dataPtr()->iColour()==PDT::Colour8))){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } else if(inpart.dataPtr() ->iColour()==PDT::Colour8 && decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar){ if(outgoingVertex1_[inter]==outgoingVertex2_[inter]){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else if (outgoingVertex2_[inter]->isIncoming(getParticleData(decay[0]->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } // one outgoing vertex else if(inpart.dataPtr()->iColour()==PDT::Colour3){ if(decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertex1 = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertex1 = outgoingVertex2_[inter]; } else if (decay[0]->dataPtr()->iColour()==PDT::Colour3 && decay[1]->dataPtr()->iColour()==PDT::Colour8){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[1]->dataPtr()->id()))){ outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } else { outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } } } else if(inpart.dataPtr()->iColour()==PDT::Colour3bar){ if(decay[1]->dataPtr()->iColour()==PDT::Colour3bar && decay[0]->dataPtr()->iColour()==PDT::Colour0){ if (outgoingVertex1_[inter]) outgoingVertex2 = outgoingVertex1_[inter]; else if(outgoingVertex2_[inter]) outgoingVertex2 = outgoingVertex2_[inter]; } else if (decay[0]->dataPtr()->iColour()==PDT::Colour8 && decay[1]->dataPtr()->iColour()==PDT::Colour3bar){ if (outgoingVertex1_[inter]->isIncoming(getParticleData(decay[0]->dataPtr()->id()))){ outgoingVertex1 = outgoingVertex1_[inter]; outgoingVertex2 = outgoingVertex2_[inter]; } else { outgoingVertex1 = outgoingVertex2_[inter]; outgoingVertex2 = outgoingVertex1_[inter]; } } } if (! ((incomingVertex_[inter] && (outgoingVertex1 || outgoingVertex2)) || ( outgoingVertex1 && outgoingVertex2))) throw Exception() << "Invalid vertices for QCD radiation in VVV decay in VVVDecayer::identifyVertices" << Exception::runerror; } else { if(decay[0]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[0]->dataPtr()))) outgoingVertex1 = outgoingVertex1_[inter]; else outgoingVertex1 = outgoingVertex2_[inter]; } if(decay[1]->dataPtr()->charged()) { if (outgoingVertex1_[inter] && outgoingVertex1_[inter]->isIncoming(const_ptr_cast(decay[1]->dataPtr()))) outgoingVertex2 = outgoingVertex1_[inter]; else outgoingVertex2 = outgoingVertex2_[inter]; } } } diff --git a/Decay/General/VtoFFVDecayer.cc b/Decay/General/VtoFFVDecayer.cc --- a/Decay/General/VtoFFVDecayer.cc +++ b/Decay/General/VtoFFVDecayer.cc @@ -1,369 +1,371 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the VtoFFVDecayer class. // #include "VtoFFVDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG; using namespace ThePEG::Helicity; IBPtr VtoFFVDecayer::clone() const { return new_ptr(*this); } IBPtr VtoFFVDecayer::fullclone() const { return new_ptr(*this); } void VtoFFVDecayer::persistentOutput(PersistentOStream & os) const { os << sca_ << fer_ << vec_ << ten_; } void VtoFFVDecayer::persistentInput(PersistentIStream & is, int) { is >> sca_ >> fer_ >> vec_ >> ten_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigVtoFFVDecayer("Herwig::VtoFFVDecayer", "Herwig.so"); void VtoFFVDecayer::Init() { static ClassDocumentation documentation ("The VtoFFVDecayer class implements the general three-body " "decay of a vector to a two fermions and a vector."); } WidthCalculatorBasePtr VtoFFVDecayer:: threeBodyMEIntegrator(const DecayMode & ) const { vector intype; vector inmass,inwidth; vector inpow,inweights; constructIntegratorChannels(intype,inmass,inwidth,inpow,inweights); return new_ptr(ThreeBodyAllOnCalculator (inweights,intype,inmass,inwidth,inpow,*this,0, outgoing()[0]->mass(),outgoing()[1]->mass(), outgoing()[2]->mass(),relativeError())); } -void VtoFFVDecayer::doinit() { - GeneralThreeBodyDecayer::doinit(); +void VtoFFVDecayer::setupDiagrams(bool kinCheck) { + GeneralThreeBodyDecayer::setupDiagrams(kinCheck); if(outgoing().empty()) return; unsigned int ndiags = getProcessInfo().size(); sca_.resize(ndiags); fer_.resize(ndiags); vec_.resize(ndiags); ten_.resize(ndiags); for(unsigned int ix = 0;ix < ndiags; ++ix) { TBDiagram current = getProcessInfo()[ix]; tcPDPtr offshell = current.intermediate; if( offshell->CC() ) offshell = offshell->CC(); if(offshell->iSpin() == PDT::Spin0) { AbstractVVSVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFSVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a scalar diagram in VtoFFVDecayer::doinit()" + << "Invalid vertices for a scalar diagram in VtoFFVDecayer::setupDiagrams()" << Exception::runerror; sca_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1Half) { AbstractFFVVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a fermion diagram in VtoFFVDecayer::doinit()" + << "Invalid vertices for a fermion diagram in VtoFFVDecayer::setupDiagrams()" << Exception::runerror; fer_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin1) { AbstractVVVVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFVVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a vector diagram in VtoFFVDecayer::doinit()" + << "Invalid vertices for a vector diagram in VtoFFVDecayer::setupDiagrams()" << Exception::runerror; vec_[ix] = make_pair(vert1, vert2); } else if(offshell->iSpin() == PDT::Spin2) { AbstractVVTVertexPtr vert1 = dynamic_ptr_cast (current.vertices.first); AbstractFFTVertexPtr vert2 = dynamic_ptr_cast (current.vertices.second); if(!vert1||!vert2) throw Exception() - << "Invalid vertices for a tensor diagram in VtoFFVDecayer::doinit()" + << "Invalid vertices for a tensor diagram in VtoFFVDecayer::setupDiagrams()" << Exception::runerror; ten_[ix] = make_pair(vert1, vert2); } } } double VtoFFVDecayer::me2(const int ichan, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // particle or CC of particle bool cc = (*getProcessInfo().begin()).incoming != inpart.id(); // special handling or first/last call if(meopt==Initialize) { VectorWaveFunction:: calculateWaveFunctions(inVector_,rho_,const_ptr_cast(&inpart), Helicity::incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction:: constructSpinInfo(inVector_,const_ptr_cast(&inpart), Helicity::incoming,true,false); for(unsigned int ix=0;ixdataPtr()->iSpin()==PDT::Spin1) { VectorWaveFunction::constructSpinInfo(outVector_,decay[ix], Helicity::outgoing,true,false); } else { SpinorWaveFunction:: constructSpinInfo(outspin_[ix].first,decay[ix],Helicity::outgoing,true); } } } unsigned int ivec(0); bool massless = false; for(unsigned int ix = 0; ix < decay.size();++ix) { if(decay[ix]->dataPtr()->iSpin() == PDT::Spin1) { massless = decay[ix]->id()==ParticleID::g || decay[ix]->id()==ParticleID::gamma; ivec = ix; VectorWaveFunction:: calculateWaveFunctions(outVector_, decay[ix], Helicity::outgoing, massless ); } else { SpinorWaveFunction:: calculateWaveFunctions(outspin_[ix].first,decay[ix],Helicity::outgoing); outspin_[ix].second.resize(2); // Need a ubar and a v spinor if(outspin_[ix].first[0].wave().Type() == SpinorType::u) { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].first[iy].conjugate(); } } else { for(unsigned int iy = 0; iy < 2; ++iy) { outspin_[ix].second[iy] = outspin_[ix].first[iy].bar(); outspin_[ix].second[iy].conjugate(); } } } } const vector > cfactors(getColourFactors()); const vector > nfactors(getLargeNcColourFactors()); Energy2 scale(sqr(inpart.mass())); const size_t ncf(numberOfFlows()); vector flows(ncf, Complex(0.)), largeflows(ncf, Complex(0.)); // setup the DecayMatrixElement vector mes(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, ivec == 0 ? PDT::Spin1 : PDT::Spin1Half, ivec == 1 ? PDT::Spin1 : PDT::Spin1Half, ivec == 2 ? PDT::Spin1 : PDT::Spin1Half))); vector mel(ncf,new_ptr(GeneralDecayMatrixElement(PDT::Spin1, ivec == 0 ? PDT::Spin1 : PDT::Spin1Half, ivec == 1 ? PDT::Spin1 : PDT::Spin1Half, ivec == 2 ? PDT::Spin1 : PDT::Spin1Half))); //the channel possiblities static const unsigned int out2[3] = {1,0,0}, out3[3] = {2,2,1}; for(unsigned int vi = 0; vi < 3; ++vi) { for(unsigned int s1 = 0; s1 < 2; ++s1) { for(unsigned int s2 = 0; s2 < 2; ++s2) { for(unsigned int v1 = 0; v1 < 3; ++v1) { if ( massless && v1 == 1 ) continue; flows = vector(ncf, Complex(0.)); largeflows = vector(ncf, Complex(0.)); unsigned int idiag(0); for(vector::const_iterator dit=getProcessInfo().begin(); dit!=getProcessInfo().end();++dit) { // channels if selecting if( ichan >=0 && diagramMap()[ichan] != idiag ) { ++idiag; continue; } tcPDPtr offshell = dit->intermediate; if(cc&&offshell->CC()) offshell=offshell->CC(); Complex diag; unsigned int o2(out2[dit->channelType]), o3(out3[dit->channelType]); double sign = (o3 < o2) ? 1. : -1.; // intermediate scalar if(offshell->iSpin() == PDT::Spin0) { ScalarWaveFunction inters = sca_[idiag].first-> evaluate(scale, widthOption(), offshell, outVector_[v1], inVector_[vi]); unsigned int h1(s1),h2(s2); if(o2 > o3) swap(h1, h2); if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag = -sign*sca_[idiag].second-> evaluate(scale,outspin_[o2].first[h1], outspin_[o3].second[h2],inters); } else { diag = sign*sca_[idiag].second-> evaluate(scale, outspin_[o3].first [h2], outspin_[o2].second[h1],inters); } } // intermediate fermion else if(offshell->iSpin() == PDT::Spin1Half) { int iferm = (decay[o2]->dataPtr()->iSpin() == PDT::Spin1Half) ? o2 : o3; unsigned int h1(s1),h2(s2); if(dit->channelType > iferm) swap(h1, h2); sign = iferm < dit->channelType ? 1. : -1.; if(decay[dit->channelType]->id() < 0 && decay[iferm]->id() > 0 ) { SpinorWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].first[h1], inVector_[vi]); diag = -sign*fer_[idiag].second-> evaluate(scale,inters,outspin_[iferm].second[h2], outVector_[v1]); } else { SpinorBarWaveFunction inters = fer_[idiag].first-> evaluate(scale,widthOption(),offshell, outspin_[dit->channelType].second[h1],inVector_[vi]); diag = sign*fer_[idiag].second-> evaluate(scale,outspin_[iferm].first [h2],inters, outVector_[v1]); } } // intermediate vector else if(offshell->iSpin() == PDT::Spin1) { VectorWaveFunction interv = vec_[idiag].first-> evaluate(scale, widthOption(), offshell, outVector_[v1], inVector_[vi]); unsigned int h1(s1),h2(s2); if(o2 > o3) swap(h1,h2); if(decay[o2]->id() < 0 && decay[o3]->id() > 0) { diag =-sign*vec_[idiag].second-> evaluate(scale, outspin_[o2].first[h1], outspin_[o3].second[h2], interv); } else { diag = sign*vec_[idiag].second-> evaluate(scale, outspin_[o3].first[h2], outspin_[o2].second[h1], interv); } } else if(offshell->iSpin() == PDT::Spin2) { TensorWaveFunction intert = ten_[idiag].first-> evaluate(scale, widthOption(), offshell, inVector_[vi], outVector_[v1]); unsigned int h1(s1),h2(s2); if(out2[dit->channelType]>out3[dit->channelType]) swap(h1,h2); if(decay[out2[dit->channelType]]->id()<0&& decay[out3[dit->channelType]]->id()>0) { diag =-sign*ten_[idiag].second-> evaluate(scale, outspin_[out2[dit->channelType]].first [h1], outspin_[out3[dit->channelType]].second[h2],intert); } else { diag = sign*ten_[idiag].second-> evaluate(scale, outspin_[out3[dit->channelType]].first [h2], outspin_[out2[dit->channelType]].second[h1],intert); } } // unknown else throw Exception() << "Unknown intermediate in VtoFFVDecayer::me2()" << Exception::runerror; // matrix element for the different colour flows if(ichan < 0) { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } else { for(unsigned iy = 0; iy < dit->colourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1 != colourFlow()) continue; flows[dit->colourFlow[iy].first - 1] += dit->colourFlow[iy].second * diag; } for(unsigned iy = 0; iy < dit->largeNcColourFlow.size(); ++iy) { if(dit->colourFlow[iy].first - 1!=colourFlow()) continue; largeflows[dit->largeNcColourFlow[iy].first - 1] += dit->largeNcColourFlow[iy].second * diag; } } ++idiag; } //end of diagrams // now add the flows to the me2 with appropriate colour factors for(unsigned int ix = 0; ix < ncf; ++ix) { if (ivec == 0) { (*mes[ix])(vi, v1, s1, s2) = flows[ix]; (*mel[ix])(vi, v1, s1, s2) = largeflows[ix]; } else if(ivec == 1) { (*mes[ix])(vi, s1, v1, s2) = flows[ix]; (*mel[ix])(vi, s1, v1, s2) = largeflows[ix]; } else if(ivec == 2) { (*mes[ix])(vi, s1, s2, v1) = flows[ix]; (*mel[ix])(vi, s1, s2, v1) = largeflows[ix]; } } } } } } double me2(0.); if(ichan < 0) { vector pflows(ncf,0.); for(unsigned int ix = 0; ix < ncf; ++ix) { for(unsigned int iy = 0; iy < ncf; ++ iy) { double con = cfactors[ix][iy]*(mes[ix]->contract(*mes[iy],rho_)).real(); me2 += con; if(ix == iy) { con = nfactors[ix][iy]*(mel[ix]->contract(*mel[iy],rho_)).real(); pflows[ix] += con; } } } double ptotal(std::accumulate(pflows.begin(),pflows.end(),0.)); ptotal *= UseRandom::rnd(); for(unsigned int ix = 0;ix < pflows.size(); ++ix) { if(ptotal <= pflows[ix]) { colourFlow(ix); ME(mes[ix]); break; } ptotal -= pflows[ix]; } } else { unsigned int iflow = colourFlow(); me2 = nfactors[iflow][iflow]*(mel[iflow]->contract(*mel[iflow],rho_)).real(); } // return the matrix element squared return me2; } diff --git a/Decay/General/VtoFFVDecayer.h b/Decay/General/VtoFFVDecayer.h --- a/Decay/General/VtoFFVDecayer.h +++ b/Decay/General/VtoFFVDecayer.h @@ -1,161 +1,156 @@ // -*- C++ -*- #ifndef THEPEG_VtoFFVDecayer_H #define THEPEG_VtoFFVDecayer_H // // This is the declaration of the VtoFFVDecayer class. // #include "GeneralThreeBodyDecayer.h" #include "ThePEG/Helicity/Vertex/AbstractFFSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFVVertex.h" #include "ThePEG/Helicity/Vertex/AbstractFFTVertex.h" #include "ThePEG/Helicity/Vertex/AbstractVVVVertex.h" #include "ThePEG/Helicity/Vertex/AbstractVVSVertex.h" #include "ThePEG/Helicity/Vertex/AbstractVVTVertex.h" namespace Herwig { using namespace ThePEG; /** * Here is the documentation of the VtoFFVDecayer class. * * @see \ref VtoFFVDecayerInterfaces "The interfaces" * defined for VtoFFVDecayer. */ class VtoFFVDecayer: public GeneralThreeBodyDecayer { public: /** * Return the matrix element squared for a given mode and phase-space channel * @param ichan The channel we are calculating the matrix element for. * @param part The decaying Particle. * @param decay The particles produced in the decay. * @param meopt Option for the matrix element * @return The matrix element squared for the phase-space configuration. */ virtual double me2(const int ichan, const Particle & part, const ParticleVector & decay, MEOption meopt) const; /** * Method to return an object to calculate the 3 (or higher body) partial width * @param dm The DecayMode * @return A pointer to a WidthCalculatorBase object capable of * calculating the width */ virtual WidthCalculatorBasePtr threeBodyMEIntegrator(const DecayMode & dm) const; 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(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(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 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 IBPtr fullclone() const; //@} protected: - /** @name Standard Interfaced functions. */ - //@{ /** - * Initialize this object after the setup phase before saving an - * EventGenerator to disk. - * @throws InitException if object could not be initialized properly. + * Set up the diagrams etc */ - virtual void doinit(); - //@} + virtual void setupDiagrams(bool checkKinematics); private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ VtoFFVDecayer & operator=(const VtoFFVDecayer &); private: /** * Store the vertices for scalar intrermediate */ vector > sca_; /** * Store the vertices for fermion intrermediate */ vector > fer_; /** * Store the vertices for vector intrermediate */ vector > vec_; /** * Store the vertices for vector intrermediate */ vector > ten_; /** * Spinr density matrix */ mutable RhoDMatrix rho_; /** * Polarization vectors for the decaying particle */ mutable vector inVector_; /** * Scalar wavefunction for the decay products */ mutable ScalarWaveFunction swave_; /** * Polarization vectors for the decay products */ mutable vector outVector_; /** * Spinors for the decay products */ mutable pair,vector > outspin_[3]; }; } #endif /* THEPEG_VtoFFVDecayer_H */ diff --git a/Decay/HwDecayerBase.cc b/Decay/HwDecayerBase.cc --- a/Decay/HwDecayerBase.cc +++ b/Decay/HwDecayerBase.cc @@ -1,156 +1,163 @@ // -*- C++ -*- // // HwDecayerBase.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 HwDecayerBase class. // #include "HwDecayerBase.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "Herwig/Shower/RealEmissionProcess.h" +#include "Herwig/Shower/ShowerHandler.h" using namespace Herwig; bool HwDecayerBase::accept(const DecayMode & dm) const { // get the primary products tPDVector products=dm.orderedProducts(); // add products for which the decay mode is all ready specified if(!dm.cascadeProducts().empty()) { for(ModeMSet::const_iterator mit=dm.cascadeProducts().begin(); mit!=dm.cascadeProducts().end();++mit) { products.push_back(const_ptr_cast((**mit).parent())); } } // can this mode be handled ? return accept(dm.parent(),products); } ParticleVector HwDecayerBase::decay(const DecayMode & dm, const Particle & p) const { // handling of the decay including the special features of the // DecayMode // get the primary products tPDVector products=dm.orderedProducts(); // add products for which the decay mode is all ready specified if(!dm.cascadeProducts().empty()) { for(ModeMSet::const_iterator mit=dm.cascadeProducts().begin(); mit!=dm.cascadeProducts().end();++mit) { products.push_back(const_ptr_cast((**mit).parent())); } } // perform the primary decay ParticleVector output=decay(p,products); // perform the secondary decays if(!dm.cascadeProducts().empty()) { unsigned int iloc=dm.orderedProducts().size(); for(ModeMSet::const_iterator mit=dm.cascadeProducts().begin(); mit!=dm.cascadeProducts().end();++mit) { if(!(*mit)->decayer()) throw Exception() << "Decay mode " << (**mit).tag() << "does not have a decayer, can't perform" << "decay in HwDecayerBase::decay()" << Exception::eventerror; ParticleVector children=(*mit)->decayer()->decay(**mit,*output[iloc]); for(unsigned int ix=0;ixaddChild(children[ix]); } ++iloc; } } return output; } void HwDecayerBase::persistentOutput(PersistentOStream & os) const { os << _initialize << _dbOutput; } void HwDecayerBase::persistentInput(PersistentIStream & is, int) { is >> _initialize >> _dbOutput; } // The following static variable is needed for the type // description system in ThePEG. DescribeAbstractClass describeHerwigHwDecayerBase("Herwig::HwDecayerBase", "Herwig.so"); void HwDecayerBase::Init() { static ClassDocumentation documentation ("The HwDecayerBase class is the base class for Decayers in Hw++."); static Switch interfaceInitialize ("Initialize", "Initialization of the phase space calculation", &HwDecayerBase::_initialize, false, false, false); static SwitchOption interfaceInitializeon (interfaceInitialize, "Yes", "At initialisation find max weight and optimise the integration", true); static SwitchOption interfaceInitializeoff (interfaceInitialize, "No", "Use the maximum weight and channel weights supplied for the integration", false); static Switch interfaceDatabaseOutput ("DatabaseOutput", "Whether to print the database information", &HwDecayerBase::_dbOutput, false, false, false); static SwitchOption interfaceDatabaseOutputYes (interfaceDatabaseOutput, "Yes", "Output information on the decayer initialization", true); static SwitchOption interfaceDatabaseOutputNo (interfaceDatabaseOutput, "No", "Do not output information about the decayer initialization", false); } void HwDecayerBase::dofinish() { Decayer::dofinish(); if(initialize() && databaseOutput()) { string fname = CurrentGenerator::current().filename() + string("-") + name() + string(".output"); ofstream output(fname.c_str()); dataBaseOutput(output,true); } } bool HwDecayerBase::softMatrixElementVeto(PPtr , PPtr, const bool &, const Energy & , const vector & , const double & , const Energy & , const Energy & ) { return false; } RealEmissionProcessPtr HwDecayerBase::generateHardest(RealEmissionProcessPtr) { return RealEmissionProcessPtr(); } void HwDecayerBase::initializeMECorrection(RealEmissionProcessPtr , double & , double & ) { assert(false); } RealEmissionProcessPtr HwDecayerBase::applyHardMatrixElementCorrection(RealEmissionProcessPtr) { assert(false); return RealEmissionProcessPtr(); } + +void HwDecayerBase::fixRho(RhoDMatrix & rho) const { + if(ShowerHandler::currentHandlerIsSet() && + !ShowerHandler::currentHandler()->spinCorrelations()) + rho.reset(); +} diff --git a/Decay/HwDecayerBase.h b/Decay/HwDecayerBase.h --- a/Decay/HwDecayerBase.h +++ b/Decay/HwDecayerBase.h @@ -1,237 +1,244 @@ // -*- C++ -*- // // HwDecayerBase.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_HwDecayerBase_H #define HERWIG_HwDecayerBase_H // // This is the declaration of the HwDecayerBase class. // #include "ThePEG/PDT/Decayer.h" #include "Herwig/Shower/RealEmissionProcess.fh" #include "HwDecayerBase.fh" namespace Herwig { struct Branching; using namespace ThePEG; /** * The HwDecayerBase class is the base class for Decayers in Herwig. It inherits * from the Decayer class of ThePEG and implements additional functionality for the * output of the results to the particle database and initialization of the datbase. * * It also provide the option of specifying a class based on the DecayRadiationGenerator * which should be used to generate QED radiation in the decay * * @see \ref HwDecayerBaseInterfaces "The interfaces" * defined for HwDecayerBase. */ class HwDecayerBase: public Decayer { public: /** * The default constructor. */ HwDecayerBase() : _initialize(false), _dbOutput(false) {} /** @name Virtual functions required by the Decayer class. */ //@{ /** * Check if this decayer can perfom the decay specified by the * given decay mode. * @param dm the DecayMode describing the decay. * @return true if this decayer can handle the given mode, otherwise false. */ virtual bool accept(const DecayMode & dm) const; /** * Perform a decay for a given DecayMode and a given Particle instance. * @param dm the DecayMode describing the decay. * @param p the Particle instance to be decayed. * @return a ParticleVector containing the decay products. */ virtual ParticleVector decay(const DecayMode & dm, const Particle & p) const; //@} public: /** * Virtual members to be overridden by inheriting classes * which implement hard corrections */ //@{ /** * Type of POWHEG correction */ enum POWHEGType {No, ISR, FSR, Both}; /** * Has a POWHEG style correction */ virtual POWHEGType hasPOWHEGCorrection() {return No;} /** * Has an old fashioned ME correction */ virtual bool hasMECorrection() {return false;} /** * Initialize the ME correction */ virtual void initializeMECorrection(RealEmissionProcessPtr , double & , double & ); /** * Apply the hard matrix element correction to a given hard process or decay */ virtual RealEmissionProcessPtr applyHardMatrixElementCorrection(RealEmissionProcessPtr); /** * Apply the soft matrix element correction * @param parent The initial particle in the current branching * @param progenitor The progenitor particle of the jet * @param fs Whether the emission is initial or final-state * @param highestpT The highest pT so far in the shower * @param ids ids of the particles produced in the branching * @param z The momentum fraction of the branching * @param scale the evolution scale of the branching * @param pT The transverse momentum of the branching * @return If true the emission should be vetoed */ virtual bool softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & fs, const Energy & highestpT, const vector & ids, const double & z, const Energy & scale, const Energy & pT); /** * Apply the POWHEG style correction */ virtual RealEmissionProcessPtr generateHardest(RealEmissionProcessPtr); //@} protected: /** @name Virtual functions to replaced those from the Decayer class. * This is so that the decay and accept members of this class can handle all * the more complicated features of the DecayMode class */ //@{ /** * Check if this decayer can perfom the decay for a particular mode * @param parent The decaying particle * @param children The decay products * @return true If this decayer can handle the given mode, otherwise false. */ virtual bool accept(tcPDPtr parent, const tPDVector & children) const = 0; /** * Perform the decay of the particle to the specified decay products * @param parent The decaying particle * @param children The decay products * @return a ParticleVector containing the decay products. */ virtual ParticleVector decay(const Particle & parent, const tPDVector & children) const = 0; //@} 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(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(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(); public: /** * Functions for the Herwig decayer */ //@{ /** * Output the setup information for the particle database * @param os The stream to output the information to * @param header Whether or not to output the information for MySQL */ virtual void dataBaseOutput(ofstream & os,bool header) const = 0; /** * Access to the initialize variable */ bool initialize() const {return _initialize;} /** * Access the database output variable */ bool databaseOutput() const {return _dbOutput;} //@} protected: + /** + * Set rho to be diagonal if no correlations + */ + void fixRho(RhoDMatrix &) const; + +protected: + /** @name Standard Interfaced functions. */ //@{ /** * 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 assignment operator is private and must never be called. * In fact, it should not even be implemented. */ HwDecayerBase & operator=(const HwDecayerBase &); private: /** * perform initialisation */ bool _initialize; /** * Print out database */ bool _dbOutput; }; } #endif /* HERWIG_HwDecayerBase_H */ diff --git a/Decay/Perturbative/SMHiggsFermionsDecayer.cc b/Decay/Perturbative/SMHiggsFermionsDecayer.cc --- a/Decay/Perturbative/SMHiggsFermionsDecayer.cc +++ b/Decay/Perturbative/SMHiggsFermionsDecayer.cc @@ -1,393 +1,395 @@ // -*- C++ -*- // // SMHiggsFermionsDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SMHiggsFermionsDecayer class. // #include "SMHiggsFermionsDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/ScalarSpinInfo.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "Herwig/Utilities/Maths.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Shower/ShowerAlpha.h" using namespace Herwig; using namespace ThePEG::Helicity; SMHiggsFermionsDecayer::SMHiggsFermionsDecayer() : CF_(4./3.), NLO_(false) { _maxwgt.resize(9); _maxwgt[0]=0.; _maxwgt[1]=0; _maxwgt[2]=0; _maxwgt[3]=0.0194397; _maxwgt[4]=0.463542; _maxwgt[5]=0.; _maxwgt[6]=6.7048e-09; _maxwgt[7]=0.00028665; _maxwgt[8]=0.0809643; } void SMHiggsFermionsDecayer::doinit() { PerturbativeDecayer::doinit(); // get the vertices from the Standard Model object tcHwSMPtr hwsm=dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "SMHiggsFermionsDecayer needs the StandardModel class" << " to be either the Herwig one or a class inheriting" << " from it"; _hvertex = hwsm->vertexFFH(); // make sure they are initialized _hvertex->init(); // get the width generator for the higgs tPDPtr higgs = getParticleData(ParticleID::h0); // set up the decay modes vector wgt(0); unsigned int imode=0; tPDVector extpart(3); DecayPhaseSpaceModePtr mode; int iy; extpart[0]=higgs; for(unsigned int istep=0;istep<11;istep+=10) { for(unsigned ix=1;ix<7;++ix) { if(istep<10||ix%2!=0) { iy = ix+istep; extpart[1]=getParticleData( iy); extpart[2]=getParticleData(-iy); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,_maxwgt[imode],wgt); ++imode; } } } // Energy quarkMass = getParticleData(ParticleID::b )->mass(); // Energy higgsMass = getParticleData(ParticleID::h0)->mass(); // double mu = quarkMass/higgsMass; // double beta = sqrt(1.-4.*sqr(mu)); // double beta2 = sqr(beta); // double aS = SM().alphaS(sqr(higgsMass)); // double L = log((1.+beta)/(1.-beta)); // cerr << "testing " << beta << " " << mu << "\n"; // cerr << "testing " << aS << " " << L << "\n"; // double fact = // 6.-0.75*(1.+beta2)/beta2+12.*log(mu)-8.*log(beta) // +(5./beta-2.*beta+0.375*sqr(1.-beta2)/beta2/beta)*L // +(1.+beta2)/beta*(4.*L*log(0.5*(1.+beta)/beta) // -2.*log(0.5*(1.+beta))*log(0.5*(1.-beta)) // +8.*Herwig::Math::ReLi2((1.-beta)/(1.+beta)) // -4.*Herwig::Math::ReLi2(0.5*(1.-beta))); // cerr << "testing correction " // << 1.+4./3.*aS/Constants::twopi*fact // << "\n"; // double real = 4./3.*aS/Constants::twopi* // (8.-0.75*(1.+beta2)/beta2+8.*log(mu)-8.*log(beta) // +(3./beta+0.375*sqr(1.-beta2)/pow(beta,3))*L // +(1.+beta2)/beta*(-0.5*sqr(L)+4.*L*log(0.5*(1.+beta)) // -2.*L*log(beta)-2.*log(0.5*(1.+beta))*log(0.5*(1.-beta)) // +6.*Herwig::Math::ReLi2((1.-beta)/(1.+beta)) // -4.*Herwig::Math::ReLi2(0.5*(1.-beta)) // -2./3.*sqr(Constants::pi))); // double virt = 4./3.*aS/Constants::twopi* // (-2.+4.*log(mu)+(2./beta-2.*beta)*L // +(1.+beta2)/beta*(0.5*sqr(L)-2.*L*log(beta)+2.*sqr(Constants::pi)/3. // +2.*Herwig::Math::ReLi2((1.-beta)/(1.+beta)))); // cerr << "testing real " << real << "\n"; // cerr << "testing virtual " << virt << "\n"; // cerr << "testing total no mb corr " << 1.+real+virt << "\n"; // cerr << "testing total mb corr " << 1.+real+virt +(8./3. - 2.*log(sqr(mu)))*aS/Constants::pi << "\n"; // InvEnergy2 Gf = 1.166371e-5/GeV2; // Gf = sqrt(2.)*4*Constants::pi*SM().alphaEM(sqr(higgsMass))/8./SM().sin2ThetaW()/ // sqr(getParticleData(ParticleID::Wplus)->mass()); // cerr << "testing GF " << Gf*GeV2 << "\n"; // Energy LO = (3./8./Constants::pi)*sqrt(2)*sqr(quarkMass)*Gf*higgsMass*beta*beta*beta; // cerr << "testing LO " << LO/GeV << "\n"; // cerr << "testing quark mass " << quarkMass/GeV << "\n"; // cerr << "testing gamma " << (1.+real+virt)*LO/MeV << "\n"; } bool SMHiggsFermionsDecayer::accept(tcPDPtr parent, const tPDVector & children) const { if(parent->id()!=ParticleID::h0||children.size()!=2) return false; tPDVector::const_iterator pit = children.begin(); int id1=(**pit).id(); ++pit; int id2=(**pit).id(); if(id1==-id2&&(abs(id1)<=6||(abs(id1)>=11&&abs(id1)<=16))) return true; else return false; } ParticleVector SMHiggsFermionsDecayer::decay(const Particle & parent, const tPDVector & children) const { // id's of the decaying particles tPDVector::const_iterator pit(children.begin()); int id1((**pit).id()); int imode=-1; if(abs(id1)<=6) imode = abs(id1)-1; else if(abs(id1)>=11&&abs(id1)<=16) imode = (abs(id1)-11)/2+6; ParticleVector output(generate(false,false,imode,parent)); // set up the colour flow if(output[0]->hasColour()) output[0]->antiColourNeighbour(output[1]); else if(output[1]->hasColour()) output[1]->antiColourNeighbour(output[0]); return output; } void SMHiggsFermionsDecayer::persistentOutput(PersistentOStream & os) const { os << _maxwgt << _hvertex << NLO_; } void SMHiggsFermionsDecayer::persistentInput(PersistentIStream & is, int) { is >> _maxwgt >> _hvertex >> NLO_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMHiggsFermionsDecayer("Herwig::SMHiggsFermionsDecayer", "HwPerturbativeHiggsDecay.so"); void SMHiggsFermionsDecayer::Init() { static ClassDocumentation documentation ("The SMHiggsFermionsDecayer class implements the decat of the Standard Model" " Higgs boson to the Standard Model fermions"); static ParVector interfaceMaxWeights ("MaxWeights", "Maximum weights for the various decays", &SMHiggsFermionsDecayer::_maxwgt, 9, 1.0, 0.0, 10.0, false, false, Interface::limited); static Switch interfaceNLO ("NLO", "Whether to return the LO or NLO result", &SMHiggsFermionsDecayer::NLO_, false, false, false); static SwitchOption interfaceNLOLO (interfaceNLO, "No", "Leading-order result", false); static SwitchOption interfaceNLONLO (interfaceNLO, "Yes", "NLO result", true); } // return the matrix element squared double SMHiggsFermionsDecayer::me2(const int, const Particle & part, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin1Half))); int iferm(1),ianti(0); if(decay[0]->id()>0) swap(iferm,ianti); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(_rho,const_ptr_cast(&part),incoming); _swave = ScalarWaveFunction(part.momentum(),part.dataPtr(),incoming); + // fix rho if no correlations + fixRho(_rho); } if(meopt==Terminate) { ScalarWaveFunction::constructSpinInfo(const_ptr_cast(&part), incoming,true); SpinorBarWaveFunction:: constructSpinInfo(_wavebar,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(_wave ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(_wavebar,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(_wave ,decay[ianti],outgoing); Energy2 scale(sqr(part.mass())); unsigned int ifm,ia; for(ifm=0;ifm<2;++ifm) { for(ia=0;ia<2;++ia) { if(iferm>ianti) (*ME())(0,ia,ifm)=_hvertex->evaluate(scale,_wave[ia], _wavebar[ifm],_swave); else (*ME())(0,ifm,ia)=_hvertex->evaluate(scale,_wave[ia], _wavebar[ifm],_swave); } } int id = abs(decay[0]->id()); double output=(ME()->contract(_rho)).real()*UnitRemoval::E2/scale; if(id <=6) output*=3.; // test of the partial width // Ptr::transient_const_pointer // hwsm=dynamic_ptr_cast::transient_const_pointer>(standardModel()); // double g2(hwsm->alphaEM(scale)*4.*Constants::pi/hwsm->sin2ThetaW()); // Energy mass(hwsm->mass(scale,decay[0]->dataPtr())), // mw(getParticleData(ParticleID::Wplus)->mass()); // double beta(sqrt(1.-4.*decay[0]->mass()*decay[0]->mass()/scale)); // cerr << "testing alpha " << hwsm->alphaEM(scale) << "\n"; // Energy test(g2*mass*mass*beta*beta*beta*part.mass()/32./Constants::pi/mw/mw); // if(abs(decay[0]->id())<=6){test *=3.;} // cout << "testing the answer " << output << " " // << test/GeV // << endl; // leading-order result if(!NLO_) return output; // fermion mass Energy particleMass = decay[0]->dataPtr()->mass(); // check decay products coloured, otherwise return if(!decay[0]->dataPtr()->coloured()|| particleMass==ZERO) return output; // inital masses, couplings etc // higgs mass mHiggs_ = part.mass(); // strong coupling aS_ = SM().alphaS(sqr(mHiggs_)); // reduced mass mu_ = particleMass/mHiggs_; mu2_ = sqr(mu_); // generate y double yminus = 0.; double yplus = 1.-2.*mu_*(1.-mu_)/(1.-2*mu2_); double y = yminus + UseRandom::rnd()*(yplus-yminus); //generate z for D31,2 double v = sqrt(sqr(2.*mu2_+(1.-2.*mu2_)*(1.-y))-4.*mu2_)/(1.-2.*mu2_)/(1.-y); double zplus = (1.+v)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y); double zminus = (1.-v)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y); double z = zminus + UseRandom::rnd()*(zplus-zminus); // map y,z to x1,x2 for both possible emissions double x2 = 1. - y*(1.-2.*mu2_); double x1 = 1. - z*(x2-2.*mu2_); //get the dipoles InvEnergy2 D1 = dipoleSubtractionTerm( x1, x2); InvEnergy2 D2 = dipoleSubtractionTerm( x2, x1); InvEnergy2 dipoleSum = abs(D1) + abs(D2); //jacobian double jac = (1.-y)*(yplus-yminus)*(zplus-zminus); //calculate real Energy2 realPrefactor = 0.25*sqr(mHiggs_)*sqr(1.-2.*mu2_) /sqrt(calculateLambda(1,mu2_,mu2_))/sqr(Constants::twopi); InvEnergy2 realEmission = 4.*Constants::pi*aS_*CF_*calculateRealEmission( x1, x2); // calculate the virtual double virtualTerm = calculateVirtualTerm(); // running mass correction virtualTerm += (8./3. - 2.*log(mu2_))*aS_/Constants::pi; //answer = (born + virtual + real)/born * LO output *= 1. + virtualTerm + 2.*jac*realPrefactor*(realEmission*abs(D1)/dipoleSum - D1); // return the answer return output; } void SMHiggsFermionsDecayer::dataBaseOutput(ofstream & os,bool header) const { if(header) os << "update decayers set parameters=\""; // parameters for the PerturbativeDecayer base class for(unsigned int ix=0;ix<_maxwgt.size();++ix) { os << "newdef " << name() << ":MaxWeights " << ix << " " << _maxwgt[ix] << "\n"; } PerturbativeDecayer::dataBaseOutput(os,false); if(header) os << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl; } void SMHiggsFermionsDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); } } } //calculate lambda double SMHiggsFermionsDecayer::calculateLambda(double x, double y, double z) const{ return sqr(x)+sqr(y)+sqr(z)-2.*x*y-2.*x*z-2.*y*z; } //calculates the dipole subtraction term for x1, D31,2 (Dij,k), // 2 is the spectator anti-fermion and 3 is the gluon InvEnergy2 SMHiggsFermionsDecayer:: dipoleSubtractionTerm(double x1, double x2) const{ InvEnergy2 commonPrefactor = CF_*8.*Constants::pi*aS_/sqr(mHiggs_); return commonPrefactor/(1.-x2)* (2.*(1.-2.*mu2_)/(2.-x1-x2)- sqrt((1.-4.*mu2_)/(sqr(x2)-4.*mu2_))* (x2-2.*mu2_)*(2.+(x1-1.)/(x2-2.*mu2_)+2.*mu2_/(1.-x2))/(1.-2.*mu2_)); } //return ME for real emission InvEnergy2 SMHiggsFermionsDecayer:: calculateRealEmission(double x1, double x2) const { InvEnergy2 prefactor = 2./sqr(mHiggs_)/(1.-4.*mu2_); return prefactor*(2. + (1.-x1)/(1.-x2) + (1.-x2)/(1.-x1) + 2.*(1.-2.*mu2_)*(1.-4.*mu2_)/(1.-x1)/(1.-x2) - 2.*(1.-4.*mu2_)*(1./(1.-x2)+1./(1.-x1)) - 2.*mu2_*(1.-4.*mu2_)*(1./sqr(1.-x2)+1./sqr(1.-x1))); } double SMHiggsFermionsDecayer:: calculateVirtualTerm() const { // logs and prefactors double beta = sqrt(1.-4.*mu2_); double L = log((1.+beta)/(1.-beta)); double prefactor = CF_*aS_/Constants::twopi; // non-singlet piece double nonSingletTerm = calculateNonSingletTerm(beta, L); double virtualTerm = -2.+4.*log(mu_)+(2./beta - 2.*beta)*L + (2.-4.*mu2_)/beta*(0.5*sqr(L) - 2.*L*log(beta) + 2.*Herwig::Math::ReLi2((1.-beta)/(1.+beta)) + 2.*sqr(Constants::pi)/3.); double iEpsilonTerm = 2.*(3.-sqr(Constants::pi)/2. + 0.5*log(mu2_) - 1.5*log(1.-2.*mu2_) -(1.-2.*mu2_)/beta*(0.5*sqr(L)+sqr(Constants::pi)/6. -2.*L*log(1.-2.*mu2_)) + nonSingletTerm); return prefactor*(virtualTerm+iEpsilonTerm); } //non-singlet piece of I(epsilon) insertion operator double SMHiggsFermionsDecayer:: calculateNonSingletTerm(double beta, double L) const { return 1.5*log(1.-2.*mu2_) + (1.-2.*mu2_)/beta*(- 2.*L*log(4.*(1.-2.*mu2_)/sqr(1.+beta))+ + 2.*Herwig::Math::ReLi2(sqr((1.-beta)/(1.+beta))) - 2.*Herwig::Math::ReLi2(2.*beta/(1.+beta)) - sqr(Constants::pi)/6.) + log(1.-mu_) - 2.*log(1.-2.*mu_) - 2.*mu2_/(1.-2.*mu2_)*log(mu_/(1.-mu_)) - mu_/(1.-mu_) + 2.*mu_*(2*mu_-1.)/(1.-2.*mu2_) + 0.5*sqr(Constants::pi); } double SMHiggsFermionsDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption, ShowerInteraction inter) { mHiggs_ = inpart.mass(); mu_ = decay2[0]->mass()/mHiggs_; mu2_ = sqr(mu_); double x1 = 2.*decay3[0]->momentum().t()/mHiggs_; double x2 = 2.*decay3[1]->momentum().t()/mHiggs_; double pre = inter==ShowerInteraction::QCD ? CF_ : sqr(double(decay2[0]->dataPtr()->iCharge())/3.); return pre*calculateRealEmission(x1,x2)*4.*Constants::pi*sqr(mHiggs_); } diff --git a/Decay/Perturbative/SMHiggsGGHiggsPPDecayer.cc b/Decay/Perturbative/SMHiggsGGHiggsPPDecayer.cc --- a/Decay/Perturbative/SMHiggsGGHiggsPPDecayer.cc +++ b/Decay/Perturbative/SMHiggsGGHiggsPPDecayer.cc @@ -1,424 +1,426 @@ // -*- C++ -*- // // SMHiggsGGHiggsPPDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SMHiggsGGHiggsPPDecayer class. // #include "SMHiggsGGHiggsPPDecayer.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Helicity/WaveFunction/ScalarWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "Herwig/Utilities/HiggsLoopFunctions.h" using namespace Herwig; using namespace Herwig::HiggsLoopFunctions; using namespace ThePEG::Helicity; // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMHiggsGGHiggsPPDecayer("Herwig::SMHiggsGGHiggsPPDecayer", "HwPerturbativeHiggsDecay.so"); bool SMHiggsGGHiggsPPDecayer::accept(tcPDPtr parent, const tPDVector & children) const { int idp = parent->id(); int id0 = children[0]->id(); int id1 = children[1]->id(); if((idp == ParticleID::h0 && id0 == ParticleID::g && id1 == ParticleID::g) || (idp == ParticleID::h0 && id0 == ParticleID::gamma && id1 == ParticleID::gamma)|| (idp == ParticleID::h0 && id0 == ParticleID::Z0 && id1 == ParticleID::gamma)|| (idp == ParticleID::h0 && id0 == ParticleID::gamma && id1 == ParticleID::Z0)) return true; else return false; } ParticleVector SMHiggsGGHiggsPPDecayer::decay(const Particle & parent, const tPDVector & children) const { int imode(2); if(children[0]->id() == ParticleID::gamma && children[1]->id() == ParticleID::gamma) imode = 1; else if(children[0]->id() ==ParticleID::g) imode = 0; ParticleVector out(generate(true,false,imode,parent)); //colour flow if(children[0]->id() == ParticleID::g && children[1]->id() == ParticleID::g) { out[0]->colourNeighbour(out[1]); out[0]->antiColourNeighbour(out[1]); } return out; } void SMHiggsGGHiggsPPDecayer::persistentOutput(PersistentOStream & os) const { os << _hggvertex << _hppvertex << _hzpvertex << _h0wgt << _minloop << _maxloop << _massopt; } void SMHiggsGGHiggsPPDecayer::persistentInput(PersistentIStream & is, int) { is >> _hggvertex >> _hppvertex >> _hzpvertex >> _h0wgt >> _minloop >> _maxloop >> _massopt; } void SMHiggsGGHiggsPPDecayer::Init() { static ClassDocumentation documentation ("This is an implentation of h0->gg or h0->gamma,gamma " "decayer using the SMHGGVertex."); static Reference interfaceSMHGGVertex ("SMHGGVertex", "Pointer to SMHGGVertex", &SMHiggsGGHiggsPPDecayer::_hggvertex, false, false, true, false, false); static Reference interfaceSMHPPVertex ("SMHPPVertex", "Pointer to SMHPPVertex", &SMHiggsGGHiggsPPDecayer::_hppvertex, false, false, true, false, false); static Reference interfaceSMHZPVertex ("SMHZPVertex", "Pointer to SMHZPVertex", &SMHiggsGGHiggsPPDecayer::_hzpvertex, false, false, true, false, false); static ParVector interfaceMaxWeights ("MaxWeights", "Maximum weights for the various decays", &SMHiggsGGHiggsPPDecayer::_h0wgt, 3, 1.0, 0.0, 10.0, false, false, Interface::limited); static Parameter interfaceMinimumInLoop ("MinimumInLoop", "The minimum flavour of the quarks to include in the loops", &SMHiggsGGHiggsPPDecayer::_minloop, 6, 4, 6, false, false, Interface::limited); static Parameter interfaceMaximumInLoop ("MaximumInLoop", "The maximum flavour of the quarks to include in the loops", &SMHiggsGGHiggsPPDecayer::_maxloop, 6, 4, 6, false, false, Interface::limited); static Switch interfaceMassOption ("MassOption", "Option for the treatment of the masses in the loop diagrams", &SMHiggsGGHiggsPPDecayer::_massopt, 0, false, false); static SwitchOption interfaceMassOptionFull (interfaceMassOption, "Full", "Include the full mass dependence", 0); static SwitchOption interfaceMassOptionLarge (interfaceMassOption, "Large", "Use the heavy mass limit", 1); } double SMHiggsGGHiggsPPDecayer::me2(const int, const Particle & part, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1,PDT::Spin1))); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(_rho,const_ptr_cast(&part),incoming); _swave = ScalarWaveFunction(part.momentum(),part.dataPtr(),incoming); + // fix rho if no correlations + fixRho(_rho); } if(meopt==Terminate) { ScalarWaveFunction::constructSpinInfo(const_ptr_cast(&part), incoming,true); for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction::constructSpinInfo(_vwave[ix],decay[ix], outgoing,true, decay[ix]->id()!=ParticleID::Z0); return 0.; } for(unsigned int ix=0;ix<2;++ix) VectorWaveFunction:: calculateWaveFunctions(_vwave[ix],decay[ix],outgoing,decay[ix]->id()!=ParticleID::Z0); //Set up decay matrix Energy2 scale(sqr(part.mass())); unsigned int v1hel,v2hel; AbstractVVSVertexPtr vertex; unsigned int vstep1(2),vstep2(2); double sym(1.); if(decay[0]->id() == ParticleID::g && decay[1]->id() == ParticleID::g) { vertex = _hggvertex; sym = 2.; } else if(decay[0]->id() == ParticleID::gamma && decay[1]->id() == ParticleID::gamma) { vertex = _hppvertex; sym = 2.; } else if(decay[0]->id() == ParticleID::Z0 && decay[1]->id() == ParticleID::gamma) { vertex = _hzpvertex; vstep1 = 1; } else if(decay[1]->id() == ParticleID::Z0 && decay[0]->id() == ParticleID::gamma) { vertex = _hzpvertex; vstep2 = 1; } else assert(false); // loop over the helicities of the outgoing bosons for(v1hel = 0;v1hel < 3;v1hel+=vstep1) { for(v2hel = 0;v2hel < 3;v2hel+=vstep2) { (*ME())(0,v1hel,v2hel) = vertex->evaluate(scale,_vwave[0][v1hel], _vwave[1][v2hel],_swave); } } //store matrix element double output = ME()->contract(_rho).real()*UnitRemoval::E2/scale; //colour factor (N^2 - 1)/4 if(decay[0]->id() == ParticleID::g) output *= 8.; //symmetric final states output /= sym; // return the answer return output; } void SMHiggsGGHiggsPPDecayer::doinit() { PerturbativeDecayer::doinit(); // get the width generator for the higgs tPDPtr higgs = getParticleData(ParticleID::h0); if(_hggvertex) { _hggvertex->init(); } else { throw InitException() << "SMHiggsGGHiggsPPDecayer::doinit() - " << "_hggvertex is null"; } if(_hppvertex) { _hppvertex->init(); } else { throw InitException() << "SMHiggsGGHiggsPPDecayer::doinit() - " << "_hppvertex is null"; } if(_hzpvertex) { _hzpvertex->init(); } else { throw InitException() << "SMHiggsGGHiggsZPDecayer::doinit() - " << "_hzpvertex is null"; } //set up decay modes DecayPhaseSpaceModePtr mode; tPDVector extpart(3); vector wgt(0); // glu,glu mode extpart[0] = getParticleData(ParticleID::h0); extpart[1] = getParticleData(ParticleID::g); extpart[2] = getParticleData(ParticleID::g); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,_h0wgt[0],wgt); // gamma,gamma mode extpart[1] = getParticleData(ParticleID::gamma); extpart[2] = getParticleData(ParticleID::gamma); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,_h0wgt[1],wgt); // Z0,gamma mode extpart[1] = getParticleData(ParticleID::Z0); extpart[2] = getParticleData(ParticleID::gamma); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,_h0wgt[2],wgt); } void SMHiggsGGHiggsPPDecayer::doinitrun() { _hggvertex->initrun(); _hppvertex->initrun(); _hzpvertex->initrun(); PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); } } } void SMHiggsGGHiggsPPDecayer::dataBaseOutput(ofstream & os,bool header) const { if(header) os << "update decayers set parameters=\""; // parameters for the PerturbativeDecayer base class for(unsigned int ix=0;ix<_h0wgt.size();++ix) { os << "newdef " << name() << ":MaxWeights " << ix << " " << _h0wgt[ix] << "\n"; } os << "newdef " << name() << ":SMHGGVertex " << _hggvertex->fullName() << "\n"; os << "newdef " << name() << ":SMHPPVertex " << _hppvertex->fullName() << "\n"; os << "newdef " << name() << ":SMHZPVertex " << _hzpvertex->fullName() << "\n"; PerturbativeDecayer::dataBaseOutput(os,false); if(header) os << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl; } double SMHiggsGGHiggsPPDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption, ShowerInteraction inter) { assert(inter==ShowerInteraction::QCD); // extract partons and LO momentas vector partons(1,inpart.dataPtr()); vector lomom(1,inpart.momentum()); for(unsigned int ix=0;ix<2;++ix) { partons.push_back(decay2[ix]->dataPtr()); lomom.push_back(decay2[ix]->momentum()); } vector realmom(1,inpart.momentum()); for(unsigned int ix=0;ix<3;++ix) { if(ix==2) partons.push_back(decay3[ix]->dataPtr()); realmom.push_back(decay3[ix]->momentum()); } Energy2 scale = sqr(inpart.mass()); Energy2 lome = loME(inpart.mass()); double reme = realME(partons,realmom); double ratio = reme/lome*scale; // // analytic value for mt -> infinity // double x1 = 2.*decay3[0]->momentum().t()/inpart.mass(); // double x2 = 2.*decay3[1]->momentum().t()/inpart.mass(); // double x3 = 2.*decay3[2]->momentum().t()/inpart.mass(); // double test = 8.*Constants::pi*3.*(1.+pow(1-x1,4)+pow(1-x2,4)+pow(1-x3,4)) // /(1.-x1)/(1.-x2)/(1.-x3); // generator()->log() << "TESTING RATIO " << test << " " << ratio << " " << ratio/test << "\n"; // remember the symmetry factor return ratio/3.; } double SMHiggsGGHiggsPPDecayer::realME(//const vector & partons, const vector &, const vector & momenta) const { // using std::norm; // ScalarWaveFunction hout(momenta[0],partons[0],outgoing); // LorentzPolarizationVector g[3][2]; // // calculate the polarization vectors for the gluons // for(unsigned int iw=0;iw<3;++iw) { // VectorWaveFunction gwave(momenta[iw+1],partons[iw+1],outgoing); // for(unsigned int ix=0;ix<2;++ix) { // //if(iw==2) gwave.reset(10); // //else // gwave.reset(2*ix); // g[iw][ix] = gwave.wave(); // } // } Energy2 mh2 = momenta[0].mass2(); Energy2 s = (momenta[1]+momenta[2]).m2(); Energy2 t = (momenta[1]+momenta[3]).m2(); Energy2 u = (momenta[2]+momenta[3]).m2(); // calculate the loop functions Complex A4stu(0.),A2stu(0.),A2tsu(0.),A2ust(0.); for(int ix=_minloop;ix<=_maxloop;++ix) { // loop functions if(_massopt==0) { Energy2 mf2=sqr(getParticleData(ix)->mass()); A4stu+=A4(s,t,u,mf2); A2stu+=A2(s,t,u,mf2); A2tsu+=A2(t,s,u,mf2); A2ust+=A2(u,s,t,mf2); } else { A4stu=-1./3.; A2stu=-sqr(s/mh2)/3.; A2tsu=-sqr(t/mh2)/3.; A2ust=-sqr(u/mh2)/3.; } } // Complex A3stu=0.5*(A2stu+A2ust+A2tsu-A4stu); // // compute the dot products for the matrix element // // and polarization vector * momenta // Energy2 pdot[3][3]; // complex eps[3][3][2]; // for(unsigned int ig=0;ig<3;++ig) { // for(unsigned int ip=0;ip<3;++ip) { // pdot[ig][ip]=momenta[ig+1]*momenta[ip+1]; // for(unsigned int ih=0;ih<2;++ih) { // if(ig!=ip) // eps[ig][ip][ih]=g[ig][ih].dot(momenta[ip+1])/pdot[ig][ip]; // else // eps[ig][ip][ih]=ZERO; // } // } // } // prefactors Energy mw(getParticleData(ParticleID::Wplus)->mass()); // Energy3 pre=sqr(mh2)/mw; // // compute the matrix element // double output(0.); // complex wdot[3][3]; // for(unsigned int ghel1=0;ghel1<2;++ghel1) { // for(unsigned int ghel2=0;ghel2<2;++ghel2) { // for(unsigned int ghel3=0;ghel3<2;++ghel3) { // wdot[0][1]=g[0][ghel1].dot(g[1][ghel2])/pdot[0][1]; // wdot[0][2]=g[0][ghel1].dot(g[2][ghel3])/pdot[0][2]; // wdot[1][0]=wdot[0][1]; // wdot[1][2]=g[1][ghel2].dot(g[2][ghel3])/pdot[1][2]; // wdot[2][0]=wdot[0][2]; // wdot[2][1]=wdot[1][2]; // // last piece // Complex diag=pre*A3stu*(eps[0][2][ghel1]*eps[1][0][ghel2]*eps[2][1][ghel3]- // eps[0][1][ghel1]*eps[1][2][ghel2]*eps[2][0][ghel3]+ // (eps[2][0][ghel3]-eps[2][1][ghel3])*wdot[0][1]+ // (eps[1][2][ghel2]-eps[1][0][ghel2])*wdot[0][2]+ // (eps[0][1][ghel1]-eps[0][2][ghel1])*wdot[1][2]); // // first piece // diag+=pre*(+A2stu*(eps[0][1][ghel1]*eps[1][0][ghel2]-wdot[0][1])* // (eps[2][0][ghel3]-eps[2][1][ghel3]) // +A2tsu*(eps[0][2][ghel1]*eps[2][0][ghel3]-wdot[0][2])* // (eps[1][2][ghel2]-eps[1][0][ghel2]) // +A2ust*(eps[1][2][ghel2]*eps[2][1][ghel3]-wdot[1][2])* // (eps[0][1][ghel1]-eps[0][2][ghel1])); // output+=norm(diag); // } // } // } // // colour factor and what's left of the prefactor // output *= 6.; double me=4.*24./s/t/u*pow<4,1>(mh2)/sqr(mw)* (norm(A2stu)+norm(A2ust)+norm(A2tsu)+norm(A4stu)); return me; } Energy2 SMHiggsGGHiggsPPDecayer::loME(Energy mh) const { Complex loop(0.); Energy2 mh2(sqr(mh)); Energy mw(getParticleData(ParticleID::Wplus)->mass()); for(int ix=_minloop;ix<=_maxloop;++ix) { // loop functions if(_massopt==0) { Energy2 mf2=sqr(getParticleData(ix)->mass()); loop += A1(mh2,mf2); } else { loop += 2./3.; } } return 1./Constants::pi*sqr(mh2)/sqr(mw)*norm(loop); } diff --git a/Decay/Perturbative/SMHiggsWWDecayer.cc b/Decay/Perturbative/SMHiggsWWDecayer.cc --- a/Decay/Perturbative/SMHiggsWWDecayer.cc +++ b/Decay/Perturbative/SMHiggsWWDecayer.cc @@ -1,325 +1,327 @@ // -*- C++ -*- // // SMHiggsWWDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SMHiggsWWDecayer class. // #include "SMHiggsWWDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/PDT/ParticleData.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; typedef Selector DecaySelector; // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMHiggsWWDecayer("Herwig::SMHiggsWWDecayer", "HwPerturbativeHiggsDecay.so"); void SMHiggsWWDecayer::Init() { static ClassDocumentation documentation ("The SMHiggsWWDecayer class performs the decay of the Standard Model Higgs" " boson to W+W- and Z0Z0"); static ParVector interfaceWMaximum ("WMaximum", "The maximum weight for H-> W+W- decays", &SMHiggsWWDecayer::_wmax, 2, 1.0, 0.0, 10000.0, false, false, Interface::limited); static ParVector interfaceZMaximum ("ZMaximum", "The maximum weight for H-> Z0Z0 decays", &SMHiggsWWDecayer::_zmax, 2, 1.0, 0.0, 10000.0, false, false, Interface::limited); } SMHiggsWWDecayer::SMHiggsWWDecayer() : _wmax(2,1.00), _zmax(2,1.00) {} void SMHiggsWWDecayer::doinit() { PerturbativeDecayer::doinit(); // get the vertices from the Standard Model object tcHwSMPtr hwsm=dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "SMHiggsWWDecayer needs the StandardModel class" << " to be either the Herwig one or a class inheriting" << " from it"; _theFFWVertex = hwsm->vertexFFW(); _theFFZVertex = hwsm->vertexFFZ(); _theHVVVertex = hwsm->vertexWWH(); // get the width generator for the higgs tPDPtr higgs = getParticleData(ParticleID::h0); // the W+W- decays for(unsigned int ix=0;ix<2;++ix) { tPDPtr h0 = getParticleData(ParticleID::h0); tPDPtr wplus = getParticleData(ParticleID::Wplus); tPDPtr wminus = getParticleData(ParticleID::Wminus); DecaySelector wpDecay = wplus->decaySelector(); DecaySelector wmDecay = wminus->decaySelector(); tPDVector extpart(5); extpart[0]=h0; DecayPhaseSpaceModePtr mode; DecayPhaseSpaceChannelPtr newchannel; vector wgt(1,1.); unsigned int imode=0; for(DecaySelector::const_iterator wp=wpDecay.begin();wp!=wpDecay.end();++wp) { // extract the decay products of W+ tPDVector prod=(*wp).second->orderedProducts(); if(prod[0]->id()id()) swap(prod[0],prod[1]); extpart[1]=prod[0]; extpart[2]=prod[1]; for(DecaySelector::const_iterator wm=wmDecay.begin();wm!=wmDecay.end();++wm) { // extract the decay products of W- tPDVector prod=(*wm).second->orderedProducts(); if(prod[0]->id()id()) swap(prod[0],prod[1]); extpart[3]=prod[0]; extpart[4]=prod[1]; // create the new mode mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); // create the phase space channel newchannel=new_ptr(DecayPhaseSpaceChannel(mode)); newchannel->addIntermediate(extpart[0],0,0.0,-1,-2); if(ix==0) { newchannel->addIntermediate(wplus ,1,0., 1, 2); newchannel->addIntermediate(wminus ,1,0., 3, 4); } else { newchannel->addIntermediate(wplus ,0,0., 1, 2); newchannel->addIntermediate(wminus ,0,0., 3, 4); } mode->addChannel(newchannel); addMode(mode,_wmax[ix],wgt); // insert mode into selector _ratio.push_back(wp->second->brat()*wm->second->brat()); if(ix==0) _wdecays.insert (_ratio.back(),imode); ++imode; } } // the Z0Z0 decays tPDPtr Z0=getParticleData(ParticleID::Z0); DecaySelector Z0Decay = Z0->decaySelector(); for(DecaySelector::const_iterator z1=Z0Decay.begin();z1!=Z0Decay.end();++z1) { // extract the decay products of Z0 tPDVector prod=(*z1).second->orderedProducts(); if(prod[0]->id()id()) swap(prod[0],prod[1]); extpart[1]=prod[0]; extpart[2]=prod[1]; for(DecaySelector::const_iterator z2=Z0Decay.begin();z2!=Z0Decay.end();++z2) { // extract the decay products of Z0 tPDVector prod=(*z2).second->orderedProducts(); if(prod[0]->id()id()) swap(prod[0],prod[1]); extpart[3]=prod[0]; extpart[4]=prod[1]; // create the new mode mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); // create the phase space channel newchannel=new_ptr(DecayPhaseSpaceChannel(mode)); newchannel->addIntermediate(extpart[0],0,0.0,-1,-2); if(ix==0) { newchannel->addIntermediate(Z0 ,1,0., 1, 2); newchannel->addIntermediate(Z0 ,1,0., 3, 4); } else { newchannel->addIntermediate(Z0 ,0,0., 1, 2); newchannel->addIntermediate(Z0 ,0,0., 3, 4); } mode->addChannel(newchannel); addMode(mode,_zmax[ix],wgt); // insert mode into selector _ratio.push_back(z1->second->brat()*z2->second->brat()); if(ix==0) _zdecays.insert (_ratio.back(),imode); ++imode; } } } } bool SMHiggsWWDecayer::accept(tcPDPtr parent, const tPDVector & children) const { // if not two decay products return false if(children.size()!=2) return false; // if not decaying higgs return false if(parent->id()!=ParticleID::h0) return false; tPDVector::const_iterator pit = children.begin(); int id1=(**pit).id(); ++pit; int id2=(**pit).id(); if((id1==-id2&&abs(id1)==ParticleID::Wplus)|| (id1== id2&& id1 ==ParticleID::Z0)) return true; else return false; } void SMHiggsWWDecayer::persistentOutput(PersistentOStream & os) const { os << _theFFWVertex << _theFFZVertex << _theHVVVertex << _wdecays << _zdecays << _ratio << _wmax << _zmax; } void SMHiggsWWDecayer::persistentInput(PersistentIStream & is, int) { is >> _theFFWVertex >> _theFFZVertex >> _theHVVVertex >> _wdecays >> _zdecays >> _ratio >> _wmax >> _zmax; } ParticleVector SMHiggsWWDecayer::decay(const Particle & parent, const tPDVector & children) const { // select the decay modes of the gauge bosons unsigned int imode; if(abs(children[0]->id())==ParticleID::Wplus) imode=_wdecays.select(UseRandom::rnd()); else imode=_zdecays.select(UseRandom::rnd()); // use different phase space for low/high mass higgs if(parent.mass()>1.8*children[0]->mass()) imode+=_wdecays.size()+_zdecays.size(); // generate the kinematics return generate(true,false,imode,parent); } double SMHiggsWWDecayer::me2(const int, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin0,PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); // check if Z or W decay bool Z0=decay[0]->id()==-decay[1]->id(); if(meopt==Initialize) { ScalarWaveFunction:: calculateWaveFunctions(_rho,const_ptr_cast(&inpart),incoming); _swave = ScalarWaveFunction(inpart.momentum(),inpart.dataPtr(),incoming); + // fix rho if no correlations + fixRho(_rho); } if(meopt==Terminate) { ScalarWaveFunction::constructSpinInfo(const_ptr_cast(&inpart), incoming,true); SpinorBarWaveFunction:: constructSpinInfo(_fwave1,decay[0],outgoing,true); SpinorWaveFunction :: constructSpinInfo(_awave1,decay[1],outgoing,true); SpinorBarWaveFunction:: constructSpinInfo(_fwave2,decay[2],outgoing,true); SpinorWaveFunction :: constructSpinInfo(_awave2,decay[3],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(_fwave1,decay[0],outgoing); SpinorWaveFunction :: calculateWaveFunctions(_awave1,decay[1],outgoing); SpinorBarWaveFunction:: calculateWaveFunctions(_fwave2,decay[2],outgoing); SpinorWaveFunction :: calculateWaveFunctions(_awave2,decay[3],outgoing); // get the intermediates and vertex tcPDPtr inter[2]; AbstractFFVVertexPtr vert; if(Z0) { inter[0]=getParticleData(ParticleID::Z0); inter[1]=inter[0]; vert=_theFFZVertex; } else { inter[0]=getParticleData(ParticleID::Wplus); inter[1]=getParticleData(ParticleID::Wminus); vert=_theFFWVertex; } // construct the spinors for the outgoing particles Energy2 scale0(sqr(inpart.mass())); Energy2 scale1((decay[0]->momentum()+decay[1]->momentum()).m2()); Energy2 scale2((decay[2]->momentum()+decay[3]->momentum()).m2()); // for decays to quarks ensure boson is massive enough to // put quarks on constituent mass-shell if(scale1dataPtr()->constituentMass()+ decay[1]->dataPtr()->constituentMass())) return 0.; if(scale2dataPtr()->constituentMass()+ decay[3]->dataPtr()->constituentMass())) return 0.; // compute the boson currents VectorWaveFunction curr1[2][2],curr2[2][2]; unsigned int ohel1,ohel2,ohel3,ohel4; for(ohel1=0;ohel1<2;++ohel1) { for(ohel2=0;ohel2<2;++ohel2) { curr1[ohel1][ohel2]=vert->evaluate(scale1,1,inter[0], _awave1[ohel2],_fwave1[ohel1]); curr2[ohel1][ohel2]=vert->evaluate(scale2,1,inter[1], _awave2[ohel2],_fwave2[ohel1]); } } // compute the matrix element for(ohel1=0;ohel1<2;++ohel1) { for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { for(ohel4=0;ohel4<2;++ohel4) { (*ME())(0,ohel1,ohel2,ohel3,ohel4)= _theHVVVertex->evaluate(scale0,curr1[ohel1][ohel2], curr2[ohel3][ohel4],_swave); } } } } double output=(ME()->contract(_rho)).real()*scale0*UnitRemoval::InvE2; // set up the colour flows if(decay[0]->coloured()) { output*=3.; decay[0]->antiColourNeighbour(decay[1]); } if(decay[2]->coloured()) { output*=3.; decay[2]->antiColourNeighbour(decay[3]); } // divide out the gauge boson branching ratios output/=_ratio[imode()]; // if Z0 decays identical particle factor if(Z0) output*=0.5; // return the answer return output; } void SMHiggsWWDecayer::dataBaseOutput(ofstream & os,bool header) const { if(header) os << "update decayers set parameters=\""; for(unsigned int ix=0;ix<2;++ix) { os << "newdef " << name() << ":WMaximum " << ix << " " << _wmax[ix] << "\n"; os << "newdef " << name() << ":ZMaximum " << ix << " " << _zmax[ix] << "\n"; } PerturbativeDecayer::dataBaseOutput(os,false); if(header) os << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl; } void SMHiggsWWDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); for(unsigned int ix=0;ix<2;++ix) { _zmax[ix]=0.; _wmax[ix]=0.; } unsigned int ntest=_wdecays.size()+_zdecays.size(); if(initialize()) { for(unsigned int ix=0;ixexternalParticles(1)->iCharge()== -mode(ix)->externalParticles(2)->iCharge()) { _zmax[iloc]=max(mode(ix)->maxWeight(),_zmax[iloc]); } else { _wmax[iloc]=max(mode(ix)->maxWeight(),_wmax[iloc]); } } } } diff --git a/Decay/Perturbative/SMTopDecayer.cc b/Decay/Perturbative/SMTopDecayer.cc --- a/Decay/Perturbative/SMTopDecayer.cc +++ b/Decay/Perturbative/SMTopDecayer.cc @@ -1,764 +1,764 @@ // -*- C++ -*- // // SMTopDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SMTopDecayer class. // #include "SMTopDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/PDT/ThreeBodyAllOn1IntegralCalculator.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" using namespace Herwig; using namespace ThePEG::Helicity; SMTopDecayer::SMTopDecayer() : _wquarkwgt(6,0.),_wleptonwgt(3,0.), _xg_sampling(1.5), _initialenhance(1.), _finalenhance(2.3) { _wleptonwgt[0] = 0.302583; _wleptonwgt[1] = 0.301024; _wleptonwgt[2] = 0.299548; _wquarkwgt[0] = 0.851719; _wquarkwgt[1] = 0.0450162; _wquarkwgt[2] = 0.0456962; _wquarkwgt[3] = 0.859839; _wquarkwgt[4] = 3.9704e-06; _wquarkwgt[5] = 0.000489657; generateIntermediates(true); } bool SMTopDecayer::accept(tcPDPtr parent, const tPDVector & children) const { if(abs(parent->id()) != ParticleID::t) return false; int id0(0),id1(0),id2(0); for(tPDVector::const_iterator it = children.begin(); it != children.end();++it) { int id=(**it).id(),absid(abs(id)); if(absid==ParticleID::b&&double(id)/double(parent->id())>0) { id0=id; } else { switch (absid) { case ParticleID::nu_e: case ParticleID::nu_mu: case ParticleID::nu_tau: id1 = id; break; case ParticleID::eminus: case ParticleID::muminus: case ParticleID::tauminus: id2 = id; break; case ParticleID::b: case ParticleID::d: case ParticleID::s: id1 = id; break; case ParticleID::u: case ParticleID::c: id2=id; break; default : break; } } } if(id0==0||id1==0||id2==0) return false; if(double(id1)/double(id2)>0) return false; return true; } ParticleVector SMTopDecayer::decay(const Particle & parent, const tPDVector & children) const { int id1(0),id2(0); for(tPDVector::const_iterator it = children.begin(); it != children.end();++it) { int id=(**it).id(),absid=abs(id); if(absid == ParticleID::b && double(id)/double(parent.id())>0) continue; //leptons if(absid > 10 && absid%2==0) id1=absid; if(absid > 10 && absid%2==1) id2=absid; //quarks if(absid < 10 && absid%2==0) id2=absid; if(absid < 10 && absid%2==1) id1=absid; } unsigned int imode(0); if(id2 >=11 && id2<=16) imode = (id1-12)/2; else imode = id1+1+id2/2; bool cc = parent.id() == ParticleID::tbar; ParticleVector out(generate(true,cc,imode,parent)); //arrange colour flow PPtr pparent=const_ptr_cast(&parent); out[1]->incomingColour(pparent,out[1]->id()<0); ParticleVector products = out[0]->children(); if(products[0]->hasColour()) products[0]->colourNeighbour(products[1],true); else if(products[0]->hasAntiColour()) products[0]->colourNeighbour(products[1],false); return out; } void SMTopDecayer::persistentOutput(PersistentOStream & os) const { os << FFWVertex_ << FFGVertex_ << FFPVertex_ << WWWVertex_ << _wquarkwgt << _wleptonwgt << _wplus << _initialenhance << _finalenhance << _xg_sampling; } void SMTopDecayer::persistentInput(PersistentIStream & is, int) { is >> FFWVertex_ >> FFGVertex_ >> FFPVertex_ >> WWWVertex_ >> _wquarkwgt >> _wleptonwgt >> _wplus >> _initialenhance >> _finalenhance >> _xg_sampling; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMTopDecayer("Herwig::SMTopDecayer", "HwPerturbativeDecay.so"); void SMTopDecayer::Init() { static ClassDocumentation documentation ("This is the implementation of the SMTopDecayer which " "decays top quarks into bottom quarks and either leptons " "or quark-antiquark pairs including the matrix element for top decay", "The matrix element correction for top decay \\cite{Hamilton:2006ms}.", "%\\cite{Hamilton:2006ms}\n" "\\bibitem{Hamilton:2006ms}\n" " K.~Hamilton and P.~Richardson,\n" " ``A simulation of QCD radiation in top quark decays,''\n" " JHEP {\\bf 0702}, 069 (2007)\n" " [arXiv:hep-ph/0612236].\n" " %%CITATION = JHEPA,0702,069;%%\n"); static ParVector interfaceQuarkWeights ("QuarkWeights", "Maximum weights for the hadronic decays", &SMTopDecayer::_wquarkwgt, 6, 1.0, 0.0, 10.0, false, false, Interface::limited); static ParVector interfaceLeptonWeights ("LeptonWeights", "Maximum weights for the semi-leptonic decays", &SMTopDecayer::_wleptonwgt, 3, 1.0, 0.0, 10.0, false, false, Interface::limited); static Parameter interfaceEnhancementFactor ("InitialEnhancementFactor", "The enhancement factor for initial-state radiation in the shower to ensure" " the weight for the matrix element correction is less than one.", &SMTopDecayer::_initialenhance, 1.0, 1.0, 10000.0, false, false, Interface::limited); static Parameter interfaceFinalEnhancementFactor ("FinalEnhancementFactor", "The enhancement factor for final-state radiation in the shower to ensure" " the weight for the matrix element correction is less than one", &SMTopDecayer::_finalenhance, 1.6, 1.0, 1000.0, false, false, Interface::limited); static Parameter interfaceSamplingTopHardMEC ("SamplingTopHardMEC", "The importance sampling power for choosing an initial xg, " "to sample xg according to xg^-_xg_sampling", &SMTopDecayer::_xg_sampling, 1.5, 1.2, 2.0, false, false, Interface::limited); } double SMTopDecayer::me2(const int, const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half))); // spinors etc for the decaying particle if(meopt==Initialize) { // spinors and rho if(inpart.id()>0) SpinorWaveFunction ::calculateWaveFunctions(_inHalf,_rho, const_ptr_cast(&inpart), incoming); else SpinorBarWaveFunction::calculateWaveFunctions(_inHalfBar,_rho, const_ptr_cast(&inpart), incoming); + // fix rho if no correlations + fixRho(_rho); } // setup spin info when needed if(meopt==Terminate) { // for the decaying particle if(inpart.id()>0) { SpinorWaveFunction:: constructSpinInfo(_inHalf,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction::constructSpinInfo(_inHalfBar,decay[0],outgoing,true); SpinorWaveFunction ::constructSpinInfo(_outHalf ,decay[1],outgoing,true); SpinorBarWaveFunction::constructSpinInfo(_outHalfBar,decay[2],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(_inHalfBar,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction::constructSpinInfo(_inHalf,decay[0],outgoing,true); SpinorBarWaveFunction::constructSpinInfo(_outHalfBar,decay[1],outgoing,true); SpinorWaveFunction ::constructSpinInfo(_outHalf ,decay[2],outgoing,true); } } if ( ( decay[1]->momentum() + decay[2]->momentum() ).m() < decay[1]->data().constituentMass() + decay[2]->data().constituentMass() ) return 0.0; // spinors for the decay product if(inpart.id()>0) { SpinorBarWaveFunction::calculateWaveFunctions(_inHalfBar ,decay[0],outgoing); SpinorWaveFunction ::calculateWaveFunctions(_outHalf ,decay[1],outgoing); SpinorBarWaveFunction::calculateWaveFunctions(_outHalfBar,decay[2],outgoing); } else { SpinorWaveFunction ::calculateWaveFunctions(_inHalf ,decay[0],outgoing); SpinorBarWaveFunction::calculateWaveFunctions(_outHalfBar,decay[1],outgoing); SpinorWaveFunction ::calculateWaveFunctions(_outHalf ,decay[2],outgoing); } Energy2 scale(sqr(inpart.mass())); if(inpart.id() == ParticleID::t) { //Define intermediate vector wave-function for Wplus tcPDPtr Wplus(getParticleData(ParticleID::Wplus)); VectorWaveFunction inter; unsigned int thel,bhel,fhel,afhel; for(thel = 0;thel<2;++thel){ for(bhel = 0;bhel<2;++bhel){ inter = FFWVertex_->evaluate(scale,1,Wplus,_inHalf[thel], _inHalfBar[bhel]); for(afhel=0;afhel<2;++afhel){ for(fhel=0;fhel<2;++fhel){ (*ME())(thel,bhel,afhel,fhel) = FFWVertex_->evaluate(scale,_outHalf[afhel], _outHalfBar[fhel],inter); } } } } } else if(inpart.id() == ParticleID::tbar) { VectorWaveFunction inter; tcPDPtr Wminus(getParticleData(ParticleID::Wminus)); unsigned int tbhel,bbhel,afhel,fhel; for(tbhel = 0;tbhel<2;++tbhel){ for(bbhel = 0;bbhel<2;++bbhel){ inter = FFWVertex_-> evaluate(scale,1,Wminus,_inHalf[bbhel],_inHalfBar[tbhel]); for(afhel=0;afhel<2;++afhel){ for(fhel=0;fhel<2;++fhel){ (*ME())(tbhel,bbhel,fhel,afhel) = FFWVertex_->evaluate(scale,_outHalf[afhel], _outHalfBar[fhel],inter); } } } } } double output = (ME()->contract(_rho)).real(); if(abs(decay[1]->id())<=6) output *=3.; return output; } void SMTopDecayer::doinit() { PerturbativeDecayer::doinit(); //get vertices from SM object tcHwSMPtr hwsm = dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "Must have Herwig::StandardModel in " << "SMTopDecayer::doinit()"; FFWVertex_ = hwsm->vertexFFW(); FFGVertex_ = hwsm->vertexFFG(); FFPVertex_ = hwsm->vertexFFP(); WWWVertex_ = hwsm->vertexWWW(); //initialise FFWVertex_->init(); FFGVertex_->init(); FFPVertex_->init(); WWWVertex_->init(); //set up decay modes _wplus = getParticleData(ParticleID::Wplus); DecayPhaseSpaceModePtr mode; DecayPhaseSpaceChannelPtr Wchannel; tPDVector extpart(4); vector wgt(1,1.0); extpart[0] = getParticleData(ParticleID::t); extpart[1] = getParticleData(ParticleID::b); //lepton modes for(int i=11; i<17;i+=2) { extpart[2] = getParticleData(-i); extpart[3] = getParticleData(i+1); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); Wchannel = new_ptr(DecayPhaseSpaceChannel(mode)); Wchannel->addIntermediate(extpart[0],0,0.0,-1,1); Wchannel->addIntermediate(_wplus,0,0.0,2,3); - Wchannel->init(); mode->addChannel(Wchannel); addMode(mode,_wleptonwgt[(i-11)/2],wgt); } //quark modes unsigned int iz=0; for(int ix=1;ix<6;ix+=2) { for(int iy=2;iy<6;iy+=2) { // check that the combination of particles is allowed if(FFWVertex_->allowed(-ix,iy,ParticleID::Wminus)) { extpart[2] = getParticleData(-ix); extpart[3] = getParticleData( iy); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); Wchannel = new_ptr(DecayPhaseSpaceChannel(mode)); Wchannel->addIntermediate(extpart[0],0,0.0,-1,1); Wchannel->addIntermediate(_wplus,0,0.0,2,3); - Wchannel->init(); mode->addChannel(Wchannel); addMode(mode,_wquarkwgt[iz],wgt); ++iz; } else { throw InitException() << "SMTopDecayer::doinit() the W vertex" << "cannot handle all the quark modes" << Exception::abortnow; } } } } void SMTopDecayer::dataBaseOutput(ofstream & os,bool header) const { if(header) os << "update decayers set parameters=\""; // parameters for the PerturbativeDecayer base class for(unsigned int ix=0;ix<_wquarkwgt.size();++ix) { os << "newdef " << name() << ":QuarkWeights " << ix << " " << _wquarkwgt[ix] << "\n"; } for(unsigned int ix=0;ix<_wleptonwgt.size();++ix) { os << "newdef " << name() << ":LeptonWeights " << ix << " " << _wleptonwgt[ix] << "\n"; } PerturbativeDecayer::dataBaseOutput(os,false); if(header) os << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";" << endl; } void SMTopDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); else _wquarkwgt [ix-3] = mode(ix)->maxWeight(); } } } WidthCalculatorBasePtr SMTopDecayer::threeBodyMEIntegrator(const DecayMode & dm) const { // identify W decay products int sign = dm.parent()->id() > 0 ? 1 : -1; int iferm(0),ianti(0); for(ParticleMSet::const_iterator pit=dm.products().begin(); pit!=dm.products().end();++pit) { int id = (**pit).id(); if(id*sign != ParticleID::b) { if (id*sign > 0 ) iferm = id*sign; else ianti = id*sign; } } assert(iferm!=0&&ianti!=0); // work out which mode we are doing int imode(-1); for(unsigned int ix=0;ixexternalParticles(2)->id() == ianti && mode(ix)->externalParticles(3)->id() == iferm ) { imode = ix; break; } } assert(imode>=0); // get the masses we need Energy m[3] = {mode(imode)->externalParticles(1)->mass(), mode(imode)->externalParticles(3)->mass(), mode(imode)->externalParticles(2)->mass()}; return new_ptr(ThreeBodyAllOn1IntegralCalculator (3,_wplus->mass(),_wplus->width(),0.0,*this,imode,m[0],m[1],m[2])); } InvEnergy SMTopDecayer::threeBodydGammads(const int imode, const Energy2 mt2, const Energy2 mffb2, const Energy mb, const Energy mf, const Energy mfb) const { Energy mffb(sqrt(mffb2)); Energy mw(_wplus->mass()); Energy2 mw2(sqr(mw)),gw2(sqr(_wplus->width())); Energy mt(sqrt(mt2)); Energy Eb = 0.5*(mt2-mffb2-sqr(mb))/mffb; Energy Ef = 0.5*(mffb2-sqr(mfb)+sqr(mf))/mffb; Energy Ebm = sqrt(sqr(Eb)-sqr(mb)); Energy Efm = sqrt(sqr(Ef)-sqr(mf)); Energy2 upp = sqr(Eb+Ef)-sqr(Ebm-Efm); Energy2 low = sqr(Eb+Ef)-sqr(Ebm+Efm); InvEnergy width=(dGammaIntegrand(mffb2,upp,mt,mb,mf,mfb,mw)- dGammaIntegrand(mffb2,low,mt,mb,mf,mfb,mw)) /32./mt2/mt/8/pow(Constants::pi,3)/(sqr(mffb2-mw2)+mw2*gw2); // couplings width *= 0.25*sqr(4.*Constants::pi*generator()->standardModel()->alphaEM(mt2)/ generator()->standardModel()->sin2ThetaW()); width *= generator()->standardModel()->CKM(*mode(imode)->externalParticles(0), *mode(imode)->externalParticles(1)); if(abs(mode(imode)->externalParticles(2)->id())<=6) { width *=3.; if(abs(mode(imode)->externalParticles(2)->id())%2==0) width *=generator()->standardModel()->CKM(*mode(imode)->externalParticles(2), *mode(imode)->externalParticles(3)); else width *=generator()->standardModel()->CKM(*mode(imode)->externalParticles(3), *mode(imode)->externalParticles(2)); } // final spin average assert(!std::isnan(double(width*MeV))); return 0.5*width; } Energy6 SMTopDecayer::dGammaIntegrand(Energy2 mffb2, Energy2 mbf2, Energy mt, Energy mb, Energy mf, Energy mfb, Energy mw) const { Energy2 mt2(sqr(mt)) ,mb2(sqr(mb)) ,mf2(sqr(mf )),mfb2(sqr(mfb )),mw2(sqr(mw )); Energy4 mt4(sqr(mt2)),mb4(sqr(mb2)),mf4(sqr(mf2)),mfb4(sqr(mfb2)),mw4(sqr(mw2)); return -mbf2 * ( + 6 * mb2 * mf2 * mfb2 * mffb2 + 6 * mb2 * mt2 * mfb2 * mffb2 + 6 * mb2 * mt2 * mf2 * mffb2 + 12 * mb2 * mt2 * mf2 * mfb2 - 3 * mb2 * mfb4 * mffb2 + 3 * mb2 * mf2 * mffb2 * mffb2 - 3 * mb2 * mf4 * mffb2 - 6 * mb2 * mt2 * mfb4 - 6 * mb2 * mt2 * mf4 - 3 * mb4 * mfb2 * mffb2 - 3 * mb4 * mf2 * mffb2 - 6 * mb4 * mf2 * mfb2 + 3 * mt4 * mf4 + 3 * mb4 * mfb4 + 3 * mb4 * mf4 + 3 * mt4 * mfb4 + 3 * mb2 * mfb2 * mffb2 * mffb2 + 3 * mt2 * mfb2 * mffb2 * mffb2 - 3 * mt2 * mfb4 * mffb2 + 3 * mt2 * mf2 * mffb2 * mffb2 - 3 * mt2 * mf4 * mffb2 - 3 * mt4 * mfb2 * mffb2 - 3 * mt4 * mf2 * mffb2 - 6 * mt4 * mf2 * mfb2 + 6 * mt2 * mf2 * mfb2 * mffb2 + 12 * mt2 * mf2 * mw4 + 12 * mb2 * mfb2 * mw4 + 12 * mb2 * mt2 * mw4 + 6 * mw2 * mt2 * mfb2 * mbf2 - 12 * mw2 * mt2 * mf2 * mffb2 - 6 * mw2 * mt2 * mf2 * mbf2 - 12 * mw2 * mt2 * mf2 * mfb2 - 12 * mw2 * mb2 * mfb2 * mffb2 - 6 * mw2 * mb2 * mfb2 * mbf2 + 6 * mw2 * mb2 * mf2 * mbf2 - 12 * mw2 * mb2 * mf2 * mfb2 - 12 * mw2 * mb2 * mt2 * mfb2 - 12 * mw2 * mb2 * mt2 * mf2 + 12 * mf2 * mfb2 * mw4 + 4 * mbf2 * mbf2 * mw4 - 6 * mfb2 * mbf2 * mw4 - 6 * mf2 * mbf2 * mw4 - 6 * mt2 * mbf2 * mw4 - 6 * mb2 * mbf2 * mw4 + 12 * mw2 * mt2 * mf4 + 12 * mw2 * mt4 * mf2 + 12 * mw2 * mb2 * mfb4 + 12 * mw2 * mb4 * mfb2) /mw4 / 3.; } void SMTopDecayer::initializeMECorrection(RealEmissionProcessPtr born, double & initial, double & final) { // check the outgoing particles PPtr part[2]; for(unsigned int ix=0;ixbornOutgoing().size();++ix) { part[ix]= born->bornOutgoing()[ix]; } // check the final-state particles and get the masses if(abs(part[0]->id())==ParticleID::Wplus&&abs(part[1]->id())==ParticleID::b) { _ma=part[0]->mass(); _mc=part[1]->mass(); } else if(abs(part[1]->id())==ParticleID::Wplus&&abs(part[0]->id())==ParticleID::b) { _ma=part[1]->mass(); _mc=part[0]->mass(); } else { return; } // set the top mass _mt=born->bornIncoming()[0]->mass(); // set the gluon mass _mg=getParticleData(ParticleID::g)->constituentMass(); // set the radiation enhancement factors initial = _initialenhance; final = _finalenhance; // reduced mass parameters _a=sqr(_ma/_mt); _g=sqr(_mg/_mt); _c=sqr(_mc/_mt); double lambda = sqrt(1.+sqr(_a)+sqr(_c)-2.*_a-2.*_c-2.*_a*_c); _ktb = 0.5*(3.-_a+_c+lambda); _ktc = 0.5*(1.-_a+3.*_c+lambda); useMe(); } bool SMTopDecayer::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & , const Energy & highestpT, const vector &, const double & z, const Energy & scale, const Energy & pt) { // check if we need to apply the full correction // the initial-state correction if(abs(progenitor->id())==ParticleID::t&&abs(parent->id())==ParticleID::t) { // check if hardest so far // if not just need to remove effect of enhancement bool veto(false); // if not hardest so far if(ptxgbcut(_ktb)) wgt = 0.; if(wgt>1.) { generator()->log() << "Violation of maximum for initial-state " << " soft veto in " << "SMTopDecayer::softMatrixElementVeto" << "xg = " << xg << " xa = " << xa << "weight = " << wgt << "\n"; wgt=1.; } // compute veto from weight veto = !UseRandom::rndbool(wgt); } } // return the veto return veto; } // final-state correction else if(abs(progenitor->id())==ParticleID::b&&abs(parent->id())==ParticleID::b) { // check if hardest so far // if not just need to remove effect of enhancement // if not hardest so far if(ptlog() << "Imaginary root for final-state veto in " << "SMTopDecayer::softMatrixElementVeto" << "\nz = " << z << "\nkappa = " << kappa << "\nxa = " << xa << "\nroot^2= " << root; return true; } root=sqrt(root); double xg((2.-xa)*(1.-r)-(z-r)*root); // xfact (below) is supposed to equal xg/(1-z). double xfact(z*kappa/2./(z*(1.-z)*kappa+_c)*(2.-xa-root)+root); // calculate the full result double f(me(xa,xg)); // jacobian double J(z*root); double wgt(f*J*2.*kappa/(1.+sqr(z)-2.*_c/kappa/z)/sqr(xfact)/_finalenhance); if(wgt>1.) { generator()->log() << "Violation of maximum for final-state soft veto in " << "SMTopDecayer::softMatrixElementVeto" << "xg = " << xg << " xa = " << xa << "weight = " << wgt << "\n"; wgt=1.; } // compute veto from weight and return return !UseRandom::rndbool(wgt); } // otherwise don't veto else return !UseRandom::rndbool(1./_finalenhance); } double SMTopDecayer::me(double xw,double xg) { double prop(1.+_a-_c-xw),xg2(sqr(xg)); double lambda=sqrt(1.+_a*_a+_c*_c-2.*_a-2.*_c-2.*_a*_c); double denom=(1.-2*_a*_a+_a+_c*_a+_c*_c-2.*_c); double wgt=-_c*xg2/prop+(1.-_a+_c)*xg-(prop*(1 - xg)+xg2) +(0.5*(1.+2.*_a+_c)*sqr(prop-xg)*xg+2.*_a*prop*xg2)/denom; return wgt/(lambda*prop); } // xgbcut is the point along the xg axis where the upper bound on the // top quark (i.e. b) emission phase space goes back on itself in the // xa vs xg plane i.e. roughly mid-way along the xg axis in // the xa vs xg Dalitz plot. double SMTopDecayer::xgbcut(double kt) { double lambda2 = 1.+_a*_a+_c*_c-2.*_a-2.*_c-2.*_a*_c; double num1 = kt*kt*(1.-_a-_c); double num2 = 2.*kt*sqrt(_a*(kt*kt*_c+lambda2*(kt-1.))); return (num1-num2)/(kt*kt-4.*_a*(kt-1.)); } double SMTopDecayer::loME(const Particle & inpart, const ParticleVector & decay) { // spinors vector swave; vector awave; vector vwave; tPPtr Wboson = abs(decay[0]->id())==ParticleID::Wplus ? decay[0] : decay[1]; tPPtr bquark = abs(decay[0]->id())==ParticleID::Wplus ? decay[1] : decay[0]; // spinors if(inpart.id()>0) { SpinorWaveFunction ::calculateWaveFunctions(swave,const_ptr_cast(&inpart), incoming); SpinorBarWaveFunction::calculateWaveFunctions(awave,bquark,outgoing); } else { SpinorBarWaveFunction::calculateWaveFunctions(awave,const_ptr_cast(&inpart), incoming); SpinorWaveFunction ::calculateWaveFunctions(swave,bquark,outgoing); } // polarization vectors VectorWaveFunction::calculateWaveFunctions(vwave,Wboson,outgoing,false); Energy2 scale(sqr(inpart.mass())); double me=0.; if(inpart.id() == ParticleID::t) { for(unsigned int thel = 0; thel < 2; ++thel) { for(unsigned int bhel = 0; bhel < 2; ++bhel) { for(unsigned int whel = 0; whel < 3; ++whel) { Complex diag = FFWVertex_->evaluate(scale,swave[thel],awave[bhel],vwave[whel]); me += norm(diag); } } } } else if(inpart.id() == ParticleID::tbar) { for(unsigned int thel = 0; thel < 2; ++thel) { for(unsigned int bhel = 0; bhel < 2; ++bhel){ for(unsigned int whel = 0; whel < 3; ++whel) { Complex diag = FFWVertex_->evaluate(scale,swave[bhel],awave[thel],vwave[whel]); me += norm(diag); } } } } return me; } double SMTopDecayer::realME(const Particle & inpart, const ParticleVector & decay, ShowerInteraction inter) { // vertex for emission from fermions AbstractFFVVertexPtr vertex = inter==ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; // spinors vector swave; vector awave; vector vwave,gwave; tPPtr Wboson = abs(decay[0]->id())==ParticleID::Wplus ? decay[0] : decay[1]; tPPtr bquark = abs(decay[0]->id())==ParticleID::Wplus ? decay[1] : decay[0]; // spinors if(inpart.id()>0) { SpinorWaveFunction ::calculateWaveFunctions(swave,const_ptr_cast(&inpart), incoming); SpinorBarWaveFunction::calculateWaveFunctions(awave,bquark,outgoing); } else { SpinorBarWaveFunction::calculateWaveFunctions(awave,const_ptr_cast(&inpart), incoming); SpinorWaveFunction ::calculateWaveFunctions(swave,bquark,outgoing); } // polarization vectors VectorWaveFunction::calculateWaveFunctions(vwave,Wboson,outgoing,false); VectorWaveFunction::calculateWaveFunctions(gwave,decay[2],outgoing,true ); Energy2 scale(sqr(inpart.mass())); double me=0.; vector diag(3,0.); if(inpart.id() == ParticleID::t) { for(unsigned int thel = 0; thel < 2; ++thel) { for(unsigned int bhel = 0; bhel < 2; ++bhel) { for(unsigned int whel = 0; whel < 3; ++whel) { for(unsigned int ghel =0; ghel <3; ghel+=2) { // emission from top SpinorWaveFunction interF = vertex->evaluate(scale,3,inpart.dataPtr(),swave[thel],gwave[ghel]); diag[0] = FFWVertex_->evaluate(scale,interF,awave[bhel],vwave[whel]); // emission from bottom SpinorBarWaveFunction interB = vertex->evaluate(scale,3,bquark->dataPtr()->CC(),awave[bhel],gwave[ghel]); diag[1] = FFWVertex_->evaluate(scale,swave[thel],interB,vwave[whel]); // emission from W if(inter==ShowerInteraction::QED) { VectorWaveFunction interV = WWWVertex_->evaluate(scale,3,Wboson->dataPtr()->CC(),vwave[whel],gwave[ghel]); diag[1] = FFWVertex_->evaluate(scale,swave[thel],awave[bhel],interV); } Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); me += norm(sum); } } } } } else if(inpart.id() == ParticleID::tbar) { for(unsigned int thel = 0; thel < 2; ++thel) { for(unsigned int bhel = 0; bhel < 2; ++bhel){ for(unsigned int whel = 0; whel < 3; ++whel) { for(unsigned int ghel =0; ghel <3; ghel+=2) { // emission from top SpinorBarWaveFunction interB = vertex->evaluate(scale,3,inpart.dataPtr(),awave[thel],gwave[ghel]); diag[1] = FFWVertex_->evaluate(scale,swave[bhel],interB,vwave[whel]); // emission from bottom SpinorWaveFunction interF = vertex->evaluate(scale,3,bquark->dataPtr()->CC(),swave[bhel],gwave[ghel]); diag[0] = FFWVertex_->evaluate(scale,interF,awave[thel],vwave[whel]); // emission from W if(inter==ShowerInteraction::QED) { VectorWaveFunction interV = WWWVertex_->evaluate(scale,3,Wboson->dataPtr()->CC(),vwave[whel],gwave[ghel]); diag[1] = FFWVertex_->evaluate(scale,swave[bhel],awave[thel],interV); } Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); me += norm(sum); } } } } } // divide out the coupling me /= norm(vertex->norm()); // return the total return me; } double SMTopDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption , ShowerInteraction inter) { double Nc = standardModel()->Nc(); double Cf = (sqr(Nc) - 1.) / (2.*Nc); // if(inter==ShowerInteraction::QED) return 0.; // double f = (1. + sqr(e2()) - 2.*sqr(s2()) + s2() + s2()*e2() - 2.*e2()); // // // double B = f/s2(); // Energy2 PbPg = decay3[0]->momentum()*decay3[2]->momentum(); // Energy2 PtPg = inpart.momentum()*decay3[2]->momentum(); // Energy2 PtPb = inpart.momentum()*decay3[0]->momentum(); // double R = Cf *((-4.*sqr(mb())*f/s2()) * ((sqr(mb())*e2()/sqr(PbPg)) + // (sqr(mb())/sqr(PtPg)) - 2.*(PtPb/(PtPg*PbPg))) + // (16. + 8./s2() + 8.*e2()/s2()) * ((PtPg/PbPg) + (PbPg/PtPg)) - // (16./s2()) * (1. + e2())); // return R/B*Constants::pi; double Bnew = loME(inpart,decay2); double Rnew = realME(inpart,decay3,inter); double output = Rnew/Bnew*4.*Constants::pi*sqr(inpart.mass())*UnitRemoval::InvE2; if(inter==ShowerInteraction::QCD) output *= Cf; return output; } diff --git a/Decay/Perturbative/SMWDecayer.cc b/Decay/Perturbative/SMWDecayer.cc --- a/Decay/Perturbative/SMWDecayer.cc +++ b/Decay/Perturbative/SMWDecayer.cc @@ -1,740 +1,742 @@ // -*- C++ -*- // // SMWDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SMWDecayer class. // #include "SMWDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/VectorSpinInfo.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG::Helicity; const double SMWDecayer::EPS_=0.00000001; SMWDecayer::SMWDecayer() : quarkWeight_(6,0.), leptonWeight_(3,0.), CF_(4./3.), NLO_(false) { quarkWeight_[0] = 1.01596; quarkWeight_[1] = 0.0537308; quarkWeight_[2] = 0.0538085; quarkWeight_[3] = 1.01377; quarkWeight_[4] = 1.45763e-05; quarkWeight_[5] = 0.0018143; leptonWeight_[0] = 0.356594; leptonWeight_[1] = 0.356593; leptonWeight_[2] = 0.356333; // intermediates generateIntermediates(false); } void SMWDecayer::doinit() { PerturbativeDecayer::doinit(); // get the vertices from the Standard Model object tcHwSMPtr hwsm=dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "Must have Herwig StandardModel object in" << "SMWDecayer::doinit()" << Exception::runerror; FFWVertex_ = hwsm->vertexFFW(); FFGVertex_ = hwsm->vertexFFG(); WWWVertex_ = hwsm->vertexWWW(); FFPVertex_ = hwsm->vertexFFP(); // make sure they are initialized FFGVertex_->init(); FFWVertex_->init(); WWWVertex_->init(); FFPVertex_->init(); // now set up the decay modes DecayPhaseSpaceModePtr mode; tPDVector extpart(3); vector wgt(0); // W modes extpart[0]=getParticleData(ParticleID::Wplus); // loop for the quarks unsigned int iz=0; for(int ix=1;ix<6;ix+=2) { for(int iy=2;iy<6;iy+=2) { // check that the combination of particles is allowed if(!FFWVertex_->allowed(-ix,iy,ParticleID::Wminus)) throw InitException() << "SMWDecayer::doinit() the W vertex" << "cannot handle all the quark modes" << Exception::abortnow; extpart[1] = getParticleData(-ix); extpart[2] = getParticleData( iy); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,quarkWeight_[iz],wgt); ++iz; } } // loop for the leptons for(int ix=11;ix<17;ix+=2) { // check that the combination of particles is allowed // if(!FFWVertex_->allowed(-ix,ix+1,ParticleID::Wminus)) // throw InitException() << "SMWDecayer::doinit() the W vertex" // << "cannot handle all the lepton modes" // << Exception::abortnow; extpart[1] = getParticleData(-ix); extpart[2] = getParticleData(ix+1); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); addMode(mode,leptonWeight_[(ix-11)/2],wgt); } gluon_ = getParticleData(ParticleID::g); } int SMWDecayer::modeNumber(bool & cc,tcPDPtr parent, const tPDVector & children) const { int imode(-1); if(children.size()!=2) return imode; int id0=parent->id(); tPDVector::const_iterator pit = children.begin(); int id1=(**pit).id(); ++pit; int id2=(**pit).id(); if(abs(id0)!=ParticleID::Wplus) return imode; int idd(0),idu(0); if(abs(id1)%2==1&&abs(id2)%2==0) { idd=abs(id1); idu=abs(id2); } else if(abs(id1)%2==0&&abs(id2)%2==1) { idd=abs(id2); idu=abs(id1); } if(idd==0&&idu==0) { return imode; } else if(idd<=5) { imode=idd+idu/2-2; } else { imode=(idd-1)/2+1; } cc= (id0==ParticleID::Wminus); return imode; } void SMWDecayer::persistentOutput(PersistentOStream & os) const { os << FFWVertex_ << quarkWeight_ << leptonWeight_ << FFGVertex_ << gluon_ << NLO_ << WWWVertex_ << FFPVertex_; } void SMWDecayer::persistentInput(PersistentIStream & is, int) { is >> FFWVertex_ >> quarkWeight_ >> leptonWeight_ >> FFGVertex_ >> gluon_ >> NLO_ >> WWWVertex_ >> FFPVertex_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMWDecayer("Herwig::SMWDecayer", "HwPerturbativeDecay.so"); void SMWDecayer::Init() { static ClassDocumentation documentation ("The SMWDecayer class is the implementation of the decay" " of the W boson to the Standard Model fermions."); static ParVector interfaceWquarkMax ("QuarkMax", "The maximum weight for the decay of the W to quarks", &SMWDecayer::quarkWeight_, 0, 0, 0, -10000, 10000, false, false, true); static ParVector interfaceWleptonMax ("LeptonMax", "The maximum weight for the decay of the W to leptons", &SMWDecayer::leptonWeight_, 0, 0, 0, -10000, 10000, false, false, true); static Switch interfaceNLO ("NLO", "Whether to return the LO or NLO result", &SMWDecayer::NLO_, false, false, false); static SwitchOption interfaceNLOLO (interfaceNLO, "No", "Leading-order result", false); static SwitchOption interfaceNLONLO (interfaceNLO, "Yes", "NLO result", true); } // return the matrix element squared double SMWDecayer::me2(const int, const Particle & part, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); int iferm(1),ianti(0); if(decay[0]->id()>0) swap(iferm,ianti); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(vectors_,rho_, const_ptr_cast(&part), incoming,false); + // fix rho if no correlations + fixRho(rho_); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(vectors_,const_ptr_cast(&part), incoming,true,false); SpinorBarWaveFunction:: constructSpinInfo(wavebar_,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(wave_ ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(wavebar_,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(wave_ ,decay[ianti],outgoing); // compute the matrix element Energy2 scale(sqr(part.mass())); for(unsigned int ifm=0;ifm<2;++ifm) { for(unsigned int ia=0;ia<2;++ia) { for(unsigned int vhel=0;vhel<3;++vhel) { if(iferm>ianti) (*ME())(vhel,ia,ifm)= FFWVertex_->evaluate(scale,wave_[ia],wavebar_[ifm],vectors_[vhel]); else (*ME())(vhel,ifm,ia)= FFWVertex_->evaluate(scale,wave_[ia],wavebar_[ifm],vectors_[vhel]); } } } double output=(ME()->contract(rho_)).real()*UnitRemoval::E2/scale; if(abs(decay[0]->id())<=6) output*=3.; if(decay[0]->hasColour()) decay[0]->antiColourNeighbour(decay[1]); else if(decay[1]->hasColour()) decay[1]->antiColourNeighbour(decay[0]); // leading-order result if(!NLO_) return output; // check decay products coloured, otherwise return if(!decay[0]->dataPtr()->coloured()) return output; // inital masses, couplings etc // W mass mW_ = part.mass(); // strong coupling aS_ = SM().alphaS(sqr(mW_)); // reduced mass double mu1 = (decay[0]->dataPtr()->mass())/mW_; double mu2 = (decay[1]->dataPtr()->mass())/mW_; // scale scale_ = sqr(mW_); // now for the nlo loop correction double virt = CF_*aS_/Constants::pi; // now for the real correction double realFact=0.; for(int iemit=0;iemit<2;++iemit) { double phi = UseRandom::rnd()*Constants::twopi; // set the emitter and the spectator double muj = iemit==0 ? mu1 : mu2; double muk = iemit==0 ? mu2 : mu1; double muj2 = sqr(muj); double muk2 = sqr(muk); // calculate y double yminus = 0.; double yplus = 1.-2.*muk*(1.-muk)/(1.-muj2-muk2); double y = yminus + UseRandom::rnd()*(yplus-yminus); double v = sqrt(sqr(2.*muk2 + (1.-muj2-muk2)*(1.-y))-4.*muk2) /(1.-muj2-muk2)/(1.-y); double zplus = (1.+v)*(1.-muj2-muk2)*y/2./(muj2+(1.-muj2-muk2)*y); double zminus = (1.-v)*(1.-muj2-muk2)*y/2./(muj2+(1.-muj2-muk2)*y); double z = zminus + UseRandom::rnd()*(zplus-zminus); double jac = (1.-y)*(yplus-yminus)*(zplus-zminus); // calculate x1,x2,x3,xT double x2 = 1.-y*(1.-muj2-muk2)-muj2+muk2; double x1 = 1.+muj2-muk2-z*(x2-2.*muk2); // copy the particle objects over for calculateRealEmission vector hardProcess(3); hardProcess[0] = const_ptr_cast(&part); hardProcess[1] = decay[0]; hardProcess[2] = decay[1]; realFact += 0.25*jac*sqr(1.-muj2-muk2)/ sqrt((1.-sqr(muj-muk))*(1.-sqr(muj+muk)))/Constants::twopi *2.*CF_*aS_*calculateRealEmission(x1, x2, hardProcess, phi, muj, muk, iemit, true); } // the born + virtual + real output *= (1. + virt + realFact); return output; } void SMWDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); else leptonWeight_[ix-6]=mode(ix)->maxWeight(); } } } void SMWDecayer::dataBaseOutput(ofstream & output, bool header) const { if(header) output << "update decayers set parameters=\""; for(unsigned int ix=0;ixbornOutgoing().size();++ix) qq.push_back(born->bornOutgoing()[ix]); // ensure quark first if(qq[0]->id()<0) swap(qq[0],qq[1]); // centre of mass energy d_Q_ = (qq[0]->momentum() + qq[1]->momentum()).m(); // quark mass d_m_ = 0.5*(qq[0]->momentum().m()+qq[1]->momentum().m()); // set the other parameters setRho(sqr(d_m_/d_Q_)); setKtildeSymm(); // otherwise can do it initial=1.; final =1.; } bool SMWDecayer::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & , const Energy & highestpT, const vector & ids, const double & d_z, const Energy & d_qt, const Energy & ) { // check we should be applying the veto if(parent->id()!=progenitor->id()|| ids[0]!=ids[1]|| ids[2]->id()!=ParticleID::g) return false; // calculate pt Energy2 d_m2 = parent->momentum().m2(); Energy2 pPerp2 = sqr(d_z*d_qt) - d_m2; if(pPerp2id()>0) weight = qWeightX(d_qt, d_z); else weight = qbarWeightX(d_qt, d_z); // compute veto from weight and return return !UseRandom::rndbool(weight); } void SMWDecayer::setRho(double r) { d_rho_ = r; d_v_ = sqrt(1.-4.*d_rho_); } void SMWDecayer::setKtildeSymm() { d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.; setKtilde2(); } void SMWDecayer::setKtilde2() { double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_); double den = d_kt1_ - d_rho_; d_kt2_ = num/den; } double SMWDecayer::getZfromX(double x1, double x2) { double uval = u(x2); double num = x1 - (2. - x2)*uval; double den = sqrt(x2*x2 - 4.*d_rho_); return uval + num/den; } double SMWDecayer::getKfromX(double x1, double x2) { double zval = getZfromX(x1, x2); return (1.-x2)/(zval*(1.-zval)); } double SMWDecayer::MEV(double x1, double x2) { // Vector part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) - 8.*d_rho_*(1.+2.*d_rho_); double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMWDecayer::MEA(double x1, double x2) { // Axial part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) + 2.*d_rho_*((5.-x1-x2)*(5.-x1-x2) - 19.0 + 4*d_rho_); double den = d_v_*d_v_*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMWDecayer::u(double x2) { return 0.5*(1. + d_rho_/(1.-x2+d_rho_)); } void SMWDecayer:: getXXbar(double kti, double z, double &x, double &xbar) { double w = sqr(d_v_) + kti*(-1. + z)*z*(2. + kti*(-1. + z)*z); if (w < 0) { x = -1.; xbar = -1; } else { x = (1. + sqr(d_v_)*(-1. + z) + sqr(kti*(-1. + z))*z*z*z + z*sqrt(w) - kti*(-1. + z)*z*(2. + z*(-2 + sqrt(w))))/ (1. - kti*(-1. + z)*z + sqrt(w)); xbar = 1. + kti*(-1. + z)*z; } } double SMWDecayer::qWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the quark emission zone? if(k1 < d_kt1_) { rval = MEV(x, xbar)/PS(x, xbar); // is it also in the anti-quark emission zone? if(k2 < d_kt2_) rval *= 0.5; return rval; } return 1.0; } double SMWDecayer::qbarWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the antiquark emission zone? if(k2 < d_kt2_) { rval = MEV(x, xbar)/PS(xbar, x); // is it also in the quark emission zone? if(k1 < d_kt1_) rval *= 0.5; return rval; } return 1.0; } double SMWDecayer::qWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, x, xb); // if exceptionally out of phase space, leave this emission, as there // is no good interpretation for the soft ME correction. if (x < 0 || xb < 0) return 1.0; return qWeight(x, xb); } double SMWDecayer::qbarWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, xb, x); // see above in qWeightX. if (x < 0 || xb < 0) return 1.0; return qbarWeight(x, xb); } double SMWDecayer::PS(double x, double xbar) { double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_)); double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_); double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar); // interesting: the splitting function without the subtraction // term. Actually gives a much worse approximation in the collinear // limit. double brack = (1.+z*z)/(1.-z); double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_); return brack/den; } double SMWDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption, ShowerInteraction inter) { // extract partons and LO momentas vector partons(1,inpart.dataPtr()); vector lomom(1,inpart.momentum()); for(unsigned int ix=0;ix<2;++ix) { partons.push_back(decay2[ix]->dataPtr()); lomom.push_back(decay2[ix]->momentum()); } vector realmom(1,inpart.momentum()); for(unsigned int ix=0;ix<3;++ix) { if(ix==2) partons.push_back(decay3[ix]->dataPtr()); realmom.push_back(decay3[ix]->momentum()); } if(partons[0]->id()<0) { swap(partons[1],partons[2]); swap(lomom[1],lomom[2]); swap(realmom[1],realmom[2]); } scale_ = sqr(inpart.mass()); double lome = loME(partons,lomom); InvEnergy2 reme = realME(partons,realmom,inter); double ratio = reme/lome*sqr(inpart.mass())*4.*Constants::pi; if(inter==ShowerInteraction::QCD) ratio *= CF_; return ratio; } double SMWDecayer::meRatio(vector partons, vector momenta, unsigned int iemitter, bool subtract) const { Lorentz5Momentum q = momenta[1]+momenta[2]+momenta[3]; Energy2 Q2=q.m2(); Energy2 lambda = sqrt((Q2-sqr(momenta[1].mass()+momenta[2].mass()))* (Q2-sqr(momenta[1].mass()-momenta[2].mass()))); InvEnergy2 D[2]; double lome(0.); for(unsigned int iemit=0;iemit<2;++iemit) { unsigned int ispect = iemit==0 ? 1 : 0; Energy2 pipj = momenta[3 ] * momenta[1+iemit ]; Energy2 pipk = momenta[3 ] * momenta[1+ispect]; Energy2 pjpk = momenta[1+iemit] * momenta[1+ispect]; double y = pipj/(pipj+pipk+pjpk); double z = pipk/( pipk+pjpk); Energy mij = sqrt(2.*pipj+sqr(momenta[1+iemit].mass())); Energy2 lamB = sqrt((Q2-sqr(mij+momenta[1+ispect].mass()))* (Q2-sqr(mij-momenta[1+ispect].mass()))); Energy2 Qpk = q*momenta[1+ispect]; Lorentz5Momentum pkt = lambda/lamB*(momenta[1+ispect]-Qpk/Q2*q) +0.5/Q2*(Q2+sqr(momenta[1+ispect].mass())-sqr(momenta[1+ispect].mass()))*q; Lorentz5Momentum pijt = q-pkt; double muj = momenta[1+iemit ].mass()/sqrt(Q2); double muk = momenta[1+ispect].mass()/sqrt(Q2); double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk)) /(1.-y)/(1.-sqr(muj)-sqr(muk)); // dipole term D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) -vt/v*(2.-z+sqr(momenta[1+iemit].mass())/pipj)); // matrix element vector lomom(3); lomom[0] = momenta[0]; if(iemit==0) { lomom[1] = pijt; lomom[2] = pkt ; } else { lomom[2] = pijt; lomom[1] = pkt ; } if(iemit==0) lome = loME(partons,lomom); } InvEnergy2 ratio = realME(partons,momenta,ShowerInteraction::QCD)/lome*abs(D[iemitter]) /(abs(D[0])+abs(D[1])); if(subtract) return Q2*(ratio-2.*D[iemitter]); else return Q2*ratio; } double SMWDecayer::loME(const vector & partons, const vector & momenta) const { // compute the spinors vector vin; vector aout; vector fout; VectorWaveFunction win (momenta[0],partons[0],incoming); SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing); SpinorWaveFunction qbout(momenta[2],partons[2],outgoing); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); } for(unsigned int ix=0;ix<3;++ix){ win.reset(ix); vin.push_back(win); } // temporary storage of the different diagrams // sum over helicities to get the matrix element double total(0.); for(unsigned int inhel=0;inhel<3;++inhel) { for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { Complex diag1 = FFWVertex_->evaluate(scale_,aout[outhel2],fout[outhel1],vin[inhel]); total += norm(diag1); } } } // return the answer return total; } InvEnergy2 SMWDecayer::realME(const vector & partons, const vector & momenta, ShowerInteraction inter) const { // compute the spinors vector vin; vector aout; vector fout; vector gout; VectorWaveFunction win (momenta[0],partons[0],incoming); SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing); SpinorWaveFunction qbout(momenta[2],partons[2],outgoing); VectorWaveFunction gluon(momenta[3],partons[3],outgoing); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); gluon.reset(2*ix); gout.push_back(gluon); } for(unsigned int ix=0;ix<3;++ix){ win.reset(ix); vin.push_back(win); } vector diag(3,0.); double total(0.); AbstractFFVVertexPtr vertex = inter==ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; for(unsigned int inhel1=0;inhel1<3;++inhel1) { for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int outhel3=0;outhel3<2;++outhel3) { SpinorBarWaveFunction off1 = vertex->evaluate(scale_,3,partons[1]->CC(),fout[outhel1],gout[outhel3]); diag[0] = FFWVertex_->evaluate(scale_,aout[outhel2],off1,vin[inhel1]); SpinorWaveFunction off2 = vertex->evaluate(scale_,3,partons[2]->CC(),aout[outhel2],gout[outhel3]); diag[1] = FFWVertex_->evaluate(scale_,off2,fout[outhel1],vin[inhel1]); if(inter==ShowerInteraction::QED) { VectorWaveFunction off3 = WWWVertex_->evaluate(scale_,3,partons[0],vin[inhel1],gout[outhel3]); diag[2] = FFWVertex_->evaluate(scale_,aout[outhel2],fout[outhel1],off3); } // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // me2 total += norm(sum); } } } } // divide out the coupling total /= norm(vertex->norm()); // double g = sqrt(2.)*abs(FFWVertex_->norm()); // double xg = 2.*momenta[3].t()/momenta[0].mass(); // double xe,mue2; // if(abs(partons[1]->id())==ParticleID::eminus) { // xe = 2.*momenta[1].t()/momenta[0].mass(); // mue2 = sqr(momenta[1].mass()/momenta[0].mass()); // } // else { // xe = 2.*momenta[2].t()/momenta[0].mass(); // mue2 = sqr(momenta[2].mass()/momenta[0].mass()); // } // double cg = -4. * g * g * (-pow(mue2, 3.) / 2. + (xg * xg / 4. + (xe / 2. + 1.) * xg + 5. / 2. * xe - 2.) * mue2 * mue2 // + (pow(xg, 3.) / 4. + (xe / 4. - 5. / 4.) * xg * xg + (-7. / 2. * xe + 3.) * xg - 3. * xe * xe // + 11. / 2. * xe - 7. / 2.) * mue2 + (xg * xg / 2. + (xe - 2.) * xg + xe * xe - 2. * xe + 2.) * (-1. + xg + xe)) * (xe - mue2 - 1.) * // pow(xg, -2.) * pow(-1. + xg + xe - mue2, -2.); // cerr << "real " << cg/total << "\n"; // return the total return total*UnitRemoval::InvE2; } double SMWDecayer::calculateRealEmission(double x1, double x2, vector hardProcess, double phi, double muj, double muk, int iemit, bool subtract) const { // make partons data object for meRatio vector partons (3); for(int ix=0; ix<3; ++ix) partons[ix] = hardProcess[ix]->dataPtr(); partons.push_back(gluon_); // calculate x3 double x3 = 2.-x1-x2; double xT = sqrt(max(0.,sqr(x3)-0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1)-4.*sqr(muk)+4.*sqr(muj)) /(sqr(x2)-4.*sqr(muk)))); // calculate the momenta Energy M = mW_; Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*sqr(muk),0.)), 0.5*M*x2,M*muk); Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*sqr(muj),0.)), 0.5*M*x1,M*muj); Lorentz5Momentum pgluon(0.5*M*xT*cos(phi), 0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO); if(abs(pspect.z()+pemit.z()-pgluon.z())/M<1e-6) pgluon.setZ(-pgluon.z()); else if(abs(pspect.z()-pemit.z()+pgluon.z())/M<1e-6) pemit .setZ(- pemit.z()); // boost and rotate momenta LorentzRotation eventFrame( ( hardProcess[1]->momentum() + hardProcess[2]->momentum() ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*hardProcess[iemit+1]->momentum(); eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); vector momenta(3); momenta[0] = hardProcess[0]->momentum(); if(iemit==0) { momenta[2] = eventFrame*pspect; momenta[1] = eventFrame*pemit ; } else { momenta[1] = eventFrame*pspect; momenta[2] = eventFrame*pemit ; } momenta.push_back(eventFrame*pgluon); // calculate the weight double realwgt(0.); if(1.-x1>1e-5 && 1.-x2>1e-5) realwgt = meRatio(partons,momenta,iemit,subtract); return realwgt; } diff --git a/Decay/Perturbative/SMZDecayer.cc b/Decay/Perturbative/SMZDecayer.cc --- a/Decay/Perturbative/SMZDecayer.cc +++ b/Decay/Perturbative/SMZDecayer.cc @@ -1,1119 +1,1121 @@ // -*- C++ -*- // // SMZDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SMZDecayer class. // #include "SMZDecayer.h" #include "Herwig/Utilities/Maths.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "Herwig/Decay/DecayVertex.h" #include "ThePEG/Helicity/VectorSpinInfo.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/Helicity/WaveFunction/VectorWaveFunction.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include using namespace Herwig; using namespace ThePEG::Helicity; const double SMZDecayer::EPS_=0.00000001; SMZDecayer::SMZDecayer() : quarkWeight_(5,0.), leptonWeight_(6,0.), CF_(4./3.), NLO_(false) { quarkWeight_[0] = 0.488029; quarkWeight_[1] = 0.378461; quarkWeight_[2] = 0.488019; quarkWeight_[3] = 0.378027; quarkWeight_[4] = 0.483207; leptonWeight_[0] = 0.110709; leptonWeight_[1] = 0.220276; leptonWeight_[2] = 0.110708; leptonWeight_[3] = 0.220276; leptonWeight_[4] = 0.110458; leptonWeight_[5] = 0.220276; // intermediates generateIntermediates(false); // QED corrections hasRealEmissionME(true); hasOneLoopME(true); } void SMZDecayer::doinit() { PerturbativeDecayer::doinit(); // get the vertices from the Standard Model object tcHwSMPtr hwsm=dynamic_ptr_cast(standardModel()); if(!hwsm) throw InitException() << "Must have Herwig StandardModel object in" << "SMZDecayer::doinit()" << Exception::runerror; // cast the vertices FFZVertex_ = dynamic_ptr_cast(hwsm->vertexFFZ()); FFZVertex_->init(); FFGVertex_ = hwsm->vertexFFG(); FFGVertex_->init(); FFPVertex_ = hwsm->vertexFFP(); FFPVertex_->init(); gluon_ = getParticleData(ParticleID::g); // now set up the decay modes DecayPhaseSpaceModePtr mode; tPDVector extpart(3); vector wgt(0); // the Z decay modes extpart[0]=getParticleData(ParticleID::Z0); // loop over the quarks and the leptons for(int istep=0;istep<11;istep+=10) { for(int ix=1;ix<7;++ix) { int iy=istep+ix; if(iy==6) continue; extpart[1] = getParticleData(-iy); extpart[2] = getParticleData( iy); mode = new_ptr(DecayPhaseSpaceMode(extpart,this)); if(iy<=6) addMode(mode, quarkWeight_.at(ix-1),wgt); else addMode(mode,leptonWeight_.at(iy-11),wgt); } } } int SMZDecayer::modeNumber(bool & cc,tcPDPtr parent, const tPDVector & children) const { int imode(-1); if(children.size()!=2) return imode; int id0=parent->id(); tPDVector::const_iterator pit = children.begin(); int id1=(**pit).id(); ++pit; int id2=(**pit).id(); // Z to quarks or leptons cc =false; if(id0!=ParticleID::Z0) return imode; if(abs(id1)<6&&id1==-id2) { imode=abs(id1)-1; } else if(abs(id1)>=11&&abs(id1)<=16&&id1==-id2) { imode=abs(id1)-6; } cc = false; return imode; } void SMZDecayer::persistentOutput(PersistentOStream & os) const { os << FFZVertex_ << FFPVertex_ << FFGVertex_ << quarkWeight_ << leptonWeight_ << NLO_ << gluon_; } void SMZDecayer::persistentInput(PersistentIStream & is, int) { is >> FFZVertex_ >> FFPVertex_ >> FFGVertex_ >> quarkWeight_ >> leptonWeight_ >> NLO_ >> gluon_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigSMZDecayer("Herwig::SMZDecayer", "HwPerturbativeDecay.so"); void SMZDecayer::Init() { static ClassDocumentation documentation ("The SMZDecayer class is the implementation of the decay" " Z boson to the Standard Model fermions."); static ParVector interfaceZquarkMax ("QuarkMax", "The maximum weight for the decay of the Z to quarks", &SMZDecayer::quarkWeight_, 0, 0, 0, -10000, 10000, false, false, true); static ParVector interfaceZleptonMax ("LeptonMax", "The maximum weight for the decay of the Z to leptons", &SMZDecayer::leptonWeight_, 0, 0, 0, -10000, 10000, false, false, true); static Switch interfaceNLO ("NLO", "Whether to return the LO or NLO result", &SMZDecayer::NLO_, false, false, false); static SwitchOption interfaceNLOLO (interfaceNLO, "No", "Leading-order result", false); static SwitchOption interfaceNLONLO (interfaceNLO, "Yes", "NLO result", true); } // return the matrix element squared double SMZDecayer::me2(const int, const Particle & part, const ParticleVector & decay, MEOption meopt) const { if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); int iferm(1),ianti(0); if(decay[0]->id()>0) swap(iferm,ianti); if(meopt==Initialize) { VectorWaveFunction::calculateWaveFunctions(_vectors,_rho, const_ptr_cast(&part), incoming,false); + // fix rho if no correlations + fixRho(_rho); } if(meopt==Terminate) { VectorWaveFunction::constructSpinInfo(_vectors,const_ptr_cast(&part), incoming,true,false); SpinorBarWaveFunction:: constructSpinInfo(_wavebar,decay[iferm],outgoing,true); SpinorWaveFunction:: constructSpinInfo(_wave ,decay[ianti],outgoing,true); return 0.; } SpinorBarWaveFunction:: calculateWaveFunctions(_wavebar,decay[iferm],outgoing); SpinorWaveFunction:: calculateWaveFunctions(_wave ,decay[ianti],outgoing); // compute the matrix element Energy2 scale(sqr(part.mass())); unsigned int ifm,ia,vhel; for(ifm=0;ifm<2;++ifm) { for(ia=0;ia<2;++ia) { for(vhel=0;vhel<3;++vhel) { if(iferm>ianti) (*ME())(vhel,ia,ifm)= FFZVertex_->evaluate(scale,_wave[ia],_wavebar[ifm],_vectors[vhel]); else (*ME())(vhel,ifm,ia)= FFZVertex_->evaluate(scale,_wave[ia],_wavebar[ifm],_vectors[vhel]); } } } double output=(ME()->contract(_rho)).real()*UnitRemoval::E2/scale; if(abs(decay[0]->id())<=6) output*=3.; if(decay[0]->hasColour()) decay[0]->antiColourNeighbour(decay[1]); else if(decay[1]->hasColour()) decay[1]->antiColourNeighbour(decay[0]); // if LO return if(!NLO_) return output; // check decay products coloured, otherwise return if(!decay[0]->dataPtr()->coloured()) return output; // inital masses, couplings etc // fermion mass Energy particleMass = decay[0]->dataPtr()->mass(); // Z mass mZ_ = part.mass(); // strong coupling aS_ = SM().alphaS(sqr(mZ_)); // reduced mass mu_ = particleMass/mZ_; mu2_ = sqr(mu_); // scale scale_ = sqr(mZ_); // compute the spinors vector aout; vector fout; vector vin; SpinorBarWaveFunction qkout(decay[0]->momentum(),decay[0]->dataPtr(),outgoing); SpinorWaveFunction qbout(decay[1]->momentum(),decay[1]->dataPtr(),outgoing); VectorWaveFunction zin (part.momentum() ,part.dataPtr() ,incoming); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); } for(unsigned int ix=0;ix<3;++ix){ zin.reset(ix); vin.push_back(zin); } // temporary storage of the different diagrams // sum over helicities to get the matrix element double total=0.; if(mu_!=0.) { LorentzPolarizationVector momDiff = (decay[0]->momentum()-decay[1]->momentum())/2./ (decay[0]->momentum().mass()+decay[1]->momentum().mass()); // scalars Complex scalar1 = zin.wave().dot(momDiff); for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int inhel=0;inhel<3;++inhel) { // first the LO bit Complex diag1 = FFZVertex_->evaluate(scale_,aout[outhel2], fout[outhel1],vin[inhel]); // extra stuff for NLO LorentzPolarizationVector left = aout[outhel2].wave().leftCurrent(fout[outhel1].wave()); LorentzPolarizationVector right = aout[outhel2].wave().rightCurrent(fout[outhel1].wave()); Complex scalar = aout[outhel2].wave().scalar(fout[outhel1].wave()); // nlo specific pieces Complex diag3 = Complex(0.,1.)*FFZVertex_->norm()* (FFZVertex_->right()*( left.dot(zin.wave())) + FFZVertex_-> left()*(right.dot(zin.wave())) - ( FFZVertex_-> left()+FFZVertex_->right())*scalar1*scalar); // nlo piece total += real(diag1*conj(diag3) + diag3*conj(diag1)); } } } // rescale total *= UnitRemoval::E2/scale_; } else { total = ZERO; } // now for the NLO bit double mu4 = sqr(mu2_); double lmu = mu_!=0. ? log(mu_) : 0.; double v = sqrt(1.-4.*mu2_),v2(sqr(v)); double omv = 4.*mu2_/(1.+v); double f1,f2,fNS,VNS; double r = omv/(1.+v); double lr = mu_!=0. ? log(r) : 0.; // normal form if(mu_>1e-4) { f1 = CF_*aS_/Constants::pi* ( +1. + 3.*log(0.5*(1.+v)) - 1.5*log(0.5*(1.+v2)) + sqr(Constants::pi)/6. - 0.5*sqr(lr) - (1.+v2)/v*(lr*log(1.+v2) + sqr(Constants::pi)/12. -0.5*log(4.*mu2_)*lr + 0.25*sqr(lr))); fNS = -0.5*(1.+2.*v2)*lr/v + 1.5*lr - 2./3.*sqr(Constants::pi) + 0.5*sqr(lr) + (1.+v2)/v*(Herwig::Math::ReLi2(r) + sqr(Constants::pi)/3. - 0.25*sqr(lr) + lr*log((2.*v/ (1.+v)))); VNS = 1.5*log(0.5*(1.+v2)) + 0.5*(1.+v2)/v*( 2.*lr*log(2.*(1.+v2)/sqr(1.+v)) + 2.*Herwig::Math::ReLi2(sqr(r)) - 2.*Herwig::Math::ReLi2(2.*v/(1.+v)) - sqr(Constants::pi)/6.) + log(1.-mu_) - 2.*log(1.-2.*mu_) - 4.*mu2_/(1.+v2)*log(mu_/(1.-mu_)) - mu_/(1.-mu_) + 4.*(2.*mu2_-mu_)/(1.+v2) + 0.5*sqr(Constants::pi); f2 = CF_*aS_/Constants::pi*mu2_*lr/v; } // small mass limit else { f1 = -CF_*aS_/Constants::pi/6.* ( - 6. - 24.*lmu*mu2_ - 15.*mu4 - 12.*mu4*lmu - 24.*mu4*sqr(lmu) + 2.*mu4*sqr(Constants::pi) - 12.*mu2_*mu4 - 96.*mu2_*mu4*sqr(lmu) + 8.*mu2_*mu4*sqr(Constants::pi) - 80.*mu2_*mu4*lmu); fNS = - mu2_/18.*( + 36.*lmu - 36. - 45.*mu2_ + 216.*lmu*mu2_ - 24.*mu2_*sqr(Constants::pi) + 72.*mu2_*sqr(lmu) - 22.*mu4 + 1032.*mu4 * lmu - 96.*mu4*sqr(Constants::pi) + 288.*mu4*sqr(lmu)); VNS = - mu2_/1260.*(-6930. + 7560.*lmu + 2520.*mu_ - 16695.*mu2_ + 1260.*mu2_*sqr(Constants::pi) + 12600.*lmu*mu2_ + 1344.*mu_*mu2_ - 52780.*mu4 + 36960.*mu4*lmu + 5040.*mu4*sqr(Constants::pi) - 12216.*mu_*mu4); f2 = CF_*aS_*mu2_/Constants::pi*( 2.*lmu + 4.*mu2_*lmu + 2.*mu2_ + 12.*mu4*lmu + 7.*mu4); } // add up bits for f1 f1 += CF_*aS_/Constants::pi*(fNS+VNS); double realFact(0.); for(int iemit=0;iemit<2;++iemit) { // now for the real correction double phi = UseRandom::rnd()*Constants::twopi; // calculate y double yminus = 0.; double yplus = 1.-2.*mu_*(1.-mu_)/(1.-2*mu2_); double y = yminus + UseRandom::rnd()*(yplus-yminus); // calculate z double v1 = sqrt(sqr(2.*mu2_+(1.-2.*mu2_)*(1.-y))-4.*mu2_)/(1.-2.*mu2_)/(1.-y); double zplus = (1.+v1)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y); double zminus = (1.-v1)*(1.-2.*mu2_)*y/2./(mu2_ +(1.-2.*mu2_)*y); double z = zminus + UseRandom::rnd()*(zplus-zminus); double jac = (1.-y)*(yplus-yminus)*(zplus-zminus); // calculate x1,x2 double x2 = 1. - y*(1.-2.*mu2_); double x1 = 1. - z*(x2-2.*mu2_); // copy the particle objects over for calculateRealEmission vector hardProcess(3); hardProcess[0] = const_ptr_cast(&part); hardProcess[1] = decay[0]; hardProcess[2] = decay[1]; // total real emission contribution realFact += 0.25*jac*sqr(1.-2.*mu2_)/ sqrt(1.-4.*mu2_)/Constants::twopi *2.*CF_*aS_*calculateRealEmission(x1, x2, hardProcess, phi, iemit, true); } // the born + virtual + real output = output*(1. + f1 + realFact) + f2*total; return output; } void SMZDecayer::doinitrun() { PerturbativeDecayer::doinitrun(); if(initialize()) { for(unsigned int ix=0;ixmaxWeight(); else if(ix<11) leptonWeight_[ix-5 ]=mode(ix)->maxWeight(); } } } void SMZDecayer::dataBaseOutput(ofstream & output, bool header) const { if(header) output << "update decayers set parameters=\""; for(unsigned int ix=0;ixmomentum().phi(); // wavefunctions for the decaying particle in the rotated dipole frame vector vec1 = _vectors; for(unsigned int ix=0;ix vec2 = _vectors; for(unsigned int ix=0;ixid()<0) swap(iferm,ianti); // wavefunctions for the particles before the radiation // wavefunctions for the outgoing fermion SpinorBarWaveFunction wavebartemp; Lorentz5Momentum ptemp = - _wavebar[0].momentum(); ptemp *= rot2; if(ptemp.perp()/ptemp.e()<1e-10) { ptemp.setX(ZERO); ptemp.setY(ZERO); } wavebartemp = SpinorBarWaveFunction(ptemp,_wavebar[0].particle(),outgoing); // wavefunctions for the outgoing antifermion SpinorWaveFunction wavetemp; ptemp = - _wave[0].momentum(); ptemp *= rot2; if(ptemp.perp()/ptemp.e()<1e-10) { ptemp.setX(ZERO); ptemp.setY(ZERO); } wavetemp = SpinorWaveFunction(ptemp,_wave[0].particle(),outgoing); // loop over helicities vector wf_old; vector wfb_old; for(unsigned int ihel=0;ihel<2;++ihel) { wavetemp.reset(ihel); wf_old.push_back(wavetemp); wavebartemp.reset(ihel); wfb_old.push_back(wavebartemp); } // calculate the wave functions for the new fermions // ensure the momenta have pT=0 for(unsigned int ix=0;ix<2;++ix) { Lorentz5Momentum ptemp = children[ix]->momentum(); if(ptemp.perp()/ptemp.e()<1e-10) { ptemp.setX(ZERO); ptemp.setY(ZERO); children[ix]->set5Momentum(ptemp); } } // calculate the wavefunctions vector wfb; SpinorBarWaveFunction::calculateWaveFunctions(wfb,children[iferm],outgoing); vector wf; SpinorWaveFunction::calculateWaveFunctions (wf ,children[ianti],outgoing); // wave functions for the photons vector photon; VectorWaveFunction::calculateWaveFunctions(photon,children[2],outgoing,true); // loop to calculate the matrix elements Complex lome[3][2][2],diffme[3][2][2][2],summe[3][2][2][2]; Energy2 scale(sqr(parent.mass())); Complex diff[2]={0.,0.}; Complex sum [2]={0.,0.}; for(unsigned int ifm=0;ifm<2;++ifm) { for(unsigned int ia=0;ia<2;++ia) { for(unsigned int vhel=0;vhel<3;++vhel) { // calculation of the leading-order matrix element Complex loamp = FFZVertex_->evaluate(scale,wf_old[ia], wfb_old[ifm],vec2[vhel]); Complex lotemp = FFZVertex_->evaluate(scale,wf[ia], wfb[ifm],vec1[vhel]); if(iferm>ianti) lome[vhel][ia][ifm] = loamp; else lome[vhel][ifm][ia] = loamp; // photon loop for the real emmision terms for(unsigned int phel=0;phel<2;++phel) { // radiation from the antifermion // normal case with small angle treatment if(children[2 ]->momentum().z()/ children[iferm]->momentum().z()>=ZERO && iemitter == iferm ) { Complex dipole = e*double(children[iferm]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[iferm]->momentum()*photon[2*phel].wave())/ (children[iferm]->momentum()*children[2]->momentum()); // sum and difference SpinorBarWaveFunction foff = FFPVertex_->evaluateSmall(ZERO,3,children[iferm]->dataPtr()->CC(), wfb[ifm],photon[2*phel], ifm,2*phel,ctheta,phi,stheta,false); diff[0] = FFZVertex_->evaluate(scale,wf[ia],foff,vec1[vhel]) + e*double(children[iferm]->dataPtr()->iCharge())/3.* UnitRemoval::E*(lotemp-loamp)* (children[iferm]->momentum()*photon[2*phel].wave())/ (children[iferm]->momentum()*children[2]->momentum()); sum [0] = diff[0]+2.*dipole; } // special if fermion backwards else { SpinorBarWaveFunction foff = FFPVertex_->evaluate(ZERO,3,children[iferm]->dataPtr()->CC(), wfb[ifm],photon[2*phel]); Complex diag = FFZVertex_->evaluate(scale,wf[ia],foff,vec1[vhel]); Complex dipole = e*double(children[iferm]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[iferm]->momentum()*photon[2*phel].wave())/ (children[iferm]->momentum()*children[2]->momentum()); diff[0] = diag-dipole; sum [0] = diag+dipole; } // radiation from the anti fermion // small angle case in general if(children[2 ]->momentum().z()/ children[ianti]->momentum().z()>=ZERO && iemitter == ianti ) { Complex dipole = e*double(children[ianti]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[ianti]->momentum()*photon[2*phel].wave())/ (children[ianti]->momentum()*children[2]->momentum()); // sum and difference SpinorWaveFunction foff = FFPVertex_->evaluateSmall(ZERO,3,children[ianti]->dataPtr()->CC(), wf[ia],photon[2*phel], ia,2*phel,ctheta,phi,stheta,false); diff[1] = FFZVertex_->evaluate(scale,foff ,wfb[ifm],vec1[vhel]) + e*double(children[ianti]->dataPtr()->iCharge())/3.* UnitRemoval::E*(lotemp-loamp)* (children[ianti]->momentum()*photon[2*phel].wave())/ (children[ianti]->momentum()*children[2]->momentum()); sum [1] = diff[1]+2.*dipole; } // special if fermion backwards after radiation else { SpinorWaveFunction foff = FFPVertex_->evaluate(ZERO,3,children[ianti]->dataPtr()->CC(), wf[ia],photon[2*phel]); Complex diag = FFZVertex_->evaluate(scale,foff ,wfb[ifm],vec1[vhel]); Complex dipole = e*double(children[ianti]->dataPtr()->iCharge())/3.* UnitRemoval::E*loamp* (children[ianti]->momentum()*photon[2*phel].wave())/ (children[ianti]->momentum()*children[2]->momentum()); // sum and difference diff[1] = diag - dipole; sum [1] = diag + dipole; } // add to me if(iferm>ianti) { diffme[vhel][ia][ifm][phel] = diff[0] + diff[1]; summe [vhel][ia][ifm][phel] = sum[0] + sum[1] ; } else { diffme [vhel][ifm][ia][phel] = diff[0] + diff[1]; summe [vhel][ifm][ia][phel] = sum[0] + sum[1] ; } } } } } // cerr << parent << "\n"; // for(unsigned int ix=0;ixdataPtr()->iCharge()* // children[1]->dataPtr()->iCharge()/9.; // Energy2 ubar = 2.*children[0]->momentum()*children[2]->momentum(); // Energy2 tbar = 2.*children[1]->momentum()*children[2]->momentum(); // double mu2 = sqr(children[1]->mass()/parent.mass()); // double gL = (FFZVertex_->left() *FFZVertex_->norm()).real(); // double gR = (FFZVertex_->right()*FFZVertex_->norm()).real(); // Energy2 den = sqr(parent.mass())*(((sqr(gL)+sqr(gR))*(1-mu2)+6.*mu2*gL*gR)); // InvEnergy2 anal = -iCharge*( 2.*(ubar/tbar+tbar/ubar)/sqr(parent.mass())+ // 4.*mu2/den*((sqr(gL)+sqr(gR))*(1+ubar/tbar+tbar/ubar) // -2.*gL*gR*(1.+2.*(ubar/tbar+tbar/ubar)))); // cerr << "testing ratio " << parent.PDGName() // << " " << difference.real()/sqr(e)/lo.real()*UnitRemoval::InvE2/(anal) << "\n" // << stheta << " " << ctheta << "\n"; return difference.real()/sqr(e)/lo.real()*UnitRemoval::InvE2; } double SMZDecayer::oneLoopVirtualME(unsigned int, const Particle & parent, const ParticleVector & children) { assert(children.size()==2); // velocities of the particles double beta = sqrt(1.-4.*sqr(children[0]->mass()/parent.mass())); double opb = 1.+beta; double omb = 4.*sqr(children[0]->mass()/parent.mass())/opb; // couplings double gL = (FFZVertex_->left() *FFZVertex_->norm()).real(); double gR = (FFZVertex_->right()*FFZVertex_->norm()).real(); double gA = 0.5*(gL-gR); double gV = 0.5*(gL+gR); // correction terms double ln = log(omb/opb); double f1 = 1. + ln*beta; double fA = 1. + ln/beta; InvEnergy f2 = 0.5*sqrt(omb*opb)/parent.mass()/beta*ln; // momentum difference for the loop Lorentz5Momentum q = children[0]->momentum()-children[1]->momentum(); if(children[0]->id()<0) q *= -1.; // spinors vector > sp; vector > sbar; for(unsigned int ix=0;ix<2;++ix) { sp .push_back( _wave[ix].dimensionedWave()); sbar.push_back(_wavebar[ix].dimensionedWave()); } // polarization vectors vector pol; for(unsigned int ix=0;ix<3;++ix) pol.push_back(_vectors[ix].wave()); // matrix elements complex lome[3][2][2],loopme[3][2][2]; for(unsigned int vhel=0;vhel<3;++vhel) { for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { complex vector = sp[ihel1].generalCurrent(sbar[ihel2], 1.,1.).dot(pol[vhel]); complex axial = sp[ihel1].generalCurrent(sbar[ihel2],-1.,1.).dot(pol[vhel]); complex scalar = sp[ihel1].scalar(sbar[ihel2])*(q*pol[vhel]); lome [vhel][ihel1][ihel2] = gV* vector-gA* axial; loopme[vhel][ihel1][ihel2] = gV*f1*vector-gA*fA*axial+scalar*f2*gV; } } } // sum sums complex den(ZERO),num(ZERO); for(unsigned int vhel1=0;vhel1<3;++vhel1) { for(unsigned int vhel2=0;vhel2<3;++vhel2) { for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { num += _rho(vhel1,vhel2)* ( lome[vhel1][ihel1][ihel2]*conj(loopme[vhel2][ihel1][ihel2])+ loopme[vhel1][ihel1][ihel2]*conj( lome[vhel2][ihel1][ihel2])); den += _rho(vhel1,vhel2)* lome[vhel1][ihel1][ihel2]*conj(lome[vhel2][ihel1][ihel2]); } } } } // prefactor double iCharge = children[0]->dataPtr()->iCharge()* children[1]->dataPtr()->iCharge()/9.; double pre = 0.5*SM().alphaEM()*iCharge/Constants::pi; // output return pre*num.real()/den.real(); } void SMZDecayer:: initializeMECorrection(RealEmissionProcessPtr born, double & initial, double & final) { // get the quark and antiquark ParticleVector qq; for(unsigned int ix=0;ixbornOutgoing().size();++ix) qq.push_back(born->bornOutgoing()[ix]); // ensure quark first if(qq[0]->id()<0) swap(qq[0],qq[1]); // centre of mass energy d_Q_ = (qq[0]->momentum() + qq[1]->momentum()).m(); // quark mass d_m_ = 0.5*(qq[0]->momentum().m()+qq[1]->momentum().m()); // set the other parameters setRho(sqr(d_m_/d_Q_)); setKtildeSymm(); // otherwise can do it initial=1.; final =1.; } bool SMZDecayer::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & , const Energy & highestpT, const vector & ids, const double & d_z, const Energy & d_qt, const Energy &) { // check we should be applying the veto if(parent->id()!=progenitor->id()|| ids[0]->id()!=ids[1]->id()|| ids[2]->id()!=ParticleID::g) return false; // calculate pt Energy2 d_m2 = parent->momentum().m2(); Energy pPerp = (1.-d_z)*sqrt( sqr(d_z*d_qt) - d_m2); // if not hardest so far don't apply veto if(pPerpid()>0) weight = qWeightX(d_qt, d_z); else weight = qbarWeightX(d_qt, d_z); // compute veto from weight and return return !UseRandom::rndbool(weight); } void SMZDecayer::setRho(double r) { d_rho_ = r; d_v_ = sqrt(1.-4.*d_rho_); } void SMZDecayer::setKtildeSymm() { d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.; setKtilde2(); } void SMZDecayer::setKtilde2() { double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_); double den = d_kt1_ - d_rho_; d_kt2_ = num/den; } double SMZDecayer::getZfromX(double x1, double x2) { double uval = u(x2); double num = x1 - (2. - x2)*uval; double den = sqrt(x2*x2 - 4.*d_rho_); return uval + num/den; } double SMZDecayer::getKfromX(double x1, double x2) { double zval = getZfromX(x1, x2); return (1.-x2)/(zval*(1.-zval)); } double SMZDecayer::MEV(double x1, double x2) { // Vector part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) - 8.*d_rho_*(1.+2.*d_rho_); double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMZDecayer::MEA(double x1, double x2) { // Axial part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) + 2.*d_rho_*((5.-x1-x2)*(5.-x1-x2) - 19.0 + 4*d_rho_); double den = d_v_*d_v_*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double SMZDecayer::u(double x2) { return 0.5*(1. + d_rho_/(1.-x2+d_rho_)); } void SMZDecayer:: getXXbar(double kti, double z, double &x, double &xbar) { double w = sqr(d_v_) + kti*(-1. + z)*z*(2. + kti*(-1. + z)*z); if (w < 0) { x = -1.; xbar = -1; } else { x = (1. + sqr(d_v_)*(-1. + z) + sqr(kti*(-1. + z))*z*z*z + z*sqrt(w) - kti*(-1. + z)*z*(2. + z*(-2 + sqrt(w))))/ (1. - kti*(-1. + z)*z + sqrt(w)); xbar = 1. + kti*(-1. + z)*z; } } double SMZDecayer::qWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the quark emission zone? if(k1 < d_kt1_) { rval = MEV(x, xbar)/PS(x, xbar); // is it also in the anti-quark emission zone? if(k2 < d_kt2_) rval *= 0.5; return rval; } return 1.0; } double SMZDecayer::qbarWeight(double x, double xbar) { double rval; double xg = 2. - xbar - x; // always return one in the soft gluon region if(xg < EPS_) return 1.0; // check it is in the phase space if((1.-x)*(1.-xbar)*(1.-xg) < d_rho_*xg*xg) return 0.0; double k1 = getKfromX(x, xbar); double k2 = getKfromX(xbar, x); // Is it in the antiquark emission zone? if(k2 < d_kt2_) { rval = MEV(x, xbar)/PS(xbar, x); // is it also in the quark emission zone? if(k1 < d_kt1_) rval *= 0.5; return rval; } return 1.0; } double SMZDecayer::qWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, x, xb); // if exceptionally out of phase space, leave this emission, as there // is no good interpretation for the soft ME correction. if (x < 0 || xb < 0) return 1.0; return qWeight(x, xb); } double SMZDecayer::qbarWeightX(Energy qtilde, double z) { double x, xb; getXXbar(sqr(qtilde/d_Q_), z, xb, x); // see above in qWeightX. if (x < 0 || xb < 0) return 1.0; return qbarWeight(x, xb); } double SMZDecayer::PS(double x, double xbar) { double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_)); double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_); double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar); // interesting: the splitting function without the subtraction // term. Actually gives a much worse approximation in the collinear // limit. double brack = (1.+z*z)/(1.-z); double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_); return brack/den; } double SMZDecayer::matrixElementRatio(const Particle & inpart, const ParticleVector & decay2, const ParticleVector & decay3, MEOption, ShowerInteraction inter) { // extract partons and LO momentas vector partons(1,inpart.dataPtr()); vector lomom(1,inpart.momentum()); for(unsigned int ix=0;ix<2;++ix) { partons.push_back(decay2[ix]->dataPtr()); lomom.push_back(decay2[ix]->momentum()); } vector realmom(1,inpart.momentum()); for(unsigned int ix=0;ix<3;++ix) { if(ix==2) partons.push_back(decay3[ix]->dataPtr()); realmom.push_back(decay3[ix]->momentum()); } if(partons[0]->id()<0) { swap(partons[1],partons[2]); swap(lomom[1],lomom[2]); swap(realmom[1],realmom[2]); } scale_ = sqr(inpart.mass()); double lome = loME(partons,lomom); InvEnergy2 reme = realME(partons,realmom,inter); double ratio = reme/lome*sqr(inpart.mass())*4.*Constants::pi; if(inter==ShowerInteraction::QCD) ratio *= CF_; return ratio; } double SMZDecayer::meRatio(vector partons, vector momenta, unsigned int iemitter, bool subtract) const { Lorentz5Momentum q = momenta[1]+momenta[2]+momenta[3]; Energy2 Q2=q.m2(); Energy2 lambda = sqrt((Q2-sqr(momenta[1].mass()+momenta[2].mass()))* (Q2-sqr(momenta[1].mass()-momenta[2].mass()))); InvEnergy2 D[2]; double lome[2]; for(unsigned int iemit=0;iemit<2;++iemit) { unsigned int ispect = iemit==0 ? 1 : 0; Energy2 pipj = momenta[3 ] * momenta[1+iemit ]; Energy2 pipk = momenta[3 ] * momenta[1+ispect]; Energy2 pjpk = momenta[1+iemit] * momenta[1+ispect]; double y = pipj/(pipj+pipk+pjpk); double z = pipk/( pipk+pjpk); Energy mij = sqrt(2.*pipj+sqr(momenta[1+iemit].mass())); Energy2 lamB = sqrt((Q2-sqr(mij+momenta[1+ispect].mass()))* (Q2-sqr(mij-momenta[1+ispect].mass()))); Energy2 Qpk = q*momenta[1+ispect]; Lorentz5Momentum pkt = lambda/lamB*(momenta[1+ispect]-Qpk/Q2*q) +0.5/Q2*(Q2+sqr(momenta[1+ispect].mass())-sqr(momenta[1+ispect].mass()))*q; Lorentz5Momentum pijt = q-pkt; double muj = momenta[1+iemit ].mass()/sqrt(Q2); double muk = momenta[1+ispect].mass()/sqrt(Q2); double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); double v = sqrt(sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk)) /(1.-y)/(1.-sqr(muj)-sqr(muk)); // dipole term D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) -vt/v*(2.-z+sqr(momenta[1+iemit].mass())/pipj)); // matrix element vector lomom(3); lomom[0] = momenta[0]; if(iemit==0) { lomom[1] = pijt; lomom[2] = pkt ; } else { lomom[2] = pijt; lomom[1] = pkt ; } lome[iemit] = loME(partons,lomom); } InvEnergy2 ratio = realME(partons,momenta,ShowerInteraction::QCD)*abs(D[iemitter]) /(abs(D[0]*lome[0])+abs(D[1]*lome[1])); if(subtract) return Q2*(ratio-2.*D[iemitter]); else return Q2*ratio; } double SMZDecayer::loME(const vector & partons, const vector & momenta) const { // compute the spinors vector vin; vector aout; vector fout; VectorWaveFunction zin (momenta[0],partons[0],incoming); SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing); SpinorWaveFunction qbout(momenta[2],partons[2],outgoing); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); } for(unsigned int ix=0;ix<3;++ix){ zin.reset(ix); vin.push_back(zin); } // temporary storage of the different diagrams // sum over helicities to get the matrix element double total(0.); for(unsigned int inhel=0;inhel<3;++inhel) { for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { Complex diag1 = FFZVertex_->evaluate(scale_,aout[outhel2],fout[outhel1],vin[inhel]); total += norm(diag1); } } } // return the answer return total; } InvEnergy2 SMZDecayer::realME(const vector & partons, const vector & momenta, ShowerInteraction inter) const { AbstractFFVVertexPtr vertex = inter==ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; // compute the spinors vector vin; vector aout; vector fout; vector gout; VectorWaveFunction zin (momenta[0],partons[0],incoming); SpinorBarWaveFunction qkout(momenta[1],partons[1],outgoing); SpinorWaveFunction qbout(momenta[2],partons[2],outgoing); VectorWaveFunction gluon(momenta[3],partons[3],outgoing); for(unsigned int ix=0;ix<2;++ix){ qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); gluon.reset(2*ix); gout.push_back(gluon); } for(unsigned int ix=0;ix<3;++ix){ zin.reset(ix); vin.push_back(zin); } vector diag(2,0.); double total(0.); for(unsigned int inhel1=0;inhel1<3;++inhel1) { for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int outhel3=0;outhel3<2;++outhel3) { SpinorBarWaveFunction off1 = vertex->evaluate(scale_,3,partons[1]->CC(),fout[outhel1],gout[outhel3]); diag[0] = FFZVertex_->evaluate(scale_,aout[outhel2],off1,vin[inhel1]); SpinorWaveFunction off2 = vertex->evaluate(scale_,3,partons[2]->CC(),aout[outhel2],gout[outhel3]); diag[1] = FFZVertex_->evaluate(scale_,off2,fout[outhel1],vin[inhel1]); // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // me2 total += norm(sum); } } } } // divide out the coupling total /= norm(vertex->norm()); // return the total return total*UnitRemoval::InvE2; } double SMZDecayer::calculateRealEmission(double x1, double x2, vector hardProcess, double phi, bool subtract) const { // make partons data object for meRatio vector partons (3); for(int ix=0; ix<3; ++ix) partons[ix] = hardProcess[ix]->dataPtr(); partons.push_back(gluon_); // calculate x3 double x3 = 2.-x1-x2; double xT = sqrt(max(0.,sqr(x3) -0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1))/(sqr(x2)-4.*mu2_))); // calculate the momenta Energy M = mZ_; Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*mu2_,0.)),0.5*M*x2,M*mu_); Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*mu2_,0.)),0.5*M*x1,M*mu_); Lorentz5Momentum pgluon(0.5*M*xT*cos(phi), 0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO); if(abs(pspect.z()+pemit.z()-pgluon.z())/M<1e-6) pgluon.setZ(-pgluon.z()); else if(abs(pspect.z()-pemit.z()+pgluon.z())/M<1e-6) pemit .setZ(- pemit.z()); // loop over the possible emitting partons double realwgt(0.); for(unsigned int iemit=0;iemit<2;++iemit) { // boost and rotate momenta LorentzRotation eventFrame( ( hardProcess[1]->momentum() + hardProcess[2]->momentum() ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*hardProcess[iemit+1]->momentum(); eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); vector momenta(3); momenta[0] = hardProcess[0]->momentum(); if(iemit==0) { momenta[2] = eventFrame*pspect; momenta[1] = eventFrame*pemit ; } else { momenta[1] = eventFrame*pspect; momenta[2] = eventFrame*pemit ; } momenta.push_back(eventFrame*pgluon); // calculate the weight if(1.-x1>1e-5 && 1.-x2>1e-5) realwgt += meRatio(partons,momenta,iemit,subtract); } // total real emission contribution return realwgt; } double SMZDecayer::calculateRealEmission(double x1, double x2, vector hardProcess, double phi, bool subtract, int emitter) const { // make partons data object for meRatio vector partons (3); for(int ix=0; ix<3; ++ix) partons[ix] = hardProcess[ix]->dataPtr(); partons.push_back(gluon_); // calculate x3 double x3 = 2.-x1-x2; double xT = sqrt(max(0.,sqr(x3) -0.25*sqr(sqr(x2)+sqr(x3)-sqr(x1))/(sqr(x2)-4.*mu2_))); // calculate the momenta Energy M = mZ_; Lorentz5Momentum pspect(ZERO,ZERO,-0.5*M*sqrt(max(sqr(x2)-4.*mu2_,0.)),0.5*M*x2,M*mu_); Lorentz5Momentum pemit (-0.5*M*xT*cos(phi),-0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x1)-sqr(xT)-4.*mu2_,0.)),0.5*M*x1,M*mu_); Lorentz5Momentum pgluon( 0.5*M*xT*cos(phi), 0.5*M*xT*sin(phi), 0.5*M*sqrt(max(sqr(x3)-sqr(xT),0.)),0.5*M*x3,ZERO); if(abs(pspect.z()+pemit.z()-pgluon.z())/M<1e-6) pgluon.setZ(-pgluon.z()); else if(abs(pspect.z()-pemit.z()+pgluon.z())/M<1e-6) pemit .setZ(- pemit.z()); // boost and rotate momenta LorentzRotation eventFrame( ( hardProcess[1]->momentum() + hardProcess[2]->momentum() ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*hardProcess[emitter+1]->momentum(); eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); vector momenta(3); momenta[0] = hardProcess[0]->momentum(); if(emitter==0) { momenta[2] = eventFrame*pspect; momenta[1] = eventFrame*pemit ; } else { momenta[1] = eventFrame*pspect; momenta[2] = eventFrame*pemit ; } momenta.push_back(eventFrame*pgluon); // calculate the weight double realwgt(0.); if(1.-x1>1e-5 && 1.-x2>1e-5) realwgt = meRatio(partons,momenta,emitter,subtract); // total real emission contribution return realwgt; } diff --git a/Decay/Tau/TauDecayer.cc b/Decay/Tau/TauDecayer.cc --- a/Decay/Tau/TauDecayer.cc +++ b/Decay/Tau/TauDecayer.cc @@ -1,359 +1,361 @@ // -*- C++ -*- // // TauDecayer.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 TauDecayer class. // // Author: Peter Richardson // #include "TauDecayer.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Helicity/VectorSpinInfo.h" #include "ThePEG/Helicity/WaveFunction/SpinorWaveFunction.h" #include "ThePEG/Helicity/WaveFunction/SpinorBarWaveFunction.h" #include "Herwig/Decay/DecayVertex.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "ThePEG/Helicity/FermionSpinInfo.h" #include "ThePEG/StandardModel/StandardModelBase.h" using namespace Herwig; using namespace ThePEG::Helicity; void TauDecayer::doinit() { DecayIntegrator::doinit(); // make sure the current got initialised _current->init(); // set up the phase-space channels DecayPhaseSpaceModePtr mode; DecayPhaseSpaceChannelPtr channel; tPDVector extpart,ptemp; extpart.push_back(getParticleData(ParticleID::tauminus)); extpart.push_back(getParticleData(ParticleID::nu_tau)); Energy mtau(extpart[0]->mass()); double maxweight; vector channelwgts; int iq(0),ia(0); _modemap.clear(); unsigned int ix,iy; bool done; vector::iterator start,end; for(ix=0;ix<_current->numberOfModes();++ix) { // get the external particles for this mode extpart.resize(2); ptemp=_current->particles(-3,ix,iq,ia); for(iy=0;iyaddIntermediate(extpart[0],0,0.0,-1,1); done=_current->createMode(-3,ix,mode,2,1,channel,mtau); if(done) { // the maximum weight and the channel weights // the maximum maxweight = _wgtmax.size()>numberModes() ? _wgtmax[numberModes()] : 0; // the weights for the channel if(_wgtloc.size()>numberModes()&& _wgtloc[numberModes()]+mode->numberChannels()<=_weights.size()) { start=_weights.begin()+_wgtloc[numberModes()]; end = start+mode->numberChannels(); channelwgts=vector(start,end); } else { channelwgts.resize(mode->numberChannels(),1./(mode->numberChannels())); } _modemap.push_back(ix); // special for the two body modes if(extpart.size()==3) { channelwgts.clear(); mode=new_ptr(DecayPhaseSpaceMode(extpart,this)); } addMode(mode,maxweight,channelwgts); } } _current->reset(); _current->touch(); _current->update(); } void TauDecayer::doinitrun() { _current->initrun(); DecayIntegrator::doinitrun(); if(initialize()) { _weights.clear();_wgtloc.clear();_wgtmax.clear(); unsigned int ix,iy; for(ix=0;ixmaxWeight()); _wgtloc.push_back(_weights.size()); for(iy=0;iynumberChannels();++iy) { _weights.push_back(mode(ix)->channelWeight(iy)); } } } } bool TauDecayer::accept(tcPDPtr parent, const tPDVector & children) const { bool allowed(false); // find the neutrino int idnu(0),idtemp,idin(parent->id()); vector idother; tPDVector::const_iterator pit = children.begin(); tPDVector::const_iterator pend = children.end(); for( ; pit!=pend;++pit) { idtemp=(**pit).id(); if(abs(idtemp)==16) idnu=idtemp; else idother.push_back(idtemp); } if((idnu==ParticleID::nu_tau && idin==ParticleID::tauminus)|| (idnu==ParticleID::nu_taubar && idin==ParticleID::tauplus )) { allowed=_current->accept(idother); } return allowed; } int TauDecayer::modeNumber(bool & cc,tcPDPtr parent, const tPDVector & children) const { int imode(-1); tPDVector::const_iterator pit = children.begin(); tPDVector::const_iterator pend = children.end(); int idtemp;vector idother; for( ; pit!=pend;++pit) { idtemp=(**pit).id(); if(abs(idtemp)!=16) idother.push_back(idtemp); } unsigned int itemp=_current->decayMode(idother); for(unsigned int ix=0;ix<_modemap.size();++ix) { if(_modemap[ix]==itemp) imode=ix; } // perform the decay cc=parent->id()==ParticleID::tauplus; return imode; } void TauDecayer::persistentOutput(PersistentOStream & os) const { os << _modemap << _current << _wgtloc << _wgtmax << _weights << _polOpt << _tauMpol << _tauPpol; } void TauDecayer::persistentInput(PersistentIStream & is, int) { is >> _modemap >> _current >> _wgtloc >> _wgtmax >> _weights >> _polOpt >> _tauMpol >> _tauPpol; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigTauDecayer("Herwig::TauDecayer", "HwTauDecay.so"); void TauDecayer::Init() { static ClassDocumentation documentation ("The TauDecayer class is designed to use a weak current" " to perform the decay of the tau."); static Reference interfaceWeakCurrent ("WeakCurrent", "The reference for the decay current to be used.", &TauDecayer::_current, false, false, true, false, false); static ParVector interfaceWeightLocation ("WeightLocation", "The locations of the weights for a given channel in the vector", &TauDecayer::_wgtloc, 0, 0, 0, 0, 10000, false, false, true); static ParVector interfaceWeightMax ("MaximumWeight", "The maximum weight for a given channel.", &TauDecayer::_wgtmax, 0, 0, 0, 0., 100., false, false, true); static ParVector interfaceWeights ("Weights", "The weights for the integration.", &TauDecayer::_weights, 0, 0, 0, 0., 1., false, false, true); static Switch interfacePolarizationOption ("PolarizationOption", "Option of forcing the polarization of the tau leptons, N.B. you" " should only use this option for making distributions for" " comparision if you really know what you are doing.", &TauDecayer::_polOpt, false, false, false); static SwitchOption interfacePolarizationOptionDefault (interfacePolarizationOption, "Default", "Don't force the polarization use the full spin density matrices" " to get the right answer", false); static SwitchOption interfacePolarizationOptionForce (interfacePolarizationOption, "Force", "Force the polarizations", true); static Parameter interfaceTauMinusPolarization ("TauMinusPolarization", "The polarization of the tau-, left=-1, right=+1 if this is forced.", &TauDecayer::_tauMpol, 0.0, -1.0, 1.0, false, false, Interface::limited); static Parameter interfaceTauPlusPolarization ("TauPlusPolarization", "The polarization of the tau+, left=-1, right=+1 if this is forced.", &TauDecayer::_tauPpol, 0.0, -1.0, 1.0, false, false, Interface::limited); } // combine the currents to give the matrix element double TauDecayer::me2(const int ichan,const Particle & inpart, const ParticleVector & decay, MEOption meopt) const { // map the mode to those in the current int mode(_modemap[imode()]); // get the particles for the hadronic current ParticleVector hadpart(decay.begin()+1,decay.end()); Energy q; // extract info on the decaying particle if(meopt==Initialize) { // spin density matrix for the decaying particle _rho = RhoDMatrix(PDT::Spin1Half); if(inpart.id()==ParticleID::tauminus) SpinorWaveFunction ::calculateWaveFunctions(_inspin,_rho, const_ptr_cast(&inpart), incoming); else SpinorBarWaveFunction::calculateWaveFunctions(_inbar ,_rho, const_ptr_cast(&inpart), incoming); + // fix rho if no correlations + fixRho(_rho); if(_polOpt) { _rho(0,1) = _rho(1,0) = 0.; if(inpart.id()==ParticleID::tauminus) { _rho(0,0) = 0.5*(1.-_tauMpol); _rho(1,1) = 0.5*(1.+_tauMpol); } else { _rho(0,0) = 0.5*(1.+_tauPpol); _rho(1,1) = 0.5*(1.-_tauPpol); } } // work out the mapping for the hadron vector _constants = vector(decay.size()+1); _ispin = vector(decay.size()); int itemp(1); unsigned int ix(decay.size()); do { --ix; _ispin[ix] = decay[ix]->data().iSpin(); itemp *= _ispin[ix]; _constants[ix] = itemp; } while(ix>0); _constants[decay.size()] = 1; _constants[0 ] = _constants[1]; } if(!ME()) ME(new_ptr(GeneralDecayMatrixElement(PDT::Spin1Half,_ispin))); // connect the spininfo up if needed if(meopt==Terminate) { if(inpart.id()==ParticleID::tauminus) { SpinorWaveFunction :: constructSpinInfo(_inspin,const_ptr_cast(&inpart),incoming,true); SpinorBarWaveFunction:: constructSpinInfo(_inbar,decay[0],outgoing,true); } else { SpinorBarWaveFunction:: constructSpinInfo(_inbar ,const_ptr_cast(&inpart),incoming,true); SpinorWaveFunction:: constructSpinInfo(_inspin,decay[0],outgoing,true); } _current->current(mode,ichan,q,hadpart,meopt); return 0.; } // calculate the spinors for the decay products if(inpart.id()==ParticleID::tauminus) SpinorBarWaveFunction::calculateWaveFunctions(_inbar ,decay[0],outgoing); else SpinorWaveFunction ::calculateWaveFunctions(_inspin,decay[0],outgoing); // calculate the hadron current vector hadron(_current->current(mode,ichan,q,hadpart,meopt)); // prefactor double pre = sqr(pow(inpart.mass()/q,int(hadpart.size()-2))); // calculate the lepton current LorentzPolarizationVectorE lepton[2][2]; for(unsigned ix=0;ix<2;++ix) { for(unsigned iy=0;iy<2;++iy) { if(inpart.id()==15) lepton[ix][iy]=2.*_inspin[ix].leftCurrent(_inbar[iy]); else lepton[iy][ix]=2.*_inspin[ix].leftCurrent(_inbar[iy]); } } // compute the matrix element vector ihel(decay.size()+1); for(unsigned int hhel=0;hhel1;--ix) { ihel[ix]=(hhel%_constants[ix-1])/_constants[ix]; } // loop over the helicities of the tau and neutrino and set up the matrix // element for(ihel[1]=0;ihel[1]<2;++ihel[1]){ for(ihel[0]=0;ihel[0]<2;++ihel[0]) { (*ME())(ihel)= lepton[ihel[0]][ihel[1]].dot(hadron[hhel])* SM().fermiConstant(); } } } // multiply by the CKM element int iq,ia; _current->decayModeInfo(mode,iq,ia); double ckm(1.); if(iq<=6) { if(iq%2==0) ckm = SM().CKM(iq/2-1,(abs(ia)-1)/2); else ckm = SM().CKM(abs(ia)/2-1,(iq-1)/2); } return 0.5*pre*ckm*(ME()->contract(_rho)).real(); } // output the setup information for the particle database void TauDecayer::dataBaseOutput(ofstream & output,bool header) const { unsigned int ix; if(header) output << "update decayers set parameters=\""; DecayIntegrator::dataBaseOutput(output,false); for(ix=0;ix<_wgtloc.size();++ix) { output << "insert " << name() << ":WeightLocation " << ix << " " << _wgtloc[ix] << "\n"; } for(ix=0;ix<_wgtmax.size();++ix) { output << "insert " << name() << ":MaximumWeight " << ix << " " << _wgtmax[ix] << "\n"; } for(ix=0;ix<_weights.size();++ix) { output << "insert " << name() << ":Weights " << ix << " " << _weights[ix] << "\n"; } _current->dataBaseOutput(output,false,true); output << "newdef " << name() << ":WeakCurrent " << _current->name() << " \n"; output << "\n\" where BINARY ThePEGName=\"" << fullName() << "\";\n"; } diff --git a/Hadronization/HadronSelector.cc b/Hadronization/HadronSelector.cc --- a/Hadronization/HadronSelector.cc +++ b/Hadronization/HadronSelector.cc @@ -1,1003 +1,1003 @@ // -*- C++ -*- // // HadronSelector.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 HadronSelector class. // #include "HadronSelector.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include #include #include #include #include "CheckId.h" #include using namespace Herwig; DescribeAbstractClass describeHadronSelector("Herwig::HadronSelector",""); namespace { // // debug helper // void dumpTable(const HadronSelector::HadronTable & tbl) { // typedef HadronSelector::HadronTable::const_iterator TableIter; // for (TableIter it = tbl.begin(); it != tbl.end(); ++it) { // cerr << it->first.first << ' ' // << it->first.second << '\n'; // for (HadronSelector::KupcoData::const_iterator jt = it->second.begin(); // jt != it->second.end(); ++jt) { // cerr << '\t' << *jt << '\n'; // } // } // } bool weightIsLess (pair a, pair b) { return a.second < b.second; } } ostream & operator<< (ostream & os, const HadronSelector::HadronInfo & hi ) { os << std::scientific << std::showpoint << std::setprecision(4) << setw(2) << hi.id << '\t' // << hi.ptrData << ' ' << hi.swtef << '\t' << hi.wt << '\t' << hi.overallWeight << '\t' << ounit(hi.mass,GeV); return os; } HadronSelector::HadronSelector(unsigned int opt) : _pwtDquark( 1.0 ),_pwtUquark( 1.0 ),_pwtSquark( 1.0 ),_pwtCquark( 1.0 ), _pwtBquark( 1.0 ),_pwtDIquark( 1.0 ), _weight1S0(Nmax,1.),_weight3S1(Nmax,1.),_weight1P1(Nmax,1.),_weight3P0(Nmax,1.), _weight3P1(Nmax,1.),_weight3P2(Nmax,1.),_weight1D2(Nmax,1.),_weight3D1(Nmax,1.), _weight3D2(Nmax,1.),_weight3D3(Nmax,1.), _repwt(Lmax,vector >(Jmax,vector(Nmax))), _sngWt( 1.0 ),_decWt( 1.0 ), _topt(opt),_trial(0), _limBottom(), _limCharm(), _limExotic(), belowThreshold_(0) { // The mixing angles // the ideal mixing angle const double idealAngleMix = atan( sqrt(0.5) ) * 180.0 / Constants::pi; // \eta-\eta' mixing angle _etamix = -23.0; // phi-omega mixing angle _phimix = +36.0; // h_1'-h_1 mixing angle _h1mix = idealAngleMix; // f_0(1710)-f_0(1370) mixing angle _f0mix = idealAngleMix; // f_1(1420)-f_1(1285)\f$ mixing angle _f1mix = idealAngleMix; // f'_2-f_2\f$ mixing angle _f2mix = +26.0; // eta_2(1870)-eta_2(1645) mixing angle _eta2mix = idealAngleMix; // phi(???)-omega(1650) mixing angle _omhmix = idealAngleMix; // phi_3-omega_3 mixing angle _ph3mix = +28.0; // eta(1475)-eta(1295) mixing angle _eta2Smix = idealAngleMix; // phi(1680)-omega(1420) mixing angle _phi2Smix = idealAngleMix; } void HadronSelector::persistentOutput(PersistentOStream & os) const { os << _partons << _pwtDquark << _pwtUquark << _pwtSquark << _pwtCquark << _pwtBquark << _pwtDIquark << _etamix << _phimix << _h1mix << _f0mix << _f1mix << _f2mix << _eta2mix << _omhmix << _ph3mix << _eta2Smix << _phi2Smix << _weight1S0 << _weight3S1 << _weight1P1 << _weight3P0 << _weight3P1 << _weight3P2 << _weight1D2 << _weight3D1 << _weight3D2 << _weight3D3 << _forbidden << _sngWt << _decWt << _repwt << _pwt << _limBottom << _limCharm << _limExotic << belowThreshold_ << _table; } void HadronSelector::persistentInput(PersistentIStream & is, int) { is >> _partons >> _pwtDquark >> _pwtUquark >> _pwtSquark >> _pwtCquark >> _pwtBquark >> _pwtDIquark>> _etamix >> _phimix >> _h1mix >> _f0mix >> _f1mix >> _f2mix >> _eta2mix >> _omhmix >> _ph3mix >> _eta2Smix >> _phi2Smix >> _weight1S0 >> _weight3S1 >> _weight1P1 >> _weight3P0 >> _weight3P1 >> _weight3P2 >> _weight1D2 >> _weight3D1 >> _weight3D2 >> _weight3D3 >> _forbidden >> _sngWt >> _decWt >> _repwt >> _pwt >> _limBottom >> _limCharm >> _limExotic >> belowThreshold_ >> _table; } void HadronSelector::Init() { static ClassDocumentation documentation ("There is no documentation for the HadronSelector class"); static Parameter interfacePwtDquark("PwtDquark","Weight for choosing a quark D", &HadronSelector::_pwtDquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter interfacePwtUquark("PwtUquark","Weight for choosing a quark U", &HadronSelector::_pwtUquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter interfacePwtSquark("PwtSquark","Weight for choosing a quark S", &HadronSelector::_pwtSquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter interfacePwtCquark("PwtCquark","Weight for choosing a quark C", &HadronSelector::_pwtCquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter interfacePwtBquark("PwtBquark","Weight for choosing a quark B", &HadronSelector::_pwtBquark, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter interfacePwtDIquark("PwtDIquark","Weight for choosing a DIquark", &HadronSelector::_pwtDIquark, 0, 1.0, 0.0, 100.0, false,false,false); static Parameter interfaceSngWt("SngWt","Weight for singlet baryons", &HadronSelector::_sngWt, 0, 1.0, 0.0, 10.0, false,false,false); static Parameter interfaceDecWt("DecWt","Weight for decuplet baryons", &HadronSelector::_decWt, 0, 1.0, 0.0, 10.0, false,false,false); static RefVector interfacePartons ("Partons", "The partons which are to be considered as the consistuents of the hadrons.", &HadronSelector::_partons, -1, false, false, true, false, false); static RefVector interfaceForbidden ("Forbidden", "The PDG codes of the particles which cannot be produced in the hadronization.", &HadronSelector::_forbidden, -1, false, false, true, false, false); // // mixing angles // // the ideal mixing angle const double idealAngleMix = atan( sqrt(0.5) ) * 180.0 / Constants::pi; static Parameter interface11S0Mixing ("11S0Mixing", "The mixing angle for the I=0 mesons from the 1 1S0 multiplet," " i.e. eta and etaprime.", &HadronSelector::_etamix, -23., -180., 180., false, false, Interface::limited); static Parameter interface13S1Mixing ("13S1Mixing", "The mixing angle for the I=0 mesons from the 1 3S1 multiplet," " i.e. phi and omega.", &HadronSelector::_phimix, +36., -180., 180., false, false, Interface::limited); static Parameter interface11P1Mixing ("11P1Mixing", "The mixing angle for the I=0 mesons from the 1 1P1 multiplet," " i.e. h_1' and h_1.", &HadronSelector::_h1mix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter interface13P0Mixing ("13P0Mixing", "The mixing angle for the I=0 mesons from the 1 3P0 multiplet," " i.e. f_0(1710) and f_0(1370).", &HadronSelector::_f0mix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter interface13P1Mixing ("13P1Mixing", "The mixing angle for the I=0 mesons from the 1 3P1 multiplet," " i.e. f_1(1420) and f_1(1285).", &HadronSelector::_f1mix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter interface13P2Mixing ("13P2Mixing", "The mixing angle for the I=0 mesons from the 1 3P2 multiplet," " i.e. f'_2 and f_2.", &HadronSelector::_f2mix, 26.0, -180., 180., false, false, Interface::limited); static Parameter interface11D2Mixing ("11D2Mixing", "The mixing angle for the I=0 mesons from the 1 1D2 multiplet," " i.e. eta_2(1870) and eta_2(1645).", &HadronSelector::_eta2mix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter interface13D0Mixing ("13D0Mixing", "The mixing angle for the I=0 mesons from the 1 3D0 multiplet," " i.e. eta_2(1870) phi(?) and omega(1650).", &HadronSelector::_omhmix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter interface13D1Mixing ("13D1Mixing", "The mixing angle for the I=0 mesons from the 1 3D1 multiplet," " i.e. phi_3 and omega_3.", &HadronSelector::_ph3mix, 28.0, -180., 180., false, false, Interface::limited); static Parameter interface21S0Mixing ("21S0Mixing", "The mixing angle for the I=0 mesons from the 2 1S0 multiplet," " i.e. eta(1475) and eta(1295).", &HadronSelector::_eta2Smix, idealAngleMix, -180., 180., false, false, Interface::limited); static Parameter interface23S1Mixing ("23S1Mixing", "The mixing angle for the I=0 mesons from the 1 3S1 multiplet," " i.e. phi(1680) and omega(1420).", &HadronSelector::_phi2Smix, idealAngleMix, -180., 180., false, false, Interface::limited); // // the meson weights // static ParVector interface1S0Weights ("1S0Weights", "The weights for the 1S0 multiplets start with n=1.", &HadronSelector::_weight1S0, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector interface3S1Weights ("3S1Weights", "The weights for the 3S1 multiplets start with n=1.", &HadronSelector::_weight3S1, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector interface1P1Weights ("1P1Weights", "The weights for the 1P1 multiplets start with n=1.", &HadronSelector::_weight1P1, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector interface3P0Weights ("3P0Weights", "The weights for the 3P0 multiplets start with n=1.", &HadronSelector::_weight3P0, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector interface3P1Weights ("3P1Weights", "The weights for the 3P1 multiplets start with n=1.", &HadronSelector::_weight3P1, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector interface3P2Weights ("3P2Weights", "The weights for the 3P2 multiplets start with n=1.", &HadronSelector::_weight3P2, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector interface1D2Weights ("1D2Weights", "The weights for the 1D2 multiplets start with n=1.", &HadronSelector::_weight1D2, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector interface3D1Weights ("3D1Weights", "The weights for the 3D1 multiplets start with n=1.", &HadronSelector::_weight3D1, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector interface3D2Weights ("3D2Weights", "The weights for the 3D2 multiplets start with n=1.", &HadronSelector::_weight3D2, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static ParVector interface3D3Weights ("3D3Weights", "The weights for the 3D3 multiplets start with n=1.", &HadronSelector::_weight3D3, Nmax, 1.0, 0.0, 100.0, false, false, Interface::limited); static Switch interfaceTrial ("Trial", "A Debugging option to only produce certain types of hadrons", &HadronSelector::_trial, 0, false, false); static SwitchOption interfaceTrialAll (interfaceTrial, "All", "Produce all the hadrons", 0); static SwitchOption interfaceTrialPions (interfaceTrial, "Pions", "Only produce pions", 1); static SwitchOption interfaceTrialSpin2 (interfaceTrial, "Spin2", "Only mesons with spin less than or equal to two are produced", 2); static SwitchOption interfaceTrialSpin3 (interfaceTrial, "Spin3", "Only hadrons with spin less than or equal to three are produced", 3); static Parameter interfaceSingleHadronLimitBottom ("SingleHadronLimitBottom", "Threshold for one-hadron decay of b-cluster", &HadronSelector::_limBottom, 0, 0.0, 0.0, 100.0,false,false,false); static Parameter interfaceSingleHadronLimitCharm ("SingleHadronLimitCharm", "threshold for one-hadron decay of c-cluster", &HadronSelector::_limCharm, 0, 0.0, 0.0, 100.0,false,false,false); static Parameter interfaceSingleHadronLimitExotic ("SingleHadronLimitExotic", "threshold for one-hadron decay of exotic cluster", &HadronSelector::_limExotic, 0, 0.0, 0.0, 100.0,false,false,false); static Switch interfaceBelowThreshold ("BelowThreshold", "Option fo the selection of the hadrons if the cluster is below the pair threshold", &HadronSelector::belowThreshold_, 0, false, false); static SwitchOption interfaceBelowThresholdLightest (interfaceBelowThreshold, "Lightest", "Force cluster to decay to the lightest hadron with the appropriate flavours", 0); static SwitchOption interfaceBelowThresholdAll (interfaceBelowThreshold, "All", "Select from all the hadrons below the two hadron threshold according to their spin weights", 1); } double HadronSelector::mixingStateWeight(long id) const { switch(id) { case ParticleID::eta: return 0.5*probabilityMixing(_etamix ,1); case ParticleID::etaprime: return 0.5*probabilityMixing(_etamix ,2); case ParticleID::phi: return 0.5*probabilityMixing(_phimix ,1); case ParticleID::omega: return 0.5*probabilityMixing(_phimix ,2); case ParticleID::hprime_1: return 0.5*probabilityMixing(_h1mix ,1); case ParticleID::h_1: return 0.5*probabilityMixing(_h1mix ,2); case 10331: return 0.5*probabilityMixing(_f0mix ,1); case 10221: return 0.5*probabilityMixing(_f0mix ,2); case ParticleID::fprime_1: return 0.5*probabilityMixing(_f1mix ,1); case ParticleID::f_1: return 0.5*probabilityMixing(_f1mix ,2); case ParticleID::fprime_2: return 0.5*probabilityMixing(_f2mix ,1); case ParticleID::f_2: return 0.5*probabilityMixing(_f2mix ,2); case 10335: return 0.5*probabilityMixing(_eta2mix ,1); case 10225: return 0.5*probabilityMixing(_eta2mix ,2); // missing phi member of 13D1 should be here case 30223: return 0.5*probabilityMixing(_omhmix ,2); case 337: return 0.5*probabilityMixing(_ph3mix ,1); case 227: return 0.5*probabilityMixing(_ph3mix ,2); case 100331: return 0.5*probabilityMixing(_eta2mix ,1); case 100221: return 0.5*probabilityMixing(_eta2mix ,2); case 100333: return 0.5*probabilityMixing(_phi2Smix,1); case 100223: return 0.5*probabilityMixing(_phi2Smix,2); default: return 1./3.; } } void HadronSelector::doinit() { Interfaced::doinit(); // the default partons allowed // the quarks for ( int ix=1; ix<=5; ++ix ) { _partons.push_back(getParticleData(ix)); } // the diquarks for(unsigned int ix=1;ix<=5;++ix) { for(unsigned int iy=1; iy<=ix;++iy) { _partons.push_back(getParticleData(CheckId::makeDiquarkID(ix,iy))); } } // set the weights for the various excited mesons // set all to one to start with for (int l = 0; l < Lmax; ++l ) { for (int j = 0; j < Jmax; ++j) { for (int n = 0; n < Nmax; ++n) { _repwt[l][j][n] = 1.0; } } } // set the others from the relevant vectors for( int ix=0;ixid()]=1.; } _pwt[1] = _pwtDquark; _pwt[2] = _pwtUquark; _pwt[3] = _pwtSquark; _pwt[4] = _pwtCquark; _pwt[5] = _pwtBquark; _pwt[1103] = _pwtDIquark * _pwtDquark * _pwtDquark; _pwt[2101] = 0.5 * _pwtDIquark * _pwtUquark * _pwtDquark; _pwt[2203] = _pwtDIquark * _pwtUquark * _pwtUquark; _pwt[3101] = 0.5 * _pwtDIquark * _pwtSquark * _pwtDquark; _pwt[3201] = 0.5 * _pwtDIquark * _pwtSquark * _pwtUquark; _pwt[3303] = _pwtDIquark * _pwtSquark * _pwtSquark; // Commenting out heavy di-quark weights _pwt[4101] = 0.0; _pwt[4201] = 0.0; _pwt[4301] = 0.0; _pwt[4403] = 0.0; _pwt[5101] = 0.0; _pwt[5201] = 0.0; _pwt[5301] = 0.0; _pwt[5401] = 0.0; _pwt[5503] = 0.0; // find the maximum map::iterator pit = max_element(_pwt.begin(),_pwt.end(),weightIsLess); const double pmax = pit->second; for(pit=_pwt.begin(); pit!=_pwt.end(); ++pit) { pit->second/=pmax; } // construct the hadron tables constructHadronTable(); // for debugging // dumpTable(table()); } void HadronSelector::constructHadronTable() { // initialise the table _table.clear(); for(unsigned int ix=0; ix<_partons.size(); ++ix) { for(unsigned int iy=0; iy<_partons.size(); ++iy) { if (!(DiquarkMatcher::Check(_partons[ix]->id()) && DiquarkMatcher::Check(_partons[iy]->id()))) _table[make_pair(_partons[ix]->id(),_partons[iy]->id())] = KupcoData(); } } // get the particles from the event generator ParticleMap particles = generator()->particles(); // loop over the particles double maxdd(0.),maxss(0.),maxrest(0.); for(ParticleMap::iterator it=particles.begin(); it!=particles.end(); ++it) { long pid = it->first; tPDPtr particle = it->second; int pspin = particle->iSpin(); // Don't include hadrons which are explicitly forbidden if(find(_forbidden.begin(),_forbidden.end(),particle)!=_forbidden.end()) continue; // Don't include non-hadrons or antiparticles if(pid < 100) continue; // remove diffractive particles if(pspin == 0) continue; // K_0S and K_0L not made make K0 and Kbar0 if(pid==ParticleID::K_S0||pid==ParticleID::K_L0) continue; // Debugging options // Only include those with 2J+1 less than...5 if(_trial==2 && pspin >= 5) continue; // Only include those with 2J+1 less than...7 if(_trial==3 && pspin >= 7) continue; // Only include pions if(_trial==1 && pid!=111 && pid!=211) continue; // shouldn't be coloured if(particle->coloured()) continue; // Get the flavours const int x4 = (pid/1000)%10; const int x3 = (pid/100 )%10; const int x2 = (pid/10 )%10; const int x7 = (pid/1000000)%10; const bool wantSusy = x7 == 1 || x7 == 2; int flav1; int flav2; // Skip non-hadrons (susy particles, etc...) if(x3 == 0 || x2 == 0) continue; else if(x4 == 0) { // meson flav1 = x2; flav2 = x3; } else { // baryon flav1 = CheckId::makeDiquarkID(x2,x3); flav2 = x4; } if (wantSusy) flav2 += 1000000 * x7; HadronInfo a(pid, particle, specialWeight(pid), particle->mass()); // set the weight to the number of spin states a.overallWeight = pspin; // identical light flavours if(flav1 == flav2 && flav1<=3) { // ddbar> uubar> admixture states if(flav1==1) { if(_topt != 0) a.overallWeight *= 0.5*a.swtef; _table[make_pair(1,1)].insert(a); _table[make_pair(2,2)].insert(a); if(_topt == 0 && a.overallWeight > maxdd) maxdd = a.overallWeight; } // load up ssbar> uubar> ddbar> admixture states else { a.wt = mixingStateWeight(pid); a.overallWeight *= a.wt; if(_topt != 0) a.overallWeight *= a.swtef; _table[make_pair(1,1)].insert(a); _table[make_pair(2,2)].insert(a); if(_topt == 0 && a.overallWeight > maxdd) maxdd = a.overallWeight; a.wt = (_topt != 0) ? 1.- 2.*a.wt : 1 - a.wt; if(a.wt > 0) { a.overallWeight = a.wt * a.swtef * pspin; _table[make_pair(3,3)].insert(a); if(_topt == 0 && a.overallWeight > maxss) maxss = a.overallWeight; } } } // light baryons with all quarks identical else if((flav1 == 1 && flav2 == 1103) || (flav1 == 1103 && flav2 == 1) || (flav1 == 2 && flav2 == 2203) || (flav1 == 2203 && flav2 == 2) || (flav1 == 3 && flav2 == 3303) || (flav1 == 3303 && flav2 == 3)) { if(_topt != 0) a.overallWeight *= 1.5*a.swtef; _table[make_pair(flav1,flav2)].insert(a); _table[make_pair(flav2,flav1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } // all other cases else { if(_topt != 0) a.overallWeight *=a.swtef; _table[make_pair(flav1,flav2)].insert(a); if(flav1 != flav2) _table[make_pair(flav2,flav1)].insert(a); if(_topt == 0 && a.overallWeight > maxrest) maxrest = a.overallWeight; } } // Account for identical combos of diquark/quarks and symmetrical elements // e.g. U UD = D UU HadronTable::iterator tit; for(tit=_table.begin();tit!=_table.end();++tit) { if(tit->first.first>ParticleID::c) continue; if(!DiquarkMatcher::Check(tit->first.second)) continue; long k, l, sub; if(tit->first.second>=ParticleID::bd_0) { k = ParticleID::b; sub = ParticleID::bd_0/100; } else if(tit->first.second>=ParticleID::cd_0) { k = ParticleID::c; sub = ParticleID::cd_0/100; } else if(tit->first.second>=ParticleID::sd_0) { k = ParticleID::s; sub = ParticleID::sd_0/100; } else if(tit->first.second>=ParticleID::ud_0) { k = ParticleID::u; sub = ParticleID::ud_0/100; } else if(tit->first.second==ParticleID::dd_1) { k = ParticleID::d; sub = ParticleID::dd_1/100; } else continue; sub=tit->first.second/100-sub+1; if(sub > tit->first.first) { l = 1000*sub+100*tit->first.first+1; } else if(sub==tit->first.first) { l = 1000*sub+ 100*tit->first.first+3; } else { l = 100*sub +1000*tit->first.first+1; } if(tit->second.empty()) { pair newpair(k,l); tit->second=_table[newpair]; newpair=make_pair(tit->first.second,tit->first.first); _table[newpair]=tit->second; }; } // normalise weights to one for first option if(_topt == 0) { HadronTable::const_iterator tit; KupcoData::iterator it; for(tit=_table.begin();tit!=_table.end();++tit) { double weight; if(tit->first.first==tit->first.second) { if(tit->first.first==1||tit->first.first==2) weight=1./maxdd; else if (tit->first.first==3) weight=1./maxss; else weight=1./maxrest; } else weight=1./maxrest; for(it = tit->second.begin(); it!=tit->second.end(); ++it) { it->rescale(weight); } } } } double HadronSelector::specialWeight(long id) const { const int pspin = id % 10; // Only K0L and K0S have pspin == 0, should // not get them until Decay step assert( pspin != 0 ); // Baryon : J = 1/2 or 3/2 if(pspin == 2) { // Singlet (Lambda-like) baryon if( (id/100)%10 < (id/10 )%10 ) return sqr(_sngWt); // octet else return 1.; } // Decuplet baryon else if (pspin == 4) { return sqr(_decWt); } // Meson else if(pspin % 2 == 1) { // Total angular momentum int j = (pspin - 1) / 2; // related to Orbital angular momentum l int nl = (id/10000 )%10; int l = -999; int n = (id/100000)%10; // Radial excitation if(j == 0) l = nl; else if(nl == 0) l = j - 1; else if(nl == 1 || nl == 2) l = j; else if(nl == 3) l = j + 1; // Angular or Radial excited meson if((l||j||n) && l>=0 && l= 5/2 (ispin >= 6), haven't got those return 1.0; } int HadronSelector::signHadron(tcPDPtr idQ1, tcPDPtr idQ2, tcPDPtr hadron) const { // This method receives in input three PDG ids, whose the // first two have proper signs (corresponding to particles, id > 0, // or antiparticles, id < 0 ), whereas the third one must // be always positive (particle not antiparticle), // corresponding to: // --- quark-antiquark, or antiquark-quark, or // quark-diquark, or diquark-quark, or // antiquark-antidiquark, or antidiquark-antiquark // for the first two input (idQ1, idQ2); // --- meson or baryon for the third input (idHad): // The method returns: // --- + 1 if the two partons (idQ1, idQ2) are exactly // the constituents for the hadron idHad; // --- - 1 if the two partons (idQ1, idQ2) are exactly // the constituents for the anti-hadron -idHad; // --- + 0 otherwise. // The method it is therefore useful to decide the // sign of the id of the produced hadron as appeared // in the vector _vecHad (where only hadron idHad > 0 are present) // given the two constituent partons. int sign = 0; long idHad = hadron->id(); assert(idHad > 0); int chargeIn = idQ1->iCharge() + idQ2->iCharge(); int chargeOut = hadron->iCharge(); // same charge if( chargeIn == chargeOut && chargeIn !=0 ) sign = +1; else if(chargeIn == -chargeOut && chargeIn !=0 ) sign = -1; else if(chargeIn == 0 && chargeOut == 0 ) { // In the case of same null charge, there are four cases: // i) K0-like mesons, B0-like mesons, Bs-like mesons // the PDG convention is to consider them "antiparticle" (idHad < 0) // if the "dominant" (heavier) flavour (respectively, s, b) // is a quark (idQ > 0): for instance, B0s = (b, sbar) has id < 0 // Remember that there is an important exception for K0L (id=130) and // K0S (id=310): they don't have antiparticles, therefore idHad > 0 // always. We use below the fact that K0L and K0S are the unique // hadrons having 0 the first (less significant) digit of their id. // 2) D0-like mesons: the PDG convention is to consider them "particle" // (idHad > 0) if the charm flavour is carried by a c: (c,ubar) has id>0 // 3) the remaining mesons should not have antiparticle, therefore their // sign is always positive. // 4) for baryons, that is when one of idQ1 and idQ2 is a (anti-) quark and // the other one is a (anti-) diquark the sign is negative when both // constituents are "anti", that is both with id < 0; positive otherwise. // meson if(abs(int(idQ1->iColour()))== 3 && abs(int(idQ2->iColour())) == 3 && !DiquarkMatcher::Check(idQ1->id()) && !DiquarkMatcher::Check(idQ2->id())) { int idQa = abs(idQ1->id()); int idQb = abs(idQ2->id()); int dominant = idQ2->id(); if(idQa > idQb) { swap(idQa,idQb); dominant = idQ1->id(); } if((idQa==ParticleID::d && idQb==ParticleID::s) || (idQa==ParticleID::d && idQb==ParticleID::b) || (idQa==ParticleID::s && idQb==ParticleID::b)) { // idHad%10 is zero for K0L,K0S if (dominant < 0 || idHad%10 == 0) sign = +1; else if(dominant > 0) sign = -1; } else if((idQa==ParticleID::u && idQb==ParticleID::c) || (idQa==ParticleID::u && idQb==ParticleID::t) || (idQa==ParticleID::c && idQb==ParticleID::t)) { if (dominant > 0) sign = +1; else if(dominant < 0) sign = -1; } else if(idQa==idQb) sign = +1; // sets sign for Susy particles else sign = (dominant > 0) ? +1 : -1; } // baryon else if(DiquarkMatcher::Check(idQ1->id()) || DiquarkMatcher::Check(idQ2->id())) { if (idQ1->id() > 0 && idQ2->id() > 0) sign = +1; else if(idQ1->id() < 0 && idQ2->id() < 0) sign = -1; } } if (sign == 0) { cerr << "Could not work out sign for " << idQ1->PDGName() << ' ' << idQ2->PDGName() << " => " << hadron->PDGName() << '\n'; assert(false); } return sign; } pair HadronSelector::lightestHadronPair(tcPDPtr ptr1, tcPDPtr ptr2, tcPDPtr ptr3) const { // throw exception of id3!=0 as doesn't work if ( ptr3 ) throw Exception() << "ptr3!=0 not yet implemented in HadronSelector::lightestHadronPair" << Exception::abortnow; // charge int totalcharge = ptr1->iCharge() + ptr2->iCharge(); if ( ptr3 ) totalcharge += ptr3->iCharge(); tcPDPtr vIdHad1[2]={tcPDPtr(),tcPDPtr()},vIdHad2[2]={tcPDPtr(),tcPDPtr()}; bool vOk[2] = {false, false}; Energy vMassPair[2] = { ZERO, ZERO }; for (int i = 0; i < 2; i++) { tcPDPtr idPartner = i==0 ? getParticleData(ParticleID::d) : getParticleData(ParticleID::u); // Change sign to idPartner (transform it into a anti-quark) if it is not // possible to form a meson or a baryon. assert (ptr1 && idPartner); if (!CheckId::canBeHadron(ptr1, idPartner)) idPartner = idPartner->CC(); vIdHad1[i] = lightestHadron(ptr1, idPartner); vIdHad2[i] = lightestHadron(ptr2, idPartner->CC()); if ( vIdHad1[i] && vIdHad2[i] && vIdHad1[i]->iCharge() + vIdHad2[i]->iCharge() == totalcharge ) { vOk[i] = true; vMassPair[i] = vIdHad1[i]->mass() + vIdHad2[i]->mass(); } } // Take the lightest pair compatible with charge conservation. if ( vOk[0] && ( ! vOk[1] || vMassPair[0] <= vMassPair[1] ) ) { return make_pair(vIdHad1[0],vIdHad2[0]); } else if ( vOk[1] && ( ! vOk[0] || vMassPair[1] < vMassPair[0] ) ) { return make_pair(vIdHad1[1],vIdHad2[1]); } else { return make_pair(tcPDPtr(),tcPDPtr()); } } Energy HadronSelector::massLightestBaryonPair(tcPDPtr ptr1, tcPDPtr ptr2) const { // Make sure that we don't have any diquarks as input, return arbitrarily // large value if we do Energy currentSum = Constants::MaxEnergy; for(unsigned int ix=0; ix<_partons.size(); ++ix) { if(!DiquarkMatcher::Check(_partons[ix]->id())) continue; HadronTable::const_iterator tit1=_table.find(make_pair(abs(ptr1->id()),_partons[ix]->id())), tit2=_table.find(make_pair(_partons[ix]->id(),abs(ptr2->id()))); if( tit1==_table.end() || tit2==_table.end()) continue; if(tit1->second.empty()||tit2->second.empty()) continue; Energy s = tit1->second.begin()->mass + tit2->second.begin()->mass; if(currentSum > s) currentSum = s; } return currentSum; } tcPDPtr HadronSelector::lightestHadron(tcPDPtr ptr1, tcPDPtr ptr2,tcPDPtr ptr3) const { // The method assumes ptr3 == 0 rest not implemented assert(ptr1 && ptr2 && !ptr3); // find entry in the table pair ids = make_pair(abs(ptr1->id()),abs(ptr2->id())); HadronTable::const_iterator tit=_table.find(ids); // throw exception if flavours wrong if (tit==_table.end()) throw Exception() << "Could not find " << ids.first << ' ' << ids.second << " in _table. " << "In HadronSelector::lightestHadron()" << Exception::eventerror; if(tit->second.empty()) throw Exception() << "HadronSelector::lightestHadron " << "could not find any hadrons containing " << ptr1->id() << ' ' << ptr2->id() << '\n' << tit->first.first << ' ' << tit->first.second << Exception::eventerror; // find the lightest hadron int sign = signHadron(ptr1,ptr2,tit->second.begin()->ptrData); tcPDPtr candidate = sign > 0 ? tit->second.begin()->ptrData : tit->second.begin()->ptrData->CC(); // \todo 20 GeV limit is temporary fudge to let SM particles go through. // \todo Use isExotic instead? if (candidate->mass() > 20*GeV && candidate->mass() < ptr1->constituentMass() + ptr2->constituentMass()) { generator()->log() << "HadronSelector::lightestHadron: " << "chosen candidate " << candidate->PDGName() << " is lighter than its constituents " << ptr1->PDGName() << ", " << ptr2->PDGName() << '\n' << candidate->mass()/GeV << " < " << ptr1->constituentMass()/GeV << " + " << ptr2->constituentMass()/GeV << '\n' << "Check your particle data tables.\n"; assert(false); } return candidate; } vector > HadronSelector::hadronsBelowThreshold(Energy threshold, tcPDPtr ptr1, tcPDPtr ptr2, tcPDPtr ptr3) const { // The method assumes ptr3 == 0 rest not implemented assert(ptr1 && ptr2 && !ptr3); // find entry in the table pair ids = make_pair(abs(ptr1->id()),abs(ptr2->id())); HadronTable::const_iterator tit=_table.find(ids); // throw exception if flavours wrong if (tit==_table.end()) throw Exception() << "Could not find " << ids.first << ' ' << ids.second << " in _table. " << "In HadronSelector::hadronsBelowThreshold()" << Exception::eventerror; if(tit->second.empty()) throw Exception() << "HadronSelector::hadronsBelowThreshold() " << "could not find any hadrons containing " << ptr1->id() << ' ' << ptr2->id() << '\n' << tit->first.first << ' ' << tit->first.second << Exception::eventerror; vector > candidates; KupcoData::const_iterator hit = tit->second.begin(); // find the hadrons - while(hit->masssecond.end()) { + while(hit!=tit->second.end()&&hit->massptrData); tcPDPtr candidate = sign > 0 ? hit->ptrData : hit->ptrData->CC(); // \todo 20 GeV limit is temporary fudge to let SM particles go through. // \todo Use isExotic instead? if (candidate->mass() > 20*GeV && candidate->mass() < ptr1->constituentMass() + ptr2->constituentMass()) { generator()->log() << "HadronSelector::hadronsBelowTheshold: " << "chosen candidate " << candidate->PDGName() << " is lighter than its constituents " << ptr1->PDGName() << ", " << ptr2->PDGName() << '\n' << candidate->mass()/GeV << " < " << ptr1->constituentMass()/GeV << " + " << ptr2->constituentMass()/GeV << '\n' << "Check your particle data tables.\n"; assert(false); } candidates.push_back(make_pair(candidate,hit->overallWeight)); ++hit; } return candidates; } tcPDPtr HadronSelector::chooseSingleHadron(tcPDPtr par1, tcPDPtr par2, Energy mass) const { // Determine the sum of the nominal masses of the two lightest hadrons // with the right flavour numbers as the cluster under consideration. // Notice that we don't need real masses (drawn by a Breit-Wigner // distribution) because the lightest pair of hadrons does not involve // any broad resonance. Energy threshold = massLightestHadronPair(par1,par2); // Special: it allows one-hadron decays also above threshold. if (CheckId::isExotic(par1,par2)) threshold *= (1.0 + UseRandom::rnd()*_limExotic); else if (CheckId::hasBottom(par1,par2)) threshold *= (1.0 + UseRandom::rnd()*_limBottom); else if (CheckId::hasCharm(par1,par2)) threshold *= (1.0 + UseRandom::rnd()*_limCharm); // only do one hadron decay is mass less than the threshold if(mass>=threshold) return tcPDPtr(); // select the hadron tcPDPtr hadron; // old option pick the lightest hadron if(belowThreshold_ == 0) { hadron= lightestHadron(par1,par2); } // new option select from those available else if(belowThreshold_ == 1) { vector > hadrons = hadronsBelowThreshold(threshold,par1,par2); if(hadrons.size()==1) { hadron = hadrons[0].first; } else if(hadrons.empty()) { hadron= lightestHadron(par1,par2); } else { double totalWeight=0.; for(unsigned int ix=0;ix::transient_const_pointer hwsm=ThePEG::dynamic_ptr_cast< ThePEG::Ptr ::transient_const_pointer>(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Must be Herwig::StandardModel in MEPP2WJet::doinit()" << Exception::runerror; // set the vertex pointers _theFFWVertex = hwsm->vertexFFW(); _theQQGVertex = hwsm->vertexFFG(); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2WJet("Herwig::MEPP2WJet", "HwMEHadron.so"); void MEPP2WJet::Init() { static ClassDocumentation documentation ("The MEPP2WJet class implements the matrix element for W + jet production"); static Parameter interfaceMaxFlavour ( "MaxFlavour", "The heaviest incoming quark flavour this matrix element is allowed to handle " "(if applicable).", &MEPP2WJet::_maxflavour, 5, 0, 8, false, false, true); static Switch interfaceProcess ("Process", "Which subprocesses to include", &MEPP2WJet::_process, 0, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all subprocesses", 0); static SwitchOption interfaceProcessqqbar (interfaceProcess, "qqbar", "Only include q qbar -> W g process", 1); static SwitchOption interfaceProcessqg (interfaceProcess, "qg", "Only include the q g -> W q process", 2); static SwitchOption interfaceProcessqbarg (interfaceProcess, "qbarg", "Only include the qbar g -> W qbar process", 3); static Switch interfacePlusMinus ("Wcharge", "Which intermediate W bosons to include", &MEPP2WJet::_plusminus, 0, false, false); static SwitchOption interfacePlusMinusAll (interfacePlusMinus, "Both", "Include W+ and W-", 0); static SwitchOption interfacePlusMinusPlus (interfacePlusMinus, "Plus", "Only include W+", 1); static SwitchOption interfacePlusMinusMinus (interfacePlusMinus, "Minus", "Only include W-", 2); static Switch interfaceWDecay ("WDecay", "Which processes to include", &MEPP2WJet::_wdec, 0, false, false); static SwitchOption interfaceWDecayAll (interfaceWDecay, "All", "Include all SM fermions as outgoing particles", 0); static SwitchOption interfaceWDecayQuarks (interfaceWDecay, "Quarks", "Only include outgoing quarks", 1); static SwitchOption interfaceWDecayLeptons (interfaceWDecay, "Leptons", "All include outgoing leptons", 2); static SwitchOption interfaceWDecayElectron (interfaceWDecay, "Electron", "Only include outgoing e nu_e", 3); static SwitchOption interfaceWDecayMuon (interfaceWDecay, "Muon", "Only include outgoing mu nu_mu", 4); static SwitchOption interfaceWDecayTau (interfaceWDecay, "Tau", "Only include outgoing tauu nu_tau", 5); static SwitchOption interfaceWDecayUpDown (interfaceWDecay, "UpDown", "Only include outgoing u dbar/ d ubar", 6); static SwitchOption interfaceWDecayUpStrange (interfaceWDecay, "UpStrange", "Only include outgoing u sbar/ s ubar", 7); static SwitchOption interfaceWDecayUpBottom (interfaceWDecay, "UpBottom", "Only include outgoing u bbar/ b ubar", 8); static SwitchOption interfaceWDecayCharmDown (interfaceWDecay, "CharmDown", "Only include outgoing c dbar/ d cbar", 9); static SwitchOption interfaceWDecayCharmStrange (interfaceWDecay, "CharmStrange", "Only include outgoing c sbar/ s cbar", 10); static SwitchOption interfaceWDecayCharmBottom (interfaceWDecay, "CharmBottom", "Only include outgoing c bbar/ b cbar", 11); static Switch interfaceWidthOption ("WidthOption", "The option for handling the width of the off-shell W boson", &MEPP2WJet::_widthopt, 1, false, false); static SwitchOption interfaceWidthOptionFixedDenominator (interfaceWidthOption, "FixedDenominator", "Use a fixed with in the W propagator but the full matrix element" " in the numerator", 1); static SwitchOption interfaceWidthOptionAllRunning (interfaceWidthOption, "AllRunning", "Use a running width in the W propagator and the full matrix " "element in the numerator", 2); } void MEPP2WJet::getDiagrams() const { // which intgermediates to include bool wplus = _plusminus==0 || _plusminus==1; bool wminus = _plusminus==0 || _plusminus==2; // possible incoming and outgoing particles typedef std::vector > Pairvector; // possible parents Pairvector parentpair; parentpair.reserve(6); // don't even think of putting 'break' in here! switch(_maxflavour) { case 5: parentpair.push_back(make_pair(ParticleID::b, ParticleID::cbar)); parentpair.push_back(make_pair(ParticleID::b, ParticleID::ubar)); [[fallthrough]]; case 4: parentpair.push_back(make_pair(ParticleID::s, ParticleID::cbar)); parentpair.push_back(make_pair(ParticleID::d, ParticleID::cbar)); [[fallthrough]]; case 3: parentpair.push_back(make_pair(ParticleID::s, ParticleID::ubar)); [[fallthrough]]; case 2: parentpair.push_back(make_pair(ParticleID::d, ParticleID::ubar)); [[fallthrough]]; default: ; } // possible children Pairvector childpair; childpair.reserve(9); childpair.push_back(make_pair(ParticleID::eminus, ParticleID::nu_ebar)); childpair.push_back(make_pair(ParticleID::muminus, ParticleID::nu_mubar)); childpair.push_back(make_pair(ParticleID::tauminus, ParticleID::nu_taubar)); childpair.push_back(make_pair(ParticleID::d, ParticleID::ubar)); childpair.push_back(make_pair(ParticleID::s, ParticleID::ubar)); childpair.push_back(make_pair(ParticleID::b, ParticleID::ubar)); childpair.push_back(make_pair(ParticleID::d, ParticleID::cbar)); childpair.push_back(make_pair(ParticleID::s, ParticleID::cbar)); childpair.push_back(make_pair(ParticleID::b, ParticleID::cbar)); // gluon for diagrams tcPDPtr g = getParticleData(ParticleID::g); // loop over the children bool lepton,quark; Pairvector::const_iterator child = childpair.begin(); for (; child != childpair.end(); ++child) { // allowed leptonic decay lepton=child->first>10&& (_wdec==0||_wdec==2|| (abs(child->first)-5)/2==int(_wdec)); // allowed quark decay quark =abs(child->second)<10&& (_wdec==0||_wdec==1|| (abs(child->second)==2&&(abs(child->first)+11)/2==int(_wdec))|| (abs(child->second)==4&&(abs(child->first)+17)/2==int(_wdec))); // if decay not allowed skip if(!(quark||lepton)) continue; // decay products tcPDPtr lNeg1 = getParticleData(child->first); tcPDPtr lNeg2 = getParticleData(child->second); tcPDPtr lPos1 = lNeg2->CC(); tcPDPtr lPos2 = lNeg1->CC(); Pairvector::const_iterator parent = parentpair.begin(); for (; parent != parentpair.end(); ++parent) { // parents tcPDPtr qNeg1 = getParticleData(parent->first); tcPDPtr qNeg2 = getParticleData(parent->second); tcPDPtr qPos1 = qNeg2->CC(); tcPDPtr qPos2 = qNeg1->CC(); // diagrams // q qbar annhilation processes if(_process==0||_process==1) { // q qbar -> W- g if(wminus) { add(new_ptr((Tree2toNDiagram(3), qNeg1, qNeg2, qNeg2, 1, _wminus, 2, g, 4, lNeg1, 4, lNeg2, -1))); add(new_ptr((Tree2toNDiagram(3), qNeg1, qNeg1, qNeg2, 2, _wminus, 1, g, 4, lNeg1, 4, lNeg2, -2))); } // q qbar -> W+ g if(wplus) { add(new_ptr((Tree2toNDiagram(3), qPos1, qPos2, qPos2, 1, _wplus, 2, g, 4, lPos1, 4, lPos2, -3))); add(new_ptr((Tree2toNDiagram(3), qPos1, qPos1, qPos2, 2, _wplus, 1, g, 4, lPos1, 4, lPos2, -4))); } } // q g compton if(_process==0||_process==2) { if(wminus) { add(new_ptr((Tree2toNDiagram(3), qNeg1, qPos1, g , 1, _wminus, 2, qPos1, 4, lNeg1, 4, lNeg2, -5))); add(new_ptr((Tree2toNDiagram(2), qNeg1, g, 1, qNeg1, 3, _wminus, 3, qPos1, 4, lNeg1, 4, lNeg2, -6))); } if(wplus) { add(new_ptr((Tree2toNDiagram(3), qPos1, qNeg1, g, 1, _wplus, 2, qNeg1, 4, lPos1, 4, lPos2, -7))); add(new_ptr((Tree2toNDiagram(2), qPos1, g, 1, qNeg1, 3, _wplus, 3, qNeg1, 4, lPos1, 4, lPos2, -8))); } } // qbar g compton if(_process==0||_process==3) { if(wminus) { add(new_ptr((Tree2toNDiagram(3), qNeg2, qPos2, g, 1, _wminus, 2, qPos2, 4, lNeg1, 4, lNeg2, -9 ))); add(new_ptr((Tree2toNDiagram(2), qNeg2, g, 1, qNeg2, 3, _wminus, 3, qPos2, 4, lNeg1, 4, lNeg2, -10))); } if(wplus) { add(new_ptr((Tree2toNDiagram(3), qPos2, qNeg2, g, 1, _wplus, 2, qNeg2, 4, lPos1, 4, lPos2, -11))); add(new_ptr((Tree2toNDiagram(2), qPos2, g, 1, qPos2, 3, _wplus, 3, qNeg2, 4, lPos1, 4, lPos2, -12))); } } } } } unsigned int MEPP2WJet::orderInAlphaS() const { return 1; } unsigned int MEPP2WJet::orderInAlphaEW() const { return 2; } void MEPP2WJet::persistentOutput(PersistentOStream & os) const { os << _theFFWVertex << _theQQGVertex << _wplus << _widthopt << _wminus << _process << _maxflavour << _plusminus << _wdec; } void MEPP2WJet::persistentInput(PersistentIStream & is, int) { is >> _theFFWVertex >> _theQQGVertex >> _wplus >> _widthopt >> _wminus >> _process >> _maxflavour >> _plusminus >> _wdec; } int MEPP2WJet::nDim() const { return 5; } Selector MEPP2WJet::colourGeometries(tcDiagPtr diag) const { // colour lines for q qbar -> W g static const ColourLines cqqbar[4]={ColourLines("1 -2 5,-3 -5"), ColourLines("1 5, -5 2 -3"), ColourLines("1 -2 5,-3 -5,6 -7"), ColourLines("1 5, -5 2 -3,6 -7")}; // colour lines for q g -> W q static const ColourLines cqg [4]={ColourLines("1 2 -3,3 5"), ColourLines("1 -2,2 3 5"), ColourLines("1 2 -3,3 5,6 -7"), ColourLines("1 -2,2 3 5,6 -7")}; // colour lines for qbar q -> W qbar static const ColourLines cqbarg[4]={ColourLines("-1 -2 3,-3 -5"), ColourLines("-1 2,-2 -3 -5"), ColourLines("-1 -2 3,-3 -5,6 -7"), ColourLines("-1 2,-2 -3 -5,6 -7")}; // select the correct line unsigned int icol = mePartonData()[3]->coloured() ? 2 : 0; Selector sel; switch(abs(diag->id())) { case 1 : case 3: sel.insert(1.0, &cqqbar[icol]); break; case 2 : case 4: sel.insert(1.0, &cqqbar[icol+1]); break; case 5 : case 7: sel.insert(1.0, &cqg[icol]); break; case 6 : case 8: sel.insert(1.0, &cqg[icol+1]); break; case 9 : case 11: sel.insert(1.0, &cqbarg[icol]); break; case 10 : case 12: sel.insert(1.0, &cqbarg[icol+1]); break; } return sel; } Selector MEPP2WJet::diagrams(const DiagramVector & diags) const { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { int id=abs(diags[i]->id()); if (id <= 2 ) sel.insert(meInfo()[id- 1],i); else if(id <= 4 ) sel.insert(meInfo()[id- 3],i); else if(id <= 6 ) sel.insert(meInfo()[id- 5],i); else if(id <= 8 ) sel.insert(meInfo()[id- 7],i); else if(id <= 10) sel.insert(meInfo()[id- 9],i); else if(id <= 12) sel.insert(meInfo()[id-11],i); } return sel; } Energy2 MEPP2WJet::scale() const { return _scale; } CrossSection MEPP2WJet::dSigHatDR() const { return me2()*jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc); } bool MEPP2WJet::generateKinematics(const double * r) { // initialize jacobian jacobian(1.); // cms energy Energy ecm=sqrt(sHat()); // find the right W pointer tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ? _wplus :_wminus; // first generate the mass of the off-shell gauge boson // minimum mass of the tcPDVector ptemp; ptemp.push_back(mePartonData()[3]); ptemp.push_back(mePartonData()[4]); Energy2 minMass2 = max(lastCuts().minSij(mePartonData()[3],mePartonData()[4]), lastCuts().minS(ptemp)); // minimum pt of the jet Energy ptmin = max(lastCuts().minKT(mePartonData()[2]), lastCuts().minKT(wdata)); // maximum mass of the gauge boson so pt is possible Energy2 maxMass2 = min(ecm*(ecm-2.*ptmin),lastCuts().maxS(ptemp)); if(maxMass2<=ZERO||minMass2massMin())); maxMass2 = min(maxMass2,sqr(wdata->massMax())); // return if not kinematically possible if(minMass2>maxMass2) return false; // generation of the mass Energy M(wdata->mass()),Gamma(wdata->width()); Energy2 M2(sqr(M)),MG(M*Gamma); double rhomin = atan2((minMass2-M2),MG); double rhomax = atan2((maxMass2-M2),MG); _mw2=M2+MG*tan(rhomin+r[1]*(rhomax-rhomin)); Energy mw=sqrt(_mw2); // jacobian jacobian(jacobian()*(sqr(_mw2-M2)+sqr(MG))/MG*(rhomax-rhomin)/sHat()); // set the masses of the outgoing particles in the 2-2 scattering meMomenta()[2].setMass(ZERO); Lorentz5Momentum pw(mw); // generate the polar angle of the hard scattering double ctmin(-1.0), ctmax(1.0); Energy q(ZERO); try { q = SimplePhaseSpace::getMagnitude(sHat(), meMomenta()[2].mass(),mw); } catch ( ImpossibleKinematics ) { return false; } Energy2 pq = sqrt(sHat())*q; if ( ptmin > ZERO ) { double ctm = 1.0 - sqr(ptmin/q); if ( ctm <= 0.0 ) return false; ctmin = max(ctmin, -sqrt(ctm)); ctmax = min(ctmax, sqrt(ctm)); } if ( ctmin >= ctmax ) return false; double cth = getCosTheta(ctmin, ctmax, r[0]); // momenta of particle in hard scattering Energy pt = q*sqrt(1.0-sqr(cth)); double phi=2.0*Constants::pi*r[2]; meMomenta()[2].setVect(Momentum3( pt*sin(phi), pt*cos(phi), q*cth)); pw.setVect( Momentum3(-pt*sin(phi),-pt*cos(phi),-q*cth)); meMomenta()[2].rescaleEnergy(); pw.rescaleEnergy(); // set the scale _scale = _mw2+sqr(pt); // generate the momenta of the W decay products meMomenta()[3].setMass(mePartonData()[3]->mass()); meMomenta()[4].setMass(mePartonData()[4]->mass()); Energy q2 = ZERO; try { q2 = SimplePhaseSpace::getMagnitude(_mw2, meMomenta()[3].mass(), meMomenta()[4].mass()); } catch ( ImpossibleKinematics ) { return false; } double cth2 =-1.+2.*r[3]; double phi2=Constants::twopi*r[4]; Energy pt2 =q2*sqrt(1.-sqr(cth2)); Lorentz5Momentum pl[2]={Lorentz5Momentum( pt2*cos(phi2), pt2*sin(phi2), q2*cth2,ZERO, meMomenta()[3].mass()), Lorentz5Momentum(-pt2*cos(phi2),-pt2*sin(phi2),-q2*cth2,ZERO, meMomenta()[4].mass())}; pl[0].rescaleEnergy(); pl[1].rescaleEnergy(); Boost boostv(pw.boostVector()); pl[0].boost(boostv); pl[1].boost(boostv); meMomenta()[3] = pl[0]; meMomenta()[4] = pl[1]; // check passes all the cuts vector out(3); out[0] = meMomenta()[2]; out[1] = meMomenta()[3]; out[2] = meMomenta()[4]; tcPDVector tout(3); tout[0] = mePartonData()[2]; tout[1] = mePartonData()[3]; tout[2] = mePartonData()[4]; if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) ) return false; // jacobian jacobian((pq/sHat())*Constants::pi*jacobian()/8./sqr(Constants::pi)*q2/mw); return true; } double MEPP2WJet::me2() const { InvEnergy2 output(ZERO); // construct spinors for the leptons (always the same) vector lm; vector lp; SpinorBarWaveFunction lmout(meMomenta()[3],mePartonData()[3],outgoing); SpinorWaveFunction lpout(meMomenta()[4],mePartonData()[4],outgoing); for(unsigned int ix=0;ix<2;++ix) { lmout.reset(ix);lm.push_back(lmout); lpout.reset(ix);lp.push_back(lpout); } // q g to q W if(mePartonData()[0]->id()<=6&&mePartonData()[0]->id()>0&& mePartonData()[1]->id()==ParticleID::g) { // polarization states for the particles vector fin; vector gin; vector fout; SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction glin(meMomenta()[1],mePartonData()[1],incoming); SpinorBarWaveFunction qout(meMomenta()[2],mePartonData()[2],outgoing); for(unsigned int ix=0;ix<2;++ix) { qin.reset(ix) ; fin.push_back(qin); glin.reset(2*ix); gin.push_back(glin); qout.reset(ix);fout.push_back(qout); } output=qgME(fin,gin,fout,lm,lp); } // qbar g to qbar W else if(mePartonData()[0]->id()>=-6&&mePartonData()[0]->id()<0&& mePartonData()[1]->id()==ParticleID::g) { vector ain; vector gin; vector aout; SpinorBarWaveFunction qbin (meMomenta()[0],mePartonData()[0],incoming); VectorWaveFunction glin (meMomenta()[1],mePartonData()[1],incoming); SpinorWaveFunction qbout(meMomenta()[2],mePartonData()[2],outgoing); for(unsigned int ix=0;ix<2;++ix) { qbin.reset(ix) ; ain.push_back(qbin); glin.reset(2*ix) ; gin.push_back(glin); qbout.reset(ix);aout.push_back(qbout); } output=qbargME(ain,gin,aout,lm,lp); } // q qbar to g W else { vector fin; vector ain; vector gout; SpinorWaveFunction qin (meMomenta()[0],mePartonData()[0],incoming); SpinorBarWaveFunction qbin(meMomenta()[1],mePartonData()[1],incoming); VectorWaveFunction glout(meMomenta()[2],mePartonData()[2],outgoing); for(unsigned int ix=0;ix<2;++ix) { qin.reset(ix) ; fin.push_back(qin); qbin.reset(ix) ; ain.push_back(qbin); glout.reset(2*ix); gout.push_back(glout); } output=qqbarME(fin,ain,gout,lm,lp); } return output*sHat(); } InvEnergy2 MEPP2WJet::qqbarME(vector & fin, vector & ain, vector & gout, vector & lm, vector & lp, bool calc) const { // if calculation spin corrections construct the me if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1Half, PDT::Spin1Half)); // some integers unsigned int ihel1,ihel2,ohel1,ohel2,ohel3; // find the right W pointer tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ? _wplus :_wminus; // compute the W current for speed VectorWaveFunction bcurr[2][2]; for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata, lp[ohel3],lm[ohel2]); } } double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(ihel1=0;ihel1<2;++ihel1) { for(ihel2=0;ihel2<2;++ihel2) { for(ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0], fin[ihel1],gout[ohel1]); interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[1], ain[ihel2],gout[ohel1]); for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { diag[0] = _theFFWVertex->evaluate(_mw2,fin[ihel1],interb, bcurr[ohel2][ohel3]); diag[1] = _theFFWVertex->evaluate(_mw2,inters,ain[ihel2], bcurr[ohel2][ohel3]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); if(calc) _me(ihel1,ihel2,2*ohel1,ohel2,ohel3) = diag[0]; } } } } } // results // initial state spin and colour average double colspin=1./9./4.; // and C_F N_c from matrix element colspin *= 4.; // colour factor for the W decay if(mePartonData()[3]->coloured()) colspin*=3.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix]*=colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); return me[0] * UnitRemoval::InvE2; } InvEnergy2 MEPP2WJet::qgME(vector & fin, vector & gin, vector & fout, vector & lm, vector & lp, bool calc) const { // if calculation spin corrections construct the me if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half)); // find the right W pointer tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ? _wplus :_wminus; // some integers unsigned int ihel1,ihel2,ohel1,ohel2,ohel3; // compute the leptonic W current for speed VectorWaveFunction bcurr[2][2]; for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata, lp[ohel3],lm[ohel2]); } } // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(ihel1=0;ihel1<2;++ihel1) { for(ihel2=0;ihel2<2;++ihel2) { for(ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams - interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[2], + interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[2]->CC(), fout[ohel1],gin[ihel2]); inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[0], fin[ihel1],gin[ihel2]); for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { diag[0]=_theFFWVertex->evaluate(_mw2,fin[ihel1],interb, bcurr[ohel2][ohel3]); diag[1]=_theFFWVertex->evaluate(_mw2,inters,fout[ohel1], bcurr[ohel2][ohel3]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0]; } } } } } // results // initial state spin and colour average double colspin=1./24./4.; // and C_F N_c from matrix element colspin *=4.; // colour factor for the W decay if(mePartonData()[3]->coloured()) colspin*=3.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix]*=colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); return me[0] * UnitRemoval::InvE2; } InvEnergy2 MEPP2WJet::qbargME(vector & fin, vector & gin, vector & fout, vector & lm, vector & lp, bool calc) const { // if calculation spin corrections construct the me if(calc) _me.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half)); // find the right W pointer tcPDPtr wdata = mePartonData()[3]->iCharge()+mePartonData()[4]->iCharge() > 0 ? _wplus :_wminus; // some integers unsigned int ihel1,ihel2,ohel1,ohel2,ohel3; // compute the leptonic W current for speed VectorWaveFunction bcurr[2][2]; for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { bcurr[ohel2][ohel3] = _theFFWVertex->evaluate(_mw2,_widthopt,wdata, lp[ohel3],lm[ohel2]); } } // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(ihel1=0;ihel1<2;++ihel1) { for(ihel2=0;ihel2<2;++ihel2) { for(ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters=_theQQGVertex->evaluate(_scale,5,mePartonData()[2]->CC(), fout[ohel1],gin[ihel2]); interb=_theQQGVertex->evaluate(_scale,5,mePartonData()[0], fin[ihel1],gin[ihel2]); for(ohel2=0;ohel2<2;++ohel2) { for(ohel3=0;ohel3<2;++ohel3) { diag[0]= _theFFWVertex->evaluate(_mw2,inters,fin[ihel1], bcurr[ohel2][ohel3]); diag[1]= _theFFWVertex->evaluate(_mw2,fout[ohel1],interb, bcurr[ohel2][ohel3]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); if(calc) _me(ihel1,2*ihel2,ohel1,ohel2,ohel3) = diag[0]; } } } } } // results // initial state spin and colour average double colspin=1./24./4.; // and C_F N_c from matrix element colspin *= 4.; // colour factor for the W decay if(mePartonData()[3]->coloured()) colspin*=3.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix]*=colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); return me[0] * UnitRemoval::InvE2; } void MEPP2WJet::constructVertex(tSubProPtr sub) { // extract the particles in the hard process ParticleVector hard(5); // incoming hard[0]=sub->incoming().first; hard[1]=sub->incoming().second; if((hard[0]->id()<0&&hard[1]->id()<=6)|| hard[0]->id()==ParticleID::g) swap(hard[0],hard[1]); // outgoing for(unsigned int ix=0;ix<3;++ix) { unsigned int iloc; PPtr mother=sub->outgoing()[ix]->parents()[0]; if(mother&&abs(mother->id())==ParticleID::Wplus) { if(sub->outgoing()[ix]->id()>0) iloc=3; else iloc=4; } else iloc=2; hard[iloc]=sub->outgoing()[ix]; } // wavefunctions for the W decay products vector lm; vector lp; SpinorBarWaveFunction(lm,hard[3],outgoing,true,true); SpinorWaveFunction (lp,hard[4],outgoing,true,true); // identify hard process and calculate matrix element // q g to q W if(hard[0]->id()<=6&&hard[0]->id()>0&&hard[1]->id()==ParticleID::g) { vector fin; vector gin; vector fout; SpinorWaveFunction (fin ,hard[0],incoming,false,true); VectorWaveFunction (gin ,hard[1],incoming,false,true,true); SpinorBarWaveFunction (fout,hard[2],outgoing,true ,true); gin[1]=gin[2]; qgME(fin,gin,fout,lm,lp,true); } // qbar g to qbar W else if(hard[0]->id()>=-6&&hard[0]->id()<0&&hard[1]->id()==ParticleID::g) { vector ain; vector gin; vector aout; SpinorBarWaveFunction(ain ,hard[0],incoming,false,true); VectorWaveFunction (gin ,hard[1],incoming,false,true,true); SpinorWaveFunction (aout,hard[2],outgoing,true ,true); gin[1]=gin[2]; qbargME(ain,gin,aout,lm,lp,true); } // q qbar to g W else { vector fin; vector ain; vector gout; SpinorWaveFunction (fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); VectorWaveFunction (gout,hard[2],outgoing,true ,true,true); gout[1]=gout[2]; qqbarME(fin,ain,gout,lm,lp,true); } // construct the vertex HardVertexPtr hardvertex=new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(_me); // set the pointers and to and from the vertex for(unsigned int ix=0;ix<5;++ix) (hard[ix]->spinInfo())->productionVertex(hardvertex); } diff --git a/MatrixElement/Hadron/Makefile.am b/MatrixElement/Hadron/Makefile.am --- a/MatrixElement/Hadron/Makefile.am +++ b/MatrixElement/Hadron/Makefile.am @@ -1,28 +1,28 @@ pkglib_LTLIBRARIES = HwMEHadron.la HwMEHadron_la_SOURCES = \ MEqq2gZ2ff.cc MEqq2gZ2ff.h \ MEqq2W2ff.cc MEqq2W2ff.h \ MEPP2GammaJet.h MEPP2GammaJet.cc\ MEQCD2to2.h MEQCD2to2.cc\ MEPP2HiggsJet.h MEPP2HiggsJet.cc\ MEPP2GammaGamma.h MEPP2GammaGamma.cc \ MEPP2QQ.h MEPP2QQ.cc \ MEPP2QQHiggs.h MEPP2QQHiggs.cc \ MEPP2Higgs.h MEPP2Higgs.cc\ MEPP2WH.h MEPP2WH.cc \ MEPP2ZH.h MEPP2ZH.cc \ MEPP2WJet.cc MEPP2WJet.h \ MEPP2ZJet.cc MEPP2ZJet.h \ MEPP2VV.cc MEPP2VV.h \ MEPP2VGamma.cc MEPP2VGamma.h \ MEPP2HiggsVBF.cc MEPP2HiggsVBF.h \ MEPP2SingleTop.cc MEPP2SingleTop.h \ MEMinBias.h MEMinBias.cc \ MEDiffraction.h MEDiffraction.cc -HwMEHadron_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 8:1:0 +HwMEHadron_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 8:2:0 pkglib_LTLIBRARIES += HwMEHadronFast.la HwMEHadronFast_la_SOURCES = \ MEQCD2to2Fast.h MEQCD2to2Fast.cc HwMEHadronFast_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 6:0:0 diff --git a/MatrixElement/Lepton/MEee2Higgs2SM.cc b/MatrixElement/Lepton/MEee2Higgs2SM.cc --- a/MatrixElement/Lepton/MEee2Higgs2SM.cc +++ b/MatrixElement/Lepton/MEee2Higgs2SM.cc @@ -1,354 +1,354 @@ // -*- C++ -*- // // MEee2Higgs2SM.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 MEee2Higgs2SM class. // #include "MEee2Higgs2SM.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Handlers/StandardXComb.h" #include "Herwig/MatrixElement/HardVertex.h" #include "ThePEG/PDT/EnumParticles.h" using namespace Herwig; void MEee2Higgs2SM::doinit() { ME2to2Base::doinit(); h0_ = getParticleData(ThePEG::ParticleID::h0); tcHwSMPtr hwsm=ThePEG::dynamic_ptr_cast(standardModel()); // do the initialisation if(hwsm) { FFHVertex_ = hwsm->vertexFFH(); HGGVertex_ = hwsm->vertexHGG(); } else { throw InitException() << "Must have Herwig StandardModel object in " << "MEee2Higgs2SM::doinit()" << Exception::runerror; } } Energy2 MEee2Higgs2SM::scale() const { return sHat(); } unsigned int MEee2Higgs2SM::orderInAlphaS() const { return 0; } unsigned int MEee2Higgs2SM::orderInAlphaEW() const { return 2; } void MEee2Higgs2SM::getDiagrams() const { // specific the diagrams tcPDPtr ep = getParticleData(ParticleID::eplus ); tcPDPtr em = getParticleData(ParticleID::eminus); // outgoing quarks for(int i=1;i<=5;++i) { if(allowed_==0 || allowed_==1 || allowed_==i+2) { tcPDPtr lm = getParticleData(i); tcPDPtr lp = lm->CC(); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, h0_, 3, lm, 3, lp, -1))); } } // outgoing leptons for( int i =11;i<=16;i+=2) { if(allowed_==0 || allowed_==2 || allowed_==(i+7)/2) { tcPDPtr lm = getParticleData(i); tcPDPtr lp = lm->CC(); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, h0_, 3, lm, 3, lp, -1))); } } if(allowed_==0 || allowed_==12) { tcPDPtr g = getParticleData(ParticleID::g); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, h0_, 3, g, 3, g, -1))); } } double MEee2Higgs2SM::me2() const { double aver=0.; // get the order right int ielectron(0),ipositron(1),ilp(2),ilm(3); if(mePartonData()[0]->id()!=11) swap(ielectron,ipositron); if(mePartonData()[2]->id()>mePartonData()[3]->id()) swap(ilp,ilm); // the arrays for the wavefunction to be passed to the matrix element vector fin; vector ain; for(unsigned int ihel=0;ihel<2;++ihel) { fin .push_back(SpinorWaveFunction(meMomenta()[ielectron], mePartonData()[ielectron],ihel,incoming)); ain .push_back(SpinorBarWaveFunction(meMomenta()[ipositron], mePartonData()[ipositron],ihel,incoming)); } // H -> f fbar if(mePartonData()[2]->id()!=ParticleID::g) { vector aout; vector fout; for(unsigned int ihel=0;ihel<2;++ihel) { fout.push_back(SpinorBarWaveFunction(meMomenta()[ilm], mePartonData()[ilm],ihel,outgoing)); aout.push_back(SpinorWaveFunction(meMomenta()[ilp], mePartonData()[ilp],ihel,outgoing)); } HelicityME(fin,ain,fout,aout,aver); if(mePartonData()[ilm]->id()<=6) aver*=3.; } else { vector g1,g2; for(unsigned int ihel=0;ihel<2;++ihel) { g1.push_back(VectorWaveFunction(meMomenta()[2],mePartonData()[2], 2*ihel,outgoing)); g2.push_back(VectorWaveFunction(meMomenta()[3],mePartonData()[3], 2*ihel,outgoing)); } ggME(fin,ain,g1,g2,aver); aver *= 8.; } return aver; } // the helicity amplitude matrix element ProductionMatrixElement MEee2Higgs2SM::HelicityME(vector fin, vector ain, vector fout, vector aout, double & aver) const { // the particles should be in the order // for the incoming // 0 incoming fermion (u spinor) // 1 incoming antifermion (vbar spinor) // for the outgoing // 0 outgoing fermion (ubar spinor) // 1 outgoing antifermion (v spinor) // me to be returned ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); // wavefunctions for the intermediate particles ScalarWaveFunction interh; // temporary storage of the different diagrams Complex diag; aver=0.; // sum over helicities to get the matrix element unsigned int inhel1,inhel2,outhel1,outhel2; for(inhel1=0;inhel1<2;++inhel1) { for(inhel2=0;inhel2<2;++inhel2) { interh = FFHVertex_->evaluate(sHat(),1,h0_,fin[inhel1],ain[inhel2]); for(outhel1=0;outhel1<2;++outhel1) { for(outhel2=0;outhel2<2;++outhel2) { diag = FFHVertex_->evaluate(sHat(),aout[outhel2], fout[outhel1],interh); output(inhel1,inhel2,outhel1,outhel2)=diag; aver +=real(diag*conj(diag)); } } } } return output; } Selector MEee2Higgs2SM::diagrams(const DiagramVector &) const { Selector sel;sel.insert(1.0, 0); return sel; } Selector MEee2Higgs2SM::colourGeometries(tcDiagPtr diag) const { static ColourLines neutral ( " " ); static ColourLines quarks ( "-5 4"); static ColourLines gluons ( "-5 4, 5 -4"); Selector sel; int id = abs((diag->partons()[2])->id()); if (id<=6 ) sel.insert(1.0, &quarks); - if (id==21) + else if (id==21) sel.insert(1.0, &gluons); else sel.insert(1.0, &neutral); return sel; } void MEee2Higgs2SM::persistentOutput(PersistentOStream & os) const { os << FFHVertex_ << HGGVertex_ << h0_ << allowed_; } void MEee2Higgs2SM::persistentInput(PersistentIStream & is, int) { is >> FFHVertex_ >> HGGVertex_ >> h0_ >> allowed_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEee2Higgs2SM("Herwig::MEee2Higgs2SM", "HwMELepton.so"); void MEee2Higgs2SM::Init() { static ClassDocumentation documentation ("The MEee2Higgs2SM class implements the matrix element for e+e- to" " SM particle via Higgs exchnage and is designed to be a process to test" " things involving scalar particles. "); static Switch interfaceallowed ("Allowed", "Allowed outgoing particles", &MEee2Higgs2SM::allowed_, 0, false, false); static SwitchOption interfaceallowedAll (interfaceallowed, "All", "All SM particles allowed", 0); static SwitchOption interfaceallowed1 (interfaceallowed, "Quarks", "Only the quarks allowed", 1); static SwitchOption interfaceallowed2 (interfaceallowed, "Leptons", "Only the leptons allowed", 2); static SwitchOption interfacealloweddown (interfaceallowed, "Down", "Only d dbar allowed", 3); static SwitchOption interfaceallowedup (interfaceallowed, "Up", "Only u ubar allowed", 4); static SwitchOption interfaceallowedstrange (interfaceallowed, "Strange", "Only s sbar allowed", 5); static SwitchOption interfaceallowedcharm (interfaceallowed, "Charm", "Only c cbar allowed", 6); static SwitchOption interfaceallowedbottom (interfaceallowed, "Bottom", "Only b bbar allowed", 7); static SwitchOption interfaceallowedtop (interfaceallowed, "Top", "Only t tbar allowed", 8); static SwitchOption interfaceallowedelectron (interfaceallowed, "Electron", "Only e+e- allowed", 9); static SwitchOption interfaceallowedMuon (interfaceallowed, "Muon", "Only mu+mu- allowed", 10); static SwitchOption interfaceallowedTau (interfaceallowed, "Tau", "Only tau+tau- allowed", 11); static SwitchOption interfaceallowedGluon (interfaceallowed, "Gluon", "Only gg allowed", 12); } void MEee2Higgs2SM::constructVertex(tSubProPtr sub) { // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first);hard.push_back(sub->incoming().second); hard.push_back(sub->outgoing()[0]);hard.push_back(sub->outgoing()[1]); if(hard[0]->id()id()) swap(hard[0],hard[1]); if(hard[2]->id()id()) swap(hard[2],hard[3]); vector fin; vector ain; SpinorWaveFunction( fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); double me; ProductionMatrixElement prodme; if(hard[2]->id()!=ParticleID::g) { vector aout; vector fout; SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true); SpinorWaveFunction( aout,hard[3],outgoing,true ,true); // calculate the matrix element prodme=HelicityME(fin,ain,fout,aout,me); } else { vector g1,g2; VectorWaveFunction(g1,hard[2],outgoing,true,true); VectorWaveFunction(g2,hard[3],outgoing,true,true); g1[1]=g1[2]; g2[1]=g2[2]; prodme=ggME(fin,ain,g1,g2,me); } // construct the vertex HardVertexPtr hardvertex=new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(prodme); // set the pointers and to and from the vertex for(unsigned int ix=0;ix<4;++ix) { (hard[ix]->spinInfo())->productionVertex(hardvertex); } } void MEee2Higgs2SM::rebind(const TranslationMap & trans) { // dummy = trans.translate(dummy); FFHVertex_ = trans.translate(FFHVertex_); HGGVertex_ = trans.translate(HGGVertex_); h0_ = trans.translate(h0_); ME2to2Base::rebind(trans); } IVector MEee2Higgs2SM::getReferences() { IVector ret = ME2to2Base::getReferences(); ret.push_back(FFHVertex_); ret.push_back(HGGVertex_); ret.push_back(h0_); return ret; } // the helicity amplitude matrix element ProductionMatrixElement MEee2Higgs2SM::ggME(vector fin, vector ain, vector g1, vector g2, double & aver) const { ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1); // wavefunctions for the intermediate particles ScalarWaveFunction interh; // temporary storage of the different diagrams Complex diag; aver=0.; // sum over helicities to get the matrix element unsigned int inhel1,inhel2,outhel1,outhel2; for(inhel1=0;inhel1<2;++inhel1) { for(inhel2=0;inhel2<2;++inhel2) { interh = FFHVertex_->evaluate(sHat(),1,h0_,fin[inhel1],ain[inhel2]); for(outhel1=0;outhel1<2;++outhel1) { for(outhel2=0;outhel2<2;++outhel2) { diag = HGGVertex_->evaluate(sHat(),g1[outhel1],g2[outhel2],interh); output(inhel1,inhel2,2*outhel1,2*outhel2)=diag; aver +=real(diag*conj(diag)); } } } } return output; } diff --git a/MatrixElement/Lepton/MEee2gZ2qq.cc b/MatrixElement/Lepton/MEee2gZ2qq.cc --- a/MatrixElement/Lepton/MEee2gZ2qq.cc +++ b/MatrixElement/Lepton/MEee2gZ2qq.cc @@ -1,985 +1,984 @@ // -*- C++ -*- // // MEee2gZ2qq.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 MEee2gZ2qq class. // #include "MEee2gZ2qq.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Handlers/StandardXComb.h" #include "Herwig/MatrixElement/HardVertex.h" #include "ThePEG/PDF/PolarizedBeamParticleData.h" #include #include "ThePEG/Utilities/DescribeClass.h" #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; const double MEee2gZ2qq::EPS_=0.00000001; void MEee2gZ2qq::doinit() { HwMEBase::doinit(); massOption(vector(2,massopt_)); rescalingOption(3); if(minflav_>maxflav_) throw InitException() << "The minimum flavour " << minflav_ << "must be lower the than maximum flavour " << maxflav_ << " in MEee2gZ2qq::doinit() " << Exception::runerror; // set the particle data objects Z0_ = getParticleData(ParticleID::Z0); gamma_ = getParticleData(ParticleID::gamma); gluon_ = getParticleData(ParticleID::g); // cast the SM pointer to the Herwig SM pointer tcHwSMPtr hwsm= dynamic_ptr_cast(standardModel()); // do the initialisation if(!hwsm) throw InitException() << "Wrong type of StandardModel object in " << "MEee2gZ2qq::doinit() the Herwig version must be used" << Exception::runerror; FFZVertex_ = hwsm->vertexFFZ(); FFPVertex_ = hwsm->vertexFFP(); FFGVertex_ = hwsm->vertexFFG(); } void MEee2gZ2qq::getDiagrams() const { // specific the diagrams tcPDPtr ep = getParticleData(ParticleID::eplus); tcPDPtr em = getParticleData(ParticleID::eminus); tcPDPtr gamma = getParticleData(ParticleID::gamma); tcPDPtr Z0 = getParticleData(ParticleID::Z0); // setup the processes for ( int i =minflav_; i<=maxflav_; ++i ) { tcPDPtr qk = getParticleData(i); tcPDPtr qb = qk->CC(); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, gamma, 3, qk, 3, qb, -1))); add(new_ptr((Tree2toNDiagram(2), em, ep, 1, Z0 , 3, qk, 3, qb, -2))); } } Energy2 MEee2gZ2qq::scale() const { - return sqr(getParticleData(ParticleID::Z0)->mass()); -// return sHat(); + return sHat(); } unsigned int MEee2gZ2qq::orderInAlphaS() const { return 0; } unsigned int MEee2gZ2qq::orderInAlphaEW() const { return 2; } Selector MEee2gZ2qq::diagrams(const DiagramVector & diags) const { double lastCont(0.5),lastBW(0.5); if ( lastXCombPtr() ) { lastCont = meInfo()[0]; lastBW = meInfo()[1]; } Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if ( diags[i]->id() == -1 ) sel.insert(lastCont, i); else if ( diags[i]->id() == -2 ) sel.insert(lastBW, i); } return sel; } Selector MEee2gZ2qq::colourGeometries(tcDiagPtr ) const { static const ColourLines c("-5 4"); Selector sel; sel.insert(1.0, &c); return sel; } void MEee2gZ2qq::persistentOutput(PersistentOStream & os) const { os << FFZVertex_ << FFPVertex_ << FFGVertex_ << Z0_ << gamma_ << gluon_ << minflav_ << maxflav_ << massopt_ << alphaQCD_ << alphaQED_ << ounit(pTminQED_,GeV) << ounit(pTminQCD_,GeV) << preFactor_ << spinCorrelations_; } void MEee2gZ2qq::persistentInput(PersistentIStream & is, int) { is >> FFZVertex_ >> FFPVertex_ >> FFGVertex_ >> Z0_ >> gamma_ >> gluon_ >> minflav_ >> maxflav_ >> massopt_ >> alphaQCD_ >> alphaQED_ >> iunit(pTminQED_,GeV) >> iunit(pTminQCD_,GeV) >> preFactor_ >> spinCorrelations_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeMEee2gZ2qq("Herwig::MEee2gZ2qq", "HwMELepton.so"); void MEee2gZ2qq::Init() { static ClassDocumentation documentation ("The MEee2gZ2qq class implements the matrix element for e+e- -> q qbar"); static Parameter interfaceMinimumFlavour ("MinimumFlavour", "The PDG code of the quark with the lowest PDG code to produce.", &MEee2gZ2qq::minflav_, 1, 1, 6, false, false, Interface::limited); static Parameter interfaceMaximumFlavour ("MaximumFlavour", "The PDG code of the quark with the highest PDG code to produce", &MEee2gZ2qq::maxflav_, 5, 1, 6, false, false, Interface::limited); static Switch interfaceTopMassOption ("TopMassOption", "Option for the treatment of the top quark mass", &MEee2gZ2qq::massopt_, 1, false, false); static SwitchOption interfaceTopMassOptionOnMassShell (interfaceTopMassOption, "OnMassShell", "The top is produced on its mass shell", 1); static SwitchOption interfaceTopMassOption2 (interfaceTopMassOption, "OffShell", "The top is generated off-shell using the mass and width generator.", 2); static Parameter interfacepTMinQED ("pTMinQED", "Minimum pT for hard QED radiation", &MEee2gZ2qq::pTminQED_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfacepTMinQCD ("pTMinQCD", "Minimum pT for hard QCD radiation", &MEee2gZ2qq::pTminQCD_, GeV, 1.0*GeV, 0.001*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfacePrefactor ("Prefactor", "Prefactor for the overestimate of the emission probability", &MEee2gZ2qq::preFactor_, 6.0, 1.0, 100.0, false, false, Interface::limited); static Reference interfaceQCDCoupling ("AlphaQCD", "Pointer to the object to calculate the strong coupling for the correction", &MEee2gZ2qq::alphaQCD_, false, false, true, false, false); static Reference interfaceEMCoupling ("AlphaQED", "Pointer to the object to calculate the EM coupling for the correction", &MEee2gZ2qq::alphaQED_, false, false, true, false, false); static Switch interfaceSpinCorrelations ("SpinCorrelations", "Switch the construction of the veretx for spin correlations on/off", &MEee2gZ2qq::spinCorrelations_, true, false, false); static SwitchOption interfaceSpinCorrelationsYes (interfaceSpinCorrelations, "Yes", "Swtich On", true); static SwitchOption interfaceSpinCorrelationsNo (interfaceSpinCorrelations, "No", "Switch off", false); } double MEee2gZ2qq::me2() const { return loME(mePartonData(),rescaledMomenta(),true); } ProductionMatrixElement MEee2gZ2qq::HelicityME(vector & fin, vector & ain, vector & fout, vector & aout, double & me, double & cont, double & BW ) const { // the particles should be in the order // for the incoming // 0 incoming fermion (u spinor) // 1 incoming antifermion (vbar spinor) // for the outgoing // 0 outgoing fermion (ubar spinor) // 1 outgoing antifermion (v spinor) // me to be returned ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); ProductionMatrixElement gamma (PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); ProductionMatrixElement Zboson(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half); // wavefunctions for the intermediate particles VectorWaveFunction interZ,interG; // temporary storage of the different diagrams Complex diag1,diag2; // sum over helicities to get the matrix element unsigned int inhel1,inhel2,outhel1,outhel2; double total[3]={0.,0.,0.}; for(inhel1=0;inhel1<2;++inhel1) { for(inhel2=0;inhel2<2;++inhel2) { // intermediate Z interZ = FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]); // intermediate photon interG = FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]); for(outhel1=0;outhel1<2;++outhel1) { for(outhel2=0;outhel2<2;++outhel2) { // first the Z exchange diagram diag1 = FFZVertex_->evaluate(scale(),aout[outhel2],fout[outhel1], - interZ); + interZ); // then the photon exchange diagram diag2 = FFPVertex_->evaluate(scale(),aout[outhel2],fout[outhel1], - interG); + interG); // add up squares of individual terms total[1] += norm(diag1); Zboson(inhel1,inhel2,outhel1,outhel2) = diag1; total[2] += norm(diag2); gamma (inhel1,inhel2,outhel1,outhel2) = diag2; // the full thing including interference diag1 += diag2; total[0] += norm(diag1); output(inhel1,inhel2,outhel1,outhel2)=diag1; } } } } for(int ix=0;ix<3;++ix) total[ix] *= 0.25; tcPolarizedBeamPDPtr beam[2] = {dynamic_ptr_cast(mePartonData()[0]), dynamic_ptr_cast(mePartonData()[1])}; if( beam[0] || beam[1] ) { RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; total[0] = output.average(rho[0],rho[1]); total[1] = Zboson.average(rho[0],rho[1]); total[2] = gamma .average(rho[0],rho[1]); } // results for(int ix=0;ix<3;++ix) total[ix]*= 3.; cont = total[2]; BW = total[1]; me = total[0]; return output; } void MEee2gZ2qq::constructVertex(tSubProPtr sub) { if(!spinCorrelations_) return; // extract the particles in the hard process ParticleVector hard; hard.push_back(sub->incoming().first); hard.push_back(sub->incoming().second); hard.push_back(sub->outgoing()[0]); hard.push_back(sub->outgoing()[1]); if(hard[0]->id()id()) swap(hard[0],hard[1]); if(hard[2]->id()id()) swap(hard[2],hard[3]); vector fin,aout; vector ain,fout; // get wave functions for off-shell momenta for later on SpinorWaveFunction( fin ,hard[0],incoming,false,true); SpinorBarWaveFunction(ain ,hard[1],incoming,false,true); SpinorBarWaveFunction(fout,hard[2],outgoing,true ,true); SpinorWaveFunction( aout,hard[3],outgoing,true ,true); // now rescale the momenta and compute the matrix element with the // rescaled momenta for correlations vector momenta; cPDVector data; for(unsigned int ix=0;ix<4;++ix) { momenta.push_back(hard[ix]->momentum()); data .push_back(hard[ix]->dataPtr()); } rescaleMomenta(momenta,data); SpinorWaveFunction ein (rescaledMomenta()[0],data[0],incoming); SpinorBarWaveFunction pin (rescaledMomenta()[1],data[1],incoming); SpinorBarWaveFunction qkout(rescaledMomenta()[2],data[2],outgoing); SpinorWaveFunction qbout(rescaledMomenta()[3],data[3],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin [ix] = ein ; pin.reset(ix) ; ain [ix] = pin ; qkout.reset(ix); fout[ix] = qkout; qbout.reset(ix); aout[ix] = qbout; } // calculate the matrix element double me,cont,BW; ProductionMatrixElement prodme=HelicityME(fin,ain,fout,aout,me,cont,BW); // construct the vertex HardVertexPtr hardvertex=new_ptr(HardVertex()); // set the matrix element for the vertex hardvertex->ME(prodme); // set the pointers and to and from the vertex for(unsigned int ix=0;ix<4;++ix) { tSpinPtr spin = hard[ix]->spinInfo(); if(ix<2) { tcPolarizedBeamPDPtr beam = dynamic_ptr_cast(hard[ix]->dataPtr()); if(beam) spin->rhoMatrix() = beam->rhoMatrix(); } spin->productionVertex(hardvertex); } } void MEee2gZ2qq::rebind(const TranslationMap & trans) { FFZVertex_ = trans.translate(FFZVertex_); FFPVertex_ = trans.translate(FFPVertex_); FFGVertex_ = trans.translate(FFGVertex_); Z0_ = trans.translate(Z0_); gamma_ = trans.translate(gamma_); gluon_ = trans.translate(gluon_); HwMEBase::rebind(trans); } IVector MEee2gZ2qq::getReferences() { IVector ret = HwMEBase::getReferences(); ret.push_back(FFZVertex_); ret.push_back(FFPVertex_); ret.push_back(FFGVertex_); ret.push_back(Z0_ ); ret.push_back(gamma_ ); ret.push_back(gluon_ ); return ret; } void MEee2gZ2qq::initializeMECorrection(RealEmissionProcessPtr, double & initial, double & final) { d_Q_ = sqrt(sHat()); d_m_ = 0.5*(meMomenta()[2].mass()+meMomenta()[3].mass()); // set the other parameters d_rho_ = sqr(d_m_/d_Q_); d_v_ = sqrt(1.-4.*d_rho_); // maximum evolution scale d_kt1_ = (1. + sqrt(1. - 4.*d_rho_))/2.; double num = d_rho_ * d_kt1_ + 0.25 * d_v_ *(1.+d_v_)*(1.+d_v_); double den = d_kt1_ - d_rho_; d_kt2_ = num/den; // maximums for reweighting initial = 1.; final = 1.; } RealEmissionProcessPtr MEee2gZ2qq::applyHardMatrixElementCorrection(RealEmissionProcessPtr born) { return calculateRealEmission(born,true,ShowerInteraction::QCD); } RealEmissionProcessPtr MEee2gZ2qq::calculateRealEmission(RealEmissionProcessPtr born, bool veto, ShowerInteraction inter) { vector emission; unsigned int iemit,ispect; pair output = generateHard(born,emission,iemit,ispect,veto,inter); if(emission.empty()) { if(inter!=ShowerInteraction::QCD) born->pT()[ShowerInteraction::QED] = pTminQED_; if(inter!=ShowerInteraction::QED) born->pT()[ShowerInteraction::QCD] = pTminQCD_; return born; } else { Energy pTveto = output.first; if(inter!=ShowerInteraction::QCD) born->pT()[ShowerInteraction::QED] = pTveto; if(inter!=ShowerInteraction::QED) born->pT()[ShowerInteraction::QCD] = pTveto; } // generate the momenta for the hard emission ShowerInteraction force = output.second; born->interaction(force); // get the quark and antiquark ParticleVector qq; for(unsigned int ix=0;ix<2;++ix) qq.push_back(born->bornOutgoing()[ix]); bool order = qq[0]->id()>0; if(!order) swap(qq[0],qq[1]); // perform final check to ensure energy greater than constituent mass for (int i=0; i<2; i++) { if (emission[i+2].e() < qq[i]->data().constituentMass()) return RealEmissionProcessPtr(); } if(force!=ShowerInteraction::QED && emission[4].e() < gluon_->constituentMass()) return RealEmissionProcessPtr(); // set masses for (int i=0; i<2; i++) emission[i+2].setMass(qq[i]->mass()); emission[4].setMass(ZERO); // create the new quark, antiquark and gluon PPtr newq = qq[0]->dataPtr()->produceParticle(emission[2]); PPtr newa = qq[1]->dataPtr()->produceParticle(emission[3]); PPtr newg; if(force==ShowerInteraction::QCD) newg = gluon_->produceParticle(emission[4]); else newg = gamma_->produceParticle(emission[4]); // create the output real emission process for(unsigned int ix=0;ixbornIncoming().size();++ix) { born->incoming().push_back(born->bornIncoming()[ix]->dataPtr()-> produceParticle(born->bornIncoming()[ix]->momentum())); } if(order) { born->outgoing().push_back(newq); born->outgoing().push_back(newa); } else { born->outgoing().push_back(newa); born->outgoing().push_back(newq); swap(iemit,ispect); } born->outgoing().push_back(newg); // set emitter and spectator born->emitter (iemit); born->spectator(ispect); born->emitted(4); // make colour connections if(force==ShowerInteraction::QCD) { newg->colourNeighbour(newq); newa->colourNeighbour(newg); } else { newa->colourNeighbour(newq); } return born; } bool MEee2gZ2qq::softMatrixElementVeto(PPtr parent, PPtr progenitor, const bool & , const Energy & highestpT, const vector & ids, const double & d_z, const Energy & d_qt, const Energy & ) { // check we should be applying the veto if(parent->id()!=progenitor->id()|| ids[0]->id()!=ids[1]->id()|| ids[2]->id()!=ParticleID::g) return false; // calculate pt Energy2 d_m2 = parent->momentum().m2(); Energy pPerp = (1.-d_z)*sqrt( sqr(d_z*d_qt) - d_m2); // if not hardest so far don't apply veto if(pPerpid()<0) swap(x,xb); // if exceptionally out of phase space, leave this emission, as there // is no good interpretation for the soft ME correction. if( x<0 || xb<0) return false; double xg = 2. - xb - x; // always return one in the soft gluon region if(xg < EPS_) return false; // check it is in the phase space if((1.-x)*(1.-xb)*(1.-xg) < d_rho_*xg*xg) return true; double k1 = getKfromX(x, xb); double k2 = getKfromX(xb, x); double weight = 1.; // quark emission if(parent->id() > 0 && k1 < d_kt1_) { weight = MEV(x, xb)/PS(x, xb); // is it also in the anti-quark emission zone? if(k2 < d_kt2_) weight *= 0.5; } // antiquark emission if(parent->id() < 0 && k2 < d_kt2_) { weight = MEV(x, xb)/PS(xb, x); // is it also in the quark emission zone? if(k1 < d_kt1_) weight *= 0.5; } // compute veto from weight return !UseRandom::rndbool(weight); } double MEee2gZ2qq::getKfromX(double x1, double x2) { double uval = 0.5*(1. + d_rho_/(1.-x2+d_rho_)); double num = x1 - (2. - x2)*uval; double den = sqrt(x2*x2 - 4.*d_rho_); double zval = uval + num/den; return (1.-x2)/(zval*(1.-zval)); } double MEee2gZ2qq::MEV(double x1, double x2) { // Vector part double num = (x1+2.*d_rho_)*(x1+2.*d_rho_) + (x2+2.*d_rho_)*(x2+2.*d_rho_) - 8.*d_rho_*(1.+2.*d_rho_); double den = (1.+2.*d_rho_)*(1.-x1)*(1.-x2); return (num/den - 2.*d_rho_/((1.-x1)*(1.-x1)) - 2*d_rho_/((1.-x2)*(1.-x2)))/d_v_; } double MEee2gZ2qq::PS(double x, double xbar) { double u = 0.5*(1. + d_rho_ / (1.-xbar+d_rho_)); double z = u + (x - (2.-xbar)*u)/sqrt(xbar*xbar - 4.*d_rho_); double brack = (1.+z*z)/(1.-z)- 2.*d_rho_/(1-xbar); // interesting: the splitting function without the subtraction // term. Actually gives a much worse approximation in the collinear // limit. double brack = (1.+z*z)/(1.-z); double den = (1.-xbar)*sqrt(xbar*xbar - 4.*d_rho_); return brack/den; } pair MEee2gZ2qq::generateHard(RealEmissionProcessPtr born, vector & emmision, unsigned int & iemit, unsigned int & ispect, bool applyVeto,ShowerInteraction inter) { vector interactions; if(inter==ShowerInteraction::QCD) interactions.push_back(ShowerInteraction::QCD); else if(inter==ShowerInteraction::QED) interactions.push_back(ShowerInteraction::QED); else if(inter==ShowerInteraction::QEDQCD || inter==ShowerInteraction::ALL) { interactions.push_back(ShowerInteraction::QCD); interactions.push_back(ShowerInteraction::QED); } // incoming particles tPPtr em = born->bornIncoming()[0]; tPPtr ep = born->bornIncoming()[1]; if(em->id()<0) swap(em,ep); // outgoing particles tPPtr qk = born->bornOutgoing()[0]; tPPtr qb = born->bornOutgoing()[1]; if(qk->id()<0) swap(qk,qb); // extract the momenta loMomenta_.clear(); loMomenta_.push_back(em->momentum()); loMomenta_.push_back(ep->momentum()); loMomenta_.push_back(qk->momentum()); loMomenta_.push_back(qb->momentum()); // and ParticleData objects partons_.resize(5); partons_[0]=em->dataPtr(); partons_[1]=ep->dataPtr(); partons_[2]=qk->dataPtr(); partons_[3]=qb->dataPtr(); partons_[4]=cPDPtr(); // boost from lab to CMS frame with outgoing particles // along the z axis LorentzRotation eventFrame( ( loMomenta_[2] + loMomenta_[3] ).findBoostToCM() ); Lorentz5Momentum spectator = eventFrame*loMomenta_[2]; eventFrame.rotateZ( -spectator.phi() ); eventFrame.rotateY( -spectator.theta() ); eventFrame.invert(); // mass of the final-state system Energy2 M2 = (loMomenta_[2]+loMomenta_[3]).m2(); Energy M = sqrt(M2); double mu1 = loMomenta_[2].mass()/M; double mu2 = loMomenta_[3].mass()/M; double mu12 = sqr(mu1), mu22 = sqr(mu2); double lambda = sqrt(1.+sqr(mu12)+sqr(mu22)-2.*mu12-2.*mu22-2.*mu12*mu22); // max pT Energy pTmax = 0.5*sqrt(M2)* (1.-sqr(loMomenta_[2].mass()+loMomenta_[3].mass())/M2); // max y if ( pTmax < pTminQED_ && pTmax < pTminQCD_ ) return make_pair(ZERO,ShowerInteraction::QCD); vector pTemit; vector > emittedMomenta;; vector iemitter,ispectator; for(unsigned int iinter=0;iinteroverestimateValue()/Constants::twopi* 2.*ymax*preFactor_; } else { pTmin = pTminQED_; ymax = acosh(pTmax/pTmin); partons_[4] = gamma_; a = alphaQED_->overestimateValue()/Constants::twopi* 2.*ymax*preFactor_*sqr(double(mePartonData()[2]->iCharge())/3.); } // variables for the emission Energy pT[2]; double y[2],phi[2],x3[2],x1[2][2],x2[2][2]; double contrib[2][2]; // storage of the real emission momenta vector realMomenta[2][2]= {{vector(5),vector(5)}, {vector(5),vector(5)}}; for(unsigned int ix=0;ix<2;++ix) for(unsigned int iy=0;iy<2;++iy) for(unsigned int iz=0;iz<2;++iz) realMomenta[ix][iy][iz] = loMomenta_[iz]; // generate the emission for(unsigned int ix=0;ix<2;++ix) { if(ix==1) { swap(mu1 ,mu2 ); swap(mu12,mu22); } pT[ix] = pTmax; y [ix] = 0.; bool reject = true; do { // generate pT pT[ix] *= pow(UseRandom::rnd(),1./a); if(pT[ix] 1. -sqr( mu1 + mu2 ) ) continue; // find the possible solutions for x1 double xT2 = sqr(2./M*pT[ix]); double root = (-sqr(x3[ix])+xT2)* (xT2*mu22+2.*x3[ix]-sqr(mu12)+2.*mu22+2.*mu12-sqr(x3[ix])-1. +2.*mu12*mu22-sqr(mu22)-2.*mu22*x3[ix]-2.*mu12*x3[ix]); double c1=2.*sqr(x3[ix])-4.*mu22-6.*x3[ix]+4.*mu12-xT2*x3[ix] +2.*xT2-2.*mu12*x3[ix]+2.*mu22*x3[ix]+4.; if(root<0.) continue; x1[ix][0] = 1./(4.-4.*x3[ix]+xT2)*(c1-2.*sqrt(root)); x1[ix][1] = 1./(4.-4.*x3[ix]+xT2)*(c1+2.*sqrt(root)); // change sign of y if 2nd particle emits if(ix==1) y[ix] *=-1.; // loop over the solutions for(unsigned int iy=0;iy<2;++iy) { contrib[ix][iy]=0.; // check x1 value allowed if(x1[ix][iy]<2.*mu1||x1[ix][iy]>1.+mu12-mu22) continue; // calculate x2 value and check allowed x2[ix][iy] = 2.-x3[ix]-x1[ix][iy]; double root = max(0.,sqr(x1[ix][iy])-4.*mu12); root = sqrt(root); double x2min = 1.+mu22-mu12 -0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12+root); double x2max = 1.+mu22-mu12 -0.5*(1.-x1[ix][iy]+mu12-mu22)/(1.-x1[ix][iy]+mu12)*(x1[ix][iy]-2.*mu12-root); if(x2[ix][iy]x2max) continue; // check the z components double z1 = sqr(x1[ix][iy])-4.*mu12-xT2; if(z1<0. && z1>-1e-12) z1 = 0.; assert(z1>=0.); z1 = sqrt(z1); double z2 = sqr(x2[ix][iy])-4.*mu22; if(z2<0. && z2>-1e-12) z2 = 0.; assert(z2>=0.); z2 = -sqrt(z2); double z3 = pT[ix]*sinh(y[ix])*2./M; if(ix==1) z3 *=-1.; if(abs(-z1+z2+z3)<1e-9) z1 *= -1.; if(abs(z1+z2+z3)>1e-5) continue; // if using as an ME correction the veto if(applyVeto) { double xb = x1[ix][iy], xc = x2[ix][iy]; double b = mu12, c = mu22; double r = 0.5*(1.+b/(1.+c-xc)); double z1 = r + (xb-(2.-xc)*r)/sqrt(sqr(xc)-4.*c); double kt1 = (1.-b+c-xc)/z1/(1.-z1); r = 0.5*(1.+c/(1.+b-xb)); double z2 = r + (xc-(2.-xb)*r)/sqrt(sqr(xb)-4.*b); double kt2 = (1.-c+b-xb)/z2/(1.-z2); if(ix==1) { swap(z1 ,z2); swap(kt1,kt2); } // veto the shower region if( kt1 < d_kt1_ || kt2 < d_kt2_ ) continue; } // construct the momenta realMomenta[ix][iy][4] = Lorentz5Momentum(pT[ix]*cos(phi[ix]),pT[ix]*sin(phi[ix]), pT[ix]*sinh(y[ix]) ,pT[ix]*cosh(y[ix]),ZERO); if(ix==0) { realMomenta[ix][iy][2] = Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); realMomenta[ix][iy][3] = Lorentz5Momentum(ZERO,ZERO, z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); } else { realMomenta[ix][iy][2] = Lorentz5Momentum(ZERO,ZERO,-z2*0.5*M,x2[ix][iy]*0.5*M,M*mu2); realMomenta[ix][iy][3] = Lorentz5Momentum(-pT[ix]*cos(phi[ix]),-pT[ix]*sin(phi[ix]), -z1*0.5*M,x1[ix][iy]*0.5*M,M*mu1); } // boost the momenta back to the lab for(unsigned int iz=2;iz<5;++iz) realMomenta[ix][iy][iz] *= eventFrame; // jacobian and prefactors for the weight Energy J = M/sqrt(xT2)*abs(-x1[ix][iy]*x2[ix][iy]+2.*mu22*x1[ix][iy] +x2[ix][iy]+x2[ix][iy]*mu12+mu22*x2[ix][iy] -sqr(x2[ix][iy])) /pow(sqr(x2[ix][iy])-4.*mu22,1.5); // prefactors etc contrib[ix][iy] = 0.5*pT[ix]/J/preFactor_/lambda; // matrix element piece contrib[ix][iy] *= meRatio(partons_,realMomenta[ix][iy], ix,interactions[iinter],false); // coupling piece if(interactions[iinter]==ShowerInteraction::QCD) contrib[ix][iy] *= alphaQCD_->ratio(sqr(pT[ix])); else contrib[ix][iy] *= alphaQED_->ratio(sqr(pT[ix])); } if(contrib[ix][0]+contrib[ix][1]>1.) { ostringstream s; s << "MEee2gZ2qq::generateHardest weight for channel " << ix << "is " << contrib[ix][0]+contrib[ix][1] << " which is greater than 1"; generator()->logWarning( Exception(s.str(), Exception::warning) ); } reject = UseRandom::rnd() > contrib[ix][0] + contrib[ix][1]; } while (reject); if(pT[ix]()); iemitter .push_back(0); ispectator.push_back(0); continue; } // now pick the emission with highest pT vector emission; if(pT[0]>pT[1]) { iemitter .push_back(2); ispectator.push_back(3); pTemit.push_back(pT[0]); if(UseRandom::rnd()pTmax) { iselect = ix; pTmax = pTemit[ix]; } } // no emission return if(iselect<0) { return make_pair(ZERO,ShowerInteraction::QCD); } partons_[4] = interactions[iselect]==ShowerInteraction::QCD ? gluon_ : gamma_; iemit = iemitter[iselect]; ispect = ispectator[iselect]; emmision = emittedMomenta[iselect]; // return pT of emission return make_pair(pTmax,interactions[iselect]); } RealEmissionProcessPtr MEee2gZ2qq::generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { return calculateRealEmission(born,false,inter); } double MEee2gZ2qq::meRatio(vector partons, vector momenta, unsigned int iemitter, ShowerInteraction inter, bool subtract) const { Lorentz5Momentum q = momenta[2]+momenta[3]+momenta[4]; Energy2 Q2=q.m2(); Energy2 lambda = sqrt((Q2-sqr(momenta[2].mass()+momenta[3].mass()))* (Q2-sqr(momenta[2].mass()-momenta[3].mass()))); InvEnergy2 D[2]; double lome[2]; for(unsigned int iemit=0;iemit<2;++iemit) { unsigned int ispect = iemit==0 ? 1 : 0; Energy2 pipj = momenta[4 ] * momenta[2+iemit ]; Energy2 pipk = momenta[4 ] * momenta[2+ispect]; Energy2 pjpk = momenta[2+iemit] * momenta[2+ispect]; double y = pipj/(pipj+pipk+pjpk); double z = pipk/( pipk+pjpk); Energy mij = sqrt(2.*pipj+sqr(momenta[2+iemit].mass())); Energy2 lamB = sqrt((Q2-sqr(mij+momenta[2+ispect].mass()))* (Q2-sqr(mij-momenta[2+ispect].mass()))); Energy2 Qpk = q*momenta[2+ispect]; Lorentz5Momentum pkt = lambda/lamB*(momenta[2+ispect]-Qpk/Q2*q) +0.5/Q2*(Q2+sqr(momenta[2+ispect].mass())-sqr(momenta[2+ispect].mass()))*q; Lorentz5Momentum pijt = q-pkt; double muj = momenta[2+iemit ].mass()/sqrt(Q2); double muk = momenta[2+ispect].mass()/sqrt(Q2); double vt = sqrt((1.-sqr(muj+muk))*(1.-sqr(muj-muk)))/(1.-sqr(muj)-sqr(muk)); double v = sqr(2.*sqr(muk)+(1.-sqr(muj)-sqr(muk))*(1.-y))-4.*sqr(muk); if(v<=0.) return 0.; v = sqrt(v)/(1.-y)/(1.-sqr(muj)-sqr(muk)); // dipole term D[iemit] = 0.5/pipj*(2./(1.-(1.-z)*(1.-y)) -vt/v*(2.-z+sqr(momenta[2+iemit].mass())/pipj)); // matrix element vector lomom(4); lomom[0] = momenta[0]; lomom[1] = momenta[1]; if(iemit==0) { lomom[2] = pijt; lomom[3] = pkt ; } else { lomom[3] = pijt; lomom[2] = pkt ; } lome[iemit] = loME(partons,lomom,false)/3.; } InvEnergy2 ratio = realME(partons,momenta,inter) *abs(D[iemitter])/(abs(D[0]*lome[0])+abs(D[1]*lome[1])); double output = Q2*ratio; if(subtract) output -= 2.*Q2*D[iemitter]; return output; } double MEee2gZ2qq::loME(const vector & partons, const vector & momenta, bool first) const { // compute the spinors vector fin,aout; vector ain,fout; SpinorWaveFunction ein (momenta[0],partons[0],incoming); SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing); SpinorWaveFunction qbout(momenta[3],partons[3],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin.push_back( ein ); pin.reset(ix) ; ain.push_back( pin ); qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); } // compute the matrix element double me,lastCont,lastBW; HelicityME(fin,ain,fout,aout,me,lastCont,lastBW); // save the components if(first) { DVector save; save.push_back(lastCont); save.push_back(lastBW); meInfo(save); } // return the answer return me; } InvEnergy2 MEee2gZ2qq::realME(const vector & partons, const vector & momenta, ShowerInteraction inter) const { // compute the spinors vector fin,aout; vector ain,fout; vector gout; SpinorWaveFunction ein (momenta[0],partons[0],incoming); SpinorBarWaveFunction pin (momenta[1],partons[1],incoming); SpinorBarWaveFunction qkout(momenta[2],partons[2],outgoing); SpinorWaveFunction qbout(momenta[3],partons[3],outgoing); VectorWaveFunction gluon(momenta[4],partons[4],outgoing); for(unsigned int ix=0;ix<2;++ix) { ein.reset(ix) ; fin.push_back( ein ); pin.reset(ix) ; ain.push_back( pin ); qkout.reset(ix); fout.push_back(qkout); qbout.reset(ix); aout.push_back(qbout); gluon.reset(2*ix); gout.push_back(gluon); } AbstractFFVVertexPtr vertex = inter == ShowerInteraction::QCD ? FFGVertex_ : FFPVertex_; vector diag(4,0.); ProductionMatrixElement output(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1); double total(0.); for(unsigned int inhel1=0;inhel1<2;++inhel1) { for(unsigned int inhel2=0;inhel2<2;++inhel2) { // intermediate Z VectorWaveFunction interZ = FFZVertex_->evaluate(scale(),1,Z0_,fin[inhel1],ain[inhel2]); // intermediate photon VectorWaveFunction interG = FFPVertex_->evaluate(scale(),1,gamma_,fin[inhel1],ain[inhel2]); for(unsigned int outhel1=0;outhel1<2;++outhel1) { for(unsigned int outhel2=0;outhel2<2;++outhel2) { for(unsigned int outhel3=0;outhel3<2;++outhel3) { SpinorBarWaveFunction off1 = vertex->evaluate(scale(),3,partons[2]->CC(),fout[outhel1],gout[outhel3]); diag[0] = FFZVertex_->evaluate(scale(),aout[outhel2],off1,interZ); diag[1] = FFPVertex_->evaluate(scale(),aout[outhel2],off1,interG); SpinorWaveFunction off2 = vertex->evaluate(scale(),3,partons[3]->CC(),aout[outhel2],gout[outhel3]); diag[2] = FFZVertex_->evaluate(scale(),off2,fout[outhel1],interZ); diag[3] = FFPVertex_->evaluate(scale(),off2,fout[outhel1],interG); // sum of diagrams Complex sum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); // matrix element output(inhel1,inhel2,outhel1,outhel2,outhel3)=sum; // me2 total += norm(sum); } } } } } // spin average total *= 0.25; tcPolarizedBeamPDPtr beam[2] = {dynamic_ptr_cast(partons[0]), dynamic_ptr_cast(partons[1])}; if( beam[0] || beam[1] ) { RhoDMatrix rho[2] = {beam[0] ? beam[0]->rhoMatrix() : RhoDMatrix(mePartonData()[0]->iSpin()), beam[1] ? beam[1]->rhoMatrix() : RhoDMatrix(mePartonData()[1]->iSpin())}; total = output.average(rho[0],rho[1]); } // divide out the coupling total /= norm(vertex->norm()); // and charge (if needed) if(inter==ShowerInteraction::QED) total /= sqr(double(mePartonData()[2]->iCharge())/3.); // return the total return total*UnitRemoval::InvE2; } diff --git a/MatrixElement/Lepton/Makefile.am b/MatrixElement/Lepton/Makefile.am --- a/MatrixElement/Lepton/Makefile.am +++ b/MatrixElement/Lepton/Makefile.am @@ -1,10 +1,10 @@ pkglib_LTLIBRARIES = HwMELepton.la HwMELepton_la_SOURCES = \ MEee2gZ2qq.h MEee2gZ2qq.cc\ MEee2gZ2ll.h MEee2gZ2ll.cc\ MEee2ZH.h MEee2ZH.cc\ MEee2HiggsVBF.h MEee2HiggsVBF.cc \ MEee2VV.h MEee2VV.cc \ MEee2VectorMeson.h MEee2VectorMeson.cc \ MEee2Higgs2SM.h MEee2Higgs2SM.cc -HwMELepton_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 7:0:0 +HwMELepton_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 7:1:0 diff --git a/MatrixElement/Matchbox/Matching/QTildeMatching.cc b/MatrixElement/Matchbox/Matching/QTildeMatching.cc --- a/MatrixElement/Matchbox/Matching/QTildeMatching.cc +++ b/MatrixElement/Matchbox/Matching/QTildeMatching.cc @@ -1,525 +1,538 @@ // -*- C++ -*- // // QTildeMatching.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 QTildeMatching class. // #include "QTildeMatching.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/MatrixElement/Matchbox/Dipoles/SubtractionDipole.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/TildeKinematics.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicHelpers.h" using namespace Herwig; QTildeMatching::QTildeMatching() : theCorrectForXZMismatch(true) {} QTildeMatching::~QTildeMatching() {} IBPtr QTildeMatching::clone() const { return new_ptr(*this); } IBPtr QTildeMatching::fullclone() const { return new_ptr(*this); } void QTildeMatching::checkCutoff() { if ( showerTildeKinematics() ) { showerTildeKinematics()-> prepare(realCXComb(),bornCXComb()); showerTildeKinematics()->dipole(dipole()); showerTildeKinematics()->getShowerVariables(); } } void QTildeMatching::getShowerVariables() { // already filled from checkCutoff in this case if ( showerTildeKinematics() ) return; // get the shower variables calculateShowerVariables(); // check for the cutoff dipole()->isAboveCutoff(isAboveCutoff()); // get the hard scale dipole()->showerHardScale(hardScale()); // check for phase space dipole()->isInShowerPhasespace(isInShowerPhasespace()); } bool QTildeMatching::isInShowerPhasespace() const { - assert((theQTildeSudakov->cutOffOption() == 0 || theQTildeSudakov->cutOffOption() == 2) && - "implementation only provided for default and pt cutoff"); - Energy qtildeHard = ZERO; Energy qtilde = dipole()->showerScale(); assert(!dipole()->showerParameters().empty()); double z = dipole()->showerParameters()[0]; // FF if ( dipole()->bornEmitter() > 1 && dipole()->bornSpectator() > 1 ) { qtildeHard = theQTildeFinder-> calculateFinalFinalScales(bornCXComb()->meMomenta()[dipole()->bornEmitter()], - bornCXComb()->meMomenta()[dipole()->bornSpectator()], - bornCXComb()->mePartonData()[dipole()->bornEmitter()]->iColour() == PDT::Colour3).first; + bornCXComb()->meMomenta()[dipole()->bornSpectator()]).first; } // FI if ( dipole()->bornEmitter() > 1 && dipole()->bornSpectator() < 2 ) { qtildeHard = theQTildeFinder-> calculateInitialFinalScales(bornCXComb()->meMomenta()[dipole()->bornSpectator()], bornCXComb()->meMomenta()[dipole()->bornEmitter()],false).second; } // IF if ( dipole()->bornEmitter() < 2 && dipole()->bornSpectator() > 1 ) { qtildeHard = theQTildeFinder-> calculateInitialFinalScales(bornCXComb()->meMomenta()[dipole()->bornEmitter()], bornCXComb()->meMomenta()[dipole()->bornSpectator()],false).first; if ( z < (dipole()->bornEmitter() == 0 ? bornCXComb()->lastX1() : bornCXComb()->lastX2()) ) return false; } // II if ( dipole()->bornEmitter() < 2 && dipole()->bornSpectator() < 2 ) { qtildeHard = theQTildeFinder-> calculateInitialInitialScales(bornCXComb()->meMomenta()[dipole()->bornEmitter()], bornCXComb()->meMomenta()[dipole()->bornSpectator()]).first; if ( z < (dipole()->bornEmitter() == 0 ? bornCXComb()->lastX1() : bornCXComb()->lastX2()) ) return false; } + Energy2 pt2 = ZERO; - Energy Qg = theQTildeSudakov->kinScale(); - Energy2 pt2 = ZERO; + const vector & masses = theQTildeSudakov->virtualMasses({{ + bornCXComb()->mePartonData()[dipole()->bornEmitter() ], + realCXComb()->mePartonData()[dipole()->realEmitter() ], + realCXComb()->mePartonData()[dipole()->realEmission()] + }}); + + const Energy2 m22 = sqr(masses[2]); + if ( dipole()->bornEmitter() > 1 ) { - Energy mu = max(Qg,realCXComb()->meMomenta()[dipole()->realEmitter()].mass()); - if ( bornCXComb()->mePartonData()[dipole()->bornEmitter()]->id() == ParticleID::g ) - pt2 = sqr(z*(1.-z)*qtilde) - sqr(mu); - else - pt2 = sqr(z*(1.-z)*qtilde) - sqr((1.-z)*mu) - z*sqr(Qg); + const Energy2 m02 = sqr(masses[0]); + const Energy2 m12 = sqr(masses[1]); + + pt2 = QTildeKinematics::pT2_FSR(sqr(qtilde),z,m02,m12,m22); } - if ( dipole()->bornEmitter() < 2 ) { - pt2 = sqr((1.-z)*qtilde) - z*sqr(Qg); + else { + pt2 = QTildeKinematics::pT2_ISR(sqr(qtilde),z,m22); } if ( pt2 < max(theQTildeSudakov->pT2min(),sqr(safeCut()) )) return false; bool hardVeto = restrictPhasespace() && sqrt(pt2) >= dipole()->showerHardScale(); return qtilde <= qtildeHard && !hardVeto; } bool QTildeMatching::isAboveCutoff() const { - - assert((theQTildeSudakov->cutOffOption() == 0 || theQTildeSudakov->cutOffOption() == 2) && - "implementation only provided for default and pt cutoff"); Energy qtilde = dipole()->showerScale(); assert(!dipole()->showerParameters().empty()); double z = dipole()->showerParameters()[0]; - Energy Qg = theQTildeSudakov->kinScale(); + + + const vector & masses = theQTildeSudakov->virtualMasses({{ + bornCXComb()->mePartonData()[dipole()->bornEmitter() ], + realCXComb()->mePartonData()[dipole()->realEmitter() ], + realCXComb()->mePartonData()[dipole()->realEmission()] + }}); + + const Energy2 m22 = sqr(masses[2]); + if ( dipole()->bornEmitter() > 1 ) { - Energy mu = max(Qg,realCXComb()->meMomenta()[dipole()->realEmitter()].mass()); - if ( bornCXComb()->mePartonData()[dipole()->bornEmitter()]->id() == ParticleID::g ) - return sqr(z*(1.-z)*qtilde) - sqr(mu) >= - max(theQTildeSudakov->pT2min(),sqr(safeCut())); - else - return sqr(z*(1.-z)*qtilde) - sqr((1.-z)*mu) - z*sqr(Qg) >= - max(theQTildeSudakov->pT2min(),sqr(safeCut())); + const Energy2 m02 = sqr(masses[0]); + const Energy2 m12 = sqr(masses[1]); + + const Energy2 pt2 = QTildeKinematics::pT2_FSR(sqr(qtilde),z,m02,m12,m22); + + return pt2 >= max(theQTildeSudakov->pT2min(),sqr(safeCut())); } - if ( dipole()->bornEmitter() < 2 ) { - return - sqr((1.-z)*qtilde) - z*sqr(Qg) >= - max(theQTildeSudakov->pT2min(),sqr(safeCut())); + else { + const Energy2 pt2 = QTildeKinematics::pT2_ISR(sqr(qtilde),z,m22); + return pt2 >= max(theQTildeSudakov->pT2min(),sqr(safeCut())); } return false; } CrossSection QTildeMatching::dSigHatDR() const { assert(!dipole()->showerParameters().empty()); pair vars = make_pair(sqr(dipole()->showerScale()), dipole()->showerParameters()[0]); pair ij(dipole()->bornEmitter(), dipole()->bornSpectator()); double ccme2 = dipole()->underlyingBornME()->largeNColourCorrelatedME2(ij,theLargeNBasis); if(ccme2==0.)return 0.*nanobarn; double lnme2=dipole()->underlyingBornME()->largeNME2(theLargeNBasis); if(lnme2==0){ generator()->log() <<"\nQTildeMatching: "; generator()->log() <<"\n largeNME2 is ZERO, while largeNColourCorrelatedME2 is not ZERO." ; generator()->log() <<"\n This is too seriuos.\n" ; generator()->log() << Exception::runerror; } ccme2 *= dipole()->underlyingBornME()->me2() /lnme2; Energy2 prop = ZERO; if ( dipole()->bornEmitter() > 1 ) { prop = (realCXComb()->meMomenta()[dipole()->realEmitter()] + realCXComb()->meMomenta()[dipole()->realEmission()]).m2() - bornCXComb()->meMomenta()[dipole()->bornEmitter()].m2(); } else { prop = 2.*vars.second*(realCXComb()->meMomenta()[dipole()->realEmitter()]* realCXComb()->meMomenta()[dipole()->realEmission()]); } // note alphas included downstream from subtractionScaleWeight() double xme2 = -8.*Constants::pi*ccme2*splitFn(vars)*realXComb()->lastSHat()/prop; xme2 *= pow(realCXComb()->lastSHat() / bornCXComb()->lastSHat(), bornCXComb()->mePartonData().size()-4.); double bornPDF = bornPDFWeight(dipole()->underlyingBornME()->lastScale()); if ( bornPDF == 0.0 ) return ZERO; xme2 *= bornPDF; xme2 *= dipole()->realEmissionME()->finalStateSymmetry() / dipole()->underlyingBornME()->finalStateSymmetry(); // take care of mismatch between z and x as we are approaching the // hard phase space boundary // TODO get rid of this useless scale option business and simplify PDF handling in here if ( dipole()->bornEmitter() < 2 && theCorrectForXZMismatch ) { Energy2 emissionScale = ZERO; if ( emissionScaleInSubtraction() == showerScale ) { emissionScale = showerFactorizationScale(); } else if ( emissionScaleInSubtraction() == realScale ) { emissionScale = dipole()->realEmissionME()->lastScale(); } else if ( emissionScaleInSubtraction() == bornScale ) { emissionScale = dipole()->underlyingBornME()->lastScale(); } double xzMismatch = dipole()->subtractionParameters()[0] / dipole()->showerParameters()[0]; double realCorrectedPDF = dipole()->bornEmitter() == 0 ? dipole()->realEmissionME()->pdf1(emissionScale,theExtrapolationX, xzMismatch) : dipole()->realEmissionME()->pdf2(emissionScale,theExtrapolationX, xzMismatch); double realPDF = dipole()->bornEmitter() == 0 ? dipole()->realEmissionME()->pdf1(emissionScale,theExtrapolationX,1.0) : dipole()->realEmissionME()->pdf2(emissionScale,theExtrapolationX,1.0); if ( realPDF == 0.0 || realCorrectedPDF == 0.0 ) return ZERO; xme2 *= realCorrectedPDF / realPDF; } Energy qtilde = sqrt(vars.first); double z = vars.second; Energy2 pt2 = ZERO; - Energy Qg = theQTildeSudakov->kinScale(); + + const vector & masses = theQTildeSudakov->virtualMasses({{ + bornCXComb()->mePartonData()[dipole()->bornEmitter() ], + realCXComb()->mePartonData()[dipole()->realEmitter() ], + realCXComb()->mePartonData()[dipole()->realEmission()] + }}); + + const Energy2 m22 = sqr(masses[2]); if ( dipole()->bornEmitter() > 1 ) { - Energy mu = max(Qg,realCXComb()->meMomenta()[dipole()->realEmitter()].mass()); - if ( bornCXComb()->mePartonData()[dipole()->bornEmitter()]->id() == ParticleID::g ) - pt2 = sqr(z*(1.-z)*qtilde) - sqr(mu); - else - pt2 = sqr(z*(1.-z)*qtilde) - sqr((1.-z)*mu) - z*sqr(Qg); + const Energy2 m02 = sqr(masses[0]); + const Energy2 m12 = sqr(masses[1]); + + pt2 = QTildeKinematics::pT2_FSR(sqr(qtilde),z,m02,m12,m22); } - if ( dipole()->bornEmitter() < 2 ) { - pt2 = sqr((1.-z)*qtilde) - z*sqr(Qg); + else { + pt2 = QTildeKinematics::pT2_ISR(sqr(qtilde),z,m22); } assert(pt2 >= ZERO); if ( profileScales() ) xme2 *= profileScales()->hardScaleProfile(dipole()->showerHardScale(),sqrt(pt2)); CrossSection res = sqr(hbarc) * realXComb()->jacobian() * subtractionScaleWeight() * xme2 / (2. * realXComb()->lastSHat()); return res; } double QTildeMatching::me2() const { throw Exception() << "QTildeMatching::me2(): Not intented to use. Disable the ShowerApproximationGenerator." << Exception::runerror; return 0.; } void QTildeMatching::calculateShowerVariables() const { Lorentz5Momentum n; Energy2 Q2 = ZERO; const Lorentz5Momentum& pb = bornCXComb()->meMomenta()[dipole()->bornEmitter()]; const Lorentz5Momentum& pc = bornCXComb()->meMomenta()[dipole()->bornSpectator()]; if ( dipole()->bornEmitter() > 1 ) { Q2 = (pb+pc).m2(); } else { Q2 = -(pb-pc).m2(); } if ( dipole()->bornEmitter() > 1 && dipole()->bornSpectator() > 1 ) { double b = sqr(bornCXComb()->meMomenta()[dipole()->bornEmitter()].m())/Q2; double c = sqr(bornCXComb()->meMomenta()[dipole()->bornSpectator()].m())/Q2; double lambda = sqrt(1.+sqr(b)+sqr(c)-2.*b-2.*c-2.*b*c); n = (1.-0.5*(1.-b+c-lambda))*pc - 0.5*(1.-b+c-lambda)*pb; } if ( dipole()->bornEmitter() > 1 && dipole()->bornSpectator() < 2 ) { n = bornCXComb()->meMomenta()[dipole()->bornSpectator()]; } if ( dipole()->bornEmitter() < 2 && dipole()->bornSpectator() > 1 ) { double c = sqr(bornCXComb()->meMomenta()[dipole()->bornSpectator()].m())/Q2; n = (1.+c)*pc - c*pb; } if ( dipole()->bornEmitter() < 2 && dipole()->bornSpectator() < 2 ) { n = bornCXComb()->meMomenta()[dipole()->bornSpectator()]; } // the light-cone condition is numerically not very stable, so we // explicitly push it on the light-cone here n.setMass(ZERO); n.rescaleEnergy(); double z = 0.0; if ( dipole()->bornEmitter() > 1 ) { z = 1. - (n*realCXComb()->meMomenta()[dipole()->realEmission()])/ (n*bornCXComb()->meMomenta()[dipole()->bornEmitter()]); } else { z = 1. - (n*realCXComb()->meMomenta()[dipole()->realEmission()])/ (n*realCXComb()->meMomenta()[dipole()->realEmitter()]); } // allow small violations (numerical inaccuracies) if ( z <= 0 && z >= -1e-6 ) { z = std::numeric_limits::epsilon(); } else if ( z >= 1 && z <= 1+1e-6 ) { z = 1-std::numeric_limits::epsilon(); } Energy2 qtilde2 = ZERO; Energy2 q2 = ZERO; if ( dipole()->bornEmitter() > 1 ) { q2 = (realCXComb()->meMomenta()[dipole()->realEmitter()] + realCXComb()->meMomenta()[dipole()->realEmission()]).m2(); qtilde2 = (q2 - bornCXComb()->meMomenta()[dipole()->bornEmitter()].m2())/(z*(1.-z)); } else { q2 = -(realCXComb()->meMomenta()[dipole()->realEmitter()] - realCXComb()->meMomenta()[dipole()->realEmission()]).m2(); qtilde2 = (q2 + bornCXComb()->meMomenta()[dipole()->bornEmitter()].m2())/(1.-z); } if ( qtilde2 < ZERO ) { qtilde2 = ZERO; } assert(qtilde2 >= ZERO && z > 0.0 && z < 1.0); dipole()->showerScale(sqrt(qtilde2)); dipole()->showerParameters().resize(1); dipole()->showerParameters()[0] = z; } double QTildeMatching::splitFn(const pair& vars) const { const Energy2& qtilde2 = vars.first; const double z = vars.second; double Nc = SM().Nc(); // final state branching if ( dipole()->bornEmitter() > 1 ) { // final state quark quark branching if ( abs(bornCXComb()->mePartonData()[dipole()->bornEmitter()]->id()) < 7 ) { Energy m = bornCXComb()->mePartonData()[dipole()->bornEmitter()]->hardProcessMass(); return ((sqr(Nc)-1.)/(2.*Nc))*(1+sqr(z)-2.*sqr(m)/(z*qtilde2))/(1.-z); } // final state gluon branching if ( bornCXComb()->mePartonData()[dipole()->bornEmitter()]->id() == ParticleID::g ) { if ( realCXComb()->mePartonData()[dipole()->realEmission()]->id() == ParticleID::g ) { // ATTENTION the factor 2 here is intentional as it cancels to the 1/2 // stemming from the large-N colour correlator return 2.*Nc*(z/(1.-z)+(1.-z)/z+z*(1.-z)); } if ( abs(realCXComb()->mePartonData()[dipole()->realEmission()]->id()) < 7 ) { Energy m = realCXComb()->mePartonData()[dipole()->realEmission()]->hardProcessMass(); return (1./2.)*(1.-2.*z*(1.-z)+2.*sqr(m)/(z*(1.-z)*qtilde2)); } } // final state squark branching if ((abs(bornCXComb()->mePartonData()[dipole()->bornEmitter()]->id()) > 1000000 && abs(bornCXComb()->mePartonData()[dipole()->bornEmitter()]->id()) < 1000007) || (abs(bornCXComb()->mePartonData()[dipole()->bornEmitter()]->id()) > 2000000 && abs(bornCXComb()->mePartonData()[dipole()->bornEmitter()]->id()) < 2000007)){ Energy m = bornCXComb()->mePartonData()[dipole()->bornEmitter()]->hardProcessMass(); return ((sqr(Nc)-1.)/Nc)*(z-sqr(m)/(z*qtilde2))/(1.-z); } // final state gluino branching if (bornCXComb()->mePartonData()[dipole()->bornEmitter()]->id() == 1000021){ Energy m = bornCXComb()->mePartonData()[dipole()->bornEmitter()]->hardProcessMass(); return Nc*(1.+sqr(z)-2.*sqr(m)/(z*qtilde2))/(1.-z); } } // initial state branching if ( dipole()->bornEmitter() < 2 ) { // g/g if ( realCXComb()->mePartonData()[dipole()->realEmitter()]->id() == ParticleID::g && realCXComb()->mePartonData()[dipole()->realEmission()]->id() == ParticleID::g ) { // see above for factor of 2 return 2.*Nc*(z/(1.-z)+(1.-z)/z+z*(1.-z)); } // q/q if ( abs(realCXComb()->mePartonData()[dipole()->realEmitter()]->id()) < 7 && realCXComb()->mePartonData()[dipole()->realEmission()]->id() == ParticleID::g ) { return ((sqr(Nc)-1.)/(2.*Nc))*(1+sqr(z))/(1.-z); } // g/q if ( realCXComb()->mePartonData()[dipole()->realEmitter()]->id() == ParticleID::g && abs(realCXComb()->mePartonData()[dipole()->realEmission()]->id()) < 7 ) { return (1./2.)*(1.-2.*z*(1.-z)); } // q/g if ( abs(realCXComb()->mePartonData()[dipole()->realEmitter()]->id()) < 7 && abs(realCXComb()->mePartonData()[dipole()->realEmission()]->id()) < 7 ) { return ((sqr(Nc)-1.)/(2.*Nc))*(1+sqr(1.-z))/z; } } return 0.0; } // If needed, insert default implementations of virtual function defined // in the InterfacedBase class here (using ThePEG-interfaced-impl in Emacs). void QTildeMatching::doinit() { assert(theShowerHandler && theQTildeFinder && theQTildeSudakov); theShowerHandler->init(); theQTildeFinder->init(); theQTildeSudakov->init(); hardScaleFactor(theShowerHandler->hardScaleFactor()); factorizationScaleFactor(theShowerHandler->factorizationScaleFactor()); renormalizationScaleFactor(theShowerHandler->renormalizationScaleFactor()); profileScales(theShowerHandler->profileScales()); restrictPhasespace(theShowerHandler->restrictPhasespace()); hardScaleIsMuF(theShowerHandler->hardScaleIsMuF()); ShowerApproximation::doinit(); } void QTildeMatching::doinitrun() { assert(theShowerHandler && theQTildeFinder && theQTildeSudakov); theShowerHandler->initrun(); theQTildeFinder->initrun(); theQTildeSudakov->initrun(); ShowerApproximation::doinitrun(); } void QTildeMatching::persistentOutput(PersistentOStream & os) const { os << theQTildeFinder << theQTildeSudakov << theShowerHandler << theCorrectForXZMismatch; } void QTildeMatching::persistentInput(PersistentIStream & is, int) { is >> theQTildeFinder >> theQTildeSudakov >> theShowerHandler >> theCorrectForXZMismatch; } // *** Attention *** The following static variable is needed for the type // description system in ThePEG. Please check that the template arguments // are correct (the class and its base class), and that the constructor // arguments are correct (the class name and the name of the dynamically // loadable library where the class implementation can be found). DescribeClass describeHerwigQTildeMatching("Herwig::QTildeMatching", "HwShower.so HwQTildeMatching.so"); void QTildeMatching::Init() { static ClassDocumentation documentation ("QTildeMatching implements NLO matching with the default shower."); - static Reference interfaceQTildeFinder + static Reference interfaceQTildeFinder ("QTildeFinder", "Set the partner finder to calculate hard scales.", &QTildeMatching::theQTildeFinder, false, false, true, false, false); interfaceQTildeFinder.rank(-1); - static Reference interfaceQTildeSudakov + static Reference interfaceQTildeSudakov ("QTildeSudakov", "Set the partner finder to calculate hard scales.", &QTildeMatching::theQTildeSudakov, false, false, true, false, false); interfaceQTildeSudakov.rank(-1); static Reference interfaceShowerHandler ("ShowerHandler", "The QTilde shower handler to use.", &QTildeMatching::theShowerHandler, false, false, true, true, false); interfaceShowerHandler.rank(-1); static Switch interfaceCorrectForXZMismatch ("CorrectForXZMismatch", "Correct for x/z mismatch near hard phase space boundary.", &QTildeMatching::theCorrectForXZMismatch, true, false, false); static SwitchOption interfaceCorrectForXZMismatchYes (interfaceCorrectForXZMismatch, "Yes", "Include the correction factor.", true); static SwitchOption interfaceCorrectForXZMismatchNo (interfaceCorrectForXZMismatch, "No", "Do not include the correction factor.", false); interfaceCorrectForXZMismatch.rank(-1); } diff --git a/MatrixElement/Matchbox/Matching/QTildeMatching.h b/MatrixElement/Matchbox/Matching/QTildeMatching.h --- a/MatrixElement/Matchbox/Matching/QTildeMatching.h +++ b/MatrixElement/Matchbox/Matching/QTildeMatching.h @@ -1,201 +1,201 @@ // -*- C++ -*- // // QTildeMatching.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef Herwig_QTildeMatching_H #define Herwig_QTildeMatching_H // // This is the declaration of the QTildeMatching class. // #include "Herwig/MatrixElement/Matchbox/Matching/ShowerApproximation.h" #include "Herwig/Shower/ShowerHandler.h" -#include "Herwig/Shower/QTilde/Default/QTildeFinder.h" -#include "Herwig/Shower/QTilde/Default/QTildeSudakov.h" +#include "Herwig/Shower/QTilde/Base/PartnerFinder.h" +#include "Herwig/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h" namespace Herwig { using namespace ThePEG; /** * \ingroup Matchbox * \author Simon Platzer * * \brief QTildeMatching implements NLO matching with the default shower. * */ class QTildeMatching: public Herwig::ShowerApproximation { public: /** @name Standard constructors and destructors. */ //@{ /** * The default constructor. */ QTildeMatching(); /** * The destructor. */ virtual ~QTildeMatching(); //@} public: /** * Return the shower approximation to the real emission cross * section for the given pair of Born and real emission * configurations. */ virtual CrossSection dSigHatDR() const; /** * Return the shower approximation splitting kernel for the given * pair of Born and real emission configurations in units of the * Born center of mass energy squared, and including a weight to * project onto the splitting given by the dipole used. */ virtual double me2() const; /** * Determine if the configuration is below or above the cutoff. */ virtual void checkCutoff(); /** * Determine all kinematic variables which are not provided by the * dipole kinematics; store all shower variables in the respective * dipole object for later use. */ virtual void getShowerVariables(); protected: /** * Return true, if the shower was able to generate an emission * leading from the given Born to the given real emission process. */ virtual bool isInShowerPhasespace() const; /** * Return true, if the shower emission leading from the given Born * to the given real emission process would have been generated * above the shower's infrared cutoff. */ virtual bool isAboveCutoff() const; /** * Calculate qtilde^2 and z for the splitting considered */ void calculateShowerVariables() const; /** * Return the splitting function as a function of the kinematic * variables */ double splitFn(const pair&) const; 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(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(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 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 IBPtr fullclone() const; //@} // If needed, insert declarations of virtual function defined in the // InterfacedBase class here (using ThePEG-interfaced-decl in Emacs). protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); /** * Initialize this object. Called in the run phase just before * a run begins. */ virtual void doinitrun(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ QTildeMatching & operator=(const QTildeMatching &); /** * The shower handler to be used */ Ptr::ptr theShowerHandler; /** * The qtilde partner finder for calculating the hard scales */ - Ptr::ptr theQTildeFinder; + Ptr::ptr theQTildeFinder; /** * The qtilde Sudakov to access the cutoff */ - Ptr::ptr theQTildeSudakov; + Ptr::ptr theQTildeSudakov; /** * True, if PDF weight should be corrected for z/x mismatch at the * hard phase space boundary */ bool theCorrectForXZMismatch; }; } #endif /* Herwig_QTildeMatching_H */ diff --git a/MatrixElement/Matchbox/Phasespace/PhasespaceHelpers.cc b/MatrixElement/Matchbox/Phasespace/PhasespaceHelpers.cc --- a/MatrixElement/Matchbox/Phasespace/PhasespaceHelpers.cc +++ b/MatrixElement/Matchbox/Phasespace/PhasespaceHelpers.cc @@ -1,602 +1,563 @@ // -*- C++ -*- // // PhasespaceHelpers.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #include "PhasespaceHelpers.h" #include "Herwig/MatrixElement/Matchbox/Phasespace/RandomHelpers.h" using namespace Herwig; using namespace Herwig::PhasespaceHelpers; using namespace Herwig::RandomHelpers; Energy PhasespaceInfo::generateMass(tcPDPtr data, - const pair& range) { + const pair& range) { double xlow = sqr(range.first)/sHat; if ( range.first < ZERO ) xlow = -xlow; double xup = sqr(range.second)/sHat; if ( range.second < ZERO ) xup = -xup; double mu = sqr(data->hardProcessMass())/sHat; double gamma = sqr(data->hardProcessWidth())/sHat; if ( gamma < 1e-14 ) gamma = 0.0; if ( M0 != ZERO ) x0 = M0/sqrtSHat; if ( Mc != ZERO ) xc = Mc/sqrtSHat; double r = rnd(); pair event; if ( gamma == 0. ) { if ( mu < xlow || mu > xup ) { if ( abs(xlow-mu) < xc ) - xlow = mu; + xlow = mu; if ( abs(xup-mu) < xc ) - xup = mu; + xup = mu; } if ( mu < xlow || mu > xup ) { event = - generate(inverse(mu,xlow,xup),r); + generate(inverse(mu,xlow,xup),r); } else { pair pLeft(xlow,xlow < mu-x0 ? mu-x0 : xlow); pair pRight(xup > mu+x0 ? mu+x0 : xup,xup); pair fLeft(pLeft.second < mu-x0 ? mu-x0 : pLeft.second,mu-xc); - if ( fLeft.first >= fLeft.second ) - fLeft.first = fLeft.second; + if ( fLeft.first >= fLeft.second ) fLeft.first = fLeft.second; pair fRight(mu+xc,pRight.first > mu+x0 ? mu+x0 : pRight.first); - if ( fRight.first >= fRight.second ) - fRight.second = fRight.first; + if ( fRight.first >= fRight.second ) fRight.second = fRight.first; - if ( pLeft.first != pLeft.second && - fLeft.first != fLeft.second && - fRight.first != fRight.second && - pRight.first != pRight.second ) { - event = - generate((piecewise(), - inverse(mu,pLeft.first,pLeft.second), - match(flat(fLeft.first,fLeft.second))) + - match((piecewise(), - flat(fRight.first,fRight.second), - match(inverse(mu,pRight.first,pRight.second)))), - r); - } else if ( pLeft.first == pLeft.second && - fLeft.first != fLeft.second && - fRight.first != fRight.second && - pRight.first != pRight.second ) { - event = - generate(flat(fLeft.first,fLeft.second) + - match((piecewise(), - flat(fRight.first,fRight.second), - match(inverse(mu,pRight.first,pRight.second)))), - r); - } else if ( pLeft.first != pLeft.second && - fLeft.first != fLeft.second && - fRight.first != fRight.second && - pRight.first == pRight.second ) { - event = - generate((piecewise(), - inverse(mu,pLeft.first,pLeft.second), - match(flat(fLeft.first,fLeft.second))) + - match(flat(fRight.first,fRight.second)), - r); - } else if ( pLeft.first == pLeft.second && - fLeft.first == fLeft.second && - fRight.first != fRight.second && - pRight.first != pRight.second ) { - event = - generate((piecewise(), - flat(fRight.first,fRight.second), - match(inverse(mu,pRight.first,pRight.second))), - r); - } else if ( pLeft.first != pLeft.second && - fLeft.first != fLeft.second && - fRight.first == fRight.second && - pRight.first == pRight.second ) { - event = - generate((piecewise(), - inverse(mu,pLeft.first,pLeft.second), - match(flat(fLeft.first,fLeft.second))), - r); - } else if ( pLeft.first == pLeft.second && - fLeft.first != fLeft.second && - fRight.first != fRight.second && - pRight.first == pRight.second ) { - event = - generate(flat(fLeft.first,fLeft.second) + - match(flat(fRight.first,fRight.second)), - r); - } else if ( pLeft.first == pLeft.second && - fLeft.first == fLeft.second && - fRight.first != fRight.second && - pRight.first == pRight.second ) { - event = - generate(flat(fRight.first,fRight.second), - r); - } else if ( pLeft.first == pLeft.second && - fLeft.first != fLeft.second && - fRight.first == fRight.second && - pRight.first == pRight.second ) { - event = - generate(flat(fLeft.first,fLeft.second), - r); - } else if ( pLeft.first == pLeft.second && - fLeft.first == fLeft.second && - fRight.first == fRight.second && - pRight.first == pRight.second ) { - throw Veto(); + + const bool pL= abs( pLeft.first - pLeft.second ) < 1e-14; + const bool fL= abs( fLeft.first - fLeft.second ) < 1e-14; + const bool fR= abs( fRight.first - fRight.second ) < 1e-14; + const bool pR= abs( pRight.first - pRight.second ) < 1e-14; + + + if ( !pL && !fL && !fR && !pR ) { + event = + generate((piecewise(), + inverse(mu,pLeft.first,pLeft.second), + match(flat(fLeft.first,fLeft.second))) + + match((piecewise(), + flat(fRight.first,fRight.second), + match(inverse(mu,pRight.first,pRight.second)))), + r); + } else if ( pL && !fL && !fR && !pR ) { + event = + generate(flat(fLeft.first,fLeft.second) + + match((piecewise(), + flat(fRight.first,fRight.second), + match(inverse(mu,pRight.first,pRight.second)))), r); + } else if ( !pL && !fL && !fR && pR ) { + event = + generate((piecewise(), + inverse(mu,pLeft.first,pLeft.second), + match(flat(fLeft.first,fLeft.second))) + + match(flat(fRight.first,fRight.second)), + r); + } else if ( pL && fL && !fR && !pR ) { + event = + generate((piecewise(),flat(fRight.first,fRight.second), + match(inverse(mu,pRight.first,pRight.second))), r); + } else if ( !pL && !fL && fR && pR ) { + event = + generate((piecewise(), + inverse(mu,pLeft.first,pLeft.second), + match(flat(fLeft.first,fLeft.second))),r); + } else if ( pL && !fL && !fR && pR ) { + event = generate(flat(fLeft.first,fLeft.second) + + match(flat(fRight.first,fRight.second)),r); + } else if ( pL && fL && !fR && pR ) { + event = generate(flat(fRight.first,fRight.second),r); + } else if ( pL && !fL && fR && pR ) { + event = generate(flat(fLeft.first,fLeft.second),r); + } else if ( pL && fL && fR && pR ) { + throw Veto(); } else assert(false); } } else { event = generate(breitWigner(mu,gamma,xlow,xup),r); } - if ( abs(event.first) < xc ) + if ( abs(event.first) < xc ) throw Veto(); weight *= event.second; Energy res = sqrt(abs(event.first)*sHat); if ( event.first < 0. ) res = -res; return res; } Lorentz5Momentum PhasespaceInfo::generateKt(const Lorentz5Momentum& p1, - const Lorentz5Momentum& p2, - Energy pt) { + const Lorentz5Momentum& p2, + Energy pt) { double phi = 2.*Constants::pi*rnd(); weight *= 2.*Constants::pi; Lorentz5Momentum P = p1 + p2; Energy2 Q2 = abs(P.m2()); - Lorentz5Momentum Q = - Lorentz5Momentum(ZERO,ZERO,ZERO,sqrt(Q2),sqrt(Q2)); + Lorentz5Momentum Q = Lorentz5Momentum(ZERO,ZERO,ZERO,sqrt(Q2),sqrt(Q2)); bool boost = abs((P-Q).vect().mag2()/GeV2) > 1e-8 || abs((P-Q).t()/GeV) > 1e-4; boost &= (P*Q-Q.mass2())/GeV2 > 1e-8; Lorentz5Momentum inFrame1; if ( boost ) inFrame1 = p1 + ((P*p1-Q*p1)/(P*Q-Q.mass2()))*(P-Q); else inFrame1 = p1; Energy ptx = inFrame1.x(); Energy pty = inFrame1.y(); Energy q = 2.*inFrame1.z(); Energy Qp = sqrt(4.*(sqr(ptx)+sqr(pty))+sqr(q)); Energy Qy = sqrt(4.*sqr(pty)+sqr(q)); double cPhi = cos(phi); double sPhi = sqrt(1.-sqr(cPhi)); if ( phi > Constants::pi ) sPhi = -sPhi; Lorentz5Momentum kt; kt.setT(ZERO); kt.setX(pt*Qy*cPhi/Qp); kt.setY(-pt*(4*ptx*pty*cPhi/Qp+q*sPhi)/Qy); kt.setZ(2.*pt*(-ptx*q*cPhi/Qp + pty*sPhi)/Qy); if ( boost ) kt = kt + ((P*kt-Q*kt)/(P*Q-Q.mass2()))*(P-Q); kt.setMass(-pt); kt.rescaleRho(); return kt; } void PhasespaceTree::setup(const Tree2toNDiagram& diag, - int pos) { + int pos) { doMirror = false; - pair dchildren = - diag.children(pos); + pair dchildren = diag.children(pos); data = diag.allPartons()[pos]; spacelike = pos < diag.nSpace(); if ( pos == 0 ) externalId = 0; if ( dchildren.first == -1 ) { externalId = diag.externalId(pos); leafs.insert(externalId); return; } children.push_back(PhasespaceTree()); children.back().setup(diag,dchildren.first); children.push_back(PhasespaceTree()); children.back().setup(diag,dchildren.second); if ( !children[0].children.empty() && - children[1].children.empty() && - !spacelike ) + children[1].children.empty() && + !spacelike ) swap(children[0],children[1]); if ( spacelike && - !children[0].spacelike ) + !children[0].spacelike ) swap(children[0],children[1]); copy(children[0].leafs.begin(),children[0].leafs.end(), inserter(leafs,leafs.begin())); copy(children[1].leafs.begin(),children[1].leafs.end(), inserter(leafs,leafs.begin())); } void PhasespaceTree::setupMirrored(const Tree2toNDiagram& diag, - int pos) { + int pos) { doMirror = true; spacelike = pos < diag.nSpace(); pair dchildren; if (pos != 0 && spacelike) - dchildren = - make_pair(diag.parent(pos), diag.children(diag.parent(pos)).second); - else if ( !spacelike ) - dchildren = - diag.children(pos); - else - dchildren = - make_pair(-1,-1); + dchildren = {diag.parent(pos), diag.children(diag.parent(pos)).second}; + else if ( !spacelike ) dchildren = diag.children(pos); + else dchildren = {-1,-1}; data = diag.allPartons()[pos]; if ( pos == diag.nSpace() - 1 ) externalId = 1; if ( dchildren.first == -1 ) { externalId = diag.externalId(pos); leafs.insert(externalId); return; } children.push_back(PhasespaceTree()); children.back().setupMirrored(diag,dchildren.first); children.push_back(PhasespaceTree()); children.back().setupMirrored(diag,dchildren.second); if ( !children[0].children.empty() && - children[1].children.empty() && - !spacelike ) + children[1].children.empty() && + !spacelike ) swap(children[0],children[1]); if ( spacelike && - !children[0].spacelike ) { + !children[0].spacelike ) { assert (false); } copy(children[0].leafs.begin(),children[0].leafs.end(), inserter(leafs,leafs.begin())); copy(children[1].leafs.begin(),children[1].leafs.end(), inserter(leafs,leafs.begin())); } void PhasespaceTree::print(int in) { for (int i = 0; i != in; i++) cerr << " "; cerr << " |- " << data->PDGName() << " " << externalId << "\n" << flush; if ( !children.empty() ) { children[1].print(in+1); children[0].print(in+int(!spacelike)); } else { - cerr << "\n"; + cerr << "\n"; } } void PhasespaceTree::init(const vector& meMomenta) { if ( children.empty() ) { massRange.first = meMomenta[externalId].mass(); massRange.second = massRange.first; if ( !doMirror && externalId == 1 ) momentum = meMomenta[1]; if ( doMirror && externalId == 0 ) momentum = meMomenta[0]; momentum.setMass(meMomenta[externalId].mass()); return; } children[0].init(meMomenta); children[1].init(meMomenta); if ( !children[0].spacelike && - !children[1].spacelike ) { - massRange.first = - children[0].massRange.first + - children[1].massRange.first; + !children[1].spacelike ) { + massRange.first = + children[0].massRange.first + + children[1].massRange.first; } } void PhasespaceTree::generateKinematics(PhasespaceInfo& info, - vector& meMomenta) { + vector& meMomenta) { if ( !doMirror && externalId == 0 ) { init(meMomenta); momentum = meMomenta[0]; } else if ( doMirror && externalId == 1) { init(meMomenta); momentum = meMomenta[1]; } if ( children.empty() ) { if ( ( !doMirror && externalId != 1 ) - || ( doMirror && externalId !=0 ) ) + || ( doMirror && externalId !=0 ) ) meMomenta[externalId] = momentum; return; } - // s-channel + // s-channel if ( ( !doMirror && externalId == 0 && - children[0].externalId == 1 ) - || ( doMirror && externalId == 1 && - children[0].externalId == 0 ) ) { - children[1].momentum = meMomenta[0] + meMomenta[1]; - children[1].momentum.setMass(info.sqrtSHat); - children[1].momentum.rescaleEnergy(); - children[1].generateKinematics(info,meMomenta); - return; - } + children[0].externalId == 1 ) + || ( doMirror && externalId == 1 && + children[0].externalId == 0 ) ) { + children[1].momentum = meMomenta[0] + meMomenta[1]; + children[1].momentum.setMass(info.sqrtSHat); + children[1].momentum.rescaleEnergy(); + children[1].generateKinematics(info,meMomenta); + return; + } if ( !spacelike ) { Energy mij = momentum.mass(); Energy mi,mj; - - // work out the mass for the first child + + // work out the mass for the first child if ( !children[0].children.empty() ) { Energy sumOthers = ZERO; for ( size_t k = 2; k < meMomenta.size(); ++k ) - if ( children[1].leafs.find(k) != children[1].leafs.end() ) - sumOthers += meMomenta[k].mass(); + if ( children[1].leafs.find(k) != children[1].leafs.end() ) + sumOthers += meMomenta[k].mass(); children[0].massRange.second = momentum.mass() - sumOthers; if ( children[0].massRange.second < children[0].massRange.first ) - throw Veto(); + throw Veto(); if ( children[0].massRange.second > momentum.mass() ) - throw Veto(); + throw Veto(); mi = info.generateMass(children[0].data,children[0].massRange); children[0].momentum.setMass(mi); } else { mi = children[0].momentum.mass(); } - // work out the mass for the second child + // work out the mass for the second child if ( !children[1].children.empty() ) { children[1].massRange.second = momentum.mass()-children[0].momentum.mass(); if ( children[1].massRange.second < children[1].massRange.first ) - throw Veto(); + throw Veto(); mj = info.generateMass(children[1].data,children[1].massRange); children[1].momentum.setMass(mj); } else { mj = children[1].momentum.mass(); } Energy2 mij2 = sqr(mij); Energy2 mi2 = sqr(mi); Energy2 mj2 = sqr(mj); - // perform the decay + // perform the decay Energy4 lambda2 = sqr(mij2-mi2-mj2)-4.*mi2*mj2; if ( lambda2 <= ZERO ) throw Veto(); Energy2 lambda = sqrt(lambda2); double phi = 2.*Constants::pi*info.rnd(); double cosPhi = cos(phi); double sinPhi = sqrt(1.-sqr(cosPhi)); if ( phi > Constants::pi ) sinPhi = -sinPhi; info.weight *= Constants::pi*lambda/(2.*mij2); double cosTheta = 2.*info.rnd() - 1.; double sinTheta = sqrt(1.-sqr(cosTheta)); Energy p = lambda/(2.*mij); children[0].momentum.setX(p*cosPhi*sinTheta); children[0].momentum.setY(p*sinPhi*sinTheta); children[0].momentum.setZ(p*cosTheta); children[0].momentum.rescaleEnergy(); if ( momentum.m2() <= ZERO ) throw Veto(); Boost out = momentum.boostVector(); if ( out.mag2() > Constants::epsilon ) { children[0].momentum.boost(out); } children[1].momentum = momentum - children[0].momentum; children[1].momentum.setMass(mj); children[1].momentum.rescaleEnergy(); - // go on with next branchings + // go on with next branchings children[0].generateKinematics(info,meMomenta); children[1].generateKinematics(info,meMomenta); return; } - // get the minimum mass of the `W' system + // get the minimum mass of the `W' system Energy Wmin = ZERO; PhasespaceTree* current = &children[0]; while ( !(current->children.empty()) ) { Wmin += current->children[1].massRange.first; current = &(current->children[0]); } - // get the CM energy avaialble + // get the CM energy avaialble Energy2 s = (momentum+meMomenta[int(!doMirror)]).m2(); if ( s <= ZERO ) throw Veto(); - // generate a mass for the timelike child + // generate a mass for the timelike child Energy mi; if ( !children[1].children.empty() ) { children[1].massRange.second = sqrt(s)-Wmin; if ( children[1].massRange.second < children[1].massRange.first ) throw Veto(); mi = info.generateMass(children[1].data,children[1].massRange); children[1].momentum.setMass(mi); } else { mi = children[1].momentum.mass(); } Energy2 mi2 = sqr(mi); + + // wether or not this is the last 2->2 scatter + bool lastScatter = children[0].children[0].children.empty(); - // wether or not this is the last 2->2 scatter - bool lastScatter - = children[0].children[0].children.empty(); - - // `W' mass relevant for the other boundaries + // `W' mass relevant for the other boundaries Energy MW = Wmin; - // generate a mass for second outgoing leg, if needed + // generate a mass for second outgoing leg, if needed if ( lastScatter ) if ( !children[0].children[1].children.empty() ) { - // get the maximum `W' mass + // get the maximum `W' mass Energy Wmax = sqrt(s)-children[1].momentum.mass(); children[0].children[1].massRange.second = Wmax; if ( children[0].children[1].massRange.second < - children[0].children[1].massRange.first ) - throw Veto(); + children[0].children[1].massRange.first ) + throw Veto(); MW = info.generateMass(children[0].children[1].data, - children[0].children[1].massRange); + children[0].children[1].massRange); children[0].children[1].momentum.setMass(MW); } Energy2 MW2 = sqr(MW); Energy ma = momentum.mass(); Energy2 ma2 = sqr(ma); if ( ma < ZERO ) ma2 = -ma2; Energy mb = meMomenta[int(!doMirror)].mass(); Energy2 mb2 = sqr(mb); - // pick the ys variable + // pick the ys variable Energy2 ys = ZERO; if ( !lastScatter ) { ys = info.rnd()*(sqr(sqrt(s)-mi)-MW2); info.weight *= (sqr(sqrt(s)-mi)-MW2)/info.sHat; } Energy4 lambda2 = sqr(s-ma2-mb2)-4.*ma2*mb2; if ( lambda2 <= ZERO ) { throw Veto(); } Energy2 lambda = sqrt(lambda2); info.weight *= info.sHat/(4.*lambda); - // get the boundaries on the momentum transfer + // get the boundaries on the momentum transfer Energy4 rho2 = sqr(s-ys-MW2-mi2)-4.*mi2*(ys+MW2); if ( rho2 < ZERO ) throw Veto(); Energy2 rho = sqrt(rho2); - Energy4 tau2 = - ys*(ma2-mb2+s) - - sqr(s)+s*(ma2+mb2+mi2+MW2)-(mi2-MW2)*(ma2-mb2); + Energy4 tau2 = + ys*(ma2-mb2+s) + - sqr(s)+s*(ma2+mb2+mi2+MW2)-(mi2-MW2)*(ma2-mb2); pair tBounds - ((tau2-rho*lambda)/(2.*s),(tau2+rho*lambda)/(2.*s)); + ((tau2-rho*lambda)/(2.*s),(tau2+rho*lambda)/(2.*s)); children[0].massRange.first = sqrt(abs(tBounds.first)); if ( tBounds.first < ZERO ) children[0].massRange.first = -children[0].massRange.first; children[0].massRange.second = sqrt(abs(tBounds.second)); if ( tBounds.second < ZERO ) children[0].massRange.second = -children[0].massRange.second; - // generate a momentum transfer + // generate a momentum transfer Energy mai = info.generateMass(children[0].data,children[0].massRange); children[0].momentum.setMass(mai); Energy2 t = sqr(mai); if ( mai < ZERO ) t = -t; Energy2 u = -s -t + ys + ma2 + mb2 + mi2 + MW2; Energy2 st = s - ma2 - mb2; Energy2 tt = t - mi2 - ma2; Energy2 ut = u - mi2 - mb2; - // get the timelike momentum + // get the timelike momentum double xa = (-st*ut+2.*mb2*tt)/lambda2; double xb = (-st*tt+2.*ma2*ut)/lambda2; Energy2 pt2 = (st*tt*ut-ma2*sqr(ut)-mb2*sqr(tt)-mi2*sqr(st)+4.*ma2*mb2*mi2)/lambda2; if ( pt2 < ZERO ) throw Veto(); Energy pt = sqrt(pt2); - children[1].momentum = - xa*momentum + xb*meMomenta[int(!doMirror)] + info.generateKt(momentum,meMomenta[int(!doMirror)],pt); + children[1].momentum = + xa*momentum + xb*meMomenta[int(!doMirror)] + + info.generateKt(momentum,meMomenta[int(!doMirror)],pt); children[1].momentum.setMass(mi); children[1].momentum.rescaleEnergy(); children[0].momentum = - momentum - children[1].momentum; + momentum - children[1].momentum; children[0].momentum.setMass(mai); bool changeSign = false; if ( children[0].momentum.t() < ZERO && mai > ZERO ) changeSign = true; if ( mai < ZERO ) children[0].momentum.rescaleRho(); else children[0].momentum.rescaleEnergy(); if ( changeSign ) children[0].momentum.setT(-children[0].momentum.t()); children[1].generateKinematics(info,meMomenta); if ( !lastScatter ) { children[0].generateKinematics(info,meMomenta); } else { children[0].children[1].momentum = - meMomenta[int(!doMirror)] + children[0].momentum; + meMomenta[int(!doMirror)] + children[0].momentum; children[0].children[1].momentum.setMass(MW); children[0].children[1].momentum.rescaleEnergy(); children[0].children[1].generateKinematics(info,meMomenta); } } void PhasespaceTree::put(PersistentOStream& os) const { os << children.size(); if ( !children.empty() ) { children[0].put(os); children[1].put(os); } os << data << externalId << leafs << spacelike << doMirror; } void PhasespaceTree::get(PersistentIStream& is) { size_t nc; is >> nc; assert(nc == 0 || nc == 2); if ( nc == 2 ) { children.resize(2,PhasespaceTree()); children[0].get(is); children[1].get(is); } is >> data >> externalId >> leafs >> spacelike >> doMirror; } diff --git a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc --- a/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc +++ b/MatrixElement/Powheg/MEPP2GammaGammaPowheg.cc @@ -1,2055 +1,2055 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MEPP2GammaGammaPowheg class. // #include "MEPP2GammaGammaPowheg.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Cuts/Cuts.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Utilities/Maths.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeMEPP2GammaGammaPowheg("Herwig::MEPP2GammaGammaPowheg", "HwMEHadron.so HwPowhegMEHadron.so"); unsigned int MEPP2GammaGammaPowheg::orderInAlphaS() const { return 0; } unsigned int MEPP2GammaGammaPowheg::orderInAlphaEW() const { return 2; } IBPtr MEPP2GammaGammaPowheg::clone() const { return new_ptr(*this); } IBPtr MEPP2GammaGammaPowheg::fullclone() const { return new_ptr(*this); } MEPP2GammaGammaPowheg::MEPP2GammaGammaPowheg() : contrib_(1), power_(0.1), process_(0), threeBodyProcess_(0), maxflavour_(5), alphaS_(0.), fixedAlphaS_(false), supressionFunction_(0), supressionScale_(0), lambda_(20.*GeV), preQCDqqbarq_(5.), preQCDqqbarqbar_(0.5), preQCDqg_(50.), preQCDgqbar_(50.), preQEDqqbarq_(40.), preQEDqqbarqbar_(0.5), preQEDqgq_(1.), preQEDgqbarqbar_(1.), minpT_(2.*GeV), scaleChoice_(0), scalePreFactor_(1.) {} void MEPP2GammaGammaPowheg::getDiagrams() const { tcPDPtr gamma = getParticleData(ParticleID::gamma); tcPDPtr g = getParticleData(ParticleID::g); for(int ix=1;ix<=maxflavour_;++ix) { tcPDPtr qk = getParticleData(ix); tcPDPtr qb = qk->CC(); // gamma gamma if(process_==0 || process_ == 1) { add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 1, gamma, 2, gamma, -1))); add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 2, gamma, 1, gamma, -2))); } // gamma +jet if(process_==0 || process_ == 2) { add(new_ptr((Tree2toNDiagram(3), qk, qb, qb, 1, gamma, 2, g, -4))); add(new_ptr((Tree2toNDiagram(3), qk, qk, qb, 2, gamma, 1, g, -5))); add(new_ptr((Tree2toNDiagram(3), qk, qk, g, 1, gamma, 2, qk, -6))); add(new_ptr((Tree2toNDiagram(2), qk, g, 1, qk, 3, gamma, 3, qk, -7))); add(new_ptr((Tree2toNDiagram(3), g, qb, qb, 2, gamma, 1, qb, -8))); add(new_ptr((Tree2toNDiagram(2), g, qb, 1, qb, 3, gamma, 3, qb, -9))); } // gamma + jet + gamma if((process_==0 && contrib_==1) || process_ == 3) { // gamma + g + gamma if(threeBodyProcess_==0 || threeBodyProcess_==1) { add(new_ptr((Tree2toNDiagram(4), qk, qk, qk, qb, 1, gamma, 2, gamma, 3, g, -10))); add(new_ptr((Tree2toNDiagram(4), qk, qk, qk, qb, 3, gamma, 2, gamma, 1, g, -12))); } // Z + q + gamma if(threeBodyProcess_==0 || threeBodyProcess_==2) { add(new_ptr((Tree2toNDiagram(4),qk,qk,qk,g,1,gamma,2,gamma,3,qk, -20))); add(new_ptr((Tree2toNDiagram(4),qk,qk,qk,g,2,gamma,1,gamma,3,qk, -21))); add(new_ptr((Tree2toNDiagram(3),qk,qk,g,1,gamma,2,qk,5,gamma,5,qk,-22))); } // Z + qbar + gamma if(threeBodyProcess_==0 || threeBodyProcess_==3) { add(new_ptr((Tree2toNDiagram(4),g,qb,qb,qb,3,gamma,2,gamma,1,qb ,-30))); add(new_ptr((Tree2toNDiagram(4),g,qb,qb,qb,2,gamma,3,gamma,1,qb ,-31))); add(new_ptr((Tree2toNDiagram(3),g,qb,qb ,2,gamma,1,qb,5,gamma,5,qb,-32))); } } } } Energy2 MEPP2GammaGammaPowheg::scale() const { Energy2 scale; if(scaleChoice_==0) { Energy pt; if(meMomenta()[2].perp(meMomenta()[0].vect())>= meMomenta()[3].perp(meMomenta()[0].vect())){ pt = meMomenta()[2].perp(meMomenta()[0].vect()); } else { pt = meMomenta()[3].perp(meMomenta()[0].vect()); } scale = sqr(pt); } else if(scaleChoice_==1) { scale = sHat(); } return scalePreFactor_*scale; } int MEPP2GammaGammaPowheg::nDim() const { return HwMEBase::nDim() + ( contrib_>=1 ? 3 : 0 ); } bool MEPP2GammaGammaPowheg::generateKinematics(const double * r) { // radiative variables if(contrib_>=1) { zTilde_ = r[nDim()-1]; vTilde_ = r[nDim()-2]; phi_ = Constants::twopi*r[nDim()-3]; } // set the jacobian jacobian(1.0); // set up the momenta for ( int i = 2, N = meMomenta().size(); i < N; ++i ) meMomenta()[i] = Lorentz5Momentum(ZERO); // generate sHat Energy2 shat(sHat()); if(mePartonData().size()==5) { double eps = sqr(meMomenta()[2].mass())/shat; jacobian(jacobian()*(1.-eps)); shat *= eps+zTilde_*(1.-eps); } // momenta of the core process double ctmin = -1.0, ctmax = 1.0; Energy q = ZERO; try { q = SimplePhaseSpace:: getMagnitude(shat, meMomenta()[2].mass(), ZERO); } catch ( ImpossibleKinematics ) { return false; } Energy e = 0.5*sqrt(shat); Energy2 m22 = meMomenta()[2].mass2(); Energy2 e0e2 = 2.0*e*sqrt(sqr(q) + m22); Energy2 e1e2 = 2.0*e*sqrt(sqr(q) + m22); Energy2 e0e3 = 2.0*e*sqrt(sqr(q)); Energy2 e1e3 = 2.0*e*sqrt(sqr(q)); Energy2 pq = 2.0*e*q; if(mePartonData().size()==4) { Energy2 thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[2]); if ( thmin > ZERO ) ctmax = min(ctmax, (e0e2 - m22 - thmin)/pq); thmin = lastCuts().minTij(mePartonData()[1], mePartonData()[2]); if ( thmin > ZERO ) ctmin = max(ctmin, (thmin + m22 - e1e2)/pq); thmin = lastCuts().minTij(mePartonData()[1], mePartonData()[3]); if ( thmin > ZERO ) ctmax = min(ctmax, (e1e3 - thmin)/pq); thmin = lastCuts().minTij(mePartonData()[0], mePartonData()[3]); if ( thmin > ZERO ) ctmin = max(ctmin, (thmin - e0e3)/pq); Energy ptmin = max(lastCuts().minKT(mePartonData()[2]), lastCuts().minKT(mePartonData()[3])); if ( ptmin > ZERO ) { double ctm = 1.0 - sqr(ptmin/q); if ( ctm <= 0.0 ) return false; ctmin = max(ctmin, -sqrt(ctm)); ctmax = min(ctmax, sqrt(ctm)); } double ymin2 = lastCuts().minYStar(mePartonData()[2]); double ymax2 = lastCuts().maxYStar(mePartonData()[2]); double ymin3 = lastCuts().minYStar(mePartonData()[3]); double ymax3 = lastCuts().maxYStar(mePartonData()[3]); double ytot = lastCuts().Y() + lastCuts().currentYHat(); if ( ymin2 + ytot > -0.9*Constants::MaxRapidity ) ctmin = max(ctmin, sqrt(sqr(q) + m22)*tanh(ymin2)/q); if ( ymax2 + ytot < 0.9*Constants::MaxRapidity ) ctmax = min(ctmax, sqrt(sqr(q) + m22)*tanh(ymax2)/q); if ( ymin3 + ytot > -0.9*Constants::MaxRapidity ) ctmax = min(ctmax, tanh(-ymin3)); if ( ymax3 + ytot < 0.9*Constants::MaxRapidity ) ctmin = max(ctmin, tanh(-ymax3)); if ( ctmin >= ctmax ) return false; } double cth = getCosTheta(ctmin, ctmax, r[0]); Energy pt = q*sqrt(1.0-sqr(cth)); phi(rnd(2.0*Constants::pi)); meMomenta()[2].setVect(Momentum3( pt*sin(phi()), pt*cos(phi()), q*cth)); meMomenta()[3].setVect(Momentum3(-pt*sin(phi()), -pt*cos(phi()), -q*cth)); meMomenta()[2].rescaleEnergy(); meMomenta()[3].rescaleEnergy(); // jacobian tHat(pq*cth + m22 - e0e2); uHat(m22 - shat - tHat()); jacobian(pq/shat*Constants::pi*jacobian()); // end for 2->2 processes if(mePartonData().size()==4) { vector out(2); out[0] = meMomenta()[2]; out[1] = meMomenta()[3]; tcPDVector tout(2); tout[0] = mePartonData()[2]; tout[1] = mePartonData()[3]; if ( !lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]) ) return false; return true; } // special for 2-3 processes pair x = make_pair(lastX1(),lastX2()); // partons pair partons = make_pair(mePartonData()[0],mePartonData()[1]); // If necessary swap the particle data objects so that // first beam gives the incoming quark if(lastPartons().first ->dataPtr()!=partons.first) { swap(x.first,x.second); } // use vTilde to select the dipole for emission // gamma gamma g processes if(mePartonData()[4]->id()==ParticleID::g) { if(vTilde_<=0.5) { dipole_ = IIQCD1; vTilde_ = 4.*vTilde_; } else { dipole_ = IIQCD2; vTilde_ = 4.*(vTilde_-0.25); } jacobian(2.*jacobian()); } // gamma gamma q processes else if(mePartonData()[4]->id()>0&&mePartonData()[4]->id()<6) { if(vTilde_<=1./3.) { dipole_ = IIQCD2; vTilde_ = 3.*vTilde_; } else if(vTilde_<=2./3.) { dipole_ = IFQED1; vTilde_ = 3.*vTilde_-1.; } else { dipole_ = FIQED1; vTilde_ = 3.*vTilde_-2.; } jacobian(3.*jacobian()); } // gamma gamma qbar processes else if(mePartonData()[4]->id()<0&&mePartonData()[4]->id()>-6) { if(vTilde_<=1./3.) { dipole_ = IIQCD1; vTilde_ = 3.*vTilde_; } else if(vTilde_<=2./3.) { dipole_ = IFQED2; vTilde_ = 3.*vTilde_-1.; } else { dipole_ = FIQED2; vTilde_ = 3.*vTilde_-2.; } jacobian(3.*jacobian()); } else { assert(false); } // initial-initial dipoles if(dipole_<=4) { double z = shat/sHat(); double vt = vTilde_*(1.-z); double vJac = 1.-z; Energy pT = sqrt(shat*vt*(1.-vt-z)/z); if(pT pnew(5); pnew [0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first, 0.5*rs*x.first,ZERO); pnew [1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second, 0.5*rs*x.second,ZERO) ; pnew [2] = meMomenta()[2]; pnew [3] = meMomenta()[3]; pnew [4] = Lorentz5Momentum(pT*cos(phi_),pT*sin(phi_), pT*sinh(rapidity), pT*cosh(rapidity), ZERO); pnew[4].rescaleEnergy(); Lorentz5Momentum K = pnew [0]+pnew [1]-pnew [4]; Lorentz5Momentum Kt = pcmf; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); for(unsigned int ix=2;ix<4;++ix) { pnew [ix].boost(blab); pnew [ix] = pnew [ix] - 2.*Ksum*(Ksum*pnew [ix])/Ksum2 +2*K*(Kt*pnew [ix])/K2; pnew[ix].rescaleEnergy(); } pcmf = Lorentz5Momentum(ZERO,ZERO, 0.5*rs*(x.first-x.second), 0.5*rs*(x.first+x.second)); pcmf.rescaleMass(); blab = pcmf.boostVector(); for(unsigned int ix=0;ix1e-20) { rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); } if(abs(1.-q.e()/q.vect().mag())>1e-6) rot.boostZ(q.e()/q.vect().mag()); pin *= rot; if(pin.perp2()/GeV2>1e-20) { Boost trans = -1./pin.e()*pin.vect(); trans.setZ(0.); rot.boost(trans); } rot.invert(); Energy Q = sqrt(-q.m2()); meMomenta()[4] = rot*Lorentz5Momentum( 0.5*Q*xT*cos(phi_), 0.5*Q*xT*sin(phi_), -0.5*Q*x2,0.5*Q*sqrt(sqr(x2)+sqr(xT))); meMomenta()[3] = rot*Lorentz5Momentum(-0.5*Q*xT*cos(phi_),-0.5*Q*xT*sin(phi_), -0.5*Q*x3,0.5*Q*sqrt(sqr(x3)+sqr(xT))); double ratio; if(dipole_<=6) { ratio = 2.*((meMomenta()[3]+meMomenta()[4])*meMomenta()[0])/sHat(); } else { ratio = 2.*((meMomenta()[3]+meMomenta()[4])*meMomenta()[1])/sHat(); } jacobian(jacobian()*ratio); } else { assert(false); } vector out(3); tcPDVector tout(3); for(unsigned int ix=0;ix<3;++ix) { out[ix] = meMomenta() [2+ix]; tout[ix] = mePartonData()[2+ix]; } return lastCuts().passCuts(tout, out, mePartonData()[0], mePartonData()[1]); } double MEPP2GammaGammaPowheg::me2() const { // Born configurations if(mePartonData().size()==4) { // gamma gamma core process if(mePartonData()[3]->id()==ParticleID::gamma) { return 2.*Constants::twopi*alphaEM_* loGammaGammaME(mePartonData(),meMomenta(),true); } // V jet core process else if(mePartonData()[3]->id()==ParticleID::g) { return 2.*Constants::twopi*alphaS_* loGammagME(mePartonData(),meMomenta(),true); } else if(mePartonData()[3]->id()>0) { return 2.*Constants::twopi*alphaS_* loGammaqME(mePartonData(),meMomenta(),true); } else if(mePartonData()[3]->id()<0) { return 2.*Constants::twopi*alphaS_* loGammaqbarME(mePartonData(),meMomenta(),true); } else assert(false); } // hard emission configurations else { if(mePartonData()[4]->id()==ParticleID::g) return sHat()*realGammaGammagME (mePartonData(),meMomenta(),dipole_,Hard,true); else if(mePartonData()[4]->id()>0&&mePartonData()[4]->id()<6) return sHat()*realGammaGammaqME (mePartonData(),meMomenta(),dipole_,Hard,true); else if(mePartonData()[4]->id()<0&&mePartonData()[4]->id()>-6) return sHat()*realGammaGammaqbarME(mePartonData(),meMomenta(),dipole_,Hard,true); else assert(false); } } CrossSection MEPP2GammaGammaPowheg::dSigHatDR() const { // couplings if(!fixedAlphaS_) alphaS_ = SM().alphaS(scale()); alphaEM_ = SM().alphaEM(); // cross section CrossSection preFactor = jacobian()/(16.0*sqr(Constants::pi)*sHat())*sqr(hbarc); loME_ = me2(); if( contrib_== 0 || mePartonData().size()==5 || (mePartonData().size()==4&& mePartonData()[3]->coloured())) return loME_*preFactor; else return NLOWeight()*preFactor; } Selector MEPP2GammaGammaPowheg::diagrams(const DiagramVector & diags) const { if(mePartonData().size()==4) { if(mePartonData()[3]->id()==ParticleID::gamma) { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ){ sel.insert(meInfo()[abs(diags[i]->id())], i); } return sel; } else { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ){ sel.insert(meInfo()[abs(diags[i]->id())%2], i); } return sel; } } else { Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { if(abs(diags[i]->id()) == 10 && dipole_ == IIQCD2 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 12 && dipole_ == IIQCD1 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 20 && dipole_ == IIQCD2 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 21 && dipole_ == IFQED1 ) sel.insert(1., i); else if(abs(diags[i]->id()) == 22 && dipole_ == FIQED1 ) sel.insert(1., i); else sel.insert(0., i); } return sel; } } Selector MEPP2GammaGammaPowheg::colourGeometries(tcDiagPtr diag) const { // colour lines for V gamma static ColourLines cs("1 -2"); static ColourLines ct("1 2 -3"); // colour lines for q qbar -> V g static const ColourLines cqqbar[2]={ColourLines("1 -2 5,-3 -5"), ColourLines("1 5,-5 2 -3")}; // colour lines for q g -> V q static const ColourLines cqg [2]={ColourLines("1 2 -3,3 5"), ColourLines("1 -2,2 3 5")}; // colour lines for g qbar -> V qbar static const ColourLines cgqbar[2]={ColourLines("-3 -2 1,-1 -5"), ColourLines("-2 1,-1 -3 -5")}; // colour lines for q qbar -> V gamma g static const ColourLines cqqbarg[4]={ColourLines("1 2 3 7,-4 -7"), ColourLines("1 2 7,-4 3 -7"), ColourLines("1 7,-4 3 2 -7"), ColourLines("1 2 7,-4 3 -7")}; // colour lines for q g -> V gamma q static const ColourLines cqgq [3]={ColourLines("1 2 3 -4,4 7"), ColourLines("1 2 3 -4,4 7"), ColourLines("1 2 -3,3 5 7")}; // colour lines for gbar -> V gamma qbar static const ColourLines cqbargqbar[3]={ColourLines("1 -2 -3 -4,-1 -7"), ColourLines("1 -2 -3 -4,-1 -7"), ColourLines("1 -2 -3,-1 -5 -7")}; Selector sel; switch(abs(diag->id())) { case 1 :case 2 : sel.insert(1.0, &ct); break; case 3 : sel.insert(1.0, &cs); break; case 4 : sel.insert(1.0, &cqqbar[0]); break; case 5: sel.insert(1.0, &cqqbar[1]); break; case 6: sel.insert(1.0, &cqg[0]); break; case 7: sel.insert(1.0, &cqg[1]); break; case 8: sel.insert(1.0, &cgqbar[0]); break; case 9: sel.insert(1.0, &cgqbar[1]); break; case 10: case 11: case 12: case 13: sel.insert(1.0, &cqqbarg[abs(diag->id())-10]); break; case 20: case 21: case 22: sel.insert(1.0, &cqgq[abs(diag->id())-20]); break; case 30: case 31: case 32: sel.insert(1.0, &cqbargqbar[abs(diag->id())-30]); break; default: assert(false); } return sel; } void MEPP2GammaGammaPowheg::persistentOutput(PersistentOStream & os) const { os << FFPvertex_ << FFGvertex_ << contrib_ << power_ << gluon_ << prefactor_ << process_ << threeBodyProcess_<< maxflavour_ << alphaS_ << fixedAlphaS_ << supressionFunction_ << supressionScale_ << ounit(lambda_,GeV) << alphaQCD_ << alphaQED_ << ounit(minpT_,GeV) << preQCDqqbarq_ << preQCDqqbarqbar_ << preQCDqg_ << preQCDgqbar_ << preQEDqqbarq_ << preQEDqqbarqbar_ << preQEDqgq_ << preQEDgqbarqbar_ << scaleChoice_ << scalePreFactor_; } void MEPP2GammaGammaPowheg::persistentInput(PersistentIStream & is, int) { is >> FFPvertex_ >> FFGvertex_ >> contrib_ >> power_ >> gluon_ >> prefactor_ >> process_ >> threeBodyProcess_ >> maxflavour_ >> alphaS_ >> fixedAlphaS_ >> supressionFunction_ >> supressionScale_ >> iunit(lambda_,GeV) >> alphaQCD_ >> alphaQED_ >> iunit(minpT_,GeV) >> preQCDqqbarq_ >> preQCDqqbarqbar_ >> preQCDqg_ >> preQCDgqbar_ >> preQEDqqbarq_ >> preQEDqqbarqbar_ >> preQEDqgq_ >> preQEDgqbarqbar_ >> scaleChoice_ >> scalePreFactor_; } void MEPP2GammaGammaPowheg::Init() { static ClassDocumentation documentation ("TheMEPP2GammaGammaPowheg class implements gamma gamma production at NLO"); static Switch interfaceProcess ("Process", "Which processes to include", &MEPP2GammaGammaPowheg::process_, 0, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all the processes", 0); static SwitchOption interfaceProcessGammaGamma (interfaceProcess, "GammaGamma", "Only include gamma gamma", 1); static SwitchOption interfaceProcessVJet (interfaceProcess, "VJet", "Only include gamma + jet", 2); static SwitchOption interfaceProcessHard (interfaceProcess, "Hard", "Only include hard radiation contributions", 3); static Switch interfaceThreeBodyProcess ("ThreeBodyProcess", "The possible three body processes to include", &MEPP2GammaGammaPowheg::threeBodyProcess_, 0, false, false); static SwitchOption interfaceThreeBodyProcessAll (interfaceThreeBodyProcess, "All", "Include all processes", 0); static SwitchOption interfaceThreeBodyProcessqqbar (interfaceThreeBodyProcess, "qqbar", "Only include q qbar -> gamma gamma g processes", 1); static SwitchOption interfaceThreeBodyProcessqg (interfaceThreeBodyProcess, "qg", "Only include q g -> gamma gamma q processes", 2); static SwitchOption interfaceThreeBodyProcessgqbar (interfaceThreeBodyProcess, "gqbar", "Only include g qbar -> gamma gamma qbar processes", 3); static Switch interfaceContribution ("Contribution", "Which contributions to the cross section to include", &MEPP2GammaGammaPowheg::contrib_, 1, false, false); static SwitchOption interfaceContributionLeadingOrder (interfaceContribution, "LeadingOrder", "Just generate the leading order cross section", 0); static SwitchOption interfaceContributionPositiveNLO (interfaceContribution, "PositiveNLO", "Generate the positive contribution to the full NLO cross section", 1); static SwitchOption interfaceContributionNegativeNLO (interfaceContribution, "NegativeNLO", "Generate the negative contribution to the full NLO cross section", 2); static Parameter interfaceMaximumFlavour ("MaximumFlavour", "The maximum flavour allowed for the incoming quarks", &MEPP2GammaGammaPowheg::maxflavour_, 5, 1, 5, false, false, Interface::limited); static Parameter interfaceAlphaS ("AlphaS", "The value of alphaS to use if using a fixed alphaS", &MEPP2GammaGammaPowheg::alphaS_, 0.118, 0.0, 0.2, false, false, Interface::limited); static Switch interfaceFixedAlphaS ("FixedAlphaS", "Use a fixed value of alphaS", &MEPP2GammaGammaPowheg::fixedAlphaS_, false, false, false); static SwitchOption interfaceFixedAlphaSYes (interfaceFixedAlphaS, "Yes", "Use a fixed alphaS", true); static SwitchOption interfaceFixedAlphaSNo (interfaceFixedAlphaS, "No", "Use a running alphaS", false); static Switch interfaceSupressionFunction ("SupressionFunction", "Choice of the supression function", &MEPP2GammaGammaPowheg::supressionFunction_, 0, false, false); static SwitchOption interfaceSupressionFunctionNone (interfaceSupressionFunction, "None", "Default POWHEG approach", 0); static SwitchOption interfaceSupressionFunctionThetaFunction (interfaceSupressionFunction, "ThetaFunction", "Use theta functions at scale Lambda", 1); static SwitchOption interfaceSupressionFunctionSmooth (interfaceSupressionFunction, "Smooth", "Supress high pT by pt^2/(pt^2+lambda^2)", 2); static Parameter interfaceSupressionScale ("SupressionScale", "The square of the scale for the supression function", &MEPP2GammaGammaPowheg::lambda_, GeV, 20.0*GeV, 0.0*GeV, 0*GeV, false, false, Interface::lowerlim); static Switch interfaceSupressionScaleChoice ("SupressionScaleChoice", "Choice of the supression scale", &MEPP2GammaGammaPowheg::supressionScale_, 0, false, false); static SwitchOption interfaceSupressionScaleChoiceFixed (interfaceSupressionScaleChoice, "Fixed", "Use a fixed scale", 0); static SwitchOption interfaceSupressionScaleChoiceVariable (interfaceSupressionScaleChoice, "Variable", "Use the pT of the hard process as the scale", 1); static Reference interfaceShowerAlphaQCD ("ShowerAlphaQCD", "Reference to the object calculating the QCD coupling for the shower", &MEPP2GammaGammaPowheg::alphaQCD_, false, false, true, false, false); static Reference interfaceShowerAlphaQED ("ShowerAlphaQED", "Reference to the object calculating the QED coupling for the shower", &MEPP2GammaGammaPowheg::alphaQED_, false, false, true, false, false); static Parameter interfacepreQCDqqbarq ("preQCDqqbarq", "The constant for the Sudakov overestimate for the " "q qbar -> V Gamma +g with emission from the q", &MEPP2GammaGammaPowheg::preQCDqqbarq_, 23.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacepreQCDqqbarqbar ("preQCDqqbarqbar", "The constant for the Sudakov overestimate for the " "q qbar -> V Gamma +g with emission from the qbar", &MEPP2GammaGammaPowheg::preQCDqqbarqbar_, 23.0, 0.0, 1000.0, false, false, Interface::limited); static Switch interfaceScaleChoice ("ScaleChoice", "The scale choice to use", &MEPP2GammaGammaPowheg::scaleChoice_, 0, false, false); static SwitchOption interfaceScaleChoicepT (interfaceScaleChoice, "pT", "Use the pT of the photons", 0); static SwitchOption interfaceScaleChoiceMGammaGamma (interfaceScaleChoice, "MGammaGamma", "Use the mass of the photon pair", 1); static Parameter interfaceScalePreFactor ("ScalePreFactor", "Prefactor to change factorization/renormalisation scale", &MEPP2GammaGammaPowheg::scalePreFactor_, 1.0, 0.1, 10.0, false, false, Interface::limited); // prefactor_.push_back(preQCDqg_); // prefactor_.push_back(preQCDgqbar_); // prefactor_.push_back(preQEDqqbarq_); // prefactor_.push_back(preQEDqqbarqbar_); // prefactor_.push_back(preQEDqgq_); // prefactor_.push_back(preQEDgqbarqbar_); } double MEPP2GammaGammaPowheg::NLOWeight() const { // if leading-order return if(contrib_==0) return loME_; // prefactors CFfact_ = 4./3.*alphaS_/Constants::twopi; TRfact_ = 1./2.*alphaS_/Constants::twopi; // scale Energy2 mu2 = scale(); // virtual pieces double virt = CFfact_*subtractedVirtual(); // extract the partons and stuff for the real emission // and collinear counter terms // hadrons pair hadrons= make_pair(dynamic_ptr_cast(lastParticles().first->dataPtr() ), dynamic_ptr_cast(lastParticles().second->dataPtr())); // momentum fractions pair x = make_pair(lastX1(),lastX2()); // partons pair partons = make_pair(mePartonData()[0],mePartonData()[1]); // If necessary swap the particle data objects so that // first beam gives the incoming quark if(lastPartons().first ->dataPtr()!=partons.first) { swap(x.first,x.second); swap(hadrons.first,hadrons.second); } // convert the values of z tilde to z pair z; pair zJac; double rhomax(pow(1.-x.first,1.-power_)); double rho = zTilde_*rhomax; z.first = 1.-pow(rho,1./(1.-power_)); zJac.first = rhomax*pow(1.-z.first,power_)/(1.-power_); rhomax = pow(1.-x.second,1.-power_); rho = zTilde_*rhomax; z.second = 1.-pow(rho,1./(1.-power_)); zJac.second = rhomax*pow(1.-z.second,power_)/(1.-power_); // calculate the PDFs pair oldqPDF = make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,partons.first ,scale(), x.first )/x.first , hadrons.second->pdf()->xfx(hadrons.second,partons.second,scale(), x.second)/x.second); // real/coll q/qbar pair newqPDF = make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,partons.first ,scale(), x.first /z.first )*z.first /x.first , hadrons.second->pdf()->xfx(hadrons.second,partons.second,scale(), x.second/z.second)*z.second/x.second); // real/coll gluon pair newgPDF = make_pair(hadrons.first ->pdf()->xfx(hadrons.first ,gluon_,scale(), x.first /z.first )*z.first /x.first , hadrons.second->pdf()->xfx(hadrons.second,gluon_,scale(), x.second/z.second)*z.second/x.second); // coll terms // g -> q double collGQ = collinearGluon(mu2,zJac.first,z.first, oldqPDF.first,newgPDF.first); // g -> qbar double collGQbar = collinearGluon(mu2,zJac.second,z.second, oldqPDF.second,newgPDF.second); // q -> q double collQQ = collinearQuark(x.first ,mu2,zJac.first ,z.first , oldqPDF.first ,newqPDF.first ); // qbar -> qbar double collQbarQbar = collinearQuark(x.second,mu2,zJac.second,z.second, oldqPDF.second,newqPDF.second); // collinear remnants double coll = collQQ+collQbarQbar+collGQ+collGQbar; // real emission contribution double real1 = subtractedReal(x,z. first,zJac. first,oldqPDF. first, newqPDF. first,newgPDF. first, true); double real2 = subtractedReal(x,z.second,zJac.second,oldqPDF.second, newqPDF.second,newgPDF.second,false); // the total weight double wgt = loME_ + loME_*virt + loME_*coll + real1 + real2; return contrib_ == 1 ? max(0.,wgt) : max(0.,-wgt); } double MEPP2GammaGammaPowheg::loGammaGammaME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 th = (momenta[0]-momenta[2]).m2(); Energy2 uh = (momenta[0]-momenta[3]).m2(); output = 4./3.*Constants::pi*SM().alphaEM(ZERO)*(th/uh+uh/th)* pow(double(particles[0]->iCharge())/3.,4); } // HE code result else { // wavefunctions for the incoming fermions SpinorWaveFunction em_in( momenta[0],particles[0],incoming); SpinorBarWaveFunction ep_in( momenta[1],particles[1],incoming); // wavefunctions for the outgoing bosons VectorWaveFunction v1_out(momenta[2],particles[2],outgoing); VectorWaveFunction v2_out(momenta[3],particles[3],outgoing); vector f1; vector a1; vector v1,v2; // calculate the wavefunctions for(unsigned int ix=0;ix<2;++ix) { em_in.reset(ix); f1.push_back(em_in); ep_in.reset(ix); a1.push_back(ep_in); v1_out.reset(2*ix); v1.push_back(v1_out); v2_out.reset(2*ix); v2.push_back(v2_out); } vector me(4,0.0); me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1)); vector diag(2,0.0); SpinorWaveFunction inter; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { for(unsigned int ohel2=0;ohel2<2;++ohel2) { - inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle(), + inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle()->CC(), f1[ihel1],v1[ohel1]); diag[0] = FFPvertex_->evaluate(ZERO,inter,a1[ihel2],v2[ohel2]); - inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle(), + inter = FFPvertex_->evaluate(ZERO,5,f1[ihel1].particle()->CC(), f1[ihel1] ,v2[ohel2]); diag[1] = FFPvertex_->evaluate(ZERO,inter,a1[ihel2],v1[ohel1]); // individual diagrams for (size_t ii=0; ii<2; ++ii) me[ii] += std::norm(diag[ii]); // full matrix element diag[0] += diag[1]; output += std::norm(diag[0]); // storage of the matrix element for spin correlations me_(ihel1,ihel2,2*ohel1,2*ohel2) = diag[0]; } } } } // store diagram info, etc. DVector save(3); for (size_t i = 0; i < 3; ++i) save[i] = 0.25 * me[i]; meInfo(save); // spin and colour factors output *= 0.125/3./norm(FFPvertex_->norm()); } return output; } double MEPP2GammaGammaPowheg::loGammaqME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 sh = (momenta[0]+momenta[1]).m2(); Energy2 th = (momenta[0]-momenta[2]).m2(); Energy2 uh = (momenta[0]-momenta[3]).m2(); output = -1./3./sh/th*(sh*sh+th*th+2.*uh*(sh+th+uh))* 4.*Constants::pi*SM().alphaEM(ZERO)* sqr(particles[0]->iCharge()/3.); } // HE result else { vector fin; vector gin; vector fout; vector vout; SpinorWaveFunction qin (momenta[0],particles[0],incoming); VectorWaveFunction glin(momenta[1],particles[1],incoming); VectorWaveFunction wout(momenta[2],particles[2],outgoing); SpinorBarWaveFunction qout(momenta[3],particles[3],outgoing); // polarization states for the particles for(unsigned int ix=0;ix<2;++ix) { qin.reset(ix) ; fin.push_back(qin); qout.reset(ix); fout.push_back(qout); glin.reset(2*ix); gin.push_back(glin); wout.reset(2*ix); vout.push_back(wout); } me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, PDT::Spin1,PDT::Spin1Half)); // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams - interb= FFGvertex_->evaluate(scale(),5,particles[3], + interb= FFGvertex_->evaluate(scale(),5,particles[3]->CC(), fout[ohel1],gin[ihel2]); inters= FFGvertex_->evaluate(scale(),5,particles[0], fin[ihel1],gin[ihel2]); for(unsigned int vhel=0;vhel<2;++vhel) { diag[0] = FFPvertex_->evaluate(ZERO,fin[ihel1],interb,vout[vhel]); diag[1] = FFPvertex_->evaluate(ZERO,inters,fout[ohel1],vout[vhel]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); me_(ihel1,2*ihel2,2*vhel,ohel1) = diag[0]; } } } } // results // initial state spin and colour average double colspin = 1./24./4.; // and C_F N_c from matrix element colspin *= 4.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); output = me[0]/norm(FFGvertex_->norm()); } return output; } double MEPP2GammaGammaPowheg::loGammaqbarME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 sh = (momenta[0]+momenta[1]).m2(); Energy2 uh = (momenta[0]-momenta[2]).m2(); Energy2 th = (momenta[0]-momenta[3]).m2(); output = -1./3./sh/th*(sh*sh+th*th+2.*uh*(sh+th+uh))* 4.*Constants::pi*SM().alphaEM()* sqr(particles[1]->iCharge()/3.); } // HE result else { vector ain; vector gin; vector aout; vector vout; VectorWaveFunction glin (momenta[0],particles[0],incoming); SpinorBarWaveFunction qbin (momenta[1],particles[1],incoming); VectorWaveFunction wout (momenta[2],particles[2],outgoing); SpinorWaveFunction qbout(momenta[3],particles[3],outgoing); // polarization states for the particles for(unsigned int ix=0;ix<2;++ix) { qbin .reset(ix ); ain .push_back(qbin ); qbout.reset(ix ); aout.push_back(qbout); glin.reset(2*ix); gin.push_back(glin); wout.reset(2*ix); vout.push_back(wout); } // if calculation spin corrections construct the me me_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1Half, PDT::Spin1,PDT::Spin1Half)); // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams - inters= FFGvertex_->evaluate(scale(),5,particles[3], + inters= FFGvertex_->evaluate(scale(),5,particles[3]->CC(), aout[ohel1],gin[ihel1]); interb= FFGvertex_->evaluate(scale(),5,particles[1], ain[ihel2],gin[ihel1]); for(unsigned int vhel=0;vhel<2;++vhel) { diag[0]= FFPvertex_->evaluate(ZERO,inters,ain[ihel2],vout[vhel]); diag[1]= FFPvertex_->evaluate(ZERO,aout[ohel1],interb,vout[vhel]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); me_(2*ihel1,ihel2,2*vhel,ohel1) = diag[0]; } } } } // results // initial state spin and colour average double colspin = 1./24./4.; // and C_F N_c from matrix element colspin *= 4.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); output = me[0]/norm(FFGvertex_->norm()); } return output; } double MEPP2GammaGammaPowheg::loGammagME(const cPDVector & particles, const vector & momenta, bool first) const { double output(0.); // analytic formula for speed if(!first) { Energy2 uh = (momenta[0]-momenta[2]).m2(); Energy2 th = (momenta[0]-momenta[3]).m2(); output = 8./9.*double((th*th+uh*uh)/uh/th)* 4.*Constants::pi*SM().alphaEM(ZERO)* sqr(particles[0]->iCharge()/3.); } else { vector fin; vector ain; vector gout; vector vout; SpinorWaveFunction qin (momenta[0],particles[0],incoming); SpinorBarWaveFunction qbin(momenta[1],particles[1],incoming); VectorWaveFunction wout(momenta[2],particles[2],outgoing); VectorWaveFunction glout(momenta[3],particles[3],outgoing); // polarization states for the particles for(unsigned int ix=0;ix<2;++ix) { qin.reset(ix) ; fin.push_back(qin); qbin.reset(ix) ; ain.push_back(qbin); glout.reset(2*ix); gout.push_back(glout); wout.reset(2*ix); vout.push_back(wout); } // if calculation spin corrections construct the me if(first) me_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1,PDT::Spin1)); // compute the matrix elements double me[3]={0.,0.,0.}; Complex diag[2]; SpinorWaveFunction inters; SpinorBarWaveFunction interb; for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int ohel1=0;ohel1<2;++ohel1) { // intermediates for the diagrams inters= FFGvertex_->evaluate(scale(),5,particles[0], fin[ihel1],gout[ohel1]); interb= FFGvertex_->evaluate(scale(),5,particles[1], ain[ihel2],gout[ohel1]); for(unsigned int vhel=0;vhel<2;++vhel) { diag[0]= FFPvertex_->evaluate(ZERO,fin[ihel1],interb,vout[vhel]); diag[1]= FFPvertex_->evaluate(ZERO,inters,ain[ihel2],vout[vhel]); // diagram contributions me[1] += norm(diag[0]); me[2] += norm(diag[1]); // total diag[0] += diag[1]; me[0] += norm(diag[0]); if(first) me_(ihel1,ihel2,vhel,2*ohel1) = diag[0]; } } } } // results // initial state spin and colour average double colspin = 1./9./4.; // and C_F N_c from matrix element colspin *= 4.; DVector save; for(unsigned int ix=0;ix<3;++ix) { me[ix] *= colspin; if(ix>0) save.push_back(me[ix]); } meInfo(save); output = me[0]/norm(FFGvertex_->norm()); } return output; } InvEnergy2 MEPP2GammaGammaPowheg:: realGammaGammagME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool ) const { // matrix element double sum = realME(particles,momenta); // loop over the QCD and QCD dipoles InvEnergy2 dipoles[2]; pair supress[2]; // compute the two dipole terms unsigned int iemit = 4, ihard = 3; double x = (momenta[0]*momenta[1]-momenta[iemit]*momenta[1]- momenta[iemit]*momenta[0])/(momenta[0]*momenta[1]); Lorentz5Momentum Kt = momenta[0]+momenta[1]-momenta[iemit]; vector pa(4),pb(4); // momenta for q -> q g/gamma emission pa[0] = x*momenta[0]; pa[1] = momenta[1]; Lorentz5Momentum K = pa[0]+pa[1]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); pa[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pa[2].setMass(momenta[2].mass()); pa[3] = momenta[ihard] -2.*Ksum*(Ksum*momenta[ihard])/Ksum2+2*K*(Kt*momenta[ihard])/K2; pa[3].setMass(ZERO); cPDVector part(particles.begin(),--particles.end()); part[3] = particles[ihard]; // first leading-order matrix element double lo1 = loGammaGammaME(part,pa); // first dipole dipoles[0] = 1./(momenta[0]*momenta[iemit])/x*(2./(1.-x)-(1.+x))*lo1; supress[0] = supressionFunction(momenta[iemit].perp(),pa[3].perp()); // momenta for qbar -> qbar g/gamma emission pb[0] = momenta[0]; pb[1] = x*momenta[1]; K = pb[0]+pb[1]; Ksum = K+Kt; K2 = K.m2(); Ksum2 = Ksum.m2(); pb[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pb[2].setMass(momenta[2].mass()); pb[3] = momenta[ihard] -2.*Ksum*(Ksum*momenta[ihard])/Ksum2+2*K*(Kt*momenta[ihard])/K2; pb[3].setMass(ZERO); // second LO matrix element double lo2 = loGammaGammaME(part,pb); // second dipole dipoles[1] = 1./(momenta[1]*momenta[iemit])/x*(2./(1.-x)-(1.+x))*lo2; supress[1] = supressionFunction(momenta[iemit].perp(),pb[3].perp()); for(unsigned int ix=0;ix<2;++ix) dipoles[ix] *= 4./3.; // denominator for the matrix element InvEnergy2 denom = abs(dipoles[0]) + abs(dipoles[1]); // contribution if( denom==ZERO || dipoles[(dipole-1)/2]==ZERO ) return ZERO; sum *= abs(dipoles[(dipole-1)/2])/denom; // final coupling factors InvEnergy2 output; if(rad==Subtraction) { output = alphaS_*alphaEM_* (sum*UnitRemoval::InvE2*supress[(dipole-1)/2].first - dipoles[(dipole-1)/2]); } else { output = alphaS_*alphaEM_*sum*UnitRemoval::InvE2; if(rad==Hard) output *=supress[(dipole-1)/2].second; else if(rad==Shower) output *=supress[(dipole-1)/2].first ; } return output; } InvEnergy2 MEPP2GammaGammaPowheg::realGammaGammaqME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool ) const { double sum = realME(particles,momenta); // initial-state QCD dipole double x = (momenta[0]*momenta[1]-momenta[4]*momenta[1]- momenta[4]*momenta[0])/(momenta[0]*momenta[1]); Lorentz5Momentum Kt = momenta[0]+momenta[1]-momenta[4]; vector pa(4); pa[0] = momenta[0]; pa[1] = x*momenta[1]; Lorentz5Momentum K = pa[0]+pa[1]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); pa[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pa[2].setMass(momenta[2].mass()); pa[3] = momenta[3] -2.*Ksum*(Ksum*momenta[3])/Ksum2+2*K*(Kt*momenta[3])/K2; pa[3].setMass(ZERO); cPDVector part(particles.begin(),--particles.end()); part[1] = particles[4]->CC(); double lo1 = loGammaGammaME(part,pa); InvEnergy2 D1 = 0.5/(momenta[1]*momenta[4])/x*(1.-2.*x*(1.-x))*lo1; // initial-final QED dipole vector pb(4); x = 1.-(momenta[3]*momenta[4])/(momenta[4]*momenta[0]+momenta[0]*momenta[3]); pb[3] = momenta[4]+momenta[3]-(1.-x)*momenta[0]; pb[0] = x*momenta[0]; pb[1] = momenta[1]; pb[2] = momenta[2]; double z = momenta[0]*momenta[3]/(momenta[0]*momenta[3]+momenta[0]*momenta[4]); part[1] = particles[1]; part[3] = particles[4]; double lo2 = loGammaqME(part,pb); Energy pT = sqrt(-(pb[0]-pb[3]).m2()*(1.-x)*(1.-z)*z/x); InvEnergy2 DF = 1./(momenta[4]*momenta[3])/x*(1./(1.-x+z)-2.+z)*lo2; InvEnergy2 DI = 1./(momenta[0]*momenta[3])/x*(1./(1.-x+z)-1.-x)*lo2; DI *= sqr(double(particles[0]->iCharge())/3.); DF *= sqr(double(particles[0]->iCharge())/3.); InvEnergy2 denom = abs(D1)+abs(DI)+abs(DF); pair supress; InvEnergy2 term; if ( dipole == IFQED1 ) { term = DI; supress = supressionFunction(pT,pb[3].perp()); } else if( dipole == FIQED1 ) { term = DF; supress = supressionFunction(pT,pb[3].perp()); } else { term = D1; supress = supressionFunction(momenta[4].perp(),pa[3].perp()); } if( denom==ZERO || term == ZERO ) return ZERO; sum *= abs(term)/denom; // final coupling factors InvEnergy2 output; if(rad==Subtraction) { output = alphaS_*alphaEM_* (sum*UnitRemoval::InvE2*supress.first - term); } else { output = alphaS_*alphaEM_*sum*UnitRemoval::InvE2; if(rad==Hard) output *= supress.second; else if(rad==Shower) output *= supress.first ; } // final coupling factors return output; } InvEnergy2 MEPP2GammaGammaPowheg:: realGammaGammaqbarME(const cPDVector & particles, const vector & momenta, DipoleType dipole, RadiationType rad, bool) const { double sum = realME(particles,momenta); // initial-state QCD dipole double x = (momenta[0]*momenta[1]-momenta[4]*momenta[1]-momenta[4]*momenta[0])/ (momenta[0]*momenta[1]); Lorentz5Momentum Kt = momenta[0]+momenta[1]-momenta[4]; vector pa(4); pa[0] = x*momenta[0]; pa[1] = momenta[1]; Lorentz5Momentum K = pa[0]+pa[1]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); pa[2] = momenta[2]-2.*Ksum*(Ksum*momenta[2])/Ksum2+2*K*(Kt*momenta[2])/K2; pa[2].setMass(momenta[2].mass()); pa[3] = momenta[3] -2.*Ksum*(Ksum*momenta[3])/Ksum2+2*K*(Kt*momenta[3])/K2; pa[3].setMass(ZERO); cPDVector part(particles.begin(),--particles.end()); part[0] = particles[4]->CC(); double lo1 = loGammaGammaME(part,pa); InvEnergy2 D1 = 0.5/(momenta[0]*momenta[4])/x*(1.-2.*x*(1.-x))*lo1; // initial-final QED dipole vector pb(4); x = 1.-(momenta[3]*momenta[4])/(momenta[4]*momenta[1]+momenta[1]*momenta[3]); pb[3] = momenta[4]+momenta[3]-(1.-x)*momenta[1]; pb[0] = momenta[0]; pb[1] = x*momenta[1]; pb[2] = momenta[2]; double z = momenta[1]*momenta[3]/(momenta[1]*momenta[3]+momenta[1]*momenta[4]); part[0] = particles[0]; part[3] = particles[4]; double lo2 = loGammaqbarME(part,pb); Energy pT = sqrt(-(pb[1]-pb[3]).m2()*(1.-x)*(1.-z)*z/x); InvEnergy2 DF = 1./(momenta[4]*momenta[3])/x*(2./(1.-x+z)-2.+z)*lo2; InvEnergy2 DI = 1./(momenta[0]*momenta[3])/x*(2./(1.-x+z)-1.-x)*lo2; InvEnergy2 term; DI *= sqr(double(particles[1]->iCharge())/3.); DF *= sqr(double(particles[1]->iCharge())/3.); InvEnergy2 denom = abs(D1)+abs(DI)+abs(DF); pair supress; if ( dipole == IFQED2 ) { term = DI; supress = supressionFunction(pT,pb[3].perp()); } else if( dipole == FIQED2 ) { term = DF; supress = supressionFunction(pT,pb[3].perp()); } else { term = D1; supress = supressionFunction(momenta[4].perp(),pa[3].perp()); } if( denom==ZERO || dipole==ZERO ) return ZERO; sum *= abs(term)/denom; // final coupling factors InvEnergy2 output; if(rad==Subtraction) { output = alphaS_*alphaEM_* (sum*UnitRemoval::InvE2*supress.first - term); } else { output = alphaS_*alphaEM_*sum*UnitRemoval::InvE2; if(rad==Hard) output *= supress.second; else if(rad==Shower) output *= supress.first ; } // final coupling factors return output; } double MEPP2GammaGammaPowheg:: realME(const cPDVector & particles, const vector & momenta) const { vector qin; vector qbarin; vector wout,pout,gout; SpinorWaveFunction q_in; SpinorBarWaveFunction qbar_in; VectorWaveFunction g_out; VectorWaveFunction v_out (momenta[2],particles[2],outgoing); VectorWaveFunction p_out (momenta[3],particles[3],outgoing); // q qbar -> gamma gamma g if(particles[4]->id()==ParticleID::g) { q_in = SpinorWaveFunction (momenta[0],particles[0],incoming); qbar_in = SpinorBarWaveFunction (momenta[1],particles[1],incoming); g_out = VectorWaveFunction (momenta[4],particles[4],outgoing); } // q g -> gamma gamma q else if(particles[4]->id()>0) { q_in = SpinorWaveFunction (momenta[0],particles[0],incoming); qbar_in = SpinorBarWaveFunction (momenta[4],particles[4],outgoing); g_out = VectorWaveFunction (momenta[1],particles[1],incoming); } else if(particles[4]->id()<0) { q_in = SpinorWaveFunction (momenta[4],particles[4],outgoing); qbar_in = SpinorBarWaveFunction (momenta[1],particles[1],incoming); g_out = VectorWaveFunction (momenta[0],particles[0],incoming); } else assert(false); for(unsigned int ix=0;ix<2;++ix) { q_in.reset(ix); qin.push_back(q_in); qbar_in.reset(ix); qbarin.push_back(qbar_in); g_out.reset(2*ix); gout.push_back(g_out); p_out.reset(2*ix); pout.push_back(p_out); v_out.reset(2*ix); wout.push_back(v_out); } vector diag(6 , 0.); Energy2 mu2 = scale(); double sum(0.); for(unsigned int ihel1=0;ihel1<2;++ihel1) { for(unsigned int ihel2=0;ihel2<2;++ihel2) { for(unsigned int whel=0;whel<2;++whel) { for(unsigned int phel=0;phel<2;++phel) { for(unsigned int ghel=0;ghel<2;++ghel) { // first diagram SpinorWaveFunction inters1 = - FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle(),qin[ihel1],pout[phel]); + FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle()->CC(),qin[ihel1],pout[phel]); SpinorBarWaveFunction inters2 = - FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle()->CC(), + FFPvertex_->evaluate(ZERO,5,qin[ihel1].particle(), qbarin[ihel2],wout[whel]); diag[0] = FFGvertex_->evaluate(mu2,inters1,inters2,gout[ghel]); // second diagram SpinorWaveFunction inters3 = - FFGvertex_->evaluate(mu2,5,qin[ihel1].particle(),qin[ihel1],gout[ghel]); + FFGvertex_->evaluate(mu2,5,qin[ihel1].particle()->CC(),qin[ihel1],gout[ghel]); SpinorBarWaveFunction inters4 = - FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle(), + FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle()->CC(), qbarin[ihel2],pout[phel]); diag[1] = FFPvertex_->evaluate(ZERO,inters3,inters4,wout[whel]); // fourth diagram diag[2] = FFPvertex_->evaluate(ZERO,inters3,inters2,pout[phel]); // fifth diagram SpinorBarWaveFunction inters5 = - FFGvertex_->evaluate(mu2,5,qbarin[ihel2].particle(), + FFGvertex_->evaluate(mu2,5,qbarin[ihel2].particle()->CC(), qbarin[ihel2],gout[ghel]); diag[3] = FFPvertex_->evaluate(ZERO,inters1,inters5,wout[whel]); // sixth diagram SpinorWaveFunction inters6 = - FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle()->CC(), - qin[ihel1],wout[whel]); + FFPvertex_->evaluate(ZERO,5,qbarin[ihel2].particle(), + qin[ihel1],wout[whel]); diag[4] = FFGvertex_->evaluate(mu2,inters6,inters4,gout[ghel]); // eighth diagram diag[5] = FFPvertex_->evaluate(ZERO,inters6,inters5,pout[phel]); // sum Complex dsum = std::accumulate(diag.begin(),diag.end(),Complex(0.)); sum += norm(dsum); } } } } } // divide out the em and strong couplings sum /= norm(FFGvertex_->norm()*FFPvertex_->norm()); // final spin and colour factors spin = 1/4 colour = 4/9 if(particles[4]->id()==ParticleID::g) sum /= 9.; // final spin and colour factors spin = 1/4 colour = 4/(3*8) else sum /= 24.; // finally identical particle factor return 0.5*sum; } double MEPP2GammaGammaPowheg::subtractedVirtual() const { double v = 1+tHat()/sHat(); double born = (1-v)/v+v/(1-v); double finite_term = born* (2./3.*sqr(Constants::pi)-3.+sqr(log(v))+sqr(log(1-v))+3.*log(1-v))+ 2.+2.*log(v)+2.*log(1-v)+3.*(1-v)/v*(log(v)-log(1-v))+ (2.+v/(1-v))*sqr(log(v))+(2.+(1-v)/v)*sqr(log(1-v)); double virt = ((6.-(2./3.)*sqr(Constants::pi))* born-2.+finite_term); return virt/born; } double MEPP2GammaGammaPowheg::subtractedReal(pair x, double z, double zJac, double oldqPDF, double newqPDF, double newgPDF,bool order) const { double vt = vTilde_*(1.-z); double vJac = 1.-z; Energy pT = sqrt(sHat()*vt*(1.-vt-z)/z); // rapidities double rapidity; if(order) { rapidity = -log(x.second*sqrt(lastS())/pT*vt); } else { rapidity = log(x.first *sqrt(lastS())/pT*vt); } // CMS system Energy rs=sqrt(lastS()); Lorentz5Momentum pcmf = Lorentz5Momentum(ZERO,ZERO,0.5*rs*(x.first-x.second), 0.5*rs*(x.first+x.second)); pcmf.rescaleMass(); Boost blab(pcmf.boostVector()); // emission from the quark radiation vector pnew(5); if(order) { pnew [0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first/z, 0.5*rs*x.first/z,ZERO); pnew [1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second, 0.5*rs*x.second,ZERO) ; } else { pnew[0] = Lorentz5Momentum(ZERO,ZERO,0.5*rs*x.first, 0.5*rs*x.first,ZERO); pnew[1] = Lorentz5Momentum(ZERO,ZERO,-0.5*rs*x.second/z, 0.5*rs*x.second/z,ZERO) ; } pnew [2] = meMomenta()[2]; pnew [3] = meMomenta()[3]; pnew [4] = Lorentz5Momentum(pT*cos(phi_),pT*sin(phi_), pT*sinh(rapidity), pT*cosh(rapidity), ZERO); Lorentz5Momentum K = pnew [0]+pnew [1]-pnew [4]; Lorentz5Momentum Kt = pcmf; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(); Energy2 Ksum2 = Ksum.m2(); for(unsigned int ix=2;ix<4;++ix) { pnew [ix].boost(blab); pnew [ix] = pnew [ix] - 2.*Ksum*(Ksum*pnew [ix])/Ksum2 +2*K*(Kt*pnew [ix])/K2; } // phase-space prefactors double phase = zJac*vJac/z; // real emission q qbar vector output(4,0.); double realQQ(0.),realGQ(0.); if(!(zTilde_<1e-7 || vt<1e-7 || 1.-z-vt < 1e-7 )) { cPDVector particles(mePartonData()); particles.push_back(gluon_); // calculate the full 2->3 matrix element realQQ = sHat()*phase*newqPDF/oldqPDF* realGammaGammagME(particles,pnew,order ? IIQCD1 : IIQCD2,Subtraction,false); if(order) { particles[0] = gluon_; particles[4] = mePartonData()[0]->CC(); realGQ = sHat()*phase*newgPDF/oldqPDF* realGammaGammaqbarME(particles,pnew,IIQCD2,Subtraction,false); } else { particles[1] = gluon_; particles[4] = mePartonData()[1]->CC(); realGQ = sHat()*phase*newgPDF/oldqPDF* realGammaGammaqME (particles,pnew,IIQCD1,Subtraction,false); } } // return the answer return realQQ+realGQ; } double MEPP2GammaGammaPowheg::collinearQuark(double x, Energy2 mu2, double jac, double z, double oldPDF, double newPDF) const { if(1.-z < 1.e-8) return 0.; return CFfact_*( // this bit is multiplied by LO PDF sqr(Constants::pi)/3.-5.+2.*sqr(log(1.-x )) +(1.5+2.*log(1.-x ))*log(sHat()/mu2) // NLO PDF bit +jac /z * newPDF /oldPDF * (1.-z -(1.+z )*log(sqr(1.-z )/z ) -(1.+z )*log(sHat()/mu2)-2.*log(z )/(1.-z )) // + function bit +jac /z *(newPDF /oldPDF -z )* 2./(1.-z )*log(sHat()*sqr(1.-z )/mu2)); } double MEPP2GammaGammaPowheg::collinearGluon(Energy2 mu2, double jac, double z, double oldPDF, double newPDF) const { if(1.-z < 1.e-8) return 0.; return TRfact_*jac/z*newPDF/oldPDF* ((sqr(z)+sqr(1.-z))*log(sqr(1.-z)*sHat()/z/mu2) +2.*z*(1.-z)); } void MEPP2GammaGammaPowheg::doinit() { HwMEBase::doinit(); vector mopt(2,1); massOption(mopt); // get the vertices we need // get a pointer to the standard model object in the run static const tcHwSMPtr hwsm = dynamic_ptr_cast(standardModel()); if (!hwsm) throw InitException() << "hwsm pointer is null in" << " MEPP2GammaGamma::doinit()" << Exception::abortnow; // get pointers to all required Vertex objects FFPvertex_ = hwsm->vertexFFP(); FFGvertex_ = hwsm->vertexFFG(); gluon_ = getParticleData(ParticleID::g); // sampling factors prefactor_.push_back(preQCDqqbarq_); prefactor_.push_back(preQCDqqbarqbar_); prefactor_.push_back(preQCDqg_); prefactor_.push_back(preQCDgqbar_); prefactor_.push_back(preQEDqqbarq_); prefactor_.push_back(preQEDqqbarqbar_); prefactor_.push_back(preQEDqgq_); prefactor_.push_back(preQEDgqbarqbar_); } RealEmissionProcessPtr MEPP2GammaGammaPowheg:: generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { beams_.clear(); partons_.clear(); bool QCDAllowed(false),QEDAllowed(false); if(inter==ShowerInteraction::QCD) QCDAllowed = true; else if(inter==ShowerInteraction::QED) QEDAllowed = true; else if(inter==ShowerInteraction::QEDQCD || inter==ShowerInteraction::ALL) { QEDAllowed = true; QCDAllowed = true; } // find the incoming particles // and get the particles to be showered ParticleVector incoming,particlesToShower; pair x; for(unsigned int ix=0;ixbornIncoming().size();++ix) { incoming.push_back( born->bornIncoming()[ix] ); beams_.push_back(dynamic_ptr_cast(born->hadrons()[ix]->dataPtr())); partons_.push_back( born->bornIncoming()[ix]->dataPtr() ); particlesToShower.push_back( born->bornIncoming()[ix] ); if(ix==0) x.first = incoming.back()->momentum().rho()/born->hadrons()[ix]->momentum().rho(); else x.second = incoming.back()->momentum().rho()/born->hadrons()[ix]->momentum().rho(); } // find the parton which should be first if( ( particlesToShower[1]->id() > 0 && particlesToShower[0]->id() < 0 ) || ( particlesToShower[0]->id() == ParticleID::g && particlesToShower[1]->id() < 6 && particlesToShower[1]->id() > 0 ) ) { swap(particlesToShower[0],particlesToShower[1]); swap(partons_[0],partons_[1]); swap(beams_ [0],beams_ [1]); swap(x.first ,x.second ); } // check that quark is along +ve z direction quarkplus_ = particlesToShower[0]->momentum().z() > ZERO; // outgoing partons for(unsigned int ix=0;ixbornOutgoing().size();++ix) { particlesToShower.push_back( born->bornOutgoing()[ix] ); } if(particlesToShower.size()!=4) return RealEmissionProcessPtr(); if(particlesToShower[2]->id()!=ParticleID::gamma) swap(particlesToShower[2],particlesToShower[3]); if(particlesToShower[3]->id()==ParticleID::gamma) { if(QCDAllowed) return hardQCDEmission(born,particlesToShower,x); } else { if(QEDAllowed) return hardQEDEmission(born,particlesToShower,x); } return born; } RealEmissionProcessPtr MEPP2GammaGammaPowheg:: hardQCDEmission(RealEmissionProcessPtr born, ParticleVector particlesToShower, pair x) { Energy rootS = sqrt(lastS()); // limits on the rapidity of the jet double minyj = -8.0,maxyj = 8.0; // generate the hard emission vector pT; Energy pTmax(-GeV); cPDVector selectedParticles; vector selectedMomenta; int iemit(-1); for(unsigned int ix=0;ix<4;++ix) { pT.push_back(0.5*generator()->maximumCMEnergy()); double a = alphaQCD_->overestimateValue()/Constants::twopi* prefactor_[ix]*(maxyj-minyj); cPDVector particles; for(unsigned int iy=0;iydataPtr()); if(ix<2) particles.push_back(gluon_); else if(ix==2) { particles.push_back(particles[0]->CC()); particles[0] = gluon_; } else { particles.push_back(particles[1]->CC()); particles[1] = gluon_; } vector momenta(5); do { pT[ix] *= pow(UseRandom::rnd(),1./a); double y = UseRandom::rnd()*(maxyj-minyj)+ minyj; double vt,z; if(ix%2==0) { vt = pT[ix]*exp(-y)/rootS/x.second; z = (1.-pT[ix]*exp(-y)/rootS/x.second)/(1.+pT[ix]*exp( y)/rootS/x.first ); if(z>1.||z1.||z1.-z || vt<0.) continue; if(ix%2==0) { momenta[0] = particlesToShower[0]->momentum()/z; momenta[1] = particlesToShower[1]->momentum(); } else { momenta[0] = particlesToShower[0]->momentum(); momenta[1] = particlesToShower[1]->momentum()/z; } double phi = Constants::twopi*UseRandom::rnd(); momenta[2] = particlesToShower[2]->momentum(); momenta[3] = particlesToShower[3]->momentum(); if(!quarkplus_) y *= -1.; momenta[4] = Lorentz5Momentum(pT[ix]*cos(phi),pT[ix]*sin(phi), pT[ix]*sinh(y),pT[ix]*cosh(y), ZERO); Lorentz5Momentum K = momenta[0] + momenta[1] - momenta[4]; Lorentz5Momentum Kt = momenta[2]+momenta[3]; Lorentz5Momentum Ksum = K+Kt; Energy2 K2 = K.m2(), Ksum2 = Ksum.m2(); for(unsigned int iy=2;iy<4;++iy) { momenta [iy] = momenta [iy] - 2.*Ksum*(Ksum*momenta [iy])/Ksum2 +2*K*(Kt*momenta [iy])/K2; } // matrix element piece double wgt = alphaQCD_->ratio(sqr(pT[ix]))*z/(1.-vt)/prefactor_[ix]/loME_; if(ix==0) wgt *= sqr(pT[ix])*realGammaGammagME(particles,momenta,IIQCD1,Shower,false); else if(ix==1) wgt *= sqr(pT[ix])*realGammaGammagME(particles,momenta,IIQCD2,Shower,false); else if(ix==2) wgt *= sqr(pT[ix])*realGammaGammaqbarME(particles,momenta,IIQCD1,Shower,false); else if(ix==3) wgt *= sqr(pT[ix])*realGammaGammaqME(particles,momenta,IIQCD2,Shower,false); wgt *= 4.*Constants::pi/alphaS_; // pdf piece double pdf[2]; if(ix%2==0) { pdf[0] = beams_[0]->pdf()->xfx(beams_[0],partons_ [0], scale(), x.first ) /x.first; pdf[1] = beams_[0]->pdf()->xfx(beams_[0],particles[0], scale()+sqr(pT[ix]),x.first /z)*z/x.first; } else { pdf[0] = beams_[1]->pdf()->xfx(beams_[1],partons_ [1], scale() ,x.second ) /x.second; pdf[1] = beams_[1]->pdf()->xfx(beams_[1],particles[1], scale()+sqr(pT[ix]),x.second/z)*z/x.second; } if(pdf[0]<=0.||pdf[1]<=0.) continue; wgt *= pdf[1]/pdf[0]; if(wgt>1.) generator()->log() << "Weight greater than one in " << "MEPP2GammaGammaPowheg::hardQCDEmission() " << "for channel " << ix << " Weight = " << wgt << "\n"; if(UseRandom::rnd()minpT_); if(pT[ix]>minpT_ && pT[ix]>pTmax) { pTmax = pT[ix]; selectedParticles = particles; selectedMomenta = momenta; iemit=ix; } } // if no emission if(pTmaxpT()[ShowerInteraction::QCD] = minpT_; return born; } // construct the HardTree object needed to perform the showers // create the partons ParticleVector newparticles; newparticles.push_back(selectedParticles[0]->produceParticle(selectedMomenta[0])); newparticles.push_back(selectedParticles[1]->produceParticle(selectedMomenta[1])); for(unsigned int ix=2;ixdataPtr()-> produceParticle(selectedMomenta[ix])); } newparticles.push_back(selectedParticles[4]->produceParticle(selectedMomenta[4])); // identify the type of process // gluon emission if(newparticles.back()->id()==ParticleID::g) { newparticles[4]->incomingColour(newparticles[0]); newparticles[4]->incomingColour(newparticles[1],true); } // quark else if(newparticles.back()->id()>0) { iemit=1; newparticles[4]->incomingColour(newparticles[1]); newparticles[1]-> colourConnect(newparticles[0]); } // antiquark else { iemit=0; newparticles[4]->incomingColour(newparticles[0],true); newparticles[1]-> colourConnect(newparticles[0]); } // add incoming int ispect = iemit==0 ? 1 : 0; if(particlesToShower[0]==born->bornIncoming()[0]) { born->incoming().push_back(newparticles[0]); born->incoming().push_back(newparticles[1]); } else { born->incoming().push_back(newparticles[1]); born->incoming().push_back(newparticles[0]); swap(iemit,ispect); } // add the outgoing for(unsigned int ix=2;ixoutgoing().push_back(newparticles[ix]); // emitter spectator etc born->emitter (iemit ); born->spectator(ispect); born->emitted(4); // x values pair xnew; for(unsigned int ix=0;ix<2;++ix) { double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); if(ix==0) xnew.first = x; else xnew.second = x; } born->x(xnew); // max pT born->pT()[ShowerInteraction::QCD] = pTmax; born->interaction(ShowerInteraction::QCD); // return the process return born; } RealEmissionProcessPtr MEPP2GammaGammaPowheg:: hardQEDEmission(RealEmissionProcessPtr born, ParticleVector particlesToShower, pair x) { // return if not emission from quark if(particlesToShower[0]->id()!=ParticleID::g && particlesToShower[1]->id()!=ParticleID::g ) return RealEmissionProcessPtr(); // generate the hard emission vector pT; Energy pTmax(-GeV); cPDVector selectedParticles; vector selectedMomenta; int iemit(-1); pair mewgt(make_pair(0.,0.)); for(unsigned int ix=0;ixdataPtr()); selectedMomenta.push_back(particlesToShower[ix]->momentum()); } selectedParticles.push_back(getParticleData(ParticleID::gamma)); swap(selectedParticles[3],selectedParticles[4]); selectedMomenta.push_back(Lorentz5Momentum()); swap(selectedMomenta[3],selectedMomenta[4]); Lorentz5Momentum pin,pout; double xB; unsigned int iloc; if(particlesToShower[0]->dataPtr()->charged()) { pin = particlesToShower[0]->momentum(); xB = x.first; iloc = 6; } else { pin = particlesToShower[1]->momentum(); xB = x.second; iloc = 7; } pout = particlesToShower[3]->momentum(); Lorentz5Momentum q = pout-pin; Axis axis(q.vect().unit()); LorentzRotation rot; double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot = LorentzRotation(); if(axis.perp2()>1e-20) { rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); rot.rotateX(Constants::pi); } if(abs(1.-q.e()/q.vect().mag())>1e-6) rot.boostZ(q.e()/q.vect().mag()); Lorentz5Momentum ptemp = rot*pin; if(ptemp.perp2()/GeV2>1e-20) { Boost trans = -1./ptemp.e()*ptemp.vect(); trans.setZ(0.); rot.boost(trans); } rot.invert(); Energy Q = sqrt(-q.m2()); double xT = sqrt((1.-xB)/xB); double xTMin = 2.*minpT_/Q; double wgt(0.); double a = alphaQED_->overestimateValue()*prefactor_[iloc]/Constants::twopi; Lorentz5Momentum p1,p2,p3; do { wgt = 0.; // intergration variables dxT/xT^3 xT *= 1./sqrt(1.-2.*log(UseRandom::rnd())/a*sqr(xT)); // dz double zp = UseRandom::rnd(); double xp = 1./(1.+0.25*sqr(xT)/zp/(1.-zp)); if(xT1.) continue; // phase-space piece of the weight wgt = 4.*sqr(1.-xp)*(1.-zp)*zp/prefactor_[iloc]/loME_; // coupling Energy2 pT2 = 0.25*sqr(Q*xT); wgt *= alphaQED_->ratio(pT2); // matrix element wgt *= 4.*Constants::pi/alphaEM_; // PDF double pdf[2]; if(iloc==6) { pdf[0] = beams_[0]->pdf()-> xfx(beams_[0],partons_[0],scale() ,x.first ); pdf[1] = beams_[0]->pdf()-> xfx(beams_[0],partons_[0],scale()+pT2,x.first /xp); } else { pdf[0] = beams_[1]->pdf()-> xfx(beams_[1],partons_[1],scale() ,x.second ); pdf[1] = beams_[1]->pdf()-> xfx(beams_[1],partons_[1],scale()+pT2,x.second/xp); } if(pdf[0]<=0.||pdf[1]<=0.) { wgt = 0.; continue; } wgt *= pdf[1]/pdf[0]; // matrix element piece double phi = Constants::twopi*UseRandom::rnd(); double x2 = 1.-(1.-zp)/xp; double x3 = 2.-1./xp-x2; p1=Lorentz5Momentum(ZERO,ZERO,0.5*Q/xp,0.5*Q/xp,ZERO); p2=Lorentz5Momentum( 0.5*Q*xT*cos(phi), 0.5*Q*xT*sin(phi), -0.5*Q*x2,0.5*Q*sqrt(sqr(xT)+sqr(x2))); p3=Lorentz5Momentum(-0.5*Q*xT*cos(phi),-0.5*Q*xT*sin(phi), -0.5*Q*x3,0.5*Q*sqrt(sqr(xT)+sqr(x3))); selectedMomenta[iloc-6] = rot*p1; selectedMomenta[3] = rot*p3; selectedMomenta[4] = rot*p2; if(iloc==6) { mewgt.first = sqr(Q)*realGammaGammaqME(selectedParticles,selectedMomenta,IFQED1,Shower,false); mewgt.second = sqr(Q)*realGammaGammaqME(selectedParticles,selectedMomenta,FIQED1,Shower,false); wgt *= mewgt.first+mewgt.second; } else { mewgt.first = sqr(Q)*realGammaGammaqbarME(selectedParticles,selectedMomenta,IFQED2,Shower,false); mewgt.second = sqr(Q)*realGammaGammaqbarME(selectedParticles,selectedMomenta,FIQED2,Shower,false); wgt *= mewgt.first+mewgt.second; } if(wgt>1.) generator()->log() << "Weight greater than one in " << "MEPP2GammaGammaPowheg::hardQEDEmission() " << "for IF channel " << " Weight = " << wgt << "\n"; } while(xT>xTMin&&UseRandom::rnd()>wgt); // if no emission if(xTpT()[ShowerInteraction::QED] = minpT_; return born; } pTmax = 0.5*xT*Q; iemit = mewgt.first>mewgt.second ? 2 : 3; // construct the object needed to perform the showers // create the partons ParticleVector newparticles; newparticles.push_back(selectedParticles[0]->produceParticle(selectedMomenta[0])); newparticles.push_back(selectedParticles[1]->produceParticle(selectedMomenta[1])); for(unsigned int ix=2;ix dataPtr()->produceParticle(selectedMomenta[ix==2 ? 2 : 4 ])); } newparticles.push_back(selectedParticles[3]->produceParticle(selectedMomenta[3])); // make the colour connections bool col = newparticles[3]->id()<0; if(particlesToShower[0]->dataPtr()->charged()) { newparticles[3]->incomingColour(newparticles[1],col); newparticles[1]->colourConnect (newparticles[0],col); } else { newparticles[3]->incomingColour(newparticles[0],col); newparticles[0]->colourConnect (newparticles[1],col); } bool FSR = iemit==3; // add incoming particles if(particlesToShower[0]==born->bornIncoming()[0]) { born->incoming().push_back(newparticles[0]); born->incoming().push_back(newparticles[1]); } else { born->incoming().push_back(newparticles[1]); born->incoming().push_back(newparticles[0]); } // IS radiatng particle unsigned int iemitter = born->incoming()[0]->dataPtr()->charged() ? 0 : 1; // add outgoing particles if(particlesToShower[2]==born->bornOutgoing()[0]) { born->outgoing().push_back(newparticles[2]); born->outgoing().push_back(newparticles[3]); } else { born->outgoing().push_back(newparticles[3]); born->outgoing().push_back(newparticles[2]); } born->outgoing().push_back(newparticles[4]); // outgoing radiating particle unsigned int ispectator = born->outgoing()[0]->dataPtr()->charged() ? 2 : 3; // get emitter and spectator right if(FSR) swap(iemitter,ispectator); born->emitter (iemitter ); born->spectator(ispectator); born->emitted(4); // x values pair xnew; for(unsigned int ix=0;ix<2;++ix) { double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); if(ix==0) xnew.first = x; else xnew.second = x; } born->x(xnew); // max pT born->pT()[ShowerInteraction::QED] = pTmax; // return the process born->interaction(ShowerInteraction::QED); return born; } diff --git a/MatrixElement/Powheg/MEPP2VVPowheg.cc b/MatrixElement/Powheg/MEPP2VVPowheg.cc --- a/MatrixElement/Powheg/MEPP2VVPowheg.cc +++ b/MatrixElement/Powheg/MEPP2VVPowheg.cc @@ -1,5282 +1,5284 @@ // -*- C++ -*- // // MEPP2VVPowheg.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 MEPP2VVPowheg class. // #include "MEPP2VVPowheg.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Handlers/StandardXComb.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/MatrixElement/HardVertex.h" #include "Herwig/Decay/GeneralDecayMatrixElement.h" #include "Herwig/Shower/RealEmissionProcess.h" using namespace Herwig; MEPP2VVPowheg::MEPP2VVPowheg() : tiny(1.e-10), CF_(4./3.), TR_(0.5), NC_(3.), contrib_(1), channels_(0), nlo_alphaS_opt_(0) , fixed_alphaS_(0.1180346226), removebr_(1), scaleopt_(1), mu_F_(100.*GeV), mu_UV_(100.*GeV), ckm_(3,vector(3,0.0)), helicityConservation_(true), realMESpinCorrelations_(true), power_(2.0), preqqbar_(3.7),preqg_(16.0),pregqbar_(11.0), b0_((11.-2./3.*5.)/4./Constants::pi), LambdaQCD_(91.118*GeV*exp(-1./2./((11.-2./3.*5.)/4./Constants::pi)/0.118)), min_pT_(2.*GeV){ massOption(vector(2,1)); } void MEPP2VVPowheg::persistentOutput(PersistentOStream & os) const { os << contrib_ << channels_ << nlo_alphaS_opt_ << fixed_alphaS_ << removebr_ << scaleopt_ << ounit(mu_F_,GeV) << ounit(mu_UV_,GeV) << ckm_ << helicityConservation_ << FFPvertex_ << FFWvertex_ << FFZvertex_ << WWWvertex_ << FFGvertex_ << realMESpinCorrelations_ << showerAlphaS_ << power_ << preqqbar_ << preqg_ << pregqbar_ << prefactor_ << b0_ << ounit(LambdaQCD_,GeV) << ounit( min_pT_,GeV ); } void MEPP2VVPowheg::persistentInput(PersistentIStream & is, int) { is >> contrib_ >> channels_ >> nlo_alphaS_opt_ >> fixed_alphaS_ >> removebr_ >> scaleopt_ >> iunit(mu_F_,GeV) >> iunit(mu_UV_,GeV) >> ckm_ >> helicityConservation_ >> FFPvertex_ >> FFWvertex_ >> FFZvertex_ >> WWWvertex_ >> FFGvertex_ >> realMESpinCorrelations_ >> showerAlphaS_ >> power_ >> preqqbar_ >> preqg_ >> pregqbar_ >> prefactor_ >> b0_ >> iunit(LambdaQCD_,GeV) >> iunit( min_pT_, GeV ); } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigMEPP2VVPowheg("Herwig::MEPP2VVPowheg", "HwMEHadron.so HwPowhegMEHadron.so"); void MEPP2VVPowheg::Init() { static ClassDocumentation documentation ("The MEPP2VVPowheg class implements the NLO matrix elements for the production of" "pairs of electroweak vector bosons.", "The calcultaion of $W^+W^-$, $W^\\pm Z^0$ and $Z^0Z^0$ production" " in hadron collisions at next-to-leading order in the POWHEG scheme" " is described in \\cite{Hamilton:2010mb}.", "\\bibitem{Hamilton:2010mb}\n" " K.~Hamilton,\n" "%``A positive-weight next-to-leading order simulation of weak boson pair\n" "%production,''\n" "JHEP {\bf 1101} (2011) 009\n" "[arXiv:1009.5391 [hep-ph]].\n" "%%CITATION = JHEPA,1101,009;%%\n"); static Switch interfaceContribution ("Contribution", "Which contributions to the cross section to include", &MEPP2VVPowheg::contrib_, 1, false, false); static SwitchOption interfaceContributionLeadingOrder (interfaceContribution, "LeadingOrder", "Just generate the leading order cross section", 0); static SwitchOption interfaceContributionPositiveNLO (interfaceContribution, "PositiveNLO", "Generate the positive contribution to the full NLO cross section", 1); static SwitchOption interfaceContributionNegativeNLO (interfaceContribution, "NegativeNLO", "Generate the negative contribution to the full NLO cross section", 2); static Switch interfaceChannels ("Channels", "Which channels to include in the cross section", &MEPP2VVPowheg::channels_, 0, false, false); static SwitchOption interfaceChannelsAll (interfaceChannels, "All", "All channels required for the full NLO cross section: qqb, qg, gqb", 0); static SwitchOption interfaceChannelsAnnihilation (interfaceChannels, "Annihilation", "Only include the qqb annihilation channel, omitting qg and gqb channels", 1); static SwitchOption interfaceChannelsCompton (interfaceChannels, "Compton", "Only include the qg and gqb compton channels, omitting all qqb processes", 2); static Switch interfaceNLOalphaSopt ("NLOalphaSopt", "An option allowing you to supply a fixed value of alpha_S " "through the FixedNLOAlphaS interface.", &MEPP2VVPowheg::nlo_alphaS_opt_, 0, false, false); static SwitchOption interfaceNLOalphaSoptRunningAlphaS (interfaceNLOalphaSopt, "RunningAlphaS", "Use the usual running QCD coupling evaluated at scale mu_UV2()", 0); static SwitchOption interfaceNLOalphaSoptFixedAlphaS (interfaceNLOalphaSopt, "FixedAlphaS", "Use a constant QCD coupling for comparison/debugging purposes", 1); static Parameter interfaceFixedNLOalphaS ("FixedNLOalphaS", "The value of alphaS to use for the nlo weight if nlo_alphaS_opt_=1", &MEPP2VVPowheg::fixed_alphaS_, 0.1180346226, 0., 1.0, false, false, Interface::limited); static Switch interfaceremovebr ("removebr", "Whether to multiply the event weights by the MCFM branching ratios", &MEPP2VVPowheg::removebr_, 1, false, false); static SwitchOption interfaceProductionCrossSection (interfaceremovebr, "Yes", "Do not multiply in the branching ratios (default running)", 1); static SwitchOption interfaceIncludeBRs (interfaceremovebr, "No", "Multiply by MCFM branching ratios for comparison/debugging purposes", 0); static Switch interfaceScaleOption ("ScaleOption", "Option for running / fixing EW and QCD factorization & renormalization scales", &MEPP2VVPowheg::scaleopt_, 1, false, false); static SwitchOption interfaceDynamic (interfaceScaleOption, "Dynamic", "QCD factorization & renormalization scales are sqr(pV1+pV2). " "EW scale is (mV1^2+mV2^2)/2 (similar to MCatNLO)", 1); static SwitchOption interfaceFixed (interfaceScaleOption, "Fixed", "QCD factorization fixed to value by FactorizationScaleValue." "EW and QCD renormalization scales fixed by RenormalizationScaleValue.", 2); static Parameter interfaceFactorizationScaleValue ("FactorizationScaleValue", "Value to use for the QCD factorization scale if fixed scales" "have been requested with the ScaleOption interface.", &MEPP2VVPowheg::mu_F_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV, true, false, Interface::limited); static Parameter interfaceRenormalizationScaleValue ("RenormalizationScaleValue", "Value to use for the EW and QCD renormalization scales if fixed " "scales have been requested with the ScaleOption interface.", &MEPP2VVPowheg::mu_UV_, GeV, 100.0*GeV, 50.0*GeV, 500.0*GeV, true, false, Interface::limited); static Switch interfaceSpinCorrelations ("SpinCorrelations", "Flag to select leading order spin correlations or a " "calculation taking into account the real NLO effects", &MEPP2VVPowheg::realMESpinCorrelations_, 1, false, false); static SwitchOption interfaceSpinCorrelationsLeadingOrder (interfaceSpinCorrelations, "LeadingOrder", "Decay bosons using a leading order 2->2 calculation of the " "production spin density matrix", 0); static SwitchOption interfaceSpinCorrelationsRealNLO (interfaceSpinCorrelations, "RealNLO", "Decay bosons using a production spin density matrix which " "takes into account the effects of real radiation", 1); static Reference interfaceCoupling ("Coupling", "The object calculating the strong coupling constant", &MEPP2VVPowheg::showerAlphaS_, false, false, true, false, false); static Parameter interfacePower ("Power", "The power for the sampling of the matrix elements", &MEPP2VVPowheg::power_, 2.0, 1.0, 10.0, false, false, Interface::limited); static Parameter interfacePrefactorqqbar ("Prefactorqqbar", "The prefactor for the sampling of the q qbar channel", &MEPP2VVPowheg::preqqbar_, 5.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorqg ("Prefactorqg", "The prefactor for the sampling of the q g channel", &MEPP2VVPowheg::preqg_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacePrefactorgqbar ("Prefactorgqbar", "The prefactor for the sampling of the g qbar channel", &MEPP2VVPowheg::pregqbar_, 3.0, 0.0, 1000.0, false, false, Interface::limited); static Parameter interfacepTMin ("minPt", "The pT cut on hardest emision generation" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &MEPP2VVPowheg::min_pT_, GeV, 2.*GeV, ZERO, 100000.0*GeV, false, false, Interface::limited); } Energy2 MEPP2VVPowheg::scale() const { // N.B. This scale is the electroweak scale! // It is used in the evaluation of the LO code // in the MEPP2VV base class. This means it // should appear in the denominator of the // NLOweight here and all other LO parts like // the function for the lumi ratio (Lhat). It // should also be used for evaluating any EW // parameters / vertices in the numerator. // The scaleopt_ == 1 "running" option is // chosen to be like the MC@NLO one (it ought // to be more like sHat instead?). return scaleopt_ == 1 ? // 0.5*(meMomenta()[2].m2()+meMomenta()[3].m2()) : sqr(mu_UV_); sHat() : sqr(mu_UV_); } Energy2 MEPP2VVPowheg::mu_F2() const { return scaleopt_ == 1 ? // ((H_.k1r()).m2()+k1r_perp2_lab_+(H_.k2r()).m2()+k2r_perp2_lab_)/2. : sqr(mu_F_); sHat() : sqr(mu_F_); } Energy2 MEPP2VVPowheg::mu_UV2() const { return scaleopt_ == 1 ? // ((H_.k1r()).m2()+k1r_perp2_lab_+(H_.k2r()).m2()+k2r_perp2_lab_)/2. : sqr(mu_UV_); sHat() : sqr(mu_UV_); } void MEPP2VVPowheg::doinit() { MEPP2VV::doinit(); // get the vertices we need // get a pointer to the standard model object in the run static const tcHwSMPtr hwsm = dynamic_ptr_cast(standardModel()); if (!hwsm) throw InitException() << "missing hwsm pointer in MEPP2VVPowheg::doinit()" << Exception::abortnow; // get pointers to all required Vertex objects FFPvertex_ = hwsm->vertexFFP(); FFZvertex_ = hwsm->vertexFFZ(); WWWvertex_ = hwsm->vertexWWW(); FFWvertex_ = hwsm->vertexFFW(); FFGvertex_ = hwsm->vertexFFG(); // get the ckm object Ptr::pointer theCKM=dynamic_ptr_cast::pointer>(SM().CKM()); if(!theCKM) throw InitException() << "MEPP2VVPowheg::doinit() " << "the CKM object must be the Herwig one" << Exception::runerror; unsigned int ix,iy; // get the CKM matrix (unsquared for interference) vector< vector > CKM(theCKM->getUnsquaredMatrix(SM().families())); for(ix=0;ix<3;++ix){for(iy=0;iy<3;++iy){ckm_[ix][iy]=CKM[ix][iy];}} // insert the different prefactors in the vector for easy look up prefactor_.push_back(preqqbar_); prefactor_.push_back(preqg_); prefactor_.push_back(pregqbar_); } int MEPP2VVPowheg::nDim() const { int output = MEPP2VV::nDim(); // See related comment in MEPP2VVPowheg::generateKinematics! if(contrib_>0) output += 2; return output; } bool MEPP2VVPowheg::generateKinematics(const double * r) { // N.B. A fix was made to make theta2 a radiative // variable in r4532. Originally theta2 was take to // be the azimuthal angle coming from the generation // of the Born kinematics inherited from MEPP2VV i.e. // before the change theta2 was a random number between // 0 and 2pi. On changing theta2 was set to be // theta2 = (*(r+3)) * 2.*Constants::pi; // and nDim returned if(contrib_>0) output += 3; // In the months following it was noticed that agreement // with MCFM was per mille at Tevatron energies but got // close to 1 percent for LHC energies (for all VV // processes). After searching back up the svn branch // running 2M events each time, the change was spotted // to occur on r4532. Changing: // if(contrib_>0) output += 3; // in ::nDim() and also, // xt = (*(r +nDim() -3)); // y = (*(r +nDim() -2)) * 2. - 1.; // theta2 = (*(r +nDim() -1)) * 2.*Constants::pi; // did not fix the problem. The following code gives the // same good level of agreement at LHC and TVT: double xt( -999.); double y( -999.); double theta2( -999.); if(contrib_>0) { // Generate the radiative integration variables: xt = (*(r +nDim() -2)); y = (*(r +nDim() -1)) * 2. - 1.; // KH 19th August - next line changed for phi in 0->pi not 0->2pi // theta2 = UseRandom::rnd() * 2.*Constants::pi; theta2 = UseRandom::rnd() *Constants::pi; } // Continue with lo matrix element code: bool output(MEPP2VV::generateKinematics(r)); // Work out the kinematics for the leading order / virtual process // and also get the leading order luminosity function: getKinematics(xt,y,theta2); return output; } double MEPP2VVPowheg::me2() const { double output(0.0); useMe(); output = MEPP2VV::me2(); double mcfm_brs(1.); if(!removebr_) { switch(MEPP2VV::process()) { case 1: // W+(->e+,nu_e) W-(->e-,nu_ebar) (MCFM: 61 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.109338816; break; case 2: // W+/-(mu+,nu_mu / mu-,nu_mubar) Z(nu_e,nu_ebar) // (MCFM: 72+77 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; case 3: // Z(mu-,mu+) Z(e-,e+) (MCFM: 86 [nproc]) mcfm_brs *= 0.034616433; mcfm_brs *= 0.034616433; mcfm_brs *= 2.; // as identical particle factor 1/2 is now obsolete. break; case 4: // W+(mu+,nu_mu) Z(nu_e,nu_ebar) (MCFM: 72 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; case 5: // W-(mu-,nu_mubar) Z(nu_e,nu_ebar) (MCFM: 77 [nproc]) mcfm_brs *= 0.109338816; mcfm_brs *= 0.06839002; break; } } // Store the value of the leading order squared matrix element: lo_me2_ = output; output *= NLOweight(); output *= mcfm_brs; return output; } void MEPP2VVPowheg::getKinematics(double xt, double y, double theta2) { // In this member we want to get the lo_lumi_ as this is a // common denominator in the NLO weight. We want also the // bornVVKinematics object and all of the realVVKinematics // objects needed for the NLO weight. // Check if the W- is first in W+W- production. Already confirmed // mePartonData()[0] is a quark, and mePartonData()[1] is an antiquark. // We assume mePartonData[2] and mePartonData[3] are, respectively, // W+/- Z, W+/- W-/+, or Z Z. bool wminus_first(false); if((mePartonData()[2]->id()==-24)&&(mePartonData()[3]->id()==24)) wminus_first=true; // Now get all data on the LO process needed for the NLO computation: // The +z hadron in the lab: hadron_A_=dynamic_ptr_cast::transient_const_pointer> (lastParticles().first->dataPtr()); // The -z hadron in the lab: hadron_B_=dynamic_ptr_cast::transient_const_pointer> (lastParticles().second->dataPtr()); // Leading order momentum fractions: double xa(lastX1()); // The +z momentum fraction in the lab. double xb(lastX2()); // The -z momentum fraction in the lab. // Particle data for incoming +z & -z QCD particles respectively: ab_ = lastPartons().first ->dataPtr(); // The +z momentum parton in the lab. bb_ = lastPartons().second->dataPtr(); // The -z momentum parton in the lab. // We checked TVT & LHC for all VV channels with 10K events: // lastParticles().first ->momentum().z() is always positive // lastParticles().second->momentum().z() is always negative // lastParticles().first ->momentum().z()*xa=lastPartons().first ->momentum().z() 1 in 10^6 // lastParticles().second->momentum().z()*xb=lastPartons().second->momentum().z() 1 in 10^6 // Set the quark and antiquark data pointers. quark_ = mePartonData()[0]; antiquark_ = mePartonData()[1]; if(quark_->id()<0) swap(quark_,antiquark_); // Now in _our_ calculation we basically define the +z axis as being // given by the direction of the incoming quark for q+qb & q+g processes // and the incoming gluon for g+qbar processes. So now we might need to // flip the values of hadron_A_, hadron_B_, ab_, bb_, xa, xb accordingly: if(ab_->id()!=quark_->id()) { swap(hadron_A_,hadron_B_); swap(ab_,bb_); swap(xa,xb); } // So hadron_A_ is the thing containing a quark (ab_) with momentum frac xa, // hadron_B_ is the thing containing an antiquark (bb_) with momentum frac xb. // Now get the partonic flux for the Born process: lo_lumi_ = hadron_A_->pdf()->xfx(hadron_A_,ab_,scale(),xa)/xa * hadron_B_->pdf()->xfx(hadron_B_,bb_,scale(),xb)/xb; // For W+W- events make sure k1 corresponds to the W+ momentum: if(MEPP2VV::process()==1&&wminus_first) swap(meMomenta()[2],meMomenta()[3]); // Create the object containing all 2->2 __kinematic__ information: B_ = bornVVKinematics(meMomenta(),xa,xb); // We checked that meMomenta()[0] (quark) is in the +z direction and meMomenta()[1] // is in the -z direction (antiquark). // Revert momentum swap in case meMomenta and mePartonData correlation // needs preserving for other things. if(MEPP2VV::process()==1&&wminus_first) swap(meMomenta()[2],meMomenta()[3]); // Check the Born kinematics objects is internally consistent: // B_.sanityCheck(); // If we are going beyond leading order then lets calculate all of // the necessary real emission kinematics. if(contrib_>0) { // Soft limit of the 2->3 real emission kinematics: S_ = realVVKinematics(B_, 1., y, theta2); // Soft-collinear limit of the 2->3 kinematics (emission in +z direction): SCp_ = realVVKinematics(B_, 1., 1., theta2); // Soft-collinear limit of the 2->3 kinematics (emission in -z direction): SCm_ = realVVKinematics(B_, 1.,-1., theta2); // Collinear limit of the 2->3 kinematics (emission in +z direction): Cp_ = realVVKinematics(B_, xt, 1., theta2); // Collinear limit of the 2->3 kinematics (emission in -z direction): Cm_ = realVVKinematics(B_, xt,-1., theta2); // The resolved 2->3 real emission kinematics: H_ = realVVKinematics(B_, xt, y, theta2); // Borrowed from VVhardGenerator (lab momenta of k1,k2): Energy pT(sqrt(H_.pT2_in_lab())); LorentzRotation yzRotation; yzRotation.setRotateX(-atan2(pT/GeV,sqrt(B_.sb())/GeV)); LorentzRotation boostFrompTisZero; boostFrompTisZero.setBoostY(-pT/sqrt(B_.sb()+pT*pT)); LorentzRotation boostFromYisZero; boostFromYisZero.setBoostZ(tanh(B_.Yb())); k1r_perp2_lab_ = (boostFromYisZero*boostFrompTisZero*yzRotation*(H_.k1r())).perp2(); k2r_perp2_lab_ = (boostFromYisZero*boostFrompTisZero*yzRotation*(H_.k2r())).perp2(); // Check all the real kinematics objects are internally consistent: // S_.sanityCheck(); // SCp_.sanityCheck(); // SCm_.sanityCheck(); // Cp_.sanityCheck(); // Cm_.sanityCheck(); // H_.sanityCheck(); } return; } double MEPP2VVPowheg::NLOweight() const { // If only leading order is required return 1: if(contrib_==0) return lo_me()/lo_me2_; // Calculate alpha_S and alpha_S/(2*pi). alphaS_ = nlo_alphaS_opt_==1 ? fixed_alphaS_ : SM().alphaS(mu_UV2()); double alsOn2pi(alphaS_/2./pi); // Particle data objects for the new plus and minus colliding partons. tcPDPtr gluon; gluon = getParticleData(ParticleID::g); // Get the all couplings. gW_ = sqrt(4.0*pi*SM().alphaEM(scale())/SM().sin2ThetaW()); sin2ThetaW_ = SM().sin2ThetaW(); double cosThetaW(sqrt(1.-sin2ThetaW_)); guL_ = gW_/2./cosThetaW*( 1.-4./3.*sin2ThetaW_); gdL_ = gW_/2./cosThetaW*(-1.+2./3.*sin2ThetaW_); guR_ = gW_/2./cosThetaW*( -4./3.*sin2ThetaW_); gdR_ = gW_/2./cosThetaW*( +2./3.*sin2ThetaW_); eZ_ = gW_*cosThetaW; eZ2_ = sqr(eZ_); // MCFM has gwsq = 0.4389585130009 -> gw = 0.662539442600115 // Here we have gW_ = 0.662888 // MCFM has xw = 0.22224653300000 -> sqrt(xw) = 0.471430306 // Here we have 0.222247 // MCFM has esq = 0.097557007645279 -> e = 0.31234117187024679 // Here we have 4.0*pi*SM().alphaEM(sqr(100.*GeV)) = 0.0976596 // If the process is W-Z instead of W+Z we must transform these // couplings as follows, according to NPB 383(1992)3-44 Eq.3.23 if(mePartonData()[2]->id()==-24&&mePartonData()[3]->id()==23) { swap(guL_,gdL_); eZ_ *= -1.; } // Get the CKM entry. Note that this code was debugged // considerably; the call to CKM(particle,particle) // did not appear to work, so we extract the elements // as follows below. The right numbers now appear to // to be associated with the right quarks. double Kij(-999.); // W+Z / W-Z if(abs(mePartonData()[2]->id())==24&&mePartonData()[3]->id()==23) { int up_id(-999),dn_id(-999); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==1) { up_id = abs(quark_->id()); dn_id = abs(antiquark_->id()); } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==0) { up_id = abs(antiquark_->id()); dn_id = abs(quark_->id()); } else { cout << "MEPP2VVPowheg:" << endl; cout << "WZ needs an up and a down type quark as incoming!" << endl; } up_id /= 2; up_id -= 1; dn_id -= 1; dn_id /= 2; Kij = sqrt(SM().CKM(up_id,dn_id)); } // W+W- else if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { int up_ida(abs(quark_->id())/2-1); int up_idb(abs(antiquark_->id())/2-1); Kij = sqrt(std::norm( CKM(up_ida,0)*CKM(up_idb,0) + CKM(up_ida,1)*CKM(up_idb,1) + CKM(up_ida,2)*CKM(up_idb,2))); } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { int dn_ida((abs(quark_->id())-1)/2); int dn_idb((abs(antiquark_->id())-1)/2); Kij = sqrt(std::norm( CKM(0,dn_ida)*CKM(0,dn_idb) + CKM(1,dn_ida)*CKM(1,dn_idb) + CKM(2,dn_ida)*CKM(2,dn_idb))); } else { cout << "MEPP2VVPowheg:" << endl; cout << "WW needs 2 down-type / 2 up-type!" << endl; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { Kij = 2.*sqrt(2.)/gW_; } else { cout << "MEPP2VVPowheg: incompatible final state particles!" << endl; } Fij2_ = sqr(gW_/2./sqrt(2.)*Kij); // Get the leading order matrix element (this is necessary!) M_Born_ = M_Born_WZ(B_); // // Get the regular part of the virtual correction (only needed for sanityCheck()!) // M_V_regular_ = M_V_regular(S_); // // Get the q + qbar real emission matrix element (only needed for sanityCheck()!) // t_u_M_R_qqb_ = t_u_M_R_qqb(H_); // Calculate the integrand double wgt(0.); double wqqb(0.); double wgqb(0.); double wqg(0.); double wqqbvirt(0.); double wqqbcollin(0.); double wqqbreal(0.); double wqgcollin(0.); double wqgreal(0.); double wgqbcollin(0.); double wgqbreal(0.); if(channels_==0||channels_==1) { // q+qb wqqbvirt = Vtilde_universal(S_) + M_V_regular(S_)/lo_me2_; wqqbcollin = alsOn2pi*( Ctilde_Ltilde_qq_on_x(quark_,antiquark_,Cp_) + Ctilde_Ltilde_qq_on_x(quark_,antiquark_,Cm_) ); wqqbreal = alsOn2pi*Rtilde_Ltilde_qqb_on_x(quark_,antiquark_); wqqb = wqqbvirt + wqqbcollin + wqqbreal; } if(channels_==0||channels_==2) { // q+g wqgcollin = alsOn2pi*Ctilde_Ltilde_gq_on_x(quark_,gluon,Cm_); wqgreal = alsOn2pi*Rtilde_Ltilde_qg_on_x(quark_,gluon); wqg = wqgreal + wqgcollin; // g+qb wgqbcollin = alsOn2pi*Ctilde_Ltilde_gq_on_x(gluon,antiquark_,Cp_); wgqbreal = alsOn2pi*Rtilde_Ltilde_gqb_on_x(gluon,antiquark_); wgqb = wgqbreal+wgqbcollin; } // total contribution wgt = 1.+(wqqb+wgqb+wqg); // If restricting to qg, gqb channels then subtract the LO contribution: if(channels_==2) wgt -= 1.; if(!isfinite(wgt)) { cout << "MEPP2VVPowheg:: NLO weight " << "is bad: wgt = " << wgt << endl; cout << "MEPP2VVPowheg sanityCheck invoked!" << endl; cout << ab_->PDGName() << ", " << bb_->PDGName() << ", " << mePartonData()[2]->PDGName() << ", " << mePartonData()[3]->PDGName() << endl; cout << "lo_me2_ - M_Born_ (rel) = " << lo_me2_-M_Born_ << " (" << (lo_me2_-M_Born_)/M_Born_ << ")\n"; cout << "lo_me2_, M_Born_ " << lo_me2_ << ", " << M_Born_ << endl; cout << "xr = " << H_.xr() << " 1-xr = " << 1.-H_.xr() << " y = " << H_.y() << endl; cout << "tkr = " << H_.tkr()/GeV2 << " ukr = " << H_.ukr()/GeV2 << endl; cout << "root(sb) = " << sqrt(B_.sb())/GeV << endl; cout << "sb+tb+ub = " << B_.sb()/GeV2 << " + " << B_.tb()/GeV2 << " + " << B_.ub()/GeV2 << endl; cout << "sqrt(k12) " << sqrt(H_.k12r())/GeV << endl; cout << "sqrt(k22) " << sqrt(H_.k22r())/GeV << endl; cout << "sqr(Kij) " << Kij*Kij << endl; cout << "wqqbvirt " << wqqbvirt << endl; cout << "wqqbcollin " << wqqbcollin << endl; cout << "wqqbreal " << wqqbreal << endl; cout << "wqqb " << wqqb << endl; cout << "wqgcollin " << wqgcollin << endl; cout << "wqgreal " << wqgreal << endl; cout << "wqg " << wqg << endl; cout << "wgqbcollin " << wgqbcollin << endl; cout << "wgqbreal " << wgqbreal << endl; cout << "wgqb " << wgqb << endl; cout << "wgt " << wgt << endl; throw Exception() << "MEPP2VVPowheg:: NLO weight " << "is bad: " << wgt << Exception::eventerror; } return contrib_==1 ? max(0.,wgt) : max(0.,-wgt); } double MEPP2VVPowheg::Lhat_ab(tcPDPtr a, tcPDPtr b, realVVKinematics Kinematics) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Lhat_ab: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double nlo_lumi(-999.); double x1(Kinematics.x1r()),x2(Kinematics.x2r()); nlo_lumi = (hadron_A_->pdf()->xfx(hadron_A_,a,mu_F2(),x1)/x1) * (hadron_B_->pdf()->xfx(hadron_B_,b,mu_F2(),x2)/x2); return nlo_lumi / lo_lumi_; } double MEPP2VVPowheg::Vtilde_universal(realVVKinematics S) const { double xbar_y = S.xbar(); double y = S.y(); double eta1b(S.bornVariables().eta1b()); double eta2b(S.bornVariables().eta2b()); Energy2 sb(S.s2r()); return alphaS_/2./pi*CF_ * ( log(sb/mu_F2()) * (3. + 4.*log(eta1b)+4.*log(eta2b)) + 8.*sqr(log(eta1b)) +8.*sqr(log(eta2b)) - 2.*sqr(pi)/3. ) + alphaS_/2./pi*CF_ * ( 8./(1.+y)*log(sqrt(1.-xbar_y)/eta2b) + 8./(1.-y)*log(sqrt(1.-xbar_y)/eta1b) ); } double MEPP2VVPowheg::Ctilde_Ltilde_qq_on_x(tcPDPtr a, tcPDPtr b, realVVKinematics C) const { if(C.y()!= 1.&&C.y()!=-1.) cout << "\nCtilde_qq::y value not allowed."; if(C.y()== 1.&&!(abs(a->id())>0&&abs(a->id())<7)) cout << "\nCtilde_qq::for Cqq^plus a must be a quark! id = " << a->id() << "\n"; if(C.y()==-1.&&!(abs(b->id())>0&&abs(b->id())<7)) cout << "\nCtilde_qq::for Cqq^minus b must be a quark! id = " << b->id() << "\n"; double xt = C.xt(); double x = C.xr(); double etab = C.y() == 1. ? C.bornVariables().eta1b() : C.bornVariables().eta2b() ; Energy2 sb(C.s2r()); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; return ( ( (1./(1.-xt))*log(sb/mu_F2()/x)+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*CF_*(1.+sqr(x)) + sqr(etab)*CF_*(1.-x) )*Lhat_ab(a,b,C) / x - ( ( (1./(1.-xt))*log(sb/mu_F2() )+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*CF_*2. )*Lhat_ab(a,b,S_); } double MEPP2VVPowheg::Ctilde_Ltilde_gq_on_x(tcPDPtr a, tcPDPtr b, realVVKinematics C) const { if(C.y()!= 1.&&C.y()!=-1.) cout << "\nCtilde_gq::y value not allowed."; if(C.y()== 1.&&a->id()!=21) cout << "\nCtilde_gq::for Cgq^plus a must be a gluon! id = " << a->id() << "\n"; if(C.y()==-1.&&b->id()!=21) cout << "\nCtilde_gq::for Cgq^minus b must be a gluon! id = " << b->id() << "\n"; double xt = C.xt(); double x = C.xr(); double etab = C.y() == 1. ? C.bornVariables().eta1b() : C.bornVariables().eta2b() ; Energy2 sb(C.s2r()); return ( ( (1./(1.-xt))*log(sb/mu_F2()/x)+4.*log(etab)/(1.-xt) + 2.*log(1.-xt)/(1.-xt) )*(1.-x)*TR_*(sqr(x)+sqr(1.-x)) + sqr(etab)*TR_*2.*x*(1.-x) )*Lhat_ab(a,b,C) / x; } double MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_qqb_H (t_u_M_R_qqb(H_ )); Energy2 t_u_M_R_qqb_Cp(t_u_M_R_qqb(Cp_)); Energy2 t_u_M_R_qqb_Cm(t_u_M_R_qqb(Cm_)); // Energy2 t_u_M_R_qqb_H (t_u_M_R_qqb_hel_amp(H_)); // Energy2 t_u_M_R_qqb_Cp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr() // *CF_*(1.+sqr(Cp_.xr()))*lo_me2_); // Energy2 t_u_M_R_qqb_Cm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr() // *CF_*(1.+sqr(Cm_.xr()))*lo_me2_); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_qqb_H = t_u_M_R_qqb_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_qqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_qqb_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } double MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_gqb_H (t_u_M_R_gqb(H_ )); Energy2 t_u_M_R_gqb_Cp(t_u_M_R_gqb(Cp_)); Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb(Cm_)); // Energy2 t_u_M_R_gqb_H (t_u_M_R_gqb_hel_amp(H_)); // Energy2 t_u_M_R_gqb_Cp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr()*(1.-Cp_.xr()) // *TR_*(sqr(Cp_.xr())+sqr(1.-Cp_.xr()))*lo_me2_); // Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb(Cm_)); // // Energy2 t_u_M_R_gqb_Cm(t_u_M_R_gqb_hel_amp(Cm_)); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_gqb_H = t_u_M_R_gqb_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_gqb_H*Lhat_ab(a,b,H_)/s - t_u_M_R_gqb_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_gqb_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } double MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x(tcPDPtr a , tcPDPtr b) const { if(!(abs(a->id())<=6||a->id()==21)||!(abs(b->id())<=6||b->id()==21)) cout << "MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x: Error," << "particle a = " << a->PDGName() << ", " << "particle b = " << b->PDGName() << endl; double xt(H_.xt()); double y(H_.y()); Energy2 s(H_.sr()); Energy2 sCp(Cp_.sr()); Energy2 sCm(Cm_.sr()); Energy2 t_u_M_R_qg_H (t_u_M_R_qg(H_ )); Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg(Cp_)); Energy2 t_u_M_R_qg_Cm(t_u_M_R_qg(Cm_)); // Energy2 t_u_M_R_qg_H (t_u_M_R_qg_hel_amp(H_)); // Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg(Cp_)); // // Energy2 t_u_M_R_qg_Cp(t_u_M_R_qg_hel_amp(Cp_)); // Energy2 t_u_M_R_qg_Cm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr()*(1.-Cm_.xr()) // *TR_*(sqr(Cm_.xr())+sqr(1.-Cm_.xr()))*lo_me2_); int config(0); if(fabs(1.-xt)<=tiny||fabs(1.-H_.xr())<=tiny) return 0.; if(fabs(1.-y )<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cp ; config = 1; } if(fabs(1.+y )<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cm ; config = -1; } if(fabs(H_.tkr()/s)<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cp ; config = 1; } if(fabs(H_.ukr()/s)<=tiny) { t_u_M_R_qg_H = t_u_M_R_qg_Cm ; config = -1; } if(config== 0) return ( ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) + ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) ) / lo_me2_ / 8. / pi / alphaS_; else if(config== 1) return ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cm*Lhat_ab(a,b,Cm_)/sCm) )*2./(1.+y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else if(config==-1) return ( (t_u_M_R_qg_H*Lhat_ab(a,b,H_)/s - t_u_M_R_qg_Cp*Lhat_ab(a,b,Cp_)/sCp) )*2./(1.-y)/(1.-xt) / lo_me2_ / 8. / pi / alphaS_; else throw Exception() << "MEPP2VVPowheg::Rtilde_Ltilde_qg_on_x\n" << "The configuration is not identified as hard / soft / fwd collinear or bwd collinear." << "config = " << config << "\n" << "xt = " << xt << " 1.-xt = " << 1.-xt << "\n" << "y = " << y << " 1.-y = " << 1.-y << "\n" << Exception::eventerror; } /***************************************************************************/ // The following three functions are identically \tilde{I}_{4,t}, // \tilde{I}_{3,WZ} and \tilde{I}_{3,W} given in Eqs. B.8,B.9,B.10 // of NPB 383(1992)3-44, respectively. They are related to / derived // from the loop integrals in Eqs. A.3, A.5 and A.8 of the same paper. InvEnergy4 TildeI4t(Energy2 s, Energy2 t, Energy2 mW2, Energy2 mZ2); InvEnergy2 TildeI3WZ(Energy2 s, Energy2 mW2, Energy2 mZ2, double beta); InvEnergy2 TildeI3W(Energy2 s, Energy2 t, Energy2 mW2); /***************************************************************************/ // The following six functions are identically I_{dd}^{(1)}, I_{ud}^{(1)}, // I_{uu}^{(1)}, F_{u}^{(1)}, F_{d}^{(1)}, H^{(1)} from Eqs. B.4, B.5, B.3, // B.3, B.6, B.7 of NPB 383(1992)3-44, respectively. They make up the // one-loop matrix element. Ixx functions correspond to the graphs // with no TGC, Fx functions are due to non-TGC graphs interfering // with TGC graphs, while the H function is due purely to TGC graphs. double Idd1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); double Iud1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); double Iuu1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy2 Fu1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy2 Fd1(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2,double beta); Energy4 H1 (Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); /***************************************************************************/ // M_V_Regular is the regular part of the one-loop matrix element // exactly as defined in Eqs. B.1 and B.2 of of NPB 383(1992)3-44. double MEPP2VVPowheg::M_V_regular(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mW2(S.k12r()); // N.B. the diboson masses are preserved in getting Energy2 mZ2(S.k22r()); // the 2->2 from the 2->3 kinematics. double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *( 2./3.+2.*eZ*guL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *(-1./3.+2.*eZ*gdL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return 4.*pi*alphaS_*Fij2_*CF_*(1./sqr(4.*pi))/NC_ * ( gdL*gdL*Idd1(s,t,u,mW2,mZ2,beta) + gdL*guL*Iud1(s,t,u,mW2,mZ2,beta) + guL*guL*Iuu1(s,t,u,mW2,mZ2,beta) - eZ/(s-mW2) * ( gdL*Fd1(s,t,u,mW2,mZ2,beta) - guL*Fu1(s,t,u,mW2,mZ2,beta) ) + eZ2/sqr(s-mW2) * H1(s,t,u,mW2,mZ2) ); } /***************************************************************************/ InvEnergy4 TildeI4t(Energy2 s, Energy2 t, Energy2 mW2, Energy2 mZ2) { double sqrBrackets; sqrBrackets = ( sqr(log(-t/mW2))/2.+log(-t/mW2)*log(-t/mZ2)/2. - 2.*log(-t/mW2)*log((mW2-t)/mW2)-2.*ReLi2(t/mW2) ); swap(mW2,mZ2); sqrBrackets+= ( sqr(log(-t/mW2))/2.+log(-t/mW2)*log(-t/mZ2)/2. - 2.*log(-t/mW2)*log((mW2-t)/mW2)-2.*ReLi2(t/mW2) ); swap(mW2,mZ2); return sqrBrackets/s/t; } InvEnergy2 TildeI3WZ(Energy2 s, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double sqrBrackets ; sqrBrackets = ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; sqrBrackets -= ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; swap(mW2,mZ2); del *= -1.; sqrBrackets += ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); swap(mW2,mZ2); del *= -1.; beta *= -1; swap(mW2,mZ2); del *= -1.; sqrBrackets -= ( ReLi2(2.*mW2/(sig-del*(del/s+beta))) + ReLi2((1.-del/s+beta)/2.) + sqr(log((1.-del/s+beta)/2.))/2. + log((1.-del/s-beta)/2.)*log((1.+del/s-beta)/2.) ); beta *= -1; swap(mW2,mZ2); del *= -1.; return sqrBrackets/s/beta; } InvEnergy2 TildeI3W(Energy2 s, Energy2 t, Energy2 mW2) { return 1./(mW2-t)*(sqr(log(mW2/s))/2.-sqr(log(-t/s))/2.-sqr(pi)/2.); } /***************************************************************************/ double Idd1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double Val(0.); Val += 2.*(22.*t*t+t*(19.*s-18.*sig)+18.*mW2*mZ2)/t/t - 8.*(u*t+2*s*sig)/mW2/mZ2 - 2.*sqr(t-u)/t/s/sqr(beta); Val += +( 2.*(8.*t*t+4.*t*(s-3.*sig)+4*sqr(sig)-5.*s*sig+s*s)/t/s/sqr(beta) + 4.*(t*(3.*u+s)-3.*mW2*mZ2)/t/t + 6.*(t+u)*sqr(t-u)/t/s/s/sqr(sqr(beta)) )*log(-t/s); Val += +( ( 8.*t*t*(-2.*s+del)+8.*t*(-s*s+3.*s*sig-2.*del*sig) - 2.*(s-sig)*(s*s-4.*s*sig+3.*del*sig) )/t/s/s/beta/beta + 16.*s*(t-mZ2)/(t*(u+s)-mW2*mZ2) + 2.*(4.*t*t+t*(10.*s-3.*mZ2-9.*mW2)+12.*mW2*mZ2)/t/t -6.*(s-del)*(t+u)*sqr(t-u)/t/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( - ( 4.*t*t*(2.*sig-3.*s) - 4.*t*(s-sig)*(2.*s-3.*sig) - 2.*(s-2.*sig)*sqr(s-sig) )/t/s/beta/beta + ( 4.*sig*t-3.*s*s+4.*s*sig - 4.*(mW2*mW2+mZ2*mZ2) )/t - 3.*sqr(t*t-u*u)/t/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += +( 4.*(t*u+2.*s*sig)/3./mW2/mZ2 - 4.*(t-2.*u)/3./t )*pi*pi; Val += -( 4.*s*(t*u-2.*mW2*mZ2)/t )*TildeI4t(s,t,mW2,mZ2); Val += ( 8.*(t-mW2)*(u*t-2.*mW2*mZ2)/t/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; Val += 2.*(22.*t*t+t*(19.*s-18.*sig)+18.*mW2*mZ2)/t/t - 8.*(u*t+2*s*sig)/mW2/mZ2 - 2.*sqr(t-u)/t/s/sqr(beta); Val += +( 2.*(8.*t*t+4.*t*(s-3.*sig)+4*sqr(sig)-5.*s*sig+s*s)/t/s/sqr(beta) + 4.*(t*(3.*u+s)-3.*mW2*mZ2)/t/t + 6.*(t+u)*sqr(t-u)/t/s/s/sqr(sqr(beta)) )*log(-t/s); Val += +( ( 8.*t*t*(-2.*s+del)+8.*t*(-s*s+3.*s*sig-2.*del*sig) - 2.*(s-sig)*(s*s-4.*s*sig+3.*del*sig) )/t/s/s/beta/beta + 16.*s*(t-mZ2)/(t*(u+s)-mW2*mZ2) + 2.*(4.*t*t+t*(10.*s-3.*mZ2-9.*mW2)+12.*mW2*mZ2)/t/t -6.*(s-del)*(t+u)*sqr(t-u)/t/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( - ( 4.*t*t*(2.*sig-3.*s) - 4.*t*(s-sig)*(2.*s-3.*sig) - 2.*(s-2.*sig)*sqr(s-sig) )/t/s/beta/beta + ( 4.*sig*t-3.*s*s+4.*s*sig - 4.*(mW2*mW2+mZ2*mZ2) )/t - 3.*sqr(t*t-u*u)/t/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += +( 4.*(t*u+2.*s*sig)/3./mW2/mZ2 - 4.*(t-2.*u)/3./t )*pi*pi; Val += -( 4.*s*(t*u-2.*mW2*mZ2)/t )*TildeI4t(s,t,mW2,mZ2); Val += ( 8.*(t-mW2)*(u*t-2.*mW2*mZ2)/t/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ double Iud1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); double Val(0.); Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); swap(mW2,mZ2); del *= -1; Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(mW2,mZ2); del *= -1; swap(t,u); swap(mW2,mZ2); del *= -1; Val += 2.*(4.*t*t+t*(9.*s-4.*sig)-18.*s*sig)/t/u + 8.*(t*u+2.*s*sig)/mW2/mZ2 + 4.*s*s*(2.*t-sig)/u/(mW2*mZ2-t*(u+s)) - 2.*sqr(t-u)/u/s/sqr(beta); Val += ( 2.*(8.*t*t-4.*t*(s+3.*sig)-(s-sig)*(3.*s+4.*sig))/u/s/sqr(beta) + 6.*(t+u)*sqr(t-u)/u/s/s/sqr(sqr(beta)) - 12.*s*(t-sig)/t/u )*log(-t/s); Val += ( (2./u/s/s/sqr(beta))*( 4.*t*t*(-2.*s+del) + 4.*t*(s*s+s*(mZ2+5.*mW2)-2.*sig*del) + (s-sig)*(3.*s*s+8.*mW2*s-3.*sig*del) ) + (2.*t*(18.*s+3.*mW2+mZ2)-24.*s*sig)/t/u - 8.*s*(2.*t*t-t*(3.*s+4.*mZ2+2.*mW2)+2.*mZ2*(s+sig)) /u/(mW2*mZ2-t*(u+s)) - 8.*s*s*t*(2.*t-sig)*(t-mZ2)/u/sqr(mW2*mZ2-t*(u+s)) + 6.*(s-del)*(s-sig)*sqr(t-u)/u/s/s/s/sqr(sqr(beta)) )*log(-t/mW2); Val += ( -2.*(2.*t*t*(2.*sig-3.*s)+6.*sig*t*(s-sig)+sqr(s-sig)*(s+2.*sig)) /u/s/sqr(beta) +3.*s*(4.*t-4.*sig-s)/u -3.*sqr(s-sig)*sqr(t-u)/u/s/s/sqr(sqr(beta)) )*TildeI3WZ(s,mW2,mZ2,beta); Val += ( 4.*(u+4.*s)/3./u - 4.*(u*t+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += -( 16.*s*(t-sig)*(t-mW2)/t/u )*TildeI3W(s,t,mW2); Val += ( 8.*s*s*(t-sig)/u )*TildeI4t(s,t,mW2,mZ2); swap(t,u); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ double Iuu1(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { double Val(Idd1(s,u,t,mW2,mZ2,beta)); return Val; } /***************************************************************************/ Energy2 Fd1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 sig(mZ2+mW2); Energy2 del(mZ2-mW2); Energy2 Val(0.*GeV2); Val += 4.*(17.*t*t+t*(11.*s-13.*sig)+17.*(s*sig+mW2*mZ2))/t + 16.*(s-sig)*(t*u+2.*s*sig)/mW2/mZ2 + 4*s*s*(2.*t-sig)/(t*(u+s)-mW2*mZ2); Val += ( 8.*(t-u)/sqr(beta) - 4.*(3.*t*t-t*(s+3.*sig)+3.*(s*sig+mW2*mZ2))/t )*log(-t/s); Val += ( 8.*(t*t-t*(2.*s+3.*mW2+mZ2)+3.*(s*sig+mW2*mZ2))/t + 8.*s*(t*(3.*s+2.*sig)-2.*mZ2*(s+sig))/(t*(u+s)-mW2*mZ2) + 8.*s*s*t*(2.*t-sig)*(t-mZ2)/sqr(t*(u+s)-mW2*mZ2) - 8.*(s-del)*(t-u)/s/sqr(beta) )*log(-t/mW2); Val += ( 4.*(s-sig)*(t-u)/sqr(beta) + 4.*(sig-3.*s)*t + 4.*(4.*s*sig-mZ2*mZ2-mW2*mW2) )*TildeI3WZ(s,mW2,mZ2,beta); Val += -( 8.*(3.*t*t+2.*t*(2.*s-sig)+2.*(s*sig+mW2*mZ2))/3./t + 8.*(s-sig)*(t*u+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += ( 4.*(s*t*t-s*(s+sig)*t+2.*s*(s*sig+mW2*mZ2)) )*TildeI4t(s,t,mW2,mZ2); Val += -( 8.*(t-mW2)*(t*t-t*(s+sig)+2.*(s*sig+mW2*mZ2))/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; Val += 4.*(17.*t*t+t*(11.*s-13.*sig)+17.*(s*sig+mW2*mZ2))/t + 16.*(s-sig)*(t*u+2.*s*sig)/mW2/mZ2 + 4*s*s*(2.*t-sig)/(t*(u+s)-mW2*mZ2); Val += ( 8.*(t-u)/sqr(beta) - 4.*(3.*t*t-t*(s+3.*sig)+3.*(s*sig+mW2*mZ2))/t )*log(-t/s); Val += ( 8.*(t*t-t*(2.*s+3.*mW2+mZ2)+3.*(s*sig+mW2*mZ2))/t + 8.*s*(t*(3.*s+2.*sig)-2.*mZ2*(s+sig))/(t*(u+s)-mW2*mZ2) + 8.*s*s*t*(2.*t-sig)*(t-mZ2)/sqr(t*(u+s)-mW2*mZ2) - 8.*(s-del)*(t-u)/s/sqr(beta) )*log(-t/mW2); Val += ( 4.*(s-sig)*(t-u)/sqr(beta) + 4.*(sig-3.*s)*t + 4.*(4.*s*sig-mZ2*mZ2-mW2*mW2) )*TildeI3WZ(s,mW2,mZ2,beta); Val += -( 8.*(3.*t*t+2.*t*(2.*s-sig)+2.*(s*sig+mW2*mZ2))/3./t + 8.*(s-sig)*(t*u+2.*s*sig)/3./mW2/mZ2 )*pi*pi; Val += ( 4.*(s*t*t-s*(s+sig)*t+2.*s*(s*sig+mW2*mZ2)) )*TildeI4t(s,t,mW2,mZ2); Val += -( 8.*(t-mW2)*(t*t-t*(s+sig)+2.*(s*sig+mW2*mZ2))/t )*TildeI3W(s,t,mW2); swap(mW2,mZ2); del *= -1; return Val; } /***************************************************************************/ Energy2 Fu1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2, double beta) { Energy2 Val(Fd1(s,u,t,mW2,mZ2,beta)); return Val; } /***************************************************************************/ Energy4 H1 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { Energy2 sig(mZ2+mW2); Energy4 Val(0.*GeV2*GeV2); Val = 8.*t*t+8.*t*(s-sig)+s*s+6.*s*sig+mZ2*mZ2+10.*mW2*mZ2+mW2*mW2 - sqr(s-sig)*(t*u+2.*s*sig)/mW2/mZ2; Val *= ( 16.-8.*pi*pi/3.); return Val; } Energy2 t_u_Rdd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2, Energy2 mW2, Energy2 mZ2); Energy2 t_u_Rud(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2, Energy2 q1h, Energy2 q2h, Energy2 mW2, Energy2 mZ2); Energy2 t_u_Ruu(Energy2 s , Energy2 tk , Energy2 uk, Energy2 q1h, Energy2 q2h, Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZds(Energy2 s ,Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2,Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZda(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2 , Energy2 s2 , Energy2 mW2, Energy2 mZ2); Energy4 t_u_RZu(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1h, Energy2 q2h, Energy2 s2 , Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZs(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZa(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2); Energy6 t_u_RZ(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2 , Energy2 mW2, Energy2 mZ2); /***************************************************************************/ // t_u_M_R_qqb is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); } Energy2 t_u_Rdd(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 mW2, Energy2 mZ2) { Energy2 Val(0.*GeV2); Val += 4.*(q2*(uk+2.*s+q2)+q1*(s+q1))/mW2/mZ2*uk + 16.*(uk+s)/q2*uk - 4.*(2.*uk+4.*s+q2)/mW2*uk - 4.*(2.*uk+5.*s+q2+2.*q1-mW2)/mZ2*uk + 4.*q1*s*(s+q1)/mW2/mZ2 + 16.*s*(s+q2-mZ2-mW2)/q1 - 4.*s*(4.*s+q2+q1)/mW2 + 16.*mW2*mZ2*s/q1/q2 + 4.*s + 16.*mZ2*(tk-2.*mW2)/q1/q2/q2*tk*uk + 16.*(2.*mZ2+mW2-tk)/q1/q2*tk*uk + 16.*mW2*(s-mZ2-mW2)/q1/q2*uk + 16.*mZ2*(q1-2.*mW2)/q2/q2*uk + 32.*mW2*mW2*mZ2/q1/q2/q2*uk + 16.*mW2/q1*uk + 4.*uk + 8./q2*tk*uk + 4.*q1/mW2/mZ2*tk*uk - 24./q1*tk*uk - 4./mW2*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += 4.*(q2*(uk+2.*s+q2)+q1*(s+q1))/mW2/mZ2*uk + 16.*(uk+s)/q2*uk - 4.*(2.*uk+4.*s+q2)/mW2*uk - 4.*(2.*uk+5.*s+q2+2.*q1-mW2)/mZ2*uk + 4.*q1*s*(s+q1)/mW2/mZ2 + 16.*s*(s+q2-mZ2-mW2)/q1 - 4.*s*(4.*s+q2+q1)/mW2 + 16.*mW2*mZ2*s/q1/q2 + 4.*s + 16.*mZ2*(tk-2.*mW2)/q1/q2/q2*tk*uk + 16.*(2.*mZ2+mW2-tk)/q1/q2*tk*uk + 16.*mW2*(s-mZ2-mW2)/q1/q2*uk + 16.*mZ2*(q1-2.*mW2)/q2/q2*uk + 32.*mW2*mW2*mZ2/q1/q2/q2*uk + 16.*mW2/q1*uk + 4.*uk + 8./q2*tk*uk + 4.*q1/mW2/mZ2*tk*uk - 24./q1*tk*uk - 4./mW2*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy2 t_u_Rud(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 q1h,Energy2 q2h,Energy2 mW2, Energy2 mZ2) { Energy2 Val(0.*GeV2); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); swap(q1h,q2h); // Note this swap is done in accordance with MC@NLO. // It is not in NPB 383(1992)3-44 Eq.C.4! Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); swap(q1h,q2h); // Note this swap is done in accordance with MC@NLO. // It is not in NPB 383(1992)3-44 Eq.C.4! swap(tk,uk); swap(q1,q2h); swap(q2,q1h); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(tk,uk); swap(q1,q2h); swap(q2,q1h); swap(mW2,mZ2); swap(q1,q1h); swap(q2,q2h); Val += (uk*s*(uk+3.*s+q1h)+s*s*(s+mZ2)-(s+uk)*(2.*mZ2*s+3.*mW2*s+mW2*q1h) ) * 8./q1/q2h/q2*uk - (uk*(uk+3.*s+q1h-mW2)-(q2+s)*(q2-s)+s*(q2-mW2)+q1h*(q2-mW2)+mW2*q2 ) * 4.*s/mZ2/q1/q2h*uk - 4.*((s+uk+q2h-2.*mZ2)*(s+q1h-mZ2)-mZ2*q1)/mW2/q2*uk + 4.*(2.*s*uk+2.*mW2*uk+5.*s*s+2.*q1h*s-2.*mZ2*s)/q1/q2h*uk + 4.*(2.*s*uk-s*s-2.*q1h*s+2.*mW2*s+2.*mW2*q1h)/q1/q2h/q2*tk*uk + ((2.*uk+s)*(s+q1h)+s*(q2+q2h)+2.*q2*(s+q2h)-q1*s+q1*q2+q1h*q2h ) /mW2/mZ2*uk + 8.*s*(uk-q1h+mZ2)/q1/q2*uk + 4.*s*(-uk+s-q2+q1+q1h)/mZ2/q2h*uk + 4.*s*(-uk-q2+q1h)/mZ2/q1*uk + 8.*(mZ2*uk-s*s+mW2*s-2.*mZ2*q1-2.*mZ2*q1h)/q2h/q2*uk + 2.*(-uk-9.*s-4.*q2-5.*q2h-3.*q1-4.*q1h+8.*mZ2)/mW2*uk + 2.*(-4.*uk+3.*s+5.*q1+4.*q1h)/q2h*uk + 2.*(s*tk+q2*tk+s*s-q2*q2+q1h*q2)/mW2/mZ2*tk - 8.*s*(tk+s+q1h)/mW2/q2*tk + 2.*(-tk+3.*s+q2-q1h)/mW2*tk - 8.*s*s*s/q1h/q2 - 2.*s*q2*(s+q2)/mW2/mZ2 + 2.*s*(2.*s+q2)/mZ2 + 2.*s*(2.*s+q2)/mW2 - 16.*s*s/q1h - 2.*s - 16.*s*s/q1h/q2*tk - 8.*s/q2*tk - 16.*s/q1h*tk + 6.*s/mZ2*tk + 4.*s/q1*uk + 4.*s/mZ2*uk + 12.*uk + 4.*s*(tk+q1h-mW2)/mZ2/q1/q2h*tk*uk + 2.*(s+4.*q1+5.*q1h-4.*mZ2)/q2*uk - 4.*s*s*s/q1h/q1/q2h/q2*tk*uk - 4.*s*s/q1h/q2h/q2*tk*uk - 4.*s*s/q1h/q1/q2*tk*uk + 8.*s*s/mW2/q1h/q2*tk*uk - 4.*s*s/q1h/q1/q2h*tk*uk + 4.*(s+mZ2)/mW2/q2*tk*uk - 4.*s/q1h/q2h*tk*uk - 4.*s/q1h/q1*tk*uk + 12.*s/mW2/q1h*tk*uk - (s+4.*q2)/mW2/mZ2*tk*uk - 4.*(s+2.*mZ2)/q2h/q2*tk*uk - 4.*(3.*s+2.*q1h)/q1/q2*tk*uk - 8.*mW2/q1/q2h*tk*uk + 8./q2h*tk*uk + 8./q1*tk*uk; swap(mW2,mZ2); swap(q1,q1h); swap(q2,q2h); return Val; } Energy2 t_u_Ruu(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1h,Energy2 q2h, Energy2 mW2, Energy2 mZ2) { return t_u_Rdd(s,tk,uk,q1h,q2h,mZ2,mW2); } Energy4 t_u_RZds(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Energy2 sig(mZ2+mW2); Val += ( q1*q2*(5./2.*s*s+5.*s*tk+3.*tk*tk)+(tk*uk*uk+q1*q1*q2)*(tk+s) + q1*(tk*tk*uk+s*uk*uk-s*s*tk+s*s*uk)+q1*q1*q1*(uk+s)-q1*q1*s*s2 ) * 8./q1/q2 - ( tk*tk*(4.*uk+s+q1-2.*q2)+tk*(sqr(q1+q2)-q1*s-3.*q2*s-2.*q1*q1) - q1*s*(4.*s-2.*q1-q2)+tk*uk*(q1+3.*s) ) * 4.*sig/q1/q2 - 4.*sig*sig*(s*(2.*s+q1)+tk*(uk+5./2.*tk+5.*s+q1+q2) )/mW2/mZ2 + 2.*sig*s2*(4.*sqr(s+tk)+tk*(uk+s+4.*q1+2.*q2)+2.*q1*(2.*s+q1) )/mW2/mZ2 + 4.*sig*sig*(s2+s-q1+q2)/q1/q2*tk - 16.*mW2*mZ2*(tk*uk/2.+q2*tk-q1*s)/q1/q2 - 4.*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + sig*sig*sig*(uk+tk)/mW2/mZ2 + 4.*mW2*mZ2*sig*(uk+tk)/q1/q2; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += ( q1*q2*(5./2.*s*s+5.*s*tk+3.*tk*tk)+(tk*uk*uk+q1*q1*q2)*(tk+s) + q1*(tk*tk*uk+s*uk*uk-s*s*tk+s*s*uk)+q1*q1*q1*(uk+s)-q1*q1*s*s2 ) * 8./q1/q2 - ( tk*tk*(4.*uk+s+q1-2.*q2)+tk*(sqr(q1+q2)-q1*s-3.*q2*s-2.*q1*q1) - q1*s*(4.*s-2.*q1-q2)+tk*uk*(q1+3.*s) ) * 4.*sig/q1/q2 - 4.*sig*sig*(s*(2.*s+q1)+tk*(uk+5./2.*tk+5.*s+q1+q2) )/mW2/mZ2 + 2.*sig*s2*(4.*sqr(s+tk)+tk*(uk+s+4.*q1+2.*q2)+2.*q1*(2.*s+q1) )/mW2/mZ2 + 4.*sig*sig*(s2+s-q1+q2)/q1/q2*tk - 16.*mW2*mZ2*(tk*uk/2.+q2*tk-q1*s)/q1/q2 - 4.*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + sig*sig*sig*(uk+tk)/mW2/mZ2 + 4.*mW2*mZ2*sig*(uk+tk)/q1/q2; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy4 t_u_RZda(Energy2 s ,Energy2 tk ,Energy2 uk ,Energy2 q1,Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val += 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); // N.B. Here we subtract! Val -= 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); swap(q1,q2); // N.B. Here we subtract! swap(tk,uk); Val -= 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(q1,q2); swap(tk,uk); swap(mW2,mZ2); // N.B. Here we add! swap(q1,q2); swap(tk,uk); Val += 4.*mZ2*(2.*uk*uk-s*tk+q1*(uk-tk-s+q1+0.5*q2)+q2*(s-3.*q2) ) /q1/q2*tk - 4.*mZ2*mZ2*(q1-tk-2.*s-q2)/q1/q2*tk - 2.*mZ2*(tk+2.*s+2.*q2)/mW2*tk - 2.*s2*(s+2.*q2)/mZ2*tk + 8.*mW2*mZ2*mZ2/q1/q2*tk + 2.*mZ2*mZ2/mW2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy4 t_u_RZd(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1 , Energy2 q2 , Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val = t_u_RZds(s,tk,uk,q1,q2,s2,mW2,mZ2) + t_u_RZda(s,tk,uk,q1,q2,s2,mW2,mZ2); return Val; } Energy4 t_u_RZu(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1h, Energy2 q2h, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy4 Val(0.*GeV2*GeV2); Val = t_u_RZd(s,tk,uk,q1h,q2h,s2,mZ2,mW2); return Val; } Energy6 t_u_RZs(Energy2 s,Energy2 tk,Energy2 uk,Energy2 q1,Energy2 q2, Energy2 s2,Energy2 mW2,Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Energy2 sig(mZ2+mW2); Val += 2.*sig*sig*s2*( tk*(3.*uk+9.*tk+19.*s+6.*q1+4.*q2)+8.*s*s+6.*q1*s + 2.*q1*q1 )/mW2/mZ2 - 2.*sig*sig*sig*(tk*(3.*uk+6.*tk+11.*s+2.*q1+2.*q2)+2.*s*(2.*s+q1)) / mW2/mZ2 - 2.*sig*s2*s2*(tk*(uk+4.*tk+9.*s+6.*q1+2.*q2)+4.*sqr(s+q1)-2.*q1*s) /mW2/mZ2 - 16.*sig*(2.*tk*(uk/2.-tk-s+q1+q2)-s*(3.*s/2.-2.*q1)) + 8.*s2*(s*(s/2.+tk)+4.*q1*(tk+s+q1)) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + 8.*sig*sig*(2.*tk+s/2.) + 2.*sig*sig*sig*sig*tk/mW2/mZ2 + 32.*mW2*mZ2*s; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += 2.*sig*sig*s2*( tk*(3.*uk+9.*tk+19.*s+6.*q1+4.*q2)+8.*s*s+6.*q1*s + 2.*q1*q1 )/mW2/mZ2 - 2.*sig*sig*sig*(tk*(3.*uk+6.*tk+11.*s+2.*q1+2.*q2)+2.*s*(2.*s+q1)) / mW2/mZ2 - 2.*sig*s2*s2*(tk*(uk+4.*tk+9.*s+6.*q1+2.*q2)+4.*sqr(s+q1)-2.*q1*s) /mW2/mZ2 - 16.*sig*(2.*tk*(uk/2.-tk-s+q1+q2)-s*(3.*s/2.-2.*q1)) + 8.*s2*(s*(s/2.+tk)+4.*q1*(tk+s+q1)) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mZ2 + 8.*sig*sig*(2.*tk+s/2.) + 2.*sig*sig*sig*sig*tk/mW2/mZ2 + 32.*mW2*mZ2*s; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy6 t_u_RZa(Energy2 s,Energy2 tk,Energy2 uk,Energy2 q1,Energy2 q2, Energy2 s2,Energy2 mW2,Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Val += - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); Val -= - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val -= - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(q1,q2); swap(tk,uk); swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); Val += - 2.*mZ2*(2.*tk+11.*s+18.*q2)*tk - 2.*mZ2*mZ2*(2.*tk+3.*s+2.*q2)/mW2*tk + 2.*mZ2*s2*(tk+3.*s+4.*q2)/mW2*tk - 2.*s2*s2*(s+2.*q2)/mW2*tk + 2.*mZ2*mZ2*mZ2/mW2*tk + 20.*mZ2*mZ2*tk; swap(mW2,mZ2); swap(q1,q2); swap(tk,uk); return Val; } Energy6 t_u_RZ(Energy2 s , Energy2 tk , Energy2 uk , Energy2 q1, Energy2 q2, Energy2 s2, Energy2 mW2, Energy2 mZ2) { Energy6 Val(0.*GeV2*GeV2*GeV2); Val = t_u_RZs(s,tk,uk,q1,q2,s2,mW2,mZ2) + t_u_RZa(s,tk,uk,q1,q2,s2,mW2,mZ2); return Val; } /***************************************************************************/ // t_u_M_R_qg is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.9 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qg(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); Energy2 w1(R.w1r()); Energy2 w2(R.w2r()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } Energy2 Val(0.*GeV2); swap(s,tk); swap(q2,w2); swap(q2h,w1); Val = -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); swap(s,tk); swap(q2,w2); swap(q2h,w1); Val *= -tk/s * TR_/CF_; return Val; } /***************************************************************************/ // t_u_M_R_gqb is the real emission g + qb -> n + q matrix element // exactly as defined in Eqs. C.9 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_gqb(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); Energy2 w1(R.w1r()); Energy2 w2(R.w2r()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *( 2./3.+2.*eZ*guL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s2-mW2)/Fij2_ * (e2*e2/s2/s2*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s2/(s2-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s2-mW2) * (gW_*gW_*e2/4./s2 *(-1./3.+2.*eZ*gdL/2./e2*s2/(s2-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } Energy2 Val(0.*GeV2); swap(s,uk); swap(q1,w1); swap(q1h,w2); Val = -2.*pi*alphaS_*Fij2_*CF_/NC_ * ( gdL*gdL*t_u_Rdd(s,tk,uk,q1,q2,mW2,mZ2) + 2.*gdL*guL*t_u_Rud(s,tk,uk,q1,q2,q1h,q2h,mW2,mZ2) + guL*guL*t_u_Ruu(s,tk,uk,q1h,q2h,mW2,mZ2) - 2.*eZ/(s2-mW2) * ( gdL * t_u_RZd(s,tk,uk,q1 ,q2 ,s2,mW2,mZ2) - guL * t_u_RZu(s,tk,uk,q1h,q2h,s2,mW2,mZ2) ) + eZ2/sqr(s2-mW2) *t_u_RZ(s,tk,uk,q1,q2,s2,mW2,mZ2) ); swap(s,uk); swap(q1,w1); swap(q1h,w2); Val *= -uk/s * TR_/CF_; return Val; } /***************************************************************************/ // The following six functions are I_{dd}^{(0)}, I_{ud}^{(0)}, // I_{uu}^{(0)}, F_{u}^{(0)}, F_{d}^{(0)}, H^{(0)} from Eqs. 3.9 - 3.14 // They make up the Born matrix element. Ixx functions correspond to the // graphs with no TGC, Fx functions are due to non-TGC graphs interfering // with TGC graphs, while the H function is due purely to TGC graphs. double Idd0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); double Iud0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); double Iuu0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy2 Fu0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy2 Fd0(Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); Energy4 H0 (Energy2 s,Energy2 t,Energy2 u,Energy2 mW2,Energy2 mZ2); /***************************************************************************/ // M_Born_WZ is the Born matrix element exactly as defined in Eqs. 3.3-3.14 // of of NPB 383(1992)3-44 (with a spin*colour averaging factor 1./4./NC_/NC_). double MEPP2VVPowheg::M_Born_WZ(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mW2(B.k12b()); // N.B. the diboson masses are preserved in getting Energy2 mZ2(B.k22b()); // the 2->2 from the 2->3 kinematics. double cosThetaW(sqrt(1.-sin2ThetaW_)); double eZ2(eZ2_); double eZ(eZ_); double gdL(gdL_); double guL(guL_); double gdR(gdR_); double guR(guR_); // W+W- if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { double e2(sqr(gW_)*sin2ThetaW_); if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr( 2./3.+eZ*(guL+guR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(guL-guR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *( 2./3.+2.*eZ*guL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } gdL = gW_/sqrt(2.); guL = 0.; } else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) { // N.B. OLD eZ used to calculate new eZ2 *then* new eZ is set! if(quark_->id()==-antiquark_->id()) { eZ2 = 1./2.*sqr(s-mW2)/Fij2_ * (e2*e2/s/s*(sqr(-1./3.+eZ*(gdL+gdR)/2./e2*s/(s-mW2/sqr(cosThetaW))) +sqr( eZ*(gdL-gdR)/2./e2*s/(s-mW2/sqr(cosThetaW)))) ); eZ = -1./2./Fij2_/(gW_*gW_/4./sqrt(Fij2_))*(s-mW2) * (gW_*gW_*e2/4./s *(-1./3.+2.*eZ*gdL/2./e2*s/(s-mW2/sqr(cosThetaW)))); } else { eZ2 =0.; eZ =0.; } guL = gW_/sqrt(2.); gdL = 0.; } } // ZZ else if(mePartonData()[2]->id()==23&&mePartonData()[3]->id()==23) { eZ = 0.; eZ2 = 0.; double gV2,gA2; gV2 = sqr(guL/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); guL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gdL = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; if(abs(quark_->id())%2==0&&abs(antiquark_->id())%2==0) gdL = guL; else if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) guL = gdL; else { cout << "MEPP2VVPowheg:" << endl; cout << "ZZ needs 2 down-type / 2 up-type!" << endl; } } return Fij2_/2./NC_ * ( gdL*gdL*Idd0(s,t,u,mW2,mZ2) + 2.*gdL*guL*Iud0(s,t,u,mW2,mZ2) + guL*guL*Iuu0(s,t,u,mW2,mZ2) - 2.*eZ/(s-mW2) * ( gdL*Fd0(s,t,u,mW2,mZ2) - guL*Fu0(s,t,u,mW2,mZ2) ) + eZ2/sqr(s-mW2) * H0(s,t,u,mW2,mZ2) ); } /***************************************************************************/ double Idd0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return 8.*((u*t/mW2/mZ2-1.)/4.+s/2.*(mW2+mZ2)/mW2/mZ2) + 8.*(u/t-mW2*mZ2/t/t); } /***************************************************************************/ double Iud0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return - 8.*((u*t/mW2/mZ2-1.)/4.+s/2.*(mW2+mZ2)/mW2/mZ2) + 8.*s/t/u*(mW2+mZ2); } /***************************************************************************/ double Iuu0(Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return Idd0(s,u,t,mW2,mZ2); } /***************************************************************************/ Energy2 Fd0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return - 8.*s*( (u*t/mW2/mZ2-1.)*(1.-(mW2+mZ2)/s-4.*mW2*mZ2/s/t)/4. + (mW2+mZ2)/2./mW2/mZ2*(s-mW2-mZ2+2.*mW2*mZ2/t) ); } /***************************************************************************/ Energy2 Fu0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return Fd0(s,u,t,mW2,mZ2); } /***************************************************************************/ Energy4 H0 (Energy2 s, Energy2 t, Energy2 u, Energy2 mW2, Energy2 mZ2) { return 8.*s*s*(u*t/mW2/mZ2-1.)*( 1./4.-(mW2+mZ2)/2./s + (sqr(mW2+mZ2)+8.*mW2*mZ2)/4./s/s ) + 8.*s*s*(mW2+mZ2)/mW2/mZ2*(s/2.-mW2-mZ2+sqr(mW2-mZ2)/2./s); } /***************************************************************************/ bool MEPP2VVPowheg::sanityCheck() const { bool alarm(false); Energy2 prefacs(8.*pi*alphaS_*S_.sr() /S_.xr() ); Energy2 prefacsp(8.*pi*alphaS_*SCp_.sr() /SCp_.xr() ); Energy2 prefacsm(8.*pi*alphaS_*SCm_.sr() /SCm_.xr() ); Energy2 prefacp(8.*pi*alphaS_*Cp_.sr()/Cp_.xr()); Energy2 prefacm(8.*pi*alphaS_*Cm_.sr()/Cm_.xr()); double xp(Cp_.xr()); double xm(Cm_.xr()); double M_B_WW(M_Born_WW(B_)); double M_B_ZZ(M_Born_ZZ(B_)); double M_V_reg_WW(M_V_regular_WW(S_)); double M_V_reg_ZZ(M_V_regular_ZZ(S_)); Energy2 t_u_qqb_WW(t_u_M_R_qqb_WW(H_)); Energy2 t_u_qqb_ZZ(t_u_M_R_qqb_ZZ(H_)); // Check that the native leading order Herwig matrix // element is equivalent to the WZ leading order matrix // element in NPB 383 (1992) 3-44, with the relevant WZ->WW // WZ->ZZ transformation applied (M_Born_). // if(fabs((lo_me2_ - M_Born_)/M_Born_)>1.e-2) { // alarm=true; // cout << "lo_me2_ - M_Born_ (%) = " // << lo_me2_ - M_Born_ << " (" // << (lo_me2_ - M_Born_)/M_Born_*100. << ")\n"; // } // Check that the transformation from NPB 383 (1992) 3-44 WZ // matrix elements to WW matrix elements actually works, by // comparing them to the explicit WW matrix elements in // NPB 410 (1993) 280-324. if(abs(mePartonData()[2]->id())==24&&abs(mePartonData()[3]->id())==24) { if(fabs((M_Born_ -M_B_WW )/M_B_WW )>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "M_Born_ - M_B_WW (rel) = " << M_Born_ - M_B_WW << " (" << (M_Born_ - M_B_WW)/M_B_WW << ")\n"; cout << "M_Born_ = " << M_Born_ << endl; cout << "M_B_WW = " << M_B_WW << endl; } if(fabs((M_V_regular_-M_V_reg_WW)/M_V_reg_WW)>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "M_V_regular_ - M_V_reg_WW (rel) = " << M_V_regular_ - M_V_reg_WW << " (" << (M_V_regular_ - M_V_reg_WW)/M_V_reg_WW << ")\n"; cout << "M_V_regular_ = " << M_V_regular_ << endl; cout << "M_V_reg_WW = " << M_V_reg_WW << endl; } if(fabs((t_u_M_R_qqb_-t_u_qqb_WW)/t_u_qqb_WW)>1.e-6) { alarm=true; cout << "WZ->WW transformation error!\n"; cout << "t_u_M_R_qqb_ - t_u_qqb_WW (rel) = " << (t_u_M_R_qqb_ - t_u_qqb_WW)/GeV2 << " (" << (t_u_M_R_qqb_ - t_u_qqb_WW)/t_u_qqb_WW << ")\n"; cout << "t_u_M_R_qqb_ = " << t_u_M_R_qqb_/GeV2 << endl; cout << "t_u_qqb_WW = " << t_u_qqb_WW /GeV2 << endl; } } // Check that the transformation from NPB 383 (1992) 3-44 WZ // matrix elements to ZZ matrix elements actually works, by // comparing them to the explicit ZZ matrix elements in // NPB 357 (1991) 409-438. if(abs(mePartonData()[2]->id())==23&&abs(mePartonData()[3]->id())==23) { if(fabs((M_Born_ -M_B_ZZ )/M_B_ZZ )>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "M_Born_ - M_B_ZZ (rel) = " << M_Born_ - M_B_ZZ << " (" << (M_Born_ - M_B_ZZ)/M_B_ZZ << ")\n"; cout << "M_Born_ = " << M_Born_ << endl; cout << "M_B_ZZ = " << M_B_ZZ << endl; } if(fabs((M_V_regular_-M_V_reg_ZZ)/M_V_reg_ZZ)>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "M_V_regular_ - M_V_reg_ZZ (rel) = " << M_V_regular_ - M_V_reg_ZZ << " (" << (M_V_regular_ - M_V_reg_ZZ)/M_V_reg_ZZ << ")\n"; cout << "M_V_regular_ = " << M_V_regular_ << endl; cout << "M_V_reg_ZZ = " << M_V_reg_ZZ << endl; } if(fabs((t_u_M_R_qqb_-t_u_qqb_ZZ)/t_u_qqb_ZZ)>1.e-6) { alarm=true; cout << "WZ->ZZ transformation error!\n"; cout << "t_u_M_R_qqb_ - t_u_qqb_ZZ (rel) = " << (t_u_M_R_qqb_ - t_u_qqb_ZZ)/GeV2 << " (" << (t_u_M_R_qqb_ - t_u_qqb_ZZ)/t_u_qqb_ZZ << ")\n"; cout << "t_u_M_R_qqb_ = " << t_u_M_R_qqb_/GeV2 << endl; cout << "t_u_qqb_ZZ = " << t_u_qqb_ZZ /GeV2 << endl; } } // Check the soft limit of the q + qbar matrix element. Energy2 absDiff_qqbs = t_u_M_R_qqb(S_) - prefacs*2.*CF_*M_Born_; double relDiff_qqbs = absDiff_qqbs / t_u_M_R_qqb(S_); if(fabs(relDiff_qqbs)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(S_) " << t_u_M_R_qqb(S_) /GeV2 << endl; cout << "t_u_M_R_qqb(S_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbs / GeV2 << " (" << relDiff_qqbs << ")\n"; } // Check the positive soft-collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbsp = t_u_M_R_qqb(SCp_) - prefacsp*2.*CF_*M_Born_; double relDiff_qqbsp = absDiff_qqbsp / t_u_M_R_qqb(SCp_); if(fabs(relDiff_qqbsp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(SCp_) " << t_u_M_R_qqb(SCp_)/GeV2 << endl; cout << "t_u_M_R_qqb(SCp_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbsp / GeV2 << " (" << relDiff_qqbsp << ")\n"; } // Check the negative soft-collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbsm = t_u_M_R_qqb(SCm_) - prefacsm*2.*CF_*M_Born_; double relDiff_qqbsm = absDiff_qqbsm / t_u_M_R_qqb(SCm_); if(fabs(relDiff_qqbsm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(SCm_) " << t_u_M_R_qqb(SCm_)/GeV2 << endl; cout << "t_u_M_R_qqb(SCm_)-8*pi*alphaS*sHat/x*2*Cab*M_Born_ (rel):\n" << absDiff_qqbsm / GeV2 << " (" << relDiff_qqbsm << ")\n"; } // Check the positive collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbp = t_u_M_R_qqb(Cp_) - prefacp*CF_*(1.+xp*xp)*M_Born_; double relDiff_qqbp = absDiff_qqbp / t_u_M_R_qqb(Cp_); if(fabs(relDiff_qqbp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(Cp_) " << t_u_M_R_qqb(Cp_) /GeV2 << endl; cout << "t_u_M_R_qqb(Cp_)-8*pi*alphaS*sHat/x*(1-x)*Pqq*M_Born_ (rel):\n" << absDiff_qqbp / GeV2 << " (" << relDiff_qqbp << ")\n"; } // Check the negative collinearlimit of the q + qbar matrix element. Energy2 absDiff_qqbm = t_u_M_R_qqb(Cm_) - prefacm*CF_*(1.+xm*xm)*M_Born_; double relDiff_qqbm = absDiff_qqbm / t_u_M_R_qqb(Cm_); if(fabs(relDiff_qqbm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qqb(Cm_) " << t_u_M_R_qqb(Cm_) /GeV2 << endl; cout << "t_u_M_R_qqb(Cm_)-8*pi*alphaS*sHat/x*(1-x)*Pqq*M_Born_ (rel):\n" << absDiff_qqbm / GeV2 << " (" << relDiff_qqbm << ")\n"; } // Check the positive collinear limit of the g + qbar matrix element. Energy2 absDiff_gqbp = t_u_M_R_gqb(Cp_) - prefacp*(1.-xp)*TR_*(xp*xp+sqr(1.-xp))*M_Born_; double relDiff_gqbp = absDiff_gqbp/ t_u_M_R_gqb(Cp_); if(fabs(relDiff_gqbp)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_gqb(Cp_) " << t_u_M_R_gqb(Cp_) /GeV2 << endl; cout << "t_u_M_R_gqb(Cp_)-8*pi*alphaS*sHat/x*(1-x)*Pgq*M_Born_ (rel):\n" << absDiff_gqbp / GeV2 << " (" << relDiff_gqbp << ")\n"; } // Check the negative collinear limit of the q + g matrix element. Energy2 absDiff_qgm = t_u_M_R_qg(Cm_) - prefacm*(1.-xm)*TR_*(xm*xm+sqr(1.-xm))*M_Born_; double relDiff_qgm = absDiff_qgm / t_u_M_R_qg(Cm_); if(fabs(relDiff_qgm)>1.e-6) { alarm=true; cout << "\n"; cout << "t_u_M_R_qg(Cm_) " << t_u_M_R_qg(Cm_) /GeV2 << endl; cout << "t_u_M_R_qg(Cm_)-8*pi*alphaS*sHat/x*(1-x)*Pgq*M_Born_ (rel):\n" << absDiff_qgm / GeV2 << " (" << relDiff_qgm << ")\n"; } return alarm; } /***************************************************************************/ // M_Born_ZZ is the Born matrix element exactly as defined in Eqs. 2.18-2.19 // of of NPB 357(1991)409-438. double MEPP2VVPowheg::M_Born_ZZ(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mZ2(B.k22b()); // the 2->2 from the 2->3 kinematics. double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; return 1./NC_*sqr(gZ*2.)*(t/u+u/t+4.*mZ2*s/t/u-mZ2*mZ2*(1./t/t+1./u/u)); } /***************************************************************************/ // M_V_regular_ZZ is the one-loop ZZ matrix element exactly as defined in // Eqs. B.1 & B.2 of NPB 357(1991)409-438. double MEPP2VVPowheg::M_V_regular_ZZ(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mZ2(S.k22r()); // the 2->2 from the 2->3 kinematics. double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; double M_V_reg(0.); M_V_reg = 2.*s*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/sqr(4.*pi)/2. *( 2.*sqr(t+mZ2)/sqr(beta)/s/t/u + 4.*s/(t-mZ2)/u - ( 16.*t*t*t+(28.*s-68.*mZ2)*t*t+(18.*s*s-36.*mZ2*s+88.*mZ2*mZ2)*t + 18.*mZ2*mZ2*s-36.*mZ2*mZ2*mZ2 )/t/t/s/u + ( 12.*s/(t-mZ2)/u-4.*mZ2*s/sqr(t-mZ2)/u+2.*(t+4.*s)/s/u - 6.*(s*s+mZ2*mZ2)/s/t/u+6.*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u )*log(-t/mZ2) + ( - ( 5.*t*t*t+(8.*s-18.*mZ2)*t*t+(6.*s*s+25.*mZ2*mZ2)*t + 6.*mZ2*mZ2*s-12.*mZ2*mZ2*mZ2 )/t/t/s/u - 12.*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u + ( 3.*t*t-26.*mZ2*t-25.*mZ2*mZ2)/sqr(beta)/s/t/u )*log(s/mZ2) + ( (-2.*t*t+8.*mZ2*t-2.*s*s-12.*mZ2*mZ2)/u + 4.*mZ2*mZ2*(2.*mZ2-s)/t/u) / (s*t) * ( 2.*sqr(log(-t/mZ2))-4.*log(-t/mZ2)*log((mZ2-t)/mZ2)-4.*ReLi2(t/mZ2)) + ( 4.*(t*t-5.*mZ2*t+s*s+10.*mZ2*mZ2)/s/u + 4.*mZ2*(-s*s+2.*mZ2*s-10.*mZ2*mZ2)/s/t/u + 8.*mZ2*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u ) / (t-mZ2) * (pi*pi/2.+log(-t/mZ2)*log(-t/s)-1./2.*sqr(log(-t/mZ2))) + ( ( (2.*s-3.*mZ2)*t*t+(6.*mZ2*mZ2-8.*mZ2*s)*t+2.*s*s*s-4.*mZ2*s*s + 12.*mZ2*mZ2*s-3.*mZ2*mZ2*mZ2 ) /s/t/u + 12.*mZ2*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u - (mZ2*t*t-30.*mZ2*mZ2*t-27.*mZ2*mZ2*mZ2)/beta/beta/s/t/u ) / (beta*s) * (pi*pi/3.+sqr(log((1.-beta)/(1.+beta)))+4.*ReLi2(-(1.-beta)/(1.+beta))) + (4.*(t+4.*s-4.*mZ2)/3./s/u+4.*sqr(s-2.*mZ2)/3./s/t/u)*pi*pi ); swap(t,u); M_V_reg += 2.*s*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/sqr(4.*pi)/2. *( 2.*sqr(t+mZ2)/sqr(beta)/s/t/u + 4.*s/(t-mZ2)/u - ( 16.*t*t*t+(28.*s-68.*mZ2)*t*t+(18.*s*s-36.*mZ2*s+88.*mZ2*mZ2)*t + 18.*mZ2*mZ2*s-36.*mZ2*mZ2*mZ2 )/t/t/s/u + ( 12.*s/(t-mZ2)/u-4.*mZ2*s/sqr(t-mZ2)/u+2.*(t+4.*s)/s/u - 6.*(s*s+mZ2*mZ2)/s/t/u+6.*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u )*log(-t/mZ2) + ( - ( 5.*t*t*t+(8.*s-18.*mZ2)*t*t+(6.*s*s+25.*mZ2*mZ2)*t + 6.*mZ2*mZ2*s-12.*mZ2*mZ2*mZ2 )/t/t/s/u - 12.*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u + ( 3.*t*t-26.*mZ2*t-25.*mZ2*mZ2)/sqr(beta)/s/t/u )*log(s/mZ2) + ( (-2.*t*t+8.*mZ2*t-2.*s*s-12.*mZ2*mZ2)/u + 4.*mZ2*mZ2*(2.*mZ2-s)/t/u) / (s*t) * ( 2.*sqr(log(-t/mZ2))-4.*log(-t/mZ2)*log((mZ2-t)/mZ2)-4.*ReLi2(t/mZ2)) + ( 4.*(t*t-5.*mZ2*t+s*s+10.*mZ2*mZ2)/s/u + 4.*mZ2*(-s*s+2.*mZ2*s-10.*mZ2*mZ2)/s/t/u + 8.*mZ2*mZ2*mZ2*(2.*mZ2-s)/t/t/s/u ) / (t-mZ2) * (pi*pi/2.+log(-t/mZ2)*log(-t/s)-1./2.*sqr(log(-t/mZ2))) + ( ( (2.*s-3.*mZ2)*t*t+(6.*mZ2*mZ2-8.*mZ2*s)*t+2.*s*s*s-4.*mZ2*s*s + 12.*mZ2*mZ2*s-3.*mZ2*mZ2*mZ2 ) /s/t/u + 12.*mZ2*mZ2*sqr(t+mZ2)/sqr(sqr(beta))/s/s/t/u - (mZ2*t*t-30.*mZ2*mZ2*t-27.*mZ2*mZ2*mZ2)/beta/beta/s/t/u ) / (beta*s) * (pi*pi/3.+sqr(log((1.-beta)/(1.+beta)))+4.*ReLi2(-(1.-beta)/(1.+beta))) + (4.*(t+4.*s-4.*mZ2)/3./s/u+4.*sqr(s-2.*mZ2)/3./s/t/u)*pi*pi ); return M_V_reg; } /***************************************************************************/ // t_u_M_R_qqb_ZZ is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 357(1991)409-438, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_ZZ(realVVKinematics R) const { // First the Born variables: Energy2 mZ2(R.k22r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); double cosThetaW(sqrt(1.-sin2ThetaW_)); double gV2,gA2,gX,gY,gZ; gV2 = sqr(guL_/2.-gW_/2./cosThetaW*2./3.*sin2ThetaW_); gA2 = sqr(guL_/2.+gW_/2./cosThetaW*2./3.*sin2ThetaW_); gX = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gV2 = sqr(gdL_/2.+gW_/2./cosThetaW*1./3.*sin2ThetaW_); gA2 = sqr(gdL_/2.-gW_/2./cosThetaW*1./3.*sin2ThetaW_); gY = sqrt(gV2*gV2+gA2*gA2+6.*gA2*gV2)/2.; gZ = gX; if(abs(quark_->id())%2==1&&abs(antiquark_->id())%2==1) gZ = gY; Energy2 t_u_qqb(0.*GeV2); t_u_qqb = (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2 ); swap(q1h,q2h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2 ); swap(q1h,q2h); swap(q1 ,q1h); swap(q2 ,q2h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(q1 ,q1h); swap(q2 ,q2h); swap(tk ,uk ); swap(q1 ,q2h); swap(q2 ,q1h); t_u_qqb += (2.*s)*sqr(gZ*2.)*4.*pi*alphaS_*CF_/NC_/2. * ( - ( tk*uk*uk+2.*s*uk*uk-tk*tk*uk - 2.*s*tk*uk+mZ2*(tk*tk-uk*uk+2.*s*uk-2.*s*tk-2.*s*s) )/q1h/q1/q2h/s*tk + 2.*(tk*uk*uk-mZ2*uk*(s+3.*tk)+mZ2*mZ2*(2.*uk-s))/q1/q2/s + ( tk*uk*(uk+s)-mZ2*(uk*uk+3.*tk*uk+3.*s*uk+s*tk) + 2.*mZ2*mZ2*(uk+tk+2.*s) )/q1h/q1/q2/s*tk + ( tk*(uk*uk+tk*uk-s*s)+mZ2*(4.*s*uk-3.*tk*uk-tk*tk+4.*s*s) )/q1h/q2/s - ( tk*uk+s*uk-s*tk-s*s+2.*mZ2*(s-tk) ) /q1h/q1/s*tk + q2*(tk*uk-s*uk-2.*s*tk-2.*s*s)/q1/q2h/s + 2.*(tk*uk-tk*tk-s*tk-s*s+mZ2*(2.*s-uk))/q1/s - 2.*mZ2*(uk*uk-2.*mZ2*uk+2.*mZ2*mZ2)/q1/q1/q2/s*tk + (2.*s*uk+tk*tk+3.*s*tk+2*s*s)/q1h/s + q1*(uk+s)*(uk+tk)/q1h/q2h/s + (tk*uk+s*uk+3.*s*tk+2.*s*s-mZ2*(uk+tk+2.*s))/q1h/q2h/s*uk + (uk-tk)/2./q1h/q2h/s*(q1*(uk+s)/q2/tk-q2*(tk+s)/q1/uk)*tk*uk + (tk-2.*mZ2)*(uk-2.*mZ2)/q1h/q1/q2h/q2*tk*uk - (q1*q1+q2*q2)/q1/q2 - 2.*mZ2*(q2-2.*mZ2)/q1/q1/s*tk ); swap(tk ,uk ); swap(q1 ,q2h); swap(q2 ,q1h); return t_u_qqb; } /***************************************************************************/ // M_B_WW is the Born matrix element exactly as defined in Eqs. 3.2-3.8 // of of NPB 410(1993)280-384. double MEPP2VVPowheg::M_Born_WW(bornVVKinematics B) const { Energy2 s(B.sb()); Energy2 t(B.tb()); Energy2 u(B.ub()); Energy2 mW2(B.k12b()); // N.B. the diboson masses are preserved in getting bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3. ; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s *(Qi+2.*eZ_*giL/e2*s/(s-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s/s*(sqr(Qi+eZ_*(giL+giR)/e2*s/(s-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s/(s-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) swap(t,u); double signf = up_type ? 1. : -1.; return 1./4./NC_ * ( ctt_i*( 16.*(u*t/mW2/mW2-1.)*(1./4.+mW2*mW2/t/t)+16.*s/mW2) - cts_i*( 16.*(u*t/mW2/mW2-1.)*(s/4.-mW2/2.-mW2*mW2/t) + 16.*s*(s/mW2-2.+2.*mW2/t) ) *signf + css_i*( 8.*(u*t/mW2/mW2-1.)*(s*s/4.-s*mW2+3.*mW2*mW2) + 8.*s*s*(s/mW2-4.) ) ); } /***************************************************************************/ // M_V_regular_WW is the regular part of the one-loop WW matrix element // exactly as defined in Eqs. C.1 - C.7 of of NPB 410(1993)280-324 *** // modulo a factor 1/(2s) ***, which is a flux factor that those authors // absorb in the matrix element. double MEPP2VVPowheg::M_V_regular_WW(realVVKinematics S) const { Energy2 s(S.bornVariables().sb()); Energy2 t(S.bornVariables().tb()); Energy2 u(S.bornVariables().ub()); Energy2 mW2(S.k12r()); // N.B. the diboson masses are preserved in getting double beta(S.betaxr()); // N.B. for x=1 \beta_x=\beta in NPB 383(1992)3-44. bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3.; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s *(Qi+2.*eZ_*giL/e2*s/(s-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s/s*(sqr(Qi+eZ_*(giL+giR)/e2*s/(s-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s/(s-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) swap(t,u); double signf = up_type ? 1. : -1.; InvEnergy4 TildeI4 = ( 2.*sqr(log(-t/mW2))-4.*log((mW2-t)/mW2)*log(-t/mW2) - 4.*ReLi2(t/mW2) )/s/t; InvEnergy2 TildeI3t = 1./(mW2-t) *(sqr(log(mW2/s))/2.-sqr(log(-t/s))/2.-pi*pi/2.); InvEnergy2 TildeI3l = 1./s/beta*( 4.*ReLi2((beta-1.)/(beta+1.)) + sqr(log((1.-beta)/(1.+beta))) + pi*pi/3.); double Fup1_st(0.); Fup1_st = 4.*(80.*t*t+73.*s*t-140.*mW2*t+72.*mW2*mW2)/t/t - 4.*sqr(4.*t+s)/s/beta/beta/t - 128.*(t+2.*s)/mW2 + 64.*t*(t+s)/mW2/mW2 - (32.*(t*t-3.*s*t-3.*mW2*mW2)/t/t+128.*s/(t-mW2))*log(-t/mW2) + ( 8.*(6.*t*t+8.*s*t-19.*mW2*t+12.*mW2*mW2)/t/t - (32.*t*t-128.*s*t-26.*s*s)/s/beta/beta/t + 6.*sqr(4.*t+s)/s/sqr(sqr(beta))/t )*log(s/mW2) + 32.*s*(2.*mW2*mW2/t-u)*TildeI4 - 64.*(t-mW2)*(2.*mW2*mW2/t/t-u/t)*TildeI3t + ( (16.*t*(4.*mW2-u)-49.*s*s+72.*mW2*s-48.*mW2*mW2)/2./t + 2.*(8.*t*t-14.*s*t-3.*s*s)/beta/beta/t - 3.*sqr(4.*t+s)/2./sqr(sqr(beta))/t )*TildeI3l + 32./3.*( 2.*(t+2.*s)/mW2 - (3.*t+2.*s-4.*mW2)/t - t*(t+s)/mW2/mW2 )*pi*pi; Energy2 Jup1_st(0.*GeV2); Jup1_st = -128.*(t*t+2.*s*t+2.*s*s)/mW2 - 16.*(t*t-21.*s*t-26.*mW2*t+34.*mW2*s+17.*mW2*mW2)/t + 64.*s*t*(t+s)/mW2/mW2 +32.*s*s/(t-mW2) + ( 16.*(t-5.*s+2.*mW2)-48.*mW2*(2.*s+mW2)/t + 64.*s*(2.*t+s)/(t-mW2) - 32.*s*s*t/sqr(t-mW2) )*log(-t/mW2) + ( 16.*(4.*t+s)/beta/beta - 16.*(3.*t-2.*s) + 48.*mW2*(2.*t-2.*s-mW2)/t )*log(s/mW2) + 16.*s*(t*(2.*s+u)-2.*mW2*(2.*s+mW2))*TildeI4 + 32.*(t-mW2)*(2.*mW2*(2.*s+mW2)/t-2.*s-u)*TildeI3t + ( 32.*s*t-12.*s*s+32.*mW2*mW2 - 16.*mW2*(2.*t+7.*s)-4.*s*(4.*t+s)/beta/beta )*TildeI3l + 32./3.*( 2.*(t*t+2.*s*t+2.*s*s)/mW2 - s*t*(t+s)/mW2/mW2-2.*mW2*(2.*t-2.*s-mW2)/t-t-4.*s )*pi*pi; Energy4 Kup1_st(0.*GeV2*GeV2); Kup1_st = 16.*( 12.*t*t+20.*s*t-24.*mW2*t+17.*s*s-4.*mW2*s+12.*mW2*mW2 + s*s*t*(t+s)/mW2/mW2-2.*s*(2.*t*t+3.*s*t+2.*s*s)/mW2) *(2.-pi*pi/3.); return pi*alphaS_*CF_/NC_/(sqr(4.*pi)) * ( ctt_i*Fup1_st - cts_i*Jup1_st*signf + css_i*Kup1_st ); } /***************************************************************************/ // t_u_M_R_qqb is the real emission q + qb -> n + g matrix element // exactly as defined in Eqs. C.1 of NPB 383(1992)3-44, multiplied by // tk * uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_WW(realVVKinematics R) const { // First the Born variables: Energy2 s2(R.s2r()); Energy2 mW2(R.k12r()); // Then the rest: Energy2 s(R.sr()); Energy2 tk(R.tkr()); Energy2 uk(R.ukr()); Energy2 q1(R.q1r()); Energy2 q2(R.q2r()); Energy2 q1h(R.q1hatr()); Energy2 q2h(R.q2hatr()); bool up_type = abs(quark_->id())%2==0 ? true : false; double Qi = up_type ? 2./3. : -1./3.; double giL = up_type ? guL_/2. : gdL_/2.; double giR = up_type ? guR_/2. : gdR_/2.; double e2 = sqr(gW_)*sin2ThetaW_; double cos2ThetaW(1.-sin2ThetaW_); double ctt_i(gW_*gW_*gW_*gW_/16.); InvEnergy2 cts_i(gW_*gW_*e2/4./s2*(Qi+2.*eZ_*giL/e2*s2/(s2-mW2/cos2ThetaW))); InvEnergy4 css_i(e2*e2/s2/s2*(sqr(Qi+eZ_*(giL+giR)/e2*s2/(s2-mW2/cos2ThetaW)) +sqr( eZ_*(giL-giR)/e2*s2/(s2-mW2/cos2ThetaW))) ); ctt_i *= 8.*Fij2_/gW_/gW_; cts_i *= sqrt(8.*Fij2_/gW_/gW_); if(quark_->id()!=-antiquark_->id()) { cts_i = 0./GeV2; css_i = 0./GeV2/GeV2; } if(!up_type) { swap(q1,q1h); swap(q2,q2h); } double signf = up_type ? 1. : -1.; Energy2 t_u_Xup(0.*GeV2); Energy4 t_u_Yup(0.*GeV2*GeV2); Energy6 t_u_Zup(0.*GeV2*GeV2*GeV2); t_u_Xup = 32.*mW2*(tk*uk+3.*q2*uk+q2*s+q1*q2)/q1/q2/q2*tk + 32.*mW2*q1/q2/q2*uk - 64.*mW2*s/q2 - 32.*tk*(uk-q2)/q1/q2*tk + 64.*mW2*mW2*mW2/q1/q1/q2*tk - 16.*(2.*tk-2.*s-q2)/q2*uk + 16.*s*(2.*s+2.*q1+q2/2.)/q2 - 8.*(4.*tk+uk+9.*s+2.*q2+2.*q1)/mW2*tk - 16.*s*(2.*s+q1)/mW2 - 64.*mW2*mW2*(tk*uk+q2*tk+q1*uk-q2*s/2.)/q1/q2/q2 + 8.*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Xup += 32.*mW2*(tk*uk+3.*q2*uk+q2*s+q1*q2)/q1/q2/q2*tk + 32.*mW2*q1/q2/q2*uk - 64.*mW2*s/q2 - 32.*tk*(uk-q2)/q1/q2*tk + 64.*mW2*mW2*mW2/q1/q1/q2*tk - 16.*(2.*tk-2.*s-q2)/q2*uk + 16.*s*(2.*s+2.*q1+q2/2.)/q2 - 8.*(4.*tk+uk+9.*s+2.*q2+2.*q1)/mW2*tk - 16.*s*(2.*s+q1)/mW2 - 64.*mW2*mW2*(tk*uk+q2*tk+q1*uk-q2*s/2.)/q1/q2/q2 + 8.*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Yup = - 16.*tk*(uk*(uk+s+q1)+q2*(s-2.*q1))/q1/q2*tk - 32.*mW2*mW2*s/q2 - 32.*mW2*mW2*mW2/q1/q2*tk + 16.*(2.*q2*uk+s*s+q1*s+5.*q2*s+q1*q2+2.*q2*q2)/q2*tk - 16.*(q2*q2+s*s-q2*s)/q1*tk + 16.*s*(q1*s+3./2.*q2*s+q1*q2-q1*q1)/q2 + 16.*mW2*tk*(4.*uk+s+q1-2.*q2)/q1/q2*tk + 16.*mW2*(3.*s*uk+q1*uk-q1*s-3.*q2*s-q1*q1+q2*q2)/q1/q2*tk + 16.*mW2*s*(q2-4.*s+2.*q1)/q2 - 8.*s2*(4.*tk+uk+9.*s+4.*q1+2.*q2)/mW2*tk - 16.*s2*(2.*s*s+2.*q1*s+q1*q1)/mW2 - 32.*mW2*mW2*(tk+uk/2.+2.*s-q1)/q1/q2*tk + 8.*s2*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Yup += - 16.*tk*(uk*(uk+s+q1)+q2*(s-2.*q1))/q1/q2*tk - 32.*mW2*mW2*s/q2 - 32.*mW2*mW2*mW2/q1/q2*tk + 16.*(2.*q2*uk+s*s+q1*s+5.*q2*s+q1*q2+2.*q2*q2)/q2*tk - 16.*(q2*q2+s*s-q2*s)/q1*tk + 16.*s*(q1*s+3./2.*q2*s+q1*q2-q1*q1)/q2 + 16.*mW2*tk*(4.*uk+s+q1-2.*q2)/q1/q2*tk + 16.*mW2*(3.*s*uk+q1*uk-q1*s-3.*q2*s-q1*q1+q2*q2)/q1/q2*tk + 16.*mW2*s*(q2-4.*s+2.*q1)/q2 - 8.*s2*(4.*tk+uk+9.*s+4.*q1+2.*q2)/mW2*tk - 16.*s2*(2.*s*s+2.*q1*s+q1*q1)/mW2 - 32.*mW2*mW2*(tk+uk/2.+2.*s-q1)/q1/q2*tk + 8.*s2*s2*q1*(tk+s+q1)/mW2/mW2; swap(tk,uk); swap(q1,q2); t_u_Zup = 8.*s2*(9.*tk+3.*uk+20.*s+10.*q1+4.*q2)*tk + 8.*s2*(17./2.*s*s+10.*q1*s+6.*q1*q1) - 4.*s2*s2*(4.*tk+uk+9.*s+6.*q1+2.*q2)/mW2*tk - 8.*s2*s2*(2.*s*s+3.*q1*s+2.*q1*q1)/mW2 - 16.*mW2*(2.*tk+5.*uk+7.*s+6.*q1+6.*q2)*tk - 16.*mW2*s*(s+6.*q1) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mW2 + 48.*mW2*mW2*s2; swap(tk,uk); swap(q1,q2); t_u_Zup += 8.*s2*(9.*tk+3.*uk+20.*s+10.*q1+4.*q2)*tk + 8.*s2*(17./2.*s*s+10.*q1*s+6.*q1*q1) - 4.*s2*s2*(4.*tk+uk+9.*s+6.*q1+2.*q2)/mW2*tk - 8.*s2*s2*(2.*s*s+3.*q1*s+2.*q1*q1)/mW2 - 16.*mW2*(2.*tk+5.*uk+7.*s+6.*q1+6.*q2)*tk - 16.*mW2*s*(s+6.*q1) + 4.*s2*s2*s2*q1*(tk+s+q1)/mW2/mW2 + 48.*mW2*mW2*s2; swap(tk,uk); swap(q1,q2); return -pi*alphaS_*CF_/NC_ * ( ctt_i*t_u_Xup - cts_i*t_u_Yup*signf + css_i*t_u_Zup ); } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_qqb above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_qqb_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // qqb_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1Half, // PDT::Spin1,PDT::Spin1, // PDT::Spin1)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata(getParticleData(ParticleID::g)); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qbSpinor(R.p2r(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.kr(),kdata,outgoing); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_k = ffg->evaluate(mu_UV2(),5,p1data,q[p1hel],g[khel]); SpinorBarWaveFunction p2_k = ffg->evaluate(mu_UV2(),5,p2data,qb[p2hel],g[khel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel=p2hel // but if the production ME is required first fill it with (0.,0.). if((p1hel==p2hel)&&helicityConservation_) { // if(getMatrix) { // if(khel==0) // qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,0) = Complex(0.,0.); // else // qqb_hel_amps_(p1hel,p2hel,k1hel,k2hel,2) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_t,q[p1hel],v1[k1hel]); SpinorBarWaveFunction p2_v2 = ffv2->evaluate(scale(),5,intermediate_t,qb[p2hel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->g+v1+v2, q+qb->v1+g+v2, q+qb->v1+v2+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(scale(),p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v1,p2_v2,g[khel])); diagrams.push_back(ffv2->evaluate(scale(),p1_v1,p2_k,v2[k2hel])); } intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_t,q[p1hel],v2[k2hel]); SpinorBarWaveFunction p2_v1 = ffv1->evaluate(scale(),5,intermediate_t,qb[p2hel],v1[k1hel]); // q+qb->g+v2+v1, q+qb->v2+g+v1, q+qb->v2+v1+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(scale(),p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v2,p2_v1,g[khel])); diagrams.push_back(ffv1->evaluate(scale(),p1_v2,p2_k,v1[k1hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),q[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),q[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),q[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_qg above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_qg_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // qg_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1Half,PDT::Spin1, // PDT::Spin1,PDT::Spin1, // PDT::Spin1Half)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(getParticleData(ParticleID::g)); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata (antiquark_->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qinSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qoutSpinor(R.kr(),kdata,outgoing); vector qin; vector qout; for(unsigned int ix=0;ix<2;ix++) { qinSpinor.reset(ix); qoutSpinor.reset(ix); qin.push_back(qinSpinor); qout.push_back(qoutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p2r(),p2data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_p2 = ffg->evaluate(mu_UV2(),5,p1data,qin[p1hel],g[p2hel]); SpinorBarWaveFunction p2_k = ffg->evaluate(mu_UV2(),5,kdata->CC(),qout[khel],g[p2hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p1hel!=khel)&&helicityConservation_) { // if(getMatrix) { // if(p2hel==0) // qg_hel_amps_(p1hel,0,k1hel,k2hel,khel) = Complex(0.,0.); // else // qg_hel_amps_(p1hel,2,k1hel,k2hel,khel) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? antiquark_ : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_q,qin[p1hel],v1[k1hel]); SpinorBarWaveFunction k_v2 = ffv2->evaluate(scale(),5,intermediate_q,qout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams // q+g->v1+v2+q with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv2->evaluate(scale(),p1_v1,p2_k,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v1,k_v2,g[p2hel])); diagrams.push_back(ffv1->evaluate(scale(),p1_p2,k_v2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_q,qin[p1hel],v2[k2hel]); SpinorBarWaveFunction k_v1 = ffv1->evaluate(scale(),5,intermediate_q,qout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv1->evaluate(scale(),p1_v2,p2_k,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),p1_v2,k_v1,g[p2hel])); diagrams.push_back(ffv2->evaluate(scale(),p1_p2,k_v1,v2[k2hel])); } } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),qin[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // The game here is to get this helicity amplitude squared to return all the // same values as t_u_M_R_gqb above, TIMES a further factor tk*uk! Energy2 MEPP2VVPowheg::t_u_M_R_gqb_hel_amp(realVVKinematics R) const { using namespace ThePEG::Helicity; // gqb_hel_amps_.reset(ProductionMatrixElement(PDT::Spin1,PDT::Spin1Half, // PDT::Spin1,PDT::Spin1, // PDT::Spin1Half)); double sum_hel_amps_sqr(0.); tcPDPtr p1data(getParticleData(ParticleID::g)); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); tcPDPtr kdata (quark_->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorBarWaveFunction qbinSpinor(R.p2r(),p2data,incoming); SpinorWaveFunction qboutSpinor(R.kr(),kdata,outgoing); vector qbin; vector qbout; for(unsigned int ix=0;ix<2;ix++) { qbinSpinor.reset(ix); qboutSpinor.reset(ix); qbin.push_back(qbinSpinor); qbout.push_back(qboutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p1r(),p1data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p2data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p2data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorBarWaveFunction p1_p2 = ffg->evaluate(mu_UV2(),5,p2data,qbin[p2hel],g[p1hel]); SpinorWaveFunction p1_k = ffg->evaluate(mu_UV2(),5,kdata->CC(),qbout[khel],g[p1hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p2hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p2hel!=khel)&&helicityConservation_) { // if(getMatrix) { // if(p1hel==0) // gqb_hel_amps_(0,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); // else // gqb_hel_amps_(2,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); // } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? quark_ : tc[ix]; SpinorBarWaveFunction p2_v1 = ffv1->evaluate(scale(),5,intermediate_q,qbin[p2hel],v1[k1hel]); SpinorWaveFunction k_v2 = ffv2->evaluate(scale(),5,intermediate_q,qbout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams q+g->v1+v2+q // with 2 t-channel propagators, 1 s- and 1 t-channel // and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(scale(),p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),k_v2,p2_v1,g[p1hel])); diagrams.push_back(ffv1->evaluate(scale(),k_v2,p1_p2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorBarWaveFunction p2_v2 = ffv2->evaluate(scale(),5,intermediate_q,qbin[p2hel],v2[k2hel]); SpinorWaveFunction k_v1 = ffv1->evaluate(scale(),5,intermediate_q,qbout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(scale(),p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(mu_UV2(),k_v1,p2_v2,g[p1hel])); diagrams.push_back(ffv2->evaluate(scale(),k_v1,p1_p2,v2[k2hel])); } } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(ffv1->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p2data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFZvertex_->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFPvertex_->evaluate(scale(),p1_k,qbin[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } double MEPP2VVPowheg::lo_me() const { using namespace ThePEG::Helicity; double sum_hel_amps_sqr(0.); tcPDPtr p1data(quark_); tcPDPtr p2data(antiquark_); tcPDPtr k1data(mePartonData()[2]); tcPDPtr k2data(mePartonData()[3]); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); // Should never actually occur. SpinorWaveFunction qSpinor(B_.p1b(),p1data,incoming); SpinorBarWaveFunction qbSpinor(B_.p2b(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(B_.k1b(),k1data,outgoing); VectorWaveFunction v2Polarization(B_.k2b(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { if((p1hel==p2hel)&&helicityConservation_) continue; for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(scale(),5,intermediate_t,q[p1hel],v1[k1hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->v1+v2 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) diagrams.push_back(ffv2->evaluate(scale(),p1_v1,qb[p2hel],v2[k2hel])); intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(scale(),5,intermediate_t,q[p1hel],v2[k2hel]); // q+qb->v2+v1 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) diagrams.push_back(ffv1->evaluate(scale(),p1_v2,qb[p2hel],v1[k1hel])); } // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(scale(),3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->v1*->v1+v2 diagrams.push_back(ffv1->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->Z0*->v1+v2 tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(scale(),3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); // q+qb->gamma*->v1+v2 tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(scale(),3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(scale(),q[p1hel],qb[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr; } RealEmissionProcessPtr MEPP2VVPowheg::generateHardest(RealEmissionProcessPtr born, ShowerInteraction inter) { // check if generating QCD radiation if(inter!=ShowerInteraction::QCD && inter!=ShowerInteraction::QEDQCD && inter!=ShowerInteraction::ALL) return RealEmissionProcessPtr(); // Now we want to set these data vectors according to the particles we've // received from the current 2->2 hard collision: vector particlesToShower; for(unsigned int ix=0;ixbornIncoming().size();++ix) particlesToShower.push_back(born->bornIncoming()[ix]); qProgenitor_ = particlesToShower[0]; qbProgenitor_ = particlesToShower[1]; showerQuark_ = particlesToShower[0]; showerAntiquark_ = particlesToShower[1]; qHadron_ = dynamic_ptr_cast(born->hadrons()[0]->dataPtr()); qbHadron_ = dynamic_ptr_cast(born->hadrons()[1]->dataPtr()); if(showerQuark_->id()<0) { swap(qProgenitor_,qbProgenitor_); swap(showerQuark_,showerAntiquark_); swap(qHadron_,qbHadron_); } // In _our_ calculation we basically define the +z axis as being given // by the direction of the incoming quark for q+qb & q+g processes and // the incoming gluon for g+qbar processes. So now we might need to flip // the beams, bjorken x values, colliding partons accordingly: flipped_ = showerQuark_->momentum().z() cmap; // undecayed gauge bosons if(born->bornOutgoing().size()==2) { for(unsigned int ix=0;ixbornOutgoing().size();++ix) { particlesToShower.push_back(born->bornOutgoing()[ix]); } V1_ = particlesToShower[2]; V2_ = particlesToShower[3]; } else if(born->bornOutgoing().size()==4) { // If the vector bosons have decayed already then we may want to // to get the children_ (and any associated photons) to correct // spin correlations: children_.clear(); map clines; for(unsigned int ix=0;ixbornOutgoing().size();++ix) { tPPtr original = born->bornOutgoing()[ix]; PPtr copy = original->dataPtr()->produceParticle(original->momentum()); children_.push_back(copy); cmap.push_back(ix); // sort out colour if(original->colourLine()) { map::iterator cit = clines.find(original->colourLine()); if(cit!=clines.end()) { cit->second->addColoured(copy); } else { ColinePtr newline = new_ptr(ColourLine()); clines[original->colourLine()] = newline; newline->addColoured(copy); } } // and anticolour else if(original->antiColourLine()) { map::iterator cit = clines.find(original->antiColourLine()); if(cit!=clines.end()) { cit->second->addAntiColoured(copy); } else { ColinePtr newline = new_ptr(ColourLine()); clines[original->antiColourLine()] = newline; newline->addAntiColoured(copy); } } } assert(children_.size()==4); PPtr V[2]; for(unsigned int ix=0;ix<2;++ix) { int charge = children_[0+2*ix]->dataPtr()->iCharge()+ children_[1+2*ix]->dataPtr()->iCharge(); Lorentz5Momentum psum =children_[0+2*ix]->momentum()+ children_[1+2*ix]->momentum(); psum.rescaleMass(); if(charge==-3) V[ix] = getParticleData(ParticleID::Wminus)->produceParticle(psum); else if(charge==0) V[ix] = getParticleData(ParticleID::Z0)->produceParticle(psum); else if(charge==3) V[ix] = getParticleData(ParticleID::Wplus)->produceParticle(psum); else assert(false); } V1_ = V[0]; V2_ = V[1]; if(children_[0]->id()<0) { swap(children_[0],children_[1]); swap(cmap[0],cmap[1]); } if(children_[2]->id()<0) { swap(children_[2],children_[3]); swap(cmap[2],cmap[3]); } } else assert(false); gluon_ = getParticleData(ParticleID::g)->produceParticle(); // Abort the run if V1_ and V2_ are not just pointers to different gauge bosons if(!V1_||!V2_) throw Exception() << "MEPP2VVPowheg::generateHardest()\n" << "one or both of the gauge boson pointers is null." << Exception::abortnow; if(!(abs(V1_->id())==24||V1_->id()==23)||!(abs(V2_->id())==24||V2_->id()==23)) throw Exception() << "MEPP2VVPowheg::generateHardest()\nmisidentified gauge bosons" << "V1_ = " << V1_->PDGName() << "\n" << "V2_ = " << V2_->PDGName() << "\n" << Exception::abortnow; // Order the gauge bosons in the same way as in the NLO calculation // (the same way as in the NLO matrix element): // W+(->e+,nu_e) W-(->e-,nu_ebar) (MCFM: 61 [nproc]) bool order = false; if((V1_->id()==-24&&V2_->id()== 24) || // W+/-(mu+,nu_mu / mu-,nu_mubar) Z(nu_e,nu_ebar) (MCFM: 72+77 [nproc]) (V1_->id()== 23&&abs(V2_->id())== 24) ) { swap(V1_,V2_); order = true; - swap(cmap[0],cmap[2]); - swap(cmap[1],cmap[3]); - swap(children_[0],children_[2]); - swap(children_[1],children_[3]); + if(born->bornOutgoing().size()==4) { + swap(cmap[0],cmap[2]); + swap(cmap[1],cmap[3]); + swap(children_[0],children_[2]); + swap(children_[1],children_[3]); + } } // *** N.B. *** // We should not have to do a swap in the ZZ case, even if the different // (off-shell) masses of the Z's are taken into account by generating // the Born variables using the WZ LO/NLO matrix element(s), because // those transformed matrix elements are, according to mathematica, // symmetric in the momenta (and therefore also the masses) of the 2 Z's. // Now we want to construct a bornVVKinematics object. The // constructor for that needs all 4 momenta, q, qbar, V1_, V2_ // in that order, as well as the Bjorken xq and xqbar. // Get the momenta first: vector theBornMomenta; theBornMomenta.push_back(showerQuark_->momentum()); theBornMomenta.push_back(showerAntiquark_->momentum()); theBornMomenta.push_back(V1_->momentum()); theBornMomenta.push_back(V2_->momentum()); // N.B. if the showerQuark_ travels in the -z direction the born kinematics object // will detect this and rotate all particles by pi about the y axis! // Leading order momentum fractions: tcPPtr qHadron = generator()->currentEvent()->primaryCollision()->incoming().first; tcPPtr qbHadron = generator()->currentEvent()->primaryCollision()->incoming().second; assert(qHadron->children().size()>0&&qbHadron->children().size()>0); if(qHadron->children()[0]->id()<0) swap(qHadron,qbHadron); // quark and antiquark momentum fractions respectively double xa = showerQuark_ ->momentum().z()/qHadron ->momentum().z(); double xb = showerAntiquark_->momentum().z()/qbHadron->momentum().z(); // Create the object containing all 2->2 __kinematic__ information: B_ = bornVVKinematics(theBornMomenta,xa,xb); // lo_me_ is the colour & spin averaged n-body matrix element squared: lo_me_ = lo_me(true); // Attempt to generate some radiative variables and their kinematics: vector theRealMomenta; channel_ = 999; if(!getEvent(theRealMomenta,channel_)) { born->pT()[ShowerInteraction::QCD] = min_pT_; return born; } // Set the maximum pT for subsequent emissions: born->pT()[ShowerInteraction::QCD] = pT_ < min_pT_ ? min_pT_ : pT_; // Determine whether the quark or antiquark emitted: fermionNumberOfMother_=0; if((channel_==0&&theRealMomenta[0].z()/theRealMomenta[4].z()>=ZERO)|| channel_==2) fermionNumberOfMother_ = 1; else if((channel_==0&&theRealMomenta[0].z()/theRealMomenta[4].z()0.1*GeV||inMinusOut.x()>0.1*GeV|| inMinusOut.y()>0.1*GeV||inMinusOut.z()>0.1*GeV) cout << "MEPP2VVPowheg::generateHardest\n" << "Momentum imbalance in V1 V2 rest frame\n" << "P_in minus P_out = " << inMinusOut/GeV << endl; // From the radiative kinematics we now have to form ShowerParticle objects: PPtr p1,p2,k; PPtr k1 = V1_->dataPtr()->produceParticle(theRealMomenta[2]); PPtr k2 = V2_->dataPtr()->produceParticle(theRealMomenta[3]); // q+qbar -> V1+V2+g if(channel_==0) { p1 = showerQuark_ ->dataPtr()->produceParticle(theRealMomenta[0]); p2 = showerAntiquark_->dataPtr()->produceParticle(theRealMomenta[1]); k = gluon_ ->dataPtr()->produceParticle(theRealMomenta[4]); k->incomingColour(p1); k->incomingColour(p2,true); } // q+g -> V1+V2+q else if(channel_==1) { p1 = showerQuark_ ->dataPtr() ->produceParticle(theRealMomenta[0]); p2 = gluon_ ->dataPtr() ->produceParticle(theRealMomenta[1]); k = showerAntiquark_->dataPtr()->CC()->produceParticle(theRealMomenta[4]); k->incomingColour(p2); p2->colourConnect(p1); } // g+qbar -> V1+V2+qbar else { p1 = gluon_ ->dataPtr() ->produceParticle(theRealMomenta[0]); p2 = showerAntiquark_->dataPtr() ->produceParticle(theRealMomenta[1]); k = showerQuark_ ->dataPtr()->CC()->produceParticle(theRealMomenta[4]); k->incomingColour(p1,true); p1->colourConnect(p2,true); } Lorentz5Momentum pmother,pspect; if(fermionNumberOfMother_==1) { pmother = theRealMomenta[0]-theRealMomenta[4]; pspect = theRealMomenta[1]; } else { pmother = theRealMomenta[1]-theRealMomenta[4]; pspect = theRealMomenta[0]; } unsigned int iemit = fermionNumberOfMother_==1 ? 0 : 1; unsigned int ispect = fermionNumberOfMother_==1 ? 1 : 0; // fill the output if(showerQuark_ !=born->bornIncoming()[0]) { born->incoming().push_back(p2); born->incoming().push_back(p1); swap(iemit,ispect); } else { born->incoming().push_back(p1); born->incoming().push_back(p2); } born->emitter (iemit); born->spectator(ispect); pair xnew; for(unsigned int ix=0;ixincoming().size();++ix) { double x = born->incoming()[ix]->momentum().rho()/born->hadrons()[ix]->momentum().rho(); if(ix==0) xnew.first = x; else if (ix==1) xnew.second = x; } born->x(xnew); born->interaction(ShowerInteraction::QCD); // if gauge bosons not decayed, we're done if(born->bornOutgoing().size()==2) { born->emitted(4); if(!order) { born->outgoing().push_back(k1); born->outgoing().push_back(k2); } else { born->outgoing().push_back(k2); born->outgoing().push_back(k1); } born->outgoing().push_back(k); return born; } // Recalculate the hard vertex for this event: // For spin correlations, if an emission occurs go calculate the relevant // combination of amplitudes for the ProductionMatrixElement. if(realMESpinCorrelations_) { // Here we reset the realVVKinematics n+1 momenta to be those // of the lab frame in order to calculate the spin correlations. // Note that these momenta are not used for anything else after // this. R_.p1r(theRealMomenta[0]); R_.p2r(theRealMomenta[1]); R_.k1r(theRealMomenta[2]); R_.k2r(theRealMomenta[3]); R_.kr (theRealMomenta[4]); if(channel_==0) t_u_M_R_qqb_hel_amp(R_,true); else if(channel_==1) t_u_M_R_qg_hel_amp (R_,true); else if(channel_==2) t_u_M_R_gqb_hel_amp(R_,true); recalculateVertex(); } born->emitted(6); for(unsigned int ix=0;ixoutgoing().push_back(children_[cmap[ix]]); born->outgoing().push_back(k); // return the result return born; } double MEPP2VVPowheg::getResult(int channel, realVVKinematics R, Energy pT) { // This routine should return the integrand of the exact Sudakov form factor, // defined precisely as // KH 19th August - next 2 lines changed for phi in 0->pi not 0->2pi // \Delta(pT) = exp[ - \int_{pT}^{pTmax} dpT dYk d\phi/pi * getResult(...) ] // (Where phi is in 0->pi NOT 0->2*pi !) // Get pi for the prefactor: using Constants::pi; // Get the VV invariant mass^2: Energy2 p2 = B_.sb(); // Get the momentum fractions for the n+1 body event: double x1 = R.x1r(); double x2 = R.x2r(); // Reject the event if the x1 and x2 values are outside the phase space: if(x1<0.||x1>1.||x2<0.||x2>1.||x1*x2maximumCMEnergy())) return 0.; // Get the momentum fractions for the n body event: double x1b = B_.x1b(); double x2b = B_.x2b(); // Get the mandelstam variables needed to calculate the n+1 body matrix element: Energy2 s = R.sr() ; Energy2 t_u_MR_o_MB; double lo_lumi, nlo_lumi; // The luminosity function for the leading order n-body process: lo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_ ->dataPtr(),PDFScale_,x1b)* qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr(),PDFScale_,x2b); // Now we calculate the luminosity functions (product of the two pdfs) for the // real emission process(es) and also their matrix elements: // q + qbar -> V + V + g if(channel==0) { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_ ->dataPtr() ,PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr() ,PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_qqb_hel_amp(R,false)/lo_me_; } // q + g -> V + V + q else if(channel==1) { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,showerQuark_->dataPtr() ,PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,getParticleData(ParticleID::g),PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_qg_hel_amp(R,false)/lo_me_; } // g + qbar -> V + V + qbar else { nlo_lumi = qHadron_ ->pdf()->xfx(qHadron_ ,getParticleData(ParticleID::g),PDFScale_,x1) * qbHadron_->pdf()->xfx(qbHadron_,showerAntiquark_->dataPtr() ,PDFScale_,x2); t_u_MR_o_MB = t_u_M_R_gqb_hel_amp(R,false)/lo_me_; } // Multiply ratio of the real emission matrix elements to the Born matrix element // by the ratio of the pdfs for the real emission and born processes to get theWeight if(lo_lumi<=0.||nlo_lumi<=0.) return 0.; else return t_u_MR_o_MB * ( nlo_lumi/lo_lumi * p2/s ) * sqr(p2/s)/8./pi/pi / pT / p2 * GeV; } bool MEPP2VVPowheg::getEvent(vector & theRealMomenta, unsigned int & channel) { // Invariant mass of the colliding hadrons: Energy2 S = sqr(generator()->maximumCMEnergy()); // Born variables which are preserved (mass and rapidity of the diboson system): Energy2 p2 = B_.sb(); double Yb = B_.Yb(); // Born variables which are not preserved but are needed (the momentum fractions): double x1b(B_.x1b()), x2b(B_.x2b()); double x12b(x1b*x1b), x22b(x2b*x2b); // Maximum jet pT (half of the hadronic C.O.M. energy. N.B. this is overestimated a lot): Energy starting_pT = sqrt(S)/2.; // Initialize the pT_ *integration limit* i.e. the pT of the generated emission: pT_ = ZERO; // The pT *integration variable*: Energy pT; // The x_1 & x_2 momentum fractions corresponding to incoming momenta p1 & p2: double x1_(-999.), x2_(-999.); double x1 (-999.), x2 (-999.); // The jet rapidity *integration variable* and its limits: double Yk, minYk(-8.0), maxYk(8.0); // The theta2 integration variable (the azimuthal angle of the gluon w.r.t // V1 in the V1 & V2 rest frame: double theta2; // The realVVKinematics object corresponding to the current integration // set of integration variables: realVVKinematics R; // The veto algorithm rejection weight and a corresponding flag: double rejectionWeight; bool rejectEmission ; // Initialize the flag indicating the selected radiation channel: channel=999; // Some product of constants used for the crude distribution: double a(0.); for(int j=0;j<3;j++) { pT=starting_pT; a =(maxYk-minYk)*prefactor_[j]/2./b0_; do { // Generate next pT according to exp[- \int^{pTold}_{pT} dpT a*(power-1)/(pT^power)] // pT = GeV/pow( pow(GeV/pT,power_-1.) - log(UseRandom::rnd())/a // , 1./(power_-1.) ); // Generate next pT according to exp[- \int^{pTold}_{pT} dpT alpha1loop*prefactor/pT ] pT = LambdaQCD_*exp( 0.5*exp( log(log(sqr(pT/LambdaQCD_)))+log(UseRandom::rnd())/a ) ); // Generate rapidity of the jet: Yk = minYk + UseRandom::rnd()*(maxYk - minYk); // Generate the theta2 radiative variable: // KH 19th August - next line changed for phi in 0->pi not 0->2pi // theta2 = UseRandom::rnd() * 2.*Constants::pi; theta2 = UseRandom::rnd() * Constants::pi; // eT of the diboson system: Energy eT = sqrt(pT*pT+p2); // Calculate the eT and then solve for x_{\oplus} & x_{\ominus}: x1 = (pT*exp( Yk)+eT*exp( Yb))/sqrt(S); x2 = (pT*exp(-Yk)+eT*exp(-Yb))/sqrt(S); // Calculate the xr radiative variable: double xr(p2/(x1*x2*S)); // Then use this to calculate the y radiative variable: double y(-((xr+1.)/(xr-1.))*(xr*sqr(x1/x1b)-1.)/(xr*sqr(x1/x1b)+1.)); // The y value above should equal the one commented out below this line: // double y( ((xr+1.)/(xr-1.))*(xr*sqr(x2/x2b)-1.)/(xr*sqr(x2/x2b)+1.)); // Now we get the lower limit on the x integration, xbar: double omy(1.-y), opy(1.+y); double xbar1 = 2.*opy*x12b/(sqrt(sqr(1.+x12b)*sqr(omy)+16.*y*x12b)+omy*(1.-x1b)*(1.+x1b)); double xbar2 = 2.*omy*x22b/(sqrt(sqr(1.+x22b)*sqr(opy)-16.*y*x22b)+opy*(1.-x2b)*(1.+x2b)); double xbar = max(xbar1,xbar2); // Now we can calculate xtilde: double xt = (xr-xbar)/(1.-xbar); // Finally we can make the realVVKinematics object: R = realVVKinematics(B_,xt,y,theta2); // The next thing we have to do is set the QCD, EW and PDF scales using R: setTheScales(pT); // ... and so calculate rejection weight: rejectionWeight = getResult(j,R,pT); // If generating according to exp[- \int^{pTold}_{pT} dpT a*(power-1)/(pT^power)] // rejectionWeight/= showerAlphaS_->overestimateValue()*prefactor_[j]*pow(GeV/pT,power_); // If generating according to exp[- \int^{pTold}_{pT} dpT alpha1loop*prefactor/pT ] rejectionWeight/= 1./b0_/log(sqr(pT/LambdaQCD_))*prefactor_[j]*GeV/pT; rejectEmission = UseRandom::rnd()>rejectionWeight; // The event is a no-emission event if pT goes past min_pT_ - basically set to // outside the histogram bounds (hopefully histogram objects just ignore it then). if(pT1.) { ostringstream stream; stream << "MEPP2VVPowheg::getEvent weight for channel " << j << " is greater than one: " << rejectionWeight << endl; generator()->logWarning( Exception(stream.str(), Exception::warning) ); } } while(rejectEmission); // set pT of emission etc if(pT>pT_) { channel = j; pT_ = pT; Yk_ = Yk; R_ = R ; x1_ = x1; x2_ = x2; } } // Was this an (overall) no emission event? if(pT_3) throw Exception() << "MEPP2VVPowheg::getEvent() channel = " << channel << " pT = " << pT/GeV << " pT_ = " << pT_/GeV << Exception::abortnow; // Work out the momenta in the lab frame, reserving the mass and rapidity // of the VV system: LorentzRotation yzRotation; yzRotation.setRotateX(-atan2(pT_/GeV,sqrt(p2)/GeV)); LorentzRotation boostFrompTisZero; boostFrompTisZero.setBoostY(-pT_/sqrt(p2+pT_*pT_)); LorentzRotation boostFromYisZero; boostFromYisZero.setBoostZ(tanh(Yb)); theRealMomenta.resize(5); theRealMomenta[0] = Lorentz5Momentum(ZERO,ZERO, x1_*sqrt(S)/2., x1_*sqrt(S)/2.,ZERO); theRealMomenta[1] = Lorentz5Momentum(ZERO,ZERO,-x2_*sqrt(S)/2., x2_*sqrt(S)/2.,ZERO); theRealMomenta[2] = boostFromYisZero*boostFrompTisZero*yzRotation*(R_.k1r()); theRealMomenta[3] = boostFromYisZero*boostFrompTisZero*yzRotation*(R_.k2r()); theRealMomenta[4] = Lorentz5Momentum(ZERO, pT_, pT_*sinh(Yk_), pT_*cosh(Yk_),ZERO); return true; } void MEPP2VVPowheg::setTheScales(Energy pT) { // Work out the scales we want to use in the matrix elements and the pdfs: // Scale for alpha_S: pT^2 of the diboson system. QCDScale_ = max(pT*pT,sqr(min_pT_)); // Scale for real emission PDF: // pT^2+mVV^2 - as mcfm does in the case of a single W/Z boson). // Energy2 PDFScale_ = max(R.pT2_in_lab(),sqr(min_pT_))+R.s2r(); // pT^2 - as advocated by Nason & Ridolfi for ZZ production & Alioli et al for gg->h: PDFScale_ = max(pT*pT,sqr(min_pT_)); // Scale of electroweak vertices: mVV^2 the invariant mass of the diboson system. // EWScale_ = B_.sb(); // ... And this choice is more like what can be seen in mcatnlo_vbmain.f (weird). EWScale_ = 0.5*(B_.k12b()+B_.k22b()); return; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_qqb in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_qqb_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement qqb_hel_amps(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1 ,PDT::Spin1 , PDT::Spin1); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata(getParticleData(ParticleID::g)); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qbSpinor(R.p2r(),p2data,incoming); vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.kr(),kdata,outgoing); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_k = ffg->evaluate(QCDScale_,5,p1data,q[p1hel],g[khel]); SpinorBarWaveFunction p2_k = ffg->evaluate(QCDScale_,5,p2data,qb[p2hel],g[khel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel=p2hel // but if the production ME is required first fill it with (0.,0.). if((p1hel==p2hel)&&helicityConservation_) { if(getMatrix) { if(khel==0) qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,0) = Complex(0.,0.); else qqb_hel_amps(p1hel,p2hel,k1hel,k2hel,2) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; // Note: choosing 5 as the second argument ffvX_->evaluate() sets // option 5 in thepeg/Helicity/Vertex/VertexBase.cc, which makes // the (fermion) propagator denominator massless: 1/p^2. // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,q[p1hel],v1[k1hel]); - SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,qb[p2hel],v2[k2hel]); + SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_t->CC(),qb[p2hel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->g+v1+v2, q+qb->v1+g+v2, q+qb->v1+v2+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v1,p2_v2,g[khel])); diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,p2_k,v2[k2hel])); } intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,q[p1hel],v2[k2hel]); - SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,qb[p2hel],v1[k1hel]); + SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_t->CC(),qb[p2hel],v1[k1hel]); // q+qb->g+v2+v1, q+qb->v2+g+v1, q+qb->v2+v1+g if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v2,p2_v1,g[khel])); diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,p2_k,v1[k1hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_k,qb[p2hel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,q[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_qg in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_qg_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement qg_hel_amps(PDT::Spin1Half,PDT::Spin1, PDT::Spin1,PDT::Spin1, PDT::Spin1Half); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(getParticleData(ParticleID::g)); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata (showerAntiquark_->dataPtr()->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorWaveFunction qinSpinor(R.p1r(),p1data,incoming); SpinorBarWaveFunction qoutSpinor(R.kr(),kdata,outgoing); vector qin; vector qout; for(unsigned int ix=0;ix<2;ix++) { qinSpinor.reset(ix); qoutSpinor.reset(ix); qin.push_back(qinSpinor); qout.push_back(qoutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p2r(),p2data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorWaveFunction p1_p2 = ffg->evaluate(QCDScale_,5,p1data,qin[p1hel],g[p2hel]); SpinorBarWaveFunction p2_k = ffg->evaluate(QCDScale_,5,kdata->CC(),qout[khel],g[p2hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p1hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p1hel!=khel)&&helicityConservation_) { if(getMatrix) { if(p2hel==0) qg_hel_amps(p1hel,0,k1hel,k2hel,khel) = Complex(0.,0.); else qg_hel_amps(p1hel,2,k1hel,k2hel,khel) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? showerAntiquark_->dataPtr() : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qin[p1hel],v1[k1hel]); - SpinorBarWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qout[khel],v2[k2hel]); + SpinorBarWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q->CC(),qout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams // q+g->v1+v2+q with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,p2_k,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v1,k_v2,g[p2hel])); diagrams.push_back(ffv1->evaluate(EWScale_,p1_p2,k_v2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qin[p1hel],v2[k2hel]); - SpinorBarWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qout[khel],v1[k1hel]); + SpinorBarWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q->CC(),qout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,p2_k,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,p1_v2,k_v1,g[p2hel])); diagrams.push_back(ffv2->evaluate(EWScale_,p1_p2,k_v1,v2[k2hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_p2,qout[khel],k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,qin[p1hel],p2_k,k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This is identical to the code in the Powheg matrix element. It should // equal t_u_M_R_gqb in there, which is supposed to be the real emission ME // times tk*uk. Energy2 MEPP2VVPowheg::t_u_M_R_gqb_hel_amp(realVVKinematics R, bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement gqb_hel_amps(PDT::Spin1,PDT::Spin1Half, PDT::Spin1,PDT::Spin1, PDT::Spin1Half); double sum_hel_amps_sqr(0.); tcPDPtr p1data(getParticleData(ParticleID::g)); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); tcPDPtr kdata (showerQuark_->dataPtr()->CC()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); SpinorBarWaveFunction qbinSpinor(R.p2r(),p2data,incoming); SpinorWaveFunction qboutSpinor(R.kr(),kdata,outgoing); vector qbin; vector qbout; for(unsigned int ix=0;ix<2;ix++) { qbinSpinor.reset(ix); qboutSpinor.reset(ix); qbin.push_back(qbinSpinor); qbout.push_back(qboutSpinor); } VectorWaveFunction v1Polarization(R.k1r(),k1data,outgoing); VectorWaveFunction v2Polarization(R.k2r(),k2data,outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } VectorWaveFunction gPolarization(R.p1r(),p1data,incoming); vector g; for(unsigned int ix=0;ix<3;ix+=2) { gPolarization.reset(ix); g.push_back(gPolarization); } AbstractFFVVertexPtr ffg = FFGvertex_; AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p2data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p2data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(kdata->CC()); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int khel=0;khel<2;++khel) { SpinorBarWaveFunction p1_p2 = ffg->evaluate(QCDScale_,5,p2data,qbin[p2hel],g[p1hel]); SpinorWaveFunction p1_k = ffg->evaluate(QCDScale_,5,kdata->CC(),qbout[khel],g[p1hel]); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { // If helicity is exactly conserved (massless quarks) skip if p2hel!=khel // but if the production ME is required first fill it with (0.,0.). if((p2hel!=khel)&&helicityConservation_) { if(getMatrix) { if(p1hel==0) gqb_hel_amps(0,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); else gqb_hel_amps(2,p2hel,k1hel,k2hel,khel) = Complex(0.,0.); } continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_q; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? showerQuark_->dataPtr() : tc[ix]; - SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qbin[p2hel],v1[k1hel]); + SpinorBarWaveFunction p2_v1 = ffv1->evaluate(EWScale_,5,intermediate_q->CC(),qbin[p2hel],v1[k1hel]); SpinorWaveFunction k_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qbout[khel],v2[k2hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 abelian diagrams q+g->v1+v2+q // with 2 t-channel propagators, 1 s- and 1 t-channel // and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==0))) { diagrams.push_back(ffv2->evaluate(EWScale_,p1_k,p2_v1,v2[k2hel])); diagrams.push_back(ffg->evaluate(QCDScale_,k_v2,p2_v1,g[p1hel])); diagrams.push_back(ffv1->evaluate(EWScale_,k_v2,p1_p2,v1[k1hel])); } intermediate_q = (!(k1data->id()==24&&k2data->id()==-24)) ? p2data : tc[ix]; - SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_q,qbin[p2hel],v2[k2hel]); + SpinorBarWaveFunction p2_v2 = ffv2->evaluate(EWScale_,5,intermediate_q->CC(),qbin[p2hel],v2[k2hel]); SpinorWaveFunction k_v1 = ffv1->evaluate(EWScale_,5,intermediate_q,qbout[khel],v1[k1hel]); // q+g->v2+v1+q, with 2 t-channel propagators, 1 s- and 1 t-channel and 2 t-channel ones. if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p2data->id())%2==1))) { diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,p2_v2,v1[k1hel])); diagrams.push_back(ffg->evaluate(QCDScale_,k_v1,p2_v2,g[p1hel])); diagrams.push_back(ffv2->evaluate(EWScale_,k_v1,p1_p2,v2[k2hel])); } } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->g+v1*->g+v1+v2, q+qb->v1*+g->v1+v2+g diagrams.push_back(ffv1->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(ffv1->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p2data->id()==kdata->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->g+Z0*->g+v1+v2,q+qb->Z0*+g->v1+v2+g, tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFZvertex_->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); // q+qb->g+gamma*->g+v1+v2,q+qb->gamma*+g->v1+v2+g, tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,qbout[khel],p1_p2,k1_k2)); diagrams.push_back(FFPvertex_->evaluate(EWScale_,p1_k,qbin[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr*R.tkr()*R.ukr()*UnitRemoval::InvE2; } /***************************************************************************/ // This returns exactly the same value as lo_me2_ when you put it in MEPP2VVPowheg.cc double MEPP2VVPowheg::lo_me(bool getMatrix) const { using namespace ThePEG::Helicity; ProductionMatrixElement lo_hel_amps(PDT::Spin1Half,PDT::Spin1Half, PDT::Spin1 ,PDT::Spin1); double sum_hel_amps_sqr(0.); tcPDPtr p1data(showerQuark_->dataPtr()); tcPDPtr p2data(showerAntiquark_->dataPtr()); tcPDPtr k1data(V1_->dataPtr()); tcPDPtr k2data(V2_->dataPtr()); if(k1data->id()==-24&&k2data->id()==24) swap(k1data,k2data); // Should never actually occur. // If you want to reproduce the spin correlations of MEPP2VV // you should evaluate this ME using the lab frame momenta // instead of the bornVVKinematics ones (partonic C.O.M. frame). SpinorWaveFunction qSpinor; SpinorBarWaveFunction qbSpinor; if(!getMatrix) { qSpinor=SpinorWaveFunction(B_.p1b(),p1data,incoming); qbSpinor=SpinorBarWaveFunction(B_.p2b(),p2data,incoming); } else { qSpinor=SpinorWaveFunction(showerQuark_->momentum(),p1data,incoming); qbSpinor=SpinorBarWaveFunction(showerAntiquark_->momentum(),p2data,incoming); } vector q; vector qb; for(unsigned int ix=0;ix<2;ix++) { qSpinor.reset(ix); qbSpinor.reset(ix); q.push_back(qSpinor); qb.push_back(qbSpinor); } // If you want to reproduce the spin correlations of MEPP2VV // you should evaluate this ME using the lab frame momenta // instead of the bornVVKinematics ones (partonic C.O.M. frame). VectorWaveFunction v1Polarization; VectorWaveFunction v2Polarization; if(!getMatrix) { v1Polarization=VectorWaveFunction(B_.k1b(),k1data,outgoing); v2Polarization=VectorWaveFunction(B_.k2b(),k2data,outgoing); } else { v1Polarization=VectorWaveFunction(V1_->momentum(),k1data,outgoing); v2Polarization=VectorWaveFunction(V2_->momentum(),k2data,outgoing); } vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = k1data->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = k2data->id()==23 ? FFZvertex_ : FFWvertex_; // Collecting information for intermediate fermions vector tc; if(abs(k1data->id())==24&&abs(k2data->id())==24) { if(abs(p1data->id())%2==0) for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(1+2*ix)); else for(int ix=0;ix<3;++ix) tc.push_back(getParticleData(2+2*ix)); } else if(k1data->id()==23&&k2data->id()==23) tc.push_back(p1data); else if(abs(k1data->id())==24&&k2data->id()==23) tc.push_back(p2data); // Loop over helicities summing the relevant diagrams for(unsigned int p1hel=0;p1hel<2;++p1hel) { for(unsigned int p2hel=0;p2hel<2;++p2hel) { for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { if((p1hel==p2hel)&&helicityConservation_) { lo_hel_amps(p1hel,p2hel,k1hel,k2hel) = Complex(0.,0.); continue; } vector diagrams; // Get all t-channel diagram contributions tcPDPtr intermediate_t; for(unsigned int ix=0;ixid()==24&&k2data->id()==-24)) ? p2data : tc[ix]; SpinorWaveFunction p1_v1 = ffv1->evaluate(EWScale_,5,intermediate_t,q[p1hel],v1[k1hel]); // First calculate all the off-shell fermion currents // Now calculate the 6 t-channel diagrams // q+qb->v1+v2 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==1))) diagrams.push_back(ffv2->evaluate(EWScale_,p1_v1,qb[p2hel],v2[k2hel])); intermediate_t = (!(k1data->id()==24&&k2data->id()==-24)) ? p1data : tc[ix]; SpinorWaveFunction p1_v2 = ffv2->evaluate(EWScale_,5,intermediate_t,q[p1hel],v2[k2hel]); // q+qb->v2+v1 if(!((k1data->id()==24&&k2data->id()==-24)&&(abs(p1data->id())%2==0))) diagrams.push_back(ffv1->evaluate(EWScale_,p1_v2,qb[p2hel],v1[k1hel])); } // Note: choosing 3 as the second argument in WWWvertex_->evaluate() // sets option 3 in thepeg/Helicity/Vertex/VertexBase.cc , which // means the propagator does not contain a width factor (which is // good re. gauge invariance). // If W+Z / W-Z calculate the two V+jet-like s-channel diagrams if(abs(k1data->id())==24&&k2data->id()==23) { // The off-shell s-channel boson current VectorWaveFunction k1_k2 = WWWvertex_->evaluate(EWScale_,3,k1data->CC(),v2[k2hel],v1[k1hel]); // q+qb->v1*->v1+v2 diagrams.push_back(ffv1->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); } // If W+W- calculate the four V+jet-like s-channel diagrams if((k1data->id()==24&&k2data->id()==-24)&&(p1data->id()==-p2data->id())) { // The off-shell s-channel boson current VectorWaveFunction k1_k2; // q+qb->Z0*->v1+v2 tcPDPtr Z0 = getParticleData(ParticleID::Z0); k1_k2 = WWWvertex_->evaluate(EWScale_,3,Z0,v2[k2hel],v1[k1hel]); diagrams.push_back(FFZvertex_->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); // q+qb->gamma*->v1+v2 tcPDPtr gamma = getParticleData(ParticleID::gamma); k1_k2 = WWWvertex_->evaluate(EWScale_,3,gamma,v2[k2hel],v1[k1hel]); diagrams.push_back(FFPvertex_->evaluate(EWScale_,q[p1hel],qb[p2hel],k1_k2)); } // Add up all diagrams to get the total amplitude: Complex hel_amp(0.); for(unsigned int ix=0;ixid()==23&&k2data->id()==23) sum_hel_amps_sqr /= 2.; return sum_hel_amps_sqr; } /***************************************************************************/ // This member selects a [2-body] decay mode and assigns children to the // vector bosons with momenta which are isotropic in their rest frames. bool MEPP2VVPowheg::isotropicDecayer() { using namespace ThePEG::Helicity; // Generate the children's momenta isotropically in // the rest frames of V1 and V2: double cth,phi; // First V1's children: cth = UseRandom::rnd()*2.-1.; phi = UseRandom::rnd()*2.*Constants::pi; Energy m1(V1_->momentum().m()); Energy m3(children_[0]->data().constituentMass()); Energy m4(children_[1]->data().constituentMass()); Energy p34(triangleFn(sqr(m1),sqr(m3),sqr(m4)) /2./m1); if(std::isnan(double(p34/MeV))||cth>1.||cth<-1.) return false; Energy pT34(p34*sqrt(1.-cth)*sqrt(1.+cth)); Lorentz5Momentum k3(pT34*sin(phi),pT34*cos(phi),p34 *cth, sqrt(p34*p34+sqr(m3)),m3); Lorentz5Momentum k4(-k3); k4.setE(sqrt(p34*p34+sqr(m4))); k4.setTau(m4); Boost boostToV1RF(R_.k1r().boostVector()); k3.boost(boostToV1RF); k3.rescaleRho(); k4.boost(boostToV1RF); k4.rescaleRho(); // Second V2's children: cth = UseRandom::rnd()*2.-1.; phi = UseRandom::rnd()*2.*Constants::pi; Energy m2(V2_->momentum().m()); Energy m5(children_[2]->data().constituentMass()); Energy m6(children_[3]->data().constituentMass()); Energy p56(triangleFn(sqr(m2),sqr(m5),sqr(m6)) /2./m2); if(std::isnan(double(p56/MeV))||cth>1.||cth<-1.) return false; Energy pT56(p56*sqrt(1.-cth)*sqrt(1.+cth)); Lorentz5Momentum k5(pT56*sin(phi),pT56*cos(phi),p56*cth, sqrt(p56*p56+sqr(m5)),m5); Lorentz5Momentum k6(-k5); k6.setE(sqrt(p56*p56+sqr(m6))); k6.setTau(m6); Boost boostToV2RF(R_.k2r().boostVector()); k5.boost(boostToV2RF); k5.rescaleRho(); k6.boost(boostToV2RF); k6.rescaleRho(); // Assign the momenta to the children: children_[0]->set5Momentum(k3); children_[1]->set5Momentum(k4); children_[2]->set5Momentum(k5); children_[3]->set5Momentum(k6); return true; } // Override 2->2 production matrix here: void MEPP2VVPowheg::recalculateVertex() { // Zero the squared amplitude; this equals sum_hel_amps_sqr if all // is working as it should: Complex productionMatrix2(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) for(unsigned int k2hel=0;k2hel<3;++k2hel) productionMatrix2 += productionMatrix_[k1hel][k1hel][k2hel][k2hel]; // Get the vector wavefunctions: VectorWaveFunction v1Polarization; VectorWaveFunction v2Polarization; v1Polarization=VectorWaveFunction(R_.k1r(),V1_->dataPtr(),outgoing); v2Polarization=VectorWaveFunction(R_.k2r(),V2_->dataPtr(),outgoing); vector v1; vector v2; for(unsigned int ix=0;ix<3;ix++) { v1Polarization.reset(ix); v2Polarization.reset(ix); v1.push_back(v1Polarization); v2.push_back(v2Polarization); } AbstractFFVVertexPtr ffv1 = V1_->id()==23 ? FFZvertex_ : FFWvertex_; AbstractFFVVertexPtr ffv2 = V2_->id()==23 ? FFZvertex_ : FFWvertex_; bool vetoed(true); while(vetoed) { // Decay the bosons isotropically in their rest frames: isotropicDecayer(); // Get the spinor wavefunctions: SpinorWaveFunction k3Spinor(children_[0]->momentum(),children_[0]->dataPtr(),outgoing); SpinorBarWaveFunction k4Spinor(children_[1]->momentum(),children_[1]->dataPtr(),outgoing); SpinorWaveFunction k5Spinor(children_[2]->momentum(),children_[2]->dataPtr(),outgoing); SpinorBarWaveFunction k6Spinor(children_[3]->momentum(),children_[3]->dataPtr(),outgoing); vector k3,k5; vector k4,k6; for(unsigned int ix=0;ix<2;ix++) { k3Spinor.reset(ix); k4Spinor.reset(ix); k3.push_back(k3Spinor); k4.push_back(k4Spinor); k5Spinor.reset(ix); k6Spinor.reset(ix); k5.push_back(k5Spinor); k6.push_back(k6Spinor); } DecayMEPtr decayAmps(new_ptr(GeneralDecayMatrixElement(PDT::Spin1,PDT::Spin1Half,PDT::Spin1Half))); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k3hel=0;k3hel<2;++k3hel) { for(unsigned int k4hel=0;k4hel<2;++k4hel) { (*decayAmps)(k1hel,k3hel,k4hel) = ffv1->evaluate(EWScale_,k3[k3hel],k4[k4hel],v1[k1hel]); } } } Complex V1decayMatrix[3][3]; for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k1helpr=0;k1helpr<3;++k1helpr) { Complex theElement(0.,0.); for(unsigned int k3hel=0;k3hel<2;++k3hel) { for(unsigned int k4hel=0;k4hel<2;++k4hel) { theElement += (*decayAmps)(k1hel,k3hel,k4hel) *conj((*decayAmps)(k1helpr,k3hel,k4hel)); } } V1decayMatrix[k1hel][k1helpr] = theElement; } } Complex V1decayMatrix2(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) V1decayMatrix2 += V1decayMatrix[k1hel][k1hel]; for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k5hel=0;k5hel<2;++k5hel) { for(unsigned int k6hel=0;k6hel<2;++k6hel) { (*decayAmps)(k2hel,k5hel,k6hel) = ffv2->evaluate(EWScale_,k5[k5hel],k6[k6hel],v2[k2hel]); } } } Complex V2decayMatrix[3][3]; for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k2helpr=0;k2helpr<3;++k2helpr) { Complex theElement(0.,0.); for(unsigned int k5hel=0;k5hel<2;++k5hel) { for(unsigned int k6hel=0;k6hel<2;++k6hel) { theElement += (*decayAmps)(k2hel,k5hel,k6hel) *conj((*decayAmps)(k2helpr,k5hel,k6hel)); } } V2decayMatrix[k2hel][k2helpr] = theElement; } } Complex V2decayMatrix2(0.,0.); for(unsigned int k2hel=0;k2hel<3;++k2hel) V2decayMatrix2 += V2decayMatrix[k2hel][k2hel]; // Contract the production matrix and the decay matrices: Complex meTimesV1V2denominators(0.,0.); for(unsigned int k1hel=0;k1hel<3;++k1hel) { for(unsigned int k1helpr=0;k1helpr<3;++k1helpr) { for(unsigned int k2hel=0;k2hel<3;++k2hel) { for(unsigned int k2helpr=0;k2helpr<3;++k2helpr) { meTimesV1V2denominators += productionMatrix_[k1hel][k1helpr][k2hel][k2helpr] *V1decayMatrix[k1hel][k1helpr] *V2decayMatrix[k2hel][k2helpr]; } } } } if(imag(meTimesV1V2denominators)/real(meTimesV1V2denominators)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the matrix element's imaginary part is large " << meTimesV1V2denominators << endl; if(imag(productionMatrix2)/real(productionMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the production matrix element's imaginary part is large " << productionMatrix2 << endl; if(imag(V1decayMatrix2)/real(V1decayMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the V1 decay matrix element's imaginary part is large " << V1decayMatrix2 << endl; if(imag(V2decayMatrix2)/real(V2decayMatrix2)>1.e-7) cout << "MEPP2VVPowheg warning\n" << "the V2 decay matrix element's imaginary part is large " << V2decayMatrix2 << endl; // Need branching ratio at least in here I would think ---> double decayWeight( real(meTimesV1V2denominators) / real(productionMatrix2*V1decayMatrix2*V2decayMatrix2)); if(decayWeight>1.) cout << "MEPP2VVPowheg::recalculateVertex decayWeight > 1., decayWeight = " << decayWeight << endl; if(decayWeight<0.) cout << "MEPP2VVPowheg::recalculateVertex decayWeight < 0., decayWeight = " << decayWeight << endl; if(UseRandom::rnd()=ZERO) { return sqrt(lambda2); } else { generator()->log() << "MEPP2VVPowheg::triangleFn " << "kinematic instability, imaginary triangle function\n"; return -999999.*GeV2; } } diff --git a/Models/Feynrules/python/ufo2peg/general_lorentz.py b/Models/Feynrules/python/ufo2peg/general_lorentz.py --- a/Models/Feynrules/python/ufo2peg/general_lorentz.py +++ b/Models/Feynrules/python/ufo2peg/general_lorentz.py @@ -1,3018 +1,3029 @@ import copy from .helpers import SkipThisVertex,def_from_model from .converter import py2cpp import string,re from string import Template epsValue=[[[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]], [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]], [[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]], [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]], [[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]], [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]], [[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]], [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]]] epsValue[0][1][2][3] = -1. epsValue[0][1][3][2] = 1. epsValue[0][2][1][3] = 1. epsValue[0][2][3][1] = -1. epsValue[0][3][1][2] = -1. epsValue[0][3][2][1] = 1. epsValue[1][0][2][3] = 1. epsValue[1][0][3][2] = -1. epsValue[1][2][0][3] = -1. epsValue[1][2][3][0] = 1. epsValue[1][3][0][2] = 1. epsValue[1][3][2][0] = -1. epsValue[2][0][1][3] = -1. epsValue[2][0][3][1] = 1. epsValue[2][1][0][3] = 1. epsValue[2][1][3][0] = -1. epsValue[2][3][0][1] = -1. epsValue[2][3][1][0] = 1. epsValue[3][0][1][2] = 1. epsValue[3][0][2][1] = -1. epsValue[3][1][0][2] = -1. epsValue[3][1][2][0] = 1. epsValue[3][2][0][1] = 1. epsValue[3][2][1][0] = -1. # self contracted tensor propagator tPropA=[[],[],[],[]] tPropA[0].append(Template("-2. / 3. * (M${iloc}2 + 2 * P${iloc}t ** 2) * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[0].append(Template("-4. / 3. * P${iloc}t * P${iloc}x * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[0].append(Template("-4. / 3. * P${iloc}t * P${iloc}y * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[0].append(Template("-4. / 3. * P${iloc}t * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[1].append(Template("-4. / 3. * P${iloc}t * P${iloc}x * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[1].append(Template(" 2. / 3. * (M${iloc}2 - 2 * P${iloc}x ** 2) * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[1].append(Template("-4. / 3. * P${iloc}x * P${iloc}y * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[1].append(Template("-4. / 3. * P${iloc}x * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[2].append(Template("-4. / 3. * P${iloc}t * P${iloc}y * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[2].append(Template("-4. / 3. * P${iloc}x * P${iloc}y * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[2].append(Template(" 2. / 3. * (M${iloc}2 - 2 * P${iloc}y ** 2) * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[2].append(Template("-4. / 3. * P${iloc}y * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[3].append(Template("-4. / 3. * P${iloc}t * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[3].append(Template("-4. / 3. * P${iloc}x * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[3].append(Template("-4. / 3. * P${iloc}y * P${iloc}z * (M${iloc}2 -p2)*OM${iloc}**2")) tPropA[3].append(Template(" 2. / 3. * (M${iloc}2 - 2 * P${iloc}z ** 2) * (M${iloc}2 -p2)*OM${iloc}**2")) # tensor propagator 1 index contracted tPropB=[[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]] tPropB[0][0].append(Template("4. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (1. - OM${iloc} * P${iloc}t ** 2)")) tPropB[0][0].append(Template("-2 * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}x - 2. / 3. * (1. - OM${iloc} * P${iloc}t ** 2) * (${V}x - ${dot}*OM${iloc} * P${iloc}x)")) tPropB[0][0].append(Template(" -2 * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}y - 2. / 3. * (1. - OM${iloc} * P${iloc}t ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[0][0].append(Template(" -2 * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}z - 2. / 3. * (1. - OM${iloc} * P${iloc}t ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[0][1].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}x / 3. + (1. - OM${iloc} * P${iloc}t ** 2) * (${V}x - ${dot}*OM${iloc} * P${iloc}x)")) tPropB[0][1].append(Template(" (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1. - OM${iloc} * P${iloc}x ** 2) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}x - ${dot}*OM${iloc} * P${iloc}x) / 3.")) tPropB[0][1].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y - OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[0][1].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[0][2].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}y / 3. + (1. - OM${iloc} * P${iloc}t ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[0][2].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y - OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x)")) tPropB[0][2].append(Template(" (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1. - OM${iloc} * P${iloc}y ** 2) - OM${iloc} * P${iloc}t * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) / 3.")) tPropB[0][2].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[0][3].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}z / 3. + (1. - OM${iloc} * P${iloc}t ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[0][3].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x)")) tPropB[0][3].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[0][3].append(Template("(${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1. - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}t * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3.")) tPropB[1][0].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}x / 3. + (1 - OM${iloc} * P${iloc}t ** 2) * (${V}x - ${dot}*OM${iloc} * P${iloc}x)")) tPropB[1][0].append(Template(" (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}x ** 2) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}x - ${dot}*OM${iloc} * P${iloc}x) / 3.")) tPropB[1][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y - OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[1][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[1][1].append(Template(" -2*OM${iloc} * P${iloc}t * P${iloc}x * (${V}x - ${dot}*OM${iloc} * P${iloc}x) - 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropB[1][1].append(Template(" 4. / 3. * (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropB[1][1].append(Template(" -2 * (${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}y - 2. / 3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[1][1].append(Template(" -2 * (${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}z - 2. / 3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[1][2].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y")) tPropB[1][2].append(Template(" -(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}y / 3. + (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[1][2].append(Template(" (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}y ** 2) - OM${iloc} * P${iloc}x * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) / 3.")) tPropB[1][2].append(Template("-(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[1][3].append(Template("-OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z")) tPropB[1][3].append(Template(" -(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}z / 3. + (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[1][3].append(Template(" -(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[1][3].append(Template("(${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}x * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3.")) tPropB[2][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}y / 3. + (1 - OM${iloc} * P${iloc}t ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[2][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y - OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x)")) tPropB[2][0].append(Template(" (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}y ** 2) - OM${iloc} * P${iloc}t * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) / 3.")) tPropB[2][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[2][1].append(Template("-OM${iloc} * P${iloc}t * P${iloc}y * (${V}x - ${dot}*OM${iloc} * P${iloc}x) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}y")) tPropB[2][1].append(Template("-(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}y / 3. + (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[2][1].append(Template(" (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}y ** 2) - OM${iloc} * P${iloc}x * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) / 3.")) tPropB[2][1].append(Template("-(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) + 2. / 3.*OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[2][2].append(Template(" -2*OM${iloc} * P${iloc}t * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropB[2][2].append(Template(" -2*OM${iloc} * P${iloc}x * P${iloc}y * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - 2. / 3. * (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropB[2][2].append(Template("4. / 3. * (${V}y - ${dot}*OM${iloc} * P${iloc}y) * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropB[2][2].append(Template(" -2 * (${V}y - ${dot}*OM${iloc} * P${iloc}y)*OM${iloc} * P${iloc}y * P${iloc}z - 2. / 3. * (-1 - OM${iloc} * P${iloc}y ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[2][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropB[2][3].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropB[2][3].append(Template(" -(${V}y - ${dot}*OM${iloc} * P${iloc}y)*OM${iloc} * P${iloc}y * P${iloc}z / 3. + (-1 - OM${iloc} * P${iloc}y ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[2][3].append(Template(" (${V}y - ${dot}*OM${iloc} * P${iloc}y) * (-1 - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}y * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3.")) tPropB[3][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}t * P${iloc}z / 3. + (1 - OM${iloc} * P${iloc}t ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[3][0].append(Template(" -(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x)")) tPropB[3][0].append(Template("-(${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[3][0].append(Template(" (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}t * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3.")) tPropB[3][1].append(Template("-OM${iloc} * P${iloc}t * P${iloc}z * (${V}x - ${dot}*OM${iloc} * P${iloc}x) - OM${iloc} * P${iloc}t * P${iloc}x * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}x * P${iloc}z")) tPropB[3][1].append(Template(" -(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}x * P${iloc}z / 3. + (-1 - OM${iloc} * P${iloc}x ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[3][1].append(Template(" -(${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z - OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3.*OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y)")) tPropB[3][1].append(Template(" (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}x * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3.")) tPropB[3][2].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - OM${iloc} * P${iloc}t * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropB[3][2].append(Template("-OM${iloc} * P${iloc}x * P${iloc}z * (${V}y - ${dot}*OM${iloc} * P${iloc}y) - OM${iloc} * P${iloc}x * P${iloc}y * (${V}z - ${dot}*OM${iloc} * P${iloc}z) + 2. / 3. * (${V}x - ${dot}*OM${iloc} * P${iloc}x)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropB[3][2].append(Template(" -(${V}y - ${dot}*OM${iloc} * P${iloc}y)*OM${iloc} * P${iloc}y * P${iloc}z / 3. + (-1 - OM${iloc} * P${iloc}y ** 2) * (${V}z - ${dot}*OM${iloc} * P${iloc}z)")) tPropB[3][2].append(Template(" (${V}y - ${dot}*OM${iloc} * P${iloc}y) * (-1 - OM${iloc} * P${iloc}z ** 2) - OM${iloc} * P${iloc}y * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) / 3.")) tPropB[3][3].append(Template(" -2*OM${iloc} * P${iloc}t * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) - 2. / 3. * (${V}t - ${dot}*OM${iloc} * P${iloc}t) * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropB[3][3].append(Template("-2*OM${iloc} * P${iloc}x * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) - 2. / 3. * (${V}x - ${dot}*OM${iloc} * P${iloc}x) * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropB[3][3].append(Template("-2*OM${iloc} * P${iloc}y * P${iloc}z * (${V}z - ${dot}*OM${iloc} * P${iloc}z) - 2. / 3. * (${V}y - ${dot}*OM${iloc} * P${iloc}y) * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropB[3][3].append(Template("4. / 3. * (${V}z - ${dot}*OM${iloc} * P${iloc}z) * (-1 - OM${iloc} * P${iloc}z ** 2)")) # tensor propagator, no contracted indices tPropC=[[[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]], [[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]], [[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]], [[[],[],[],[]],[[],[],[],[]],[[],[],[],[]],[[],[],[],[]]]] tPropC[0][0][0].append(Template("4./3. * (1 - OM${iloc} * P${iloc}t ** 2) ** 2")) tPropC[0][0][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}x")) tPropC[0][0][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}y")) tPropC[0][0][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}z")) tPropC[0][0][1].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}x")) tPropC[0][0][1].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[0][0][1].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y")) tPropC[0][0][1].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z")) tPropC[0][0][2].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}y")) tPropC[0][0][2].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y")) tPropC[0][0][2].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[0][0][2].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropC[0][0][3].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}z")) tPropC[0][0][3].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z")) tPropC[0][0][3].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropC[0][0][3].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[0][1][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}x")) tPropC[0][1][0].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 /3.")) tPropC[0][1][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3.")) tPropC[0][1][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3.")) tPropC[0][1][1].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 /3.")) tPropC[0][1][1].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[0][1][1].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[0][1][1].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[0][1][2].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3.")) tPropC[0][1][2].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[0][1][2].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[0][1][2].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z")) tPropC[0][1][3].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3.")) tPropC[0][1][3].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[0][1][3].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z")) tPropC[0][1][3].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[0][2][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}y")) tPropC[0][2][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3.")) tPropC[0][2][0].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 /3.")) tPropC[0][2][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[0][2][1].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3.")) tPropC[0][2][1].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[0][2][1].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3.")) tPropC[0][2][1].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z")) tPropC[0][2][2].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 /3.")) tPropC[0][2][2].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3.")) tPropC[0][2][2].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[0][2][2].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[0][2][3].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[0][2][3].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z")) tPropC[0][2][3].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[0][2][3].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[0][3][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}z")) tPropC[0][3][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3.")) tPropC[0][3][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[0][3][0].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 /3.")) tPropC[0][3][1].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3.")) tPropC[0][3][1].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[0][3][1].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z")) tPropC[0][3][1].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3.")) tPropC[0][3][2].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[0][3][2].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z")) tPropC[0][3][2].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[0][3][2].append(Template("-OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[0][3][3].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 /3.")) tPropC[0][3][3].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3.")) tPropC[0][3][3].append(Template("-OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[0][3][3].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[1][0][0].append(Template(" -4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}x")) tPropC[1][0][0].append(Template(" (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 /3.")) tPropC[1][0][0].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3.")) tPropC[1][0][0].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3.")) tPropC[1][0][1].append(Template(" (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 /3.")) tPropC[1][0][1].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][0][1].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][0][1].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][0][2].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3.")) tPropC[1][0][2].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][0][2].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[1][0][2].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z")) tPropC[1][0][3].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3.")) tPropC[1][0][3].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][0][3].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z")) tPropC[1][0][3].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[1][1][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][1][0].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][1][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][1][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][1][1].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][1][1].append(Template(" 4./3. * (-1 - OM${iloc} * P${iloc}x ** 2) ** 2")) tPropC[1][1][1].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}y")) tPropC[1][1][1].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}z")) tPropC[1][1][2].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][1][2].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}y")) tPropC[1][1][2].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[1][1][2].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z + 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropC[1][1][3].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][1][3].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}z")) tPropC[1][1][3].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z + 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropC[1][1][3].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[1][2][0].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y")) tPropC[1][2][0].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][2][0].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3.")) tPropC[1][2][0].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[1][2][1].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][2][1].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}y ")) tPropC[1][2][1].append(Template(" (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 /3. ")) tPropC[1][2][1].append(Template(" -(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[1][2][2].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3.")) tPropC[1][2][2].append(Template(" (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 /3. ")) tPropC[1][2][2].append(Template(" -4./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[1][2][2].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[1][2][3].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[1][2][3].append(Template(" -(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[1][2][3].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[1][2][3].append(Template(" 2*OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[1][3][0].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z")) tPropC[1][3][0].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][3][0].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[1][3][0].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3.")) tPropC[1][3][1].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[1][3][1].append(Template("-4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}z ")) tPropC[1][3][1].append(Template("-(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[1][3][1].append(Template("(-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 /3. ")) tPropC[1][3][2].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[1][3][2].append(Template("-(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[1][3][2].append(Template("2*OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[1][3][2].append(Template("-OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[1][3][3].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3.")) tPropC[1][3][3].append(Template("(-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 /3. ")) tPropC[1][3][3].append(Template("-OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[1][3][3].append(Template("-4./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[2][0][0].append(Template("-4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}y ")) tPropC[2][0][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3. ")) tPropC[2][0][0].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 /3. ")) tPropC[2][0][0].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3. ")) tPropC[2][0][1].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y /3. ")) tPropC[2][0][1].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[2][0][1].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3.")) tPropC[2][0][1].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[2][0][2].append(Template("(1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 /3. ")) tPropC[2][0][2].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3.")) tPropC[2][0][2].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][0][2].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[2][0][3].append(Template("-(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3. ")) tPropC[2][0][3].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[2][0][3].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[2][0][3].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[2][1][0].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}y + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}y")) tPropC[2][1][0].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[2][1][0].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3.")) tPropC[2][1][0].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[2][1][1].append(Template("OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}y /3. - OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[2][1][1].append(Template("-4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}y ")) tPropC[2][1][1].append(Template("(-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 /3. ")) tPropC[2][1][1].append(Template("-(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[2][1][2].append(Template("-OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x /3.")) tPropC[2][1][2].append(Template("(-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 /3. ")) tPropC[2][1][2].append(Template("-4./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][1][2].append(Template("OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[2][1][3].append(Template("4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[2][1][3].append(Template("-(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[2][1][3].append(Template("OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[2][1][3].append(Template("2*OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[2][2][0].append(Template("2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][0].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][0].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][0].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][1].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][1].append(Template("2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][1].append(Template("-4./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][1].append(Template("2*OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][2].append(Template("-4./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][2].append(Template("-4./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][2].append(Template("4./3. * (-1 - OM${iloc} * P${iloc}y ** 2) ** 2 ")) tPropC[2][2][2].append(Template("-4./3. * (-1 - OM${iloc} * P${iloc}y ** 2)*OM${iloc} * P${iloc}y * P${iloc}z ")) tPropC[2][2][3].append(Template("2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][3].append(Template("2*OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2) ")) tPropC[2][2][3].append(Template("-4./3. * (-1 - OM${iloc} * P${iloc}y ** 2)*OM${iloc} * P${iloc}y * P${iloc}z ")) tPropC[2][2][3].append(Template("2*OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[2][3][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropC[2][3][0].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[2][3][0].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[2][3][0].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[2][3][1].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[2][3][1].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z + 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropC[2][3][1].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[2][3][1].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[2][3][2].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[2][3][2].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[2][3][2].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}y ** 2)*OM${iloc} * P${iloc}y * P${iloc}z ")) tPropC[2][3][2].append(Template(" (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 /3. ")) tPropC[2][3][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[2][3][3].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[2][3][3].append(Template(" (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 /3. ")) tPropC[2][3][3].append(Template(" -4./3.*OM${iloc} * P${iloc}y * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2) ")) tPropC[3][0][0].append(Template(" -4./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}t * P${iloc}z ")) tPropC[3][0][0].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3. ")) tPropC[3][0][0].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3. ")) tPropC[3][0][0].append(Template(" (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 /3. ")) tPropC[3][0][1].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z /3. ")) tPropC[3][0][1].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[3][0][1].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[3][0][1].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3.")) tPropC[3][0][2].append(Template(" -(1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z /3. ")) tPropC[3][0][2].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[3][0][2].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[3][0][2].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[3][0][3].append(Template(" (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 /3. ")) tPropC[3][0][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3.")) tPropC[3][0][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[3][0][3].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][1][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}x * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}x * P${iloc}z")) tPropC[3][1][0].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[3][1][0].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[3][1][0].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3.")) tPropC[3][1][1].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}x ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}x ** 2)")) tPropC[3][1][1].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}x * P${iloc}z ")) tPropC[3][1][1].append(Template(" -(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[3][1][1].append(Template(" (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 /3. ")) tPropC[3][1][2].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z ")) tPropC[3][1][2].append(Template(" -(-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z /3.")) tPropC[3][1][2].append(Template(" 2*OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z + 2./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[3][1][2].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[3][1][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x /3.")) tPropC[3][1][3].append(Template(" (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 /3. ")) tPropC[3][1][3].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[3][1][3].append(Template(" -4./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2) ")) tPropC[3][2][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}y * P${iloc}z + 2./3. * (1 - OM${iloc} * P${iloc}t ** 2)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropC[3][2][0].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z")) tPropC[3][2][0].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[3][2][0].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[3][2][1].append(Template(" 4./3.*OM${iloc}**2 * P${iloc}t * P${iloc}y * P${iloc}x * P${iloc}z")) tPropC[3][2][1].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}y * P${iloc}z + 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropC[3][2][1].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[3][2][1].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[3][2][2].append(Template(" OM${iloc}**2 * P${iloc}t * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[3][2][2].append(Template(" OM${iloc}**2 * P${iloc}x * P${iloc}y ** 2 * P${iloc}z /3. - OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}y ** 2)")) tPropC[3][2][2].append(Template(" -4./3. * (-1 - OM${iloc} * P${iloc}y ** 2)*OM${iloc} * P${iloc}y * P${iloc}z")) tPropC[3][2][2].append(Template(" (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 /3. ")) tPropC[3][2][3].append(Template(" -OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[3][2][3].append(Template(" -OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y /3.")) tPropC[3][2][3].append(Template(" (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2) + OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 /3. ")) tPropC[3][2][3].append(Template(" -4./3.*OM${iloc} * P${iloc}y * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t ** 2 * P${iloc}z ** 2 - 2./3. * (1 - OM${iloc} * P${iloc}t ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][0].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][0].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2) ")) tPropC[3][3][1].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}x + 2./3.*OM${iloc} * P${iloc}t * P${iloc}x * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][1].append(Template(" 2*OM${iloc}**2 * P${iloc}x ** 2 * P${iloc}z ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}x ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][1].append(Template(" 2*OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][1].append(Template(" -4./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2) ")) tPropC[3][3][2].append(Template(" 2*OM${iloc}**2 * P${iloc}t * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}t * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][2].append(Template(" 2*OM${iloc}**2 * P${iloc}x * P${iloc}z ** 2 * P${iloc}y + 2./3.*OM${iloc} * P${iloc}x * P${iloc}y * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][2].append(Template(" 2*OM${iloc}**2 * P${iloc}y ** 2 * P${iloc}z ** 2 - 2./3. * (-1 - OM${iloc} * P${iloc}y ** 2) * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][2].append(Template(" -4./3.*OM${iloc} * P${iloc}y * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][3].append(Template(" -4./3.*OM${iloc} * P${iloc}t * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][3].append(Template(" -4./3.*OM${iloc} * P${iloc}x * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][3].append(Template(" -4./3.*OM${iloc} * P${iloc}y * P${iloc}z * (-1 - OM${iloc} * P${iloc}z ** 2)")) tPropC[3][3][3].append(Template(" 4./3. * (-1 - OM${iloc} * P${iloc}z ** 2) ** 2")) imap=["t","x","y","z"] RSDotProduct = Template("${s}ts${si}*${v}t-${s}xs${si}*${v}x-${s}ys${si}*${v}y-${s}zs${si}*${v}z") vTemplateT="""\ {header} {{ if({type}W{iloc}.id()=={id}) {{ return {normal}; }} else {{ return {transpose}; }} }}; """ vTemplate4="""\ {header} {{ {swap} if(id{iloc1}=={id1}) {{ if(id{iloc2}=={id2}) {{ return {res1}; }} else {{ return {res2}; }} }} else {{ if(id{iloc2}=={id2}) {{ return {res3}; }} else {{ return {res4}; }} }} }}; """ vecTemplate="""\ Energy2 p2 = P{iloc}.m2(); LorentzPolarizationVector vtemp = {res}; Complex fact = -Complex(0.,1.)*({cf})*propagator(iopt,p2,out,mass,width); if(mass.real() < ZERO) mass = (iopt==5) ? ZERO : out->mass(); complex mass2 = sqr(mass); if(mass.real()==ZERO) {{ vtemp =fact*vtemp; }} else {{ complex dot = P{iloc}*vtemp; vtemp = fact*(vtemp-dot/mass2*P{iloc}); }} return VectorWaveFunction(P{iloc},out,vtemp.x(),vtemp.y(),vtemp.z(),vtemp.t()); """ sTemplate="""\ Energy2 p2 = P{iloc}.m2(); if(mass.real() < ZERO) mass = (iopt==5) ? ZERO : out->mass(); Complex fact = Complex(0.,1.)*({cf})*propagator(iopt,p2,out,mass,width); Lorentz{offTypeA} newSpin = fact*({res}); return {offTypeB}(P{iloc},out,newSpin); """ RSTemplate="""\ if(mass.real() < ZERO) mass = (iopt==5) ? ZERO : out->mass(); Energy2 p2 = P{iloc}.m2(); Complex fact = Complex(0.,-1.)*({cf})*propagator(iopt,p2,out,mass,width); complex Omass = mass.real()==ZERO ? InvEnergy(ZERO) : 1./mass; Lorentz{offTypeA} newSpin = fact*({res}); return {offTypeB}(P{iloc},out,newSpin); """ scaTemplate="""\ if(mass.real() < ZERO) mass = (iopt==5) ? ZERO : out->mass(); Energy2 p2 = P{iloc}.m2(); Complex fact = Complex(0.,1.)*({cf})*propagator(iopt,p2,out,mass,width); complex output = fact*({res}); return ScalarWaveFunction(P{iloc},out,output); """ tenTemplate="""\ if(mass.real() < ZERO) mass = (iopt==5) ? ZERO : out->mass(); InvEnergy2 OM{iloc} = mass.real()==ZERO ? InvEnergy2(ZERO) : 1./sqr(mass.real()); Energy2 M{iloc}2 = sqr(mass.real()); Energy2 p2 = P{iloc}.m2(); Complex fact = Complex(0.,1.)*({cf})*propagator(iopt,p2,out,mass,width); LorentzTensor output = fact*({res}); return TensorWaveFunction(P{iloc},out,output); """ # various strings for matrixes I4 = "Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,1.,0],[0,0,0,1.]])" G5 = "Matrix([[-1.,0,0,0],[0,-1.,0,0],[0,0,1.,0],[0,0,0,1.]])" PM = "Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,0,0],[0,0,0,0]])" PP = "Matrix([[0,0,0,0],[0,0,0,0],[0,0,1.,0],[0,0,0,1.]])" vslash = Template("Matrix([[0,0,${v}TMZ,-${v}XMY],[0,0,-${v}XPY,${v}TPZ],[${v}TPZ,${v}XMY,0,0],[${v}XPY,${v}TMZ,0,0]])") vslashS = Template("${v}TPZ=Symbol(\"${v}TPZ\")\n${v}TMZ=Symbol(\"${v}TMZ\")\n${v}XPY=Symbol(\"${v}XPY\")\n${v}XMY=Symbol(\"${v}XMY\")\n") momCom = Template("${v}t = Symbol(\"${v}t\")\n${v}x = Symbol(\"${v}x\")\n${v}y = Symbol(\"${v}y\")\n${v}z = Symbol(\"${v}z\")\n") vslashD = Template("complex<${var}> ${v}TPZ = ${v}.t()+${v}.z();\n complex<${var}> ${v}TMZ = ${v}.t()-${v}.z();\n complex<${var}> ${v}XPY = ${v}.x()+Complex(0.,1.)*${v}.y();\n complex<${var}> ${v}XMY = ${v}.x()-Complex(0.,1.)*${v}.y();") vslashM = Template("Matrix([[$m,0,${v}TMZ,-${v}XMY],[0,$m,-${v}XPY,${v}TPZ],[${v}TPZ,${v}XMY,$m,0],[${v}XPY,${v}TMZ,0,$m]])") vslashM2 = Template("Matrix([[$m,0,-${v}TMZ,${v}XMY],[0,$m,${v}XPY,-${v}TPZ],[-${v}TPZ,-${v}XMY,$m,0],[-${v}XPY,-${v}TMZ,0,$m]])") vslashMS = Template("${v}TPZ=Symbol(\"${v}TPZ\")\n${v}TMZ=Symbol(\"${v}TMZ\")\n${v}XPY=Symbol(\"${v}XPY\")\n${v}XMY=Symbol(\"${v}XMY\")\n${m}=Symbol(\"${m}\")\nO${m}=Symbol(\"O${m}\")\n") rslash = Template("Matrix([[$m,0,${v}TMZ,-${v}XMY],[0,$m,-${v}XPY,${v}TPZ],[${v}TPZ,${v}XMY,$m,0],[${v}XPY,${v}TMZ,0,$m]])*( ($${eta}-2./3.*O${m}**2*${v}$${A}*${v}$${B})*Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,1.,0],[0,0,0,1.]]) -1./3.*$${DA}*$${DB} -1./3.*O${m}*(${v}$${B}*$${DA}-${v}$${A}*$${DB}))") rslashB = Template("Matrix([[$m,0,${v}TMZ,-${v}XMY],[0,$m,-${v}XPY,${v}TPZ],[${v}TPZ,${v}XMY,$m,0],[${v}XPY,${v}TMZ,0,$m]])*( (${v2}$${A}-2./3.*O${m}**2*${v}$${A}*${dot})*Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,1.,0],[0,0,0,1.]]) -1./3.*$${DA}*${DB} -1./3.*O${m}*(${dot}*$${DA}-${v}$${A}*${DB}))") rslash2 = Template("Matrix([[$m,0,-${v}TMZ,${v}XMY],[0,$m,${v}XPY,-${v}TPZ],[-${v}TPZ,-${v}XMY,$m,0],[-${v}XPY,-${v}TMZ,0,$m]])*( ($${eta}-2./3.*O${m}**2*${v}$${A}*${v}$${B})*Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,1.,0],[0,0,0,1.]]) -1./3.*$${DA}*$${DB} +1./3.*O${m}*(${v}$${B}*$${DA}-${v}$${A}*$${DB}))") rslash2B = Template("Matrix([[$m,0,-${v}TMZ,${v}XMY],[0,$m,${v}XPY,-${v}TPZ],[-${v}TPZ,-${v}XMY,$m,0],[-${v}XPY,-${v}TMZ,0,$m]])*( (${v2}$${B}-2./3.*O${m}**2*${dot}*${v}$${B})*Matrix([[1.,0,0,0],[0,1.,0,0],[0,0,1.,0],[0,0,0,1.]]) -1./3.*${DA}*$${DB} +1./3.*O${m}*(${v}$${B}*${DA}-${dot}*$${DB}))") dirac=["Matrix([[0,0,1.,0],[0,0,0,1.],[1.,0,0,0],[0,1.,0,0]])","Matrix([[0,0,0,1.],[0,0,1.,0],[0,-1.,0,0],[-1.,0,0,0]])", "Matrix([[0,0,0,complex(0, -1.)],[0,0,complex(0, 1.),0],[0,complex(0, 1.),0,0],[complex(0, -1.),0,0,0]])", "Matrix([[0,0,1.,0],[0,0,0,-1.],[-1.,0,0,0],[0,1.,0,0]])"] CC = "Matrix([[0,1.,0,0],[-1.,0,0,0],[0,0,0,-1.],[0,0,1.,0]])" CD = "Matrix([[0,-1.,0,0],[1.,0,0,0],[0,0,0,1.],[0,0,-1.,0]])" evaluateTemplate = """\ {decl} {{ {momenta} {waves} {swap} {symbols} {couplings} {defns} {result} }} """ spinor = Template("Matrix([[${s}s1],[${s}s2],[${s}s3],[${s}s4]])") sbar = Template("Matrix([[${s}s1,${s}s2,${s}s3,${s}s4]])") sline = Template("${s}s1=Symbol(\"${s}s1\")\n${s}s2=Symbol(\"${s}s2\")\n${s}s3=Symbol(\"${s}s3\")\n${s}s4=Symbol(\"${s}s4\")\n") RSSpinorTemplate = Template("${type}(${outxs1},\n${outxs2},\n${outxs3},\n${outxs4},\n${outys1},\n${outys2},\n${outys3},\n${outys4},\n${outzs1},\n${outzs2},\n${outzs3},\n${outzs4},\n${outts1},\n${outts2},\n${outts3},\n${outts4})") SpinorTemplate = Template("${type}(${outs1},\n${outs2},\n${outs3},\n${outs4})") class LorentzIndex : """ A simple classs to store a Lorentz index """ type="" value=0 dimension=0 def __repr__(self): if(self.type=="V" and not isinstance(self.value,int)) : return self.value else : return "%s%s" % (self.type,self.value) def __init__(self,val) : if(isinstance(val,int)) : self.dimension=0 if(val<0) : self.type="D" self.value = val elif(val>0 and val/1000==0) : self.type="E" self.value = val elif(val>0 and val/1000==1) : self.type="T1" self.value = val%1000 elif(val>0 and val/1000==2) : self.type="T2" self.value = val%1000 else : print "Unknown value in Lorentz index:",val raise SkipThisVertex() else : print "Unknown value in Lorentz index:",val raise SkipThisVertex() def __eq__(self,other): if(not isinstance(other,LorentzIndex)) : return False return ( (self.type, self.value) == (other.type, other.value) ) def __hash__(self) : return hash((self.type,self.value)) class DiracMatrix: """A simple class to store Dirac matrices""" name ="" value="" index=0 def __init(self) : self.name="" self.value="" self.index=0 def __repr__(self) : if(self.value==0) : return "%s" % self.index else : return "%s" % self.value class LorentzStructure: """A simple class to store a Lorentz structures""" name="" value=0 lorentz=[] spin=[] def __init(self) : self.name="" self.value=0 self.lorentz=[] self.spin=[] def __repr__(self): output = self.name if((self.name=="P" or self.name=="Tensor") and self.value!=0) : output += "%s" % self.value if(self.name=="int" or self.name=="sign") : output += "=%s" % self.value elif(len(self.spin)==0) : output += "(" for val in self.lorentz : output += "%s," % val output=output.rstrip(",") output+=")" elif(len(self.lorentz)==0) : output += "(" for val in self.spin : output += "%s," % val output=output.rstrip(",") output+=")" else : output += "(" for val in self.lorentz : output += "%s," % val for val in self.spin : output += "%s," % val output=output.rstrip(",") output+=")" return output def LorentzCompare(a,b) : if(a.name=="int" and b.name=="int") : return int(abs(b.value)-abs(a.value)) elif(a.name=="int") : return -1 elif(b.name=="int") : return 1 elif(len(a.spin)==0) : if(len(b.spin)==0) : return len(b.lorentz)-len(a.lorentz) else : return -1 elif(len(b.spin)==0) : return 1 else : if(len(a.spin)==0 or len(b.spin)==0) : print 'Index problem in lorentz compare',\ a.name,b.name,a.spin,b.spin raise SkipThisVertex() if(a.spin[0]>0 or b.spin[1]>0 ) : return -1 if(a.spin[1]>0 or b.spin[0]>0 ) : return 1 if(a.spin[1]==b.spin[0]) : return -1 if(b.spin[1]==a.spin[0]) : return 1 return 0 def extractIndices(struct) : if(struct.find("(")<0) : return [] temp=struct.split("(")[1].split(")")[0].split(",") output=[] for val in temp : output.append(int(val)) return output def parse_structure(structure,spins) : output=[] found = True while(found) : found = False # signs between terms if(structure=="+" or structure=="-") : output.append(LorentzStructure()) output[0].name="sign" output[0].value=structure[0]+"1." output[0].value=float(output[0].value) output[0].lorentz=[] output[0].spin=[] return output # simple numeric pre/post factors elif((structure[0]=="-" or structure[0]=="+") and structure[-1]==")" and structure[1]=="(") : output.append(LorentzStructure()) output[-1].name="int" output[-1].value=structure[0]+"1." output[-1].value=float(output[-1].value) output[-1].lorentz=[] output[-1].spin=[] structure=structure[2:-1] found=True elif(structure[0]=="(") : temp=structure.rsplit(")",1) structure=temp[0][1:] output.append(LorentzStructure()) output[-1].name="int" output[-1].value="1."+temp[1] output[-1].value=float(eval(output[-1].value)) output[-1].lorentz=[] output[-1].spin=[] found=True elif(structure[0:2]=="-(") : temp=structure.rsplit(")",1) structure=temp[0][2:] output.append(LorentzStructure()) output[-1].name="int" output[-1].value="-1."+temp[1] output[-1].value=float(eval(output[-1].value)) output[-1].lorentz=[] output[-1].spin=[] found=True # special handling for powers power = False if("**" in structure ) : power = True structure = structure.replace("**","^") structures = structure.split("*") if(power) : for j in range(0,len(structures)): if(structures[j].find("^")>=0) : temp = structures[j].split("^") structures[j] = temp[0] for i in range(0,int(temp[1])-1) : structures.append(temp[0]) # split up the structure for struct in structures: ind = extractIndices(struct) # different types of object # object with only spin indices if(struct.find("Identity")==0 or struct.find("Proj")==0 or struct.find("Gamma5")==0) : output.append(LorentzStructure()) output[-1].spin=ind output[-1].lorentz=[] output[-1].name=struct.split("(")[0] output[-1].value=0 if(len(struct.replace("%s(%s,%s)" % (output[-1].name,ind[0],ind[1]),""))!=0) : print "Problem handling %s structure " % output[-1].name raise SkipThisVertex() # objects with 2 lorentz indices elif(struct.find("Metric")==0) : output.append(LorentzStructure()) output[-1].lorentz=[LorentzIndex(ind[0]),LorentzIndex(ind[1])] output[-1].name=struct.split("(")[0] output[-1].value=0 output[-1].spin=[] if(len(struct.replace("%s(%s,%s)" % (output[-1].name,ind[0],ind[1]),""))!=0) : print "Problem handling %s structure " % output[-1].name raise SkipThisVertex() elif(struct.find("P(")==0) : output.append(LorentzStructure()) output[-1].lorentz=[LorentzIndex(ind[0])] output[-1].name=struct.split("(")[0] output[-1].value=ind[1] output[-1].spin=[] if(len(struct.replace("%s(%s,%s)" % (output[-1].name,ind[0],ind[1]),""))!=0) : print "Problem handling %s structure " % output[-1].name raise SkipThisVertex() # 1 lorentz and 1 spin index elif(struct.find("Gamma")==0) : output.append(LorentzStructure()) output[-1].lorentz=[LorentzIndex(ind[0])] output[-1].spin=[ind[1],ind[2]] output[-1].name=struct.split("(")[0] output[-1].value=1 if(len(struct.replace("%s(%s,%s,%s)" % (output[-1].name,ind[0],ind[1],ind[2]),""))!=0) : print "problem parsing gamma matrix",struct raise SkipThisVertex() # objects with 4 lorentz indices elif(struct.find("Epsilon")==0) : output.append(LorentzStructure()) output[-1].lorentz=[] for i in range(0,len(ind)) : output[-1].lorentz.append(LorentzIndex(ind[i])) output[-1].spin=[] output[-1].name=struct.split("(")[0] output[-1].value=1 if(len(struct.replace("%s(%s,%s,%s,%s)" % (output[-1].name,ind[0],ind[1],ind[2],ind[3]),""))!=0) : print 'Problem parsing epsilon',struct raise SkipThisVertex() # scalars else : try : output.append(LorentzStructure()) output[-1].value=float(struct) output[-1].name="int" output[-1].lorentz=[] output[-1].spin=[] except : if(struct.find("complex")==0) : vals = struct[0:-1].replace("complex(","").split(",") output[-1].value=complex(float(vals[0]),float(vals[1])) output[-1].name="int" output[-1].lorentz=[] output[-1].spin=[] else : print 'Problem parsing scalar',struct raise SkipThisVertex() # now do the sorting if(len(output)==1) : return output output = sorted(output,cmp=LorentzCompare) # fix indices in the RS case if(4 in spins) : for i in range(0,len(output)) : for ll in range(0,len(output[i].lorentz)) : if(spins[output[i].lorentz[ll].value-1]==4 and output[i].lorentz[ll].type=="E") : output[i].lorentz[ll].type="R" # return the answer return output def constructDotProduct(ind1,ind2,defns) : (ind1,ind2) = sorted((ind1,ind2),cmp=indSort) dimension=ind1.dimension+ind2.dimension # this product already dealt with ? if((ind1,ind2) in defns) : name = defns[(ind1,ind2)][0] # handle the product else : name = "dot%s" % (len(defns)+1) unit = computeUnit(dimension) defns[(ind1,ind2)] = [name,"complex<%s> %s = %s*%s;" % (unit,name,ind1,ind2)] return (name,dimension) def contract(parsed) : for j in range(0,len(parsed)) : if(parsed[j]=="") : continue if(parsed[j].name=="P") : # simplest case if(parsed[j].lorentz[0].type=="E" or parsed[j].lorentz[0].type=="P") : newIndex = LorentzIndex(parsed[j].value) newIndex.type="P" newIndex.dimension=1 parsed[j].name="Metric" parsed[j].lorentz.append(newIndex) parsed[j].lorentz = sorted(parsed[j].lorentz,cmp=indSort) continue ll=1 found=False for k in range(0,len(parsed)) : if(j==k or parsed[k]=="" ) : continue for i in range(0,len(parsed[k].lorentz)) : if(parsed[k].lorentz[i] == parsed[j].lorentz[0]) : parsed[k].lorentz[i].type="P" parsed[k].lorentz[i].value = parsed[j].value parsed[k].lorentz[i].dimension=1 if(parsed[k].name=="P") : parsed[k].lorentz.append(LorentzIndex(parsed[k].value)) parsed[k].lorentz[1].type="P" parsed[k].lorentz[1].dimension=1 parsed[k].name="Metric" parsed[k].value = 0 found=True break if(found) : parsed[j]="" break return [x for x in parsed if x != ""] def computeUnit(dimension) : if(isinstance(dimension,int)) : dtemp = dimension else : dtemp=dimension[1]+dimension[2] if(dtemp==0) : unit="double" elif(dtemp==1) : unit="Energy" elif(dtemp==-1) : unit="InvEnergy" elif(dtemp>0) : unit="Energy%s" % (dtemp) elif(dtemp<0) : unit="InvEnergy%s" % (dtemp) return unit def computeUnit2(dimension,vDim) : # first correct for any coupling power in vertex totalDim = int(dimension[0])+dimension[2]+vDim-4 output="" if(totalDim!=0) : if(totalDim>0) : if(totalDim==1) : output = "1./GeV" elif(totalDim==2) : output = "1./GeV2" else : output="1." for i in range(0,totalDim) : output +="/GeV" else : if(totalDim==-1) : output = "GeV" elif(totalDim==-2) : output = "GeV2" else : output="1." for i in range(0,-totalDim) : output +="*GeV" expr="" # now remove the remaining dimensionality removal=dimension[1]-int(dimension[0])-vDim+4 if(removal!=0) : if(removal>0) : if(removal==1) : expr = "UnitRemovalInvE" else : expr = "UnitRemovalInvE%s" % removal else : if(removal==-1) : expr = "UnitRemovalE" else : expr = "UnitRemovalE%s" % (-removal) if(output=="") : return expr elif(expr=="") : return output else : return "%s*%s" %(output,expr) # order the indices of a dot product def indSort(a,b) : if(not isinstance(a,LorentzIndex) or not isinstance(b,LorentzIndex)) : print "Trying to sort something that's not a Lorentz index",a,b raise SkipThisVertex() if(a.type==b.type) : i1=a.value i2=b.value if(i1>i2) : return 1 elif(i10) : output="+" else : output="-" parsed=[] return (output,parsed,dimension,eps) # replace integers (really lorentz scalars) for j in range(0,len(parsed)) : if(parsed[j]!="" and parsed[j].name=="int") : output *= parsed[j].value parsed[j]="" # bracket this for safety if(output!="") : output = "(%s)" % output # special for tensor indices if("T" in lorentztag) : for j in range(0,len(parsed)) : if(parsed[j]=="") :continue # check for tensor index found=False for li in parsed[j].lorentz : if(li.type[0]=="T") : index = li found=True break if(not found) : continue # workout the other index for the tensor index2 = LorentzIndex(li.value) if(index.type=="T1") : index2.type="T2" else : index2.type="T1" # special is tensor contracted with itself if(parsed[j].name=="Metric" and index2 == parsed[j].lorentz[1]) : parsed[j].name = "Tensor" parsed[j].value = index.value parsed[j].lorentz = [] if(iloc!=index.value) : name= "traceT%s" % parsed[j].value if( name in defns ) : output += "*(%s)" % defns[name][0] else : defns[name] = [name,"Complex %s = T%s.trace();" % (name,parsed[j].value)] output += "*(%s)" % defns[name][0] parsed[j]="" continue # otherwise search for the match for k in range(j+1,len(parsed)) : found = False for li in parsed[k].lorentz : if(li == index2) : found=True break if(not found) : continue if(parsed[j].name=="P") : newIndex1 = LorentzIndex(parsed[j].value) newIndex1.type="P" newIndex1.dimension=1 elif(parsed[j].name=="Metric") : for li in parsed[j].lorentz : if(li != index) : newIndex1=li break else : print 'Unknown object with tensor index, first object',parsed[j] raise SkipThisVertex() if(parsed[k].name=="P") : newIndex2 = LorentzIndex(parsed[k].value) newIndex2.type="P" newIndex2.dimension=1 elif(parsed[k].name=="Metric") : for li in parsed[k].lorentz : if(li != index) : newIndex2=li break elif(parsed[k].name=="Gamma") : # if we can't contract if(index.value==iloc or (newIndex1.type=="E" and newIndex1.value==iloc)) : newIndex2=index2 # otherwise contract else : unit=computeUnit(newIndex1.dimension) if(index.type=="T1") : name="T%s%sF" % (index.value,newIndex1) defns[name] = [name,"LorentzVector > %s = T%s.preDot(%s);" % (unit,name,index.value,newIndex1)] else : name="T%s%sS" % (index.value,newIndex1) defns[name] = [name,"LorentzVector > %s = T%s.postDot(%s);" % (unit,name,index.value,newIndex1)] parsed[j]="" gIndex=LorentzIndex(-1) gIndex.type="V" gIndex.value=name gIndex.dimension=newIndex1.dimension parsed[k].lorentz[0] = gIndex break else : print 'Unknown object with tensor index, second object',parsed[j],parsed[k] raise SkipThisVertex() if(index2.type=="T1") : newIndex1,newIndex2=newIndex2,newIndex1 parsed[j].name = "Tensor" parsed[j].value= int(index.value) parsed[j].lorentz= [newIndex1,newIndex2] if(parsed[k].name!="Gamma") : parsed[k]="" break # main handling of lorentz structures for j in range(0,len(parsed)) : if(parsed[j]=="") : continue if(parsed[j].name=="Metric") : # check whether or not we can contract canContract=True for ll in parsed[j].lorentz : if((ll.type=="E" and ll.value==iloc) or ll.type=="R") : canContract = False break if(not canContract) : continue # if we can do it (name,dTemp) = constructDotProduct(parsed[j].lorentz[0],parsed[j].lorentz[1],defns) output += "*(%s)" % name dimension[2] += dTemp parsed[j]="" elif(parsed[j].name=="Epsilon") : if(not eps) : eps = True # work out which, if any of the indices can be summed over summable=[] for ix in range(0,len(parsed[j].lorentz)) : if(parsed[j].lorentz[ix].type=="P" or (parsed[j].lorentz[ix].type=="E" and iloc !=parsed[j].lorentz[ix].value)) : summable.append(True) else : summable.append(False) sc = summable.count(True) # less than 3 contractable indices, leave for later if(sc<3) : continue # can contract to a vector elif(sc==3) : offLoc = -1 for i in range(0,len(summable)): if(not summable[i]) : offLoc = i break else : offLoc = 0 indices=[] dTemp=0 for ix in range(0,len(parsed[j].lorentz)) : dTemp += parsed[j].lorentz[ix].dimension if(ix!=offLoc) : indices.append(parsed[j].lorentz[ix]) # contract all the indices if(sc==4) : dimension[2] += dTemp iTemp = (parsed[j].lorentz[0],parsed[j].lorentz[1], parsed[j].lorentz[2],parsed[j].lorentz[3]) if(iTemp in defns) : output += "*(%s)" % defns[iTemp][0] parsed[j]="" else : name = "dot%s" % (len(defns)+1) unit = computeUnit(dTemp) defns[iTemp] = [name,"complex<%s> %s =-%s*epsilon(%s,%s,%s);" % (unit,name,parsed[j].lorentz[0], indices[0],indices[1],indices[2]) ] output += "*(%s)" % name parsed[j]="" # contract 3 indices leaving a vector else : iTemp = (indices[0],indices[1],indices[2]) sign = "1" if(offLoc%2!=0) : sign="-1" if(iTemp in defns) : name = defns[iTemp][0] else : name = "V%s" % (len(defns)+1) unit = computeUnit(dTemp) defns[iTemp] = [name,"LorentzVector > %s =-epsilon(%s,%s,%s);" % (unit,name, indices[0],indices[1],indices[2]) ] newIndex = LorentzIndex(int(name[1:])) newIndex.type="V" newIndex.dimension=dTemp output += "*(%s)" % (sign) oi = parsed[j].lorentz[offLoc] if(oi.type!="D") : parsed[j].name="Metric" parsed[j].spins=[] parsed[j].value=0 parsed[j].lorentz=[newIndex,oi] else : found=False for k in range(0,len(parsed)): if(k==j or parsed[k]=="") : continue for ll in range(0,len(parsed[k].lorentz)) : if(parsed[k].lorentz[ll]==oi) : found=True parsed[k].lorentz[ll]=newIndex break if(found) : break if(not found) : print "Problem contracting indices of Epsilon tensor" raise SkipThisVertex() parsed[j]="" elif(parsed[j].name=="Tensor") : # not an external tensor if(parsed[j].value!=iloc) : # now check the lorentz indices con=[] uncon=[] dtemp=0 for li in parsed[j].lorentz : if(li.type=="P" or li.type=="V") : con.append(li) dtemp+=li.dimension elif(li.type=="E") : if(li.value!=iloc) : con.append(li) else : uncon.append(li) else : print "Can't handle index ",li,"in tensor",parsed[j] raise SkipThisVertex() if(len(con)==2) : iTemp = ("T%s%s%s"% (parsed[j].value,con[0],con[1])) dimension[2]+=dtemp if(iTemp in defns) : output += "*(%s)" % defns[iTemp][0] else : unit=computeUnit(dtemp) name = "dot%s" % (len(defns)+1) defns[iTemp] = [name,"complex<%s> %s = T%s.preDot(%s)*%s;" % (unit,name,parsed[j].value,con[0],con[1])] output += "*(%s)" % name parsed[j]="" # handled in final stage else : continue elif(parsed[j].name.find("Proj")>=0 or parsed[j].name.find("Gamma")>=0 or parsed[j].name.find("Identity")>=0) : continue elif(parsed[j].name=="P" and parsed[j].lorentz[0].type=="R") : continue else : print 'Lorentz structure',parsed[j],'not handled' raise SkipThisVertex() # remove leading * if(output!="" and output[0]=="*") : output = output[1:] # remove any (now) empty elements parsed = [x for x in parsed if x != ""] return (output,parsed,dimension,eps) def finalContractions(output,parsed,dimension,lorentztag,iloc,defns) : if(len(parsed)==0) : return (output,dimension) elif(len(parsed)!=1) : print "Summation can't be handled",parsed raise SkipThisVertex() if(parsed[0].name=="Tensor") : # contracted with off-shell vector if(parsed[0].value!=iloc) : found = False for ll in parsed[0].lorentz : if(ll.type=="E" and ll.value==iloc) : found = True else : lo=ll if(found) : dimension[2]+= lo.dimension unit=computeUnit(lo.dimension) if(lo==parsed[0].lorentz[0]) : name="T%s%sF" % (parsed[0].value,lo) defns[name] = [name,"LorentzVector > %s = T%s.preDot(%s);" % (unit,name,parsed[0].value,lo)] else : name="T%s%sS" % (parsed[0].value,lo) defns[name] = [name,"LorentzVector > %s = T%s.postDot(%s);" % (unit,name,parsed[0].value,lo)] parsed[0]="" if(output=="") : output="1." output = "(%s)*(%s)" %(output,name) else : print "Can\'t contract tensor",lo,iloc raise SkipThisVertex() # off-shell tensor else : if(len(parsed[0].lorentz)!=0) : dimension[2]+=parsed[0].lorentz[0].dimension+parsed[0].lorentz[1].dimension tensor = tensorPropagator(parsed[0],defns) if(output=="") : output="1." output = [output,tensor,()] elif(parsed[0].name=="Metric") : found = False for ll in parsed[0].lorentz : if(ll.type=="E" and ll.value==iloc) : found = True else : lo=ll if(found) : parsed[0]="" dimension[2] += lo.dimension if(output=="") : output="1." output = "(%s)*(%s)" %(output,lo) else : print "Structure can't be handled",parsed,iloc raise SkipThisVertex() return (output,dimension) def tensorPropagator(struct,defns) : # dummy index i0 = LorentzIndex(-1000) # index for momentum of propagator ip = LorentzIndex(struct.value) ip.type="P" ip.dimension=1 # the metric tensor terms=[] if(len(struct.lorentz)==0) : (dp,dTemp) = constructDotProduct(ip,ip,defns) pre = "-1./3.*(1.-%s*OM%s)" % (dp,struct.value) terms.append((pre,i0,i0)) pre = "-2./3.*(1.-%s*OM%s)" % (dp,struct.value) terms.append(("%s*OM%s" %(pre,struct.value),ip,ip)) else : # indices of the tensor ind1 = struct.lorentz[0] ind2 = struct.lorentz[1] # the dot products we need (d1,dtemp) = constructDotProduct(ind1,ip,defns) (d2,dtemp) = constructDotProduct(ind2,ip,defns) (d3,dtemp) = constructDotProduct(ind1,ind2,defns) # various terms in the propagator terms.append(("0.5",ind1,ind2)) terms.append(("-0.5*OM%s*%s"%(struct.value,d1),ip,ind2)) terms.append(("-0.5*OM%s*%s"%(struct.value,d2),ind1,ip)) terms.append(("0.5",ind2,ind1)) terms.append(("-0.5*OM%s*%s"%(struct.value,d2),ip,ind1)) terms.append(("-0.5*OM%s*%s"%(struct.value,d1),ind2,ip)) terms.append(("-1./3.*"+d3,i0,i0)) terms.append(("1./3.*OM%s*%s*%s"%(struct.value,d1,d2),i0,i0)) terms.append(("1./3.*OM%s*%s"%(struct.value,d3),ip,ip)) terms.append(("2./3.*OM%s*OM%s*%s*%s"%(struct.value,struct.value,d1,d2),ip,ip)) # compute the output as a dict output={} for i1 in imap: for i2 in imap : val="" for term in terms: if(term[0][0]!="-") : pre = "+"+term[0] else : pre = term[0] if(term[1]==i0) : if(i1==i2) : if(i1=="t") : val += pre else : if(pre[0]=="+") : val +="-"+pre[1:] else : val +="+"+pre[1:] else : val += "%s*%s%s*%s%s" % (pre,term[1],i1,term[2],i2) output["%s%s" % (i1,i2) ] = val.replace("+1*","+").replace("-1*","-") return output def generateVertex(iloc,L,parsed,lorentztag,vertex,defns) : # try to import sympy and exit if required try : import sympy from sympy import Matrix,Symbol except : print 'ufo2herwig uses the python sympy module to translate general lorentz structures.' print 'This must be installed if you wish to use this option.' print 'EXITTING' quit() eps=False # parse the lorentz structures output = [1.]*len(parsed) dimension=[] for i in range(0,len(parsed)) : dimension.append([0,0,0]) for i in range (0,len(parsed)) : (output[i],parsed[i],dimension[i],eps) = finishParsing(parsed[i],dimension[i],lorentztag,iloc,defns,eps) # still need to process gamma matrix strings for fermions if(lorentztag[0] in ["F","R"] ) : return convertDirac(output,dimension,eps,iloc,L,parsed,lorentztag,vertex,defns) # return the answer else : handled=True for i in range (0,len(parsed)) : if(len(parsed[i])!=0) : handled = False break if(not handled) : for i in range (0,len(parsed)) : (output[i],dimension[i]) = finalContractions(output[i],parsed[i],dimension[i],lorentztag,iloc,defns) return (output,dimension,eps) def convertDirac(output,dimension,eps,iloc,L,parsed,lorentztag,vertex,defns) : for i in range(0,len(parsed)): # skip empty elements if(len(parsed[i])==0 or (len(parsed[i])==1 and parsed[i][0]=="")) : continue # parse the string (output[i],dimension[i],defns) = convertDiracStructure(parsed[i],output[i],dimension[i], defns,iloc,L,lorentztag,vertex) return (output,dimension,eps) # parse the gamma matrices def convertMatrix(structure,spins,unContracted,Symbols,dtemp,defns,iloc) : i1 = structure.spin[0] i2 = structure.spin[1] if(structure.name=="Identity") : output = DiracMatrix() output.value = I4 output.index=0 output.name="M" structure="" elif(structure.name=="Gamma5") : output = DiracMatrix() output.value = G5 output.index=0 output.name="M" structure="" elif(structure.name=="ProjM") : output = DiracMatrix() output.value = PM output.index=0 output.name="M" structure="" elif(structure.name=="ProjP") : output = DiracMatrix() output.value = PP output.index=0 output.name="M" structure="" elif(structure.name=="Gamma") : # gamma(mu) lorentz matrix contracted with dummy index if(structure.lorentz[0].type=="D" or structure.lorentz[0].type=="R") : if(structure.lorentz[0] not in unContracted) : unContracted[structure.lorentz[0]] = 0 output = DiracMatrix() output.value=0 output.index=structure.lorentz[0] output.name="GMU" structure="" elif(structure.lorentz[0].type == "E" and structure.lorentz[0].value == iloc ) : if(structure.lorentz[0] not in unContracted) : unContracted[structure.lorentz[0]] = 0 output = DiracMatrix() output.value=0 output.index=structure.lorentz[0] output.name="GMU" structure="" elif(structure.lorentz[0].type == "T1" or structure.lorentz[0].type == "T2") : if(structure.lorentz[0] not in unContracted) : unContracted[structure.lorentz[0]] = 0 output = DiracMatrix() output.value=0 output.index=structure.lorentz[0] output.name="GMU" structure="" else : output=DiracMatrix() output.name="M" output.value = vslash.substitute({ "v" : structure.lorentz[0]}) Symbols += vslashS.substitute({ "v" : structure.lorentz[0]}) variable = computeUnit(structure.lorentz[0].dimension) #if(structure.lorentz[0].type!="V" or # structure.lorentz[0].type=="V") : dtemp[2] += structure.lorentz[0].dimension defns["vv%s" % structure.lorentz[0] ] = \ ["vv%s" % structure.lorentz[0], vslashD.substitute({ "var" : variable, "v" : structure.lorentz[0]})] structure="" else : print 'Unknown Gamma matrix structure',structure raise SkipThisVertex() return (i1,i2,output,structure,Symbols) def checkRSContract(parsed,loc,dtemp) : rindex=LorentzIndex(loc) rindex.type="R" contract="" for i in range(0,len(parsed)) : if(parsed[i]=="") : continue found = False for ll in range(0,len(parsed[i].lorentz)) : if(parsed[i].lorentz[ll]==rindex) : found=True break if(not found) : continue if(parsed[i].name=="P") : dtemp[2]+=1 contract = LorentzIndex(parsed[i].value) contract.type="P" contract.dimension=1 parsed[i]="" break elif(parsed[i].name=="Metric") : for ll in parsed[i].lorentz : if(ll==rindex) : continue else : break if(ll.type=="P") : dtemp[2]+=1 contract=ll parsed[i]="" break elif(parsed[i].name=="Epsilon") : continue else : print "Unkonwn type contracted with RS spinor",parsed[i] raise SkipThisVertex() return contract def processChain(dtemp,parsed,spins,Symbols,unContracted,defns,iloc) : # piece of dimension which is common (0.5 for sbar and spinor) dtemp[0]+=1 # set up the spin indices sind = 0 lind = 0 expr=[] # now find the next thing in the matrix string ii = 0 index=0 while True : # already handled if(parsed[ii]=="") : ii+=1 continue # start of the chain elif(sind==0 and len(parsed[ii].spin)==2 and parsed[ii].spin[0]>0 ) : (sind,index,matrix,parsed[ii],Symbols) \ = convertMatrix(parsed[ii],spins,unContracted,Symbols,dtemp,defns,iloc) expr.append(matrix) # next element in the chain elif(index!=0 and len(parsed[ii].spin)==2 and parsed[ii].spin[0]==index) : (crap,index,matrix,parsed[ii],Symbols) \ = convertMatrix(parsed[ii],spins,unContracted,Symbols,dtemp,defns,iloc) expr.append(matrix) # check the index to see if we're at the end if(index>0) : lind=index break ii+=1 if(ii>=len(parsed)) : print "Can't parsed the chain of dirac matrices" print parsed raise SkipThisVertex() # start and end of the spin chains # first particle spin 1/2 if(spins[sind-1]==2) : start = DiracMatrix() endT = DiracMatrix() start.index=0 endT .index=0 # start of chain and end of transpose # off shell if(sind==iloc) : start.name="M" endT .name="M" start.value = vslashM .substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind} ) Symbols += vslashMS.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind} ) endT.value = vslashM2.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind} ) defns["vvP%s" % sind ] = ["vvP%s" % sind , vslashD.substitute({ "var" : "Energy", "v" : "P%s" % sind })] dtemp[1]+=1 # onshell else : start.name="S" endT .name="S" subs = {'s' : ("sbar%s" % sind)} start.value = sbar .substitute(subs) Symbols += sline.substitute(subs) subs = {'s' : ("s%s" % sind)} endT.value = spinor.substitute(subs) Symbols += sline.substitute(subs) # spin 3/2 fermion elif spins[sind-1]==4 : # check if we can easily contract contract=checkRSContract(parsed,sind,dtemp) # off-shell if(sind==iloc) : oindex = LorentzIndex(sind) oindex.type="O" unContracted[oindex]=0 Symbols += vslashMS.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind} ) Symbols += momCom.substitute({"v" : "P%s" %sind }) defns["vvP%s" % sind ] = ["vvP%s" % sind , vslashD.substitute({ "var" : "Energy", "v" : "P%s" % sind })] dtemp[1] += 1 if(contract=="") : rindex = LorentzIndex(sind) rindex.type="R" start=DiracMatrix() start.value = Template(rslash.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind, "loc" : sind })) start.name = "RP" start.index = (oindex,rindex) endT=DiracMatrix() endT.value = Template(rslash2.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind, "loc" : sind })) endT.name = "RP" endT.index = (rindex,oindex) else : # construct dot product pi = LorentzIndex(sind) pi.type="P" pi.dimension=1 (name,dummy) = constructDotProduct(pi,contract,defns) Symbols += momCom.substitute({"v" : contract }) RB = vslash.substitute({ "v" : contract}) Symbols += vslashS.substitute({ "v" : contract }) Symbols += "%s = Symbol('%s')\n" % (name,name) defns["vv%s" % contract ] = ["vv%s" % contract, vslashD.substitute({ "var" : computeUnit(contract.dimension), "v" : "%s" % contract })] start=DiracMatrix() start.name="RQ" start.index = oindex start.value =Template( rslashB.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind, "loc" : sind, "DB" : RB, "dot" : name , "v2" : contract})) endT=DiracMatrix() endT.name = "RQ" endT.index = oindex endT.value = Template(rslash2B.substitute({ "v" : "P%s" % sind, "m" : "M%s" % sind, "loc" : sind , "DA" : RB, "dot" : name , "v2" : contract})) # on-shell else : start = DiracMatrix() endT = DiracMatrix() # no contraction if(contract=="" or (contract.type=="E" and contract.value==iloc) ) : if contract == "" : contract = LorentzIndex(sind) contract.type="R" # start of matrix string start.value = Template(sbar .substitute({'s' : ("Rsbar%s${L}" % sind)})) start.name="RS" start.index = contract # end of transpose string endT.value=Template(spinor.substitute({'s' : ("Rs%s${L}" % sind)})) endT.name="RS" endT.index = contract unContracted[contract]=0 # variables for sympy for LI in imap : Symbols += sline.substitute({'s' : ("Rs%s%s" % (sind,LI))}) Symbols += sline.substitute({'s' : ("Rsbar%s%s" % (sind,LI))}) else : # start of matrix string start.name="S" start.value = "Matrix([[%s,%s,%s,%s]])" % (RSDotProduct.substitute({'s' : ("Rsbar%s" % sind), 'v':contract, 'si' : 1}), RSDotProduct.substitute({'s' : ("Rsbar%s" % sind), 'v':contract, 'si' : 2}), RSDotProduct.substitute({'s' : ("Rsbar%s" % sind), 'v':contract, 'si' : 3}), RSDotProduct.substitute({'s' : ("Rsbar%s" % sind), 'v':contract, 'si' : 4})) endT.name="S" endT.value = "Matrix([[%s],[%s],[%s],[%s]])" % (RSDotProduct.substitute({'s' : ("Rs%s" % sind), 'v':contract, 'si' : 1}), RSDotProduct.substitute({'s' : ("Rs%s" % sind), 'v':contract, 'si' : 2}), RSDotProduct.substitute({'s' : ("Rs%s" % sind), 'v':contract, 'si' : 3}), RSDotProduct.substitute({'s' : ("Rs%s" % sind), 'v':contract, 'si' : 4})) Symbols += momCom.substitute({"v" : contract }) for LI in ["x","y","z","t"] : Symbols += sline.substitute({'s' : ("Rs%s%s" % (sind,LI))}) Symbols += sline.substitute({'s' : ("Rsbar%s%s" % (sind,LI))}) # last particle spin 1/2 if( spins[lind-1]==2 ) : end = DiracMatrix() startT = DiracMatrix() end .index=0 startT.index=0 # end of chain if(lind==iloc) : end.name ="M" startT.name="M" end.value = vslashM2.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind} ) startT.value = vslashM.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind} ) Symbols += vslashMS.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind} ) defns["vvP%s" % lind ] = ["vvP%s" % lind , vslashD.substitute({ "var" : "Energy", "v" : "P%s" % lind })] dtemp[1] += 1 else : startT.name="S" end .name="S" subs = {'s' : ("s%s" % lind)} end.value = spinor.substitute(subs) Symbols += sline.substitute(subs) subs = {'s' : ("sbar%s" % lind)} startT.value = sbar .substitute(subs) Symbols += sline.substitute(subs) # last particle spin 3/2 elif spins[lind-1]==4 : # check if we can easily contract contract=checkRSContract(parsed,lind,dtemp) # off-shell if(lind==iloc) : oindex = LorentzIndex(lind) oindex.type="O" unContracted[oindex]=0 Symbols += vslashMS.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind} ) Symbols += momCom.substitute({"v" : "P%s" %lind }) defns["vvP%s" % lind ] = ["vvP%s" % lind , vslashD.substitute({ "var" : "Energy", "v" : "P%s" % lind })] dtemp[1] += 1 if(contract=="") : rindex = LorentzIndex(lind) rindex.type="R" end=DiracMatrix() end.value = Template(rslash2.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind, "loc" : lind })) end.name = "RP" end.index = (rindex,oindex) startT=DiracMatrix() startT.value=Template(rslash.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind, "loc" : lind })) startT.name = "RP" startT.index = (oindex,rindex) else : # construct dot product pi = LorentzIndex(lind) pi.type="P" pi.dimension=1 (name,unit) = constructDotProduct(pi,contract,defns) Symbols += momCom.substitute({"v" : contract }) RB = vslash.substitute({ "v" : contract}) Symbols += vslashS.substitute({ "v" : contract }) Symbols += "%s = Symbol('%s')\n" % (name,name) defns["vv%s" % contract ] = ["vv%s" % contract, vslashD.substitute({ "var" : computeUnit(contract.dimension), "v" : "%s" % contract })] end=DiracMatrix() end.name="RQ" end.index = oindex end.value =Template( rslash2B.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind, "loc" : lind, "DA" : RB, "dot" : name , "v2" : contract})) startT=DiracMatrix() startT.name = "RQ" startT.index = oindex startT.value = Template(rslashB.substitute({ "v" : "P%s" % lind, "m" : "M%s" % lind, "loc" : lind , "DB" : RB, "dot" : name , "v2" : contract})) # on-shell else : end = DiracMatrix() startT = DiracMatrix() # no contraction if(contract=="" or (contract.type=="E" and contract.value==iloc) ) : if contract == "" : contract = LorentzIndex(lind) contract.type="R" # end of matrix string end.value = Template(spinor.substitute({'s' : ("Rs%s${L}" % lind)})) end.name = "RS" end.index = contract # start of matrix string startT.value = Template(sbar .substitute({'s' : ("Rsbar%s${L}" % lind)})) startT.name = "RS" startT.index = contract unContracted[contract]=0 # variables for sympy for LI in imap : Symbols += sline.substitute({'s' : ("Rs%s%s" % (lind,LI))}) Symbols += sline.substitute({'s' : ("Rsbar%s%s" % (lind,LI))}) # contraction else : # end of the matrix string end.name = "S" end.value = "Matrix([[%s],[%s],[%s],[%s]])" % (RSDotProduct.substitute({'s' : ("Rs%s" % lind), 'v':contract, 'si' : 1}), RSDotProduct.substitute({'s' : ("Rs%s" % lind), 'v':contract, 'si' : 2}), RSDotProduct.substitute({'s' : ("Rs%s" % lind), 'v':contract, 'si' : 3}), RSDotProduct.substitute({'s' : ("Rs%s" % lind), 'v':contract, 'si' : 4})) startT.name = "S" startT.value = "Matrix([[%s,%s,%s,%s]])" % (RSDotProduct.substitute({'s' : ("Rsbar%s" % lind), 'v':contract, 'si' : 1}), RSDotProduct.substitute({'s' : ("Rsbar%s" % lind), 'v':contract, 'si' : 2}), RSDotProduct.substitute({'s' : ("Rsbar%s" % lind), 'v':contract, 'si' : 3}), RSDotProduct.substitute({'s' : ("Rsbar%s" % lind), 'v':contract, 'si' : 4})) Symbols += momCom.substitute({"v" : contract }) for LI in ["x","y","z","t"] : Symbols += sline.substitute({'s' : ("Rs%s%s" % (lind,LI))}) Symbols += sline.substitute({'s' : ("Rsbar%s%s" % (lind,LI))}) return(sind,lind,expr,start,startT,end,endT,Symbols) def calculateDirac(expr,start,end,startT,endT,sind,lind,Symbols,iloc) : res=[] for ichain in range(0,len(start)) : # calculate the matrix string etemp="*".join(str(x) for x in expr[ichain]) temp={} exec("import sympy\nfrom sympy import Symbol,Matrix\n"+Symbols+"result="+ ( "%s*%s*%s" %(start[ichain],etemp,end[ichain]))) in temp res.append(temp["result"]) tempT={} exec("import sympy\nfrom sympy import Symbol,Matrix,Transpose\n"+Symbols+"result="+ - ( "%s*%s*Transpose(%s)*%s*%s" %(startT[0],CC,etemp,CD,endT[0]))) in tempT + ( "%s*%s*Transpose(%s)*%s*%s" %(startT[ichain],CC,etemp,CD,endT[ichain]))) in tempT res.append(tempT["result"]) if(len(start)==1) : - if(iloc==0 or (iloc!=sind[0] and iloc!=lind[0])) : + if(iloc==0 or (iloc!=sind[ichain] and iloc!=lind[ichain])) : sVal = {'s' : temp ["result"][0,0],'sT' : tempT["result"][0,0]} else : sVal={} for jj in range(1,5) : sVal["s%s" % jj] = temp ["result"][jj-1] sVal["sT%s" % jj] = tempT["result"][jj-1] else : sVal={} sVal["s" ] = res[0][0,0]*res[2][0,0] sVal["sT2" ] = res[0][0,0]*res[3][0,0] sVal["sT1" ] = res[1][0,0]*res[2][0,0] sVal["sT12"] = res[1][0,0]*res[3][0,0] return sVal def addToOutput(res,nchain,sign,rTemp) : # 1 spin chain if(nchain==1) : for ii in range(0,2) : if(rTemp[ii][0].shape[0]==1) : # result is scalar if(rTemp[ii][0].shape[1]==1) : if(len(res[ii])==0) : res[ii].append(sign*rTemp [ii][0][0,0]) else : res[ii][0] += sign*rTemp [ii][0][0,0] # result is a spinor elif(rTemp[ii][0].shape[1]==4) : if(len(res[ii])==0) : for j in range(0,4) : res[ii].append(sign*rTemp[ii][0][0,j]) else : for j in range(0,4) : res[ii][j] += sign*rTemp[ii][0][0,j] else : print "Size problem adding results A",sign,rTemp[ii].shape raise SkipThisVertex() # spinor elif(rTemp[ii][0].shape[0]==4 and rTemp[ii][0].shape[1]==1 ) : if(len(res[ii])==0) : for j in range(0,4) : res[ii].append(sign*rTemp[ii][0][j,0]) else : for j in range(0,4) : res[ii][j] += sign*rTemp[ii][0][j,0] else : print "Size problem adding results A",sign,rTemp[ii][0].shape raise SkipThisVertex() # 2 spin chains, should only be for a vertex else : for j1 in range(0,2) : for j2 in range (0,2) : val = sign*rTemp[j1][0]*rTemp[j2][1] if(len(res[3])==0) : res[2*j1+j2].append(val[0,0]) else : res[2*j1+j2][0] += val[0,0] def calculateDirac2(expr,start,end,startT,endT,sind,lind,Symbols,defns, iloc,unContracted,spins,lorentz) : tDot="" # output sVal={} # no of chains nchain=len(expr) # now deal with the uncontracted cases contracted={} # sort out contracted and uncontracted indices keys = unContracted.keys() for key in keys: # summed dummy index if key.type=="D" : contracted[key]=0 del unContracted[key] # RS index elif key.type =="R" : contracted[key]=0 del unContracted[key] # tensor index elif key.type == "T1" or key.type=="T2" : contracted[key]=0 del unContracted[key] # external index elif key.type == "O" : continue # uncontracted vector index elif key.type=="E" or key.type=="Q": continue else : print 'Unknown type of uncontracted index',key raise SkipThisVertex() # check the lorentz structures for lstruct in lorentz : if(lstruct.name=="Epsilon" or lstruct.name=="Vector") : for index in lstruct.lorentz : if(index.type=="E" and index.value==iloc) : unContracted[index]=0 elif(index.type=="P" or index.type=="E" or index.type=="R" or index.type=="D") : contracted[index]=0 else : print 'Unknown index',index, 'in ',lstruct raise SkipThisVertex() elif(lstruct.name=="Tensor") : if(iloc==lstruct.value) : Symbols += momCom.substitute({"v": "P%s"%lstruct.value}) Symbols += "OM%s = Symbol(\"OM%s\")\n" % (lstruct.value,lstruct.value) Symbols += "M%s2 = Symbol(\"M%s2\")\n" % (lstruct.value,lstruct.value) Symbols += "p2 = Symbol(\"p2\")\n" for ival in range(1,3) : newIndex=LorentzIndex(ival) newIndex.type="O" newIndex.dimension=0 lstruct.lorentz.append(newIndex) unContracted[newIndex]=0 # contracted with self if(len(lstruct.lorentz)==0) : pass # both indices uncontracted, deal with later elif lstruct.lorentz[0].type=="T1" and lstruct.lorentz[1].type=="T2": pass elif lstruct.lorentz[0].type=="T1": pIndex = LorentzIndex(lstruct.value) pIndex.dimension=1 pIndex.type="P" (tDot,dtemp) = constructDotProduct(pIndex,lstruct.lorentz[1],defns) Symbols+="%s = Symbol(\"%s\")\n" %(tDot,tDot) Symbols += momCom.substitute({"v": lstruct.lorentz[1]}) elif lstruct.lorentz[1].type=="T2" : pIndex = LorentzIndex(lstruct.value) pIndex.dimension=1 pIndex.type="P" (tDot,dtemp) = constructDotProduct(pIndex,lstruct.lorentz[0],defns) Symbols+="%s = Symbol(\"%s\")\n" %(tDot,tDot) Symbols += momCom.substitute({"v": lstruct.lorentz[0]}) # both indices still to be contracted else : contracted[lstruct.lorentz[0].type]=0 contracted[lstruct.lorentz[1].type]=0 else : print 'Unknown lorentz object in calculateDirac2',lstruct,iloc raise SkipThisVertex() # iterate over the uncontracted indices while True : # loop over the unContracted indices res = [] for i in range(0,nchain) : res.append([]) res.append([]) # loop over the contracted indices while True : # sign from metric tensor in contractions sign = 1 for key,val in contracted.iteritems() : if(val>0) : sign *=-1 eTemp =[] sTemp =[] fTemp =[] sTTemp=[] fTTemp=[] # make the necessary replacements for remaining indices for ichain in range(0,nchain) : # compute the main expression eTemp.append([]) for val in expr[ichain] : # already a matrix if(val.name=="M") : eTemp[ichain].append(val) # gamma(mu), replace with correct dirac matrix elif(val.name=="GMU") : if(val.index in contracted) : eTemp[ichain].append(dirac[contracted[val.index]]) elif(val.index in unContracted) : eTemp[ichain].append(dirac[unContracted[val.index]]) else : print 'Unknown index for gamma matrix',val raise SkipThisVertex() # unknown to be sorted out else : print 'Unknown type in expr',val raise SkipThisVertex() # start and end # start if(start[ichain].name=="S" or start[ichain].name=="M" ) : sTemp.append(start[ichain].value) elif(start[ichain].name=="RS") : if(start[ichain].index in contracted) : sTemp.append(start[ichain].value.substitute({"L" : imap[ contracted[start[ichain].index]] })) else : sTemp.append(start[ichain].value.substitute({"L" : imap[unContracted[start[ichain].index]] })) elif(start[ichain].name=="RQ") : i1 = unContracted[start[ichain].index] sTemp.append(start[ichain].value.substitute({"A" : imap[i1], "DA" : dirac[i1] })) elif(start[ichain].name=="RP") : i1 = unContracted[start[ichain].index[0]] i2 = contracted[start[ichain].index[1]] eta=0 if(i1==i2) : if(i1==0) : eta = 1 else : eta = -1 sTemp.append(start[ichain].value.substitute({"eta" : eta, "A":imap[i1] , "B":imap[i2] , "DA": dirac[i1], "DB": dirac[i2]})) else : print 'Barred spinor not a spinor',start[ichain] raise SkipThisVertex() if(startT[ichain].name=="S" or startT[ichain].name=="M" ) : sTTemp.append(startT[ichain].value) elif(startT[ichain].name=="RS") : if(startT[ichain].index in contracted) : sTTemp.append(startT[ichain].value.substitute({"L" : imap[ contracted[startT[ichain].index]] })) else : sTTemp.append(startT[ichain].value.substitute({"L" : imap[unContracted[startT[ichain].index]] })) elif(startT[ichain].name=="RQ") : i1 = unContracted[startT[ichain].index] sTTemp.append(startT[ichain].value.substitute({"A" : imap[i1], "DA" : dirac[i1] })) elif(startT[ichain].name=="RP") : i1 = unContracted[startT[ichain].index[0]] i2 = contracted[startT[ichain].index[1]] eta=0 if(i1==i2) : if(i1==0) : eta = 1 else : eta = -1 sTTemp.append(startT[ichain].value.substitute({"eta" : eta, "A":imap[i1] , "B":imap[i2] , "DA": dirac[i1], "DB": dirac[i2]})) else : print 'barred spinorT not a spinor',startT[ichain] raise SkipThisVertex() # end if(end[ichain].name=="S" or end[ichain].name=="M" ) : fTemp.append(end[ichain].value) elif(end[ichain].name=="RS") : if(end[ichain].index in contracted) : fTemp.append(end[ichain].value.substitute({"L" : imap[ contracted[end[ichain].index]] })) else : fTemp.append(end[ichain].value.substitute({"L" : imap[unContracted[end[ichain].index]] })) elif(end[ichain].name=="RQ") : i1 = unContracted[end[ichain].index] fTemp.append(end[ichain].value.substitute({"B" : imap[i1], "DB": dirac[i1] })) elif(end[ichain].name=="RP") : i1 = contracted[end[ichain].index[0]] i2 = unContracted[end[ichain].index[1]] eta=0 if(i1==i2) : if(i1==0) : eta = 1 else : eta = -1 fTemp.append(end[ichain].value.substitute({"eta" : eta, "A":imap[i1] , "B":imap[i2] , "DA": dirac[i1], "DB": dirac[i2]})) else : print 'spinor not a spinor',end[ichain] raise SkipThisVertex() if(endT[ichain].name=="S" or endT[ichain].name=="M" ) : fTTemp.append(endT[ichain].value) elif(endT[ichain].name=="RS") : if(endT[ichain].index in contracted) : fTTemp.append(endT[ichain].value.substitute({"L" : imap[ contracted[endT[ichain].index]] })) else : fTTemp.append(endT[ichain].value.substitute({"L" : imap[unContracted[endT[ichain].index]] })) elif(endT[ichain].name=="RQ") : i1 = unContracted[endT[ichain].index] fTTemp.append(endT[ichain].value.substitute({"B" : imap[i1], "DB": dirac[i1] })) elif(endT[ichain].name=="RP") : i1 = contracted[endT[ichain].index[0]] i2 = unContracted[endT[ichain].index[1]] eta=0 if(i1==i2) : if(i1==0) : eta = 1 else : eta = -1 fTTemp.append(endT[ichain].value.substitute({"eta" : eta, "A":imap[i1] , "B":imap[i2] , "DA": dirac[i1], "DB": dirac[i2]})) else : print 'spinorT not a spinor',endT[ichain] raise SkipThisVertex() # and none dirac lorentz structures isZero = False for li in lorentz: # uncontracted vector if(li.name=="Vector") : index = unContracted[li.lorentz[0]] Symbols += momCom.substitute({"v":li.value}) for ichain in range(0,nchain) : eTemp[ichain].append("%s%s"% (li.value,imap[index]) ) elif(li.name=="Epsilon") : value="" ival=[] for index in li.lorentz : if(index in contracted) : if(index.type=="P" or index.type=="E") : value += "*%s%s" % (index,imap[contracted[index]]) ival.append(contracted[index]) elif(index.type=="R" or index.type=="D") : ival.append(contracted[index]) else : print 'Unknown index in Epsilon Tensor',index raise SkipThisVertex() elif(index in unContracted) : ival.append(unContracted[index]) if(len(value)!=0 and value[0]=="*") : value = value[1:] eVal = epsValue[ival[0]][ival[1]][ival[2]][ival[3]] if(eVal==0) : isZero = True else : for ichain in range(0,nchain) : eTemp[ichain].append("(%s*%s)"% (eVal,value) ) elif(li.name=="Tensor") : if(li.lorentz[0] in unContracted and li.lorentz[1] in unContracted) : value='0.5*(%s)'%tPropA[unContracted[li.lorentz[0]]][unContracted[li.lorentz[0]]].substitute({"iloc" : li.value}) for ichain in range(0,nchain) : eTemp[ichain].append("(%s)"% (value) ) elif(len(li.lorentz)==4) : if li.lorentz[0].type=="T1" and li.lorentz[1].type=="T2" : value='0.5*(%s)'%tPropC[unContracted[li.lorentz[2]]][unContracted[li.lorentz[3]]][contracted[li.lorentz[0]]][contracted[li.lorentz[1]]].substitute({"iloc" : li.value}) elif li.lorentz[0].type=="T1": value='0.5*(%s)'%tPropB[unContracted[li.lorentz[2]]][unContracted[li.lorentz[3]]][contracted[li.lorentz[0]]].substitute({"iloc" : li.value, "V" : li.lorentz[1], "dot" : tDot}) elif li.lorentz[1].type=="T2" : value= '0.5*(%s)'%tPropB[unContracted[li.lorentz[2]]][unContracted[li.lorentz[3]]][contracted[li.lorentz[1]]].substitute({"iloc" : li.value, "V" : li.lorentz[0], "dot" : tDot}) else : print 'Both contracted tensor indices contracted' raise SkipThisVertex() for ichain in range(0,nchain) : eTemp[ichain].append("(%s)"% (value) ) else : print 'Uncontracted on-shell tensor' raise SkipThisVertex() # unknown else : print 'Unknown expression in lorentz loop',li raise SkipThisVertex() # now evaluate the result if(not isZero) : rTemp =[[],[]] for ichain in range(0,nchain) : core = "*".join(str(x) for x in eTemp[ichain]) temp={} exec("import sympy\nfrom sympy import Symbol,Matrix\n"+Symbols+"result="+ ( "(%s)*(%s)*(%s)" %(sTemp[ichain],core,fTemp[ichain]))) in temp rTemp[0].append(temp["result"]) temp={} exec("import sympy\nfrom sympy import Symbol,Matrix,Transpose\n"+Symbols+"result="+ ( "(%s)*(%s)*(Transpose(%s))*(%s)*(%s)" %(sTTemp[ichain],CC,core,CD,fTTemp[ichain]))) in temp rTemp[1].append(temp["result"]) # and add it to the output addToOutput(res,nchain,sign,rTemp) #### END OF THE CONTRACTED LOOP ##### # increment the indices being summed over keys=contracted.keys() ii = len(keys)-1 while ii >=0 : if(contracted[keys[ii]]<3) : contracted[keys[ii]]+=1 break else : contracted[keys[ii]]=0 ii-=1 nZero=0 for (key,val) in contracted.iteritems() : if(val==0) : nZero+=1 if(nZero==len(contracted)) : break ###### END OF THE UNCONTRACTED LOOP ###### # no uncontracted indices if(len(unContracted)==0) : if(len(res[0])==1) : # scalar if(len(res)==2) : sVal["s" ] = res[0] sVal["sT"] = res[1] # 4 fermion else : sVal["s" ] = res[0] sVal["sT2" ] = res[1] sVal["sT1" ] = res[2] sVal["sT12"] = res[3] # spinor elif(len(res[0])==4) : for k in range(0,4) : sVal[ "s%s" % (k+1) ] = res[0][k] sVal[ "sT%s" % (k+1) ] = res[1][k] else : print 'Sum problem',len(res),len(res[0]) raise SkipThisVertex() break # uncontracted indices else : istring = "" for (key,val) in unContracted.iteritems() : istring +=imap[val] if(len(istring)>2) : print 'Index problem',istring raise SkipThisVertex() sVal[istring] = res[0] sVal[istring+"T"] = res[1] # increment the unsummed indices keys=unContracted.keys() ii = len(keys)-1 while ii >=0 : if(unContracted[keys[ii]]<3) : unContracted[keys[ii]]+=1 break else : unContracted[keys[ii]]=0 ii-=1 nZero=0 for (key,val) in unContracted.iteritems() : if(val==0) : nZero+=1 if(nZero==len(unContracted)) : break # handle the vector case if( "tt" in sVal) : if(len(sVal)==32 and "tt" in sVal and len(sVal["tt"])==1) : for key in sVal: sVal[key] = sVal[key][0] else : print 'Tensor sum problem',len(sVal) raise SkipThisVertex() elif( "t" in sVal ) : # deal with pure vectors if(len(sVal)==8 and "t" in sVal and len(sVal["t"])==1) : pass # RS spinors elif(len(sVal)==8 and "t" in sVal and len(sVal["t"])==4) : pass else : print 'Value problem',len(sVal) raise SkipThisVertex() else : if("s" in sVal) : for key in sVal: sVal[key] = sVal[key][0] return sVal def convertDiracStructure(parsed,output,dimension,defns,iloc,L,lorentztag,vertex) : # get the spins of the particles spins = vertex.lorentz[0].spins # check if we have one or two spin chains nchain = (lorentztag.count("F")+lorentztag.count("R"))/2 # storage of the intermediate results expr =[] start =[] end =[] startT=[] endT =[] sind=[0]*nchain lind=[0]*nchain unContracted={} Symbols="" dtemp=[0,0,0] # parse the dirac matrix strings for ichain in range(0,nchain) : expr .append([]) start .append("") startT.append("") end .append("") endT .append("") sind[ichain],lind[ichain],expr[ichain],start[ichain],startT[ichain],end[ichain],endT[ichain],Symbols =\ processChain(dtemp,parsed,spins,Symbols,unContracted,defns,iloc) + # standard ordering of the chains + for ichain in range(0,nchain) : + for jchain in range(ichain+1,nchain) : + if(sind[jchain] s%s = sW%s.wave();" % (fIndex[i-1],fIndex[i-1])) nf+=1 else : decls.append("SpinorBarWaveFunction & sbarW%s" % (fIndex[i-1])) momenta.append([False,"Lorentz5Momentum P%s =-sbarW%s.momentum();" % (fIndex[i-1],fIndex[i-1])]) waves.append("LorentzSpinorBar sbar%s = sbarW%s.wave();" % (fIndex[i-1],fIndex[i-1])) nf+=1 elif(spin==3) : decls.append("VectorWaveFunction & vW%s" % (i)) momenta.append([False,"Lorentz5Momentum P%s =-vW%s.momentum();" % (i,i)]) waves.append("LorentzPolarizationVector E%s = vW%s.wave();" % (i,i)) elif(spin==4) : if(i%2==1) : decls.append("RSSpinorWaveFunction & RsW%s" % (i)) momenta.append([False,"Lorentz5Momentum P%s =-RsW%s.momentum();" % (i,i)]) waves.append("LorentzRSSpinor Rs%s = RsW%s.wave();" % (i,i)) nf+=1 else : decls.append("RSSpinorBarWaveFunction & RsbarW%s" % (i)) momenta.append([False,"Lorentz5Momentum P%s =-RsbarW%s.momentum();" % (i,i)]) waves.append("LorentzRSSpinorBar Rsbar%s = RsbarW%s.wave();" % (i,i)) nf+=1 elif(spin==5) : decls.append("TensorWaveFunction & tW%s" % (i)) momenta.append([False,"Lorentz5Momentum P%s =-tW%s.momentum();" % (i,i)]) waves.append("LorentzTensor T%s = tW%s.wave();" % (i,i)) else : print 'Unknown spin',spin raise SkipThisVertex() poff += "-P%s" % (i) # ensure unbarred spinor first ibar=-1 isp=-1 for i in range(0,len(decls)) : if(decls[i].find("Bar")>0 and ibar==-1) : ibar=i elif(decls[i].find("Spinor")>=0 and isp==-1) : isp=i if(isp!=-1 and ibar!=-1 and isp>ibar) : decls[ibar],decls[isp] = decls[isp],decls[ibar] # constrct the signature poff = ("Lorentz5Momentum P%s = " % iloc ) + poff sig="" if(iloc==0) : sig="%s evaluate(Energy2, const %s)" % (offType,", const ".join(decls)) # special for VVT vertex if(len(vertex.lorentz[0].spins)==3 and vertex.lorentz[0].spins.count(3)==2 and vertex.lorentz[0].spins.count(5)==1) : sig = sig[0:-1] + ", Energy vmass=-GeV)" else : sig="%s evaluate(Energy2, int iopt, tcPDPtr out, const %s, complex mass=-GeV, complex width=-GeV)" % (offType,", const ".join(decls)) momenta.append([True,poff+";"]) # special for VVT vertex if(len(vertex.lorentz[0].spins)==3 and vertex.lorentz[0].spins.count(3)==2 and vertex.lorentz[0].spins.count(5)==1 and vertex.lorentz[0].spins[iloc-1]==5) : sig=sig.replace("complex mass=-GeV","Energy vmass=-GeV, complex mass=-GeV") for i in range(0,len(momenta)) : momenta[i][0]=True return offType,nf,poff,sig def combineResult(res,nf,ispin,vertex) : # extract the vals and dimensions (vals,dim) = res # construct the output structure # vertex and off-shell scalars if(ispin<=1) : otype={'res':""} # spins elif(ispin==2) : otype={'s1':"",'s2':"",'s3':"",'s4':""} # vectors elif(ispin==3) : if( "t" in vals[0][1] ) : otype={'t':"",'x':"",'y':"",'z':""} else : otype={"res":""} # RS spinors elif(ispin==4) : otype={} for i1 in imap : for i in range(1,5) : otype["%ss%s"% (i1,i)]="" # off-shell tensors elif(ispin==5) : otype={} for i1 in imap : for i2 in imap : otype["%s%s"%(i1,i2)]="" else : print 'Unknown spin',ispin raise SkipThisVertex() expr=[otype] for i in range(0,nf-1) : expr.append(copy.copy(otype)) # dimension for checking dimCheck=dim[0] for i in range(0,len(vals)) : # simple signs if(vals[i]=="+" or vals[i]=="-") : for ii in range(0,len(expr)) : for(key,val) in expr[ii].iteritems() : expr[ii][key] = expr[ii][key]+vals[i] continue # check the dimensions if(dimCheck[0]!=dim[i][0] or dimCheck[1]!=dim[i][1] or dimCheck[2]!=dim[i][2]) : print "Dimension problem in result",i,dimCheck,dim,vertex print vertex.lorentz for j in range(0,len(vals)) : print j,dim[j],vals[j] raise SkipThisVertex() # simplest case if(isinstance(vals[i], basestring)) : for ii in range(0,len(expr)) : for(key,val) in expr[ii].iteritems() : expr[ii][key] = expr[ii][key]+vals[i] continue # more complex structures pre = vals[i][0] if(pre=="(1.0)") : pre="" if(not isinstance(vals[i][1],dict)) : print 'must be a dict here' raise SkipThisVertex() # tensors if("tt" in vals[i][1]) : for i1 in imap : for i2 in imap : key="%s%s"%(i1,i2) if(pre=="") : expr[0][key] += "(%s)" % vals[i][1][key] else : expr[0][key] += "%s*(%s)" % (pre,vals[i][1][key]) if(len(expr)==2) : if(pre=="") : expr[1][key] +="(%s)" % vals[i][1][key+"T"] else : expr[1][key] +="%s*(%s)" % (pre,vals[i][1][key+"T"]) # standard fermion vertex case elif(len(vals[i][1])==2 and "s" in vals[i][1] and "sT" in vals[i][1]) : if(pre=="") : expr[0]["res"] += "(%s)" % vals[i][1]["s"] expr[1]["res"] += "(%s)" % vals[i][1]["sT"] else : expr[0]["res"] += "%s*(%s)" % (pre,vals[i][1]["s"]) expr[1]["res"] += "%s*(%s)" % (pre,vals[i][1]["sT"]) # spinor case elif(len(vals[i][1])==8 and "s1" in vals[i][1]) : for jj in range(1,5) : if(pre=="") : expr[0]["s%s" % jj] += "(%s)" % vals[i][1]["s%s" % jj] expr[1]["s%s" % jj] += "(%s)" % vals[i][1]["sT%s" % jj] else : expr[0]["s%s" % jj] += "%s*(%s)" % (pre,vals[i][1]["s%s" % jj]) expr[1]["s%s" % jj] += "%s*(%s)" % (pre,vals[i][1]["sT%s" % jj]) # vector elif(len(vals[i][1])%4==0 and "t" in vals[i][1] and len(vals[i][1]["t"])==1 ) : for i1 in imap : if(pre=="") : expr[0][i1] += "(%s)" % vals[i][1][i1][0] else : expr[0][i1] += "%s*(%s)" % (pre,vals[i][1][i1][0]) if(len(expr)==2) : if(pre=="") : expr[1][i1] +="(%s)" % vals[i][1][i1+"T"][0] else : expr[1][i1] +="%s*(%s)" % (pre,vals[i][1][i1+"T"][0]) # 4 fermion vertex case elif(len(vals[i][1])==4 and "sT12" in vals[i][1]) : if(pre=="") : expr[0]["res"] += "(%s)" % vals[i][1]["s"] expr[1]["res"] += "(%s)" % vals[i][1]["sT2"] expr[2]["res"] += "(%s)" % vals[i][1]["sT1"] expr[3]["res"] += "(%s)" % vals[i][1]["sT12"] else : expr[0]["res"] += "%s*(%s)" % (pre,vals[i][1]["s"]) expr[1]["res"] += "%s*(%s)" % (pre,vals[i][1]["sT2"]) expr[2]["res"] += "(%s)" % vals[i][1]["sT1"] expr[3]["res"] += "(%s)" % vals[i][1]["sT12"] # RS spinor elif(len(vals[i][1])%4==0 and "t" in vals[i][1] and len(vals[i][1]["t"])==4 ) : for i1 in imap : for k in range(1,5) : key = "%ss%s" % (i1,k) if(pre=="") : expr[0][key] += "(%s)" % vals[i][1][i1][k-1] expr[1][key] += "(%s)" % vals[i][1][i1+"T"][k-1] else : expr[0][key] += "%s*(%s)" % (pre,vals[i][1][i1][k-1]) expr[1][key] += "%s*(%s)" % (pre,vals[i][1][i1+"T"][k-1]) else : print 'problem with type',vals[i] raise SkipThisVertex() # no of particles in the vertex vDim = len(vertex.lorentz[0].spins) # compute the unit and apply it unit = computeUnit2(dimCheck,vDim) if(unit!="") : for ii in range(0,len(expr)) : for (key,val) in expr[ii].iteritems() : expr[ii][key] = "(%s)*(%s)" % (val,unit) return expr def headerReplace(inval) : return inval.replace("virtual","").replace("ScalarWaveFunction","").replace("SpinorWaveFunction","") \ .replace("SpinorBarWaveFunction","").replace("VectorWaveFunction","").replace("TensorWaveFunction","") \ .replace("Energy2","q2").replace("int","").replace("complex","").replace("Energy","").replace("=-GeV","") \ .replace("const &","").replace("tcPDPtr","").replace(" "," ").replace("Complex","") def combineComponents(result,offType,RS) : for i in range(0,len(result)) : for (key,value) in result[i].iteritems() : output=py2cpp(value.strip(),True) result[i][key]=output[0] # simplest case, just a value if(len(result[0])==1 and "res" in result[0]) : for i in range(0,len(result)) : result[i] = result[i]["res"] result[i]=result[i].replace("1j","ii") return # calculate the substitutions if(not isinstance(result[0],basestring)) : subs=[] for ii in range(0,len(result)) : subs.append({}) for (key,val) in result[ii].iteritems() : subs[ii]["out%s" % key]= val # spinors if("s1" in result[0]) : stype = "LorentzSpinor" sbtype = "LorentzSpinorBar" if(offType.find("Bar")>0) : (stype,sbtype)=(sbtype,stype) subs[0]["type"] = stype result[0] = SpinorTemplate.substitute(subs[0]) subs[1]["type"] = sbtype result[1] = SpinorTemplate.substitute(subs[1]) # tensors elif("tt" in result[0]) : for ii in range(0,len(result)) : result[ii] = Template("LorentzTensor(${outxx},\n${outxy},\n${outxz},\n${outxt},\n${outyx},\n${outyy},\n${outyz},\n${outyt},\n${outzx},\n${outzy},\n${outzz},\n${outzt},\n${outtx},\n${outty},\n${outtz},\n${outtt})").substitute(subs[ii]) result[ii]=result[ii].replace("(+","(") # vectors elif("t" in result[0]) : for ii in range(0,len(result)) : result[ii] = Template("LorentzVector(${outx},\n${outy},\n${outz},\n${outt})").substitute(subs[ii]) result[ii]=result[ii].replace("(+","(") # RS spinors elif("ts1" in result[0]) : stype = "LorentzRSSpinor" sbtype = "LorentzRSSpinorBar" if(offType.find("Bar")>0) : (stype,sbtype)=(sbtype,stype) subs[0]["type"] = stype result[0] = RSSpinorTemplate.substitute(subs[0]) subs[1]["type"] = sbtype result[1] = RSSpinorTemplate.substitute(subs[1]) else : print 'Type not implemented',result raise SkipThisVertex() for i in range(0,len(result)) : result[i]=result[i].replace("1j","ii") def generateEvaluateFunction(model,vertex,iloc,values,defns,vertexEval,cf,order) : RS = "R" in vertex.lorentz[0].name FM = "F" in vertex.lorentz[0].name # extract the start and end of the spin chains if( RS or FM ) : fIndex = vertexEval[0][0][0][2] else : fIndex=0 # first construct the signature of the function decls=[] momenta=[] waves=[] offType,nf,poff,sig = constructSignature(vertex,order,iloc,decls,momenta,waves,fIndex) # combine the different terms in the result symbols=set() localCouplings=[] result=[] ispin = 0 if(iloc!=0) : ispin = vertex.lorentz[0].spins[iloc-1] # put the lorentz structures and couplings together for j in range(0,len(vertexEval)) : # get the lorentz structure piece expr = combineResult(vertexEval[j],nf,ispin,vertex) # get the coupling for this bit val, sym = py2cpp(values[j]) localCouplings.append("Complex local_C%s = %s;\n" % (j,val)) symbols |=sym # put them together vtype="Complex" if("res" in expr[0] and offType=="VectorWaveFunction") : vtype="LorentzPolarizationVector" if(len(result)==0) : for ii in range(0,len(expr)) : result.append({}) for (key,val) in expr[ii].iteritems() : result[ii][key] = " %s((local_C%s)*(%s)) " % (vtype,j,val) else : for ii in range(0,len(expr)) : for (key,val) in expr[ii].iteritems(): result[ii][key] += " + %s((local_C%s)*(%s)) " % (vtype,j,val) # for more complex types merge the spin/lorentz components combineComponents(result,offType,RS) # multiple by scalar wavefunctions scalars="" for i in range (0,len(vertex.lorentz[0].spins)) : if(vertex.lorentz[0].spins[i]==1 and i+1!=iloc) : scalars += "sca%s*" % (i+1) if(scalars!="") : for ii in range(0,len(result)) : result[ii] = "(%s)*(%s)" % (result[ii],scalars[0:-1]) # vertex, just return the answer if(iloc==0) : result[0] = "return (%s)*(%s);\n" % (result[0],py2cpp(cf)[0]) if(FM or RS) : for i in range(1,len(result)) : result[i] = "return (%s)*(%s);\n" % (result[i],py2cpp(cf)[0]) # off-shell particle else : # off-shell scalar if(vertex.lorentz[0].spins[iloc-1] == 1 ) : result[0] = scaTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],res=result[0]) if(FM or RS) : result[1] = scaTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],res=result[1]) # off-shell fermion elif(vertex.lorentz[0].spins[iloc-1] == 2 ) : result[0] = sTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],offTypeA=offType.replace("WaveFunction",""), res=result[0].replace( "M%s" % iloc, "mass" ),offTypeB=offType) if(FM or RS) : if(offType.find("Bar")>0) : offTypeT=offType.replace("Bar","") else : offTypeT=offType.replace("Spinor","SpinorBar") result[1] = sTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],offTypeA=offTypeT.replace("WaveFunction",""), res=result[1].replace( "M%s" % iloc, "mass" ),offTypeB=offTypeT) # off-shell vector elif(vertex.lorentz[0].spins[iloc-1] == 3 ) : result[0] = vecTemplate.format(iloc=iloc,res=result[0],cf=py2cpp(cf)[0]) if(FM or RS) : result[1] = vecTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],res=result[1]) elif(vertex.lorentz[0].spins[iloc-1] == 4 ) : if(offType.find("Bar")>0) : offTypeT=offType.replace("Bar","") else : offTypeT=offType.replace("Spinor","SpinorBar") result[1] = RSTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],offTypeA=offTypeT.replace("WaveFunction",""), res=result[1].replace( "M%s" % iloc, "mass" ),offTypeB=offTypeT) result[0] = RSTemplate.format(iloc=iloc,cf=py2cpp(cf[0])[0],offTypeA=offType.replace("WaveFunction",""), res=result[0].replace( "M%s" % iloc, "mass" ),offTypeB=offType) # tensors elif(vertex.lorentz[0].spins[iloc-1]) : if(RS) : print "RS spinors and tensors not handled" raise SkipThisVertex() result[0] = tenTemplate.format(iloc=iloc,cf=py2cpp(cf)[0],res=result[0]) if(FM or RS) : result[1] = tenTemplate.format(iloc=iloc,cf=py2cpp(cf)[0],res=result[1]) else : print 'Unknown spin for off-shell particle',vertex.lorentz[0].spins[iloc-1] raise SkipThisVertex() # check if momenta defns needed to clean up compile of code for (key,val) in defns.iteritems() : if( isinstance(key, basestring)) : if(key.find("vvP")==0) : momenta[int(key[3])-1][0] = True else : for vals in key : if(vals.type=="P") : momenta[vals.value-1][0] = True # cat the definitions defString="" for (key,value) in defns.iteritems() : if(value[0]=="") : continue if(value[0][0]=="V" or value[0][0]=="T") : defString+=" %s\n" %value[1] for (key,value) in defns.iteritems() : if(value[0]=="") : continue if(value[0][0]!="V" and value[0][0]!="T") : defString+=" %s\n" %value[1] if(len(result)<=2) : sorder=swapOrder(vertex,iloc,momenta,fIndex) else : sorder="" momentastring="" for i in range(0,len(momenta)) : if(momenta[i][0] and momenta[i][1]!="") : momentastring+=momenta[i][1]+"\n " # special for 4-point VVVV if(vertex.lorentz[0].spins.count(3)==4 and iloc==0) : sig=sig.replace("Energy2","Energy2,int") header="virtual %s" % sig sig=sig.replace("=-GeV","") symboldefs = [ def_from_model(model,s) for s in symbols ] function = evaluateTemplate.format(decl=sig,momenta=momentastring,defns=defString, waves="\n ".join(waves),symbols='\n '.join(symboldefs), couplings="\n ".join(localCouplings), result=result[0],swap=sorder) # special for transpose if(FM or RS) : h2=header if(not RS) : h2=header.replace("evaluate","evaluateN") function=function.replace("evaluate(","evaluateN(") headers=[] newHeader="" for ifunction in range(1,len(result)) : waveNew=[] momentastring="" htemp = header.split(",") irs=-1 isp=-1 # RS case if(RS) : # sort out the wavefunctions for i in range(0,len(waves)) : if(waves[i].find("Spinor")<0) : waveNew.append(waves[i]) continue if(waves[i].find("Bar")>0) : waveNew.append(waves[i].replace("Bar","").replace("bar","")) else : waveNew.append(waves[i].replace("Spinor","SpinorBar").replace(" s"," sbar").replace("Rs","Rsbar")) # sort out the momenta definitions for i in range(0,len(momenta)) : if(momenta[i][0] and momenta[i][1]!="") : if(momenta[i][1].find("barW")>0) : momentastring+=momenta[i][1].replace("barW","W")+"\n " elif(momenta[i][1].find("sW")>0) : momentastring+=momenta[i][1].replace("sW","sbarW")+"\n " else : momentastring+=momenta[i][1]+"\n " # header string for i in range(0,len(htemp)) : if(htemp[i].find("RS")>0) : if(htemp[i].find("Bar")>0) : htemp[i]=htemp[i].replace("Bar","").replace("RsbarW","RsW") else : htemp[i]=htemp[i].replace("Spinor","SpinorBar").replace("RsW","RsbarW") if(i>0) : irs=i elif(htemp[i].find("Spinor")>0) : if(htemp[i].find("Bar")>0) : htemp[i]=htemp[i].replace("Bar","").replace("sbarW","sW") else : htemp[i]=htemp[i].replace("Spinor","SpinorBar").replace("sW","sbarW") if(i>0) : isp=i if(irs>0 and isp >0) : htemp[irs],htemp[isp] = htemp[isp],htemp[irs] # fermion case else : htemp2 = header.split(",") # which fermions to exchange if(len(fIndex)==2) : isp = (fIndex[0],) ibar = (fIndex[1],) else : if(ifunction==1) : isp = (fIndex[2],) ibar = (fIndex[3],) elif(ifunction==2) : isp = (fIndex[0],) ibar = (fIndex[1],) elif(ifunction==3) : isp = (fIndex[0],fIndex[2]) ibar = (fIndex[1],fIndex[3]) # wavefunctions for i in range(0,len(waves)) : if(waves[i].find("Spinor")<0) : waveNew.append(waves[i]) continue if(waves[i].find("Bar")>0) : found=False for itest in range(0,len(ibar)) : if(waves[i].find("sbarW%s"%ibar[itest])>=0) : waveNew.append(waves[i].replace("Bar","").replace("bar","")) found=True break if(not found) : waveNew.append(waves[i]) else : found=False for itest in range(0,len(isp)) : if(waves[i].find("sW%s"%isp[itest])>=0) : waveNew.append(waves[i].replace("Spinor","SpinorBar").replace(" s"," sbar")) found=True break if(not found) : waveNew.append(waves[i]) # momenta definitions for i in range(0,len(momenta)) : if(momenta[i][0] and momenta[i][1]!="") : if(momenta[i][1].find("barW")>0) : found = False for itest in range(0,len(ibar)) : if(momenta[i][1].find("barW%s"%ibar[itest])>=0) : momentastring+=momenta[i][1].replace("barW","W")+"\n " found=True break if(not found) : momentastring+=momenta[i][1]+"\n " elif(momenta[i][1].find("sW")>0) : found=False for itest in range(0,len(isp)) : if(momenta[i][1].find("sW%s"%isp[itest])>=0) : momentastring+=momenta[i][1].replace("sW","sbarW")+"\n " found=True break if(not found) : momentastring+=momenta[i][1]+"\n " else : momentastring+=momenta[i][1]+"\n " # header for i in range(0,len(htemp)) : if(htemp[i].find("Spinor")<0) : continue if(htemp[i].find("Bar")>0) : if(i==0) : htemp[i] =htemp [i].replace("Bar","") htemp2[i]=htemp2[i].replace("Bar","") continue for itest in range(0,len(ibar)) : if(htemp[i].find("sbarW%s"%ibar[itest])>=0) : htemp[i] =htemp [i].replace("Bar","").replace("sbarW","sW") htemp2[i]=htemp2[i].replace("Bar","").replace("sbarW%s"%ibar[itest],"sW%s"%isp[itest]) break else : if(i==0) : htemp [i]=htemp [i].replace("Spinor","SpinorBar") htemp2[i]=htemp2[i].replace("Spinor","SpinorBar") continue for itest in range(0,len(isp)) : if(htemp[i].find("sW%s"%isp[itest])>=0) : htemp [i]=htemp [i].replace("Spinor","SpinorBar").replace("sW","sbarW") htemp2[i]=htemp2[i].replace("Spinor","SpinorBar").replace("sW%s"%isp[itest],"sbarW%s"%ibar[itest]) break # header for transposed function hnew = ','.join(htemp) hnew = hnew.replace("virtual ","").replace("=-GeV","") if(not RS) : theader = ','.join(htemp2) theader = theader.replace("virtual ","").replace("=-GeV","") if(len(result)==2) : hnew =hnew .replace("evaluate","evaluateT") theader=theader.replace("evaluate","evaluateT") else : hnew =hnew .replace("evaluate","evaluateT%s" % ifunction) theader=theader.replace("evaluate","evaluateT%s" % ifunction) if(iloc not in fIndex) : theader = headerReplace(theader) else : theader = headerReplace(h2).replace("evaluateN","evaluateT") headers.append(theader) newHeader += hnew +";\n" else : newHeader += hnew fnew = evaluateTemplate.format(decl=hnew,momenta=momentastring,defns=defString, waves="\n ".join(waveNew),symbols='\n '.join(symboldefs), couplings="\n ".join(localCouplings), result=result[ifunction],swap=sorder) function +="\n" + fnew if(FM and not RS) : if(len(result)==2) : if(iloc!=fIndex[1]) : fi=1 stype="sbar" else : fi=0 stype="s" header = vTemplateT.format(header=header.replace("Energy2,","Energy2 q2,"), normal=headerReplace(h2), transpose=theader,type=stype, iloc=fIndex[fi],id=vertex.particles[fIndex[fi]-1].pdg_code) \ +newHeader+h2.replace("virtual","") else : sorder = swapOrderFFFF(vertex,iloc,fIndex) header = vTemplate4.format(header=header.replace("Energy2,","Energy2 q2,"), iloc1=fIndex[1],iloc2=fIndex[3],swap=sorder, id1=vertex.particles[fIndex[1]-1].pdg_code, id2=vertex.particles[fIndex[3]-1].pdg_code, cf=py2cpp(cf)[0], res1=headerReplace(h2).replace("W",""), res2=headers[0].replace("W",""), res3=headers[1].replace("W",""), res4=headers[2].replace("W",""))\ +newHeader+h2.replace("virtual","") else : header=header + ";\n" + newHeader return (header,function) evaluateMultiple = """\ {decl} {{ {code} }} """ def multipleEvaluate(vertex,spin,defns) : if(spin==1) : name="scaW" elif(spin==3) : name="vW" else : print 'Evaluate multiple problem',spin raise SkipThisVertex() if(len(defns)==0) : return ("","") header = defns[0] ccdefn = header.replace("=-GeV","").replace("virtual ","").replace("Energy2","Energy2 q2") code="" spins=vertex.lorentz[0].spins iloc=1 waves=[] for i in range(0,len(spins)) : if(spins[i]==spin) : waves.append("%s%s" %(name,i+1)) for i in range(0,len(spins)) : if(spins[i]==spin) : if(iloc==1) : el="" else : el="else " call = headerReplace(defns[iloc]) if(iloc!=1) : call = call.replace(waves[0],waves[iloc-1]) pdgid = vertex.particles[i].pdg_code code += " %sif(out->id()==%s) return %s;\n" % (el,pdgid,call) iloc+=1 code+=" else assert(false);\n" return (header,evaluateMultiple.format(decl=ccdefn,code=code)) diff --git a/Models/General/BSMWidthGenerator.cc b/Models/General/BSMWidthGenerator.cc --- a/Models/General/BSMWidthGenerator.cc +++ b/Models/General/BSMWidthGenerator.cc @@ -1,74 +1,78 @@ // -*- C++ -*- // // BSMWidthGenerator.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 BSMWidthGenerator class. // #include "BSMWidthGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Decay/General/GeneralTwoBodyDecayer.h" using namespace Herwig; IBPtr BSMWidthGenerator::clone() const { return new_ptr(*this); } IBPtr BSMWidthGenerator::fullclone() const { return new_ptr(*this); } void BSMWidthGenerator::persistentOutput(PersistentOStream & os) const { os << theModes; } void BSMWidthGenerator::persistentInput(PersistentIStream & is, int) { is >> theModes; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigBSMWidthGenerator("Herwig::BSMWidthGenerator", "Herwig.so"); void BSMWidthGenerator::Init() { static ClassDocumentation documentation ("A width generator for BSM particles."); } void BSMWidthGenerator::setupMode(tcDMPtr mode, tDecayIntegratorPtr decayer, unsigned int) { tcGeneralTwoBodyDecayerPtr dec = dynamic_ptr_cast(decayer); theModes.push_back(make_pair(mode, dec)); } Energy BSMWidthGenerator::partial2BodyWidth(int iloc, Energy m0, Energy m1, Energy m2) const { if( m0 < (m1 + m2) ) return ZERO; //need pointers to particles involved tcDMPtr dm = theModes[iloc].first; ParticleMSet::const_iterator pit = dm->products().begin(); tcPDPtr parta = *pit; ++pit; tcPDPtr partb = *pit; int dummya(0); double dummyb(0.); - if( !theModes[iloc].second->twoBodyMEcode(*dm, dummya, dummyb) ) - swap(parta, partb); - return theModes[iloc].second->partialWidth(make_pair(dm->parent(), m0), - make_pair(parta, m1), - make_pair(partb, m2)); + if(theModes[iloc].second) { + if( !theModes[iloc].second->twoBodyMEcode(*dm, dummya, dummyb) ) + swap(parta, partb); + return theModes[iloc].second->partialWidth(make_pair(dm->parent(), m0), + make_pair(parta, m1), + make_pair(partb, m2)); + } + else + return ZERO; } diff --git a/Models/General/ModelGenerator.cc b/Models/General/ModelGenerator.cc --- a/Models/General/ModelGenerator.cc +++ b/Models/General/ModelGenerator.cc @@ -1,555 +1,556 @@ // -*- C++ -*- // // ModelGenerator.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 ModelGenerator class. // #include "ModelGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "BSMWidthGenerator.h" #include "Herwig/PDT/GenericMassGenerator.h" #include "Herwig/Decay/DecayIntegrator.h" #include "ThePEG/Repository/BaseRepository.h" using namespace Herwig; IBPtr ModelGenerator::clone() const { return new_ptr(*this); } IBPtr ModelGenerator::fullclone() const { return new_ptr(*this); } void ModelGenerator::persistentOutput(PersistentOStream & os) const { os << hardProcessConstructors_ << _theDecayConstructor << particles_ << offshell_ << Offsel_ << BRnorm_ << twoBodyOnly_ << howOffShell_ << Npoints_ << Iorder_ << BWshape_ << brMin_ << decayOutput_; } void ModelGenerator::persistentInput(PersistentIStream & is, int) { is >> hardProcessConstructors_ >> _theDecayConstructor >> particles_ >> offshell_ >> Offsel_ >> BRnorm_ >> twoBodyOnly_ >> howOffShell_ >> Npoints_ >> Iorder_ >> BWshape_ >> brMin_ >> decayOutput_; } // Static variable needed for the type description system in ThePEG. DescribeClass describeThePEGModelGenerator("Herwig::ModelGenerator", "Herwig.so"); void ModelGenerator::Init() { static ClassDocumentation documentation ("This class controls the the use of BSM physics.", "BSM physics was produced using the algorithm of " "\\cite{Gigg:2007cr,Gigg:2008yc}", "\\bibitem{Gigg:2007cr} M.~Gigg and P.~Richardson, \n" "Eur.\\ Phys.\\ J.\\ C {\\bf 51} (2007) 989.\n" "%%CITATION = EPHJA,C51,989;%%\n" " %\\cite{Gigg:2008yc}\n" "\\bibitem{Gigg:2008yc}\n" " M.~A.~Gigg and P.~Richardson,\n" " %``Simulation of Finite Width Effects in Physics Beyond the Standard Model,''\n" " arXiv:0805.3037 [hep-ph].\n" " %%CITATION = ARXIV:0805.3037;%%\n" ); static RefVector interfaceHardProcessConstructors ("HardProcessConstructors", "The objects to construct hard processes", &ModelGenerator::hardProcessConstructors_, -1, false, false, true, false, false); static Reference interfaceDecayConstructor ("DecayConstructor", "Pointer to DecayConstructor helper class", &ModelGenerator::_theDecayConstructor, false, false, true, false); static RefVector interfaceModelParticles ("DecayParticles", "ParticleData pointers to the particles requiring spin correlation " "decayers. If decay modes do not exist they will also be created.", &ModelGenerator::particles_, -1, false, false, true, false); static RefVector interfaceOffshell ("Offshell", "The particles to treat as off-shell", &ModelGenerator::offshell_, -1, false, false, true, false); static Switch interfaceWhichOffshell ("WhichOffshell", "A switch to determine which particles to create mass and width " "generators for.", &ModelGenerator::Offsel_, 0, false, false); static SwitchOption interfaceWhichOffshellSelected (interfaceWhichOffshell, "Selected", "Only create mass and width generators for the particles specified", 0); static SwitchOption interfaceWhichOffshellAll (interfaceWhichOffshell, "All", "Treat all particles specified in the DecayParticles " "list as off-shell", 1); static Switch interfaceBRNormalize ("BRNormalize", "Whether to normalize the partial widths to BR*total width for an " "on-shell particle", &ModelGenerator::BRnorm_, true, false, false); static SwitchOption interfaceBRNormalizeNormalize (interfaceBRNormalize, "Yes", "Normalize the partial widths", true); static SwitchOption interfaceBRNormalizeNoNormalize (interfaceBRNormalize, "No", "Do not normalize the partial widths", false); static Parameter interfacePoints ("InterpolationPoints", "Number of points to use for interpolation tables when needed", &ModelGenerator::Npoints_, 10, 5, 1000, false, false, true); static Parameter interfaceInterpolationOrder ("InterpolationOrder", "The interpolation order for the tables", &ModelGenerator::Iorder_, 1, 1, 5, false, false, Interface::limited); static Switch interfaceBreitWignerShape ("BreitWignerShape", "Controls the shape of the mass distribution generated", &ModelGenerator::BWshape_, 0, false, false); static SwitchOption interfaceBreitWignerShapeDefault (interfaceBreitWignerShape, "Default", "Running width with q in numerator and denominator width factor", 0); static SwitchOption interfaceBreitWignerShapeFixedWidth (interfaceBreitWignerShape, "FixedWidth", "Use a fixed width", 1); static SwitchOption interfaceBreitWignerShapeNoq (interfaceBreitWignerShape, "Noq", "Use M rather than q in the numerator and denominator width factor", 2); static SwitchOption interfaceBreitWignerShapeNoNumerator (interfaceBreitWignerShape, "NoNumerator", "Neglect the numerator factors", 3); static Switch interfaceTwoBodyOnly ("TwoBodyOnly", "Whether to use only two-body or all modes in the running width calculation", &ModelGenerator::twoBodyOnly_, false, false, false); static SwitchOption interfaceTwoBodyOnlyYes (interfaceTwoBodyOnly, "Yes", "Only use two-body modes", true); static SwitchOption interfaceTwoBodyOnlyNo (interfaceTwoBodyOnly, "No", "Use all modes", false); static Parameter interfaceMinimumBR ("MinimumBR", "The minimum branching fraction to include", &ModelGenerator::brMin_, 1e-6, 0.0, 1.0, false, false, Interface::limited); static Switch interfaceDecayOutput ("DecayOutput", "Option to control the output of the decay mode information", &ModelGenerator::decayOutput_, 1, false, false); static SwitchOption interfaceDecayOutputNone (interfaceDecayOutput, "None", "No output", 0); static SwitchOption interfaceDecayOutputPlain (interfaceDecayOutput, "Plain", "Default plain text output", 1); static SwitchOption interfaceDecayOutputSLHA (interfaceDecayOutput, "SLHA", "Output in the Susy Les Houches Accord format", 2); static Parameter interfaceMinimumWidthFraction ("MinimumWidthFraction", "Minimum fraction of the particle's mass the width can be" " for the off-shell treatment.", &ModelGenerator::minWidth_, 1e-6, 1e-15, 1., false, false, Interface::limited); static Parameter interfaceHowMuchOffShell ("HowMuchOffShell", "The multiple of the particle's width by which it is allowed to be off-shell", &ModelGenerator::howOffShell_, 5., 0.0, 100., false, false, Interface::limited); } namespace { /// Helper function for sorting by mass inline bool massIsLess(tcPDPtr a, tcPDPtr b) { return a->mass() < b->mass(); } // Helper function to find minimum possible mass of a particle inline Energy minimumMass(tcPDPtr parent) { Energy output(Constants::MaxEnergy); for(set::const_iterator dit = parent->decayModes().begin(); dit != parent->decayModes().end(); ++dit) { Energy outMass(ZERO); for(unsigned int ix=0;ix<(**dit).orderedProducts().size();++ix) { outMass += (**dit).orderedProducts()[ix]->massMin(); } output = min(output,outMass); } return output; } } void ModelGenerator::doinit() { useMe(); Interfaced::doinit(); // make sure the model is initialized Ptr::pointer model = dynamic_ptr_cast::pointer>(generator()->standardModel()); model->init(); // and the vertices for(size_t iv = 0; iv < model->numberOfVertices(); ++iv) model->vertex(iv)->init(); // uniq and sort DecayParticles list by mass set tmp(particles_.begin(),particles_.end()); particles_.assign(tmp.begin(),tmp.end()); sort(particles_.begin(),particles_.end(),massIsLess); //create decayers and decaymodes (if necessary) if( _theDecayConstructor ) { _theDecayConstructor->init(); _theDecayConstructor->createDecayers(particles_,brMin_); } // write out decays with spin correlations ostream & os = CurrentGenerator::current().misc(); ofstream ofs; if ( decayOutput_ > 1 ) { string filename = CurrentGenerator::current().filename() + "-BR.spc"; ofs.open(filename.c_str()); } if(decayOutput_!=0) { if(decayOutput_==1) { os << "# The decay modes listed below will have spin\n" << "# correlations included when they are generated.\n#\n#"; } else { ofs << "# Herwig decay tables in SUSY Les Houches accord format\n"; ofs << "Block DCINFO # Program information\n"; ofs << "1 Herwig # Decay Calculator\n"; ofs << "2 " << generator()->strategy()->versionstring() << " # Version number\n"; } } //create mass and width generators for the requested particles set offShell; if( Offsel_ == 0 ) offShell = set(offshell_.begin() ,offshell_.end() ); else offShell = set(particles_.begin(),particles_.end()); for(PDVector::iterator pit = particles_.begin(); pit != particles_.end(); ++pit) { tPDPtr parent = *pit; // Check decays for ones where quarks cannot be put on constituent // mass-shell checkDecays(parent); parent->reset(); // Now switch off the modes if needed for(DecaySet::const_iterator it=parent->decayModes().begin(); it!=parent->decayModes().end();++it) { if( _theDecayConstructor->disableDecayMode((**it).tag()) ) { DMPtr mode = *it; generator()->preinitInterface(mode, "Active", "set", "No"); if(mode->CC()) { DMPtr CCmode = mode->CC(); generator()->preinitInterface(CCmode, "Active", "set", "No"); } } } parent->update(); if( parent->CC() ) parent->CC()->synchronize(); if( parent->decaySelector().empty() ) { parent->stable(true); parent->width(ZERO); parent->widthCut(ZERO); parent->massGenerator(tGenericMassGeneratorPtr()); parent->widthGenerator(tGenericWidthGeneratorPtr()); } else { if(parent->mass()*minWidth_>parent->width()) { parent->massGenerator(tGenericMassGeneratorPtr()); parent->widthGenerator(tGenericWidthGeneratorPtr()); } else { if( offShell.find(*pit) != offShell.end() ) { createWidthGenerator(*pit); } else { parent->massGenerator(tGenericMassGeneratorPtr()); parent->widthGenerator(tGenericWidthGeneratorPtr()); } } } - + // set the offshellness + Energy minMass = minimumMass(parent); + Energy offShellNess = howOffShell_*parent->width(); + if(minMass>parent->mass()-offShellNess) { + offShellNess = parent->mass()-minMass; + } + parent->widthCut(offShellNess); + if( parent->massGenerator() ) { - Energy minMass = minimumMass(parent); - Energy offShellNess = howOffShell_*parent->width(); - if(minMass>parent->mass()-offShellNess) { - offShellNess = parent->mass()-minMass; - } - parent->widthCut(offShellNess); parent->massGenerator()->reset(); if(decayOutput_==1) os << "# " <PDGName() << " will be considered off-shell.\n#\n"; } if( parent->widthGenerator() ) parent->widthGenerator()->reset(); } // loop again to initialise mass and width generators // switch off modes and write output for(PDVector::iterator pit = particles_.begin(); pit != particles_.end(); ++pit) { tPDPtr parent = *pit; if(parent->widthGenerator()) parent->widthGenerator()->init(); if(parent->massGenerator()) parent->massGenerator()->init(); // output the modes if needed if( !parent->decaySelector().empty() ) { if ( decayOutput_ == 2 ) writeDecayModes(ofs, parent); else writeDecayModes(os, parent); } } //Now construct hard processes given that we know which //objects have running widths for(unsigned int ix=0;ixinit(); hardProcessConstructors_[ix]->constructDiagrams(); } } void ModelGenerator::checkDecays(PDPtr parent) { if( parent->stable() ) { if(parent->coloured()) cerr << "Warning: No decays for coloured particle " << parent->PDGName() << "\n\n" << "have been calcluated in BSM model.\n" << "This may cause problems in the hadronization phase.\n" << "You may have forgotten to switch on the decay mode calculation using\n" << " set TwoBodyDC:CreateDecayModes Yes\n" << " set ThreeBodyDC:CreateDecayModes Yes\n" << " set WeakDecayConstructor:CreateDecayModes Yes\n" << "or the decays of this particle are missing from your\n" << "input spectrum and decay file in the SLHA format.\n\n"; return; } DecaySet::iterator dit = parent->decayModes().begin(); DecaySet::iterator dend = parent->decayModes().end(); Energy oldwidth(parent->width()), newwidth(ZERO); bool rescalebrat(false); double brsum(0.); for(; dit != dend; ++dit ) { if( !(**dit).on() ) continue; Energy release((**dit).parent()->mass()); tPDVector::const_iterator pit = (**dit).orderedProducts().begin(); tPDVector::const_iterator pend =(**dit).orderedProducts().end(); for( ; pit != pend; ++pit ) { release -= (**pit).constituentMass(); } if( (**dit).brat() < brMin_ || release < ZERO ) { if( release < ZERO ) cerr << "Warning: The shower cannot be generated using this decay " << (**dit).tag() << " because it is too close to threshold.\nIt " << "will be switched off and the branching fractions of the " << "remaining modes rescaled.\n"; rescalebrat = true; generator()->preinitInterface(*dit, "Active", "set", "No"); generator()->preinitInterface(*dit, "BranchingRatio", "set", "0.0"); DecayIntegratorPtr decayer = dynamic_ptr_cast((**dit).decayer()); if(decayer) { generator()->preinitInterface(decayer->fullName(), "Initialize", "set","0"); } } else { brsum += (**dit).brat(); newwidth += (**dit).brat()*oldwidth; } } // if no modes left set stable if(newwidth==ZERO) { parent->stable(true); parent->width(ZERO); parent->widthCut(ZERO); parent->massGenerator(tGenericMassGeneratorPtr()); parent->widthGenerator(tGenericWidthGeneratorPtr()); } // otherwise rescale if needed else if( ( rescalebrat || abs(brsum - 1.) > 1e-12 ) && !parent->decayModes().empty()) { dit = parent->decayModes().begin(); dend = parent->decayModes().end(); double factor = oldwidth/newwidth; brsum = 0.; for( ; dit != dend; ++dit ) { if( !(**dit).on() ) continue; double newbrat = ((**dit).brat())*factor; brsum += newbrat; ostringstream brf; brf << setprecision(13) << newbrat; generator()->preinitInterface(*dit, "BranchingRatio", "set", brf.str()); } parent->width(newwidth); if( newwidth > ZERO ) parent->cTau(hbarc/newwidth); } } namespace { struct DecayModeOrdering { bool operator()(tcDMPtr m1, tcDMPtr m2) { if(m1->brat()!=m2->brat()) { return m1->brat()>m2->brat(); } else { if(m1->products().size()==m2->products().size()) { ParticleMSet::const_iterator it1=m1->products().begin(); ParticleMSet::const_iterator it2=m2->products().begin(); do { if((**it1).id()!=(**it2).id()) { return (**it1).id()>(**it2).id(); } ++it1; ++it2; } while(it1!=m1->products().end()&& it2!=m2->products().end()); assert(false); } else return m1->products().size()products().size(); } return false; } }; } void ModelGenerator::writeDecayModes(ostream & os, tcPDPtr parent) const { if(decayOutput_==0) return; set modes(parent->decayModes().begin(), parent->decayModes().end()); if(decayOutput_==1) { os << " Parent: " << parent->PDGName() << " Mass (GeV): " << parent->mass()/GeV << " Total Width (GeV): " << parent->width()/GeV << endl; os << std::left << std::setw(40) << '#' << std::left << std::setw(20) << "Partial Width/GeV" << std::left << std::setw(20) << "BR" << "Yes/No\n"; for(set::iterator dit=modes.begin(); dit!=modes.end();++dit) os << std::left << std::setw(40) << (**dit).tag() << std::left << std::setw(20) << (**dit).brat()*parent->width()/GeV << std::left << std::setw(20) << (**dit).brat() << ((**dit).on() ? "Yes" : "No" ) << '\n'; os << "#\n#"; } else if(decayOutput_==2) { os << "# \t PDG \t Width\n"; os << "DECAY\t" << parent->id() << "\t" << parent->width()/GeV << "\t # " << parent->PDGName() << "\n"; for(set::iterator dit=modes.begin(); dit!=modes.end();++dit) { os << "\t" << std::left << std::setw(10) << (**dit).brat() << "\t" << (**dit).orderedProducts().size() << "\t"; for(unsigned int ix=0;ix<(**dit).orderedProducts().size();++ix) os << std::right << std::setw(10) << (**dit).orderedProducts()[ix]->id() ; for(unsigned int ix=(**dit).orderedProducts().size();ix<4;++ix) os << "\t"; os << "# " << (**dit).tag() << "\n"; } } } void ModelGenerator::createWidthGenerator(tPDPtr p) { string wn = p->fullName() + string("-WGen"); string mn = p->fullName() + string("-MGen"); GenericMassGeneratorPtr mgen = dynamic_ptr_cast (generator()->preinitCreate("Herwig::GenericMassGenerator", mn)); BSMWidthGeneratorPtr wgen = dynamic_ptr_cast (generator()->preinitCreate("Herwig::BSMWidthGenerator", wn)); //set the particle interface mgen->particle(p); wgen->particle(p); //set the generator interfaces in the ParticleData object generator()->preinitInterface(p, "Mass_generator","set", mn); generator()->preinitInterface(p, "Width_generator","set", wn); //allow the branching fraction of this particle type to vary p->variableRatio(true); if( p->CC() ) p->CC()->variableRatio(true); //initialize the generators generator()->preinitInterface(mgen, "Initialize", "set", "Yes"); generator()->preinitInterface(wgen, "Initialize", "set", "Yes"); string norm = BRnorm_ ? "Yes" : "No"; generator()->preinitInterface(wgen, "BRNormalize", "set", norm); string twob = twoBodyOnly_ ? "Yes" : "No"; generator()->preinitInterface(wgen, "TwoBodyOnly", "set", twob); ostringstream os; os << Npoints_; generator()->preinitInterface(wgen, "Points", "set", os.str()); os.str(""); os << Iorder_; generator()->preinitInterface(wgen, "InterpolationOrder", "set", os.str()); os.str(""); os << BWshape_; generator()->preinitInterface(mgen, "BreitWignerShape", "set", os.str()); } diff --git a/Models/General/ThreeBodyDecayConstructor.cc b/Models/General/ThreeBodyDecayConstructor.cc --- a/Models/General/ThreeBodyDecayConstructor.cc +++ b/Models/General/ThreeBodyDecayConstructor.cc @@ -1,374 +1,378 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the ThreeBodyDecayConstructor class. // #include "ThreeBodyDecayConstructor.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Utilities/Debug.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "Herwig/Decay/General/GeneralThreeBodyDecayer.h" #include "Herwig/Decay/DecayPhaseSpaceMode.h" #include "Herwig/PDT/ThreeBodyAllOnCalculator.h" #include "ThePEG/PDT/StandardMatchers.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Utilities/Throw.h" #include "DecayConstructor.h" #include "WeakCurrentDecayConstructor.h" using namespace Herwig; IBPtr ThreeBodyDecayConstructor::clone() const { return new_ptr(*this); } IBPtr ThreeBodyDecayConstructor::fullclone() const { return new_ptr(*this); } void ThreeBodyDecayConstructor::persistentOutput(PersistentOStream & os) const { os << interOpt_ << widthOpt_ << intOpt_ << relErr_ << includeIntermediatePhotons_; } void ThreeBodyDecayConstructor::persistentInput(PersistentIStream & is, int) { is >> interOpt_ >> widthOpt_ >> intOpt_ >> relErr_ >> includeIntermediatePhotons_; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigThreeBodyDecayConstructor("Herwig::ThreeBodyDecayConstructor", "Herwig.so"); void ThreeBodyDecayConstructor::Init() { static ClassDocumentation documentation ("The ThreeBodyDecayConstructor class constructs the three body decay modes"); static Switch interfaceIncludeIntermediatePhotons ("IncludeIntermediatePhotons", "Whether or not ot allow intermediate photons", &ThreeBodyDecayConstructor::includeIntermediatePhotons_, false, false, false); static SwitchOption interfaceIncludeIntermediatePhotonsYes (interfaceIncludeIntermediatePhotons, "Yes", "Include them", true); static SwitchOption interfaceIncludeIntermediatePhotonsNo (interfaceIncludeIntermediatePhotons, "No", "Don't include them", false); static Switch interfaceWidthOption ("WidthOption", "Option for the treatment of the widths of the intermediates", &ThreeBodyDecayConstructor::widthOpt_, 1, false, false); static SwitchOption interfaceWidthOptionFixed (interfaceWidthOption, "Fixed", "Use fixed widths", 1); static SwitchOption interfaceWidthOptionRunning (interfaceWidthOption, "Running", "Use running widths", 2); static SwitchOption interfaceWidthOptionZero (interfaceWidthOption, "Zero", "Set the widths to zero", 3); static Switch interfaceIntermediateOption ("IntermediateOption", "Option for the inclusion of intermediates in the event", &ThreeBodyDecayConstructor::interOpt_, 0, false, false); static SwitchOption interfaceIntermediateOptionAlways (interfaceIntermediateOption, "Always", "Always include the intermediates", 1); static SwitchOption interfaceIntermediateOptionNever (interfaceIntermediateOption, "Never", "Never include the intermediates", 2); static SwitchOption interfaceIntermediateOptionOnlyIfOnShell (interfaceIntermediateOption, "OnlyIfOnShell", "Only if there are on-shell diagrams", 0); static Switch interfaceIntegrationOption ("IntegrationOption", "Option for the integration of the partial width", &ThreeBodyDecayConstructor::intOpt_, 1, false, false); static SwitchOption interfaceIntegrationOptionAllPoles (interfaceIntegrationOption, "AllPoles", "Include all potential poles", 0); static SwitchOption interfaceIntegrationOptionShallowestPole (interfaceIntegrationOption, "ShallowestPole", "Only include the shallowest pole", 1); static Parameter interfaceRelativeError ("RelativeError", "The relative error for the GQ integration", &ThreeBodyDecayConstructor::relErr_, 1e-2, 1e-10, 1., false, false, Interface::limited); } void ThreeBodyDecayConstructor::DecayList(const set & particles) { if( particles.empty() ) return; // special for weak decays for(unsigned int ix=0;ixdecayConstructors().size();++ix) { Ptr::pointer weak = dynamic_ptr_cast::pointer > (decayConstructor()->decayConstructors()[ix]); if(!weak) continue; weakMassCut_ = max(weakMassCut_,weak->massCut()); } NBodyDecayConstructorBase::DecayList(particles); } GeneralThreeBodyDecayerPtr ThreeBodyDecayConstructor:: createDecayer(vector & diagrams, bool inter, double symfac) const { if(diagrams.empty()) return GeneralThreeBodyDecayerPtr(); // extract the external particles for the process PDPtr incoming = getParticleData(diagrams[0].incoming); // outgoing particles OrderedParticles outgoing; outgoing.insert(getParticleData(diagrams[0].outgoing )); outgoing.insert(getParticleData(diagrams[0].outgoingPair.first )); outgoing.insert(getParticleData(diagrams[0].outgoingPair.second)); // get the object name string objectname ("/Herwig/Decays/"); string classname = DecayerClassName(incoming, outgoing, objectname); if(classname=="") return GeneralThreeBodyDecayerPtr(); // create the object GeneralThreeBodyDecayerPtr decayer = dynamic_ptr_cast (generator()->preinitCreate(classname, objectname)); // set up the decayer and return if doesn't work vector outVector(outgoing.begin(),outgoing.end()); if(!decayer->setDecayInfo(incoming,outVector,diagrams,symfac)) return GeneralThreeBodyDecayerPtr(); // set decayer options from base class setDecayerInterfaces(objectname); // options for partial width integration ostringstream value; value << intOpt_; generator()->preinitInterface(objectname, "PartialWidthIntegration", "set", value.str()); value.str(""); value << relErr_; generator()->preinitInterface(objectname, "RelativeError", "set", value.str()); // set the width option value.str(""); value << widthOpt_; generator()->preinitInterface(objectname, "WidthOption", "set", value.str()); // set the intermediates option value.str(""); value << inter; generator()->preinitInterface(objectname, "GenerateIntermediates", "set", value.str()); // initialize the decayer decayer->init(); // return the decayer return decayer; } string ThreeBodyDecayConstructor:: DecayerClassName(tcPDPtr incoming, const OrderedParticles & outgoing, string & objname) const { string classname("Herwig::"); // spins of the outgoing particles unsigned int ns(0),nf(0),nv(0); objname += incoming->PDGName() + "2"; for(OrderedParticles::const_iterator it=outgoing.begin(); it!=outgoing.end();++it) { if ((**it).iSpin()==PDT::Spin0 ) ++ns; else if((**it).iSpin()==PDT::Spin1Half) ++nf; else if((**it).iSpin()==PDT::Spin1 ) ++nv; objname += (**it).PDGName(); } objname += "Decayer"; if(incoming->iSpin()==PDT::Spin0) { if(ns==1&&nf==2) classname += "StoSFFDecayer"; else if(nf==2&&nv==1) classname += "StoFFVDecayer"; else classname = ""; } else if(incoming->iSpin()==PDT::Spin1Half) { if(nf==3) classname += "FtoFFFDecayer"; else if(nf==1&&nv==2) classname += "FtoFVVDecayer"; else classname = ""; } else if(incoming->iSpin()==PDT::Spin1) { if(nf==2&&nv==1) classname += "VtoFFVDecayer"; else classname = ""; } else { classname=""; } return classname; } void ThreeBodyDecayConstructor:: createDecayMode(vector & mode, bool possibleOnShell, double symfac) { // convert the diagrams from the general to the three body structure vector diagrams; for(unsigned int iy=0;iyZERO && diagrams.back().intermediate && abs(diagrams.back().intermediate->id())==ParticleID::Wplus) { Energy deltaM = getParticleData(diagrams.back().incoming)->mass() - getParticleData(diagrams.back().outgoing)->mass(); if(deltaMid())==ParticleID::gamma) diagrams.pop_back(); } if(diagrams.empty()) return; // check if possible on-shell internal particles bool inter = interOpt_ == 1 || (interOpt_ == 0 && possibleOnShell); // incoming particle tPDPtr inpart = getParticleData(diagrams[0].incoming); // outgoing particles OrderedParticles outgoing; outgoing.insert(getParticleData(diagrams[0].outgoing)); outgoing.insert(getParticleData(diagrams[0].outgoingPair.first )); outgoing.insert(getParticleData(diagrams[0].outgoingPair.second)); // sort out ordering and labeling of diagrams vector outVector(outgoing.begin(),outgoing.end()); for(unsigned int ix=0;ixid() != diagrams[ix].outgoingPair.first) || ( diagrams[ix].channelType == TBDiagram::channel13 && outVector[0]->id() != diagrams[ix].outgoingPair.first) || ( diagrams[ix].channelType == TBDiagram::channel12 && outVector[0]->id() != diagrams[ix].outgoingPair.first) ) swap(diagrams[ix].outgoingPair.first, diagrams[ix].outgoingPair.second); } // construct the tag for the decay mode string tag = inpart->name() + "->"; unsigned int iprod=0; for(OrderedParticles::const_iterator it = outgoing.begin(); it != outgoing.end(); ++it) { ++iprod; tag += (**it).name(); if(iprod != 3) tag += ","; } tag += ";"; tDMPtr dm = generator()->findDecayMode(tag); // create mode if needed if( createDecayModes() && (!dm || inpart->id() == ParticleID::h0) ) { // create the decayer GeneralThreeBodyDecayerPtr decayer = createDecayer(diagrams,inter,symfac); if(!decayer) { if(Debug::level > 1 ) generator()->log() << "Can't create the decayer for " << tag << " so mode not created\n"; return; } + OrderedParticles::const_iterator pit=outgoing.begin(); + tPDPtr pa = *pit; ++pit; + tPDPtr pb = *pit; ++pit; + tPDPtr pc = *pit; + Energy width = + decayer->partialWidth(make_pair(inpart,inpart->mass()), + make_pair(pa,pa->mass()) , + make_pair(pb,pb->mass()) , + make_pair(pc,pc->mass())); + if ( Debug::level > 1 ) + generator()->log() << "Partial width is: " << width / GeV << " GeV\n"; + if(width==ZERO) { + if ( Debug::level > 1 ) + generator()->log() << "Partial width for " + << tag << " zero so mode not created \n"; + generator()->preinitRemove(decayer); + return; + } tDMPtr ndm = generator()->preinitCreateDecayMode(tag); - if(ndm) { - generator()->preinitInterface(ndm, "Decayer", "set", - decayer->fullName()); - generator()->preinitInterface(ndm, "Active", "set", "Yes"); - if(!ndm->decayer()) { - generator()->log() << "Can't set the decayer for " - << tag << " so mode not created \n"; - return; - } - OrderedParticles::const_iterator pit=outgoing.begin(); - tPDPtr pa = *pit; ++pit; - tPDPtr pb = *pit; ++pit; - tPDPtr pc = *pit; - Energy width = - decayer->partialWidth(make_pair(inpart,inpart->mass()), - make_pair(pa,pa->mass()) , - make_pair(pb,pb->mass()) , - make_pair(pc,pc->mass())); - if ( Debug::level > 1 ) - generator()->log() << "Partial width is: " << width / GeV << " GeV\n"; - - setBranchingRatio(ndm, width); - if(ndm->brat()minimumBR()) { - generator()->preinitInterface(decayer->fullName(), - "Initialize", "set","0"); - } - // incoming particle is now unstable - inpart->stable(false); - if(Debug::level > 1 ) { - generator()->log() << "Calculated partial width for mode " - << tag << " is " << width/GeV << "\n"; - } - } - else + if(!ndm) throw NBodyDecayConstructorError() << "ThreeBodyDecayConstructor::createDecayMode - Needed to create " << "new decaymode but one could not be created for the tag " << tag << Exception::warning; + generator()->preinitInterface(ndm, "Decayer", "set", + decayer->fullName()); + generator()->preinitInterface(ndm, "Active", "set", "Yes"); + if(!ndm->decayer()) { + generator()->log() << "Can't set the decayer for " + << tag << " so mode not created \n"; + return; + } + setBranchingRatio(ndm, width); + if(ndm->brat()minimumBR()) { + generator()->preinitInterface(decayer->fullName(), + "Initialize", "set","0"); + } + // incoming particle is now unstable + inpart->stable(false); + if(Debug::level > 1 ) { + generator()->log() << "Calculated partial width for mode " + << tag << " is " << width/GeV << "\n"; + } } else if( dm ) { if(dm->brat()minimumBR()) { return; } if((dm->decayer()->fullName()).find("Mambo") != string::npos) { // create the decayer GeneralThreeBodyDecayerPtr decayer = createDecayer(diagrams,inter,symfac); if(decayer) { generator()->preinitInterface(dm, "Decayer", "set", decayer->fullName()); // check not zero OrderedParticles::const_iterator pit=outgoing.begin(); tPDPtr pa = *pit; ++pit; tPDPtr pb = *pit; ++pit; tPDPtr pc = *pit; Energy width = decayer->partialWidth(make_pair(inpart,inpart->mass()), make_pair(pa,pa->mass()) , make_pair(pb,pb->mass()) , make_pair(pc,pc->mass())); if(width/(dm->brat()*inpart->width())<1e-10) { string message = "Herwig calculation of the partial width for the decay mode " + inpart->PDGName() + " -> " + pa->PDGName() + " " + pb->PDGName() + " " + pc->PDGName() + " is zero.\n This will cause problems with the calculation of" + " spin correlations.\n It is probably due to inconsistent parameters" + " and decay modes being passed to Herwig via the SLHA file.\n" + " Zeroing the branching ratio for this mode."; setBranchingRatio(dm,ZERO); generator()->logWarning(NBodyDecayConstructorError(message,Exception::warning)); } } // incoming particle is now unstable inpart->stable(false); } } //update CC mode if it exists if( inpart->CC() ) inpart->CC()->synchronize(); } diff --git a/Models/Makefile.am b/Models/Makefile.am --- a/Models/Makefile.am +++ b/Models/Makefile.am @@ -1,181 +1,181 @@ SUBDIRS = RSModel StandardModel General Susy UED Zprime \ Transplanckian ADD Leptoquarks Sextet TTbAsymm \ LH LHTP Feynrules noinst_LTLIBRARIES = libHwStandardModel.la nodist_libHwStandardModel_la_SOURCES = \ StandardModel/SM__all.cc libHwStandardModel_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/StandardModel noinst_LTLIBRARIES += libHwModelGenerator.la nodist_libHwModelGenerator_la_SOURCES = \ General/ModelGenerator__all.cc libHwModelGenerator_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/General if WANT_BSM pkglib_LTLIBRARIES = \ HwRSModel.la \ HwUED.la \ HwSusy.la \ HwNMSSM.la \ HwRPV.la \ HwZprimeModel.la \ HwTransplanck.la \ HwADDModel.la \ HwLeptoquarkModel.la \ HwSextetModel.la \ HwTTbAModel.la \ HwLHModel.la \ HwLHTPModel.la endif ############# HwRSModel_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 10:0:0 HwRSModel_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/RSModel nodist_HwRSModel_la_SOURCES = \ RSModel/RS__all.cc ############# HwUED_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 10:1:0 HwUED_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/UED nodist_HwUED_la_SOURCES = \ UED/UED__all.cc ############# HwSusy_la_LDFLAGS = \ -$(AM_LDFLAGS) -module -version-info 13:1:0 +$(AM_LDFLAGS) -module -version-info 13:2:0 HwSusy_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/Susy nodist_HwSusy_la_SOURCES = \ Susy/Susy__all.cc ############# HwNMSSM_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 5:0:0 HwNMSSM_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/Susy/NMSSM nodist_HwNMSSM_la_SOURCES = \ Susy/NMSSM/NMSSM__all.cc ############# HwRPV_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 3:0:0 HwRPV_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/Susy/RPV nodist_HwRPV_la_SOURCES = \ Susy/RPV/RPV__all.cc ############# HwZprimeModel_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 3:0:0 HwZprimeModel_la_SOURCES = \ Zprime/ZprimeModel.cc Zprime/ZprimeModelZPQQVertex.cc ############# HwTransplanck_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 4:1:0 HwTransplanck_la_SOURCES = \ Transplanckian/METRP2to2.cc ############# HwADDModel_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 4:0:0 HwADDModel_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/ADD nodist_HwADDModel_la_SOURCES = \ ADD/ADD__all.cc ############# HwLeptoquarkModel_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 5:0:0 HwLeptoquarkModel_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/Leptoquarks nodist_HwLeptoquarkModel_la_SOURCES = \ Leptoquarks/Leptoquark__all.cc ############# HwSextetModel_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 3:0:0 HwSextetModel_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/Sextet nodist_HwSextetModel_la_SOURCES = \ Sextet/Sextet__all.cc ############# HwTTbAModel_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 3:0:0 HwTTbAModel_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/TTbAsymm nodist_HwTTbAModel_la_SOURCES = \ TTbAsymm/TTbA__all.cc ############# HwLHModel_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 5:0:0 HwLHModel_la_CPPFLAGS = \ $(AM_CPPFLAGS) -I$(srcdir)/LH nodist_HwLHModel_la_SOURCES = \ LH/LH__all.cc ############# HwLHTPModel_la_LDFLAGS = \ $(AM_LDFLAGS) -module -version-info 5:0:0 HwLHTPModel_la_LIBADD = \ $(GSLLIBS) HwLHTPModel_la_CPPFLAGS = \ $(AM_CPPFLAGS) $(GSLINCLUDE) -I$(srcdir)/LHTP nodist_HwLHTPModel_la_SOURCES = \ LHTP/LHTP__all.cc ############# diff --git a/Models/Susy/SSGOGOHVertex.cc b/Models/Susy/SSGOGOHVertex.cc --- a/Models/Susy/SSGOGOHVertex.cc +++ b/Models/Susy/SSGOGOHVertex.cc @@ -1,238 +1,238 @@ // -*- C++ -*- // // SSGOGOHVertex.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SSGOGOHVertex class. // #include "SSGOGOHVertex.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDT/EnumParticles.h" #include using namespace ThePEG::Helicity; using namespace Herwig; -SSGOGOHVertex::SSGOGOHVertex() : theMw(), theSij(2, {{0., 0.}}), - theQij(2, {{0., 0.}}), - theQijLp(4, {{0., 0.}}), - theQijRp(4, {{0., 0.}}), - theSijdp(4, {{0., 0., 0., 0.}}), - theQijdp(4, {{0., 0., 0., 0.}}), +SSGOGOHVertex::SSGOGOHVertex() : theMw(), theSij(2, {0., 0.}), + theQij(2, {0., 0.}), + theQijLp(4, {0., 0.}), + theQijRp(4, {0., 0.}), + theSijdp(4, {0., 0., 0., 0.}), + theQijdp(4, {0., 0., 0., 0.}), theSa(0.0), theSb(0.0), theCa(0.0), theCb(0.0), theCoupLast(0.0), theLLast(0.0), theRLast(0.0), theHLast(0), theID1Last(0), theID2Last(0), theq2last() { orderInGem(1); orderInGs(0); colourStructure(ColourStructure::SINGLET); } void SSGOGOHVertex::doinit() { long neu[4] = {1000022, 1000023, 1000025, 1000035}; long chg[2] = {1000024, 1000037}; long higgs[3] = {25, 35, 36}; for(unsigned int i = 0; i < 4; ++i) { //neutralinos for(unsigned int j = 0; j < 4; ++j) { for(unsigned int k = 0; k < 4; ++k) { if( i < 3 ) { if(k<=j) addToList(neu[j], neu[k], higgs[i]); //charginos if( j < 2 && k < 2 ) { addToList(-chg[j], chg[k], higgs[i]); } } else { if( k == 2 ) break; addToList(-chg[k], neu[j], 37); addToList( chg[k], neu[j],-37); } } } } FFSVertex::doinit(); tMSSMPtr theMSSM = dynamic_ptr_cast(generator()->standardModel()); if( !theMSSM ) throw InitException() << "SSGOGOHVertex::doinit() - The pointer to the MSSM object is null!" << Exception::abortnow; theMw = getParticleData(ParticleID::Wplus)->mass(); double theSw = sqrt(sin2ThetaW()); double tw = theSw/sqrt(1. - theSw*theSw); double tanb = theMSSM->tanBeta(); theSb = tanb/sqrt(1. + sqr(tanb)); theCb = sqrt( 1. - sqr(theSb) ); theSa = sin(theMSSM->higgsMixingAngle()); theCa = sqrt(1. - sqr(theSa)); MixingMatrix nmix = *theMSSM->neutralinoMix(); MixingMatrix umix = *theMSSM->charginoUMix(); MixingMatrix vmix = *theMSSM->charginoVMix(); for(unsigned int i = 0; i < 4; ++i) { for(unsigned int j = 0; j < 4; ++j) { if( i < 2 && j < 2 ) { theQij[i][j] = vmix(i,0)*umix(j,1)/sqrt(2); theSij[i][j] = vmix(i,1)*umix(j,0)/sqrt(2); } if( j < 2 ) { theQijLp[i][j] = conj(nmix(i, 3)*vmix(j,0) + (nmix(i,1) + nmix(i,0)*tw)*vmix(j,1)/sqrt(2)); theQijRp[i][j] = nmix(i, 2)*umix(j,0) - (nmix(i,1) + nmix(i,0)*tw)*umix(j,1)/sqrt(2); } theQijdp[i][j] = 0.5*( nmix(i,2)*( nmix(j,1) - tw*nmix(j,0) ) + nmix(j,2)*( nmix(i,1) - tw*nmix(i,0) ) ); theSijdp[i][j] = 0.5*( nmix(i,3)*( nmix(j,1) - tw*nmix(j,0) ) + nmix(j,3)*( nmix(i,1) - tw*nmix(i,0) ) ); } } } void SSGOGOHVertex::persistentOutput(PersistentOStream & os) const { os << theSij << theQij << theQijLp << theQijRp << theSijdp << theQijdp << ounit(theMw,GeV) << theSa << theSb << theCa << theCb; } void SSGOGOHVertex::persistentInput(PersistentIStream & is, int) { is >> theSij >> theQij >> theQijLp >> theQijRp >> theSijdp >> theQijdp >> iunit(theMw,GeV) >> theSa >> theSb >> theCa >> theCb; } // Static variable needed for the type description system in ThePEG. DescribeClass describeHerwigSSGOGOHVertex("Herwig::SSGOGOHVertex", "HwSusy.so"); void SSGOGOHVertex::Init() { static ClassDocumentation documentation ("The coupling of the higgs bosons to SM fermions in the MSSM"); } /// \todo fixme void SSGOGOHVertex::setCoupling(Energy2 q2, tcPDPtr particle1, tcPDPtr particle2,tcPDPtr particle3) { long f1ID(particle1->id()), f2ID(particle2->id()), higgsID(particle3->id()); assert(higgsID == ParticleID::h0 || higgsID == ParticleID::H0 || higgsID == ParticleID::A0 || abs(higgsID) == ParticleID::Hplus); if( f1ID < 0 ) swap(f1ID, f2ID); if( q2 != theq2last || theCoupLast == 0. ) { theCoupLast = weakCoupling(q2); theq2last = q2; } if( higgsID == theHLast && f1ID == theID1Last && f2ID == theID2Last) { norm(theCoupLast); left(theLLast); right(theRLast); return; } theHLast = higgsID; theID1Last = f1ID; theID2Last = f2ID; if( higgsID == ParticleID::h0 ) { //charginos if( abs(f2ID) == ParticleID::SUSY_chi_1plus || abs(f2ID) == ParticleID::SUSY_chi_2plus ) { unsigned int ei = (abs(f1ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1; unsigned int ej = (abs(f2ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1; theLLast = conj(theQij[ej][ei])*theSa - conj(theSij[ej][ei])*theCa; theRLast = theQij[ei][ej]*theSa - theSij[ei][ej]*theCa; } //neutralinos else { unsigned int ei(f1ID - ParticleID::SUSY_chi_10), ej(f2ID - ParticleID::SUSY_chi_10); if( ei > 1 ) ei = ( ei == 13 ) ? 3 : 2; if( ej > 1 ) ej = ( ej == 13 ) ? 3 : 2; theLLast = conj(theQijdp[ej][ei])*theSa + conj(theSijdp[ej][ei])*theCa; theRLast = theQijdp[ei][ej]*theSa + theSijdp[ei][ej]*theCa ; } } else if( higgsID == ParticleID::H0 ) { //charginos if( abs(f2ID) == ParticleID::SUSY_chi_1plus || abs(f2ID) == ParticleID::SUSY_chi_2plus ) { unsigned int ei = (abs(f1ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1; unsigned int ej = (abs(f2ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1; theLLast = -conj(theQij[ej][ei])*theCa - conj(theSij[ej][ei])*theSa; theRLast = -theQij[ei][ej]*theCa - theSij[ei][ej]*theSa; } //neutralinos else { unsigned int ei(f1ID - ParticleID::SUSY_chi_10), ej(f2ID - ParticleID::SUSY_chi_10); if( ei > 1 ) ei = ( ei == 13 ) ? 3 : 2; if( ej > 1 ) ej = ( ej == 13 ) ? 3 : 2; theLLast = -conj(theQijdp[ej][ei])*theCa + conj(theSijdp[ej][ei])*theSa; theRLast = -theQijdp[ei][ej]*theCa + theSijdp[ei][ej]*theSa; } } else if( higgsID == ParticleID::A0 ) { if( abs(f2ID) == ParticleID::SUSY_chi_1plus || abs(f2ID) == ParticleID::SUSY_chi_2plus ) { unsigned int ei = (abs(f1ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1; unsigned int ej = (abs(f2ID) == ParticleID::SUSY_chi_1plus) ? 0 : 1; theLLast = Complex(0.,1.)*( conj(theQij[ej][ei])*theSb + conj(theSij[ej][ei])*theCb ); theRLast = -Complex(0.,1.)*(theQij[ei][ej]*theSb + theSij[ei][ej]*theCb); } //neutralinos else { unsigned int ei(f1ID - ParticleID::SUSY_chi_10), ej(f2ID - ParticleID::SUSY_chi_10); if( ei > 1 ) ei = ( ei == 13 ) ? 3 : 2; if( ej > 1 ) ej = ( ej == 13 ) ? 3 : 2; theLLast = Complex(0.,1.)*( conj(theQijdp[ej][ei])*theSb - conj(theSijdp[ej][ei])*theCb ); theRLast = -Complex(0.,1.)*(theQijdp[ei][ej]*theSb - theSijdp[ei][ej]*theCb); } } //charged higgs else { unsigned int ei(0),ej(0); long chg(f2ID), neu(f1ID); if( abs(neu) == ParticleID::SUSY_chi_1plus || abs(neu) == ParticleID::SUSY_chi_2plus ) swap(chg, neu); ej = ( abs(chg) == ParticleID::SUSY_chi_1plus) ? 0 : 1; ei = neu - ParticleID::SUSY_chi_10; if( ei > 1 ) ei = ( ei == 13 ) ? 3 : 2; theLLast = -theQijLp[ei][ej]*theCb; theRLast = -theQijRp[ei][ej]*theSb; if( higgsID < 0 ) { Complex tmp = theLLast; theLLast = conj(theRLast); theRLast = conj(tmp); } } norm(theCoupLast); left(theLLast); right(theRLast); } diff --git a/Models/Transplanckian/METRP2to2.cc b/Models/Transplanckian/METRP2to2.cc --- a/Models/Transplanckian/METRP2to2.cc +++ b/Models/Transplanckian/METRP2to2.cc @@ -1,344 +1,344 @@ // -*- C++ -*- // // METRP2to2.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2009-2017 The Herwig Collaboration // // Herwig 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 METRP2to2 class. // #include "METRP2to2.h" #include "ThePEG/Utilities/SimplePhaseSpace.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "Herwig/Models/StandardModel/StandardModel.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/Utilities/Interpolator.h" #include "ThePEG/Utilities/DescribeClass.h" #include using namespace Herwig; DescribeClass describeHerwigMETRP2to2("Herwig::METRP2to2","HwTransplanck.so"); HERWIG_INTERPOLATOR_CLASSDESC(METRP2to2,double,double) METRP2to2::METRP2to2() : _maxflavour(2), _ndim(6), _planckmass(1500.0*GeV), _process(0) { massOption({{0,0}}); } void METRP2to2::doinit() { HwMEBase::doinit(); setup_interpolator(); } void METRP2to2::rebind(const TranslationMap & trans) { _interpol = trans.translate(_interpol); HwMEBase::rebind(trans); } IVector METRP2to2::getReferences() { IVector ret = HwMEBase::getReferences(); ret.push_back(_interpol); return ret; } void METRP2to2::setup_interpolator() { static const array xmatrix1 = {{0.0, 0.02, 0.10, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3., 3.2, 3.4, 3.6, 3.8, 4., 4.2, 4.4, 4.6, 4.8, 5.0, 5.2, 5.4, 5.6, 5.8, 6., 6.2, 6.4, 6.6, 6.8, 7., 7.2, 7.4, 7.6, 7.8, 8., 8.2, 8.4, 8.6, 8.8, 9., 9.2, 9.4, 9.6, 9.8, 10., 10.2, 10.4, 10.6, 10.8, 11., 11.2, 11.4, 11.6, 11.8, 12., 12.2, 12.4, 12.6, 12.8, 13., 13.2, 13.4, 13.6, 13.8, 14., 14.2, 14.4, 14.6, 14.8, 15., 15.2, 15.4, 15.6, 15.8, 16., 16.2, 16.4, 16.6, 16.8, 17., 17.2, 17.4, 17.6, 17.8, 18., 18.2, 18.4, 18.6, 18.8, 19., 19.2, 19.4, 19.6, 19.8, 20.0 }}; static const array xmatrix2 = {{0.02, 0.10, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3., 3.2, 3.4, 3.6, 3.8, 4., 4.2, 4.4, 4.6, 4.8, 5., 5.2, 5.4, 5.6, 5.8, 6., 6.2, 6.4, 6.6, 6.8, 7., 7.2, 7.4, 7.6, 7.8, 8., 8.2, 8.4, 8.6, 8.8, 9., 9.2, 9.4, 9.6, 9.8, 10., 10.2, 10.4, 10.6, 10.8, 11., 11.2, 11.4, 11.6, 11.8, 12., 12.2, 12.4, 12.6, 12.8, 13., 13.2, 13.4, 13.6, 13.8, 14., 14.2, 14.4, 14.6, 14.8, 15., 15.2, 15.4, 15.6, 15.8, 16., 16.2, 16.4, 16.6, 16.8, 17., 17.2, 17.4, 17.6, 17.8, 18., 18.2, 18.4, 18.6, 18.8, 19., 19.2, 19.4, 19.6, 19.8, 20.0 }}; static const array datamatrix2 = {{4.32048, 2.74662, 2.090560, 1.457590, 1.113050, 0.885216, 0.720795, 0.597404, 0.501483, 0.425543, 0.364668, 0.315299, 0.274983, 0.241792, 0.214466, 0.191698, 0.172689, 0.156841, 0.143329, 0.131919, 0.122174, 0.113656, 0.106339, 0.099869, 0.094101, 0.089013, 0.084378, 0.080185, 0.076376, 0.072856, 0.069622, 0.066624, 0.063844, 0.061242, 0.058820, 0.056561, 0.054417, 0.052433, 0.05055, 0.048772, 0.047129, 0.045546, 0.044056, 0.042673, 0.041328, 0.040078, 0.038895, 0.037749, 0.036688, 0.035666, 0.034687, 0.033771, 0.032883, 0.032041, 0.031239, 0.030467, 0.029731, 0.029025, 0.028350, 0.027698, 0.027075, 0.026479, 0.025896, 0.025347, 0.024812, 0.024291, 0.023804, 0.023318, 0.022854, 0.022416, 0.021974, 0.021561, 0.021160, 0.020761, 0.020390, 0.020021, 0.019662, 0.019325, 0.01898, 0.018662, 0.018351, 0.018041, 0.017747, 0.017459, 0.017177, 0.016906, 0.016641, 0.016384, 0.016132, 0.015889, 0.015651, 0.015418, 0.015196, 0.014973, 0.014759, 0.014553, 0.014345, 0.014149, 0.013956, 0.013762, 0.013582, 0.013399 }}; static const array datamatrix3 = {{1.33947, 1.32238, 1.25505, 1.17491, 1.02696, 0.89463, 0.77688, 0.67270, 0.58105, 0.50095, 0.43143, 0.37156, 0.32046, 0.27726, 0.24113, 0.21126, 0.18684, 0.16707, 0.15118, 0.13843, 0.12815, 0.11974, 0.11271, 0.10670, 0.10141, 0.09663, 0.09224, 0.08814, 0.08427, 0.08061, 0.07715, 0.07387, 0.07077, 0.06785, 0.06511, 0.06254, 0.06014, 0.05790, 0.05582, 0.05388, 0.05207, 0.05038, 0.04879, 0.04731, 0.04591, 0.04459, 0.04334, 0.04216, 0.04103, 0.03996, 0.03894, 0.03796, 0.03702, 0.03612, 0.03526, 0.03443, 0.03363, 0.03287, 0.03214, 0.03143, 0.03075, 0.03010, 0.02947, 0.02887, 0.02829, 0.02773, 0.02719, 0.02666, 0.02616, 0.02567, 0.0250, 0.02475, 0.02431, 0.02388, 0.02347, 0.02306, 0.02267, 0.02230, 0.02193, 0.02157, 0.02123, 0.02089, 0.02056, 0.02025, 0.01994, 0.01964, 0.01934, 0.01906, 0.018, 0.01851, 0.01825, 0.01799, 0.01774, 0.01750, 0.01726, 0.01703, 0.01680, 0.01658, 0.01637, 0.01616, 0.01595, 0.01575, 0.01555}}; static const array datamatrix4 = {{0.88623, 0.885845, 0.879328, 0.86361, 0.81617, 0.75594, 0.68928, 0.62036, 0.55206, 0.48641, 0.42484, 0.36832, 0.31749, 0.27273, 0.23419, 0.20185, 0.17547, 0.15464, 0.13871, 0.12685, 0.11813, 0.11162, 0.10654, 0.10229, 0.09844, 0.09475, 0.09107, 0.08738, 0.08368, 0.08000, 0.07641, 0.07295, 0.06967, 0.06660, 0.06377, 0.06118, 0.05883, 0.05670, 0.05476, 0.05300, 0.05138, 0.04989, 0.04849, 0.04716, 0.04590, 0.04469, 0.04353, 0.04240, 0.04131, 0.04026, 0.03924, 0.03826, 0.037, 0.03642, 0.03556, 0.03473, 0.03394, 0.03319, 0.03247, 0.03178, 0.03112, 0.03049, 0.02988, 0.02930, 0.02873, 0.02819, 0.02767, 0.02716, 0.02667, 0.02619, 0.02573, 0.02529, 0.02486, 0.02444, 0.02403, 0.02364, 0.02326, 0.02289, 0.02253, 0.02218, 0.02184, 0.02152, 0.02120, 0.02089, 0.02058, 0.02029, 0.02000, 0.01972, 0.01944, 0.01918, 0.01892, 0.01866, 0.01841, 0.01816, 0.01792, 0.01769, 0.01746, 0.01724, 0.01702, 0.01681, 0.01660, 0.01639, 0.01619 }}; static const array datamatrix5 = {{0.744596, 0.744489, 0.742327, 0.73584, 0.71183, 0.67590, 0.63118, 0.58053, 0.52645, 0.47109, 0.41628, 0.36351, 0.31401, 0.26878, 0.22857, 0.19396, 0.16533, 0.14280, 0.12611, 0.11459, 0.10713, 0.10244, 0.09934, 0.09690, 0.09453, 0.09189, 0.08887, 0.08548, 0.08180, 0.07796, 0.07410, 0.07035, 0.06681, 0.06358, 0.06068, 0.05815, 0.05595, 0.05405, 0.05240, 0.05094, 0.04962, 0.04838, 0.04720, 0.04604, 0.04489, 0.04375, 0.04262, 0.04150, 0.04040, 0.03934, 0.03831, 0.03733, 0.03639, 0.03551, 0.03469, 0.03391, 0.03317, 0.03247, 0.03181, 0.03118, 0.03057, 0.02998, 0.02941, 0.02886, 0.02832, 0.02779, 0.02728, 0.02678, 0.02630, 0.02583, 0.02538, 0.02494, 0.02452, 0.02412, 0.02373, 0.02335, 0.02299, 0.02264, 0.02230, 0.02197, 0.02165, 0.02134, 0.02104, 0.02074, 0.02045, 0.02016, 0.01989, 0.01961, 0.01935, 0.01909, 0.01883, 0.01858, 0.01834, 0.01810, 0.01787, 0.01764, 0.01742, 0.01721, 0.01699, 0.01679, 0.01659, 0.01639, 0.01620}}; static const array datamatrix6 = {{0.67759, 0.677074, 0.675686, 0.67139, 0.65466, 0.62818, 0.59351, 0.55242, 0.50671, 0.45815, 0.40837, 0.35888, 0.31104, 0.26603, 0.22490, 0.18855, 0.15777, 0.13319, 0.11510, 0.10322, 0.09650, 0.09333, 0.09206, 0.09137, 0.09045, 0.08888, 0.08652, 0.08343, 0.07977, 0.07574, 0.07157, 0.06747, 0.06364, 0.06020, 0.05725, 0.05479, 0.05281, 0.05121, 0.04991, 0.04880, 0.04779, 0.04680, 0.04580, 0.04475, 0.04364, 0.04249, 0.04130, 0.04012, 0.03895, 0.03783, 0.03677, 0.03579, 0.03488, 0.03405, 0.03330, 0.03261, 0.03197, 0.03137, 0.03080, 0.03025, 0.02970, 0.02917, 0.02863, 0.02811, 0.02758, 0.02707, 0.02657, 0.02608, 0.02560, 0.02515, 0.02471, 0.02430, 0.02390, 0.02351, 0.02314, 0.02279, 0.02244, 0.02211, 0.02178, 0.02146, 0.02115, 0.02084, 0.02054, 0.02025, 0.01996, 0.01968, 0.01941, 0.01915, 0.01890, 0.01865, 0.01841, 0.01818, 0.01795, 0.01773, 0.01751, 0.01730, 0.01710, 0.01690, 0.01670, 0.01650, 0.01631, 0.01612, 0.01593 }}; //assign the appropriate tabulated points for the number of extra dimensions switch ( _ndim ) { case 2 : _interpol = make_InterpolatorPtr(datamatrix2, xmatrix2, 1); break; case 3 : _interpol = make_InterpolatorPtr(datamatrix3, xmatrix1, 1); break; case 4 : _interpol = make_InterpolatorPtr(datamatrix4, xmatrix1, 1); break; case 5 : _interpol = make_InterpolatorPtr(datamatrix5, xmatrix1, 1); break; case 6 : _interpol = make_InterpolatorPtr(datamatrix6, xmatrix1, 1); break; default : assert(false); } } IBPtr METRP2to2::clone() const { return new_ptr(*this); } IBPtr METRP2to2::fullclone() const { return new_ptr(*this); } void METRP2to2::persistentOutput(PersistentOStream & os) const { os << _interpol << _maxflavour << _process << _ndim << ounit(_planckmass,GeV); } void METRP2to2::persistentInput(PersistentIStream & is, int) { is >> _interpol >> _maxflavour >> _process >> _ndim >> iunit(_planckmass,GeV); } Energy2 METRP2to2::scale() const { Energy2 invbcsq = 1 / sqr(bccalc(sHat())); return ( -tHat() > invbcsq ) ? invbcsq : -tHat(); } void METRP2to2::Init() { static ClassDocumentation documentation ("The METRP2to2 class implements the transplanckian 2->2 processes in hadron-hadron" " collisions"); static Parameter interfaceMaximumFlavour ("MaximumFlavour", "The maximum flavour of the quarks in the process", &METRP2to2::_maxflavour, 2, 1, 5, false, false, Interface::limited); static Parameter interfacePlanckMass ("PlanckMass", "The Planck Mass", &METRP2to2::_planckmass, GeV, 2000.0*GeV, 200.0*GeV, 200000.0*GeV, false, false, Interface::limited); static Parameter interfaceNumberExtraDimensions ("NumberExtraDimensions", "The number of extra dimensions to consider", &METRP2to2::_ndim, 6, 2, 6, false, false, Interface::limited); static Switch interfaceProcess ("Process", "Which subprocesses to include", &METRP2to2::_process, 0, false, false); static SwitchOption interfaceProcessAll (interfaceProcess, "All", "Include all subprocesses", 0); static SwitchOption interfaceProcess1 (interfaceProcess, "gg2gg", "Include only gg->gg subprocesses", 1); static SwitchOption interfaceProcessqgqg (interfaceProcess, "qg2qg", "Include only q g -> q g processes", 4); static SwitchOption interfaceProcessqbargqbarg (interfaceProcess, "qbarg2qbarg", "Include only qbar g -> qbar g processes", 5); static SwitchOption interfaceProcessqqqq (interfaceProcess, "qq2qq", "Include only q q -> q q processes", 6); static SwitchOption interfaceProcessqbarqbarqbarqbar (interfaceProcess, "qbarqbar2qbarqbar", "Include only qbar qbar -> qbar qbar processes", 7); static SwitchOption interfaceProcessqqbarqqbar (interfaceProcess, "qqbar2qqbar", "Include only q qbar -> q qbar processes", 8); } Selector METRP2to2::diagrams(const DiagramVector & diags) const { // select the diagram, this is easy for us as we have already done it Selector sel; for ( DiagramIndex i = 0; i < diags.size(); ++i ) { sel.insert(1.0, i); } return sel; } void METRP2to2::getDiagrams() const { // get the particle data objects PDPtr gluon = getParticleData(ParticleID::g); PDPtr trpon = getParticleData(39); vector quark,antiquark; for(int ix=1;ix<=int(_maxflavour);++ix) { quark.push_back( getParticleData( ix)); antiquark.push_back(getParticleData(-ix)); } // gg-> gg subprocess if(_process==0||_process==1) { add(new_ptr((Tree2toNDiagram(3),gluon,trpon,gluon, 1,gluon, 2,gluon,-2))); } // processes involving one quark line for(unsigned int ix=0;ix<_maxflavour;++ix) { // q g -> q g subprocesses if(_process==0||_process==4) { add(new_ptr((Tree2toNDiagram(3),quark[ix],trpon,gluon, 1,quark[ix],2,gluon,-12))); } // qbar g -> qbar g subprocesses if(_process==0||_process==5) { add(new_ptr((Tree2toNDiagram(3),antiquark[ix],trpon,gluon, 1,antiquark[ix],2,gluon,-15))); } // processes involving two quark lines for(unsigned int iy=0;iy<_maxflavour;++iy) { // q q -> q q subprocesses if(_process==0||_process==6) { // t-channel add(new_ptr((Tree2toNDiagram(3),quark[ix],trpon,quark[iy], 1,quark[ix],2,quark[iy],-16))); //exchange for identical quarks if(ix==iy) add(new_ptr((Tree2toNDiagram(3),quark[ix],trpon,quark[iy], 2,quark[ix],1,quark[iy],-17))); } // qbar qbar -> qbar qbar subprocesses if(_process==0||_process==7) { // t-channel add(new_ptr((Tree2toNDiagram(3),antiquark[ix],trpon,antiquark[iy], 1,antiquark[ix],2,antiquark[iy],-18))); //exchange for identical quarks if(ix==iy) add(new_ptr((Tree2toNDiagram(3),antiquark[ix],trpon,antiquark[iy], 2,antiquark[ix],1,antiquark[iy],-19))); } // q qbar -> q qbar if(_process==0||_process==8) { add(new_ptr((Tree2toNDiagram(3),quark[ix],trpon,antiquark[iy], 1,quark[ix],2,antiquark[iy],-21))); } } } } Selector METRP2to2::colourGeometries(tcDiagPtr diag) const { // colour lines for gg to gg static const ColourLines cgggg("1 4, -1 -4, 3 5, -3 -5"); // colour lines for q g to q g static const ColourLines cqgqg("1 4, 3 5, -3 -5"); // colour lines for qbar g -> qbar g static const ColourLines cqbgqbg("-1 -4, -3 -5, 3 5"); // colour lines for q q -> q q static const ColourLines cqqqq("1 4,3 5"); // colour lines for qbar qbar -> qbar qbar static const ColourLines cqbqbqbqb("-1 -4,-3 -5"); // colour lines for q qbar -> q qbar static const ColourLines cqqbqqb("1 4,-3 -5"); // select the colour flow (as already picked just insert answer) Selector sel; switch(abs(diag->id())) { //gg -> gg case 2: sel.insert(1.0, &cgggg); break; // q g -> q g subprocess case 12: sel.insert(1.0, &cqgqg); break; // qbar g -> qbar g subprocess case 15: sel.insert(1.0, &cqbgqbg); break; // q q -> q q subprocess case 16: case 17: sel.insert(1.0, &cqqqq); break; // qbar qbar -> qbar qbar subprocess case 18: case 19: sel.insert(1.0, &cqbqbqbqb); break; // q qbar -> q qbar subprocess case 21: sel.insert(1.0, &cqqbqqb); break; } return sel; } double METRP2to2::me2() const { double me(0.), me_exch(0.); double fac1(1.), fac2(0.); if ( mePartonData()[0]->id() == mePartonData()[1]->id() ) { if ( mePartonData()[0]->id()>0 ) { me_exch = - A_ny(sHat(),uHat()); fac1 = 2./3.; fac2 = 1./6.; } else if ( mePartonData()[0]->id() == ParticleID::g ) { me_exch = A_ny(sHat(),uHat()); fac1 = 7./8.; fac2 = 1./16.; } } me = A_ny(sHat(),tHat()); return fac1 * sqr(me) + fac2 * sqr(me+me_exch); } // Calculate the constant b_c which depends on s_hat and the number of // extra dimensions InvEnergy METRP2to2::bccalc(Energy2 s) const { static const double fourpi = 4.0*Constants::pi; return 1/_planckmass * sqrt(fourpi) * - pow( (0.5 * s / (sqr(_planckmass) * fourpi)) * Math::gamma(_ndim/2.0), + pow( (0.5 * s / (sqr(_planckmass) * fourpi)) * tgamma(_ndim/2.0), 1.0/_ndim); } //Calculation of the matrix element squared using the function F_n(y) double METRP2to2::A_ny(Energy2 s, Energy2 t) const { InvEnergy bc = bccalc(s); double fny = 0; double y = bc * sqrt(-t); if ( y >= 20.0 ) fny = fnyasympt(y); else fny = fpoint(y); return 4. * Constants::pi * fny * s * sqr(bc); } //The asymptotic form of the F_n functions; used for x > 20 double METRP2to2::fnyasympt(double y) const { return pow( _ndim, 1.0/(_ndim+1.0) ) * pow( y, -(_ndim+2.0)/(_ndim+1.0) ) / sqrt(_ndim+1.0); } //fpoint uses the interpolator to calculate the value of F_n for intermediate values of the argument double METRP2to2::fpoint(double x) const { assert( x < 20.0 ); if ( _ndim == 2 && x < 0.02 ) { return sqrt( sqr(-log(x/1.4)) + sqr(Constants::pi)/16 ); } else { return (*_interpol)(x); } } diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -1,1689 +1,1699 @@ Herwig News -*- outline -*- ================================================================================ +* Herwig 7.1.4 release: 2018-06-28 + +** More matrix elements and better handling of BSM physics + +** Fix for spin correlations in angular-ordered shower, effects top decays + +** Allow fixed target collisions + +** various minor fixes + * Herwig 7.1.3 release: 2018-04-05 ** Dipole Shower *** Changed default phase space limits *** g -> gg splitting function asymmetrized *** Initial retune supplied, given the visible changes to LEP observables ** Added new Baryonic colour reconnection model (arXiv 1710:10906) ** Added Schuler-Sjostrand Photon PDFs ** Handling of massless taus from external sources ** various minor fixes ** use std::array<> where possible * Herwig 7.1.2 release: 2017-11-01 ** Reduction of the default pt cut for QED radiation off leptons. ** Inputfile changes due to new read mode in ThePEG. ThePEG remains in current repo dir when reading input-file/snippet. ** Fix for shower scale variations in qtilde shower. ** All standard input files now use the tuned intrinsic pt. ** Remove obsolete input files for various tunes. ** Fix for Madgraph interface for NLO corrections with recent version. ** Run file size reduction for processes using madgraph/openloops. ** Fix in jacobian for massive dipole kinematics. ** General improvements for UFO model handling. * Herwig 7.1.1 release: 2017-07-14 ** Snippets are now all installed ** Fixed broken ufo2herwig output and LHC-MB.in ** UFO improvements *** More robust SLHA file handling *** option of creating diagonal mixing matrices, needed for ATLAS simplfied models *** Improved warnings about resetting standard model particles *** Fixed certain cases where the wrong lorentz structure was picked in VVS vertices ** Improved error message for unhandled beam particles ** Fix for Dipole Shower chain selection ** Fixed crash in double diffractive delta resonances * Herwig 7.1.0 release: 2017-05-19 ** Major new release For a more detailed overview and further references please see the release note arXiv:1705.06919 ** NLO multijet merging with the dipole shower ** A new soft model ** An interface to EvtGen ** Improved calculation of mass effects in the dipole shower ** Top decays in the dipole shower, and NLO corrections to the decay ** An implementation of the KrkNLO method for simple processes ** Major restructuring and cleanup of default input files ** C++11 is now mandatory and heavily used in the code ** Many smaller bugfixes and improvements * Herwig 7.0.4 release: 2016-10-24 ** API The high level API is now properly available as a library, providing an alternative to the Herwig main program. ** Dipole shower Added nloops() function to the AlphaS classes to return the number of loops in the running coupling ** Matchbox Improved error handling and clearer messages ** BSM models Initialize W mass correctly from SLHA file. Improved reading in of decay modes if they already exist. ** Sampling Introduced option to reduce reference weight in AlmostUnweighted mode by Kappa factor. Useful for processes where full unweighting is infeasible. ** Qtilde shower Better control of scale in splitting functions using the SplittingFunction:ScaleChoice interface. ** Tests New NLO fixed-order input files for testing Matchbox in Tests/ExternNLO. ** Input files Set diagonal CKM options consistently. Added TauTauHVertex and MuMuHVertex to MatchboxDefaults. * Herwig 7.0.3 release: 2016-07-21 ** subprocess generation filters A number of filters has been implemented to speed up process and diagram generation for the case of Standard Model like processes; this is particularly helpful for processes involving a large number of electroweak combinatorics. See the documentation for more details. ** fix to directory hierarchy A bug in the Herwig-scratch directory hierarchy when integrating with different seeds has been fixed. ** fix for relocating MadGraph generated amplitudes The directory and symbolic link structure for MadGraph-built amplitudes has been changed to allow for relocation of a run directory to a different file system hierarchy. ** z* variable added to LeptonsJetsAnalysis The builtin LeptonsJetsAnalysis has been extented to include the normalized relative rapidity z* ** detuning parameter for shower reweighting An efficiency tweak when using the shower reweighting facilities has been introduced for the veto algorithms in both the QTilde and the Dipole shower. See the documentation for more details. ** BaryonThreeQuarkModelFormFactor A scaling bug in the form factor series expansion was fixed. * Herwig 7.0.2 release: 2016-04-29 ** Event reweighting New option of calculating the weights for the effect of varying the scale used in both the default and dipole showers. The method is described in arXiv:1605.08256 ** mergegrids mode A main mode for the Herwig executable has been added which merges the integration grids from parallel runs. ** NLO Diphoton production The NLO matrix elements in the POWHEG approach for diphoton production as described in JHEP 1202 (2012) 130, arXiv:1106.3939 have been included as MEPP2GammaGammaPowheg. ** BSM Hard process constructor A missing Feynman diagram with a t-channel vector boson has been added to the matrix element for vv2ss ** BSM Decay Modes calculation The behaviour of the option to disable decay modes in BSM Models has been changed so that the partial width for the ignored modes is now calculated and included in the total width, but the branching ratio is set to zero. This is more physical than the previous option where the mode was t otally ignored and hence not included in the calculation of the width. ** Mass Generation The behaviour of the GenericMassGenerator has been changed so that modes which have been disabled are only included in the calculation of the total width and not in the partial width used in the numerator of the weight used to select the off-shell mass. ** Boost detection Boost could not detect the compiler version for gcc-5.3 and gcc-6.1 * Herwig 7.0.1 release: 2016-01-17 ** Version number written to log file The Herwig version number is now included in addition to ThePEG's version. ** Tau lifetimes A bug with lifetimes for hard process Taus is fixed. Thanks to ATLAS for the report! ** Shower FSR retries Rare events could take a long time due to an extremely large number of FSR retries. These are now capped at a configurable number. ** Dipole shower Reweighting for non-radiating events; fixes for shower profile handling; option to downgrade large-Q expansion for alphaS ** Matchbox builtins Added massive currents for q-qbar ** ShowerAlphaQCD can now use user-defined thresholds ** Input snippets W/Z/H on-shell now split into three files; 4-flavour scheme added ** UFO converter The converter now has experimental support for writing out param cards of its current settings. ** LEPJetAnalysis loading fixed ** Contrib HJets++ has moved to a stand-alone project, FxFx has been added * Herwig 7.0.0 (Herwig++ 3.0.0) release: 2015-12-04 ** Major new release A major new release of the Monte Carlo event generator Herwig++ (version 3.0) is now available. This release marks the end of distinguishing Herwig++ and HERWIG development and therefore constitutes the first major release of version 7 of the Herwig event generator family. The new version features a number of significant improvements to the event simulation, including: built-in NLO hard process calculation for all Standard Model processes, with matching to both angular ordered and dipole shower modules via variants of both subtractive (MC@NLO-type) and multiplicative (Powheg-type) algorithms; QED radiation and spin correlations in the angular ordered shower; a consistent treatment of perturbative uncertainties within the hard process and parton showering, as well as a vastly improved documentation. This version includes (for a more detailed overview and further references please see the release note arXiv:1512.01178): ** A long list of improvements and fixes for the Matchbox module *** includes MC@NLO and Powheg matching to both showers with truncated showering ** A long list of improvements and fixes for both of the shower modules *** includes improvements of numerics issues relevant to 100 TeV pp collisions ** NLO event simulation and Matchbox development *** Interfaces to a number of external libraries *** A new workflow for event generation *** Electroweak corrections to VV production ** Parton shower development *** QED radiation in the angular ordered shower *** Spin correlations in the angular ordered shower *** New scale choices in gluon branchings ** Improvements to event generation workflow *** Re-organized and streamlined input files for the new NLO development *** A unified treatment of shower and matching uncertainties *** New integrator modules featuring parallel integration ** New default tunes for both shower modules ** New contrib modules *** Electroweak Higgs plus jets production *** FxFx merging support *** Higgs boson pair production * Herwig++-2.7.1 release: 2014-07-07 ** New shower switches to select schemes for momentum reconstruction *** QTildeReconstructor:FinalStateReconOption has the following options: *** Default All momenta are rescaled in the rest frame. *** MostOffShell Put all particles on the new-mass shell and the most off-shell and recoiling system are rescaled to ensure 4-momentum is conserved. *** Recursive Recursively put the most off-shell particle which hasn't yet been rescaled on-shell by rescaling the particles and the recoiling system. *** RestMostOffShell The most off-shell is put on shell by rescaling it and the recoiling system, the recoiling system is then put on-shell in its rest frame. *** RestRecursive As above, but recursively treat the currently most-off shell (only makes a difference for more than 3 partons) ** Ticket #378: Hadronization of baryon number violating clusters involving diquarks Fixed by only considering non-diquarks to be combined in the ClusterFinder. ** UFO converter can now parse SLHA files for parameter settings The UFO converter code can now use SLHA files for modifying parameters. The first pass "ufo2herwig" produces the model to be compiled. For each parameter card, run "slha2herwig" to get the matching input file. ** Fix for systems using lib64 The repository is now initialized correctly on systems using lib64 as the library location. ** Efficiency optimization Better allocation of internal vector variables for a noticeable speed increase of 10-20% with LHC events. * Herwig++-2.7.0 release: 2013-10-28 ** UFO interface to Feynman rules generators Herwig++ now includes "ufo2herwig", a tool that automatically creates all required files to run a BSM model from a UFO directory. The conversion has been extensively tested against Feynrules models MSSM, NMSSM, RS, Technicolor, and less extensively with most of the other models in the Feynrules model database. We expect that following this release there will be no further hard-coded new physics models added to Herwig++ and that future models will be included using the UFO interface. ** Shower uncertainties A first set of scaling parameters to estimate shower uncertainties is provided for both the angular ordered as well as the dipole shower; they are Evolver:HardScaleFactor and ShowerAlphaQCD: RenormalizationScaleFactor. ** Rewrite of Matchbox NLO matching The NLO matching implementation has been rewritten and is now more flexible and consistent. Profile scales are provided for the hardest emission both for the dipole shower and matrix element correction matching. ** BLHA2 Interface and new processes Matchbox now features a generic BLHA2 interface to one-loop amplitude codes and now also includes W and W+jet production as well as Higss production in gluon fusion as builtin processes. ** Impoved dipole shower kinematics parametrization The kinematics parametrization for emissions in the dipole shower has been made more efficient. ** W and Z Powheg decays Decays of W and Z bosons now use the Powheg decayers by default. ** Improved treatment of beam remnants The handling of beam remnants has been improved in multiple contexts, leading to a much lower error rate at p+/p- collisions. An additional value "VeryHard" for ClusterFissioner:RemnantOption can be used to disable any special treatment of beam remnant clusters. ** New underlying event tune Herwig++ now uses tune UE-EE-5-MRST by default. Other related tunes can be obtained from the Herwig++ tunes page ** Improvements in BSM code The UFO development identified many sign fixes in rarely used BSM vertices; many improvements were made to general decayers, allowing four-body decays in BSM for the first time; Powheg is enabled in General two-body decayers; and the handling of colour sextets has been improved. ** A new HiggsPair matrix element in Contrib. ** A new matrix element for single top production. ** The Higgs mass is now set to 125.9 GeV (from PDG 2013 update). ** C++-11 testing To help with the coming transition to C++-11, we provide the new --enable-stdcxx11 configure flag. Please try to test builds with this flag enabled and let us know any problems, but do not use this in production code yet. In future releases, this flag will be on by default. ** Other changes *** Many new Rivet analyses have been included in the Tests directory. *** Cleaned Shower header structure; grouped shower parameters into one struct. *** The boolean Powheg flag in HwMEBase changed to an enumeration. * Herwig++-2.6.3 release: 2013-02-22 ** Decay vertex positioning in HepMC output Pseudo-vertices that Herwig++ inserts for technical reasons will now not contribute to the Lorentz positions of downstream vertices. Thanks to ATLAS for the bug report! ** Updated Rivet tests Herwig's library of Rivet test runs has been brought up-to-date with new analyses that were recently published by the Rivet collaboration. * Herwig++-2.6.2 release: 2013-01-30 ** Fixes for PDF and scale choices in POWHEG events Scale settings for MPI and the regular shower are now correct in POWHEG events. This should fix reported anomalies in POWHEG jet rates. NLO PDFs are now also set consistently in the example input files. ** Ticket #373: Branching ratio factors in cross-section If any decay modes are selectively disabled, setting the following post-handler will cause all reported cross-sections to include the branching ratio factor(s) from the previous stages correctly: create Herwig::BranchingRatioReweighter BRreweight insert LHCGenerator:EventHandler:PostDecayHandlers 0 BRreweight ** Anomalous vertices now possible in MEfftoVH ** Interactive shell does not quit on error ** Better warning messages for events from inconsistent LHEF files ** Possible division by zero error fixed in BSM branching ratio calculations ** Decayer and ME changes to improve checkpointing The checkpointing changes in ThePEG 1.8.2 are implemented here, too. Regular dump files are consistent now. * Herwig++-2.6.1 release: 2012-10-16 ** Configure switches The various switches to turn off compilation of BSM models have been unified into a single '--disable-models'. A new flag '--disable-dipole' can be used to turn off the compilation of the Dipole and Matchbox codes. ** Ticket #348: Search path for repository 'read' command The search path for the 'read' command is configurable on the command line with the -i and -I switches. By default, the installation location is now included in the search path, so that 'Herwig++ read LEP.in' will work in an empty directory. The current working directory will always be searched first. The rarely used "Herwig++ init" command has been made consistent with 'read' and 'run' and should now be used without the '-i' flag. ** Width treatment in BSM The width treatment in BSM decay chains has been greatly improved and is now switched on by default in the .model files. To get the old behaviour, use set /Herwig/NewPhysics/NewModel:WhichOffshell Selected ** New BSM models Little Higgs models with and without T-parity are now available. ** Resonance photon lifetime A lifetime bug affecting decays of pi0 to e+e-X was fixed. The virtual photon is not part of the event record anymore. ** Ticket #371: Hard diffraction FPE Herwig++ 2.6.0 introduced a bug into the diffraction code which would abort any runs. This is now fixed. ** O2AlphaS Support for setting quark masses different from the particle data objects as introduced in ThePEG 1.8.1 has been enabled. ** Matchbox Several improvements and bug fixes are included for Matchbox. Amplitudes relevant to pp -> Z+jet and crossed processes at NLO are now available, and various scale choices have been added in a more flexible way. All subtraction dipoles for massive quarks are now included. ** Dipole shower Parameters to perform scale variations in the shower have been added to estimate uncertainties. A bug in showering off gg -> h has been fixed. ** Minor fixes *** Two broken colour structures in GeneralHardME *** Susy Higgs mixing matrix *** BaryonFactorizedDecayer out-of-bounds access *** Mass values in SimpleLHCAnalysis * Herwig++-2.6.0 release: 2012-05-21 (tagged at SVN r7407) ** New NLO framework Matchbox, a flexible and very general framework for performing NLO calculations at fixed order or matched to parton showers is provided with this release. ** Dipole shower algorithm A first implementation of the coherent dipole shower algorithm by Plätzer and Gieseke (arXiv:0909.5593 and arXiv:1109.6256) is available. ** Alternative samplers and the ExSample library The ExSample library by Plätzer (arXiv:1108.6182) is shipped along with Herwig++ in an extended version. The extended version provides SamplerBase objects which can be used alternatively to the default ACDCSampler. ** New BSM models *** New colour sextet diquark model A colour sextet diquark model has been included, as described in Richardson and Winn (arXiv:1108.6154). *** Models reproducing the CDF t-tbar asymmetry Four models that can reproduce the reported t-tbar asymmetry have been included. *** Zprime A simple standard model extension by one additional heavy neutral vector boson. ** Interface to AlpGen, with MLM merging The Contrib directory contains a new interface to the AlpGen matrix element generator. AlpGen events must be preprocessed with the provided AlpGenToLH.exe tool before they can be used. More information can be found in the Herwig++ 2.6 release note. ** HiggsVBF Powheg Higgs boson production by vector boson fusion is available at NLO in the POWHEG scheme, as described in d'Errico, Richardson (arXiv:1106.2983). The Powheg DIS processes were available in Herwig++-2.5.2 already. ** Statistical colour reconnection Alternative mechanisms to minimize the colour length Sum(m_clu) before the hadronization stage, based on Metropolis and annealing algorithms. ** Energy extrapolation of underlying-event tunes To describe underlying-event data at different c.m. energies, the energy-dependent parameter pT_min will now be adjusted automatically, following a power-law. The new tune parameters are the value at 7000 GeV "MPIHandler:pTmin0", and MPIHandler:Power. ** Ticket #239: Reporting of minimum-bias cross-section When simulating minimum-bias events using the MEMinBias matrix element, the correct unitarized cross section can now be reported via the standard facilities; it is no longer necessary to extract it from the .log file of the run. The corresponding functionality is enabled by inserting a MPIXSecReweighter object as a post-subprocess handler: create Herwig::MPIXSecReweighter MPIXSecReweighter insert LHCHandler:PostSubProcessHandlers 0 MPIXSecReweighter ** Dependency on 'boost' Herwig++ now requires the boost headers to build; if not detected in standard locations, specify with the --with-boost configure option. ** Tests directory The Tests directory now contains input cards for almost all Rivet analyses. A full comparison run can be initiated with 'make tests'. ** Minor changes *** Default LHC energy now 8 TeV All LHC-based defaults have now been updated to use 8 TeV as the center-of-mass energy. *** Herwig::ExtraParticleID -> ThePEG::ParticleID The namespace for additional particles has been unified into ThePEG::ParticleID *** MEee2VectorMeson The e+e- -> vector meson matrix element has moved from Contrib into HwMELepton.so *** SUSY numerics fixes Better handling of rare numerical instabilities. *** YODA output for Rivet The built-in histogramming handler can now output data in the YODA format used by Rivet. *** Consistency checks in SLHA file reader Better warnings for inconsistent SusyLHA files *** better colour flow checking for development ** Bug fixes *** Extremely offshell W from top decay Numerical improvements for very off-shell W bosons coming from top decays. *** Ticket #367: problems in using SUSY + LHE Susy events from Les Houches event files are now handled better. *** Infinite loop in remnant decayer The remnant decayer will now abort after 100 tries. *** Fix to HiggsVBF LO diagrams The diagram structure of HiggsVBF LO matrix elements has been fixed. *** LEP thrust fix The calculation of the transverse momentum of a branching from the evolution variable in final-state radiation can now be changed. While formally a sub-leading choice this enables a better description of the thrust distribution in e+e- collisions at small values of the thrust. Currently the default behaviour, where the cut-off masses are used in the calculation, remains the same as previous versions. * Herwig++-2.5.2 release: 2011-11-01 (tagged at SVN r6928) ** Optional new jet vetoing model The jet vetoing model by Schofield and Seymour (arXiv:1103.4811) is available via Evolver:ColourEvolutionMethod, PartnerFinder:PartnerMethod and SplittingFunction:SplittingColourMethod. The default behaviour is unchanged. ** MPI tune Version 3 of the MPI tunes is now the default. Please note that the pT parameter is energy-dependent and needs to be modified when an LHC run is not at 7 TeV. The latest tunes are always available at http://projects.hepforge.org/herwig/trac/wiki/MB_UE_tunes ** MPI PDFs MPI PDFs can now be controlled independently. ** Initialization time speedup A new BSMModel base class was introduced between StandardModel and the BSM model classes. Together with a restructured decay mode initialization, this offers significantly faster startup times for BSM runs. ThreeBodyDecays can now always be switched on without a large speed penalty. ** Decay mode file Decay mode files in the SLHA format can now be read separately in any BSM model with 'set Model:DecayFileName filename' ** Powheg DIS Charged- and neutral-current DIS processes implementing the POWHEG method are now available. ** Diffraction models Xi cut implemented in PomeronFlux ** Ticket #352: Colour reconnection fixed in DIS ** Ticket #353: Improved numerical stability in chargino decays ** Ticket #358: Infinite loop in top events with pT cut in shower ** Ticket #361: Problem with duplicate 2-body modes in BSM ** Tickets #362 / #363: Crashes with baryon number violating models Particle decays in SUSY models with RPV now work correctly in the colour 8 -> 3,3,3 case. Colour reshuffling now works for RPV clusters. ** Improved Fastjet detection The configure step uses fastjet-config to make sure all header file paths are seen. ** Darwin 11 / OS X Lion A configure bug was fixed which prevented 'make check' from succeeding on OS X Lion. ** Vertex classes The specification of QED / QCD orders has been moved to the vertex constructors, to allow ThePEG consistency checks. WWHH vertices in MSSM and NMSSM were fixed. Some Leptoquark and UED vertices fixed. ** Hadronization Cleanup of obsolete code. * Herwig++-2.5.1 release: 2011-06-24 (tagged at SVN r6609) ** Example input files at 7 TeV All our example input files for LHC now have their beam energy set to 7 TeV instead of 14 TeV. ** Colour reconnection on by default The colour reconnection tunes are now the default setup. Version 2 of the tunes replaces the *-1 tunes, which had a problem with LEP event shapes. ** Run name tags Aded possibility to add a tag to the run name when running with the '-t' option. One run file can thus be run with different seeds and results stored in different output files. ** Floating point exceptions The new command line option -D enables floating point error checking. ** General improvements to WeakCurrent decays ** Remnant decayer Hardwired gluon mass was removed. ** WeakCurrentDecayConstructor Instead of specifying separate Particle1...Particle5 vectors for the decay modes, the new interface DecayModes can be filled with decay tags in the standard syntax. ** BSM: improvements to handling of vertex and model initialisation ** Powheg Higgs Option to use pT or mT as the scale in alphaS and for the factorization scale in the PDFs ** Ticket #337: Tau polarization wrong in charged Higgs decay ** Ticket #339: Colour flows in GeneralThreeBody Decayers for 3bar -> 8 3bar 1 ** Ticket #340: Crash for resonant zero-width particles ** Ticket #341: Varying scale for BSM processes The scale used is now ResonantProcessConstructor:ScaleFactor or TwoToTwoProcessConstructor:ScaleFactor multiplied by sHat. ** Ticket #346: Chargino decays Chargino decayers now automatically switch between the mesonic decays for mass differences less than 2 GeV and the normal partonic decays above 2 GeV. ** Ticket #349: Stop by default on input file errors The '--exitonerror' flag is now the default behaviour for the Herwig++ binary. To switch back to the old behaviour, '--noexitonerror' is required. ** Ticket #351: Four-body stop decays ** Tested with gcc-4.6 * Herwig++-2.5.0 release: 2011-02-08 (tagged at SVN r6274) ** Uses ThePEG-1.7.0 Herwig++ 2.5.0 requires ThePEG 1.7.0 to benefit from various improvements, particularly: handling of diffractive processes; respecting LD_LIBRARY_PATH when loading dynamic libraries, including LHAPDF; improvements to repository commands for decay modes. See ThePEG's NEWS file for more details. ** POWHEG improvements *** New POWHEG processes Simulation at NLO accuracy using the POWHEG method is now available for hadronic diboson production (pp to WW,WZ,ZZ), Higgs decays to heavy quarks, and e+e- to two jets or ttbar, including full mass dependence. *** Input file changes The input files for setting up POWHEG process simulation have been simplified. See the example files LHC-Powheg.in and TVT-Powheg.in for the improved command list. *** Structural changes The POWHEG backend in the shower code has been restructured to make future additions easier: PowhegEvolver has merged with Evolver; both the matrix element corrections and real corrections in the POWHEG scheme are implemented directly in the ME or Decayer classes. ** New processes at leading order *** Photon initiated processes We have added a matrix element for dijet production in gamma hadron collisions. *** Bottom and charm in heavy quark ME The option of bottom and charm quarks is now supported for heavy quark production in MEHeavyQuark. ** Colour reconnection The cluster hadronization model has been extended by an option to reconnect coloured constituents between clusters with a given probability. This new model is different from the colour reconnection model used in FORTRAN HERWIG, and improves the description of minimum bias and underlying event data. ** Diffractive Processes Both single and double diffractive processes are now supported in Herwig++. The Pomeron PDF is implemented using a fit to HERA data, and a pion PDF can be used to model reggeon flux. ** BSM physics *** New models We have added new BSM models, particularly ADD-type extra dimension models and the next-to-minimal supersymmetric standard model (NMSSM). Effects of leptoquarks can as well be simulated. *** Vertex additions We have added flavour changing stop interactions (stop - neutralino - charm) and gravitino interactions with particular emphasis on numerical stability for very light gravitinos. Tri-linear Higgs and Higgs-Higgs/Vector-Vector four-vertices are available as well. *** Input file changes The SUSY model can now also extract the SLHA information from the header of a Les Houches event file: replace the SLHA file name in the example input files with the LH file name. *** Structure The backend structure of the HardProcessConstructor has changed, to allow easier inclusion of new process constructors. Some 2->3 BSM scattering processes involving neutral higgs bosons are now included. The spin handling has been improved in the background. ** Shower splitting code reorganized The selection of spin structures has been decoupled from the choice of colour structure. This gives more flexibility in implementing new splittings. Selected splittings can be disabled in the input files. ** B mixing B mixing, and indirect CP violation in the B meson system are included now. ** Looptools The Looptools directory has been updated to reflect T.Hahn's Looptools 2.6. ** Contrib changes The ROOT interface has been removed as deprecated. The MCPWNLO code has temporarily been removed from the Contrib directory as a major review of this code is required. Additionally, there are various fixes to all other codes shipped in Contrib. ** DIS improvements The momentum reshuffling in DIS events has been improved. ** mu and nu beams mu, nu_e and nu_mu and their antiparticles are now available as beam particles. They are all supported in the DIS matrix elements. mu+ mu- collisions are supported in the general matrix element code for BSM models, but not yet in the hard-coded matrix elements for lepton-lepton scattering. ** Structural changes *** Inline code Inline code has been merged into the header files, .icc files were removed. *** Silent build By default, Herwig++ now builds with silent build rules. To get the old behaviour, run 'make V=1'. *** Debug level The debug level on the command line will now always have priority. *** Event counter The event counter has been simplified. *** Interpolator persistency Interpolators can now be written persistently. ** Ticket #307: Momentum violation check in BasicConsistency Added parameters AbsoluteMomentumTolerance and RelativeMomentumTolerance ** Example POWHEG input files The example input files for Powheg processes now set the NLO alpha_S correctly, and are run as part of 'make check'. ** Truncated shower A problem which lead to the truncated shower not being applied in some cases has been fixed. ** Fixes to numerical problems Minor problems with values close to zero were fixed in several locations. ** Remove duplicated calculation of event shapes An accidental duplication in the calculation of event shapes was removed, they are now only calculated once per event. Several other minor issues in the event shape calculations have also been fixed. ** MRST PDFs fixed An initialization problem in the internal MRST PDFs was fixed. ** Vertex scale choice The scale in the Vertex classes can now be zero where possible. ** Treatment of -N flag The Herwig++ main program now correctly treats the -N flag as optional. ** Numerical stability improved The numerical stability in the 'RunningMass' and 'QTildeReconstructor' classes has been improved. The stability of the boosts in the SOPTHY code for the simulation of QED radiation has been improved. The accuracy of boosts in the z-direction has been improved to fix problems with extremely high p_T partons. ** Bugfix in initial state splittings A bug in the implementation of the PDF weight in initial-state qbar -> qbar g splittings has been fixed. ** Bugfix in chargino neutralino vertices A bug in the 'chi+- chi0 W-+' and charged Higgs-sfermions vertices has been fixed. ** Remove uninitialized variables written to repository A number of uninitialised variables which were written to the repository have been initialised to zero to avoid problems on some systems. ** Fix to QED radiation in hadronic collisions The longitudinal boost of the centre-of-mass frame in hadronic collisions is correctly accounted for now in the generation of QED radiation. ** Fix to numerical problems in two-body decays Numerical problems have been fixed, which appeared in the rare case that the three-momenta of the decay products in two-body decays are zero in the rest frame of the decay particle. ** A problem with forced splittings in the Remnant was fixed. ** ME correction for W+- decays applied properly The matrix element correction for QCD radiation in W+- decays which was not being applied is now correctly used. ** Top quark decays from SLHA file The presence of top quark decay modes in SLHA files is now handled correctly. ** Exceptional shower reconstruction kinematics Additional protection against problems due to the shower reconstruction leading to partons with x>1 has been added. ** Ordering of particles in BSM processes Changes have been made to allow arbitrary ordering of the outgoing particles in BSM processes. ** Bugfixes in tau decays Two bugs involving tau decays have been fixed. The wrong masses were used in the 'KPiCurrent' class for the scalar form factors and a mistake in the selection of decay products lead to tau- --> pi0 K- being generated instead of tau- --> eta K-. ** Avoid crashes in baryon number violating processes. To avoid crashes, better protection has been introduced for the case where diquarks cannot be formed from the quarks in a baryon-number violating process. In addition, the parents of the baryon-number violating clusters have been changed to avoid problems with the conversion of the events to HepMC. ** QED radiation in W- decays A bug in the 'QEDRadiationHandler' class which resulted in no QED radiation being generated in W- decays has been fixed. ** A number of minor fixes to the SUSY models have been made. ** Partial width calculations in BSM models A fix for the direction of the incoming particle in the calculation of two-body partial widths in BSM models has been made. ** LoopTools improvements The LoopTools cache is now cleared more frequently to reduce the amount of memory used by the particle. ** Negative gluino masses are now correctly handled. ** A problem with mixing matrices which are not square has been fixed. ** Removed duplicate diagram The 'MEee2gZ2ll' class has been fixed to only include the photon exchange diagram once rather than twice as previously. ** Fix for duplicate particles in DecayConstructor A problem has been fixed which occurred if the same particle was included in the list of DecayConstructor:DecayParticles. ** Fixes for UED model vertices A number of minor problems in the vertices for the UED model have been fixed. ** Include missing symmetry factor The missing identical-particle symmetry factor in 'MEPP2GammaGamma' has been included. ** Fix floating point problem in top decays A floating point problem in the matrix element correction for top decays has been fixed. * Herwig++-2.4.2 release: 2009-12-11 (tagged at SVN r5022) ** Ticket #292: Tau decay numerical instability The momentum assignment in tau decays contained numerical instabilities which have been fixed by postponing the tau decay until after the parton shower. A new interface setting DecayHandler:Excluded is available to prevent decays in the shower step. This is enabled by default for tau only. ** Ticket #290: Missing MSSM colour structure The missing colour structure for gluino -> gluon neutralino was added. ** Ticket #294: Zero momentum in some decays Some rare phase space points lead to zero momentum in two-body decays. This has been fixed. ** Ticket #295: Stability of QED radiation for lepton collider processes The numerical stability of QED radiation momenta was improved further. ** Ticket #296: K0 oscillation vertex was wrong The oscillation from K0 to K0_L/S now takes place at the production vertex of K0. ** Ticket #289: Undefined variables in repository On some system configurations, undefined variables were written to the repository. These have been fixed. ** Fixed QED radiation for hadron processes The longitudinal boost of the centre-of-mass frame in hadronic collisions is correctly accounted for now. ** Numerical stability fixes Small fixes in RunningMass and QTildeReconstructor. ** Powheg example input files The example input files for Powheg processes now set the NLO alpha_S correctly, and are run as part of 'make check'. ** OS X builds for Snow Leopard Snow Leopard machines will now be recognized as a 64bit architecture. * Herwig++-2.4.1 release: 2009-11-19 (tagged at SVN r4932) ** Uses ThePEG-1.6.0 Herwig++ now requires ThePEG-1.6.0 to benefit from the improved helicity code there. If you have self-written vertex classes, see ThePEG's NEWS file for conversion instructions. ** Vertex improvements ThePEG's new helicity code allowed major simplification of the vertex implementations for all Standard Model and BSM physics models. ** New Transplanckian scattering model An example configuration is in LHC-TRP.in ** BSM ModelGenerator as branching ratio calculator The BSM ModelGenerator has a new switch to output the branching ratios for a given SLHA file in SLHA format, which can then be used elsewhere. ** BSM debugging: HardProcessConstructor New interface 'Excluded' to exclude certain particles from intermediate lines. ** Chargino-Neutralino-W vertex fixed ** Spin correlations are now switched on by default for all perturbative decays. ** Ticket #276: Scale choice in BSM models' HardProcessConstructor New interface 'ScaleChoice' to choose process scale between - sHat (default for colour neutral intermediates) and - transverse mass (default for all other processes). ** Ticket #287: Powheg process scale choice The default choice is now the mass of the colour-singlet system. ** Ticket #278: QED radiation for BSM Soft QED radiation is now enabled in BSM decays and all perturbative decays by default. ** Ticket #279: Full 1-loop QED radiation for Z decays Soft QED radiation in Z decays is now fully 1-loop by default. ** Ticket #280: Redirect all files to stdout This is now implemented globally. The files previously ending in -UE.out and -BSMinfo.out are now appended to the log file. They now also obey the EventGenerator:UseStdout flag. ** Ticket #270: LaTeX output updated After each run, a LaTeX file is produced that contains the full list of citations. Please include the relevant ones in publications. ** Ticket #256: Mac OS X problems An initialization problem that affected only some configurations has been identified and fixed. ** Tests directory added This contains many .in files, to exercise most matrix elements. ** Minor fixes *** Prevent rare x>1 partons in shower reconstruction. *** SUSY-LHA parameter EXTPAR can be used to set tan beta *** Improved Fastjet detection at configure time * Herwig++-2.4.0 release: 2009-09-01 (tagged at SVN r4616) ** New matrix elements We have added a built-in implementation of several new matrix elements: PP --> WW / WZ / ZZ PP --> W gamma / Z gamma PP --> VBF Higgs PP --> Higgs tt / Higgs bb e+e- --> WW / ZZ gamma gamma --> ff / WW ** Base code improvements *** Ticket #257: Remnant handling A problem with forced splittings in the Remnant was fixed. *** Ticket #264: Soft matrix element correction A problem with emissions form antiquarks was fixed. ** PDF sets *** New default set MRST LO** is the new default PDF set. LO* is also available built-in. *** Shower PDFs can be set separately from the hard process Use the 'ShowerHandler:PDF' interface. ** Parameter tunes Shower, hadronization and underlying event parameters were retuned against LEP and Tevatron data respectively. ** BSM module improvements *** Ticket #259: read error for some UED models Arbitrary ordering of outgoing lines in the process description is now possible. *** Ticket #266: branching ratio sums The warning threshold for branching ratios not summing to 1 has been relaxed. It is now a user interface parameter. *** Ticket #267: Top decay modes Top decay modes listed in SLHA files are now handled correctly. ** QED radiation *** Ticket #241: Soft QED radiation is now enabled by default *** Ticket #265: Radiation off W+ and W- is now handled correctly ** Interfaces *** Ticket #243: Fastjet Fastjet is now the only supported jet finder code. All example analyses have been converted to use Fastjet. *** KtJet and CLHEP interfaces have been removed. *** New interfaces to AcerDet and PGS available in Contrib *** MCPWnlo distributed in Contrib *** HepMC and Rivet interfaces moved to ThePEG ** Ticket #239: Inelastic cross-section for MinBias This information is now available in the ...-UE.out files. ** Technical changes *** Ticket #186 Configure now looks for ThePEG in the --prefix location first. *** Configure information Important configuration information is listed at the end of the 'configure' run and in the file 'config.thepeg'. Please provide this file in any bug reports. *** New ZERO object The ZERO object can be used to set any dimensionful quantity to zero. This avoids explicit constructs like 0.0*GeV. *** Exception specifiers removed Client code changes are needed in doinit() etc., simply remove the exception specifier after the function name. *** Ticket #263: Tau polarizations can be forced in TauDecayer * Herwig++-2.3.2 release: 2009-05-08 (tagged at SVN r4249) ** SUSY enhancements *** Ticket #245: Select inclusive / exclusive production Using the new 'HardProcessConstructor:Processes' switch options 'SingleParticleInclusive', 'TwoParticleInclusive' or 'Exclusive' *** Improved three-body decay generation Several problems were fixed, incl. tickets #249 #250 #251 Thanks to J.Tattersall and K.Rolbiecki for the stress-testing! *** Looptools fix Release 2.3.1 had broken the Looptools initialization. *** Improved warning message texts ** Ticket #237: Values of q2last can now be zero where possible. ** Ticket #240: The Herwig++ main program now correctly treats the -N flag as optional. ** Ticket #246: Extreme pT partons fixed by improving accuracy of z boosts. ** DIS Improved parton shower momentum reshuffling. ** Minimum Bias events The zero-momentum interacting particle used for bookkeeping is now labelled as a pomeron. ** User Makefile Makefile-UserModules does not enable -pedantic anymore. User's ROOT code will not compile otherwise. ** Build system Small fixes in the build system. * Herwig++-2.3.1 release: 2009-03-31 (tagged at SVN r4140) ** Initial state showers The PDF veto was wrongly applied to qbar->qbar g splittings. ** User interaction The Makefile-UserModules now includes the Herwig version number. The -N flag to 'Herwig++ run' is optional now, as was always intended. ** Contrib The contrib directory is now included in the tarball. The omission was accidental. ** Numerical accuracy Minor problems with values close to zero were fixed in several locations. ** LEP event shapes An accidental duplication was removed, they are now only calculated once per event. ** MRST PDF code Initialization problem fixed. ** Mac OS X The configure script was improved to detect libraries better. ** Libtool Updated to version 2.2.6 * Herwig++-2.3.0 release: 2008-12-02 (tagged at SVN r3939) ** Major release, with many new features and bug fixes ** Extension to lepton-hadron collisions ** Inclusion of several processes accurate at next-to-leading order in the POsitive Weight Hardest Emission Generator (POWHEG) scheme ** Inclusion of three-body decays and finite-width effects in BSM processes ** New procedure for reconstructing kinematics of the parton shower based on the colour structure of the hard scattering process ** New model for baryon decays including excited baryon multiplets ** Addition of a soft component to the multiple scattering model of the underlying event and the option to choose more than one hard scattering explicitly ** New matrix elements for DIS and e+e- processes ** New /Contrib directory added containing external modules that will hopefully be of use to some users but are not expected to be needed by most users and are not supported at the same level as the main Herwig++ code ** Minor changes to improve the physics simulation: *** IncomingPhotonEvolver added to allow the simulation of partonic processes with incoming photons in hadron collisions *** KTRapidityCut added to allow cuts on the p_T and rapidity, rather than just the p_T and pseudorapidity used in SimpleKTCut. This is now used by default for cuts on massive particles such as the $W^\pm$, $Z^0$ and Higgs bosons and the top quark *** Several changes to the decayers of B mesons both to resolve problems with the modelling of partonic decays and improve agreement with $\Upsilon(4s)$ data *** Changes to allow values other than transverse mass of final-state particles as maximum transverse momentum for radiation in parton shower either SCALUP for Les Houches events or the scale of the hard process for internally generated hard processes *** Changed defaults for intrinsic transverse momentum in hadron collisions to 1.9GeV, 2.1GeV and 2.2GeV for the Tevatron and LHC at 10 TeV and 14 TeV, respectively *** Pdfinfo object is now created in the HepMC interface However in order to support all versions of HepMC containing this feature the PDF set is not specified as not all versions contain this information *** New option of only decaying particles with lifetimes below user specified value *** New options for the cut-off in the shower and some obsolete parameters removed *** Added option of switching off certain decay modes in BSM models *** Added a Matcher for Higgs boson to allow cuts to be placed on it *** Diffractive particles deleted from default input files they were not previously used ** Technical changes: *** Some AnalysisHandler classes comparing to LEP data have been renamed e.g. MultiplicityCount becomes LEPMultiplicityCount to avoid confusion with those supplied in /Contrib for observables at the Upsilon(4s) resonance *** Reorganisation to remove the majority of the .icc files by moving inlined functions to headers in an effort to improve compile time *** Restructured the decay libraries to reduce the amount of memory allocation and de-allocation which improves run-time performance *** The switch to turn off LoopTools has been removed because LoopTools is now used by several core modules. As LoopTools does not work on 64-bit platforms with g77 this build option is not supported *** Removed support for obsolete version of HepMC supplied with CLHEP and improved the support for different units options with HepMC *** EvtGen interface has been removed until it is more stable *** Support for ROOT has been removed it was not previously used *** CKKW infrastructure has been removed from the release until a concrete implementation is available *** Default optimisation has been increased from -O2 to -O3 *** Handling of the fortran compiler has been improved mainly due to improvements in the autotools *** Use of FixedAllocator for Particle objects in ThePEG has been removed as it had no performance benefits ** Bugs fixed: *** Problems with the mother/daughter relations in the hard process and diagram selection in W+- and Z0 production in association with a hard jet *** In general matrix element code for fermion-vector to fermion-scalar where the outgoing fermion is coloured and the scalar neutral *** In the selection of diagrams in some associated squark gaugino processes *** h0->mu+mu- was being generated when h0->tau+tau- *** Normalisation in the Histogram class for non unit-weight events *** Protection against negative PDF values has been improved these can occur when using NLO PDF sets *** Lifetime for BSM particles is now automatically calculated at the same time as the width *** Hadrons containing a top quark now treated like hadrons containing BSM particles in order to support this possibility *** Several ambiguous uses of unsigned int *** Several variables that may have been used undefined *** Several memory leaks at initialisation *** The configuration now aborts if no fortran compiler is found as this is required to compile Looptools *** Several minor floating point errors that did not affect results * Herwig++-2.2.1 release: 2008-07-09 (tagged at SVN r3434) ** Ticket #181: BSM shower with a decay close to threshold Now fixed. ** Ticket #191: Split SUSY crash Improved error message. ** Ticket #192: using SCALUP as the pT veto in the shower Now implemented. ** Ticket #194: production processes of ~chi_1(2)- Fixed bug in the diagram creation. ** Removed unused particles DiffractiveParticles.in was removed, they were never produced. ** Hadronization Top quark clusters now possible, handled as 'exotic' clusters. ** Improved handling of decay modes See ThePEG-1.3.0. 'defaultparticle' command is now obsolete. ** Multi-Parton interactions Increased phase space sampling to have less than 1% uncertainty on average multiplicity. ** New libtool version gfortran is now used as default if it is available. Set FC=g77 to override this. ** Fixed several memory leaks ** Memory allocation Now using plain 'new' and 'delete'. * Herwig++-2.2.0 release: 2008-04-18 (tagged at SVN r3195) ** Major release: now as stand-alone library Herwig++ is now a stand-alone dlopen() plugin to ThePEG. No compile-time linking to Herwig code is required. The Herwig++ binary is a simple executable steering ThePEG, which can be replaced by other frontends (such as setupThePEG / runThePEG). ** New matrix elements p p -> W + jet / Z + jet / W + higgs / Z + higgs e+ e- -> Z + higgs ** Looptools Updated to version 2.2. ** Ticket #141: segfault from using 'run' command Fixed by using default allocators in Herwig++, and the Repository::cleanup() method in ThePEG 1.2.0. ** Ticket #157: broken gsl library path on some 64bit systems Paths with lib64 are correctly identified now. ** Ticket #159: p_t spectrum of ttbar pair Fixed identical particle multiplier in Sudakov form factor. ** Ticket #161: glibc segfault Rare segfault in MPI handler fixed. ** Ticket #165: rare infinite loop in four-body decay All 4-body decays without dedicated decayers now use the Mambo algorithm. A loop guard has been introduced to 3-body decays to avoid infinite retries. ** Ticket #166: rare infinite loop in top ME correction These very rare events (O(1) in 10^7) close to mass threshold now are discarded. ** Higgs width fixes ** SatPDF Optionally, the PDF extrapolation behaviour outside a given range can now be specified. ** gcc 4.3 Herwig++-2.2 compiles cleanly with the new gcc 4.3 series. * Herwig++-2.1.4 release: 2008-03-03 (tagged at SVN r3024) ** Ticket #152: Vertex positions All vertex positions of unphysical particles are set to zero until a fix for the previous nonsensical values can be implemented. * Herwig++-2.1.3 release: 2008-02-25 (tagged at SVN r2957) ** Ticket #129: Baryon decays Fix for baryon decay modes. ** Ticket #131: HepMC Check if IO_GenEvent exists ** Ticket #134: Hadronization Smearing of hadron directions in cluster decay fixed. ** Ticket #137: HepMC HepMC conversion allows specification of energy and length units to be used. ** Ticket #139: Neutral kaons Ratio K_L / K_S corrected. ** Ticket #140 / #141: Crash on shutdown Event generation from the 'read' stage or an interface now shuts down cleanly. Fixes a crash bug introduced in 2.1.1 which affected external APIs to ThePEG / Herwig. ** Ticket #146: BSM models can be disabled To save build time, some or all of the BSM models can be disabled using the '--enable-models' configure switch. ** Reorganised .model files The .model files now include the model-specific particles, too. ** Re-tune Re-tuned hadronization parameters to LEP data. ** Other fixes in QSPAC implementation in Shower; Multi-parton interaction tuning; MRST initialization * Herwig++-2.1.2 release: 2008-01-05 (tagged at SVN r2694) ** Ticket #127 Thanks to a patch submitted by Fred Stober, HepMCFile now can output event files in all supported formats. ** Ticket #128 Fixed incorrect value of pi in histogram limits. ** Other fixes in CKKW Qtilde clusterers, BSM width cut, SUSY mixing matrices. * Herwig++-2.1.1 release: 2007-12-08 (tagged at SVN r2589) ** Bug #123 Fixed a bug with particle lifetimes which resulted in nan for some vertex positions. ** Secondary scatters Fixed bug which gave intrinsic pT to secondary scatters. ** gcc abs bug detection configure now checks for and works around http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34130 ** CKKW reweighting Fixed wrong check for top quarks. ** MPIHandler Fixed call order ambiguity. * Herwig++-2.1.0 release: 2007-11-20 (tagged at SVN r2542) ** Major new release Herwig++-2.1 includes significant improvements, including multi-parton interactions, BSM physics and a new hadronic decay model, tuned to LEP data. For an overview of the changes, please see the release note arXiv:0711.3137 * Herwig++-2.0.3 release: 2007-08-21 (tagged at SVN r2101) ** Bug #90 nan in top decay ME corrections fixed. ** unlisted Colour flow fix in LightClusterDecayer ** unlisted Updated version of MultiplicityCount analysis handler. * Herwig++-2.0.2 release: 2007-07-06 (tagged at SVN r1716) ** Bug #80 Separation of HepMC from CLHEP is handled properly now. ** Bug #83 Workaround for OS X header problem ** unlisted Veto on very hard emissions from Shower. ** unlisted Detailed documentation in .in files * Herwig++-2.0.1 release: 2006-12-05 (tagged at SVN r1195) ** Bug #54 ClusterFissioner vertex calculation fixed. ** Bug #57 Crash when showering W+jet events supplied by Les Houches interface. ** Bug #59 Fix for #57 applied to LHC events. ** Bug #60 Segfault when PDF is set to NoPDF. ** Bug #61 Missing weight factor for I=0 mesons ** Bug #62 Spinor vertex calculations broken when spinor rep is not default rep. ** Bug #63 Top decay never produces tau. ** Bug #69 TTbar and HiggsJet analysis handlers fixed. ** unlisted Reorganization of Hadronization module gives 30% speedup. Thanks to Vincenzo Innocente at CMS for his profiling work! ** unlisted cleaner automake files in include/ and src/ ** unlisted Hw64 hadron selection algorithm 'abortnow' fixed. ** unlisted Top/LeptonDalitzAnalysis removed (only worked with modified code). ** unlisted removed f'_0 from particle list, decays were not handled * Herwig++-2.0.0 release: 2006-09-28 (tagged at SVN r1066) ** Full simulation of hadron collisions diff --git a/PDF/SaSPhotonPDF.h b/PDF/SaSPhotonPDF.h --- a/PDF/SaSPhotonPDF.h +++ b/PDF/SaSPhotonPDF.h @@ -1,134 +1,134 @@ // -*- C++ -*- #ifndef Herwig_SaSPhotonPDF_H #define Herwig_SaSPhotonPDF_H // // This is the declaration of the SaSPhotonPDF class. // #include "ThePEG/PDF/PDFBase.h" namespace Herwig { using namespace ThePEG; /** * The SaSPhotonPDF class provides an interface to the * * @see \ref SaSPhotonPDFInterfaces "The interfaces" * defined for SaSPhotonPDF. */ class SaSPhotonPDF: public PDFBase { public: /** * The default constructor. */ SaSPhotonPDF() : iset_(2), ip_(0) {} public: /** @name Virtual functions to be overridden by sub-classes. */ //@{ /** * Return true if this PDF can handle the extraction of partons from * the given \a particle. */ virtual bool canHandleParticle(tcPDPtr particle) const; /** * Return the partons which this PDF may extract from the given * \a particle. */ virtual cPDVector partons(tcPDPtr particle) const; /** * The density. Return the pdf for the given \a parton inside the * given \a particle for the virtuality \a partonScale and - * logarithmic momentum fraction \a l \f$(l=\log(1/x)\$f. The \a + * logarithmic momentum fraction \a l \f$(l=\log(1/x)\f$. The \a * particle is assumed to have a virtuality \a particleScale. */ virtual double xfl(tcPDPtr particle, tcPDPtr parton, Energy2 partonScale, double l, Energy2 particleScale = 0.0*GeV2) const; /** * The valence density. Return the pdf for the given cvalence \a * parton inside the given \a particle for the virtuality \a * partonScale and logarithmic momentum fraction \a l - * \f$(l=\log(1/x)\$f. The \a particle is assumed to have a + * \f$(l=\log(1/x)\f$. The \a particle is assumed to have a * virtuality \a particleScale. If not overidden by a sub class this * will return zero. */ virtual double xfvl(tcPDPtr particle, tcPDPtr parton, Energy2 partonScale, double l, Energy2 particleScale = 0.0*GeV2) const; //@} 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(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(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 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 IBPtr fullclone() const; //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ SaSPhotonPDF & operator=(const SaSPhotonPDF &); private: /** * PDF Set */ mutable int iset_; /** * Scheme used to evaluate off-shell anomalous component. */ mutable int ip_; }; } #endif /* Herwig_SaSPhotonPDF_H */ diff --git a/README b/README --- a/README +++ b/README @@ -1,14 +1,14 @@ ======== Herwig 7 ======== -This is the release of Herwig 7.1.3, a multi purpose event +This is the release of Herwig 7.1.4, a multi purpose event generator for high energy physics. The Herwig++ distribution contains an adapted version of LoopTools 2.6 . BUILD AND INSTALL ================= Please refer to https://herwig.hepforge.org/tutorials/ for detailed instructions. diff --git a/Shower/Dipole/Makefile.am b/Shower/Dipole/Makefile.am --- a/Shower/Dipole/Makefile.am +++ b/Shower/Dipole/Makefile.am @@ -1,23 +1,23 @@ SUBDIRS = Base Kernels Kinematics Utility AlphaS Merging Colorea pkglib_LTLIBRARIES = HwDipoleShower.la -HwDipoleShower_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 9:0:0 +HwDipoleShower_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 9:1:0 HwDipoleShower_la_LIBADD = \ Base/libHwDipoleShowerBase.la \ Kernels/libHwDipoleShowerKernels.la \ Kinematics/libHwDipoleShowerKinematics.la \ Utility/libHwDipoleShowerUtility.la \ Merging/libHwDipoleShowerMerging.la \ Colorea/libHwDipoleShowerColorea.la HwDipoleShower_la_SOURCES = \ DipoleShowerHandler.h DipoleShowerHandler.fh DipoleShowerHandler.cc pkglib_LTLIBRARIES += HwKrknloEventReweight.la HwKrknloEventReweight_la_SOURCES = \ KrkNLO/KrknloEventReweight.h KrkNLO/KrknloEventReweight.cc HwKrknloEventReweight_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 1:0:0 diff --git a/Shower/Dipole/Merging/MergingReweight.cc b/Shower/Dipole/Merging/MergingReweight.cc --- a/Shower/Dipole/Merging/MergingReweight.cc +++ b/Shower/Dipole/Merging/MergingReweight.cc @@ -1,117 +1,119 @@ // -*- C++ -*- // // MergingReweight.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #include "MergingReweight.h" using namespace Herwig; IBPtr MergingReweight::clone() const { return new_ptr(*this); } IBPtr MergingReweight::fullclone() const { return new_ptr(*this); } double MergingReweight::weight() const { Energy maxpt = ZERO; Energy ht = ZERO; Energy maxmjj = ZERO; - - for (auto const & out : subProcess()->outgoing()) + + const auto sub=subProcess()->head()?subProcess()->head():subProcess(); + + for (auto const & out : sub->outgoing()) if ( !onlyColoured || out->coloured() ){ - for (auto const & out2 : subProcess()->outgoing()) + for (auto const & out2 : sub->outgoing()) if (!onlyColoured || out2->coloured() ) maxmjj=max(maxmjj,(out->momentum()+out2->momentum()).m()); maxpt = max(maxpt, out->momentum().perp()); ht+=out->momentum().perp(); } if (maxpt==ZERO||ht==ZERO) { return 1.; } return pow(maxpt/scale, MaxPTPower)*pow(ht/scale, HTPower)*pow(maxmjj/scale,MaxMjjPower); } #include "ThePEG/Persistency/PersistentOStream.h" void MergingReweight::persistentOutput(PersistentOStream & os) const { os << HTPower << MaxPTPower<> HTPower >> MaxPTPower >>MaxMjjPower>> iunit(scale,GeV) >> onlyColoured; } // Definition of the static class description member. // *** Attention *** The following static variable is needed for the type // description system in ThePEG. Please check that the template arguments // are correct (the class and its base class), and that the constructor // arguments are correct (the class name and the name of the dynamically // loadable library where the class implementation can be found). #include "ThePEG/Utilities/DescribeClass.h" DescribeClass describeHerwigMergingReweight("Herwig::MergingReweight", "HwDipoleShower.so"); #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" void MergingReweight::Init() { static ClassDocumentation documentation ("There is no documentation for the ThePEG::MergingReweight class"); static Parameter interfacePower ("HTPower", "Ht power", &MergingReweight::HTPower, 4.0, -10.0, 10.0, false, false, true); static Parameter interfaceMaxPtPower ("MaxPTPower", "PT2 power", &MergingReweight::MaxPTPower, 4.0, -10.0, 10.0, false, false, true); static Parameter interfaceMaxMjjPower ("MaxMjjPower", "Mjj power", &MergingReweight::MaxMjjPower, 0.0, 0.0, 10.0, false, false, true); static Parameter interfaceScale ("Scale", "The reference scale", &MergingReweight::scale, GeV, 50.0*GeV, ZERO, ZERO, false, false, Interface::lowerlim); static Switch interfaceOnlyColoured ("OnlyColoured", "Only consider coloured particles in the SubProcess when finding the minimum transverse momentum.", &MergingReweight::onlyColoured, false, true, false); static SwitchOption interfaceOnlyColouredYes (interfaceOnlyColoured, "Yes", "Use only coloured particles.", true); static SwitchOption interfaceOnlyColouredNo (interfaceOnlyColoured, "No", "Use all particles.", false); } diff --git a/Shower/QTilde/Base/Branching.h b/Shower/QTilde/Base/Branching.h --- a/Shower/QTilde/Base/Branching.h +++ b/Shower/QTilde/Base/Branching.h @@ -1,69 +1,69 @@ // -*- C++ -*- #ifndef HERWIG_Branching_H #define HERWIG_Branching_H // // This is the declaration of the Branching struct. // #include "Herwig/Shower/QTilde/ShowerConfig.h" -#include "Herwig/Shower/QTilde/Base/ShowerKinematics.h" +#include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * The branching struct is used to store information on the branching. * The kinematics variable is a pointer to the ShowerKinematics for the branching * The sudakov variable is a pointer to the SudakovFormFactor for the branching * The ids variable is the list of particles in the branching */ struct Branching { /** * Pointer to the ShowerKinematics object for the branching */ ShoKinPtr kinematics; /** * PDG codes of the particles in the branching */ IdList ids; /** * The SudakovFormFactor for the branching */ tSudakovPtr sudakov; /** * The type of radiation line */ ShowerPartnerType type; /** * Whether or not it keep from forced hard emisson */ bool hard; /** * Which of the children is same as incoming */ unsigned int iout; /** * Constructor for the struct * @param a pointer to the ShowerKinematics object for the branching * @param c PDG codes of the particles in the branching * @param d The SudakovFormFactor for the branching */ Branching(ShoKinPtr a, IdList c,tSudakovPtr d,ShowerPartnerType t) : kinematics(a), ids(c), sudakov(d), type(t), hard(false), iout(0) {} /** * Default constructor */ Branching() : hard(false), iout(0) {} }; } #endif /* HERWIG_Branching_H */ diff --git a/Shower/QTilde/Base/HardBranching.h b/Shower/QTilde/Base/HardBranching.h --- a/Shower/QTilde/Base/HardBranching.h +++ b/Shower/QTilde/Base/HardBranching.h @@ -1,363 +1,363 @@ // -*- C++ -*- #ifndef HERWIG_HardBranching_H #define HERWIG_HardBranching_H // // This is the declaration of the HardBranching class. // #include "ThePEG/Config/ThePEG.h" #include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" -#include "Herwig/Shower/QTilde/Base/SudakovFormFactor.h" +#include "Herwig/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h" #include "HardBranching.fh" #include "HardTree.fh" namespace Herwig { using namespace ThePEG; /** * The HardBranching class is designed to contain the information needed for * an individual branching in the POWHEG approach */ class HardBranching : public Base { /** * The HardTree is friend */ friend class HardTree; public: /** * Enum for the status */ enum Status {Outgoing=0,Incoming,Decay}; public: /** * The default constructor * @param particle The particle which is branching * @param sudakov The Sudakov form factor for the branching * @param parent The parent for the branching * @param status Whether the particle is incoming or outgoing */ HardBranching(ShowerParticlePtr particle, SudakovPtr sudakov, tHardBranchingPtr parent,Status status); /** * Add a child of the branching * @param child The child of the branching */ void addChild(HardBranchingPtr child) {_children.push_back(child);} /** * Clear the children */ void clearChildren() { _children.clear(); } /** * Set the momenta of the particles */ void setMomenta(LorentzRotation R, double alpha, Lorentz5Momentum pt, bool setMomentum=true); /** * Set and get members for the private member variables */ //@{ /** * Return the branching particle. */ tShowerParticlePtr branchingParticle() const {return _particle;} /** * Set the branching particle */ void branchingParticle(ShowerParticlePtr in) {_particle=in;} /** * Get the original momentum */ const Lorentz5Momentum & original() const {return _original;} /** * Set the original momentum */ void original(const Lorentz5Momentum & in) {_original=in;} /** * Get the p reference vector */ const Lorentz5Momentum & pVector() const {return _p;} /** * Set the p reference vector */ void pVector(const Lorentz5Momentum & in) {_p=in;} /** * Get the n reference vector */ const Lorentz5Momentum & nVector() const {return _n;} /** * Set the n reference vector */ void nVector(const Lorentz5Momentum & in) {_n=in;} /** * Get the transverse momentum vector */ const Lorentz5Momentum & qPerp() const {return _qt;} /** * Set the transverse momentum vector */ void qPerp(const Lorentz5Momentum & in) {_qt=in;} /** * Get the momentum the particle should have as the start of a shower */ const Lorentz5Momentum & showerMomentum() const {return _shower;} /** * Set the momentum the particle should have as the start of a shower */ void showerMomentum(const Lorentz5Momentum & in ) {_shower=in;} /** * Get the transverse momentum */ Energy pT() const {return _pt;} /** * Set the transverse momentum */ void pT(Energy in) { _pt=in;} /** * Get the fraction of beam momentum x */ double x_frac() const {return _x_frac;} /** * Set the fraction of beam momentum x */ void x_frac( double x ) { _x_frac = x; } /** * Get whether the branching is incoming, outgoing or decay */ Status status() const {return _status;} /** * Set whether the branching is incoming, outgoing or decay */ void status(Status in) {_status=in;} /** * The parent of the branching */ tHardBranchingPtr parent() const {return _parent;} /** * Set the parent of the branching */ void parent(tHardBranchingPtr in) {_parent=in;} /** * The Sudakov form-factor */ SudakovPtr sudakov() const {return _sudakov;} /** * The Sudakov form-factor */ void sudakov(SudakovPtr in) {_sudakov=in;} /** * Get the beam particle */ PPtr beam() const {return _beam;} /** * Set the beam particle */ void beam(PPtr in) {_beam=in;} /** * The children */ vector & children() {return _children;} //@} /** * Information on the Shower variables for the branching */ //@{ /** * Get the evolution scale */ Energy scale() const {return _scale;} /** * The evolution scale */ void scale(Energy in) {_scale=in;} /** * The energy fraction */ double z() const {return _z;} /** * The energy fraction */ void z(double in) {_z=in;} /** * The azimthual angle */ double phi() const {return _phi;} /** * The azimthual angle */ void phi(double in) {_phi=in;} //@} /** * Colour partners */ //@{ /** * Get the colour partner */ tHardBranchingPtr colourPartner() const {return _partner;} /** * The colour partner of the branching */ void colourPartner(tHardBranchingPtr in) {_partner=in;} //@} /** * Type of branching */ ShowerPartnerType type() const { assert(type_!=ShowerPartnerType::Undefined); return type_; } /** * Type of branching */ void type(ShowerPartnerType in) { type_ = in; assert(type_!=ShowerPartnerType::Undefined); } private: /** * The branching particle */ ShowerParticlePtr _particle; /** * The rescaled momentum */ Lorentz5Momentum _original; /** * The \f$p\f$ reference vector */ Lorentz5Momentum _p; /** * The \f$n\f$ reference vector */ Lorentz5Momentum _n; /** * The transverse momentum vector */ Lorentz5Momentum _qt; /** * The momentum the particle should have as the start of a shower */ Lorentz5Momentum _shower; /** * The transverse momentum */ Energy _pt; /** * The beam momentum fraction carried by an incoming parton x */ double _x_frac; /** * Whether the branching is incoming, outgoing or a decay */ Status _status; /** * Information on the Shower variables for the branching */ //@{ /** * The evolution scale */ Energy _scale; /** * The energy fraction */ double _z; /** * The azimthual angle */ double _phi; //@} /** * The parent of the branching */ tHardBranchingPtr _parent; /** * The Sudakov form-factor */ SudakovPtr _sudakov; /** * The children */ vector _children; /** * The beam particle */ PPtr _beam; /** * The colour partner */ tHardBranchingPtr _partner; /** * The type of branching */ ShowerPartnerType type_; }; } #endif /* HERWIG_HardBranching_H */ diff --git a/Shower/QTilde/Base/HardTree.h b/Shower/QTilde/Base/HardTree.h --- a/Shower/QTilde/Base/HardTree.h +++ b/Shower/QTilde/Base/HardTree.h @@ -1,143 +1,143 @@ // -*- C++ -*- #ifndef HERWIG_HardTree_H #define HERWIG_HardTree_H // // This is the declaration of the HardTree class. // #include "ThePEG/Config/ThePEG.h" #include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" -#include "Herwig/Shower/QTilde/Base/SudakovFormFactor.h" +#include "Herwig/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h" #include "Herwig/Shower/RealEmissionProcess.fh" #include "HardBranching.h" #include "HardTree.fh" namespace Herwig { using namespace ThePEG; /** * The HardTree class is designed to contain the information required * to implement the POWHEG approach for Monte Carlo at next-to-leading order. */ class HardTree : public Base { /** * Output operator for testing */ friend ostream & operator << (ostream &, const HardTree & ); public: /** * The default constructor. */ HardTree(vector, vector, ShowerInteraction); /** * Contructor from Real emission process */ HardTree(RealEmissionProcessPtr real); /** * Match particles in the ShowerTree to branchings in the HardTree */ bool connect(ShowerParticlePtr particle, HardBranchingPtr branching) { if(branchings_.find(branching)==branchings_.end()) return false; particles_[particle]=branching; return true; } /** * Match the prticles in the ShowerTree to the branchings in the HardTree */ bool connect(ShowerTreePtr); /** * Access the map between the ShowerParticle and the HardBranching */ map & particles() {return particles_;} /** * Access the set of branchings */ set & branchings() {return branchings_;} /** * Access the incoming branchings */ set & incoming() {return spacelike_;} /** * Type of interaction */ ShowerInteraction interaction() {return interaction_;} /** * Get the Rotation to be applied to the tree */ LorentzRotation showerRot() { return showerRot_; } /** * Set the Rotation to be applied to the tree */ void showerRot( LorentzRotation r ) { showerRot_ = r; } /** * Whether or not the evolution partners are set */ bool partnersSet() const {return partnersSet_;} /** * Whether or not the evolution partners are set */ void partnersSet(bool in) {partnersSet_=in;} private: /** * Type of interaction */ ShowerInteraction interaction_; /** * The ShowerTree */ ShowerTreePtr _tree; /** * Map from the particles in the ShowerTree to the HardBranchings */ map particles_; /** * The HardBranchings in the hard process */ set branchings_; /** * The HardBranchings which initiate the space-like showers */ set spacelike_; /** * Rotation to shower frame */ LorentzRotation showerRot_; /** * Whether or not partners are set */ bool partnersSet_; }; /** * Output operator for testing */ ostream & operator << (ostream &, const HardTree & ); } #endif /* HERWIG_HardTree_H */ diff --git a/Shower/QTilde/Base/KinematicsReconstructor.cc b/Shower/QTilde/Base/KinematicsReconstructor.cc deleted file mode 100644 --- a/Shower/QTilde/Base/KinematicsReconstructor.cc +++ /dev/null @@ -1,30 +0,0 @@ -// -*- C++ -*- -// -// KinematicsReconstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig 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 KinematicsReconstructor class. -// - -#include "KinematicsReconstructor.h" -#include "ThePEG/Interface/ClassDocumentation.h" -#include "ThePEG/Utilities/DescribeClass.h" - -using namespace Herwig; - -DescribeAbstractNoPIOClass -describeKinematicsReconstructor ("Herwig::KinematicsReconstructor","HwShower.so"); - -void KinematicsReconstructor::Init() { - - static ClassDocumentation documentation - ( "This class is responsible for the kinematics reconstruction of the showering,", - " including the kinematics reshuffling necessary to compensate for the recoil" - "of the emissions." ); - -} diff --git a/Shower/QTilde/Base/KinematicsReconstructor.h b/Shower/QTilde/Base/KinematicsReconstructor.h deleted file mode 100644 --- a/Shower/QTilde/Base/KinematicsReconstructor.h +++ /dev/null @@ -1,132 +0,0 @@ -// -*- C++ -*- -// -// KinematicsReconstructor.h is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig is licenced under version 3 of the GPL, see COPYING for details. -// Please respect the MCnet academic guidelines, see GUIDELINES for details. -// -#ifndef HERWIG_KinematicsReconstructor_H -#define HERWIG_KinematicsReconstructor_H -// -// This is the declaration of the KinematicsReconstructor class. -// - -#include "ThePEG/Interface/Interfaced.h" -#include "Herwig/Shower/QTilde/Base/ShowerParticle.h" -#include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h" -#include "Herwig/Shower/QTilde/Base/ShowerTree.h" -#include "Herwig/Shower/QTilde/Base/HardTree.h" -#include "KinematicsReconstructor.fh" -#include - -namespace Herwig { - -using namespace ThePEG; - - /**\ingroup Shower - * Exception class - * used to communicate failure of kinematics - * reconstruction. - */ - struct KinematicsReconstructionVeto {}; - - -/** \ingroup Shower - * - * This class is responsible for the kinematical reconstruction - * after each showering step, and also for the necessary Lorentz boosts - * in order to preserve energy-momentum conservation in the overall collision, - * and also the invariant mass and the rapidity of the hard subprocess system. - * In the case of multi-step showering, there will be not unnecessary - * kinematical reconstructions. - * - * Notice: - * - although we often use the term "jet" in either methods or variables names, - * or in comments, which could appear applicable only for QCD showering, - * there is indeed no "dynamics" represented in this class: only kinematics - * is involved, as the name of this class remainds. Therefore it can be used - * for any kind of showers (QCD-,QED-,EWK-,... bremsstrahlung). - * - * @see \ref KinematicsReconstructorInterfaces "The interfaces" - * defined for KinematicsReconstructor. - */ -class KinematicsReconstructor: public Interfaced { - -public: - - /** - * Methods to reconstruct the kinematics of a scattering or decay process - */ - //@{ - /** - * Given the ShowerTree for the shower from a hard process - * the method does the reconstruction of the jets, - * including the appropriate boosts (kinematics reshufflings) - * needed to conserve the total energy-momentum of the collision - * and preserving the invariant mass and the rapidity of the - * hard subprocess system. - */ - virtual bool reconstructHardJets(ShowerTreePtr hard, - const map > & pt, - ShowerInteraction type, - bool switchRecon) const=0; - - /** - * Given the ShowerTree for a decay shower - * the method does the reconstruction of the jets, - * including the appropriate boosts (kinematics reshufflings) - * needed to conserve the total energy-momentum of the collision - * and preserving the invariant mass and the rapidity of the - * hard subprocess system. - */ - virtual bool reconstructDecayJets(ShowerTreePtr decay, - ShowerInteraction type) const=0; - //@} - - /** - * Methods to invert the reconstruction of the shower for - * a scattering or decay process and calculate - * the variables used to generate the - * shower given the particles produced. - * This is needed for the CKKW and POWHEG approaches - */ - //@{ - /** - * Given the particles, with a history which we wish to interpret - * as a shower reconstruct the variables used to generate the - * shower for a decay process - */ - virtual bool deconstructDecayJets(HardTreePtr decay,ShowerInteraction) const=0; - - /** - * Given the particles, with a history which we wish to interpret - * as a shower reconstruct the variables used to generate the shower - * for a hard process - */ - virtual bool deconstructHardJets(HardTreePtr hard,ShowerInteraction) const=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. - */ - KinematicsReconstructor & operator=(const KinematicsReconstructor &); -}; - -} - -#endif /* HERWIG_KinematicsReconstructor_H */ diff --git a/Shower/QTilde/Base/PartnerFinder.cc b/Shower/QTilde/Base/PartnerFinder.cc --- a/Shower/QTilde/Base/PartnerFinder.cc +++ b/Shower/QTilde/Base/PartnerFinder.cc @@ -1,642 +1,694 @@ // -*- C++ -*- // // PartnerFinder.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 PartnerFinder class. // #include "PartnerFinder.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Utilities/Debug.h" #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; -DescribeAbstractClass +DescribeClass describePartnerFinder ("Herwig::PartnerFinder","HwShower.so"); // some useful functions to avoid using #define namespace { // return bool if final-state particle inline bool FS(const tShowerParticlePtr a) { return a->isFinalState(); } // return colour line pointer inline Ptr::transient_pointer CL(const tShowerParticlePtr a, unsigned int index=0) { return a->colourInfo()->colourLines().empty() ? ThePEG::tColinePtr() : const_ptr_cast(a->colourInfo()->colourLines()[index]); } // return colour line size - inline unsigned int + inline size_t CLSIZE(const tShowerParticlePtr a) { return a->colourInfo()->colourLines().size(); } inline Ptr::transient_pointer ACL(const tShowerParticlePtr a, unsigned int index=0) { return a->colourInfo()->antiColourLines().empty() ? ThePEG::tColinePtr() : const_ptr_cast(a->colourInfo()->antiColourLines()[index]); } - inline unsigned int + inline size_t ACLSIZE(const tShowerParticlePtr a) { return a->colourInfo()->antiColourLines().size(); } } void PartnerFinder::persistentOutput(PersistentOStream & os) const { os << partnerMethod_ << QEDPartner_ << scaleChoice_; } void PartnerFinder::persistentInput(PersistentIStream & is, int) { is >> partnerMethod_ >> QEDPartner_ >> scaleChoice_; } void PartnerFinder::Init() { static ClassDocumentation documentation ("This class is responsible for finding the partners for each interaction types ", "and within the evolution scale range specified by the ShowerVariables ", "then to determine the initial evolution scales for each pair of partners."); static Switch interfacePartnerMethod ("PartnerMethod", "Choice of partner finding method for gluon evolution.", &PartnerFinder::partnerMethod_, 0, false, false); static SwitchOption interfacePartnerMethodRandom (interfacePartnerMethod, "Random", "Choose partners of a gluon randomly.", 0); static SwitchOption interfacePartnerMethodMaximum (interfacePartnerMethod, "Maximum", "Choose partner of gluon with largest angle.", 1); static Switch interfaceQEDPartner ("QEDPartner", "Control of which particles to use as the partner for QED radiation", &PartnerFinder::QEDPartner_, 0, false, false); static SwitchOption interfaceQEDPartnerAll (interfaceQEDPartner, "All", "Consider all possible choices which give a positive contribution" " in the soft limit.", 0); static SwitchOption interfaceQEDPartnerIIandFF (interfaceQEDPartner, "IIandFF", "Only allow initial-initial or final-final combinations", 1); static SwitchOption interfaceQEDPartnerIF (interfaceQEDPartner, "IF", "Only allow initial-final combinations", 2); static Switch interfaceScaleChoice ("ScaleChoice", "The choice of the evolution scales", &PartnerFinder::scaleChoice_, 0, false, false); static SwitchOption interfaceScaleChoicePartner (interfaceScaleChoice, "Partner", "Scale of all interactions is that of the evolution partner", 0); static SwitchOption interfaceScaleChoiceDifferent (interfaceScaleChoice, "Different", "Allow each interaction to have different scales", 1); - } void PartnerFinder::setInitialEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, ShowerInteraction type, const bool setPartners) { // clear the existing partners for(ShowerParticleVector::const_iterator cit = particles.begin(); cit != particles.end(); ++cit) (*cit)->clearPartners(); // set them if(type==ShowerInteraction::QCD) { setInitialQCDEvolutionScales(particles,isDecayCase,setPartners); } else if(type==ShowerInteraction::QED) { setInitialQEDEvolutionScales(particles,isDecayCase,setPartners); } else if(type==ShowerInteraction::EW) { setInitialEWEvolutionScales(particles,isDecayCase,false); } else if(type==ShowerInteraction::QEDQCD) { setInitialQCDEvolutionScales(particles,isDecayCase,setPartners); setInitialQEDEvolutionScales(particles,isDecayCase,false); } else if(type==ShowerInteraction::ALL) { setInitialQCDEvolutionScales(particles,isDecayCase,setPartners); setInitialQEDEvolutionScales(particles,isDecayCase,false); setInitialEWEvolutionScales(particles,isDecayCase,false); } else assert(false); // \todo EW scales here // print out for debugging if(Debug::level>=10) { for(ShowerParticleVector::const_iterator cit = particles.begin(); cit != particles.end(); ++cit) { generator()->log() << "Particle: " << **cit << "\n"; if(!(**cit).partner()) continue; generator()->log() << "Primary partner: " << *(**cit).partner() << "\n"; for(vector::const_iterator it= (**cit).partners().begin(); it!=(**cit).partners().end();++it) { generator()->log() << static_cast(it->type) << " " << it->weight << " " << it->scale/GeV << " " << *(it->partner) << "\n"; } } generator()->log() << flush; } } void PartnerFinder::setInitialQCDEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, const bool setPartners) { - // set the partners and the scales - if(setPartners) { - // Loop over particles and consider only coloured particles which don't - // have already their colour partner fixed and that don't have children - // (the latter requirement is relaxed in the case isDecayCase is true). - // Build a map which has as key one of these particles (i.e. a pointer - // to a ShowerParticle object) and as a corresponding value the vector - // of all its possible *normal* candidate colour partners, defined as follows: - // --- have colour, and no children (this is not required in the case - // isDecayCase is true); - // --- if both are initial (incoming) state particles, then the (non-null) colourLine() - // of one of them must match the (non-null) antiColourLine() of the other. - // --- if one is an initial (incoming) state particle and the other is - // a final (outgoing) state particle, then both must have the - // same (non-null) colourLine() or the same (non-null) antiColourLine(); - // Notice that this definition exclude the special case of baryon-violating - // processes (as in R-parity Susy), which will show up as particles - // without candidate colour partners, and that we will be treated a part later - // (this means that no modifications of the following loop is needed!) - ShowerParticleVector::const_iterator cit, cjt; - for(cit = particles.begin(); cit != particles.end(); ++cit) { - // Skip colourless particles - if(!(*cit)->data().coloured()) continue; - // find the partners - vector< pair > partners = - findQCDPartners(*cit,particles); + // Loop over particles and consider only coloured particles which don't + // have already their colour partner fixed and that don't have children + // (the latter requirement is relaxed in the case isDecayCase is true). + // Build a map which has as key one of these particles (i.e. a pointer + // to a ShowerParticle object) and as a corresponding value the vector + // of all its possible *normal* candidate colour partners, defined as follows: + // --- have colour, and no children (this is not required in the case + // isDecayCase is true); + // --- if both are initial (incoming) state particles, then the (non-null) colourLine() + // of one of them must match the (non-null) antiColourLine() of the other. + // --- if one is an initial (incoming) state particle and the other is + // a final (outgoing) state particle, then both must have the + // same (non-null) colourLine() or the same (non-null) antiColourLine(); + // Notice that this definition exclude the special case of baryon-violating + // processes (as in R-parity Susy), which will show up as particles + // without candidate colour partners, and that we will be treated a part later + // (this means that no modifications of the following loop is needed! + + for ( const auto & sp : particles ) { + // Skip colourless particles + if(!sp->data().coloured()) continue; + // find the partners + auto partners = findQCDPartners(sp,particles); // must have a partner if(partners.empty()) { - throw Exception() << "`Failed to make colour connections in " + throw Exception() << "`Failed to make colour connections in " << "PartnerFinder::setQCDInitialEvolutionScales" - << (**cit) + << *sp << Exception::eventerror; } // Calculate the evolution scales for all possible pairs of of particles - vector > scales; - for(unsigned int ix=0;ix< partners.size();++ix) { - scales.push_back(calculateInitialEvolutionScales(ShowerPPair(*cit,partners[ix].second), - isDecayCase)); + vector > scales; + int position = -1; + for(size_t ix=0; ix< partners.size(); ++ix) { + scales.push_back( + calculateInitialEvolutionScales( + ShowerPPair(sp, partners[ix].second), + isDecayCase + ) + ); + if (!setPartners && partners[ix].second) position = ix; + } + assert(setPartners || position >= 0); + + // set partners if required + if (setPartners) { + // In the case of more than one candidate colour partners, + // there are now two approaches to choosing the partner. The + // first method is based on two assumptions: + // 1) the choice of which is the colour partner is done + // *randomly* between the available candidates. + // 2) the choice of which is the colour partner is done + // *independently* from each particle: in other words, + // if for a particle "i" its selected colour partner is + // the particle "j", then the colour partner of "j" + // does not have to be necessarily "i". + // The second method always chooses the furthest partner + // for hard gluons and gluinos. + // random choice + if( partnerMethod_ == 0 ) { + // random choice of partner + position = UseRandom::irnd(partners.size()); + } + // take the one with largest angle + else if (partnerMethod_ == 1 ) { + if (sp->perturbative() == 1 && + sp->dataPtr()->iColour()==PDT::Colour8 ) { + assert(partners.size()==2); + // Determine largest angle + double maxAngle(0.); + for(unsigned int ix=0;ixmomentum().vect(). + angle(partners[ix].second->momentum().vect()); + if(angle>maxAngle) { + maxAngle = angle; + position = ix; + } + } + } + else position = UseRandom::irnd(partners.size()); + } + else assert(false); + // set the evolution partner + sp->partner(partners[position].second); + } + + + // primary partner set, set the others and do the scale + for(size_t ix=0; ixaddPartner( + ShowerParticle::EvolutionPartner( + partners[ix].second, + 1., + partners[ix].first, + scales[ix].first + ) + ); } - // In the case of more than one candidate colour partners, - // there are now two approaches to choosing the partner. The - // first method is based on two assumptions: - // 1) the choice of which is the colour partner is done - // *randomly* between the available candidates. - // 2) the choice of which is the colour partner is done - // *independently* from each particle: in other words, - // if for a particle "i" its selected colour partner is - // the particle "j", then the colour partner of "j" - // does not have to be necessarily "i". - // The second method always chooses the furthest partner - // for hard gluons and gluinos. - // store the choice - int position(-1); - // random choice - if( partnerMethod_ == 0 ) { - // random choice of partner - position = UseRandom::irnd(partners.size()); - } - // take the one with largest angle - else if (partnerMethod_ == 1 ) { - if ((*cit)->perturbative() == 1 && - (*cit)->dataPtr()->iColour()==PDT::Colour8 ) { - assert(partners.size()==2); - // Determine largest angle - double maxAngle(0.); - for(unsigned int ix=0;ixmomentum().vect(). - angle(partners[ix].second->momentum().vect()); - if(angle>maxAngle) { - maxAngle = angle; - position = ix; - } - } - } - else - position = UseRandom::irnd(partners.size()); - } - else - assert(false); - // set the evolution partner - (*cit)->partner(partners[position].second); - for(unsigned int ix=0;ixscales().QCD_c = + sp->scales().QCD_c_noAO = + (scaleChoice_==0 ? scale : scales[ix].first); + } + else if(partners[ix].first==ShowerPartnerType::QCDAntiColourLine) { + sp->scales().QCD_ac = + sp->scales().QCD_ac_noAO = + (scaleChoice_==0 ? scale : scales[ix].first); + } + else assert(false); } - } - } - // primary partner set, set the others and do the scale - else { - for(ShowerParticleVector::const_iterator cit = particles.begin(); - cit != particles.end(); ++cit) { - // Skip colourless particles - if(!(*cit)->data().coloured()) continue; - // find the partners - vector< pair > partners = - findQCDPartners(*cit,particles); - // must have a partner - if(partners.empty()) { - throw Exception() << "`Failed to make colour connections in " - << "PartnerFinder::setQCDInitialEvolutionScales" - << (**cit) - << Exception::eventerror; - } - // Calculate the evolution scales for all possible pairs of of particles - vector > scales; - int position(-1); - for(unsigned int ix=0;ix< partners.size();++ix) { - if(partners[ix].second) position = ix; - scales.push_back(calculateInitialEvolutionScales(ShowerPPair(*cit,partners[ix].second), - isDecayCase)); - } - assert(position>=0); - for(unsigned int ix=0;ixcharged()) continue; - // if(!(**cit).dataPtr()->charged() && - // (**cit).id()!=ParticleID::gamma) continue; + if(!sp->dataPtr()->charged()) continue; // find the potential partners - vector > partners = findQEDPartners(*cit,particles,isDecayCase); + vector > partners = findQEDPartners(sp,particles,isDecayCase); if(partners.empty()) { throw Exception() << "Failed to find partner in " << "PartnerFinder::setQEDInitialEvolutionScales" - << (**cit) << Exception::eventerror; + << *sp << Exception::eventerror; } // calculate the probabilities double prob(0.); for(unsigned int ix=0;ixpartner()) { + if(!setPartners&&sp->partner()) { for(unsigned int ix=0;ixpartner()==partners[ix].second) { + if(sp->partner()==partners[ix].second) { position = ix; break; } } } // set the partner - if(setPartners||!(*cit)->partner()||position<0) { + if(setPartners||!sp->partner()||position<0) { prob = UseRandom::rnd(); for(unsigned int ix=0;ixprob) { position = ix; break; } prob -= partners[ix].first; } - if(position>=0&&(setPartners||!(*cit)->partner())) { - (*cit)->partner(partners[position].second); + if(position>=0&&(setPartners||!sp->partner())) { + sp->partner(partners[position].second); } } // must have a partner if(position<0) throw Exception() << "Failed to find partner in " << "PartnerFinder::setQEDInitialEvolutionScales" - << (**cit) << Exception::eventerror; + << *sp << Exception::eventerror; // Calculate the evolution scales for all possible pairs of of particles vector > scales; for(unsigned int ix=0;ix< partners.size();++ix) { - scales.push_back(calculateInitialEvolutionScales(ShowerPPair(*cit,partners[ix].second), + scales.push_back(calculateInitialEvolutionScales(ShowerPPair(sp,partners[ix].second), isDecayCase)); } // store all the possible partners for(unsigned int ix=0;ixaddPartner(ShowerParticle::EvolutionPartner(partners[ix].second, partners[ix].first, ShowerPartnerType::QED, scales[ix].first)); } // set scales - (**cit).scales().QED = scales[position].first; - (**cit).scales().QED_noAO = scales[position].first; + sp->scales().QED = scales[position].first; + sp->scales().QED_noAO = scales[position].first; } } pair PartnerFinder:: calculateInitialEvolutionScales(const ShowerPPair &particlePair, const bool isDecayCase) { bool FS1=FS(particlePair.first),FS2= FS(particlePair.second); if(FS1 && FS2) - return calculateFinalFinalScales(particlePair); + return calculateFinalFinalScales(particlePair.first->momentum(), + particlePair.second->momentum()); else if(FS1 && !FS2) { - ShowerPPair a(particlePair.second, particlePair.first); - pair rval = calculateInitialFinalScales(a,isDecayCase); - return pair(rval.second,rval.first); + pair rval = calculateInitialFinalScales(particlePair.second->momentum(), + particlePair.first->momentum(), + isDecayCase); + return { rval.second, rval.first }; } else if(!FS1 &&FS2) - return calculateInitialFinalScales(particlePair,isDecayCase); + return calculateInitialFinalScales(particlePair.first->momentum(),particlePair.second->momentum(),isDecayCase); else - return calculateInitialInitialScales(particlePair); + return calculateInitialInitialScales(particlePair.first->momentum(),particlePair.second->momentum()); } vector< pair > PartnerFinder::findQCDPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles) { vector< pair > partners; - ShowerParticleVector::const_iterator cjt; - for(cjt = particles.begin(); cjt != particles.end(); ++cjt) { - if(!(*cjt)->data().coloured() || particle==*cjt) continue; + for(const auto & sp : particles) { + if(!sp->data().coloured() || particle==sp) continue; // one initial-state and one final-state particle - if(FS(particle) != FS(*cjt)) { + if(FS(particle) != FS(sp)) { // loop over all the colours of both particles - for(unsigned int ix=0; ixsourceNeighbours().first) { tColinePair cpair = col->sourceNeighbours(); - for(cjt=particles.begin();cjt!=particles.end();++cjt) { - if(( FS(*cjt) && ( CL(*cjt) == cpair.first || CL(*cjt) == cpair.second))|| - (!FS(*cjt) && (ACL(*cjt) == cpair.first || ACL(*cjt) == cpair.second ))) { - partners.push_back(make_pair(ShowerPartnerType:: QCDColourLine,*cjt)); + for(const auto & sp : particles) { + if(( FS(sp) && ( CL(sp) == cpair.first || CL(sp) == cpair.second))|| + (!FS(sp) && (ACL(sp) == cpair.first || ACL(sp) == cpair.second ))) { + partners.push_back({ ShowerPartnerType:: QCDColourLine, sp }); } } } else if(col&&col->sinkNeighbours().first) { tColinePair cpair = col->sinkNeighbours(); - for(cjt=particles.begin();cjt!=particles.end();++cjt) { - if(( FS(*cjt) && (ACL(*cjt) == cpair.first || ACL(*cjt) == cpair.second))|| - (!FS(*cjt) && ( CL(*cjt) == cpair.first || CL(*cjt) == cpair.second))) { - partners.push_back(make_pair(ShowerPartnerType:: QCDColourLine,*cjt)); + for(const auto & sp : particles) { + if(( FS(sp) && (ACL(sp) == cpair.first || ACL(sp) == cpair.second))|| + (!FS(sp) && ( CL(sp) == cpair.first || CL(sp) == cpair.second))) { + partners.push_back({ ShowerPartnerType:: QCDColourLine, sp }); } } } col = ACL(particle); if(FS(particle)&&col&&col->sinkNeighbours().first) { tColinePair cpair = col->sinkNeighbours(); - for(cjt=particles.begin();cjt!=particles.end();++cjt) { - if(( FS(*cjt) && (ACL(*cjt) == cpair.first || ACL(*cjt) == cpair.second))|| - (!FS(*cjt) && ( CL(*cjt) == cpair.first || CL(*cjt) == cpair.second ))) { - partners.push_back(make_pair(ShowerPartnerType::QCDAntiColourLine,*cjt)); + for(const auto & sp : particles) { + if(( FS(sp) && (ACL(sp) == cpair.first || ACL(sp) == cpair.second))|| + (!FS(sp) && ( CL(sp) == cpair.first || CL(sp) == cpair.second ))) { + partners.push_back({ ShowerPartnerType::QCDAntiColourLine, sp }); } } } else if(col&&col->sourceNeighbours().first) { tColinePair cpair = col->sourceNeighbours(); - for(cjt=particles.begin();cjt!=particles.end();++cjt) { - if(( FS(*cjt) && ( CL(*cjt) == cpair.first || CL(*cjt) == cpair.second))|| - (!FS(*cjt) && (ACL(*cjt) == cpair.first ||ACL(*cjt) == cpair.second))) { - partners.push_back(make_pair(ShowerPartnerType::QCDAntiColourLine,*cjt)); + for(const auto & sp : particles) { + if(( FS(sp) && ( CL(sp) == cpair.first || CL(sp) == cpair.second))|| + (!FS(sp) && (ACL(sp) == cpair.first ||ACL(sp) == cpair.second))) { + partners.push_back({ ShowerPartnerType::QCDAntiColourLine, sp }); } } } } // return the partners return partners; } vector< pair > PartnerFinder::findQEDPartners(tShowerParticlePtr particle, - const ShowerParticleVector &particles, + const ShowerParticleVector & particles, const bool isDecayCase) { vector< pair > partners; - ShowerParticleVector::const_iterator cjt; - double pcharge = particle->id()==ParticleID::gamma ? 1 : double(particle->data().iCharge()); - // vector< pair > photons; - for(cjt = particles.begin(); cjt != particles.end(); ++cjt) { - if(particle == *cjt) continue; - // if((**cjt).id()==ParticleID::gamma) photons.push_back(make_pair(1.,*cjt)); - if(!(*cjt)->data().charged() ) continue; - double charge = pcharge*double((*cjt)->data().iCharge()); - if( FS(particle) != FS(*cjt) ) charge *=-1.; - if( QEDPartner_ != 0 && !isDecayCase ) { + const double pcharge = + particle->id()==ParticleID::gamma ? 1 : double(particle->data().iCharge()); + vector< pair > photons; + for (const auto & sp : particles) { + if (particle == sp) continue; + if (sp->id()==ParticleID::gamma) photons.push_back(make_pair(1.,sp)); + if (!sp->data().charged() ) continue; + double charge = pcharge*double((sp)->data().iCharge()); + if ( FS(particle) != FS(sp) ) charge *=-1.; + if ( QEDPartner_ != 0 && !isDecayCase ) { // only include II and FF as requested - if( QEDPartner_ == 1 && FS(particle) != FS(*cjt) ) + if ( QEDPartner_ == 1 && FS(particle) != FS(sp) ) continue; // only include IF is requested - else if(QEDPartner_ == 2 && FS(particle) == FS(*cjt) ) + else if (QEDPartner_ == 2 && FS(particle) == FS(sp) ) continue; } - if(particle->id()==ParticleID::gamma) charge = -abs(charge); + if (particle->id()==ParticleID::gamma) charge = -abs(charge); // only keep positive dipoles - if(charge<0.) partners.push_back(make_pair(-charge,*cjt)); + if (charge<0.) partners.push_back({ -charge, sp }); } - // if(particle->id()==ParticleID::gamma&& partners.empty()) { - // return photons; - // } + if (particle->id()==ParticleID::gamma && partners.empty()) + return photons; return partners; } void PartnerFinder::setInitialEWEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, const bool setPartners) { // loop over all the particles for(ShowerParticleVector::const_iterator cit = particles.begin(); cit != particles.end(); ++cit) { // if not weakly interacting continue if( !weaklyInteracting( (**cit).dataPtr())) continue; // find the potential partners vector > partners = findEWPartners(*cit,particles,isDecayCase); if(partners.empty()) { throw Exception() << "Failed to find partner in " << "PartnerFinder::setEWInitialEvolutionScales" << (**cit) << Exception::eventerror; } // calculate the probabilities double prob(0.); for(unsigned int ix=0;ixpartner()) { for(unsigned int ix=0;ixpartner()==partners[ix].second) { position = ix; break; } } } // set the partner if(setPartners||!(*cit)->partner()||position<0) { prob = UseRandom::rnd(); for(unsigned int ix=0;ixprob) { position = ix; break; } prob -= partners[ix].first; } if(position>=0&&(setPartners||!(*cit)->partner())) { (*cit)->partner(partners[position].second); } } // must have a partner if(position<0) throw Exception() << "Failed to find partner in " << "PartnerFinder::setEWInitialEvolutionScales" << (**cit) << Exception::eventerror; // Calculate the evolution scales for all possible pairs of of particles vector > scales; for(unsigned int ix=0;ix< partners.size();++ix) { scales.push_back(calculateInitialEvolutionScales(ShowerPPair(*cit,partners[ix].second), isDecayCase)); } // store all the possible partners for(unsigned int ix=0;ix > PartnerFinder::findEWPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles, const bool isDecayCase ) { vector< pair > partners; ShowerParticleVector::const_iterator cjt; for(cjt = particles.begin(); cjt != particles.end(); ++cjt) { if(!weaklyInteracting((*cjt)->dataPtr()) || particle == *cjt) continue; if( QEDPartner_ != 0 && !isDecayCase ) { // only include II and FF as requested if( QEDPartner_ == 1 && FS(particle) != FS(*cjt) ) continue; // only include IF is requested else if(QEDPartner_ == 2 && FS(particle) == FS(*cjt) ) continue; } double charge = 1.; // only keep positive dipoles if(charge>0.) partners.push_back(make_pair(charge,*cjt)); } return partners; } + +pair +PartnerFinder::calculateFinalFinalScales( + const Lorentz5Momentum & p1, + const Lorentz5Momentum & p2) +{ + static const double eps=1e-7; + // Using JHEP 12(2003)045 we find that we need ktilde = 1/2(1+b-c+lambda) + // ktilde = qtilde^2/Q^2 therefore qtilde = sqrt(ktilde*Q^2) + // find momenta in rest frame of system + // calculate quantities for the scales + Energy2 Q2 = (p1+p2).m2(); + double b = p1.mass2()/Q2; + double c = p2.mass2()/Q2; + if(b<0.) { + if(b<-eps) { + throw Exception() << "Negative Mass squared b = " << b + << "in PartnerFinder::calculateFinalFinalScales()" + << Exception::eventerror; + } + b = 0.; + } + if(c<0.) { + if(c<-eps) { + throw Exception() << "Negative Mass squared c = " << c + << "in PartnerFinder::calculateFinalFinalScales()" + << Exception::eventerror; + } + c = 0.; + } + // KMH & PR - 16 May 2008 - swapped lambda calculation from + // double lam=2.*p1.vect().mag()/Q; to sqrt(kallen(1,b,c)), + // which should be identical for p1 & p2 onshell in their COM + // but in the inverse construction for the Nason method, this + // was not the case, leading to misuse. + const double lam=sqrt((1.+sqrt(b)+sqrt(c))*(1.-sqrt(b)-sqrt(c)) + *(sqrt(b)-1.-sqrt(c))*(sqrt(c)-1.-sqrt(b))); + // symmetric case + return { sqrt(0.5*Q2*(1.+b-c+lam)), sqrt(0.5*Q2*(1.-b+c+lam)) }; +} + + +pair +PartnerFinder::calculateInitialFinalScales(const Lorentz5Momentum& pb, const Lorentz5Momentum& pc, + const bool isDecayCase) { + if(!isDecayCase) { + // In this case from JHEP 12(2003)045 we find the conditions + // ktilde_b = (1+c) and ktilde_c = (1+2c) + // We also find that c = m_c^2/Q^2. The process is a+b->c where + // particle a is not colour connected (considered as a colour singlet). + // Therefore we simply find that q_b = sqrt(Q^2+m_c^2) and + // q_c = sqrt(Q^2+2 m_c^2) + // We also assume that the first particle in the pair is the initial + // state particle and the second is the final state one c + const Energy2 mc2 = sqr(pc.mass()); + const Energy2 Q2 = -(pb-pc).m2(); + return { sqrt(Q2+mc2), sqrt(Q2+2*mc2) }; + } + else { + // In this case from JHEP 12(2003)045 we find, for the decay + // process b->c+a(neutral), the condition + // (ktilde_b-1)*(ktilde_c-c)=(1/4)*sqr(1-a+c+lambda). + // We also assume that the first particle in the pair is the initial + // state particle (b) and the second is the final state one (c). + // - We find maximal phase space coverage through emissions from + // c if we set ktilde_c = 4.*(sqr(1.-sqrt(a))-c) + // - We find the most 'symmetric' way to populate the phase space + // occurs for (ktilde_b-1)=(ktilde_c-c)=(1/2)*(1-a+c+lambda) + // - We find the most 'smooth' way to populate the phase space + // occurs for... + Energy2 mb2(sqr(pb.mass())); + double a=(pb-pc).m2()/mb2; + double c=sqr(pc.mass())/mb2; + double lambda = 1. + a*a + c*c - 2.*a - 2.*c - 2.*a*c; + lambda = sqrt(max(lambda,0.)); + const double PROD = 0.25*sqr(1. - a + c + lambda); + const double ktilde_c = 0.5*(1-a+c+lambda) + c ; + const double ktilde_b = 1.+PROD/(ktilde_c-c) ; + return { sqrt(mb2*ktilde_b), sqrt(mb2*ktilde_c) }; + } +} + +pair +PartnerFinder::calculateInitialInitialScales(const Lorentz5Momentum& p1, const Lorentz5Momentum& p2) { + // This case is quite simple. From JHEP 12(2003)045 we find the condition + // that ktilde_b = ktilde_c = 1. In this case we have the process + // b+c->a so we need merely boost to the CM frame of the two incoming + // particles and then qtilde is equal to the energy in that frame + const Energy Q = sqrt((p1+p2).m2()); + return {Q,Q}; +} diff --git a/Shower/QTilde/Base/PartnerFinder.h b/Shower/QTilde/Base/PartnerFinder.h --- a/Shower/QTilde/Base/PartnerFinder.h +++ b/Shower/QTilde/Base/PartnerFinder.h @@ -1,234 +1,256 @@ // -*- C++ -*- // // PartnerFinder.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_PartnerFinder_H #define HERWIG_PartnerFinder_H // // This is the declaration of the PartnerFinder class. // #include "Herwig/Shower/QTilde/ShowerConfig.h" #include "ThePEG/Interface/Interfaced.h" #include "PartnerFinder.fh" namespace Herwig { using namespace ThePEG; /** * typedef of a pair of particle for calculating the evolution scales */ typedef pair ShowerPPair; /** \ingroup Shower * * This class is responsible of two related tasks: * - it finds the partners * - for each pair of partners (and interaction therefore) * it sets the initial evolution scales of both of them. * * In general the finding of the partners is performed by this class but * the calculation of the initial evolution scales should be implemented * for different shower evolution models in classes inheriting from this one. * Notice that a given particle has, in general, a different partner * for each different interaction; however, given a partner, its * initial evolution scale, Q, is purely a kinematical relationship * between the pair, without dependence on the dynamics (i.e. type of interaction). * * @see \ref PartnerFinderInterfaces "The interfaces" * defined for PartnerFinder. */ class PartnerFinder: public Interfaced { public: /** * The default constructor. */ PartnerFinder() : partnerMethod_(0), QEDPartner_(0), scaleChoice_(0) {} /** * Given in input a collection of particles (ShowerParticle objects), * each of these methods set the initial evolution scales of those particles, * between the ones given in input, that do not have yet their * evolution scale set. * The input collection of particles can be either the full collection of * showering particles (kept in the main class ShowerHandler, * in the case isDecayCase is false, or simply, in the case isDecayCase * is true, the decaying particle and its decay products. * The methods returns true, unless something wrong (inconsistencies, * or undefined values) happens. * * These methods are virtual but in most cases inheriting classes should not * need to overide them as they simply find the relevant partner and call * one of the calculateScale members to calculate the scale. */ //@{ /** * Set the initial scales * @param particles The particles to be considered * @param isDecayCase Whether or not this is a decay * @param setPartners Whether to set the colour partners or just the scales */ virtual void setInitialEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, ShowerInteraction, const bool setPartners=true); //@} +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const {return new_ptr(*this);} + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const {return new_ptr(*this);} + //@} + 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(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(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: /** * Members to set the scales for different interactions */ //@{ /** * Set initial scales for a QCD interaction */ virtual void setInitialQCDEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, const bool setPartners=true); /** * Set initial scales for a QED interaction */ virtual void setInitialQEDEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, const bool setPartners=true); /** * Set initial scales for a EW interaction */ virtual void setInitialEWEvolutionScales(const ShowerParticleVector &particles, const bool isDecayCase, const bool setPartners=true); //@} /** * Find the QCD partners * @param particle The particle to find the partners for * @param particles The full set of particles to search */ vector< pair > findQCDPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles); /** * Find the QED partners * @param particle The particle to find the partners for * @param particles The full set of particles to search */ vector< pair > findQEDPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles, const bool isDecayCase); +public: /** * Find the EW partners * @param particle The particle to find the partners for * @param particles The full set of particles to search */ vector< pair > findEWPartners(tShowerParticlePtr particle, const ShowerParticleVector &particles, const bool isDecayCase); /** * Given a pair of particles, supposedly partners w.r.t. an interaction, * this method returns their initial evolution scales as a pair. * If something wrong happens, it returns the null (ZERO,ZERO) pair. * This method is used by the above setXXXInitialEvolutionScales * methods. * These methods must be overiden in inheriting classes */ //@{ /** * General method to calculate the initial evolution scales */ - virtual pair calculateInitialEvolutionScales(const ShowerPPair &, - const bool isDecayCase); + pair calculateInitialEvolutionScales(const ShowerPPair &, + const bool isDecayCase); /** - * Calculate the initial evolution scales for two final-state particles + * Calculate the initial evolution scales given momenta */ - virtual pair calculateFinalFinalScales(const ShowerPPair &)=0; + pair calculateFinalFinalScales(const Lorentz5Momentum & p1, + const Lorentz5Momentum & p2); /** - * Calculate the initial evolution scales for two initial-state particles + * Calculate the initial evolution scales given momenta */ - virtual pair calculateInitialInitialScales(const ShowerPPair &)=0; + pair calculateInitialInitialScales(const Lorentz5Momentum& p1, + const Lorentz5Momentum& p2); /** - * Calculate the initial evolution scales for one initial - * and one final-state particles + * Calculate the initial evolution scales given momenta */ - virtual pair calculateInitialFinalScales(const ShowerPPair &, - const bool isDecayCase)=0; + pair calculateInitialFinalScales(const Lorentz5Momentum& pb, const Lorentz5Momentum& pc, + const bool isDecayCase); + + //@} protected: /** * Find weakling interacting particles */ bool weaklyInteracting(tcPDPtr pd) { long id = abs(pd->id()); return ( id==ParticleID::Wplus || id ==ParticleID::Z0 || (id>=1 && id<=6 ) || (id>=11 && id<=16)); } private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ PartnerFinder & operator=(const PartnerFinder &); private: /** * Method for choosing colour partner */ int partnerMethod_; /** * Choice for the QED radiation partner */ int QEDPartner_; /** * Choice of the scale */ int scaleChoice_; + }; } #endif /* HERWIG_PartnerFinder_H */ diff --git a/Shower/QTilde/Base/ShowerModel.cc b/Shower/QTilde/Base/ShowerModel.cc deleted file mode 100644 --- a/Shower/QTilde/Base/ShowerModel.cc +++ /dev/null @@ -1,65 +0,0 @@ -// -*- C++ -*- -// -// ShowerModel.cc is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig 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 ShowerModel class. -// - -#include "ShowerModel.h" -#include "ThePEG/Interface/ClassDocumentation.h" -#include "ThePEG/Interface/Reference.h" -#include "ThePEG/Interface/RefVector.h" -#include "ThePEG/Persistency/PersistentOStream.h" -#include "ThePEG/Persistency/PersistentIStream.h" -#include "KinematicsReconstructor.h" -#include "PartnerFinder.h" -#include "Herwig/Shower/QTilde/Base/SudakovFormFactor.h" -#include "ThePEG/Utilities/DescribeClass.h" - -using namespace Herwig; - -DescribeAbstractClass -describeShowerModel ("Herwig::ShowerModel","HwShower.so"); - -void ShowerModel::persistentOutput(PersistentOStream & os) const { - os << _reconstructor << _partnerfinder << _sudakovs; -} - -void ShowerModel::persistentInput(PersistentIStream & is, int) { - is >> _reconstructor >> _partnerfinder >> _sudakovs; -} - -void ShowerModel::doinit() { - Interfaced::doinit(); - checkConsistency(); -} - -void ShowerModel::Init() { - - static ClassDocumentation documentation - ("The ShowerModel class contains the references for the classes which" - " are specific to the shower evolution scheme."); - - static Reference interfaceKinematicsReconstructor - ("KinematicsReconstructor", - "Reference to the KinematicsReconstructor object", - &ShowerModel::_reconstructor, false, false, true, false, false); - - static Reference interfacePartnerFinder - ("PartnerFinder", - "Reference to the PartnerFinder object", - &ShowerModel::_partnerfinder, false, false, true, false, false); - - static RefVector interfaceSudakovFormFactors - ("SudakovFormFactors", - "Vector of references to the SudakovFormFactor objects", - &ShowerModel::_sudakovs, -1, false, false, true, false, false); - -} - diff --git a/Shower/QTilde/Base/ShowerModel.fh b/Shower/QTilde/Base/ShowerModel.fh deleted file mode 100644 --- a/Shower/QTilde/Base/ShowerModel.fh +++ /dev/null @@ -1,22 +0,0 @@ -// -*- C++ -*- -// -// This is the forward declaration of the ShowerModel class. -// -#ifndef HERWIG_ShowerModel_FH -#define HERWIG_ShowerModel_FH - -#include "ThePEG/Config/Pointers.h" - -namespace Herwig { - -class ShowerModel; - -} - -namespace ThePEG { - -ThePEG_DECLARE_POINTERS(Herwig::ShowerModel,ShowerModelPtr); - -} - -#endif diff --git a/Shower/QTilde/Base/ShowerModel.h b/Shower/QTilde/Base/ShowerModel.h deleted file mode 100644 --- a/Shower/QTilde/Base/ShowerModel.h +++ /dev/null @@ -1,148 +0,0 @@ -// -*- C++ -*- -// -// ShowerModel.h is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig is licenced under version 3 of the GPL, see COPYING for details. -// Please respect the MCnet academic guidelines, see GUIDELINES for details. -// -#ifndef HERWIG_ShowerModel_H -#define HERWIG_ShowerModel_H -// -// This is the declaration of the ShowerModel class. -// -#include "ThePEG/Interface/Interfaced.h" -#include "KinematicsReconstructor.fh" -#include "PartnerFinder.fh" -#include "Herwig/Shower/QTilde/Base/SudakovFormFactor.fh" -#include "ShowerModel.fh" - -namespace Herwig { - -using namespace ThePEG; - -/** \ingroup Shower - * - * The ShowerModel class is a container for all the objects needed to implement a - * specific model of the shower evolution, as opposed to those which are independent - * of the evolution. - * - * In general there are four types of object - * - The KinematicsReconstructor object which is responsible for reconstruction - * of the shower kinematics after the evolution. - * - The PartnerFinder which is responsible for finding the partner and setting the - * initial evolution scale - * - A vector of SudakovFormFactor objects which will usually all be instances - * of a class implementing the SudakovFormFactor for a specific model with - * different splitting functions for different branchings - * - * For each model the checkConsistency member must be implemented to check that - * the correct objects for the model are used. - * - * @see \ref ShowerModelInterfaces "The interfaces" - * defined for ShowerModel. - */ -class ShowerModel: public Interfaced { - -public: - - /** - * Access methods to access the objects - */ - //@{ - /** - * Access to the KinematicsReconstructor object - */ - tKinematicsReconstructorPtr kinematicsReconstructor() const { return _reconstructor; } - - /** - * Access to the PartnerFinder object - */ - tPartnerFinderPtr partnerFinder() const { return _partnerfinder; } - - /** - * Access to the SudakovFormFactor objects - */ - const vector & sudakovFormFactors() const { return _sudakovs; } - //@} - -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(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(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: - - /** - * The checkConsitency member which must be implemented in classes - * inheriting from this one. - */ - virtual void checkConsistency() =0; - - /** @name Standard Interfaced functions. */ - //@{ - /** - * Initialize this object after the setup phase before saving an - * EventGenerator to disk. - * @throws InitException if object could not be initialized properly. - */ - virtual void doinit(); - //@} - -private: - - /** - * The assignment operator is private and must never be called. - * In fact, it should not even be implemented. - */ - ShowerModel & operator=(const ShowerModel &); - -private: - - /** - * Pointer to the various objects - */ - //@{ - /** - * Pointer to the KinematicsReconstructor object - */ - KinematicsReconstructorPtr _reconstructor; - - /** - * Pointer to the PartnerFinder object - */ - PartnerFinderPtr _partnerfinder; - - /** - * Pointers to the SudakovFormFactor objects - */ - vector _sudakovs; - //@} - -}; - -} - -#endif /* HERWIG_ShowerModel_H */ diff --git a/Shower/QTilde/Base/ShowerParticle.h b/Shower/QTilde/Base/ShowerParticle.h --- a/Shower/QTilde/Base/ShowerParticle.h +++ b/Shower/QTilde/Base/ShowerParticle.h @@ -1,540 +1,535 @@ // -*- C++ -*- // // ShowerParticle.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerParticle_H #define HERWIG_ShowerParticle_H // // This is the declaration of the ShowerParticle class. // #include "ThePEG/EventRecord/Particle.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.fh" #include "Herwig/Shower/QTilde/ShowerConfig.h" -#include "ShowerBasis.h" -#include "ShowerKinematics.h" +#include "Herwig/Shower/QTilde/Kinematics/ShowerBasis.h" +#include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.h" #include "ShowerParticle.fh" #include namespace Herwig { using namespace ThePEG; /** \ingroup Shower * This class represents a particle in the showering process. * It inherits from the Particle class of ThePEG and has some * specifics information useful only during the showering process. * * Notice that: * - for forward evolution, it is clear what is meant by parent/child; * for backward evolution, however, it depends whether we want * to keep a physical picture or a Monte-Carlo effective one. * In the former case, an incoming particle (emitting particle) * splits into an emitted particle and the emitting particle after * the emission: the latter two are then children of the * emitting particle, the parent. In the Monte-Carlo effective * picture, we have that the particle close to the hard subprocess, * with higher (space-like) virtuality, splits into an emitted particle * and the emitting particle at lower virtuality: the latter two are, * in this case, the children of the first one, the parent. However we * choose a more physical picture where the new emitting particle is the * parented of the emitted final-state particle and the original emitting * particle. * - the pointer to a SplitFun object is set only in the case * that the particle has undergone a shower emission. This is similar to * the case of the decay of a normal Particle where * the pointer to a Decayer object is set only in the case * that the particle has undergone to a decay. * In the case of particle connected directly to the hard subprocess, * there is no pointer to the hard subprocess, but there is a method * isFromHardSubprocess() which returns true only in this case. * * @see Particle * @see ShowerConfig * @see ShowerKinematics */ class ShowerParticle: public Particle { public: /** * Struct for all the info on an evolution partner */ struct EvolutionPartner { /** * Constructor */ EvolutionPartner(tShowerParticlePtr p,double w, ShowerPartnerType t, Energy s) : partner(p), weight(w), type(t), scale(s) {} /** * The partner */ tShowerParticlePtr partner; /** * Weight */ double weight; /** * Type */ ShowerPartnerType type; /** * The assoicated evolution scale */ Energy scale; }; /** * Struct to store the evolution scales */ struct EvolutionScales { /** * Constructor */ EvolutionScales() : QED(),QCD_c(),QCD_ac(), - QED_noAO(),QCD_c_noAO(),QCD_ac_noAO(),EW(), - Max_Q2(Constants::MaxEnergy2) + QED_noAO(),QCD_c_noAO(),QCD_ac_noAO() {} /** * QED scale */ Energy QED; /** * QCD colour scale */ Energy QCD_c; /** * QCD anticolour scale */ Energy QCD_ac; /** * QED scale */ Energy QED_noAO; /** * QCD colour scale */ Energy QCD_c_noAO; /** * QCD anticolour scale */ Energy QCD_ac_noAO; /** * EW scale */ Energy EW; /** * EW scale */ Energy EW_noAO; - - /** - * Maximum allowed virtuality of the particle - */ - Energy2 Max_Q2; + }; /** @name Construction and descruction functions. */ //@{ /** * Standard Constructor. Note that the default constructor is * private - there is no particle without a pointer to a * ParticleData object. * @param x the ParticleData object * @param fs Whether or not the particle is an inital or final-state particle * @param tls Whether or not the particle initiates a time-like shower */ ShowerParticle(tcEventPDPtr x, bool fs, bool tls=false) : Particle(x), _isFinalState(fs), _perturbative(0), _initiatesTLS(tls), _x(1.0), _showerKinematics(), _vMass(ZERO), _thePEGBase() {} /** * Copy constructor from a ThePEG Particle * @param x ThePEG particle * @param pert Where the particle came from * @param fs Whether or not the particle is an inital or final-state particle * @param tls Whether or not the particle initiates a time-like shower */ ShowerParticle(const Particle & x, unsigned int pert, bool fs, bool tls=false) : Particle(x), _isFinalState(fs), _perturbative(pert), _initiatesTLS(tls), _x(1.0), _showerKinematics(), _vMass(ZERO), _thePEGBase(&x) {} //@} public: /** * Set a preliminary momentum for the particle */ void setShowerMomentum(bool timelike); /** * Construct the spin info object for a shower particle */ void constructSpinInfo(bool timelike); /** * Perform any initial calculations needed after the branching has been selected */ void initializeDecay(); /** * Perform any initial calculations needed after the branching has been selected * @param parent The beam particle */ void initializeInitialState(PPtr parent); /** * Perform any initial calculations needed after the branching has been selected */ void initializeFinalState(); /** * Access/Set various flags about the state of the particle */ //@{ /** * Access the flag that tells if the particle is final state * or initial state. */ bool isFinalState() const { return _isFinalState; } /** * Access the flag that tells if the particle is initiating a * time like shower when it has been emitted in an initial state shower. */ bool initiatesTLS() const { return _initiatesTLS; } /** * Access the flag which tells us where the particle came from * This is 0 for a particle produced in the shower, 1 if the particle came * from the hard sub-process and 2 is it came from a decay. */ unsigned int perturbative() const { return _perturbative; } //@} /** * Set/Get the momentum fraction for initial-state particles */ //@{ /** * For an initial state particle get the fraction of the beam momentum */ void x(double x) { _x = x; } /** * For an initial state particle set the fraction of the beam momentum */ double x() const { return _x; } //@} /** * Set/Get methods for the ShowerKinematics objects */ //@{ /** * Access/ the ShowerKinematics object. */ const ShoKinPtr & showerKinematics() const { return _showerKinematics; } /** * Set the ShowerKinematics object. */ void showerKinematics(const ShoKinPtr in) { _showerKinematics = in; } //@} /** * Set/Get methods for the ShowerBasis objects */ //@{ /** * Access/ the ShowerBasis object. */ const ShowerBasisPtr & showerBasis() const { return _showerBasis; } /** * Set the ShowerBasis object. */ void showerBasis(const ShowerBasisPtr in, bool copy) { if(!copy) _showerBasis = in; else { _showerBasis = new_ptr(ShowerBasis()); _showerBasis->setBasis(in->pVector(),in->nVector(),in->frame()); } } //@} /** * Members relating to the initial evolution scale and partner for the particle */ //@{ /** * Veto emission at a given scale */ void vetoEmission(ShowerPartnerType type, Energy scale); /** * Access to the evolution scales */ const EvolutionScales & scales() const {return scales_;} /** * Access to the evolution scales */ EvolutionScales & scales() {return scales_;} /** * Return the virtual mass\f$ */ Energy virtualMass() const { return _vMass; } /** * Set the virtual mass */ void virtualMass(Energy mass) { _vMass = mass; } /** * Return the partner */ tShowerParticlePtr partner() const { return _partner; } /** * Set the partner */ void partner(const tShowerParticlePtr partner) { _partner = partner; } /** * Get the possible partners */ vector & partners() { return partners_; } /** * Add a possible partners */ void addPartner(EvolutionPartner in ); /** * Clear the evolution partners */ void clearPartners() { partners_.clear(); } /** * Return the progenitor of the shower */ tShowerParticlePtr progenitor() const { return _progenitor; } /** * Set the progenitor of the shower */ void progenitor(const tShowerParticlePtr progenitor) { _progenitor = progenitor; } //@} /** * Members to store and provide access to variables for a specific * shower evolution scheme */ //@{ struct Parameters { Parameters() : alpha(1.), beta(), ptx(), pty(), pt() {} double alpha; double beta; Energy ptx; Energy pty; Energy pt; }; /** * Set the vector containing dimensionless variables */ Parameters & showerParameters() { return _parameters; } //@} /** * If this particle came from the hard process get a pointer to ThePEG particle * it came from */ const tcPPtr thePEGBase() const { return _thePEGBase; } public: /** * Extract the rho matrix including mapping needed in the shower */ RhoDMatrix extractRhoMatrix(bool forward); /** * For a particle which came from the hard process get the spin density and * the mapping required to the basis used in the Shower * @param rho The \f$\rho\f$ matrix * @param mapping The mapping * @param showerkin The ShowerKinematics object */ bool getMapping(SpinPtr &, RhoDMatrix & map); protected: /** * Standard clone function. */ virtual PPtr clone() const; /** * Standard clone function. */ virtual PPtr fullclone() const; private: /** * The static object used to initialize the description of this class. * Indicates that this is a concrete class with persistent data. */ static ClassDescription initShowerParticle; /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ ShowerParticle & operator=(const ShowerParticle &); private: /** * Whether the particle is in the final or initial state */ bool _isFinalState; /** * Whether the particle came from */ unsigned int _perturbative; /** * Does a particle produced in the backward shower initiate a time-like shower */ bool _initiatesTLS; /** * Dimensionless parameters */ Parameters _parameters; /** * The beam energy fraction for particle's in the initial state */ double _x; /** * The shower kinematics for the particle */ ShoKinPtr _showerKinematics; /** * The shower basis for the particle */ ShowerBasisPtr _showerBasis; /** * Storage of the evolution scales */ EvolutionScales scales_; /** * Virtual mass */ Energy _vMass; /** * Partners */ tShowerParticlePtr _partner; /** * Pointer to ThePEG Particle this ShowerParticle was created from */ const tcPPtr _thePEGBase; /** * Progenitor */ tShowerParticlePtr _progenitor; /** * Partners */ vector partners_; }; inline ostream & operator<<(ostream & os, const ShowerParticle::EvolutionScales & es) { os << "Scales: QED=" << es.QED / GeV << " QCD_c=" << es.QCD_c / GeV << " QCD_ac=" << es.QCD_ac / GeV << " EW=" << es.EW / GeV << " QED_noAO=" << es.QED_noAO / GeV << " QCD_c_noAO=" << es.QCD_c_noAO / GeV << " QCD_ac_noAO=" << es.QCD_ac_noAO / GeV << " EW_noAO=" << es.EW_noAO / GeV << '\n'; return os; } } #include "ThePEG/Utilities/ClassTraits.h" namespace ThePEG { /** @cond TRAITSPECIALIZATIONS */ /** This template specialization informs ThePEG about the * base classes of ShowerParticle. */ template <> struct BaseClassTrait { /** Typedef of the first base class of ShowerParticle. */ typedef Particle NthBase; }; /** This template specialization informs ThePEG about the name of * the ShowerParticle class and the shared object where it is defined. */ template <> struct ClassTraits : public ClassTraitsBase { /** Return a platform-independent class name */ static string className() { return "Herwig::ShowerParticle"; } /** Create a Event object. */ static TPtr create() { return TPtr::Create(Herwig::ShowerParticle(tcEventPDPtr(),true)); } }; /** @endcond */ } #endif /* HERWIG_ShowerParticle_H */ diff --git a/Shower/QTilde/Base/ShowerTree.cc b/Shower/QTilde/Base/ShowerTree.cc --- a/Shower/QTilde/Base/ShowerTree.cc +++ b/Shower/QTilde/Base/ShowerTree.cc @@ -1,923 +1,914 @@ // -*- C++ -*- // // ShowerTree.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #include "ThePEG/EventRecord/MultiColour.h" #include "ThePEG/Repository/EventGenerator.h" #include "ShowerTree.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "Herwig/Shower/ShowerHandler.h" #include "ThePEG/PDT/DecayMode.h" #include "ThePEG/Handlers/EventHandler.h" #include "ThePEG/Handlers/XComb.h" #include #include "ThePEG/Repository/CurrentGenerator.h" #include "ThePEG/PDT/StandardMatchers.h" using namespace Herwig; using namespace ThePEG; bool ShowerTree::_spaceTime = false; Energy2 ShowerTree::_vmin2 = 0.1*GeV2; namespace { void findBeam(tPPtr & beam, PPtr incoming) { + if(beam==incoming) return; while(!beam->children().empty()) { bool found=false; for(unsigned int ix=0;ixchildren().size();++ix) { if(beam->children()[ix]==incoming) { found = true; break; } } if(found) break; beam = beam->children()[0]; } } } ShowerTree::ShowerTree(PerturbativeProcessPtr process) - : _hardMECorrection(false), - _parent(), _hasShowered(false) { + : _parent(), _hasShowered(false) { // get the incoming and outgoing particles and make copies vector original,copy; for(unsigned int ix=0;ixincoming().size();++ix) { original.push_back(process->incoming()[ix].first); copy .push_back(new_ptr(Particle(*original.back()))); } for(unsigned int ix=0;ixoutgoing().size();++ix) { original.push_back(process->outgoing()[ix].first); copy .push_back(new_ptr(Particle(*original.back()))); } // isolate the colour colourIsolate(original,copy); // hard process unsigned int itype(1); if(process->incoming().size()==2) { _wasHard = true; // set the beams and incoming particles tPPair beam = CurrentGenerator::current().currentEvent()->incoming(); findBeam(beam.first ,process->incoming()[0].first); findBeam(beam.second,process->incoming()[1].first); _incoming = make_pair(process->incoming()[0].first, process->incoming()[1].first); double x1(_incoming.first ->momentum().rho()/beam.first ->momentum().rho()); double x2(_incoming.second->momentum().rho()/beam.second->momentum().rho()); // must have two incoming particles assert(_incoming.first && _incoming.second); // set the parent tree _parent=ShowerTreePtr(); for(unsigned int ix=0;ix<2;++ix) { ShowerParticlePtr temp=new_ptr(ShowerParticle(*copy[ix],itype,false)); fixColour(temp); temp->x(ix==0 ? x1 : x2); _incomingLines.insert(make_pair(new_ptr(ShowerProgenitor(original[ix], copy[ix],temp)),temp)); - _backward.insert(temp); } } // decay process else if(process->incoming().size()==1) { _wasHard = false; itype=2; // create the parent shower particle ShowerParticlePtr sparent(new_ptr(ShowerParticle(*copy[0],itype,false))); fixColour(sparent); _incomingLines.insert(make_pair(new_ptr(ShowerProgenitor(original[0],copy[0],sparent)) ,sparent)); // return if not decayed if(original.size()==1) return; } else assert(false); // create the children assert(copy.size() == original.size()); for (unsigned int ix=process->incoming().size();ixid()==progenitor->id(); } ShowerParticlePtr newpart; if(matches[0]&&matches[1]) { if(parent->showerKinematics()->z()>0.5) newpart=children[0]; else newpart=children[1]; } else if(matches[0]) newpart=children[0]; else if(matches[1]) newpart=children[1]; _outgoingLines[progenitor]=newpart; } void ShowerTree::updateInitialStateShowerProduct(ShowerProgenitorPtr progenitor, ShowerParticlePtr newParent) { _incomingLines[progenitor]=newParent; } void ShowerTree::insertHard(StepPtr pstep, bool ISR, bool) { assert(_incomingLines.size()==2); colourLines().clear(); map::const_iterator cit; // construct the map of colour lines for hard process for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit) { if(!cit->first->perturbative()) continue; mapColour(cit->first->original(),cit->first->copy()); } map::const_iterator cjt; for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt) { if(!cjt->first->perturbative()) continue; mapColour(cjt->first->original(),cjt->first->copy()); } // initial-state radiation if(ISR) { for(cit=incomingLines().begin();cit!=incomingLines().end();++cit) { ShowerParticlePtr init=(*cit).first->progenitor(); assert(init->thePEGBase()); PPtr original = (*cit).first->original(); if(original->parents().empty()) continue; PPtr hadron= original->parents()[0]; assert(!original->children().empty()); PPtr copy=cit->first->copy(); ParticleVector intermediates=original->children(); for(unsigned int ix=0;ixabandonChild(intermediates[ix]); copy->abandonChild(intermediates[ix]); } // if not from a matrix element correction if(cit->first->perturbative()) { // break mother/daugther relations init->addChild(original); hadron->abandonChild(original); // if particle showers add shower if(cit->first->hasEmitted()) { addInitialStateShower(init,hadron,pstep,false); } // no showering for this particle else { updateColour(init,false); hadron->addChild(init); pstep->addIntermediate(init); init->setLifeLength(Lorentz5Distance()); init->setVertex(LorentzPoint()); } } // from matrix element correction else { // break mother/daugther relations hadron->abandonChild(original); copy->addChild(original); updateColour(copy,false); init->addChild(copy); pstep->addIntermediate(copy); copy->setLifeLength(Lorentz5Distance()); copy->setVertex(LorentzPoint()); // if particle showers add shower if(cit->first->hasEmitted()) { addInitialStateShower(init,hadron,pstep,false); } // no showering for this particle else { updateColour(init,false); hadron->addChild(init); pstep->addIntermediate(init); init->setLifeLength(Lorentz5Distance()); init->setVertex(LorentzPoint()); } } } } else { for(cit=incomingLines().begin();cit!=incomingLines().end();++cit) { ShowerParticlePtr init=(*cit).first->progenitor(); assert(init->thePEGBase()); PPtr original = (*cit).first->original(); if(original->parents().empty()) continue; PPtr hadron= original->parents()[0]; assert(!original->children().empty()); PPtr copy=cit->first->copy(); ParticleVector intermediates=original->children(); for(unsigned int ix=0;ixabandonChild(intermediates[ix]); copy->abandonChild(intermediates[ix]); } // break mother/daugther relations init->addChild(original); hadron->abandonChild(original); // no showering for this particle updateColour(init,false); hadron->addChild(init); pstep->addIntermediate(init); init->setLifeLength(Lorentz5Distance()); init->setVertex(LorentzPoint()); original->setLifeLength(Lorentz5Distance()); original->setVertex(LorentzPoint()); } } // final-state radiation for(cjt=outgoingLines().begin();cjt!=outgoingLines().end();++cjt) { ShowerParticlePtr init=(*cjt).first->progenitor(); assert(init->thePEGBase()); // ZERO the distance of original (*cjt).first->original()->setLifeLength(Lorentz5Distance()); (*cjt).first->original()->setVertex(LorentzPoint()); // if not from a matrix element correction if(cjt->first->perturbative()) { // register the shower particle as a // copy of the one from the hard process tParticleVector parents=init->parents(); for(unsigned int ix=0;ixabandonChild(init); (*cjt).first->original()->addChild(init); pstep->addDecayProduct(init); } // from a matrix element correction else { if(cjt->first->original()==_incoming.first|| cjt->first->original()==_incoming.second) { updateColour((*cjt).first->copy(),false); (*cjt).first->original()->parents()[0]-> addChild((*cjt).first->copy()); pstep->addDecayProduct((*cjt).first->copy()); (*cjt).first->copy()->addChild(init); pstep->addDecayProduct(init); } else { updateColour((*cjt).first->copy(),false); (*cjt).first->original()->addChild((*cjt).first->copy()); pstep->addDecayProduct((*cjt).first->copy()); (*cjt).first->copy()->addChild(init); pstep->addDecayProduct(init); } // ZERO the distance of copy ??? \todo change if add space-time (*cjt).first->copy()->setLifeLength(Lorentz5Distance()); (*cjt).first->copy()->setVertex(LorentzPoint()); } // copy so travels no distance init->setLifeLength(Lorentz5Distance()); init->setVertex(init->parents()[0]->decayVertex()); // sort out the colour updateColour(init,false); // insert shower products addFinalStateShower(init,pstep); } colourLines().clear(); } void ShowerTree::addFinalStateShower(PPtr p, StepPtr s) { // if endpoint assume doesn't travel if(p->children().empty()) { if(p->dataPtr()->stable()||ShowerHandler::currentHandler()->decaysInShower(p->id())) p->setLifeLength(Lorentz5Distance()); else { Energy mass = p->mass()!=ZERO ? p->mass() : p->dataPtr()->mass(); Length ctau = p->dataPtr()->generateLifeTime(mass, p->dataPtr()->width()); Lorentz5Distance lifeLength(ctau,p->momentum().vect()*(ctau/mass)); p->setLifeLength(lifeLength); } return; } // set the space-time distance else { p->setLifeLength(spaceTimeDistance(p)); } ParticleVector::const_iterator child; for(child=p->children().begin(); child != p->children().end(); ++child) { updateColour(*child,false); s->addDecayProduct(*child); (**child).setVertex(p->decayVertex()); addFinalStateShower(*child,s); } } void ShowerTree::addInitialStateShower(PPtr p, PPtr hadron, StepPtr s, bool addchildren) { // Each parton here should only have one parent if(!p->parents().empty()) { if(p->parents().size()!=1) throw Exception() << "Particle must only have one parent in ShowerTree" << "::addInitialStateShower" << Exception::runerror; // set the space-time distances if(addchildren) { p->setLifeLength(spaceTimeDistance(p)); p->setVertex(p->children()[0]->vertex()-p->lifeLength()); } else { p->setLifeLength(spaceTimeDistance(p)); p->setVertex(-p->lifeLength()); } // recurse addInitialStateShower(p->parents()[0],hadron,s); } else { hadron->addChild(p); s->addIntermediate(p); p->setVertex(p->children()[0]->vertex()); p->setLifeLength(Lorentz5Distance()); } updateColour(p,false); // if not adding children return if(!addchildren) return; // add children ParticleVector::const_iterator child; for(child = p->children().begin(); child != p->children().end(); ++child) { // if a final-state particle update the colour ShowerParticlePtr schild = dynamic_ptr_cast(*child); (**child).setVertex(p->decayVertex()); if(schild && schild->isFinalState()) updateColour(*child,false); // if there are grandchildren of p if(!(*child)->children().empty()) { // Add child as intermediate s->addIntermediate(*child); // If child is shower particle and final-state, add children if(schild && schild->isFinalState()) addFinalStateShower(schild,s); } else s->addDecayProduct(*child); } } void ShowerTree::update(PerturbativeProcessPtr newProcess) { // must be one incoming particle assert(_incomingLines.size()==1); colourLines().clear(); // copy the particles and isolate the colour vector original,copy; for(unsigned int ix=0;ixincoming().size();++ix) { original.push_back(newProcess->incoming()[ix].first); copy .push_back(new_ptr(Particle(*original.back()))); } for(unsigned int ix=0;ixoutgoing().size();++ix) { original.push_back(newProcess->outgoing()[ix].first); copy .push_back(new_ptr(Particle(*original.back()))); } // isolate the colour colourIsolate(original,copy); // make the new progenitor ShowerParticlePtr stemp=new_ptr(ShowerParticle(*copy[0],2,false)); fixColour(stemp); ShowerProgenitorPtr newprog=new_ptr(ShowerProgenitor(original[0],copy[0],stemp)); _incomingLines.clear(); _incomingLines.insert(make_pair(newprog,stemp)); // create the children assert(copy.size() == original.size()); for (unsigned int ix=newProcess->incoming().size();ix_treelinks.empty()) final = _parent->_treelinks[this].second; else final=_incomingLines.begin()->first->original(); // construct the map of colour lines PPtr copy=_incomingLines.begin()->first->copy(); mapColour(final,copy); // now this is the ONE instance of the particle which should have a life length // \todo change if space-time picture added // set the lifelength, need this so that still in right direction after // any ISR recoils Length ctau = copy->lifeTime(); Lorentz5Distance lifeLength(ctau,final->momentum().vect()*(ctau/final->mass())); final->setLifeLength(lifeLength); // initial-state radiation if(ISR&&!_incomingLines.begin()->first->progenitor()->children().empty()) { ShowerParticlePtr init=_incomingLines.begin()->first->progenitor(); updateColour(init,false); final->addChild(init); pstep->addDecayProduct(init); // just a copy doesn't travel init->setLifeLength(Lorentz5Distance()); init->setVertex(final->decayVertex()); // insert shower products addFinalStateShower(init,pstep); // sort out colour final=_incomingLines.begin()->second; colourLines().clear(); mapColour(final,copy); } // get the decaying particles // make the copy tColinePair cline=make_pair(copy->colourLine(),copy->antiColourLine()); updateColour(copy,false); // sort out sinks and sources if needed if(cline.first) { if(cline.first->sourceNeighbours().first) { copy->colourLine()->setSourceNeighbours(cline.first->sourceNeighbours().first, cline.first->sourceNeighbours().second); } else if (cline.first->sinkNeighbours().first) { copy->colourLine()->setSinkNeighbours(cline.first->sinkNeighbours().first, cline.first->sinkNeighbours().second); } } if(cline.second) { if(cline.second->sourceNeighbours().first) { copy->antiColourLine()->setSourceNeighbours(cline.second->sourceNeighbours().first, cline.second->sourceNeighbours().second); } else if (cline.second->sinkNeighbours().first) { copy->antiColourLine()->setSinkNeighbours(cline.second->sinkNeighbours().first, cline.second->sinkNeighbours().second); } } // copy of the one from the hard process tParticleVector dpar=copy->parents(); for(unsigned int ix=0;ixabandonChild(copy); final->addChild(copy); pstep->addDecayProduct(copy); // just a copy does not move copy->setLifeLength(Lorentz5Distance()); copy->setVertex(final->decayVertex()); // final-state radiation map::const_iterator cit; for(cit=outgoingLines().begin();cit!=outgoingLines().end();++cit) { ShowerParticlePtr init=cit->first->progenitor(); // ZERO the distance init->setLifeLength(Lorentz5Distance()); if(!init->thePEGBase()) throw Exception() << "Final-state particle must have a ThePEGBase" << " in ShowerTree::insertDecay()" << Exception::runerror; // if not from matrix element correction if(cit->first->perturbative()) { // add the child updateColour(cit->first->copy(),false); PPtr orig=cit->first->original(); orig->setLifeLength(Lorentz5Distance()); orig->setVertex(copy->decayVertex()); copy->addChild(orig); pstep->addDecayProduct(orig); orig->addChild(cit->first->copy()); pstep->addDecayProduct(cit->first->copy()); // register the shower particle as a // copy of the one from the hard process tParticleVector parents=init->parents(); for(unsigned int ix=0;ixabandonChild(init);} (*cit).first->copy()->addChild(init); pstep->addDecayProduct(init); updateColour(init,false); } // from a matrix element correction else { if(copy->children().end()== find(copy->children().begin(),copy->children().end(), cit->first->original())) { updateColour(cit->first->original(),false); copy->addChild(cit->first->original()); pstep->addDecayProduct(cit->first->original()); } updateColour(cit->first->copy(),false); cit->first->original()->addChild(cit->first->copy()); pstep->addDecayProduct(cit->first->copy()); // register the shower particle as a // copy of the one from the hard process tParticleVector parents=init->parents(); for(unsigned int ix=0;ixabandonChild(init);} (*cit).first->copy()->addChild(init); pstep->addDecayProduct(init); updateColour(init,false); } // ZERO the distances as just copies cit->first->copy()->setLifeLength(Lorentz5Distance()); init->setLifeLength(Lorentz5Distance()); cit->first->copy()->setVertex(copy->decayVertex()); init->setVertex(copy->decayVertex()); // insert shower products addFinalStateShower(init,pstep); } colourLines().clear(); } void ShowerTree::clear() { // reset the has showered flag _hasShowered=false; // clear the colour map colourLines().clear(); map::const_iterator cit; map::const_iterator cjt; // abandon the children of the outgoing particles for(cit=_outgoingLines.begin();cit!=_outgoingLines.end();++cit) { ShowerParticlePtr orig=cit->first->progenitor(); orig->set5Momentum(cit->first->copy()->momentum()); ParticleVector children=orig->children(); for(unsigned int ix=0;ixabandonChild(children[ix]); _outgoingLines[cit->first]=orig; cit->first->hasEmitted(false); cit->first->reconstructed(ShowerProgenitor::notReconstructed); } // forward products _forward.clear(); for(cit=_outgoingLines.begin();cit!=_outgoingLines.end();++cit) _forward.insert(cit->first->progenitor()); // if a decay if(!_wasHard) { ShowerParticlePtr orig=_incomingLines.begin()->first->progenitor(); orig->set5Momentum(_incomingLines.begin()->first->copy()->momentum()); ParticleVector children=orig->children(); for(unsigned int ix=0;ixabandonChild(children[ix]); _incomingLines.begin()->first->reconstructed(ShowerProgenitor::notReconstructed); } // if a hard process else { for(cjt=_incomingLines.begin();cjt!=_incomingLines.end();++cjt) { tPPtr parent = cjt->first->original()->parents().empty() ? tPPtr() : cjt->first->original()->parents()[0]; ShowerParticlePtr temp= new_ptr(ShowerParticle(*cjt->first->copy(), cjt->first->progenitor()->perturbative(), cjt->first->progenitor()->isFinalState())); fixColour(temp); temp->x(cjt->first->progenitor()->x()); cjt->first->hasEmitted(false); if(!(cjt->first->progenitor()==cjt->second)&&cjt->second&&parent) parent->abandonChild(cjt->second); cjt->first->progenitor(temp); _incomingLines[cjt->first]=temp; cjt->first->reconstructed(ShowerProgenitor::notReconstructed); } } - // reset the particles at the end of the shower - _backward.clear(); - // if hard process backward products - if(_wasHard) - for(cjt=_incomingLines.begin();cjt!=_incomingLines.end();++cjt) - _backward.insert(cjt->first->progenitor()); clearTransforms(); } void ShowerTree::resetShowerProducts() { map::const_iterator cit; map::const_iterator cjt; - _backward.clear(); _forward.clear(); - for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit) - _backward.insert(cit->second); for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt) _forward.insert(cjt->second); } void ShowerTree::updateAfterShower(ShowerDecayMap & decay) { // update the links map::const_iterator mit; map >::iterator tit; for(tit=_treelinks.begin();tit!=_treelinks.end();++tit) { if(tit->second.first) { mit=_outgoingLines.find(tit->second.first); if(mit!=_outgoingLines.end()) tit->second.second=mit->second; } } // get the particles coming from those in the hard process set hard; for(mit=_outgoingLines.begin();mit!=_outgoingLines.end();++mit) hard.insert(mit->second); // find the shower particles which should be decayed in the // shower but didn't come from the hard process set::const_iterator cit; + + // TODO construct _forward here? + for(cit=_forward.begin();cit!=_forward.end();++cit) { if((ShowerHandler::currentHandler()->decaysInShower((**cit).id())&& !(**cit).dataPtr()->stable()) && hard.find(*cit)==hard.end()) { PerturbativeProcessPtr newProcess(new_ptr(PerturbativeProcess())); newProcess->incoming().push_back(make_pair(*cit,PerturbativeProcessPtr())); ShowerTreePtr newtree=new_ptr(ShowerTree(newProcess)); newtree->setParents(); newtree->_parent=this; Energy width=(**cit).dataPtr()->generateWidth((**cit).mass()); decay.insert(make_pair(width,newtree)); _treelinks.insert(make_pair(newtree, make_pair(tShowerProgenitorPtr(),*cit))); } } } void ShowerTree::addFinalStateBranching(ShowerParticlePtr parent, const ShowerParticleVector & children) { assert(children.size()==2); _forward.erase(parent); for(unsigned int ix=0; ix >::const_iterator tit; for(tit=_treelinks.begin();tit!=_treelinks.end();++tit) tit->first->_parent=this; } vector ShowerTree::extractProgenitors() { // extract the particles from the ShowerTree map::const_iterator mit; vector ShowerHardJets; for(mit=incomingLines().begin();mit!=incomingLines().end();++mit) ShowerHardJets.push_back((*mit).first); map::const_iterator mjt; for(mjt=outgoingLines().begin();mjt!=outgoingLines().end();++mjt) ShowerHardJets.push_back((*mjt).first); return ShowerHardJets; } void ShowerTree::transform(const LorentzRotation & boost, bool applyNow) { if(applyNow) { // now boost all the particles map::const_iterator cit; // incoming for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit) { cit->first->progenitor()->deepTransform(boost); cit->first->copy()->deepTransform(boost); } // outgoing map::const_iterator cjt; for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt) { cjt->first->progenitor()->deepTransform(boost); cjt->first->copy()->deepTransform(boost); } } else { _transforms.transform(boost); } // child trees for(map >::const_iterator tit=_treelinks.begin();tit!=_treelinks.end();++tit) tit->first->transform(boost,applyNow); } void ShowerTree::applyTransforms() { // now boost all the particles map::const_iterator cit; // incoming for(cit=_incomingLines.begin();cit!=_incomingLines.end();++cit) { cit->first->progenitor()->deepTransform(_transforms); cit->first->copy()->deepTransform(_transforms); } // outgoing map::const_iterator cjt; for(cjt=_outgoingLines.begin();cjt!=_outgoingLines.end();++cjt) { cjt->first->progenitor()->deepTransform(_transforms); cjt->first->copy()->deepTransform(_transforms); } // child trees for(map >::const_iterator tit=_treelinks.begin();tit!=_treelinks.end();++tit) tit->first->applyTransforms(); _transforms = LorentzRotation(); } void ShowerTree::clearTransforms() { _transforms = LorentzRotation(); // // child trees // for(map >::const_iterator // tit=_treelinks.begin();tit!=_treelinks.end();++tit) // tit->first->clearTransforms(); } void ShowerTree::fixColour(tShowerParticlePtr part) { if(!part->colourInfo()->colourLines().empty()) { if(part->colourInfo()->colourLines().size()==1) { ColinePtr line=part->colourLine(); if(line) { line->removeColoured(part); line->addColoured(part); } } else { Ptr::pointer colour = dynamic_ptr_cast::pointer>(part->colourInfo()); vector lines = colour->colourLines(); for(unsigned int ix=0;ix(lines[ix]); if(line) { line->removeColoured(part); line->addColoured(part); } } } } if(!part->colourInfo()->antiColourLines().empty()) { if(part->colourInfo()->antiColourLines().size()==1) { ColinePtr line=part->antiColourLine(); if(line) { line->removeAntiColoured(part); line->addAntiColoured(part); } } else { Ptr::pointer colour = dynamic_ptr_cast::pointer>(part->colourInfo()); vector lines = colour->antiColourLines(); for(unsigned int ix=0;ix(lines[ix]); if(line) { line->removeAntiColoured(part); line->addAntiColoured(part); } } } } } vector ShowerTree::extractProgenitorParticles() { vector particles; // incoming particles for(map::const_iterator cit=incomingLines().begin(); cit!=incomingLines().end();++cit) particles.push_back(cit->first->progenitor()); // outgoing particles for(map::const_iterator cjt=outgoingLines().begin(); cjt!=outgoingLines().end();++cjt) particles.push_back(cjt->first->progenitor()); return particles; } Lorentz5Distance ShowerTree::spaceTimeDistance(tPPtr particle) { if(!_spaceTime) return Lorentz5Distance(); Energy2 q2 = particle->mass() > ZERO ? sqr(particle->mass()) : -sqr(particle->mass()); const tcPDPtr data = particle->dataPtr(); // calculate width imposing min value Energy conMass = max(data->constituentMass(),200*MeV); Energy width = max(data->generateWidth(particle->mass()),_vmin2/conMass); // offshellness Energy2 offShell = q2-sqr(data->constituentMass()); if(abs(offShell)<1e-10*GeV2) offShell = ZERO; InvEnergy2 fact = UseRandom::rndExp(1./sqrt((sqr(offShell)+sqr(q2*width/conMass)))); Lorentz5Distance output = (hbarc*fact)*particle->momentum(); return output; } void ShowerTree::constructTrees(ShowerTreePtr & hardTree, ShowerDecayMap & decayTrees, PerturbativeProcessPtr hard, DecayProcessMap decay) { map treeMap; // convert the hard process if(hardTree) { if(hardTree->isDecay()) hardTree->update(hard); } else { hardTree = new_ptr(ShowerTree(hard)); } treeMap.insert(make_pair(hard,hardTree)); for(DecayProcessMap::const_iterator it=decay.begin();it!=decay.end();++it) { ShowerTreePtr newTree = new_ptr(ShowerTree(it->second)); treeMap.insert(make_pair(it->second,newTree)); decayTrees.insert(make_pair(it->first,newTree)); } // set up the links between the trees for(map::const_iterator it=treeMap.begin(); it!=treeMap.end();++it) { // links to daughter trees map::const_iterator mit; for(mit=it->second->_outgoingLines.begin(); mit!=it->second->_outgoingLines.end();++mit) { unsigned int iloc=0; for(;ilocfirst->outgoing().size();++iloc) { if(it->first->outgoing()[iloc].first==mit->first->original()) break; } if(it->first->outgoing()[iloc].second) it->second->_treelinks.insert(make_pair(treeMap[it->first->outgoing()[iloc].second], make_pair(mit->first,mit->first->progenitor()))); } // links to parent trees if(it->first->incoming()[0].second) { it->second->_parent = treeMap[it->first->incoming()[0].second]; } } } namespace { Lorentz5Momentum sumMomenta(tPPtr particle) { if(particle->children().empty()) return particle->momentum(); Lorentz5Momentum output; for(unsigned int ix=0;ixchildren().size();++ix) { output += sumMomenta(particle->children()[ix]); } return output; } } void ShowerTree::checkMomenta() { vector pin; for(map::const_iterator it=_incomingLines.begin(); it!=_incomingLines.end();++it) { if(isDecay()) { tPPtr parent = it->first->progenitor(); pin.push_back(parent->momentum()); while(!parent->children().empty()) { pin.back() -= sumMomenta(parent->children()[1]); parent = parent->children()[0]; } } else { tPPtr parent = it->second; pin.push_back(parent->momentum()); while(!parent->children().empty()&&parent->children().size()==2) { pin.back() -= sumMomenta(parent->children()[1]); parent = parent->children()[0]; if(parent==it->first->progenitor()) break; } } } vector pout; for(map::const_iterator it= _outgoingLines.begin(); it!=_outgoingLines.end();++it) { pout.push_back(sumMomenta(it->first->progenitor())); } Lorentz5Momentum psum; for(unsigned int ix=0;ix< pin.size();++ix) { CurrentGenerator::log() << "pin " << ix << pin[ix]/GeV << "\n"; psum +=pin[ix]; } CurrentGenerator::log() << "In total " << psum/GeV << " " << psum.m()/GeV << "\n"; Lorentz5Momentum psum2; for(unsigned int ix=0;ix< pout.size();++ix) { CurrentGenerator::log() << "pout " << ix << pout[ix]/GeV << "\n"; psum2 +=pout[ix]; } CurrentGenerator::log() << "Out total " << psum2/GeV << " " << psum2.m()/GeV << "\n"; CurrentGenerator::log() << "Total " << (psum-psum2)/GeV << "\n"; } RealEmissionProcessPtr ShowerTree::perturbativeProcess() { RealEmissionProcessPtr output(new_ptr(RealEmissionProcess())); // add the incoming particles unsigned int ix=0; pair x; for(map::const_iterator it=_incomingLines.begin(); it!=_incomingLines.end();++it) { output->bornIncoming().push_back(it->first->progenitor()); if(!it->first->original()->parents().empty()) output->hadrons().push_back(it->first->original()->parents()[0]); else output->hadrons().push_back(it->first->progenitor()); if(ix==0) x.first = it->second->x(); else x.second = it->second->x(); ++ix; } output->x(x); // add the outgoing particles for(map::const_iterator it= _outgoingLines.begin(); it!=_outgoingLines.end();++it) { output->bornOutgoing().push_back(it->first->progenitor()); } return output; } void ShowerTree::setVetoes(const map & pTs, unsigned int type) { if(type==1||type==3) { for(map::const_iterator it=_incomingLines.begin(); it!=_incomingLines.end();++it) { for(map::const_iterator jt=pTs.begin();jt!=pTs.end();++jt) it->first->maximumpT(jt->second,jt->first); } } if(type==2||type==3) { for(map::const_iterator it= _outgoingLines.begin(); it!=_outgoingLines.end();++it) { for(map::const_iterator jt=pTs.begin();jt!=pTs.end();++jt) it->first->maximumpT(jt->second,jt->first); } } } diff --git a/Shower/QTilde/Base/ShowerTree.h b/Shower/QTilde/Base/ShowerTree.h --- a/Shower/QTilde/Base/ShowerTree.h +++ b/Shower/QTilde/Base/ShowerTree.h @@ -1,414 +1,388 @@ // -*- C++ -*- // // ShowerTree.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerTree_H #define HERWIG_ShowerTree_H #include "ThePEG/Config/ThePEG.h" #include "Herwig/Shower/ShowerHandler.fh" #include "Herwig/Shower/PerturbativeProcess.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Shower/ShowerEventRecord.h" #include "Herwig/Shower/QTilde/ShowerConfig.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h" #include "ThePEG/EventRecord/Step.h" #include #include "ShowerTree.fh" namespace Herwig { /** * Typedef for map of ShowerTrees for decays */ typedef multimap > ShowerDecayMap; using namespace ThePEG; /** \ingroup Shower * * The ShowerTree class stores the basic information needed for * each hard interaction, either a scattering process or decay, which * needs to be showered. * */ class ShowerTree : public ShowerEventRecord { friend class QTildeShowerHandler; public: /** * Constructor from a perturbative process * @param process The perturbative process */ ShowerTree(PerturbativeProcessPtr process); /** * Calculate the space-time displacement * @param particle The particle for which to calculate the displacement */ static Lorentz5Distance spaceTimeDistance(tPPtr particle); /** * Construct the trees from the hard process * @param hardTree The output ShowerTree for the hard process * @param decayTrees The output ShowerTrees for any decays. * @param hard The output ShowerTree for the hard process * @param decay The output ShowerTrees for any decays. */ static void constructTrees(ShowerTreePtr & hardTree, ShowerDecayMap & decayTrees, PerturbativeProcessPtr hard, DecayProcessMap decay); public: /** * Insert the tree into the event record * @param pstep The step into which the particles should be inserted * @param ISR Whether or not ISR is switched on * @param FSR Whether or not FSR is switched on */ void fillEventRecord(StepPtr pstep,bool ISR,bool FSR) { if(_wasHard) insertHard (pstep,ISR,FSR); else insertDecay(pstep,ISR,FSR); } /** * Set the parent tree to this tree for trees which come from this one. * This needs to be run after the constructor. */ void setParents(); /** * Access methods for the type of interaction */ //@{ /** * Whether or not this is a scattering process */ bool isHard() const { return _wasHard; } /** * Whether or not this is a decay. */ bool isDecay() const { return !_wasHard; } //@} /** - * Flags relating to the application of the hard matrix element correction - */ - //@{ - /** - * Was the hard matrix element correction applied - */ - bool hardMatrixElementCorrection() const { return _hardMECorrection; } - - /** - * Set whether or not the hard matrix element correction was applied - */ - void hardMatrixElementCorrection(bool in) { _hardMECorrection=in; } - //@} - - /** * Get the incoming shower particles */ map & incomingLines() { return _incomingLines; } /** * Get the outgoing shower particles */ map & outgoingLines() { return _outgoingLines; } /** * Update the shower product for a final-state particle */ void updateFinalStateShowerProduct(ShowerProgenitorPtr progenitor, ShowerParticlePtr parent, const ShowerParticleVector & children); /** * Update the shower product for an initial-state particle */ void updateInitialStateShowerProduct(ShowerProgenitorPtr progenitor, ShowerParticlePtr newParent); /** * Get the current final shower product for a final-state particle */ tShowerParticlePtr getFinalStateShowerProduct(ShowerProgenitorPtr progenitor) { return _outgoingLines.find(progenitor)==_outgoingLines.end() ? tShowerParticlePtr() : _outgoingLines[progenitor]; } /** * Add a final-state branching. This method removes the parent of the branching * from the list of particles at the end of the shower and inserts the children * @param parent The parent for the branching * @param children The outgoing particles in the branching */ void addFinalStateBranching(ShowerParticlePtr parent, const ShowerParticleVector & children); /** * Add an initial-state branching. This method removes the oldParent of the * branching and inserts the result of the backward evolution and the * outgoing particle into the relevant lists. * @param oldParent The particle being backward evolved * @param newParent The initial-state particle resulting from the backward evolution * @param otherChild The final-state particle produced in the evolution. */ void addInitialStateBranching(ShowerParticlePtr oldParent, ShowerParticlePtr newParent, ShowerParticlePtr otherChild); // /** // * Member called at the end of the shower of a tree to perform a number of // * updates. // * @param decay The map of widths and ShowerTrees for the decays so that // * any unstable decay products can be added. // */ void updateAfterShower(ShowerDecayMap & decay); /** * Access and set the flag for whether this tree has been showered */ //@{ /** * Access the flag */ bool hasShowered() const { return _hasShowered; } /** * Set the flag */ void hasShowered(bool in) { _hasShowered=in; } //@} /** * Access the parent tree */ ShowerTreePtr parent() const { return _parent; } /** * Clear all the shower products so that the event can be reshowered * if the first attempt fail */ void clear(); /** * Reset the particles resulting from the shower to those which started * the shower */ void resetShowerProducts(); /** * Set maximum Emission scales */ void setVetoes(const map & pTs, unsigned int type); /** * Extract the progenitors for the reconstruction */ vector extractProgenitors(); /** * Access to the outgoing particles */ const set & forwardParticles() const { return _forward; } /** * Map of particles in this Tree which are the initial particles in other * trees */ const map > & treelinks() const {return _treelinks;} /** * Update the link between shower particle and tree */ void updateLink(tShowerTreePtr tree, pair in) { _treelinks[tree] = in; } /** * Transform the tree */ void transform(const LorentzRotation & rot, bool applyNow); /** * Apply any postphoned transformations */ void applyTransforms(); /** * Clear any postphoned transformations */ void clearTransforms(); /** * Transform which needs to be applied */ const LorentzRotation & transform() {return _transforms;} /** * Get all the progenitors */ vector extractProgenitorParticles(); /** * Check the momentum conservation in the tree */ void checkMomenta(); /** * Update tree after the parent has been decayed. */ void update(PerturbativeProcessPtr newProcess); /** * The perturbative process */ RealEmissionProcessPtr perturbativeProcess(); protected: /** * Functions to add the shower to the event record. */ //@{ /** * Insert a hard process * @param pstep The step into which the particles should be inserted * @param ISR Whether or not ISR is switched on * @param FSR Whether or not FSR is switched on */ void insertHard(StepPtr pstep,bool ISR,bool FSR); /** * Insert a decay process * @param pstep The step into which the particles should be inserted * @param ISR Whether or not ISR is switched on * @param FSR Whether or not FSR is switched on */ void insertDecay(StepPtr pstep,bool ISR,bool FSR); /** * Recursively add the final-state shower from the particle to the event record. * @param particle The final-state particle * @param step The step */ void addFinalStateShower(PPtr particle, StepPtr step); /** * Add the initial-state shwoer from the particle to the step * @param particle The final-state particle * @param hadron The incoming hadron * @param step The step * @param addchildren Add the children of the particle */ void addInitialStateShower(PPtr particle, PPtr hadron, StepPtr step, bool addchildren=true); //@} /** * After the creatation of a ShowerParticle make sure it is properly attached * to its ColourLine * @param part The particle */ void fixColour(tShowerParticlePtr part); private: - /** * Incoming partons for the hard process */ PPair _incoming; /** * The incoming ShowerParticles connected to the interaction * as the index of a map with the particle the shower backward evolves * them to as the value */ map _incomingLines; /** * The outgoing ShowerParticles connected to the interaction * as the index of a map with the particle the shower * evolves them to as the value */ map _outgoingLines; /** * The outgoing ShowerParticles at the end of the final-state shower */ set _forward; /** - * The incoming ShowerParticles at the end of the initial-state shower - */ - set _backward; - - /** - * Was the hard matrix element correction applied - */ - bool _hardMECorrection; - - /** * Was this a scattering process or a decay */ bool _wasHard; /** * Map of particles in this Tree which are the initial particles in other * trees */ map > _treelinks; /** * The parent tree */ tShowerTreePtr _parent; /** * Has this tree showered */ bool _hasShowered; /** * The transforms which still need to be applied */ LorentzRotation _transforms; private: /** * Whether or not to include space-time distances */ static bool _spaceTime; /** * Minimum virtuality for the space-time model */ static Energy2 _vmin2; }; } #endif diff --git a/Shower/QTilde/Couplings/ShowerAlphaQCD.cc b/Shower/QTilde/Couplings/ShowerAlphaQCD.cc --- a/Shower/QTilde/Couplings/ShowerAlphaQCD.cc +++ b/Shower/QTilde/Couplings/ShowerAlphaQCD.cc @@ -1,453 +1,383 @@ // -*- C++ -*- // // ShowerAlphaQCD.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 ShowerAlphaQCD class. // #include "ShowerAlphaQCD.h" #include "ThePEG/PDT/ParticleData.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Command.h" +#include "ThePEG/Interface/Deleted.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/Throw.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Config/Constants.h" +#include "Herwig/Utilities/AlphaS.h" using namespace Herwig; +using Herwig::Math::alphaS; +using Herwig::Math::derivativeAlphaS; DescribeClass describeShowerAlphaQCD("Herwig::ShowerAlphaQCD","HwShower.so"); IBPtr ShowerAlphaQCD::clone() const { return new_ptr(*this); } IBPtr ShowerAlphaQCD::fullclone() const { return new_ptr(*this); } void ShowerAlphaQCD::persistentOutput(PersistentOStream & os) const { - os << _asType << _asMaxNP << ounit(_qmin,GeV) << _nloop << _lambdaopt << _thresopt - << ounit(_lambdain,GeV) << _alphain << _inopt - << _tolerance << _maxtry << _alphamin + os << _asType << _asMaxNP << ounit(_qmin,GeV) << _nloop << _thresopt + << _alphain << _tolerance << _maxtry << _alphamin << ounit(_thresholds,GeV) << ounit(_lambda,GeV) << _val0 << ounit(_optInputScale,GeV) << ounit(_quarkMasses,GeV); } void ShowerAlphaQCD::persistentInput(PersistentIStream & is, int) { - is >> _asType >> _asMaxNP >> iunit(_qmin,GeV) >> _nloop >> _lambdaopt >> _thresopt - >> iunit(_lambdain,GeV) >> _alphain >> _inopt - >> _tolerance >> _maxtry >> _alphamin + is >> _asType >> _asMaxNP >> iunit(_qmin,GeV) >> _nloop >> _thresopt + >> _alphain >> _tolerance >> _maxtry >> _alphamin >> iunit(_thresholds,GeV) >> iunit(_lambda,GeV) >> _val0 >> iunit(_optInputScale,GeV) >> iunit(_quarkMasses,GeV); } void ShowerAlphaQCD::Init() { static ClassDocumentation documentation ("This (concrete) class describes the QCD alpha running."); static Switch intAsType ("NPAlphaS", "Behaviour of AlphaS in the NP region", &ShowerAlphaQCD::_asType, 1, false, false); static SwitchOption intAsTypeZero (intAsType, "Zero","zero below Q_min", 1); static SwitchOption intAsTypeConst (intAsType, "Const","const as(qmin) below Q_min", 2); static SwitchOption intAsTypeLin (intAsType, "Linear","growing linearly below Q_min", 3); static SwitchOption intAsTypeQuad (intAsType, "Quadratic","growing quadratically below Q_min", 4); static SwitchOption intAsTypeExx1 (intAsType, "Exx1", "quadratic from AlphaMaxNP down to as(Q_min)", 5); static SwitchOption intAsTypeExx2 (intAsType, "Exx2", "const = AlphaMaxNP below Q_min", 6); // default such that as(qmin) = 1 in the current parametrization. // min = Lambda3 static Parameter intQmin ("Qmin", "Q < Qmin is treated with NP parametrization as of (unit [GeV])," " if negative it is solved for at initialisation such that alpha_S(Qmin)=AlphaMaxNP", &ShowerAlphaQCD::_qmin, GeV, 0.630882*GeV, 0.330445*GeV, 100.0*GeV,false,false,false); static Parameter interfaceAlphaMaxNP ("AlphaMaxNP", "Max value of alpha in NP region, only relevant if NPAlphaS = 5,6", &ShowerAlphaQCD::_asMaxNP, 1.0, 0., 100.0, false, false, Interface::limited); static Parameter interfaceNumberOfLoops ("NumberOfLoops", "The number of loops to use in the alpha_S calculation", &ShowerAlphaQCD::_nloop, 3, 1, 3, false, false, Interface::limited); - static Switch interfaceLambdaOption - ("LambdaOption", - "Option for the calculation of the Lambda used in the simulation from the input" - " Lambda_MSbar", - &ShowerAlphaQCD::_lambdaopt, false, false, false); - static SwitchOption interfaceLambdaOptionfalse - (interfaceLambdaOption, - "Same", - "Use the same value", - false); - static SwitchOption interfaceLambdaOptionConvert - (interfaceLambdaOption, - "Convert", - "Use the conversion to the Herwig scheme from NPB349, 635", - true); + static Deleted delInputOption + ("InputOption", "The old default (1) is now the only choice"); - static Parameter interfaceLambdaQCD - ("LambdaQCD", - "Input value of Lambda_MSBar", - &ShowerAlphaQCD::_lambdain, MeV, 0.208364*GeV, 100.0*MeV, 500.0*MeV, - false, false, Interface::limited); + static Deleted delAlphaMZ + ("AlphaMZ", "Renamed to AlphaIn."); static Parameter interfaceAlphaMZ - ("AlphaMZ", - "The input value of the strong coupling at the Z mass ", + ("AlphaIn", + "The input value of the strong coupling at the chosen InputScale (default: MZ)", &ShowerAlphaQCD::_alphain, 0.118, 0.1, 0.2, false, false, Interface::limited); - static Switch interfaceInputOption - ("InputOption", - "Option for inputing the initial value of the coupling", - &ShowerAlphaQCD::_inopt, true, false, false); - static SwitchOption interfaceInputOptionAlphaMZ - (interfaceInputOption, - "AlphaMZ", - "Use the value of alpha at MZ to calculate the coupling", - true); - static SwitchOption interfaceInputOptionLambdaQCD - (interfaceInputOption, - "LambdaQCD", - "Use the input value of Lambda to calculate the coupling", - false); - static Parameter interfaceTolerance ("Tolerance", "The tolerance for discontinuities in alphaS at thresholds.", &ShowerAlphaQCD::_tolerance, 1e-10, 1e-20, 1e-4, false, false, Interface::limited); static Parameter interfaceMaximumIterations ("MaximumIterations", "The maximum number of iterations for the Newton-Raphson method to converge.", &ShowerAlphaQCD::_maxtry, 100, 10, 1000, false, false, Interface::limited); static Switch interfaceThresholdOption ("ThresholdOption", "Whether to use the consistuent or normal masses for the thresholds", &ShowerAlphaQCD::_thresopt, true, false, false); static SwitchOption interfaceThresholdOptionCurrent (interfaceThresholdOption, "Current", "Use the current masses", true); static SwitchOption interfaceThresholdOptionConstituent (interfaceThresholdOption, "Constituent", "Use the constitent masses.", false); static Command interfaceValue ("Value", "", &ShowerAlphaQCD::value, false); static Command interfacecheck ("check", "check", &ShowerAlphaQCD::check, false); + + + static Parameter interfaceInputScale ("InputScale", "An optional input scale. MZ will be used if not set.", - &ShowerAlphaQCD::_optInputScale, GeV, ZERO, ZERO, 0*GeV, + &ShowerAlphaQCD::_optInputScale, GeV, 91.1876_GeV, ZERO, 0*GeV, false, false, Interface::lowerlim); + + + static ParVector interfaceQuarkMasses ("QuarkMasses", "The quark masses to be used instead of the masses set in the particle data.", &ShowerAlphaQCD::_quarkMasses, GeV, -1, 0.0*GeV, 0.0*GeV, 0*GeV, false, false, Interface::lowerlim); } void ShowerAlphaQCD::doinit() { ShowerAlpha::doinit(); // calculate the value of 5-flavour lambda // evaluate the initial // value of Lambda from alphas if needed using Newton-Raphson - if(_inopt) { - _lambda[2]=computeLambda(_optInputScale == ZERO ? - getParticleData(ParticleID::Z0)->mass() : - _optInputScale, - _alphain,5); - } - // otherwise it was an input parameter - else{_lambda[2]=_lambdain;} - // convert lambda to the Monte Carlo scheme if needed - using Constants::pi; - if(_lambdaopt) _lambda[2] *=exp(0.5*(67.-3.*sqr(pi)-50./3.)/23.)/sqrt(2.); + _lambda[2]=computeLambda(_optInputScale,_alphain,5); + // compute the threshold matching // top threshold for(int ix=1;ix<4;++ix) { if ( _quarkMasses.empty() ) { if(_thresopt) _thresholds[ix]=getParticleData(ix+3)->mass(); else _thresholds[ix]=getParticleData(ix+3)->constituentMass(); } else { // starting at zero rather than one, cf the other alphas's _thresholds[ix] = _quarkMasses[ix+2]; } } // compute 6 flavour lambda by matching at top mass using Newton Raphson - _lambda[3]=computeLambda(_thresholds[3],alphaS(_thresholds[3],_lambda[2],5),6); + _lambda[3]=computeLambda(_thresholds[3],alphaS(_thresholds[3],_lambda[2],5,_nloop),6); // bottom threshold // compute 4 flavour lambda by matching at bottom mass using Newton Raphson - _lambda[1]=computeLambda(_thresholds[2],alphaS(_thresholds[2],_lambda[2],5),4); + _lambda[1]=computeLambda(_thresholds[2],alphaS(_thresholds[2],_lambda[2],5,_nloop),4); // charm threshold // compute 3 flavour lambda by matching at charm mass using Newton Raphson - _lambda[0]=computeLambda(_thresholds[1],alphaS(_thresholds[1],_lambda[1],4),3); + _lambda[0]=computeLambda(_thresholds[1],alphaS(_thresholds[1],_lambda[1],4,_nloop),3); // if qmin less than zero solve for alphaS(_qmin) = 1. if(_qmin() << "The value of Qmin is less than Lambda_3 in" << " ShowerAlphaQCD::doinit " << Exception::abortnow; Energy high = 10*GeV; while (value(sqr(high))>_asMaxNP) high *=2.; double as; do { _qmin = 0.5*(low+high); as = value(sqr(_qmin)); if(_asMaxNP>as) high = _qmin; else if(_asMaxNP _tolerance ); } // final threshold is qmin _thresholds[0]=_qmin; // value of alphaS at threshold pair nflam = getLamNfTwoLoop(_qmin); - _val0 = alphaS(_qmin, nflam.second, nflam.first); + _val0 = alphaS(_qmin, nflam.second, nflam.first, _nloop); // compute the maximum value of as if ( _asType < 5 ) _alphamin = _val0; else _alphamin = max(_asMaxNP, _val0); // check consistency lambda_3 < qmin if(_lambda[0]>_qmin) Throw() << "The value of Qmin is less than Lambda_3 in" << " ShowerAlphaQCD::doinit " << Exception::abortnow; } string ShowerAlphaQCD::check(string args) { doinit(); istringstream argin(args); double Q_low, Q_high; long n_steps; argin >> Q_low >> Q_high >> n_steps; string fname; argin >> fname; Repository::clog() << "checking alpha_s in range [" << Q_low << "," << Q_high << "] GeV in " << n_steps << " steps.\nResults are written to " << fname << "\n"; double step_width = (Q_high-Q_low)/n_steps; ofstream out (fname.c_str()); for (long k = 0; k <= n_steps; ++k) { Energy Q = Q_low*GeV + k*step_width*GeV; out << (Q/GeV) << " " << value(Q*Q) << "\n"; } return "alpha_s check finished"; } double ShowerAlphaQCD::value(const Energy2 scale) const { Energy q = scaleFactor()*sqrt(scale); double val(0.); // normal case if (q >= _qmin) { pair nflam = getLamNfTwoLoop(q); - val = alphaS(q, nflam.second, nflam.first); + val = alphaS(q, nflam.second, nflam.first, _nloop); } // special handling if the scale is less than Qmin else { switch (_asType) { case 1: // flat, zero; the default type with no NP effects. val = 0.; break; case 2: // flat, non-zero alpha_s = alpha_s(q2min). val = _val0; break; case 3: // linear in q val = _val0*q/_qmin; break; case 4: // quadratic in q val = _val0*sqr(q/_qmin); break; case 5: // quadratic in q, starting off at asMaxNP, ending on as(qmin) val = (_val0 - _asMaxNP)*sqr(q/_qmin) + _asMaxNP; break; case 6: // just asMaxNP and constant val = _asMaxNP; break; } } return val; } double ShowerAlphaQCD::overestimateValue() const { return _alphamin; } double ShowerAlphaQCD::ratio(const Energy2 scale, double factor) const { Energy q = scaleFactor()*factor*sqrt(scale); double val(0.); // normal case if (q >= _qmin) { pair nflam = getLamNfTwoLoop(q); - val = alphaS(q, nflam.second, nflam.first); + val = alphaS(q, nflam.second, nflam.first, _nloop); } // special handling if the scale is less than Qmin else { switch (_asType) { case 1: // flat, zero; the default type with no NP effects. val = 0.; break; case 2: // flat, non-zero alpha_s = alpha_s(q2min). val = _val0; break; case 3: // linear in q val = _val0*q/_qmin; break; case 4: // quadratic in q val = _val0*sqr(q/_qmin); break; case 5: // quadratic in q, starting off at asMaxNP, ending on as(qmin) val = (_val0 - _asMaxNP)*sqr(q/_qmin) + _asMaxNP; break; case 6: // just asMaxNP and constant val = _asMaxNP; break; } } // denominator return val/_alphamin; } string ShowerAlphaQCD::value (string scale) { istringstream readscale(scale); double inScale; readscale >> inScale; Energy theScale = inScale * GeV; initialize(); ostringstream showvalue (""); showvalue << "alpha_s (" << theScale/GeV << " GeV) = " << value (sqr(theScale)); return showvalue.str(); } pair ShowerAlphaQCD::getLamNfTwoLoop(Energy q) const { short nf = 6; // get lambda and nf according to the thresholds if (q < _thresholds[1]) nf = 3; else if (q < _thresholds[2]) nf = 4; else if (q < _thresholds[3]) nf = 5; return pair(nf, _lambda[nf-3]); } Energy ShowerAlphaQCD::computeLambda(Energy match, double alpha, unsigned int nflav) const { Energy lamtest=200.0*MeV; double xtest; unsigned int ntry=0; do { ++ntry; xtest = log(sqr(match/lamtest)); - xtest += (alpha-alphaS(match,lamtest,nflav))/derivativealphaS(match,lamtest,nflav); + xtest += (alpha-alphaS(match,lamtest,nflav,_nloop))/derivativeAlphaS(match,lamtest,nflav,_nloop); Energy newLambda = match/exp(0.5*xtest); lamtest = newLambda _tolerance && ntry < _maxtry); + while(abs(alpha-alphaS(match,lamtest,nflav,_nloop)) > _tolerance && ntry < _maxtry); return lamtest; } - -double ShowerAlphaQCD::derivativealphaS(Energy q, Energy lam, int nf) const { - using Constants::pi; - double lx = log(sqr(q/lam)); - double b0 = 11. - 2./3.*nf; - double b1 = 51. - 19./3.*nf; - double b2 = 2857. - 5033./9.*nf + 325./27.*sqr(nf); - if(_nloop==1) - return -4.*pi/(b0*sqr(lx)); - else if(_nloop==2) - return -4.*pi/(b0*sqr(lx))*(1.+2.*b1/sqr(b0)/lx*(1.-2.*log(lx))); - else - return -4.*pi/(b0*sqr(lx))* - (1. + 2.*b1/sqr(b0)/lx*(1.-2.*log(lx)) - + 4.*sqr(b1)/(sqr(sqr(b0))*sqr(lx))*(1. - 2.*log(lx) - + 3.*(sqr(log(lx) - 0.5)+b2*b0/(8.*sqr(b1))-1.25))); -} - -double ShowerAlphaQCD::alphaS(Energy q, Energy lam, int nf) const { - using Constants::pi; - double lx(log(sqr(q/lam))); - double b0 = 11. - 2./3.*nf; - double b1 = 51. - 19./3.*nf; - double b2 = 2857. - 5033./9.*nf + 325./27.*sqr(nf); - // one loop - if(_nloop==1) - {return 4.*pi/(b0*lx);} - // two loop - else if(_nloop==2) { - return 4.*pi/(b0*lx)*(1.-2.*b1/sqr(b0)*log(lx)/lx); - } - // three loop - else - {return 4.*pi/(b0*lx)*(1.-2.*b1/sqr(b0)*log(lx)/lx + - 4.*sqr(b1)/(sqr(sqr(b0))*sqr(lx))* - (sqr(log(lx) - 0.5) + b2*b0/(8.*sqr(b1)) - 5./4.));} -} - diff --git a/Shower/QTilde/Couplings/ShowerAlphaQCD.h b/Shower/QTilde/Couplings/ShowerAlphaQCD.h --- a/Shower/QTilde/Couplings/ShowerAlphaQCD.h +++ b/Shower/QTilde/Couplings/ShowerAlphaQCD.h @@ -1,308 +1,276 @@ // -*- C++ -*- // // ShowerAlphaQCD.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerAlphaQCD_H #define HERWIG_ShowerAlphaQCD_H // // This is the declaration of the ShowerAlphaQCD class. // #include "Herwig/Shower/ShowerAlpha.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This concrete class provides the definition of the * pure virtual function value() and overestimateValue() for the * strong coupling. * * A number of different options for the running of the coupling * and its initial definition are supported. * * @see \ref ShowerAlphaQCDInterfaces "The interfaces" * defined for ShowerAlphaQCD. */ class ShowerAlphaQCD: public ShowerAlpha { public: /** * The default constructor. */ ShowerAlphaQCD() : ShowerAlpha(), _qmin(0.630882*GeV), _asType(1), _asMaxNP(1.0), _thresholds(4), _lambda(4), - _nloop(3),_lambdaopt(false),_thresopt(false), - _lambdain(0.208364*GeV),_alphain(0.118),_inopt(true),_tolerance(1e-10), - _maxtry(100),_alphamin(0.),_val0(1.), _optInputScale(ZERO) {} + _nloop(3),_thresopt(false), + _alphain(0.118),_tolerance(1e-10), + _maxtry(100),_alphamin(0.),_val0(1.), _optInputScale(91.1876_GeV) {} public: /** * Methods to return the coupling */ //@{ /** * It returns the running coupling value evaluated at the input scale * multiplied by the scale factor scaleFactor(). * @param scale The scale * @return The coupling */ virtual double value(const Energy2 scale) const; /** * It returns the running coupling value evaluated at the input scale * multiplied by the scale factor scaleFactor(). */ virtual double overestimateValue() const; /** * Return the ratio of the coupling at the scale to the overestimated value */ virtual double ratio(const Energy2 scale,double factor =1.) const; /** * Initialize this coupling. */ virtual void initialize() { doinit(); } /** * A command to initialize the coupling and write * its value at the scale given by the argument (in GeV) */ string value(string); /** * Match thresholds and write alpha_s * specified file; arguments are * Q_low/GeV Q_high/GeV n_steps filename */ string check(string args); //@} /** * Get the value of \f$\Lambda_{\rm QCd}\f$ * @param nf number of flavours */ Energy lambdaQCD(unsigned int nf) { if (nf <= 3) return _lambda[0]; else if (nf==4 || nf==5) return _lambda[nf-3]; else return _lambda[3]; } /** * Return the quark masses to be used; if not empty these masses * should be considered instead of the ones set in the particle data * objects. */ const vector& quarkMasses() const { return _quarkMasses; } 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(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(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 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 IBPtr fullclone() const; //@} protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); //@} private: /** * Member functions which calculate the coupling */ //@{ /** - * The 1,2,3-loop parametrization of \f$\alpha_S\f$. - * @param q The scale - * @param lam \f$\Lambda_{\rm QCD}\f$ - * @param nf The number of flavours - */ - double alphaS(Energy q, Energy lam, int nf) const; - - /** - * The derivative of \f$\alpha_S\f$ with respect to \f$\ln(Q^2/\Lambda^2)\f$ - * @param q The scale - * @param lam \f$\Lambda_{\rm QCD}\f$ - * @param nf The number of flavours - */ - double derivativealphaS(Energy q, Energy lam, int nf) const; - - /** * Compute the value of \f$Lambda\f$ needed to get the input value of * the strong coupling at the scale given for the given number of flavours * using the Newton-Raphson method * @param match The scale for the coupling * @param alpha The input coupling * @param nflav The number of flavours */ Energy computeLambda(Energy match, double alpha, unsigned int nflav) const; /** * Return the value of \f$\Lambda\f$ and the number of flavours at the scale. * @param q The scale * @return The number of flavours at the scale and \f$\Lambda\f$. */ pair getLamNfTwoLoop(Energy q) const; //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ - ShowerAlphaQCD & operator=(const ShowerAlphaQCD &); + ShowerAlphaQCD & operator=(const ShowerAlphaQCD &) = delete; private: /** * Minimum value of the scale */ Energy _qmin; /** * Parameter controlling the behaviour of \f$\alpha_S\f$ in the * non-perturbative region. */ int _asType; /** * Another parameter, a possible (maximum) value of alpha in the * non-perturbative region. */ double _asMaxNP; /** * Thresholds for the different number of flavours */ vector _thresholds; /** * \f$\Lambda\f$ for the different number of flavours */ vector _lambda; /** * Option for the number of loops */ unsigned int _nloop; /** - * Option for the translation between \f$\Lambda_{\bar{MS}}\f$ and - * \f$\Lambda_{\rm Herwig}\f$ - */ - bool _lambdaopt; - - /** * Option for the threshold masses */ bool _thresopt; /** - * Input value of Lambda - */ - Energy _lambdain; - - /** * Input value of \f$alpha_S(M_Z)\f$ */ double _alphain; /** - * Option for the calculation of Lambda from input parameters - */ - bool _inopt; - - /** * Tolerance for discontinuities at the thresholds */ double _tolerance; /** * Maximum number of iterations for the Newton-Raphson method to converge */ unsigned int _maxtry; /** * The minimum value of the coupling */ double _alphamin; /** * Value of \f$\alpha_S\f$ at the minimum scale */ double _val0; /** * An optional input scale to be used for the input alphas; if zero MZ will * be used out of the particle data object. */ Energy _optInputScale; /** * The quark masses to be used; if not empty these masses should be * considered instead of the ones set in the particle data objects. */ vector _quarkMasses; }; } #endif /* HERWIG_ShowerAlphaQCD_H */ diff --git a/Shower/QTilde/Default/QTildeFinder.cc b/Shower/QTilde/Default/QTildeFinder.cc deleted file mode 100644 --- a/Shower/QTilde/Default/QTildeFinder.cc +++ /dev/null @@ -1,273 +0,0 @@ -// -*- C++ -*- -// -// QTildeFinder.cc is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig 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 QTildeFinder class. -// - -#include "QTildeFinder.h" -#include "ThePEG/Interface/ClassDocumentation.h" -#include "ThePEG/Persistency/PersistentOStream.h" -#include "ThePEG/Persistency/PersistentIStream.h" -#include "ThePEG/Interface/Switch.h" -#include "ThePEG/Repository/EventGenerator.h" -#include "ThePEG/EventRecord/Event.h" -#include "Herwig/Shower/QTilde/Base/ShowerParticle.h" -#include "ThePEG/Repository/UseRandom.h" -#include "ThePEG/Utilities/DescribeClass.h" - -using namespace Herwig; - -DescribeClass -describeQTildeFinder ("Herwig::QTildeFinder","HwShower.so"); - -void QTildeFinder::persistentOutput(PersistentOStream & os) const { - os << _finalFinalConditions << _initialFinalDecayConditions - << _initialInitialConditions; -} - -void QTildeFinder::persistentInput(PersistentIStream & is, int) { - is >> _finalFinalConditions >> _initialFinalDecayConditions - >>_initialInitialConditions; -} - -void QTildeFinder::Init() { - - static ClassDocumentation documentation - ("This class is responsible for finding the partners for each interaction types ", - "and within the evolution scale range specified by the ShowerVariables ", - "then to determine the initial evolution scales for each pair of partners."); - - static Switch interfaceFinalFinalConditions - ("FinalFinalConditions", - "The initial conditions for the shower of a final-final colour connection", - &QTildeFinder::_finalFinalConditions, 0, false, false); - static SwitchOption interfaceFinalFinalConditionsSymmetric - (interfaceFinalFinalConditions, - "Symmetric", - "The symmetric choice", - 0); - static SwitchOption interfaceFinalFinalConditionsColoured - (interfaceFinalFinalConditions, - "Coloured", - "Maximal radiation from the coloured particle", - 1); - static SwitchOption interfaceFinalFinalConditionsAntiColoured - (interfaceFinalFinalConditions, - "AntiColoured", - "Maximal emission from the anticoloured particle", - 2); - static SwitchOption interfaceFinalFinalConditionsRandom - (interfaceFinalFinalConditions, - "Random", - "Randomly selected maximal emission from one of the particles", - 3); - - static Switch interfaceInitialFinalDecayConditions - ("InitialFinalDecayConditions", - "The initial conditions for the shower of an initial-final" - " decay colour connection.", - &QTildeFinder::_initialFinalDecayConditions, 0, false, false); - static SwitchOption interfaceInitialFinalDecayConditionsSymmetric - (interfaceInitialFinalDecayConditions, - "Symmetric", - "The symmetric choice", - 0); - static SwitchOption interfaceInitialFinalDecayConditionsMaximal - (interfaceInitialFinalDecayConditions, - "Maximal", - "Maximal radiation from the decay product", - 1); - static SwitchOption interfaceInitialFinalDecayConditionsSmooth - (interfaceInitialFinalDecayConditions, - "Smooth", - "Smooth matching in the soft limit", - 2); - - static Switch interfaceInitialInitialConditions - ("InitialInitialConditions", - "The initial conditions for the shower of an initial-initial" - " colour connection.", - &QTildeFinder::_initialInitialConditions, 0, false, false); - static SwitchOption interfaceInitialInitialConditionsSymmetric - (interfaceInitialInitialConditions, - "Symmetric", - "The symmetric choice", - 0); - static SwitchOption interfaceInitialInitialConditionsMaximiseB - (interfaceInitialInitialConditions, - "MaximiseB", - "Maximal radiation from parton b", - 1); - static SwitchOption interfaceInitialInitialConditionsMaximiseC - (interfaceInitialInitialConditions, - "MaximiseC", - "Maximal radiation from parton c", - 2); -} - -pair QTildeFinder:: -calculateInitialFinalScales(const ShowerPPair &ppair, const bool isDecayCase) { - return - calculateInitialFinalScales(ppair.first->momentum(),ppair.second->momentum(),isDecayCase); -} - -pair QTildeFinder:: -calculateInitialFinalScales(const Lorentz5Momentum& pb, const Lorentz5Momentum& pc, - const bool isDecayCase) { - if(!isDecayCase) { - // In this case from JHEP 12(2003)045 we find the conditions - // ktilde_b = (1+c) and ktilde_c = (1+2c) - // We also find that c = m_c^2/Q^2. The process is a+b->c where - // particle a is not colour connected (considered as a colour singlet). - // Therefore we simply find that q_b = sqrt(Q^2+m_c^2) and - // q_c = sqrt(Q^2+2 m_c^2) - // We also assume that the first particle in the pair is the initial - // state particle and the second is the final state one c - Energy2 mc2 = sqr(pc.mass()); - Energy2 Q2 = -(pb-pc).m2(); - return pair(sqrt(Q2+mc2), sqrt(Q2+2*mc2)); - } - else { - // In this case from JHEP 12(2003)045 we find, for the decay - // process b->c+a(neutral), the condition - // (ktilde_b-1)*(ktilde_c-c)=(1/4)*sqr(1-a+c+lambda). - // We also assume that the first particle in the pair is the initial - // state particle (b) and the second is the final state one (c). - // - We find maximal phase space coverage through emissions from - // c if we set ktilde_c = 4.*(sqr(1.-sqrt(a))-c) - // - We find the most 'symmetric' way to populate the phase space - // occurs for (ktilde_b-1)=(ktilde_c-c)=(1/2)*(1-a+c+lambda) - // - We find the most 'smooth' way to populate the phase space - // occurs for... - Energy2 mb2(sqr(pb.mass())); - double a=(pb-pc).m2()/mb2; - double c=sqr(pc.mass())/mb2; - double lambda = 1. + a*a + c*c - 2.*a - 2.*c - 2.*a*c; - lambda = sqrt(max(lambda,0.)); - double PROD = 0.25*sqr(1. - a + c + lambda); - double ktilde_b, ktilde_c,cosi(0.); - switch(initialFinalDecayConditions()) { - case 0: // the 'symmetric' choice - ktilde_c = 0.5*(1-a+c+lambda) + c ; - ktilde_b = 1.+PROD/(ktilde_c-c) ; - break; - case 1: // the 'maximal' choice - ktilde_c = 4.0*(sqr(1.-sqrt(a))-c); - ktilde_b = 1.+PROD/(ktilde_c-c) ; - break; - case 2: // the 'smooth' choice - // c is a problem if very small here use 1GeV as minimum - c = max(c,1.*GeV2/mb2); - cosi = (sqr(1-sqrt(c))-a)/lambda; - ktilde_b = 2.0/(1.0-cosi); - ktilde_c = (1.0-a+c+lambda)*(1.0+c-a-lambda*cosi)/(2.0*(1.0+cosi)); - break; - default: - throw Exception() << "Invalid option for decay shower's phase space" - << " QTildeFinder::calculateInitialFinalScales" - << Exception::abortnow; - } - return pair(sqrt(mb2*ktilde_b),sqrt(mb2*ktilde_c)); - } -} - -pair QTildeFinder:: -calculateInitialInitialScales(const ShowerPPair &ppair) { - return - calculateInitialInitialScales(ppair.first->momentum(), - ppair.second->momentum()); -} - -pair QTildeFinder:: -calculateInitialInitialScales(const Lorentz5Momentum& p1, const Lorentz5Momentum& p2) { - // This case is quite simple. From JHEP 12(2003)045 we find the condition - // that ktilde_b = ktilde_c = 1. In this case we have the process - // b+c->a so we need merely boost to the CM frame of the two incoming - // particles and then qtilde is equal to the energy in that frame - Energy Q = sqrt((p1+p2).m2()); - if(_initialInitialConditions==1) { - return pair(sqrt(2.0)*Q,sqrt(0.5)*Q); - } else if(_initialInitialConditions==2) { - return pair(sqrt(0.5)*Q,sqrt(2.0)*Q); - } else { - return pair(Q,Q); - } -} - -pair QTildeFinder:: -calculateFinalFinalScales(const ShowerPPair & pp) { - bool colouredFirst = - pp.first->colourLine()&& - pp.first->colourLine()==pp.second->antiColourLine(); - return calculateFinalFinalScales(pp.first->momentum(),pp.second->momentum(), - colouredFirst); -} - -pair QTildeFinder:: -calculateFinalFinalScales(Lorentz5Momentum p1, Lorentz5Momentum p2, - bool colouredFirst) { - static const double eps=1e-7; - // Using JHEP 12(2003)045 we find that we need ktilde = 1/2(1+b-c+lambda) - // ktilde = qtilde^2/Q^2 therefore qtilde = sqrt(ktilde*Q^2) - // find momenta in rest frame of system - // calculate quantities for the scales - Energy2 Q2 = (p1+p2).m2(); - double b = p1.mass2()/Q2; - double c = p2.mass2()/Q2; - if(b<0.) { - if(b<-eps) { - throw Exception() << "Negative Mass squared b = " << b - << "in QTildeFinder::calculateFinalFinalScales()" - << Exception::eventerror; - } - b = 0.; - } - if(c<0.) { - if(c<-eps) { - throw Exception() << "Negative Mass squared c = " << c - << "in QTildeFinder::calculateFinalFinalScales()" - << Exception::eventerror; - } - c = 0.; - } - // KMH & PR - 16 May 2008 - swapped lambda calculation from - // double lam=2.*p1.vect().mag()/Q; to sqrt(kallen(1,b,c)), - // which should be identical for p1 & p2 onshell in their COM - // but in the inverse construction for the Nason method, this - // was not the case, leading to misuse. - double lam=sqrt((1.+sqrt(b)+sqrt(c))*(1.-sqrt(b)-sqrt(c)) - *(sqrt(b)-1.-sqrt(c))*(sqrt(c)-1.-sqrt(b))); - // symmetric case - unsigned int iopt=finalFinalConditions(); - Energy firstQ,secondQ; - if(iopt==0) { - firstQ = sqrt(0.5*Q2*(1.+b-c+lam)); - secondQ = sqrt(0.5*Q2*(1.-b+c+lam)); - } - // assymetric choice - else { - double kappab,kappac; - // calculate kappa with coloured line getting maximum - if((iopt==1&&colouredFirst)|| // first particle coloured+maximal for coloured - (iopt==2&&!colouredFirst)|| // first particle anticoloured+maximal for acoloured - (iopt==3&&UseRandom::rndbool(0.5))) { // random choice - kappab=4.*(1.-2.*sqrt(c)-b+c); - kappac=c+0.25*sqr(1.-b-c+lam)/(kappab-b); - } - else { - kappac=4.*(1.-2.*sqrt(b)-c+b); - kappab=b+0.25*sqr(1.-b-c+lam)/(kappac-c); - } - // calculate the scales - firstQ = sqrt(Q2*kappab); - secondQ = sqrt(Q2*kappac); - } - return pair(firstQ, secondQ); -} diff --git a/Shower/QTilde/Default/QTildeFinder.h b/Shower/QTilde/Default/QTildeFinder.h deleted file mode 100644 --- a/Shower/QTilde/Default/QTildeFinder.h +++ /dev/null @@ -1,206 +0,0 @@ -// -*- C++ -*- -// -// QTildeFinder.h is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig is licenced under version 3 of the GPL, see COPYING for details. -// Please respect the MCnet academic guidelines, see GUIDELINES for details. -// -#ifndef HERWIG_QTildeFinder_H -#define HERWIG_QTildeFinder_H -// -// This is the declaration of the QTildeFinder class. -// - -#include "Herwig/Shower/QTilde/Base/PartnerFinder.h" -#include "Herwig/Shower/QTilde/ShowerConfig.h" -#include "ThePEG/Interface/Interfaced.h" - -namespace Herwig { -using namespace ThePEG; - -/** \ingroup Shower - * - * The QTildeFinder class is responsible for finding the partners and - * setting the initial evolution scales for the shower evolution described - * in JHEP 0312:045,2003. - * - * @see \ref QTildeFinderInterfaces "The interfaces" - * defined for QTildeFinder. - */ -class QTildeFinder: public PartnerFinder { - -public: - - /** - * The default constructor. - */ - QTildeFinder() : _finalFinalConditions(0), - _initialFinalDecayConditions(0), - _initialInitialConditions(0) {} - - /** @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(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(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(); - -public: - - /** - * Calculate the initial evolution scales given momenta - */ - pair calculateFinalFinalScales(Lorentz5Momentum p1, Lorentz5Momentum p2, - bool colouredfirst); - - /** - * Calculate the initial evolution scales given momenta - */ - pair calculateInitialInitialScales(const Lorentz5Momentum& p1, - const Lorentz5Momentum& p2); - - /** - * Calculate the initial evolution scales given momenta - */ - pair calculateInitialFinalScales(const Lorentz5Momentum& pb, const Lorentz5Momentum& pc, - const bool isDecayCase); - -protected: - - /** - * Given a pair of particles, supposedly partners w.r.t. an interaction, - * this method returns their initial evolution scales as a pair. - * If something wrong happens, it returns the null (ZERO,ZERO) pair. - * This method is used by the above setXXXInitialEvolutionScales - * methods. - */ - //@{ - /** - * Calculate the initial evolution scales for two final-state particles - */ - virtual pair calculateFinalFinalScales(const ShowerPPair &); - - /** - * Calculate the initial evolution scales for two initial-state particles - */ - virtual pair calculateInitialInitialScales(const ShowerPPair &); - - /** - * Calculate the initial evolution scales for one initial - * and one final-state particles - */ - virtual pair calculateInitialFinalScales(const ShowerPPair &, - const bool isDecayCase); - //@} - - /** - * Access function for the initial conditions for the shower - */ - //@{ - /** - * Initial conditions for the shower of a final-final colour connection - * - 0 is the symmetric choice - * - 1 is maximal emmision from the coloured particle - * - 2 is maximal emmision from the anticoloured particle - * - 3 is randomly selected maximal emmision - */ - unsigned int finalFinalConditions() const - {return _finalFinalConditions;} - - /** - * Initial conditions for the shower of an initial-final decay colour connection - * - 0 is the symmetric choice - * - 1 is maximal emission from the decay product - * - 2 is the smooth choice - */ - unsigned int initialFinalDecayConditions() const - {return _initialFinalDecayConditions;} - //@} - -protected: - - /** @name Clone Methods. */ - //@{ - /** - * Make a simple clone of this object. - * @return a pointer to the new object. - */ - virtual IBPtr clone() const {return new_ptr(*this);} - - /** Make a clone of this object, possibly modifying the cloned object - * to make it sane. - * @return a pointer to the new object. - */ - virtual IBPtr fullclone() const {return new_ptr(*this);} - //@} - -private: - - /** - * The assignment operator is private and must never be called. - * In fact, it should not even be implemented. - */ - QTildeFinder & operator=(const QTildeFinder &); - -private: - - /** - * Flags controlling the initial conditions for the shower - */ - //@{ - /** - * Initial conditions for the shower with a final-final colour - * connection - */ - unsigned int _finalFinalConditions; - - /** - * Initial conditions for the shower with an initial-final decay colour - * connection. This is done according to the top decay colour - * connection calculation in JHEP12(2003)_045. The options act as follows: - * 0: This is the default 'symmetric' choice which more or less divides - * the phase space evenly between the parent and its charged child. - * 1: This 'maximal' choice maximises the phase space available for - * gluons emitted from the charged child. - * 2: This (experimental) 'smooth' choice does not suffer from - * a discontinuity at the boundary between the region populated by - * emissions from the charged child and the region populated by emissions - * from the parent. This does, however, mean that the phase space - * available for emissions from the charged child is fairly minimal. - */ - unsigned int _initialFinalDecayConditions; - - /** - * Initial conditions for the shower with an initial-initial colour - * connection. This is done according to the colour connection - * calculation in JHEP12(2003)_045. The options act as follows: - * 0: This is the default 'symmetric' choice which more or less divides - * the phase space evenly between the two incoming partons. - * 1: This increases the phase space for emission from "parton b". - * 2: This increases the phase space for emission from "parton c". - */ - unsigned int _initialInitialConditions; - //@} -}; - -} - -#endif /* HERWIG_QTildeFinder_H */ diff --git a/Shower/QTilde/Default/QTildeModel.cc b/Shower/QTilde/Default/QTildeModel.cc deleted file mode 100644 --- a/Shower/QTilde/Default/QTildeModel.cc +++ /dev/null @@ -1,61 +0,0 @@ -// -*- C++ -*- -// -// QTildeModel.cc is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig 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 QTildeModel class. -// - -#include "QTildeModel.h" -#include "ThePEG/Interface/ClassDocumentation.h" -#include "QTildeReconstructor.h" -#include "QTildeFinder.h" -#include "QTildeSudakov.h" -#include "ThePEG/Utilities/Throw.h" -#include "ThePEG/Utilities/DescribeClass.h" - -using namespace Herwig; - -DescribeNoPIOClass -describeQTildeModel ("Herwig::QTildeModel","HwShower.so"); - -IBPtr QTildeModel::clone() const { - return new_ptr(*this); -} - -IBPtr QTildeModel::fullclone() const { - return new_ptr(*this); -} - -void QTildeModel::Init() { - - static ClassDocumentation documentation - ("The QTildeModel class is the ShowerModel object for the Herwig shower."); - -} - -void QTildeModel::checkConsistency() { - // check KinematicsReconstructor - if(!dynamic_ptr_cast::pointer>(kinematicsReconstructor())) - Throw() << "KinematicsReconstructor must be either " - << "QTildeKinematicsReconstructor or a class inheriting from it" - << "in QTildeModel::checkConsistency()"; - // check PartnerFinder - if(!dynamic_ptr_cast::pointer>(partnerFinder())) - Throw() << "PartnerFinder must be either " - << "QTildeFinder or a class inheriting from it" - << "in QTildeModel::checkConsistency()"; - // Sudakov form factors - vector::const_iterator sit; - for(sit=sudakovFormFactors().begin();sit!=sudakovFormFactors().end();++sit) { - if(!dynamic_ptr_cast::pointer>(*sit)) - Throw() << "SudakovFormFactors must be either " - << "QTildeSudakov or a class inheriting from it" - << "in QTildeModel::checkConsistency()"; - } -} diff --git a/Shower/QTilde/Default/QTildeModel.h b/Shower/QTilde/Default/QTildeModel.h deleted file mode 100644 --- a/Shower/QTilde/Default/QTildeModel.h +++ /dev/null @@ -1,77 +0,0 @@ -// -*- C++ -*- -// -// QTildeModel.h is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig is licenced under version 3 of the GPL, see COPYING for details. -// Please respect the MCnet academic guidelines, see GUIDELINES for details. -// -#ifndef HERWIG_QTildeModel_H -#define HERWIG_QTildeModel_H -// -// This is the declaration of the QTildeModel class. -// - -#include "Herwig/Shower/QTilde/Base/ShowerModel.h" - -namespace Herwig { - -using namespace ThePEG; - -/** \ingroup Shower - * The QTildeModel class inherits from the ShowerModel class and implements the - * checkConsistency member for the default Herwig Shower. - * - * @see \ref QTildeModelInterfaces "The interfaces" - * defined for QTildeModel. - */ -class QTildeModel: public ShowerModel { - -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(); - -protected: - - /** - * The implementation of the virtual member from the base class to - * check that the correct objects are loaded - */ - virtual void checkConsistency(); - -protected: - - /** @name Clone Methods. */ - //@{ - /** - * Make a simple clone of this object. - * @return a pointer to the new object. - */ - virtual 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 IBPtr fullclone() const; - //@} - -private: - - /** - * The assignment operator is private and must never be called. - * In fact, it should not even be implemented. - */ - QTildeModel & operator=(const QTildeModel &); - -}; - -} - -#endif /* HERWIG_QTildeModel_H */ diff --git a/Shower/QTilde/Default/QTildeReconstructor.cc b/Shower/QTilde/Default/QTildeReconstructor.cc deleted file mode 100644 --- a/Shower/QTilde/Default/QTildeReconstructor.cc +++ /dev/null @@ -1,2942 +0,0 @@ -// -*- C++ -*- -// -// QTildeReconstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig 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 QTildeReconstructor class. -// - -#include "QTildeReconstructor.h" -#include "ThePEG/PDT/EnumParticles.h" -#include "ThePEG/Repository/EventGenerator.h" -#include "ThePEG/EventRecord/Event.h" -#include "ThePEG/Interface/Parameter.h" -#include "ThePEG/Interface/Switch.h" -#include "ThePEG/Interface/ClassDocumentation.h" -#include "ThePEG/Interface/RefVector.h" -#include "Herwig/Shower/QTilde/Base/PartnerFinder.h" -#include "ThePEG/Persistency/PersistentOStream.h" -#include "ThePEG/Persistency/PersistentIStream.h" -#include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" -#include "ThePEG/Repository/UseRandom.h" -#include "ThePEG/EventRecord/ColourLine.h" -#include "ThePEG/Utilities/DescribeClass.h" -#include "Herwig/Shower/QTilde/QTildeShowerHandler.h" -#include - -using namespace Herwig; - -DescribeClass -describeQTildeReconstructor("Herwig::QTildeReconstructor", "HwShower.so"); - -namespace { - -/** - * Struct to order the jets in off-shellness - */ -struct JetOrdering { - - bool operator() (const JetKinStruct & j1, const JetKinStruct & j2) { - Energy diff1 = j1.q.m()-j1.p.m(); - Energy diff2 = j2.q.m()-j2.p.m(); - if(diff1!=diff2) { - return diff1>diff2; - } - else if( j1.q.e() != j2.q.e() ) - return j1.q.e()>j2.q.e(); - else - return j1.parent->uniqueId>j2.parent->uniqueId; - } -}; - -} - -void QTildeReconstructor::persistentOutput(PersistentOStream & os) const { - os << _reconopt << _initialBoost << ounit(_minQ,GeV) << _noRescale - << _noRescaleVector << _finalStateReconOption - << _initialStateReconOption; -} - -void QTildeReconstructor::persistentInput(PersistentIStream & is, int) { - is >> _reconopt >> _initialBoost >> iunit(_minQ,GeV) >> _noRescale - >> _noRescaleVector >> _finalStateReconOption - >> _initialStateReconOption; -} - -void QTildeReconstructor::Init() { - - static ClassDocumentation documentation - ( "This class is responsible for the kinematics reconstruction of the showering,", - " including the kinematics reshuffling necessary to compensate for the recoil" - "of the emissions." ); - - static Switch interfaceReconstructionOption - ("ReconstructionOption", - "Option for the kinematics reconstruction", - &QTildeReconstructor::_reconopt, 0, false, false); - static SwitchOption interfaceReconstructionOptionGeneral - (interfaceReconstructionOption, - "General", - "Use the general solution which ignores the colour structure for all processes", - 0); - static SwitchOption interfaceReconstructionOptionColour - (interfaceReconstructionOption, - "Colour", - "Use the colour structure of the process to determine the reconstruction procedure.", - 1); - static SwitchOption interfaceReconstructionOptionColour2 - (interfaceReconstructionOption, - "Colour2", - "Make the most use possible of the colour structure of the process to determine the reconstruction procedure. " - "Start with FF, then IF then II colour connections", - 2); - static SwitchOption interfaceReconstructionOptionColour3 - (interfaceReconstructionOption, - "Colour3", - "Make the most use possible of the colour structure of the process to determine the reconstruction procedure. " - "Do the colour connections in order of the pT's emitted in the shower starting with the hardest." - " The colour partner is fully reconstructed at the same time.", - 3); - static SwitchOption interfaceReconstructionOptionColour4 - (interfaceReconstructionOption, - "Colour4", - "Make the most use possible of the colour structure of the process to determine the reconstruction procedure. " - "Do the colour connections in order of the pT's emitted in the shower starting with the hardest, while leaving" - " the colour partner on mass-shell", - 4); - - static Parameter interfaceMinimumQ2 - ("MinimumQ2", - "The minimum Q2 for the reconstruction of initial-final systems", - &QTildeReconstructor::_minQ, GeV, 0.001*GeV, 1e-6*GeV, 10.0*GeV, - false, false, Interface::limited); - - static RefVector interfaceNoRescale - ("NoRescale", - "Particles which shouldn't be rescaled to be on shell by the shower", - &QTildeReconstructor::_noRescaleVector, -1, false, false, true, false, false); - - static Switch interfaceInitialInitialBoostOption - ("InitialInitialBoostOption", - "Option for how the boost from the system before ISR to that after ISR is applied.", - &QTildeReconstructor::_initialBoost, 0, false, false); - static SwitchOption interfaceInitialInitialBoostOptionOneBoost - (interfaceInitialInitialBoostOption, - "OneBoost", - "Apply one boost from old CMS to new CMS", - 0); - static SwitchOption interfaceInitialInitialBoostOptionLongTransBoost - (interfaceInitialInitialBoostOption, - "LongTransBoost", - "First apply a longitudinal and then a transverse boost", - 1); - - static Switch interfaceFinalStateReconOption - ("FinalStateReconOption", - "Option for how to reconstruct the momenta of the final-state system", - &QTildeReconstructor::_finalStateReconOption, 0, false, false); - static SwitchOption interfaceFinalStateReconOptionDefault - (interfaceFinalStateReconOption, - "Default", - "All the momenta are rescaled in the rest frame", - 0); - static SwitchOption interfaceFinalStateReconOptionMostOffShell - (interfaceFinalStateReconOption, - "MostOffShell", - "All particles put on the new-mass shell and then the most off-shell and" - " recoiling system are rescaled to ensure 4-momentum is conserved.", - 1); - static SwitchOption interfaceFinalStateReconOptionRecursive - (interfaceFinalStateReconOption, - "Recursive", - "Recursively put on shell by putting the most off-shell particle which" - " hasn't been rescaled on-shell by rescaling the particles and the recoiling system. ", - 2); - static SwitchOption interfaceFinalStateReconOptionRestMostOffShell - (interfaceFinalStateReconOption, - "RestMostOffShell", - "The most off-shell is put on shell by rescaling it and the recoiling system," - " the recoiling system is then put on-shell in its rest frame.", - 3); - static SwitchOption interfaceFinalStateReconOptionRestRecursive - (interfaceFinalStateReconOption, - "RestRecursive", - "As 3 but recursive treated the currently most-off shell," - " only makes a difference if more than 3 partons.", - 4); - - static Switch interfaceInitialStateReconOption - ("InitialStateReconOption", - "Option for the reconstruction of initial state radiation", - &QTildeReconstructor::_initialStateReconOption, 0, false, false); - static SwitchOption interfaceInitialStateReconOptionRapidity - (interfaceInitialStateReconOption, - "Rapidity", - "Preserve shat and rapidity", - 0); - static SwitchOption interfaceInitialStateReconOptionLongitudinal - (interfaceInitialStateReconOption, - "Longitudinal", - "Preserve longitudinal momentum", - 1); - static SwitchOption interfaceInitialStateReconOptionSofterFraction - (interfaceInitialStateReconOption, - "SofterFraction", - "Preserve the momentum fraction of the parton which has emitted softer.", - 2); - -} - -void QTildeReconstructor::doinit() { - KinematicsReconstructor::doinit(); - _noRescale = set(_noRescaleVector.begin(),_noRescaleVector.end()); -} - -bool QTildeReconstructor:: -reconstructTimeLikeJet(const tShowerParticlePtr particleJetParent) const { - assert(particleJetParent); - bool emitted=true; - // if this is not a fixed point in the reconstruction - if( !particleJetParent->children().empty() ) { - // if not a reconstruction fixpoint, dig deeper for all children: - for ( ParticleVector::const_iterator cit = - particleJetParent->children().begin(); - cit != particleJetParent->children().end(); ++cit ) - reconstructTimeLikeJet(dynamic_ptr_cast(*cit)); - } - // it is a reconstruction fixpoint, ie kinematical data has to be available - else { - // check if the parent was part of the shower - ShowerParticlePtr jetGrandParent; - if(!particleJetParent->parents().empty()) - jetGrandParent= dynamic_ptr_cast - (particleJetParent->parents()[0]); - // update if so - if (jetGrandParent) { - if (jetGrandParent->showerKinematics()) { - if(particleJetParent->id()==_progenitor->id()&& - !_progenitor->data().stable()&&abs(_progenitor->data().id())!=ParticleID::tauminus) { - jetGrandParent->showerKinematics()->reconstructLast(particleJetParent, - _progenitor->mass()); - } - else { - jetGrandParent->showerKinematics()->reconstructLast(particleJetParent); - } - } - } - // otherwise - else { - Energy dm = particleJetParent->data().constituentMass(); - if (abs(dm-particleJetParent->momentum().m())>0.001*MeV - &&(particleJetParent->dataPtr()->stable() || abs(particleJetParent->id())==ParticleID::tauminus) - &&particleJetParent->id()!=ParticleID::gamma - &&_noRescale.find(particleJetParent->dataPtr())==_noRescale.end()) { - Lorentz5Momentum dum = particleJetParent->momentum(); - dum.setMass(dm); - dum.rescaleEnergy(); - particleJetParent->set5Momentum(dum); - } - else { - emitted=false; - } - } - } - // recursion has reached an endpoint once, ie we can reconstruct the - // kinematics from the children. - if( !particleJetParent->children().empty() ) - particleJetParent->showerKinematics() - ->reconstructParent( particleJetParent, particleJetParent->children() ); - return emitted; -} - -bool QTildeReconstructor:: -reconstructHardJets(ShowerTreePtr hard, - const map > & intrinsic, - ShowerInteraction type, - bool switchRecon) const { - _currentTree = hard; - _intrinsic=intrinsic; - // extract the particles from the ShowerTree - vector ShowerHardJets=hard->extractProgenitors(); - for(unsigned int ix=0;ixprogenitor()] = vector(); - } - for(map >::const_iterator - tit = _currentTree->treelinks().begin(); - tit != _currentTree->treelinks().end();++tit) { - _treeBoosts[tit->first] = vector(); - } - try { - // old recon method, using new member functions - if(_reconopt == 0 || switchRecon ) { - reconstructGeneralSystem(ShowerHardJets); - } - // reconstruction based on coloured systems - else if( _reconopt == 1) { - reconstructColourSinglets(ShowerHardJets,type); - } - // reconstruction of FF, then IF, then II - else if( _reconopt == 2) { - reconstructFinalFirst(ShowerHardJets); - } - // reconstruction based on coloured systems - else if( _reconopt == 3 || _reconopt == 4) { - reconstructColourPartner(ShowerHardJets); - } - else - assert(false); - } - catch(KinematicsReconstructionVeto) { - _progenitor=tShowerParticlePtr(); - _intrinsic.clear(); - for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { - for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { - LorentzRotation rot = rit->inverse(); - bit->first->transform(rot); - } - } - _boosts.clear(); - for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { - for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { - LorentzRotation rot = rit->inverse(); - bit->first->transform(rot,false); - } - } - _currentTree = tShowerTreePtr(); - _treeBoosts.clear(); - return false; - } - catch (Exception & ex) { - _progenitor=tShowerParticlePtr(); - _intrinsic.clear(); - _currentTree = tShowerTreePtr(); - _boosts.clear(); - _treeBoosts.clear(); - throw ex; - } - _progenitor=tShowerParticlePtr(); - _intrinsic.clear(); - // ensure x<1 - for(map::const_iterator - cit=hard->incomingLines().begin();cit!=hard->incomingLines().end();++cit) { - tPPtr parent = cit->first->progenitor(); - while (!parent->parents().empty()) { - parent = parent->parents()[0]; - } - tPPtr hadron; - if ( cit->first->original()->parents().empty() ) { - hadron = cit->first->original(); - } - else { - hadron = cit->first->original()->parents()[0]; - } - if( ! (hadron->id() == parent->id() && hadron->children().size() <= 1) - && parent->momentum().rho() > hadron->momentum().rho()) { - _progenitor=tShowerParticlePtr(); - _intrinsic.clear(); - for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { - for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { - LorentzRotation rot = rit->inverse(); - bit->first->transform(rot); - } - } - _boosts.clear(); - for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { - for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { - LorentzRotation rot = rit->inverse(); - bit->first->transform(rot,false); - } - } - _currentTree = tShowerTreePtr(); - _treeBoosts.clear(); - return false; - } - } - _boosts.clear(); - _treeBoosts.clear(); - _currentTree = tShowerTreePtr(); - return true; -} - -double -QTildeReconstructor::solveKfactor(const Energy & root_s, - const JetKinVect & jets) const { - Energy2 s = sqr(root_s); - // must be at least two jets - if ( jets.size() < 2) throw KinematicsReconstructionVeto(); - // sum of jet masses must be less than roots - if(momConsEq( 0.0, root_s, jets )>ZERO) throw KinematicsReconstructionVeto(); - // if two jets simple solution - if ( jets.size() == 2 ) { - static const Energy2 eps = 1.0e-4 * MeV2; - if ( sqr(jets[0].p.x()+jets[1].p.x()) < eps && - sqr(jets[0].p.y()+jets[1].p.y()) < eps && - sqr(jets[0].p.z()+jets[1].p.z()) < eps ) { - Energy test = (jets[0].p+jets[1].p).vect().mag(); - if(test > 1.0e-4 * MeV) throw KinematicsReconstructionVeto(); - if ( jets[0].p.vect().mag2() < eps ) throw KinematicsReconstructionVeto(); - Energy2 m1sq(jets[0].q.m2()),m2sq(jets[1].q.m2()); - return sqrt( ( sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq ) - /(4.*s*jets[0].p.vect().mag2()) ); - } - else throw KinematicsReconstructionVeto(); - } - // i.e. jets.size() > 2, numerically - // check convergence, if it's a problem maybe use Newton iteration? - else { - double k1 = 0.,k2 = 1.,k = 0.; - if ( momConsEq( k1, root_s, jets ) < ZERO ) { - while ( momConsEq( k2, root_s, jets ) < ZERO ) { - k1 = k2; - k2 *= 2; - } - while ( fabs( (k1 - k2)/(k1 + k2) ) > 1.e-10 ) { - if( momConsEq( k2, root_s, jets ) == ZERO ) { - return k2; - } else { - k = (k1+k2)/2.; - if ( momConsEq( k, root_s, jets ) > ZERO ) { - k2 = k; - } else { - k1 = k; - } - } - } - return k1; - } else throw KinematicsReconstructionVeto(); - } - throw KinematicsReconstructionVeto(); -} - -bool QTildeReconstructor:: -reconstructSpaceLikeJet( const tShowerParticlePtr p) const { - bool emitted = true; - tShowerParticlePtr child; - tShowerParticlePtr parent; - if(!p->parents().empty()) - parent = dynamic_ptr_cast(p->parents()[0]); - if(parent) { - emitted=true; - reconstructSpaceLikeJet(parent); - } - // if branching reconstruct time-like child - if(p->children().size()==2) - child = dynamic_ptr_cast(p->children()[1]); - if(p->perturbative()==0 && child) { - dynamic_ptr_cast(p->children()[0])-> - showerKinematics()->reconstructParent(p,p->children()); - if(!child->children().empty()) { - _progenitor=child; - reconstructTimeLikeJet(child); - // calculate the momentum of the particle - Lorentz5Momentum pnew=p->momentum()-child->momentum(); - pnew.rescaleMass(); - p->children()[0]->set5Momentum(pnew); - } - } - return emitted; -} - -Boost QTildeReconstructor:: -solveBoostBeta( const double k, const Lorentz5Momentum & newq, - const Lorentz5Momentum & oldp ) { - // try something different, purely numerical first: - // a) boost to rest frame of newq, b) boost with kp/E - Energy q = newq.vect().mag(); - Energy2 qs = sqr(q); - Energy2 Q2 = newq.m2(); - Energy kp = k*(oldp.vect().mag()); - Energy2 kps = sqr(kp); - - // usually we take the minus sign, since this boost will be smaller. - // we only require |k \vec p| = |\vec q'| which leaves the sign of - // the boost open but the 'minus' solution gives a smaller boost - // parameter, i.e. the result should be closest to the previous - // result. this is to be changed if we would get many momentum - // conservation violations at the end of the shower from a hard - // process. - double betam = (q*sqrt(qs + Q2) - kp*sqrt(kps + Q2))/(kps + qs + Q2); - // move directly to 'return' - Boost beta = -betam*(k/kp)*oldp.vect(); - // note that (k/kp)*oldp.vect() = oldp.vect()/oldp.vect().mag() but cheaper. - // leave this out if it's running properly! - if ( betam >= 0 ) return beta; - else return Boost(0., 0., 0.); -} - -bool QTildeReconstructor:: -reconstructDecayJets(ShowerTreePtr decay, - ShowerInteraction) const { - _currentTree = decay; - // extract the particles from the ShowerTree - vector ShowerHardJets=decay->extractProgenitors(); - for(unsigned int ix=0;ixprogenitor()] = vector(); - } - for(map >::const_iterator - tit = _currentTree->treelinks().begin(); - tit != _currentTree->treelinks().end();++tit) { - _treeBoosts[tit->first] = vector(); - } - try { - bool radiated[2]={false,false}; - // find the decaying particle and check if particles radiated - ShowerProgenitorPtr initial; - for(unsigned int ix=0;ixprogenitor()->isFinalState()) { - radiated[1] |=ShowerHardJets[ix]->hasEmitted(); - } - else { - initial=ShowerHardJets[ix]; - radiated[0]|=ShowerHardJets[ix]->hasEmitted(); - } - } - // find boost to the rest frame if needed - Boost boosttorest=-initial->progenitor()->momentum().boostVector(); - double gammarest = - initial->progenitor()->momentum().e()/ - initial->progenitor()->momentum().mass(); - // check if need to boost to rest frame - bool gottaBoost = (boosttorest.mag() > 1e-12); - // if initial state radiation reconstruct the jet and set up the basis vectors - Lorentz5Momentum pjet; - Lorentz5Momentum nvect; - // find the partner - ShowerParticlePtr partner = initial->progenitor()->partner(); - Lorentz5Momentum ppartner[2]; - if(partner) ppartner[0]=partner->momentum(); - // get the n reference vector - if(partner) { - if(initial->progenitor()->showerKinematics()) { - nvect = initial->progenitor()->showerBasis()->getBasis()[1]; - } - else { - Lorentz5Momentum ppartner=initial->progenitor()->partner()->momentum(); - if(gottaBoost) ppartner.boost(boosttorest,gammarest); - nvect = Lorentz5Momentum( ZERO,0.5*initial->progenitor()->mass()* - ppartner.vect().unit()); - nvect.boost(-boosttorest,gammarest); - } - } - // if ISR - if(radiated[0]) { - // reconstruct the decay jet - reconstructDecayJet(initial->progenitor()); - // momentum of decaying particle after ISR - pjet=initial->progenitor()->momentum() - -decay->incomingLines().begin()->second->momentum(); - pjet.rescaleMass(); - } - // boost initial state jet and basis vector if needed - if(gottaBoost) { - pjet.boost(boosttorest,gammarest); - nvect.boost(boosttorest,gammarest); - ppartner[0].boost(boosttorest,gammarest); - } - // loop over the final-state particles and do the reconstruction - JetKinVect possiblepartners; - JetKinVect jetKinematics; - bool atLeastOnce = radiated[0]; - LorentzRotation restboost(boosttorest,gammarest); - Energy inmass(ZERO); - for(unsigned int ix=0;ixprogenitor()->isFinalState()) { - inmass=ShowerHardJets[ix]->progenitor()->mass(); - continue; - } - // do the reconstruction - JetKinStruct tempJetKin; - tempJetKin.parent = ShowerHardJets[ix]->progenitor(); - if(ShowerHardJets.size()==2) { - Lorentz5Momentum dum=ShowerHardJets[ix]->progenitor()->momentum(); - dum.setMass(inmass); - dum.rescaleRho(); - tempJetKin.parent->set5Momentum(dum); - } - tempJetKin.p = ShowerHardJets[ix]->progenitor()->momentum(); - if(gottaBoost) tempJetKin.p.boost(boosttorest,gammarest); - _progenitor=tempJetKin.parent; - if(ShowerHardJets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { - atLeastOnce |= reconstructTimeLikeJet(tempJetKin.parent); - ShowerHardJets[ix]->reconstructed(ShowerProgenitor::done); - } - if(gottaBoost) deepTransform(tempJetKin.parent,restboost); - tempJetKin.q = ShowerHardJets[ix]->progenitor()->momentum(); - jetKinematics.push_back(tempJetKin); - } - if(partner) ppartner[1]=partner->momentum(); - // calculate the rescaling parameters - double k1,k2; - Lorentz5Momentum qt; - if(!solveDecayKFactor(initial->progenitor()->mass(),nvect,pjet, - jetKinematics,partner,ppartner,k1,k2,qt)) { - for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { - for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { - LorentzRotation rot = rit->inverse(); - bit->first->transform(rot); - } - } - _boosts.clear(); - for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { - for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { - LorentzRotation rot = rit->inverse(); - bit->first->transform(rot,false); - } - } - _treeBoosts.clear(); - _currentTree = tShowerTreePtr(); - return false; - } - // apply boosts and rescalings to final-state jets - for(JetKinVect::iterator it = jetKinematics.begin(); - it != jetKinematics.end(); ++it) { - LorentzRotation Trafo = LorentzRotation(); - if(it->parent!=partner) { - // boost for rescaling - if(atLeastOnce) { - map >::const_iterator tit; - for(tit = _currentTree->treelinks().begin(); - tit != _currentTree->treelinks().end();++tit) { - if(tit->second.first && tit->second.second==it->parent) - break; - } - if(it->parent->children().empty()&&!it->parent->spinInfo() && - tit==_currentTree->treelinks().end()) { - Lorentz5Momentum pnew(k2*it->p.vect(), - sqrt(sqr(k2*it->p.vect().mag())+it->q.mass2()), - it->q.mass()); - it->parent->set5Momentum(pnew); - } - else { - // rescaling boost can't ever work in this case - if(k2<0. && it->q.mass()==ZERO) - throw KinematicsReconstructionVeto(); - Trafo = solveBoost(k2, it->q, it->p); - } - } - if(gottaBoost) Trafo.boost(-boosttorest,gammarest); - if(atLeastOnce || gottaBoost) deepTransform(it->parent,Trafo); - } - else { - Lorentz5Momentum pnew=ppartner[0]; - pnew *=k1; - pnew-=qt; - pnew.setMass(ppartner[1].mass()); - pnew.rescaleEnergy(); - LorentzRotation Trafo=solveBoost(1.,ppartner[1],pnew); - if(gottaBoost) Trafo.boost(-boosttorest,gammarest); - deepTransform(partner,Trafo); - } - } - } - catch(KinematicsReconstructionVeto) { - for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { - for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { - LorentzRotation rot = rit->inverse(); - bit->first->transform(rot); - } - } - _boosts.clear(); - for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { - for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { - LorentzRotation rot = rit->inverse(); - bit->first->transform(rot,false); - } - } - _treeBoosts.clear(); - _currentTree = tShowerTreePtr(); - return false; - } - catch (Exception & ex) { - _currentTree = tShowerTreePtr(); - _boosts.clear(); - _treeBoosts.clear(); - throw ex; - } - _boosts.clear(); - _treeBoosts.clear(); - _currentTree = tShowerTreePtr(); - return true; -} - -bool QTildeReconstructor:: -reconstructDecayJet( const tShowerParticlePtr p) const { - if(p->children().empty()) return false; - tShowerParticlePtr child; - // if branching reconstruct time-like child - child = dynamic_ptr_cast(p->children()[1]); - if(child) { - _progenitor=child; - reconstructTimeLikeJet(child); - // calculate the momentum of the particle - Lorentz5Momentum pnew=p->momentum()-child->momentum(); - pnew.rescaleMass(); - p->children()[0]->set5Momentum(pnew); - child=dynamic_ptr_cast(p->children()[0]); - reconstructDecayJet(child); - return true; - } - return false; -} - -bool QTildeReconstructor:: -solveDecayKFactor(Energy mb, - const Lorentz5Momentum & n, - const Lorentz5Momentum & pjet, - const JetKinVect & jetKinematics, - ShowerParticlePtr partner, - Lorentz5Momentum ppartner[2], - double & k1, double & k2, - Lorentz5Momentum & qt) const { - Energy2 pjn = partner ? pjet.vect()*n.vect() : ZERO; - Energy2 pcn = partner ? ppartner[0].vect()*n.vect() : 1.*MeV2; - Energy2 nmag = n.vect().mag2(); - Lorentz5Momentum pn = partner ? (pjn/nmag)*n : Lorentz5Momentum(); - qt=pjet-pn; qt.setE(ZERO); - Energy2 pt2=qt.vect().mag2(); - Energy Ejet = pjet.e(); - // magnitudes of the momenta for fast access - vector pmag; - Energy total(Ejet); - for(unsigned int ix=0;ixmb) return false; - Energy2 pcmag=ppartner[0].vect().mag2(); - // used newton-raphson to get the rescaling - static const Energy eps=1e-8*GeV; - long double d1(1.),d2(1.); - Energy roots, ea, ec, ds; - unsigned int ix=0; - do { - ++ix; - d2 = d1 + pjn/pcn; - roots = Ejet; - ds = ZERO; - for(unsigned int iy=0;iyeps && ix<100); - k1=d1; - k2=d2; - // return true if N-R succeed, otherwise false - return ix<100; -} - -bool QTildeReconstructor:: -deconstructDecayJets(HardTreePtr decay,ShowerInteraction) const { - // extract the momenta of the particles - vector pin; - vector pout; - // on-shell masses of the decay products - vector mon; - Energy mbar(-GeV); - // the hard branchings of the particles - set::iterator cit; - set branchings=decay->branchings(); - // properties of the incoming particle - bool ISR = false; - HardBranchingPtr initial; - Lorentz5Momentum qisr; - // find the incoming particle, both before and after - // any ISR - for(cit=branchings.begin();cit!=branchings.end();++cit){ - if((*cit)->status()==HardBranching::Incoming|| - (*cit)->status()==HardBranching::Decay) { - // search back up isr if needed - HardBranchingPtr branch = *cit; - while(branch->parent()) branch=branch->parent(); - initial=branch; - // momentum or original parent - pin.push_back(branch->branchingParticle()->momentum()); - // ISR? - ISR = !branch->branchingParticle()->children().empty(); - // ISR momentum - qisr = pin.back()-(**cit).branchingParticle()->momentum(); - qisr.rescaleMass(); - } - } - assert(pin.size()==1); - // compute boost to rest frame - Boost boostv=-pin[0].boostVector(); - // partner for ISR - ShowerParticlePtr partner; - Lorentz5Momentum ppartner; - if(initial->branchingParticle()->partner()) { - partner=initial->branchingParticle()->partner(); - ppartner=partner->momentum(); - } - // momentum of the decay products - for(cit=branchings.begin();cit!=branchings.end();++cit) { - if((*cit)->status()!=HardBranching::Outgoing) continue; - // find the mass of the particle - // including special treatment for off-shell resonances - // to preserve off-shell mass - Energy mass; - if(!(**cit).branchingParticle()->dataPtr()->stable()) { - HardBranchingPtr branch=*cit; - while(!branch->children().empty()) { - for(unsigned int ix=0;ixchildren().size();++ix) { - if(branch->children()[ix]->branchingParticle()->id()== - (**cit).branchingParticle()->id()) { - branch = branch->children()[ix]; - continue; - } - } - }; - mass = branch->branchingParticle()->mass(); - } - else { - mass = (**cit).branchingParticle()->dataPtr()->mass(); - } - // if not evolution partner of decaying particle - if((*cit)->branchingParticle()!=partner) { - pout.push_back((*cit)->branchingParticle()->momentum()); - mon.push_back(mass); - } - // evolution partner of decaying particle - else { - mbar = mass; - } - } - // boost all the momenta to the rest frame of the decaying particle - for(unsigned int ix=0;ixbranchingParticle()->partner()) { - ppartner.boost(boostv); - qisr.boost(boostv); - } - // compute the rescaling factors - double k1,k2; - if(!ISR) { - if(partner) { - pout.push_back(ppartner); - mon.push_back(mbar); - } - k1=k2=inverseRescalingFactor(pout,mon,pin[0].mass()); - if(partner) { - pout.pop_back(); - mon.pop_back(); - } - } - else { - if(!inverseDecayRescalingFactor(pout,mon,pin[0].mass(), - ppartner,mbar,k1,k2)) return false; - } - // now calculate the p reference vectors - unsigned int ifinal=0; - for(cit=branchings.begin();cit!=branchings.end();++cit) { - if((**cit).status()!=HardBranching::Outgoing) continue; - // for partners other than colour partner of decaying particle - if((*cit)->branchingParticle()!=partner) { - Lorentz5Momentum pvect = (*cit)->branchingParticle()->momentum(); - pvect.boost(boostv); - pvect /= k1; - pvect.setMass(mon[ifinal]); - ++ifinal; - pvect.rescaleEnergy(); - pvect.boost(-boostv); - (*cit)->pVector(pvect); - (*cit)->showerMomentum(pvect); - } - // for colour partner of decaying particle - else { - Lorentz5Momentum pvect = (*cit)->branchingParticle()->momentum(); - pvect.boost(boostv); - Lorentz5Momentum qtotal; - for(unsigned int ix=0;ixpVector(pvect); - (*cit)->showerMomentum(pvect); - } - } - // For initial-state if needed - if(initial) { - tShowerParticlePtr newPartner=initial->branchingParticle()->partner(); - if(newPartner) { - tHardBranchingPtr branch; - for( set::iterator clt = branchings.begin(); - clt != branchings.end(); ++clt ) { - if((**clt).branchingParticle()==newPartner) { - initial->colourPartner(*clt); - branch=*clt; - break; - } - } - Lorentz5Momentum pvect = initial->branchingParticle()->momentum(); - initial->pVector(pvect); - Lorentz5Momentum ptemp = branch->pVector(); - ptemp.boost(boostv); - Lorentz5Momentum nvect = Lorentz5Momentum( ZERO, - 0.5*initial->branchingParticle()->mass()* - ptemp.vect().unit()); - nvect.boost(-boostv); - initial->nVector(nvect); - } - } - // calculate the reference vectors, then for outgoing particles - for(cit=branchings.begin();cit!=branchings.end();++cit){ - if((**cit).status()!=HardBranching::Outgoing) continue; - // find the partner branchings - tShowerParticlePtr newPartner=(*cit)->branchingParticle()->partner(); - if(!newPartner) continue; - tHardBranchingPtr branch; - for( set::iterator clt = branchings.begin(); - clt != branchings.end(); ++clt ) { - if(cit==clt) continue; - if((**clt).branchingParticle()==newPartner) { - (**cit).colourPartner(*clt); - branch=*clt; - break; - } - } - if((**decay->incoming().begin()).branchingParticle()==newPartner) { - (**cit).colourPartner(*decay->incoming().begin()); - branch = *decay->incoming().begin(); - } - // final-state colour partner - if(branch->status()==HardBranching::Outgoing) { - Boost boost=((*cit)->pVector()+branch->pVector()).findBoostToCM(); - Lorentz5Momentum pcm = branch->pVector(); - pcm.boost(boost); - Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect()); - nvect.boost( -boost); - (*cit)->nVector(nvect); - } - // initial-state colour partner - else { - Boost boost=branch->pVector().findBoostToCM(); - Lorentz5Momentum pcm = (*cit)->pVector(); - pcm.boost(boost); - Lorentz5Momentum nvect = Lorentz5Momentum( ZERO, -pcm.vect()); - nvect.boost( -boost); - (*cit)->nVector(nvect); - } - } - // now compute the new momenta - // and calculate the shower variables - for(cit=branchings.begin();cit!=branchings.end();++cit) { - if((**cit).status()!=HardBranching::Outgoing) continue; - LorentzRotation B=LorentzRotation(-boostv); - LorentzRotation A=LorentzRotation(boostv),R; - if((*cit)->branchingParticle()==partner) { - Lorentz5Momentum qnew; - Energy2 dot=(*cit)->pVector()*(*cit)->nVector(); - double beta = 0.5*((*cit)->branchingParticle()->momentum().m2() - -sqr((*cit)->pVector().mass()))/dot; - qnew=(*cit)->pVector()+beta*(*cit)->nVector(); - qnew.rescaleMass(); - // compute the boost - R=B*solveBoost(A*qnew,A*(*cit)->branchingParticle()->momentum())*A; - } - else { - Lorentz5Momentum qnew; - if((*cit)->branchingParticle()->partner()) { - Energy2 dot=(*cit)->pVector()*(*cit)->nVector(); - double beta = 0.5*((*cit)->branchingParticle()->momentum().m2() - -sqr((*cit)->pVector().mass()))/dot; - qnew=(*cit)->pVector()+beta*(*cit)->nVector(); - qnew.rescaleMass(); - } - else { - qnew = (*cit)->pVector(); - } - // compute the boost - R=B*solveBoost(A*qnew,A*(*cit)->branchingParticle()->momentum())*A; - } - // reconstruct the momenta - (*cit)->setMomenta(R,1.0,Lorentz5Momentum()); - } - if(initial) { - initial->setMomenta(LorentzRotation(),1.0,Lorentz5Momentum()); - } - return true; -} - -double QTildeReconstructor:: -inverseRescalingFactor(vector pout, - vector mon, Energy roots) const { - double lambda=1.; - if(pout.size()==2) { - double mu_q1(pout[0].m()/roots), mu_q2(pout[1].m()/roots); - double mu_p1(mon[0]/roots) , mu_p2(mon[1]/roots); - lambda = - ((1.+mu_q1+mu_q2)*(1.-mu_q1-mu_q2)*(mu_q1-1.-mu_q2)*(mu_q2-1.-mu_q1))/ - ((1.+mu_p1+mu_p2)*(1.-mu_p1-mu_p2)*(mu_p1-1.-mu_p2)*(mu_p2-1.-mu_p1)); - if(lambda<0.) - throw Exception() << "Rescaling factor is imaginary in QTildeReconstructor::" - << "inverseRescalingFactor lambda^2= " << lambda - << Exception::eventerror; - lambda = sqrt(lambda); - } - else { - unsigned int ntry=0; - // compute magnitudes once for speed - vector pmag; - for(unsigned int ix=0;ix root(pout.size()); - do { - // compute new energies - Energy sum(ZERO); - for(unsigned int ix=0;ix::const_iterator it=tree->branchings().begin(); - it!=tree->branchings().end();++it) { - if((**it).status()==HardBranching::Incoming) in .jets.push_back(*it); - else out.jets.push_back(*it); - } - LorentzRotation toRest,fromRest; - bool applyBoost(false); - // do the initial-state reconstruction - deconstructInitialInitialSystem(applyBoost,toRest,fromRest, - tree,in.jets,type); - // do the final-state reconstruction - deconstructFinalStateSystem(toRest,fromRest,tree, - out.jets,type); - // only at this point that we can be sure all the reference vectors - // are correct - for(set::const_iterator it=tree->branchings().begin(); - it!=tree->branchings().end();++it) { - if((**it).status()==HardBranching::Incoming) continue; - if((**it).branchingParticle()->coloured()) - (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); - } - for(set::const_iterator it=tree->incoming().begin(); - it!=tree->incoming().end();++it) { - (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); - } - return true; -} - -bool QTildeReconstructor::deconstructHardJets(HardTreePtr tree, - ShowerInteraction type) const { - // inverse of old recon method - if(_reconopt == 0) { - return deconstructGeneralSystem(tree,type); - } - else if(_reconopt == 1) { - return deconstructColourSinglets(tree,type); - } - else if(_reconopt == 2) { - throw Exception() << "Inverse reconstruction is not currently supported for ReconstructionOption Colour2 " - << "in QTildeReconstructor::deconstructHardJets(). Please use one of the other options\n" - << Exception::runerror; - } - else if(_reconopt == 3 || _reconopt == 4 ) { - return deconstructColourPartner(tree,type); - } - else - assert(false); -} - -bool QTildeReconstructor:: -deconstructColourSinglets(HardTreePtr tree, - ShowerInteraction type) const { - // identify the colour singlet systems - unsigned int nnun(0),nnii(0),nnif(0),nnf(0),nni(0); - vector - systems(identifySystems(tree->branchings(),nnun,nnii,nnif,nnf,nni)); - // now decide what to do - LorentzRotation toRest,fromRest; - bool applyBoost(false); - bool general(false); - // initial-initial connection and final-state colour singlet systems - // Drell-Yan type - if(nnun==0&&nnii==1&&nnif==0&&nnf>0&&nni==0) { - // reconstruct initial-initial system - for(unsigned int ix=0;ix0&&nni==1)|| - (nnif==2&& nni==0))) { - for(unsigned int ix=0;ix0&&nni==2) { - // only FS needed - // but need to boost to rest frame if QED ISR - Lorentz5Momentum ptotal; - for(unsigned int ix=0;ixbranchingParticle()->momentum(); - } - toRest = LorentzRotation(ptotal.findBoostToCM()); - fromRest = toRest; - fromRest.invert(); - if(type!=ShowerInteraction::QCD) { - combineFinalState(systems); - general=false; - } - } - // general type - else { - general = true; - } - // final-state systems except for general recon - if(!general) { - for(unsigned int ix=0;ix::const_iterator it=tree->branchings().begin(); - it!=tree->branchings().end();++it) { - if((**it).status()==HardBranching::Incoming) continue; - if((**it).branchingParticle()->coloured()) - (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); - } - for(set::const_iterator it=tree->incoming().begin(); - it!=tree->incoming().end();++it) { - (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); - } - return true; - } - else { - return deconstructGeneralSystem(tree,type); - } - return true; -} - -bool QTildeReconstructor:: -deconstructColourPartner(HardTreePtr tree, - ShowerInteraction type) const { - Lorentz5Momentum ptotal; - HardBranchingPtr emitter; - ColourSingletShower incomingShower,outgoingShower; - for(set::const_iterator it=tree->branchings().begin(); - it!=tree->branchings().end();++it) { - if((**it).status()==HardBranching::Incoming) { - incomingShower.jets.push_back(*it); - ptotal += (*it)->branchingParticle()->momentum(); - // check for emitting particle - if((**it).parent() ) { - if(!emitter) - emitter = *it; - else - throw Exception() << "Only one emitting particle allowed in " - << "QTildeReconstructor::deconstructColourPartner()" - << Exception::runerror; - } - } - else if ((**it).status()==HardBranching::Outgoing) { - outgoingShower.jets.push_back(*it); - // check for emitting particle - if(!(**it).children().empty() ) { - if(!emitter) - emitter = *it; - else - throw Exception() << "Only one emitting particle allowed in " - << "QTildeReconstructor::deconstructColourPartner()" - << Exception::runerror; - } - } - } - assert(emitter); - assert(emitter->colourPartner()); - ColourSingletShower system; - system.jets.push_back(emitter); - system.jets.push_back(emitter->colourPartner()); - LorentzRotation toRest,fromRest; - bool applyBoost(false); - // identify the colour singlet system - if(emitter->status() == HardBranching::Outgoing && - emitter->colourPartner()->status() == HardBranching::Outgoing ) { - system.type=F; - // need to boost to rest frame if QED ISR - if( !incomingShower.jets[0]->branchingParticle()->coloured() && - !incomingShower.jets[1]->branchingParticle()->coloured() ) { - Boost boost = ptotal.findBoostToCM(); - toRest = LorentzRotation( boost); - fromRest = LorentzRotation(-boost); - } - else - findInitialBoost(ptotal,ptotal,toRest,fromRest); - deconstructFinalStateSystem(toRest,fromRest,tree, - system.jets,type); - } - else if (emitter->status() == HardBranching::Incoming && - emitter->colourPartner()->status() == HardBranching::Incoming) { - system.type=II; - deconstructInitialInitialSystem(applyBoost,toRest,fromRest,tree,system.jets,type); - // make sure the recoil gets applied - deconstructFinalStateSystem(toRest,fromRest,tree, - outgoingShower.jets,type); - } - else if ((emitter->status() == HardBranching::Outgoing && - emitter->colourPartner()->status() == HardBranching::Incoming ) || - (emitter->status() == HardBranching::Incoming && - emitter->colourPartner()->status() == HardBranching::Outgoing)) { - system.type=IF; - // enusre incoming first - if(system.jets[0]->status() == HardBranching::Outgoing) - swap(system.jets[0],system.jets[1]); - deconstructInitialFinalSystem(tree,system.jets,type); - } - else { - throw Exception() << "Unknown type of system in " - << "QTildeReconstructor::deconstructColourPartner()" - << Exception::runerror; - } - // only at this point that we can be sure all the reference vectors - // are correct - for(set::const_iterator it=tree->branchings().begin(); - it!=tree->branchings().end();++it) { - if((**it).status()==HardBranching::Incoming) continue; - if((**it).branchingParticle()->coloured()) - (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); - } - for(set::const_iterator it=tree->incoming().begin(); - it!=tree->incoming().end();++it) { - (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); - } - for(set::const_iterator it=tree->branchings().begin(); - it!=tree->branchings().end();++it) { - if((**it).status()!=HardBranching::Incoming) continue; - if(*it==system.jets[0] || *it==system.jets[1]) continue; - if((**it).branchingParticle()->momentum().z()>ZERO) { - (**it).z((**it).branchingParticle()->momentum().plus()/(**it).beam()->momentum().plus()); - } - else { - (**it).z((**it).branchingParticle()->momentum().minus()/(**it).beam()->momentum().minus()); - } - } - return true; -} - -void QTildeReconstructor:: -reconstructInitialFinalSystem(vector jets) const { - Lorentz5Momentum pin[2],pout[2],pbeam; - for(unsigned int ix=0;ixprogenitor()->isFinalState()) { - pout[0] +=jets[ix]->progenitor()->momentum(); - _progenitor = jets[ix]->progenitor(); - if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { - reconstructTimeLikeJet(jets[ix]->progenitor()); - jets[ix]->reconstructed(ShowerProgenitor::done); - } - } - // initial-state parton - else { - pin[0] +=jets[ix]->progenitor()->momentum(); - if(jets[ix]->progenitor()->showerKinematics()) { - pbeam = jets[ix]->progenitor()->showerBasis()->getBasis()[0]; - } - else { - if ( jets[ix]->original()->parents().empty() ) { - pbeam = jets[ix]->progenitor()->momentum(); - } - else { - pbeam = jets[ix]->original()->parents()[0]->momentum(); - } - } - if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { - reconstructSpaceLikeJet(jets[ix]->progenitor()); - jets[ix]->reconstructed(ShowerProgenitor::done); - } - assert(!jets[ix]->original()->parents().empty()); - } - } - // add intrinsic pt if needed - addIntrinsicPt(jets); - // momenta after showering - for(unsigned int ix=0;ixprogenitor()->isFinalState()) - pout[1] += jets[ix]->progenitor()->momentum(); - else - pin[1] += jets[ix]->progenitor()->momentum(); - } - // work out the boost to the Breit frame - Lorentz5Momentum pa = pout[0]-pin[0]; - Axis axis(pa.vect().unit()); - LorentzRotation rot; - double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); - if ( sinth > 1.e-9 ) - rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); - rot.rotateX(Constants::pi); - rot.boostZ( pa.e()/pa.vect().mag()); - Lorentz5Momentum ptemp=rot*pbeam; - Boost trans = -1./ptemp.e()*ptemp.vect(); - trans.setZ(0.); - if ( trans.mag2() - 1. >= 0. ) throw KinematicsReconstructionVeto(); - rot.boost(trans); - pa *=rot; - // project and calculate rescaling - // reference vectors - Lorentz5Momentum n1(ZERO,ZERO,-pa.z(),-pa.z()); - Lorentz5Momentum n2(ZERO,ZERO, pa.z(),-pa.z()); - Energy2 n1n2 = n1*n2; - // decompose the momenta - Lorentz5Momentum qbp=rot*pin[1],qcp=rot*pout[1]; - qbp.rescaleMass(); - qcp.rescaleMass(); - double a[2],b[2]; - a[0] = n2*qbp/n1n2; - b[0] = n1*qbp/n1n2; - Lorentz5Momentum qperp = qbp-a[0]*n1-b[0]*n2; - b[1] = 0.5; - a[1] = 0.5*(qcp.m2()-qperp.m2())/n1n2/b[1]; - double kb; - if(a[0]!=0.) { - double A(0.5*a[0]),B(b[0]*a[0]-a[1]*b[1]-0.25),C(-0.5*b[0]); - if(sqr(B)-4.*A*C<0.) throw KinematicsReconstructionVeto(); - kb = 0.5*(-B+sqrt(sqr(B)-4.*A*C))/A; - } - else { - kb = 0.5*b[0]/(b[0]*a[0]-a[1]*b[1]-0.25); - } - // changed to improve stability - if(kb==0.) throw KinematicsReconstructionVeto(); - if ( a[1]>b[1] && abs(a[1]) < 1e-12 ) - throw KinematicsReconstructionVeto(); - if ( a[1]<=b[1] && abs(0.5+b[0]/kb) < 1e-12 ) - throw KinematicsReconstructionVeto(); - double kc = (a[1]>b[1]) ? (a[0]*kb-0.5)/a[1] : b[1]/(0.5+b[0]/kb); - if(kc==0.) throw KinematicsReconstructionVeto(); - Lorentz5Momentum pnew[2] = { a[0]*kb*n1+b[0]/kb*n2+qperp, - a[1]*kc*n1+b[1]/kc*n2+qperp}; - LorentzRotation rotinv=rot.inverse(); - for(unsigned int ix=0;ixprogenitor()->isFinalState()) { - deepTransform(jets[ix]->progenitor(),rot); - deepTransform(jets[ix]->progenitor(),solveBoost(pnew[1],qcp)); - Energy delta = jets[ix]->progenitor()->momentum().m()-jets[ix]->progenitor()->momentum().mass(); - if ( abs(delta) > MeV ) throw KinematicsReconstructionVeto(); - deepTransform(jets[ix]->progenitor(),rotinv); - } - else { - tPPtr parent; - boostChain(jets[ix]->progenitor(),rot,parent); - boostChain(jets[ix]->progenitor(),solveBoostZ(pnew[0],qbp),parent); - // check the first boost worked, and if not apply small correction to - // fix energy/momentum conservation - // this is a kludge but it reduces momentum non-conservation dramatically - Lorentz5Momentum pdiff = pnew[0]-jets[ix]->progenitor()->momentum(); - Energy2 delta = sqr(pdiff.x())+sqr(pdiff.y())+sqr(pdiff.z())+sqr(pdiff.t()); - unsigned int ntry=0; - while(delta>1e-6*GeV2 && ntry<5 ) { - ntry +=1; - boostChain(jets[ix]->progenitor(),solveBoostZ(pnew[0],jets[ix]->progenitor()->momentum()),parent); - pdiff = pnew[0]-jets[ix]->progenitor()->momentum(); - delta = sqr(pdiff.x())+sqr(pdiff.y())+sqr(pdiff.z())+sqr(pdiff.t()); - } - // apply test in breit-frame - Lorentz5Momentum ptest1 = parent->momentum(); - Lorentz5Momentum ptest2 = rot*pbeam; - if(ptest1.z()/ptest2.z()<0. || ptest1.z()/ptest2.z()>1.) - throw KinematicsReconstructionVeto(); - boostChain(jets[ix]->progenitor(),rotinv,parent); - } - } -} - -bool QTildeReconstructor::addIntrinsicPt(vector jets) const { - bool added=false; - // add the intrinsic pt if needed - for(unsigned int ix=0;ixprogenitor()->isFinalState()|| - jets[ix]->hasEmitted()|| - jets[ix]->reconstructed()==ShowerProgenitor::dontReconstruct) continue; - if(_intrinsic.find(jets[ix])==_intrinsic.end()) continue; - pair pt=_intrinsic[jets[ix]]; - Energy etemp = jets[ix]->original()->parents()[0]->momentum().z(); - Lorentz5Momentum - p_basis(ZERO, ZERO, etemp, abs(etemp)), - n_basis(ZERO, ZERO,-etemp, abs(etemp)); - double alpha = jets[ix]->progenitor()->x(); - double beta = 0.5*(sqr(jets[ix]->progenitor()->data().mass())+ - sqr(pt.first))/alpha/(p_basis*n_basis); - Lorentz5Momentum pnew=alpha*p_basis+beta*n_basis; - pnew.setX(pt.first*cos(pt.second)); - pnew.setY(pt.first*sin(pt.second)); - pnew.rescaleMass(); - jets[ix]->progenitor()->set5Momentum(pnew); - added = true; - } - return added; -} - -namespace { - -double defaultSolveBoostGamma(const double & betam,const Energy2 & kps, - const Energy2 & qs, const Energy2 & Q2, - const Energy & kp, - const Energy & q, const Energy & qE) { - if(betam<0.5) { - return 1./sqrt(1.-sqr(betam)); - } - else { - return ( kps+ qs + Q2)/ - sqrt(2.*kps*qs + kps*Q2 + qs*Q2 + sqr(Q2) + 2.*q*qE*kp*sqrt(kps + Q2)); - } -} - -} - -LorentzRotation QTildeReconstructor:: -solveBoost(const double k, const Lorentz5Momentum & newq, - const Lorentz5Momentum & oldp ) const { - Energy q = newq.vect().mag(); - Energy2 qs = sqr(q); - Energy2 Q2 = newq.mass2(); - Energy kp = k*(oldp.vect().mag()); - Energy2 kps = sqr(kp); - double betam = (q*newq.e() - kp*sqrt(kps + Q2))/(kps + qs + Q2); - if ( abs(betam) - 1. >= 0. ) throw KinematicsReconstructionVeto(); - Boost beta = -betam*(k/kp)*oldp.vect(); - double gamma = 0.; - if(Q2/sqr(oldp.e())>1e-4) { - gamma = defaultSolveBoostGamma(betam,kps,qs,Q2,kp,q,newq.e()); - } - else { - if(k>0) { - gamma = 4.*kps*qs/sqr(kps +qs) + 2.*sqr(kps-qs)*Q2/pow<3,1>(kps +qs) - - 0.25*( sqr(kps) + 14.*kps*qs + sqr(qs))*sqr(kps-qs)/(pow<4,1>(kps +qs)*kps*qs)*sqr(Q2); - } - else { - gamma = 0.25*sqr(Q2)/(kps*qs)*(1. - 0.5*(kps+qs)/(kps*qs)*Q2); - } - if(gamma<=0.) throw KinematicsReconstructionVeto(); - gamma = 1./sqrt(gamma); - if(gamma>2.) gamma = defaultSolveBoostGamma(betam,kps,qs,Q2,kp,q,newq.e()); - } - // note that (k/kp)*oldp.vect() = oldp.vect()/oldp.vect().mag() but cheaper. - ThreeVector ax = newq.vect().cross( oldp.vect() ); - double delta; - if (newq.x()*oldp.x()+newq.y()*oldp.y()+newq.z()*oldp.z()< 1e-16*GeV2) { - throw KinematicsReconstructionVeto(); - }else{ - delta = newq.vect().angle( oldp.vect() ); - } - - - LorentzRotation R; - using Constants::pi; - Energy2 scale1 = sqr(newq.x())+ sqr(newq.y())+sqr(newq.z()); - Energy2 scale2 = sqr(oldp.x())+ sqr(oldp.y())+sqr(oldp.z()); - if ( ax.mag2()/scale1/scale2 > 1e-28 ) { - R.rotate( delta, unitVector(ax) ).boost( beta , gamma ); - } - else if(abs(delta-pi)/pi < 0.001) { - double phi=2.*pi*UseRandom::rnd(); - Axis axis(cos(phi),sin(phi),0.); - axis.rotateUz(newq.vect().unit()); - R.rotate(delta,axis).boost( beta , gamma ); - } - else { - R.boost( beta , gamma ); - } - return R; -} - -LorentzRotation QTildeReconstructor::solveBoost(const Lorentz5Momentum & q, - const Lorentz5Momentum & p ) const { - Energy modp = p.vect().mag(); - Energy modq = q.vect().mag(); - double betam = (p.e()*modp-q.e()*modq)/(sqr(modq)+sqr(modp)+p.mass2()); - if ( abs(betam)-1. >= 0. ) throw KinematicsReconstructionVeto(); - Boost beta = -betam*q.vect().unit(); - ThreeVector ax = p.vect().cross( q.vect() ); - double delta = p.vect().angle( q.vect() ); - LorentzRotation R; - using Constants::pi; - if ( beta.mag2() - 1. >= 0. ) throw KinematicsReconstructionVeto(); - if ( ax.mag2()/GeV2/MeV2 > 1e-16 ) { - R.rotate( delta, unitVector(ax) ).boost( beta ); - } - else { - R.boost( beta ); - } - return R; -} - -LorentzRotation QTildeReconstructor::solveBoostZ(const Lorentz5Momentum & q, - const Lorentz5Momentum & p ) const { - static const double eps = 1e-6; - LorentzRotation R; - double beta; - Energy2 mt2 = p.mass()eps) { - double erat = (q.t()+q.z())/(p.t()+p.z()); - Energy2 den = mt2*(erat+1./erat); - Energy2 num = (q.z()-p.z())*(q.t()+p.t()) + (p.z()+q.z())*(p.t()-q.t()); - beta = num/den; - if ( abs(beta) - 1. >= 0. ) throw KinematicsReconstructionVeto(); - R.boostZ(beta); - } - else { - double er = sqr(p.t()/q.t()); - double x = ratio+0.125*(er+10.+1./er)*sqr(ratio); - beta = -(p.t()-q.t())*(p.t()+q.t())/(sqr(p.t())+sqr(q.t()))*(1.+x); - double gamma = (4.*sqr(p.t()*q.t()) +sqr(p.t()-q.t())*sqr(p.t()+q.t())* - (-2.*x+sqr(x)))/sqr(sqr(p.t())+sqr(q.t())); - if ( abs(beta) - 1. >= 0. ) throw KinematicsReconstructionVeto(); - gamma = 1./sqrt(gamma); - R.boost(0.,0.,beta,gamma); - } - Lorentz5Momentum ptest = R*p; - if(ptest.z()/q.z() < 0. || ptest.t()/q.t() < 0. ) { - throw KinematicsReconstructionVeto(); - } - return R; -} - -void QTildeReconstructor:: -reconstructFinalStateSystem(bool applyBoost, - const LorentzRotation & toRest, - const LorentzRotation & fromRest, - vector jets) const { - LorentzRotation trans = applyBoost? toRest : LorentzRotation(); - // special for case of individual particle - if(jets.size()==1) { - deepTransform(jets[0]->progenitor(),trans); - deepTransform(jets[0]->progenitor(),fromRest); - return; - } - bool radiated(false); - // find the hard process centre-of-mass energy - Lorentz5Momentum pcm; - // check if radiated and calculate total momentum - for(unsigned int ix=0;ixhasEmitted(); - pcm += jets[ix]->progenitor()->momentum(); - } - if(applyBoost) pcm *= trans; - // check if in CMF frame - Boost beta_cm = pcm.findBoostToCM(); - bool gottaBoost(false); - if(beta_cm.mag() > 1e-12) { - gottaBoost = true; - trans.boost(beta_cm); - } - // collection of pointers to initial hard particle and jet momenta - // for final boosts - JetKinVect jetKinematics; - vector::const_iterator cit; - for(cit = jets.begin(); cit != jets.end(); cit++) { - JetKinStruct tempJetKin; - tempJetKin.parent = (*cit)->progenitor(); - if(applyBoost || gottaBoost) { - deepTransform(tempJetKin.parent,trans); - } - tempJetKin.p = (*cit)->progenitor()->momentum(); - _progenitor=tempJetKin.parent; - if((**cit).reconstructed()==ShowerProgenitor::notReconstructed) { - radiated |= reconstructTimeLikeJet((*cit)->progenitor()); - (**cit).reconstructed(ShowerProgenitor::done); - } - else { - radiated |= !(*cit)->progenitor()->children().empty(); - } - tempJetKin.q = (*cit)->progenitor()->momentum(); - jetKinematics.push_back(tempJetKin); - } - // default option rescale everything with the same factor - if( _finalStateReconOption == 0 || jetKinematics.size() <= 2 ) { - // find the rescaling factor - double k = 0.0; - if(radiated) { - k = solveKfactor(pcm.m(), jetKinematics); - // perform the rescaling and boosts - for(JetKinVect::iterator it = jetKinematics.begin(); - it != jetKinematics.end(); ++it) { - LorentzRotation Trafo = solveBoost(k, it->q, it->p); - deepTransform(it->parent,Trafo); - } - } - } - // different treatment of most off-shell - else if ( _finalStateReconOption <= 4 ) { - // sort the jets by virtuality - std::sort(jetKinematics.begin(),jetKinematics.end(),JetOrdering()); - // Bryan's procedures from FORTRAN - if( _finalStateReconOption <=2 ) { - // loop over the off-shell partons, _finalStateReconOption==1 only first ==2 all - JetKinVect::const_iterator jend = _finalStateReconOption==1 ? jetKinematics.begin()+1 : jetKinematics.end(); - for(JetKinVect::const_iterator jit=jetKinematics.begin(); jit!=jend;++jit) { - // calculate the 4-momentum of the recoiling system - Lorentz5Momentum psum; - bool done = true; - for(JetKinVect::const_iterator it=jetKinematics.begin();it!=jetKinematics.end();++it) { - if(it==jit) { - done = false; - continue; - } - // first option put on-shell and sum 4-momenta - if( _finalStateReconOption == 1 ) { - LorentzRotation Trafo = solveBoost(1., it->q, it->p); - deepTransform(it->parent,Trafo); - psum += it->parent->momentum(); - } - // second option, sum momenta - else { - // already rescaled - if(done) psum += it->parent->momentum(); - // still needs to be rescaled - else psum += it->p; - } - } - // set the mass - psum.rescaleMass(); - // calculate the 3-momentum rescaling factor - Energy2 s(pcm.m2()); - Energy2 m1sq(jit->q.m2()),m2sq(psum.m2()); - Energy4 num = sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq; - if(nump.vect().mag2()) ); - // boost the off-shell parton - LorentzRotation B1 = solveBoost(k, jit->q, jit->p); - deepTransform(jit->parent,B1); - // boost everything else to rescale - LorentzRotation B2 = solveBoost(k, psum, psum); - for(JetKinVect::iterator it=jetKinematics.begin();it!=jetKinematics.end();++it) { - if(it==jit) continue; - deepTransform(it->parent,B2); - it->p *= B2; - it->q *= B2; - } - } - } - // Peter's C++ procedures - else { - reconstructFinalFinalOffShell(jetKinematics,pcm.m2(), _finalStateReconOption == 4); - } - } - else - assert(false); - // apply the final boosts - if(gottaBoost || applyBoost) { - LorentzRotation finalBoosts; - if(gottaBoost) finalBoosts.boost(-beta_cm); - if(applyBoost) finalBoosts.transform(fromRest); - for(JetKinVect::iterator it = jetKinematics.begin(); - it != jetKinematics.end(); ++it) { - deepTransform(it->parent,finalBoosts); - } - } -} - -void QTildeReconstructor:: -reconstructInitialInitialSystem(bool & applyBoost, - LorentzRotation & toRest, - LorentzRotation & fromRest, - vector jets) const { - bool radiated = false; - Lorentz5Momentum pcm; - // check whether particles radiated and calculate total momentum - for( unsigned int ix = 0; ix < jets.size(); ++ix ) { - radiated |= jets[ix]->hasEmitted(); - pcm += jets[ix]->progenitor()->momentum(); - if(jets[ix]->original()->parents().empty()) return; - } - pcm.rescaleMass(); - // check if intrinsic pt to be added - radiated |= !_intrinsic.empty(); - // if no radiation return - if(!radiated) { - for(unsigned int ix=0;ixreconstructed()==ShowerProgenitor::notReconstructed) - jets[ix]->reconstructed(ShowerProgenitor::done); - } - return; - } - // initial state shuffling - applyBoost=false; - vector p, pq, p_in; - vector pts; - for(unsigned int ix=0;ixprogenitor()->momentum()); - // reconstruct the jet - if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { - radiated |= reconstructSpaceLikeJet(jets[ix]->progenitor()); - jets[ix]->reconstructed(ShowerProgenitor::done); - } - assert(!jets[ix]->original()->parents().empty()); - Energy etemp = jets[ix]->original()->parents()[0]->momentum().z(); - Lorentz5Momentum ptemp = Lorentz5Momentum(ZERO, ZERO, etemp, abs(etemp)); - pq.push_back(ptemp); - pts.push_back(jets[ix]->highestpT()); - } - // add the intrinsic pt if needed - radiated |=addIntrinsicPt(jets); - for(unsigned int ix=0;ixprogenitor()->momentum()); - } - double x1 = p_in[0].z()/pq[0].z(); - double x2 = p_in[1].z()/pq[1].z(); - vector beta=initialStateRescaling(x1,x2,p_in[0]+p_in[1],p,pq,pts); - // if not need don't apply boosts - if(!(radiated && p.size() == 2 && pq.size() == 2)) return; - applyBoost=true; - // apply the boosts - Lorentz5Momentum newcmf; - for(unsigned int ix=0;ixprogenitor(); - Boost betaboost(0, 0, beta[ix]); - tPPtr parent; - boostChain(toBoost, LorentzRotation(0.,0.,beta[ix]),parent); - if(parent->momentum().e()/pq[ix].e()>1.|| - parent->momentum().z()/pq[ix].z()>1.) throw KinematicsReconstructionVeto(); - newcmf+=toBoost->momentum(); - } - if(newcmf.m() jets, - ShowerInteraction) const { - assert(jets.size()==2); - // put beam with +z first - if(jets[0]->beam()->momentum().z() pin,pq; - for(unsigned int ix=0;ixbranchingParticle()->momentum()); - Energy etemp = jets[ix]->beam()->momentum().z(); - pq.push_back(Lorentz5Momentum(ZERO, ZERO,etemp, abs(etemp))); - } - // calculate the rescaling - double x[2]; - Lorentz5Momentum pcm=pin[0]+pin[1]; - assert(pcm.mass2()>ZERO); - pcm.rescaleMass(); - vector boost = inverseInitialStateRescaling(x[0],x[1],pcm,pin,pq); - set::const_iterator cjt=tree->incoming().begin(); - HardBranchingPtr incoming[2]; - incoming[0] = *cjt; - ++cjt; - incoming[1] = *cjt; - if((*tree->incoming().begin())->beam()->momentum().z()/pq[0].z()<0.) - swap(incoming[0],incoming[1]); - // apply the boost the the particles - unsigned int iswap[2]={1,0}; - for(unsigned int ix=0;ix<2;++ix) { - LorentzRotation R(0.,0.,-boost[ix]); - incoming[ix]->pVector(pq[ix]); - incoming[ix]->nVector(pq[iswap[ix]]); - incoming[ix]->setMomenta(R,1.,Lorentz5Momentum()); - jets[ix]->showerMomentum(x[ix]*jets[ix]->pVector()); - } - // and calculate the boosts - applyBoost=true; - // do one boost - if(_initialBoost==0) { - toRest = LorentzRotation(-pcm.boostVector()); - } - else if(_initialBoost==1) { - // first the transverse boost - Energy pT = sqrt(sqr(pcm.x())+sqr(pcm.y())); - double beta = -pT/pcm.t(); - toRest=LorentzRotation(Boost(beta*pcm.x()/pT,beta*pcm.y()/pT,0.)); - // the longitudinal - beta = pcm.z()/sqrt(pcm.m2()+sqr(pcm.z())); - toRest.boost(Boost(0.,0.,-beta)); - } - else - assert(false); - fromRest = LorentzRotation((jets[0]->showerMomentum()+ - jets[1]->showerMomentum()).boostVector()); -} - -void QTildeReconstructor:: -deconstructFinalStateSystem(const LorentzRotation & toRest, - const LorentzRotation & fromRest, - HardTreePtr tree, vector jets, - ShowerInteraction type) const { - LorentzRotation trans = toRest; - if(jets.size()==1) { - Lorentz5Momentum pnew = toRest*(jets[0]->branchingParticle()->momentum()); - pnew *= fromRest; - jets[0]-> original(pnew); - jets[0]->showerMomentum(pnew); - // find the colour partners - ShowerParticleVector particles; - vector ptemp; - set::const_iterator cjt; - for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { - ptemp.push_back((**cjt).branchingParticle()->momentum()); - (**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum()); - particles.push_back((**cjt).branchingParticle()); - } - dynamic_ptr_cast(ShowerHandler::currentHandler())->showerModel()->partnerFinder() - ->setInitialEvolutionScales(particles,false,type,false); - // calculate the reference vectors - unsigned int iloc(0); - set::iterator clt; - for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { - // reset the momentum - (**cjt).branchingParticle()->set5Momentum(ptemp[iloc]); - ++iloc; - // sort out the partners - tShowerParticlePtr partner = - (*cjt)->branchingParticle()->partner(); - if(!partner) continue; - for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { - if((**clt).branchingParticle()==partner) { - (**cjt).colourPartner(*clt); - break; - } - } - tHardBranchingPtr branch; - for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { - if(clt==cjt) continue; - if((*clt)->branchingParticle()==partner) { - branch=*clt; - break; - } - } - } - return; - } - vector::iterator cit; - vector pout; - vector mon; - Lorentz5Momentum pin; - for(cit=jets.begin();cit!=jets.end();++cit) { - pout.push_back((*cit)->branchingParticle()->momentum()); - mon.push_back(findMass(*cit)); - pin+=pout.back(); - } - // boost all the momenta to the rest frame of the decaying particle - pin.rescaleMass(); - pin *=trans; - Boost beta_cm = pin.findBoostToCM(); - bool gottaBoost(false); - if(beta_cm.mag() > 1e-12) { - gottaBoost = true; - trans.boost(beta_cm); - pin.boost(beta_cm); - } - for(unsigned int ix=0;ixbranchingParticle()->momentum(); - pvect.transform(trans); - pvect /= lambda; - pvect.setMass(mon[ix]); - pvect.rescaleEnergy(); - if(gottaBoost) pvect.boost(-beta_cm); - pvect.transform(fromRest); - jets[ix]->pVector(pvect); - jets[ix]->showerMomentum(pvect); - } - // find the colour partners - ShowerParticleVector particles; - vector ptemp; - set::const_iterator cjt; - for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { - ptemp.push_back((**cjt).branchingParticle()->momentum()); - (**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum()); - particles.push_back((**cjt).branchingParticle()); - } - dynamic_ptr_cast(ShowerHandler::currentHandler())->showerModel()->partnerFinder() - ->setInitialEvolutionScales(particles,false,type,false); - // calculate the reference vectors - unsigned int iloc(0); - set::iterator clt; - for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { - // reset the momentum - (**cjt).branchingParticle()->set5Momentum(ptemp[iloc]); - ++iloc; - } - for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { - // sort out the partners - tShowerParticlePtr partner = - (*cjt)->branchingParticle()->partner(); - if(!partner) continue; - for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { - if((**clt).branchingParticle()==partner) { - (**cjt).colourPartner(*clt); - break; - } - } - tHardBranchingPtr branch; - for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { - if(clt==cjt) continue; - if((*clt)->branchingParticle()==partner) { - branch=*clt; - break; - } - } - // compute the reference vectors - // both incoming, should all ready be done - if((**cjt).status()==HardBranching::Incoming && - (**clt).status()==HardBranching::Incoming) { - continue; - } - // both outgoing - else if((**cjt).status()!=HardBranching::Incoming&& - branch->status()==HardBranching::Outgoing) { - Boost boost=((*cjt)->pVector()+branch->pVector()).findBoostToCM(); - Lorentz5Momentum pcm = branch->pVector(); - pcm.boost(boost); - Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect()); - nvect.boost( -boost); - (**cjt).nVector(nvect); - } - else if((**cjt).status()==HardBranching::Incoming) { - Lorentz5Momentum pa = -(**cjt).showerMomentum()+branch->showerMomentum(); - Lorentz5Momentum pb = (**cjt).showerMomentum(); - Axis axis(pa.vect().unit()); - LorentzRotation rot; - double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); - rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); - rot.rotateX(Constants::pi); - rot.boostZ( pa.e()/pa.vect().mag()); - pb*=rot; - Boost trans = -1./pb.e()*pb.vect(); - trans.setZ(0.); - rot.boost(trans); - Energy scale=(**cjt).beam()->momentum().e(); - Lorentz5Momentum pbasis(ZERO,(**cjt).beam()->momentum().vect().unit()*scale); - Lorentz5Momentum pcm = rot*pbasis; - rot.invert(); - (**cjt).nVector(rot*Lorentz5Momentum(ZERO,-pcm.vect())); - tHardBranchingPtr branch2 = *cjt;; - while (branch2->parent()) { - branch2=branch2->parent(); - branch2->nVector(rot*Lorentz5Momentum(ZERO,-pcm.vect())); - } - } - else if(branch->status()==HardBranching::Incoming) { - (**cjt).nVector(Lorentz5Momentum(ZERO,branch->showerMomentum().vect())); - } - } - // now compute the new momenta - for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { - if(!(*cjt)->branchingParticle()->isFinalState()) continue; - Lorentz5Momentum qnew; - if((*cjt)->branchingParticle()->partner()) { - Energy2 dot=(*cjt)->pVector()*(*cjt)->nVector(); - double beta = 0.5*((*cjt)->branchingParticle()->momentum().m2() - -sqr((*cjt)->pVector().mass()))/dot; - qnew=(*cjt)->pVector()+beta*(*cjt)->nVector(); - qnew.rescaleMass(); - } - else { - qnew = (*cjt)->pVector(); - } - // qnew is the unshuffled momentum in the rest frame of the p basis vectors, - // for the simple case Z->q qbar g this was checked against analytic formulae. - // compute the boost - LorentzRotation R=solveBoost(qnew, - toRest*(*cjt)->branchingParticle()->momentum())*toRest; - (*cjt)->setMomenta(R,1.0,Lorentz5Momentum()); - } -} - -Energy QTildeReconstructor::momConsEq(double k, - const Energy & root_s, - const JetKinVect & jets) const { - static const Energy2 eps=1e-8*GeV2; - Energy dum = ZERO; - for(JetKinVect::const_iterator it = jets.begin(); it != jets.end(); ++it) { - Energy2 dum2 = (it->q).m2() + sqr(k)*(it->p).vect().mag2(); - if(dum2 < ZERO) { - if(dum2 < -eps) throw KinematicsReconstructionVeto(); - dum2 = ZERO; - } - dum += sqrt(dum2); - } - return dum - root_s; -} - -void QTildeReconstructor::boostChain(tPPtr p, const LorentzRotation &bv, - tPPtr & parent) const { - if(!p->parents().empty()) boostChain(p->parents()[0], bv,parent); - else parent=p; - p->transform(bv); - if(p->children().size()==2) { - if(dynamic_ptr_cast(p->children()[1])) - deepTransform(p->children()[1],bv); - } -} - -namespace { - -bool sortJets(ShowerProgenitorPtr j1, ShowerProgenitorPtr j2) { - return j1->highestpT()>j2->highestpT(); -} - -} - -void QTildeReconstructor:: -reconstructGeneralSystem(vector & ShowerHardJets) const { - // find initial- and final-state systems - ColourSingletSystem in,out; - for(unsigned int ix=0;ixprogenitor()->isFinalState()) - out.jets.push_back(ShowerHardJets[ix]); - else - in.jets.push_back(ShowerHardJets[ix]); - } - // reconstruct initial-initial system - LorentzRotation toRest,fromRest; - bool applyBoost(false); - // reconstruct initial-initial system - reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets); - // reconstruct the final-state systems - reconstructFinalStateSystem(applyBoost,toRest,fromRest,out.jets); -} - - -void QTildeReconstructor:: -reconstructFinalFirst(vector & ShowerHardJets) const { - static const Energy2 minQ2 = 1e-4*GeV2; - map used; - for(unsigned int ix=0;ix outgoing; - // first find any particles with final state partners - for(unsigned int ix=0;ixprogenitor()->isFinalState()&& - ShowerHardJets[ix]->progenitor()->partner()&& - ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) outgoing.insert(ShowerHardJets[ix]); - } - // then find the colour partners - if(!outgoing.empty()) { - set partners; - for(set::const_iterator it=outgoing.begin();it!=outgoing.end();++it) { - for(unsigned int ix=0;ixpartner()==ShowerHardJets[ix]->progenitor()) { - partners.insert(ShowerHardJets[ix]); - break; - } - } - } - outgoing.insert(partners.begin(),partners.end()); - } - // do the final-state reconstruction if needed - if(!outgoing.empty()) { - assert(outgoing.size()!=1); - LorentzRotation toRest,fromRest; - vector outgoingJets(outgoing.begin(),outgoing.end()); - reconstructFinalStateSystem(false,toRest,fromRest,outgoingJets); - } - // Now do any initial-final systems which are needed - vector IFSystems; - // find the systems N.B. can have duplicates - // find initial-state with FS partners or FS with IS partners - for(unsigned int ix=0;ixprogenitor()->isFinalState()&& - ShowerHardJets[ix]->progenitor()->partner()&& - ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) { - IFSystems.push_back(ColourSingletSystem(IF,ShowerHardJets[ix])); - } - else if(ShowerHardJets[ix]->progenitor()->isFinalState()&& - ShowerHardJets[ix]->progenitor()->partner()&& - !ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) { - IFSystems.push_back(ColourSingletSystem(IF,ShowerHardJets[ix])); - } - } - // then add the partners - for(unsigned int is=0;isprogenitor()->partner()==ShowerHardJets[ix]->progenitor()) { - IFSystems[is].jets.push_back(ShowerHardJets[ix]); - } - } - // ensure incoming first - if(IFSystems[is].jets[0]->progenitor()->isFinalState()) - swap(IFSystems[is].jets[0],IFSystems[is].jets[1]); - } - if(!IFSystems.empty()) { - unsigned int istart = UseRandom::irnd(IFSystems.size()); - unsigned int istop=IFSystems.size(); - for(unsigned int is=istart;is<=istop;++is) { - if(is==IFSystems.size()) { - if(istart!=0) { - istop = istart-1; - is=0; - } - else break; - } - // skip duplicates - if(used[IFSystems[is].jets[0]] && - used[IFSystems[is].jets[1]] ) continue; - if(IFSystems[is].jets[0]->original()&&IFSystems[is].jets[0]->original()->parents().empty()) continue; - Lorentz5Momentum psum; - for(unsigned int ix=0;ixprogenitor()->isFinalState()) - psum += IFSystems[is].jets[ix]->progenitor()->momentum(); - else - psum -= IFSystems[is].jets[ix]->progenitor()->momentum(); - } - if(-psum.m2()>minQ2) { - reconstructInitialFinalSystem(IFSystems[is].jets); - for(unsigned int ix=0;ixprogenitor()->isFinalState()) - out.jets.push_back(ShowerHardJets[ix]); - else - in.jets.push_back(ShowerHardJets[ix]); - } - // reconstruct initial-initial system - bool doRecon = false; - for(unsigned int ix=0;ix & ShowerHardJets) const { - static const Energy2 minQ2 = 1e-4*GeV2; - // sort the vector by hardness of emission - std::sort(ShowerHardJets.begin(),ShowerHardJets.end(),sortJets); - // map between particles and progenitors for easy lookup - map progenitorMap; - for(unsigned int ix=0;ixprogenitor()] = ShowerHardJets[ix]; - } - // check that the IF systems can be reconstructed - bool canReconstruct = true; - for(unsigned int ix=0;ixprogenitor(); - tShowerParticlePtr partner = progenitor->partner(); - if(!partner) continue; - else if((progenitor->isFinalState() && - !partner->isFinalState()) || - (!progenitor->isFinalState() && - partner->isFinalState()) ) { - vector jets(2); - jets[0] = ShowerHardJets[ix]; - jets[1] = progenitorMap[partner]; - Lorentz5Momentum psum; - for(unsigned int iy=0;iyprogenitor()->isFinalState()) - psum += jets[iy]->progenitor()->momentum(); - else - psum -= jets[iy]->progenitor()->momentum(); - } - if(-psum.m2() used; - for(unsigned int ix=0;ixreconstructed()==ShowerProgenitor::done) continue; - // already reconstructed - if(used[ShowerHardJets[ix]]) continue; - // no partner continue - tShowerParticlePtr progenitor = ShowerHardJets[ix]->progenitor(); - tShowerParticlePtr partner = progenitor->partner(); - if(!partner) { - // check if there's a daughter tree which also needs boosting - Lorentz5Momentum porig = progenitor->momentum(); - map >::const_iterator tit; - for(tit = _currentTree->treelinks().begin(); - tit != _currentTree->treelinks().end();++tit) { - // if there is, boost it - if(tit->second.first && tit->second.second==progenitor) { - Lorentz5Momentum pnew = tit->first->incomingLines().begin() - ->first->progenitor()->momentum(); - pnew *= tit->first->transform(); - Lorentz5Momentum pdiff = porig-pnew; - Energy2 test = sqr(pdiff.x()) + sqr(pdiff.y()) + - sqr(pdiff.z()) + sqr(pdiff.t()); - LorentzRotation rot; - if(test>1e-6*GeV2) rot = solveBoost(porig,pnew); - tit->first->transform(rot,false); - _treeBoosts[tit->first].push_back(rot); - } - } - ShowerHardJets[ix]->reconstructed(ShowerProgenitor::done); - continue; - } - // do the reconstruction - // final-final - if(progenitor->isFinalState() && - partner->isFinalState() ) { - LorentzRotation toRest,fromRest; - vector jets(2); - jets[0] = ShowerHardJets[ix]; - jets[1] = progenitorMap[partner]; - if(_reconopt==4 && jets[1]->reconstructed()==ShowerProgenitor::notReconstructed) - jets[1]->reconstructed(ShowerProgenitor::dontReconstruct); - reconstructFinalStateSystem(false,toRest,fromRest,jets); - if(_reconopt==4 && jets[1]->reconstructed()==ShowerProgenitor::dontReconstruct) - jets[1]->reconstructed(ShowerProgenitor::notReconstructed); - used[jets[0]] = true; - if(_reconopt==3) used[jets[1]] = true; - } - // initial-final - else if((progenitor->isFinalState() && - !partner->isFinalState()) || - (!progenitor->isFinalState() && - partner->isFinalState()) ) { - vector jets(2); - jets[0] = ShowerHardJets[ix]; - jets[1] = progenitorMap[partner]; - if(jets[0]->progenitor()->isFinalState()) swap(jets[0],jets[1]); - if(jets[0]->original()&&jets[0]->original()->parents().empty()) continue; - Lorentz5Momentum psum; - for(unsigned int iy=0;iyprogenitor()->isFinalState()) - psum += jets[iy]->progenitor()->momentum(); - else - psum -= jets[iy]->progenitor()->momentum(); - } - if(_reconopt==4 && progenitorMap[partner]->reconstructed()==ShowerProgenitor::notReconstructed) - progenitorMap[partner]->reconstructed(ShowerProgenitor::dontReconstruct); - reconstructInitialFinalSystem(jets); - if(_reconopt==4 && progenitorMap[partner]->reconstructed()==ShowerProgenitor::dontReconstruct) - progenitorMap[partner]->reconstructed(ShowerProgenitor::notReconstructed); - used[ShowerHardJets[ix]] = true; - if(_reconopt==3) used[progenitorMap[partner]] = true; - } - // initial-initial - else if(!progenitor->isFinalState() && - !partner->isFinalState() ) { - ColourSingletSystem in,out; - in.jets.push_back(ShowerHardJets[ix]); - in.jets.push_back(progenitorMap[partner]); - for(unsigned int iy=0;iyprogenitor()->isFinalState()) - out.jets.push_back(ShowerHardJets[iy]); - } - LorentzRotation toRest,fromRest; - bool applyBoost(false); - if(_reconopt==4 && in.jets[1]->reconstructed()==ShowerProgenitor::notReconstructed) - in.jets[1]->reconstructed(ShowerProgenitor::dontReconstruct); - reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets); - if(_reconopt==4 && in.jets[1]->reconstructed()==ShowerProgenitor::dontReconstruct) - in.jets[1]->reconstructed(ShowerProgenitor::notReconstructed); - used[in.jets[0]] = true; - if(_reconopt==3) used[in.jets[1]] = true; - for(unsigned int iy=0;iyreconstructed()==ShowerProgenitor::notReconstructed) - out.jets[iy]->reconstructed(ShowerProgenitor::dontReconstruct); - } - // reconstruct the final-state systems - LorentzRotation finalBoosts; - finalBoosts.transform( toRest); - finalBoosts.transform(fromRest); - for(unsigned int iy=0;iyprogenitor(),finalBoosts); - } - for(unsigned int iy=0;iyreconstructed()==ShowerProgenitor::dontReconstruct) - out.jets[iy]->reconstructed(ShowerProgenitor::notReconstructed); - } - } - } -} - -bool QTildeReconstructor:: -inverseDecayRescalingFactor(vector pout, - vector mon,Energy roots, - Lorentz5Momentum ppartner, Energy mbar, - double & k1, double & k2) const { - ThreeVector qtotal; - vector pmag; - for(unsigned int ix=0;ix1e10) return false; - } - while (abs(numer)>eps&&itry<100); - k1 = abs(k1); - k2 = a*k1; - return itry<100; -} - -void QTildeReconstructor:: -deconstructInitialFinalSystem(HardTreePtr tree,vector jets, - ShowerInteraction type) const { - HardBranchingPtr incoming; - Lorentz5Momentum pin[2],pout[2],pbeam; - HardBranchingPtr initial; - Energy mc(ZERO); - for(unsigned int ix=0;ixstatus()==HardBranching::Outgoing) { - pout[0] += jets[ix]->branchingParticle()->momentum(); - mc = jets[ix]->branchingParticle()->thePEGBase() ? - jets[ix]->branchingParticle()->thePEGBase()->mass() : - jets[ix]->branchingParticle()->dataPtr()->mass(); - } - // initial-state parton - else { - pin[0] += jets[ix]->branchingParticle()->momentum(); - initial = jets[ix]; - pbeam = jets[ix]->beam()->momentum(); - Energy scale=pbeam.t(); - pbeam = Lorentz5Momentum(ZERO,pbeam.vect().unit()*scale); - incoming = jets[ix]; - while(incoming->parent()) incoming = incoming->parent(); - } - } - if(jets.size()>2) { - pout[0].rescaleMass(); - mc = pout[0].mass(); - } - // work out the boost to the Breit frame - Lorentz5Momentum pa = pout[0]-pin[0]; - Axis axis(pa.vect().unit()); - LorentzRotation rot; - double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); - if(axis.perp2()>0.) { - rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); - rot.rotateX(Constants::pi); - rot.boostZ( pa.e()/pa.vect().mag()); - } - // transverse part - Lorentz5Momentum paxis=rot*pbeam; - Boost trans = -1./paxis.e()*paxis.vect(); - trans.setZ(0.); - rot.boost(trans); - pa *= rot; - // reference vectors - Lorentz5Momentum n1(ZERO,ZERO,-pa.z(),-pa.z()); - Lorentz5Momentum n2(ZERO,ZERO, pa.z(),-pa.z()); - Energy2 n1n2 = n1*n2; - // decompose the momenta - Lorentz5Momentum qbp=rot*pin[0],qcp= rot*pout[0]; - double a[2],b[2]; - a[0] = n2*qbp/n1n2; - b[0] = n1*qbp/n1n2; - a[1] = n2*qcp/n1n2; - b[1] = n1*qcp/n1n2; - Lorentz5Momentum qperp = qbp-a[0]*n1-b[0]*n2; - // before reshuffling - Energy Q = abs(pa.z()); - double c = sqr(mc/Q); - Lorentz5Momentum pb(ZERO,ZERO,0.5*Q*(1.+c),0.5*Q*(1.+c)); - Lorentz5Momentum pc(ZERO,ZERO,0.5*Q*(c-1.),0.5*Q*(1.+c)); - double anew[2],bnew[2]; - anew[0] = pb*n2/n1n2; - bnew[0] = 0.5*(qbp.m2()-qperp.m2())/n1n2/anew[0]; - bnew[1] = pc*n1/n1n2; - anew[1] = 0.5*qcp.m2()/bnew[1]/n1n2; - Lorentz5Momentum qnewb = (anew[0]*n1+bnew[0]*n2+qperp); - Lorentz5Momentum qnewc = (anew[1]*n1+bnew[1]*n2); - // initial-state boost - LorentzRotation rotinv=rot.inverse(); - LorentzRotation transb=rotinv*solveBoostZ(qnewb,qbp)*rot; - // final-state boost - LorentzRotation transc=rotinv*solveBoost(qnewc,qcp)*rot; - // this will need changing for more than one outgoing particle - // set the pvectors - for(unsigned int ix=0;ixstatus()==HardBranching::Incoming) { - jets[ix]->pVector(pbeam); - jets[ix]->showerMomentum(rotinv*pb); - incoming->pVector(jets[ix]->pVector()); - } - else { - jets[ix]->pVector(rotinv*pc); - jets[ix]->showerMomentum(jets[ix]->pVector()); - } - } - // find the colour partners - ShowerParticleVector particles; - vector ptemp; - set::const_iterator cjt; - for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { - ptemp.push_back((**cjt).branchingParticle()->momentum()); - (**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum()); - particles.push_back((**cjt).branchingParticle()); - } - dynamic_ptr_cast(ShowerHandler::currentHandler())->showerModel()->partnerFinder() - ->setInitialEvolutionScales(particles,false,type,false); - unsigned int iloc(0); - for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { - // reset the momentum - (**cjt).branchingParticle()->set5Momentum(ptemp[iloc]); - ++iloc; - } - for(vector::const_iterator cjt=jets.begin(); - cjt!=jets.end();++cjt) { - // sort out the partners - tShowerParticlePtr partner = - (*cjt)->branchingParticle()->partner(); - if(!partner) continue; - tHardBranchingPtr branch; - for(set::const_iterator - clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { - if((**clt).branchingParticle()==partner) { - (**cjt).colourPartner(*clt); - branch=*clt; - break; - } - } - // compute the reference vectors - // both incoming, should all ready be done - if((**cjt).status()==HardBranching::Incoming && - branch->status()==HardBranching::Incoming) { - Energy etemp = (*cjt)->beam()->momentum().z(); - Lorentz5Momentum nvect(ZERO, ZERO,-etemp, abs(etemp)); - tHardBranchingPtr branch2 = *cjt; - (**cjt).nVector(nvect); - while (branch2->parent()) { - branch2=branch2->parent(); - branch2->nVector(nvect); - } - } - // both outgoing - else if((**cjt).status()==HardBranching::Outgoing&& - branch->status()==HardBranching::Outgoing) { - Boost boost=((*cjt)->pVector()+branch->pVector()).findBoostToCM(); - Lorentz5Momentum pcm = branch->pVector(); - pcm.boost(boost); - Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect()); - nvect.boost( -boost); - (**cjt).nVector(nvect); - } - else if((**cjt).status()==HardBranching::Incoming) { - Lorentz5Momentum pa = -(**cjt).showerMomentum()+branch->showerMomentum(); - Lorentz5Momentum pb = (**cjt).showerMomentum(); - Axis axis(pa.vect().unit()); - LorentzRotation rot; - double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); - if(axis.perp2()>1e-20) { - rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); - rot.rotateX(Constants::pi); - } - if(abs(1.-pa.e()/pa.vect().mag())>1e-6) rot.boostZ( pa.e()/pa.vect().mag()); - pb*=rot; - Boost trans = -1./pb.e()*pb.vect(); - trans.setZ(0.); - rot.boost(trans); - Energy scale=(**cjt).beam()->momentum().t(); - Lorentz5Momentum pbasis(ZERO,(**cjt).beam()->momentum().vect().unit()*scale); - Lorentz5Momentum pcm = rot*pbasis; - rot.invert(); - Lorentz5Momentum nvect = rot*Lorentz5Momentum(ZERO,-pcm.vect()); - (**cjt).nVector(nvect); - tHardBranchingPtr branch2 = *cjt; - while (branch2->parent()) { - branch2=branch2->parent(); - branch2->nVector(nvect); - } - } - else if(branch->status()==HardBranching::Incoming) { - Lorentz5Momentum nvect=Lorentz5Momentum(ZERO,branch->showerMomentum().vect()); - (**cjt).nVector(nvect); - } - } - // now compute the new momenta - for(vector::const_iterator cjt=jets.begin(); - cjt!=jets.end();++cjt) { - if((**cjt).status()==HardBranching::Outgoing) { - (**cjt).setMomenta(transc,1.,Lorentz5Momentum()); - } - } - incoming->setMomenta(transb,1.,Lorentz5Momentum()); -} - -void QTildeReconstructor::deepTransform(PPtr particle, - const LorentzRotation & r, - bool match, - PPtr original) const { - if(_boosts.find(particle)!=_boosts.end()) { - _boosts[particle].push_back(r); - } - Lorentz5Momentum porig = particle->momentum(); - if(!original) original = particle; - for ( int i = 0, N = particle->children().size(); i < N; ++i ) { - deepTransform(particle->children()[i],r, - particle->children()[i]->id()==original->id()&&match,original); - } - particle->transform(r); - // transform the p and n vectors - ShowerParticlePtr sparticle = dynamic_ptr_cast(particle); - if(sparticle && sparticle->showerBasis()) { - sparticle->showerBasis()->transform(r); - } - if ( particle->next() ) deepTransform(particle->next(),r,match,original); - if(!match) return; - if(!particle->children().empty()) return; - // force the mass shell - if(particle->dataPtr()->stable()) { - Lorentz5Momentum ptemp = particle->momentum(); - ptemp.rescaleEnergy(); - particle->set5Momentum(ptemp); - } - // check if there's a daughter tree which also needs boosting - map >::const_iterator tit; - for(tit = _currentTree->treelinks().begin(); - tit != _currentTree->treelinks().end();++tit) { - // if there is, boost it - if(tit->second.first && tit->second.second==original) { - Lorentz5Momentum pnew = tit->first->incomingLines().begin() - ->first->progenitor()->momentum(); - pnew *= tit->first->transform(); - Lorentz5Momentum pdiff = porig-pnew; - Energy2 test = sqr(pdiff.x()) + sqr(pdiff.y()) + - sqr(pdiff.z()) + sqr(pdiff.t()); - LorentzRotation rot; - if(test>1e-6*GeV2) rot = solveBoost(porig,pnew); - tit->first->transform(r*rot,false); - _treeBoosts[tit->first].push_back(r*rot); - } - } -} - -void QTildeReconstructor::reconstructFinalFinalOffShell(JetKinVect orderedJets, - Energy2 s, - bool recursive) const { - JetKinVect::iterator jit; - jit = orderedJets.begin(); ++jit; - // 4-momentum of recoiling system - Lorentz5Momentum psum; - for( ; jit!=orderedJets.end(); ++jit) psum += jit->p; - psum.rescaleMass(); - // calculate the 3-momentum rescaling factor - Energy2 m1sq(orderedJets.begin()->q.m2()),m2sq(psum.m2()); - Energy4 num = sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq; - if(nump.vect().mag2()) ); - // boost the most off-shell - LorentzRotation B1 = solveBoost(k, orderedJets.begin()->q, orderedJets.begin()->p); - deepTransform(orderedJets.begin()->parent,B1); - // boost everything else - // first to rescale - LorentzRotation B2 = solveBoost(k, psum, psum); - // and then to rest frame of new system - Lorentz5Momentum pnew = B2*psum; - pnew.rescaleMass(); - B2.transform(pnew.findBoostToCM()); - // apply transform (calling routine ensures at least 3 elements) - jit = orderedJets.begin(); ++jit; - for(;jit!=orderedJets.end();++jit) { - deepTransform(jit->parent,B2); - jit->p *= B2; - jit->q *= B2; - } - JetKinVect newJets(orderedJets.begin()+1,orderedJets.end()); - // final reconstruction - if(newJets.size()==2 || !recursive ) { - // rescaling factor - double k = solveKfactor(psum.m(), newJets); - // rescale jets in the new CMF - for(JetKinVect::iterator it = newJets.begin(); it != newJets.end(); ++it) { - LorentzRotation Trafo = solveBoost(k, it->q, it->p); - deepTransform(it->parent,Trafo); - } - } - // recursive - else { - std::sort(newJets.begin(),newJets.end(),JetOrdering()); - reconstructFinalFinalOffShell(newJets,psum.m2(),recursive); - } - // finally boost back from new CMF - LorentzRotation back(-pnew.findBoostToCM()); - for(JetKinVect::iterator it = newJets.begin(); it != newJets.end(); ++it) { - deepTransform(it->parent,back); - } -} - -Energy QTildeReconstructor::findMass(HardBranchingPtr branch) const { - // KH - 230909 - If the particle has no children then it will - // not have showered and so it should be "on-shell" so we can - // get it's mass from it's momentum. This means that the - // inverseRescalingFactor doesn't give any nans or do things - // it shouldn't if it gets e.g. two Z bosons generated with - // off-shell masses. This is for sure not the best solution. - // PR 1/1/10 modification to previous soln - // PR 28/8/14 change to procedure and factorize into a function - if(branch->children().empty()) { - return branch->branchingParticle()->mass(); - } - else if(!branch->children().empty() && - !branch->branchingParticle()->dataPtr()->stable() ) { - for(unsigned int ix=0;ixchildren().size();++ix) { - if(branch->branchingParticle()->id()== - branch->children()[ix]->branchingParticle()->id()) - return findMass(branch->children()[ix]); - } - } - return branch->branchingParticle()->dataPtr()->mass(); -} - -vector -QTildeReconstructor::inverseInitialStateRescaling(double & x1, double & x2, - const Lorentz5Momentum & pold, - const vector & p, - const vector & pq) const { - // hadronic CMS - Energy2 s = (pq[0] +pq[1] ).m2(); - // partonic CMS - Energy MDY = pold.m(); - // find alpha, beta and pt - Energy2 p12=pq[0]*pq[1]; - double a[2],b[2]; - Lorentz5Momentum pt[2]; - for(unsigned int ix=0;ix<2;++ix) { - a[ix] = p[ix]*pq[1]/p12; - b [ix] = p[ix]*pq[0]/p12; - pt[ix] = p[ix]-a[ix]*pq[0]-b[ix]*pq[1]; - } - // compute kappa - // we always want to preserve the mass of the system - double k1(1.),k2(1.); - if(_initialStateReconOption==0) { - double rap=pold.rapidity(); - x2 = MDY/sqrt(s*exp(2.*rap)); - x1 = sqr(MDY)/s/x2; - k1=a[0]/x1; - k2=b[1]/x2; - } - // longitudinal momentum - else if(_initialStateReconOption==1) { - double A = 1.; - double C = -sqr(MDY)/s; - double B = 2.*pold.z()/sqrt(s); - if(abs(B)>1e-10) { - double discrim = 1.-4.*A*C/sqr(B); - if(discrim < 0.) throw KinematicsReconstructionVeto(); - x1 = B>0. ? 0.5*B/A*(1.+sqrt(discrim)) : 0.5*B/A*(1.-sqrt(discrim)); - } - else { - x1 = -C/A; - if( x1 <= 0.) throw KinematicsReconstructionVeto(); - x1 = sqrt(x1); - } - x2 = sqr(MDY)/s/x1; - k1=a[0]/x1; - k2=b[1]/x2; - } - // preserve mass and don't scale the softer system - // to reproduce the dipole kinematics - else if(_initialStateReconOption==2) { - // in this case kp = k1 or k2 depending on who's the harder guy - k1 = a[0]*b[1]*s/sqr(MDY); - if ( pt[0].perp2() < pt[1].perp2() ) swap(k1,k2); - x1 = a[0]/k1; - x2 = b[1]/k2; - } - else - assert(false); - // decompose the momenta - double anew[2] = {a[0]/k1,a[1]*k2}; - double bnew[2] = {b[0]*k1,b[1]/k2}; - vector boost(2); - for(unsigned int ix=0;ix<2;++ix) { - boost[ix] = getBeta(a [ix]+b [ix], a[ix] -b [ix], - anew[ix]+bnew[ix], anew[ix]-bnew[ix]); - } - return boost; -} - -vector -QTildeReconstructor::initialStateRescaling(double x1, double x2, - const Lorentz5Momentum & pold, - const vector & p, - const vector & pq, - const vector& highestpts) const { - Energy2 S = (pq[0]+pq[1]).m2(); - // find alphas and betas in terms of desired basis - Energy2 p12 = pq[0]*pq[1]; - double a[2] = {p[0]*pq[1]/p12,p[1]*pq[1]/p12}; - double b[2] = {p[0]*pq[0]/p12,p[1]*pq[0]/p12}; - Lorentz5Momentum p1p = p[0] - a[0]*pq[0] - b[0]*pq[1]; - Lorentz5Momentum p2p = p[1] - a[1]*pq[0] - b[1]*pq[1]; - // compute kappa - // we always want to preserve the mass of the system - Energy MDY = pold.m(); - Energy2 A = a[0]*b[1]*S; - Energy2 B = Energy2(sqr(MDY)) - (a[0]*b[0]+a[1]*b[1])*S - (p1p+p2p).m2(); - Energy2 C = a[1]*b[0]*S; - double rad = 1.-4.*A*C/sqr(B); - if(rad < 0.) throw KinematicsReconstructionVeto(); - double kp = B/(2.*A)*(1.+sqrt(rad)); - // now compute k1 - // conserve rapidity - double k1(0.); - double k2(0.); - if(_initialStateReconOption==0) { - rad = kp*(b[0]+kp*b[1])/(kp*a[0]+a[1]); - rad *= pq[0].z()1e-10) { - double discrim = 1.-4.*a2*c2/sqr(b2); - if(discrim < 0.) throw KinematicsReconstructionVeto(); - k1 = b2>0. ? 0.5*b2/a2*(1.+sqrt(discrim)) : 0.5*b2/a2*(1.-sqrt(discrim)); - } - else { - k1 = -c2/a2; - if( k1 <= 0.) throw KinematicsReconstructionVeto(); - k1 = sqrt(k1); - } - k2 = kp/k1; - } - // preserve mass and don't scale the softer system - // to reproduce the dipole kinematics - else if(_initialStateReconOption==2) { - // in this case kp = k1 or k2 depending on who's the harder guy - k1 = kp; k2 = 1.; - if ( highestpts[0] < highestpts[1] ) - swap(k1,k2); - } - else - assert(false); - // calculate the boosts - vector beta(2); - beta[0] = getBeta((a[0]+b[0]), (a[0]-b[0]), (k1*a[0]+b[0]/k1), (k1*a[0]-b[0]/k1)); - beta[1] = getBeta((a[1]+b[1]), (a[1]-b[1]), (a[1]/k2+k2*b[1]), (a[1]/k2-k2*b[1])); - if (pq[0].z() > ZERO) { - beta[0] = -beta[0]; - beta[1] = -beta[1]; - } - return beta; -} - -void QTildeReconstructor:: -reconstructColourSinglets(vector & ShowerHardJets, - ShowerInteraction type) const { - // identify and catagorize the colour singlet systems - unsigned int nnun(0),nnii(0),nnif(0),nnf(0),nni(0); - vector - systems(identifySystems(set(ShowerHardJets.begin(),ShowerHardJets.end()), - nnun,nnii,nnif,nnf,nni)); - // now decide what to do - // initial-initial connection and final-state colour singlet systems - LorentzRotation toRest,fromRest; - bool applyBoost(false),general(false); - // Drell-Yan type - if(nnun==0&&nnii==1&&nnif==0&&nnf>0&&nni==0) { - // reconstruct initial-initial system - for(unsigned int ix=0;ix0&&nni==1)|| - (nnif==2&& nni==0))) { - // check these systems can be reconstructed - for(unsigned int ix=0;ixprogenitor()->isFinalState()) - q += systems[ix].jets[iy]->progenitor()->momentum(); - else - q -= systems[ix].jets[iy]->progenitor()->momentum(); - } - q.rescaleMass(); - // check above cut - if(abs(q.m())>=_minQ) continue; - if(nnif==1&&nni==1) { - throw KinematicsReconstructionVeto(); - } - else { - general = true; - break; - } - } - if(!general) { - for(unsigned int ix=0;ix0&&nni==2) { - general = type !=ShowerInteraction::QCD; - } - // general type - else { - general = true; - } - // final-state systems except for general recon - if(!general) { - for(unsigned int ix=0;ix JetKinVect; - -/** - * Enum to identify types of colour singlet systems - */ -enum SystemType { UNDEFINED=-1, II, IF, F ,I }; - -/** - * Struct to store colour singlets - */ -template struct ColourSinglet { - - typedef vector > VecType; - - ColourSinglet() : type(UNDEFINED) {} - - ColourSinglet(SystemType intype,Value inpart) - : type(intype),jets(1,inpart) {} - - /** - * The type of system - */ - SystemType type; - - /** - * The jets in the system - */ - vector jets; - -}; - -/** - * Struct to store a colour singlet system of particles - */ -typedef ColourSinglet ColourSingletSystem; - -/** - * Struct to store a colour singlet shower - */ -typedef ColourSinglet ColourSingletShower; - -/** \ingroup Shower - * - * This class is responsible for the kinematical reconstruction - * after each showering step, and also for the necessary Lorentz boosts - * in order to preserve energy-momentum conservation in the overall collision, - * and also the invariant mass and the rapidity of the hard subprocess system. - * In the case of multi-step showering, there will be not unnecessary - * kinematical reconstructions. - * - * There is also the option of taking a set of momenta for the particles - * and inverting the reconstruction to give the evolution variables for the - * shower. - * - * Notice: - * - although we often use the term "jet" in either methods or variables names, - * or in comments, which could appear applicable only for QCD showering, - * there is indeed no "dynamics" represented in this class: only kinematics - * is involved, as the name of this class remainds. Therefore it can be used - * for any kind of showers (QCD-,QED-,EWK-,... bremsstrahlung). - * - * @see ShowerParticle - * @see ShowerKinematics - * @see \ref QTildeReconstructorInterfaces "The interfaces" - * defined for QTildeReconstructor. - */ -class QTildeReconstructor: public KinematicsReconstructor { - -public: - - /** - * Default constructor - */ - QTildeReconstructor() : _reconopt(0), _initialBoost(0), - _finalStateReconOption(0), - _initialStateReconOption(0), _minQ(MeV) {}; - - /** - * Methods to reconstruct the kinematics of a scattering or decay process - */ - //@{ - /** - * Given in input a vector of the particles which initiated the showers - * the method does the reconstruction of such jets, - * including the appropriate boosts (kinematics reshufflings) - * needed to conserve the total energy-momentum of the collision - * and preserving the invariant mass and the rapidity of the - * hard subprocess system. - */ - virtual bool reconstructHardJets(ShowerTreePtr hard, - const map > & pt, - ShowerInteraction type, - bool switchRecon) const; - - /** - * Given in input a vector of the particles which initiated the showers - * the method does the reconstruction of such jets, - * including the appropriate boosts (kinematics reshufflings) - * needed to conserve the total energy-momentum of the collision - * and preserving the invariant mass and the rapidity of the - * hard subprocess system. - */ - virtual bool reconstructDecayJets(ShowerTreePtr decay, - ShowerInteraction type) const; - //@} - - /** - * Methods to invert the reconstruction of the shower for - * a scattering or decay process and calculate - * the variables used to generate the - * shower given the particles produced. - * This is needed for the CKKW and POWHEG approaches - */ - //@{ - /** - * Given the particles, with a history which we wish to interpret - * as a shower reconstruct the variables used to generate the - * shower - */ - virtual bool deconstructDecayJets(HardTreePtr,ShowerInteraction) const; - - /** - * Given the particles, with a history which we wish to interpret - * as a shower reconstruct the variables used to generate the shower - * for a hard process - */ - virtual bool deconstructHardJets(HardTreePtr,ShowerInteraction) const; - //@} - -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(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(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: - - /** - * Methods to reconstruct the kinematics of individual jets - */ - //@{ - /** - * Given the particle (ShowerParticle object) that - * originates a forward (time-like) jet, this method reconstructs the kinematics - * of the jet. That is, by starting from the final grand-children (which - * originates directly or indirectly from particleJetParent, - * and which don't have children), and moving "backwards" (in a physical - * time picture), towards the particleJetParent, the - * ShowerKinematics objects associated with the various particles, - * which have been created during the showering, are now completed. - * In particular, at the end, we get the mass of the jet, which is the - * main information we want. - * This methods returns false if there was no radiation or rescaling required - */ - virtual bool reconstructTimeLikeJet(const tShowerParticlePtr particleJetParent) const; - - /** - * Exactly similar to the previous one, but for a space-like jet. - * Also in this case we start from the final grand-children (which - * are childless) of the particle which originates the jet, but in - * this case we proceed "forward" (in the physical time picture) - * towards the particleJetParent. - * This methods returns false if there was no radiation or rescaling required - */ - bool reconstructSpaceLikeJet(const tShowerParticlePtr particleJetParent) const; - - /** - * Exactly similar to the previous one, but for a decay jet - * This methods returns false if there was no radiation or rescaling required - */ - bool reconstructDecayJet(const tShowerParticlePtr particleJetParent) const; - //@} - - /** - * Methods to perform the reconstruction of various types of colour - * singlet systems - */ - //@{ - /** - * Perform the reconstruction of a system with one incoming and at least one - * outgoing particle - */ - void reconstructInitialFinalSystem(vector) const; - - /** - * Perform the reconstruction of a system with only final-state - * particles - */ - void reconstructFinalStateSystem(bool applyBoost, - const LorentzRotation & toRest, - const LorentzRotation & fromRest, - vector) const; - - /** - * Reconstruction of a general coloured system - */ - void reconstructGeneralSystem(vector & ShowerHardJets) const; - - /** - * Reconstruction of a general coloured system doing - * final-final, then initial-final and then initial-initial - */ - void reconstructFinalFirst(vector & ShowerHardJets) const; - - /** - * Reconstruction of a general coloured system doing - * colour parners - */ - void reconstructColourPartner(vector & ShowerHardJets) const; - - /** - * Reconstruction based on colour singlet systems - */ - void reconstructColourSinglets(vector & ShowerHardJets, - ShowerInteraction type) const; - - /** - * Perform the reconstruction of a system with only final-state - * particles - */ - void reconstructInitialInitialSystem(bool & applyBoost, - LorentzRotation & toRest, - LorentzRotation & fromRest, - vector) const; - //@} - - /** - * Methods to perform the inverse reconstruction of various types of - * colour singlet systems - */ - //@{ - /** - * Perform the inverse reconstruction of a system with only final-state - * particles - */ - void deconstructFinalStateSystem(const LorentzRotation & toRest, - const LorentzRotation & fromRest, - HardTreePtr, - vector, - ShowerInteraction) const; - - /** - * Perform the inverse reconstruction of a system with only initial-state - * particles - */ - void deconstructInitialInitialSystem(bool & applyBoost, - LorentzRotation & toRest, - LorentzRotation & fromRest, - HardTreePtr, - vector, - ShowerInteraction ) const; - - /** - * Perform the inverse reconstruction of a system with only initial-state - * particles - */ - void deconstructInitialFinalSystem(HardTreePtr, - vector, - ShowerInteraction ) const; - - bool deconstructGeneralSystem(HardTreePtr, - ShowerInteraction) const; - - bool deconstructColourSinglets(HardTreePtr, - ShowerInteraction) const; - - bool deconstructColourPartner(HardTreePtr, - ShowerInteraction) const; - //@} - - /** - * Recursively treat the most off-shell paricle seperately - * for final-final reconstruction - */ - void reconstructFinalFinalOffShell(JetKinVect orderedJets, Energy2 s, - bool recursive) const; - - /** - * Various methods for the Lorentz transforms needed to do the - * rescalings - */ - //@{ - /** - * Compute the boost to get from the the old momentum to the new - */ - LorentzRotation solveBoost(const double k, - const Lorentz5Momentum & newq, - const Lorentz5Momentum & oldp) const; - - /** - * Compute the boost to get from the the old momentum to the new - */ - LorentzRotation solveBoost(const Lorentz5Momentum & newq, - const Lorentz5Momentum & oldq) const; - - /** - * Compute the boost to get from the the old momentum to the new - */ - LorentzRotation solveBoostZ(const Lorentz5Momentum & newq, - const Lorentz5Momentum & oldq) const; - - /** - * Recursively boost the initial-state shower - * @param p The particle - * @param bv The boost - * @param parent The parent of the chain - */ - void boostChain(tPPtr p, const LorentzRotation & bv, tPPtr & parent) const; - - /** - * Given a 5-momentum and a scale factor, the method returns the - * Lorentz boost that transforms the 3-vector vec{momentum} ---> - * k*vec{momentum}. The method returns the null boost in the case no - * solution exists. This will only work in the case where the - * outgoing jet-momenta are parallel to the momenta of the particles - * leaving the hard subprocess. - */ - Boost solveBoostBeta( const double k, const Lorentz5Momentum & newq, - const Lorentz5Momentum & oldp); - - /** - * Compute boost parameter along z axis to get (Ep, any perp, qp) - * from (E, same perp, q). - */ - double getBeta(const double E, const double q, - const double Ep, const double qp) const - {return (q*E-qp*Ep)/(sqr(qp)+sqr(E));} - //@} - - /** - * Methods to calculate the various scaling factors - */ - //@{ - /** - * Given a vector of 5-momenta of jets, where the 3-momenta are the initial - * ones before showering and the masses are reconstructed after the showering, - * this method returns the overall scaling factor for the 3-momenta of the - * vector of particles, vec{P}_i -> k * vec{P}_i, such to preserve energy- - * momentum conservation, i.e. after the rescaling the center of mass 5-momentum - * is equal to the one specified in input, cmMomentum. - * The method returns 0 if such factor cannot be found. - * @param root_s Centre-of-mass energy - * @param jets The jets - */ - double solveKfactor( const Energy & root_s, const JetKinVect & jets ) const; - - /** - * Calculate the rescaling factors for the jets in a particle decay where - * there was initial-state radiation - * @param mb The mass of the decaying particle - * @param n The reference vector for the initial state radiation - * @param pjet The momentum of the initial-state jet - * @param jetKinematics The JetKinStruct objects for the jets - * @param partner The colour partner - * @param ppartner The momentum of the colour partner of the decaying particle - * before and after radiation - * @param k1 The rescaling parameter for the partner - * @param k2 The rescaling parameter for the outgoing singlet - * @param qt The transverse momentum vector - */ - bool solveDecayKFactor(Energy mb, - const Lorentz5Momentum & n, - const Lorentz5Momentum & pjet, - const JetKinVect & jetKinematics, - ShowerParticlePtr partner, - Lorentz5Momentum ppartner[2], - double & k1, - double & k2, - Lorentz5Momentum & qt) const; - - /** - * Compute the momentum rescaling factor needed to invert the shower - * @param pout The momenta of the outgoing particles - * @param mon The on-shell masses - * @param roots The mass of the decaying particle - */ - double inverseRescalingFactor(vector pout, - vector mon,Energy roots) const; - - /** - * Compute the momentum rescaling factor needed to invert the shower - * @param pout The momenta of the outgoing particles - * @param mon The on-shell masses - * @param roots The mass of the decaying particle - * @param ppartner The momentum of the colour partner - * @param mbar The mass of the decaying particle - * @param k1 The first scaling factor - * @param k2 The second scaling factor - */ - bool inverseDecayRescalingFactor(vector pout, - vector mon,Energy roots, - Lorentz5Momentum ppartner, Energy mbar, - double & k1, double & k2) const; - - /** - * Check the rescaling conserves momentum - * @param k The rescaling - * @param root_s The centre-of-mass energy - * @param jets The jets - */ - Energy momConsEq(double k, const Energy & root_s, - const JetKinVect & jets) const; - - - void findInitialBoost(const Lorentz5Momentum & pold, const Lorentz5Momentum & pnew, - LorentzRotation & toRest, LorentzRotation & fromRest) const; - //@} - - /** - * Find the colour partners of a particle to identify the colour singlet - * systems for the reconstruction. - */ - template void findPartners(Value branch,set & done, - const set & branchings, - vector & jets) const; - - /** - * Add the intrinsic \f$p_T\f$ to the system if needed - */ - bool addIntrinsicPt(vector) const; - - /** - * Apply a transform to the particle and any child, including child ShowerTree - * objects - * @param particle The particle - * @param r The Lorentz transformation - * @param match Whether or not to look at children etc - * @param original The original particle - */ - void deepTransform(PPtr particle,const LorentzRotation & r, - bool match=true,PPtr original=PPtr()) const; - - /** - * Find the mass of a particle in the hard branching - */ - Energy findMass(HardBranchingPtr) const; - - /** - * Calculate the initial-state rescaling factors - */ - vector initialStateRescaling(double x1, double x2, - const Lorentz5Momentum & pold, - const vector & p, - const vector & pq, - const vector& highespts) const; - - /** - * Calculate the inverse of the initial-state rescaling factor - */ - vector inverseInitialStateRescaling(double & x1, double & x2, - const Lorentz5Momentum & pold, - const vector & p, - const vector & pq) const; - - /** - * Find the colour singlet systems - */ - template - typename ColourSinglet::VecType identifySystems(set jets, - unsigned int & nnun,unsigned int & nnii, - unsigned int & nnif,unsigned int & nnf, - unsigned int & nni) const; - - /** - * Combine final-state colour systems - */ - template - void combineFinalState(vector > & systems) const; - -protected: - - /** @name Clone Methods. */ - //@{ - /** - * Make a simple clone of this object. - * @return a pointer to the new object. - */ - virtual IBPtr clone() const {return new_ptr(*this);} - - /** Make a clone of this object, possibly modifying the cloned object - * to make it sane. - * @return a pointer to the new object. - */ - virtual IBPtr fullclone() const {return new_ptr(*this);} - //@} - -protected: - - /** @name Standard Interfaced functions. */ - //@{ - /** - * Initialize this object after the setup phase before saving an - * EventGenerator to disk. - * @throws InitException if object could not be initialized properly. - */ - virtual void doinit(); - //@} - -private: - - /** - * The assignment operator is private and must never be called. - * In fact, it should not even be implemented. - */ - QTildeReconstructor & operator=(const QTildeReconstructor &); - -private: - - /** - * Option for handling the reconstruction - */ - unsigned int _reconopt; - - /** - * Option for the boost for initial-initial reconstruction - */ - unsigned int _initialBoost; - - /** - * Option for the reconstruction of final state systems - */ - unsigned int _finalStateReconOption; - - /** - * Option for the initial state reconstruction - */ - unsigned int _initialStateReconOption; - - /** - * Minimum invariant mass for initial-final dipoles to allow the - * reconstruction - */ - Energy _minQ; - - /** - * The progenitor of the jet currently being reconstructed - */ - mutable tShowerParticlePtr _progenitor; - - /** - * Storage of the intrinsic \f$p_T\f$ - */ - mutable map > _intrinsic; - - /** - * Current ShowerTree - */ - mutable tShowerTreePtr _currentTree; - - /** - * Particles which shouldn't have their masses rescaled as - * vector for the interface - */ - PDVector _noRescaleVector; - - /** - * Particles which shouldn't have their masses rescaled as - * set for quick access - */ - set _noRescale; - - /** - * Storage of the boosts applied to enable resetting after failure - */ - mutable map > _boosts; - - /** - * Storage of the boosts applied to enable resetting after failure - */ - mutable map > _treeBoosts; -}; - -} - -#include "QTildeReconstructor.tcc" -#endif /* HERWIG_QTildeReconstructor_H */ diff --git a/Shower/QTilde/Default/QTildeReconstructor.tcc b/Shower/QTilde/Default/QTildeReconstructor.tcc deleted file mode 100644 --- a/Shower/QTilde/Default/QTildeReconstructor.tcc +++ /dev/null @@ -1,247 +0,0 @@ -// -*- C++ -*- -// -// QTildeReconstructor.tcc is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig 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 QTildeReconstructor class. -// -using namespace Herwig; -using namespace ThePEG; - -namespace { -/** - * find showering particle for hard branchings - */ -tShowerParticlePtr SHOWERINGPARTICLE(HardBranchingPtr a) { - return a->branchingParticle(); -} - -/** - * find showering particle for progenitors - */ -tShowerParticlePtr SHOWERINGPARTICLE(ShowerProgenitorPtr a) { - return a->progenitor(); -} - - -/** - * Return colour line progenitor pointer for ShowerProgenitor - */ -template -Ptr::transient_pointer -CL(Value a, unsigned int index=0) { - return const_ptr_cast(SHOWERINGPARTICLE(a)->colourInfo()->colourLines()[index]); -} - -/** - * Return progenitor colour line size for ShowerProgenitor - */ -template -unsigned int CLSIZE(Value a) { - return SHOWERINGPARTICLE(a)->colourInfo()->colourLines().size(); -} - -/** - * Return anti-colour line progenitor pointer for ShowerProgenitor - */ -template -Ptr::transient_pointer -ACL(Value a, unsigned int index=0) { - return const_ptr_cast(SHOWERINGPARTICLE(a)->colourInfo()->antiColourLines()[index]); -} - -/** - * Return progenitor anti-colour line size for ShowerProgenitor - */ -template -unsigned int ACLSIZE(Value a) { - return SHOWERINGPARTICLE(a)->colourInfo()->antiColourLines().size(); -} -} - -template void QTildeReconstructor:: -findPartners(Value jet,set & done, - const set & jets, - vector & system) const { - tShowerParticlePtr part=SHOWERINGPARTICLE(jet); - unsigned int partNumColourLines = part->colourInfo()-> colourLines().size(); - unsigned int partNumAColourLines = part->colourInfo()->antiColourLines().size(); - for(typename set::const_iterator cit=jets.begin();cit!=jets.end();++cit) { - if(done.find(*cit)!=done.end()||!SHOWERINGPARTICLE(*cit)->coloured()) - continue; - bool isPartner = false; - // one initial one final - if(part->isFinalState()!=SHOWERINGPARTICLE(*cit)->isFinalState()) { - //loop over all the colours of both - for(unsigned int ix=0; ixcolourLine()) { - for(unsigned int ix=0; ixantiColourLine()&&!isPartner) { - for(unsigned int ix=0; ixcolourLine()) { - if(part->colourLine()->sourceNeighbours().first) { - tColinePair lines = part->colourLine()->sourceNeighbours(); - if(lines.first == CL(*cit) || lines.first == ACL(*cit) || - lines.second == CL(*cit) || lines.second == ACL(*cit) ) - isPartner = true; - } - if(part->colourLine()->sinkNeighbours().first) { - tColinePair lines = part->colourLine()->sinkNeighbours(); - if(lines.first == CL(*cit) || lines.first == ACL(*cit) || - lines.second == CL(*cit) || lines.second == ACL(*cit) ) - isPartner = true; - } - } - if(part->antiColourLine()) { - if(part->antiColourLine()->sourceNeighbours().first) { - tColinePair lines = part->antiColourLine()->sourceNeighbours(); - if(lines.first == CL(*cit) || lines.first == ACL(*cit) || - lines.second == CL(*cit) || lines.second == ACL(*cit) ) - isPartner = true; - } - if(part->antiColourLine()->sinkNeighbours().first) { - tColinePair lines = part->antiColourLine()->sinkNeighbours(); - if(lines.first == CL(*cit) || lines.first == ACL(*cit) || - lines.second == CL(*cit) || lines.second == ACL(*cit) ) - isPartner = true; - } - } - if(isPartner) { - system.push_back(*cit); - done.insert(*cit); - findPartners(*cit,done,jets,system); - } - } -} - -template -typename Herwig::ColourSinglet::VecType QTildeReconstructor:: -identifySystems(set jets, - unsigned int & nnun,unsigned int & nnii,unsigned int & nnif, - unsigned int & nnf ,unsigned int & nni ) const { - vector > systems; - set done; - for(typename set::const_iterator it=jets.begin();it!=jets.end();++it) { - // if not treated create new system - if(done.find(*it)!=done.end()) continue; - done.insert(*it); - systems.push_back(ColourSinglet (UNDEFINED,*it)); - if(!SHOWERINGPARTICLE(*it)->coloured()) continue; - findPartners(*it,done,jets,systems.back().jets); - } - for(unsigned int ix=0;ixisFinalState()) ++nf; - else ++ni; - } - // type - // initial-initial - if(ni==2&&nf==0) { - systems[ix].type = II; - ++nnii; - } - // initial only - else if(ni==1&&nf==0) { - systems[ix].type = I; - ++nni; - } - // initial-final - else if(ni==1&&nf>0) { - systems[ix].type = IF; - ++nnif; - } - // final only - else if(ni==0&&nf>0) { - systems[ix].type = F; - ++nnf; - } - // otherwise unknown - else { - systems[ix].type = UNDEFINED; - ++nnun; - } - } - return systems; -} - -template -void QTildeReconstructor::combineFinalState(vector > & systems) const { - // check that 1 particle final-state systems which can be combine - bool canCombine(true); - for(unsigned int ix=0;ix > oldsystems=systems; - systems.clear(); - ColourSinglet finalState; - finalState.type = F; - for(unsigned int ix=0;ix QTildeShowerKinematics1to2::getBasis() const { - vector dum; - dum.push_back( _pVector ); - dum.push_back( _nVector ); - return dum; -} - -void QTildeShowerKinematics1to2::setBasis(const Lorentz5Momentum &p, - const Lorentz5Momentum & n, - Frame inframe) { - _pVector=p; - _nVector=n; - frame(inframe); - Boost beta_bb; - if(frame()==BackToBack) { - beta_bb = -(_pVector + _nVector).boostVector(); - } - else if(frame()==Rest) { - beta_bb = -pVector().boostVector(); - } - else - assert(false); - Lorentz5Momentum p_bb = pVector(); - Lorentz5Momentum n_bb = nVector(); - p_bb.boost( beta_bb ); - n_bb.boost( beta_bb ); - // rotate to have z-axis parallel to p/n - Axis axis; - if(frame()==BackToBack) { - axis = p_bb.vect().unit(); - } - else if(frame()==Rest) { - axis = n_bb.vect().unit(); - } - else - assert(false); - LorentzRotation rot; - if(axis.perp2()>1e-10) { - double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); - rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); - } - else if(axis.z()<0.) { - rot.rotate(Constants::pi,Axis(1.,0.,0.)); - } - _xPerp=LorentzVector(1.,0.,0.,0.); - _yPerp=LorentzVector(0.,1.,0.,0.); - _xPerp.transform(rot); - _yPerp.transform(rot); - // boost back - _xPerp.boost( -beta_bb ); - _yPerp.boost( -beta_bb ); -} - -void QTildeShowerKinematics1to2::setMomentum(tShowerParticlePtr particle, - bool timeLike) const { - Energy mass = particle->mass() > ZERO ? particle->mass() : particle->data().mass(); - // calculate the momentum of the assuming on-shell - Energy2 pt2 = sqr(particle->showerParameters().pt); - double alpha = timeLike ? particle->showerParameters().alpha : particle->x(); - double beta = 0.5*(sqr(mass) + pt2 - sqr(alpha)*pVector().m2())/(alpha*p_dot_n()); - Lorentz5Momentum porig=sudakov2Momentum(alpha,beta, - particle->showerParameters().ptx, - particle->showerParameters().pty); - porig.setMass(mass); - particle->set5Momentum(porig); -} - -void QTildeShowerKinematics1to2::constructSpinInfo(tShowerParticlePtr particle, - bool timeLike) const { - // now construct the required spininfo and calculate the basis states - PDT::Spin spin(particle->dataPtr()->iSpin()); - if(spin==PDT::Spin0) { - ScalarWaveFunction::constructSpinInfo(particle,outgoing,timeLike); - } - // calculate the basis states and construct the SpinInfo for a spin-1/2 particle - else if(spin==PDT::Spin1Half) { - // outgoing particle - if(particle->id()>0) { - vector > stemp; - SpinorBarWaveFunction::calculateWaveFunctions(stemp,particle,outgoing); - SpinorBarWaveFunction::constructSpinInfo(stemp,particle,outgoing,timeLike); - } - // outgoing antiparticle - else { - vector > stemp; - SpinorWaveFunction::calculateWaveFunctions(stemp,particle,outgoing); - SpinorWaveFunction::constructSpinInfo(stemp,particle,outgoing,timeLike); - } - } - // calculate the basis states and construct the SpinInfo for a spin-1 particle - else if(spin==PDT::Spin1) { - bool massless(particle->id()==ParticleID::g||particle->id()==ParticleID::gamma); - vector vtemp; - VectorWaveFunction::calculateWaveFunctions(vtemp,particle,outgoing,massless); - VectorWaveFunction::constructSpinInfo(vtemp,particle,outgoing,timeLike,massless,vector_phase); - } - else { - throw Exception() << "Spins higher than 1 are not yet implemented in " - << "FS_QtildaShowerKinematics1to2::constructVertex() " - << Exception::runerror; - } -} -void QTildeShowerKinematics1to2::transform(const LorentzRotation & r) { - _pVector *= r; - _nVector *= r; - _xPerp *= r; - _yPerp *= r; -} diff --git a/Shower/QTilde/Default/QTildeShowerKinematics1to2.h b/Shower/QTilde/Default/QTildeShowerKinematics1to2.h deleted file mode 100644 --- a/Shower/QTilde/Default/QTildeShowerKinematics1to2.h +++ /dev/null @@ -1,132 +0,0 @@ -// -*- C++ -*- -// -// QTildeShowerKinematics1to2.h is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig is licenced under version 3 of the GPL, see COPYING for details. -// Please respect the MCnet academic guidelines, see GUIDELINES for details. -// -#ifndef HERWIG_QTildeShowerKinematics1to2_H -#define HERWIG_QTildeShowerKinematics1to2_H -// -// This is the declaration of the QTildeShowerKinematics1to2 class. -// - -#include "Herwig/Shower/QTilde/Base/ShowerKinematics.h" -#include "ThePEG/Vectors/Lorentz5Vector.h" -#include "QTildeShowerKinematics1to2.fh" - -namespace Herwig { - -using namespace ThePEG; - -/** \ingroup Shower - * - * This abstract class describes the common features for initial and final - * state radiation kinematics for \f$1\to2\f$ branchings and for - * the choice of \f$\tilde{q}\f$ as evolution variable. - * - * @see ShowerKinematics - * @see IS_QTildeShowerKinematics1to2 - * @see FS_QTildeShowerKinematics1to2 - * @see KinematicsReconstructor - */ -class QTildeShowerKinematics1to2: public ShowerKinematics { - -public: - - /** - * Implementation of the virtual function returning a set of basis vectors, specific to - * the type of evolution. This function will be used by the - * ForwardShowerEvolver in order to access \f$p\f$ - * and \f$n\f$. - */ - virtual vector getBasis() const; - - /** - * Access to the \f$p\f$ vector used to describe the kinematics. - */ - const Lorentz5Momentum & pVector() const {return _pVector;} - - /** - * Access to the \f$n\f$ vector used to describe the kinematics. - */ - const Lorentz5Momentum & nVector() const {return _nVector;} - - /** - * Dot product of thew basis vectors - */ - Energy2 p_dot_n() const {return _pVector*_nVector;} - - /** - * Converts a Sudakov parametrization of a momentum w.r.t. the given - * basis \f$p\f$ and \f$n\f$ into a 5 momentum. - * @param alpha The \f$\alpha\f$ parameter of the Sudakov parameterisation - * @param beta The \f$\beta\f$ parameter of the Sudakov parameterisation - * @param px The \f$x\f$-component of the transverse momentum in the Sudakov - * parameterisation - * @param py The \f$x\f$-component of the transverse momentum in the Sudakov - * parameterisation - */ - Lorentz5Momentum sudakov2Momentum(double alpha, double beta, - Energy px, Energy py) const { - return alpha*_pVector + beta*_nVector + px*_xPerp+py*_yPerp; - } - - /** - * Transform the shower kinematics (usually the reference vectors) - */ - virtual void transform(const LorentzRotation & r); - -protected: - - /** - * Set the basis vectors - */ - void setBasis(const Lorentz5Momentum &p, const Lorentz5Momentum & n, - Frame frame); - - /** - * Set a preliminary momentum for the particle - */ - void setMomentum(tShowerParticlePtr,bool timelike) const; - - /** - * Construct the spin info object for a shower particle - */ - void constructSpinInfo(tShowerParticlePtr,bool timelike) const; - -private: - - /** - * The assignment operator is private and must never be called. - * In fact, it should not even be implemented. - */ - QTildeShowerKinematics1to2 & operator=(const QTildeShowerKinematics1to2 &); - -private: - - /** - * The \f$p\f$ reference vector - */ - Lorentz5Momentum _pVector; - - /** - * The \f$n\f$ reference vector - */ - Lorentz5Momentum _nVector; - - /** - * x \f$q_\perp\f$ reference vector - */ - LorentzVector _xPerp; - - /** - * y \f$q_\perp\f$reference vector - */ - LorentzVector _yPerp; -}; - -} - -#endif /* HERWIG_QTildeShowerKinematics1to2_H */ diff --git a/Shower/QTilde/Default/QTildeSudakov.cc b/Shower/QTilde/Default/QTildeSudakov.cc deleted file mode 100644 --- a/Shower/QTilde/Default/QTildeSudakov.cc +++ /dev/null @@ -1,1069 +0,0 @@ -// -*- C++ -*- -// -// QTildeSudakov.cc is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig 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 QTildeSudakov class. -// - -#include "QTildeSudakov.h" -#include "ThePEG/Interface/ClassDocumentation.h" -#include "ThePEG/Interface/Parameter.h" -#include "ThePEG/Interface/Switch.h" -#include "ThePEG/PDT/ParticleData.h" -#include "ThePEG/EventRecord/Event.h" -#include "ThePEG/Repository/EventGenerator.h" -#include "ThePEG/Repository/CurrentGenerator.h" -#include "ThePEG/PDT/EnumParticles.h" -#include "Herwig/Shower/QTilde/Default/FS_QTildeShowerKinematics1to2.h" -#include "Herwig/Shower/QTilde/Default/IS_QTildeShowerKinematics1to2.h" -#include "Herwig/Shower/QTilde/Default/Decay_QTildeShowerKinematics1to2.h" -#include "ThePEG/Utilities/DescribeClass.h" -#include "Herwig/Shower/QTilde/Base/ShowerVertex.h" -#include "Herwig/Shower/QTilde/Base/ShowerParticle.h" -#include "Herwig/Shower/QTilde/QTildeShowerHandler.h" -#include "Herwig/Shower/QTilde/Base/PartnerFinder.h" -#include "Herwig/Shower/QTilde/Base/ShowerModel.h" -#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" - -using namespace Herwig; - -DescribeNoPIOClass -describeQTildeSudakov ("Herwig::QTildeSudakov","HwShower.so"); - -void QTildeSudakov::Init() { - - static ClassDocumentation documentation - ("The QTildeSudakov class implements the Sudakov form factor for ordering it" - " qtilde"); -} - -bool QTildeSudakov::guessTimeLike(Energy2 &t,Energy2 tmin,double enhance, - double detune) { - Energy2 told = t; - // calculate limits on z and if lower>upper return - if(!computeTimeLikeLimits(t)) return false; - // guess values of t and z - t = guesst(told,0,ids_,enhance,ids_[1]==ids_[2],detune); - z(guessz(0,ids_)); - // actual values for z-limits - if(!computeTimeLikeLimits(t)) return false; - if(tupper return - if(!computeSpaceLikeLimits(t,x)) return false; - // guess values of t and z - t = guesst(told,1,ids_,enhance,ids_[1]==ids_[2],detune); - z(guessz(1,ids_)); - // actual values for z-limits - if(!computeSpaceLikeLimits(t,x)) return false; - if(t zLimits().second) return true; - Energy2 q2 = z()*(1.-z())*t; - if(ids_[0]->id()!=ParticleID::g && - ids_[0]->id()!=ParticleID::gamma ) q2 += masssquared_[0]; - if(q2>maxQ2) return true; - // compute the pts - Energy2 pt2 = z()*(1.-z())*q2 - masssquared_[1]*(1.-z()) - masssquared_[2]*z(); - // if pt2<0 veto - if(pt2 min - if(tmax<=tmin) return ShoKinPtr(); - // calculate next value of t using veto algorithm - Energy2 t(tmax); - // no shower variations to calculate - if(ShowerHandler::currentHandler()->showerVariations().empty()){ - // Without variations do the usual Veto algorithm - // No need for more if-statements in this loop. - do { - if(!guessTimeLike(t,tmin,enhance,detuning)) break; - } - while(PSVeto(t,maxQ2) || - SplittingFnVeto(z()*(1.-z())*t,ids,true,rho,detuning) || - alphaSVeto(splittingFn()->pTScale() ? sqr(z()*(1.-z()))*t : z()*(1.-z())*t)); - } - else { - bool alphaRew(true),PSRew(true),SplitRew(true); - do { - if(!guessTimeLike(t,tmin,enhance,detuning)) break; - PSRew=PSVeto(t,maxQ2); - if (PSRew) continue; - SplitRew=SplittingFnVeto(z()*(1.-z())*t,ids,true,rho,detuning); - alphaRew=alphaSVeto(splittingFn()->pTScale() ? sqr(z()*(1.-z()))*t : z()*(1.-z())*t); - double factor=alphaSVetoRatio(splittingFn()->pTScale() ? sqr(z()*(1.-z()))*t : z()*(1.-z())*t,1.)* - SplittingFnVetoRatio(z()*(1.-z())*t,ids,true,rho,detuning); - - tShowerHandlerPtr ch = ShowerHandler::currentHandler(); - - if( !(SplitRew || alphaRew) ) { - //Emission - q_ = t > ZERO ? Energy(sqrt(t)) : -1.*MeV; - if (q_ <= ZERO) break; - } - - for ( map::const_iterator var = - ch->showerVariations().begin(); - var != ch->showerVariations().end(); ++var ) { - if ( ( ch->firstInteraction() && var->second.firstInteraction ) || - ( !ch->firstInteraction() && var->second.secondaryInteractions ) ) { - double newfactor = alphaSVetoRatio(splittingFn()->pTScale() ? - sqr(z()*(1.-z()))*t : - z()*(1.-z())*t,var->second.renormalizationScaleFactor) - * SplittingFnVetoRatio(z()*(1.-z())*t,ids,true,rho,detuning); - - double varied; - if ( SplitRew || alphaRew ) { - // No Emission - varied = (1. - newfactor) / (1. - factor); - } else { - // Emission - varied = newfactor / factor; - } - - map::iterator wi = ch->currentWeights().find(var->first); - if ( wi != ch->currentWeights().end() ) - wi->second *= varied; - else { - assert(false); - //ch->currentWeights()[var->first] = varied; - } - } - } - - } - while(PSRew || SplitRew || alphaRew); - } - q_ = t > ZERO ? Energy(sqrt(t)) : -1.*MeV; - if(q_ < ZERO) return ShoKinPtr(); - - // return the ShowerKinematics object - return createFinalStateBranching(q_,z(),phi(),pT()); -} - -ShoKinPtr QTildeSudakov:: -generateNextSpaceBranching(const Energy startingQ, - const IdList &ids, - double x, - const RhoDMatrix & rho, - double enhance, - Ptr::transient_const_pointer beam, - double detuning) { - // First reset the internal kinematics variables that can - // have been eventually set in the previous call to the method. - q_ = ZERO; - z(0.); - phi(0.); - // perform the initialization - Energy2 tmax(sqr(startingQ)),tmin; - initialize(ids,tmin); - // check max > min - if(tmax<=tmin) return ShoKinPtr(); - // calculate next value of t using veto algorithm - Energy2 t(tmax),pt2(ZERO); - // no shower variations - if(ShowerHandler::currentHandler()->showerVariations().empty()) { - // Without variations do the usual Veto algorithm - // No need for more if-statements in this loop. - do { - if(!guessSpaceLike(t,tmin,x,enhance,detuning)) break; - pt2=sqr(1.-z())*t-z()*masssquared_[2]; - } - while(pt2 < pT2min()|| - z() > zLimits().second|| - SplittingFnVeto((1.-z())*t/z(),ids,false,rho,detuning)|| - alphaSVeto(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t)|| - PDFVeto(t,x,ids[0],ids[1],beam)); - } - // shower variations - else { - bool alphaRew(true),PDFRew(true),ptRew(true),zRew(true),SplitRew(true); - do { - if(!guessSpaceLike(t,tmin,x,enhance,detuning)) break; - pt2=sqr(1.-z())*t-z()*masssquared_[2]; - ptRew=pt2 < pT2min(); - zRew=z() > zLimits().second; - if (ptRew||zRew) continue; - SplitRew=SplittingFnVeto((1.-z())*t/z(),ids,false,rho,detuning); - alphaRew=alphaSVeto(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t); - PDFRew=PDFVeto(t,x,ids[0],ids[1],beam); - double factor=PDFVetoRatio(t,x,ids[0],ids[1],beam,1.)* - alphaSVetoRatio(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t,1.)* - SplittingFnVetoRatio((1.-z())*t/z(),ids,false,rho,detuning); - - tShowerHandlerPtr ch = ShowerHandler::currentHandler(); - - if( !(PDFRew || SplitRew || alphaRew) ) { - //Emission - q_ = t > ZERO ? Energy(sqrt(t)) : -1.*MeV; - if (q_ <= ZERO) break; - } - - for ( map::const_iterator var = - ch->showerVariations().begin(); - var != ch->showerVariations().end(); ++var ) { - if ( ( ch->firstInteraction() && var->second.firstInteraction ) || - ( !ch->firstInteraction() && var->second.secondaryInteractions ) ) { - - - - double newfactor = PDFVetoRatio(t,x,ids[0],ids[1],beam,var->second.factorizationScaleFactor)* - alphaSVetoRatio(splittingFn()->pTScale() ? - sqr(1.-z())*t : (1.-z())*t,var->second.renormalizationScaleFactor) - *SplittingFnVetoRatio((1.-z())*t/z(),ids,false,rho,detuning); - - double varied; - if( PDFRew || SplitRew || alphaRew) { - // No Emission - varied = (1. - newfactor) / (1. - factor); - } else { - // Emission - varied = newfactor / factor; - } - - - map::iterator wi = ch->currentWeights().find(var->first); - if ( wi != ch->currentWeights().end() ) - wi->second *= varied; - else { - assert(false); - //ch->currentWeights()[var->first] = varied; - } - } - } - - } - while( PDFRew || SplitRew || alphaRew); - } - - if(t > ZERO && zLimits().first < zLimits().second) q_ = sqrt(t); - else return ShoKinPtr(); - - pT(sqrt(pt2)); - // create the ShowerKinematics and return it - return createInitialStateBranching(q_,z(),phi(),pT()); -} - -void QTildeSudakov::initialize(const IdList & ids, Energy2 & tmin) { - ids_=ids; - tmin = cutOffOption() != 2 ? ZERO : 4.*pT2min(); - masses_ = virtualMasses(ids); - masssquared_.clear(); - for(unsigned int ix=0;ix0) tmin=max(masssquared_[ix],tmin); - } -} - -ShoKinPtr QTildeSudakov::generateNextDecayBranching(const Energy startingScale, - const Energy stoppingScale, - const Energy minmass, - const IdList &ids, - const RhoDMatrix & rho, - double enhance, - double detuning) { - // First reset the internal kinematics variables that can - // have been eventually set in the previous call to this method. - q_ = Constants::MaxEnergy; - z(0.); - phi(0.); - // perform initialisation - Energy2 tmax(sqr(stoppingScale)),tmin; - initialize(ids,tmin); - tmin=sqr(startingScale); - // check some branching possible - if(tmax<=tmin) return ShoKinPtr(); - // perform the evolution - Energy2 t(tmin),pt2(-MeV2); - do { - if(!guessDecay(t,tmax,minmass,enhance,detuning)) break; - pt2 = sqr(1.-z())*(t-masssquared_[0])-z()*masssquared_[2]; - } - while(SplittingFnVeto((1.-z())*t/z(),ids,true,rho,detuning)|| - alphaSVeto(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t ) || - pt2masssquared_[0]-sqr(minmass)); - if(t > ZERO) { - q_ = sqrt(t); - pT(sqrt(pt2)); - } - else return ShoKinPtr(); - phi(0.); - // create the ShowerKinematics object - return createDecayBranching(q_,z(),phi(),pT()); -} - -bool QTildeSudakov::guessDecay(Energy2 &t,Energy2 tmax, Energy minmass, - double enhance, double detune) { - // previous scale - Energy2 told = t; - // overestimated limits on z - if(tmax limits=make_pair(sqr(minmass/masses_[0]), - 1.-sqrt(masssquared_[2]+pT2min()+ - 0.25*sqr(masssquared_[2])/tm2)/tm - +0.5*masssquared_[2]/tm2); - zLimits(limits); - if(zLimits().secondtmax||zLimits().second limits; - if(ids_[0]->id()==ParticleID::g||ids_[0]->id()==ParticleID::gamma) { - // no emission possible - if(t<16.*(masssquared_[1]+pT2min())) { - t=-1.*GeV2; - return false; - } - // overestimate of the limits - limits.first = 0.5*(1.-sqrt(1.-4.*sqrt((masssquared_[1]+pT2min())/t))); - limits.second = 1.-limits.first; - } - // special case for radiated particle is gluon - else if(ids_[2]->id()==ParticleID::g||ids_[2]->id()==ParticleID::gamma) { - limits.first = sqrt((masssquared_[1]+pT2min())/t); - limits.second = 1.-sqrt((masssquared_[2]+pT2min())/t); - } - else if(ids_[1]->id()==ParticleID::g||ids_[1]->id()==ParticleID::gamma) { - limits.second = sqrt((masssquared_[2]+pT2min())/t); - limits.first = 1.-sqrt((masssquared_[1]+pT2min())/t); - } - else { - limits.first = (masssquared_[1]+pT2min())/t; - limits.second = 1.-(masssquared_[2]+pT2min())/t; - } - if(limits.first>=limits.second) { - t=-1.*GeV2; - return false; - } - zLimits(limits); - return true; -} - -bool QTildeSudakov::computeSpaceLikeLimits(Energy2 & t, double x) { - if (t < 1e-20 * GeV2) { - t=-1.*GeV2; - return false; - } - pair limits; - // compute the limits - limits.first = x; - double yy = 1.+0.5*masssquared_[2]/t; - limits.second = yy - sqrt(sqr(yy)-1.+pT2min()/t); - // return false if lower>upper - zLimits(limits); - if(limits.second(particle.parents()[0]) : tShowerParticlePtr(); - } - else { - mother = particle.children().size()==2 ? - dynamic_ptr_cast(&particle) : tShowerParticlePtr(); - } - tShowerParticlePtr partner; - while(mother) { - tPPtr otherChild; - if(forward) { - for (unsigned int ix=0;ixchildren().size();++ix) { - if(mother->children()[ix]!=child) { - otherChild = mother->children()[ix]; - break; - } - } - } - else { - otherChild = mother->children()[1]; - } - tShowerParticlePtr other = dynamic_ptr_cast(otherChild); - if((inter==ShowerInteraction::QCD && otherChild->dataPtr()->coloured()) || - (inter==ShowerInteraction::QED && otherChild->dataPtr()->charged())) { - partner = other; - break; - } - if(forward && !other->isFinalState()) { - partner = dynamic_ptr_cast(mother); - break; - } - child = mother; - if(forward) { - mother = ! mother->parents().empty() ? - dynamic_ptr_cast(mother->parents()[0]) : tShowerParticlePtr(); - } - else { - if(mother->children()[0]->children().size()!=2) - break; - tShowerParticlePtr mtemp = - dynamic_ptr_cast(mother->children()[0]); - if(!mtemp) - break; - else - mother=mtemp; - } - } - if(!partner) { - if(forward) { - partner = dynamic_ptr_cast( child)->partner(); - } - else { - if(mother) { - tShowerParticlePtr parent; - if(!mother->children().empty()) { - parent = dynamic_ptr_cast(mother->children()[0]); - } - if(!parent) { - parent = dynamic_ptr_cast(mother); - } - partner = parent->partner(); - } - else { - partner = dynamic_ptr_cast(&particle)->partner(); - } - } - } - return partner; -} - -pair softPhiMin(double phi0, double phi1, double A, double B, double C, double D) { - double c01 = cos(phi0 - phi1); - double s01 = sin(phi0 - phi1); - double s012(sqr(s01)), c012(sqr(c01)); - double A2(A*A), B2(B*B), C2(C*C), D2(D*D); - if(abs(B/A)<1e-10 && abs(D/C)<1e-10) return make_pair(phi0,phi0+Constants::pi); - double root = sqr(B2)*C2*D2*sqr(s012) + 2.*A*B2*B*C2*C*D*c01*s012 + 2.*A*B2*B*C*D2*D*c01*s012 - + 4.*A2*B2*C2*D2*c012 - A2*B2*C2*D2*s012 - A2*B2*sqr(D2)*s012 - sqr(B2)*sqr(C2)*s012 - - sqr(B2)*C2*D2*s012 - 4.*A2*A*B*C*D2*D*c01 - 4.*A*B2*B*C2*C*D*c01 + sqr(A2)*sqr(D2) - + 2.*A2*B2*C2*D2 + sqr(B2)*sqr(C2); - if(root<0.) return make_pair(phi0,phi0+Constants::pi); - root = sqrt(root); - double denom = (-2.*A*B*C*D*c01 + A2*D2 + B2*C2); - double denom2 = (-B*C*c01 + A*D); - - double num = B2*C*D*s012; - double y1 = B*s01*(-C*(num + root) + D*denom) / denom2; - double y2 = B*s01*(-C*(num - root) + D*denom) / denom2; - double x1 = -(num + root ); - double x2 = -(num - root ); - if(denom<0.) { - y1*=-1.; - y2*=-1.; - x1*=-1.; - x2*=-1.; - } - return make_pair(atan2(y1,x1) + phi0,atan2(y2,x2) + phi0); -} - -} - -double QTildeSudakov::generatePhiForward(ShowerParticle & particle, - const IdList & ids, - ShoKinPtr kinematics, - const RhoDMatrix & rho) { - // no correlations, return flat phi - if(! dynamic_ptr_cast(ShowerHandler::currentHandler())->correlations()) - return Constants::twopi*UseRandom::rnd(); - // get the kinematic variables - double z = kinematics->z(); - Energy2 t = z*(1.-z)*sqr(kinematics->scale()); - Energy pT = kinematics->pT(); - // if soft correlations - Energy2 pipj,pik; - bool canBeSoft[2] = {ids[1]->id()==ParticleID::g || ids[1]->id()==ParticleID::gamma, - ids[2]->id()==ParticleID::g || ids[2]->id()==ParticleID::gamma }; - array pjk = {}; - array Ek = {}; - Energy Ei,Ej; - Energy2 m12(ZERO),m22(ZERO); - InvEnergy2 aziMax(ZERO); - bool softAllowed = dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()&& - (canBeSoft[0] || canBeSoft[1]); - if(softAllowed) { - // find the partner for the soft correlations - tShowerParticlePtr partner=findCorrelationPartner(particle,true,splittingFn()->interactionType()); - // remember we want the softer gluon - bool swapOrder = !canBeSoft[1] || (canBeSoft[0] && canBeSoft[1] && z < 0.5); - double zFact = !swapOrder ? (1.-z) : z; - // compute the transforms to the shower reference frame - // first the boost - Lorentz5Momentum pVect = particle.showerBasis()->pVector(); - Lorentz5Momentum nVect = particle.showerBasis()->nVector(); - Boost beta_bb; - if(particle.showerBasis()->frame()==ShowerBasis::BackToBack) { - beta_bb = -(pVect + nVect).boostVector(); - } - else if(particle.showerBasis()->frame()==ShowerBasis::Rest) { - beta_bb = -pVect.boostVector(); - } - else - assert(false); - pVect.boost(beta_bb); - nVect.boost(beta_bb); - Axis axis; - if(particle.showerBasis()->frame()==ShowerBasis::BackToBack) { - axis = pVect.vect().unit(); - } - else if(particle.showerBasis()->frame()==ShowerBasis::Rest) { - axis = nVect.vect().unit(); - } - else - assert(false); - // and then the rotation - LorentzRotation rot; - if(axis.perp2()>0.) { - double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); - rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); - } - else if(axis.z()<0.) { - rot.rotate(Constants::pi,Axis(1.,0.,0.)); - } - rot.invert(); - pVect *= rot; - nVect *= rot; - // shower parameters - Energy2 pn = pVect*nVect, m2 = pVect.m2(); - double alpha0 = particle.showerParameters().alpha; - double beta0 = 0.5/alpha0/pn* - (sqr(particle.dataPtr()->mass())-sqr(alpha0)*m2+sqr(particle.showerParameters().pt)); - Lorentz5Momentum qperp0(particle.showerParameters().ptx, - particle.showerParameters().pty,ZERO,ZERO); - assert(partner); - Lorentz5Momentum pj = partner->momentum(); - pj.boost(beta_bb); - pj *= rot; - // compute the two phi independent dot products - pik = 0.5*zFact*(sqr(alpha0)*m2 - sqr(particle.showerParameters().pt) + 2.*alpha0*beta0*pn ) - +0.5*sqr(pT)/zFact; - Energy2 dot1 = pj*pVect; - Energy2 dot2 = pj*nVect; - Energy2 dot3 = pj*qperp0; - pipj = alpha0*dot1+beta0*dot2+dot3; - // compute the constants for the phi dependent dot product - pjk[0] = zFact*(alpha0*dot1+dot3-0.5*dot2/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0)) - +0.5*sqr(pT)*dot2/pn/zFact/alpha0; - pjk[1] = (pj.x() - dot2/alpha0/pn*qperp0.x())*pT; - pjk[2] = (pj.y() - dot2/alpha0/pn*qperp0.y())*pT; - m12 = sqr(particle.dataPtr()->mass()); - m22 = sqr(partner->dataPtr()->mass()); - if(swapOrder) { - pjk[1] *= -1.; - pjk[2] *= -1.; - } - Ek[0] = zFact*(alpha0*pVect.t()-0.5*nVect.t()/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0)) - +0.5*sqr(pT)*nVect.t()/pn/zFact/alpha0; - Ek[1] = -nVect.t()/alpha0/pn*qperp0.x()*pT; - Ek[2] = -nVect.t()/alpha0/pn*qperp0.y()*pT; - if(swapOrder) { - Ek[1] *= -1.; - Ek[2] *= -1.; - } - Energy mag2=sqrt(sqr(Ek[1])+sqr(Ek[2])); - Ei = alpha0*pVect.t()+beta0*nVect.t(); - Ej = pj.t(); - double phi0 = atan2(-pjk[2],-pjk[1]); - if(phi0<0.) phi0 += Constants::twopi; - double phi1 = atan2(-Ek[2],-Ek[1]); - if(phi1<0.) phi1 += Constants::twopi; - double xi_min = pik/Ei/(Ek[0]+mag2), xi_max = pik/Ei/(Ek[0]-mag2), xi_ij = pipj/Ei/Ej; - if(xi_min>xi_max) swap(xi_min,xi_max); - if(xi_min>xi_ij) softAllowed = false; - Energy2 mag = sqrt(sqr(pjk[1])+sqr(pjk[2])); - if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { - aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag); - } - else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { - double A = (pipj*Ek[0]- Ej*pik)/Ej/sqr(Ej); - double B = -sqrt(sqr(pipj)*(sqr(Ek[1])+sqr(Ek[2])))/Ej/sqr(Ej); - double C = pjk[0]/sqr(Ej); - double D = -sqrt(sqr(pjk[1])+sqr(pjk[2]))/sqr(Ej); - pair minima = softPhiMin(phi0,phi1,A,B,C,D); - aziMax = 0.5/pik/(Ek[0]-mag2)*(Ei-m12*(Ek[0]-mag2)/pik + max(Ej*(A+B*cos(minima.first -phi1))/(C+D*cos(minima.first -phi0)), - Ej*(A+B*cos(minima.second-phi1))/(C+D*cos(minima.second-phi0)))); - } - else - assert(false); - } - // if spin correlations - vector > wgts; - if(dynamic_ptr_cast(ShowerHandler::currentHandler())->spinCorrelations()) { - // calculate the weights - wgts = splittingFn()->generatePhiForward(z,t,ids,rho); - } - else { - wgts = {{ {0, 1.} }}; - } - // generate the azimuthal angle - double phi,wgt; - static const Complex ii(0.,1.); - unsigned int ntry(0); - double phiMax(0.),wgtMax(0.); - do { - phi = Constants::twopi*UseRandom::rnd(); - // first the spin correlations bit (gives 1 if correlations off) - Complex spinWgt = 0.; - for(unsigned int ix=0;ix1e-10) { - generator()->log() << "Forward spin weight problem " << wgt << " " << wgt-1. - << " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n"; - generator()->log() << "Weights \n"; - for(unsigned int ix=0;ixlog() << wgts[ix].first << " " << wgts[ix].second << "\n"; - } - // soft correlations bit - double aziWgt = 1.; - if(softAllowed) { - Energy2 dot = pjk[0]+pjk[1]*cos(phi)+pjk[2]*sin(phi); - Energy Eg = Ek[0]+Ek[1]*cos(phi)+Ek[2]*sin(phi); - if(pipj*Eg>pik*Ej) { - if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { - aziWgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax; - } - else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { - aziWgt = max(ZERO,0.5/pik/Eg*(Ei-m12*Eg/pik + (pipj*Eg - Ej*pik)/dot)/aziMax); - } - if(aziWgt-1.>1e-10||aziWgt<-1e-10) { - generator()->log() << "Forward soft weight problem " << aziWgt << " " << aziWgt-1. - << " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n"; - } - } - else { - aziWgt = 0.; - } - } - wgt *= aziWgt; - if(wgt>wgtMax) { - phiMax = phi; - wgtMax = wgt; - } - ++ntry; - } - while(wgtlog() << "Too many tries to generate phi in forward evolution\n"; - phi = phiMax; - } - // return the azimuthal angle - return phi; -} - -double QTildeSudakov::generatePhiBackward(ShowerParticle & particle, - const IdList & ids, - ShoKinPtr kinematics, - const RhoDMatrix & rho) { - // no correlations, return flat phi - if(! dynamic_ptr_cast(ShowerHandler::currentHandler())->correlations()) - return Constants::twopi*UseRandom::rnd(); - // get the kinematic variables - double z = kinematics->z(); - Energy2 t = (1.-z)*sqr(kinematics->scale())/z; - Energy pT = kinematics->pT(); - // if soft correlations - bool softAllowed = dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations() && - (ids[2]->id()==ParticleID::g || ids[2]->id()==ParticleID::gamma); - Energy2 pipj,pik,m12(ZERO),m22(ZERO); - array pjk = {}; - Energy Ei,Ej,Ek; - InvEnergy2 aziMax(ZERO); - if(softAllowed) { - // find the partner for the soft correlations - tShowerParticlePtr partner=findCorrelationPartner(particle,false,splittingFn()->interactionType()); - double zFact = (1.-z); - // compute the transforms to the shower reference frame - // first the boost - Lorentz5Momentum pVect = particle.showerBasis()->pVector(); - Lorentz5Momentum nVect = particle.showerBasis()->nVector(); - assert(particle.showerBasis()->frame()==ShowerBasis::BackToBack); - Boost beta_bb = -(pVect + nVect).boostVector(); - pVect.boost(beta_bb); - nVect.boost(beta_bb); - Axis axis = pVect.vect().unit(); - // and then the rotation - LorentzRotation rot; - if(axis.perp2()>0.) { - double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); - rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); - } - else if(axis.z()<0.) { - rot.rotate(Constants::pi,Axis(1.,0.,0.)); - } - rot.invert(); - pVect *= rot; - nVect *= rot; - // shower parameters - Energy2 pn = pVect*nVect; - Energy2 m2 = pVect.m2(); - double alpha0 = particle.x(); - double beta0 = -0.5/alpha0/pn*sqr(alpha0)*m2; - Lorentz5Momentum pj = partner->momentum(); - pj.boost(beta_bb); - pj *= rot; - double beta2 = 0.5*(1.-zFact)*(sqr(alpha0*zFact/(1.-zFact))*m2+sqr(pT))/alpha0/zFact/pn; - // compute the two phi independent dot products - Energy2 dot1 = pj*pVect; - Energy2 dot2 = pj*nVect; - pipj = alpha0*dot1+beta0*dot2; - pik = alpha0*(alpha0*zFact/(1.-zFact)*m2+pn*(beta2+zFact/(1.-zFact)*beta0)); - // compute the constants for the phi dependent dot product - pjk[0] = alpha0*zFact/(1.-zFact)*dot1+beta2*dot2; - pjk[1] = pj.x()*pT; - pjk[2] = pj.y()*pT; - m12 = ZERO; - m22 = sqr(partner->dataPtr()->mass()); - Energy2 mag = sqrt(sqr(pjk[1])+sqr(pjk[2])); - if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { - aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag); - } - else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { - Ek = alpha0*zFact/(1.-zFact)*pVect.t()+beta2*nVect.t(); - Ei = alpha0*pVect.t()+beta0*nVect.t(); - Ej = pj.t(); - if(pipj*Ek> Ej*pik) { - aziMax = 0.5/pik/Ek*(Ei-m12*Ek/pik + (pipj*Ek- Ej*pik)/(pjk[0]-mag)); - } - else { - aziMax = 0.5/pik/Ek*(Ei-m12*Ek/pik); - } - } - else { - assert(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==0); - } - } - // if spin correlations - vector > wgts; - if(dynamic_ptr_cast(ShowerHandler::currentHandler())->spinCorrelations()) { - // get the weights - wgts = splittingFn()->generatePhiBackward(z,t,ids,rho); - } - else { - wgts = {{ {0, 1.} }}; - } - // generate the azimuthal angle - double phi,wgt; - static const Complex ii(0.,1.); - unsigned int ntry(0); - double phiMax(0.),wgtMax(0.); - do { - phi = Constants::twopi*UseRandom::rnd(); - Complex spinWgt = 0.; - for(unsigned int ix=0;ix1e-10) { - generator()->log() << "Backward weight problem " << wgt << " " << wgt-1. - << " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << z << " " << phi << "\n"; - generator()->log() << "Weights \n"; - for(unsigned int ix=0;ixlog() << wgts[ix].first << " " << wgts[ix].second << "\n"; - } - // soft correlations bit - double aziWgt = 1.; - if(softAllowed) { - Energy2 dot = pjk[0]+pjk[1]*cos(phi)+pjk[2]*sin(phi); - if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { - aziWgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax; - } - else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { - aziWgt = max(ZERO,0.5/pik/Ek*(Ei-m12*Ek/pik + pipj*Ek/dot - Ej*pik/dot)/aziMax); - } - if(aziWgt-1.>1e-10||aziWgt<-1e-10) { - generator()->log() << "Backward soft weight problem " << aziWgt << " " << aziWgt-1. - << " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n"; - } - } - wgt *= aziWgt; - if(wgt>wgtMax) { - phiMax = phi; - wgtMax = wgt; - } - ++ntry; - } - while(wgtlog() << "Too many tries to generate phi in backward evolution\n"; - phi = phiMax; - } - // return the azimuthal angle - return phi; -} - -double QTildeSudakov::generatePhiDecay(ShowerParticle & particle, - const IdList & ids, - ShoKinPtr kinematics, - const RhoDMatrix &) { - // only soft correlations in this case - // no correlations, return flat phi - if( !(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations() && - (ids[2]->id()==ParticleID::g || ids[2]->id()==ParticleID::gamma ))) - return Constants::twopi*UseRandom::rnd(); - // get the kinematic variables - double z = kinematics->z(); - Energy pT = kinematics->pT(); - // if soft correlations - // find the partner for the soft correlations - tShowerParticlePtr partner = findCorrelationPartner(particle,true,splittingFn()->interactionType()); - double zFact(1.-z); - // compute the transforms to the shower reference frame - // first the boost - Lorentz5Momentum pVect = particle.showerBasis()->pVector(); - Lorentz5Momentum nVect = particle.showerBasis()->nVector(); - assert(particle.showerBasis()->frame()==ShowerBasis::Rest); - Boost beta_bb = -pVect.boostVector(); - pVect.boost(beta_bb); - nVect.boost(beta_bb); - Axis axis = nVect.vect().unit(); - // and then the rotation - LorentzRotation rot; - if(axis.perp2()>0.) { - double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); - rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); - } - else if(axis.z()<0.) { - rot.rotate(Constants::pi,Axis(1.,0.,0.)); - } - rot.invert(); - pVect *= rot; - nVect *= rot; - // shower parameters - Energy2 pn = pVect*nVect; - Energy2 m2 = pVect.m2(); - double alpha0 = particle.showerParameters().alpha; - double beta0 = 0.5/alpha0/pn* - (sqr(particle.dataPtr()->mass())-sqr(alpha0)*m2+sqr(particle.showerParameters().pt)); - Lorentz5Momentum qperp0(particle.showerParameters().ptx, - particle.showerParameters().pty,ZERO,ZERO); - Lorentz5Momentum pj = partner->momentum(); - pj.boost(beta_bb); - pj *= rot; - // compute the two phi independent dot products - Energy2 pik = 0.5*zFact*(sqr(alpha0)*m2 - sqr(particle.showerParameters().pt) + 2.*alpha0*beta0*pn ) - +0.5*sqr(pT)/zFact; - Energy2 dot1 = pj*pVect; - Energy2 dot2 = pj*nVect; - Energy2 dot3 = pj*qperp0; - Energy2 pipj = alpha0*dot1+beta0*dot2+dot3; - // compute the constants for the phi dependent dot product - array pjk = {}; - pjk[0] = zFact*(alpha0*dot1+dot3-0.5*dot2/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0)) - +0.5*sqr(pT)*dot2/pn/zFact/alpha0; - pjk[1] = (pj.x() - dot2/alpha0/pn*qperp0.x())*pT; - pjk[2] = (pj.y() - dot2/alpha0/pn*qperp0.y())*pT; - Energy2 m12 = sqr(particle.dataPtr()->mass()); - Energy2 m22 = sqr(partner->dataPtr()->mass()); - Energy2 mag = sqrt(sqr(pjk[1])+sqr(pjk[2])); - InvEnergy2 aziMax; - array Ek = {}; - Energy Ei,Ej; - if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { - aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag); - } - else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { - Ek[0] = zFact*(alpha0*pVect.t()+-0.5*nVect.t()/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0)) - +0.5*sqr(pT)*nVect.t()/pn/zFact/alpha0; - Ek[1] = -nVect.t()/alpha0/pn*qperp0.x()*pT; - Ek[2] = -nVect.t()/alpha0/pn*qperp0.y()*pT; - Energy mag2=sqrt(sqr(Ek[1])+sqr(Ek[2])); - Ei = alpha0*pVect.t()+beta0*nVect.t(); - Ej = pj.t(); - aziMax = 0.5/pik/(Ek[0]-mag2)*(Ei-m12*(Ek[0]-mag2)/pik + pipj*(Ek[0]+mag2)/(pjk[0]-mag) - Ej*pik/(pjk[0]-mag) ); - } - else - assert(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==0); - // generate the azimuthal angle - double phi,wgt(0.); - unsigned int ntry(0); - double phiMax(0.),wgtMax(0.); - do { - phi = Constants::twopi*UseRandom::rnd(); - Energy2 dot = pjk[0]+pjk[1]*cos(phi)+pjk[2]*sin(phi); - if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { - wgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax; - } - else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { - if(qperp0.m2()==ZERO) { - wgt = 1.; - } - else { - Energy Eg = Ek[0]+Ek[1]*cos(phi)+Ek[2]*sin(phi); - wgt = max(ZERO,0.5/pik/Eg*(Ei-m12*Eg/pik + (pipj*Eg - Ej*pik)/dot)/aziMax); - } - } - if(wgt-1.>1e-10||wgt<-1e-10) { - generator()->log() << "Decay soft weight problem " << wgt << " " << wgt-1. - << " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n"; - } - if(wgt>wgtMax) { - phiMax = phi; - wgtMax = wgt; - } - ++ntry; - } - while(wgtlog() << "Too many tries to generate phi\n"; - } - // return the azimuthal angle - return phi; -} - - -Energy QTildeSudakov::calculateScale(double zin, Energy pt, IdList ids, - unsigned int iopt) { - Energy2 tmin; - initialize(ids,tmin); - // final-state branching - if(iopt==0) { - Energy2 scale=(sqr(pt)+masssquared_[1]*(1.-zin)+masssquared_[2]*zin); - if(ids[0]->id()!=ParticleID::g) scale -= zin*(1.-zin)*masssquared_[0]; - scale /= sqr(zin*(1-zin)); - return scale<=ZERO ? sqrt(tmin) : sqrt(scale); - } - else if(iopt==1) { - Energy2 scale=(sqr(pt)+zin*masssquared_[2])/sqr(1.-zin); - return scale<=ZERO ? sqrt(tmin) : sqrt(scale); - } - else if(iopt==2) { - Energy2 scale = (sqr(pt)+zin*masssquared_[2])/sqr(1.-zin)+masssquared_[0]; - return scale<=ZERO ? sqrt(tmin) : sqrt(scale); - } - else { - throw Exception() << "Unknown option in QTildeSudakov::calculateScale() " - << "iopt = " << iopt << Exception::runerror; - } -} - -ShoKinPtr QTildeSudakov::createFinalStateBranching(Energy scale,double z, - double phi, Energy pt) { - ShoKinPtr showerKin = new_ptr(FS_QTildeShowerKinematics1to2()); - showerKin->scale(scale); - showerKin->z(z); - showerKin->phi(phi); - showerKin->pT(pt); - showerKin->SudakovFormFactor(this); - return showerKin; -} - -ShoKinPtr QTildeSudakov::createInitialStateBranching(Energy scale,double z, - double phi, Energy pt) { - ShoKinPtr showerKin = new_ptr(IS_QTildeShowerKinematics1to2()); - showerKin->scale(scale); - showerKin->z(z); - showerKin->phi(phi); - showerKin->pT(pt); - showerKin->SudakovFormFactor(this); - return showerKin; -} - -ShoKinPtr QTildeSudakov::createDecayBranching(Energy scale,double z, - double phi, Energy pt) { - ShoKinPtr showerKin = new_ptr(Decay_QTildeShowerKinematics1to2()); - showerKin->scale(scale); - showerKin->z(z); - showerKin->phi(phi); - showerKin->pT(pt); - showerKin->SudakovFormFactor(this); - return showerKin; -} diff --git a/Shower/QTilde/Default/QTildeSudakov.h b/Shower/QTilde/Default/QTildeSudakov.h deleted file mode 100644 --- a/Shower/QTilde/Default/QTildeSudakov.h +++ /dev/null @@ -1,291 +0,0 @@ -// -*- C++ -*- -// -// QTildeSudakov.h is a part of Herwig - A multi-purpose Monte Carlo event generator -// Copyright (C) 2002-2017 The Herwig Collaboration -// -// Herwig is licenced under version 3 of the GPL, see COPYING for details. -// Please respect the MCnet academic guidelines, see GUIDELINES for details. -// -#ifndef HERWIG_QTildeSudakov_H -#define HERWIG_QTildeSudakov_H -// -// This is the declaration of the QTildeSudakov class. -// - -#include "Herwig/Shower/QTilde/Base/SudakovFormFactor.h" - -namespace Herwig { - -using namespace ThePEG; - -/** \ingroup Shower - * - * The QTildeSudakov class implements the Sudakov form factor for evolution in - * \f$\tilde{q}^2\f$ using the veto algorithm. - * - * @see \ref QTildeSudakovInterfaces "The interfaces" - * defined for QTildeSudakov. - */ -class QTildeSudakov: public SudakovFormFactor { - -public: - - /** - * The default constructor. - */ - inline QTildeSudakov() {} - - /** - * Members to generate the scale of the next branching - */ - //@{ - /** - * Return the scale of the next time-like branching. If there is no - * branching then it returns ZERO. - * @param startingScale starting scale for the evolution - * @param ids The PDG codes of the particles in the splitting - * @param enhance The radiation enhancement factor - * @param maxQ2 The maximum \f$Q^2\f$ for the emission - */ - virtual ShoKinPtr generateNextTimeBranching(const Energy startingScale, - const IdList &ids, - const RhoDMatrix & rho, - double enhance, - double detuning, - Energy2 maxQ2); - - /** - * Return the scale of the next space-like decay branching. If there is no - * branching then it returns ZERO. - * @param startingScale starting scale for the evolution - * @param stoppingScale stopping scale for the evolution - * @param minmass The minimum mass allowed for the spake-like particle. - * @param ids The PDG codes of the particles in the splitting - * defined. - * @param enhance The radiation enhancement factor - */ - virtual ShoKinPtr generateNextDecayBranching(const Energy startingScale, - const Energy stoppingScale, - const Energy minmass, - const IdList &ids, - const RhoDMatrix & rho, - double enhance, - double detuning); - - /** - * Return the scale of the next space-like branching. If there is no - * branching then it returns ZERO. - * @param startingScale starting scale for the evolution - * @param ids The PDG codes of the particles in the splitting - * @param x The fraction of the beam momentum - * defined. - * @param enhance The radiation enhancement factor - * @param beam The beam particle - */ - virtual ShoKinPtr generateNextSpaceBranching(const Energy startingScale, - const IdList &ids,double x, - const RhoDMatrix & rho, - double enhance, - tcBeamPtr beam, - double detuning); - //@} - - /** - * Generate the azimuthal angle of the branching for forward branching - * @param particle The branching particle - * @param ids The PDG codes of the particles in the branchings - * @param The Shower kinematics - */ - virtual double generatePhiForward(ShowerParticle & particle,const IdList & ids, - ShoKinPtr kinematics, - const RhoDMatrix & rho); - - /** - * Generate the azimuthal angle of the branching for backward branching - * @param particle The branching particle - * @param ids The PDG codes of the particles in the branchings - * @param The Shower kinematics - */ - virtual double generatePhiBackward(ShowerParticle & particle,const IdList & ids, - ShoKinPtr kinematics, - const RhoDMatrix & rho); - - /** - * Generate the azimuthal angle of the branching for ISR in decays - * @param particle The branching particle - * @param ids The PDG codes of the particles in the branchings - * @param The Shower kinematics - */ - virtual double generatePhiDecay(ShowerParticle & particle,const IdList & ids, - ShoKinPtr kinematics, - const RhoDMatrix & rho); - - /** - * Method to return the evolution scale given the - * transverse momentum, \f$p_T\f$ and \f$z\f$. - */ - virtual Energy calculateScale(double z, Energy pt, IdList ids,unsigned int iopt); - - /** - * Method to create the ShowerKinematics object for a final-state branching - */ - virtual ShoKinPtr createFinalStateBranching(Energy scale,double z, - double phi, Energy pt); - - /** - * Method to create the ShowerKinematics object for an initial-state branching - */ - virtual ShoKinPtr createInitialStateBranching(Energy scale,double z, - double phi, Energy pt); - - /** - * Method to create the ShowerKinematics object for a decay branching - */ - virtual ShoKinPtr createDecayBranching(Energy scale,double z, - double phi, Energy pt); - -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(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(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: - /** - * Methods to provide the next value of the scale before the vetos - * are applied. - */ - //@{ - /** - * Value of the energy fraction and scale for time-like branching - * @param t The scale - * @param tmin The minimum scale - * @param enhance The radiation enhancement factor - * @return False if scale less than minimum, true otherwise - */ - bool guessTimeLike(Energy2 &t, Energy2 tmin, double enhance, double detune); - - /** - * Value of the energy fraction and scale for time-like branching - * @param t The scale - * @param tmax The maximum scale - * @param minmass The minimum mass of the particle after the branching - * @param enhance The radiation enhancement factor - */ - bool guessDecay(Energy2 &t, Energy2 tmax,Energy minmass, - double enhance, double detune); - - /** - * Value of the energy fraction and scale for space-like branching - * @param t The scale - * @param tmin The minimum scale - * @param x Fraction of the beam momentum. - * @param enhance The radiation enhancement factor - */ - bool guessSpaceLike(Energy2 &t, Energy2 tmin, const double x, - double enhance, double detune); - //@} - - /** - * Initialize the values of the cut-offs and scales - * @param tmin The minimum scale - * @param ids The ids of the partics in the branching - */ - void initialize(const IdList & ids,Energy2 &tmin); - - /** - * Phase Space veto member to implement the \f$\Theta\f$ function as a veto - * so that the emission is within the allowed phase space. - * @param t The scale - * @param maxQ2 The maximum virtuality - * @return true if vetoed - */ - bool PSVeto(const Energy2 t,const Energy2 maxQ2); - - /** - * Compute the limits on \f$z\f$ for time-like branching - * @param scale The scale of the particle - * @return True if lower limit less than upper, otherwise false - */ - bool computeTimeLikeLimits(Energy2 & scale); - - /** - * Compute the limits on \f$z\f$ for space-like branching - * @param scale The scale of the particle - * @param x The energy fraction of the parton - * @return True if lower limit less than upper, otherwise false - */ - bool computeSpaceLikeLimits(Energy2 & scale, double x); - -protected: - - /** @name Clone Methods. */ - //@{ - /** - * Make a simple clone of this object. - * @return a pointer to the new object. - */ - inline virtual IBPtr clone() const {return new_ptr(*this);} - - /** Make a clone of this object, possibly modifying the cloned object - * to make it sane. - * @return a pointer to the new object. - */ - inline virtual IBPtr fullclone() const {return new_ptr(*this);} - //@} - -private: - - /** - * The assignment operator is private and must never be called. - * In fact, it should not even be implemented. - */ - QTildeSudakov & operator=(const QTildeSudakov &); - -private: - - /** - * The evolution scale, \f$\tilde{q}\f$. - */ - Energy q_; - - /** - * The Ids of the particles in the current branching - */ - IdList ids_; - - /** - * The masses of the particles in the current branching - */ - vector masses_; - - /** - * The mass squared of the particles in the current branching - */ - vector masssquared_; - -}; - -} - -#endif /* HERWIG_QTildeSudakov_H */ diff --git a/Shower/QTilde/Default/Decay_QTildeShowerKinematics1to2.cc b/Shower/QTilde/Kinematics/Decay_QTildeShowerKinematics1to2.cc rename from Shower/QTilde/Default/Decay_QTildeShowerKinematics1to2.cc rename to Shower/QTilde/Kinematics/Decay_QTildeShowerKinematics1to2.cc --- a/Shower/QTilde/Default/Decay_QTildeShowerKinematics1to2.cc +++ b/Shower/QTilde/Kinematics/Decay_QTildeShowerKinematics1to2.cc @@ -1,113 +1,109 @@ // -*- C++ -*- // // Decay_QTildeShowerKinematics1to2.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 Decay_QTildeShowerKinematics1to2 class. // #include "Decay_QTildeShowerKinematics1to2.h" #include "ThePEG/PDT/EnumParticles.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include #include "Herwig/Shower/ShowerHandler.h" #include "Herwig/Shower/QTilde/Base/ShowerVertex.h" using namespace Herwig; void Decay_QTildeShowerKinematics1to2:: updateChildren(const tShowerParticlePtr parent, const ShowerParticleVector & children, - ShowerPartnerType partnerType, - bool massVeto) const { + ShowerPartnerType partnerType) const { assert(children.size() == 2); // calculate the scales splittingFn()->evaluateDecayScales(partnerType,scale(),z(),parent, children[0],children[1]); // set the maximum virtual masses IdList ids(3); ids[0] = parent->dataPtr(); ids[1] = children[0]->dataPtr(); ids[2] = children[1]->dataPtr(); const vector & virtualMasses = SudakovFormFactor()->virtualMasses(ids); Energy2 q2 = sqr(virtualMasses[0])-(1.-z())*sqr(scale()); children[0]->virtualMass(sqrt(q2)); - if(massVeto) { - children[1]->scales().Max_Q2 = (1.-z())/z()*(z()*sqr(virtualMasses[0])-q2); - } // determine alphas of children according to interpretation of z const ShowerParticle::Parameters & params = parent->showerParameters(); ShowerParticle::Parameters & child0 = children[0]->showerParameters(); ShowerParticle::Parameters & child1 = children[1]->showerParameters(); child0.alpha = z() * params.alpha; child1.alpha = (1.-z()) * params.alpha; child0.ptx = pT() * cos(phi()) + z()* params.ptx; child0.pty = pT() * sin(phi()) + z()* params.pty; child0.pt = sqrt( sqr(child0.ptx) + sqr(child0.pty) ); child1.ptx = -pT() * cos(phi()) + (1.-z()) * params.ptx; child1.pty = -pT() * sin(phi()) + (1.-z()) * params.pty; child1.pt = sqrt( sqr(child1.ptx) + sqr(child1.pty) ); // set up the colour connections splittingFn()->colourConnection(parent,children[0],children[1],partnerType,false); // make the products children of the parent parent->addChild(children[0]); parent->addChild(children[1]); // set the momenta of the children for(ShowerParticleVector::const_iterator pit=children.begin(); pit!=children.end();++pit) { (**pit).showerBasis(parent->showerBasis(),true); (**pit).setShowerMomentum(true); } } void Decay_QTildeShowerKinematics1to2:: reconstructParent( const tShowerParticlePtr, const ParticleVector &) const { throw Exception() << "Decay_QTildeShowerKinematics1to2::reconstructParent not implemented" << Exception::abortnow; } void Decay_QTildeShowerKinematics1to2:: reconstructLast(const tShowerParticlePtr last, Energy mass) const { // set beta component and consequently all missing data from that, // using the nominal (i.e. PDT) mass. Energy theMass = mass > ZERO ? mass : last->data().constituentMass(); last->showerParameters().beta= (sqr(theMass) + sqr(last->showerParameters().pt) - sqr( last->showerParameters().alpha )*last->showerBasis()->pVector().m2()) / ( 2.*last->showerParameters().alpha*last->showerBasis()->p_dot_n() ); // set that new momentum last->set5Momentum( last->showerBasis()->sudakov2Momentum( last->showerParameters().alpha, last->showerParameters().beta, last->showerParameters().ptx, last->showerParameters().pty) ); } void Decay_QTildeShowerKinematics1to2::updateParent(const tShowerParticlePtr parent, const ShowerParticleVector & children, ShowerPartnerType) const { IdList ids(3); ids[0] = parent->dataPtr(); ids[1] = children[0]->dataPtr(); ids[2] = children[1]->dataPtr(); const vector & virtualMasses = SudakovFormFactor()->virtualMasses(ids); children[0]->virtualMass(sqrt(sqr(virtualMasses[0])-(1.-z())*sqr(scale()))); if(children[1]->children().empty()) children[1]->virtualMass(virtualMasses[2]); // compute the new pT of the branching Energy2 pt2=(1.-z())*(z()*sqr(virtualMasses[0])-sqr(children[0]->virtualMass())) -z()*sqr(children[1]->virtualMass()); if(pt2>ZERO) { pT(sqrt(pt2)); } else { parent->virtualMass(ZERO); } } diff --git a/Shower/QTilde/Default/Decay_QTildeShowerKinematics1to2.h b/Shower/QTilde/Kinematics/Decay_QTildeShowerKinematics1to2.h rename from Shower/QTilde/Default/Decay_QTildeShowerKinematics1to2.h rename to Shower/QTilde/Kinematics/Decay_QTildeShowerKinematics1to2.h --- a/Shower/QTilde/Default/Decay_QTildeShowerKinematics1to2.h +++ b/Shower/QTilde/Kinematics/Decay_QTildeShowerKinematics1to2.h @@ -1,101 +1,113 @@ // -*- C++ -*- // // Decay_QTildeShowerKinematics1to2.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_Decay_QTildeShowerKinematics1to2_H #define HERWIG_Decay_QTildeShowerKinematics1to2_H // // This is the declaration of the Decay_QTildeShowerKinematics1to2 class. // -#include "Herwig/Shower/QTilde/Base/ShowerKinematics.h" +#include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This (concrete) class provides the specific decay shower * kinematics information. * * @see ShowerKinematics * @see IS_QTildeShowerKinematics1to2 * @see FS_QTildeShowerKinematics1to2 * @see KinematicsReconstructor * */ class Decay_QTildeShowerKinematics1to2: public ShowerKinematics { +public: + + /** + * Default constructor + */ + Decay_QTildeShowerKinematics1to2() = default; + + /** + * The constructor. + */ + Decay_QTildeShowerKinematics1to2(Energy scale, double z, double phi, Energy pt, tSudakovPtr sud) + : ShowerKinematics(scale,z,phi,pt,sud) {} + public: /** * The updateChildren, updateParent and updateLast * members to update the values of the \f$\alpha\f$ and * \f$p_\perp\f$ variables during the shower evolution. */ //@{ /** * Along with the showering evolution --- going forward for * time-like (forward) evolution, and going backward for space-like * (backward) evolution --- the kinematical variables of the * branching products are calculated and updated from the knowledge * of the parent kinematics. This method is used by the * ForwardShowerEvolver. * @param parent The branching particle * @param children The particles produced in the branching * @param partnerType The type of evolution partner */ virtual void updateChildren( const tShowerParticlePtr parent, const ShowerParticleVector & children, - ShowerPartnerType partnerType, - bool massVeto) const; + ShowerPartnerType partnerType) const; /** * Update the parent Kinematics from the knowledge of the kinematics * of the children. This method will be used by the * KinematicsReconstructor. */ virtual void reconstructParent( const tShowerParticlePtr parent, const ParticleVector & children ) const; /** * Update the kinematical data of a particle when a reconstruction * fixpoint was found. This will highly depend on the kind of * kinematics chosen and will be defined in the inherited concrete * classes. This method will be used by the KinematicsReconstructor. * @param last The particle to update * @param mass The mass to be used, if less than zero on-shell */ virtual void reconstructLast(const tShowerParticlePtr last, Energy mass=-1.*GeV) const; /** * Update the parent Kinematics from the knowledge of the kinematics * of the children. This method will be used by the KinematicsReconstructor. * @param parent The parent * @param children The children * @param partnerType The type of evolution partner */ virtual void updateParent(const tShowerParticlePtr parent, const ShowerParticleVector & children, ShowerPartnerType partnerType) const; //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ - Decay_QTildeShowerKinematics1to2 & operator=(const Decay_QTildeShowerKinematics1to2 &); + Decay_QTildeShowerKinematics1to2 & operator=(const Decay_QTildeShowerKinematics1to2 &) = delete; }; } #endif /* HERWIG_Decay_QTildeShowerKinematics1to2_H */ diff --git a/Shower/QTilde/Default/FS_QTildeShowerKinematics1to2.cc b/Shower/QTilde/Kinematics/FS_QTildeShowerKinematics1to2.cc rename from Shower/QTilde/Default/FS_QTildeShowerKinematics1to2.cc rename to Shower/QTilde/Kinematics/FS_QTildeShowerKinematics1to2.cc --- a/Shower/QTilde/Default/FS_QTildeShowerKinematics1to2.cc +++ b/Shower/QTilde/Kinematics/FS_QTildeShowerKinematics1to2.cc @@ -1,204 +1,191 @@ // -*- C++ -*- // // FS_QTildeShowerKinematics1to2.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 FS_QTildeShowerKinematics1to2 class. // #include "FS_QTildeShowerKinematics1to2.h" #include "ThePEG/PDT/EnumParticles.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "ThePEG/Utilities/Debug.h" #include "Herwig/Shower/QTilde/QTildeShowerHandler.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" -#include "Herwig/Shower/QTilde/Base/ShowerModel.h" -#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicHelpers.h" #include "Herwig/Shower/QTilde/Base/ShowerVertex.h" using namespace Herwig; void FS_QTildeShowerKinematics1to2:: updateParameters(tShowerParticlePtr theParent, tShowerParticlePtr theChild0, tShowerParticlePtr theChild1, bool setAlpha) const { const ShowerParticle::Parameters & parent = theParent->showerParameters(); ShowerParticle::Parameters & child0 = theChild0->showerParameters(); ShowerParticle::Parameters & child1 = theChild1->showerParameters(); // determine alphas of children according to interpretation of z if ( setAlpha ) { child0.alpha = z() * parent.alpha; child1.alpha = (1.-z()) * parent.alpha; } // set the values double cphi = cos(phi()); double sphi = sin(phi()); child0.ptx = pT() * cphi + z() * parent.ptx; child0.pty = pT() * sphi + z() * parent.pty; child0.pt = sqrt( sqr(child0.ptx) + sqr(child0.pty) ); child1.ptx = -pT() * cphi + (1.-z())* parent.ptx; child1.pty = -pT() * sphi + (1.-z())* parent.pty; child1.pt = sqrt( sqr(child1.ptx) + sqr(child1.pty) ); } void FS_QTildeShowerKinematics1to2:: updateChildren(const tShowerParticlePtr parent, const ShowerParticleVector & children, - ShowerPartnerType partnerType, - bool massVeto) const { + ShowerPartnerType partnerType) const { assert(children.size()==2); // calculate the scales splittingFn()->evaluateFinalStateScales(partnerType,scale(),z(),parent, children[0],children[1]); - // set the maximum virtual masses - if(massVeto) { - Energy2 q2 = z()*(1.-z())*sqr(scale()); - IdList ids(3); - ids[0] = parent->dataPtr(); - ids[1] = children[0]->dataPtr(); - ids[2] = children[1]->dataPtr(); - const vector & virtualMasses = SudakovFormFactor()->virtualMasses(ids); - if(ids[0]->id()!=ParticleID::g && ids[0]->id()!=ParticleID::gamma ) { - q2 += sqr(virtualMasses[0]); - } - // limits on further evolution - children[0]->scales().Max_Q2 = z() *(q2-sqr(virtualMasses[2])/(1.-z())); - children[1]->scales().Max_Q2 = (1.-z())*(q2-sqr(virtualMasses[1])/ z() ); - } + // update the parameters updateParameters(parent, children[0], children[1], true); // set up the colour connections splittingFn()->colourConnection(parent,children[0],children[1],partnerType,false); // make the products children of the parent parent->addChild(children[0]); parent->addChild(children[1]); // set the momenta of the children for(ShowerParticleVector::const_iterator pit=children.begin(); pit!=children.end();++pit) { (**pit).showerBasis(parent->showerBasis(),true); (**pit).setShowerMomentum(true); } // sort out the helicity stuff if(! dynamic_ptr_cast(ShowerHandler::currentHandler())->correlations()) return; SpinPtr pspin(parent->spinInfo()); if(!pspin || !dynamic_ptr_cast(ShowerHandler::currentHandler())->spinCorrelations() ) return; Energy2 t = sqr(scale())*z()*(1.-z()); IdList ids; ids.push_back(parent->dataPtr()); ids.push_back(children[0]->dataPtr()); ids.push_back(children[1]->dataPtr()); // create the vertex SVertexPtr vertex(new_ptr(ShowerVertex())); // set the matrix element vertex->ME(splittingFn()->matrixElement(z(),t,ids,phi(),true)); RhoDMatrix mapping; SpinPtr inspin; bool needMapping = parent->getMapping(inspin,mapping); if(needMapping) vertex->incomingBasisTransform(mapping); // set the incoming particle for the vertex parent->spinInfo()->decayVertex(vertex); for(ShowerParticleVector::const_iterator pit=children.begin(); pit!=children.end();++pit) { // construct the spin info for the children (**pit).constructSpinInfo(true); // connect the spinInfo object to the vertex (*pit)->spinInfo()->productionVertex(vertex); } } void FS_QTildeShowerKinematics1to2:: reconstructParent(const tShowerParticlePtr parent, const ParticleVector & children ) const { assert(children.size() == 2); ShowerParticlePtr c1 = dynamic_ptr_cast(children[0]); ShowerParticlePtr c2 = dynamic_ptr_cast(children[1]); parent->showerParameters().beta= c1->showerParameters().beta + c2->showerParameters().beta; Lorentz5Momentum pnew = c1->momentum() + c2->momentum(); Energy2 m2 = sqr(pT())/z()/(1.-z()) + sqr(c1->mass())/z() + sqr(c2->mass())/(1.-z()); pnew.setMass(sqrt(m2)); parent->set5Momentum( pnew ); } void FS_QTildeShowerKinematics1to2::reconstructLast(const tShowerParticlePtr last, Energy mass) const { // set beta component and consequently all missing data from that, // using the nominal (i.e. PDT) mass. Energy theMass = mass > ZERO ? mass : last->data().constituentMass(); Lorentz5Momentum pVector = last->showerBasis()->pVector(); ShowerParticle::Parameters & lastParam = last->showerParameters(); Energy2 denom = 2. * lastParam.alpha * last->showerBasis()->p_dot_n(); if(abs(denom)/(sqr(pVector.e())+pVector.rho2())<1e-10) { throw KinematicsReconstructionVeto(); } lastParam.beta = ( sqr(theMass) + sqr(lastParam.pt) - sqr(lastParam.alpha) * pVector.m2() ) / denom; // set that new momentum Lorentz5Momentum newMomentum = last->showerBasis()-> sudakov2Momentum( lastParam.alpha, lastParam.beta, lastParam.ptx , lastParam.pty); newMomentum.setMass(theMass); newMomentum.rescaleEnergy(); if(last->data().stable()) { last->set5Momentum( newMomentum ); } else { last->boost(last->momentum().findBoostToCM()); last->boost(newMomentum.boostVector()); } } void FS_QTildeShowerKinematics1to2::updateParent(const tShowerParticlePtr parent, const ShowerParticleVector & children, ShowerPartnerType) const { IdList ids(3); ids[0] = parent->dataPtr(); ids[1] = children[0]->dataPtr(); ids[2] = children[1]->dataPtr(); const vector & virtualMasses = SudakovFormFactor()->virtualMasses(ids); if(children[0]->children().empty()) children[0]->virtualMass(virtualMasses[1]); if(children[1]->children().empty()) children[1]->virtualMass(virtualMasses[2]); // compute the new pT of the branching - Energy2 pt2=sqr(z()*(1.-z()))*sqr(scale()) - - sqr(children[0]->virtualMass())*(1.-z()) - - sqr(children[1]->virtualMass())* z() ; - if(ids[0]->id()!=ParticleID::g) pt2 += z()*(1.-z())*sqr(virtualMasses[0]); + Energy2 m02 = (ids[0]->id()!=ParticleID::g && ids[0]->id()!=ParticleID::gamma) ? + sqr(virtualMasses[0]) : Energy2(); + + Energy2 pt2 = QTildeKinematics::pT2_FSR( + sqr(scale()), z(), m02, sqr(children[0]->virtualMass()), sqr(children[1]->virtualMass()) + ); + if(pt2>ZERO) { pT(sqrt(pt2)); } else { pt2=ZERO; pT(ZERO); } - Energy2 q2 = - sqr(children[0]->virtualMass())/z() + - sqr(children[1]->virtualMass())/(1.-z()) + - pt2/z()/(1.-z()); + Energy2 q2 = QTildeKinematics::q2_FSR( + pt2, z(), sqr(children[0]->virtualMass()), sqr(children[1]->virtualMass()) + ); parent->virtualMass(sqrt(q2)); } void FS_QTildeShowerKinematics1to2:: resetChildren(const tShowerParticlePtr parent, const ShowerParticleVector & children) const { updateParameters(parent, children[0], children[1], false); for(unsigned int ix=0;ixchildren().empty()) continue; ShowerParticleVector newChildren; for(unsigned int iy=0;iychildren().size();++iy) newChildren.push_back(dynamic_ptr_cast (children[ix]->children()[iy])); children[ix]->showerKinematics()->resetChildren(children[ix],newChildren); } } diff --git a/Shower/QTilde/Default/FS_QTildeShowerKinematics1to2.h b/Shower/QTilde/Kinematics/FS_QTildeShowerKinematics1to2.h rename from Shower/QTilde/Default/FS_QTildeShowerKinematics1to2.h rename to Shower/QTilde/Kinematics/FS_QTildeShowerKinematics1to2.h --- a/Shower/QTilde/Default/FS_QTildeShowerKinematics1to2.h +++ b/Shower/QTilde/Kinematics/FS_QTildeShowerKinematics1to2.h @@ -1,117 +1,123 @@ // -*- C++ -*- // // FS_QTildeShowerKinematics1to2.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_FS_QTildeShowerKinematics1to2_H #define HERWIG_FS_QTildeShowerKinematics1to2_H // // This is the declaration of the FS_QTildeShowerKinematics1to2 class. // -#include "Herwig/Shower/QTilde/Base/ShowerKinematics.h" +#include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This (concrete) class provides the specific Final State shower * kinematics information. * * @see ShowerKinematics * @see IS_QTildeShowerKinematics1to2 * @see Decay_QTildeShowerKinematics1to2 * @see KinematicsReconstructor */ class FS_QTildeShowerKinematics1to2: public ShowerKinematics { public: /** * Default constructor */ - inline FS_QTildeShowerKinematics1to2() {} + FS_QTildeShowerKinematics1to2() = default; + + /** + * The constructor. + */ + FS_QTildeShowerKinematics1to2(Energy scale, double z, double phi, Energy pt, tSudakovPtr sud) + : ShowerKinematics(scale,z,phi,pt,sud) {} + /** * The updateChildren, updateParent and updateLast * members to update the values of the \f$\alpha\f$ and * \f$p_\perp\f$ variables during the shower evolution. */ //@{ /** * Along with the showering evolution --- going forward for * time-like (forward) evolution, and going backward for space-like * (backward) evolution --- the kinematical variables of the * branching products are calculated and updated from the knowledge * of the parent kinematics. This method is used by the * ForwardShowerEvolver. * @param parent The branching particle * @param children The particles produced in the branching * @param partnerType The type of evolution partner */ private: void updateParameters(tShowerParticlePtr theParent, tShowerParticlePtr theChild0, tShowerParticlePtr theChild1, bool setAlpha) const; public: virtual void updateChildren( const tShowerParticlePtr parent, const ShowerParticleVector & children, - ShowerPartnerType partnerType, - bool massVeto ) const; + ShowerPartnerType partnerType) const; virtual void resetChildren( const tShowerParticlePtr parent, const ShowerParticleVector & children) const; /** * Update the parent Kinematics from the knowledge of the kinematics * of the children. This method will be used by the KinematicsReconstructor. * @param parent The parent * @param children The children * @param partnerType The type of evolution partner */ virtual void updateParent(const tShowerParticlePtr parent, const ShowerParticleVector & children, ShowerPartnerType partnerType) const; /** * Update the parent Kinematics from the knowledge of the kinematics * of the children. This method will be used by the * KinematicsReconstructor. */ virtual void reconstructParent( const tShowerParticlePtr parent, const ParticleVector & children ) const; /** * Update the kinematical data of a particle when a reconstruction * fixpoint was found. This will highly depend on the kind of * kinematics chosen and will be defined in the inherited concrete * classes. This method will be used by the KinematicsReconstructor. * @param last The particle to update * @param mass The mass to be used, if less than zero on-shell */ virtual void reconstructLast(const tShowerParticlePtr last, Energy mass=-1.*GeV) const; //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ - FS_QTildeShowerKinematics1to2 & operator=(const FS_QTildeShowerKinematics1to2 &); + FS_QTildeShowerKinematics1to2 & operator=(const FS_QTildeShowerKinematics1to2 &) = delete; }; } #endif /* HERWIG_FS_QTildeShowerKinematics1to2_H */ diff --git a/Shower/QTilde/Default/IS_QTildeShowerKinematics1to2.cc b/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.cc rename from Shower/QTilde/Default/IS_QTildeShowerKinematics1to2.cc rename to Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.cc --- a/Shower/QTilde/Default/IS_QTildeShowerKinematics1to2.cc +++ b/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.cc @@ -1,150 +1,144 @@ // -*- C++ -*- // // IS_QTildeShowerKinematics1to2.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 IS_QTildeShowerKinematics1to2 class. // #include "IS_QTildeShowerKinematics1to2.h" #include "ThePEG/PDT/EnumParticles.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "ThePEG/Utilities/Debug.h" #include "Herwig/Shower/QTilde/QTildeShowerHandler.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" -#include "Herwig/Shower/QTilde/Base/ShowerModel.h" -#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "Herwig/Shower/QTilde/Base/ShowerVertex.h" #include using namespace Herwig; void IS_QTildeShowerKinematics1to2:: updateChildren( const tShowerParticlePtr theParent, const ShowerParticleVector & children, - ShowerPartnerType, - bool massVeto) const { + ShowerPartnerType) const { const ShowerParticle::Parameters & parent = theParent->showerParameters(); ShowerParticle::Parameters & child0 = children[0]->showerParameters(); ShowerParticle::Parameters & child1 = children[1]->showerParameters(); double cphi = cos(phi()); double sphi = sin(phi()); child1.alpha = (1.-z()) * parent.alpha; child1.ptx = (1.-z()) * parent.ptx - cphi * pT(); child1.pty = (1.-z()) * parent.pty - sphi * pT(); child1.pt = sqrt( sqr(child1.ptx) + sqr(child1.pty) ); // space-like child child0.alpha = parent.alpha - child1.alpha; child0.beta = parent.beta - child1.beta; child0.ptx = parent.ptx - child1.ptx; child0.pty = parent.pty - child1.pty; - if(massVeto) { - Energy2 q2 = (1.-z())*sqr(scale()); - children[1]->scales().Max_Q2 = (1.-z())*q2/z(); - } } void IS_QTildeShowerKinematics1to2:: updateParent(const tShowerParticlePtr parent, const ShowerParticleVector & children, ShowerPartnerType partnerType) const { // calculate the scales splittingFn()->evaluateInitialStateScales(partnerType,scale(),z(),parent, children[0],children[1]); // set proper colour connections splittingFn()->colourConnection(parent,children[0],children[1], partnerType,true); // set proper parent/child relationships parent->addChild(children[0]); parent->addChild(children[1]); parent->x(children[0]->x()/z()); // sort out the helicity stuff // construct the spin info for parent and timelike child // temporary assignment of shower parameters to calculate correlations parent->showerParameters().alpha = parent->x(); children[1]->showerParameters().alpha = (1.-z()) * parent->x(); children[1]->showerParameters().ptx = - cos(phi()) * pT(); children[1]->showerParameters().pty = - sin(phi()) * pT(); children[1]->showerParameters().pt = pT(); parent ->showerBasis(children[0]->showerBasis(),true); children[1]->showerBasis(children[0]->showerBasis(),true); parent ->setShowerMomentum(false); children[1]->setShowerMomentum(true); if(! dynamic_ptr_cast(ShowerHandler::currentHandler())->correlations()) return; SpinPtr pspin(children[0]->spinInfo()); if(!pspin || !dynamic_ptr_cast(ShowerHandler::currentHandler())->spinCorrelations() ) return; // compute the matrix element for spin correlations IdList ids; ids.push_back(parent->dataPtr()); ids.push_back(children[0]->dataPtr()); ids.push_back(children[1]->dataPtr()); Energy2 t = (1.-z())*sqr(scale())/z(); // create the vertex SVertexPtr vertex(new_ptr(ShowerVertex())); // set the matrix element vertex->ME(splittingFn()->matrixElement(z(),t,ids,phi(),false)); // set the incoming particle for the vertex // (in reality the first child as going backwards) pspin->decayVertex(vertex); // construct the spin infos parent ->constructSpinInfo(false); children[1]->constructSpinInfo(true); // connect the spinInfo objects to the vertex parent ->spinInfo()->productionVertex(vertex); children[1]->spinInfo()->productionVertex(vertex); } void IS_QTildeShowerKinematics1to2:: reconstructParent(const tShowerParticlePtr parent, const ParticleVector & children ) const { PPtr c1 = children[0]; ShowerParticlePtr c2 = dynamic_ptr_cast(children[1]); ShowerParticle::Parameters & c2param = c2->showerParameters(); // get shower variables from 1st child in order to keep notation // parent->(c1, c2) clean even though the splitting was initiated // from c1. The name updateParent is still referring to the // timelike branching though. // on-shell child c2param.beta = 0.5*( sqr(c2->data().constituentMass()) + sqr(c2param.pt) ) / ( c2param.alpha * parent->showerBasis()->p_dot_n() ); Lorentz5Momentum pnew = parent->showerBasis()-> sudakov2Momentum(c2param.alpha, c2param.beta, c2param.ptx , c2param.pty); pnew.setMass(c2->data().constituentMass()); pnew.rescaleEnergy(); c2->set5Momentum( pnew ); // spacelike child Lorentz5Momentum pc1(parent->momentum() - c2->momentum()); pc1.rescaleMass(); c1->set5Momentum(pc1); } void IS_QTildeShowerKinematics1to2:: updateLast( const tShowerParticlePtr theLast,Energy px,Energy py) const { if(theLast->isFinalState()) return; Lorentz5Momentum pVector = theLast->showerBasis()->pVector(); ShowerParticle::Parameters & last = theLast->showerParameters(); Energy2 pt2 = sqr(px) + sqr(py); last.alpha = theLast->x(); last.beta = 0.5 * pt2 / last.alpha / theLast->showerBasis()->p_dot_n(); last.ptx = ZERO; last.pty = ZERO; last.pt = ZERO; // momentum Lorentz5Momentum ntemp = Lorentz5Momentum(ZERO,-pVector.vect()); double beta = 0.5 * pt2 / last.alpha / ( pVector * ntemp); Lorentz5Momentum plast = Lorentz5Momentum( (pVector.z()>ZERO ? px : -px), py, ZERO, ZERO) + theLast->x() * pVector + beta * ntemp; plast.rescaleMass(); theLast->set5Momentum(plast); } diff --git a/Shower/QTilde/Default/IS_QTildeShowerKinematics1to2.h b/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.h rename from Shower/QTilde/Default/IS_QTildeShowerKinematics1to2.h rename to Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.h --- a/Shower/QTilde/Default/IS_QTildeShowerKinematics1to2.h +++ b/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.h @@ -1,112 +1,117 @@ // -*- C++ -*- // // IS_QTildeShowerKinematics1to2.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_IS_QTildeShowerKinematics1to2_H #define HERWIG_IS_QTildeShowerKinematics1to2_H // // This is the declaration of the IS_QTildeShowerKinematics1to2 class. // -#include "Herwig/Shower/QTilde/Base/ShowerKinematics.h" +#include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This (concrete) class provides the specific Intial State shower * kinematics information. * * @see ShowerKinematics * @see FS_QTildeShowerKinematics1to2 * @see Decay_QTildeShowerKinematics1to2 * @see KinematicsReconstructor */ class IS_QTildeShowerKinematics1to2: public ShowerKinematics { public: /** @name Standard constructors and destructors. */ //@{ /** * Construct in terms of the basis states */ - inline IS_QTildeShowerKinematics1to2() {} + IS_QTildeShowerKinematics1to2()= default; + + /** + * The default constructor. + */ + IS_QTildeShowerKinematics1to2(Energy scale, double z, double phi, Energy pt, tSudakovPtr sud) + : ShowerKinematics(scale,z,phi,pt,sud) {} //@} public: /** * The updateChildren, updateParent and updateLast * members to update the values of the \f$\alpha\f$ and * \f$p_\perp\f$ variables during the shower evolution. */ //@{ /** * Along with the showering evolution --- going forward for * time-like (forward) evolution, and going backward for space-like * (backward) evolution --- the kinematical variables of the * branching products are calculated and updated from the knowledge * of the parent kinematics. This method is used by the * ForwardShowerEvolver. * @param parent The branching particle * @param children The particles produced in the branching * @param partnerType The type of evolution partner */ virtual void updateChildren( const tShowerParticlePtr parent, const ShowerParticleVector & children, - ShowerPartnerType partnerType, - bool massVeto) const; + ShowerPartnerType partnerType) const; /** * Update the parent Kinematics from the knowledge of the kinematics * of the children. This method will be used by the * KinematicsReconstructor. * @param parent The branching particle * @param children The particles produced in the branching * @param partnerType The type of evolution partner */ virtual void updateParent( const tShowerParticlePtr parent, const ShowerParticleVector & children, ShowerPartnerType partnerType) const; /** * Update the parent Kinematics from the knowledge of the kinematics * of the children. This method will be used by the * KinematicsReconstructor. */ virtual void reconstructParent( const tShowerParticlePtr parent, const ParticleVector & children ) const; /** * Update the kinematical data of a particle when a reconstruction * fixpoint was found. This will highly depend on the kind of * kinematics chosen and will be defined in the inherited concrete * classes. This method will be used by the KinematicsReconstructor. * @param theLast The particle. * @param px The \f$x\f$ component of the \f$p_T\f$. * @param py The \f$y\f$ component of the \f$p_T\f$. */ virtual void updateLast(const tShowerParticlePtr theLast, Energy px, Energy py) const; //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ - IS_QTildeShowerKinematics1to2 & operator=(const IS_QTildeShowerKinematics1to2 &); + IS_QTildeShowerKinematics1to2 & operator=(const IS_QTildeShowerKinematics1to2 &) = delete; }; } #endif /* HERWIG_IS_QTildeShowerKinematics1to2_H */ diff --git a/Shower/QTilde/Kinematics/KinematicHelpers.h b/Shower/QTilde/Kinematics/KinematicHelpers.h new file mode 100644 --- /dev/null +++ b/Shower/QTilde/Kinematics/KinematicHelpers.h @@ -0,0 +1,56 @@ +// -*- C++ -*- +// +// KinematicHelpers.h is a part of Herwig - A multi-purpose Monte Carlo event generator +// Copyright (C) 2018 The Herwig Collaboration +// +// Herwig is licenced under version 3 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +#ifndef HERWIG_KinematicHelpers_H +#define HERWIG_KinematicHelpers_H + +namespace QTildeKinematics { + + + +inline Energy2 pT2_FSR(Energy2 qt2, double z, Energy2 m02, Energy2 m12, Energy2 m22) { + const double z1z = z*(1.-z); + return z1z*(z1z*qt2 + m02) - m12*(1.-z) - m22*z; +} + +inline Energy2 pT2_ISR(Energy2 qt2, double z, Energy2 m22) { + return sqr(1.-z)*qt2 - m22*z; +} + +inline Energy2 pT2_Decay(Energy2 qt2, double z, Energy2 m02, Energy2 m22) { + return sqr(1.-z)*(qt2 - m02) - m22*z; +} + + + +inline Energy pT_FSR(Energy2 qt2, double z, Energy2 m02, Energy2 m12, Energy2 m22) { + return sqrt( pT2_FSR(qt2,z,m02,m12,m22) ); +} + + +inline Energy pT_ISR(Energy2 qt2, double z, Energy2 m22) { + return sqrt( pT2_ISR(qt2,z,m22) ); +} + +inline Energy pT_Decay(Energy2 qt2, double z, Energy2 m02, Energy2 m22) { + return sqrt( pT2_Decay(qt2,z,m02,m22) ); +} + + +inline Energy2 q2_FSR(Energy2 pt2, double z, Energy2 m12, Energy2 m22) { + return m12/z + m22/(1.-z) + pt2/z/(1.-z); +} + +// inline Energy2 q2_ISR(Energy2 pt2, double z, Energy2 m22) { +// return m22/(1.-z) + pt2/z/(1.-z); +// } + + +} + +#endif diff --git a/Shower/QTilde/Kinematics/KinematicsReconstructor.cc b/Shower/QTilde/Kinematics/KinematicsReconstructor.cc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/Kinematics/KinematicsReconstructor.cc @@ -0,0 +1,2942 @@ +// -*- C++ -*- +// +// KinematicsReconstructor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator +// Copyright (C) 2002-2017 The Herwig Collaboration +// +// Herwig 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 KinematicsReconstructor class. +// + +#include "KinematicsReconstructor.h" +#include "ThePEG/PDT/EnumParticles.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/EventRecord/Event.h" +#include "ThePEG/Interface/Parameter.h" +#include "ThePEG/Interface/Switch.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/Interface/RefVector.h" +#include "Herwig/Shower/QTilde/Base/PartnerFinder.h" +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" +#include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" +#include "ThePEG/Repository/UseRandom.h" +#include "ThePEG/EventRecord/ColourLine.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "Herwig/Shower/QTilde/QTildeShowerHandler.h" +#include + +using namespace Herwig; + +DescribeClass +describeKinematicsReconstructor("Herwig::KinematicsReconstructor", "HwShower.so"); + +namespace { + +/** + * Struct to order the jets in off-shellness + */ +struct JetOrdering { + + bool operator() (const JetKinStruct & j1, const JetKinStruct & j2) { + Energy diff1 = j1.q.m()-j1.p.m(); + Energy diff2 = j2.q.m()-j2.p.m(); + if(diff1!=diff2) { + return diff1>diff2; + } + else if( j1.q.e() != j2.q.e() ) + return j1.q.e()>j2.q.e(); + else + return j1.parent->uniqueId>j2.parent->uniqueId; + } +}; + +} + +void KinematicsReconstructor::persistentOutput(PersistentOStream & os) const { + os << _reconopt << _initialBoost << ounit(_minQ,GeV) << _noRescale + << _noRescaleVector << _finalStateReconOption + << _initialStateReconOption; +} + +void KinematicsReconstructor::persistentInput(PersistentIStream & is, int) { + is >> _reconopt >> _initialBoost >> iunit(_minQ,GeV) >> _noRescale + >> _noRescaleVector >> _finalStateReconOption + >> _initialStateReconOption; +} + +void KinematicsReconstructor::Init() { + + static ClassDocumentation documentation + ( "This class is responsible for the kinematics reconstruction of the showering,", + " including the kinematics reshuffling necessary to compensate for the recoil" + "of the emissions." ); + + static Switch interfaceReconstructionOption + ("ReconstructionOption", + "Option for the kinematics reconstruction", + &KinematicsReconstructor::_reconopt, 0, false, false); + static SwitchOption interfaceReconstructionOptionGeneral + (interfaceReconstructionOption, + "General", + "Use the general solution which ignores the colour structure for all processes", + 0); + static SwitchOption interfaceReconstructionOptionColour + (interfaceReconstructionOption, + "Colour", + "Use the colour structure of the process to determine the reconstruction procedure.", + 1); + static SwitchOption interfaceReconstructionOptionColour2 + (interfaceReconstructionOption, + "Colour2", + "Make the most use possible of the colour structure of the process to determine the reconstruction procedure. " + "Start with FF, then IF then II colour connections", + 2); + static SwitchOption interfaceReconstructionOptionColour3 + (interfaceReconstructionOption, + "Colour3", + "Make the most use possible of the colour structure of the process to determine the reconstruction procedure. " + "Do the colour connections in order of the pT's emitted in the shower starting with the hardest." + " The colour partner is fully reconstructed at the same time.", + 3); + static SwitchOption interfaceReconstructionOptionColour4 + (interfaceReconstructionOption, + "Colour4", + "Make the most use possible of the colour structure of the process to determine the reconstruction procedure. " + "Do the colour connections in order of the pT's emitted in the shower starting with the hardest, while leaving" + " the colour partner on mass-shell", + 4); + + static Parameter interfaceMinimumQ2 + ("MinimumQ2", + "The minimum Q2 for the reconstruction of initial-final systems", + &KinematicsReconstructor::_minQ, GeV, 0.001*GeV, 1e-6*GeV, 10.0*GeV, + false, false, Interface::limited); + + static RefVector interfaceNoRescale + ("NoRescale", + "Particles which shouldn't be rescaled to be on shell by the shower", + &KinematicsReconstructor::_noRescaleVector, -1, false, false, true, false, false); + + static Switch interfaceInitialInitialBoostOption + ("InitialInitialBoostOption", + "Option for how the boost from the system before ISR to that after ISR is applied.", + &KinematicsReconstructor::_initialBoost, 0, false, false); + static SwitchOption interfaceInitialInitialBoostOptionOneBoost + (interfaceInitialInitialBoostOption, + "OneBoost", + "Apply one boost from old CMS to new CMS", + 0); + static SwitchOption interfaceInitialInitialBoostOptionLongTransBoost + (interfaceInitialInitialBoostOption, + "LongTransBoost", + "First apply a longitudinal and then a transverse boost", + 1); + + static Switch interfaceFinalStateReconOption + ("FinalStateReconOption", + "Option for how to reconstruct the momenta of the final-state system", + &KinematicsReconstructor::_finalStateReconOption, 0, false, false); + static SwitchOption interfaceFinalStateReconOptionDefault + (interfaceFinalStateReconOption, + "Default", + "All the momenta are rescaled in the rest frame", + 0); + static SwitchOption interfaceFinalStateReconOptionMostOffShell + (interfaceFinalStateReconOption, + "MostOffShell", + "All particles put on the new-mass shell and then the most off-shell and" + " recoiling system are rescaled to ensure 4-momentum is conserved.", + 1); + static SwitchOption interfaceFinalStateReconOptionRecursive + (interfaceFinalStateReconOption, + "Recursive", + "Recursively put on shell by putting the most off-shell particle which" + " hasn't been rescaled on-shell by rescaling the particles and the recoiling system. ", + 2); + static SwitchOption interfaceFinalStateReconOptionRestMostOffShell + (interfaceFinalStateReconOption, + "RestMostOffShell", + "The most off-shell is put on shell by rescaling it and the recoiling system," + " the recoiling system is then put on-shell in its rest frame.", + 3); + static SwitchOption interfaceFinalStateReconOptionRestRecursive + (interfaceFinalStateReconOption, + "RestRecursive", + "As 3 but recursive treated the currently most-off shell," + " only makes a difference if more than 3 partons.", + 4); + + static Switch interfaceInitialStateReconOption + ("InitialStateReconOption", + "Option for the reconstruction of initial state radiation", + &KinematicsReconstructor::_initialStateReconOption, 0, false, false); + static SwitchOption interfaceInitialStateReconOptionRapidity + (interfaceInitialStateReconOption, + "Rapidity", + "Preserve shat and rapidity", + 0); + static SwitchOption interfaceInitialStateReconOptionLongitudinal + (interfaceInitialStateReconOption, + "Longitudinal", + "Preserve longitudinal momentum", + 1); + static SwitchOption interfaceInitialStateReconOptionSofterFraction + (interfaceInitialStateReconOption, + "SofterFraction", + "Preserve the momentum fraction of the parton which has emitted softer.", + 2); + +} + +void KinematicsReconstructor::doinit() { + Interfaced::doinit(); + _noRescale = set(_noRescaleVector.begin(),_noRescaleVector.end()); +} + +bool KinematicsReconstructor:: +reconstructTimeLikeJet(const tShowerParticlePtr particleJetParent) const { + assert(particleJetParent); + bool emitted=true; + // if this is not a fixed point in the reconstruction + if( !particleJetParent->children().empty() ) { + // if not a reconstruction fixpoint, dig deeper for all children: + for ( ParticleVector::const_iterator cit = + particleJetParent->children().begin(); + cit != particleJetParent->children().end(); ++cit ) + reconstructTimeLikeJet(dynamic_ptr_cast(*cit)); + } + // it is a reconstruction fixpoint, ie kinematical data has to be available + else { + // check if the parent was part of the shower + ShowerParticlePtr jetGrandParent; + if(!particleJetParent->parents().empty()) + jetGrandParent= dynamic_ptr_cast + (particleJetParent->parents()[0]); + // update if so + if (jetGrandParent) { + if (jetGrandParent->showerKinematics()) { + if(particleJetParent->id()==_progenitor->id()&& + !_progenitor->data().stable()&&abs(_progenitor->data().id())!=ParticleID::tauminus) { + jetGrandParent->showerKinematics()->reconstructLast(particleJetParent, + _progenitor->mass()); + } + else { + jetGrandParent->showerKinematics()->reconstructLast(particleJetParent); + } + } + } + // otherwise + else { + Energy dm = particleJetParent->data().constituentMass(); + if (abs(dm-particleJetParent->momentum().m())>0.001*MeV + &&(particleJetParent->dataPtr()->stable() || abs(particleJetParent->id())==ParticleID::tauminus) + &&particleJetParent->id()!=ParticleID::gamma + &&_noRescale.find(particleJetParent->dataPtr())==_noRescale.end()) { + Lorentz5Momentum dum = particleJetParent->momentum(); + dum.setMass(dm); + dum.rescaleEnergy(); + particleJetParent->set5Momentum(dum); + } + else { + emitted=false; + } + } + } + // recursion has reached an endpoint once, ie we can reconstruct the + // kinematics from the children. + if( !particleJetParent->children().empty() ) + particleJetParent->showerKinematics() + ->reconstructParent( particleJetParent, particleJetParent->children() ); + return emitted; +} + +bool KinematicsReconstructor:: +reconstructHardJets(ShowerTreePtr hard, + const map > & intrinsic, + ShowerInteraction type, + bool switchRecon) const { + _currentTree = hard; + _intrinsic=intrinsic; + // extract the particles from the ShowerTree + vector ShowerHardJets=hard->extractProgenitors(); + for(unsigned int ix=0;ixprogenitor()] = vector(); + } + for(map >::const_iterator + tit = _currentTree->treelinks().begin(); + tit != _currentTree->treelinks().end();++tit) { + _treeBoosts[tit->first] = vector(); + } + try { + // old recon method, using new member functions + if(_reconopt == 0 || switchRecon ) { + reconstructGeneralSystem(ShowerHardJets); + } + // reconstruction based on coloured systems + else if( _reconopt == 1) { + reconstructColourSinglets(ShowerHardJets,type); + } + // reconstruction of FF, then IF, then II + else if( _reconopt == 2) { + reconstructFinalFirst(ShowerHardJets); + } + // reconstruction based on coloured systems + else if( _reconopt == 3 || _reconopt == 4) { + reconstructColourPartner(ShowerHardJets); + } + else + assert(false); + } + catch(KinematicsReconstructionVeto) { + _progenitor=tShowerParticlePtr(); + _intrinsic.clear(); + for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { + for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { + LorentzRotation rot = rit->inverse(); + bit->first->transform(rot); + } + } + _boosts.clear(); + for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { + for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { + LorentzRotation rot = rit->inverse(); + bit->first->transform(rot,false); + } + } + _currentTree = tShowerTreePtr(); + _treeBoosts.clear(); + return false; + } + catch (Exception & ex) { + _progenitor=tShowerParticlePtr(); + _intrinsic.clear(); + _currentTree = tShowerTreePtr(); + _boosts.clear(); + _treeBoosts.clear(); + throw ex; + } + _progenitor=tShowerParticlePtr(); + _intrinsic.clear(); + // ensure x<1 + for(map::const_iterator + cit=hard->incomingLines().begin();cit!=hard->incomingLines().end();++cit) { + tPPtr parent = cit->first->progenitor(); + while (!parent->parents().empty()) { + parent = parent->parents()[0]; + } + tPPtr hadron; + if ( cit->first->original()->parents().empty() ) { + hadron = cit->first->original(); + } + else { + hadron = cit->first->original()->parents()[0]; + } + if( ! (hadron->id() == parent->id() && hadron->children().size() <= 1) + && parent->momentum().rho() > hadron->momentum().rho()) { + _progenitor=tShowerParticlePtr(); + _intrinsic.clear(); + for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { + for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { + LorentzRotation rot = rit->inverse(); + bit->first->transform(rot); + } + } + _boosts.clear(); + for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { + for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { + LorentzRotation rot = rit->inverse(); + bit->first->transform(rot,false); + } + } + _currentTree = tShowerTreePtr(); + _treeBoosts.clear(); + return false; + } + } + _boosts.clear(); + _treeBoosts.clear(); + _currentTree = tShowerTreePtr(); + return true; +} + +double +KinematicsReconstructor::solveKfactor(const Energy & root_s, + const JetKinVect & jets) const { + Energy2 s = sqr(root_s); + // must be at least two jets + if ( jets.size() < 2) throw KinematicsReconstructionVeto(); + // sum of jet masses must be less than roots + if(momConsEq( 0.0, root_s, jets )>ZERO) throw KinematicsReconstructionVeto(); + // if two jets simple solution + if ( jets.size() == 2 ) { + static const Energy2 eps = 1.0e-4 * MeV2; + if ( sqr(jets[0].p.x()+jets[1].p.x()) < eps && + sqr(jets[0].p.y()+jets[1].p.y()) < eps && + sqr(jets[0].p.z()+jets[1].p.z()) < eps ) { + Energy test = (jets[0].p+jets[1].p).vect().mag(); + if(test > 1.0e-4 * MeV) throw KinematicsReconstructionVeto(); + if ( jets[0].p.vect().mag2() < eps ) throw KinematicsReconstructionVeto(); + Energy2 m1sq(jets[0].q.m2()),m2sq(jets[1].q.m2()); + return sqrt( ( sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq ) + /(4.*s*jets[0].p.vect().mag2()) ); + } + else throw KinematicsReconstructionVeto(); + } + // i.e. jets.size() > 2, numerically + // check convergence, if it's a problem maybe use Newton iteration? + else { + double k1 = 0.,k2 = 1.,k = 0.; + if ( momConsEq( k1, root_s, jets ) < ZERO ) { + while ( momConsEq( k2, root_s, jets ) < ZERO ) { + k1 = k2; + k2 *= 2; + } + while ( fabs( (k1 - k2)/(k1 + k2) ) > 1.e-10 ) { + if( momConsEq( k2, root_s, jets ) == ZERO ) { + return k2; + } else { + k = (k1+k2)/2.; + if ( momConsEq( k, root_s, jets ) > ZERO ) { + k2 = k; + } else { + k1 = k; + } + } + } + return k1; + } else throw KinematicsReconstructionVeto(); + } + throw KinematicsReconstructionVeto(); +} + +bool KinematicsReconstructor:: +reconstructSpaceLikeJet( const tShowerParticlePtr p) const { + bool emitted = true; + tShowerParticlePtr child; + tShowerParticlePtr parent; + if(!p->parents().empty()) + parent = dynamic_ptr_cast(p->parents()[0]); + if(parent) { + emitted=true; + reconstructSpaceLikeJet(parent); + } + // if branching reconstruct time-like child + if(p->children().size()==2) + child = dynamic_ptr_cast(p->children()[1]); + if(p->perturbative()==0 && child) { + dynamic_ptr_cast(p->children()[0])-> + showerKinematics()->reconstructParent(p,p->children()); + if(!child->children().empty()) { + _progenitor=child; + reconstructTimeLikeJet(child); + // calculate the momentum of the particle + Lorentz5Momentum pnew=p->momentum()-child->momentum(); + pnew.rescaleMass(); + p->children()[0]->set5Momentum(pnew); + } + } + return emitted; +} + +Boost KinematicsReconstructor:: +solveBoostBeta( const double k, const Lorentz5Momentum & newq, + const Lorentz5Momentum & oldp ) { + // try something different, purely numerical first: + // a) boost to rest frame of newq, b) boost with kp/E + Energy q = newq.vect().mag(); + Energy2 qs = sqr(q); + Energy2 Q2 = newq.m2(); + Energy kp = k*(oldp.vect().mag()); + Energy2 kps = sqr(kp); + + // usually we take the minus sign, since this boost will be smaller. + // we only require |k \vec p| = |\vec q'| which leaves the sign of + // the boost open but the 'minus' solution gives a smaller boost + // parameter, i.e. the result should be closest to the previous + // result. this is to be changed if we would get many momentum + // conservation violations at the end of the shower from a hard + // process. + double betam = (q*sqrt(qs + Q2) - kp*sqrt(kps + Q2))/(kps + qs + Q2); + // move directly to 'return' + Boost beta = -betam*(k/kp)*oldp.vect(); + // note that (k/kp)*oldp.vect() = oldp.vect()/oldp.vect().mag() but cheaper. + // leave this out if it's running properly! + if ( betam >= 0 ) return beta; + else return Boost(0., 0., 0.); +} + +bool KinematicsReconstructor:: +reconstructDecayJets(ShowerTreePtr decay, + ShowerInteraction) const { + _currentTree = decay; + // extract the particles from the ShowerTree + vector ShowerHardJets=decay->extractProgenitors(); + for(unsigned int ix=0;ixprogenitor()] = vector(); + } + for(map >::const_iterator + tit = _currentTree->treelinks().begin(); + tit != _currentTree->treelinks().end();++tit) { + _treeBoosts[tit->first] = vector(); + } + try { + bool radiated[2]={false,false}; + // find the decaying particle and check if particles radiated + ShowerProgenitorPtr initial; + for(unsigned int ix=0;ixprogenitor()->isFinalState()) { + radiated[1] |=ShowerHardJets[ix]->hasEmitted(); + } + else { + initial=ShowerHardJets[ix]; + radiated[0]|=ShowerHardJets[ix]->hasEmitted(); + } + } + // find boost to the rest frame if needed + Boost boosttorest=-initial->progenitor()->momentum().boostVector(); + double gammarest = + initial->progenitor()->momentum().e()/ + initial->progenitor()->momentum().mass(); + // check if need to boost to rest frame + bool gottaBoost = (boosttorest.mag() > 1e-12); + // if initial state radiation reconstruct the jet and set up the basis vectors + Lorentz5Momentum pjet; + Lorentz5Momentum nvect; + // find the partner + ShowerParticlePtr partner = initial->progenitor()->partner(); + Lorentz5Momentum ppartner[2]; + if(partner) ppartner[0]=partner->momentum(); + // get the n reference vector + if(partner) { + if(initial->progenitor()->showerKinematics()) { + nvect = initial->progenitor()->showerBasis()->getBasis()[1]; + } + else { + Lorentz5Momentum ppartner=initial->progenitor()->partner()->momentum(); + if(gottaBoost) ppartner.boost(boosttorest,gammarest); + nvect = Lorentz5Momentum( ZERO,0.5*initial->progenitor()->mass()* + ppartner.vect().unit()); + nvect.boost(-boosttorest,gammarest); + } + } + // if ISR + if(radiated[0]) { + // reconstruct the decay jet + reconstructDecayJet(initial->progenitor()); + // momentum of decaying particle after ISR + pjet=initial->progenitor()->momentum() + -decay->incomingLines().begin()->second->momentum(); + pjet.rescaleMass(); + } + // boost initial state jet and basis vector if needed + if(gottaBoost) { + pjet.boost(boosttorest,gammarest); + nvect.boost(boosttorest,gammarest); + ppartner[0].boost(boosttorest,gammarest); + } + // loop over the final-state particles and do the reconstruction + JetKinVect possiblepartners; + JetKinVect jetKinematics; + bool atLeastOnce = radiated[0]; + LorentzRotation restboost(boosttorest,gammarest); + Energy inmass(ZERO); + for(unsigned int ix=0;ixprogenitor()->isFinalState()) { + inmass=ShowerHardJets[ix]->progenitor()->mass(); + continue; + } + // do the reconstruction + JetKinStruct tempJetKin; + tempJetKin.parent = ShowerHardJets[ix]->progenitor(); + if(ShowerHardJets.size()==2) { + Lorentz5Momentum dum=ShowerHardJets[ix]->progenitor()->momentum(); + dum.setMass(inmass); + dum.rescaleRho(); + tempJetKin.parent->set5Momentum(dum); + } + tempJetKin.p = ShowerHardJets[ix]->progenitor()->momentum(); + if(gottaBoost) tempJetKin.p.boost(boosttorest,gammarest); + _progenitor=tempJetKin.parent; + if(ShowerHardJets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { + atLeastOnce |= reconstructTimeLikeJet(tempJetKin.parent); + ShowerHardJets[ix]->reconstructed(ShowerProgenitor::done); + } + if(gottaBoost) deepTransform(tempJetKin.parent,restboost); + tempJetKin.q = ShowerHardJets[ix]->progenitor()->momentum(); + jetKinematics.push_back(tempJetKin); + } + if(partner) ppartner[1]=partner->momentum(); + // calculate the rescaling parameters + double k1,k2; + Lorentz5Momentum qt; + if(!solveDecayKFactor(initial->progenitor()->mass(),nvect,pjet, + jetKinematics,partner,ppartner,k1,k2,qt)) { + for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { + for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { + LorentzRotation rot = rit->inverse(); + bit->first->transform(rot); + } + } + _boosts.clear(); + for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { + for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { + LorentzRotation rot = rit->inverse(); + bit->first->transform(rot,false); + } + } + _treeBoosts.clear(); + _currentTree = tShowerTreePtr(); + return false; + } + // apply boosts and rescalings to final-state jets + for(JetKinVect::iterator it = jetKinematics.begin(); + it != jetKinematics.end(); ++it) { + LorentzRotation Trafo = LorentzRotation(); + if(it->parent!=partner) { + // boost for rescaling + if(atLeastOnce) { + map >::const_iterator tit; + for(tit = _currentTree->treelinks().begin(); + tit != _currentTree->treelinks().end();++tit) { + if(tit->second.first && tit->second.second==it->parent) + break; + } + if(it->parent->children().empty()&&!it->parent->spinInfo() && + tit==_currentTree->treelinks().end()) { + Lorentz5Momentum pnew(k2*it->p.vect(), + sqrt(sqr(k2*it->p.vect().mag())+it->q.mass2()), + it->q.mass()); + it->parent->set5Momentum(pnew); + } + else { + // rescaling boost can't ever work in this case + if(k2<0. && it->q.mass()==ZERO) + throw KinematicsReconstructionVeto(); + Trafo = solveBoost(k2, it->q, it->p); + } + } + if(gottaBoost) Trafo.boost(-boosttorest,gammarest); + if(atLeastOnce || gottaBoost) deepTransform(it->parent,Trafo); + } + else { + Lorentz5Momentum pnew=ppartner[0]; + pnew *=k1; + pnew-=qt; + pnew.setMass(ppartner[1].mass()); + pnew.rescaleEnergy(); + LorentzRotation Trafo=solveBoost(1.,ppartner[1],pnew); + if(gottaBoost) Trafo.boost(-boosttorest,gammarest); + deepTransform(partner,Trafo); + } + } + } + catch(KinematicsReconstructionVeto) { + for(map >::const_iterator bit=_boosts.begin();bit!=_boosts.end();++bit) { + for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { + LorentzRotation rot = rit->inverse(); + bit->first->transform(rot); + } + } + _boosts.clear(); + for(map >::const_iterator bit=_treeBoosts.begin();bit!=_treeBoosts.end();++bit) { + for(vector::const_reverse_iterator rit=bit->second.rbegin();rit!=bit->second.rend();++rit) { + LorentzRotation rot = rit->inverse(); + bit->first->transform(rot,false); + } + } + _treeBoosts.clear(); + _currentTree = tShowerTreePtr(); + return false; + } + catch (Exception & ex) { + _currentTree = tShowerTreePtr(); + _boosts.clear(); + _treeBoosts.clear(); + throw ex; + } + _boosts.clear(); + _treeBoosts.clear(); + _currentTree = tShowerTreePtr(); + return true; +} + +bool KinematicsReconstructor:: +reconstructDecayJet( const tShowerParticlePtr p) const { + if(p->children().empty()) return false; + tShowerParticlePtr child; + // if branching reconstruct time-like child + child = dynamic_ptr_cast(p->children()[1]); + if(child) { + _progenitor=child; + reconstructTimeLikeJet(child); + // calculate the momentum of the particle + Lorentz5Momentum pnew=p->momentum()-child->momentum(); + pnew.rescaleMass(); + p->children()[0]->set5Momentum(pnew); + child=dynamic_ptr_cast(p->children()[0]); + reconstructDecayJet(child); + return true; + } + return false; +} + +bool KinematicsReconstructor:: +solveDecayKFactor(Energy mb, + const Lorentz5Momentum & n, + const Lorentz5Momentum & pjet, + const JetKinVect & jetKinematics, + ShowerParticlePtr partner, + Lorentz5Momentum ppartner[2], + double & k1, double & k2, + Lorentz5Momentum & qt) const { + Energy2 pjn = partner ? pjet.vect()*n.vect() : ZERO; + Energy2 pcn = partner ? ppartner[0].vect()*n.vect() : 1.*MeV2; + Energy2 nmag = n.vect().mag2(); + Lorentz5Momentum pn = partner ? (pjn/nmag)*n : Lorentz5Momentum(); + qt=pjet-pn; qt.setE(ZERO); + Energy2 pt2=qt.vect().mag2(); + Energy Ejet = pjet.e(); + // magnitudes of the momenta for fast access + vector pmag; + Energy total(Ejet); + for(unsigned int ix=0;ixmb) return false; + Energy2 pcmag=ppartner[0].vect().mag2(); + // used newton-raphson to get the rescaling + static const Energy eps=1e-8*GeV; + long double d1(1.),d2(1.); + Energy roots, ea, ec, ds; + unsigned int ix=0; + do { + ++ix; + d2 = d1 + pjn/pcn; + roots = Ejet; + ds = ZERO; + for(unsigned int iy=0;iyeps && ix<100); + k1=d1; + k2=d2; + // return true if N-R succeed, otherwise false + return ix<100; +} + +bool KinematicsReconstructor:: +deconstructDecayJets(HardTreePtr decay,ShowerInteraction) const { + // extract the momenta of the particles + vector pin; + vector pout; + // on-shell masses of the decay products + vector mon; + Energy mbar(-GeV); + // the hard branchings of the particles + set::iterator cit; + set branchings=decay->branchings(); + // properties of the incoming particle + bool ISR = false; + HardBranchingPtr initial; + Lorentz5Momentum qisr; + // find the incoming particle, both before and after + // any ISR + for(cit=branchings.begin();cit!=branchings.end();++cit){ + if((*cit)->status()==HardBranching::Incoming|| + (*cit)->status()==HardBranching::Decay) { + // search back up isr if needed + HardBranchingPtr branch = *cit; + while(branch->parent()) branch=branch->parent(); + initial=branch; + // momentum or original parent + pin.push_back(branch->branchingParticle()->momentum()); + // ISR? + ISR = !branch->branchingParticle()->children().empty(); + // ISR momentum + qisr = pin.back()-(**cit).branchingParticle()->momentum(); + qisr.rescaleMass(); + } + } + assert(pin.size()==1); + // compute boost to rest frame + Boost boostv=-pin[0].boostVector(); + // partner for ISR + ShowerParticlePtr partner; + Lorentz5Momentum ppartner; + if(initial->branchingParticle()->partner()) { + partner=initial->branchingParticle()->partner(); + ppartner=partner->momentum(); + } + // momentum of the decay products + for(cit=branchings.begin();cit!=branchings.end();++cit) { + if((*cit)->status()!=HardBranching::Outgoing) continue; + // find the mass of the particle + // including special treatment for off-shell resonances + // to preserve off-shell mass + Energy mass; + if(!(**cit).branchingParticle()->dataPtr()->stable()) { + HardBranchingPtr branch=*cit; + while(!branch->children().empty()) { + for(unsigned int ix=0;ixchildren().size();++ix) { + if(branch->children()[ix]->branchingParticle()->id()== + (**cit).branchingParticle()->id()) { + branch = branch->children()[ix]; + continue; + } + } + }; + mass = branch->branchingParticle()->mass(); + } + else { + mass = (**cit).branchingParticle()->dataPtr()->mass(); + } + // if not evolution partner of decaying particle + if((*cit)->branchingParticle()!=partner) { + pout.push_back((*cit)->branchingParticle()->momentum()); + mon.push_back(mass); + } + // evolution partner of decaying particle + else { + mbar = mass; + } + } + // boost all the momenta to the rest frame of the decaying particle + for(unsigned int ix=0;ixbranchingParticle()->partner()) { + ppartner.boost(boostv); + qisr.boost(boostv); + } + // compute the rescaling factors + double k1,k2; + if(!ISR) { + if(partner) { + pout.push_back(ppartner); + mon.push_back(mbar); + } + k1=k2=inverseRescalingFactor(pout,mon,pin[0].mass()); + if(partner) { + pout.pop_back(); + mon.pop_back(); + } + } + else { + if(!inverseDecayRescalingFactor(pout,mon,pin[0].mass(), + ppartner,mbar,k1,k2)) return false; + } + // now calculate the p reference vectors + unsigned int ifinal=0; + for(cit=branchings.begin();cit!=branchings.end();++cit) { + if((**cit).status()!=HardBranching::Outgoing) continue; + // for partners other than colour partner of decaying particle + if((*cit)->branchingParticle()!=partner) { + Lorentz5Momentum pvect = (*cit)->branchingParticle()->momentum(); + pvect.boost(boostv); + pvect /= k1; + pvect.setMass(mon[ifinal]); + ++ifinal; + pvect.rescaleEnergy(); + pvect.boost(-boostv); + (*cit)->pVector(pvect); + (*cit)->showerMomentum(pvect); + } + // for colour partner of decaying particle + else { + Lorentz5Momentum pvect = (*cit)->branchingParticle()->momentum(); + pvect.boost(boostv); + Lorentz5Momentum qtotal; + for(unsigned int ix=0;ixpVector(pvect); + (*cit)->showerMomentum(pvect); + } + } + // For initial-state if needed + if(initial) { + tShowerParticlePtr newPartner=initial->branchingParticle()->partner(); + if(newPartner) { + tHardBranchingPtr branch; + for( set::iterator clt = branchings.begin(); + clt != branchings.end(); ++clt ) { + if((**clt).branchingParticle()==newPartner) { + initial->colourPartner(*clt); + branch=*clt; + break; + } + } + Lorentz5Momentum pvect = initial->branchingParticle()->momentum(); + initial->pVector(pvect); + Lorentz5Momentum ptemp = branch->pVector(); + ptemp.boost(boostv); + Lorentz5Momentum nvect = Lorentz5Momentum( ZERO, + 0.5*initial->branchingParticle()->mass()* + ptemp.vect().unit()); + nvect.boost(-boostv); + initial->nVector(nvect); + } + } + // calculate the reference vectors, then for outgoing particles + for(cit=branchings.begin();cit!=branchings.end();++cit){ + if((**cit).status()!=HardBranching::Outgoing) continue; + // find the partner branchings + tShowerParticlePtr newPartner=(*cit)->branchingParticle()->partner(); + if(!newPartner) continue; + tHardBranchingPtr branch; + for( set::iterator clt = branchings.begin(); + clt != branchings.end(); ++clt ) { + if(cit==clt) continue; + if((**clt).branchingParticle()==newPartner) { + (**cit).colourPartner(*clt); + branch=*clt; + break; + } + } + if((**decay->incoming().begin()).branchingParticle()==newPartner) { + (**cit).colourPartner(*decay->incoming().begin()); + branch = *decay->incoming().begin(); + } + // final-state colour partner + if(branch->status()==HardBranching::Outgoing) { + Boost boost=((*cit)->pVector()+branch->pVector()).findBoostToCM(); + Lorentz5Momentum pcm = branch->pVector(); + pcm.boost(boost); + Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect()); + nvect.boost( -boost); + (*cit)->nVector(nvect); + } + // initial-state colour partner + else { + Boost boost=branch->pVector().findBoostToCM(); + Lorentz5Momentum pcm = (*cit)->pVector(); + pcm.boost(boost); + Lorentz5Momentum nvect = Lorentz5Momentum( ZERO, -pcm.vect()); + nvect.boost( -boost); + (*cit)->nVector(nvect); + } + } + // now compute the new momenta + // and calculate the shower variables + for(cit=branchings.begin();cit!=branchings.end();++cit) { + if((**cit).status()!=HardBranching::Outgoing) continue; + LorentzRotation B=LorentzRotation(-boostv); + LorentzRotation A=LorentzRotation(boostv),R; + if((*cit)->branchingParticle()==partner) { + Lorentz5Momentum qnew; + Energy2 dot=(*cit)->pVector()*(*cit)->nVector(); + double beta = 0.5*((*cit)->branchingParticle()->momentum().m2() + -sqr((*cit)->pVector().mass()))/dot; + qnew=(*cit)->pVector()+beta*(*cit)->nVector(); + qnew.rescaleMass(); + // compute the boost + R=B*solveBoost(A*qnew,A*(*cit)->branchingParticle()->momentum())*A; + } + else { + Lorentz5Momentum qnew; + if((*cit)->branchingParticle()->partner()) { + Energy2 dot=(*cit)->pVector()*(*cit)->nVector(); + double beta = 0.5*((*cit)->branchingParticle()->momentum().m2() + -sqr((*cit)->pVector().mass()))/dot; + qnew=(*cit)->pVector()+beta*(*cit)->nVector(); + qnew.rescaleMass(); + } + else { + qnew = (*cit)->pVector(); + } + // compute the boost + R=B*solveBoost(A*qnew,A*(*cit)->branchingParticle()->momentum())*A; + } + // reconstruct the momenta + (*cit)->setMomenta(R,1.0,Lorentz5Momentum()); + } + if(initial) { + initial->setMomenta(LorentzRotation(),1.0,Lorentz5Momentum()); + } + return true; +} + +double KinematicsReconstructor:: +inverseRescalingFactor(vector pout, + vector mon, Energy roots) const { + double lambda=1.; + if(pout.size()==2) { + double mu_q1(pout[0].m()/roots), mu_q2(pout[1].m()/roots); + double mu_p1(mon[0]/roots) , mu_p2(mon[1]/roots); + lambda = + ((1.+mu_q1+mu_q2)*(1.-mu_q1-mu_q2)*(mu_q1-1.-mu_q2)*(mu_q2-1.-mu_q1))/ + ((1.+mu_p1+mu_p2)*(1.-mu_p1-mu_p2)*(mu_p1-1.-mu_p2)*(mu_p2-1.-mu_p1)); + if(lambda<0.) + throw Exception() << "Rescaling factor is imaginary in KinematicsReconstructor::" + << "inverseRescalingFactor lambda^2= " << lambda + << Exception::eventerror; + lambda = sqrt(lambda); + } + else { + unsigned int ntry=0; + // compute magnitudes once for speed + vector pmag; + for(unsigned int ix=0;ix root(pout.size()); + do { + // compute new energies + Energy sum(ZERO); + for(unsigned int ix=0;ix::const_iterator it=tree->branchings().begin(); + it!=tree->branchings().end();++it) { + if((**it).status()==HardBranching::Incoming) in .jets.push_back(*it); + else out.jets.push_back(*it); + } + LorentzRotation toRest,fromRest; + bool applyBoost(false); + // do the initial-state reconstruction + deconstructInitialInitialSystem(applyBoost,toRest,fromRest, + tree,in.jets,type); + // do the final-state reconstruction + deconstructFinalStateSystem(toRest,fromRest,tree, + out.jets,type); + // only at this point that we can be sure all the reference vectors + // are correct + for(set::const_iterator it=tree->branchings().begin(); + it!=tree->branchings().end();++it) { + if((**it).status()==HardBranching::Incoming) continue; + if((**it).branchingParticle()->coloured()) + (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); + } + for(set::const_iterator it=tree->incoming().begin(); + it!=tree->incoming().end();++it) { + (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); + } + return true; +} + +bool KinematicsReconstructor::deconstructHardJets(HardTreePtr tree, + ShowerInteraction type) const { + // inverse of old recon method + if(_reconopt == 0) { + return deconstructGeneralSystem(tree,type); + } + else if(_reconopt == 1) { + return deconstructColourSinglets(tree,type); + } + else if(_reconopt == 2) { + throw Exception() << "Inverse reconstruction is not currently supported for ReconstructionOption Colour2 " + << "in KinematicsReconstructor::deconstructHardJets(). Please use one of the other options\n" + << Exception::runerror; + } + else if(_reconopt == 3 || _reconopt == 4 ) { + return deconstructColourPartner(tree,type); + } + else + assert(false); +} + +bool KinematicsReconstructor:: +deconstructColourSinglets(HardTreePtr tree, + ShowerInteraction type) const { + // identify the colour singlet systems + unsigned int nnun(0),nnii(0),nnif(0),nnf(0),nni(0); + vector + systems(identifySystems(tree->branchings(),nnun,nnii,nnif,nnf,nni)); + // now decide what to do + LorentzRotation toRest,fromRest; + bool applyBoost(false); + bool general(false); + // initial-initial connection and final-state colour singlet systems + // Drell-Yan type + if(nnun==0&&nnii==1&&nnif==0&&nnf>0&&nni==0) { + // reconstruct initial-initial system + for(unsigned int ix=0;ix0&&nni==1)|| + (nnif==2&& nni==0))) { + for(unsigned int ix=0;ix0&&nni==2) { + // only FS needed + // but need to boost to rest frame if QED ISR + Lorentz5Momentum ptotal; + for(unsigned int ix=0;ixbranchingParticle()->momentum(); + } + toRest = LorentzRotation(ptotal.findBoostToCM()); + fromRest = toRest; + fromRest.invert(); + if(type!=ShowerInteraction::QCD) { + combineFinalState(systems); + general=false; + } + } + // general type + else { + general = true; + } + // final-state systems except for general recon + if(!general) { + for(unsigned int ix=0;ix::const_iterator it=tree->branchings().begin(); + it!=tree->branchings().end();++it) { + if((**it).status()==HardBranching::Incoming) continue; + if((**it).branchingParticle()->coloured()) + (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); + } + for(set::const_iterator it=tree->incoming().begin(); + it!=tree->incoming().end();++it) { + (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); + } + return true; + } + else { + return deconstructGeneralSystem(tree,type); + } + return true; +} + +bool KinematicsReconstructor:: +deconstructColourPartner(HardTreePtr tree, + ShowerInteraction type) const { + Lorentz5Momentum ptotal; + HardBranchingPtr emitter; + ColourSingletShower incomingShower,outgoingShower; + for(set::const_iterator it=tree->branchings().begin(); + it!=tree->branchings().end();++it) { + if((**it).status()==HardBranching::Incoming) { + incomingShower.jets.push_back(*it); + ptotal += (*it)->branchingParticle()->momentum(); + // check for emitting particle + if((**it).parent() ) { + if(!emitter) + emitter = *it; + else + throw Exception() << "Only one emitting particle allowed in " + << "KinematicsReconstructor::deconstructColourPartner()" + << Exception::runerror; + } + } + else if ((**it).status()==HardBranching::Outgoing) { + outgoingShower.jets.push_back(*it); + // check for emitting particle + if(!(**it).children().empty() ) { + if(!emitter) + emitter = *it; + else + throw Exception() << "Only one emitting particle allowed in " + << "KinematicsReconstructor::deconstructColourPartner()" + << Exception::runerror; + } + } + } + assert(emitter); + assert(emitter->colourPartner()); + ColourSingletShower system; + system.jets.push_back(emitter); + system.jets.push_back(emitter->colourPartner()); + LorentzRotation toRest,fromRest; + bool applyBoost(false); + // identify the colour singlet system + if(emitter->status() == HardBranching::Outgoing && + emitter->colourPartner()->status() == HardBranching::Outgoing ) { + system.type=F; + // need to boost to rest frame if QED ISR + if( !incomingShower.jets[0]->branchingParticle()->coloured() && + !incomingShower.jets[1]->branchingParticle()->coloured() ) { + Boost boost = ptotal.findBoostToCM(); + toRest = LorentzRotation( boost); + fromRest = LorentzRotation(-boost); + } + else + findInitialBoost(ptotal,ptotal,toRest,fromRest); + deconstructFinalStateSystem(toRest,fromRest,tree, + system.jets,type); + } + else if (emitter->status() == HardBranching::Incoming && + emitter->colourPartner()->status() == HardBranching::Incoming) { + system.type=II; + deconstructInitialInitialSystem(applyBoost,toRest,fromRest,tree,system.jets,type); + // make sure the recoil gets applied + deconstructFinalStateSystem(toRest,fromRest,tree, + outgoingShower.jets,type); + } + else if ((emitter->status() == HardBranching::Outgoing && + emitter->colourPartner()->status() == HardBranching::Incoming ) || + (emitter->status() == HardBranching::Incoming && + emitter->colourPartner()->status() == HardBranching::Outgoing)) { + system.type=IF; + // enusre incoming first + if(system.jets[0]->status() == HardBranching::Outgoing) + swap(system.jets[0],system.jets[1]); + deconstructInitialFinalSystem(tree,system.jets,type); + } + else { + throw Exception() << "Unknown type of system in " + << "KinematicsReconstructor::deconstructColourPartner()" + << Exception::runerror; + } + // only at this point that we can be sure all the reference vectors + // are correct + for(set::const_iterator it=tree->branchings().begin(); + it!=tree->branchings().end();++it) { + if((**it).status()==HardBranching::Incoming) continue; + if((**it).branchingParticle()->coloured()) + (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); + } + for(set::const_iterator it=tree->incoming().begin(); + it!=tree->incoming().end();++it) { + (**it).setMomenta(LorentzRotation(),1.,Lorentz5Momentum(),false); + } + for(set::const_iterator it=tree->branchings().begin(); + it!=tree->branchings().end();++it) { + if((**it).status()!=HardBranching::Incoming) continue; + if(*it==system.jets[0] || *it==system.jets[1]) continue; + if((**it).branchingParticle()->momentum().z()>ZERO) { + (**it).z((**it).branchingParticle()->momentum().plus()/(**it).beam()->momentum().plus()); + } + else { + (**it).z((**it).branchingParticle()->momentum().minus()/(**it).beam()->momentum().minus()); + } + } + return true; +} + +void KinematicsReconstructor:: +reconstructInitialFinalSystem(vector jets) const { + Lorentz5Momentum pin[2],pout[2],pbeam; + for(unsigned int ix=0;ixprogenitor()->isFinalState()) { + pout[0] +=jets[ix]->progenitor()->momentum(); + _progenitor = jets[ix]->progenitor(); + if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { + reconstructTimeLikeJet(jets[ix]->progenitor()); + jets[ix]->reconstructed(ShowerProgenitor::done); + } + } + // initial-state parton + else { + pin[0] +=jets[ix]->progenitor()->momentum(); + if(jets[ix]->progenitor()->showerKinematics()) { + pbeam = jets[ix]->progenitor()->showerBasis()->getBasis()[0]; + } + else { + if ( jets[ix]->original()->parents().empty() ) { + pbeam = jets[ix]->progenitor()->momentum(); + } + else { + pbeam = jets[ix]->original()->parents()[0]->momentum(); + } + } + if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { + reconstructSpaceLikeJet(jets[ix]->progenitor()); + jets[ix]->reconstructed(ShowerProgenitor::done); + } + assert(!jets[ix]->original()->parents().empty()); + } + } + // add intrinsic pt if needed + addIntrinsicPt(jets); + // momenta after showering + for(unsigned int ix=0;ixprogenitor()->isFinalState()) + pout[1] += jets[ix]->progenitor()->momentum(); + else + pin[1] += jets[ix]->progenitor()->momentum(); + } + // work out the boost to the Breit frame + Lorentz5Momentum pa = pout[0]-pin[0]; + Axis axis(pa.vect().unit()); + LorentzRotation rot; + double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); + if ( sinth > 1.e-9 ) + rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); + rot.rotateX(Constants::pi); + rot.boostZ( pa.e()/pa.vect().mag()); + Lorentz5Momentum ptemp=rot*pbeam; + Boost trans = -1./ptemp.e()*ptemp.vect(); + trans.setZ(0.); + if ( trans.mag2() - 1. >= 0. ) throw KinematicsReconstructionVeto(); + rot.boost(trans); + pa *=rot; + // project and calculate rescaling + // reference vectors + Lorentz5Momentum n1(ZERO,ZERO,-pa.z(),-pa.z()); + Lorentz5Momentum n2(ZERO,ZERO, pa.z(),-pa.z()); + Energy2 n1n2 = n1*n2; + // decompose the momenta + Lorentz5Momentum qbp=rot*pin[1],qcp=rot*pout[1]; + qbp.rescaleMass(); + qcp.rescaleMass(); + double a[2],b[2]; + a[0] = n2*qbp/n1n2; + b[0] = n1*qbp/n1n2; + Lorentz5Momentum qperp = qbp-a[0]*n1-b[0]*n2; + b[1] = 0.5; + a[1] = 0.5*(qcp.m2()-qperp.m2())/n1n2/b[1]; + double kb; + if(a[0]!=0.) { + double A(0.5*a[0]),B(b[0]*a[0]-a[1]*b[1]-0.25),C(-0.5*b[0]); + if(sqr(B)-4.*A*C<0.) throw KinematicsReconstructionVeto(); + kb = 0.5*(-B+sqrt(sqr(B)-4.*A*C))/A; + } + else { + kb = 0.5*b[0]/(b[0]*a[0]-a[1]*b[1]-0.25); + } + // changed to improve stability + if(kb==0.) throw KinematicsReconstructionVeto(); + if ( a[1]>b[1] && abs(a[1]) < 1e-12 ) + throw KinematicsReconstructionVeto(); + if ( a[1]<=b[1] && abs(0.5+b[0]/kb) < 1e-12 ) + throw KinematicsReconstructionVeto(); + double kc = (a[1]>b[1]) ? (a[0]*kb-0.5)/a[1] : b[1]/(0.5+b[0]/kb); + if(kc==0.) throw KinematicsReconstructionVeto(); + Lorentz5Momentum pnew[2] = { a[0]*kb*n1+b[0]/kb*n2+qperp, + a[1]*kc*n1+b[1]/kc*n2+qperp}; + LorentzRotation rotinv=rot.inverse(); + for(unsigned int ix=0;ixprogenitor()->isFinalState()) { + deepTransform(jets[ix]->progenitor(),rot); + deepTransform(jets[ix]->progenitor(),solveBoost(pnew[1],qcp)); + Energy delta = jets[ix]->progenitor()->momentum().m()-jets[ix]->progenitor()->momentum().mass(); + if ( abs(delta) > MeV ) throw KinematicsReconstructionVeto(); + deepTransform(jets[ix]->progenitor(),rotinv); + } + else { + tPPtr parent; + boostChain(jets[ix]->progenitor(),rot,parent); + boostChain(jets[ix]->progenitor(),solveBoostZ(pnew[0],qbp),parent); + // check the first boost worked, and if not apply small correction to + // fix energy/momentum conservation + // this is a kludge but it reduces momentum non-conservation dramatically + Lorentz5Momentum pdiff = pnew[0]-jets[ix]->progenitor()->momentum(); + Energy2 delta = sqr(pdiff.x())+sqr(pdiff.y())+sqr(pdiff.z())+sqr(pdiff.t()); + unsigned int ntry=0; + while(delta>1e-6*GeV2 && ntry<5 ) { + ntry +=1; + boostChain(jets[ix]->progenitor(),solveBoostZ(pnew[0],jets[ix]->progenitor()->momentum()),parent); + pdiff = pnew[0]-jets[ix]->progenitor()->momentum(); + delta = sqr(pdiff.x())+sqr(pdiff.y())+sqr(pdiff.z())+sqr(pdiff.t()); + } + // apply test in breit-frame + Lorentz5Momentum ptest1 = parent->momentum(); + Lorentz5Momentum ptest2 = rot*pbeam; + if(ptest1.z()/ptest2.z()<0. || ptest1.z()/ptest2.z()>1.) + throw KinematicsReconstructionVeto(); + boostChain(jets[ix]->progenitor(),rotinv,parent); + } + } +} + +bool KinematicsReconstructor::addIntrinsicPt(vector jets) const { + bool added=false; + // add the intrinsic pt if needed + for(unsigned int ix=0;ixprogenitor()->isFinalState()|| + jets[ix]->hasEmitted()|| + jets[ix]->reconstructed()==ShowerProgenitor::dontReconstruct) continue; + if(_intrinsic.find(jets[ix])==_intrinsic.end()) continue; + pair pt=_intrinsic[jets[ix]]; + Energy etemp = jets[ix]->original()->parents()[0]->momentum().z(); + Lorentz5Momentum + p_basis(ZERO, ZERO, etemp, abs(etemp)), + n_basis(ZERO, ZERO,-etemp, abs(etemp)); + double alpha = jets[ix]->progenitor()->x(); + double beta = 0.5*(sqr(jets[ix]->progenitor()->data().mass())+ + sqr(pt.first))/alpha/(p_basis*n_basis); + Lorentz5Momentum pnew=alpha*p_basis+beta*n_basis; + pnew.setX(pt.first*cos(pt.second)); + pnew.setY(pt.first*sin(pt.second)); + pnew.rescaleMass(); + jets[ix]->progenitor()->set5Momentum(pnew); + added = true; + } + return added; +} + +namespace { + +double defaultSolveBoostGamma(const double & betam,const Energy2 & kps, + const Energy2 & qs, const Energy2 & Q2, + const Energy & kp, + const Energy & q, const Energy & qE) { + if(betam<0.5) { + return 1./sqrt(1.-sqr(betam)); + } + else { + return ( kps+ qs + Q2)/ + sqrt(2.*kps*qs + kps*Q2 + qs*Q2 + sqr(Q2) + 2.*q*qE*kp*sqrt(kps + Q2)); + } +} + +} + +LorentzRotation KinematicsReconstructor:: +solveBoost(const double k, const Lorentz5Momentum & newq, + const Lorentz5Momentum & oldp ) const { + Energy q = newq.vect().mag(); + Energy2 qs = sqr(q); + Energy2 Q2 = newq.mass2(); + Energy kp = k*(oldp.vect().mag()); + Energy2 kps = sqr(kp); + double betam = (q*newq.e() - kp*sqrt(kps + Q2))/(kps + qs + Q2); + if ( abs(betam) - 1. >= 0. ) throw KinematicsReconstructionVeto(); + Boost beta = -betam*(k/kp)*oldp.vect(); + double gamma = 0.; + if(Q2/sqr(oldp.e())>1e-4) { + gamma = defaultSolveBoostGamma(betam,kps,qs,Q2,kp,q,newq.e()); + } + else { + if(k>0) { + gamma = 4.*kps*qs/sqr(kps +qs) + 2.*sqr(kps-qs)*Q2/pow<3,1>(kps +qs) + - 0.25*( sqr(kps) + 14.*kps*qs + sqr(qs))*sqr(kps-qs)/(pow<4,1>(kps +qs)*kps*qs)*sqr(Q2); + } + else { + gamma = 0.25*sqr(Q2)/(kps*qs)*(1. - 0.5*(kps+qs)/(kps*qs)*Q2); + } + if(gamma<=0.) throw KinematicsReconstructionVeto(); + gamma = 1./sqrt(gamma); + if(gamma>2.) gamma = defaultSolveBoostGamma(betam,kps,qs,Q2,kp,q,newq.e()); + } + // note that (k/kp)*oldp.vect() = oldp.vect()/oldp.vect().mag() but cheaper. + ThreeVector ax = newq.vect().cross( oldp.vect() ); + double delta; + if (newq.x()*oldp.x()+newq.y()*oldp.y()+newq.z()*oldp.z()< 1e-16*GeV2) { + throw KinematicsReconstructionVeto(); + }else{ + delta = newq.vect().angle( oldp.vect() ); + } + + + LorentzRotation R; + using Constants::pi; + Energy2 scale1 = sqr(newq.x())+ sqr(newq.y())+sqr(newq.z()); + Energy2 scale2 = sqr(oldp.x())+ sqr(oldp.y())+sqr(oldp.z()); + if ( ax.mag2()/scale1/scale2 > 1e-28 ) { + R.rotate( delta, unitVector(ax) ).boost( beta , gamma ); + } + else if(abs(delta-pi)/pi < 0.001) { + double phi=2.*pi*UseRandom::rnd(); + Axis axis(cos(phi),sin(phi),0.); + axis.rotateUz(newq.vect().unit()); + R.rotate(delta,axis).boost( beta , gamma ); + } + else { + R.boost( beta , gamma ); + } + return R; +} + +LorentzRotation KinematicsReconstructor::solveBoost(const Lorentz5Momentum & q, + const Lorentz5Momentum & p ) const { + Energy modp = p.vect().mag(); + Energy modq = q.vect().mag(); + double betam = (p.e()*modp-q.e()*modq)/(sqr(modq)+sqr(modp)+p.mass2()); + if ( abs(betam)-1. >= 0. ) throw KinematicsReconstructionVeto(); + Boost beta = -betam*q.vect().unit(); + ThreeVector ax = p.vect().cross( q.vect() ); + double delta = p.vect().angle( q.vect() ); + LorentzRotation R; + using Constants::pi; + if ( beta.mag2() - 1. >= 0. ) throw KinematicsReconstructionVeto(); + if ( ax.mag2()/GeV2/MeV2 > 1e-16 ) { + R.rotate( delta, unitVector(ax) ).boost( beta ); + } + else { + R.boost( beta ); + } + return R; +} + +LorentzRotation KinematicsReconstructor::solveBoostZ(const Lorentz5Momentum & q, + const Lorentz5Momentum & p ) const { + static const double eps = 1e-6; + LorentzRotation R; + double beta; + Energy2 mt2 = p.mass()eps) { + double erat = (q.t()+q.z())/(p.t()+p.z()); + Energy2 den = mt2*(erat+1./erat); + Energy2 num = (q.z()-p.z())*(q.t()+p.t()) + (p.z()+q.z())*(p.t()-q.t()); + beta = num/den; + if ( abs(beta) - 1. >= 0. ) throw KinematicsReconstructionVeto(); + R.boostZ(beta); + } + else { + double er = sqr(p.t()/q.t()); + double x = ratio+0.125*(er+10.+1./er)*sqr(ratio); + beta = -(p.t()-q.t())*(p.t()+q.t())/(sqr(p.t())+sqr(q.t()))*(1.+x); + double gamma = (4.*sqr(p.t()*q.t()) +sqr(p.t()-q.t())*sqr(p.t()+q.t())* + (-2.*x+sqr(x)))/sqr(sqr(p.t())+sqr(q.t())); + if ( abs(beta) - 1. >= 0. ) throw KinematicsReconstructionVeto(); + gamma = 1./sqrt(gamma); + R.boost(0.,0.,beta,gamma); + } + Lorentz5Momentum ptest = R*p; + if(ptest.z()/q.z() < 0. || ptest.t()/q.t() < 0. ) { + throw KinematicsReconstructionVeto(); + } + return R; +} + +void KinematicsReconstructor:: +reconstructFinalStateSystem(bool applyBoost, + const LorentzRotation & toRest, + const LorentzRotation & fromRest, + vector jets) const { + LorentzRotation trans = applyBoost? toRest : LorentzRotation(); + // special for case of individual particle + if(jets.size()==1) { + deepTransform(jets[0]->progenitor(),trans); + deepTransform(jets[0]->progenitor(),fromRest); + return; + } + bool radiated(false); + // find the hard process centre-of-mass energy + Lorentz5Momentum pcm; + // check if radiated and calculate total momentum + for(unsigned int ix=0;ixhasEmitted(); + pcm += jets[ix]->progenitor()->momentum(); + } + if(applyBoost) pcm *= trans; + // check if in CMF frame + Boost beta_cm = pcm.findBoostToCM(); + bool gottaBoost(false); + if(beta_cm.mag() > 1e-12) { + gottaBoost = true; + trans.boost(beta_cm); + } + // collection of pointers to initial hard particle and jet momenta + // for final boosts + JetKinVect jetKinematics; + vector::const_iterator cit; + for(cit = jets.begin(); cit != jets.end(); cit++) { + JetKinStruct tempJetKin; + tempJetKin.parent = (*cit)->progenitor(); + if(applyBoost || gottaBoost) { + deepTransform(tempJetKin.parent,trans); + } + tempJetKin.p = (*cit)->progenitor()->momentum(); + _progenitor=tempJetKin.parent; + if((**cit).reconstructed()==ShowerProgenitor::notReconstructed) { + radiated |= reconstructTimeLikeJet((*cit)->progenitor()); + (**cit).reconstructed(ShowerProgenitor::done); + } + else { + radiated |= !(*cit)->progenitor()->children().empty(); + } + tempJetKin.q = (*cit)->progenitor()->momentum(); + jetKinematics.push_back(tempJetKin); + } + // default option rescale everything with the same factor + if( _finalStateReconOption == 0 || jetKinematics.size() <= 2 ) { + // find the rescaling factor + double k = 0.0; + if(radiated) { + k = solveKfactor(pcm.m(), jetKinematics); + // perform the rescaling and boosts + for(JetKinVect::iterator it = jetKinematics.begin(); + it != jetKinematics.end(); ++it) { + LorentzRotation Trafo = solveBoost(k, it->q, it->p); + deepTransform(it->parent,Trafo); + } + } + } + // different treatment of most off-shell + else if ( _finalStateReconOption <= 4 ) { + // sort the jets by virtuality + std::sort(jetKinematics.begin(),jetKinematics.end(),JetOrdering()); + // Bryan's procedures from FORTRAN + if( _finalStateReconOption <=2 ) { + // loop over the off-shell partons, _finalStateReconOption==1 only first ==2 all + JetKinVect::const_iterator jend = _finalStateReconOption==1 ? jetKinematics.begin()+1 : jetKinematics.end(); + for(JetKinVect::const_iterator jit=jetKinematics.begin(); jit!=jend;++jit) { + // calculate the 4-momentum of the recoiling system + Lorentz5Momentum psum; + bool done = true; + for(JetKinVect::const_iterator it=jetKinematics.begin();it!=jetKinematics.end();++it) { + if(it==jit) { + done = false; + continue; + } + // first option put on-shell and sum 4-momenta + if( _finalStateReconOption == 1 ) { + LorentzRotation Trafo = solveBoost(1., it->q, it->p); + deepTransform(it->parent,Trafo); + psum += it->parent->momentum(); + } + // second option, sum momenta + else { + // already rescaled + if(done) psum += it->parent->momentum(); + // still needs to be rescaled + else psum += it->p; + } + } + // set the mass + psum.rescaleMass(); + // calculate the 3-momentum rescaling factor + Energy2 s(pcm.m2()); + Energy2 m1sq(jit->q.m2()),m2sq(psum.m2()); + Energy4 num = sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq; + if(nump.vect().mag2()) ); + // boost the off-shell parton + LorentzRotation B1 = solveBoost(k, jit->q, jit->p); + deepTransform(jit->parent,B1); + // boost everything else to rescale + LorentzRotation B2 = solveBoost(k, psum, psum); + for(JetKinVect::iterator it=jetKinematics.begin();it!=jetKinematics.end();++it) { + if(it==jit) continue; + deepTransform(it->parent,B2); + it->p *= B2; + it->q *= B2; + } + } + } + // Peter's C++ procedures + else { + reconstructFinalFinalOffShell(jetKinematics,pcm.m2(), _finalStateReconOption == 4); + } + } + else + assert(false); + // apply the final boosts + if(gottaBoost || applyBoost) { + LorentzRotation finalBoosts; + if(gottaBoost) finalBoosts.boost(-beta_cm); + if(applyBoost) finalBoosts.transform(fromRest); + for(JetKinVect::iterator it = jetKinematics.begin(); + it != jetKinematics.end(); ++it) { + deepTransform(it->parent,finalBoosts); + } + } +} + +void KinematicsReconstructor:: +reconstructInitialInitialSystem(bool & applyBoost, + LorentzRotation & toRest, + LorentzRotation & fromRest, + vector jets) const { + bool radiated = false; + Lorentz5Momentum pcm; + // check whether particles radiated and calculate total momentum + for( unsigned int ix = 0; ix < jets.size(); ++ix ) { + radiated |= jets[ix]->hasEmitted(); + pcm += jets[ix]->progenitor()->momentum(); + if(jets[ix]->original()->parents().empty()) return; + } + pcm.rescaleMass(); + // check if intrinsic pt to be added + radiated |= !_intrinsic.empty(); + // if no radiation return + if(!radiated) { + for(unsigned int ix=0;ixreconstructed()==ShowerProgenitor::notReconstructed) + jets[ix]->reconstructed(ShowerProgenitor::done); + } + return; + } + // initial state shuffling + applyBoost=false; + vector p, pq, p_in; + vector pts; + for(unsigned int ix=0;ixprogenitor()->momentum()); + // reconstruct the jet + if(jets[ix]->reconstructed()==ShowerProgenitor::notReconstructed) { + radiated |= reconstructSpaceLikeJet(jets[ix]->progenitor()); + jets[ix]->reconstructed(ShowerProgenitor::done); + } + assert(!jets[ix]->original()->parents().empty()); + Energy etemp = jets[ix]->original()->parents()[0]->momentum().z(); + Lorentz5Momentum ptemp = Lorentz5Momentum(ZERO, ZERO, etemp, abs(etemp)); + pq.push_back(ptemp); + pts.push_back(jets[ix]->highestpT()); + } + // add the intrinsic pt if needed + radiated |=addIntrinsicPt(jets); + for(unsigned int ix=0;ixprogenitor()->momentum()); + } + double x1 = p_in[0].z()/pq[0].z(); + double x2 = p_in[1].z()/pq[1].z(); + vector beta=initialStateRescaling(x1,x2,p_in[0]+p_in[1],p,pq,pts); + // if not need don't apply boosts + if(!(radiated && p.size() == 2 && pq.size() == 2)) return; + applyBoost=true; + // apply the boosts + Lorentz5Momentum newcmf; + for(unsigned int ix=0;ixprogenitor(); + Boost betaboost(0, 0, beta[ix]); + tPPtr parent; + boostChain(toBoost, LorentzRotation(0.,0.,beta[ix]),parent); + if(parent->momentum().e()/pq[ix].e()>1.|| + parent->momentum().z()/pq[ix].z()>1.) throw KinematicsReconstructionVeto(); + newcmf+=toBoost->momentum(); + } + if(newcmf.m() jets, + ShowerInteraction) const { + assert(jets.size()==2); + // put beam with +z first + if(jets[0]->beam()->momentum().z() pin,pq; + for(unsigned int ix=0;ixbranchingParticle()->momentum()); + Energy etemp = jets[ix]->beam()->momentum().z(); + pq.push_back(Lorentz5Momentum(ZERO, ZERO,etemp, abs(etemp))); + } + // calculate the rescaling + double x[2]; + Lorentz5Momentum pcm=pin[0]+pin[1]; + assert(pcm.mass2()>ZERO); + pcm.rescaleMass(); + vector boost = inverseInitialStateRescaling(x[0],x[1],pcm,pin,pq); + set::const_iterator cjt=tree->incoming().begin(); + HardBranchingPtr incoming[2]; + incoming[0] = *cjt; + ++cjt; + incoming[1] = *cjt; + if((*tree->incoming().begin())->beam()->momentum().z()/pq[0].z()<0.) + swap(incoming[0],incoming[1]); + // apply the boost the the particles + unsigned int iswap[2]={1,0}; + for(unsigned int ix=0;ix<2;++ix) { + LorentzRotation R(0.,0.,-boost[ix]); + incoming[ix]->pVector(pq[ix]); + incoming[ix]->nVector(pq[iswap[ix]]); + incoming[ix]->setMomenta(R,1.,Lorentz5Momentum()); + jets[ix]->showerMomentum(x[ix]*jets[ix]->pVector()); + } + // and calculate the boosts + applyBoost=true; + // do one boost + if(_initialBoost==0) { + toRest = LorentzRotation(-pcm.boostVector()); + } + else if(_initialBoost==1) { + // first the transverse boost + Energy pT = sqrt(sqr(pcm.x())+sqr(pcm.y())); + double beta = -pT/pcm.t(); + toRest=LorentzRotation(Boost(beta*pcm.x()/pT,beta*pcm.y()/pT,0.)); + // the longitudinal + beta = pcm.z()/sqrt(pcm.m2()+sqr(pcm.z())); + toRest.boost(Boost(0.,0.,-beta)); + } + else + assert(false); + fromRest = LorentzRotation((jets[0]->showerMomentum()+ + jets[1]->showerMomentum()).boostVector()); +} + +void KinematicsReconstructor:: +deconstructFinalStateSystem(const LorentzRotation & toRest, + const LorentzRotation & fromRest, + HardTreePtr tree, vector jets, + ShowerInteraction type) const { + LorentzRotation trans = toRest; + if(jets.size()==1) { + Lorentz5Momentum pnew = toRest*(jets[0]->branchingParticle()->momentum()); + pnew *= fromRest; + jets[0]-> original(pnew); + jets[0]->showerMomentum(pnew); + // find the colour partners + ShowerParticleVector particles; + vector ptemp; + set::const_iterator cjt; + for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { + ptemp.push_back((**cjt).branchingParticle()->momentum()); + (**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum()); + particles.push_back((**cjt).branchingParticle()); + } + dynamic_ptr_cast(ShowerHandler::currentHandler())->partnerFinder() + ->setInitialEvolutionScales(particles,false,type,false); + // calculate the reference vectors + unsigned int iloc(0); + set::iterator clt; + for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { + // reset the momentum + (**cjt).branchingParticle()->set5Momentum(ptemp[iloc]); + ++iloc; + // sort out the partners + tShowerParticlePtr partner = + (*cjt)->branchingParticle()->partner(); + if(!partner) continue; + for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { + if((**clt).branchingParticle()==partner) { + (**cjt).colourPartner(*clt); + break; + } + } + tHardBranchingPtr branch; + for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { + if(clt==cjt) continue; + if((*clt)->branchingParticle()==partner) { + branch=*clt; + break; + } + } + } + return; + } + vector::iterator cit; + vector pout; + vector mon; + Lorentz5Momentum pin; + for(cit=jets.begin();cit!=jets.end();++cit) { + pout.push_back((*cit)->branchingParticle()->momentum()); + mon.push_back(findMass(*cit)); + pin+=pout.back(); + } + // boost all the momenta to the rest frame of the decaying particle + pin.rescaleMass(); + pin *=trans; + Boost beta_cm = pin.findBoostToCM(); + bool gottaBoost(false); + if(beta_cm.mag() > 1e-12) { + gottaBoost = true; + trans.boost(beta_cm); + pin.boost(beta_cm); + } + for(unsigned int ix=0;ixbranchingParticle()->momentum(); + pvect.transform(trans); + pvect /= lambda; + pvect.setMass(mon[ix]); + pvect.rescaleEnergy(); + if(gottaBoost) pvect.boost(-beta_cm); + pvect.transform(fromRest); + jets[ix]->pVector(pvect); + jets[ix]->showerMomentum(pvect); + } + // find the colour partners + ShowerParticleVector particles; + vector ptemp; + set::const_iterator cjt; + for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { + ptemp.push_back((**cjt).branchingParticle()->momentum()); + (**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum()); + particles.push_back((**cjt).branchingParticle()); + } + dynamic_ptr_cast(ShowerHandler::currentHandler())->partnerFinder() + ->setInitialEvolutionScales(particles,false,type,false); + // calculate the reference vectors + unsigned int iloc(0); + set::iterator clt; + for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { + // reset the momentum + (**cjt).branchingParticle()->set5Momentum(ptemp[iloc]); + ++iloc; + } + for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { + // sort out the partners + tShowerParticlePtr partner = + (*cjt)->branchingParticle()->partner(); + if(!partner) continue; + for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { + if((**clt).branchingParticle()==partner) { + (**cjt).colourPartner(*clt); + break; + } + } + tHardBranchingPtr branch; + for(clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { + if(clt==cjt) continue; + if((*clt)->branchingParticle()==partner) { + branch=*clt; + break; + } + } + // compute the reference vectors + // both incoming, should all ready be done + if((**cjt).status()==HardBranching::Incoming && + (**clt).status()==HardBranching::Incoming) { + continue; + } + // both outgoing + else if((**cjt).status()!=HardBranching::Incoming&& + branch->status()==HardBranching::Outgoing) { + Boost boost=((*cjt)->pVector()+branch->pVector()).findBoostToCM(); + Lorentz5Momentum pcm = branch->pVector(); + pcm.boost(boost); + Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect()); + nvect.boost( -boost); + (**cjt).nVector(nvect); + } + else if((**cjt).status()==HardBranching::Incoming) { + Lorentz5Momentum pa = -(**cjt).showerMomentum()+branch->showerMomentum(); + Lorentz5Momentum pb = (**cjt).showerMomentum(); + Axis axis(pa.vect().unit()); + LorentzRotation rot; + double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); + rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); + rot.rotateX(Constants::pi); + rot.boostZ( pa.e()/pa.vect().mag()); + pb*=rot; + Boost trans = -1./pb.e()*pb.vect(); + trans.setZ(0.); + rot.boost(trans); + Energy scale=(**cjt).beam()->momentum().e(); + Lorentz5Momentum pbasis(ZERO,(**cjt).beam()->momentum().vect().unit()*scale); + Lorentz5Momentum pcm = rot*pbasis; + rot.invert(); + (**cjt).nVector(rot*Lorentz5Momentum(ZERO,-pcm.vect())); + tHardBranchingPtr branch2 = *cjt;; + while (branch2->parent()) { + branch2=branch2->parent(); + branch2->nVector(rot*Lorentz5Momentum(ZERO,-pcm.vect())); + } + } + else if(branch->status()==HardBranching::Incoming) { + (**cjt).nVector(Lorentz5Momentum(ZERO,branch->showerMomentum().vect())); + } + } + // now compute the new momenta + for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { + if(!(*cjt)->branchingParticle()->isFinalState()) continue; + Lorentz5Momentum qnew; + if((*cjt)->branchingParticle()->partner()) { + Energy2 dot=(*cjt)->pVector()*(*cjt)->nVector(); + double beta = 0.5*((*cjt)->branchingParticle()->momentum().m2() + -sqr((*cjt)->pVector().mass()))/dot; + qnew=(*cjt)->pVector()+beta*(*cjt)->nVector(); + qnew.rescaleMass(); + } + else { + qnew = (*cjt)->pVector(); + } + // qnew is the unshuffled momentum in the rest frame of the p basis vectors, + // for the simple case Z->q qbar g this was checked against analytic formulae. + // compute the boost + LorentzRotation R=solveBoost(qnew, + toRest*(*cjt)->branchingParticle()->momentum())*toRest; + (*cjt)->setMomenta(R,1.0,Lorentz5Momentum()); + } +} + +Energy KinematicsReconstructor::momConsEq(double k, + const Energy & root_s, + const JetKinVect & jets) const { + static const Energy2 eps=1e-8*GeV2; + Energy dum = ZERO; + for(JetKinVect::const_iterator it = jets.begin(); it != jets.end(); ++it) { + Energy2 dum2 = (it->q).m2() + sqr(k)*(it->p).vect().mag2(); + if(dum2 < ZERO) { + if(dum2 < -eps) throw KinematicsReconstructionVeto(); + dum2 = ZERO; + } + dum += sqrt(dum2); + } + return dum - root_s; +} + +void KinematicsReconstructor::boostChain(tPPtr p, const LorentzRotation &bv, + tPPtr & parent) const { + if(!p->parents().empty()) boostChain(p->parents()[0], bv,parent); + else parent=p; + p->transform(bv); + if(p->children().size()==2) { + if(dynamic_ptr_cast(p->children()[1])) + deepTransform(p->children()[1],bv); + } +} + +namespace { + +bool sortJets(ShowerProgenitorPtr j1, ShowerProgenitorPtr j2) { + return j1->highestpT()>j2->highestpT(); +} + +} + +void KinematicsReconstructor:: +reconstructGeneralSystem(vector & ShowerHardJets) const { + // find initial- and final-state systems + ColourSingletSystem in,out; + for(unsigned int ix=0;ixprogenitor()->isFinalState()) + out.jets.push_back(ShowerHardJets[ix]); + else + in.jets.push_back(ShowerHardJets[ix]); + } + // reconstruct initial-initial system + LorentzRotation toRest,fromRest; + bool applyBoost(false); + // reconstruct initial-initial system + reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets); + // reconstruct the final-state systems + reconstructFinalStateSystem(applyBoost,toRest,fromRest,out.jets); +} + + +void KinematicsReconstructor:: +reconstructFinalFirst(vector & ShowerHardJets) const { + static const Energy2 minQ2 = 1e-4*GeV2; + map used; + for(unsigned int ix=0;ix outgoing; + // first find any particles with final state partners + for(unsigned int ix=0;ixprogenitor()->isFinalState()&& + ShowerHardJets[ix]->progenitor()->partner()&& + ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) outgoing.insert(ShowerHardJets[ix]); + } + // then find the colour partners + if(!outgoing.empty()) { + set partners; + for(set::const_iterator it=outgoing.begin();it!=outgoing.end();++it) { + for(unsigned int ix=0;ixpartner()==ShowerHardJets[ix]->progenitor()) { + partners.insert(ShowerHardJets[ix]); + break; + } + } + } + outgoing.insert(partners.begin(),partners.end()); + } + // do the final-state reconstruction if needed + if(!outgoing.empty()) { + assert(outgoing.size()!=1); + LorentzRotation toRest,fromRest; + vector outgoingJets(outgoing.begin(),outgoing.end()); + reconstructFinalStateSystem(false,toRest,fromRest,outgoingJets); + } + // Now do any initial-final systems which are needed + vector IFSystems; + // find the systems N.B. can have duplicates + // find initial-state with FS partners or FS with IS partners + for(unsigned int ix=0;ixprogenitor()->isFinalState()&& + ShowerHardJets[ix]->progenitor()->partner()&& + ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) { + IFSystems.push_back(ColourSingletSystem(IF,ShowerHardJets[ix])); + } + else if(ShowerHardJets[ix]->progenitor()->isFinalState()&& + ShowerHardJets[ix]->progenitor()->partner()&& + !ShowerHardJets[ix]->progenitor()->partner()->isFinalState()) { + IFSystems.push_back(ColourSingletSystem(IF,ShowerHardJets[ix])); + } + } + // then add the partners + for(unsigned int is=0;isprogenitor()->partner()==ShowerHardJets[ix]->progenitor()) { + IFSystems[is].jets.push_back(ShowerHardJets[ix]); + } + } + // ensure incoming first + if(IFSystems[is].jets[0]->progenitor()->isFinalState()) + swap(IFSystems[is].jets[0],IFSystems[is].jets[1]); + } + if(!IFSystems.empty()) { + unsigned int istart = UseRandom::irnd(IFSystems.size()); + unsigned int istop=IFSystems.size(); + for(unsigned int is=istart;is<=istop;++is) { + if(is==IFSystems.size()) { + if(istart!=0) { + istop = istart-1; + is=0; + } + else break; + } + // skip duplicates + if(used[IFSystems[is].jets[0]] && + used[IFSystems[is].jets[1]] ) continue; + if(IFSystems[is].jets[0]->original()&&IFSystems[is].jets[0]->original()->parents().empty()) continue; + Lorentz5Momentum psum; + for(unsigned int ix=0;ixprogenitor()->isFinalState()) + psum += IFSystems[is].jets[ix]->progenitor()->momentum(); + else + psum -= IFSystems[is].jets[ix]->progenitor()->momentum(); + } + if(-psum.m2()>minQ2) { + reconstructInitialFinalSystem(IFSystems[is].jets); + for(unsigned int ix=0;ixprogenitor()->isFinalState()) + out.jets.push_back(ShowerHardJets[ix]); + else + in.jets.push_back(ShowerHardJets[ix]); + } + // reconstruct initial-initial system + bool doRecon = false; + for(unsigned int ix=0;ix & ShowerHardJets) const { + static const Energy2 minQ2 = 1e-4*GeV2; + // sort the vector by hardness of emission + std::sort(ShowerHardJets.begin(),ShowerHardJets.end(),sortJets); + // map between particles and progenitors for easy lookup + map progenitorMap; + for(unsigned int ix=0;ixprogenitor()] = ShowerHardJets[ix]; + } + // check that the IF systems can be reconstructed + bool canReconstruct = true; + for(unsigned int ix=0;ixprogenitor(); + tShowerParticlePtr partner = progenitor->partner(); + if(!partner) continue; + else if((progenitor->isFinalState() && + !partner->isFinalState()) || + (!progenitor->isFinalState() && + partner->isFinalState()) ) { + vector jets(2); + jets[0] = ShowerHardJets[ix]; + jets[1] = progenitorMap[partner]; + Lorentz5Momentum psum; + for(unsigned int iy=0;iyprogenitor()->isFinalState()) + psum += jets[iy]->progenitor()->momentum(); + else + psum -= jets[iy]->progenitor()->momentum(); + } + if(-psum.m2() used; + for(unsigned int ix=0;ixreconstructed()==ShowerProgenitor::done) continue; + // already reconstructed + if(used[ShowerHardJets[ix]]) continue; + // no partner continue + tShowerParticlePtr progenitor = ShowerHardJets[ix]->progenitor(); + tShowerParticlePtr partner = progenitor->partner(); + if(!partner) { + // check if there's a daughter tree which also needs boosting + Lorentz5Momentum porig = progenitor->momentum(); + map >::const_iterator tit; + for(tit = _currentTree->treelinks().begin(); + tit != _currentTree->treelinks().end();++tit) { + // if there is, boost it + if(tit->second.first && tit->second.second==progenitor) { + Lorentz5Momentum pnew = tit->first->incomingLines().begin() + ->first->progenitor()->momentum(); + pnew *= tit->first->transform(); + Lorentz5Momentum pdiff = porig-pnew; + Energy2 test = sqr(pdiff.x()) + sqr(pdiff.y()) + + sqr(pdiff.z()) + sqr(pdiff.t()); + LorentzRotation rot; + if(test>1e-6*GeV2) rot = solveBoost(porig,pnew); + tit->first->transform(rot,false); + _treeBoosts[tit->first].push_back(rot); + } + } + ShowerHardJets[ix]->reconstructed(ShowerProgenitor::done); + continue; + } + // do the reconstruction + // final-final + if(progenitor->isFinalState() && + partner->isFinalState() ) { + LorentzRotation toRest,fromRest; + vector jets(2); + jets[0] = ShowerHardJets[ix]; + jets[1] = progenitorMap[partner]; + if(_reconopt==4 && jets[1]->reconstructed()==ShowerProgenitor::notReconstructed) + jets[1]->reconstructed(ShowerProgenitor::dontReconstruct); + reconstructFinalStateSystem(false,toRest,fromRest,jets); + if(_reconopt==4 && jets[1]->reconstructed()==ShowerProgenitor::dontReconstruct) + jets[1]->reconstructed(ShowerProgenitor::notReconstructed); + used[jets[0]] = true; + if(_reconopt==3) used[jets[1]] = true; + } + // initial-final + else if((progenitor->isFinalState() && + !partner->isFinalState()) || + (!progenitor->isFinalState() && + partner->isFinalState()) ) { + vector jets(2); + jets[0] = ShowerHardJets[ix]; + jets[1] = progenitorMap[partner]; + if(jets[0]->progenitor()->isFinalState()) swap(jets[0],jets[1]); + if(jets[0]->original()&&jets[0]->original()->parents().empty()) continue; + Lorentz5Momentum psum; + for(unsigned int iy=0;iyprogenitor()->isFinalState()) + psum += jets[iy]->progenitor()->momentum(); + else + psum -= jets[iy]->progenitor()->momentum(); + } + if(_reconopt==4 && progenitorMap[partner]->reconstructed()==ShowerProgenitor::notReconstructed) + progenitorMap[partner]->reconstructed(ShowerProgenitor::dontReconstruct); + reconstructInitialFinalSystem(jets); + if(_reconopt==4 && progenitorMap[partner]->reconstructed()==ShowerProgenitor::dontReconstruct) + progenitorMap[partner]->reconstructed(ShowerProgenitor::notReconstructed); + used[ShowerHardJets[ix]] = true; + if(_reconopt==3) used[progenitorMap[partner]] = true; + } + // initial-initial + else if(!progenitor->isFinalState() && + !partner->isFinalState() ) { + ColourSingletSystem in,out; + in.jets.push_back(ShowerHardJets[ix]); + in.jets.push_back(progenitorMap[partner]); + for(unsigned int iy=0;iyprogenitor()->isFinalState()) + out.jets.push_back(ShowerHardJets[iy]); + } + LorentzRotation toRest,fromRest; + bool applyBoost(false); + if(_reconopt==4 && in.jets[1]->reconstructed()==ShowerProgenitor::notReconstructed) + in.jets[1]->reconstructed(ShowerProgenitor::dontReconstruct); + reconstructInitialInitialSystem(applyBoost,toRest,fromRest,in.jets); + if(_reconopt==4 && in.jets[1]->reconstructed()==ShowerProgenitor::dontReconstruct) + in.jets[1]->reconstructed(ShowerProgenitor::notReconstructed); + used[in.jets[0]] = true; + if(_reconopt==3) used[in.jets[1]] = true; + for(unsigned int iy=0;iyreconstructed()==ShowerProgenitor::notReconstructed) + out.jets[iy]->reconstructed(ShowerProgenitor::dontReconstruct); + } + // reconstruct the final-state systems + LorentzRotation finalBoosts; + finalBoosts.transform( toRest); + finalBoosts.transform(fromRest); + for(unsigned int iy=0;iyprogenitor(),finalBoosts); + } + for(unsigned int iy=0;iyreconstructed()==ShowerProgenitor::dontReconstruct) + out.jets[iy]->reconstructed(ShowerProgenitor::notReconstructed); + } + } + } +} + +bool KinematicsReconstructor:: +inverseDecayRescalingFactor(vector pout, + vector mon,Energy roots, + Lorentz5Momentum ppartner, Energy mbar, + double & k1, double & k2) const { + ThreeVector qtotal; + vector pmag; + for(unsigned int ix=0;ix1e10) return false; + } + while (abs(numer)>eps&&itry<100); + k1 = abs(k1); + k2 = a*k1; + return itry<100; +} + +void KinematicsReconstructor:: +deconstructInitialFinalSystem(HardTreePtr tree,vector jets, + ShowerInteraction type) const { + HardBranchingPtr incoming; + Lorentz5Momentum pin[2],pout[2],pbeam; + HardBranchingPtr initial; + Energy mc(ZERO); + for(unsigned int ix=0;ixstatus()==HardBranching::Outgoing) { + pout[0] += jets[ix]->branchingParticle()->momentum(); + mc = jets[ix]->branchingParticle()->thePEGBase() ? + jets[ix]->branchingParticle()->thePEGBase()->mass() : + jets[ix]->branchingParticle()->dataPtr()->mass(); + } + // initial-state parton + else { + pin[0] += jets[ix]->branchingParticle()->momentum(); + initial = jets[ix]; + pbeam = jets[ix]->beam()->momentum(); + Energy scale=pbeam.t(); + pbeam = Lorentz5Momentum(ZERO,pbeam.vect().unit()*scale); + incoming = jets[ix]; + while(incoming->parent()) incoming = incoming->parent(); + } + } + if(jets.size()>2) { + pout[0].rescaleMass(); + mc = pout[0].mass(); + } + // work out the boost to the Breit frame + Lorentz5Momentum pa = pout[0]-pin[0]; + Axis axis(pa.vect().unit()); + LorentzRotation rot; + double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); + if(axis.perp2()>0.) { + rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); + rot.rotateX(Constants::pi); + rot.boostZ( pa.e()/pa.vect().mag()); + } + // transverse part + Lorentz5Momentum paxis=rot*pbeam; + Boost trans = -1./paxis.e()*paxis.vect(); + trans.setZ(0.); + rot.boost(trans); + pa *= rot; + // reference vectors + Lorentz5Momentum n1(ZERO,ZERO,-pa.z(),-pa.z()); + Lorentz5Momentum n2(ZERO,ZERO, pa.z(),-pa.z()); + Energy2 n1n2 = n1*n2; + // decompose the momenta + Lorentz5Momentum qbp=rot*pin[0],qcp= rot*pout[0]; + double a[2],b[2]; + a[0] = n2*qbp/n1n2; + b[0] = n1*qbp/n1n2; + a[1] = n2*qcp/n1n2; + b[1] = n1*qcp/n1n2; + Lorentz5Momentum qperp = qbp-a[0]*n1-b[0]*n2; + // before reshuffling + Energy Q = abs(pa.z()); + double c = sqr(mc/Q); + Lorentz5Momentum pb(ZERO,ZERO,0.5*Q*(1.+c),0.5*Q*(1.+c)); + Lorentz5Momentum pc(ZERO,ZERO,0.5*Q*(c-1.),0.5*Q*(1.+c)); + double anew[2],bnew[2]; + anew[0] = pb*n2/n1n2; + bnew[0] = 0.5*(qbp.m2()-qperp.m2())/n1n2/anew[0]; + bnew[1] = pc*n1/n1n2; + anew[1] = 0.5*qcp.m2()/bnew[1]/n1n2; + Lorentz5Momentum qnewb = (anew[0]*n1+bnew[0]*n2+qperp); + Lorentz5Momentum qnewc = (anew[1]*n1+bnew[1]*n2); + // initial-state boost + LorentzRotation rotinv=rot.inverse(); + LorentzRotation transb=rotinv*solveBoostZ(qnewb,qbp)*rot; + // final-state boost + LorentzRotation transc=rotinv*solveBoost(qnewc,qcp)*rot; + // this will need changing for more than one outgoing particle + // set the pvectors + for(unsigned int ix=0;ixstatus()==HardBranching::Incoming) { + jets[ix]->pVector(pbeam); + jets[ix]->showerMomentum(rotinv*pb); + incoming->pVector(jets[ix]->pVector()); + } + else { + jets[ix]->pVector(rotinv*pc); + jets[ix]->showerMomentum(jets[ix]->pVector()); + } + } + // find the colour partners + ShowerParticleVector particles; + vector ptemp; + set::const_iterator cjt; + for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { + ptemp.push_back((**cjt).branchingParticle()->momentum()); + (**cjt).branchingParticle()->set5Momentum((**cjt).showerMomentum()); + particles.push_back((**cjt).branchingParticle()); + } + dynamic_ptr_cast(ShowerHandler::currentHandler())->partnerFinder() + ->setInitialEvolutionScales(particles,false,type,false); + unsigned int iloc(0); + for(cjt=tree->branchings().begin();cjt!=tree->branchings().end();++cjt) { + // reset the momentum + (**cjt).branchingParticle()->set5Momentum(ptemp[iloc]); + ++iloc; + } + for(vector::const_iterator cjt=jets.begin(); + cjt!=jets.end();++cjt) { + // sort out the partners + tShowerParticlePtr partner = + (*cjt)->branchingParticle()->partner(); + if(!partner) continue; + tHardBranchingPtr branch; + for(set::const_iterator + clt=tree->branchings().begin();clt!=tree->branchings().end();++clt) { + if((**clt).branchingParticle()==partner) { + (**cjt).colourPartner(*clt); + branch=*clt; + break; + } + } + // compute the reference vectors + // both incoming, should all ready be done + if((**cjt).status()==HardBranching::Incoming && + branch->status()==HardBranching::Incoming) { + Energy etemp = (*cjt)->beam()->momentum().z(); + Lorentz5Momentum nvect(ZERO, ZERO,-etemp, abs(etemp)); + tHardBranchingPtr branch2 = *cjt; + (**cjt).nVector(nvect); + while (branch2->parent()) { + branch2=branch2->parent(); + branch2->nVector(nvect); + } + } + // both outgoing + else if((**cjt).status()==HardBranching::Outgoing&& + branch->status()==HardBranching::Outgoing) { + Boost boost=((*cjt)->pVector()+branch->pVector()).findBoostToCM(); + Lorentz5Momentum pcm = branch->pVector(); + pcm.boost(boost); + Lorentz5Momentum nvect = Lorentz5Momentum(ZERO,pcm.vect()); + nvect.boost( -boost); + (**cjt).nVector(nvect); + } + else if((**cjt).status()==HardBranching::Incoming) { + Lorentz5Momentum pa = -(**cjt).showerMomentum()+branch->showerMomentum(); + Lorentz5Momentum pb = (**cjt).showerMomentum(); + Axis axis(pa.vect().unit()); + LorentzRotation rot; + double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); + if(axis.perp2()>1e-20) { + rot.setRotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); + rot.rotateX(Constants::pi); + } + if(abs(1.-pa.e()/pa.vect().mag())>1e-6) rot.boostZ( pa.e()/pa.vect().mag()); + pb*=rot; + Boost trans = -1./pb.e()*pb.vect(); + trans.setZ(0.); + rot.boost(trans); + Energy scale=(**cjt).beam()->momentum().t(); + Lorentz5Momentum pbasis(ZERO,(**cjt).beam()->momentum().vect().unit()*scale); + Lorentz5Momentum pcm = rot*pbasis; + rot.invert(); + Lorentz5Momentum nvect = rot*Lorentz5Momentum(ZERO,-pcm.vect()); + (**cjt).nVector(nvect); + tHardBranchingPtr branch2 = *cjt; + while (branch2->parent()) { + branch2=branch2->parent(); + branch2->nVector(nvect); + } + } + else if(branch->status()==HardBranching::Incoming) { + Lorentz5Momentum nvect=Lorentz5Momentum(ZERO,branch->showerMomentum().vect()); + (**cjt).nVector(nvect); + } + } + // now compute the new momenta + for(vector::const_iterator cjt=jets.begin(); + cjt!=jets.end();++cjt) { + if((**cjt).status()==HardBranching::Outgoing) { + (**cjt).setMomenta(transc,1.,Lorentz5Momentum()); + } + } + incoming->setMomenta(transb,1.,Lorentz5Momentum()); +} + +void KinematicsReconstructor::deepTransform(PPtr particle, + const LorentzRotation & r, + bool match, + PPtr original) const { + if(_boosts.find(particle)!=_boosts.end()) { + _boosts[particle].push_back(r); + } + Lorentz5Momentum porig = particle->momentum(); + if(!original) original = particle; + for ( int i = 0, N = particle->children().size(); i < N; ++i ) { + deepTransform(particle->children()[i],r, + particle->children()[i]->id()==original->id()&&match,original); + } + particle->transform(r); + // transform the p and n vectors + ShowerParticlePtr sparticle = dynamic_ptr_cast(particle); + if(sparticle && sparticle->showerBasis()) { + sparticle->showerBasis()->transform(r); + } + if ( particle->next() ) deepTransform(particle->next(),r,match,original); + if(!match) return; + if(!particle->children().empty()) return; + // force the mass shell + if(particle->dataPtr()->stable()) { + Lorentz5Momentum ptemp = particle->momentum(); + ptemp.rescaleEnergy(); + particle->set5Momentum(ptemp); + } + // check if there's a daughter tree which also needs boosting + map >::const_iterator tit; + for(tit = _currentTree->treelinks().begin(); + tit != _currentTree->treelinks().end();++tit) { + // if there is, boost it + if(tit->second.first && tit->second.second==original) { + Lorentz5Momentum pnew = tit->first->incomingLines().begin() + ->first->progenitor()->momentum(); + pnew *= tit->first->transform(); + Lorentz5Momentum pdiff = porig-pnew; + Energy2 test = sqr(pdiff.x()) + sqr(pdiff.y()) + + sqr(pdiff.z()) + sqr(pdiff.t()); + LorentzRotation rot; + if(test>1e-6*GeV2) rot = solveBoost(porig,pnew); + tit->first->transform(r*rot,false); + _treeBoosts[tit->first].push_back(r*rot); + } + } +} + +void KinematicsReconstructor::reconstructFinalFinalOffShell(JetKinVect orderedJets, + Energy2 s, + bool recursive) const { + JetKinVect::iterator jit; + jit = orderedJets.begin(); ++jit; + // 4-momentum of recoiling system + Lorentz5Momentum psum; + for( ; jit!=orderedJets.end(); ++jit) psum += jit->p; + psum.rescaleMass(); + // calculate the 3-momentum rescaling factor + Energy2 m1sq(orderedJets.begin()->q.m2()),m2sq(psum.m2()); + Energy4 num = sqr(s - m1sq - m2sq) - 4.*m1sq*m2sq; + if(nump.vect().mag2()) ); + // boost the most off-shell + LorentzRotation B1 = solveBoost(k, orderedJets.begin()->q, orderedJets.begin()->p); + deepTransform(orderedJets.begin()->parent,B1); + // boost everything else + // first to rescale + LorentzRotation B2 = solveBoost(k, psum, psum); + // and then to rest frame of new system + Lorentz5Momentum pnew = B2*psum; + pnew.rescaleMass(); + B2.transform(pnew.findBoostToCM()); + // apply transform (calling routine ensures at least 3 elements) + jit = orderedJets.begin(); ++jit; + for(;jit!=orderedJets.end();++jit) { + deepTransform(jit->parent,B2); + jit->p *= B2; + jit->q *= B2; + } + JetKinVect newJets(orderedJets.begin()+1,orderedJets.end()); + // final reconstruction + if(newJets.size()==2 || !recursive ) { + // rescaling factor + double k = solveKfactor(psum.m(), newJets); + // rescale jets in the new CMF + for(JetKinVect::iterator it = newJets.begin(); it != newJets.end(); ++it) { + LorentzRotation Trafo = solveBoost(k, it->q, it->p); + deepTransform(it->parent,Trafo); + } + } + // recursive + else { + std::sort(newJets.begin(),newJets.end(),JetOrdering()); + reconstructFinalFinalOffShell(newJets,psum.m2(),recursive); + } + // finally boost back from new CMF + LorentzRotation back(-pnew.findBoostToCM()); + for(JetKinVect::iterator it = newJets.begin(); it != newJets.end(); ++it) { + deepTransform(it->parent,back); + } +} + +Energy KinematicsReconstructor::findMass(HardBranchingPtr branch) const { + // KH - 230909 - If the particle has no children then it will + // not have showered and so it should be "on-shell" so we can + // get it's mass from it's momentum. This means that the + // inverseRescalingFactor doesn't give any nans or do things + // it shouldn't if it gets e.g. two Z bosons generated with + // off-shell masses. This is for sure not the best solution. + // PR 1/1/10 modification to previous soln + // PR 28/8/14 change to procedure and factorize into a function + if(branch->children().empty()) { + return branch->branchingParticle()->mass(); + } + else if(!branch->children().empty() && + !branch->branchingParticle()->dataPtr()->stable() ) { + for(unsigned int ix=0;ixchildren().size();++ix) { + if(branch->branchingParticle()->id()== + branch->children()[ix]->branchingParticle()->id()) + return findMass(branch->children()[ix]); + } + } + return branch->branchingParticle()->dataPtr()->mass(); +} + +vector +KinematicsReconstructor::inverseInitialStateRescaling(double & x1, double & x2, + const Lorentz5Momentum & pold, + const vector & p, + const vector & pq) const { + // hadronic CMS + Energy2 s = (pq[0] +pq[1] ).m2(); + // partonic CMS + Energy MDY = pold.m(); + // find alpha, beta and pt + Energy2 p12=pq[0]*pq[1]; + double a[2],b[2]; + Lorentz5Momentum pt[2]; + for(unsigned int ix=0;ix<2;++ix) { + a[ix] = p[ix]*pq[1]/p12; + b [ix] = p[ix]*pq[0]/p12; + pt[ix] = p[ix]-a[ix]*pq[0]-b[ix]*pq[1]; + } + // compute kappa + // we always want to preserve the mass of the system + double k1(1.),k2(1.); + if(_initialStateReconOption==0) { + double rap=pold.rapidity(); + x2 = MDY/sqrt(s*exp(2.*rap)); + x1 = sqr(MDY)/s/x2; + k1=a[0]/x1; + k2=b[1]/x2; + } + // longitudinal momentum + else if(_initialStateReconOption==1) { + double A = 1.; + double C = -sqr(MDY)/s; + double B = 2.*pold.z()/sqrt(s); + if(abs(B)>1e-10) { + double discrim = 1.-4.*A*C/sqr(B); + if(discrim < 0.) throw KinematicsReconstructionVeto(); + x1 = B>0. ? 0.5*B/A*(1.+sqrt(discrim)) : 0.5*B/A*(1.-sqrt(discrim)); + } + else { + x1 = -C/A; + if( x1 <= 0.) throw KinematicsReconstructionVeto(); + x1 = sqrt(x1); + } + x2 = sqr(MDY)/s/x1; + k1=a[0]/x1; + k2=b[1]/x2; + } + // preserve mass and don't scale the softer system + // to reproduce the dipole kinematics + else if(_initialStateReconOption==2) { + // in this case kp = k1 or k2 depending on who's the harder guy + k1 = a[0]*b[1]*s/sqr(MDY); + if ( pt[0].perp2() < pt[1].perp2() ) swap(k1,k2); + x1 = a[0]/k1; + x2 = b[1]/k2; + } + else + assert(false); + // decompose the momenta + double anew[2] = {a[0]/k1,a[1]*k2}; + double bnew[2] = {b[0]*k1,b[1]/k2}; + vector boost(2); + for(unsigned int ix=0;ix<2;++ix) { + boost[ix] = getBeta(a [ix]+b [ix], a[ix] -b [ix], + anew[ix]+bnew[ix], anew[ix]-bnew[ix]); + } + return boost; +} + +vector +KinematicsReconstructor::initialStateRescaling(double x1, double x2, + const Lorentz5Momentum & pold, + const vector & p, + const vector & pq, + const vector& highestpts) const { + Energy2 S = (pq[0]+pq[1]).m2(); + // find alphas and betas in terms of desired basis + Energy2 p12 = pq[0]*pq[1]; + double a[2] = {p[0]*pq[1]/p12,p[1]*pq[1]/p12}; + double b[2] = {p[0]*pq[0]/p12,p[1]*pq[0]/p12}; + Lorentz5Momentum p1p = p[0] - a[0]*pq[0] - b[0]*pq[1]; + Lorentz5Momentum p2p = p[1] - a[1]*pq[0] - b[1]*pq[1]; + // compute kappa + // we always want to preserve the mass of the system + Energy MDY = pold.m(); + Energy2 A = a[0]*b[1]*S; + Energy2 B = Energy2(sqr(MDY)) - (a[0]*b[0]+a[1]*b[1])*S - (p1p+p2p).m2(); + Energy2 C = a[1]*b[0]*S; + double rad = 1.-4.*A*C/sqr(B); + if(rad < 0.) throw KinematicsReconstructionVeto(); + double kp = B/(2.*A)*(1.+sqrt(rad)); + // now compute k1 + // conserve rapidity + double k1(0.); + double k2(0.); + if(_initialStateReconOption==0) { + rad = kp*(b[0]+kp*b[1])/(kp*a[0]+a[1]); + rad *= pq[0].z()1e-10) { + double discrim = 1.-4.*a2*c2/sqr(b2); + if(discrim < 0.) throw KinematicsReconstructionVeto(); + k1 = b2>0. ? 0.5*b2/a2*(1.+sqrt(discrim)) : 0.5*b2/a2*(1.-sqrt(discrim)); + } + else { + k1 = -c2/a2; + if( k1 <= 0.) throw KinematicsReconstructionVeto(); + k1 = sqrt(k1); + } + k2 = kp/k1; + } + // preserve mass and don't scale the softer system + // to reproduce the dipole kinematics + else if(_initialStateReconOption==2) { + // in this case kp = k1 or k2 depending on who's the harder guy + k1 = kp; k2 = 1.; + if ( highestpts[0] < highestpts[1] ) + swap(k1,k2); + } + else + assert(false); + // calculate the boosts + vector beta(2); + beta[0] = getBeta((a[0]+b[0]), (a[0]-b[0]), (k1*a[0]+b[0]/k1), (k1*a[0]-b[0]/k1)); + beta[1] = getBeta((a[1]+b[1]), (a[1]-b[1]), (a[1]/k2+k2*b[1]), (a[1]/k2-k2*b[1])); + if (pq[0].z() > ZERO) { + beta[0] = -beta[0]; + beta[1] = -beta[1]; + } + return beta; +} + +void KinematicsReconstructor:: +reconstructColourSinglets(vector & ShowerHardJets, + ShowerInteraction type) const { + // identify and catagorize the colour singlet systems + unsigned int nnun(0),nnii(0),nnif(0),nnf(0),nni(0); + vector + systems(identifySystems(set(ShowerHardJets.begin(),ShowerHardJets.end()), + nnun,nnii,nnif,nnf,nni)); + // now decide what to do + // initial-initial connection and final-state colour singlet systems + LorentzRotation toRest,fromRest; + bool applyBoost(false),general(false); + // Drell-Yan type + if(nnun==0&&nnii==1&&nnif==0&&nnf>0&&nni==0) { + // reconstruct initial-initial system + for(unsigned int ix=0;ix0&&nni==1)|| + (nnif==2&& nni==0))) { + // check these systems can be reconstructed + for(unsigned int ix=0;ixprogenitor()->isFinalState()) + q += systems[ix].jets[iy]->progenitor()->momentum(); + else + q -= systems[ix].jets[iy]->progenitor()->momentum(); + } + q.rescaleMass(); + // check above cut + if(abs(q.m())>=_minQ) continue; + if(nnif==1&&nni==1) { + throw KinematicsReconstructionVeto(); + } + else { + general = true; + break; + } + } + if(!general) { + for(unsigned int ix=0;ix0&&nni==2) { + general = type!=ShowerInteraction::QCD; + } + // general type + else { + general = true; + } + // final-state systems except for general recon + if(!general) { + for(unsigned int ix=0;ix + +namespace Herwig { + +using namespace ThePEG; + + /**\ingroup Shower + * Exception class + * used to communicate failure of kinematics + * reconstruction. + */ + struct KinematicsReconstructionVeto {}; + + +/** \ingroup Shower + * A simple struct to store the information we need on the + * showering + */ +struct JetKinStruct { + + /** + * Parent particle of the jet + */ + tShowerParticlePtr parent; + + /** + * Momentum of the particle before reconstruction + */ + Lorentz5Momentum p; + + /** + * Momentum of the particle after reconstruction + */ + Lorentz5Momentum q; +}; + +/** + * typedef for a vector of JetKinStruct + */ +typedef vector JetKinVect; + +/** + * Enum to identify types of colour singlet systems + */ +enum SystemType { UNDEFINED=-1, II, IF, F ,I }; + +/** + * Struct to store colour singlets + */ +template struct ColourSinglet { + + typedef vector > VecType; + + ColourSinglet() : type(UNDEFINED) {} + + ColourSinglet(SystemType intype,Value inpart) + : type(intype),jets(1,inpart) {} + + /** + * The type of system + */ + SystemType type; + + /** + * The jets in the system + */ + vector jets; + +}; + +/** + * Struct to store a colour singlet system of particles + */ +typedef ColourSinglet ColourSingletSystem; + +/** + * Struct to store a colour singlet shower + */ +typedef ColourSinglet ColourSingletShower; + +/** \ingroup Shower + * + * This class is responsible for the kinematical reconstruction + * after each showering step, and also for the necessary Lorentz boosts + * in order to preserve energy-momentum conservation in the overall collision, + * and also the invariant mass and the rapidity of the hard subprocess system. + * In the case of multi-step showering, there will be not unnecessary + * kinematical reconstructions. + * + * There is also the option of taking a set of momenta for the particles + * and inverting the reconstruction to give the evolution variables for the + * shower. + * + * Notice: + * - although we often use the term "jet" in either methods or variables names, + * or in comments, which could appear applicable only for QCD showering, + * there is indeed no "dynamics" represented in this class: only kinematics + * is involved, as the name of this class remainds. Therefore it can be used + * for any kind of showers (QCD-,QED-,EWK-,... bremsstrahlung). + * + * @see ShowerParticle + * @see ShowerKinematics + * @see \ref KinematicsReconstructorInterfaces "The interfaces" + * defined for KinematicsReconstructor. + */ +class KinematicsReconstructor: public Interfaced { + +public: + + /** + * Default constructor + */ + KinematicsReconstructor() : _reconopt(0), _initialBoost(0), + _finalStateReconOption(0), + _initialStateReconOption(0), _minQ(MeV) {}; + + /** + * Methods to reconstruct the kinematics of a scattering or decay process + */ + //@{ + /** + * Given in input a vector of the particles which initiated the showers + * the method does the reconstruction of such jets, + * including the appropriate boosts (kinematics reshufflings) + * needed to conserve the total energy-momentum of the collision + * and preserving the invariant mass and the rapidity of the + * hard subprocess system. + */ + virtual bool reconstructHardJets(ShowerTreePtr hard, + const map > & pt, + ShowerInteraction type, + bool switchRecon) const; + + /** + * Given in input a vector of the particles which initiated the showers + * the method does the reconstruction of such jets, + * including the appropriate boosts (kinematics reshufflings) + * needed to conserve the total energy-momentum of the collision + * and preserving the invariant mass and the rapidity of the + * hard subprocess system. + */ + virtual bool reconstructDecayJets(ShowerTreePtr decay, + ShowerInteraction type) const; + //@} + + /** + * Methods to invert the reconstruction of the shower for + * a scattering or decay process and calculate + * the variables used to generate the + * shower given the particles produced. + * This is needed for the CKKW and POWHEG approaches + */ + //@{ + /** + * Given the particles, with a history which we wish to interpret + * as a shower reconstruct the variables used to generate the + * shower + */ + virtual bool deconstructDecayJets(HardTreePtr,ShowerInteraction) const; + + /** + * Given the particles, with a history which we wish to interpret + * as a shower reconstruct the variables used to generate the shower + * for a hard process + */ + virtual bool deconstructHardJets(HardTreePtr,ShowerInteraction) const; + //@} + +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(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(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: + + /** + * Methods to reconstruct the kinematics of individual jets + */ + //@{ + /** + * Given the particle (ShowerParticle object) that + * originates a forward (time-like) jet, this method reconstructs the kinematics + * of the jet. That is, by starting from the final grand-children (which + * originates directly or indirectly from particleJetParent, + * and which don't have children), and moving "backwards" (in a physical + * time picture), towards the particleJetParent, the + * ShowerKinematics objects associated with the various particles, + * which have been created during the showering, are now completed. + * In particular, at the end, we get the mass of the jet, which is the + * main information we want. + * This methods returns false if there was no radiation or rescaling required + */ + virtual bool reconstructTimeLikeJet(const tShowerParticlePtr particleJetParent) const; + + /** + * Exactly similar to the previous one, but for a space-like jet. + * Also in this case we start from the final grand-children (which + * are childless) of the particle which originates the jet, but in + * this case we proceed "forward" (in the physical time picture) + * towards the particleJetParent. + * This methods returns false if there was no radiation or rescaling required + */ + bool reconstructSpaceLikeJet(const tShowerParticlePtr particleJetParent) const; + + /** + * Exactly similar to the previous one, but for a decay jet + * This methods returns false if there was no radiation or rescaling required + */ + bool reconstructDecayJet(const tShowerParticlePtr particleJetParent) const; + //@} + + /** + * Methods to perform the reconstruction of various types of colour + * singlet systems + */ + //@{ + /** + * Perform the reconstruction of a system with one incoming and at least one + * outgoing particle + */ + void reconstructInitialFinalSystem(vector) const; + + /** + * Perform the reconstruction of a system with only final-state + * particles + */ + void reconstructFinalStateSystem(bool applyBoost, + const LorentzRotation & toRest, + const LorentzRotation & fromRest, + vector) const; + + /** + * Reconstruction of a general coloured system + */ + void reconstructGeneralSystem(vector & ShowerHardJets) const; + + /** + * Reconstruction of a general coloured system doing + * final-final, then initial-final and then initial-initial + */ + void reconstructFinalFirst(vector & ShowerHardJets) const; + + /** + * Reconstruction of a general coloured system doing + * colour parners + */ + void reconstructColourPartner(vector & ShowerHardJets) const; + + /** + * Reconstruction based on colour singlet systems + */ + void reconstructColourSinglets(vector & ShowerHardJets, + ShowerInteraction type) const; + + /** + * Perform the reconstruction of a system with only final-state + * particles + */ + void reconstructInitialInitialSystem(bool & applyBoost, + LorentzRotation & toRest, + LorentzRotation & fromRest, + vector) const; + //@} + + /** + * Methods to perform the inverse reconstruction of various types of + * colour singlet systems + */ + //@{ + /** + * Perform the inverse reconstruction of a system with only final-state + * particles + */ + void deconstructFinalStateSystem(const LorentzRotation & toRest, + const LorentzRotation & fromRest, + HardTreePtr, + vector, + ShowerInteraction) const; + + /** + * Perform the inverse reconstruction of a system with only initial-state + * particles + */ + void deconstructInitialInitialSystem(bool & applyBoost, + LorentzRotation & toRest, + LorentzRotation & fromRest, + HardTreePtr, + vector, + ShowerInteraction ) const; + + /** + * Perform the inverse reconstruction of a system with only initial-state + * particles + */ + void deconstructInitialFinalSystem(HardTreePtr, + vector, + ShowerInteraction ) const; + + bool deconstructGeneralSystem(HardTreePtr, + ShowerInteraction) const; + + bool deconstructColourSinglets(HardTreePtr, + ShowerInteraction) const; + + bool deconstructColourPartner(HardTreePtr, + ShowerInteraction) const; + //@} + + /** + * Recursively treat the most off-shell paricle seperately + * for final-final reconstruction + */ + void reconstructFinalFinalOffShell(JetKinVect orderedJets, Energy2 s, + bool recursive) const; + + /** + * Various methods for the Lorentz transforms needed to do the + * rescalings + */ + //@{ + /** + * Compute the boost to get from the the old momentum to the new + */ + LorentzRotation solveBoost(const double k, + const Lorentz5Momentum & newq, + const Lorentz5Momentum & oldp) const; + + /** + * Compute the boost to get from the the old momentum to the new + */ + LorentzRotation solveBoost(const Lorentz5Momentum & newq, + const Lorentz5Momentum & oldq) const; + + /** + * Compute the boost to get from the the old momentum to the new + */ + LorentzRotation solveBoostZ(const Lorentz5Momentum & newq, + const Lorentz5Momentum & oldq) const; + + /** + * Recursively boost the initial-state shower + * @param p The particle + * @param bv The boost + * @param parent The parent of the chain + */ + void boostChain(tPPtr p, const LorentzRotation & bv, tPPtr & parent) const; + + /** + * Given a 5-momentum and a scale factor, the method returns the + * Lorentz boost that transforms the 3-vector vec{momentum} ---> + * k*vec{momentum}. The method returns the null boost in the case no + * solution exists. This will only work in the case where the + * outgoing jet-momenta are parallel to the momenta of the particles + * leaving the hard subprocess. + */ + Boost solveBoostBeta( const double k, const Lorentz5Momentum & newq, + const Lorentz5Momentum & oldp); + + /** + * Compute boost parameter along z axis to get (Ep, any perp, qp) + * from (E, same perp, q). + */ + double getBeta(const double E, const double q, + const double Ep, const double qp) const + {return (q*E-qp*Ep)/(sqr(qp)+sqr(E));} + //@} + + /** + * Methods to calculate the various scaling factors + */ + //@{ + /** + * Given a vector of 5-momenta of jets, where the 3-momenta are the initial + * ones before showering and the masses are reconstructed after the showering, + * this method returns the overall scaling factor for the 3-momenta of the + * vector of particles, vec{P}_i -> k * vec{P}_i, such to preserve energy- + * momentum conservation, i.e. after the rescaling the center of mass 5-momentum + * is equal to the one specified in input, cmMomentum. + * The method returns 0 if such factor cannot be found. + * @param root_s Centre-of-mass energy + * @param jets The jets + */ + double solveKfactor( const Energy & root_s, const JetKinVect & jets ) const; + + /** + * Calculate the rescaling factors for the jets in a particle decay where + * there was initial-state radiation + * @param mb The mass of the decaying particle + * @param n The reference vector for the initial state radiation + * @param pjet The momentum of the initial-state jet + * @param jetKinematics The JetKinStruct objects for the jets + * @param partner The colour partner + * @param ppartner The momentum of the colour partner of the decaying particle + * before and after radiation + * @param k1 The rescaling parameter for the partner + * @param k2 The rescaling parameter for the outgoing singlet + * @param qt The transverse momentum vector + */ + bool solveDecayKFactor(Energy mb, + const Lorentz5Momentum & n, + const Lorentz5Momentum & pjet, + const JetKinVect & jetKinematics, + ShowerParticlePtr partner, + Lorentz5Momentum ppartner[2], + double & k1, + double & k2, + Lorentz5Momentum & qt) const; + + /** + * Compute the momentum rescaling factor needed to invert the shower + * @param pout The momenta of the outgoing particles + * @param mon The on-shell masses + * @param roots The mass of the decaying particle + */ + double inverseRescalingFactor(vector pout, + vector mon,Energy roots) const; + + /** + * Compute the momentum rescaling factor needed to invert the shower + * @param pout The momenta of the outgoing particles + * @param mon The on-shell masses + * @param roots The mass of the decaying particle + * @param ppartner The momentum of the colour partner + * @param mbar The mass of the decaying particle + * @param k1 The first scaling factor + * @param k2 The second scaling factor + */ + bool inverseDecayRescalingFactor(vector pout, + vector mon,Energy roots, + Lorentz5Momentum ppartner, Energy mbar, + double & k1, double & k2) const; + + /** + * Check the rescaling conserves momentum + * @param k The rescaling + * @param root_s The centre-of-mass energy + * @param jets The jets + */ + Energy momConsEq(double k, const Energy & root_s, + const JetKinVect & jets) const; + + + void findInitialBoost(const Lorentz5Momentum & pold, const Lorentz5Momentum & pnew, + LorentzRotation & toRest, LorentzRotation & fromRest) const; + //@} + + /** + * Find the colour partners of a particle to identify the colour singlet + * systems for the reconstruction. + */ + template void findPartners(Value branch,set & done, + const set & branchings, + vector & jets) const; + + /** + * Add the intrinsic \f$p_T\f$ to the system if needed + */ + bool addIntrinsicPt(vector) const; + + /** + * Apply a transform to the particle and any child, including child ShowerTree + * objects + * @param particle The particle + * @param r The Lorentz transformation + * @param match Whether or not to look at children etc + * @param original The original particle + */ + void deepTransform(PPtr particle,const LorentzRotation & r, + bool match=true,PPtr original=PPtr()) const; + + /** + * Find the mass of a particle in the hard branching + */ + Energy findMass(HardBranchingPtr) const; + + /** + * Calculate the initial-state rescaling factors + */ + vector initialStateRescaling(double x1, double x2, + const Lorentz5Momentum & pold, + const vector & p, + const vector & pq, + const vector& highespts) const; + + /** + * Calculate the inverse of the initial-state rescaling factor + */ + vector inverseInitialStateRescaling(double & x1, double & x2, + const Lorentz5Momentum & pold, + const vector & p, + const vector & pq) const; + + /** + * Find the colour singlet systems + */ + template + typename ColourSinglet::VecType identifySystems(set jets, + unsigned int & nnun,unsigned int & nnii, + unsigned int & nnif,unsigned int & nnf, + unsigned int & nni) const; + + /** + * Combine final-state colour systems + */ + template + void combineFinalState(vector > & systems) const; + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const {return new_ptr(*this);} + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const {return new_ptr(*this);} + //@} + +protected: + + /** @name Standard Interfaced functions. */ + //@{ + /** + * Initialize this object after the setup phase before saving an + * EventGenerator to disk. + * @throws InitException if object could not be initialized properly. + */ + virtual void doinit(); + //@} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + KinematicsReconstructor & operator=(const KinematicsReconstructor &) = delete; + +private: + + /** + * Option for handling the reconstruction + */ + unsigned int _reconopt; + + /** + * Option for the boost for initial-initial reconstruction + */ + unsigned int _initialBoost; + + /** + * Option for the reconstruction of final state systems + */ + unsigned int _finalStateReconOption; + + /** + * Option for the initial state reconstruction + */ + unsigned int _initialStateReconOption; + + /** + * Minimum invariant mass for initial-final dipoles to allow the + * reconstruction + */ + Energy _minQ; + + /** + * The progenitor of the jet currently being reconstructed + */ + mutable tShowerParticlePtr _progenitor; + + /** + * Storage of the intrinsic \f$p_T\f$ + */ + mutable map > _intrinsic; + + /** + * Current ShowerTree + */ + mutable tShowerTreePtr _currentTree; + + /** + * Particles which shouldn't have their masses rescaled as + * vector for the interface + */ + PDVector _noRescaleVector; + + /** + * Particles which shouldn't have their masses rescaled as + * set for quick access + */ + set _noRescale; + + /** + * Storage of the boosts applied to enable resetting after failure + */ + mutable map > _boosts; + + /** + * Storage of the boosts applied to enable resetting after failure + */ + mutable map > _treeBoosts; +}; + +} + +#include "KinematicsReconstructor.tcc" +#endif /* HERWIG_KinematicsReconstructor_H */ diff --git a/Shower/QTilde/Kinematics/KinematicsReconstructor.tcc b/Shower/QTilde/Kinematics/KinematicsReconstructor.tcc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/Kinematics/KinematicsReconstructor.tcc @@ -0,0 +1,247 @@ +// -*- C++ -*- +// +// KinematicsReconstructor.tcc is a part of Herwig - A multi-purpose Monte Carlo event generator +// Copyright (C) 2002-2017 The Herwig Collaboration +// +// Herwig 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 KinematicsReconstructor class. +// +using namespace Herwig; +using namespace ThePEG; + +namespace { +/** + * find showering particle for hard branchings + */ +tShowerParticlePtr SHOWERINGPARTICLE(HardBranchingPtr a) { + return a->branchingParticle(); +} + +/** + * find showering particle for progenitors + */ +tShowerParticlePtr SHOWERINGPARTICLE(ShowerProgenitorPtr a) { + return a->progenitor(); +} + + +/** + * Return colour line progenitor pointer for ShowerProgenitor + */ +template +Ptr::transient_pointer +CL(Value a, unsigned int index=0) { + return const_ptr_cast(SHOWERINGPARTICLE(a)->colourInfo()->colourLines()[index]); +} + +/** + * Return progenitor colour line size for ShowerProgenitor + */ +template +unsigned int CLSIZE(Value a) { + return SHOWERINGPARTICLE(a)->colourInfo()->colourLines().size(); +} + +/** + * Return anti-colour line progenitor pointer for ShowerProgenitor + */ +template +Ptr::transient_pointer +ACL(Value a, unsigned int index=0) { + return const_ptr_cast(SHOWERINGPARTICLE(a)->colourInfo()->antiColourLines()[index]); +} + +/** + * Return progenitor anti-colour line size for ShowerProgenitor + */ +template +unsigned int ACLSIZE(Value a) { + return SHOWERINGPARTICLE(a)->colourInfo()->antiColourLines().size(); +} +} + +template void KinematicsReconstructor:: +findPartners(Value jet,set & done, + const set & jets, + vector & system) const { + tShowerParticlePtr part=SHOWERINGPARTICLE(jet); + unsigned int partNumColourLines = part->colourInfo()-> colourLines().size(); + unsigned int partNumAColourLines = part->colourInfo()->antiColourLines().size(); + for(typename set::const_iterator cit=jets.begin();cit!=jets.end();++cit) { + if(done.find(*cit)!=done.end()||!SHOWERINGPARTICLE(*cit)->coloured()) + continue; + bool isPartner = false; + // one initial one final + if(part->isFinalState()!=SHOWERINGPARTICLE(*cit)->isFinalState()) { + //loop over all the colours of both + for(unsigned int ix=0; ixcolourLine()) { + for(unsigned int ix=0; ixantiColourLine()&&!isPartner) { + for(unsigned int ix=0; ixcolourLine()) { + if(part->colourLine()->sourceNeighbours().first) { + tColinePair lines = part->colourLine()->sourceNeighbours(); + if(lines.first == CL(*cit) || lines.first == ACL(*cit) || + lines.second == CL(*cit) || lines.second == ACL(*cit) ) + isPartner = true; + } + if(part->colourLine()->sinkNeighbours().first) { + tColinePair lines = part->colourLine()->sinkNeighbours(); + if(lines.first == CL(*cit) || lines.first == ACL(*cit) || + lines.second == CL(*cit) || lines.second == ACL(*cit) ) + isPartner = true; + } + } + if(part->antiColourLine()) { + if(part->antiColourLine()->sourceNeighbours().first) { + tColinePair lines = part->antiColourLine()->sourceNeighbours(); + if(lines.first == CL(*cit) || lines.first == ACL(*cit) || + lines.second == CL(*cit) || lines.second == ACL(*cit) ) + isPartner = true; + } + if(part->antiColourLine()->sinkNeighbours().first) { + tColinePair lines = part->antiColourLine()->sinkNeighbours(); + if(lines.first == CL(*cit) || lines.first == ACL(*cit) || + lines.second == CL(*cit) || lines.second == ACL(*cit) ) + isPartner = true; + } + } + if(isPartner) { + system.push_back(*cit); + done.insert(*cit); + findPartners(*cit,done,jets,system); + } + } +} + +template +typename Herwig::ColourSinglet::VecType KinematicsReconstructor:: +identifySystems(set jets, + unsigned int & nnun,unsigned int & nnii,unsigned int & nnif, + unsigned int & nnf ,unsigned int & nni ) const { + vector > systems; + set done; + for(typename set::const_iterator it=jets.begin();it!=jets.end();++it) { + // if not treated create new system + if(done.find(*it)!=done.end()) continue; + done.insert(*it); + systems.push_back(ColourSinglet (UNDEFINED,*it)); + if(!SHOWERINGPARTICLE(*it)->coloured()) continue; + findPartners(*it,done,jets,systems.back().jets); + } + for(unsigned int ix=0;ixisFinalState()) ++nf; + else ++ni; + } + // type + // initial-initial + if(ni==2&&nf==0) { + systems[ix].type = II; + ++nnii; + } + // initial only + else if(ni==1&&nf==0) { + systems[ix].type = I; + ++nni; + } + // initial-final + else if(ni==1&&nf>0) { + systems[ix].type = IF; + ++nnif; + } + // final only + else if(ni==0&&nf>0) { + systems[ix].type = F; + ++nnf; + } + // otherwise unknown + else { + systems[ix].type = UNDEFINED; + ++nnun; + } + } + return systems; +} + +template +void KinematicsReconstructor::combineFinalState(vector > & systems) const { + // check that 1 particle final-state systems which can be combine + bool canCombine(true); + for(unsigned int ix=0;ix > oldsystems=systems; + systems.clear(); + ColourSinglet finalState; + finalState.type = F; + for(unsigned int ix=0;ix describeHerwigShowerBasis("Herwig::ShowerBasis", "libHerwig.so"); void ShowerBasis::setBasis(const Lorentz5Momentum & p, const Lorentz5Momentum & n, Frame inframe) { pVector_ = p; nVector_ = n; frame_ = inframe; Boost beta_bb; if(frame()==BackToBack) { beta_bb = -(pVector_ + nVector_).boostVector(); } else if(frame()==Rest) { beta_bb = -pVector().boostVector(); } else assert(false); Lorentz5Momentum p_bb = pVector(); Lorentz5Momentum n_bb = nVector(); p_bb.boost( beta_bb ); n_bb.boost( beta_bb ); // rotate to have z-axis parallel to p/n Axis axis; if(frame()==BackToBack) { axis = p_bb.vect().unit(); } else if(frame()==Rest) { axis = n_bb.vect().unit(); } else assert(false); LorentzRotation rot; if(axis.perp2()>1e-10) { double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); } else if(axis.z()<0.) { rot.rotate(Constants::pi,Axis(1.,0.,0.)); } xPerp_=LorentzVector(1.,0.,0.,0.); yPerp_=LorentzVector(0.,1.,0.,0.); xPerp_.transform(rot); yPerp_.transform(rot); // boost back xPerp_.boost( -beta_bb ); yPerp_.boost( -beta_bb ); } void ShowerBasis::transform(const LorentzRotation & r) { pVector_ *= r; nVector_ *= r; xPerp_ *= r; yPerp_ *= r; } vector ShowerBasis::getBasis() const { vector dum; dum.push_back( pVector_ ); dum.push_back( nVector_ ); return dum; } diff --git a/Shower/QTilde/Base/ShowerBasis.fh b/Shower/QTilde/Kinematics/ShowerBasis.fh rename from Shower/QTilde/Base/ShowerBasis.fh rename to Shower/QTilde/Kinematics/ShowerBasis.fh diff --git a/Shower/QTilde/Base/ShowerBasis.h b/Shower/QTilde/Kinematics/ShowerBasis.h rename from Shower/QTilde/Base/ShowerBasis.h rename to Shower/QTilde/Kinematics/ShowerBasis.h --- a/Shower/QTilde/Base/ShowerBasis.h +++ b/Shower/QTilde/Kinematics/ShowerBasis.h @@ -1,130 +1,130 @@ // -*- C++ -*- #ifndef Herwig_ShowerBasis_H #define Herwig_ShowerBasis_H // // This is the declaration of the ShowerBasis class. // #include "ShowerBasis.fh" -#include "ShowerParticle.fh" +#include "Herwig/Shower/QTilde/Base/ShowerParticle.fh" #include "Herwig/Shower/QTilde/ShowerConfig.h" #include "ThePEG/Config/ThePEG.h" #include "ThePEG/Vectors/Lorentz5Vector.h" namespace Herwig { using namespace ThePEG; /** * The ShowerBasis class stores the basis vectors used by the shower */ class ShowerBasis: public Base { public: /** * enum for the frame definition */ enum Frame {BackToBack,Rest}; public: /** * The default constructor. */ ShowerBasis() {} /** * Access to the frame definition */ Frame frame() const {return frame_;} /** * Implementation of the virtual function returning a set of basis vectors, specific to * the type of evolution. This function will be used by the * ForwardShowerEvolver in order to access \f$p\f$ * and \f$n\f$. */ virtual vector getBasis() const; /** * Set the basis vectors */ void setBasis(const Lorentz5Momentum &p, const Lorentz5Momentum & n, Frame frame); /** * Access to the \f$p\f$ vector used to describe the kinematics. */ const Lorentz5Momentum & pVector() const {return pVector_;} /** * Access to the \f$n\f$ vector used to describe the kinematics. */ const Lorentz5Momentum & nVector() const {return nVector_;} /** * Dot product of thew basis vectors */ Energy2 p_dot_n() const {return pVector_*nVector_;} /** * Transform the shower kinematics (usually the reference vectors) */ virtual void transform(const LorentzRotation & r); /** * Converts a Sudakov parametrization of a momentum w.r.t. the given * basis \f$p\f$ and \f$n\f$ into a 5 momentum. * @param alpha The \f$\alpha\f$ parameter of the Sudakov parameterisation * @param beta The \f$\beta\f$ parameter of the Sudakov parameterisation * @param px The \f$x\f$-component of the transverse momentum in the Sudakov * parameterisation * @param py The \f$x\f$-component of the transverse momentum in the Sudakov * parameterisation */ Lorentz5Momentum sudakov2Momentum(double alpha, double beta, Energy px, Energy py) const { return alpha*pVector_ + beta*nVector_ + px*xPerp_ + py*yPerp_; } private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ ShowerBasis & operator=(const ShowerBasis &); private: /** * The frame in which the basis vectors are defined */ Frame frame_; /** * The \f$p\f$ reference vector */ Lorentz5Momentum pVector_; /** * The \f$n\f$ reference vector */ Lorentz5Momentum nVector_; /** * x \f$q_\perp\f$ reference vector */ LorentzVector xPerp_; /** * y \f$q_\perp\f$reference vector */ LorentzVector yPerp_; }; } #endif /* Herwig_ShowerBasis_H */ diff --git a/Shower/QTilde/Base/ShowerKinematics.cc b/Shower/QTilde/Kinematics/ShowerKinematics.cc rename from Shower/QTilde/Base/ShowerKinematics.cc rename to Shower/QTilde/Kinematics/ShowerKinematics.cc --- a/Shower/QTilde/Base/ShowerKinematics.cc +++ b/Shower/QTilde/Kinematics/ShowerKinematics.cc @@ -1,69 +1,69 @@ // -*- C++ -*- // // ShowerKinematics.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 ShowerKinematics class. // #include "ShowerKinematics.h" #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; DescribeAbstractNoPIOClass describeShowerKinematics("Herwig::ShowerKinematics","Herwig.so"); void ShowerKinematics::updateChildren(const tShowerParticlePtr, const ShowerParticleVector &, - ShowerPartnerType,bool) const { + ShowerPartnerType) const { throw Exception() << "Base class ShowerKinematics::updateChildren called," << " should have been overriden in an inheriting class" << Exception::runerror; } void ShowerKinematics::resetChildren(const tShowerParticlePtr, const ShowerParticleVector &) const { throw Exception() << "Base class ShowerKinematics::resetChildren called," << " should have been overriden in an inheriting class" << Exception::runerror; } void ShowerKinematics::updateParent(const tShowerParticlePtr, const ShowerParticleVector &, ShowerPartnerType) const { throw Exception() << "Base class ShowerKinematics::updateParent called," << " should have been overriden in an inheriting class" << Exception::runerror; } void ShowerKinematics::reconstructChildren(const tShowerParticlePtr, const ShowerParticleVector &) const { throw Exception() << "Base class ShowerKinematics::reconstructChildren called," << " should have been overriden in an inheriting class" << Exception::runerror; } void ShowerKinematics::reconstructParent(const tShowerParticlePtr, const ParticleVector &) const { throw Exception() << "Base class ShowerKinematics::reconstructParent called," << " should have been overriden in an inheriting class" << Exception::runerror; } void ShowerKinematics::reconstructLast(const tShowerParticlePtr, Energy) const { throw Exception() << "Base class ShowerKinematics::reconstructLast called," << " should have been overriden in an inheriting class" << Exception::runerror; } void ShowerKinematics::updateLast(const tShowerParticlePtr, Energy,Energy) const { throw Exception() << "Base class ShowerKinematics::updatetLast called," << " should have been overriden in an inheriting class" << Exception::runerror; } diff --git a/Shower/QTilde/Base/ShowerKinematics.fh b/Shower/QTilde/Kinematics/ShowerKinematics.fh rename from Shower/QTilde/Base/ShowerKinematics.fh rename to Shower/QTilde/Kinematics/ShowerKinematics.fh diff --git a/Shower/QTilde/Base/ShowerKinematics.h b/Shower/QTilde/Kinematics/ShowerKinematics.h rename from Shower/QTilde/Base/ShowerKinematics.h rename to Shower/QTilde/Kinematics/ShowerKinematics.h --- a/Shower/QTilde/Base/ShowerKinematics.h +++ b/Shower/QTilde/Kinematics/ShowerKinematics.h @@ -1,276 +1,261 @@ // -*- C++ -*- // // ShowerKinematics.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerKinematics_H #define HERWIG_ShowerKinematics_H // // This is the declaration of the ShowerKinematics class. // #include "Herwig/Shower/QTilde/ShowerConfig.h" #include "ThePEG/Config/ThePEG.h" -#include "Herwig/Shower/QTilde/Base/SudakovFormFactor.h" -#include "ShowerKinematics.fh" +#include "Herwig/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h" +#include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.fh" namespace Herwig { using namespace ThePEG; /**\ingroup Shower * * This is the abstract base class from which all other shower * kinematics classes derive. The main purpose of the * shower kinematics classes is to allow the reconstruction * of jet masses, at the end of the showering (indeed, for * multi-scale showering, at the end of each scale-range evolution). * This is necessary for the kinematics reshuffling * in order to compensate the recoil of the emissions. * The KinematicsReconstructor class is in * charge of this job, and which is the main "user" of * ShowerKinematics and its derived classes. * How this is done depends on the choice of kinematics variables * and whether the jet is time-like (forward evolved) or * space-like (backward evolved), whereas the class ShowerKinematics * describes only the common features which are independent by them. * * In general there are a number of methods specific to a shower approach * * @see KinematicsReconstructor */ class ShowerKinematics: public Base { public: /** * The default constructor. */ - ShowerKinematics() : Base(), _isTheJetStartingPoint( false ), + ShowerKinematics() : Base(), _scale(), _z( 0.0 ), _phi( 0.0 ), _pt(), _sudakov() {} /** + * The default constructor. + */ + ShowerKinematics(Energy scale, double z, double phi, Energy pt, tSudakovPtr sud) + : Base(), + _scale(scale), _z(z), _phi(phi), _pt(pt), + _sudakov(sud) {} + + /** * The updateChildren and updateParent * members to update the values of the \f$\alpha\f$ and * \f$p_\perp\f$ variables during the shower evolution. */ //@{ /** * Along with the showering evolution --- going forward for * time-like (forward) evolution, and going backward for space-like * (backward) evolution --- the kinematical variables of the * branching products are calculated and updated from the knowledge * of the parent kinematics. * @param parent The parent * @param children The children * @param partnerType The type of evolution partner */ virtual void updateChildren(const tShowerParticlePtr parent, const ShowerParticleVector & children, - ShowerPartnerType partnerType, - bool massVeto ) const; + ShowerPartnerType partnerType) const; virtual void resetChildren( const tShowerParticlePtr parent, const ShowerParticleVector & children) const; /** * Update the parent Kinematics from the knowledge of the kinematics * of the children. This method will be used by the KinematicsReconstructor. * @param parent The parent * @param children The children * @param partnerType The type of evolution partner */ virtual void updateParent(const tShowerParticlePtr parent, const ShowerParticleVector & children, ShowerPartnerType partnerType) const; /** * Update the kinematical data of a particle when a reconstruction * fixpoint was found. This will highly depend on the kind of * kinematics chosen and will be defined in the inherited concrete * classes. This method will be used by the KinematicsReconstructor. * @param last The particle. * @param px The \f$x\f$ component of the \f$p_T\f$. * @param py The \f$y\f$ component of the \f$p_T\f$. */ virtual void updateLast(const tShowerParticlePtr last, Energy px, Energy py) const; //@} /** * The reconstructLast, reconstructChildren and reconstructParent members * are used during the reconstruction */ //@{ /** * Along with the showering evolution --- going forward for * time-like (forward) evolution, and going backward for space-like * (backward) evolution --- the kinematical variables of the * branching products are calculated and updated from the knowledge * of the parent kinematics. * @param parent The parent * @param children The children */ virtual void reconstructChildren(const tShowerParticlePtr parent, const ShowerParticleVector & children) const; /** * Reconstruct the parent Kinematics from the knowledge of the kinematics * of the children. This method will be used by the KinematicsReconstructor. * @param parent The parent * @param children The children */ virtual void reconstructParent(const tShowerParticlePtr parent, const ParticleVector & children) const; /** * Update the kinematical data of a particle when a reconstruction * fixpoint was found. This will highly depend on the kind of * kinematics chosen and will be defined in the inherited concrete * classes. This method will be used by the KinematicsReconstructor. * @param last The particle. * @param mass The mass to be used, if less than zero on-shell */ virtual void reconstructLast(const tShowerParticlePtr last, Energy mass=-1.*GeV) const; //@} public: /** - * Set/access the flag that tells whether or not this ShowerKinematics - * object is associated to the starting particle of the jet: only in this - * case it is sensible to use the two main virtual methods below. - */ - //@{ - /** - * Set the starting point flag - */ - void isTheJetStartingPoint(const bool ); - - /** - * Get the starting point flag - */ - bool isTheJetStartingPoint() const; - //@} - - /** * Set/Get methods for the kinematic variables */ //@{ /** * Access the scale of the splitting. */ Energy scale() const { return _scale; } /** * Set the scale of the splitting. */ void scale(const Energy in) { _scale=in; } /** * Access the energy fraction, \f$z\f$. */ double z() const { return _z; } /** * Set the energy fraction, \f$z\f$. */ void z(const double in) { _z=in; } /** * Access the azimuthal angle, \f$\phi\f$. */ double phi() const { return _phi; } /** * Set the azimuthal angle, \f$\phi\f$. */ void phi(const double in) { _phi=in; } /** * Access the relative \f$p_T\f$ for the branching */ Energy pT() const { return _pt; } /** * Set the relative \f$p_T\f$ for the branching */ void pT(const Energy in) const { _pt=in; } //@} /** * Set and get methods for the SplittingFunction object */ //@{ /** * Access the SplittingFunction object responsible of the * eventual branching of this particle. */ tSplittingFnPtr splittingFn() const { return _sudakov-> splittingFn(); } //@} /** * Set and get methods for the SudakovFormFactor object */ /** * Access the SudakovFormFactor object responsible of the * eventual branching of this particle. */ tSudakovPtr SudakovFormFactor() const { return _sudakov; } /** * Set the SudakovFormFactor object responsible of the * eventual branching of this particle. */ void SudakovFormFactor(const tSudakovPtr sud) { _sudakov=sud; } //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ - ShowerKinematics & operator=(const ShowerKinematics &); + ShowerKinematics & operator=(const ShowerKinematics &) = delete; private: /** - * Is this the starting point of the jet - */ - bool _isTheJetStartingPoint; - - /** * The \f$\tilde{q}\f$ evolution variable. */ Energy _scale; /** * The energy fraction, \f$z\f$ */ double _z; /** * The azimuthal angle, \f$\phi\f$. */ double _phi; /** * The relative \f$p_T\f$ */ mutable Energy _pt; /** * The splitting function for the branching of the particle */ tSudakovPtr _sudakov; }; } #endif /* HERWIG_ShowerKinematics_H */ diff --git a/Shower/QTilde/Makefile.am b/Shower/QTilde/Makefile.am --- a/Shower/QTilde/Makefile.am +++ b/Shower/QTilde/Makefile.am @@ -1,46 +1,46 @@ SUBDIRS = Matching pkglib_LTLIBRARIES = HwShower.la -HwShower_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 25:1:0 +HwShower_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 25:2:0 HwShower_la_SOURCES = \ Couplings/ShowerAlphaQCD.h Couplings/ShowerAlphaQCD.cc \ Couplings/ShowerAlphaQED.h Couplings/ShowerAlphaQED.cc\ QTildeShowerHandler.h QTildeShowerHandler.fh QTildeShowerHandler.cc \ SplittingFunctions/HalfHalfOneSplitFn.h SplittingFunctions/HalfHalfOneSplitFn.cc\ SplittingFunctions/HalfHalfOneEWSplitFn.h SplittingFunctions/HalfHalfOneEWSplitFn.cc\ SplittingFunctions/OneOneOneSplitFn.h SplittingFunctions/OneOneOneSplitFn.cc\ SplittingFunctions/OneOneOneMassiveSplitFn.h SplittingFunctions/OneOneOneMassiveSplitFn.cc\ SplittingFunctions/ZeroZeroOneSplitFn.h SplittingFunctions/ZeroZeroOneSplitFn.cc\ SplittingFunctions/OneHalfHalfSplitFn.h SplittingFunctions/OneHalfHalfSplitFn.cc\ SplittingFunctions/HalfOneHalfSplitFn.h SplittingFunctions/HalfOneHalfSplitFn.cc\ SplittingFunctions/CMWOneOneOneSplitFn.h SplittingFunctions/CMWOneOneOneSplitFn.cc\ SplittingFunctions/CMWHalfHalfOneSplitFn.h SplittingFunctions/CMWHalfHalfOneSplitFn.cc\ -Default/QTildeSudakov.cc Default/QTildeSudakov.h\ -Default/QTildeModel.cc Default/QTildeModel.h\ -Default/Decay_QTildeShowerKinematics1to2.cc \ -Default/Decay_QTildeShowerKinematics1to2.h \ -Default/IS_QTildeShowerKinematics1to2.cc Default/IS_QTildeShowerKinematics1to2.h \ -Default/FS_QTildeShowerKinematics1to2.cc Default/FS_QTildeShowerKinematics1to2.h \ -Default/QTildeFinder.cc Default/QTildeFinder.h\ -Default/QTildeReconstructor.cc Default/QTildeReconstructor.h Default/QTildeReconstructor.tcc \ -Base/KinematicsReconstructor.cc \ -Base/KinematicsReconstructor.h \ -Base/KinematicsReconstructor.fh \ -Base/ShowerModel.cc Base/ShowerModel.h Base/ShowerModel.fh \ +Kinematics/Decay_QTildeShowerKinematics1to2.cc \ +Kinematics/Decay_QTildeShowerKinematics1to2.h \ +Kinematics/IS_QTildeShowerKinematics1to2.cc Kinematics/IS_QTildeShowerKinematics1to2.h \ +Kinematics/FS_QTildeShowerKinematics1to2.cc Kinematics/FS_QTildeShowerKinematics1to2.h \ +Kinematics/KinematicsReconstructor.cc \ +Kinematics/KinematicsReconstructor.tcc \ +Kinematics/KinematicsReconstructor.h \ +Kinematics/KinematicsReconstructor.fh \ Base/HardTree.cc Base/HardTree.h Base/HardTree.fh \ Base/HardBranching.h Base/HardBranching.fh Base/HardBranching.cc\ Base/PartnerFinder.h Base/PartnerFinder.fh Base/PartnerFinder.cc \ Base/ShowerVeto.h Base/ShowerVeto.fh Base/ShowerVeto.cc \ Base/FullShowerVeto.h Base/FullShowerVeto.fh Base/FullShowerVeto.cc \ SplittingFunctions/SplittingGenerator.cc SplittingFunctions/SplittingGenerator.h\ SplittingFunctions/SplittingGenerator.fh \ Base/ShowerTree.h Base/ShowerTree.fh Base/ShowerTree.cc \ ShowerConfig.h ShowerConfig.cc \ Base/Branching.h \ Base/ShowerParticle.cc Base/ShowerParticle.fh Base/ShowerParticle.h \ -Base/ShowerKinematics.fh Base/ShowerKinematics.h Base/ShowerKinematics.cc \ -Base/ShowerBasis.fh Base/ShowerBasis.h Base/ShowerBasis.cc \ +Kinematics/ShowerKinematics.fh Kinematics/ShowerKinematics.h Kinematics/ShowerKinematics.cc \ +Kinematics/ShowerBasis.fh Kinematics/ShowerBasis.h Kinematics/ShowerBasis.cc \ Base/ShowerProgenitor.fh Base/ShowerProgenitor.h \ -Base/SudakovFormFactor.cc Base/SudakovFormFactor.h Base/SudakovFormFactor.fh \ +SplittingFunctions/SudakovFormFactor.cc SplittingFunctions/SudakovFormFactor.h SplittingFunctions/SudakovFormFactor.fh \ +SplittingFunctions/SudakovCutOff.cc SplittingFunctions/SudakovCutOff.h SplittingFunctions/SudakovCutOff.fh \ +SplittingFunctions/PTCutOff.cc SplittingFunctions/PTCutOff.h \ +SplittingFunctions/MassCutOff.cc SplittingFunctions/MassCutOff.h \ +SplittingFunctions/VariableMassCutOff.cc SplittingFunctions/VariableMassCutOff.h \ SplittingFunctions/SplittingFunction.h SplittingFunctions/SplittingFunction.fh \ SplittingFunctions/SplittingFunction.cc \ Base/ShowerVertex.cc Base/ShowerVertex.fh Base/ShowerVertex.h diff --git a/Shower/QTilde/Matching/MatchingHandler.cc b/Shower/QTilde/Matching/MatchingHandler.cc --- a/Shower/QTilde/Matching/MatchingHandler.cc +++ b/Shower/QTilde/Matching/MatchingHandler.cc @@ -1,1088 +1,1088 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the MatchingHandler class. // #include "MatchingHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDF/PartonExtractor.h" #include "ThePEG/PDF/BeamParticleData.h" #include "ThePEG/PDF/PDF.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/PDF/HwRemDecayer.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" -#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "ThePEG/MatrixElement/Tree2toNDiagram.h" #include "ThePEG/Utilities/Throw.h" using namespace Herwig; namespace { struct ParticleOrdering { bool operator()(tcPDPtr p1, tcPDPtr p2) { 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() ); } }; } MatchingHandler::MatchingHandler(bool reWeight) : reWeight_(reWeight), rejectNonAO_( true ), rejectNOHistories_( true ), includeDecays_(false) {} void MatchingHandler::persistentOutput(PersistentOStream & os) const { os << alphaS_ << matrixElement_ << HWmatrixElement_ << includeDecays_ << partonExtractor_ << cuts_ << rejectNonAO_ << rejectNOHistories_ << allowedInitial_ << allowedFinal_; } void MatchingHandler::persistentInput(PersistentIStream & is, int) { is >> alphaS_ >> matrixElement_ >> HWmatrixElement_ >> includeDecays_ >> partonExtractor_ >> cuts_ >> rejectNonAO_ >> rejectNOHistories_ >> allowedInitial_ >> allowedFinal_; } // *** Attention *** The following static variable is needed for the type // description system in ThePEG. Please check that the template arguments // are correct (the class and its base class), and that the constructor // arguments are correct (the class name and the name of the dynamically // loadable library where the class implementation can be found). DescribeAbstractClass describeHerwigMatchingHandler("Herwig::MatchingHandler", "HwMatching.so"); void MatchingHandler::Init() { static ClassDocumentation documentation ("The MatchingHandler class is the base class implementating" " many of the features needed for matching."); static Reference interfaceMatrixElement ("MatrixElement", "The matrix element class for the core 2->2 process", &MatchingHandler::matrixElement_, false, false, true, true, false); static Reference interfacePartonExtractor ("PartonExtractor", "The PartonExtractor object used to construct remnants. If no object is " "provided the LesHouchesEventHandler object must provide one instead.", &MatchingHandler::partonExtractor_, true, false, true, false, false); static Reference interfaceCuts ("Cuts", "The Cuts object to be used for this reader. Note that these " "must not be looser cuts than those used in the actual generation. " "If no object is provided the LesHouchesEventHandler object must " "provide one instead.", &MatchingHandler::cuts_, true, false, true, false, false); static Reference interfaceShowerAlpha ("ShowerAlpha", "The object calculating the strong coupling constant", &MatchingHandler::alphaS_, false, false, true, true, false); static Switch interfaceReject ("RejectNonOrdered", "Whether to reject non angular ordered cluster histories", &MatchingHandler::rejectNonAO_, true, false, false); static SwitchOption interfaceRejectYes (interfaceReject, "Reject", "Reject all non angular ordered events", true); static SwitchOption interfaceRejectNo (interfaceReject, "Select", "Select a history for non angular ordered events", false); static Switch interfaceRejectNoHist ("RejectNoHistories", "Whether to reject events with no shower interpretation", &MatchingHandler::rejectNOHistories_, true, false, false); static SwitchOption interfaceRejectNoHistYes (interfaceRejectNoHist, "Reject", "Reject all events with no shower interpretation", true); static SwitchOption interfaceRejectNoHistNo (interfaceRejectNoHist, "Shower", "Shower events with no shower interpretation directly", false); static Switch interfaceDecayingParticles ("IncludeDecayingParticles", "Separate production of decay of unstable particles", &MatchingHandler::includeDecays_, false, false, false); static SwitchOption interfaceDecayingParticlesYes (interfaceDecayingParticles, "Yes", "Separate them", true); static SwitchOption interfaceDecayingParticlesNo (interfaceDecayingParticles, "No", "Don't separate them", false); } void MatchingHandler::doinit() { ShowerHandler::doinit(); HWmatrixElement_ = dynamic_ptr_cast(matrixElement_); // check if(reWeight_ && !alphaS_) { throw Exception() << "ShowerAlpha must be set in MatchingHandler if " << "reweighting events" << Exception::runerror; } // extract the allowed branchings // final-state for(BranchingList::const_iterator it = splittingGenerator()->finalStateBranchings().begin(); it != splittingGenerator()->finalStateBranchings().end(); ++it) { pair prod(make_pair(it->second.second[1],it->second.second[2])); allowedFinal_.insert(make_pair(prod,it->second)); swap(prod.first,prod.second); allowedFinal_.insert(make_pair(prod,it->second)); } // initial-state for(BranchingList::const_iterator it = splittingGenerator()->initialStateBranchings().begin(); it != splittingGenerator()->initialStateBranchings().end(); ++it) { allowedInitial_.insert(make_pair(it->second.second[0],it->second)); } } void MatchingHandler::fillProtoTrees( ProtoTreePtr currentProtoTree ) { if(currentProtoTree->branchings().size()==4) return; for( set::const_iterator ita = currentProtoTree->branchings().begin(); ita!=currentProtoTree->branchings().end();++ita) { for( set::const_iterator itb = currentProtoTree->branchings().begin(); itb!=ita;++itb) { // can't merge two incoming branchings if( (**ita).status() == HardBranching::Incoming && (**itb).status() == HardBranching::Incoming ) continue; // get a new branching for this pair ProtoBranchingPtr currentBranching = getCluster(*ita,*itb); if( ! currentBranching ) continue; // branching allowed so make a new Tree out of these branchings set< tProtoBranchingPtr > newTreeBranchings = currentProtoTree->branchings(); newTreeBranchings.erase(*ita); newTreeBranchings.erase(*itb); newTreeBranchings.insert(currentBranching); ProtoTreePtr newProtoTree = new_ptr( ProtoTree( newTreeBranchings ) ); // remove duplicate trees if( ! repeatProtoTree( newProtoTree ) ) protoTrees().insert( newProtoTree ); // remove the current tree if it hasn't already been removed if( protoTrees().find( currentProtoTree ) != protoTrees().end() ) protoTrees().erase( currentProtoTree ); // do recursion fillProtoTrees( newProtoTree ); } } } tProtoBranchingPtr MatchingHandler::getCluster( tProtoBranchingPtr b1, tProtoBranchingPtr b2 ) { //look for the clustered pair in protoBranchings_ for(set::const_iterator cit = protoBranchings().begin(); cit != protoBranchings().end(); ++cit) { // both outgoing if(b1->status()==HardBranching::Outgoing && b2->status()==HardBranching::Outgoing) { if((**cit).status()!=HardBranching::Outgoing|| (**cit).children().empty()) continue; if( ( b1 == (**cit).children()[0] && b2 == (**cit).children()[1] ) || ( b1 == (**cit).children()[1] && b2 == (**cit).children()[0] ) ) return *cit; } // first incoming else if(b1->status()==HardBranching::Incoming) { if((**cit).backChildren().empty() ) continue; if(b1!=(**cit).backChildren()[0]) continue; if(b2==(**cit).backChildren()[1]) return *cit; } // second incoming else if(b2->status()==HardBranching::Incoming) { if((**cit).backChildren().empty() ) continue; if(b2!=(**cit).backChildren()[0]) continue; if(b1==(**cit).backChildren()[1]) return *cit; } } // is branching incoming or outgoing bool incoming = b1->status()==HardBranching::Incoming || b2->status()==HardBranching::Incoming; // get the branching BranchingElement theBranching; if( !incoming ) theBranching = allowedFinalStateBranching( b1, b2 ); else theBranching = allowedInitialStateBranching( b1, b2 ); //if branching is not allowed return null ProtoBrancing if( !theBranching.first ) return ProtoBranchingPtr(); // get the PArticleData object for the new branching tcPDPtr particle_data = incoming ? getParticleData( theBranching.second[1] ) : getParticleData( theBranching.second[0] ); // create clustered ProtoBranching ProtoBranchingPtr clusteredBranch; // outgoing if( !incoming ){ Lorentz5Momentum pairMomentum = b1->momentum() + b2->momentum(); pairMomentum.setMass(ZERO); clusteredBranch = new_ptr(ProtoBranching(particle_data,HardBranching::Outgoing, pairMomentum, theBranching.first)); } // incoming else { Lorentz5Momentum pairMomentum = b1->momentum() - b2->momentum(); pairMomentum.setMass( ZERO ); // check for CC if( particle_data->CC() && ( b1->id() != theBranching.second[0] || b2->id() != theBranching.second[2] ) ) { particle_data = particle_data->CC(); } clusteredBranch = new_ptr(ProtoBranching(particle_data,HardBranching::Incoming, pairMomentum,theBranching.first)); } protoBranchings().insert(clusteredBranch); //set children relations // outgoing if( !incoming ){ clusteredBranch->addChild( b1 ); clusteredBranch->addChild( b2 ); } else { clusteredBranch->addBackChild( b1 ); clusteredBranch->addBackChild( b2 ); } return clusteredBranch; } BranchingElement MatchingHandler:: allowedFinalStateBranching( tProtoBranchingPtr & b1, tProtoBranchingPtr & b2) { // check with normal ID's pair< long, long > ptest = make_pair( b1->id(), b2->id() ); map< pair< long, long >, pair< SudakovPtr, IdList > >::const_iterator split = allowedFinal_.find(ptest); if( split != allowedFinal_.end() ) { if( split->second.second[1] != ptest.first ) swap( b1, b2 ); return split->second; } // check with CC if( b1->particle()->CC() ) ptest.first *= -1; if( b2->particle()->CC() ) ptest.second *= -1; split = allowedFinal_.find( ptest ); if( split != allowedFinal_.end() ) { // cc the idlist only be for qbar g clusterings BranchingElement ccBranch = split->second; if( getParticleData( ccBranch.second[0] )->CC() ) ccBranch.second[0] *= -1; if( getParticleData( ccBranch.second[1] )->CC() ) ccBranch.second[1] *= -1; if( getParticleData( ccBranch.second[2] )->CC() ) ccBranch.second[2] *= -1; if( split->second.second[1] != ptest.first ) swap( b1, b2); return ccBranch; } // not found found null pointer return make_pair( SudakovPtr(), IdList() ); } BranchingElement MatchingHandler:: allowedInitialStateBranching( tProtoBranchingPtr & b1, tProtoBranchingPtr & b2) { if(b2->status()==HardBranching::Incoming) swap(b1,b2); // is initial parton an antiparticle bool cc = b1->id() < 0; //gives range of allowedInitial_ with matching first abs( id ) pair< multimap< long, pair< SudakovPtr, IdList > >::const_iterator, multimap< long, pair< SudakovPtr, IdList > >::const_iterator > location = allowedInitial_.equal_range( abs( b1->id() ) ); //iterates over this range for( multimap< long, pair< SudakovPtr, IdList> >::const_iterator it = location.first; it != location.second; ++it ) { //test id for second particle in pair long idtest = it->second.second[2]; //if it is antiparticle *= -1 if( cc && getParticleData( idtest )->CC() ) idtest *= -1; // does second id match the test if( idtest == b2->id() ) return it->second; //if the the IS parton is a gluon and charge conjugate of second parton mathes accept if( idtest == -b2->id() && ! b1->particle()->CC() ) return it->second; } // not found found null pointer return make_pair(SudakovPtr(),IdList()); } bool MatchingHandler::repeatProtoTree( ProtoTreePtr currentProtoTree ) { // loop over all prototrees and see // how many ProtoBranchings of current ProtoTree are found in each for( set< ProtoTreePtr >::const_iterator cit = protoTrees().begin(); cit != protoTrees().end(); ++cit ) { unsigned int no_matches = 0; for( set< tProtoBranchingPtr >::const_iterator ckt = currentProtoTree->branchings().begin(); ckt != currentProtoTree->branchings().end(); ckt++ ) { if( (*cit)->branchings().find( *ckt ) != (*cit)->branchings().end() ) ++no_matches; } // return true if all match if( no_matches == currentProtoTree->branchings().size() ) return true; } return false; } double MatchingHandler::getDiagram(PotentialTree & tree) { if(tree.diagrams().empty()) { set::const_iterator cit; tcPDPair incoming; multiset outgoing; //get the incoming and outgoing partons involved in hard process for( cit = tree.tree()->branchings().begin(); cit != tree.tree()->branchings().end(); ++cit ){ if( (*cit)->status() ==HardBranching::Incoming) { HardBranchingPtr parent = *cit; while(parent->parent()) parent = parent->parent(); if( parent->branchingParticle()->momentum().z()>ZERO ) incoming.first = (*cit)->branchingParticle()->dataPtr(); else incoming.second = (*cit)->branchingParticle()->dataPtr(); } else { outgoing.insert( (*cit)->branchingParticle()->dataPtr() ); } } if(!incoming.first || !incoming.second) return 0.; pair tag; tag.first = incoming.first ->PDGName() + "," + incoming.second->PDGName() + "->"; tag.second = incoming.second ->PDGName() + "," + incoming.first ->PDGName() + "->"; string tag_out; for ( multiset::iterator i = outgoing.begin(); i != outgoing.end(); ++i ) { if ( i != outgoing.begin() ) tag_out += ","; tag_out += (**i).PDGName(); } tag.first += tag_out; tag.second += tag_out; // find the diagrams for ( int i = 0, N = matrixElement()->diagrams().size(); i < N; ++i ) { string temp = matrixElement()->diagrams()[i]->getTag(); if ( temp == tag.first || temp == tag.second ) tree.diagrams().push_back(matrixElement()->diagrams()[i]); } } if(tree.diagrams().empty()) return 0.; // construct a set of on-shell momenta for the hard collison vector meMomenta; vector mePartonData; PVector particles; set::const_iterator it; // incoming particles for( it = tree.tree()->branchings().begin();it != tree.tree()->branchings().end(); ++it ) { if( (**it).status() == HardBranching::Incoming ) { meMomenta.push_back( (**it).branchingParticle()->momentum() ); mePartonData.push_back( (**it).branchingParticle()->dataPtr() ); particles.push_back( (**it).branchingParticle() ); } } assert(particles.size()==2); for( it = tree.tree()->branchings().begin(); it != tree.tree()->branchings().end(); ++it ) { if( (**it).status() == HardBranching::Outgoing ) { meMomenta.push_back( (**it).branchingParticle()->momentum() ); mePartonData.push_back( (**it).branchingParticle()->dataPtr() ); particles.push_back( (**it).branchingParticle() ); } } const cPDVector partons = tree.diagrams()[0]->partons(); // order of the incoming partons if(mePartonData[0] != partons[0]) { swap( mePartonData[0], mePartonData[1] ); swap( meMomenta[0], meMomenta[1] ); swap( particles[0], particles[1] ); } // order of the outgoing partons for(unsigned int ix=2;ix0.) { R.rotateZ(-axis.phi()); R.rotateY(-acos(axis.z())); } for( unsigned int ix = 0; ix < meMomenta.size(); ++ix ) meMomenta[ix].transform(R); // now rescale to put on shell Energy Ebeam = 0.5 * ( max(meMomenta[0].e(),abs(meMomenta[0].z())) + max(meMomenta[1].e(),abs(meMomenta[1].z())) ); for( unsigned int i = 0; i < 2; ++i ) { meMomenta[i].setZ( meMomenta[i].z() / abs(meMomenta[i].z()) * Ebeam ); meMomenta[i].setT( Ebeam ); } Energy2 s = 4.0 * sqr(Ebeam); Energy m1 = mePartonData[2]->mass(); Energy m2 = mePartonData[3]->mass(); // \todo need to improve this if(m1+m2>sqrt(s)) return 0.; double lambda = 0.25/Ebeam/meMomenta[2].rho() * sqrt( ( s - sqr(m1+m2) ) * ( s - sqr(m1-m2) ) ); for( unsigned int i = 2; i < meMomenta.size(); ++i ) { meMomenta[i] *= lambda; meMomenta[i].setMass(mePartonData[i]->mass()); meMomenta[i].rescaleEnergy(); } // incoming pair PPair in( mePartonData[0]->produceParticle( meMomenta[0] ), mePartonData[1]->produceParticle( meMomenta[1] ) ); // outgoing PVector out; for(unsigned int ix=2;ixproduceParticle(meMomenta[ix])); } // call the matrix element to initialize matrixElement()->setKinematics(in,out); if(HWMatrixElement()) { vector momenta; cPDVector data; data.push_back(in. first->dataPtr()); momenta.push_back(in. first->momentum()); data.push_back(in.second->dataPtr()); momenta.push_back(in.second->momentum()); for(unsigned int ix=0;ixdataPtr()); momenta.push_back(out[ix]->momentum()); } HWMatrixElement()->rescaleMomenta(momenta,data); } if(!cuts()->scale(matrixElement()->scale())) { return 0.; } matrixElement()->dSigHatDR(); // select the diagram if(!tree.diagram()) tree.diagram(tree.diagrams()[matrixElement()->diagram(tree.diagrams())]); // get the colour structure if(!tree.colourLines()) { Selector sel = matrixElement()->colourGeometries(tree.diagram()); tree.colourLines(sel.select(rnd())); } PVector slike; tPVector ret; slike.push_back(particles[0]); Ptr::const_pointer diagram2 = dynamic_ptr_cast::const_pointer>(tree.diagram()); for ( int i = 1; i < diagram2->nSpace() - 1; ++i ) slike.push_back(diagram2->allPartons()[i]->produceParticle()); slike.push_back(particles[1]); ret = tPVector(slike.begin(), slike.end()); int io = particles.size(); PVector tlike(diagram2->allPartons().size() - diagram2->nSpace()); for ( int i = diagram2->allPartons().size() - 1; i >= diagram2->nSpace(); --i ) { int it = i - diagram2->nSpace(); pair ch = diagram2->children(i); bool iso = ch.first < 0; if ( iso ) { tlike[it] = particles[--io]; } else { Lorentz5Momentum p = tlike[ch.first - diagram2->nSpace()]->momentum() + tlike[ch.second - diagram2->nSpace()]->momentum(); tlike[it] = diagram2->allPartons()[i]->produceParticle(p); } } ret.insert( ret.end(), tlike.begin(), tlike.end() ); tree.colourLines()->connect(ret); for( unsigned int ix = 0; ix < ret.size(); ++ix ) { PVector::iterator it = find( particles.begin(), particles.end(),ret[ix] ); if( it == particles.end() ) { ColinePtr line = ret[ix]->colourLine(); if(line) line->removeColoured(ret[ix]); line = ret[ix]->antiColourLine(); if(line) line->removeAntiColoured(ret[ix]); } } // now the colours of the rest of the particles // for( set::const_iterator it = tree.tree()->branchings().begin(); // it!=tree.tree()->branchings().end(); ++it ) (**it).fixColours(); // now make the colour connections in the tree ShowerParticleVector branchingParticles; map branchingMap; for( set< HardBranchingPtr >::iterator it = tree.tree()->branchings().begin(); it != tree.tree()->branchings().end(); ++it ) { branchingParticles.push_back((**it).branchingParticle()); branchingMap.insert(make_pair((**it).branchingParticle(),*it)); } // find the colour partners - showerModel()->partnerFinder() + partnerFinder() ->setInitialEvolutionScales(branchingParticles,false, ShowerInteraction::QCD,true); for(unsigned int ix=0;ixpartner()) { HardBranchingPtr partner = branchingMap[branchingParticles[ix]->partner()]; branchingMap[branchingParticles[ix]]->colourPartner(partner); } } double weight = 1.; // calculate the weight if needed if(reWeight_) { if(matrixElement()->orderInAlphaS()>0) { weight = pow(alphaS_->value( max(matrixElement()->scale(),sqr(pdfScale_)) ) / alphaSMG_, int(matrixElement()->orderInAlphaS())); } } // return the weight return weight; } bool MatchingHandler::updateSubProcess() { assert( hardTree().diagram() && hardTree().tree() ); PPair beams = lastXCombPtr()->lastParticles(); // PPair remnants; // // remove children of beams // PVector beam_children = beams.first->children(); // for( unsigned int ix = 0; ix != beam_children.size(); ix++ ){ // if (abs(beam_children[ix]->id())==82) // remnants.first=beam_children[ix]; // beams.first->abandonChild( beam_children[ix] ); // } // beam_children = beams.second->children(); // for( unsigned int ix = 0; ix != beam_children.size(); ix++ ){ // if (abs(beam_children[ix]->id())==82) // remnants.second=beam_children[ix]; // beams.second->abandonChild( beam_children[ix] ); // } // remove children of beams PVector beam_children = beams.first->children(); for( unsigned int ix = 0; ix != beam_children.size(); ix++ ) beams.first->abandonChild( beam_children[ix] ); beam_children = beams.second->children(); for( unsigned int ix = 0; ix != beam_children.size(); ix++ ) beams.second->abandonChild( beam_children[ix] ); if( (**hardTree().tree()->incoming().begin()).branchingParticle()->momentum().z() / beams.first->momentum().z() < 0.) swap( beams.first, beams.second ); Ptr::const_pointer diagram = dynamic_ptr_cast::const_pointer>(hardTree().diagram()); assert(diagram); set::const_iterator it; map< ColinePtr, ColinePtr> colourMap; PPair incoming; // loop over the branchings and sort out incoming particles for( it = hardTree().tree()->branchings().begin(); it != hardTree().tree()->branchings().end(); ++it) { if( (*it)->status() == HardBranching::Outgoing ) continue; PPtr newParticle = new_ptr( Particle( (**it).branchingParticle()->dataPtr() ) ); newParticle->set5Momentum( (**it).showerMomentum() ); if( (**it).branchingParticle()->colourLine() ) { map< ColinePtr, ColinePtr>::iterator loc = colourMap.find( (**it).branchingParticle()->colourLine() ); if( loc != colourMap.end() ) { loc->second->addColoured( newParticle ); } else { ColinePtr newLine = new_ptr( ColourLine() ); colourMap[ (**it).branchingParticle()->colourLine() ] = newLine; newLine->addColoured( newParticle ); } } if( (**it).branchingParticle()->antiColourLine() ) { map< ColinePtr, ColinePtr> ::iterator loc = colourMap.find( (**it).branchingParticle()->antiColourLine() ); if( loc != colourMap.end() ) { loc->second->addAntiColoured( newParticle ); } else { ColinePtr newLine = new_ptr( ColourLine() ); colourMap[ (**it).branchingParticle()->antiColourLine() ] = newLine; newLine->addAntiColoured( newParticle ); } } if( lastXCombPtr()->subProcess()->incoming().first->momentum().z() / newParticle->momentum().z() > 0. ) incoming.first = newParticle; else incoming.second = newParticle; } bool mirror = incoming.first ->dataPtr() != diagram->partons()[0] && incoming.second->dataPtr() != diagram->partons()[1]; // create the new subprocess SubProPtr newSubProcess = new_ptr( SubProcess( incoming, lastXCombPtr()->subProcess()->collision(), lastXCombPtr()->subProcess()->handler() ) ); // add the spacelike intermediates PVector slike; slike.push_back( !mirror ? incoming.first : incoming.second); for ( int i = 1; i < diagram->nSpace() - 1; ++i ) slike.push_back(diagram->allPartons()[i]->produceParticle()); slike.push_back( !mirror ? incoming.second : incoming.first); tPVector ret = tPVector(slike.begin(), slike.end()); for ( size_t i = 1; i < slike.size() - 1; ++i ) { slike[i-1]->addChild(slike[i]); newSubProcess->addIntermediate(slike[ mirror ? i: slike.size() - 1 - i], false); } // get the parton bins from the parton extractor if first time static bool first = true; if(first) { first = false; Energy e1 = lastXCombPtr()->lastParticles().first ->momentum().e(); Energy e2 = lastXCombPtr()->lastParticles().second->momentum().e(); Energy emax = 2.0*sqrt(e1*e2); cPDPair inData = make_pair(lastXCombPtr()->lastParticles().first ->dataPtr(), lastXCombPtr()->lastParticles().second->dataPtr()); cuts()->initialize(sqr(emax),0.5*log(e1/e2)); partonBins(partonExtractor()->getPartons(emax, inData, *cuts())); } // get the parton bins for this event tcPBPair sel; for ( int i = 0, N = partonBins().size(); i < N; ++i ) { tcPBPtr bin = partonBins()[i].first; tPPtr p = incoming.first; while ( bin && p ) { if ( p->dataPtr() != bin->parton() ) break; bin = bin->incoming(); p = p != lastXCombPtr()->lastParticles().first ? lastXCombPtr()->lastParticles().first : PPtr(); } if ( bin || p ) continue; bin = partonBins()[i].second; p = incoming.second; while ( bin && p ) { if ( p->dataPtr() != bin->parton() ) break; bin = bin->incoming(); p = p != lastXCombPtr()->lastParticles().second ? lastXCombPtr()->lastParticles().second : PPtr(); } if ( bin || p ) continue; sel = partonBins()[i]; break; } if ( !sel.first || !sel.second ) Throw() << "Could not find appropriate " << "PartonBin objects for event in " << "MatchingHandler " << Exception::runerror; // create the new parton bin instances Direction<0> dir(true); PBIPair partonBinInstances; // temporary mother/daugther settings // to get parton bin instances correct lastXCombPtr()->lastParticles().first ->addChild(incoming.first ); lastXCombPtr()->lastParticles().second->addChild(incoming.second); // make the parton bin instances partonBinInstances.first = new_ptr(PartonBinInstance(incoming.first, sel.first, lastXCombPtr()->partonBinInstances().first->scale())); dir.reverse(); partonBinInstances.second = new_ptr(PartonBinInstance(incoming.second, sel.second, lastXCombPtr()->partonBinInstances().second->scale())); // remove temporary mother/daugther settings lastXCombPtr()->lastParticles().first ->abandonChild(incoming.first ); lastXCombPtr()->lastParticles().second->abandonChild(incoming.second); // set the parton bin instances lastXCombPtr()->setPartonBinInstances(partonBinInstances, lastXCombPtr()->lastScale()); // momenta of the time like partons vector meMomenta; vector mePartonData; vector branchings; for( it = hardTree().tree()->branchings().begin(); it != hardTree().tree()->branchings().end(); ++it ) { if( (**it).status() == HardBranching::Outgoing ) { meMomenta.push_back( (**it).showerMomentum() ); mePartonData.push_back( (**it).branchingParticle()->dataPtr() ); branchings.push_back(*it); } } // order of the outgoing partons for(int ix=2;ixpartons().size());++ix) { for(int iy=ix-2;iypartons()[ix]==mePartonData[iy]) { if(ix!=iy) { swap(mePartonData[ix-2],mePartonData[iy]); swap(meMomenta [ix-2],meMomenta [iy]); swap(branchings [ix-2],branchings [iy]); } break; } } } // time like particles int io = meMomenta.size(); PVector tlike(diagram->allPartons().size() - diagram->nSpace()); vector tBranchings; tPVector out; for ( int i = diagram->allPartons().size() - 1; i >= diagram->nSpace(); --i ) { int it = i - diagram->nSpace(); pair ch = diagram->children(i); bool iso = ch.first < 0; if ( iso ) { tlike[it] = diagram->allPartons()[i]->produceParticle(meMomenta[--io]); } else { Lorentz5Momentum p = tlike[ch.first - diagram->nSpace()]->momentum() + tlike[ch.second - diagram->nSpace()]->momentum(); tlike[it] = diagram->allPartons()[i]->produceParticle(p); } if ( diagram->parent(i) < diagram->nSpace() ) { slike[diagram->parent(i)]->addChild(tlike[it]); if ( diagram->parent(i) == diagram->nSpace() - 2 ) slike[diagram->parent(i) + 1]->addChild(tlike[it]); } if ( !iso ) { tlike[it]->addChild(tlike[ch.first - diagram->nSpace()]); tlike[it]->addChild(tlike[ch.second - diagram->nSpace()]); } if ( iso ) { out.push_back(tlike[it]); tBranchings.push_back(branchings[io]); } else newSubProcess->addIntermediate(tlike[it], false); } ret.insert(ret.end(), tlike.begin(), tlike.end()); // select the colour structure now const ColourLines & cl = matrixElement()->selectColourGeometry(hardTree().diagram()); cl.connect(ret); // add the particles for ( int i = 0, N = out.size(); i < N; ++i ) { tPPtr particle = out[mirror ? i: out.size() - i - 1]; // if not including decays add as outgoing if(!includeDecays_) { newSubProcess->addOutgoing(particle, false); continue; } HardBranchingPtr branching = tBranchings[mirror ? i: out.size() - i - 1]; // move to end of chain for time-like branchings while(!branching->children().empty()) { bool found=false; for(unsigned int ix=0;ixchildren().size();++ix) { if(branching->children()[ix]->branchingParticle()->id()== branching->branchingParticle()->id()) { found = true; branching = branching->children()[ix]; break; } } if(!found) break; } // check if from decay map::const_iterator pit = parent(branching->branchingParticle()); // if not add as outgoing if(pit==decayingParticles_.end()) { newSubProcess->addOutgoing(particle, false); continue; } LorentzRotation decayBoost = branching->showerBoost(); // final boost if FSR Lorentz5Momentum pShower = decayBoost*(pit->first->momentum()); decayBoost = LorentzRotation(-pShower.boostVector())*decayBoost; decayBoost = LorentzRotation(particle->momentum().boostVector())*decayBoost; // add decayed particle as intermediate newSubProcess->addIntermediate(particle,false); // add decay products addDecayProducts(newSubProcess,particle,pit,decayBoost); } for ( PVector::size_type i = 0; i < slike.size() - 2; ++i ) { pair ch = diagram->children(i); slike[ch.first]->set5Momentum(slike[i]->momentum() - tlike[ch.second - diagram->nSpace()]->momentum()); } // // set parents of incoming particles?? // PPair inParents = lastXCombPtr()->lastParticles(); // if( incoming.first->momentum().z() / inParents.first->momentum().z() < 0.) // swap( inParents.first, inParents.second ); // if( remnants.first->momentum().z() / inParents.first->momentum().z() < 0.) // swap( remnants.first, remnants.second ); // if (incoming.first ->parents().empty()) { // inParents.first ->addChild(incoming.first ); // inParents.first ->addChild(remnants.first ); // } // if (incoming.second->parents().empty()){ // inParents.second->addChild(incoming.second); // inParents.second->addChild(remnants.second); // } // set the subprocess lastXCombPtr()->subProcess( newSubProcess ); decayingParticles_.clear(); return true; } void MatchingHandler::findDecayingParticles(PPtr parent) { ParticleVector decayProducts; for(unsigned int ix=0;ixchildren().size();++ix) { decayProducts.push_back(parent->children()[ix]); if(!parent->children()[ix]->children().empty()) findDecayingParticles(parent->children()[ix]); } if(decayingParticles_.find(parent)==decayingParticles_.end()) decayingParticles_[parent] = decayProducts; } PotentialTree MatchingHandler::doClustering() { noShowerHists_ = false; // clear storage of the protoTrees protoBranchings().clear(); protoTrees().clear(); nonOrderedTrees_.clear(); hardTrees_.clear(); assert( matrixElement() ); // get particles from the XComb object ParticleVector outgoing = lastXCombPtr()->subProcess()->outgoing(); PPair incoming = lastXCombPtr()->subProcess()->incoming(); // storage of decayed particles decayingParticles_.clear(); // all outgoing particles as a set for checking set outgoingset(outgoing.begin(),outgoing.end()); // loop through the FS particles and create ProtoBranchings for( unsigned int i = 0; i < outgoing.size(); ++i) { tPPtr parent = outgoing[i]->parents()[0]; bool decayProd = decayProduct(parent,lastXCombPtr()->subProcess()); if(!decayProd||!includeDecays_) { ProtoBranchingPtr currentBranching = new_ptr(ProtoBranching(outgoing[i]->dataPtr(),HardBranching::Outgoing, outgoing[i]->momentum(),tSudakovPtr())); protoBranchings().insert(currentBranching); } else { bool isHard = true; PPtr newParent = findParent(parent,isHard,outgoingset,false, lastXCombPtr()->subProcess()); assert(newParent); if(decayingParticles_.find(newParent)==decayingParticles_.end()) { ProtoBranchingPtr currentBranching = new_ptr(ProtoBranching(newParent->dataPtr(),HardBranching::Outgoing, newParent->momentum(),tSudakovPtr())); protoBranchings().insert(currentBranching); findDecayingParticles(newParent); } } } // add IS hardBranchings ProtoBranchingPtr currentBranching = new_ptr(ProtoBranching(incoming.first ->dataPtr(),HardBranching::Incoming, incoming.first ->momentum(),tSudakovPtr())); protoBranchings().insert(currentBranching); currentBranching = new_ptr(ProtoBranching(incoming.second->dataPtr(),HardBranching::Incoming, incoming.second->momentum(),tSudakovPtr())); protoBranchings().insert(currentBranching); //create and initialise the first tree ProtoTreePtr initialProtoTree = new_ptr( ProtoTree() ); for(set::const_iterator it=protoBranchings().begin(); it!=protoBranchings().end();++it) { initialProtoTree->addBranching(*it); } //fill _proto_trees with all possible trees protoTrees().insert(initialProtoTree ); fillProtoTrees( initialProtoTree ); double totalWeight = 0., nonOrderedWeight = 0.; // create a HardTree from each ProtoTree and fill hardTrees() for( set< ProtoTreePtr >::const_iterator cit = protoTrees().begin(); cit != protoTrees().end(); ++cit ) { PotentialTree newTree; newTree.tree((**cit).createHardTree()); // check the created CKKWTree corresponds to an allowed LO configuration // (does matrix element have a corresponding diagram) double meWgt = getDiagram( newTree ); if( !newTree.diagram() ) continue; // set the beam particles PPair beams = lastXCombPtr()->lastParticles(); // remove children of beams PVector beam_children = beams.first->children(); if( (**newTree.tree()->incoming().begin()).branchingParticle()->momentum().z() / beams.first->momentum().z() < 0.) swap( beams.first, beams.second ); set::iterator it = newTree.tree()->incoming().begin(); HardBranchingPtr br = *it; br->beam( beams.first ); while ( !br->children().empty() ) { for(unsigned int ix = 0; ix < br->children().size(); ++ix ) { if( br->children()[ix]->status() == HardBranching::Incoming ) { br = br->children()[ix]; break; } } br->beam( beams.first ); } ++it; br = *it; br->beam( beams.second ); while ( !br->children().empty() ) { for( unsigned int ix = 0; ix < br->children().size(); ++ix ) { if( br->children()[ix]->status() == HardBranching::Incoming ) { br = br->children()[ix]; break; } } br->beam( beams.second ); } // do inverse momentum reconstruction - if( !showerModel()->kinematicsReconstructor() + if( !kinematicsReconstructor() ->deconstructHardJets( newTree.tree(), evolver(), ShowerInteraction::QCD ) ) continue; newTree.tree()->findNodes(); if( newTree.tree()->ordered() ) { // find the wgt and fill hardTrees() map double treeWeight = 1.; if(reWeight_) treeWeight = meWgt*sudakovWeight( newTree.tree() ); newTree.weight(treeWeight); hardTrees_.push_back( make_pair( newTree, treeWeight ) ); totalWeight += treeWeight; } else { nonOrderedTrees_.push_back( make_pair( newTree, 1. ) ); nonOrderedWeight += 1.; } } // if rejecting non-ordered trees return if( hardTrees_.empty() && rejectNonAO_ ) return PotentialTree(); // select the tree PotentialTree chosen_hardTree=chooseHardTree(totalWeight, nonOrderedWeight); protoBranchings().clear(); protoTrees().clear(); nonOrderedTrees_.clear(); hardTrees_.clear(); if(! chosen_hardTree.tree() ) { noShowerHists_ = true; return PotentialTree(); } else return chosen_hardTree; } void MatchingHandler::initialiseMatching(int minMult, int maxMult) { if (!matrixElement_){ tStdXCombPtr lastXC = dynamic_ptr_cast(lastXCombPtr()); tStdXCombPtr headXC = lastXC->head(); if (headXC) matrixElement_ = dynamic_ptr_cast(headXC->matrixElement()); else if (lastXC) matrixElement_ = dynamic_ptr_cast(lastXC->matrixElement()); } HWmatrixElement_ = dynamic_ptr_cast(matrixElement_); assert(matrixElement_); // check multiplicity of FS partons int nOut = lastXCombPtr()->subProcess()->outgoing().size(); // is it the lowest multiplicity lowestMult_ = nOut == minMult; // or the highest highestMult_ = nOut == maxMult; // centre-of-mass energy sHat(lastXCombPtr()->lastSHat()); // scale for the PDFs pdfScale(sqrt(lastXCombPtr()->lastScale())); // alphaS value used by the ME generate alphaSMG(lastXCombPtr()->lastAlphaS()); // create a hard tree by clustering the event hardTree(doClustering()); } map::const_iterator MatchingHandler::parent(PPtr parent) { long id = parent->id(); for(map::const_iterator it = decayingParticles_.begin(); it!=decayingParticles_.end();++it) { if(id!=it->first->id()) continue; Energy2 diff = sqr(it->first->momentum().x()-parent->momentum().x()) + sqr(it->first->momentum().y()-parent->momentum().y()) + sqr(it->first->momentum().z()-parent->momentum().z()) + sqr(it->first->momentum().t()-parent->momentum().t()); Energy2 sum = sqr(it->first->momentum().x()+parent->momentum().x()) + sqr(it->first->momentum().y()+parent->momentum().y()) + sqr(it->first->momentum().z()+parent->momentum().z()) + sqr(it->first->momentum().t()+parent->momentum().t()); double ratio = diff/sum; if(ratio<1e-10) return it; } return decayingParticles_.end(); } void MatchingHandler::addDecayProducts(SubProPtr subProcess, PPtr parent, map::const_iterator decay, const LorentzRotation & boost) const { // map colours of the parent map cmap; if(parent->colourLine()) cmap.insert(make_pair(decay->first-> colourLine(), parent-> colourLine())); if(parent->antiColourLine()) cmap.insert(make_pair(decay->first->antiColourLine(), parent->antiColourLine())); // add the decay products for(unsigned int ix=0;ixsecond.size();++ix) { Lorentz5Momentum pnew = boost*decay->second[ix]->momentum(); PPtr newParticle = decay->second[ix]->dataPtr()->produceParticle(pnew); parent->addChild(newParticle); if(decay->second[ix]->colourLine()) { if(cmap.find(decay->second[ix]->colourLine())==cmap.end()) { ColinePtr newLine(new_ptr(ColourLine())); cmap.insert(make_pair(decay->second[ix]->colourLine(),newLine)); } cmap[decay->second[ix]->colourLine()]->addColoured(newParticle); } if(decay->second[ix]->antiColourLine()) { if(cmap.find(decay->second[ix]->antiColourLine())==cmap.end()) { ColinePtr newLine(new_ptr(ColourLine())); cmap.insert(make_pair(decay->second[ix]->antiColourLine(),newLine)); } cmap[decay->second[ix]->antiColourLine()]->addAntiColoured(newParticle); } map::const_iterator pit = decayingParticles_.find(decay->second[ix]); if(pit!=decayingParticles_.end()) { subProcess->addIntermediate(newParticle, false); addDecayProducts(subProcess,newParticle,pit,boost); } else { subProcess->addOutgoing(newParticle, false); } } } diff --git a/Shower/QTilde/Matching/PowhegHandler.cc b/Shower/QTilde/Matching/PowhegHandler.cc --- a/Shower/QTilde/Matching/PowhegHandler.cc +++ b/Shower/QTilde/Matching/PowhegHandler.cc @@ -1,167 +1,167 @@ // -*- C++ -*- // // This is the implementation of the non-inlined, non-templated member // functions of the PowhegHandler class. // #include "PowhegHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/PDF/PartonExtractor.h" #include "ThePEG/PDF/BeamParticleData.h" #include "ThePEG/PDF/PDF.h" #include "ThePEG/Cuts/Cuts.h" #include "Herwig/PDF/HwRemDecayer.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" -#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "Herwig/MatrixElement/Matchbox/Matching/ShowerApproximationGenerator.h" using namespace Herwig; IBPtr PowhegHandler::clone() const { return new_ptr(*this); } IBPtr PowhegHandler::fullclone() const { return new_ptr(*this); } void PowhegHandler::persistentOutput(PersistentOStream & os) const { os << pTDefinition_ << ounit(maxpT_,GeV); } void PowhegHandler::persistentInput(PersistentIStream & is, int) { is >> pTDefinition_ >> iunit(maxpT_,GeV); } // *** Attention *** The following static variable is needed for the type // description system in ThePEG. Please check that the template arguments // are correct (the class and its base class), and that the constructor // arguments are correct (the class name and the name of the dynamically // loadable library where the class implementation can be found). DescribeClass describeHerwigPowhegHandler("Herwig::PowhegHandler", "HwMatching.so"); void PowhegHandler::Init() { static ClassDocumentation documentation ("The PowhegHandler class handles the generation of the shower, including truncated" "showers for external processes using the POWHEG scheme."); static Switch interfacepTDefinition ("pTDefinition", "The choice of the definition of the pT for the maximum emission in the shower", &PowhegHandler::pTDefinition_, 0, false, false); static SwitchOption interfacepTDefinitionScale (interfacepTDefinition, "Scale", "Use the value of the lastScale(), which if reading Les Houches events is SCALUP", 0); static SwitchOption interfacepTDefinitionScaleAndpT (interfacepTDefinition, "ScaleAndpT", "Use the same choice as scale for non-emission events but the pT of the" " emitted particle for emission events", 1); static SwitchOption interfacepTDefinitionmaxpTAndpT (interfacepTDefinition, "maxpTAndpT", "Use the maxPt value fo non-emission events and the pT of the" " emitted particle for emission events", 2); static Parameter interfacemaxpT ("maxpT", "Maximum pT for emission from non-emission events.", &PowhegHandler::maxpT_, GeV, 1.0*GeV, 0.0*GeV, 10.0*GeV, false, false, Interface::limited); } double PowhegHandler::reweightCKKW(int minMult, int maxMult) { // as not reweighting skip if in initialisation if(generator()->state()==InterfacedBase::initializing) return 1.; initialiseMatching(minMult,maxMult); if( ! hardTree().tree() ) return 1.; // update sub process based on hardTree() updateSubProcess(); return 1.; } HardTreePtr PowhegHandler::generateCKKW(ShowerTreePtr tree) const { //get com energy from the progenitors Energy2 s = (tree->incomingLines(). begin()->first->progenitor()->momentum() + tree->incomingLines().rbegin()->first->progenitor()->momentum()).m2(); // Get the HardTree from the CKKW handler. CKKWTreePtr hardtree = getCKKWTree(); // if no hard tree return if( ! hardtree ) return HardTreePtr(); // check the trees match if( ! hardtree->connect(tree) ) return HardTreePtr(); // choice of the veto pT Energy veto_pt = sqrt( s ); // use the scale if(pTDefinition_==0) { veto_pt = sqrt(lastXCombPtr()->lastScale()); } // otherwise pT of emission if emitted else if(!lowestMult()) { veto_pt = hardtree->lowestPt( 1, s ); for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = tree->outgoingLines().begin(); it != tree->outgoingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT( veto_pt, ShowerInteraction::QCD ); } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = tree->incomingLines().begin(); it != tree->incomingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT( veto_pt, ShowerInteraction::QCD ); } } else if(pTDefinition_==1) { veto_pt = sqrt(lastXCombPtr()->lastScale()); } else if(pTDefinition_==2) { veto_pt = maxpT_; } else assert(false); // that's it return hardtree; } PotentialTree PowhegHandler::chooseHardTree(double,double) { PotentialTree chosen_hardTree; Energy min_pt = Constants::MaxEnergy; if( !hardTrees().empty() ){ for(unsigned int ix = 0; ix < hardTrees().size(); ix++ ){ if( hardTrees()[ix].first.tree()->totalPt() < min_pt ) { min_pt = hardTrees()[ix].first.tree()->totalPt(); chosen_hardTree = hardTrees()[ix].first; } } } else { for(unsigned int ix = 0; ix < nonOrderedTrees().size(); ix++ ){ if( nonOrderedTrees()[ix].first.tree()->totalPt() < min_pt ){ min_pt = nonOrderedTrees()[ix].first.tree()->totalPt(); chosen_hardTree=nonOrderedTrees()[ix].first; } } } return chosen_hardTree; } diff --git a/Shower/QTilde/Matching/PowhegShowerHandler.cc b/Shower/QTilde/Matching/PowhegShowerHandler.cc --- a/Shower/QTilde/Matching/PowhegShowerHandler.cc +++ b/Shower/QTilde/Matching/PowhegShowerHandler.cc @@ -1,1104 +1,1104 @@ // -*- C++ -*- // // PowhegShowerHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 PowhegShowerHandler class. // #include #include "PowhegShowerHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/DescribeClass.h" // include theses to have complete types #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "Herwig/PDF/MPIPDF.h" #include "Herwig/PDF/MinBiasPDF.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" -#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" #include "Herwig/PDF/HwRemDecayer.h" #include "Herwig/Shower/QTilde/Base/ShowerProgenitor.h" #include "Herwig/Shower/QTilde/Base/HardBranching.h" #include "Herwig/Shower/QTilde/Base/HardTree.h" #include "Herwig/MatrixElement/HwMEBase.h" #include "ThePEG/MatrixElement/MEBase.h" #include "ThePEG/MatrixElement/DiagramBase.fh" #include "ThePEG/PDF/PartonExtractor.h" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include "Herwig/MatrixElement/Matchbox/Utility/DiagramDrawer.h" using namespace Herwig; namespace { struct ParticleOrdering { bool operator()(tcPDPtr p1, tcPDPtr p2) { 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() ); } }; } IBPtr PowhegShowerHandler::clone() const { return new_ptr(*this); } IBPtr PowhegShowerHandler::fullclone() const { return new_ptr(*this); } HardTreePtr PowhegShowerHandler::generateCKKW(ShowerTreePtr showerTree) const { // hard subprocess tSubProPtr sub = lastXCombPtr()->subProcess(); // real emission sub-process tSubProPtr real = Factory()->hardTreeSubprocess(); // born emitter emitter_ = Factory()->hardTreeEmitter(); spectator_ = Factory()->hardTreeSpectator(); // if no hard emission return if ( !(real && emitter_>-1) ) return HardTreePtr(); // check emission if(sub->outgoing().size()>=real->outgoing().size()) return HardTreePtr(); // check if decay has radiated don't add it if(showerTree->outgoingLines().size() != sub->outgoing().size()) { // loop over the decay trees for(map >::const_iterator tit=showerTree->treelinks().begin(); tit != showerTree->treelinks().end(); ++tit) { if(tit->first->outgoingLines().empty()) continue; // match the particles set decayProducts; set outgoing(real->outgoing().begin(),real->outgoing().end()); for(map::const_iterator oit=tit->first->outgoingLines().begin(); oit!=tit->first->outgoingLines().end();++oit) { tPPtr decayProd; Energy2 dmin( 1e30*GeV2 ); tPPtr part = oit->second->original(); for( set::const_iterator it = outgoing.begin(); it != outgoing.end(); ++it ) { if((**it).id()!=part->id()) continue; Energy2 dtest = sqr( part->momentum().x() - (**it).momentum().x() ) + sqr( part->momentum().y() - (**it).momentum().y() ) + sqr( part->momentum().z() - (**it).momentum().z() ) + sqr( part->momentum().t() - (**it).momentum().t() ); dtest += 1e10*sqr(part->momentum().m()-(**it).momentum().m()); if( dtest < dmin ) { decayProd = *it; dmin = dtest; } } if(!decayProd) { throw Exception() << "PowhegShowerHandler::generateCKKW(). Can't match shower and hard trees." << Exception::eventerror; } outgoing .erase (decayProd); decayProducts.insert(decayProd); } bool coloured = false, foundParent = true; tPPtr parent,emitted; unsigned int nprod(0); for( set::const_iterator it = decayProducts.begin(); it != decayProducts.end(); ++it ) { coloured |= (**it).dataPtr()->coloured(); tPPtr newParent = !(**it).parents().empty() ? (**it).parents()[0] : tPPtr(); ++nprod; // check if from emission if(newParent->id()==(**it).id()) { if(newParent->children().size()!=2) foundParent=false; bool foundChild(false), foundGluon(false); for(unsigned int ix=0;ixchildren().size();++ix) { if(newParent->children()[ix]==*it) { foundChild = true; continue; } else if(newParent->children()[ix]->id()==ParticleID::g) { foundGluon = true; continue; } } if(foundChild && foundGluon) { newParent = !newParent->parents().empty() ? newParent->parents()[0] : tPPtr(); ++nprod; } else foundParent = false; } if(!newParent) { foundParent = false; } else if(!parent) { parent = newParent; } else { if(parent!=newParent) foundParent = false; } } if(nprod!=tit->first->outgoingLines().size()&&foundParent) { if(decayRadiation_==0) { throw Exception() << "The radiation generated in this event\n " << *real << "\n has been interepted as occuring in the " << "decay \nof a colour-singlet object and cannot be handled " << "you can either not simulated this process, " << "veto this class of events by using\n" << "set " << fullName() << ":DecayRadiation VetoEvent\n" << "or throw the hard radiation away using \n" << "set " << fullName() << ":DecayRadiation VetoRadiation\n" << "Please contact us at herwig@hepforge.org for advice\n" << "on how to simulate this process\n" << Exception::runerror; } else if(decayRadiation_==1) { throw Exception() << "The radiation generated in this event\n " << *real << "\n has been interepted as occuring in the " << "decay \nof a colour-singlet object and cannot be handled " << "vetoing event\n" << Exception::eventerror; } else if(decayRadiation_==2) { generator()->log() << "The radiation generated in this event\n " << *real << "\n has been interepted as occuring in the " << "decay \nof a colour-singlet object and cannot be handled " << "vetoing radiation\n"; return HardTreePtr(); } else assert(false); } } } tStdXCombPtr lastXC = dynamic_ptr_cast(lastXCombPtr()); tStdXCombPtr headXC = lastXC->head(); if (headXC) matrixElement_ = dynamic_ptr_cast(headXC->matrixElement()); else if (lastXC) matrixElement_ = dynamic_ptr_cast(lastXC->matrixElement()); if (lastXC){ tStdXCombPtr projector= lastXC->lastProjector(); if (projector){ matrixElement_ = dynamic_ptr_cast(projector->matrixElement()); setSubtractionIntegral(true); } else setSubtractionIntegral(false); } assert(matrixElement_); // create a hard tree by clustering the event try { hardTree(doClustering(real,showerTree)); } catch(exception &e) { throw Exception() << "Caught a problem in PowhegShowerHandler::doClustering " << e.what() << Exception::eventerror; } // Get the HardTree from the CKKW handler. CKKWTreePtr hardtree = hardTree().tree(); // zero to avoid MPI problems Factory()->setHardTreeEmitter(-1); Factory()->setHardTreeSubprocess(SubProPtr()); return hardtree; } PotentialTree PowhegShowerHandler::doClustering(tSubProPtr real,ShowerTreePtr showerTree) const { // clear storage of the protoTrees protoBranchings().clear(); protoTrees().clear(); hardTrees_.clear(); assert( matrixElement() ); // extract the XComb for the Born process tStdXCombPtr lastXC; if (subtractionIntegral()){ tStdXCombPtr lastXCReal = dynamic_ptr_cast(lastXCombPtr()); lastXC = lastXCReal->lastProjector(); } else lastXC = dynamic_ptr_cast(lastXCombPtr()); const StandardXComb xc= *lastXC; // get the particles for the born process PPair incomingBorn = xc.subProcess()->incoming(); ParticleVector outgoingBorn = xc.subProcess()->outgoing(); // get particles from the XComb object for the real process ParticleVector outgoing = real->outgoing(); PPair incoming = real->incoming(); // loop through the FS particles and create ProtoBranchings for( unsigned int i = 0; i < outgoing.size(); ++i) { tPPtr parent = outgoing[i]->parents()[0]; ProtoBranchingPtr currentBranching = new_ptr(ProtoBranching(outgoing[i]->dataPtr(),HardBranching::Outgoing, outgoing[i]->momentum(),tSudakovPtr())); currentBranching-> colourLine(outgoing[i]-> colourLine()); currentBranching->antiColourLine(outgoing[i]->antiColourLine()); protoBranchings().insert(currentBranching); } // add IS hardBranchings ProtoBranchingPtr currentBranching = new_ptr(ProtoBranching(incoming.first ->dataPtr(),HardBranching::Incoming, incoming.first ->momentum(),tSudakovPtr())); currentBranching-> colourLine(incoming.first-> colourLine()); currentBranching->antiColourLine(incoming.first->antiColourLine()); protoBranchings().insert(currentBranching); currentBranching = new_ptr(ProtoBranching(incoming.second->dataPtr(),HardBranching::Incoming, incoming.second->momentum(),tSudakovPtr())); currentBranching-> colourLine(incoming.second-> colourLine()); currentBranching->antiColourLine(incoming.second->antiColourLine()); protoBranchings().insert(currentBranching); // create and initialise the first tree ProtoTreePtr initialProtoTree = new_ptr( ProtoTree() ); for(set::const_iterator it=protoBranchings().begin(); it!=protoBranchings().end();++it) { initialProtoTree->addBranching(*it); } // fill _proto_trees with all possible trees protoTrees().insert(initialProtoTree ); fillProtoTrees( initialProtoTree , xc.mePartonData()[emitter_]->id() ); // create a HardTree from each ProtoTree and fill hardTrees() for( set< ProtoTreePtr >::const_iterator cit = protoTrees().begin(); cit != protoTrees().end(); ++cit ) { set bornParticles(outgoingBorn.begin(),outgoingBorn.end()); bornParticles.insert(incomingBorn.first ); bornParticles.insert(incomingBorn.second); PotentialTree newTree; newTree.tree((**cit).createHardTree()); // new check based on the colour structure map cmap; // make the colour connections in the tree ShowerParticleVector branchingParticles; map branchingMap; bool matched(true); int iemitter(-1); HardBranchingPtr emitter; map locMap; for( set< HardBranchingPtr >::iterator it = newTree.tree()->branchings().begin(); it != newTree.tree()->branchings().end(); ++it ) { matched = true; // map the particle to the branching for future use branchingParticles.push_back((**it).branchingParticle()); branchingMap.insert(make_pair((**it).branchingParticle(),*it)); tPPtr bornPartner; if((**it).status()==HardBranching::Incoming) { HardBranchingPtr parent=*it; while(parent->parent()) { parent = parent->parent(); }; if(parent->branchingParticle()->momentum().z()/incomingBorn.first->momentum().z()>0.) { bornPartner = incomingBorn.first; if(!parent->children().empty()) { iemitter = 0; emitter = *it; } locMap[0] = *it; } else { bornPartner = incomingBorn.second; if(!parent->children().empty()) { iemitter = 1; emitter = *it; } locMap[1] = *it; } } else { Energy2 dmin( 1e30*GeV2 ); for(set::const_iterator bit=bornParticles.begin();bit!=bornParticles.end(); ++bit) { if((**it).branchingParticle()->id()!=(**bit).id()) continue; if(*bit==incomingBorn.first||*bit==incomingBorn.second) continue; Energy2 dtest = sqr( (**bit).momentum().x() - (**it).branchingParticle()->momentum().x() ) + sqr( (**bit).momentum().y() - (**it).branchingParticle()->momentum().y() ) + sqr( (**bit).momentum().z() - (**it).branchingParticle()->momentum().z() ) + sqr( (**bit).momentum().t() - (**it).branchingParticle()->momentum().t() ); dtest += 1e10*sqr((**bit).momentum().m()-(**it).branchingParticle()->momentum().m()); if( dtest < dmin ) { bornPartner = *bit; dmin = dtest; } } // find the map int iloc(-1); for(unsigned int ix=0;ixcolourLine()) { if(cmap.find((**it).branchingParticle()->colourLine())!=cmap.end()) { if(cmap[(**it).branchingParticle()->colourLine()]!=bornPartner->colourLine()) { matched=false; } } else { cmap[(**it).branchingParticle()->colourLine()] = bornPartner->colourLine(); } } if((**it).branchingParticle()->antiColourLine()) { if(cmap.find((**it).branchingParticle()->antiColourLine())!=cmap.end()) { if(cmap[(**it).branchingParticle()->antiColourLine()]!=bornPartner->antiColourLine()) { matched=false; } } else { cmap[(**it).branchingParticle()->antiColourLine()] = bornPartner->antiColourLine(); } } // require a match if(!matched) break; } // if no match continue if(!matched) continue; // now sort out any decays if(showerTree->outgoingLines().size()+showerTree->incomingLines().size() != newTree.tree()->branchings().size()) { if(showerTree->treelinks().empty()) { matched = false; continue; } // loop over the decay trees for(map >::const_iterator tit=showerTree->treelinks().begin(); tit != showerTree->treelinks().end(); ++tit) { if(tit->first->outgoingLines().empty()) continue; set decayProducts; set branchings = newTree.tree()->branchings(); // match the particles for(map::const_iterator oit=tit->first->outgoingLines().begin(); oit!=tit->first->outgoingLines().end();++oit) { HardBranchingPtr decayProd; Energy2 dmin( 1e30*GeV2 ); tPPtr part = oit->second->original(); for( set< HardBranchingPtr >::iterator it = branchings.begin(); it != branchings.end(); ++it ) { if((**it).status()==HardBranching::Incoming ) continue; if((**it).branchingParticle()->id()!=part->id()) continue; Energy2 dtest = sqr( part->momentum().x() - (**it).branchingParticle()->momentum().x() ) + sqr( part->momentum().y() - (**it).branchingParticle()->momentum().y() ) + sqr( part->momentum().z() - (**it).branchingParticle()->momentum().z() ) + sqr( part->momentum().t() - (**it).branchingParticle()->momentum().t() ); dtest += 1e10*sqr(part->momentum().m()-(**it).branchingParticle()->momentum().m()); if( dtest < dmin ) { decayProd = *it; dmin = dtest; } } if(!decayProd) { throw Exception() << "PowhegShowerHandler::generateCKKW(). Can't match shower and hard trees." << Exception::eventerror; } branchings .erase (decayProd); decayProducts.insert(decayProd); } // erase the decay products Lorentz5Momentum pnew,pshower; for(set::iterator it = decayProducts.begin(); it!=decayProducts.end(); ++it) { newTree.tree()->branchings().erase(*it); pnew += (**it).branchingParticle()->momentum(); pshower += (**it).showerMomentum(); } pnew .setMass(tit->second.second->mass()); pshower.setMass(tit->second.second->mass()); pnew .rescaleEnergy(); pshower.rescaleEnergy(); // create the decaying particle ShowerParticlePtr particle = new_ptr( ShowerParticle( tit->second.second->dataPtr() , true ) ); particle->set5Momentum( pnew ); HardBranchingPtr newBranch = new_ptr( HardBranching( particle, tSudakovPtr(), HardBranchingPtr(), HardBranching::Outgoing ) ); newBranch->showerMomentum(pshower); newTree.tree()->branchings().insert(newBranch); } } // if no match continue if(!matched) continue; // find the colour partners try { - showerModel()->partnerFinder() + partnerFinder() ->setInitialEvolutionScales(branchingParticles,false, ShowerInteraction::QCD,true); } catch( Exception & e ) { generator()->log() << "Problem in set evolution scales in " << "PowhegShowerHandler::doClustering(). Exception was" << e.what(); continue; } for(unsigned int ix=0;ixpartner()) { HardBranchingPtr partner = branchingMap[branchingParticles[ix]->partner()]; branchingMap[branchingParticles[ix]]->colourPartner(partner); } } if(forcePartners_) { locMap[emitter_ ]->colourPartner(locMap[spectator_]); locMap[spectator_]->colourPartner(locMap[emitter_ ]); locMap[emitter_ ]->branchingParticle()->partner(locMap[spectator_]->branchingParticle()); locMap[spectator_]->branchingParticle()->partner(locMap[emitter_ ]->branchingParticle()); } newTree.tree()->partnersSet(true); // set the beam particles PPair beams = lastXCombPtr()->lastParticles(); // remove children of beams PVector beam_children = beams.first->children(); if( (**newTree.tree()->incoming().begin()).branchingParticle()->momentum().z() / beams.first->momentum().z() < 0.) swap( beams.first, beams.second ); set::iterator it = newTree.tree()->incoming().begin(); HardBranchingPtr br = *it; br->beam( beams.first ); while ( !br->children().empty() ) { for(unsigned int ix = 0; ix < br->children().size(); ++ix ) { if( br->children()[ix]->status() == HardBranching::Incoming ) { br = br->children()[ix]; break; } } br->beam( beams.first ); } ++it; br = *it; br->beam( beams.second ); while ( !br->children().empty() ) { for( unsigned int ix = 0; ix < br->children().size(); ++ix ) { if( br->children()[ix]->status() == HardBranching::Incoming ) { br = br->children()[ix]; break; } } br->beam( beams.second ); } // check the emitter and the spectator some how if(iemitter!=emitter_) continue; //do inverse momentum reconstruction - if( !showerModel()->kinematicsReconstructor() + if( !kinematicsReconstructor() ->deconstructHardJets( newTree.tree(), ShowerInteraction::QCD ) ) continue; newTree.tree()->findNodes(); newTree.weight(1.); hardTrees_.push_back( make_pair( newTree, 1. ) ); } // select the tree PotentialTree chosen_hardTree; if (hardTrees_.size()==1) { chosen_hardTree = hardTrees_[0].first; } else { // if multiple trees pick the one with matching // intermediate particle momenta for (unsigned int il=0; il > particles; PotentialTree testTree = hardTrees_[il].first; CKKWTreePtr check = testTree.tree(); // get id and momenta of particles in hard tree for (set< HardBranchingPtr >::iterator it=check->branchings().begin(); it!=check->branchings().end(); ++it) { particles.push_back(make_pair((*it)->branchingParticle()->id(), (*it)->branchingParticle()->momentum())); if (!(*it)->children().empty()){ for (unsigned int ic=0; ic<(*it)->children().size(); ++ic) particles.push_back(make_pair((*it)->children()[ic]->branchingParticle()->id(), (*it)->children()[ic]->branchingParticle()->momentum())); } if ((*it)->parent()){ particles.push_back(make_pair((*it)->parent()->branchingParticle()->id(), (*it)->parent()->branchingParticle()->momentum())); if (!(*it)->parent()->children().empty()) { for (unsigned int ic=0; ic<(*it)->parent()->children().size(); ++ic) { if(*it==(*it)->parent()->children()[ic]) continue; particles.push_back(make_pair((*it)->parent()->children()[ic]->branchingParticle()->id(), (*it)->parent()->children()[ic]->branchingParticle()->momentum())); } } } } // loop through and match to particles in real subprocess vector >::iterator part = particles.begin(); // incoming for (; part!=particles.end(); ++part){ if ((*part).first==real->incoming().first->id() && fuzzyEqual((*part).second, real->incoming().first->momentum())) break; } if (part!=particles.end()) particles.erase(part); part = particles.begin(); for (; part!=particles.end(); ++part){ if ((*part).first==real->incoming().second->id() && fuzzyEqual((*part).second, real->incoming().second->momentum())) break; } if (part!=particles.end()) particles.erase(part); // outgoing for (unsigned int io=0; iooutgoing().size(); ++io){ part = particles.begin(); for (; part!=particles.end(); ++part){ if ((*part).first==real->outgoing()[io]->id() && fuzzyEqual((*part).second, real->outgoing()[io]->momentum())) break; } if (part!=particles.end()) particles.erase(part); } // intermediate for (unsigned int ii=0; iiintermediates().size(); ++ii){ part = particles.begin(); for (; part!=particles.end(); ++part){ if ((*part).first==real->intermediates()[ii]->id() && fuzzyEqual((*part).second, real->intermediates()[ii]->momentum())) break; } if (part!=particles.end()) particles.erase(part); } // intermediate CC with -1*momentum for (unsigned int ii=0; iiintermediates().size(); ++ii){ part = particles.begin(); for (; part!=particles.end(); ++part){ if (!real->intermediates()[ii]->coloured() || (real->intermediates()[ii]->hasColour() && real->intermediates()[ii]->hasAntiColour())){ if ((*part).first==real->intermediates()[ii]->id() && fuzzyEqual((*part).second, -1.*real->intermediates()[ii]->momentum()) ) break; } else { if ((*part).first==-1.*real->intermediates()[ii]->id() && fuzzyEqual((*part).second, -1.*real->intermediates()[ii]->momentum()) ) break; } } if (part!=particles.end()) particles.erase(part); } // if all particles match, set as hardtree if (particles.empty()){ chosen_hardTree = testTree; break; } } } protoBranchings().clear(); protoTrees().clear(); hardTrees_.clear(); if(! chosen_hardTree.tree() ) { return PotentialTree(); } else return chosen_hardTree; } bool PowhegShowerHandler::checkDiagram(PotentialTree & tree, tcDiagPtr loDiagram) const { set::const_iterator cit; tcPDPair incoming; multiset outgoing; //get the incoming and outgoing partons involved in hard process for( cit = tree.tree()->branchings().begin(); cit != tree.tree()->branchings().end(); ++cit ){ if( (*cit)->status() ==HardBranching::Incoming) { HardBranchingPtr parent = *cit; while(parent->parent()) parent = parent->parent(); if( parent->branchingParticle()->momentum().z()>ZERO ) incoming.first = (*cit)->branchingParticle()->dataPtr(); else incoming.second = (*cit)->branchingParticle()->dataPtr(); } else { outgoing.insert( (*cit)->branchingParticle()->dataPtr() ); } } if(!incoming.first || !incoming.second) return 0.; pair tag; tag.first = incoming.first ->PDGName() + "," + incoming.second->PDGName() + "->"; tag.second = incoming.second ->PDGName() + "," + incoming.first ->PDGName() + "->"; string tag_out; for ( multiset::iterator i = outgoing.begin(); i != outgoing.end(); ++i ) { if ( i != outgoing.begin() ) tag_out += ","; tag_out += (**i).PDGName(); } tag.first += tag_out; tag.second += tag_out; // find the diagrams if( tag.first == loDiagram->getTag() || tag.second == loDiagram->getTag() ) tree.diagram(loDiagram); // check this is allowed return tree.diagram(); } void PowhegShowerHandler::fillProtoTrees( ProtoTreePtr currentProtoTree,long id ) const { if(currentProtoTree->branchings().size()==(lastXCombPtr()->subProcess()->outgoing().size()+2)) return; for( set::const_iterator ita = currentProtoTree->branchings().begin(); ita!=currentProtoTree->branchings().end();++ita) { for( set::const_iterator itb = currentProtoTree->branchings().begin(); itb!=ita;++itb) { // can't merge two incoming branchings if( (**ita).status() == HardBranching::Incoming && (**itb).status() == HardBranching::Incoming ) continue; // if branching must be outgoing, skip incoming if(emitter_>=2 && ( (**ita).status() == HardBranching::Incoming || (**itb).status() == HardBranching::Incoming )) continue; // if branching must be incoming, skip outgoing if(emitter_<2 && ( (**ita).status() != HardBranching::Incoming && (**itb).status() != HardBranching::Incoming )) continue; // get a new branching for this pair ProtoBranchingPtr currentBranching = getCluster(*ita,*itb); // check branching with the right PID if( ! currentBranching || currentBranching->id() != id) continue; // branching allowed so make a new Tree out of these branchings set< tProtoBranchingPtr > newTreeBranchings = currentProtoTree->branchings(); newTreeBranchings.erase(*ita); newTreeBranchings.erase(*itb); newTreeBranchings.insert(currentBranching); ProtoTreePtr newProtoTree = new_ptr( ProtoTree( newTreeBranchings ) ); // remove duplicate trees if( ! repeatProtoTree( newProtoTree ) ) protoTrees().insert( newProtoTree ); // remove the current tree if it hasn't already been removed if( protoTrees().find( currentProtoTree ) != protoTrees().end() ) protoTrees().erase( currentProtoTree ); // do recursion fillProtoTrees( newProtoTree , id); } } } bool PowhegShowerHandler::repeatProtoTree( ProtoTreePtr currentProtoTree ) const { // loop over all prototrees and see // how many ProtoBranchings of current ProtoTree are found in each for( set< ProtoTreePtr >::const_iterator cit = protoTrees().begin(); cit != protoTrees().end(); ++cit ) { unsigned int no_matches = 0; for( set< tProtoBranchingPtr >::const_iterator ckt = currentProtoTree->branchings().begin(); ckt != currentProtoTree->branchings().end(); ckt++ ) { if( (*cit)->branchings().find( *ckt ) != (*cit)->branchings().end() ) ++no_matches; } // return true if all match if( no_matches == currentProtoTree->branchings().size() ) return true; } return false; } tProtoBranchingPtr PowhegShowerHandler::getCluster( tProtoBranchingPtr b1, tProtoBranchingPtr b2 ) const { // look for the clustered pair in protoBranchings_ for(set::const_iterator cit = protoBranchings().begin(); cit != protoBranchings().end(); ++cit) { // both outgoing if(b1->status()==HardBranching::Outgoing && b2->status()==HardBranching::Outgoing) { if((**cit).status()!=HardBranching::Outgoing|| (**cit).children().empty()) continue; if( ( b1 == (**cit).children()[0] && b2 == (**cit).children()[1] ) || ( b1 == (**cit).children()[1] && b2 == (**cit).children()[0] ) ) return *cit; } // first incoming else if(b1->status()==HardBranching::Incoming) { if((**cit).backChildren().empty() ) continue; if(b1!=(**cit).backChildren()[0]) continue; if(b2==(**cit).backChildren()[1]) return *cit; } // second incoming else if(b2->status()==HardBranching::Incoming) { if((**cit).backChildren().empty() ) continue; if(b2!=(**cit).backChildren()[0]) continue; if(b1==(**cit).backChildren()[1]) return *cit; } } // is branching incoming or outgoing bool incoming = b1->status()==HardBranching::Incoming || b2->status()==HardBranching::Incoming; // get the branching BranchingElement theBranching; if( !incoming ) theBranching = allowedFinalStateBranching( b1, b2 ); else theBranching = allowedInitialStateBranching( b1, b2 ); //if branching is not allowed return null ProtoBrancing if( !theBranching.sudakov ) return ProtoBranchingPtr(); // get the ParticleData object for the new branching tcPDPtr particle_data = incoming ? theBranching.particles[1] : theBranching.particles[0]; // create clustered ProtoBranching ProtoBranchingPtr clusteredBranch; // outgoing if( !incoming ) { Lorentz5Momentum pairMomentum = b1->momentum() + b2->momentum(); pairMomentum.setMass(ZERO); clusteredBranch = new_ptr(ProtoBranching(particle_data,HardBranching::Outgoing, pairMomentum, theBranching.sudakov)); if(particle_data->iColour()==PDT::Colour0) return ProtoBranchingPtr(); else if(particle_data->iColour()==PDT::Colour3) { if(b1->particle()->iColour()==PDT::Colour3 && b2->particle()->iColour()==PDT::Colour8) { if(b1->colourLine()!=b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch->colourLine(b2->colourLine()); } else if(b2->particle()->iColour()==PDT::Colour3 && b1->particle()->iColour()==PDT::Colour8) { if(b2->colourLine()!=b1->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b1->colourLine()); } else assert(false); clusteredBranch->type(ShowerPartnerType::QCDColourLine); } else if(particle_data->iColour()==PDT::Colour3bar) { if(b1->particle()->iColour()==PDT::Colour3bar && b2->particle()->iColour()==PDT::Colour8) { if(b1->antiColourLine()!=b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b2->antiColourLine()); } else if(b2->particle()->iColour()==PDT::Colour3bar && b1->particle()->iColour()==PDT::Colour8) { if(b2->antiColourLine()!=b1->colourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b1->antiColourLine()); } else assert(false); clusteredBranch->type(ShowerPartnerType::QCDAntiColourLine); } else if(particle_data->iColour()==PDT::Colour8) { tProtoBranchingPtr coloured,antiColoured; if(b1->particle()->iColour()==PDT::Colour3 && b2->particle()->iColour()==PDT::Colour3bar) { coloured = b1; antiColoured = b2; } else if(b2->particle()->iColour()==PDT::Colour3 && b1->particle()->iColour()==PDT::Colour3bar) { coloured = b2; antiColoured = b1; } else if(b1->particle()->iColour()==PDT::Colour8 && b2->particle()->iColour()==PDT::Colour8 ) { if(b1->colourLine()==b2->antiColourLine()) { coloured = b2; antiColoured = b1; } else if(b2->colourLine()==b1->antiColourLine()) { coloured = b1; antiColoured = b2; } else return ProtoBranchingPtr(); } else assert(false); // can't have colour self connected gluons if(coloured-> colourLine()==antiColoured->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine( coloured-> colourLine()); clusteredBranch->antiColourLine(antiColoured->antiColourLine()); // softest particle is the emitted if(coloured->momentum().t()>antiColoured->momentum().t()) { clusteredBranch->type(ShowerPartnerType::QCDAntiColourLine); } else { clusteredBranch->type(ShowerPartnerType::QCDColourLine); } } else assert(false); } // incoming else { Lorentz5Momentum pairMomentum = b1->momentum() - b2->momentum(); pairMomentum.setMass( ZERO ); // check for CC if( particle_data->CC() && ( b1->id() != theBranching.particles[0]->id() || b2->id() != theBranching.particles[2]->id() ) ) { particle_data = particle_data->CC(); } clusteredBranch = new_ptr(ProtoBranching(particle_data,HardBranching::Incoming, pairMomentum,theBranching.sudakov)); // work out the type of branching if(b1->particle()->iColour()==PDT::Colour3) { b1->type(ShowerPartnerType::QCDColourLine); if(b2->particle()->iColour()==PDT::Colour3 && particle_data->iColour()==PDT::Colour8) { if(b1->colourLine()==b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine(b1->colourLine()); clusteredBranch->antiColourLine(b2->colourLine()); } else if(b2->particle()->iColour()==PDT::Colour8 && particle_data->iColour()==PDT::Colour3) { if(b1->colourLine()!=b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch->colourLine(b2->antiColourLine()); } else assert(false); } else if(b1->particle()->iColour()==PDT::Colour3bar) { b1->type(ShowerPartnerType::QCDAntiColourLine); if(b2->particle()->iColour()==PDT::Colour3bar && particle_data->iColour()==PDT::Colour8) { if(b1->antiColourLine()==b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine(b2->antiColourLine()); clusteredBranch->antiColourLine(b1->antiColourLine()); } else if(b2->particle()->iColour()==PDT::Colour8 && particle_data->iColour()==PDT::Colour3bar) { if(b1->antiColourLine()!=b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b2->colourLine()); } else assert(false); } else if(b1->particle()->iColour()==PDT::Colour8) { if(b2->particle()->iColour()==PDT::Colour3) { if(b1->colourLine()!=b2->colourLine()) return ProtoBranchingPtr(); clusteredBranch->antiColourLine(b1->antiColourLine()); b1->type(ShowerPartnerType::QCDColourLine); } else if(b2->particle()->iColour()==PDT::Colour3bar) { if(b1->antiColourLine()!=b2->antiColourLine()) return ProtoBranchingPtr(); clusteredBranch-> colourLine(b1->colourLine()); b1->type(ShowerPartnerType::QCDAntiColourLine); } else if(b2->particle()->iColour()==PDT::Colour8) { if(b1->colourLine()==b2->colourLine()) { b1->type(ShowerPartnerType::QCDColourLine); clusteredBranch->antiColourLine(b1->antiColourLine()); clusteredBranch->colourLine(b2->antiColourLine()); } else if(b1->antiColourLine()==b2->antiColourLine()) { b1->type(ShowerPartnerType::QCDAntiColourLine); clusteredBranch-> colourLine(b1->colourLine()); clusteredBranch->antiColourLine(b2->colourLine()); } else { return ProtoBranchingPtr(); } } else assert(false); } else assert(false); } protoBranchings().insert(clusteredBranch); //set children relations // outgoing if( !incoming ){ clusteredBranch->addChild( b1 ); clusteredBranch->addChild( b2 ); } else { clusteredBranch->addBackChild( b1 ); clusteredBranch->addBackChild( b2 ); } return clusteredBranch; } BranchingElement PowhegShowerHandler:: allowedFinalStateBranching( tProtoBranchingPtr & b1, tProtoBranchingPtr & b2) const { // check with normal ID's pair< long, long > ptest = make_pair( b1->id(), b2->id() ); map< pair< long, long >, BranchingElement >::const_iterator split = allowedFinal_.find(ptest); if( split != allowedFinal_.end() ) { if( split->second.particles[1]->id() != ptest.first ) swap( b1, b2 ); return split->second; } // check with CC if( b1->particle()->CC() ) ptest.first *= -1; if( b2->particle()->CC() ) ptest.second *= -1; split = allowedFinal_.find( ptest ); if( split != allowedFinal_.end() ) { // cc the idlist only be for qbar g clusterings BranchingElement ccBranch = split->second; swap(ccBranch.particles,ccBranch.conjugateParticles); if( split->second.particles[1]->id() != ptest.first ) swap( b1, b2); return ccBranch; } // not found found null pointer return BranchingElement(); } BranchingElement PowhegShowerHandler::allowedInitialStateBranching( tProtoBranchingPtr & b1, tProtoBranchingPtr & b2) const { if(b2->status()==HardBranching::Incoming) swap(b1,b2); // is initial parton an antiparticle bool cc = b1->id() < 0; //gives range of allowedInitial_ with matching first abs( id ) pair< multimap< long, BranchingElement >::const_iterator, multimap< long, BranchingElement >::const_iterator > location = allowedInitial_.equal_range( abs( b1->id() ) ); //iterates over this range for( multimap< long, BranchingElement >::const_iterator it = location.first; it != location.second; ++it ) { //test id for second particle in pair long idtest = cc ? it->second.conjugateParticles[2]->id() : it->second.particles[2]->id(); // does second id match the test if( idtest == b2->id() ) return it->second; //if the the IS parton is a gluon and charge conjugate of second parton mathes accept if( idtest == -b2->id() && ! b1->particle()->CC() ) return it->second; } // not found found null pointer return BranchingElement(); } bool PowhegShowerHandler::fuzzyEqual(Lorentz5Momentum a, Lorentz5Momentum b) const{ // check momenta are within 1% of each other if ( (a.e()==ZERO && b.e()==ZERO) || (a.e()/b.e()>0.99 && a.e()/b.e()<1.01) ){ if ((a.x()==ZERO && b.x()==ZERO) || (a.x()/b.x()>0.99 && a.x()/b.x()<1.01) ){ if ((a.y()==ZERO && b.y()==ZERO) || (a.y()/b.y()>0.99 && a.y()/b.y()<1.01) ){ if ((a.z()==ZERO && b.z()==ZERO) || (a.z()/b.z()>0.99 && a.z()/b.z()<1.01) ) return true; } } } return false; } void PowhegShowerHandler::doinit() { QTildeShowerHandler::doinit(); // extract the allowed branchings // final-state for(BranchingList::const_iterator it = splittingGenerator()->finalStateBranchings().begin(); it != splittingGenerator()->finalStateBranchings().end(); ++it) { pair prod(make_pair(it->second.particles[1]->id(), it->second.particles[2]->id())); allowedFinal_.insert(make_pair(prod,it->second)); swap(prod.first,prod.second); allowedFinal_.insert(make_pair(prod,it->second)); } // initial-state for(BranchingList::const_iterator it = splittingGenerator()->initialStateBranchings().begin(); it != splittingGenerator()->initialStateBranchings().end(); ++it) { allowedInitial_.insert(make_pair(it->second.particles[0]->id(),it->second)); } } void PowhegShowerHandler::persistentOutput(PersistentOStream & os) const { os << allowedInitial_ << allowedFinal_ << subtractionIntegral_ << enforceColourConsistency_ << forcePartners_ << decayRadiation_; } void PowhegShowerHandler::persistentInput(PersistentIStream & is, int) { is >> allowedInitial_ >> allowedFinal_ >> subtractionIntegral_ >> enforceColourConsistency_ >> forcePartners_ >> decayRadiation_; } // Static variable needed for the type description system in ThePEG. DescribeClass describeHerwigPowhegShowerHandler("Herwig::PowhegShowerHandler", "HwMatchbox.so HwMatching.so"); void PowhegShowerHandler::Init() { static ClassDocumentation documentation ("The PowhegShowerHandler class"); static Switch interfaceEnforceColourConsistency ("EnforceColourConsistency", "Force the Born and real emission colour flows to be consistent", &PowhegShowerHandler::enforceColourConsistency_, false, false, false); static SwitchOption interfaceEnforceColourConsistencyYes (interfaceEnforceColourConsistency, "Yes", "Enforce the consistency", true); static SwitchOption interfaceEnforceColourConsistencyNo (interfaceEnforceColourConsistency, "No", "Don't enforce consistency", false); static Switch interfaceForcePartners ("ForcePartners", "Whether or not to force the partners to be those from the kinematic generation", &PowhegShowerHandler::forcePartners_, false, false, false); static SwitchOption interfaceForcePartnersYes (interfaceForcePartners, "Yes", "Force them", true); static SwitchOption interfaceForcePartnersNo (interfaceForcePartners, "No", "Don't force them", false); static Switch interfaceDecayRadiation ("DecayRadiation", "Handling of radiation which is interpretted as having come from decays", &PowhegShowerHandler::decayRadiation_, 0, false,false); static SwitchOption interfaceDecayRadiationNotAllowed (interfaceDecayRadiation, "NotAllowed", "Not allowed at all, run error will be thrown", 0); static SwitchOption interfaceDecayRadiationVetoEvent (interfaceDecayRadiation, "VetoEvent", "Veto the whole event", 1); static SwitchOption interfaceDecayRadiationVetoRadiation (interfaceDecayRadiation, "VetoRadiation", "Throw the radiation away but keep the event", 2); } diff --git a/Shower/QTilde/QTildeShowerHandler.cc b/Shower/QTilde/QTildeShowerHandler.cc --- a/Shower/QTilde/QTildeShowerHandler.cc +++ b/Shower/QTilde/QTildeShowerHandler.cc @@ -1,3743 +1,3218 @@ // -*- C++ -*- // // QTildeShowerHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 QTildeShowerHandler class. // #include "QTildeShowerHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/RefVector.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/EventRecord/Particle.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Repository/EventGenerator.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Utilities/EnumIO.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "Herwig/PDF/MPIPDF.h" #include "Herwig/PDF/MinBiasPDF.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" #include "Herwig/Shower/QTilde/Base/HardTree.h" -#include "Herwig/Shower/QTilde/Base/KinematicsReconstructor.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.h" #include "Herwig/Shower/QTilde/Base/PartnerFinder.h" #include "Herwig/PDF/HwRemDecayer.h" #include "Herwig/Shower/QTilde/Base/ShowerVertex.h" #include "ThePEG/Repository/CurrentGenerator.h" #include "Herwig/MatrixElement/Matchbox/Base/SubtractedME.h" #include "Herwig/MatrixElement/Matchbox/MatchboxFactory.h" #include "ThePEG/PDF/PartonExtractor.h" #include "Herwig/Shower/RealEmissionProcess.h" +#include "Herwig/Shower/QTilde/Kinematics/FS_QTildeShowerKinematics1to2.h" +#include "Herwig/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.h" +#include "Herwig/Shower/QTilde/Kinematics/Decay_QTildeShowerKinematics1to2.h" + using namespace Herwig; bool QTildeShowerHandler::_hardEmissionWarn = true; bool QTildeShowerHandler::_missingTruncWarn = true; QTildeShowerHandler::QTildeShowerHandler() : _maxtry(100), _meCorrMode(1), _reconOpt(0), _hardVetoReadOption(false), _iptrms(ZERO), _beta(0.), _gamma(ZERO), _iptmax(), _limitEmissions(0), _initialenhance(1.), _finalenhance(1.), _nReWeight(100), _reWeight(false), interaction_(ShowerInteraction::QEDQCD), _trunc_Mode(true), _hardEmission(1), - _spinOpt(1), _softOpt(2), _hardPOWHEG(false), muPt(ZERO), - _maxTryFSR(100000), _maxFailFSR(100), _fracFSR(0.001), - _nFSR(0), _nFailedFSR(0) + _softOpt(2), _hardPOWHEG(false), muPt(ZERO) {} QTildeShowerHandler::~QTildeShowerHandler() {} IBPtr QTildeShowerHandler::clone() const { return new_ptr(*this); } IBPtr QTildeShowerHandler::fullclone() const { return new_ptr(*this); } void QTildeShowerHandler::persistentOutput(PersistentOStream & os) const { - os << _model << _splittingGenerator << _maxtry + os << _splittingGenerator << _maxtry << _meCorrMode << _hardVetoReadOption - << _limitEmissions << _spinOpt << _softOpt << _hardPOWHEG + << _limitEmissions << _softOpt << _hardPOWHEG << ounit(_iptrms,GeV) << _beta << ounit(_gamma,GeV) << ounit(_iptmax,GeV) << _vetoes << _fullShowerVetoes << _nReWeight << _reWeight << _trunc_Mode << _hardEmission << _reconOpt - << ounit(muPt,GeV) - << oenum(interaction_) << _maxTryFSR << _maxFailFSR << _fracFSR; + << ounit(muPt,GeV) << oenum(interaction_) + << _reconstructor << _partnerfinder; } void QTildeShowerHandler::persistentInput(PersistentIStream & is, int) { - is >> _model >> _splittingGenerator >> _maxtry + is >> _splittingGenerator >> _maxtry >> _meCorrMode >> _hardVetoReadOption - >> _limitEmissions >> _spinOpt >> _softOpt >> _hardPOWHEG + >> _limitEmissions >> _softOpt >> _hardPOWHEG >> iunit(_iptrms,GeV) >> _beta >> iunit(_gamma,GeV) >> iunit(_iptmax,GeV) >> _vetoes >> _fullShowerVetoes >> _nReWeight >> _reWeight >> _trunc_Mode >> _hardEmission >> _reconOpt - >> iunit(muPt,GeV) - >> ienum(interaction_) >> _maxTryFSR >> _maxFailFSR >> _fracFSR; + >> iunit(muPt,GeV) >> ienum(interaction_) + >> _reconstructor >> _partnerfinder; } // The following static variable is needed for the type // description system in ThePEG. DescribeClass describeHerwigQTildeShowerHandler("Herwig::QTildeShowerHandler", "HwShower.so"); void QTildeShowerHandler::Init() { static ClassDocumentation documentation ("TheQTildeShowerHandler class is the main class" " for the angular-ordered parton shower", "The Shower evolution was performed using an algorithm described in " "\\cite{Marchesini:1983bm,Marchesini:1987cf,Gieseke:2003rz,Bahr:2008pv}.", "%\\cite{Marchesini:1983bm}\n" "\\bibitem{Marchesini:1983bm}\n" " G.~Marchesini and B.~R.~Webber,\n" " ``Simulation Of QCD Jets Including Soft Gluon Interference,''\n" " Nucl.\\ Phys.\\ B {\\bf 238}, 1 (1984).\n" " %%CITATION = NUPHA,B238,1;%%\n" "%\\cite{Marchesini:1987cf}\n" "\\bibitem{Marchesini:1987cf}\n" " G.~Marchesini and B.~R.~Webber,\n" " ``Monte Carlo Simulation of General Hard Processes with Coherent QCD\n" " Radiation,''\n" " Nucl.\\ Phys.\\ B {\\bf 310}, 461 (1988).\n" " %%CITATION = NUPHA,B310,461;%%\n" "%\\cite{Gieseke:2003rz}\n" "\\bibitem{Gieseke:2003rz}\n" " S.~Gieseke, P.~Stephens and B.~Webber,\n" " ``New formalism for QCD parton showers,''\n" " JHEP {\\bf 0312}, 045 (2003)\n" " [arXiv:hep-ph/0310083].\n" " %%CITATION = JHEPA,0312,045;%%\n" ); static Reference interfaceSplitGen("SplittingGenerator", "A reference to the SplittingGenerator object", &Herwig::QTildeShowerHandler::_splittingGenerator, false, false, true, false); - static Reference interfaceShowerModel - ("ShowerModel", - "The pointer to the object which defines the shower evolution model.", - &QTildeShowerHandler::_model, false, false, true, false, false); - static Parameter interfaceMaxTry ("MaxTry", "The maximum number of attempts to generate the shower from a" " particular ShowerTree", &QTildeShowerHandler::_maxtry, 100, 1, 100000, false, false, Interface::limited); static Parameter interfaceNReWeight ("NReWeight", "The number of attempts for the shower when reweighting", &QTildeShowerHandler::_nReWeight, 100, 10, 10000, false, false, Interface::limited); static Switch ifaceMECorrMode ("MECorrMode", "Choice of the ME Correction Mode", &QTildeShowerHandler::_meCorrMode, 1, false, false); static SwitchOption on (ifaceMECorrMode,"HardPlusSoft","hard+soft on", 1); static SwitchOption hard (ifaceMECorrMode,"Hard","only hard on", 2); static SwitchOption soft (ifaceMECorrMode,"Soft","only soft on", 3); static Switch ifaceHardVetoReadOption ("HardVetoReadOption", "Apply read-in scale veto to all collisions or just the primary one?", &QTildeShowerHandler::_hardVetoReadOption, false, false, false); static SwitchOption AllCollisions (ifaceHardVetoReadOption, "AllCollisions", "Read-in pT veto applied to primary and secondary collisions.", false); static SwitchOption PrimaryCollision (ifaceHardVetoReadOption, "PrimaryCollision", "Read-in pT veto applied to primary but not secondary collisions.", true); static Parameter ifaceiptrms ("IntrinsicPtGaussian", "RMS of intrinsic pT of Gaussian distribution:\n" "2*(1-Beta)*exp(-sqr(intrinsicpT/RMS))/sqr(RMS)", &QTildeShowerHandler::_iptrms, GeV, ZERO, ZERO, 1000000.0*GeV, false, false, Interface::limited); static Parameter ifacebeta ("IntrinsicPtBeta", "Proportion of inverse quadratic distribution in generating intrinsic pT.\n" "(1-Beta) is the proportion of Gaussian distribution", &QTildeShowerHandler::_beta, 0, 0, 1, false, false, Interface::limited); static Parameter ifacegamma ("IntrinsicPtGamma", "Parameter for inverse quadratic:\n" "2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT))", &QTildeShowerHandler::_gamma,GeV, ZERO, ZERO, 100000.0*GeV, false, false, Interface::limited); static Parameter ifaceiptmax ("IntrinsicPtIptmax", "Upper bound on intrinsic pT for inverse quadratic", &QTildeShowerHandler::_iptmax,GeV, ZERO, ZERO, 100000.0*GeV, false, false, Interface::limited); static RefVector ifaceVetoes ("Vetoes", "The vetoes to be checked during showering", &QTildeShowerHandler::_vetoes, -1, false,false,true,true,false); static RefVector interfaceFullShowerVetoes ("FullShowerVetoes", "The vetos to be appliede on the full final state of the shower", &QTildeShowerHandler::_fullShowerVetoes, -1, false, false, true, false, false); static Switch interfaceLimitEmissions ("LimitEmissions", "Limit the number and type of emissions for testing", &QTildeShowerHandler::_limitEmissions, 0, false, false); static SwitchOption interfaceLimitEmissionsNoLimit (interfaceLimitEmissions, "NoLimit", "Allow an arbitrary number of emissions", 0); static SwitchOption interfaceLimitEmissionsOneInitialStateEmission (interfaceLimitEmissions, "OneInitialStateEmission", "Allow one emission in the initial state and none in the final state", 1); static SwitchOption interfaceLimitEmissionsOneFinalStateEmission (interfaceLimitEmissions, "OneFinalStateEmission", "Allow one emission in the final state and none in the initial state", 2); static SwitchOption interfaceLimitEmissionsHardOnly (interfaceLimitEmissions, "HardOnly", "Only allow radiation from the hard ME correction", 3); static SwitchOption interfaceLimitEmissionsOneEmission (interfaceLimitEmissions, "OneEmission", "Allow one emission in either the final state or initial state, but not both", 4); static Switch interfaceTruncMode ("TruncatedShower", "Include the truncated shower?", &QTildeShowerHandler::_trunc_Mode, 1, false, false); static SwitchOption interfaceTruncMode0 (interfaceTruncMode,"No","Truncated Shower is OFF", 0); static SwitchOption interfaceTruncMode1 (interfaceTruncMode,"Yes","Truncated Shower is ON", 1); static Switch interfaceHardEmission ("HardEmission", "Whether to use ME corrections or POWHEG for the hardest emission", &QTildeShowerHandler::_hardEmission, 0, false, false); static SwitchOption interfaceHardEmissionNone (interfaceHardEmission, "None", "No Corrections", 0); static SwitchOption interfaceHardEmissionMECorrection (interfaceHardEmission, "MECorrection", "Old fashioned ME correction", 1); static SwitchOption interfaceHardEmissionPOWHEG (interfaceHardEmission, "POWHEG", "Powheg style hard emission", 2); static Switch interfaceInteractions ("Interactions", "The interactions to be used in the shower", &QTildeShowerHandler::interaction_, ShowerInteraction::QEDQCD, false, false); static SwitchOption interfaceInteractionsQCD (interfaceInteractions, "QCD", "Only QCD radiation", ShowerInteraction::QCD); static SwitchOption interfaceInteractionsQED (interfaceInteractions, "QED", "Only QEd radiation", ShowerInteraction::QED); static SwitchOption interfaceInteractionEWOnly (interfaceInteractions, "EWOnly", "Only EW", ShowerInteraction::EW); static SwitchOption interfaceInteractionQEDQCD (interfaceInteractions, "QEDQCD", "QED and QCD", ShowerInteraction::QEDQCD); static SwitchOption interfaceInteractionALL (interfaceInteractions, "ALL", "QED, QCD and EW", ShowerInteraction::ALL); static Switch interfaceReconstructionOption ("ReconstructionOption", "Treatment of the reconstruction of the transverse momentum of " "a branching from the evolution scale.", &QTildeShowerHandler::_reconOpt, 0, false, false); static SwitchOption interfaceReconstructionOptionCutOff (interfaceReconstructionOption, "CutOff", "Use the cut-off masses in the calculation", 0); - static SwitchOption interfaceReconstructionOptionOffShell - (interfaceReconstructionOption, - "OffShell", - "Use the off-shell masses in the calculation veto the emission of the parent," - " no veto in generation of emissions from children", - 1); - static SwitchOption interfaceReconstructionOptionOffShell2 - (interfaceReconstructionOption, - "OffShell2", - "Use the off-shell masses in the calculation veto the emissions from the children." - " no veto in generation of emissions from children", - 2); - static SwitchOption interfaceReconstructionOptionOffShell3 - (interfaceReconstructionOption, - "OffShell3", - "Use the off-shell masses in the calculation veto the emissions from the children." - " veto in generation of emissions from children using cut-off for second parton", - 3); - static SwitchOption interfaceReconstructionOptionOffShell4 - (interfaceReconstructionOption, - "OffShell4", - "As OffShell3 but with a restriction on the mass of final-state" - " jets produced via backward evolution.", - 4); static SwitchOption interfaceReconstructionOptionOffShell5 (interfaceReconstructionOption, "OffShell5", "Try and preserve q2 but if pt negative just zero it", 5); - static Switch interfaceSpinCorrelations - ("SpinCorrelations", - "Treatment of spin correlations in the parton shower", - &QTildeShowerHandler::_spinOpt, 1, false, false); - static SwitchOption interfaceSpinCorrelationsNo - (interfaceSpinCorrelations, - "No", - "No spin correlations", - 0); - static SwitchOption interfaceSpinCorrelationsSpin - (interfaceSpinCorrelations, - "Yes", - "Include the azimuthal spin correlations only", - 1); - static Switch interfaceSoftCorrelations ("SoftCorrelations", "Option for the treatment of soft correlations in the parton shower", &QTildeShowerHandler::_softOpt, 2, false, false); static SwitchOption interfaceSoftCorrelationsNone (interfaceSoftCorrelations, "No", "No soft correlations", 0); static SwitchOption interfaceSoftCorrelationsFull (interfaceSoftCorrelations, "Full", "Use the full eikonal", 1); static SwitchOption interfaceSoftCorrelationsSingular (interfaceSoftCorrelations, "Singular", "Use original Webber-Marchisini form", 2); static Switch interfaceHardPOWHEG ("HardPOWHEG", "Treatment of powheg emissions which are too hard to have a shower interpretation", &QTildeShowerHandler::_hardPOWHEG, false, false, false); static SwitchOption interfaceHardPOWHEGAsShower (interfaceHardPOWHEG, "AsShower", "Still interpret as shower emissions", false); static SwitchOption interfaceHardPOWHEGRealEmission (interfaceHardPOWHEG, "RealEmission", "Generate shower from the real emmission configuration", true); - static Parameter interfaceMaxTryFSR - ("MaxTryFSR", - "The maximum number of attempted FSR emissions in" - " the generation of the FSR", - &QTildeShowerHandler::_maxTryFSR, 100000, 10, 100000000, - false, false, Interface::limited); + static Reference interfaceKinematicsReconstructor + ("KinematicsReconstructor", + "Reference to the KinematicsReconstructor object", + &QTildeShowerHandler::_reconstructor, false, false, true, false, false); - static Parameter interfaceMaxFailFSR - ("MaxFailFSR", - "Maximum number of failures generating the FSR", - &QTildeShowerHandler::_maxFailFSR, 100, 1, 100000000, - false, false, Interface::limited); - - static Parameter interfaceFSRFailureFraction - ("FSRFailureFraction", - "Maximum fraction of events allowed to fail due to too many FSR emissions", - &QTildeShowerHandler::_fracFSR, 0.001, 1e-10, 1, - false, false, Interface::limited); + static Reference interfacePartnerFinder + ("PartnerFinder", + "Reference to the PartnerFinder object", + &QTildeShowerHandler::_partnerfinder, false, false, true, false, false); } tPPair QTildeShowerHandler::cascade(tSubProPtr sub, XCPtr xcomb) { // use me for reference in tex file etc useMe(); prepareCascade(sub); // set things up in the base class resetWeights(); hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); // start of the try block for the whole showering process unsigned int countFailures=0; while (countFailuresoutgoing().begin(), currentSubProcess()->outgoing().end()), hard,decay); ShowerTree::constructTrees(hard_,decay_,hard,decay); // if no hard process if(!hard_) throw Exception() << "Shower starting with a decay" << "is not implemented" << Exception::runerror; // perform the shower for the hard process showerHardProcess(hard_,xcomb); done_.push_back(hard_); hard_->updateAfterShower(decay_); // if no decaying particles to shower break out of the loop if(decay_.empty()) break; // shower the decay products while(!decay_.empty()) { // find particle whose production process has been showered ShowerDecayMap::iterator dit = decay_.begin(); while(!dit->second->parent()->hasShowered() && dit!=decay_.end()) ++dit; assert(dit!=decay_.end()); // get the particle ShowerTreePtr decayingTree = dit->second; // remove it from the multimap decay_.erase(dit); // make sure the particle has been decayed QTildeShowerHandler::decay(decayingTree,decay_); // now shower the decay showerDecay(decayingTree); done_.push_back(decayingTree); decayingTree->updateAfterShower(decay_); } // suceeded break out of the loop break; } catch (KinematicsReconstructionVeto) { resetWeights(); ++countFailures; } catch ( ... ) { hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); throw; } } // if loop exited because of too many tries, throw event away if (countFailures >= maxtry()) { resetWeights(); hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); throw Exception() << "Too many tries for main while loop " << "in QTildeShowerHandler::cascade()." << Exception::eventerror; } //enter the particles in the event record fillEventRecord(); // clear storage hard_=ShowerTreePtr(); decay_.clear(); done_.clear(); // non hadronic case return if (!isResolvedHadron(incomingBeams().first ) && !isResolvedHadron(incomingBeams().second) ) return incomingBeams(); // remake the remnants (needs to be after the colours are sorted // out in the insertion into the event record) if ( firstInteraction() ) return remakeRemnant(sub->incoming()); //Return the new pair of incoming partons. remakeRemnant is not //necessary here, because the secondary interactions are not yet //connected to the remnants. return make_pair(findFirstParton(sub->incoming().first ), findFirstParton(sub->incoming().second)); } void QTildeShowerHandler::fillEventRecord() { // create a new step StepPtr pstep = newStep(); assert(!done_.empty()); assert(done_[0]->isHard()); // insert the steps for(unsigned int ix=0;ixfillEventRecord(pstep,doISR(),doFSR()); } } HardTreePtr QTildeShowerHandler::generateCKKW(ShowerTreePtr ) const { return HardTreePtr(); } void QTildeShowerHandler::doinit() { ShowerHandler::doinit(); - // interactions may have been changed through a setup file so we - // clear it up here - // calculate max no of FSR vetos - _maxFailFSR = max(int(_maxFailFSR), int(_fracFSR*double(generator()->N()))); // check on the reweighting for(unsigned int ix=0;ix<_fullShowerVetoes.size();++ix) { if(_fullShowerVetoes[ix]->behaviour()==1) { _reWeight = true; break; } } if(_reWeight && maximumTries()<_nReWeight) { throw Exception() << "Reweight being performed in the shower but the number of attempts for the" << "shower is less than that for the reweighting.\n" << "Maximum number of attempt for the shower " << fullName() << ":MaxTry is " << maximumTries() << "\nand for reweighting is " << fullName() << ":NReWeight is " << _nReWeight << "\n" << "we recommend the number of attempts is 10 times the number for reweighting\n" << Exception::runerror; } ShowerTree::_vmin2 = vMin(); ShowerTree::_spaceTime = includeSpaceTime(); } void QTildeShowerHandler::doinitrun() { ShowerHandler::doinitrun(); ShowerTree::_vmin2 = vMin(); ShowerTree::_spaceTime = includeSpaceTime(); } void QTildeShowerHandler::generateIntrinsicpT(vector particlesToShower) { _intrinsic.clear(); if ( !ipTon() || !doISR() ) return; // don't do anything for the moment for secondary scatters if( !firstInteraction() ) return; // generate intrinsic pT for(unsigned int ix=0;ixprogenitor()->isFinalState()) continue; if(!particlesToShower[ix]->progenitor()->dataPtr()->coloured()) continue; Energy ipt; if(UseRandom::rnd() > _beta) { ipt=_iptrms*sqrt(-log(UseRandom::rnd())); } else { ipt=_gamma*sqrt(pow(1.+sqr(_iptmax/_gamma), UseRandom::rnd())-1.); } pair pt = make_pair(ipt,UseRandom::rnd(Constants::twopi)); _intrinsic[particlesToShower[ix]] = pt; } } void QTildeShowerHandler::setupMaximumScales(const vector & p, XCPtr xcomb) { // let POWHEG events radiate freely if(_hardEmission==2&&hardTree()) { vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(Constants::MaxEnergy); return; } // return if no vetos if (!restrictPhasespace()) return; // find out if hard partonic subprocess. bool isPartonic(false); map::const_iterator cit = _currenttree->incomingLines().begin(); Lorentz5Momentum pcm; for(; cit!=currentTree()->incomingLines().end(); ++cit) { pcm += cit->first->progenitor()->momentum(); isPartonic |= cit->first->progenitor()->coloured(); } // find minimum pt from hard process, the maximum pt from all outgoing // coloured lines (this is simpler and more general than // 2stu/(s^2+t^2+u^2)). Maximum scale for scattering processes will // be transverse mass. Energy ptmax = generator()->maximumCMEnergy(); // general case calculate the scale if ( !hardScaleIsMuF() || (hardVetoReadOption()&&!firstInteraction()) ) { // scattering process if(currentTree()->isHard()) { assert(xcomb); // coloured incoming particles if (isPartonic) { map::const_iterator cjt = currentTree()->outgoingLines().begin(); for(; cjt!=currentTree()->outgoingLines().end(); ++cjt) { if (cjt->first->progenitor()->coloured()) ptmax = min(ptmax,cjt->first->progenitor()->momentum().mt()); } } if (ptmax == generator()->maximumCMEnergy() ) ptmax = pcm.m(); if(hardScaleIsMuF()&&hardVetoReadOption()&& !firstInteraction()) { ptmax=min(ptmax,sqrt(xcomb->lastShowerScale())); } } // decay, incoming() is the decaying particle. else { ptmax = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } } // hepeup.SCALUP is written into the lastXComb by the // LesHouchesReader itself - use this by user's choice. // Can be more general than this. else { if(currentTree()->isHard()) { assert(xcomb); ptmax = sqrt( xcomb->lastShowerScale() ); } else { ptmax = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } } ptmax *= hardScaleFactor(); // set maxHardPt for all progenitors. For partonic processes this // is now the max pt in the FS, for non-partonic processes or // processes with no coloured FS the invariant mass of the IS vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->maxHardPt(ptmax); } void QTildeShowerHandler::setupHardScales(const vector & p, XCPtr xcomb) { if ( hardScaleIsMuF() && (!hardVetoReadOption() || firstInteraction()) ) { Energy hardScale = ZERO; if(currentTree()->isHard()) { assert(xcomb); hardScale = sqrt( xcomb->lastShowerScale() ); } else { hardScale = currentTree()->incomingLines().begin()->first ->progenitor()->momentum().mass(); } hardScale *= hardScaleFactor(); vector::const_iterator ckt = p.begin(); for (; ckt != p.end(); ckt++) (*ckt)->hardScale(hardScale); muPt = hardScale; } } void QTildeShowerHandler::showerHardProcess(ShowerTreePtr hard, XCPtr xcomb) { _hardme = HwMEBasePtr(); // extract the matrix element tStdXCombPtr lastXC = dynamic_ptr_cast(xcomb); if(lastXC) { _hardme = dynamic_ptr_cast(lastXC->matrixElement()); } _decayme = HwDecayerBasePtr(); // set the current tree currentTree(hard); hardTree(HardTreePtr()); // work out the type of event currentTree()->xcombPtr(dynamic_ptr_cast(xcomb)); currentTree()->identifyEventType(); checkFlags(); // generate the showering doShowering(true,xcomb); } RealEmissionProcessPtr QTildeShowerHandler::hardMatrixElementCorrection(bool hard) { // set the initial enhancement factors for the soft correction _initialenhance = 1.; _finalenhance = 1.; // see if we can get the correction from the matrix element // or decayer RealEmissionProcessPtr real; if(hard) { if(_hardme&&_hardme->hasMECorrection()) { _hardme->initializeMECorrection(_currenttree->perturbativeProcess(), _initialenhance,_finalenhance); if(hardMEC()) real = _hardme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess()); } } else { if(_decayme&&_decayme->hasMECorrection()) { _decayme->initializeMECorrection(_currenttree->perturbativeProcess(), _initialenhance,_finalenhance); if(hardMEC()) real = _decayme->applyHardMatrixElementCorrection(_currenttree->perturbativeProcess()); } } return real; } ShowerParticleVector QTildeShowerHandler::createTimeLikeChildren(tShowerParticlePtr, IdList ids) { // Create the ShowerParticle objects for the two children of // the emitting particle; set the parent/child relationship // if same as definition create particles, otherwise create cc ShowerParticleVector children; for(unsigned int ix=0;ix<2;++ix) { children.push_back(new_ptr(ShowerParticle(ids[ix+1],true))); if(children[ix]->id()==_progenitor->id()&&!ids[ix+1]->stable()&&abs(ids[ix+1]->id())!=ParticleID::tauminus) children[ix]->set5Momentum(Lorentz5Momentum(_progenitor->progenitor()->mass())); else children[ix]->set5Momentum(Lorentz5Momentum(ids[ix+1]->mass())); } return children; } bool QTildeShowerHandler::timeLikeShower(tShowerParticlePtr particle, ShowerInteraction type, Branching fb, bool first) { // don't do anything if not needed if(_limitEmissions == 1 || hardOnly() || ( _limitEmissions == 2 && _nfs != 0) || ( _limitEmissions == 4 && _nfs + _nis != 0) ) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } - // too many tries - if(_nFSR>=_maxTryFSR) { - ++_nFailedFSR; - // too many failed events - if(_nFailedFSR>=_maxFailFSR) - throw Exception() << "Too many events have failed due to too many shower emissions, in\n" - << "QTildeShowerHandler::timeLikeShower(). Terminating run\n" - << Exception::runerror; - throw Exception() << "Too many attempted emissions in QTildeShowerHandler::timeLikeShower()\n" - << Exception::eventerror; - } // generate the emission ShowerParticleVector children; - int ntry=0; // generate the emission if(!fb.kinematics) fb = selectTimeLikeBranching(particle,type,HardBranchingPtr()); // no emission, return if(!fb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } - Branching fc[2]; - bool setupChildren = true; - while (ntry<50) { - fc[0] = Branching(); - fc[1] = Branching(); - ++ntry; - assert(fb.kinematics); - // has emitted - // Assign the shower kinematics to the emitting particle. - if(setupChildren) { - ++_nFSR; - particle->showerKinematics(fb.kinematics); - // check highest pT - if(fb.kinematics->pT()>progenitor()->highestpT()) - progenitor()->highestpT(fb.kinematics->pT()); - // create the children - children = createTimeLikeChildren(particle,fb.ids); - // update the children - particle->showerKinematics()-> - updateChildren(particle, children,fb.type,_reconOpt==3 || _reconOpt==4); - // update number of emissions - ++_nfs; - if(_limitEmissions!=0) { - if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); - if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); - if(particle->spinInfo()) particle->spinInfo()->develop(); - return true; - } - setupChildren = false; - } - // select branchings for children - fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); - fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); - // old default - if(_reconOpt==0||_reconOpt==5) { - break; - } - // all other options - else { - // cut-off masses for the branching - const vector & virtualMasses = fb.sudakov->virtualMasses(fb.ids); - // compute the masses of the children - Energy masses[3]; - for(unsigned int ix=0;ix<2;++ix) { - if(fc[ix].kinematics) { - const vector & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids); - Energy2 q2 = - fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale()); - if(fc[ix].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]); - masses[ix+1] = sqrt(q2); - } - else { - masses[ix+1] = virtualMasses[ix+1]; - } - } - masses[0] = fb.ids[0]->id()!=ParticleID::g ? virtualMasses[0] : ZERO; - double z = fb.kinematics->z(); - Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0])) - - sqr(masses[1])*(1.-z) - sqr(masses[2])*z; - if(pt2>=ZERO) break; - // clean up the vetoed emission - if(_reconOpt==1) { - particle->showerKinematics(ShoKinPtr()); - for(unsigned int ix=0;ixabandonChild(children[ix]); - children.clear(); - if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); - particle->vetoEmission(fb.type,fb.kinematics->scale()); - // generate the new emission - fb = selectTimeLikeBranching(particle,type,HardBranchingPtr()); - // no emission, return - if(!fb.kinematics) { - if(particle->spinInfo()) particle->spinInfo()->develop(); - return false; - } - setupChildren = true; - continue; - } - // clean up vetoed children - else if(_reconOpt>=2) { - // reset the scales for the children - for(unsigned int ix=0;ix<2;++ix) { - if(fc[ix].kinematics) - children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); - else - children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); - children[ix]->virtualMass(ZERO); - } - } - } - }; + Branching fc[2] = {Branching(),Branching()}; + + assert(fb.kinematics); + // has emitted + // Assign the shower kinematics to the emitting particle. + particle->showerKinematics(fb.kinematics); + // check highest pT + if(fb.kinematics->pT()>progenitor()->highestpT()) + progenitor()->highestpT(fb.kinematics->pT()); + // create the children + children = createTimeLikeChildren(particle,fb.ids); + // update the children + particle->showerKinematics()-> + updateChildren(particle, children,fb.type); + // update number of emissions + ++_nfs; + if(_limitEmissions!=0) { + if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); + if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); + if(particle->spinInfo()) particle->spinInfo()->develop(); + return true; + } + // select branchings for children + fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); + fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); // shower the first particle if(fc[0].kinematics) timeLikeShower(children[0],type,fc[0],false); if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); // shower the second particle if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],false); if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); if(_reconOpt>=1) particle->showerKinematics()->updateParent(particle, children,fb.type); // branching has happened if(first&&!children.empty()) particle->showerKinematics()->resetChildren(particle,children); if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } bool QTildeShowerHandler::spaceLikeShower(tShowerParticlePtr particle, PPtr beam, ShowerInteraction type) { //using the pdf's associated with the ShowerHandler assures, that //modified pdf's are used for the secondary interactions via //CascadeHandler::resetPDFs(...) tcPDFPtr pdf; if(firstPDF().particle() == _beam) pdf = firstPDF().pdf(); if(secondPDF().particle() == _beam) pdf = secondPDF().pdf(); Energy freeze = pdfFreezingScale(); // don't do anything if not needed if(_limitEmissions == 2 || hardOnly() || ( _limitEmissions == 1 && _nis != 0 ) || ( _limitEmissions == 4 && _nis + _nfs != 0 ) ) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } Branching bb; // generate branching while (true) { bb=_splittingGenerator->chooseBackwardBranching(*particle,beam, _initialenhance, _beam,type, pdf,freeze); // return if no emission if(!bb.kinematics) { if(particle->spinInfo()) particle->spinInfo()->develop(); return false; } // if not vetoed break if(!spaceLikeVetoed(bb,particle)) break; // otherwise reset scale and continue particle->vetoEmission(bb.type,bb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); } // assign the splitting function and shower kinematics particle->showerKinematics(bb.kinematics); if(bb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(bb.kinematics->pT()); // For the time being we are considering only 1->2 branching // particles as in Sudakov form factor tcPDPtr part[2]={bb.ids[0],bb.ids[2]}; // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr(ShowerParticle(part[0],false)); ShowerParticlePtr otherChild = new_ptr(ShowerParticle(part[1],true,true)); ShowerParticleVector theChildren; theChildren.push_back(particle); theChildren.push_back(otherChild); //this updates the evolution scale particle->showerKinematics()-> updateParent(newParent, theChildren,bb.type); // update the history if needed _currenttree->updateInitialStateShowerProduct(_progenitor,newParent); _currenttree->addInitialStateBranching(particle,newParent,otherChild); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower ++_nis; bool emitted = _limitEmissions==0 ? spaceLikeShower(newParent,beam,type) : false; if(newParent->spinInfo()) newParent->spinInfo()->develop(); // now reconstruct the momentum if(!emitted) { if(_intrinsic.find(_progenitor)==_intrinsic.end()) { bb.kinematics->updateLast(newParent,ZERO,ZERO); } else { pair kt=_intrinsic[_progenitor]; bb.kinematics->updateLast(newParent, kt.first*cos(kt.second), kt.first*sin(kt.second)); } } particle->showerKinematics()-> - updateChildren(newParent, theChildren,bb.type,_reconOpt>=4); + updateChildren(newParent, theChildren,bb.type); if(_limitEmissions!=0) { if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } // perform the shower of the final-state particle timeLikeShower(otherChild,type,Branching(),true); updateHistory(otherChild); if(theChildren[1]->spinInfo()) theChildren[1]->spinInfo()->develop(); // return the emitted if(particle->spinInfo()) particle->spinInfo()->develop(); return true; } void QTildeShowerHandler::showerDecay(ShowerTreePtr decay) { // work out the type of event currentTree()->xcombPtr(StdXCombPtr()); currentTree()->identifyEventType(); _decayme = HwDecayerBasePtr(); _hardme = HwMEBasePtr(); // find the decayer // try the normal way if possible tDMPtr dm = decay->incomingLines().begin()->first->original() ->decayMode(); if(!dm) dm = decay->incomingLines().begin()->first->copy() ->decayMode(); if(!dm) dm = decay->incomingLines().begin()->first->progenitor()->decayMode(); // otherwise make a string and look it up if(!dm) { string tag = decay->incomingLines().begin()->first->original()->dataPtr()->name() + "->"; OrderedParticles outgoing; for(map::const_iterator it=decay->outgoingLines().begin();it!=decay->outgoingLines().end();++it) { if(abs(decay->incomingLines().begin()->first->original()->id()) == ParticleID::t && abs(it->first->original()->id())==ParticleID::Wplus && decay->treelinks().size() == 1) { ShowerTreePtr Wtree = decay->treelinks().begin()->first; for(map::const_iterator it2=Wtree->outgoingLines().begin();it2!=Wtree->outgoingLines().end();++it2) { outgoing.insert(it2->first->original()->dataPtr()); } } else { outgoing.insert(it->first->original()->dataPtr()); } } for(OrderedParticles::const_iterator it=outgoing.begin(); it!=outgoing.end();++it) { if(it!=outgoing.begin()) tag += ","; tag +=(**it).name(); } tag += ";"; dm = findDecayMode(tag); } if(dm) _decayme = dynamic_ptr_cast(dm->decayer()); // set the ShowerTree to be showered currentTree(decay); decay->applyTransforms(); hardTree(HardTreePtr()); // generate the showering doShowering(false,XCPtr()); // if no vetos // force calculation of spin correlations SpinPtr spInfo = decay->incomingLines().begin()->first->progenitor()->spinInfo(); if(spInfo) { if(!spInfo->developed()) spInfo->needsUpdate(); spInfo->develop(); } } bool QTildeShowerHandler::spaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, Branching fb) { // don't do anything if not needed if(_limitEmissions == 1 || hardOnly() || ( _limitEmissions == 3 && _nis != 0) || ( _limitEmissions == 4 && _nfs + _nis != 0) ) { return false; } - // too many tries - if(_nFSR>=_maxTryFSR) { - ++_nFailedFSR; - // too many failed events - if(_nFailedFSR>=_maxFailFSR) - throw Exception() << "Too many events have failed due to too many shower emissions, in\n" - << "QTildeShowerHandler::timeLikeShower(). Terminating run\n" - << Exception::runerror; - throw Exception() << "Too many attempted emissions in QTildeShowerHandler::timeLikeShower()\n" - << Exception::eventerror; - } // generate the emission ShowerParticleVector children; - int ntry=0; // generate the emission if(!fb.kinematics) fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type, HardBranchingPtr()); // no emission, return if(!fb.kinematics) return false; Branching fc[2]; - bool setupChildren = true; - while (ntry<50) { - if(particle->virtualMass()==ZERO) - particle->virtualMass(_progenitor->progenitor()->mass()); - fc[0] = Branching(); - fc[1] = Branching(); - ++ntry; - assert(fb.kinematics); - // has emitted - // Assign the shower kinematics to the emitting particle. - if(setupChildren) { - ++_nFSR; - // Assign the shower kinematics to the emitting particle. - particle->showerKinematics(fb.kinematics); - if(fb.kinematics->pT()>progenitor()->highestpT()) - progenitor()->highestpT(fb.kinematics->pT()); - // create the ShowerParticle objects for the two children - children = createTimeLikeChildren(particle,fb.ids); - // updateChildren the children - particle->showerKinematics()-> - updateChildren(particle, children, fb.type,_reconOpt>=3); - setupChildren = false; - } - // select branchings for children - fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass, - type,HardBranchingPtr()); - fc[1] = selectTimeLikeBranching (children[1],type,HardBranchingPtr()); - // old default - if(_reconOpt==0) { - ++_nis; - // shower the first particle - _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); - _currenttree->addInitialStateBranching(particle,children[0],children[1]); - if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); - // shower the second particle - if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); - updateHistory(children[1]); - // branching has happened - break; - } - // Herwig default - else if(_reconOpt==1) { - // shower the first particle - _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); - _currenttree->addInitialStateBranching(particle,children[0],children[1]); - if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); - // shower the second particle - if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); - updateHistory(children[1]); - // branching has happened - particle->showerKinematics()->updateParent(particle, children,fb.type); - // clean up the vetoed emission - if(particle->virtualMass()==ZERO) { - particle->showerKinematics(ShoKinPtr()); - for(unsigned int ix=0;ixabandonChild(children[ix]); - children.clear(); - particle->vetoEmission(fb.type,fb.kinematics->scale()); - // generate the new emission - fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type, - HardBranchingPtr()); - // no emission, return - if(!fb.kinematics) { - return false; - } - setupChildren = true; - continue; - } - else { - ++_nis; - break; - } - } - else if(_reconOpt>=2) { - // cut-off masses for the branching - const vector & virtualMasses = fb.sudakov->virtualMasses(fb.ids); - // compute the masses of the children - Energy masses[3]; - // space-like children - masses[1] = children[0]->virtualMass(); - // time-like child - if(fc[1].kinematics) { - const vector & vm = fc[1].sudakov->virtualMasses(fc[1].ids); - Energy2 q2 = - fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale()); - if(fc[1].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]); - masses[2] = sqrt(q2); - } - else { - masses[2] = virtualMasses[2]; - } - masses[0]=particle->virtualMass(); - double z = fb.kinematics->z(); - Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2])); - if(pt2>=ZERO) { - ++_nis; - break; - } - else { - // reset the scales for the children - for(unsigned int ix=0;ix<2;++ix) { - if(fc[ix].kinematics) - children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); - else { - if(ix==0) - children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy); - else - children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); - } - } - children[0]->virtualMass(_progenitor->progenitor()->mass()); - children[1]->virtualMass(ZERO); - } - } - }; - if(_reconOpt>=2) { - // In the case of splittings which involves coloured particles, - // set properly the colour flow of the branching. - // update the history if needed - _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); - _currenttree->addInitialStateBranching(particle,children[0],children[1]); - // shower the first particle - if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); - // shower the second particle - if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); - updateHistory(children[1]); - // branching has happened - particle->showerKinematics()->updateParent(particle, children,fb.type); - } + if(particle->virtualMass()==ZERO) + particle->virtualMass(_progenitor->progenitor()->mass()); + fc[0] = Branching(); + fc[1] = Branching(); + assert(fb.kinematics); + // has emitted + // Assign the shower kinematics to the emitting particle. + particle->showerKinematics(fb.kinematics); + if(fb.kinematics->pT()>progenitor()->highestpT()) + progenitor()->highestpT(fb.kinematics->pT()); + // create the ShowerParticle objects for the two children + children = createTimeLikeChildren(particle,fb.ids); + // updateChildren the children + particle->showerKinematics()-> + updateChildren(particle, children, fb.type); + // select branchings for children + fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass, + type,HardBranchingPtr()); + fc[1] = selectTimeLikeBranching (children[1],type,HardBranchingPtr()); + // old default + ++_nis; + // shower the first particle + _currenttree->updateInitialStateShowerProduct(_progenitor,children[0]); + _currenttree->addInitialStateBranching(particle,children[0],children[1]); + if(fc[0].kinematics) spaceLikeDecayShower(children[0],maxScales,minmass,type,Branching()); + // shower the second particle + if(fc[1].kinematics) timeLikeShower(children[1],type,fc[1],true); + updateHistory(children[1]); + // TODO NEED AN UPDATE HERE FOR RECONOPT!=0 // branching has happened return true; } vector QTildeShowerHandler::setupShower(bool hard) { RealEmissionProcessPtr real; // generate hard me if needed if(_hardEmission==1) { real = hardMatrixElementCorrection(hard); if(real&&!real->outgoing().empty()) setupMECorrection(real); } // generate POWHEG hard emission if needed else if(_hardEmission==2) hardestEmission(hard); // set the initial colour partners setEvolutionPartners(hard,interaction_,false); // get the particles to be showered vector particlesToShower = currentTree()->extractProgenitors(); // return the answer return particlesToShower; } void QTildeShowerHandler::setEvolutionPartners(bool hard,ShowerInteraction type, bool clear) { // match the particles in the ShowerTree and hardTree if(hardTree() && !hardTree()->connect(currentTree())) throw Exception() << "Can't match trees in " << "QTildeShowerHandler::setEvolutionPartners()" << Exception::eventerror; // extract the progenitors vector particles = currentTree()->extractProgenitorParticles(); // clear the partners if needed if(clear) { for(unsigned int ix=0;ixpartner(ShowerParticlePtr()); particles[ix]->clearPartners(); } } // sort out the colour partners if(hardTree()) { // find the partner for(unsigned int ix=0;ixparticles()[particles[ix]]->branchingParticle()->partner(); if(!partner) continue; for(map::const_iterator it=hardTree()->particles().begin(); it!=hardTree()->particles().end();++it) { if(it->second->branchingParticle()==partner) { particles[ix]->partner(it->first); break; } } if(!particles[ix]->partner()) throw Exception() << "Can't match partners in " << "QTildeShowerHandler::setEvolutionPartners()" << Exception::eventerror; } } // Set the initial evolution scales - showerModel()->partnerFinder()-> + partnerFinder()-> setInitialEvolutionScales(particles,!hard,interaction_,!_hardtree); if(hardTree() && _hardPOWHEG) { bool tooHard=false; map::const_iterator eit=hardTree()->particles().end(); for(unsigned int ix=0;ix::const_iterator mit = hardTree()->particles().find(particles[ix]); Energy hardScale(ZERO); ShowerPartnerType type(ShowerPartnerType::Undefined); // final-state if(particles[ix]->isFinalState()) { if(mit!= eit && !mit->second->children().empty()) { hardScale = mit->second->scale(); type = mit->second->type(); } } // initial-state else { if(mit!= eit && mit->second->parent()) { hardScale = mit->second->parent()->scale(); type = mit->second->parent()->type(); } } if(type!=ShowerPartnerType::Undefined) { if(type==ShowerPartnerType::QED) { tooHard |= particles[ix]->scales().QED_noAOscales().QCD_c_noAOscales().QCD_ac_noAOscales().EWchildren().empty()) { ShowerParticleVector theChildren; for(unsigned int ix=0;ixchildren().size();++ix) { ShowerParticlePtr part = dynamic_ptr_cast (particle->children()[ix]); theChildren.push_back(part); } // update the history if needed if(particle==_currenttree->getFinalStateShowerProduct(_progenitor)) _currenttree->updateFinalStateShowerProduct(_progenitor, particle,theChildren); _currenttree->addFinalStateBranching(particle,theChildren); for(unsigned int ix=0;ixprogenitor()->partner()) return false; progenitor()->progenitor()->initializeFinalState(); if(hardTree()) { map::const_iterator eit=hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && !mit->second->children().empty() ) { bool output=truncatedTimeLikeShower(progenitor()->progenitor(), mit->second ,type,Branching(),true); if(output) updateHistory(progenitor()->progenitor()); return output; } } // do the shower bool output = hardOnly() ? false : timeLikeShower(progenitor()->progenitor() ,type,Branching(),true) ; if(output) updateHistory(progenitor()->progenitor()); return output; } bool QTildeShowerHandler::startSpaceLikeShower(PPtr parent, ShowerInteraction type) { // initialise the basis vectors if(!progenitor()->progenitor()->partner()) return false; progenitor()->progenitor()->initializeInitialState(parent); if(hardTree()) { map::const_iterator eit =hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && mit->second->parent() ) { return truncatedSpaceLikeShower( progenitor()->progenitor(), parent, mit->second->parent(), type ); } } // perform the shower return hardOnly() ? false : spaceLikeShower(progenitor()->progenitor(),parent,type); } bool QTildeShowerHandler:: startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction type) { - _nFSR = 0; // set up the particle basis vectors if(!progenitor()->progenitor()->partner()) return false; progenitor()->progenitor()->initializeDecay(); if(hardTree()) { map::const_iterator eit =hardTree()->particles().end(), mit = hardTree()->particles().find(progenitor()->progenitor()); if( mit != eit && mit->second->parent() ) { HardBranchingPtr branch=mit->second; while(branch->parent()) branch=branch->parent(); return truncatedSpaceLikeDecayShower(progenitor()->progenitor(),maxScales, minimumMass, branch ,type, Branching()); } } // perform the shower return hardOnly() ? false : spaceLikeDecayShower(progenitor()->progenitor(),maxScales,minimumMass,type,Branching()); } bool QTildeShowerHandler::timeLikeVetoed(const Branching & fb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(fb.type); // check whether emission was harder than largest pt of hard subprocess if ( restrictPhasespace() && fb.kinematics->pT() > _progenitor->maxHardPt() ) return true; // soft matrix element correction veto if( softMEC()) { if(_hardme && _hardme->hasMECorrection()) { if(_hardme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), fb.ids, fb.kinematics->z(), fb.kinematics->scale(), fb.kinematics->pT())) return true; } else if(_decayme && _decayme->hasMECorrection()) { if(_decayme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), fb.ids, fb.kinematics->z(), fb.kinematics->scale(), fb.kinematics->pT())) return true; } } // veto on maximum pt if(fb.kinematics->pT()>_progenitor->maximumpT(type)) return true; // general vetos if (fb.kinematics && !_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoTimeLike(_progenitor,particle,fb,currentTree()); switch((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } } if(vetoed) return true; } if ( firstInteraction() && profileScales() ) { double weight = profileScales()-> hardScaleProfile(_progenitor->hardScale(),fb.kinematics->pT()); if ( UseRandom::rnd() > weight ) return true; } return false; } bool QTildeShowerHandler::spaceLikeVetoed(const Branching & bb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(bb.type); // check whether emission was harder than largest pt of hard subprocess if (restrictPhasespace() && bb.kinematics->pT() > _progenitor->maxHardPt()) return true; // apply the soft correction if( softMEC() && _hardme && _hardme->hasMECorrection() ) { if(_hardme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), bb.ids, bb.kinematics->z(), bb.kinematics->scale(), bb.kinematics->pT())) return true; } // the more general vetos // check vs max pt for the shower if(bb.kinematics->pT()>_progenitor->maximumpT(type)) return true; if (!_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoSpaceLike(_progenitor,particle,bb,currentTree()); switch ((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } } if (vetoed) return true; } if ( firstInteraction() && profileScales() ) { double weight = profileScales()-> hardScaleProfile(_progenitor->hardScale(),bb.kinematics->pT()); if ( UseRandom::rnd() > weight ) return true; } return false; } bool QTildeShowerHandler::spaceLikeDecayVetoed( const Branching & fb, ShowerParticlePtr particle) { // work out type of interaction ShowerInteraction type = convertInteraction(fb.type); // apply the soft correction if( softMEC() && _decayme && _decayme->hasMECorrection() ) { if(_decayme->softMatrixElementVeto(particle, _progenitor->progenitor(), particle->isFinalState(), _progenitor->highestpT(), fb.ids, fb.kinematics->z(), fb.kinematics->scale(), fb.kinematics->pT())) return true; } // veto on hardest pt in the shower if(fb.kinematics->pT()> _progenitor->maximumpT(type)) return true; // general vetos if (!_vetoes.empty()) { bool vetoed=false; for (vector::iterator v = _vetoes.begin(); v != _vetoes.end(); ++v) { bool test = (**v).vetoSpaceLike(_progenitor,particle,fb,currentTree()); switch((**v).vetoType()) { case ShowerVeto::Emission: vetoed |= test; break; case ShowerVeto::Shower: if(test) throw VetoShower(); break; case ShowerVeto::Event: if(test) throw Veto(); break; } if (vetoed) return true; } } return false; } void QTildeShowerHandler::hardestEmission(bool hard) { HardTreePtr ISRTree; // internal POWHEG in production or decay if( (( _hardme && _hardme->hasPOWHEGCorrection()!=0 ) || ( _decayme && _decayme->hasPOWHEGCorrection()!=0 ) ) ) { RealEmissionProcessPtr real; unsigned int type(0); // production if(_hardme) { assert(hard); real = _hardme->generateHardest( currentTree()->perturbativeProcess(), interaction_); type = _hardme->hasPOWHEGCorrection(); } // decay else { assert(!hard); real = _decayme->generateHardest( currentTree()->perturbativeProcess() ); type = _decayme->hasPOWHEGCorrection(); } if(real) { // set up ther hard tree if(!real->outgoing().empty()) _hardtree = new_ptr(HardTree(real)); // set up the vetos currentTree()->setVetoes(real->pT(),type); } // store initial state POWHEG radiation if(_hardtree && _hardme && _hardme->hasPOWHEGCorrection()==1) ISRTree = _hardtree; } else if (hard) { // Get minimum pT cutoff used in shower approximation Energy maxpt = 1.*GeV; if ( currentTree()->showerApproximation() ) { int colouredIn = 0; int colouredOut = 0; for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if( it->second->coloured() ) ++colouredOut; } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = currentTree()->incomingLines().begin(); it != currentTree()->incomingLines().end(); ++it ) { if( it->second->coloured() ) ++colouredIn; } if ( currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->fiPtCut() && currentTree()->showerApproximation()->ffPtCut() == currentTree()->showerApproximation()->iiPtCut() ) maxpt = currentTree()->showerApproximation()->ffPtCut(); else if ( colouredIn == 2 && colouredOut == 0 ) maxpt = currentTree()->showerApproximation()->iiPtCut(); else if ( colouredIn == 0 && colouredOut > 1 ) maxpt = currentTree()->showerApproximation()->ffPtCut(); else if ( colouredIn == 2 && colouredOut == 1 ) maxpt = min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut()); else if ( colouredIn == 1 && colouredOut > 1 ) maxpt = min(currentTree()->showerApproximation()->ffPtCut(), currentTree()->showerApproximation()->fiPtCut()); else maxpt = min(min(currentTree()->showerApproximation()->iiPtCut(), currentTree()->showerApproximation()->fiPtCut()), currentTree()->showerApproximation()->ffPtCut()); } // Generate hardtree from born and real emission subprocesses _hardtree = generateCKKW(currentTree()); // Find transverse momentum of hardest emission if (_hardtree){ for(set::iterator it=_hardtree->branchings().begin(); it!=_hardtree->branchings().end();++it) { if ((*it)->parent() && (*it)->status()==HardBranching::Incoming) maxpt=(*it)->branchingParticle()->momentum().perp(); if ((*it)->children().size()==2 && (*it)->status()==HardBranching::Outgoing){ if ((*it)->branchingParticle()->id()!=21 && abs((*it)->branchingParticle()->id())>5 ){ if ((*it)->children()[0]->branchingParticle()->id()==21 || abs((*it)->children()[0]->branchingParticle()->id())<6) maxpt=(*it)->children()[0]->branchingParticle()->momentum().perp(); else if ((*it)->children()[1]->branchingParticle()->id()==21 || abs((*it)->children()[1]->branchingParticle()->id())<6) maxpt=(*it)->children()[1]->branchingParticle()->momentum().perp(); } else { if ( abs((*it)->branchingParticle()->id())<6){ if (abs((*it)->children()[0]->branchingParticle()->id())<6) maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp(); else maxpt = (*it)->children()[0]->branchingParticle()->momentum().perp(); } else maxpt = (*it)->children()[1]->branchingParticle()->momentum().perp(); } } } } // Hardest (pt) emission should be the first powheg emission. maxpt=min(sqrt(lastXCombPtr()->lastShowerScale()),maxpt); // set maximum pT for subsequent emissions from S events if ( currentTree()->isPowhegSEvent() ) { for( map< ShowerProgenitorPtr, tShowerParticlePtr >::iterator it = currentTree()->outgoingLines().begin(); it != currentTree()->outgoingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT(maxpt, ShowerInteraction::QCD ); } for( map< ShowerProgenitorPtr, ShowerParticlePtr >::iterator it = currentTree()->incomingLines().begin(); it != currentTree()->incomingLines().end(); ++it ) { if( ! it->second->coloured() ) continue; it->first->maximumpT(maxpt, ShowerInteraction::QCD ); } } } else _hardtree = generateCKKW(currentTree()); // if hard me doesn't have a FSR powheg // correction use decay powheg correction if (_hardme && _hardme->hasPOWHEGCorrection()<2) { addFSRUsingDecayPOWHEG(ISRTree); } // connect the trees if(_hardtree) { connectTrees(currentTree(),_hardtree,hard); } } void QTildeShowerHandler::addFSRUsingDecayPOWHEG(HardTreePtr ISRTree) { // check for intermediate colour singlet resonance const ParticleVector inter = _hardme->subProcess()->intermediates(); if (inter.size()!=1 || inter[0]->momentum().m2()/GeV2 < 0 || inter[0]->dataPtr()->iColour()!=PDT::Colour0) { return; } // ignore cases where outgoing particles are not coloured map out = currentTree()->outgoingLines(); if (out.size() != 2 || out. begin()->second->dataPtr()->iColour()==PDT::Colour0 || out.rbegin()->second->dataPtr()->iColour()==PDT::Colour0) { return; } // look up decay mode tDMPtr dm; string tag; string inParticle = inter[0]->dataPtr()->name() + "->"; vector outParticles; outParticles.push_back(out.begin ()->first->progenitor()->dataPtr()->name()); outParticles.push_back(out.rbegin()->first->progenitor()->dataPtr()->name()); for (int it=0; it<2; ++it){ tag = inParticle + outParticles[it] + "," + outParticles[(it+1)%2] + ";"; dm = generator()->findDecayMode(tag); if(dm) break; } // get the decayer HwDecayerBasePtr decayer; if(dm) decayer = dynamic_ptr_cast(dm->decayer()); // check if decayer has a FSR POWHEG correction if (!decayer || decayer->hasPOWHEGCorrection()<2) { return; } // generate the hardest emission // create RealEmissionProcess PPtr in = new_ptr(*inter[0]); RealEmissionProcessPtr newProcess(new_ptr(RealEmissionProcess())); newProcess->bornIncoming().push_back(in); newProcess->bornOutgoing().push_back(out.begin ()->first->progenitor()); newProcess->bornOutgoing().push_back(out.rbegin()->first->progenitor()); // generate the FSR newProcess = decayer->generateHardest(newProcess); HardTreePtr FSRTree; if(newProcess) { // set up ther hard tree if(!newProcess->outgoing().empty()) FSRTree = new_ptr(HardTree(newProcess)); // set up the vetos currentTree()->setVetoes(newProcess->pT(),2); } if(!FSRTree) return; // if there is no ISRTree make _hardtree from FSRTree if (!ISRTree){ vector inBranch,hardBranch; for(map::const_iterator cit =currentTree()->incomingLines().begin(); cit!=currentTree()->incomingLines().end();++cit ) { inBranch.push_back(new_ptr(HardBranching(cit->second,SudakovPtr(), HardBranchingPtr(), HardBranching::Incoming))); inBranch.back()->beam(cit->first->original()->parents()[0]); hardBranch.push_back(inBranch.back()); } if(inBranch[0]->branchingParticle()->dataPtr()->coloured()) { inBranch[0]->colourPartner(inBranch[1]); inBranch[1]->colourPartner(inBranch[0]); } for(set::iterator it=FSRTree->branchings().begin(); it!=FSRTree->branchings().end();++it) { if((**it).branchingParticle()->id()!=in->id()) hardBranch.push_back(*it); } hardBranch[2]->colourPartner(hardBranch[3]); hardBranch[3]->colourPartner(hardBranch[2]); HardTreePtr newTree = new_ptr(HardTree(hardBranch,inBranch, ShowerInteraction::QCD)); _hardtree = newTree; } // Otherwise modify the ISRTree to include the emission in FSRTree else { vector FSROut, ISROut; set::iterator itFSR, itISR; // get outgoing particles for(itFSR =FSRTree->branchings().begin(); itFSR!=FSRTree->branchings().end();++itFSR){ if ((**itFSR).status()==HardBranching::Outgoing) FSROut.push_back((*itFSR)->branchingParticle()); } for(itISR =ISRTree->branchings().begin(); itISR!=ISRTree->branchings().end();++itISR){ if ((**itISR).status()==HardBranching::Outgoing) ISROut.push_back((*itISR)->branchingParticle()); } // find COM frame formed by outgoing particles LorentzRotation eventFrameFSR, eventFrameISR; eventFrameFSR = ((FSROut[0]->momentum()+FSROut[1]->momentum()).findBoostToCM()); eventFrameISR = ((ISROut[0]->momentum()+ISROut[1]->momentum()).findBoostToCM()); // find rotation between ISR and FSR frames int j=0; if (ISROut[0]->id()!=FSROut[0]->id()) j=1; eventFrameISR.rotateZ( (eventFrameFSR*FSROut[0]->momentum()).phi()- (eventFrameISR*ISROut[j]->momentum()).phi() ); eventFrameISR.rotateY( (eventFrameFSR*FSROut[0]->momentum()).theta()- (eventFrameISR*ISROut[j]->momentum()).theta() ); eventFrameISR.invert(); for (itFSR=FSRTree->branchings().begin(); itFSR!=FSRTree->branchings().end();++itFSR){ if ((**itFSR).branchingParticle()->id()==in->id()) continue; for (itISR =ISRTree->branchings().begin(); itISR!=ISRTree->branchings().end();++itISR){ if ((**itISR).status()==HardBranching::Incoming) continue; if ((**itFSR).branchingParticle()->id()== (**itISR).branchingParticle()->id()){ // rotate FSRTree particle to ISRTree event frame (**itISR).branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).branchingParticle()->momentum()); (**itISR).branchingParticle()->rescaleMass(); // add the children of the FSRTree particles to the ISRTree if(!(**itFSR).children().empty()){ (**itISR).addChild((**itFSR).children()[0]); (**itISR).addChild((**itFSR).children()[1]); // rotate momenta to ISRTree event frame (**itISR).children()[0]->branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).children()[0]->branchingParticle()->momentum()); (**itISR).children()[1]->branchingParticle()->setMomentum(eventFrameISR* eventFrameFSR* (**itFSR).children()[1]->branchingParticle()->momentum()); } } } } _hardtree = ISRTree; } } bool QTildeShowerHandler::truncatedTimeLikeShower(tShowerParticlePtr particle, HardBranchingPtr branch, ShowerInteraction type, Branching fb, bool first) { // select a branching if we don't have one if(!fb.kinematics) fb = selectTimeLikeBranching(particle,type,branch); // must be an emission, the forced one it not a truncated one assert(fb.kinematics); ShowerParticleVector children; - int ntry=0; - Branching fc[2]; - bool setupChildren = true; - while (ntry<50) { - if(!fc[0].hard) fc[0] = Branching(); - if(!fc[1].hard) fc[1] = Branching(); - ++ntry; - // Assign the shower kinematics to the emitting particle. - if(setupChildren) { - ++_nFSR; - // Assign the shower kinematics to the emitting particle. - particle->showerKinematics(fb.kinematics); - if(fb.kinematics->pT()>progenitor()->highestpT()) - progenitor()->highestpT(fb.kinematics->pT()); - // create the children - children = createTimeLikeChildren(particle,fb.ids); - // update the children - particle->showerKinematics()-> - updateChildren(particle, children,fb.type,_reconOpt>=3); - setupChildren = false; - } - // select branchings for children - if(!fc[0].kinematics) { - // select branching for first particle - if(!fb.hard && fb.iout ==1 ) - fc[0] = selectTimeLikeBranching(children[0],type,branch); - else if(fb.hard && !branch->children()[0]->children().empty() ) - fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); - else - fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); - } - // select branching for the second particle - if(!fc[1].kinematics) { - // select branching for first particle - if(!fb.hard && fb.iout ==2 ) - fc[1] = selectTimeLikeBranching(children[1],type,branch); - else if(fb.hard && !branch->children()[1]->children().empty() ) - fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); - else - fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); - } - // old default - if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) { - // shower the first particle - if(fc[0].kinematics) { - // the parent has truncated emission and following line - if(!fb.hard && fb.iout == 1) - truncatedTimeLikeShower(children[0],branch,type,fc[0],false); - // hard emission and subsquent hard emissions - else if(fb.hard && !branch->children()[0]->children().empty() ) - truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); - // normal shower - else - timeLikeShower(children[0],type,fc[0],false); - } - if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); - // shower the second particle - if(fc[1].kinematics) { - // the parent has truncated emission and following line - if(!fb.hard && fb.iout == 2) - truncatedTimeLikeShower(children[1],branch,type,fc[1],false); - // hard emission and subsquent hard emissions - else if(fb.hard && !branch->children()[1]->children().empty() ) - truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false); - else - timeLikeShower(children[1],type,fc[1],false); - } - if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); - // branching has happened - particle->showerKinematics()->updateParent(particle, children,fb.type); - break; - } - // H7 default - else if(_reconOpt==1) { - // shower the first particle - if(fc[0].kinematics) { - // the parent has truncated emission and following line - if(!fb.hard && fb.iout == 1) - truncatedTimeLikeShower(children[0],branch,type,fc[0],false); - else - timeLikeShower(children[0],type,fc[0],false); - } - if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); - // shower the second particle - if(fc[1].kinematics) { - // the parent has truncated emission and following line - if(!fb.hard && fb.iout == 2) - truncatedTimeLikeShower(children[1],branch,type,fc[1],false); - else - timeLikeShower(children[1],type,fc[1],false); - } - if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); - // branching has happened - particle->showerKinematics()->updateParent(particle, children,fb.type); - // clean up the vetoed emission - if(particle->virtualMass()==ZERO) { - particle->showerKinematics(ShoKinPtr()); - for(unsigned int ix=0;ixabandonChild(children[ix]); - children.clear(); - if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); - particle->vetoEmission(fb.type,fb.kinematics->scale()); - // generate the new emission - fb = selectTimeLikeBranching(particle,type,branch); - // must be at least hard emission - assert(fb.kinematics); - setupChildren = true; - continue; - } - else - break; - } - else if(_reconOpt>=2) { - // cut-off masses for the branching - const vector & virtualMasses = fb.sudakov->virtualMasses(fb.ids); - // compute the masses of the children - Energy masses[3]; - for(unsigned int ix=0;ix<2;++ix) { - if(fc[ix].kinematics) { - const vector & vm = fc[ix].sudakov->virtualMasses(fc[ix].ids); - Energy2 q2 = - fc[ix].kinematics->z()*(1.-fc[ix].kinematics->z())*sqr(fc[ix].kinematics->scale()); - if(fc[ix].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]); - masses[ix+1] = sqrt(q2); - } - else { - masses[ix+1] = virtualMasses[ix+1]; - } - } - masses[0] = fb.ids[0]->id()!=ParticleID::g ? virtualMasses[0] : ZERO; - double z = fb.kinematics->z(); - Energy2 pt2 = z*(1.-z)*(z*(1.-z)*sqr(fb.kinematics->scale()) + sqr(masses[0])) - - sqr(masses[1])*(1.-z) - sqr(masses[2])*z; - if(pt2>=ZERO) { - break; - } - // if only the hard emission have to accept it - else if ((fc[0].hard && !fc[1].kinematics) || - (fc[1].hard && !fc[0].kinematics) ) { - break; - } - else { - // reset the scales for the children - for(unsigned int ix=0;ix<2;++ix) { - if(fc[ix].hard) continue; - if(fc[ix].kinematics && ! fc[ix].hard ) - children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); - else - children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); - children[ix]->virtualMass(ZERO); - } - } - } - }; - if(_reconOpt>=2) { - // shower the first particle - if(fc[0].kinematics) { - // the parent has truncated emission and following line - if(!fb.hard && fb.iout == 1) - truncatedTimeLikeShower(children[0],branch,type,fc[0],false); - // hard emission and subsquent hard emissions - else if(fb.hard && !branch->children()[0]->children().empty() ) - truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); - // normal shower - else - timeLikeShower(children[0],type,fc[0],false); - } - if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); - // shower the second particle - if(fc[1].kinematics) { - // the parent has truncated emission and following line - if(!fb.hard && fb.iout == 2) - truncatedTimeLikeShower(children[1],branch,type,fc[1],false); - // hard emission and subsquent hard emissions - else if(fb.hard && !branch->children()[1]->children().empty() ) - truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false); - else - timeLikeShower(children[1],type,fc[1],false); - } - if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); - // branching has happened - particle->showerKinematics()->updateParent(particle, children,fb.type); + Branching fc[2] = {Branching(),Branching()}; + // Assign the shower kinematics to the emitting particle. + particle->showerKinematics(fb.kinematics); + if(fb.kinematics->pT()>progenitor()->highestpT()) + progenitor()->highestpT(fb.kinematics->pT()); + // create the children + children = createTimeLikeChildren(particle,fb.ids); + // update the children + particle->showerKinematics()-> + updateChildren(particle, children,fb.type); + // select branchings for children + if(!fc[0].kinematics) { + // select branching for first particle + if(!fb.hard && fb.iout ==1 ) + fc[0] = selectTimeLikeBranching(children[0],type,branch); + else if(fb.hard && !branch->children()[0]->children().empty() ) + fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); + else + fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); } + // select branching for the second particle + if(!fc[1].kinematics) { + // select branching for first particle + if(!fb.hard && fb.iout ==2 ) + fc[1] = selectTimeLikeBranching(children[1],type,branch); + else if(fb.hard && !branch->children()[1]->children().empty() ) + fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); + else + fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); + } + // shower the first particle + if(fc[0].kinematics) { + // the parent has truncated emission and following line + if(!fb.hard && fb.iout == 1) + truncatedTimeLikeShower(children[0],branch,type,fc[0],false); + // hard emission and subsquent hard emissions + else if(fb.hard && !branch->children()[0]->children().empty() ) + truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); + // normal shower + else + timeLikeShower(children[0],type,fc[0],false); + } + if(children[0]->spinInfo()) children[0]->spinInfo()->develop(); + // shower the second particle + if(fc[1].kinematics) { + // the parent has truncated emission and following line + if(!fb.hard && fb.iout == 2) + truncatedTimeLikeShower(children[1],branch,type,fc[1],false); + // hard emission and subsquent hard emissions + else if(fb.hard && !branch->children()[1]->children().empty() ) + truncatedTimeLikeShower(children[1],branch->children()[1],type,fc[1],false); + else + timeLikeShower(children[1],type,fc[1],false); + } + if(children[1]->spinInfo()) children[1]->spinInfo()->develop(); + // branching has happened + particle->showerKinematics()->updateParent(particle, children,fb.type); if(first&&!children.empty()) particle->showerKinematics()->resetChildren(particle,children); if(particle->spinInfo()) particle->spinInfo()->develop(); + // TODO NEED AN UPDATE HERE FOR RECONOPT!=0 ? return true; } bool QTildeShowerHandler::truncatedSpaceLikeShower(tShowerParticlePtr particle, PPtr beam, HardBranchingPtr branch, ShowerInteraction type) { tcPDFPtr pdf; if(firstPDF().particle() == beamParticle()) pdf = firstPDF().pdf(); if(secondPDF().particle() == beamParticle()) pdf = secondPDF().pdf(); Energy freeze = pdfFreezingScale(); Branching bb; // parameters of the force branching double z(0.); HardBranchingPtr timelike; for( unsigned int ix = 0; ix < branch->children().size(); ++ix ) { if( branch->children()[ix]->status() ==HardBranching::Outgoing) { timelike = branch->children()[ix]; } if( branch->children()[ix]->status() ==HardBranching::Incoming ) z = branch->children()[ix]->z(); } // generate truncated branching tcPDPtr part[2]; if(z>=0.&&z<=1.) { while (true) { if( !isTruncatedShowerON() || hardOnly() ) break; bb = splittingGenerator()->chooseBackwardBranching( *particle, beam, 1., beamParticle(), type , pdf,freeze); if( !bb.kinematics || bb.kinematics->scale() < branch->scale() ) { bb = Branching(); break; } // particles as in Sudakov form factor part[0] = bb.ids[0]; part[1] = bb.ids[2]; double zsplit = bb.kinematics->z(); // apply the vetos for the truncated shower // if doesn't carry most of momentum ShowerInteraction type2 = convertInteraction(bb.type); if(type2==branch->sudakov()->interactionType() && zsplit < 0.5) { particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } // others if( part[0]->id() != particle->id() || // if particle changes type bb.kinematics->pT() > progenitor()->maximumpT(type2) || // pt veto bb.kinematics->scale() < branch->scale()) { // angular ordering veto particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } // and those from the base class if(spaceLikeVetoed(bb,particle)) { particle->vetoEmission(bb.type,bb.kinematics->scale()); continue; } break; } } if( !bb.kinematics ) { //do the hard emission - ShoKinPtr kinematics = - branch->sudakov()->createInitialStateBranching( branch->scale(), z, branch->phi(), - branch->children()[0]->pT() ); + ShoKinPtr kinematics = new_ptr(IS_QTildeShowerKinematics1to2( + branch->scale(), z, branch->phi(), + branch->children()[0]->pT(), branch->sudakov() + )); // assign the splitting function and shower kinematics particle->showerKinematics( kinematics ); if(kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(kinematics->pT()); // For the time being we are considering only 1->2 branching // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr( ShowerParticle( branch->branchingParticle()->dataPtr(), false ) ); ShowerParticlePtr otherChild = new_ptr( ShowerParticle( timelike->branchingParticle()->dataPtr(), true, true ) ); ShowerParticleVector theChildren; theChildren.push_back( particle ); theChildren.push_back( otherChild ); particle->showerKinematics()-> updateParent( newParent, theChildren, branch->type()); // update the history if needed currentTree()->updateInitialStateShowerProduct( progenitor(), newParent ); currentTree()->addInitialStateBranching( particle, newParent, otherChild ); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower bool emitted=false; if(!hardOnly()) { if( branch->parent() ) { emitted = truncatedSpaceLikeShower( newParent, beam, branch->parent() , type); } else { emitted = spaceLikeShower( newParent, beam , type); } } if( !emitted ) { if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) { kinematics->updateLast( newParent, ZERO, ZERO ); } else { pair kt = intrinsicpT()[progenitor()]; kinematics->updateLast( newParent, kt.first*cos( kt.second ), kt.first*sin( kt.second ) ); } } particle->showerKinematics()-> - updateChildren( newParent, theChildren,bb.type,false); + updateChildren( newParent, theChildren,bb.type); if(hardOnly()) return true; // perform the shower of the final-state particle if( timelike->children().empty() ) { timeLikeShower( otherChild , type,Branching(),true); } else { truncatedTimeLikeShower( otherChild, timelike , type,Branching(), true); } updateHistory(otherChild); // return the emitted return true; } // assign the splitting function and shower kinematics particle->showerKinematics( bb.kinematics ); if(bb.kinematics->pT()>progenitor()->highestpT()) progenitor()->highestpT(bb.kinematics->pT()); // For the time being we are considering only 1->2 branching // Now create the actual particles, make the otherChild a final state // particle, while the newParent is not ShowerParticlePtr newParent = new_ptr( ShowerParticle( part[0], false ) ); ShowerParticlePtr otherChild = new_ptr( ShowerParticle( part[1], true, true ) ); ShowerParticleVector theChildren; theChildren.push_back( particle ); theChildren.push_back( otherChild ); particle->showerKinematics()-> updateParent( newParent, theChildren, bb.type); // update the history if needed currentTree()->updateInitialStateShowerProduct( progenitor(), newParent ); currentTree()->addInitialStateBranching( particle, newParent, otherChild ); // for the reconstruction of kinematics, parent/child // relationships are according to the branching process: // now continue the shower bool emitted = truncatedSpaceLikeShower( newParent, beam, branch,type); // now reconstruct the momentum if( !emitted ) { if( intrinsicpT().find( progenitor() ) == intrinsicpT().end() ) { bb.kinematics->updateLast( newParent, ZERO, ZERO ); } else { pair kt = intrinsicpT()[ progenitor() ]; bb.kinematics->updateLast( newParent, kt.first*cos( kt.second ), kt.first*sin( kt.second ) ); } } particle->showerKinematics()-> - updateChildren( newParent, theChildren, bb.type,false); + updateChildren( newParent, theChildren, bb.type); // perform the shower of the final-state particle timeLikeShower( otherChild , type,Branching(),true); updateHistory(otherChild); // return the emitted return true; } bool QTildeShowerHandler:: truncatedSpaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass, HardBranchingPtr branch, ShowerInteraction type, Branching fb) { // select a branching if we don't have one if(!fb.kinematics) fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch); // must be an emission, the forced one it not a truncated one assert(fb.kinematics); ShowerParticleVector children; - int ntry=0; - Branching fc[2]; - bool setupChildren = true; - while (ntry<50) { - if(!fc[0].hard) fc[0] = Branching(); - if(!fc[1].hard) fc[1] = Branching(); - ++ntry; - if(setupChildren) { - ++_nFSR; - // Assign the shower kinematics to the emitting particle. - particle->showerKinematics(fb.kinematics); - if(fb.kinematics->pT()>progenitor()->highestpT()) - progenitor()->highestpT(fb.kinematics->pT()); - // create the ShowerParticle objects for the two children - children = createTimeLikeChildren(particle,fb.ids); - // updateChildren the children - particle->showerKinematics()-> - updateChildren(particle, children, fb.type,_reconOpt>=3); - setupChildren = false; + Branching fc[2]={Branching(),Branching()}; + // Assign the shower kinematics to the emitting particle. + particle->showerKinematics(fb.kinematics); + if(fb.kinematics->pT()>progenitor()->highestpT()) + progenitor()->highestpT(fb.kinematics->pT()); + // create the ShowerParticle objects for the two children + children = createTimeLikeChildren(particle,fb.ids); + // updateChildren the children + particle->showerKinematics()-> + updateChildren(particle, children, fb.type); + // select branchings for children + if(!fc[0].kinematics) { + if(children[0]->id()==particle->id()) { + // select branching for first particle + if(!fb.hard) + fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,branch); + else if(fb.hard && ! branch->children()[0]->children().empty() ) + fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, + branch->children()[0]); + else + fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, + HardBranchingPtr()); } - // select branchings for children - if(!fc[0].kinematics) { - if(children[0]->id()==particle->id()) { - // select branching for first particle - if(!fb.hard) - fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type,branch); - else if(fb.hard && ! branch->children()[0]->children().empty() ) - fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, - branch->children()[0]); - else - fc[0] = selectSpaceLikeDecayBranching(children[0],maxScales,minmass,type, - HardBranchingPtr()); - } - else { - // select branching for first particle - if(fb.hard && !branch->children()[0]->children().empty() ) - fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); - else - fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); - } + else { + // select branching for first particle + if(fb.hard && !branch->children()[0]->children().empty() ) + fc[0] = selectTimeLikeBranching(children[0],type,branch->children()[0]); + else + fc[0] = selectTimeLikeBranching(children[0],type,HardBranchingPtr()); } - // select branching for the second particle - if(!fc[1].kinematics) { - if(children[1]->id()==particle->id()) { - // select branching for first particle - if(!fb.hard) + } + // select branching for the second particle + if(!fc[1].kinematics) { + if(children[1]->id()==particle->id()) { + // select branching for first particle + if(!fb.hard) fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type,branch); - else if(fb.hard && ! branch->children()[1]->children().empty() ) - fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, - branch->children()[1]); - else - fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, - HardBranchingPtr()); - } - else { - if(fb.hard && !branch->children()[1]->children().empty() ) - fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); - else - fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); - } - } - // old default - if(_reconOpt==0 || (_reconOpt==1 && fb.hard) ) { - // update the history if needed - currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); - currentTree()->addInitialStateBranching(particle,children[0],children[1]); - // shower the first particle - if(fc[0].kinematics) { - if(children[0]->id()==particle->id()) { - if(!fb.hard) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch,type,fc[0]); - else if(fb.hard && ! branch->children()[0]->children().empty() ) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch->children()[0],type,fc[0]); - else - spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); - } - else { - if(fb.hard && !branch->children()[0]->children().empty() ) - truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); - // normal shower - else - timeLikeShower(children[0],type,fc[0],false); - } - } - // shower the second particle - if(fc[1].kinematics) { - if(children[0]->id()==particle->id()) { - if(!fb.hard) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch,type,fc[1]); - else if(fb.hard && ! branch->children()[0]->children().empty() ) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch->children()[0],type,fc[1]); - else - spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); - } - else { - if(fb.hard && !branch->children()[0]->children().empty() ) - truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); - // normal shower - else - timeLikeShower(children[0],type,fc[1],false); - } - } - updateHistory(children[1]); - // branching has happened - break; + else if(fb.hard && ! branch->children()[1]->children().empty() ) + fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, + branch->children()[1]); + else + fc[1] = selectSpaceLikeDecayBranching(children[1],maxScales,minmass,type, + HardBranchingPtr()); } - // H7 default - else if(_reconOpt==1) { - // update the history if needed - currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); - currentTree()->addInitialStateBranching(particle,children[0],children[1]); - // shower the first particle - if(fc[0].kinematics) { - if(children[0]->id()==particle->id()) { - if(!fb.hard) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch,type,fc[0]); - else if(fb.hard && ! branch->children()[0]->children().empty() ) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch->children()[0],type,fc[0]); - else - spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); - } - else { - if(fb.hard && !branch->children()[0]->children().empty() ) - truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); - // normal shower - else - timeLikeShower(children[0],type,fc[0],false); - } - } - // shower the second particle - if(fc[1].kinematics) { - if(children[0]->id()==particle->id()) { - if(!fb.hard) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch,type,fc[1]); - else if(fb.hard && ! branch->children()[0]->children().empty() ) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch->children()[0],type,fc[1]); - else - spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); - } - else { - if(fb.hard && !branch->children()[0]->children().empty() ) - truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); - // normal shower - else - timeLikeShower(children[0],type,fc[1],false); - } - } - // clean up the vetoed emission - if(particle->virtualMass()==ZERO) { - particle->showerKinematics(ShoKinPtr()); - for(unsigned int ix=0;ixabandonChild(children[ix]); - children.clear(); - particle->vetoEmission(fb.type,fb.kinematics->scale()); - // generate the new emission - fb = selectSpaceLikeDecayBranching(particle,maxScales,minmass,type,branch); - // must be at least hard emission - assert(fb.kinematics); - setupChildren = true; - continue; - } - else { - updateHistory(children[1]); - break; - } + else { + if(fb.hard && !branch->children()[1]->children().empty() ) + fc[1] = selectTimeLikeBranching(children[1],type,branch->children()[1]); + else + fc[1] = selectTimeLikeBranching(children[1],type,HardBranchingPtr()); } - else if(_reconOpt>=2) { - // cut-off masses for the branching - const vector & virtualMasses = fb.sudakov->virtualMasses(fb.ids); - // compute the masses of the children - Energy masses[3]; - // space-like children - masses[1] = children[0]->virtualMass(); - // time-like child - if(fc[1].kinematics) { - const vector & vm = fc[1].sudakov->virtualMasses(fc[1].ids); - Energy2 q2 = - fc[1].kinematics->z()*(1.-fc[1].kinematics->z())*sqr(fc[1].kinematics->scale()); - if(fc[1].ids[0]->id()!=ParticleID::g) q2 += sqr(vm[0]); - masses[2] = sqrt(q2); - } - else { - masses[2] = virtualMasses[2]; - } - masses[0]=particle->virtualMass(); - double z = fb.kinematics->z(); - Energy2 pt2 = (1.-z)*(z*sqr(masses[0])-sqr(masses[1])-z/(1.-z)*sqr(masses[2])); - if(pt2>=ZERO) { - break; - } - else { - // reset the scales for the children - for(unsigned int ix=0;ix<2;++ix) { - if(fc[ix].kinematics) - children[ix]->vetoEmission(fc[ix].type,fc[ix].kinematics->scale()); - else { - if(ix==0) - children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,Constants::MaxEnergy); - else - children[ix]->vetoEmission(ShowerPartnerType::QCDColourLine,ZERO); - } - } - children[0]->virtualMass(_progenitor->progenitor()->mass()); - children[1]->virtualMass(ZERO); - } + } + // old default + // update the history if needed + currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); + currentTree()->addInitialStateBranching(particle,children[0],children[1]); + // shower the first particle + if(fc[0].kinematics) { + if(children[0]->id()==particle->id()) { + if(!fb.hard) + truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, + branch,type,fc[0]); + else if(fb.hard && ! branch->children()[0]->children().empty() ) + truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, + branch->children()[0],type,fc[0]); + else + spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); } - }; - if(_reconOpt>=2) { - // update the history if needed - currentTree()->updateInitialStateShowerProduct(progenitor(),children[0]); - currentTree()->addInitialStateBranching(particle,children[0],children[1]); - // shower the first particle - if(fc[0].kinematics) { - if(children[0]->id()==particle->id()) { - if(!fb.hard) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch,type,fc[0]); - else if(fb.hard && ! branch->children()[0]->children().empty() ) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch->children()[0],type,fc[0]); - else - spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[0]); - } - else { - if(fb.hard && !branch->children()[0]->children().empty() ) - truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); - // normal shower - else - timeLikeShower(children[0],type,fc[0],false); - } + else { + if(fb.hard && !branch->children()[0]->children().empty() ) + truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[0],false); + // normal shower + else + timeLikeShower(children[0],type,fc[0],false); } - // shower the second particle - if(fc[1].kinematics) { - if(children[0]->id()==particle->id()) { - if(!fb.hard) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch,type,fc[1]); - else if(fb.hard && ! branch->children()[0]->children().empty() ) - truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, - branch->children()[0],type,fc[1]); - else - spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); - } - else { - if(fb.hard && !branch->children()[0]->children().empty() ) - truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); - // normal shower - else - timeLikeShower(children[0],type,fc[1],false); - } + } + // shower the second particle + if(fc[1].kinematics) { + if(children[0]->id()==particle->id()) { + if(!fb.hard) + truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, + branch,type,fc[1]); + else if(fb.hard && ! branch->children()[0]->children().empty() ) + truncatedSpaceLikeDecayShower( children[0],maxScales,minmass, + branch->children()[0],type,fc[1]); + else + spaceLikeDecayShower( children[0],maxScales,minmass,type,fc[1]); } - updateHistory(children[1]); + else { + if(fb.hard && !branch->children()[0]->children().empty() ) + truncatedTimeLikeShower(children[0],branch->children()[0],type,fc[1],false); + // normal shower + else + timeLikeShower(children[0],type,fc[1],false); + } } + updateHistory(children[1]); + // TODO DO WE NEED A CHECK IF RECONPT !=0 return true; } void QTildeShowerHandler::connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard ) { ShowerParticleVector particles; // find the Sudakovs for(set::iterator cit=hardTree->branchings().begin(); cit!=hardTree->branchings().end();++cit) { // Sudakovs for ISR if((**cit).parent()&&(**cit).status()==HardBranching::Incoming) { ++_nis; array br; br[0] = (**cit).parent()->branchingParticle()->id(); br[1] = (**cit). branchingParticle()->id(); br[2] = (**cit).parent()->children()[0]==*cit ? (**cit).parent()->children()[1]->branchingParticle()->id() : (**cit).parent()->children()[0]->branchingParticle()->id(); BranchingList branchings = splittingGenerator()->initialStateBranchings(); if(br[1]<0&&br[0]==br[1]) { br[0] = abs(br[0]); br[1] = abs(br[1]); } else if(br[1]<0) { br[1] = -br[1]; br[2] = -br[2]; } long index = abs(br[1]); SudakovPtr sudakov; for(BranchingList::const_iterator cjt = branchings.lower_bound(index); cjt != branchings.upper_bound(index); ++cjt ) { IdList ids = cjt->second.particles; if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) { sudakov=cjt->second.sudakov; break; } } if(!sudakov) throw Exception() << "Can't find Sudakov for the hard emission in " << "QTildeShowerHandler::connectTrees() for ISR" << Exception::runerror; (**cit).parent()->sudakov(sudakov); } // Sudakovs for FSR else if(!(**cit).children().empty()) { ++_nfs; array br; br[0] = (**cit) .branchingParticle()->id(); br[1] = (**cit).children()[0]->branchingParticle()->id(); br[2] = (**cit).children()[1]->branchingParticle()->id(); BranchingList branchings = splittingGenerator()->finalStateBranchings(); if(br[0]<0) { br[0] = abs(br[0]); br[1] = abs(br[1]); br[2] = abs(br[2]); } long index = br[0]; SudakovPtr sudakov; for(BranchingList::const_iterator cjt = branchings.lower_bound(index); cjt != branchings.upper_bound(index); ++cjt ) { IdList ids = cjt->second.particles; if(ids[0]->id()==br[0]&&ids[1]->id()==br[1]&&ids[2]->id()==br[2]) { sudakov=cjt->second.sudakov; break; } } if(!sudakov) { throw Exception() << "Can't find Sudakov for the hard emission in " << "QTildeShowerHandler::connectTrees()" << Exception::runerror; } (**cit).sudakov(sudakov); } } // calculate the evolution scale for(set::iterator cit=hardTree->branchings().begin(); cit!=hardTree->branchings().end();++cit) { particles.push_back((*cit)->branchingParticle()); } - showerModel()->partnerFinder()-> + partnerFinder()-> setInitialEvolutionScales(particles,!hard,interaction_,true); hardTree->partnersSet(true); // inverse reconstruction if(hard) { - showerModel()->kinematicsReconstructor()-> + kinematicsReconstructor()-> deconstructHardJets(hardTree,interaction_); } else - showerModel()->kinematicsReconstructor()-> + kinematicsReconstructor()-> deconstructDecayJets(hardTree,interaction_); // now reset the momenta of the showering particles vector particlesToShower=showerTree->extractProgenitors(); // match them map partners; for(set::const_iterator bit=hardTree->branchings().begin(); bit!=hardTree->branchings().end();++bit) { Energy2 dmin( 1e30*GeV2 ); ShowerProgenitorPtr partner; for(vector::const_iterator pit=particlesToShower.begin(); pit!=particlesToShower.end();++pit) { if(partners.find(*pit)!=partners.end()) continue; if( (**bit).branchingParticle()->id() != (**pit).progenitor()->id() ) continue; if( (**bit).branchingParticle()->isFinalState() != (**pit).progenitor()->isFinalState() ) continue; if( (**pit).progenitor()->isFinalState() ) { Energy2 dtest = sqr( (**pit).progenitor()->momentum().x() - (**bit).showerMomentum().x() ) + sqr( (**pit).progenitor()->momentum().y() - (**bit).showerMomentum().y() ) + sqr( (**pit).progenitor()->momentum().z() - (**bit).showerMomentum().z() ) + sqr( (**pit).progenitor()->momentum().t() - (**bit).showerMomentum().t() ); // add mass difference for identical particles (e.g. Z0 Z0 production) dtest += 1e10*sqr((**pit).progenitor()->momentum().m()-(**bit).showerMomentum().m()); if( dtest < dmin ) { partner = *pit; dmin = dtest; } } else { // ensure directions are right if((**pit).progenitor()->momentum().z()/(**bit).showerMomentum().z()>ZERO) { partner = *pit; break; } } } if(!partner) throw Exception() << "Failed to match shower and hard trees in QTildeShowerHandler::hardestEmission" << Exception::eventerror; partners[partner] = *bit; } for(vector::const_iterator pit=particlesToShower.begin(); pit!=particlesToShower.end();++pit) { HardBranchingPtr partner = partners[*pit]; if((**pit).progenitor()->dataPtr()->stable()) { (**pit).progenitor()->set5Momentum(partner->showerMomentum()); (**pit).copy()->set5Momentum(partner->showerMomentum()); } else { Lorentz5Momentum oldMomentum = (**pit).progenitor()->momentum(); Lorentz5Momentum newMomentum = partner->showerMomentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); (**pit).progenitor()->transform(boost); (**pit).copy() ->transform(boost); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); (**pit).progenitor()->transform(boost); (**pit).copy() ->transform(boost); } } // correction boosts for daughter trees for(map >::const_iterator tit = showerTree->treelinks().begin(); tit != showerTree->treelinks().end();++tit) { ShowerTreePtr decayTree = tit->first; map::const_iterator cit = decayTree->incomingLines().begin(); // reset the momentum of the decay particle Lorentz5Momentum oldMomentum = cit->first->progenitor()->momentum(); Lorentz5Momentum newMomentum = tit->second.second->momentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); decayTree->transform(boost,true); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); decayTree->transform(boost,true); } } void QTildeShowerHandler::doShowering(bool hard,XCPtr xcomb) { // zero number of emissions _nis = _nfs = 0; // if MC@NLO H event and limited emissions // indicate both final and initial state emission if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) { _nis = _nfs = 1; } // extract particles to shower vector particlesToShower(setupShower(hard)); // check if we should shower bool colCharge = false; for(unsigned int ix=0;ixprogenitor()->dataPtr()->coloured() || particlesToShower[ix]->progenitor()->dataPtr()->charged()) { colCharge = true; break; } } if(!colCharge) { _currenttree->hasShowered(true); return; } // setup the maximum scales for the shower if (restrictPhasespace()) setupMaximumScales(particlesToShower,xcomb); // set the hard scales for the profiles setupHardScales(particlesToShower,xcomb); // specific stuff for hard processes and decays Energy minmass(ZERO), mIn(ZERO); // hard process generate the intrinsic p_T once and for all if(hard) { generateIntrinsicpT(particlesToShower); } // decay compute the minimum mass of the final-state else { for(unsigned int ix=0;ixprogenitor()->isFinalState()) { if(particlesToShower[ix]->progenitor()->dataPtr()->stable()) minmass += particlesToShower[ix]->progenitor()->dataPtr()->constituentMass(); else minmass += particlesToShower[ix]->progenitor()->mass(); } else { mIn = particlesToShower[ix]->progenitor()->mass(); } } // throw exception if decay can't happen if ( minmass > mIn ) { throw Exception() << "QTildeShowerHandler.cc: Mass of decaying particle is " << "below constituent masses of decay products." << Exception::eventerror; } } // setup for reweighted bool reWeighting = _reWeight && hard && ShowerHandler::currentHandler()->firstInteraction(); double eventWeight=0.; unsigned int nTryReWeight(0); // create random particle vector (only need to do once) vector tmp; unsigned int nColouredIncoming = 0; while(particlesToShower.size()>0){ unsigned int xx=UseRandom::irnd(particlesToShower.size()); tmp.push_back(particlesToShower[xx]); particlesToShower.erase(particlesToShower.begin()+xx); } particlesToShower=tmp; for(unsigned int ix=0;ixprogenitor()->isFinalState() && particlesToShower[ix]->progenitor()->coloured()) ++nColouredIncoming; } bool switchRecon = hard && nColouredIncoming !=1; // main shower loop unsigned int ntry(0); bool reconstructed = false; do { // clear results of last attempt if needed if(ntry!=0) { currentTree()->clear(); setEvolutionPartners(hard,interaction_,true); _nis = _nfs = 0; // if MC@NLO H event and limited emissions // indicate both final and initial state emission if ( currentTree()->isMCatNLOHEvent() && _limitEmissions != 0 ) { _nis = _nfs = 1; } for(unsigned int ix=0; ixprogenitor()->spinInfo(); if(spin && spin->decayVertex() && dynamic_ptr_cast(spin->decayVertex())) { spin->decayVertex(VertexPtr()); } } + for(unsigned int ix=0;ixprogenitor()->isFinalState() || + (hard && !particlesToShower[ix]->progenitor()->isFinalState())) { + if(particlesToShower[ix]->progenitor()->spinInfo()) + particlesToShower[ix]->progenitor()->spinInfo()->reset(); + } + } } // loop over particles for(unsigned int ix=0;ixprogenitor()->isFinalState()) { if(!doFSR()) continue; // perform shower progenitor()->hasEmitted(startTimeLikeShower(interaction_)); } // initial-state radiation else { if(!doISR()) continue; // hard process if(hard) { // get the PDF setBeamParticle(_progenitor->beam()); if(!beamParticle()) { throw Exception() << "Incorrect type of beam particle in " << "QTildeShowerHandler::doShowering(). " << "This should not happen for conventional choices but may happen if you have used a" << " non-default choice and have not changed the create ParticleData line in the input files" << " for this particle to create BeamParticleData." << Exception::runerror; } // perform the shower // set the beam particle tPPtr beamparticle=progenitor()->original(); if(!beamparticle->parents().empty()) beamparticle=beamparticle->parents()[0]; // generate the shower progenitor()->hasEmitted(startSpaceLikeShower(beamparticle, interaction_)); } // decay else { // skip colour and electrically neutral particles if(!progenitor()->progenitor()->dataPtr()->coloured() && !progenitor()->progenitor()->dataPtr()->charged()) { progenitor()->hasEmitted(false); continue; } // perform shower // set the scales correctly. The current scale is the maximum scale for // emission not the starting scale ShowerParticle::EvolutionScales maxScales(progenitor()->progenitor()->scales()); progenitor()->progenitor()->scales() = ShowerParticle::EvolutionScales(); if(progenitor()->progenitor()->dataPtr()->charged()) { progenitor()->progenitor()->scales().QED = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QED_noAO = progenitor()->progenitor()->mass(); } if(progenitor()->progenitor()->hasColour()) { progenitor()->progenitor()->scales().QCD_c = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QCD_c_noAO = progenitor()->progenitor()->mass(); } if(progenitor()->progenitor()->hasAntiColour()) { progenitor()->progenitor()->scales().QCD_ac = progenitor()->progenitor()->mass(); progenitor()->progenitor()->scales().QCD_ac_noAO = progenitor()->progenitor()->mass(); } // perform the shower progenitor()->hasEmitted(startSpaceLikeDecayShower(maxScales,minmass, interaction_)); } } } // do the kinematic reconstruction, checking if it worked reconstructed = hard ? - showerModel()->kinematicsReconstructor()-> + kinematicsReconstructor()-> reconstructHardJets (currentTree(),intrinsicpT(),interaction_, switchRecon && ntry>maximumTries()/2) : - showerModel()->kinematicsReconstructor()-> + kinematicsReconstructor()-> reconstructDecayJets(currentTree(),interaction_); if(!reconstructed) continue; // apply vetos on the full shower for(vector::const_iterator it=_fullShowerVetoes.begin(); it!=_fullShowerVetoes.end();++it) { int veto = (**it).applyVeto(currentTree()); if(veto<0) continue; // veto the shower if(veto==0) { reconstructed = false; break; } // veto the shower and reweight else if(veto==1) { reconstructed = false; break; } // veto the event else if(veto==2) { throw Veto(); } } if(reWeighting) { if(reconstructed) eventWeight += 1.; reconstructed=false; ++nTryReWeight; if(nTryReWeight==_nReWeight) { reWeighting = false; if(eventWeight==0.) throw Veto(); } } } while(!reconstructed&&maximumTries()>++ntry); // check if failed to generate the shower if(ntry==maximumTries()) { if(hard) throw ShowerHandler::ShowerTriesVeto(ntry); else throw Exception() << "Failed to generate the shower after " << ntry << " attempts in QTildeShowerHandler::showerDecay()" << Exception::eventerror; } // handle the weights and apply any reweighting required if(nTryReWeight>0) { tStdEHPtr seh = dynamic_ptr_cast(generator()->currentEventHandler()); static bool first = true; if(seh) { seh->reweight(eventWeight/double(nTryReWeight)); } else if(first) { generator()->log() << "Reweighting the shower only works with internal Herwig7 processes" << "Presumably you are showering Les Houches Events. These will not be" << "reweighted\n"; first = false; } } // tree has now showered _currenttree->hasShowered(true); hardTree(HardTreePtr()); } void QTildeShowerHandler:: convertHardTree(bool hard,ShowerInteraction type) { map cmap; // incoming particles for(map::const_iterator cit=currentTree()->incomingLines().begin();cit!=currentTree()->incomingLines().end();++cit) { map::const_iterator mit = hardTree()->particles().find(cit->first->progenitor()); // put the colour lines in the map ShowerParticlePtr oldParticle = cit->first->progenitor(); ShowerParticlePtr newParticle = mit->second->branchingParticle(); ColinePtr cLine = oldParticle-> colourLine(); ColinePtr aLine = oldParticle->antiColourLine(); if(newParticle->colourLine() && cmap.find(newParticle-> colourLine())==cmap.end()) cmap[newParticle-> colourLine()] = cLine; if(newParticle->antiColourLine() && cmap.find(newParticle->antiColourLine())==cmap.end()) cmap[newParticle->antiColourLine()] = aLine; // check whether or not particle emits bool emission = mit->second->parent(); if(emission) { if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); } if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); } newParticle = mit->second->parent()->branchingParticle(); } // get the new colour lines ColinePtr newCLine,newALine; // sort out colour lines if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newCLine = cmap[ctemp]; } else { newCLine = new_ptr(ColourLine()); cmap[ctemp] = newCLine; } } // and anticolour lines if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newALine = cmap[ctemp]; } else { newALine = new_ptr(ColourLine()); cmap[ctemp] = newALine; } } // remove colour lines from old particle if(aLine) { aLine->removeAntiColoured(cit->first->copy()); aLine->removeAntiColoured(cit->first->progenitor()); } if(cLine) { cLine->removeColoured(cit->first->copy()); cLine->removeColoured(cit->first->progenitor()); } // add particle to colour lines if(newCLine) newCLine->addColoured (newParticle); if(newALine) newALine->addAntiColoured(newParticle); // insert new particles cit->first->copy(newParticle); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,false))); cit->first->progenitor(sp); currentTree()->incomingLines()[cit->first]=sp; cit->first->perturbative(!emission); // and the emitted particle if needed if(emission) { ShowerParticlePtr newOut = mit->second->parent()->children()[1]->branchingParticle(); if(newOut->colourLine()) { ColinePtr ctemp = newOut-> colourLine(); ctemp->removeColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addColoured (newOut); } if(newOut->antiColourLine()) { ColinePtr ctemp = newOut->antiColourLine(); ctemp->removeAntiColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addAntiColoured(newOut); } ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout)); out->perturbative(false); currentTree()->outgoingLines().insert(make_pair(out,sout)); } if(hard) { // sort out the value of x if(mit->second->beam()->momentum().z()>ZERO) { sp->x(newParticle->momentum(). plus()/mit->second->beam()->momentum(). plus()); } else { sp->x(newParticle->momentum().minus()/mit->second->beam()->momentum().minus()); } } } // outgoing particles for(map::const_iterator cit=currentTree()->outgoingLines().begin();cit!=currentTree()->outgoingLines().end();++cit) { map >::const_iterator tit; for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==cit->first->progenitor()) break; } map::const_iterator mit = hardTree()->particles().find(cit->first->progenitor()); if(mit==hardTree()->particles().end()) continue; // put the colour lines in the map ShowerParticlePtr oldParticle = cit->first->progenitor(); ShowerParticlePtr newParticle = mit->second->branchingParticle(); ShowerParticlePtr newOut; ColinePtr cLine = oldParticle-> colourLine(); ColinePtr aLine = oldParticle->antiColourLine(); if(newParticle->colourLine() && cmap.find(newParticle-> colourLine())==cmap.end()) cmap[newParticle-> colourLine()] = cLine; if(newParticle->antiColourLine() && cmap.find(newParticle->antiColourLine())==cmap.end()) cmap[newParticle->antiColourLine()] = aLine; // check whether or not particle emits bool emission = !mit->second->children().empty(); if(emission) { if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); } if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); } newParticle = mit->second->children()[0]->branchingParticle(); newOut = mit->second->children()[1]->branchingParticle(); if(newParticle->id()!=oldParticle->id()&&newParticle->id()==newOut->id()) swap(newParticle,newOut); } // get the new colour lines ColinePtr newCLine,newALine; // sort out colour lines if(newParticle->colourLine()) { ColinePtr ctemp = newParticle-> colourLine(); ctemp->removeColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newCLine = cmap[ctemp]; } else { newCLine = new_ptr(ColourLine()); cmap[ctemp] = newCLine; } } // and anticolour lines if(newParticle->antiColourLine()) { ColinePtr ctemp = newParticle->antiColourLine(); ctemp->removeAntiColoured(newParticle); if(cmap.find(ctemp)!=cmap.end()) { newALine = cmap[ctemp]; } else { newALine = new_ptr(ColourLine()); cmap[ctemp] = newALine; } } // remove colour lines from old particle if(aLine) { aLine->removeAntiColoured(cit->first->copy()); aLine->removeAntiColoured(cit->first->progenitor()); } if(cLine) { cLine->removeColoured(cit->first->copy()); cLine->removeColoured(cit->first->progenitor()); } // special for unstable particles if(newParticle->id()==oldParticle->id() && (tit!=currentTree()->treelinks().end()||!oldParticle->dataPtr()->stable())) { Lorentz5Momentum oldMomentum = oldParticle->momentum(); Lorentz5Momentum newMomentum = newParticle->momentum(); LorentzRotation boost( oldMomentum.findBoostToCM(),oldMomentum.e()/oldMomentum.mass()); if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false); oldParticle->transform(boost); boost = LorentzRotation(-newMomentum.findBoostToCM(),newMomentum.e()/newMomentum.mass()); oldParticle->transform(boost); if(tit!=currentTree()->treelinks().end()) tit->first->transform(boost,false); newParticle=oldParticle; } // add particle to colour lines if(newCLine) newCLine->addColoured (newParticle); if(newALine) newALine->addAntiColoured(newParticle); // insert new particles cit->first->copy(newParticle); ShowerParticlePtr sp(new_ptr(ShowerParticle(*newParticle,1,true))); cit->first->progenitor(sp); currentTree()->outgoingLines()[cit->first]=sp; cit->first->perturbative(!emission); // and the emitted particle if needed if(emission) { if(newOut->colourLine()) { ColinePtr ctemp = newOut-> colourLine(); ctemp->removeColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addColoured (newOut); } if(newOut->antiColourLine()) { ColinePtr ctemp = newOut->antiColourLine(); ctemp->removeAntiColoured(newOut); assert(cmap.find(ctemp)!=cmap.end()); cmap[ctemp]->addAntiColoured(newOut); } ShowerParticlePtr sout=new_ptr(ShowerParticle(*newOut,1,true)); ShowerProgenitorPtr out=new_ptr(ShowerProgenitor(cit->first->original(),newOut,sout)); out->perturbative(false); currentTree()->outgoingLines().insert(make_pair(out,sout)); } // update any decay products if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(cit->first,sp)); } // reset the tree currentTree()->resetShowerProducts(); // reextract the particles and set the colour partners vector particles = currentTree()->extractProgenitorParticles(); // clear the partners for(unsigned int ix=0;ixpartner(ShowerParticlePtr()); particles[ix]->clearPartners(); } // clear the tree hardTree(HardTreePtr()); // Set the initial evolution scales - showerModel()->partnerFinder()-> + partnerFinder()-> setInitialEvolutionScales(particles,!hard,type,!_hardtree); } Branching QTildeShowerHandler::selectTimeLikeBranching(tShowerParticlePtr particle, ShowerInteraction type, HardBranchingPtr branch) { Branching fb; unsigned int iout=0; while (true) { // break if doing truncated shower and no truncated shower needed if(branch && (!isTruncatedShowerON()||hardOnly())) break; fb=_splittingGenerator->chooseForwardBranching(*particle,_finalenhance,type); // no emission break if(!fb.kinematics) break; // special for truncated shower if(branch) { // check haven't evolved too far if(fb.kinematics->scale() < branch->scale()) { fb=Branching(); break; } // find the truncated line iout=0; if(fb.ids[1]->id()!=fb.ids[2]->id()) { if(fb.ids[1]->id()==particle->id()) iout=1; else if (fb.ids[2]->id()==particle->id()) iout=2; } else if(fb.ids[1]->id()==particle->id()) { if(fb.kinematics->z()>0.5) iout=1; else iout=2; } // apply the vetos for the truncated shower // no flavour changing branchings if(iout==0) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z(); // only if same interaction for forced branching ShowerInteraction type2 = convertInteraction(fb.type); // and evolution if(type2==branch->sudakov()->interactionType()) { if(zsplit < 0.5 || // hardest line veto fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // pt veto if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // standard vetos for all emissions if(timeLikeVetoed(fb,particle)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); continue; } // special for already decayed particles // don't allow flavour changing branchings bool vetoDecay = false; for(map >::const_iterator tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first == progenitor()) { map::const_iterator it = currentTree()->outgoingLines().find(progenitor()); if(it!=currentTree()->outgoingLines().end() && particle == it->second && fb.ids[0]!=fb.ids[1] && fb.ids[1]!=fb.ids[2]) { vetoDecay = true; break; } } } if(vetoDecay) { particle->vetoEmission(fb.type,fb.kinematics->scale()); if(particle->spinInfo()) particle->spinInfo()->decayVertex(VertexPtr()); continue; } break; } // normal case if(!branch) { if(fb.kinematics) fb.hard = false; return fb; } // truncated emission if(fb.kinematics) { fb.hard = false; fb.iout = iout; return fb; } // otherwise need to return the hard emission // construct the kinematics for the hard emission - ShoKinPtr showerKin= - branch->sudakov()->createFinalStateBranching(branch->scale(), - branch->children()[0]->z(), - branch->phi(), - branch->children()[0]->pT()); + ShoKinPtr showerKin = new_ptr(FS_QTildeShowerKinematics1to2( + branch->scale(), + branch->children()[0]->z(), + branch->phi(), + branch->children()[0]->pT(), + branch->sudakov() + )); + IdList idlist(3); idlist[0] = particle->dataPtr(); idlist[1] = branch->children()[0]->branchingParticle()->dataPtr(); idlist[2] = branch->children()[1]->branchingParticle()->dataPtr(); fb = Branching( showerKin, idlist, branch->sudakov(),branch->type() ); fb.hard = true; fb.iout=0; // return it return fb; } Branching QTildeShowerHandler::selectSpaceLikeDecayBranching(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, HardBranchingPtr branch) { Branching fb; unsigned int iout=0; while (true) { // break if doing truncated shower and no truncated shower needed if(branch && (!isTruncatedShowerON()||hardOnly())) break; // select branching fb=_splittingGenerator->chooseDecayBranching(*particle,maxScales,minmass, _initialenhance,type); // return if no radiation if(!fb.kinematics) break; // special for truncated shower if(branch) { // check haven't evolved too far if(fb.kinematics->scale() < branch->scale()) { fb=Branching(); break; } // find the truncated line iout=0; if(fb.ids[1]->id()!=fb.ids[2]->id()) { if(fb.ids[1]->id()==particle->id()) iout=1; else if (fb.ids[2]->id()==particle->id()) iout=2; } else if(fb.ids[1]->id()==particle->id()) { if(fb.kinematics->z()>0.5) iout=1; else iout=2; } // apply the vetos for the truncated shower // no flavour changing branchings if(iout==0) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } ShowerInteraction type2 = convertInteraction(fb.type); double zsplit = iout==1 ? fb.kinematics->z() : 1-fb.kinematics->z(); if(type2==branch->sudakov()->interactionType()) { if(zsplit < 0.5 || // hardest line veto fb.kinematics->scale()*zsplit < branch->scale() ) { // angular ordering veto particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // pt veto if(fb.kinematics->pT() > progenitor()->maximumpT(type2)) { particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } } // if not vetoed break if(spaceLikeDecayVetoed(fb,particle)) { // otherwise reset scale and continue particle->vetoEmission(fb.type,fb.kinematics->scale()); continue; } break; } // normal case if(!branch) { if(fb.kinematics) fb.hard = false; return fb; } // truncated emission if(fb.kinematics) { fb.hard = false; fb.iout = iout; return fb; } // otherwise need to return the hard emission // construct the kinematics for the hard emission - ShoKinPtr showerKin= - branch->sudakov()->createDecayBranching(branch->scale(), - branch->children()[0]->z(), - branch->phi(), - branch->children()[0]->pT()); + ShoKinPtr showerKin = new_ptr(Decay_QTildeShowerKinematics1to2( + branch->scale(), + branch->children()[0]->z(), + branch->phi(), + branch->children()[0]->pT(), + branch->sudakov())); IdList idlist(3); idlist[0] = particle->dataPtr(); idlist[1] = branch->children()[0]->branchingParticle()->dataPtr(); idlist[2] = branch->children()[1]->branchingParticle()->dataPtr(); // create the branching fb = Branching( showerKin, idlist, branch->sudakov(),ShowerPartnerType::QCDColourLine ); fb.hard=true; fb.iout=0; // return it return fb; } void QTildeShowerHandler::checkFlags() { string error = "Inconsistent hard emission set-up in QTildeShowerHandler::showerHardProcess(). "; if ( ( currentTree()->isMCatNLOSEvent() || currentTree()->isMCatNLOHEvent() ) ) { if (_hardEmission ==2 ) throw Exception() << error << "Cannot generate POWHEG matching with MC@NLO shower " << "approximation. Add 'set QTildeShowerHandler:HardEmission 0' to input file." << Exception::runerror; if ( canHandleMatchboxTrunc() ) throw Exception() << error << "Cannot use truncated qtilde shower with MC@NLO shower " << "approximation. Set LHCGenerator:EventHandler" << ":CascadeHandler to '/Herwig/Shower/ShowerHandler' or " << "'/Herwig/Shower/Dipole/DipoleShowerHandler'." << Exception::runerror; } else if ( ((currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) ) && _hardEmission != 2){ if ( canHandleMatchboxTrunc()) throw Exception() << error << "Unmatched events requested for POWHEG shower " << "approximation. Set QTildeShowerHandler:HardEmission to " << "'POWHEG'." << Exception::runerror; else if (_hardEmissionWarn) { _hardEmissionWarn = false; _hardEmission=2; throw Exception() << error << "Unmatched events requested for POWHEG shower " << "approximation. Changing QTildeShowerHandler:HardEmission from " << _hardEmission << " to 2" << Exception::warning; } } if ( currentTree()->isPowhegSEvent() || currentTree()->isPowhegHEvent()) { if (currentTree()->showerApproximation()->needsTruncatedShower() && !canHandleMatchboxTrunc() ) throw Exception() << error << "Current shower handler cannot generate truncated shower. " << "Set Generator:EventHandler:CascadeHandler to " << "'/Herwig/Shower/PowhegShowerHandler'." << Exception::runerror; } else if ( currentTree()->truncatedShower() && _missingTruncWarn) { _missingTruncWarn=false; throw Exception() << "Warning: POWHEG shower approximation used without " << "truncated shower. Set Generator:EventHandler:" << "CascadeHandler to '/Herwig/Shower/PowhegShowerHandler' and " << "'MEMatching:TruncatedShower Yes'." << Exception::warning; } // else if ( !dipme && _hardEmissionMode > 1 && // firstInteraction()) // throw Exception() << error // << "POWHEG matching requested for LO events. Include " // << "'set Factory:ShowerApproximation MEMatching' in input file." // << Exception::runerror; } tPPair QTildeShowerHandler::remakeRemnant(tPPair oldp){ // get the parton extractor PartonExtractor & pex = *lastExtractor(); // get the new partons tPPair newp = make_pair(findFirstParton(oldp.first ), findFirstParton(oldp.second)); // if the same do nothing if(newp == oldp) return oldp; // Creates the new remnants and returns the new PartonBinInstances // ATTENTION Broken here for very strange configuration PBIPair newbins = pex.newRemnants(oldp, newp, newStep()); newStep()->addIntermediate(newp.first); newStep()->addIntermediate(newp.second); // return the new partons return newp; } PPtr QTildeShowerHandler::findFirstParton(tPPtr seed) const{ if(seed->parents().empty()) return seed; tPPtr parent = seed->parents()[0]; //if no parent there this is a loose end which will //be connected to the remnant soon. if(!parent || parent == incomingBeams().first || parent == incomingBeams().second ) return seed; else return findFirstParton(parent); } void QTildeShowerHandler::decay(ShowerTreePtr tree, ShowerDecayMap & decay) { // must be one incoming particle assert(tree->incomingLines().size()==1); // apply any transforms tree->applyTransforms(); // if already decayed return if(!tree->outgoingLines().empty()) return; // now we need to replace the particle with a new copy after the shower // find particle after the shower map >::const_iterator tit = tree->parent()->treelinks().find(tree); assert(tit!=tree->parent()->treelinks().end()); ShowerParticlePtr newparent=tit->second.second; PerturbativeProcessPtr newProcess = new_ptr(PerturbativeProcess()); newProcess->incoming().push_back(make_pair(newparent,PerturbativeProcessPtr())); DecayProcessMap decayMap; ShowerHandler::decay(newProcess,decayMap); ShowerTree::constructTrees(tree,decay,newProcess,decayMap); } namespace { ShowerProgenitorPtr findFinalStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) { map::iterator partner; Energy2 dmin(1e30*GeV2); for(map::iterator cit =tree->outgoingLines().begin(); cit!=tree->outgoingLines().end(); ++cit) { if(cit->second->id()!=id) continue; Energy2 test = sqr(cit->second->momentum().x()-momentum.x())+ sqr(cit->second->momentum().y()-momentum.y())+ sqr(cit->second->momentum().z()-momentum.z())+ sqr(cit->second->momentum().t()-momentum.t()); if(testfirst; } ShowerProgenitorPtr findInitialStateLine(ShowerTreePtr tree, long id, Lorentz5Momentum momentum) { map::iterator partner; Energy2 dmin(1e30*GeV2); for(map::iterator cit =tree->incomingLines().begin(); cit!=tree->incomingLines().end(); ++cit) { if(cit->second->id()!=id) continue; Energy2 test = sqr(cit->second->momentum().x()-momentum.x())+ sqr(cit->second->momentum().y()-momentum.y())+ sqr(cit->second->momentum().z()-momentum.z())+ sqr(cit->second->momentum().t()-momentum.t()); if(testfirst; } void fixSpectatorColours(PPtr newSpect,ShowerProgenitorPtr oldSpect, ColinePair & cline,ColinePair & aline, bool reconnect) { cline.first = oldSpect->progenitor()->colourLine(); cline.second = newSpect->colourLine(); aline.first = oldSpect->progenitor()->antiColourLine(); aline.second = newSpect->antiColourLine(); if(!reconnect) return; if(cline.first) { cline.first ->removeColoured(oldSpect->copy()); cline.first ->removeColoured(oldSpect->progenitor()); cline.second->removeColoured(newSpect); cline.first ->addColoured(newSpect); } if(aline.first) { aline.first ->removeAntiColoured(oldSpect->copy()); aline.first ->removeAntiColoured(oldSpect->progenitor()); aline.second->removeAntiColoured(newSpect); aline.first ->addAntiColoured(newSpect); } } void fixInitialStateEmitter(ShowerTreePtr tree, PPtr newEmit,PPtr emitted, ShowerProgenitorPtr emitter, ColinePair cline,ColinePair aline,double x) { // sort out the colours if(emitted->dataPtr()->iColour()==PDT::Colour8) { // emitter if(cline.first && cline.first == emitter->progenitor()->antiColourLine() && cline.second !=newEmit->antiColourLine()) { // sort out not radiating line ColinePtr col = emitter->progenitor()->colourLine(); if(col) { col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } } else if(aline.first && aline.first == emitter->progenitor()->colourLine() && aline.second !=newEmit->colourLine()) { // sort out not radiating line ColinePtr anti = emitter->progenitor()->antiColourLine(); if(anti) { anti->removeAntiColoured(emitter->copy()); anti->removeAntiColoured(emitter->progenitor()); newEmit->colourLine()->removeAntiColoured(newEmit); anti->addAntiColoured(newEmit); } } else assert(false); // emitted if(cline.first && cline.second==emitted->colourLine()) { cline.second->removeColoured(emitted); cline.first->addColoured(emitted); } else if(aline.first && aline.second==emitted->antiColourLine()) { aline.second->removeAntiColoured(emitted); aline.first->addAntiColoured(emitted); } else assert(false); } else { if(emitter->progenitor()->antiColourLine() ) { ColinePtr col = emitter->progenitor()->antiColourLine(); col->removeAntiColoured(emitter->copy()); col->removeAntiColoured(emitter->progenitor()); if(newEmit->antiColourLine()) { newEmit->antiColourLine()->removeAntiColoured(newEmit); col->addAntiColoured(newEmit); } else if (emitted->colourLine()) { emitted->colourLine()->removeColoured(emitted); col->addColoured(emitted); } else assert(false); } if(emitter->progenitor()->colourLine() ) { ColinePtr col = emitter->progenitor()->colourLine(); col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); if(newEmit->colourLine()) { newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } else if (emitted->antiColourLine()) { emitted->antiColourLine()->removeAntiColoured(emitted); col->addAntiColoured(emitted); } else assert(false); } } // update the emitter emitter->copy(newEmit); ShowerParticlePtr sp = new_ptr(ShowerParticle(*newEmit,1,false)); sp->x(x); emitter->progenitor(sp); tree->incomingLines()[emitter]=sp; emitter->perturbative(false); // add emitted sp=new_ptr(ShowerParticle(*emitted,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->original(),emitted,sp)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sp)); } void fixFinalStateEmitter(ShowerTreePtr tree, PPtr newEmit,PPtr emitted, ShowerProgenitorPtr emitter, ColinePair cline,ColinePair aline) { map >::const_iterator tit; // special case if decayed for(tit = tree->treelinks().begin(); tit != tree->treelinks().end();++tit) { if(tit->second.first && tit->second.second==emitter->progenitor()) break; } // sort out the colour lines if(cline.first && cline.first == emitter->progenitor()->antiColourLine() && cline.second !=newEmit->antiColourLine()) { // sort out not radiating line ColinePtr col = emitter->progenitor()->colourLine(); if(col) { col->removeColoured(emitter->copy()); col->removeColoured(emitter->progenitor()); newEmit->colourLine()->removeColoured(newEmit); col->addColoured(newEmit); } } else if(aline.first && aline.first == emitter->progenitor()->colourLine() && aline.second !=newEmit->colourLine()) { // sort out not radiating line ColinePtr anti = emitter->progenitor()->antiColourLine(); if(anti) { anti->removeAntiColoured(emitter->copy()); anti->removeAntiColoured(emitter->progenitor()); newEmit->colourLine()->removeAntiColoured(newEmit); anti->addAntiColoured(newEmit); } } else assert(false); // update the emitter emitter->copy(newEmit); ShowerParticlePtr sp = new_ptr(ShowerParticle(*newEmit,1,true)); emitter->progenitor(sp); tree->outgoingLines()[emitter]=sp; emitter->perturbative(false); // update for decaying particles if(tit!=tree->treelinks().end()) tree->updateLink(tit->first,make_pair(emitter,sp)); // add the emitted particle // sort out the colour if(cline.first && cline.second==emitted->antiColourLine()) { cline.second->removeAntiColoured(emitted); cline.first->addAntiColoured(emitted); } else if(aline.first && aline.second==emitted->colourLine()) { aline.second->removeColoured(emitted); aline.first->addColoured(emitted); } else assert(false); sp=new_ptr(ShowerParticle(*emitted,1,true)); ShowerProgenitorPtr gluon=new_ptr(ShowerProgenitor(emitter->original(), emitted,sp)); gluon->perturbative(false); tree->outgoingLines().insert(make_pair(gluon,sp)); } } void QTildeShowerHandler::setupMECorrection(RealEmissionProcessPtr real) { assert(real); - currentTree()->hardMatrixElementCorrection(true); // II emission if(real->emitter() < real->incoming().size() && real->spectator() < real->incoming().size()) { // recoiling system for( map::const_iterator cjt= currentTree()->outgoingLines().begin(); cjt != currentTree()->outgoingLines().end();++cjt ) { cjt->first->progenitor()->transform(real->transformation()); cjt->first->copy()->transform(real->transformation()); } // the the radiating system ShowerProgenitorPtr emitter,spectator; unsigned int iemit = real->emitter(); unsigned int ispect = real->spectator(); int ig = int(real->emitted())-int(real->incoming().size()); emitter = findInitialStateLine(currentTree(), real->bornIncoming()[iemit]->id(), real->bornIncoming()[iemit]->momentum()); spectator = findInitialStateLine(currentTree(), real->bornIncoming()[ispect]->id(), real->bornIncoming()[ispect]->momentum()); // sort out the colours ColinePair cline,aline; fixSpectatorColours(real->incoming()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->incoming()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect],1,false))); sp->x(ispect ==0 ? real->x().first :real->x().second); spectator->progenitor(sp); currentTree()->incomingLines()[spectator]=sp; spectator->perturbative(true); // now for the emitter fixInitialStateEmitter(currentTree(),real->incoming()[iemit],real->outgoing()[ig], emitter,cline,aline,iemit ==0 ? real->x().first :real->x().second); } // FF emission else if(real->emitter() >= real->incoming().size() && real->spectator() >= real->incoming().size()) { assert(real->outgoing()[real->emitted()-real->incoming().size()]->id()==ParticleID::g); // find the emitter and spectator in the shower tree ShowerProgenitorPtr emitter,spectator; int iemit = int(real->emitter())-int(real->incoming().size()); emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit]->id(), real->bornOutgoing()[iemit]->momentum()); int ispect = int(real->spectator())-int(real->incoming().size()); spectator = findFinalStateLine(currentTree(), real->bornOutgoing()[ispect]->id(), real->bornOutgoing()[ispect]->momentum()); map >::const_iterator tit; // first the spectator // special case if decayed for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==spectator->progenitor()) break; } // sort out the colours ColinePair cline,aline; fixSpectatorColours(real->outgoing()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->outgoing()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect],1,true))); spectator->progenitor(sp); currentTree()->outgoingLines()[spectator]=sp; spectator->perturbative(true); // update for decaying particles if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(spectator,sp)); // now the emitting particle int ig = int(real->emitted())-int(real->incoming().size()); fixFinalStateEmitter(currentTree(),real->outgoing()[iemit], real->outgoing()[ig], emitter,cline,aline); } // IF emission else { // scattering process if(real->incoming().size()==2) { ShowerProgenitorPtr emitter,spectator; unsigned int iemit = real->emitter(); unsigned int ispect = real->spectator(); int ig = int(real->emitted())-int(real->incoming().size()); ColinePair cline,aline; // incoming spectator if(ispect<2) { spectator = findInitialStateLine(currentTree(), real->bornIncoming()[ispect]->id(), real->bornIncoming()[ispect]->momentum()); fixSpectatorColours(real->incoming()[ispect],spectator,cline,aline,true); // update the spectator spectator->copy(real->incoming()[ispect]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->incoming()[ispect],1,false))); sp->x(ispect ==0 ? real->x().first :real->x().second); spectator->progenitor(sp); currentTree()->incomingLines()[spectator]=sp; spectator->perturbative(true); } // outgoing spectator else { spectator = findFinalStateLine(currentTree(), real->bornOutgoing()[ispect-real->incoming().size()]->id(), real->bornOutgoing()[ispect-real->incoming().size()]->momentum()); // special case if decayed map >::const_iterator tit; for(tit = currentTree()->treelinks().begin(); tit != currentTree()->treelinks().end();++tit) { if(tit->second.first && tit->second.second==spectator->progenitor()) break; } fixSpectatorColours(real->outgoing()[ispect-real->incoming().size()],spectator,cline,aline,true); // update the spectator spectator->copy(real->outgoing()[ispect-real->incoming().size()]); ShowerParticlePtr sp(new_ptr(ShowerParticle(*real->outgoing()[ispect-real->incoming().size()],1,true))); spectator->progenitor(sp); currentTree()->outgoingLines()[spectator]=sp; spectator->perturbative(true); // update for decaying particles if(tit!=currentTree()->treelinks().end()) currentTree()->updateLink(tit->first,make_pair(spectator,sp)); } // incoming emitter if(iemit<2) { emitter = findInitialStateLine(currentTree(), real->bornIncoming()[iemit]->id(), real->bornIncoming()[iemit]->momentum()); fixInitialStateEmitter(currentTree(),real->incoming()[iemit],real->outgoing()[ig], emitter,aline,cline,iemit ==0 ? real->x().first :real->x().second); } // outgoing emitter else { emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit-real->incoming().size()]->id(), real->bornOutgoing()[iemit-real->incoming().size()]->momentum()); fixFinalStateEmitter(currentTree(),real->outgoing()[iemit-real->incoming().size()], real->outgoing()[ig],emitter,aline,cline); } } // decay process else { assert(real->spectator()==0); unsigned int iemit = real->emitter()-real->incoming().size(); int ig = int(real->emitted())-int(real->incoming().size()); ColinePair cline,aline; // incoming spectator ShowerProgenitorPtr spectator = findInitialStateLine(currentTree(), real->bornIncoming()[0]->id(), real->bornIncoming()[0]->momentum()); fixSpectatorColours(real->incoming()[0],spectator,cline,aline,false); // find the emitter ShowerProgenitorPtr emitter = findFinalStateLine(currentTree(), real->bornOutgoing()[iemit]->id(), real->bornOutgoing()[iemit]->momentum()); // recoiling system for( map::const_iterator cjt= currentTree()->outgoingLines().begin(); cjt != currentTree()->outgoingLines().end();++cjt ) { if(cjt->first==emitter) continue; cjt->first->progenitor()->transform(real->transformation()); cjt->first->copy()->transform(real->transformation()); } // sort out the emitter fixFinalStateEmitter(currentTree(),real->outgoing()[iemit], real->outgoing()[ig],emitter,aline,cline); } } // clean up the shower tree _currenttree->resetShowerProducts(); } diff --git a/Shower/QTilde/QTildeShowerHandler.h b/Shower/QTilde/QTildeShowerHandler.h --- a/Shower/QTilde/QTildeShowerHandler.h +++ b/Shower/QTilde/QTildeShowerHandler.h @@ -1,856 +1,846 @@ // -*- C++ -*- #ifndef Herwig_QTildeShowerHandler_H #define Herwig_QTildeShowerHandler_H // // This is the declaration of the QTildeShowerHandler class. // #include "QTildeShowerHandler.fh" #include "Herwig/Shower/ShowerHandler.h" -#include "Herwig/Shower/QTilde/Base/ShowerModel.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingGenerator.h" #include "Herwig/Shower/QTilde/Base/ShowerTree.h" #include "Herwig/Shower/QTilde/Base/ShowerProgenitor.fh" #include "Herwig/Shower/QTilde/Base/HardTree.h" #include "Herwig/Shower/QTilde/Base/Branching.h" #include "Herwig/Shower/QTilde/Base/ShowerVeto.h" #include "Herwig/Shower/QTilde/Base/FullShowerVeto.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicsReconstructor.fh" +#include "Herwig/Shower/QTilde/Base/PartnerFinder.fh" +#include "Herwig/Shower/QTilde/SplittingFunctions/SudakovFormFactor.fh" #include "Herwig/MatrixElement/HwMEBase.h" #include "Herwig/Decay/HwDecayerBase.h" #include "Herwig/MatrixElement/Matchbox/Matching/ShowerApproximation.h" #include "Herwig/Shower/RealEmissionProcess.h" #include "Herwig/Utilities/Statistic.h" namespace Herwig { using namespace ThePEG; /** * The QTildeShowerHandler class. * * @see \ref QTildeShowerHandlerInterfaces "The interfaces" * defined for QTildeShowerHandler. */ class QTildeShowerHandler: public ShowerHandler { public: /** * Pointer to an XComb object */ typedef Ptr::pointer XCPtr; public: /** @name Standard constructors and destructors. */ //@{ /** * The default constructor. */ QTildeShowerHandler(); /** * The destructor. */ virtual ~QTildeShowerHandler(); //@} public: /** * At the end of the Showering, transform ShowerParticle objects * into ThePEG particles and fill the event record with them. * Notice that the parent/child relationships and the * transformation from ShowerColourLine objects into ThePEG * ColourLine ones must be properly handled. */ void fillEventRecord(); /** * Return the relevant hard scale to be used in the profile scales */ virtual Energy hardScale() const { return muPt; } /** * Hook to allow vetoing of event after showering hard sub-process * as in e.g. MLM merging. */ virtual bool showerHardProcessVeto() const { return false; } /** * Generate hard emissions for CKKW etc */ virtual HardTreePtr generateCKKW(ShowerTreePtr tree) const; /** * Members to perform the shower */ //@{ /** * Perform the shower of the hard process */ virtual void showerHardProcess(ShowerTreePtr,XCPtr); /** * Perform the shower of a decay */ virtual void showerDecay(ShowerTreePtr); //@} /** * Access to the flags and shower variables */ //@{ - /** - * Get the ShowerModel - */ - ShowerModelPtr showerModel() const {return _model;} /** * Get the SplittingGenerator */ tSplittingGeneratorPtr splittingGenerator() const { return _splittingGenerator; } /** * Mode for hard emissions */ int hardEmission() const {return _hardEmission;} //@} /** * Connect the Hard and Shower trees */ virtual void connectTrees(ShowerTreePtr showerTree, HardTreePtr hardTree, bool hard ); /** * Access to switches for spin correlations */ //@{ /** - * Spin Correlations - */ - unsigned int spinCorrelations() const { - return _spinOpt; - } - - /** * Soft correlations */ unsigned int softCorrelations() const { return _softOpt; } /** * Any correlations */ - bool correlations() const { - return _spinOpt!=0||_softOpt!=0; + virtual bool correlations() const { + return spinCorrelations()!=0||_softOpt!=0; } //@} +public: + /** + * Access methods to access the objects + */ + //@{ + /** + * Access to the KinematicsReconstructor object + */ + tKinematicsReconstructorPtr kinematicsReconstructor() const { return _reconstructor; } + + /** + * Access to the PartnerFinder object + */ + tPartnerFinderPtr partnerFinder() const { return _partnerfinder; } + + //@} + protected: /** * Perform the shower */ void doShowering(bool hard,XCPtr); /** * Generate the hard matrix element correction */ virtual RealEmissionProcessPtr hardMatrixElementCorrection(bool); /** * Generate the hardest emission */ virtual void hardestEmission(bool hard); /** * Set up for applying a matrix element correction */ void setupMECorrection(RealEmissionProcessPtr real); /** * Extract the particles to be showered, set the evolution scales * and apply the hard matrix element correction * @param hard Whether this is a hard process or decay * @return The particles to be showered */ virtual vector setupShower(bool hard); /** * set the colour partners */ virtual void setEvolutionPartners(bool hard,ShowerInteraction, bool clear); /** * Methods to perform the evolution of an individual particle, including * recursive calling on the products */ //@{ /** * It does the forward evolution of the time-like input particle * (and recursively for all its radiation products). * accepting only emissions which conforms to the showerVariables * and soft matrix element correction. * If at least one emission has occurred then the method returns true. * @param particle The particle to be showered */ virtual bool timeLikeShower(tShowerParticlePtr particle, ShowerInteraction, Branching fb, bool first); /** * It does the backward evolution of the space-like input particle * (and recursively for all its time-like radiation products). * accepting only emissions which conforms to the showerVariables. * If at least one emission has occurred then the method returns true * @param particle The particle to be showered * @param beam The beam particle */ virtual bool spaceLikeShower(tShowerParticlePtr particle,PPtr beam, ShowerInteraction); /** * If does the forward evolution of the input on-shell particle * involved in a decay * (and recursively for all its time-like radiation products). * accepting only emissions which conforms to the showerVariables. * @param particle The particle to be showered * @param maxscale The maximum scale for the shower. * @param minimumMass The minimum mass of the final-state system */ virtual bool spaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction, Branching fb); /** * Truncated shower from a time-like particle */ virtual bool truncatedTimeLikeShower(tShowerParticlePtr particle, HardBranchingPtr branch, ShowerInteraction type, Branching fb, bool first); /** * Truncated shower from a space-like particle */ virtual bool truncatedSpaceLikeShower(tShowerParticlePtr particle,PPtr beam, HardBranchingPtr branch, ShowerInteraction type); /** * Truncated shower from a time-like particle */ virtual bool truncatedSpaceLikeDecayShower(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass, HardBranchingPtr branch, ShowerInteraction type, Branching fb); //@} /** * Switches for matrix element corrections */ //@{ /** * Any ME correction? */ bool MECOn() const { return _hardEmission == 1; } /** * Any hard ME correction? */ bool hardMEC() const { return _hardEmission == 1 && (_meCorrMode == 1 || _meCorrMode == 2); } /** * Any soft ME correction? */ bool softMEC() const { return _hardEmission == 1 && (_meCorrMode == 1 || _meCorrMode > 2); } //@} /** * Is the truncated shower on? */ bool isTruncatedShowerON() const {return _trunc_Mode;} /** * Switch for intrinsic pT */ //@{ /** * Any intrinsic pT? */ bool ipTon() const { return _iptrms != ZERO || ( _beta == 1.0 && _gamma != ZERO && _iptmax !=ZERO ); } //@} /**@name Additional shower vetoes */ //@{ /** * Insert a veto. */ void addVeto (ShowerVetoPtr v) { _vetoes.push_back(v); } /** * Remove a veto. */ void removeVeto (ShowerVetoPtr v) { vector::iterator vit = find(_vetoes.begin(),_vetoes.end(),v); if (vit != _vetoes.end()) _vetoes.erase(vit); } //@} /** * Switches for vetoing hard emissions */ //@{ /** * Returns true if the hard veto read-in is to be applied to only * the primary collision and false otherwise. */ bool hardVetoReadOption() const {return _hardVetoReadOption;} //@} /** * Enhancement factors for radiation needed to generate the soft matrix * element correction. */ //@{ /** * Access the enhancement factor for initial-state radiation */ double initialStateRadiationEnhancementFactor() const { return _initialenhance; } /** * Access the enhancement factor for final-state radiation */ double finalStateRadiationEnhancementFactor() const { return _finalenhance; } /** * Set the enhancement factor for initial-state radiation */ void initialStateRadiationEnhancementFactor(double in) { _initialenhance=in; } /** * Set the enhancement factor for final-state radiation */ void finalStateRadiationEnhancementFactor(double in) { _finalenhance=in; } //@} /** * Access to set/get the HardTree currently beinging showered */ //@{ /** * The HardTree currently being showered */ tHardTreePtr hardTree() {return _hardtree;} /** * The HardTree currently being showered */ void hardTree(tHardTreePtr in) {_hardtree = in;} //@} /** * Access/set the beam particle for the current initial-state shower */ //@{ /** * Get the beam particle data */ Ptr::const_pointer beamParticle() const { return _beam; } /** * Set the beam particle data */ void setBeamParticle(Ptr::const_pointer in) { _beam=in; } //@} /** * Set/Get the current tree being evolver for inheriting classes */ //@{ /** * Get the tree */ tShowerTreePtr currentTree() { return _currenttree; } /** * Set the tree */ void currentTree(tShowerTreePtr tree) { _currenttree=tree; } //@} /** * Access the maximum number of attempts to generate the shower */ unsigned int maximumTries() const { return _maxtry; } /** * Set/Get the ShowerProgenitor for the current shower */ //@{ /** * Access the progenitor */ ShowerProgenitorPtr progenitor() { return _progenitor; } /** * Set the progenitor */ void progenitor(ShowerProgenitorPtr in) { _progenitor=in; } //@} /** * Calculate the intrinsic \f$p_T\f$. */ virtual void generateIntrinsicpT(vector); /** * Access to the intrinsic \f$p_T\f$ for inheriting classes */ map > & intrinsicpT() { return _intrinsic; } /** * find the maximally allowed pt acc to the hard process. */ void setupMaximumScales(const vector &,XCPtr); /** * find the relevant hard scales for profile scales. */ void setupHardScales(const vector &,XCPtr); /** * Convert the HardTree into an extra shower emission */ void convertHardTree(bool hard,ShowerInteraction type); protected: /** * Find the parton extracted from the incoming particle after ISR */ PPtr findFirstParton(tPPtr seed) const; /** * Fix Remnant connections after ISR */ tPPair remakeRemnant(tPPair oldp); protected: /** * Start the shower of a timelike particle */ virtual bool startTimeLikeShower(ShowerInteraction); /** * Update of the time-like stuff */ void updateHistory(tShowerParticlePtr particle); /** * Start the shower of a spacelike particle */ virtual bool startSpaceLikeShower(PPtr,ShowerInteraction); /** * Start the shower of a spacelike particle */ virtual bool startSpaceLikeDecayShower(const ShowerParticle::EvolutionScales & maxScales, Energy minimumMass,ShowerInteraction); /** * Select the branching for the next time-like emission */ Branching selectTimeLikeBranching(tShowerParticlePtr particle, ShowerInteraction type, HardBranchingPtr branch); /** * Select the branching for the next space-like emission in a decay */ Branching selectSpaceLikeDecayBranching(tShowerParticlePtr particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,ShowerInteraction type, HardBranchingPtr branch); /** * Create the timelike child of a branching */ ShowerParticleVector createTimeLikeChildren(tShowerParticlePtr particle, IdList ids); /** * Vetos for the timelike shower */ virtual bool timeLikeVetoed(const Branching &,ShowerParticlePtr); /** * Vetos for the spacelike shower */ virtual bool spaceLikeVetoed(const Branching &,ShowerParticlePtr); /** * Vetos for the spacelike shower */ virtual bool spaceLikeDecayVetoed(const Branching &,ShowerParticlePtr); /** * Only generate the hard emission, for testing only. */ bool hardOnly() const {return _limitEmissions==3;} /** * Check the flags */ void checkFlags(); /** * */ void addFSRUsingDecayPOWHEG(HardTreePtr ISRTree); 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(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(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: /** * The main method which manages the showering of a subprocess. */ virtual tPPair cascade(tSubProPtr sub, XCPtr xcomb); /** * Decay a ShowerTree */ void decay(ShowerTreePtr tree, ShowerDecayMap & decay); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual 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 IBPtr fullclone() const; //@} protected: /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); /** * Initialize this object. Called in the run phase just before * a run begins. */ virtual void doinitrun(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ QTildeShowerHandler & operator=(const QTildeShowerHandler &); private: /** * Stuff from the ShowerHandler */ //@{ /** * The ShowerTree for the hard process */ ShowerTreePtr hard_; /** * The ShowerTree for the decays */ ShowerDecayMap decay_; /** * The ShowerTrees for which the initial shower */ vector done_; //@} private : /** - * Pointer to the model for the shower evolution model - */ - ShowerModelPtr _model; - - /** * Pointer to the splitting generator */ SplittingGeneratorPtr _splittingGenerator; /** * Maximum number of tries to generate the shower of a particular tree */ unsigned int _maxtry; /** * Matrix element correction switch */ unsigned int _meCorrMode; /** * Control of the reconstruction option */ unsigned int _reconOpt; /** * If hard veto pT scale is being read-in this determines * whether the read-in value is applied to primary and * secondary (MPI) scatters or just the primary one, with * the usual computation of the veto being performed for * the secondary (MPI) scatters. */ bool _hardVetoReadOption; /** * rms intrinsic pT of Gaussian distribution */ Energy _iptrms; /** * Proportion of inverse quadratic intrinsic pT distribution */ double _beta; /** * Parameter for inverse quadratic: 2*Beta*Gamma/(sqr(Gamma)+sqr(intrinsicpT)) */ Energy _gamma; /** * Upper bound on intrinsic pT for inverse quadratic */ Energy _iptmax; /** * Limit the number of emissions for testing */ unsigned int _limitEmissions; /** * The progenitor of the current shower */ ShowerProgenitorPtr _progenitor; /** * Matrix element */ HwMEBasePtr _hardme; /** * Decayer */ HwDecayerBasePtr _decayme; /** * The ShowerTree currently being showered */ ShowerTreePtr _currenttree; /** * The HardTree currently being showered */ HardTreePtr _hardtree; /** * Radiation enhancement factors for use with the veto algorithm * if needed by the soft matrix element correction */ //@{ /** * Enhancement factor for initial-state radiation */ double _initialenhance; /** * Enhancement factor for final-state radiation */ double _finalenhance; //@} /** * The beam particle data for the current initial-state shower */ Ptr::const_pointer _beam; /** * Storage of the intrinsic \f$p_t\f$ of the particles */ map > _intrinsic; /** * Vetoes */ vector _vetoes; /** * Full Shower Vetoes */ vector _fullShowerVetoes; /** * Number of iterations for reweighting */ unsigned int _nReWeight; /** * Whether or not we are reweighting */ bool _reWeight; /** * number of IS emissions */ unsigned int _nis; /** * Number of FS emissions */ unsigned int _nfs; /** * The option for wqhich interactions to use */ ShowerInteraction interaction_; /** * Truncated shower switch */ bool _trunc_Mode; /** * Count of the number of truncated emissions */ unsigned int _truncEmissions; /** * Mode for the hard emissions */ int _hardEmission; /** - * Option to include spin correlations - */ - unsigned int _spinOpt; - - /** * Option for the kernal for soft correlations */ unsigned int _softOpt; /** * Option for hard radiation in POWHEG events */ bool _hardPOWHEG; /** * True if no warnings about incorrect hard emission * mode setting have been issued yet */ static bool _hardEmissionWarn; /** * True if no warnings about missing truncated shower * have been issued yet */ static bool _missingTruncWarn; /** * The relevant hard scale to be used in the profile scales */ Energy muPt; +private: /** - * Maximum number of emission attempts for FSR + * Pointer to the various objects */ - unsigned int _maxTryFSR; + //@{ + /** + * Pointer to the KinematicsReconstructor object + */ + KinematicsReconstructorPtr _reconstructor; /** - * Maximum number of failures for FSR generation + * Pointer to the PartnerFinder object */ - unsigned int _maxFailFSR; + PartnerFinderPtr _partnerfinder; - /** - * Failure fraction for FSR generation - */ - double _fracFSR; - - /** - * Counter for number of FSR emissions - */ - unsigned int _nFSR; - - /** - * Counter for the number of failed events due to FSR emissions - */ - unsigned int _nFailedFSR; + //@} }; } #endif /* HERWIG_QTildeShowerHandler_H */ diff --git a/Shower/QTilde/ShowerConfig.cc b/Shower/QTilde/ShowerConfig.cc --- a/Shower/QTilde/ShowerConfig.cc +++ b/Shower/QTilde/ShowerConfig.cc @@ -1,47 +1,47 @@ // -*- C++ -*- // // ShowerConfig.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 ShowerConfig class. // #include "ShowerConfig.h" -#include "Base/SudakovFormFactor.h" +#include "SplittingFunctions/SudakovFormFactor.h" using namespace Herwig; BranchingElement::~BranchingElement() {} BranchingElement::BranchingElement() {} BranchingElement::BranchingElement(SudakovPtr sud, IdList part) : sudakov(sud), particles(part) { for(unsigned int ix=0;ixCC() ? tcPDPtr(part[ix]->CC()) : part[ix]); } namespace ThePEG { /** * Output operator to allow the structure */ PersistentOStream & operator << (PersistentOStream & os, const Herwig::BranchingElement & x) { os << x.sudakov << x.particles << x.conjugateParticles; return os; } /** * Input operator to allow the structure */ PersistentIStream & operator >> (PersistentIStream & is, Herwig::BranchingElement & x) { is >> x.sudakov >> x.particles >> x.conjugateParticles; return is; } } diff --git a/Shower/QTilde/ShowerConfig.h b/Shower/QTilde/ShowerConfig.h --- a/Shower/QTilde/ShowerConfig.h +++ b/Shower/QTilde/ShowerConfig.h @@ -1,153 +1,153 @@ // -*- C++ -*- // // ShowerConfig.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerConfig_H #define HERWIG_ShowerConfig_H // // This is the declaration of the ShowerConfig class. #include "ThePEG/Config/ThePEG.h" #include "ThePEG/PDT/ParticleData.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.fh" -#include "Herwig/Shower/QTilde/Base/SudakovFormFactor.fh" +#include "Herwig/Shower/QTilde/SplittingFunctions/SudakovFormFactor.fh" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "Herwig/Shower/ShowerInteraction.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * Handy header file to be included in all Shower classes. * It contains only some useful typedefs. */ /** * Pointer to a ColourLine */ typedef Ptr::pointer ColinePtr; /** * Transient Pointer to a ColourLine */ typedef Ptr::transient_pointer tColinePtr; /** * A pair of ColourLine pointers */ typedef pair ColinePair; /** * A pair of transient ColourLine pointers */ typedef pair tColinePair; /** * A Vector of ShowerParticle pointers */ typedef vector ShowerParticleVector; /** * A Vector of transient ShowerParticle pointers */ typedef vector tShowerParticleVector; /** * Definition of the IdList for branchings */ typedef vector IdList; inline ShowerInteraction convertInteraction(ShowerPartnerType partner) { if (partner==ShowerPartnerType::QCDColourLine || partner==ShowerPartnerType::QCDAntiColourLine) return ShowerInteraction::QCD; else if (partner==ShowerPartnerType::QED) return ShowerInteraction::QED; else if(partner==ShowerPartnerType::EW) return ShowerInteraction::EW; else return ShowerInteraction::UNDEFINED; } /** * typedef to pair the SudakovFormFactor and the particles in a branching */ struct BranchingElement { /** * Constructor */ BranchingElement(); /** * Constructor */ BranchingElement(SudakovPtr sud, IdList part); /** * Destructor */ ~BranchingElement(); /** * Access to the Sudakov */ SudakovPtr sudakov; /** * Access to the particles */ IdList particles; /** * Access to the charge conjugate particles */ IdList conjugateParticles; /** * Compare two BranchingElements **/ bool operator == (const BranchingElement& x) const{ return sudakov == x.sudakov && particles == x.particles && conjugateParticles == x.conjugateParticles; } }; /** * typedef to pair the PDG code of the particle and the BranchingElement */ typedef multimap BranchingList; /** * typedef to create a structure which can be inserted into a BranchingList */ typedef pair BranchingInsert; } namespace ThePEG { /** * Output operator to allow the structure */ PersistentOStream & operator << (PersistentOStream & os, const Herwig::BranchingElement & x); /** * Input operator to allow the structure */ PersistentIStream & operator >> (PersistentIStream & is, Herwig::BranchingElement & x); } #endif // HERWIG_ShowerConfig_H diff --git a/Shower/QTilde/SplittingFunctions/CMWHalfHalfOneSplitFn.h b/Shower/QTilde/SplittingFunctions/CMWHalfHalfOneSplitFn.h --- a/Shower/QTilde/SplittingFunctions/CMWHalfHalfOneSplitFn.h +++ b/Shower/QTilde/SplittingFunctions/CMWHalfHalfOneSplitFn.h @@ -1,163 +1,158 @@ // -*- C++ -*- // // CMWHalfHalfOneSplitFn.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_CMWHalfHalfOneSplitFn_H #define HERWIG_CMWHalfHalfOneSplitFn_H // // This is the declaration of the CMWHalfHalfOneSplitFn class. // #include "HalfHalfOneSplitFn.h" #include "Herwig/Shower/ShowerAlpha.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This class provides the concrete implementation * of the CMW enhanced expressions for the * splitting function for \f$\frac12\to q\frac12 1\f$. * * The kernel uses the same overestimate as the * corresponding HalfHalfOneSplitFn and thus only needs to * implement the spitting function and ratio to the overestimate. * * TODO: For a more efficient sampling one needs can rewrite the * overestimation to contain the alpha_max*Kgmax factors. * * @see \ref CMWHalfHalfOneSplitFnInterfaces "The interfaces" * defined for CMWHalfHalfOneSplitFn. */ class CMWHalfHalfOneSplitFn: public HalfHalfOneSplitFn { public: /** - * The default constructor. - */ - CMWHalfHalfOneSplitFn() : HalfHalfOneSplitFn() {} - - /** * Methods to return the splitting function. */ //@{ /** * Very similar to HalfHalfOneSplitFn. * Here the kernel only contains the soft part multiplied by the * alphas/2pi * Kg from * Nucl.Phys. B349 (1991) 635-654 * */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * Very similar to HalfHalfOneSplitFn. * Since we use only the 1/1-z part for overestimating the kernel * in the first place we can keep the same overestimation related functions * for the CMW kernels. */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * Return the correction term from: * Nucl.Phys. B349 (1991) 635-654 */ double Kg(Energy2 )const{ //TODO: Should be t-dependent int Nf=5;//alpha_->Nf(t) return (3.*(67./18.-1./6.*sqr(Constants::pi))-5./9.*Nf); } //@} 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(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(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 Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(){ HalfHalfOneSplitFn::doinit(); }; //@} private: // Pointer to the alpha_s object in use. ShowerAlphaPtr alpha_; // Provide information if the kernel is used for initial state. // as the pt definition contains an additional factor of z. bool isIS_=false; protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ CMWHalfHalfOneSplitFn & operator=(const CMWHalfHalfOneSplitFn &); }; } #endif /* HERWIG_CMWHalfHalfOneSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/CMWOneOneOneSplitFn.h b/Shower/QTilde/SplittingFunctions/CMWOneOneOneSplitFn.h --- a/Shower/QTilde/SplittingFunctions/CMWOneOneOneSplitFn.h +++ b/Shower/QTilde/SplittingFunctions/CMWOneOneOneSplitFn.h @@ -1,159 +1,154 @@ // -*- C++ -*- // // CMWOneOneOneSplitFn.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_CMWOneOneOneSplitFn_H #define HERWIG_CMWOneOneOneSplitFn_H // // This is the declaration of the CMWOneOneOneSplitFn class. // #include "OneOneOneSplitFn.h" #include "Herwig/Shower/ShowerAlpha.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This class provides the concrete implementation * of the CMW enhanced expressions for the * splitting function for \f$1\to 11\f$. * * The kernel uses the same overestimate as the * corresponding OneOneOneSplitFn and thus only needs to * implement the spitting function and ratio to the overestimate. * * TODO: For a more efficient sampling one needs can rewrite the * overestimation to contain the alpha_max*Kgmax factors. * * @see \ref CMWOneOneOneSplitFnInterfaces "The interfaces" * defined for CMWOneOneOneSplitFn. */ class CMWOneOneOneSplitFn: public OneOneOneSplitFn { public: /** - * The default constructor. - */ - CMWOneOneOneSplitFn() : OneOneOneSplitFn() {} - - /** * Methods to return the splitting function. */ //@{ /** * Very similar to HalfHalfOneSplitFn. * Here the kernel only contains the soft part multiplied by the * alphas/2pi * Kg from * Nucl.Phys. B349 (1991) 635-654 * */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * Very similar to HalfHalfOneSplitFn. * Since we use only the 1/1-z part for overestimating the kernel * in the first place we can keep the same overestimation related functions * for the CMW kernels. */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * Return the correction term from: * Nucl.Phys. B349 (1991) 635-654 */ double Kg(Energy2 )const{ //TODO: Might be t-dependent int Nf=5;//alpha_->Nf(t) return (3.*(67./18.-1./6.*sqr(Constants::pi))-5./9.*Nf); } //@} 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(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(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 Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(){ OneOneOneSplitFn::doinit(); }; //@} private: // Pointer to the alpha_s object in use. ShowerAlphaPtr alpha_; // Provide information if the kernel is used for initial state. // as the pt definition contains an additional factor of z. bool isIS_=false; protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ CMWOneOneOneSplitFn & operator=(const CMWOneOneOneSplitFn &); }; } #endif /* HERWIG_CMWOneOneOneSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/HalfHalfOneEWSplitFn.h b/Shower/QTilde/SplittingFunctions/HalfHalfOneEWSplitFn.h --- a/Shower/QTilde/SplittingFunctions/HalfHalfOneEWSplitFn.h +++ b/Shower/QTilde/SplittingFunctions/HalfHalfOneEWSplitFn.h @@ -1,217 +1,212 @@ // -*- C++ -*- #ifndef Herwig_HalfHalfOneEWSplitFn_H #define Herwig_HalfHalfOneEWSplitFn_H // // This is the declaration of the HalfHalfOneEWSplitFn class. // #include "SplittingFunction.h" namespace Herwig { using namespace ThePEG; /** * The HalfHalfOneEWSplitFn class implements the splitting function for * \f$\frac12\to q\frac12 1\f$ where the spin-1 particle is a massive electroweak gauge boson. * * @see \ref HalfHalfOneEWSplitFnInterfaces "The interfaces" * defined for HalfHalfOneEWSplitFn. */ class HalfHalfOneEWSplitFn: public SplittingFunction { public: /** - * The default constructor. - */ - HalfHalfOneEWSplitFn() : SplittingFunction(1) {} - - /** * Concrete implementation of the method to determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * The concrete implementation of the splitting function, \f$P(z,t)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the overestimate of the splitting function, * \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const; /** * The concrete implementation of the * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,t)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const; /** * The concrete implementation of the inverse of the indefinite integral. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const; //@} /** * Method to calculate the azimuthal angle * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Method to calculate the azimuthal angle for backward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Calculate the matrix element for the splitting * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike); protected: /** * Get the couplings */ void getCouplings(double & gL, double & gR, const IdList & ids) const; 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(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(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 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 IBPtr fullclone() const; //@} protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ HalfHalfOneEWSplitFn & operator=(const HalfHalfOneEWSplitFn &); private: /** * Z couplings */ map > gZ_; /** * W couplings */ double gWL_; }; } #endif /* Herwig_HalfHalfOneEWSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.h b/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.h --- a/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.h +++ b/Shower/QTilde/SplittingFunctions/HalfHalfOneSplitFn.h @@ -1,188 +1,183 @@ // -*- C++ -*- // // HalfHalfOneSplitFn.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_HalfHalfOneSplitFn_H #define HERWIG_HalfHalfOneSplitFn_H // // This is the declaration of the HalfHalfOneSplitFn class. // #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" namespace Herwig { using namespace ThePEG; /**\ingroup Shower * * This class provides the concrete implementation of the exact leading-order * splitting function for \f$\frac12\to q\frac12 1\f$. * * In this case the splitting function is given by * \f[P(z,t) =C\left(\frac{1+z^2}{1-z}-2\frac{m^2_q}{t}\right),\f] * where \f$C\f$ is the corresponding colour factor. * Our choice for the overestimate is * \f[P_{\rm over}(z) = \frac{2C}{1-z},\f] * therefore the integral is * \f[\int P_{\rm over}(z) {\rm d}z = -2C\ln(1-z),\f] * and its inverse is * \f[1-\exp\left(\frac{r}{2C}\right).\f] * * @see \ref HalfHalfOneSplitFnInterfaces "The interfaces" * defined for HalfHalfOneSplitFn. */ class HalfHalfOneSplitFn: public SplittingFunction { public: /** - * The default constructor. - */ - HalfHalfOneSplitFn() : SplittingFunction(1) {} - - /** * Concrete implementation of the method to determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * The concrete implementation of the splitting function, \f$P(z,t)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the overestimate of the splitting function, * \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const; /** * The concrete implementation of the * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,t)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const; /** * The concrete implementation of the inverse of the indefinite integral. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const; //@} /** * Method to calculate the azimuthal angle * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Method to calculate the azimuthal angle for backward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Calculate the matrix element for the splitting * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike); 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(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ HalfHalfOneSplitFn & operator=(const HalfHalfOneSplitFn &); }; } #endif /* HERWIG_HalfHalfOneSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/HalfOneHalfSplitFn.h b/Shower/QTilde/SplittingFunctions/HalfOneHalfSplitFn.h --- a/Shower/QTilde/SplittingFunctions/HalfOneHalfSplitFn.h +++ b/Shower/QTilde/SplittingFunctions/HalfOneHalfSplitFn.h @@ -1,188 +1,183 @@ // -*- C++ -*- // // HalfOneHalfSplitFn.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_HalfOneHalfSplitFn_H #define HERWIG_HalfOneHalfSplitFn_H // // This is the declaration of the HalfOneHalfSplitFn class. // #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This classs provides the concrete implementation of the exact leading-order * splitting function for \f$\frac12\to 1\frac12\f$. * * In this case the splitting function is given by * \f[P(z,t) = C\left(\frac{2(1-z)+z^2}{z}-2\frac{m^2_q}t\right),\f] * where \f$C\f$ is the corresponding colour factor. * Our choice for the overestimate is * \f[P_{\rm over}(z) = 2C\frac1z,\f] * therefore the integral is * \f[\int P_{\rm over}(z) {\rm d}z = 2C\ln z,\f] * and its inverse is * \f[\exp\left(\frac{r}{2C}\right).\f] * * @see SplittingFunction */ class HalfOneHalfSplitFn: public SplittingFunction { public: /** - * The default constructor. - */ - HalfOneHalfSplitFn() : SplittingFunction(1) {} - - /** * Concrete implementation of the method to determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * The concrete implementation of the splitting function, \f$P(z,t)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the overestimate of the splitting function, * \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const; /** * The concrete implementation of the * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,t)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const; /** * The concrete implementation of the inverse of the indefinite integral. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const; //@} /** * Method to calculate the azimuthal angle for forward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Method to calculate the azimuthal angle for backward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Calculate the matrix element for the splitting * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike); 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(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ HalfOneHalfSplitFn & operator=(const HalfOneHalfSplitFn &); }; } #endif /* HERWIG_HalfOneHalfSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/MassCutOff.cc b/Shower/QTilde/SplittingFunctions/MassCutOff.cc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/MassCutOff.cc @@ -0,0 +1,73 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the MassCutOff class. +// + +#include "MassCutOff.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/EventRecord/Particle.h" +#include "ThePEG/Repository/UseRandom.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "ThePEG/Interface/Parameter.h" + +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" + +using namespace Herwig; + +IBPtr MassCutOff::clone() const { + return new_ptr(*this); +} + +IBPtr MassCutOff::fullclone() const { + return new_ptr(*this); +} + +void MassCutOff::persistentOutput(PersistentOStream & os) const { + os << ounit(vgcut_,GeV) << ounit(vqcut_,GeV); +} + +void MassCutOff::persistentInput(PersistentIStream & is, int) { + is >> iunit(vgcut_,GeV) >> iunit(vqcut_,GeV); +} + + +// The following static variable is needed for the type +// description system in ThePEG. +DescribeClass +describeHerwigMassCutOff("Herwig::MassCutOff", "HwShower.so"); + +void MassCutOff::Init() { + + static ClassDocumentation documentation + ("There is no documentation for the MassCutOff class"); + + + static Parameter interfaceGluonVirtualityCut + ("GluonVirtualityCut", + "For the FORTRAN cut-off option the minimum virtuality of the gluon", + &MassCutOff::vgcut_, GeV, 0.85*GeV, 0.1*GeV, 10.0*GeV, + false, false, Interface::limited); + + static Parameter interfaceQuarkVirtualityCut + ("QuarkVirtualityCut", + "For the FORTRAN cut-off option the minimum virtuality added to" + " the mass for particles other than the gluon", + &MassCutOff::vqcut_, GeV, 0.85*GeV, 0.1*GeV, 10.0*GeV, + false, false, Interface::limited); + + +} + +const vector & MassCutOff::virtualMasses(const IdList & ids) { + static vector output; + output.clear(); + for(auto id : ids) { + output.push_back(id->mass()); + output.back() += id->id()==ParticleID::g ? vgcut_ : vqcut_; + } + return output; +} + diff --git a/Shower/QTilde/SplittingFunctions/MassCutOff.h b/Shower/QTilde/SplittingFunctions/MassCutOff.h new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/MassCutOff.h @@ -0,0 +1,104 @@ +// -*- C++ -*- +#ifndef Herwig_MassCutOff_H +#define Herwig_MassCutOff_H +// +// This is the declaration of the MassCutOff class. +// + +#include "SudakovCutOff.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * Here is the documentation of the MassCutOff class. + * + * @see \ref MassCutOffInterfaces "The interfaces" + * defined for MassCutOff. + */ +class MassCutOff: public SudakovCutOff { + +public: + + /** + * Calculate the virtual masses for a branchings + */ + virtual const vector & virtualMasses(const IdList & ids); + +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(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(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 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 IBPtr fullclone() const; + //@} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + MassCutOff & operator=(const MassCutOff &) = delete; + +private: + + + /** + * Parameters for the FORTRAN-like cut-off + */ + //@{ + /** + * The virtualilty cut-off for gluons + */ + Energy vgcut_ = 0.85_GeV; + + /** + * The virtuality cut-off for everything else + */ + Energy vqcut_ = 0.85_GeV; + //@} + + + +}; + +} + +#endif /* Herwig_MassCutOff_H */ diff --git a/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.h b/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.h --- a/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.h +++ b/Shower/QTilde/SplittingFunctions/OneHalfHalfSplitFn.h @@ -1,193 +1,188 @@ // -*- C++ -*- // // OneHalfHalfSplitFn.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_OneHalfHalfSplitFn_H #define HERWIG_OneHalfHalfSplitFn_H // // This is the declaration of the OneHalfHalfSplitFn class. // #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" namespace Herwig { using namespace ThePEG; /**\ingroup Shower * * This class provides the concrete implementation of the exact leading-order * splitting function for \f$1\to \frac12\frac12\f$. * * In this case the splitting function is given by * \f[P(z,t) =C\left(1-2z(1-z)+2\frac{m_q^2}{t}\right),\f] * where \f$C\f$ is the corresponding colour factor * Our choice for the overestimate is * \f[P_{\rm over}(z) = C,\f] * therefore the integral is * \f[\int P_{\rm over}(z) {\rm d}z =Cz,\f] * and its inverse is * \f[\frac{r}{C}\f] * * @see \ref OneHalfHalfSplitFnInterfaces "The interfaces" * defined for OneHalfHalfSplitFn. */ class OneHalfHalfSplitFn: public SplittingFunction { public: /** - * The default constructor. - */ - OneHalfHalfSplitFn() : SplittingFunction(1) {} - - /** * Concrete implementation of the method to determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * The concrete implementation of the splitting function, \f$P\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the overestimate of the splitting function, * \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const; /** * The concrete implementation of the * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,\tilde{q}^2)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const; /** * The concrete implementation of the inverse of the indefinite integral. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const; //@} /** * Method to calculate the azimuthal angle * @param particle The particle which is branching * @param showerkin The ShowerKinematics object * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Method to calculate the azimuthal angle * @param particle The particle which is branching * @param showerkin The ShowerKinematics object * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Calculate the matrix element for the splitting * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike); 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(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ OneHalfHalfSplitFn & operator=(const OneHalfHalfSplitFn &); }; } #endif /* HERWIG_OneHalfHalfSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/OneOneOneMassiveSplitFn.h b/Shower/QTilde/SplittingFunctions/OneOneOneMassiveSplitFn.h --- a/Shower/QTilde/SplittingFunctions/OneOneOneMassiveSplitFn.h +++ b/Shower/QTilde/SplittingFunctions/OneOneOneMassiveSplitFn.h @@ -1,189 +1,184 @@ // -*- C++ -*- // // OneOneOneSplitFn.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_OneOneOneMassiveSplitFn_H #define HERWIG_OneOneOneMassiveSplitFn_H // // This is the declaration of the OneOneOneMassiveSplitFn class. // #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This class provides the concrete implementation of the exact leading-order * splitting function for \f$1\to 11\f$ where the emitting particle is massi e * * In this case the splitting function is given by * \f[P(z) =2C\left( \frac{z}{1-z}-\frac{m^2}{q^2-m^2}) +2\rho_{00]\frac{(1-z)^2m^2}{q^2-m^2} + (1-\rho_{00})\left(\frac{1-z}{z}+z(1-z)-\frac{(1-z)^2m^2}{q^2-m^2}\right)\right),\f] * where \f$C=\f$ is the corresponding colour factor. * Our choice for the overestimate is * \f[P_{\rm over}(z) = 2C\left(\frac1z+\frac1{1-z}\right),\f] * therefore the integral is * \f[\int P_{\rm over}(z) {\rm d}z =2C\ln\left(\frac{z}{1-z}\right),\f] * and its inverse is * \f[\frac{\exp\left(\frac{r}{2C}\right)}{(1+\exp\left(\frac{r}{2C}\right)}\f] * * * @see \ref OneOneOneMassiveSplitFnInterfaces "The interfaces" * defined for OneOneOneMassiveSplitFn. */ class OneOneOneMassiveSplitFn: public SplittingFunction { public: /** - * The default constructor. - */ - OneOneOneMassiveSplitFn() : SplittingFunction(1) {} - - /** * Concrete implementation of the method to determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * The concrete implementation of the splitting function, \f$P(z,t)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the overestimate of the splitting function, * \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const; /** * The concrete implementation of the * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,t)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const; /** * The concrete implementation of the inverse of the indefinite integral. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const; //@} /** * Method to calculate the azimuthal angle for forward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Method to calculate the azimuthal angle for backward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Calculate the matrix element for the splitting * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike); 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(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ OneOneOneMassiveSplitFn & operator=(const OneOneOneMassiveSplitFn &); }; } #endif /* HERWIG_OneOneOneMassiveSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/OneOneOneSplitFn.h b/Shower/QTilde/SplittingFunctions/OneOneOneSplitFn.h --- a/Shower/QTilde/SplittingFunctions/OneOneOneSplitFn.h +++ b/Shower/QTilde/SplittingFunctions/OneOneOneSplitFn.h @@ -1,189 +1,184 @@ // -*- C++ -*- // // OneOneOneSplitFn.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_OneOneOneSplitFn_H #define HERWIG_OneOneOneSplitFn_H // // This is the declaration of the OneOneOneSplitFn class. // #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This class provides the concrete implementation of the exact leading-order * splitting function for \f$1\to 11\f$. * * In this case the splitting function is given by * \f[P(z) =2C*\left(\frac{z}{1-z}+\frac{1-z}{z}+z(1-z)\right),\f] * where \f$C=\f$ is the corresponding colour factor. * Our choice for the overestimate is * \f[P_{\rm over}(z) = 2C\left(\frac1z+\frac1{1-z}\right),\f] * therefore the integral is * \f[\int P_{\rm over}(z) {\rm d}z =2C\ln\left(\frac{z}{1-z}\right),\f] * and its inverse is * \f[\frac{\exp\left(\frac{r}{2C}\right)}{(1+\exp\left(\frac{r}{2C}\right)}\f] * * * @see \ref OneOneOneSplitFnInterfaces "The interfaces" * defined for OneOneOneSplitFn. */ class OneOneOneSplitFn: public SplittingFunction { public: /** - * The default constructor. - */ - OneOneOneSplitFn() : SplittingFunction(1) {} - - /** * Concrete implementation of the method to determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * The concrete implementation of the splitting function, \f$P(z,t)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the overestimate of the splitting function, * \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const; /** * The concrete implementation of the * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,t)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const; /** * The concrete implementation of the inverse of the indefinite integral. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const; //@} /** * Method to calculate the azimuthal angle for forward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Method to calculate the azimuthal angle for backward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Calculate the matrix element for the splitting * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike); 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(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ OneOneOneSplitFn & operator=(const OneOneOneSplitFn &); }; } #endif /* HERWIG_OneOneOneSplitFn_H */ diff --git a/Shower/QTilde/SplittingFunctions/PTCutOff.cc b/Shower/QTilde/SplittingFunctions/PTCutOff.cc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/PTCutOff.cc @@ -0,0 +1,65 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the PTCutOff class. +// + +#include "PTCutOff.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/EventRecord/Particle.h" +#include "ThePEG/Repository/UseRandom.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "ThePEG/Interface/Parameter.h" + +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" + +using namespace Herwig; + +IBPtr PTCutOff::clone() const { + return new_ptr(*this); +} + +IBPtr PTCutOff::fullclone() const { + return new_ptr(*this); +} + +void PTCutOff::persistentOutput(PersistentOStream & os) const { + os << ounit(pTmin_,GeV) << ounit(pT2min_,GeV2); +} + +void PTCutOff::persistentInput(PersistentIStream & is, int) { + is >> iunit(pTmin_,GeV) >> iunit(pT2min_,GeV2); +} + +// The following static variable is needed for the type +// description system in ThePEG. +DescribeClass +describeHerwigPTCutOff("Herwig::PTCutOff", "HwShower.so"); + +void PTCutOff::Init() { + + static ClassDocumentation documentation + ("There is no documentation for the PTCutOff class"); + + + static Parameter interfacepTmin + ("pTmin", + "The minimum pT if using a cut-off on the pT", + &PTCutOff::pTmin_, GeV, 1.0*GeV, ZERO, 10.0*GeV, + false, false, Interface::limited); + +} + +void PTCutOff::doinit() { + SudakovCutOff::doinit(); +} + +const vector & PTCutOff::virtualMasses(const IdList & ids) { + static vector output; + output.clear(); + for(auto id : ids) + output.push_back(id->mass()); + return output; +} diff --git a/Shower/QTilde/SplittingFunctions/PTCutOff.h b/Shower/QTilde/SplittingFunctions/PTCutOff.h new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/PTCutOff.h @@ -0,0 +1,125 @@ +// -*- C++ -*- +#ifndef Herwig_PTCutOff_H +#define Herwig_PTCutOff_H +// +// This is the declaration of the PTCutOff class. +// + +#include "SudakovCutOff.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * Here is the documentation of the PTCutOff class. + * + * @see \ref PTCutOffInterfaces "The interfaces" + * defined for PTCutOff. + */ +class PTCutOff: public SudakovCutOff { + +public: + + /** + * Calculate the virtual masses for a branchings + */ + virtual const vector & virtualMasses(const IdList & ids); + + /** + * Default pTmin + */ + virtual Energy pTmin() { return pTmin_; } + + /** + * Default pT2min + */ + virtual Energy2 pT2min() { return pT2min_; } + + +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(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(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 Standard Interfaced functions. */ + //@{ + /** + * Initialize this object after the setup phase before saving an + * EventGenerator to disk. + * @throws InitException if object could not be initialized properly. + */ + virtual void doinit(); + //@} + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual 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 IBPtr fullclone() const; + //@} + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + PTCutOff & operator=(const PTCutOff &) = delete; + +private: + + /** + * Parameters for the \f$p_T\f$ cut-off + */ + //@{ + /** + * The minimum \f$p_T\f$ for the branching + */ + Energy pTmin_ = 1_GeV; + + /** + * The square of the minimum \f$p_T\f$ + */ + Energy2 pT2min_ = 1_GeV2; + //@} + + +}; + +} + +#endif /* Herwig_PTCutOff_H */ diff --git a/Shower/QTilde/SplittingFunctions/SplittingFunction.cc b/Shower/QTilde/SplittingFunctions/SplittingFunction.cc --- a/Shower/QTilde/SplittingFunctions/SplittingFunction.cc +++ b/Shower/QTilde/SplittingFunctions/SplittingFunction.cc @@ -1,1043 +1,1043 @@ // -*- C++ -*- // // SplittingFunction.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SplittingFunction class. // #include "SplittingFunction.h" #include "ThePEG/Utilities/DescribeClass.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/Utilities/EnumIO.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; DescribeAbstractClass describeSplittingFunction ("Herwig::SplittingFunction",""); void SplittingFunction::Init() { static ClassDocumentation documentation ("The SplittingFunction class is the based class for 1->2 splitting functions" " in Herwig"); static Switch interfaceColourStructure ("ColourStructure", "The colour structure for the splitting function", &SplittingFunction::_colourStructure, Undefined, false, false); static SwitchOption interfaceColourStructureTripletTripletOctet (interfaceColourStructure, "TripletTripletOctet", "3 -> 3 8", TripletTripletOctet); static SwitchOption interfaceColourStructureOctetOctetOctet (interfaceColourStructure, "OctetOctetOctet", "8 -> 8 8", OctetOctetOctet); static SwitchOption interfaceColourStructureOctetTripletTriplet (interfaceColourStructure, "OctetTripletTriplet", "8 -> 3 3bar", OctetTripletTriplet); static SwitchOption interfaceColourStructureTripletOctetTriplet (interfaceColourStructure, "TripletOctetTriplet", "3 -> 8 3", TripletOctetTriplet); static SwitchOption interfaceColourStructureSextetSextetOctet (interfaceColourStructure, "SextetSextetOctet", "6 -> 6 8", SextetSextetOctet); static SwitchOption interfaceColourStructureChargedChargedNeutral (interfaceColourStructure, "ChargedChargedNeutral", "q -> q 0", ChargedChargedNeutral); static SwitchOption interfaceColourStructureNeutralChargedCharged (interfaceColourStructure, "NeutralChargedCharged", "0 -> q qbar", NeutralChargedCharged); static SwitchOption interfaceColourStructureChargedNeutralCharged (interfaceColourStructure, "ChargedNeutralCharged", "q -> 0 q", ChargedNeutralCharged); static SwitchOption interfaceColourStructureEW (interfaceColourStructure, "EW", "q -> q W/Z", EW); static Switch interfaceInteractionType ("InteractionType", "Type of the interaction", &SplittingFunction::_interactionType, ShowerInteraction::UNDEFINED, false, false); static SwitchOption interfaceInteractionTypeQCD (interfaceInteractionType, "QCD","QCD",ShowerInteraction::QCD); static SwitchOption interfaceInteractionTypeQED (interfaceInteractionType, "QED","QED",ShowerInteraction::QED); static SwitchOption interfaceInteractionTypeEW (interfaceInteractionType, "EW","EW",ShowerInteraction::EW); static Switch interfaceAngularOrdered ("AngularOrdered", "Whether or not this interaction is angular ordered, " "normally only g->q qbar and gamma-> f fbar are the only ones which aren't.", &SplittingFunction::angularOrdered_, true, false, false); static SwitchOption interfaceAngularOrderedYes (interfaceAngularOrdered, "Yes", "Interaction is angular ordered", true); static SwitchOption interfaceAngularOrderedNo (interfaceAngularOrdered, "No", "Interaction isn't angular ordered", false); static Switch interfaceScaleChoice ("ScaleChoice", "The scale choice to be used", &SplittingFunction::scaleChoice_, 2, false, false); static SwitchOption interfaceScaleChoicepT (interfaceScaleChoice, "pT", "pT of the branching", 0); static SwitchOption interfaceScaleChoiceQ2 (interfaceScaleChoice, "Q2", "Q2 of the branching", 1); static SwitchOption interfaceScaleChoiceFromAngularOrdering (interfaceScaleChoice, "FromAngularOrdering", "If angular order use pT, otherwise Q2", 2); } void SplittingFunction::persistentOutput(PersistentOStream & os) const { - os << oenum(_interactionType) << _interactionOrder + os << oenum(_interactionType) << oenum(_colourStructure) << _colourFactor << angularOrdered_ << scaleChoice_; } void SplittingFunction::persistentInput(PersistentIStream & is, int) { - is >> ienum(_interactionType) >> _interactionOrder + is >> ienum(_interactionType) >> ienum(_colourStructure) >> _colourFactor >> angularOrdered_ >> scaleChoice_; } void SplittingFunction::colourConnection(tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second, ShowerPartnerType partnerType, const bool back) const { if(_colourStructure==TripletTripletOctet) { if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency assert(( cparent.first && !cparent.second && partnerType==ShowerPartnerType::QCDColourLine) || ( !cparent.first && cparent.second && partnerType==ShowerPartnerType::QCDAntiColourLine)); // q -> q g if(cparent.first) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); newline->addColoured ( first); newline->addAntiColoured (second); } // qbar -> qbar g else { ColinePtr newline=new_ptr(ColourLine()); cparent.second->addAntiColoured(second); newline->addColoured(second); newline->addAntiColoured(first); } // Set progenitor first->progenitor(parent->progenitor()); second->progenitor(parent->progenitor()); } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(( cfirst.first && !cfirst.second && partnerType==ShowerPartnerType::QCDColourLine) || ( !cfirst.first && cfirst.second && partnerType==ShowerPartnerType::QCDAntiColourLine)); // q -> q g if(cfirst.first) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addAntiColoured(second); newline->addColoured(second); newline->addColoured(parent); } // qbar -> qbar g else { ColinePtr newline=new_ptr(ColourLine()); cfirst.second->addColoured(second); newline->addAntiColoured(second); newline->addAntiColoured(parent); } // Set progenitor parent->progenitor(first->progenitor()); second->progenitor(first->progenitor()); } } else if(_colourStructure==OctetOctetOctet) { if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency assert(cparent.first&&cparent.second); // ensure first gluon is hardest if( first->id()==second->id() && parent->showerKinematics()->z()<0.5 ) swap(first,second); // colour line radiates if(partnerType==ShowerPartnerType::QCDColourLine) { // The colour line is radiating ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); cparent.second->addAntiColoured(first); newline->addColoured(first); newline->addAntiColoured(second); } // anti colour line radiates else if(partnerType==ShowerPartnerType::QCDAntiColourLine) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); cparent.second->addAntiColoured(second); newline->addColoured(second); newline->addAntiColoured(first); } else assert(false); } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(cfirst.first&&cfirst.second); // The colour line is radiating if(partnerType==ShowerPartnerType::QCDColourLine) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addAntiColoured(second); cfirst.second->addAntiColoured(parent); newline->addColoured(parent); newline->addColoured(second); } // anti colour line radiates else if(partnerType==ShowerPartnerType::QCDAntiColourLine) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addColoured(parent); cfirst.second->addColoured(second); newline->addAntiColoured(second); newline->addAntiColoured(parent); } else assert(false); } } else if(_colourStructure == OctetTripletTriplet) { if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency assert(cparent.first&&cparent.second); cparent.first ->addColoured ( first); cparent.second->addAntiColoured(second); // Set progenitor first->progenitor(parent->progenitor()); second->progenitor(parent->progenitor()); } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(( cfirst.first && !cfirst.second) || (!cfirst.first && cfirst.second)); // g -> q qbar if(cfirst.first) { ColinePtr newline=new_ptr(ColourLine()); cfirst.first->addColoured(parent); newline->addAntiColoured(second); newline->addAntiColoured(parent); } // g -> qbar q else { ColinePtr newline=new_ptr(ColourLine()); cfirst.second->addAntiColoured(parent); newline->addColoured(second); newline->addColoured(parent); } // Set progenitor parent->progenitor(first->progenitor()); second->progenitor(first->progenitor()); } } else if(_colourStructure == TripletOctetTriplet) { if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // ensure input consistency assert(( cparent.first && !cparent.second) || (!cparent.first && cparent.second)); // q -> g q if(cparent.first) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); newline->addColoured (second); newline->addAntiColoured( first); } // qbar -> g qbar else { ColinePtr newline=new_ptr(ColourLine()); cparent.second->addAntiColoured(first); newline->addColoured ( first); newline->addAntiColoured(second); } // Set progenitor first->progenitor(parent->progenitor()); second->progenitor(parent->progenitor()); } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // ensure input consistency assert(cfirst.first&&cfirst.second); // q -> g q if(parent->id()>0) { cfirst.first ->addColoured(parent); cfirst.second->addColoured(second); } else { cfirst.first ->addAntiColoured(second); cfirst.second->addAntiColoured(parent); } // Set progenitor parent->progenitor(first->progenitor()); second->progenitor(first->progenitor()); } } else if(_colourStructure==SextetSextetOctet) { //make sure we're not doing backward evolution assert(!back); //make sure something sensible assert(parent->colourLine() || parent->antiColourLine()); //get the colour lines or anti-colour lines bool isAntiColour=true; ColinePair cparent; if(parent->colourLine()) { cparent = ColinePair(const_ptr_cast(parent->colourInfo()->colourLines()[0]), const_ptr_cast(parent->colourInfo()->colourLines()[1])); isAntiColour=false; } else { cparent = ColinePair(const_ptr_cast(parent->colourInfo()->antiColourLines()[0]), const_ptr_cast(parent->colourInfo()->antiColourLines()[1])); } //check for sensible input // assert(cparent.first && cparent.second); // sextet has 2 colour lines if(!isAntiColour) { //pick at random which of the colour topolgies to take double topology = UseRandom::rnd(); if(topology < 0.25) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); cparent.second->addColoured(first); newline->addColoured(first); newline->addAntiColoured(second); } else if(topology >=0.25 && topology < 0.5) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); cparent.second->addColoured(second); newline->addColoured(first); newline->addAntiColoured(second); } else if(topology >= 0.5 && topology < 0.75) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(second); cparent.second->addColoured(first); newline->addColoured(first); newline->addAntiColoured(second); } else { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addColoured(first); cparent.second->addColoured(second); newline->addColoured(first); newline->addAntiColoured(second); } } // sextet has 2 anti-colour lines else { double topology = UseRandom::rnd(); if(topology < 0.25){ ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(second); cparent.second->addAntiColoured(first); newline->addAntiColoured(first); newline->addColoured(second); } else if(topology >=0.25 && topology < 0.5) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(first); cparent.second->addAntiColoured(second); newline->addAntiColoured(first); newline->addColoured(second); } else if(topology >= 0.5 && topology < 0.75) { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(second); cparent.second->addAntiColoured(first); newline->addAntiColoured(first); newline->addColoured(second); } else { ColinePtr newline=new_ptr(ColourLine()); cparent.first->addAntiColoured(first); cparent.second->addAntiColoured(second); newline->addAntiColoured(first); newline->addColoured(second); } } } else if(_colourStructure == ChargedChargedNeutral) { if(!parent->data().coloured()) return; if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // q -> q g if(cparent.first) { cparent.first->addColoured(first); } // qbar -> qbar g if(cparent.second) { cparent.second->addAntiColoured(first); } } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // q -> q g if(cfirst.first) { cfirst.first->addColoured(parent); } // qbar -> qbar g if(cfirst.second) { cfirst.second->addAntiColoured(parent); } } } else if(_colourStructure == ChargedNeutralCharged) { if(!parent->data().coloured()) return; if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // q -> q g if(cparent.first) { cparent.first->addColoured(second); } // qbar -> qbar g if(cparent.second) { cparent.second->addAntiColoured(second); } } else { if (second->dataPtr()->iColour()==PDT::Colour3 ) { ColinePtr newline=new_ptr(ColourLine()); newline->addColoured(second); newline->addColoured(parent); } else if (second->dataPtr()->iColour()==PDT::Colour3bar ) { ColinePtr newline=new_ptr(ColourLine()); newline->addAntiColoured(second); newline->addAntiColoured(parent); } } } else if(_colourStructure == NeutralChargedCharged ) { if(!back) { if(first->dataPtr()->coloured()) { ColinePtr newline=new_ptr(ColourLine()); if(first->dataPtr()->iColour()==PDT::Colour3) { newline->addColoured (first ); newline->addAntiColoured(second); } else if (first->dataPtr()->iColour()==PDT::Colour3bar) { newline->addColoured (second); newline->addAntiColoured(first ); } else assert(false); } } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // gamma -> q qbar if(cfirst.first) { cfirst.first->addAntiColoured(second); } // gamma -> qbar q else if(cfirst.second) { cfirst.second->addColoured(second); } else assert(false); } } else if(_colourStructure == EW) { if(!parent->data().coloured()) return; if(!back) { ColinePair cparent = ColinePair(parent->colourLine(), parent->antiColourLine()); // q -> q g if(cparent.first) { cparent.first->addColoured(first); } // qbar -> qbar g if(cparent.second) { cparent.second->addAntiColoured(first); } } else { ColinePair cfirst = ColinePair(first->colourLine(), first->antiColourLine()); // q -> q g if(cfirst.first) { cfirst.first->addColoured(parent); } // qbar -> qbar g if(cfirst.second) { cfirst.second->addAntiColoured(parent); } } } else { assert(false); } } void SplittingFunction::doinit() { Interfaced::doinit(); assert(_interactionType!=ShowerInteraction::UNDEFINED); assert((_colourStructure>0&&_interactionType==ShowerInteraction::QCD) || (_colourStructure<0&&(_interactionType==ShowerInteraction::QED || _interactionType==ShowerInteraction::EW)) ); if(_colourFactor>0.) return; // compute the colour factors if need if(_colourStructure==TripletTripletOctet) { _colourFactor = 4./3.; } else if(_colourStructure==OctetOctetOctet) { _colourFactor = 3.; } else if(_colourStructure==OctetTripletTriplet) { _colourFactor = 0.5; } else if(_colourStructure==TripletOctetTriplet) { _colourFactor = 4./3.; } else if(_colourStructure==SextetSextetOctet) { _colourFactor = 10./3.; } else if(_colourStructure<0) { _colourFactor = 1.; } else { assert(false); } } bool SplittingFunction::checkColours(const IdList & ids) const { if(_colourStructure==TripletTripletOctet) { if(ids[0]!=ids[1]) return false; if((ids[0]->iColour()==PDT::Colour3||ids[0]->iColour()==PDT::Colour3bar) && ids[2]->iColour()==PDT::Colour8) return true; return false; } else if(_colourStructure==OctetOctetOctet) { for(unsigned int ix=0;ix<3;++ix) { if(ids[ix]->iColour()!=PDT::Colour8) return false; } return true; } else if(_colourStructure==OctetTripletTriplet) { if(ids[0]->iColour()!=PDT::Colour8) return false; if(ids[1]->iColour()==PDT::Colour3&&ids[2]->iColour()==PDT::Colour3bar) return true; if(ids[1]->iColour()==PDT::Colour3bar&&ids[2]->iColour()==PDT::Colour3) return true; return false; } else if(_colourStructure==TripletOctetTriplet) { if(ids[0]!=ids[2]) return false; if((ids[0]->iColour()==PDT::Colour3||ids[0]->iColour()==PDT::Colour3bar) && ids[1]->iColour()==PDT::Colour8) return true; return false; } else if(_colourStructure==SextetSextetOctet) { if(ids[0]!=ids[1]) return false; if((ids[0]->iColour()==PDT::Colour6 || ids[0]->iColour()==PDT::Colour6bar) && ids[2]->iColour()==PDT::Colour8) return true; return false; } else if(_colourStructure==ChargedChargedNeutral) { if(ids[0]!=ids[1]) return false; if(ids[2]->iCharge()!=0) return false; if(ids[0]->iCharge()==ids[1]->iCharge()) return true; return false; } else if(_colourStructure==ChargedNeutralCharged) { if(ids[0]!=ids[2]) return false; if(ids[1]->iCharge()!=0) return false; if(ids[0]->iCharge()==ids[2]->iCharge()) return true; return false; } else if(_colourStructure==NeutralChargedCharged) { if(ids[1]->id()!=-ids[2]->id()) return false; if(ids[0]->iCharge()!=0) return false; if(ids[1]->iCharge()==-ids[2]->iCharge()) return true; return false; } else { assert(false); } return false; } namespace { bool hasColour(tPPtr p) { PDT::Colour colour = p->dataPtr()->iColour(); return colour==PDT::Colour3 || colour==PDT::Colour8 || colour == PDT::Colour6; } bool hasAntiColour(tPPtr p) { PDT::Colour colour = p->dataPtr()->iColour(); return colour==PDT::Colour3bar || colour==PDT::Colour8 || colour == PDT::Colour6bar; } } void SplittingFunction::evaluateFinalStateScales(ShowerPartnerType partnerType, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr emitter, tShowerParticlePtr emitted) { // identify emitter and emitted double zEmitter = z, zEmitted = 1.-z; bool bosonSplitting(false); // special for g -> gg, particle highest z is emitter if(emitter->id() == emitted->id() && emitter->id() == parent->id() && zEmitted > zEmitter) { swap(zEmitted,zEmitter); swap( emitted, emitter); } // otherwise if particle ID same else if(emitted->id()==parent->id()) { swap(zEmitted,zEmitter); swap( emitted, emitter); } // no real emitter/emitted else if(emitter->id()!=parent->id()) { bosonSplitting = true; } // may need to add angularOrder flag here // now the various scales // QED if(partnerType==ShowerPartnerType::QED) { assert(colourStructure()==ChargedChargedNeutral || colourStructure()==ChargedNeutralCharged || colourStructure()==NeutralChargedCharged ); // normal case if(!bosonSplitting) { assert(colourStructure()==ChargedChargedNeutral || colourStructure()==ChargedNeutralCharged ); // set the scales // emitter emitter->scales().QED = zEmitter*scale; emitter->scales().QED_noAO = scale; emitter->scales().QCD_c = min(scale,parent->scales().QCD_c ); emitter->scales().QCD_c_noAO = min(scale,parent->scales().QCD_c_noAO ); emitter->scales().QCD_ac = min(scale,parent->scales().QCD_ac ); emitter->scales().QCD_ac_noAO = min(scale,parent->scales().QCD_ac_noAO); emitter->scales().EW = min(scale,parent->scales().EW ); emitter->scales().EW_noAO = min(scale,parent->scales().EW_noAO ); // emitted emitted->scales().QED = zEmitted*scale; emitted->scales().QED_noAO = scale; emitted->scales().QCD_c = ZERO; emitted->scales().QCD_c_noAO = ZERO; emitted->scales().QCD_ac = ZERO; emitted->scales().QCD_ac_noAO = ZERO; emitted->scales().EW = min(scale,parent->scales().EW ); emitted->scales().EW_noAO = min(scale,parent->scales().EW_noAO ); } // gamma -> f fbar else { assert(colourStructure()==NeutralChargedCharged ); // emitter emitter->scales().QED = zEmitter*scale; emitter->scales().QED_noAO = scale; if(hasColour(emitter)) { emitter->scales().QCD_c = zEmitter*scale; emitter->scales().QCD_c_noAO = scale; } if(hasAntiColour(emitter)) { emitter->scales().QCD_ac = zEmitter*scale; emitter->scales().QCD_ac_noAO = scale; } emitter->scales().EW = zEmitter*scale; emitter->scales().EW_noAO = scale; // emitted emitted->scales().QED = zEmitted*scale; emitted->scales().QED_noAO = scale; if(hasColour(emitted)) { emitted->scales().QCD_c = zEmitted*scale; emitted->scales().QCD_c_noAO = scale; } if(hasAntiColour(emitted)) { emitted->scales().QCD_ac = zEmitted*scale; emitted->scales().QCD_ac_noAO = scale; } emitted->scales().EW = zEmitted*scale; emitted->scales().EW_noAO = scale; } } // QCD else if (partnerType==ShowerPartnerType::QCDColourLine || partnerType==ShowerPartnerType::QCDAntiColourLine) { // normal case eg q -> q g and g -> g g if(!bosonSplitting) { emitter->scales().QED = min(scale,parent->scales().QED ); emitter->scales().QED_noAO = min(scale,parent->scales().QED_noAO); emitter->scales().EW = min(scale,parent->scales().EW ); emitter->scales().EW_noAO = min(scale,parent->scales().EW_noAO); if(partnerType==ShowerPartnerType::QCDColourLine) { emitter->scales().QCD_c = zEmitter*scale; emitter->scales().QCD_c_noAO = scale; emitter->scales().QCD_ac = min(zEmitter*scale,parent->scales().QCD_ac ); emitter->scales().QCD_ac_noAO = min( scale,parent->scales().QCD_ac_noAO); } else { emitter->scales().QCD_c = min(zEmitter*scale,parent->scales().QCD_c ); emitter->scales().QCD_c_noAO = min( scale,parent->scales().QCD_c_noAO ); emitter->scales().QCD_ac = zEmitter*scale; emitter->scales().QCD_ac_noAO = scale; } // emitted emitted->scales().QED = ZERO; emitted->scales().QED_noAO = ZERO; emitted->scales().QCD_c = zEmitted*scale; emitted->scales().QCD_c_noAO = scale; emitted->scales().QCD_ac = zEmitted*scale; emitted->scales().QCD_ac_noAO = scale; emitted->scales().EW = min(scale,parent->scales().EW ); emitted->scales().EW_noAO = min(scale,parent->scales().EW_noAO); } // g -> q qbar else { // emitter if(emitter->dataPtr()->charged()) { emitter->scales().QED = zEmitter*scale; emitter->scales().QED_noAO = scale; } emitter->scales().EW = zEmitter*scale; emitter->scales().EW_noAO = scale; emitter->scales().QCD_c = zEmitter*scale; emitter->scales().QCD_c_noAO = scale; emitter->scales().QCD_ac = zEmitter*scale; emitter->scales().QCD_ac_noAO = scale; // emitted if(emitted->dataPtr()->charged()) { emitted->scales().QED = zEmitted*scale; emitted->scales().QED_noAO = scale; } emitted->scales().EW = zEmitted*scale; emitted->scales().EW_noAO = scale; emitted->scales().QCD_c = zEmitted*scale; emitted->scales().QCD_c_noAO = scale; emitted->scales().QCD_ac = zEmitted*scale; emitted->scales().QCD_ac_noAO = scale; } } else if(partnerType==ShowerPartnerType::EW) { // EW emitter->scales().EW = zEmitter*scale; emitter->scales().EW_noAO = scale; emitted->scales().EW = zEmitted*scale; emitted->scales().EW_noAO = scale; // QED // W radiation AO if(emitted->dataPtr()->charged()) { emitter->scales().QED = zEmitter*scale; emitter->scales().QED_noAO = scale; emitted->scales().QED = zEmitted*scale; emitted->scales().QED_noAO = scale; } // Z don't else { emitter->scales().QED = min(scale,parent->scales().QED ); emitter->scales().QED_noAO = min(scale,parent->scales().QED_noAO); emitted->scales().QED = ZERO; emitted->scales().QED_noAO = ZERO; } // QCD emitter->scales().QCD_c = min(scale,parent->scales().QCD_c ); emitter->scales().QCD_c_noAO = min(scale,parent->scales().QCD_c_noAO ); emitter->scales().QCD_ac = min(scale,parent->scales().QCD_ac ); emitter->scales().QCD_ac_noAO = min(scale,parent->scales().QCD_ac_noAO); emitted->scales().QCD_c = ZERO; emitted->scales().QCD_c_noAO = ZERO; emitted->scales().QCD_ac = ZERO; emitted->scales().QCD_ac_noAO = ZERO; } else assert(false); } void SplittingFunction::evaluateInitialStateScales(ShowerPartnerType partnerType, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr spacelike, tShowerParticlePtr timelike) { // scale for time-like child Energy AOScale = (1.-z)*scale; // QED if(partnerType==ShowerPartnerType::QED) { if(parent->id()==spacelike->id()) { // parent parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; parent ->scales().QCD_c = min(scale,spacelike->scales().QCD_c ); parent ->scales().QCD_c_noAO = min(scale,spacelike->scales().QCD_c_noAO ); parent ->scales().QCD_ac = min(scale,spacelike->scales().QCD_ac ); parent ->scales().QCD_ac_noAO = min(scale,spacelike->scales().QCD_ac_noAO); // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; timelike->scales().QCD_c = ZERO; timelike->scales().QCD_c_noAO = ZERO; timelike->scales().QCD_ac = ZERO; timelike->scales().QCD_ac_noAO = ZERO; } else if(parent->id()==timelike->id()) { parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; if(hasColour(parent)) { parent ->scales().QCD_c = scale; parent ->scales().QCD_c_noAO = scale; } if(hasAntiColour(parent)) { parent ->scales().QCD_ac = scale; parent ->scales().QCD_ac_noAO = scale; } // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; if(hasColour(timelike)) { timelike->scales().QCD_c = AOScale; timelike->scales().QCD_c_noAO = scale; } if(hasAntiColour(timelike)) { timelike->scales().QCD_ac = AOScale; timelike->scales().QCD_ac_noAO = scale; } } else { parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; parent ->scales().QCD_c = ZERO ; parent ->scales().QCD_c_noAO = ZERO ; parent ->scales().QCD_ac = ZERO ; parent ->scales().QCD_ac_noAO = ZERO ; // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; if(hasColour(timelike)) { timelike->scales().QCD_c = min(AOScale,spacelike->scales().QCD_ac ); timelike->scales().QCD_c_noAO = min( scale,spacelike->scales().QCD_ac_noAO); } if(hasAntiColour(timelike)) { timelike->scales().QCD_ac = min(AOScale,spacelike->scales().QCD_c ); timelike->scales().QCD_ac_noAO = min( scale,spacelike->scales().QCD_c_noAO ); } } } // QCD else if (partnerType==ShowerPartnerType::QCDColourLine || partnerType==ShowerPartnerType::QCDAntiColourLine) { // timelike if(timelike->dataPtr()->charged()) { timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; } if(hasColour(timelike)) { timelike->scales().QCD_c = AOScale; timelike->scales().QCD_c_noAO = scale; } if(hasAntiColour(timelike)) { timelike->scales().QCD_ac = AOScale; timelike->scales().QCD_ac_noAO = scale; } if(parent->id()==spacelike->id()) { parent ->scales().QED = min(scale,spacelike->scales().QED ); parent ->scales().QED_noAO = min(scale,spacelike->scales().QED_noAO ); parent ->scales().QCD_c = min(scale,spacelike->scales().QCD_c ); parent ->scales().QCD_c_noAO = min(scale,spacelike->scales().QCD_c_noAO ); parent ->scales().QCD_ac = min(scale,spacelike->scales().QCD_ac ); parent ->scales().QCD_ac_noAO = min(scale,spacelike->scales().QCD_ac_noAO); } else { if(parent->dataPtr()->charged()) { parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; } if(hasColour(parent)) { parent ->scales().QCD_c = scale; parent ->scales().QCD_c_noAO = scale; } if(hasAntiColour(parent)) { parent ->scales().QCD_ac = scale; parent ->scales().QCD_ac_noAO = scale; } } } else if(partnerType==ShowerPartnerType::EW) { if(abs(spacelike->id())!=ParticleID::Wplus && spacelike->id() !=ParticleID::Z0 ) { // QCD scales parent ->scales().QCD_c = min(scale,spacelike->scales().QCD_c ); parent ->scales().QCD_c_noAO = min(scale,spacelike->scales().QCD_c_noAO ); parent ->scales().QCD_ac = min(scale,spacelike->scales().QCD_ac ); parent ->scales().QCD_ac_noAO = min(scale,spacelike->scales().QCD_ac_noAO); timelike->scales().QCD_c = ZERO; timelike->scales().QCD_c_noAO = ZERO; timelike->scales().QCD_ac = ZERO; timelike->scales().QCD_ac_noAO = ZERO; // QED scales if(timelike->id()==ParticleID::Z0) { parent ->scales().QED = min(scale,spacelike->scales().QED ); parent ->scales().QED_noAO = min(scale,spacelike->scales().QED_noAO ); timelike->scales().QED = ZERO; timelike->scales().QED_noAO = ZERO; } else { parent ->scales().QED = scale; parent ->scales().QED_noAO = scale; timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; } // EW scales parent ->scales().EW = scale; parent ->scales().EW_noAO = scale; timelike->scales().EW = AOScale; timelike->scales().EW_noAO = scale; } else assert(false); } else assert(false); } void SplittingFunction::evaluateDecayScales(ShowerPartnerType partnerType, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr spacelike, tShowerParticlePtr timelike) { assert(parent->id()==spacelike->id()); // angular-ordered scale for 2nd child Energy AOScale = (1.-z)*scale; // QED if(partnerType==ShowerPartnerType::QED) { // timelike timelike->scales().QED = AOScale; timelike->scales().QED_noAO = scale; timelike->scales().QCD_c = ZERO; timelike->scales().QCD_c_noAO = ZERO; timelike->scales().QCD_ac = ZERO; timelike->scales().QCD_ac_noAO = ZERO; timelike->scales().EW = ZERO; timelike->scales().EW_noAO = ZERO; // spacelike spacelike->scales().QED = scale; spacelike->scales().QED_noAO = scale; spacelike->scales().EW = max(scale,parent->scales().EW ); spacelike->scales().EW_noAO = max(scale,parent->scales().EW_noAO ); } // QCD else if(partnerType==ShowerPartnerType::QCDColourLine || partnerType==ShowerPartnerType::QCDAntiColourLine) { // timelike timelike->scales().QED = ZERO; timelike->scales().QED_noAO = ZERO; timelike->scales().QCD_c = AOScale; timelike->scales().QCD_c_noAO = scale; timelike->scales().QCD_ac = AOScale; timelike->scales().QCD_ac_noAO = scale; timelike->scales().EW = ZERO; timelike->scales().EW_noAO = ZERO; // spacelike spacelike->scales().QED = max(scale,parent->scales().QED ); spacelike->scales().QED_noAO = max(scale,parent->scales().QED_noAO ); spacelike->scales().EW = max(scale,parent->scales().EW ); spacelike->scales().EW_noAO = max(scale,parent->scales().EW_noAO ); } else if(partnerType==ShowerPartnerType::EW) { // EW timelike->scales().EW = AOScale; timelike->scales().EW_noAO = scale; spacelike->scales().EW = max(scale,parent->scales().EW ); spacelike->scales().EW_noAO = max(scale,parent->scales().EW_noAO ); // QCD timelike->scales().QCD_c = ZERO; timelike->scales().QCD_c_noAO = ZERO; timelike->scales().QCD_ac = ZERO; timelike->scales().QCD_ac_noAO = ZERO; timelike->scales().EW = ZERO; timelike->scales().EW_noAO = ZERO; // QED timelike->scales().QED = ZERO; timelike->scales().QED_noAO = ZERO; spacelike->scales().QED = max(scale,parent->scales().QED ); spacelike->scales().QED_noAO = max(scale,parent->scales().QED_noAO ); } else assert(false); spacelike->scales().QCD_c = max(scale,parent->scales().QCD_c ); spacelike->scales().QCD_c_noAO = max(scale,parent->scales().QCD_c_noAO ); spacelike->scales().QCD_ac = max(scale,parent->scales().QCD_ac ); spacelike->scales().QCD_ac_noAO = max(scale,parent->scales().QCD_ac_noAO); } diff --git a/Shower/QTilde/SplittingFunctions/SplittingFunction.h b/Shower/QTilde/SplittingFunctions/SplittingFunction.h --- a/Shower/QTilde/SplittingFunctions/SplittingFunction.h +++ b/Shower/QTilde/SplittingFunctions/SplittingFunction.h @@ -1,393 +1,382 @@ // -*- C++ -*- // // SplittingFunction.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_SplittingFunction_H #define HERWIG_SplittingFunction_H // // This is the declaration of the SplittingFunction class. // #include "ThePEG/Interface/Interfaced.h" #include "Herwig/Shower/QTilde/ShowerConfig.h" #include "ThePEG/EventRecord/RhoDMatrix.h" #include "Herwig/Decay/DecayMatrixElement.h" -#include "Herwig/Shower/QTilde/Base/ShowerKinematics.fh" +#include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.fh" #include "ThePEG/EventRecord/ColourLine.h" #include "ThePEG/PDT/ParticleData.h" #include "SplittingFunction.fh" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * Enum to define the possible types of colour structure which can occur in * the branching. */ enum ColourStructure {Undefined=0, TripletTripletOctet = 1,OctetOctetOctet =2, OctetTripletTriplet = 3,TripletOctetTriplet=4, SextetSextetOctet = 5, ChargedChargedNeutral=-1,ChargedNeutralCharged=-2, NeutralChargedCharged=-3,EW=-4}; /** \ingroup Shower * * This is an abstract class which defines the common interface * for all \f$1\to2\f$ splitting functions, for both initial-state * and final-state radiation. * * The SplittingFunction class contains a number of purely virtual members * which must be implemented in the inheriting classes. The class also stores * the interaction type of the spltting function. * * The inheriting classes need to specific the splitting function * \f$P(z,2p_j\cdot p_k)\f$, in terms of the energy fraction \f$z\f$ and * the evolution scale. In order to allow the splitting functions to be used * with different choices of evolution functions the scale is given by * \f[2p_j\cdot p_k=(p_j+p_k)^2-m_{jk}^2=Q^2-(p_j+p_k)^2=z(1-z)\tilde{q}^2= * \frac{p_T^2}{z(1-z)}-m_{jk}^2+\frac{m_j^2}{z}+\frac{m_k^2}{1-z},\f] * where \f$Q^2\f$ is the virtuality of the branching particle, * $p_T$ is the relative transverse momentum of the branching products and * \f$\tilde{q}^2\f$ is the angular variable described in hep-ph/0310083. * * In addition an overestimate of the * splitting function, \f$P_{\rm over}(z)\f$ which only depends upon \f$z\f$, * the integral, inverse of the integral for this overestimate and * ratio of the true splitting function to the overestimate must be provided * as they are necessary for the veto alogrithm used to implement the evolution. * * @see \ref SplittingFunctionInterfaces "The interfaces" * defined for SplittingFunction. */ class SplittingFunction: public Interfaced { public: /** * The default constructor. * @param b All splitting functions must have an interaction order */ - SplittingFunction(unsigned int b) + SplittingFunction() : Interfaced(), _interactionType(ShowerInteraction::UNDEFINED), - _interactionOrder(b), _colourStructure(Undefined), _colourFactor(-1.), angularOrdered_(true), scaleChoice_(2) {} public: /** * Methods to return the interaction type and order for the splitting function */ //@{ /** * Return the type of the interaction */ ShowerInteraction interactionType() const {return _interactionType;} /** - * Return the order of the splitting function in the interaction - */ - unsigned int interactionOrder() const {return _interactionOrder;} - - /** * Return the colour structure */ ColourStructure colourStructure() const {return _colourStructure;} /** * Return the colour factor */ double colourFactor(const IdList &ids) const { if(_colourStructure>0) return _colourFactor; else if(_colourStructure<0) { if(_colourStructure==ChargedChargedNeutral || _colourStructure==ChargedNeutralCharged) { return sqr(double(ids[0]->iCharge())/3.); } else if(_colourStructure==NeutralChargedCharged) { double fact = sqr(double(ids[1]->iCharge())/3.); if(ids[1]->coloured()) fact *= abs(double(ids[1]->iColour())); return fact; } else if(_colourStructure==EW) { return 1.; } else assert(false); } else assert(false); } //@} /** * Purely virtual method which should determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const = 0; /** * Method to check the colours are correct */ virtual bool checkColours(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * Purely virtual method which should return the exact value of the splitting function, * \f$P\f$ evaluated in terms of the energy fraction, \f$z\f$, and the evolution scale \f$\tilde{q}^2\f$. * @param z The energy fraction. * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double P(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const = 0; /** * Purely virtual method which should return * an overestimate of the splitting function, * \f$P_{\rm over}\f$ such that the result \f$P_{\rm over}\geq P\f$. This function * should be simple enough that it does not depend on the evolution scale. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const = 0; /** * Purely virtual method which should return * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,\tilde{q}^2)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, const bool mass, const RhoDMatrix & rho) const = 0; /** * Purely virtual method which should return the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ * */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const = 0; /** * Purely virtual method which should return the inverse of the * indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$ which is used to * generate the value of \f$z\f$. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const = 0; //@} /** * Purely virtual method which should make the proper colour connection * between the emitting parent and the branching products. * @param parent The parent for the branching * @param first The first branching product * @param second The second branching product * @param partnerType The type of evolution partner * @param back Whether this is foward or backward evolution. */ virtual void colourConnection(tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second, ShowerPartnerType partnerType, const bool back) const; /** * Method to calculate the azimuthal angle for forward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &) = 0; /** * Method to calculate the azimuthal angle for backward evolution * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &) = 0; /** * Calculate the matrix element for the splitting * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param phi The azimuthal angle, \f$\phi\f$. * @param timeLike Whether timelike or spacelike, affects inclusive of mass terms */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike) = 0; /** * Whether or not the interaction is angular ordered */ bool angularOrdered() const {return angularOrdered_;} /** * Scale choice */ bool pTScale() const { return scaleChoice_ == 2 ? angularOrdered_ : scaleChoice_ == 0; } /** * Functions to state scales after branching happens */ //@{ /** * Sort out scales for final-state emission */ void evaluateFinalStateScales(ShowerPartnerType type, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second); /** * Sort out scales for initial-state emission */ void evaluateInitialStateScales(ShowerPartnerType type, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second); /** * Sort out scales for decay emission */ void evaluateDecayScales(ShowerPartnerType type, Energy scale, double z, tShowerParticlePtr parent, tShowerParticlePtr first, tShowerParticlePtr second); //@} 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(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(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 Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ virtual void doinit(); //@} protected: /** * Set the colour factor */ void colourFactor(double in) {_colourFactor=in;} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ SplittingFunction & operator=(const SplittingFunction &); private: /** * The interaction type for the splitting function. */ ShowerInteraction _interactionType; /** - * The order of the splitting function in the coupling - */ - unsigned int _interactionOrder; - - /** * The colour structure */ ColourStructure _colourStructure; /** * The colour factor */ double _colourFactor; /** * Whether or not this interaction is angular-ordered */ bool angularOrdered_; /** * The choice of scale */ unsigned int scaleChoice_; }; } #endif /* HERWIG_SplittingFunction_H */ diff --git a/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc b/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc --- a/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc +++ b/Shower/QTilde/SplittingFunctions/SplittingGenerator.cc @@ -1,648 +1,647 @@ // -*- C++ -*- // // SplittingGenerator.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SplittingGenerator class. // #include "SplittingGenerator.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Command.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Utilities/StringUtils.h" #include "ThePEG/Repository/Repository.h" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "Herwig/Shower/ShowerHandler.h" #include "ThePEG/Utilities/Rebinder.h" #include #include "ThePEG/Utilities/DescribeClass.h" using namespace Herwig; namespace { bool checkInteraction(ShowerInteraction allowed, ShowerInteraction splitting) { if(allowed==ShowerInteraction::ALL) return true; else if(allowed==ShowerInteraction::QEDQCD && (splitting==ShowerInteraction::QED || splitting==ShowerInteraction::QCD )) return true; else if(allowed == splitting) return true; else return false; } } DescribeClass describeSplittingGenerator ("Herwig::SplittingGenerator",""); IBPtr SplittingGenerator::clone() const { return new_ptr(*this); } IBPtr SplittingGenerator::fullclone() const { return new_ptr(*this); } void SplittingGenerator::persistentOutput(PersistentOStream & os) const { os << _bbranchings << _fbranchings << _deTuning; } void SplittingGenerator::persistentInput(PersistentIStream & is, int) { is >> _bbranchings >> _fbranchings >> _deTuning; } void SplittingGenerator::Init() { static ClassDocumentation documentation ("There class is responsible for initializing the Sudakov form factors ", "and generating splittings."); static Command interfaceAddSplitting ("AddFinalSplitting", "Adds another splitting to the list of splittings considered " "in the shower. Command is a->b,c; Sudakov", &SplittingGenerator::addFinalSplitting); static Command interfaceAddInitialSplitting ("AddInitialSplitting", "Adds another splitting to the list of initial splittings to consider " "in the shower. Command is a->b,c; Sudakov. Here the particle a is the " "particle that is PRODUCED by the splitting. b is the initial state " "particle that is splitting in the shower.", &SplittingGenerator::addInitialSplitting); static Command interfaceDeleteSplitting ("DeleteFinalSplitting", "Deletes a splitting from the list of splittings considered " "in the shower. Command is a->b,c; Sudakov", &SplittingGenerator::deleteFinalSplitting); static Command interfaceDeleteInitialSplitting ("DeleteInitialSplitting", "Deletes a splitting from the list of initial splittings to consider " "in the shower. Command is a->b,c; Sudakov. Here the particle a is the " "particle that is PRODUCED by the splitting. b is the initial state " "particle that is splitting in the shower.", &SplittingGenerator::deleteInitialSplitting); static Parameter interfaceDetuning ("Detuning", "The Detuning parameter to make the veto algorithm less efficient to improve the weight variations", &SplittingGenerator::_deTuning, 1.0, 1.0, 10.0, false, false, Interface::limited); } string SplittingGenerator::addSplitting(string arg, bool final) { string partons = StringUtils::car(arg); string sudakov = StringUtils::cdr(arg); vector products; string::size_type next = partons.find("->"); if(next == string::npos) return "Error: Invalid string for splitting " + arg; if(partons.find(';') == string::npos) return "Error: Invalid string for splitting " + arg; tPDPtr parent = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+2); do { next = min(partons.find(','), partons.find(';')); tPDPtr pdp = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+1); if(pdp) products.push_back(pdp); else return "Error: Could not create splitting from " + arg; } while(partons[0] != ';' && partons.size()); SudakovPtr s; s = dynamic_ptr_cast(Repository::TraceObject(sudakov)); if(!s) return "Error: Could not load Sudakov " + sudakov + '\n'; IdList ids; ids.push_back(parent); for(vector::iterator it = products.begin(); it!=products.end(); ++it) ids.push_back(*it); // check splitting can handle this if(!s->splittingFn()->accept(ids)) return "Error: Sudakov " + sudakov + " SplittingFunction can't handle particles\n"; // add to map addToMap(ids,s,final); return ""; } string SplittingGenerator::deleteSplitting(string arg, bool final) { string partons = StringUtils::car(arg); string sudakov = StringUtils::cdr(arg); vector products; string::size_type next = partons.find("->"); if(next == string::npos) return "Error: Invalid string for splitting " + arg; if(partons.find(';') == string::npos) return "Error: Invalid string for splitting " + arg; tPDPtr parent = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+2); do { next = min(partons.find(','), partons.find(';')); tPDPtr pdp = Repository::findParticle(partons.substr(0,next)); partons = partons.substr(next+1); if(pdp) products.push_back(pdp); else return "Error: Could not create splitting from " + arg; } while(partons[0] != ';' && partons.size()); SudakovPtr s; s = dynamic_ptr_cast(Repository::TraceObject(sudakov)); if(!s) return "Error: Could not load Sudakov " + sudakov + '\n'; IdList ids; ids.push_back(parent); for(vector::iterator it = products.begin(); it!=products.end(); ++it) ids.push_back(*it); // check splitting can handle this if(!s->splittingFn()->accept(ids)) return "Error: Sudakov " + sudakov + " SplittingFunction can't handle particles\n"; // delete from map deleteFromMap(ids,s,final); return ""; } void SplittingGenerator::addToMap(const IdList &ids, const SudakovPtr &s, bool final) { if(!final) { // search if the branching was already included. auto binsert =BranchingInsert(abs(ids[1]->id()),BranchingElement(s,ids)); // get the range of already inserted splittings. auto eqrange=_bbranchings.equal_range(binsert.first); for(auto it = eqrange.first; it != eqrange.second; ++it){ if((*it).second == binsert.second) throw Exception()<<"SplittingGenerator: Trying to insert existing splitting.\n" << Exception::setuperror; } _bbranchings.insert(binsert); s->addSplitting(ids); } else { // search if the branching was already included. auto binsert =BranchingInsert(abs(ids[0]->id()),BranchingElement(s,ids)); // get the range of already inserted splittings. auto eqrange=_fbranchings.equal_range(binsert.first); for(auto it = eqrange.first; it != eqrange.second; ++it){ if((*it).second ==binsert.second) throw Exception()<<"SplittingGenerator: Trying to insert existing splitting.\n" << Exception::setuperror; } _fbranchings.insert(binsert); s->addSplitting(ids); } } void SplittingGenerator::deleteFromMap(const IdList &ids, const SudakovPtr &s, bool final) { bool didRemove=false; if(!final) { pair range = _bbranchings.equal_range(abs(ids[1]->id())); for(BranchingList::iterator it=range.first; it!=range.second&&it!=_bbranchings.end();++it) { if(it->second.sudakov==s&&it->second.particles==ids) { BranchingList::iterator it2=it; --it; _bbranchings.erase(it2); didRemove=true; } } s->removeSplitting(ids); } else { pair range = _fbranchings.equal_range(abs(ids[0]->id())); for(BranchingList::iterator it=range.first; it!=range.second&&it!=_fbranchings.end();++it) { if(it->second.sudakov==s&&it->second.particles==ids) { BranchingList::iterator it2 = it; --it; _fbranchings.erase(it2); didRemove=true; } } s->removeSplitting(ids); } if (!didRemove) throw Exception()<<"SplittingGenerator: Try to remove non existing splitting.\n" << Exception::setuperror; } Branching SplittingGenerator::chooseForwardBranching(ShowerParticle &particle, double enhance, ShowerInteraction type) const { RhoDMatrix rho; bool rhoCalc(false); Energy newQ = ZERO; ShoKinPtr kinematics = ShoKinPtr(); ShowerPartnerType partnerType(ShowerPartnerType::Undefined); SudakovPtr sudakov = SudakovPtr(); IdList ids; // First, find the eventual branching, corresponding to the highest scale. long index = abs(particle.data().id()); // if no branchings return empty branching struct if( _fbranchings.find(index) == _fbranchings.end() ) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined); // otherwise select branching for(BranchingList::const_iterator cit = _fbranchings.lower_bound(index); cit != _fbranchings.upper_bound(index); ++cit) { // check either right interaction or doing both if(!checkInteraction(type,cit->second.sudakov->interactionType())) continue; if(!rhoCalc) { rho = particle.extractRhoMatrix(true); rhoCalc = true; } // whether or not this interaction should be angular ordered bool angularOrdered = cit->second.sudakov->splittingFn()->angularOrdered(); ShoKinPtr newKin; ShowerPartnerType type; IdList particles = particle.id()!=cit->first ? cit->second.conjugateParticles : cit->second.particles; // work out which starting scale we need if(cit->second.sudakov->interactionType()==ShowerInteraction::QED) { type = ShowerPartnerType::QED; Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO; newKin = cit->second.sudakov-> - generateNextTimeBranching(startingScale,particles,rho,enhance,_deTuning, - particle.scales().Max_Q2); + generateNextTimeBranching(startingScale,particles,rho,enhance, + _deTuning); } else if(cit->second.sudakov->interactionType()==ShowerInteraction::QCD) { // special for octets if(particle.dataPtr()->iColour()==PDT::Colour8) { // octet -> octet octet if(cit->second.sudakov->splittingFn()->colourStructure()==OctetOctetOctet) { type = ShowerPartnerType::QCDColourLine; Energy startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; newKin= cit->second.sudakov-> - generateNextTimeBranching(startingScale,particles,rho,0.5*enhance,_deTuning, - particle.scales().Max_Q2); + generateNextTimeBranching(startingScale,particles,rho,0.5*enhance, + _deTuning); startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; ShoKinPtr newKin2 = cit->second.sudakov-> - generateNextTimeBranching(startingScale,particles,rho,0.5*enhance,_deTuning, - particle.scales().Max_Q2); + generateNextTimeBranching(startingScale,particles,rho,0.5*enhance, + _deTuning); // pick the one with the highest scale if( ( newKin && newKin2 && newKin2->scale() > newKin->scale()) || (!newKin && newKin2) ) { newKin = newKin2; type = ShowerPartnerType::QCDAntiColourLine; } } // other g -> q qbar else { Energy startingScale = angularOrdered ? max(particle.scales().QCD_c , particle.scales().QCD_ac ) : max(particle.scales().QCD_c_noAO, particle.scales().QCD_ac_noAO); newKin= cit->second.sudakov-> - generateNextTimeBranching(startingScale,particles,rho,enhance,_deTuning, - particle.scales().Max_Q2); + generateNextTimeBranching(startingScale,particles,rho,enhance, + _deTuning); type = UseRandom::rndbool() ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine; } } // everything else q-> qg etc else { Energy startingScale; if(particle.hasColour()) { type = ShowerPartnerType::QCDColourLine; startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; } else { type = ShowerPartnerType::QCDAntiColourLine; startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; } newKin= cit->second.sudakov-> - generateNextTimeBranching(startingScale,particles,rho,enhance,_deTuning, - particle.scales().Max_Q2); + generateNextTimeBranching(startingScale,particles,rho,enhance, + _deTuning); } } else if(cit->second.sudakov->interactionType()==ShowerInteraction::EW) { type = ShowerPartnerType::EW; Energy startingScale = particle.scales().EW; newKin = cit->second.sudakov-> - generateNextTimeBranching(startingScale,particles,rho,enhance,_deTuning, - particle.scales().Max_Q2); + generateNextTimeBranching(startingScale,particles,rho,enhance,_deTuning); } // shouldn't be anything else else assert(false); // if no kinematics contine if(!newKin) continue; // select highest scale if( newKin->scale() > newQ ) { kinematics = newKin; newQ = newKin->scale(); ids = particles; sudakov = cit->second.sudakov; partnerType = type; } } // return empty branching if nothing happened if(!kinematics) { - particle.spinInfo()->undecay(); + if ( particle.spinInfo() ) particle.spinInfo()->undecay(); return Branching(ShoKinPtr(), IdList(),SudakovPtr(), ShowerPartnerType::Undefined); } // if not hard generate phi kinematics->phi(sudakov->generatePhiForward(particle,ids,kinematics,rho)); // and return it return Branching(kinematics, ids,sudakov,partnerType); } Branching SplittingGenerator:: chooseDecayBranching(ShowerParticle &particle, const ShowerParticle::EvolutionScales & stoppingScales, Energy minmass, double enhance, ShowerInteraction interaction) const { RhoDMatrix rho(particle.dataPtr()->iSpin()); Energy newQ = Constants::MaxEnergy; ShoKinPtr kinematics; SudakovPtr sudakov; ShowerPartnerType partnerType(ShowerPartnerType::Undefined); IdList ids; // First, find the eventual branching, corresponding to the lowest scale. long index = abs(particle.data().id()); // if no branchings return empty branching struct if(_fbranchings.find(index) == _fbranchings.end()) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined); // otherwise select branching for(BranchingList::const_iterator cit = _fbranchings.lower_bound(index); cit != _fbranchings.upper_bound(index); ++cit) { // check interaction doesn't change flavour if(cit->second.particles[1]->id()!=index&&cit->second.particles[2]->id()!=index) continue; // check either right interaction or doing both if(!checkInteraction(interaction,cit->second.sudakov->interactionType())) continue; // whether or not this interaction should be angular ordered bool angularOrdered = cit->second.sudakov->splittingFn()->angularOrdered(); ShoKinPtr newKin; IdList particles = particle.id()!=cit->first ? cit->second.conjugateParticles : cit->second.particles; ShowerPartnerType type; // work out which starting scale we need if(cit->second.sudakov->interactionType()==ShowerInteraction::QED) { type = ShowerPartnerType::QED; Energy stoppingScale = angularOrdered ? stoppingScales.QED : stoppingScales.QED_noAO; Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO; if(startingScale < stoppingScale ) { newKin = cit->second.sudakov-> generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho, enhance,_deTuning); } } else if(cit->second.sudakov->interactionType()==ShowerInteraction::QCD) { // special for octets if(particle.dataPtr()->iColour()==PDT::Colour8) { // octet -> octet octet if(cit->second.sudakov->splittingFn()->colourStructure()==OctetOctetOctet) { Energy stoppingColour = angularOrdered ? stoppingScales.QCD_c : stoppingScales.QCD_c_noAO; Energy stoppingAnti = angularOrdered ? stoppingScales.QCD_ac : stoppingScales.QCD_ac_noAO; Energy startingColour = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; Energy startingAnti = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; type = ShowerPartnerType::QCDColourLine; if(startingColoursecond.sudakov-> generateNextDecayBranching(startingColour,stoppingColour,minmass, particles,rho,0.5*enhance,_deTuning); } ShoKinPtr newKin2; if(startingAntisecond.sudakov-> generateNextDecayBranching(startingAnti,stoppingAnti,minmass, particles,rho,0.5*enhance,_deTuning); } // pick the one with the lowest scale if( (newKin&&newKin2&&newKin2->scale()scale()) || (!newKin&&newKin2) ) { newKin = newKin2; type = ShowerPartnerType::QCDAntiColourLine; } } // other else { assert(false); } } // everything else else { Energy startingScale,stoppingScale; if(particle.hasColour()) { type = ShowerPartnerType::QCDColourLine; stoppingScale = angularOrdered ? stoppingScales.QCD_c : stoppingScales.QCD_c_noAO; startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; } else { type = ShowerPartnerType::QCDAntiColourLine; stoppingScale = angularOrdered ? stoppingScales.QCD_ac : stoppingScales.QCD_ac_noAO; startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; } if(startingScale < stoppingScale ) { newKin = cit->second.sudakov-> generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho, enhance,_deTuning); } } } else if(cit->second.sudakov->interactionType()==ShowerInteraction::EW) { type = ShowerPartnerType::EW; Energy stoppingScale = stoppingScales.EW; Energy startingScale = particle.scales().EW; if(startingScale < stoppingScale ) { newKin = cit->second.sudakov-> generateNextDecayBranching(startingScale,stoppingScale,minmass,particles,rho,enhance,_deTuning); } } // shouldn't be anything else else assert(false); if(!newKin) continue; // select highest scale if(newKin->scale() < newQ ) { newQ = newKin->scale(); ids = particles; kinematics=newKin; sudakov=cit->second.sudakov; partnerType = type; } } // return empty branching if nothing happened if(!kinematics) return Branching(ShoKinPtr(), IdList(),SudakovPtr(), ShowerPartnerType::Undefined); // and generate phi kinematics->phi(sudakov->generatePhiDecay(particle,ids,kinematics,rho)); // and return it return Branching(kinematics, ids,sudakov,partnerType); } Branching SplittingGenerator:: chooseBackwardBranching(ShowerParticle &particle,PPtr, double enhance, Ptr::transient_const_pointer beam, ShowerInteraction type, tcPDFPtr pdf, Energy freeze) const { RhoDMatrix rho; bool rhoCalc(false); Energy newQ=ZERO; ShoKinPtr kinematics=ShoKinPtr(); ShowerPartnerType partnerType(ShowerPartnerType::Undefined); SudakovPtr sudakov; IdList ids; // First, find the eventual branching, corresponding to the highest scale. long index = abs(particle.id()); // if no possible branching return if(_bbranchings.find(index) == _bbranchings.end()) return Branching(ShoKinPtr(), IdList(),SudakovPtr(),ShowerPartnerType::Undefined); // otherwise select branching for(BranchingList::const_iterator cit = _bbranchings.lower_bound(index); cit != _bbranchings.upper_bound(index); ++cit ) { // check either right interaction or doing both if(!checkInteraction(type,cit->second.sudakov->interactionType())) continue; // setup the PDF cit->second.sudakov->setPDF(pdf,freeze); //calc rho as needed if(!rhoCalc) { rho = particle.extractRhoMatrix(false); rhoCalc = true; } // whether or not this interaction should be angular ordered bool angularOrdered = cit->second.sudakov->splittingFn()->angularOrdered(); ShoKinPtr newKin; IdList particles = particle.id()!=cit->first ? cit->second.conjugateParticles : cit->second.particles; ShowerPartnerType type; if(cit->second.sudakov->interactionType()==ShowerInteraction::QED) { type = ShowerPartnerType::QED; Energy startingScale = angularOrdered ? particle.scales().QED : particle.scales().QED_noAO; newKin=cit->second.sudakov-> generateNextSpaceBranching(startingScale,particles, particle.x(),rho,enhance, beam,_deTuning); } else if(cit->second.sudakov->interactionType()==ShowerInteraction::QCD) { // special for octets if(particle.dataPtr()->iColour()==PDT::Colour8) { // octet -> octet octet if(cit->second.sudakov->splittingFn()->colourStructure()==OctetOctetOctet) { type = ShowerPartnerType::QCDColourLine; Energy startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; newKin = cit->second.sudakov-> generateNextSpaceBranching(startingScale,particles, particle.x(),rho,0.5*enhance, beam,_deTuning); startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; ShoKinPtr newKin2 = cit->second.sudakov-> generateNextSpaceBranching(startingScale,particles, particle.x(),rho, 0.5*enhance,beam,_deTuning); // pick the one with the highest scale if( (newKin&&newKin2&&newKin2->scale()>newKin->scale()) || (!newKin&&newKin2) ) { newKin = newKin2; type = ShowerPartnerType::QCDAntiColourLine; } } else { Energy startingScale = angularOrdered ? max(particle.scales().QCD_c , particle.scales().QCD_ac ) : max(particle.scales().QCD_c_noAO, particle.scales().QCD_ac_noAO); type = UseRandom::rndbool() ? ShowerPartnerType::QCDColourLine : ShowerPartnerType::QCDAntiColourLine; newKin=cit->second.sudakov-> generateNextSpaceBranching(startingScale,particles, particle.x(),rho,enhance,beam,_deTuning); } } // everything else else { Energy startingScale; if(particle.hasColour()) { type = ShowerPartnerType::QCDColourLine; startingScale = angularOrdered ? particle.scales().QCD_c : particle.scales().QCD_c_noAO; } else { type = ShowerPartnerType::QCDAntiColourLine; startingScale = angularOrdered ? particle.scales().QCD_ac : particle.scales().QCD_ac_noAO; } newKin=cit->second.sudakov-> generateNextSpaceBranching(startingScale,particles,particle.x(),rho,enhance,beam,_deTuning); } } else if(cit->second.sudakov->interactionType()==ShowerInteraction::EW) { type = ShowerPartnerType::EW; Energy startingScale = particle.scales().EW; newKin=cit->second.sudakov-> generateNextSpaceBranching(startingScale,particles,particle.x(),rho,enhance,beam,_deTuning); } // shouldn't be anything else else assert(false); // if no kinematics contine if(!newKin) continue; // select highest scale if(newKin->scale() > newQ) { newQ = newKin->scale(); kinematics=newKin; ids = particles; sudakov=cit->second.sudakov; partnerType = type; } } // return empty branching if nothing happened if(!kinematics) { - particle.spinInfo()->undecay(); + if ( particle.spinInfo() ) particle.spinInfo()->undecay(); return Branching(ShoKinPtr(), IdList(),SudakovPtr(), ShowerPartnerType::Undefined); } // initialize the ShowerKinematics // and generate phi kinematics->phi(sudakov->generatePhiBackward(particle,ids,kinematics,rho)); // return the answer return Branching(kinematics, ids,sudakov,partnerType); } void SplittingGenerator::rebind(const TranslationMap & trans) { BranchingList::iterator cit; for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit) { (cit->second).sudakov=trans.translate((cit->second).sudakov); for(unsigned int ix=0;ix<(cit->second).particles.size();++ix) { (cit->second).particles[ix]=trans.translate((cit->second).particles[ix]); } for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix) { (cit->second).conjugateParticles[ix]=trans.translate((cit->second).conjugateParticles[ix]); } } for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit) { (cit->second).sudakov=trans.translate((cit->second).sudakov); for(unsigned int ix=0;ix<(cit->second).particles.size();++ix) { (cit->second).particles[ix]=trans.translate((cit->second).particles[ix]); } for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix) { (cit->second).conjugateParticles[ix]=trans.translate((cit->second).conjugateParticles[ix]); } } Interfaced::rebind(trans); } IVector SplittingGenerator::getReferences() { IVector ret = Interfaced::getReferences(); BranchingList::iterator cit; for(cit=_fbranchings.begin();cit!=_fbranchings.end();++cit) { ret.push_back((cit->second).sudakov); for(unsigned int ix=0;ix<(cit->second).particles.size();++ix) ret.push_back(const_ptr_cast((cit->second).particles[ix])); for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix) ret.push_back(const_ptr_cast((cit->second).conjugateParticles[ix])); } for(cit=_bbranchings.begin();cit!=_bbranchings.end();++cit) { ret.push_back((cit->second).sudakov); for(unsigned int ix=0;ix<(cit->second).particles.size();++ix) ret.push_back(const_ptr_cast((cit->second).particles[ix])); for(unsigned int ix=0;ix<(cit->second).conjugateParticles.size();++ix) ret.push_back(const_ptr_cast((cit->second).conjugateParticles[ix])); } return ret; } diff --git a/Shower/QTilde/SplittingFunctions/SplittingGenerator.h b/Shower/QTilde/SplittingFunctions/SplittingGenerator.h --- a/Shower/QTilde/SplittingFunctions/SplittingGenerator.h +++ b/Shower/QTilde/SplittingFunctions/SplittingGenerator.h @@ -1,321 +1,321 @@ // -*- C++ -*- // // SplittingGenerator.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_SplittingGenerator_H #define HERWIG_SplittingGenerator_H // // This is the declaration of the SplittingGenerator class. // #include "ThePEG/Interface/Interfaced.h" #include "Herwig/Shower/QTilde/Base/Branching.h" -#include "Herwig/Shower/QTilde/Base/SudakovFormFactor.h" +#include "Herwig/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h" #include "SplittingGenerator.fh" #include "Herwig/Shower/QTilde/Base/ShowerParticle.h" -#include "Herwig/Shower/QTilde/Base/ShowerKinematics.h" +#include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This class is responsible for creating, at the beginning of the Run, * all the SplittingFunction objects and the corresponding * SudakovFormFactor objects, and then of the generation of splittings * (radiation emissions) during the event. * Many switches are defined in this class which allowed the user to turn on/off: * - each type of interaction (QCD, QED, EWK,...); * - initial- and final-state radiation for all type of interactions; * - initial- and final-state radiation for each type of interaction; * - each type of splitting (\f$u\to ug\f$, \f$d\to dg\f$, \f$\ldots\f$, * \f$g\to gg\f$, \f$g\to u\bar{u}\f$, \f$\ldots\f$). * * These switches are useful mainly for debugging, but eventually can * also be used for a "quick and dirty" estimation of systematic errors. * * In the future it should be possible to implement in this class * * - the \f$1\to2\f$ azimuthal correlations for soft emission due to QCD coherence * using the ShowerParticle object provided in the input. * - Similarly having the \f$\rho-D\f$ matrix and the SplittingFunction pointer * it should be possible to implement the spin correlations. * * @see SudakovFormFactor * @see SplitFun * * @see \ref SplittingGeneratorInterfaces "The interfaces" * defined for SplittingGenerator. */ class SplittingGenerator: public Interfaced { public: /** @name Standard constructors and destructors. */ //@{ /** * The default constructor. */ SplittingGenerator() : _deTuning(1.) {} //@} public: /** * Methods to select the next branching and reconstruct the kinematics */ //@{ /** * Choose a new forward branching for a time-like particle * The method returns: * - a pointer to a ShowerKinematics object, which * contains the information about the new scale and all other * kinematics variables that need to be generated simultaneously; * - a pointer to the SudakovFormFactor object associated * with the chosen emission. * - The PDG codes of the particles in the branching, * as a Branching struct. * * In the case no branching has been generated, both the returned * pointers are null ( ShoKinPtr() , tSudakovFFPtr() ). * * @param particle The particle to be evolved * @param enhance The factor by which to ehnace the emission of radiation * @param type The type of interaction to generate * @return The Branching struct for the branching */ Branching chooseForwardBranching(ShowerParticle & particle, double enhance, ShowerInteraction type) const; /** * Select the next branching of a particles for the initial-state shower * in the particle's decay. * @param particle The particle being showerwed * @param maxscale The maximum scale * @param minmass Minimum mass of the particle after the branching * @param enhance The factor by which to ehnace the emission of radiation * @param type The type of interaction to generate * @return The Branching struct for the branching */ Branching chooseDecayBranching(ShowerParticle & particle, const ShowerParticle::EvolutionScales & maxScales, Energy minmass,double enhance, ShowerInteraction type) const; /** * Choose a new backward branching for a space-like particle. * The method returns: * - a pointer to a ShowerKinematics object, which * contains the information about the new scale and all other * kinematics variables that need to be generated simultaneously; * - a pointer to the SudakovFormFactor object associated * with the chosen emission. * - The PDG codes of the particles in the branching, * as a Branching struct. * * In the case no branching has been generated, both the returned * pointers are null ( ShoKinPtr() , tSudakovFFPtr() ). * * @param particle The particle to be evolved * @param enhance The factor by which to ehnace the emission of radiation * @param beamparticle The beam particle * @param beam The BeamParticleData object * @param type The type of interaction to generate * @return The Branching struct for the branching */ Branching chooseBackwardBranching(ShowerParticle & particle, PPtr beamparticle, double enhance, Ptr::transient_const_pointer beam, ShowerInteraction type, tcPDFPtr , Energy ) const; //@} public: /** * Methods to parse the information from the input files to create the * branchings */ //@{ /** * Add a final-state splitting */ string addFinalSplitting(string arg) { return addSplitting(arg,true); } /** * Add an initial-state splitting */ string addInitialSplitting(string arg) { return addSplitting(arg,false); } /** * Add a final-state splitting */ string deleteFinalSplitting(string arg) { return deleteSplitting(arg,true); } /** * Add an initial-state splitting */ string deleteInitialSplitting(string arg) { return deleteSplitting(arg,false); } //@} /** * Access to the splittings */ //@{ /** * Access the final-state branchings */ const BranchingList & finalStateBranchings() const { return _fbranchings; } /** * Access the initial-state branchings */ const BranchingList & initialStateBranchings() const { return _bbranchings; } //@} 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(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(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 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 IBPtr fullclone() const; //@} protected: /** @name Standard Interfaced functions. */ //@{ /** * Rebind pointer to other Interfaced objects. Called in the setup phase * after all objects used in an EventGenerator has been cloned so that * the pointers will refer to the cloned objects afterwards. * @param trans a TranslationMap relating the original objects to * their respective clones. * @throws RebindException if no cloned object was found for a given * pointer. */ virtual void rebind(const TranslationMap & trans) ; /** * Return a vector of all pointers to Interfaced objects used in this * object. * @return a vector of pointers. */ virtual IVector getReferences(); //@} private: /** * Add a branching to the map * @param ids PDG coeds of the particles in the branching * @param sudakov The SudakovFormFactor for the branching * @param final Whether this is an initial- or final-state branching */ void addToMap(const IdList & ids, const SudakovPtr & sudakov, bool final); /** * Remove a branching to the map * @param ids PDG coeds of the particles in the branching * @param sudakov The SudakovFormFactor for the branching * @param final Whether this is an initial- or final-state branching */ void deleteFromMap(const IdList & ids, const SudakovPtr & sudakov, bool final); /** * Obtain the reference vectors for a final-state particle * @param particle The particle * @param p The p reference vector * @param n The n reference vector */ void finalStateBasisVectors(ShowerParticle particle, Lorentz5Momentum & p, Lorentz5Momentum & n) const; /** * Add a splitting * @param in string to be parsed * @param final Whether this is an initial- or final-state branching */ string addSplitting(string in ,bool final); /** * Delete a splitting * @param in string to be parsed * @param final Whether this is an initial- or final-state branching */ string deleteSplitting(string in ,bool final); private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ SplittingGenerator & operator=(const SplittingGenerator &); private: /** * List of the branchings and the appropriate Sudakovs for forward branchings */ BranchingList _fbranchings; /** * Lists of the branchings and the appropriate Sudakovs for backward branchings. */ BranchingList _bbranchings; /** * The detuning parameter */ double _deTuning; }; } #endif /* HERWIG_SplittingGenerator_H */ diff --git a/Shower/QTilde/SplittingFunctions/SudakovCutOff.cc b/Shower/QTilde/SplittingFunctions/SudakovCutOff.cc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/SudakovCutOff.cc @@ -0,0 +1,27 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the SudakovCutOff class. +// + +#include "SudakovCutOff.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/EventRecord/Particle.h" +#include "ThePEG/Repository/UseRandom.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Utilities/DescribeClass.h" + +using namespace Herwig; + +// The following static variable is needed for the type +// description system in ThePEG. +DescribeAbstractNoPIOClass +describeHerwigSudakovCutOff("Herwig::SudakovCutOff", "HwShower.so"); + +void SudakovCutOff::Init() { + + static ClassDocumentation documentation + ("Base class for cut-offs in the form factor"); + +} + diff --git a/Shower/QTilde/SplittingFunctions/SudakovCutOff.fh b/Shower/QTilde/SplittingFunctions/SudakovCutOff.fh new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/SudakovCutOff.fh @@ -0,0 +1,18 @@ +// -*- C++ -*- +// +// This is the forward declaration of the SudakovCutOff class. +// +#ifndef Herwig_SudakovCutOff_FH +#define Herwig_SudakovCutOff_FH + +#include "ThePEG/Config/ThePEG.h" + +namespace Herwig { + +class SudakovCutOff; + +ThePEG_DECLARE_POINTERS(Herwig::SudakovCutOff,SudakovCutOffPtr); + +} + +#endif diff --git a/Shower/QTilde/SplittingFunctions/SudakovCutOff.h b/Shower/QTilde/SplittingFunctions/SudakovCutOff.h new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/SudakovCutOff.h @@ -0,0 +1,63 @@ +// -*- C++ -*- +#ifndef Herwig_SudakovCutOff_H +#define Herwig_SudakovCutOff_H +// +// This is the declaration of the SudakovCutOff class. +// + +#include "SudakovCutOff.fh" +#include "Herwig/Shower/QTilde/ShowerConfig.h" +#include "ThePEG/Interface/Interfaced.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * The SudakovCutOff class is the base class for cut-offs in the Sudakov + * + * @see \ref SudakovCutOffInterfaces "The interfaces" + * defined for SudakovCutOff. + */ +class SudakovCutOff: public Interfaced { + +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(); + +public: + + /** + * Calculate the virtual masses for a branchings + */ + virtual const vector & virtualMasses(const IdList & ids) = 0; + + /** + * Default pTmin + */ + virtual Energy pTmin() { return ZERO; } + + /** + * Default pT2min + */ + virtual Energy2 pT2min() { return ZERO; } + +private: + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + SudakovCutOff & operator=(const SudakovCutOff &) = delete; + +}; + +} + +#endif /* Herwig_SudakovCutOff_H */ diff --git a/Shower/QTilde/Base/SudakovFormFactor.cc b/Shower/QTilde/SplittingFunctions/SudakovFormFactor.cc rename from Shower/QTilde/Base/SudakovFormFactor.cc rename to Shower/QTilde/SplittingFunctions/SudakovFormFactor.cc --- a/Shower/QTilde/Base/SudakovFormFactor.cc +++ b/Shower/QTilde/SplittingFunctions/SudakovFormFactor.cc @@ -1,364 +1,1236 @@ // -*- C++ -*- // // SudakovFormFactor.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 SudakovFormFactor class. // #include "SudakovFormFactor.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Parameter.h" -#include "ShowerKinematics.h" -#include "ShowerParticle.h" +#include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.h" +#include "Herwig/Shower/QTilde/Base/ShowerParticle.h" #include "ThePEG/Utilities/DescribeClass.h" -#include "Herwig/Shower/ShowerHandler.h" +#include "Herwig/Shower/QTilde/QTildeShowerHandler.h" +#include "Herwig/Shower/QTilde/Kinematics/FS_QTildeShowerKinematics1to2.h" +#include "Herwig/Shower/QTilde/Kinematics/IS_QTildeShowerKinematics1to2.h" +#include "Herwig/Shower/QTilde/Kinematics/Decay_QTildeShowerKinematics1to2.h" +#include "Herwig/Shower/QTilde/Kinematics/KinematicHelpers.h" +#include "SudakovCutOff.h" + +#include +using std::array; using namespace Herwig; -DescribeAbstractClass +DescribeClass describeSudakovFormFactor ("Herwig::SudakovFormFactor",""); void SudakovFormFactor::persistentOutput(PersistentOStream & os) const { - os << splittingFn_ << alpha_ << pdfmax_ << particles_ << pdffactor_ - << a_ << b_ << ounit(c_,GeV) << ounit(kinCutoffScale_,GeV) << cutOffOption_ - << ounit(vgcut_,GeV) << ounit(vqcut_,GeV) - << ounit(pTmin_,GeV) << ounit(pT2min_,GeV2); + os << splittingFn_ << alpha_ << pdfmax_ << particles_ << pdffactor_ << cutoff_; } void SudakovFormFactor::persistentInput(PersistentIStream & is, int) { - is >> splittingFn_ >> alpha_ >> pdfmax_ >> particles_ >> pdffactor_ - >> a_ >> b_ >> iunit(c_,GeV) >> iunit(kinCutoffScale_,GeV) >> cutOffOption_ - >> iunit(vgcut_,GeV) >> iunit(vqcut_,GeV) - >> iunit(pTmin_,GeV) >> iunit(pT2min_,GeV2); + is >> splittingFn_ >> alpha_ >> pdfmax_ >> particles_ >> pdffactor_ >> cutoff_; } void SudakovFormFactor::Init() { static ClassDocumentation documentation ("The SudakovFormFactor class is the base class for the implementation of Sudakov" " form factors in Herwig"); static Reference interfaceSplittingFunction("SplittingFunction", "A reference to the SplittingFunction object", &Herwig::SudakovFormFactor::splittingFn_, false, false, true, false); static Reference interfaceAlpha("Alpha", "A reference to the Alpha object", &Herwig::SudakovFormFactor::alpha_, false, false, true, false); + static Reference + interfaceCutoff("Cutoff", + "A reference to the SudakovCutOff object", + &Herwig::SudakovFormFactor::cutoff_, + false, false, true, false); + static Parameter interfacePDFmax ("PDFmax", "Maximum value of PDF weight. ", &SudakovFormFactor::pdfmax_, 35.0, 1.0, 1000000.0, false, false, Interface::limited); static Switch interfacePDFFactor ("PDFFactor", "Include additional factors in the overestimate for the PDFs", &SudakovFormFactor::pdffactor_, 0, false, false); static SwitchOption interfacePDFFactorNo (interfacePDFFactor, "No", "Don't include any factors", 0); static SwitchOption interfacePDFFactorOverZ (interfacePDFFactor, "OverZ", "Include an additional factor of 1/z", 1); static SwitchOption interfacePDFFactorOverOneMinusZ (interfacePDFFactor, "OverOneMinusZ", "Include an additional factor of 1/(1-z)", 2); static SwitchOption interfacePDFFactorOverZOneMinusZ (interfacePDFFactor, "OverZOneMinusZ", "Include an additional factor of 1/z/(1-z)", 3); static SwitchOption interfacePDFFactorOverRootZ (interfacePDFFactor, "OverRootZ", "Include an additional factor of 1/sqrt(z)", 4); static SwitchOption interfacePDFFactorRootZ (interfacePDFFactor, "RootZ", "Include an additional factor of sqrt(z)", 5); - static Switch interfaceCutOffOption - ("CutOffOption", - "The type of cut-off to use to end the shower", - &SudakovFormFactor::cutOffOption_, 0, false, false); - static SwitchOption interfaceCutOffOptionDefault - (interfaceCutOffOption, - "Default", - "Use the standard Herwig cut-off on virtualities with the minimum" - " virtuality depending on the mass of the branching particle", - 0); - static SwitchOption interfaceCutOffOptionFORTRAN - (interfaceCutOffOption, - "FORTRAN", - "Use a FORTRAN-like cut-off on virtualities", - 1); - static SwitchOption interfaceCutOffOptionpT - (interfaceCutOffOption, - "pT", - "Use a cut on the minimum allowed pT", - 2); - - static Parameter interfaceaParameter - ("aParameter", - "The a parameter for the kinematic cut-off", - &SudakovFormFactor::a_, 0.3, -10.0, 10.0, - false, false, Interface::limited); - - static Parameter interfacebParameter - ("bParameter", - "The b parameter for the kinematic cut-off", - &SudakovFormFactor::b_, 2.3, -10.0, 10.0, - false, false, Interface::limited); - - static Parameter interfacecParameter - ("cParameter", - "The c parameter for the kinematic cut-off", - &SudakovFormFactor::c_, GeV, 0.3*GeV, 0.1*GeV, 10.0*GeV, - false, false, Interface::limited); - - static Parameter - interfaceKinScale ("cutoffKinScale", - "kinematic cutoff scale for the parton shower phase" - " space (unit [GeV])", - &SudakovFormFactor::kinCutoffScale_, GeV, - 2.3*GeV, 0.001*GeV, 10.0*GeV,false,false,false); - - static Parameter interfaceGluonVirtualityCut - ("GluonVirtualityCut", - "For the FORTRAN cut-off option the minimum virtuality of the gluon", - &SudakovFormFactor::vgcut_, GeV, 0.85*GeV, 0.1*GeV, 10.0*GeV, - false, false, Interface::limited); - - static Parameter interfaceQuarkVirtualityCut - ("QuarkVirtualityCut", - "For the FORTRAN cut-off option the minimum virtuality added to" - " the mass for particles other than the gluon", - &SudakovFormFactor::vqcut_, GeV, 0.85*GeV, 0.1*GeV, 10.0*GeV, - false, false, Interface::limited); - - static Parameter interfacepTmin - ("pTmin", - "The minimum pT if using a cut-off on the pT", - &SudakovFormFactor::pTmin_, GeV, 1.0*GeV, ZERO, 10.0*GeV, - false, false, Interface::limited); } bool SudakovFormFactor::alphaSVeto(Energy2 pt2) const { double ratio=alphaSVetoRatio(pt2,1.); return UseRandom::rnd() > ratio; } double SudakovFormFactor::alphaSVetoRatio(Energy2 pt2, double factor) const { factor *= ShowerHandler::currentHandler()->renormalizationScaleFactor(); - return ThePEG::Math::powi(alpha_->ratio(pt2, factor), - splittingFn_->interactionOrder()); + return alpha_->ratio(pt2, factor); } bool SudakovFormFactor::PDFVeto(const Energy2 t, const double x, const tcPDPtr parton0, const tcPDPtr parton1, Ptr::transient_const_pointer beam) const { double ratio=PDFVetoRatio(t,x,parton0,parton1,beam,1.); return UseRandom::rnd() > ratio; } double SudakovFormFactor::PDFVetoRatio(const Energy2 t, const double x, const tcPDPtr parton0, const tcPDPtr parton1, Ptr::transient_const_pointer beam,double factor) const { assert(pdf_); Energy2 theScale = t * sqr(ShowerHandler::currentHandler()->factorizationScaleFactor()*factor); if (theScale < sqr(freeze_)) theScale = sqr(freeze_); - double newpdf(0.0), oldpdf(0.0); + const double newpdf=pdf_->xfx(beam,parton0,theScale,x/z()); + if(newpdf<=0.) return 0.; - newpdf=pdf_->xfx(beam,parton0,theScale,x/z()); - oldpdf=pdf_->xfx(beam,parton1,theScale,x); - - if(newpdf<=0.) return 0.; + const double oldpdf=pdf_->xfx(beam,parton1,theScale,x); if(oldpdf<=0.) return 1.; - double ratio = newpdf/oldpdf; + const double ratio = newpdf/oldpdf; double maxpdf = pdfmax_; switch (pdffactor_) { - case 0: - break; - case 1: - maxpdf /= z(); - break; - case 2: - maxpdf /= 1.-z(); - break; - case 3: - maxpdf /= (z()*(1.-z())); - break; - case 4: - maxpdf /= sqrt(z()); - break; - case 5: - maxpdf *= sqrt(z()); - break; + case 0: break; + case 1: maxpdf /= z(); break; + case 2: maxpdf /= 1.-z(); break; + case 3: maxpdf /= (z()*(1.-z())); break; + case 4: maxpdf /= sqrt(z()); break; + case 5: maxpdf *= sqrt(z()); break; default : throw Exception() << "SudakovFormFactor::PDFVetoRatio invalid PDFfactor = " << pdffactor_ << Exception::runerror; } if (ratio > maxpdf) { generator()->log() << "PDFVeto warning: Ratio > " << name() << ":PDFmax (by a factor of " << ratio/maxpdf <<") for " << parton0->PDGName() << " to " << parton1->PDGName() << "\n"; } return ratio/maxpdf ; } void SudakovFormFactor::addSplitting(const IdList & in) { bool add=true; for(unsigned int ix=0;ix::iterator it=particles_.begin(); it!=particles_.end();++it) { if(it->size()==in.size()) { bool match=true; for(unsigned int iy=0;iy::iterator itemp=it; --itemp; particles_.erase(it); it = itemp; } } } } Energy2 SudakovFormFactor::guesst(Energy2 t1,unsigned int iopt, const IdList &ids, double enhance,bool ident, double detune) const { unsigned int pdfopt = iopt!=1 ? 0 : pdffactor_; double c = 1./((splittingFn_->integOverP(zlimits_.second,ids,pdfopt) - splittingFn_->integOverP(zlimits_.first ,ids,pdfopt))* alpha_->overestimateValue()/Constants::twopi*enhance*detune); assert(iopt<=2); if(iopt==1) { c/=pdfmax_; //symmetry of FS gluon splitting if(ident) c*=0.5; } else if(iopt==2) c*=-1.; - if(splittingFn_->interactionOrder()==1) { - double r = UseRandom::rnd(); - if(iopt!=2 || c*log(r)interactionOrder()-1); - c/=Math::powi(alpha_->overestimateValue()/Constants::twopi,nm); - return t1 / pow (1. - nm*c*log(UseRandom::rnd()) - * Math::powi(t1*UnitRemoval::InvE2,nm) - ,1./double(nm)); - } + else + return Constants::MaxEnergy2; } double SudakovFormFactor::guessz (unsigned int iopt, const IdList &ids) const { unsigned int pdfopt = iopt!=1 ? 0 : pdffactor_; double lower = splittingFn_->integOverP(zlimits_.first,ids,pdfopt); return splittingFn_->invIntegOverP (lower + UseRandom::rnd()*(splittingFn_->integOverP(zlimits_.second,ids,pdfopt) - lower),ids,pdfopt); } -void SudakovFormFactor::doinit() { - Interfaced::doinit(); - pT2min_ = cutOffOption()==2 ? sqr(pTmin_) : ZERO; +bool SudakovFormFactor::guessTimeLike(Energy2 &t,Energy2 tmin,double enhance, + double detune) { + Energy2 told = t; + // calculate limits on z and if lower>upper return + if(!computeTimeLikeLimits(t)) return false; + // guess values of t and z + t = guesst(told,0,ids_,enhance,ids_[1]==ids_[2],detune); + z_ = guessz(0,ids_); + // actual values for z-limits + if(!computeTimeLikeLimits(t)) return false; + if(tupper return + if(!computeSpaceLikeLimits(t,x)) return false; + // guess values of t and z + t = guesst(told,1,ids_,enhance,ids_[1]==ids_[2],detune); + z_ = guessz(1,ids_); + // actual values for z-limits + if(!computeSpaceLikeLimits(t,x)) return false; + if(t zlimits_.second) return true; + + Energy2 m02 = (ids_[0]->id()!=ParticleID::g && ids_[0]->id()!=ParticleID::gamma) ? + masssquared_[0] : Energy2(); + + Energy2 pt2 = QTildeKinematics::pT2_FSR(t,z(),m02,masssquared_[1],masssquared_[2]); + + // if pt2<0 veto + if (pt2pT2min()) return true; + // otherwise calculate pt and return + pT_ = sqrt(pt2); + return false; } -const vector & SudakovFormFactor::virtualMasses(const IdList & ids) { - static vector output; - output.clear(); - if(cutOffOption() == 0) { - for(unsigned int ix=0;ixmass()); - Energy kinCutoff= - kinematicCutOff(kinScale(),*std::max_element(output.begin(),output.end())); - for(unsigned int ix=0;ix min + if(tmax<=tmin) return ShoKinPtr(); + // calculate next value of t using veto algorithm + Energy2 t(tmax); + // no shower variations to calculate + if(ShowerHandler::currentHandler()->showerVariations().empty()){ + // Without variations do the usual Veto algorithm + // No need for more if-statements in this loop. + do { + if(!guessTimeLike(t,tmin,enhance,detuning)) break; + } + while(PSVeto(t) || + SplittingFnVeto(z()*(1.-z())*t,ids,true,rho,detuning) || + alphaSVeto(splittingFn()->pTScale() ? sqr(z()*(1.-z()))*t : z()*(1.-z())*t)); } - else if(cutOffOption() == 1) { - for(unsigned int ix=0;ixmass()); - output.back() += ids[ix]->id()==ParticleID::g ? vgCut() : vqCut(); + else { + bool alphaRew(true),PSRew(true),SplitRew(true); + do { + if(!guessTimeLike(t,tmin,enhance,detuning)) break; + PSRew=PSVeto(t); + if (PSRew) continue; + SplitRew=SplittingFnVeto(z()*(1.-z())*t,ids,true,rho,detuning); + alphaRew=alphaSVeto(splittingFn()->pTScale() ? sqr(z()*(1.-z()))*t : z()*(1.-z())*t); + double factor=alphaSVetoRatio(splittingFn()->pTScale() ? sqr(z()*(1.-z()))*t : z()*(1.-z())*t,1.)* + SplittingFnVetoRatio(z()*(1.-z())*t,ids,true,rho,detuning); + + tShowerHandlerPtr ch = ShowerHandler::currentHandler(); + + if( !(SplitRew || alphaRew) ) { + //Emission + q_ = t > ZERO ? Energy(sqrt(t)) : -1.*MeV; + if (q_ <= ZERO) break; + } + + for ( map::const_iterator var = + ch->showerVariations().begin(); + var != ch->showerVariations().end(); ++var ) { + if ( ( ch->firstInteraction() && var->second.firstInteraction ) || + ( !ch->firstInteraction() && var->second.secondaryInteractions ) ) { + + double newfactor = alphaSVetoRatio(splittingFn()->pTScale() ? + sqr(z()*(1.-z()))*t : + z()*(1.-z())*t,var->second.renormalizationScaleFactor) + * SplittingFnVetoRatio(z()*(1.-z())*t,ids,true,rho,detuning); + + double varied; + if ( SplitRew || alphaRew ) { + // No Emission + varied = (1. - newfactor) / (1. - factor); + } else { + // Emission + varied = newfactor / factor; + } + + map::iterator wi = ch->currentWeights().find(var->first); + if ( wi != ch->currentWeights().end() ) + wi->second *= varied; + else { + assert(false); + //ch->currentWeights()[var->first] = varied; + } + } + } + + } + while(PSRew || SplitRew || alphaRew); + } + q_ = t > ZERO ? Energy(sqrt(t)) : -1.*MeV; + if(q_ < ZERO) return ShoKinPtr(); + + // return the ShowerKinematics object + return new_ptr(FS_QTildeShowerKinematics1to2(q_,z(),phi(),pT(),this)); +} + +ShoKinPtr SudakovFormFactor:: +generateNextSpaceBranching(const Energy startingQ, + const IdList &ids, + double x, + const RhoDMatrix & rho, + double enhance, + Ptr::transient_const_pointer beam, + double detuning) { + // First reset the internal kinematics variables that can + // have been eventually set in the previous call to the method. + q_ = ZERO; + z_ = 0.; + phi_ = 0.; + // perform the initialization + Energy2 tmax(sqr(startingQ)),tmin; + initialize(ids,tmin); + // check max > min + if(tmax<=tmin) return ShoKinPtr(); + // calculate next value of t using veto algorithm + Energy2 t(tmax),pt2(ZERO); + // no shower variations + if(ShowerHandler::currentHandler()->showerVariations().empty()){ + // Without variations do the usual Veto algorithm + // No need for more if-statements in this loop. + do { + if(!guessSpaceLike(t,tmin,x,enhance,detuning)) break; + pt2 = QTildeKinematics::pT2_ISR(t,z(),masssquared_[2]); + } + while(pt2 < cutoff_->pT2min()|| + z() > zlimits_.second|| + SplittingFnVeto((1.-z())*t/z(),ids,false,rho,detuning)|| + alphaSVeto(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t)|| + PDFVeto(t,x,ids[0],ids[1],beam)); + } + // shower variations + else + { + bool alphaRew(true),PDFRew(true),ptRew(true),zRew(true),SplitRew(true); + do { + if(!guessSpaceLike(t,tmin,x,enhance,detuning)) break; + pt2 = QTildeKinematics::pT2_ISR(t,z(),masssquared_[2]); + ptRew=pt2 < cutoff_->pT2min(); + zRew=z() > zlimits_.second; + if (ptRew||zRew) continue; + SplitRew=SplittingFnVeto((1.-z())*t/z(),ids,false,rho,detuning); + alphaRew=alphaSVeto(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t); + PDFRew=PDFVeto(t,x,ids[0],ids[1],beam); + double factor=PDFVetoRatio(t,x,ids[0],ids[1],beam,1.)* + alphaSVetoRatio(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t,1.)* + SplittingFnVetoRatio((1.-z())*t/z(),ids,false,rho,detuning); + + tShowerHandlerPtr ch = ShowerHandler::currentHandler(); + + if( !(PDFRew || SplitRew || alphaRew) ) { + //Emission + q_ = t > ZERO ? Energy(sqrt(t)) : -1.*MeV; + if (q_ <= ZERO) break; + } + + for ( map::const_iterator var = + ch->showerVariations().begin(); + var != ch->showerVariations().end(); ++var ) { + if ( ( ch->firstInteraction() && var->second.firstInteraction ) || + ( !ch->firstInteraction() && var->second.secondaryInteractions ) ) { + + + + double newfactor = PDFVetoRatio(t,x,ids[0],ids[1],beam,var->second.factorizationScaleFactor)* + alphaSVetoRatio(splittingFn()->pTScale() ? + sqr(1.-z())*t : (1.-z())*t,var->second.renormalizationScaleFactor) + *SplittingFnVetoRatio((1.-z())*t/z(),ids,false,rho,detuning); + + double varied; + if( PDFRew || SplitRew || alphaRew) { + // No Emission + varied = (1. - newfactor) / (1. - factor); + } else { + // Emission + varied = newfactor / factor; + } + + + map::iterator wi = ch->currentWeights().find(var->first); + if ( wi != ch->currentWeights().end() ) + wi->second *= varied; + else { + assert(false); + //ch->currentWeights()[var->first] = varied; + } + } + } + + } + while( PDFRew || SplitRew || alphaRew); + } + if(t > ZERO && zlimits_.first < zlimits_.second) q_ = sqrt(t); + else return ShoKinPtr(); + + pT_ = sqrt(pt2); + // create the ShowerKinematics and return it + return new_ptr(IS_QTildeShowerKinematics1to2(q_,z(),phi(),pT(),this)); +} + +void SudakovFormFactor::initialize(const IdList & ids, Energy2 & tmin) { + ids_=ids; + tmin = 4.*cutoff_->pT2min(); + masses_ = cutoff_->virtualMasses(ids); + masssquared_.clear(); + for(unsigned int ix=0;ix0) tmin=max(masssquared_[ix],tmin); + } +} + +ShoKinPtr SudakovFormFactor::generateNextDecayBranching(const Energy startingScale, + const Energy stoppingScale, + const Energy minmass, + const IdList &ids, + const RhoDMatrix & rho, + double enhance, + double detuning) { + // First reset the internal kinematics variables that can + // have been eventually set in the previous call to this method. + q_ = Constants::MaxEnergy; + z_ = 0.; + phi_ = 0.; + // perform initialisation + Energy2 tmax(sqr(stoppingScale)),tmin; + initialize(ids,tmin); + tmin=sqr(startingScale); + // check some branching possible + if(tmax<=tmin) return ShoKinPtr(); + // perform the evolution + Energy2 t(tmin),pt2(-MeV2); + do { + if(!guessDecay(t,tmax,minmass,enhance,detuning)) break; + pt2 = QTildeKinematics::pT2_Decay(t,z(),masssquared_[0],masssquared_[2]); + } + while(SplittingFnVeto((1.-z())*t/z(),ids,true,rho,detuning)|| + alphaSVeto(splittingFn()->pTScale() ? sqr(1.-z())*t : (1.-z())*t ) || + pt2pT2min() || + t*(1.-z())>masssquared_[0]-sqr(minmass)); + if(t > ZERO) { + q_ = sqrt(t); + pT_ = sqrt(pt2); + } + else return ShoKinPtr(); + phi_ = 0.; + // create the ShowerKinematics object + return new_ptr(Decay_QTildeShowerKinematics1to2(q_,z(),phi(),pT(),this)); +} + +bool SudakovFormFactor::guessDecay(Energy2 &t,Energy2 tmax, Energy minmass, + double enhance, double detune) { + // previous scale + Energy2 told = t; + // overestimated limits on z + if(tmaxpT2min()+ + 0.25*sqr(masssquared_[2])/tm2)/tm + +0.5*masssquared_[2]/tm2); + if(zlimits_.secondpT2min()+ + 0.25*sqr(masssquared_[2])/tm2)/tm + +0.5*masssquared_[2]/tm2); + if(t>tmax||zlimits_.secondpT2min(); + // special case for gluon radiating + if(ids_[0]->id()==ParticleID::g||ids_[0]->id()==ParticleID::gamma) { + // no emission possible + if(t<16.*(masssquared_[1]+pT2min)) { + t=-1.*GeV2; + return false; + } + // overestimate of the limits + zlimits_.first = 0.5*(1.-sqrt(1.-4.*sqrt((masssquared_[1]+pT2min)/t))); + zlimits_.second = 1.-zlimits_.first; + } + // special case for radiated particle is gluon + else if(ids_[2]->id()==ParticleID::g||ids_[2]->id()==ParticleID::gamma) { + zlimits_.first = sqrt((masssquared_[1]+pT2min)/t); + zlimits_.second = 1.-sqrt((masssquared_[2]+pT2min)/t); + } + else if(ids_[1]->id()==ParticleID::g||ids_[1]->id()==ParticleID::gamma) { + zlimits_.second = sqrt((masssquared_[2]+pT2min)/t); + zlimits_.first = 1.-sqrt((masssquared_[1]+pT2min)/t); + } + else { + zlimits_.first = (masssquared_[1]+pT2min)/t; + zlimits_.second = 1.-(masssquared_[2]+pT2min)/t; + } + if(zlimits_.first>=zlimits_.second) { + t=-1.*GeV2; + return false; + } + return true; +} + +bool SudakovFormFactor::computeSpaceLikeLimits(Energy2 & t, double x) { + if (t < 1e-20 * GeV2) { + t=-1.*GeV2; + return false; + } + // compute the limits + zlimits_.first = x; + double yy = 1.+0.5*masssquared_[2]/t; + zlimits_.second = yy - sqrt(sqr(yy)-1.+cutoff_->pT2min()/t); + // return false if lower>upper + if(zlimits_.second(particle.parents()[0]) : tShowerParticlePtr(); + } + else { + mother = particle.children().size()==2 ? + dynamic_ptr_cast(&particle) : tShowerParticlePtr(); + } + tShowerParticlePtr partner; + while(mother) { + tPPtr otherChild; + if(forward) { + for (unsigned int ix=0;ixchildren().size();++ix) { + if(mother->children()[ix]!=child) { + otherChild = mother->children()[ix]; + break; + } + } + } + else { + otherChild = mother->children()[1]; + } + tShowerParticlePtr other = dynamic_ptr_cast(otherChild); + if((inter==ShowerInteraction::QCD && otherChild->dataPtr()->coloured()) || + (inter==ShowerInteraction::QED && otherChild->dataPtr()->charged())) { + partner = other; + break; + } + if(forward && !other->isFinalState()) { + partner = dynamic_ptr_cast(mother); + break; + } + child = mother; + if(forward) { + mother = ! mother->parents().empty() ? + dynamic_ptr_cast(mother->parents()[0]) : tShowerParticlePtr(); + } + else { + if(mother->children()[0]->children().size()!=2) + break; + tShowerParticlePtr mtemp = + dynamic_ptr_cast(mother->children()[0]); + if(!mtemp) + break; + else + mother=mtemp; } } - else if(cutOffOption() == 2) { - for(unsigned int ix=0;ixmass()); + if(!partner) { + if(forward) { + partner = dynamic_ptr_cast( child)->partner(); + } + else { + if(mother) { + tShowerParticlePtr parent; + if(!mother->children().empty()) { + parent = dynamic_ptr_cast(mother->children()[0]); + } + if(!parent) { + parent = dynamic_ptr_cast(mother); + } + partner = parent->partner(); + } + else { + partner = dynamic_ptr_cast(&particle)->partner(); + } + } + } + return partner; +} + +pair softPhiMin(double phi0, double phi1, double A, double B, double C, double D) { + double c01 = cos(phi0 - phi1); + double s01 = sin(phi0 - phi1); + double s012(sqr(s01)), c012(sqr(c01)); + double A2(A*A), B2(B*B), C2(C*C), D2(D*D); + if(abs(B/A)<1e-10 && abs(D/C)<1e-10) return make_pair(phi0,phi0+Constants::pi); + double root = sqr(B2)*C2*D2*sqr(s012) + 2.*A*B2*B*C2*C*D*c01*s012 + 2.*A*B2*B*C*D2*D*c01*s012 + + 4.*A2*B2*C2*D2*c012 - A2*B2*C2*D2*s012 - A2*B2*sqr(D2)*s012 - sqr(B2)*sqr(C2)*s012 + - sqr(B2)*C2*D2*s012 - 4.*A2*A*B*C*D2*D*c01 - 4.*A*B2*B*C2*C*D*c01 + sqr(A2)*sqr(D2) + + 2.*A2*B2*C2*D2 + sqr(B2)*sqr(C2); + if(root<0.) return make_pair(phi0,phi0+Constants::pi); + root = sqrt(root); + double denom = (-2.*A*B*C*D*c01 + A2*D2 + B2*C2); + double denom2 = (-B*C*c01 + A*D); + + double num = B2*C*D*s012; + double y1 = B*s01*(-C*(num + root) + D*denom) / denom2; + double y2 = B*s01*(-C*(num - root) + D*denom) / denom2; + double x1 = -(num + root ); + double x2 = -(num - root ); + if(denom<0.) { + y1*=-1.; + y2*=-1.; + x1*=-1.; + x2*=-1.; + } + return make_pair(atan2(y1,x1) + phi0,atan2(y2,x2) + phi0); +} + +} + +double SudakovFormFactor::generatePhiForward(ShowerParticle & particle, + const IdList & ids, + ShoKinPtr kinematics, + const RhoDMatrix & rho) { + // no correlations, return flat phi + if(! dynamic_ptr_cast(ShowerHandler::currentHandler())->correlations()) + return Constants::twopi*UseRandom::rnd(); + // get the kinematic variables + double z = kinematics->z(); + Energy2 t = z*(1.-z)*sqr(kinematics->scale()); + Energy pT = kinematics->pT(); + // if soft correlations + Energy2 pipj,pik; + bool canBeSoft[2] = {ids[1]->id()==ParticleID::g || ids[1]->id()==ParticleID::gamma, + ids[2]->id()==ParticleID::g || ids[2]->id()==ParticleID::gamma }; + array pjk; + array Ek; + Energy Ei,Ej; + Energy2 m12(ZERO),m22(ZERO); + InvEnergy2 aziMax(ZERO); + bool softAllowed = dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()&& + (canBeSoft[0] || canBeSoft[1]); + if(softAllowed) { + // find the partner for the soft correlations + tShowerParticlePtr partner=findCorrelationPartner(particle,true,splittingFn()->interactionType()); + // remember we want the softer gluon + bool swapOrder = !canBeSoft[1] || (canBeSoft[0] && canBeSoft[1] && z < 0.5); + double zFact = !swapOrder ? (1.-z) : z; + // compute the transforms to the shower reference frame + // first the boost + Lorentz5Momentum pVect = particle.showerBasis()->pVector(); + Lorentz5Momentum nVect = particle.showerBasis()->nVector(); + Boost beta_bb; + if(particle.showerBasis()->frame()==ShowerBasis::BackToBack) { + beta_bb = -(pVect + nVect).boostVector(); + } + else if(particle.showerBasis()->frame()==ShowerBasis::Rest) { + beta_bb = -pVect.boostVector(); + } + else + assert(false); + pVect.boost(beta_bb); + nVect.boost(beta_bb); + Axis axis; + if(particle.showerBasis()->frame()==ShowerBasis::BackToBack) { + axis = pVect.vect().unit(); + } + else if(particle.showerBasis()->frame()==ShowerBasis::Rest) { + axis = nVect.vect().unit(); + } + else + assert(false); + // and then the rotation + LorentzRotation rot; + if(axis.perp2()>0.) { + double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); + rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); + } + else if(axis.z()<0.) { + rot.rotate(Constants::pi,Axis(1.,0.,0.)); + } + rot.invert(); + pVect *= rot; + nVect *= rot; + // shower parameters + Energy2 pn = pVect*nVect, m2 = pVect.m2(); + double alpha0 = particle.showerParameters().alpha; + double beta0 = 0.5/alpha0/pn* + (sqr(particle.dataPtr()->mass())-sqr(alpha0)*m2+sqr(particle.showerParameters().pt)); + Lorentz5Momentum qperp0(particle.showerParameters().ptx, + particle.showerParameters().pty,ZERO,ZERO); + assert(partner); + Lorentz5Momentum pj = partner->momentum(); + pj.boost(beta_bb); + pj *= rot; + // compute the two phi independent dot products + pik = 0.5*zFact*(sqr(alpha0)*m2 - sqr(particle.showerParameters().pt) + 2.*alpha0*beta0*pn ) + +0.5*sqr(pT)/zFact; + Energy2 dot1 = pj*pVect; + Energy2 dot2 = pj*nVect; + Energy2 dot3 = pj*qperp0; + pipj = alpha0*dot1+beta0*dot2+dot3; + // compute the constants for the phi dependent dot product + pjk[0] = zFact*(alpha0*dot1+dot3-0.5*dot2/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0)) + +0.5*sqr(pT)*dot2/pn/zFact/alpha0; + pjk[1] = (pj.x() - dot2/alpha0/pn*qperp0.x())*pT; + pjk[2] = (pj.y() - dot2/alpha0/pn*qperp0.y())*pT; + m12 = sqr(particle.dataPtr()->mass()); + m22 = sqr(partner->dataPtr()->mass()); + if(swapOrder) { + pjk[1] *= -1.; + pjk[2] *= -1.; + } + Ek[0] = zFact*(alpha0*pVect.t()-0.5*nVect.t()/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0)) + +0.5*sqr(pT)*nVect.t()/pn/zFact/alpha0; + Ek[1] = -nVect.t()/alpha0/pn*qperp0.x()*pT; + Ek[2] = -nVect.t()/alpha0/pn*qperp0.y()*pT; + if(swapOrder) { + Ek[1] *= -1.; + Ek[2] *= -1.; + } + Energy mag2=sqrt(sqr(Ek[1])+sqr(Ek[2])); + Ei = alpha0*pVect.t()+beta0*nVect.t(); + Ej = pj.t(); + double phi0 = atan2(-pjk[2],-pjk[1]); + if(phi0<0.) phi0 += Constants::twopi; + double phi1 = atan2(-Ek[2],-Ek[1]); + if(phi1<0.) phi1 += Constants::twopi; + double xi_min = pik/Ei/(Ek[0]+mag2), xi_max = pik/Ei/(Ek[0]-mag2), xi_ij = pipj/Ei/Ej; + if(xi_min>xi_max) swap(xi_min,xi_max); + if(xi_min>xi_ij) softAllowed = false; + Energy2 mag = sqrt(sqr(pjk[1])+sqr(pjk[2])); + if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { + aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag); + } + else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { + double A = (pipj*Ek[0]- Ej*pik)/Ej/sqr(Ej); + double B = -sqrt(sqr(pipj)*(sqr(Ek[1])+sqr(Ek[2])))/Ej/sqr(Ej); + double C = pjk[0]/sqr(Ej); + double D = -sqrt(sqr(pjk[1])+sqr(pjk[2]))/sqr(Ej); + pair minima = softPhiMin(phi0,phi1,A,B,C,D); + aziMax = 0.5/pik/(Ek[0]-mag2)*(Ei-m12*(Ek[0]-mag2)/pik + max(Ej*(A+B*cos(minima.first -phi1))/(C+D*cos(minima.first -phi0)), + Ej*(A+B*cos(minima.second-phi1))/(C+D*cos(minima.second-phi0)))); + } + else + assert(false); + } + // if spin correlations + vector > wgts; + if(dynamic_ptr_cast(ShowerHandler::currentHandler())->spinCorrelations()) { + // calculate the weights + wgts = splittingFn()->generatePhiForward(z,t,ids,rho); } else { - throw Exception() << "Unknown option for the cut-off" - << " in SudakovFormFactor::virtualMasses()" - << Exception::runerror; + wgts = {{ {0, 1.} }}; } - return output; + // generate the azimuthal angle + double phi,wgt; + static const Complex ii(0.,1.); + unsigned int ntry(0); + double phiMax(0.),wgtMax(0.); + do { + phi = Constants::twopi*UseRandom::rnd(); + // first the spin correlations bit (gives 1 if correlations off) + Complex spinWgt = 0.; + for(unsigned int ix=0;ix1e-10) { + generator()->log() << "Forward spin weight problem " << wgt << " " << wgt-1. + << " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n"; + generator()->log() << "Weights \n"; + for(unsigned int ix=0;ixlog() << wgts[ix].first << " " << wgts[ix].second << "\n"; + } + // soft correlations bit + double aziWgt = 1.; + if(softAllowed) { + Energy2 dot = pjk[0]+pjk[1]*cos(phi)+pjk[2]*sin(phi); + Energy Eg = Ek[0]+Ek[1]*cos(phi)+Ek[2]*sin(phi); + if(pipj*Eg>pik*Ej) { + if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { + aziWgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax; + } + else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { + aziWgt = max(ZERO,0.5/pik/Eg*(Ei-m12*Eg/pik + (pipj*Eg - Ej*pik)/dot)/aziMax); + } + if(aziWgt-1.>1e-10||aziWgt<-1e-10) { + generator()->log() << "Forward soft weight problem " << aziWgt << " " << aziWgt-1. + << " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n"; + } + } + else { + aziWgt = 0.; + } + } + wgt *= aziWgt; + if(wgt>wgtMax) { + phiMax = phi; + wgtMax = wgt; + } + ++ntry; + } + while(wgtlog() << "Too many tries to generate phi in forward evolution\n"; + phi = phiMax; + } + // return the azimuthal angle + return phi; } + +double SudakovFormFactor::generatePhiBackward(ShowerParticle & particle, + const IdList & ids, + ShoKinPtr kinematics, + const RhoDMatrix & rho) { + // no correlations, return flat phi + if(! dynamic_ptr_cast(ShowerHandler::currentHandler())->correlations()) + return Constants::twopi*UseRandom::rnd(); + // get the kinematic variables + double z = kinematics->z(); + Energy2 t = (1.-z)*sqr(kinematics->scale())/z; + Energy pT = kinematics->pT(); + // if soft correlations + bool softAllowed = dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations() && + (ids[2]->id()==ParticleID::g || ids[2]->id()==ParticleID::gamma); + Energy2 pipj,pik,m12(ZERO),m22(ZERO); + array pjk; + Energy Ei,Ej,Ek; + InvEnergy2 aziMax(ZERO); + if(softAllowed) { + // find the partner for the soft correlations + tShowerParticlePtr partner=findCorrelationPartner(particle,false,splittingFn()->interactionType()); + double zFact = (1.-z); + // compute the transforms to the shower reference frame + // first the boost + Lorentz5Momentum pVect = particle.showerBasis()->pVector(); + Lorentz5Momentum nVect = particle.showerBasis()->nVector(); + assert(particle.showerBasis()->frame()==ShowerBasis::BackToBack); + Boost beta_bb = -(pVect + nVect).boostVector(); + pVect.boost(beta_bb); + nVect.boost(beta_bb); + Axis axis = pVect.vect().unit(); + // and then the rotation + LorentzRotation rot; + if(axis.perp2()>0.) { + double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); + rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); + } + else if(axis.z()<0.) { + rot.rotate(Constants::pi,Axis(1.,0.,0.)); + } + rot.invert(); + pVect *= rot; + nVect *= rot; + // shower parameters + Energy2 pn = pVect*nVect; + Energy2 m2 = pVect.m2(); + double alpha0 = particle.x(); + double beta0 = -0.5/alpha0/pn*sqr(alpha0)*m2; + Lorentz5Momentum pj = partner->momentum(); + pj.boost(beta_bb); + pj *= rot; + double beta2 = 0.5*(1.-zFact)*(sqr(alpha0*zFact/(1.-zFact))*m2+sqr(pT))/alpha0/zFact/pn; + // compute the two phi independent dot products + Energy2 dot1 = pj*pVect; + Energy2 dot2 = pj*nVect; + pipj = alpha0*dot1+beta0*dot2; + pik = alpha0*(alpha0*zFact/(1.-zFact)*m2+pn*(beta2+zFact/(1.-zFact)*beta0)); + // compute the constants for the phi dependent dot product + pjk[0] = alpha0*zFact/(1.-zFact)*dot1+beta2*dot2; + pjk[1] = pj.x()*pT; + pjk[2] = pj.y()*pT; + m12 = ZERO; + m22 = sqr(partner->dataPtr()->mass()); + Energy2 mag = sqrt(sqr(pjk[1])+sqr(pjk[2])); + if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { + aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag); + } + else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { + Ek = alpha0*zFact/(1.-zFact)*pVect.t()+beta2*nVect.t(); + Ei = alpha0*pVect.t()+beta0*nVect.t(); + Ej = pj.t(); + if(pipj*Ek> Ej*pik) { + aziMax = 0.5/pik/Ek*(Ei-m12*Ek/pik + (pipj*Ek- Ej*pik)/(pjk[0]-mag)); + } + else { + aziMax = 0.5/pik/Ek*(Ei-m12*Ek/pik); + } + } + else { + assert(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==0); + } + } + // if spin correlations + vector > wgts; + if(dynamic_ptr_cast(ShowerHandler::currentHandler())->spinCorrelations()) { + // get the weights + wgts = splittingFn()->generatePhiBackward(z,t,ids,rho); + } + else { + wgts = {{ {0, 1.} }}; + } + // generate the azimuthal angle + double phi,wgt; + static const Complex ii(0.,1.); + unsigned int ntry(0); + double phiMax(0.),wgtMax(0.); + do { + phi = Constants::twopi*UseRandom::rnd(); + Complex spinWgt = 0.; + for(unsigned int ix=0;ix1e-10) { + generator()->log() << "Backward weight problem " << wgt << " " << wgt-1. + << " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << z << " " << phi << "\n"; + generator()->log() << "Weights \n"; + for(unsigned int ix=0;ixlog() << wgts[ix].first << " " << wgts[ix].second << "\n"; + } + // soft correlations bit + double aziWgt = 1.; + if(softAllowed) { + Energy2 dot = pjk[0]+pjk[1]*cos(phi)+pjk[2]*sin(phi); + if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { + aziWgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax; + } + else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { + aziWgt = max(ZERO,0.5/pik/Ek*(Ei-m12*Ek/pik + pipj*Ek/dot - Ej*pik/dot)/aziMax); + } + if(aziWgt-1.>1e-10||aziWgt<-1e-10) { + generator()->log() << "Backward soft weight problem " << aziWgt << " " << aziWgt-1. + << " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n"; + } + } + wgt *= aziWgt; + if(wgt>wgtMax) { + phiMax = phi; + wgtMax = wgt; + } + ++ntry; + } + while(wgtlog() << "Too many tries to generate phi in backward evolution\n"; + phi = phiMax; + } + // return the azimuthal angle + return phi; +} + +double SudakovFormFactor::generatePhiDecay(ShowerParticle & particle, + const IdList & ids, + ShoKinPtr kinematics, + const RhoDMatrix &) { + // only soft correlations in this case + // no correlations, return flat phi + if( !(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations() && + (ids[2]->id()==ParticleID::g || ids[2]->id()==ParticleID::gamma ))) + return Constants::twopi*UseRandom::rnd(); + // get the kinematic variables + double z = kinematics->z(); + Energy pT = kinematics->pT(); + // if soft correlations + // find the partner for the soft correlations + tShowerParticlePtr partner = findCorrelationPartner(particle,true,splittingFn()->interactionType()); + double zFact(1.-z); + // compute the transforms to the shower reference frame + // first the boost + Lorentz5Momentum pVect = particle.showerBasis()->pVector(); + Lorentz5Momentum nVect = particle.showerBasis()->nVector(); + assert(particle.showerBasis()->frame()==ShowerBasis::Rest); + Boost beta_bb = -pVect.boostVector(); + pVect.boost(beta_bb); + nVect.boost(beta_bb); + Axis axis = nVect.vect().unit(); + // and then the rotation + LorentzRotation rot; + if(axis.perp2()>0.) { + double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); + rot.rotate(acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); + } + else if(axis.z()<0.) { + rot.rotate(Constants::pi,Axis(1.,0.,0.)); + } + rot.invert(); + pVect *= rot; + nVect *= rot; + // shower parameters + Energy2 pn = pVect*nVect; + Energy2 m2 = pVect.m2(); + double alpha0 = particle.showerParameters().alpha; + double beta0 = 0.5/alpha0/pn* + (sqr(particle.dataPtr()->mass())-sqr(alpha0)*m2+sqr(particle.showerParameters().pt)); + Lorentz5Momentum qperp0(particle.showerParameters().ptx, + particle.showerParameters().pty,ZERO,ZERO); + Lorentz5Momentum pj = partner->momentum(); + pj.boost(beta_bb); + pj *= rot; + // compute the two phi independent dot products + Energy2 pik = 0.5*zFact*(sqr(alpha0)*m2 - sqr(particle.showerParameters().pt) + 2.*alpha0*beta0*pn ) + +0.5*sqr(pT)/zFact; + Energy2 dot1 = pj*pVect; + Energy2 dot2 = pj*nVect; + Energy2 dot3 = pj*qperp0; + Energy2 pipj = alpha0*dot1+beta0*dot2+dot3; + // compute the constants for the phi dependent dot product + array pjk; + pjk[0] = zFact*(alpha0*dot1+dot3-0.5*dot2/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0)) + +0.5*sqr(pT)*dot2/pn/zFact/alpha0; + pjk[1] = (pj.x() - dot2/alpha0/pn*qperp0.x())*pT; + pjk[2] = (pj.y() - dot2/alpha0/pn*qperp0.y())*pT; + Energy2 m12 = sqr(particle.dataPtr()->mass()); + Energy2 m22 = sqr(partner->dataPtr()->mass()); + Energy2 mag = sqrt(sqr(pjk[1])+sqr(pjk[2])); + InvEnergy2 aziMax; + array Ek; + Energy Ei,Ej; + if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { + aziMax = -m12/sqr(pik) -m22/sqr(pjk[0]+mag) +2.*pipj/pik/(pjk[0]-mag); + } + else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { + Ek[0] = zFact*(alpha0*pVect.t()+-0.5*nVect.t()/pn*(alpha0*m2-sqr(particle.showerParameters().pt)/alpha0)) + +0.5*sqr(pT)*nVect.t()/pn/zFact/alpha0; + Ek[1] = -nVect.t()/alpha0/pn*qperp0.x()*pT; + Ek[2] = -nVect.t()/alpha0/pn*qperp0.y()*pT; + Energy mag2=sqrt(sqr(Ek[1])+sqr(Ek[2])); + Ei = alpha0*pVect.t()+beta0*nVect.t(); + Ej = pj.t(); + aziMax = 0.5/pik/(Ek[0]-mag2)*(Ei-m12*(Ek[0]-mag2)/pik + pipj*(Ek[0]+mag2)/(pjk[0]-mag) - Ej*pik/(pjk[0]-mag) ); + } + else + assert(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==0); + // generate the azimuthal angle + double phi,wgt(0.); + unsigned int ntry(0); + double phiMax(0.),wgtMax(0.); + do { + phi = Constants::twopi*UseRandom::rnd(); + Energy2 dot = pjk[0]+pjk[1]*cos(phi)+pjk[2]*sin(phi); + if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==1) { + wgt = (-m12/sqr(pik) -m22/sqr(dot) +2.*pipj/pik/dot)/aziMax; + } + else if(dynamic_ptr_cast(ShowerHandler::currentHandler())->softCorrelations()==2) { + if(qperp0.m2()==ZERO) { + wgt = 1.; + } + else { + Energy Eg = Ek[0]+Ek[1]*cos(phi)+Ek[2]*sin(phi); + wgt = max(ZERO,0.5/pik/Eg*(Ei-m12*Eg/pik + (pipj*Eg - Ej*pik)/dot)/aziMax); + } + } + if(wgt-1.>1e-10||wgt<-1e-10) { + generator()->log() << "Decay soft weight problem " << wgt << " " << wgt-1. + << " " << ids[0]->id() << " " << ids[1]->id() << " " << ids[2]->id() << " " << " " << phi << "\n"; + } + if(wgt>wgtMax) { + phiMax = phi; + wgtMax = wgt; + } + ++ntry; + } + while(wgtlog() << "Too many tries to generate phi\n"; + } + // return the azimuthal angle + return phi; +} + + +Energy SudakovFormFactor::calculateScale(double zin, Energy pt, IdList ids, + unsigned int iopt) { + Energy2 tmin; + initialize(ids,tmin); + // final-state branching + if(iopt==0) { + Energy2 scale=(sqr(pt)+masssquared_[1]*(1.-zin)+masssquared_[2]*zin); + if(ids[0]->id()!=ParticleID::g) scale -= zin*(1.-zin)*masssquared_[0]; + scale /= sqr(zin*(1-zin)); + return scale<=ZERO ? sqrt(tmin) : sqrt(scale); + } + else if(iopt==1) { + Energy2 scale=(sqr(pt)+zin*masssquared_[2])/sqr(1.-zin); + return scale<=ZERO ? sqrt(tmin) : sqrt(scale); + } + else if(iopt==2) { + Energy2 scale = (sqr(pt)+zin*masssquared_[2])/sqr(1.-zin)+masssquared_[0]; + return scale<=ZERO ? sqrt(tmin) : sqrt(scale); + } + else { + throw Exception() << "Unknown option in SudakovFormFactor::calculateScale() " + << "iopt = " << iopt << Exception::runerror; + } +} diff --git a/Shower/QTilde/Base/SudakovFormFactor.fh b/Shower/QTilde/SplittingFunctions/SudakovFormFactor.fh rename from Shower/QTilde/Base/SudakovFormFactor.fh rename to Shower/QTilde/SplittingFunctions/SudakovFormFactor.fh diff --git a/Shower/QTilde/Base/SudakovFormFactor.h b/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h rename from Shower/QTilde/Base/SudakovFormFactor.h rename to Shower/QTilde/SplittingFunctions/SudakovFormFactor.h --- a/Shower/QTilde/Base/SudakovFormFactor.h +++ b/Shower/QTilde/SplittingFunctions/SudakovFormFactor.h @@ -1,688 +1,633 @@ // -*- C++ -*- // // SudakovFormFactor.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_SudakovFormFactor_H #define HERWIG_SudakovFormFactor_H // // This is the declaration of the SudakovFormFactor class. // #include "ThePEG/Interface/Interfaced.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" #include "Herwig/Shower/ShowerAlpha.h" #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingGenerator.fh" #include "ThePEG/Repository/UseRandom.h" #include "ThePEG/PDF/BeamParticleData.h" #include "ThePEG/EventRecord/RhoDMatrix.h" #include "ThePEG/EventRecord/SpinInfo.h" -#include "ShowerKinematics.fh" +#include "Herwig/Shower/QTilde/Kinematics/ShowerKinematics.fh" #include "SudakovFormFactor.fh" +#include "SudakovCutOff.h" namespace Herwig { using namespace ThePEG; /** * A typedef for the BeamParticleData */ typedef Ptr::transient_const_pointer tcBeamPtr; /** \ingroup Shower * * This is the definition of the Sudakov form factor class. In general this * is the base class for the implementation of Sudakov form factors in Herwig. * The methods generateNextTimeBranching(), generateNextDecayBranching() and * generateNextSpaceBranching need to be implemented in classes inheriting from this * one. * * In addition a number of methods are implemented to assist with the calculation * of the form factor using the veto algorithm in classes inheriting from this one. * * In general the Sudakov form-factor, for final-state radiation, is given * by * \f[\Delta_{ba}(\tilde{q}_{i+1},\tilde{q}_i)= * \exp\left\{ * -\int^{\tilde{q}^2_i}_{\tilde{q}^2_{i+1}} * \frac{{\rm d}\tilde{q}^2}{\tilde{q}^2} * \int\frac{\alpha_S(z,\tilde{q})}{2\pi} * P_{ba}(z,\tilde{q})\Theta(p_T) * \right\}. * \f] * We can solve this to obtain the next value of the scale \f$\tilde{q}_{i+1}\f$ * given the previous value \f$\tilde{q}_i\f$ * in the following way. First we obtain a simplified form of the integrand * which is greater than or equal to the true integrand for all values of * \f$\tilde{q}\f$. * * In practice it is easiest to obtain this over estimate in pieces. The ShowerAlpha * object contains an over estimate for \f$\alpha_S\f$, the splitting function * contains both an over estimate of the spltting function and its integral * which is needed to compute the over estimate of the \f$\tilde{q}\f$ integrand, * together with an over estimate of the limit of the \f$z\f$ integral. * * This gives an overestimate of the integrand * \f[g(\tilde{q}^2) = \frac{c}{\tilde{q}^2}, \f] * where because the over estimates are chosen to be independent of \f$\tilde{q}\f$ the * parameter * \f[c = \frac{\alpha_{\rm over}}{2\pi}\int^{z_1}_{z_0}P_{\rm over}(z),\f] * is a constant independent of \f$\tilde{q}\f$. * * The guesst() member can then be used to generate generate the value of * \f$\tilde{q}^2\f$ according to this result. This is done by solving the Sudakov * form factor, with the over estimates, is equal to a random number * \f$r\f$ in the interval \f$[0,1]\f$. This gives * \f[\tilde{q}^2_{i+1}=G^{-1}\left[G(\tilde{q}^2_i)+\ln r\right],\f] * where \f$G(\tilde{q}^2)=c\ln(\tilde{q}^2)\f$ is the infinite integral * of \f$g(\tilde{q}^2)\f$ and \f$G^{-1}(x)=\exp\left(\frac{x}c\right)\f$ * is its inverse. * It this case we therefore obtain * \f[\tilde{q}^2_{i+1}=\tilde{q}^2_ir^{\frac1c}.\f] * The value of \f$z\f$ can then be calculated in a similar way * \f[z = I^{-1}\left[I(z_0)+r\left(I(z_1)-I(z_0)\right)\right],\f] * using the guessz() member, * where \f$I=\int P(z){\rm d}z\f$ and \f$I^{-1}\f$ is its inverse. * * The veto algorithm then uses rejection using the ratio of the * true value to the overestimated one to obtain the original distribution. * This is accomplished using the * - alphaSVeto() member for the \f$\alpha_S\f$ veto * - SplittingFnVeto() member for the veto on the value of the splitting function. * in general there must also be a chech that the emission is in the allowed * phase space but this is left to the inheriting classes as it will depend * on the ordering variable. * * The Sudakov form factor for the initial-scale shower is different because * it must include the PDF which guides the backward evolution. * It is given by * \f[\Delta_{ba}(\tilde{q}_{i+1},\tilde{q}_i)= * \exp\left\{ * -\int^{\tilde{q}^2_i}_{\tilde{q}^2_{i+1}} * \frac{{\rm d}\tilde{q}^2}{\tilde{q}^2} * \int\frac{\alpha_S(z,\tilde{q})}{2\pi} * P_{ba}(z,\tilde{q})\frac{x'f_a(\frac{x}z,\tilde{q}^2)}{xf_b(x,\tilde{q^2})} * \right\}, * \f] * where \f$x\f$ is the fraction of the beam momentum the parton \f$b\f$ had before * the backward evolution. * This can be solve in the same way as for the final-state branching but the constant * becomes * \f[c = \frac{\alpha_{\rm over}}{2\pi}\int^{z_1}_{z_0}P_{\rm over}(z)PDF_{\rm max},\f] * where * \f[PDF_{\rm max}=\max\frac{x'f_a(\frac{x}z,\tilde{q}^2)}{xf_b(x,\tilde{q^2})},\f] * which can be set using an interface. * In addition the PDFVeto() member then is needed to implement the relevant veto. * * @see SplittingGenerator * @see SplittingFunction * @see ShowerAlpha * @see \ref SudakovFormFactorInterfaces "The interfaces" * defined for SudakovFormFactor. */ class SudakovFormFactor: public Interfaced { /** * The SplittingGenerator is a friend to insert the particles in the * branchings at initialisation */ friend class SplittingGenerator; public: /** * The default constructor. */ SudakovFormFactor() : pdfmax_(35.0), pdffactor_(0), - cutOffOption_(0), a_(0.3), b_(2.3), c_(0.3*GeV), - kinCutoffScale_( 2.3*GeV ), vgcut_(0.85*GeV), - vqcut_(0.85*GeV), pTmin_(1.*GeV), pT2min_(ZERO), z_( 0.0 ),phi_(0.0), pT_(){} /** * Members to generate the scale of the next branching */ //@{ /** * Return the scale of the next time-like branching. If there is no * branching then it returns ZERO. * @param startingScale starting scale for the evolution * @param ids The PDG codes of the particles in the splitting * @param enhance The radiation enhancement factor * defined. */ virtual ShoKinPtr generateNextTimeBranching(const Energy startingScale, const IdList &ids, const RhoDMatrix & rho, - double enhance, double detuning, - Energy2 maxQ2)=0; + double enhance, double detuning); /** * Return the scale of the next space-like decay branching. If there is no * branching then it returns ZERO. * @param startingScale starting scale for the evolution * @param stoppingScale stopping scale for the evolution * @param minmass The minimum mass allowed for the spake-like particle. * @param ids The PDG codes of the particles in the splitting * defined. * @param enhance The radiation enhancement factor */ virtual ShoKinPtr generateNextDecayBranching(const Energy startingScale, const Energy stoppingScale, const Energy minmass, const IdList &ids, const RhoDMatrix & rho, double enhance, - double detuning)=0; + double detuning); /** * Return the scale of the next space-like branching. If there is no * branching then it returns ZERO. * @param startingScale starting scale for the evolution * @param ids The PDG codes of the particles in the splitting * @param x The fraction of the beam momentum * defined. * @param beam The beam particle * @param enhance The radiation enhancement factor */ virtual ShoKinPtr generateNextSpaceBranching(const Energy startingScale, const IdList &ids,double x, const RhoDMatrix & rho, double enhance, tcBeamPtr beam, - double detuning)=0; + double detuning); //@} /** * Generate the azimuthal angle of the branching for forward evolution * @param particle The branching particle * @param ids The PDG codes of the particles in the branchings * @param The Shower kinematics */ virtual double generatePhiForward(ShowerParticle & particle,const IdList & ids, ShoKinPtr kinematics, - const RhoDMatrix & rho)=0; + const RhoDMatrix & rho); /** * Generate the azimuthal angle of the branching for backward evolution * @param particle The branching particle * @param ids The PDG codes of the particles in the branchings * @param The Shower kinematics */ virtual double generatePhiBackward(ShowerParticle & particle,const IdList & ids, ShoKinPtr kinematics, - const RhoDMatrix & rho)=0; + const RhoDMatrix & rho); /** * Generate the azimuthal angle of the branching for ISR in decays * @param particle The branching particle * @param ids The PDG codes of the particles in the branchings * @param The Shower kinematics */ virtual double generatePhiDecay(ShowerParticle & particle,const IdList & ids, ShoKinPtr kinematics, - const RhoDMatrix & rho)=0; + const RhoDMatrix & rho); /** * Methods to provide public access to the private member variables */ //@{ /** * Return the pointer to the SplittingFunction object. */ tSplittingFnPtr splittingFn() const { return splittingFn_; } /** * Return the pointer to the ShowerAlpha object. */ tShowerAlphaPtr alpha() const { return alpha_; } /** * The type of interaction */ inline ShowerInteraction interactionType() const {return splittingFn_->interactionType();} //@} public: /** * Methods to access the kinematic variables for the branching */ //@{ /** * The energy fraction */ double z() const { return z_; } /** * The azimuthal angle */ double phi() const { return phi_; } /** * The transverse momentum */ Energy pT() const { return pT_; } //@} /** * Access the maximum weight for the PDF veto */ double pdfMax() const { return pdfmax_;} /** * Method to return the evolution scale given the * transverse momentum, \f$p_T\f$ and \f$z\f$. */ - virtual Energy calculateScale(double z, Energy pt, IdList ids,unsigned int iopt)=0; - - /** - * Method to create the ShowerKinematics object for a final-state branching - */ - virtual ShoKinPtr createFinalStateBranching(Energy scale,double z, - double phi, Energy pt)=0; - - /** - * Method to create the ShowerKinematics object for an initial-state branching - */ - virtual ShoKinPtr createInitialStateBranching(Energy scale,double z, - double phi, Energy pt)=0; - - /** - * Method to create the ShowerKinematics object for a decay branching - */ - virtual ShoKinPtr createDecayBranching(Energy scale,double z, - double phi, Energy pt)=0; + virtual Energy calculateScale(double z, Energy pt, IdList ids,unsigned int iopt); 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(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(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 Standard Interfaced functions. */ + /** + * Methods to provide the next value of the scale before the vetos + * are applied. + */ //@{ /** - * Initialize this object after the setup phase before saving an - * EventGenerator to disk. - * @throws InitException if object could not be initialized properly. + * Value of the energy fraction and scale for time-like branching + * @param t The scale + * @param tmin The minimum scale + * @param enhance The radiation enhancement factor + * @return False if scale less than minimum, true otherwise */ - virtual void doinit(); + bool guessTimeLike(Energy2 &t, Energy2 tmin, double enhance, double detune); + + /** + * Value of the energy fraction and scale for time-like branching + * @param t The scale + * @param tmax The maximum scale + * @param minmass The minimum mass of the particle after the branching + * @param enhance The radiation enhancement factor + */ + bool guessDecay(Energy2 &t, Energy2 tmax,Energy minmass, + double enhance, double detune); + + /** + * Value of the energy fraction and scale for space-like branching + * @param t The scale + * @param tmin The minimum scale + * @param x Fraction of the beam momentum. + * @param enhance The radiation enhancement factor + */ + bool guessSpaceLike(Energy2 &t, Energy2 tmin, const double x, + double enhance, double detune); //@} + /** + * Initialize the values of the cut-offs and scales + * @param tmin The minimum scale + * @param ids The ids of the partics in the branching + */ + void initialize(const IdList & ids,Energy2 &tmin); + + /** + * Phase Space veto member to implement the \f$\Theta\f$ function as a veto + * so that the emission is within the allowed phase space. + * @param t The scale + * @param maxQ2 The maximum virtuality + * @return true if vetoed + */ + bool PSVeto(const Energy2 t); + + /** + * Compute the limits on \f$z\f$ for time-like branching + * @param scale The scale of the particle + * @return True if lower limit less than upper, otherwise false + */ + bool computeTimeLikeLimits(Energy2 & scale); + + /** + * Compute the limits on \f$z\f$ for space-like branching + * @param scale The scale of the particle + * @param x The energy fraction of the parton + * @return True if lower limit less than upper, otherwise false + */ + bool computeSpaceLikeLimits(Energy2 & scale, double x); + protected: /** * Methods to implement the veto algorithm to generate the scale of * the next branching */ //@{ /** * Value of the energy fraction for the veto algorithm * @param iopt The option for calculating z * @param ids The PDG codes of the particles in the splitting * - 0 is final-state * - 1 is initial-state for the hard process * - 2 is initial-state for particle decays */ double guessz (unsigned int iopt, const IdList &ids) const; /** * Value of the scale for the veto algorithm * @param t1 The starting valoe of the scale * @param iopt The option for calculating t * @param ids The PDG codes of the particles in the splitting * - 0 is final-state * - 1 is initial-state for the hard process * - 2 is initial-state for particle decays * @param enhance The radiation enhancement factor * @param identical Whether or not the outgoing particles are identical */ Energy2 guesst (Energy2 t1,unsigned int iopt, const IdList &ids, double enhance, bool identical, double detune) const; /** * Veto on the PDF for the initial-state shower * @param t The scale * @param x The fraction of the beam momentum * @param parton0 Pointer to the particleData for the * new parent (this is the particle we evolved back to) * @param parton1 Pointer to the particleData for the * original particle * @param beam The BeamParticleData object */ bool PDFVeto(const Energy2 t, const double x, const tcPDPtr parton0, const tcPDPtr parton1, tcBeamPtr beam) const; /** * The PDF veto ratio */ double PDFVetoRatio(const Energy2 t, const double x, const tcPDPtr parton0, const tcPDPtr parton1, tcBeamPtr beam,double factor) const; /** * The veto on the splitting function. * @param t The scale * @param ids The PDG codes of the particles in the splitting * @param mass Whether or not to use the massive splitting functions * @return true if vetoed */ bool SplittingFnVeto(const Energy2 t, const IdList &ids, const bool mass, const RhoDMatrix & rho, const double & detune) const { return UseRandom::rnd()>SplittingFnVetoRatio(t,ids,mass,rho,detune); } /** * The Splitting function veto ratio */ double SplittingFnVetoRatio(const Energy2 t, const IdList &ids, const bool mass, const RhoDMatrix & rho, const double & detune) const { return splittingFn_->ratioP(z_, t, ids,mass,rho)/detune; } /** * The veto on the coupling constant * @param pt2 The value of ther transverse momentum squared, \f$p_T^2\f$. * @return true if vetoed */ bool alphaSVeto(Energy2 pt2) const; /** * The alpha S veto ratio */ double alphaSVetoRatio(Energy2 pt2,double factor) const; //@} /** - * Methods to set the kinematic variables for the branching - */ - //@{ - /** - * The energy fraction - */ - void z(double in) { z_=in; } - - /** - * The azimuthal angle - */ - void phi(double in) { phi_=in; } - - /** - * The transverse momentum - */ - void pT(Energy in) { pT_=in; } - //@} - - /** - * Set/Get the limits on the energy fraction for the splitting - */ - //@{ - /** - * Get the limits - */ - pair zLimits() const { return zlimits_;} - - /** - * Set the limits - */ - void zLimits(pair in) { zlimits_=in; } - //@} - - /** * Set the particles in the splittings */ void addSplitting(const IdList &); /** * Delete the particles in the splittings */ void removeSplitting(const IdList &); /** * Access the potential branchings */ const vector & particles() const { return particles_; } public: /** - * @name Methods for the cut-off - */ - //@{ - /** - * The option being used - */ - unsigned int cutOffOption() const { return cutOffOption_; } - - /** - * The kinematic scale - */ - Energy kinScale() const {return kinCutoffScale_;} - - /** - * The virtuality cut-off on the gluon \f$Q_g=\frac{\delta-am_q}{b}\f$ - * @param scale The scale \f$\delta\f$ - * @param mq The quark mass \f$m_q\f$. - */ - Energy kinematicCutOff(Energy scale, Energy mq) const - {return max((scale -a_*mq)/b_,c_);} - - /** - * The virtualilty cut-off for gluons - */ - Energy vgCut() const { return vgcut_; } - - /** - * The virtuality cut-off for everything else - */ - Energy vqCut() const { return vqcut_; } - - /** - * The minimum \f$p_T\f$ for the branching - */ - Energy pTmin() const { return pTmin_; } - - /** - * The square of the minimum \f$p_T\f$ - */ - Energy2 pT2min() const { return pT2min_; } - - /** - * Calculate the virtual masses for a branchings - */ - const vector & virtualMasses(const IdList & ids); - //@} - - /** * Set the PDF */ void setPDF(tcPDFPtr pdf, Energy scale) { pdf_ = pdf; freeze_ = scale; } +public: + + /** + * Calculate the virtual masses for a branchings + */ + const vector & virtualMasses(const IdList & ids) { + return cutoff_->virtualMasses(ids); + } + + /** + * The minimum pT2 + */ + Energy2 pT2min() { return cutoff_->pT2min(); } + +protected: + + /** @name Clone Methods. */ + //@{ + /** + * Make a simple clone of this object. + * @return a pointer to the new object. + */ + virtual IBPtr clone() const {return new_ptr(*this);} + + /** Make a clone of this object, possibly modifying the cloned object + * to make it sane. + * @return a pointer to the new object. + */ + virtual IBPtr fullclone() const {return new_ptr(*this);} + //@} + private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ - SudakovFormFactor & operator=(const SudakovFormFactor &); + SudakovFormFactor & operator=(const SudakovFormFactor &) = delete; private: /** * Pointer to the splitting function for this Sudakov form factor */ SplittingFnPtr splittingFn_; /** * Pointer to the coupling for this Sudakov form factor */ ShowerAlphaPtr alpha_; /** + * Pointer to the coupling for this Sudakov form factor + */ + SudakovCutOffPtr cutoff_; + + /** * Maximum value of the PDF weight */ double pdfmax_; /** * List of the particles this Sudakov is used for to aid in setting up * interpolation tables if needed */ vector particles_; /** * Option for the inclusion of a factor \f$1/(1-z)\f$ in the PDF estimate */ unsigned pdffactor_; private: /** - * Option for the type of cut-off to be applied - */ - unsigned int cutOffOption_; - - /** - * Parameters for the default Herwig cut-off option, i.e. the parameters for - * the \f$Q_g=\max(\frac{\delta-am_q}{b},c)\f$ kinematic cut-off - */ - //@{ - /** - * The \f$a\f$ parameter - */ - double a_; - - /** - * The \f$b\f$ parameter - */ - double b_; - - /** - * The \f$c\f$ parameter - */ - Energy c_; - - /** - * Kinematic cutoff used in the parton shower phase space. - */ - Energy kinCutoffScale_; - //@} - - /** - * Parameters for the FORTRAN-like cut-off - */ - //@{ - /** - * The virtualilty cut-off for gluons - */ - Energy vgcut_; - - /** - * The virtuality cut-off for everything else - */ - Energy vqcut_; - //@} - - /** - * Parameters for the \f$p_T\f$ cut-off - */ - //@{ - /** - * The minimum \f$p_T\f$ for the branching - */ - Energy pTmin_; - - /** - * The square of the minimum \f$p_T\f$ - */ - Energy2 pT2min_; - //@} - -private: - - /** * Member variables to keep the shower kinematics information * generated by a call to generateNextTimeBranching or generateNextSpaceBranching */ //@{ /** * The energy fraction */ double z_; /** * The azimuthal angle */ double phi_; /** * The transverse momentum */ Energy pT_; //@} /** * The limits of \f$z\f$ in the splitting */ pair zlimits_; /** * Stuff for the PDFs */ //@{ /** * PDf */ tcPDFPtr pdf_; /** * Freezing scale */ Energy freeze_; //@} +private: + + /** + * The evolution scale, \f$\tilde{q}\f$. + */ + Energy q_; + + /** + * The Ids of the particles in the current branching + */ + IdList ids_; + + /** + * The masses of the particles in the current branching + */ + vector masses_; + + /** + * The mass squared of the particles in the current branching + */ + vector masssquared_; }; } #endif /* HERWIG_SudakovFormFactor_H */ diff --git a/Shower/QTilde/SplittingFunctions/VariableMassCutOff.cc b/Shower/QTilde/SplittingFunctions/VariableMassCutOff.cc new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/VariableMassCutOff.cc @@ -0,0 +1,93 @@ +// -*- C++ -*- +// +// This is the implementation of the non-inlined, non-templated member +// functions of the VariableMassCutOff class. +// + +#include "VariableMassCutOff.h" +#include "ThePEG/Interface/ClassDocumentation.h" +#include "ThePEG/EventRecord/Particle.h" +#include "ThePEG/Repository/UseRandom.h" +#include "ThePEG/Repository/EventGenerator.h" +#include "ThePEG/Utilities/DescribeClass.h" +#include "ThePEG/Interface/Parameter.h" + +#include "ThePEG/Persistency/PersistentOStream.h" +#include "ThePEG/Persistency/PersistentIStream.h" + +using namespace Herwig; + +IBPtr VariableMassCutOff::clone() const { + return new_ptr(*this); +} + +IBPtr VariableMassCutOff::fullclone() const { + return new_ptr(*this); +} + +void VariableMassCutOff::persistentOutput(PersistentOStream & os) const { + os << a_ << b_ << ounit(c_,GeV) << ounit(kinCutoffScale_, GeV); +} + +void VariableMassCutOff::persistentInput(PersistentIStream & is, int) { + is >> a_ >> b_ >> iunit(c_,GeV) >> iunit(kinCutoffScale_, GeV); +} + + +// The following static variable is needed for the type +// description system in ThePEG. +DescribeClass +describeHerwigVariableMassCutOff("Herwig::VariableMassCutOff", "HwShower.so"); + +void VariableMassCutOff::Init() { + + static ClassDocumentation documentation + ("There is no documentation for the VariableMassCutOff class"); + + + static Parameter interfaceaParameter + ("aParameter", + "The a parameter for the kinematic cut-off", + &VariableMassCutOff::a_, 0.3, -10.0, 10.0, + false, false, Interface::limited); + + static Parameter interfacebParameter + ("bParameter", + "The b parameter for the kinematic cut-off", + &VariableMassCutOff::b_, 2.3, -10.0, 10.0, + false, false, Interface::limited); + + static Parameter interfacecParameter + ("cParameter", + "The c parameter for the kinematic cut-off", + &VariableMassCutOff::c_, GeV, 0.3*GeV, 0.1*GeV, 10.0*GeV, + false, false, Interface::limited); + + static Parameter + interfaceKinScale ("cutoffKinScale", + "kinematic cutoff scale for the parton shower phase" + " space (unit [GeV])", + &VariableMassCutOff::kinCutoffScale_, GeV, + 2.3*GeV, 0.001*GeV, 10.0*GeV,false,false,false); + + +} + + +const vector & VariableMassCutOff::virtualMasses(const IdList & ids) { + static vector output; + output.clear(); + + for(auto id : ids) + output.push_back(id->mass()); + + Energy kinCutoff = kinematicCutOff( + kinCutoffScale_, + *std::max_element(output.begin(),output.end()) + ); + + for(auto & el : output) + el = max(kinCutoff, el); + + return output; +} diff --git a/Shower/QTilde/SplittingFunctions/VariableMassCutOff.h b/Shower/QTilde/SplittingFunctions/VariableMassCutOff.h new file mode 100644 --- /dev/null +++ b/Shower/QTilde/SplittingFunctions/VariableMassCutOff.h @@ -0,0 +1,124 @@ +// -*- C++ -*- +#ifndef Herwig_VariableMassCutOff_H +#define Herwig_VariableMassCutOff_H +// +// This is the declaration of the VariableMassCutOff class. +// + +#include "SudakovCutOff.h" + +namespace Herwig { + +using namespace ThePEG; + +/** + * Here is the documentation of the VariableMassCutOff class. + * + * @see \ref VariableMassCutOffInterfaces "The interfaces" + * defined for VariableMassCutOff. + */ +class VariableMassCutOff: public SudakovCutOff { + +public: + + /** + * Calculate the virtual masses for a branchings + */ + virtual const vector & virtualMasses(const IdList & ids); + +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(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(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 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 IBPtr fullclone() const; + //@} + +private: + + /** + * The virtuality cut-off on the gluon \f$Q_g=\frac{\delta-am_q}{b}\f$ + * @param scale The scale \f$\delta\f$ + * @param mq The quark mass \f$m_q\f$. + */ + Energy kinematicCutOff(Energy scale, Energy mq) const { + return max((scale -a_*mq)/b_,c_); + } + + + /** + * The assignment operator is private and must never be called. + * In fact, it should not even be implemented. + */ + VariableMassCutOff & operator=(const VariableMassCutOff &) = delete; + +private: + + /** + * Parameters for the default Herwig cut-off option, i.e. the parameters for + * the \f$Q_g=\max(\frac{\delta-am_q}{b},c)\f$ kinematic cut-off + */ + //@{ + /** + * The \f$a\f$ parameter + */ + double a_ = 0.3; + + /** + * The \f$b\f$ parameter + */ + double b_ = 2.3; + + /** + * The \f$c\f$ parameter + */ + Energy c_ = 0.3_GeV; + + /** + * Kinematic cutoff used in the parton shower phase space. + */ + Energy kinCutoffScale_ = 2.3_GeV; + //@} + + + +}; + +} + +#endif /* Herwig_VariableMassCutOff_H */ diff --git a/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.h b/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.h --- a/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.h +++ b/Shower/QTilde/SplittingFunctions/ZeroZeroOneSplitFn.h @@ -1,193 +1,188 @@ // -*- C++ -*- // // ZeroZeroOneSplitFn.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ZeroZeroOneSplitFn_H #define HERWIG_ZeroZeroOneSplitFn_H // // This is the declaration of the ZeroZeroOneSplitFn class. // #include "Herwig/Shower/QTilde/SplittingFunctions/SplittingFunction.h" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * This class provides the concrete implementation of the exact leading-order * splitting function for \f$\phi\to \phi g\f$. * * In this case the splitting function is given by * \f[P(z,t) = 2C\left(\frac{z}{1-z}-\frac{m^2_\phi}{t}\right),\f] * where \f$C\f$ is the corresponding colour factor. * Our choice for the overestimate is * \f[P_{\rm over}(z) = \frac{2C}{1-z},\f] * therefore the integral is * \f[\int P_{\rm over}(z) {\rm d}z = -2C\ln(1-z),\f] * and its inverse is * \f[1-\exp\left(\frac{r}{2C}\right).\f] * * @see \ref ZeroZeroOneSplitFnInterfaces "The interfaces" * defined for ZeroZeroOneSplitFn. */ class ZeroZeroOneSplitFn: public SplittingFunction { public: /** - * The default constructor. - */ - ZeroZeroOneSplitFn() : SplittingFunction(1) {} - - /** * Concrete implementation of the method to determine whether this splitting * function can be used for a given set of particles. * @param ids The PDG codes for the particles in the splitting. */ virtual bool accept(const IdList & ids) const; /** * Methods to return the splitting function. */ //@{ /** * The concrete implementation of the splitting function, \f$P\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double P(const double z, const Energy2 t, const IdList & ids, bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the overestimate of the splitting function, * \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. */ virtual double overestimateP(const double z, const IdList & ids) const; /** * The concrete implementation of the * the ratio of the splitting function to the overestimate, i.e. * \f$P(z,\tilde{q}^2)/P_{\rm over}(z)\f$. * @param z The energy fraction. * @param t The scale. * @param ids The PDG codes for the particles in the splitting. * @param mass Whether or not to include the mass dependent terms * @param rho The spin density matrix */ virtual double ratioP(const double z, const Energy2 t, const IdList & ids, bool mass, const RhoDMatrix & rho) const; /** * The concrete implementation of the indefinite integral of the * overestimated splitting function, \f$P_{\rm over}\f$. * @param z The energy fraction. * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double integOverP(const double z, const IdList & ids, unsigned int PDFfactor=0) const; /** * The concrete implementation of the inverse of the indefinite integral. * @param r Value of the splitting function to be inverted * @param ids The PDG codes for the particles in the splitting. * @param PDFfactor Which additional factor to include for the PDF * 0 is no additional factor, * 1 is \f$1/z\f$, 2 is \f$1/(1-z)\f$ and 3 is \f$1/z/(1-z)\f$ */ virtual double invIntegOverP(const double r, const IdList & ids, unsigned int PDFfactor=0) const; //@} /** * Method to calculate the azimuthal angle for forward evolution * @param particle The particle which is branching * @param showerkin The ShowerKinematics object * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiForward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Method to calculate the azimuthal angle for backward * Shouldn't be needed and NOT IMPLEMENTED * @param particle The particle which is branching * @param showerkin The ShowerKinematics object * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. * @return The weight */ virtual vector > generatePhiBackward(const double z, const Energy2 t, const IdList & ids, const RhoDMatrix &); /** * Calculate the matrix element for the splitting * @param particle The particle which is branching * @param showerkin The ShowerKinematics object * @param z The energy fraction * @param t The scale \f$t=2p_j\cdot p_k\f$. * @param ids The PDG codes for the particles in the splitting. * @param The azimuthal angle, \f$\phi\f$. */ virtual DecayMEPtr matrixElement(const double z, const Energy2 t, const IdList & ids, const double phi, bool timeLike); 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(); protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual IBPtr clone() const {return new_ptr(*this);} /** Make a clone of this object, possibly modifying the cloned object * to make it sane. * @return a pointer to the new object. */ virtual IBPtr fullclone() const {return new_ptr(*this);} //@} private: /** * The assignment operator is private and must never be called. * In fact, it should not even be implemented. */ ZeroZeroOneSplitFn & operator=(const ZeroZeroOneSplitFn &); }; } #endif /* HERWIG_ZeroZeroOneSplitFn_H */ diff --git a/Shower/ShowerHandler.cc b/Shower/ShowerHandler.cc --- a/Shower/ShowerHandler.cc +++ b/Shower/ShowerHandler.cc @@ -1,1097 +1,1114 @@ // -*- C++ -*- // // ShowerHandler.cc is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig 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 ShowerHandler class. // #include "ShowerHandler.h" #include "ThePEG/Interface/ClassDocumentation.h" #include "ThePEG/Interface/Reference.h" #include "ThePEG/Interface/Parameter.h" #include "ThePEG/Interface/ParVector.h" #include "ThePEG/Interface/Switch.h" #include "ThePEG/Interface/Command.h" #include "ThePEG/PDF/PartonExtractor.h" #include "ThePEG/PDF/PartonBinInstance.h" #include "Herwig/PDT/StandardMatchers.h" #include "ThePEG/Cuts/Cuts.h" #include "ThePEG/Handlers/StandardXComb.h" #include "ThePEG/Utilities/Throw.h" #include "ThePEG/Utilities/StringUtils.h" #include "ThePEG/Persistency/PersistentOStream.h" #include "ThePEG/Persistency/PersistentIStream.h" #include "ThePEG/Repository/EventGenerator.h" #include "Herwig/Utilities/EnumParticles.h" #include "Herwig/PDF/MPIPDF.h" #include "Herwig/PDF/MinBiasPDF.h" #include "ThePEG/Handlers/EventHandler.h" #include "Herwig/PDF/HwRemDecayer.h" #include #include "ThePEG/Utilities/DescribeClass.h" #include "Herwig/Decay/DecayIntegrator.h" #include "Herwig/Decay/DecayPhaseSpaceMode.h" using namespace Herwig; DescribeClass describeShowerHandler ("Herwig::ShowerHandler","HwShower.so"); ShowerHandler::~ShowerHandler() {} tShowerHandlerPtr ShowerHandler::currentHandler_ = tShowerHandlerPtr(); void ShowerHandler::doinit() { CascadeHandler::doinit(); // copy particles to decay before showering from input vector to the // set used in the simulation if ( particlesDecayInShower_.empty() ) { for(unsigned int ix=0;ixunrestrictedPhasespace() && restrictPhasespace() ) { generator()->log() << "ShowerApproximation warning: The scale profile chosen requires an unrestricted phase space,\n" << "however, the phase space was set to be restricted. Will switch to unrestricted phase space.\n" << flush; restrictPhasespace_ = false; } } } IBPtr ShowerHandler::clone() const { return new_ptr(*this); } IBPtr ShowerHandler::fullclone() const { return new_ptr(*this); } ShowerHandler::ShowerHandler() : maxtry_(10),maxtryMPI_(10),maxtryDP_(10),maxtryDecay_(100), factorizationScaleFactor_(1.0), renormalizationScaleFactor_(1.0), hardScaleFactor_(1.0), restrictPhasespace_(true), maxPtIsMuF_(false), - pdfFreezingScale_(2.5*GeV), + spinOpt_(1), pdfFreezingScale_(2.5*GeV), doFSR_(true), doISR_(true), splitHardProcess_(true), includeSpaceTime_(false), vMin_(0.1*GeV2), reweight_(1.0) { inputparticlesDecayInShower_.push_back( 6 ); // top inputparticlesDecayInShower_.push_back( 23 ); // Z0 inputparticlesDecayInShower_.push_back( 24 ); // W+/- inputparticlesDecayInShower_.push_back( 25 ); // h0 } void ShowerHandler::doinitrun(){ CascadeHandler::doinitrun(); //can't use isMPIOn here, because the EventHandler is not set at that stage if(MPIHandler_) { MPIHandler_->initialize(); if(MPIHandler_->softInt()) remDec_->initSoftInteractions(MPIHandler_->Ptmin(), MPIHandler_->beta()); } } void ShowerHandler::dofinish() { CascadeHandler::dofinish(); if(MPIHandler_) MPIHandler_->finalize(); } void ShowerHandler::persistentOutput(PersistentOStream & os) const { os << remDec_ << ounit(pdfFreezingScale_,GeV) << maxtry_ << maxtryMPI_ << maxtryDP_ << maxtryDecay_ << inputparticlesDecayInShower_ << particlesDecayInShower_ << MPIHandler_ << PDFA_ << PDFB_ << PDFARemnant_ << PDFBRemnant_ << includeSpaceTime_ << ounit(vMin_,GeV2) << factorizationScaleFactor_ << renormalizationScaleFactor_ << hardScaleFactor_ << restrictPhasespace_ << maxPtIsMuF_ << hardScaleProfile_ - << showerVariations_ << doFSR_ << doISR_ << splitHardProcess_; + << showerVariations_ << doFSR_ << doISR_ << splitHardProcess_ + << spinOpt_; } void ShowerHandler::persistentInput(PersistentIStream & is, int) { is >> remDec_ >> iunit(pdfFreezingScale_,GeV) >> maxtry_ >> maxtryMPI_ >> maxtryDP_ >> maxtryDecay_ >> inputparticlesDecayInShower_ >> particlesDecayInShower_ >> MPIHandler_ >> PDFA_ >> PDFB_ >> PDFARemnant_ >> PDFBRemnant_ >> includeSpaceTime_ >> iunit(vMin_,GeV2) >> factorizationScaleFactor_ >> renormalizationScaleFactor_ >> hardScaleFactor_ >> restrictPhasespace_ >> maxPtIsMuF_ >> hardScaleProfile_ - >> showerVariations_ >> doFSR_ >> doISR_ >> splitHardProcess_; + >> showerVariations_ >> doFSR_ >> doISR_ >> splitHardProcess_ + >> spinOpt_; } void ShowerHandler::Init() { static ClassDocumentation documentation ("Main driver class for the showering."); static Reference interfaceRemDecayer("RemDecayer", "A reference to the Remnant Decayer object", &Herwig::ShowerHandler::remDec_, false, false, true, false); static Parameter interfacePDFFreezingScale ("PDFFreezingScale", "The PDF freezing scale", &ShowerHandler::pdfFreezingScale_, GeV, 2.5*GeV, 2.0*GeV, 10.0*GeV, false, false, Interface::limited); static Parameter interfaceMaxTry ("MaxTry", "The maximum number of attempts for the main showering loop", &ShowerHandler::maxtry_, 10, 1, 100, false, false, Interface::limited); static Parameter interfaceMaxTryMPI ("MaxTryMPI", "The maximum number of regeneration attempts for an additional scattering", &ShowerHandler::maxtryMPI_, 10, 0, 100, false, false, Interface::limited); static Parameter interfaceMaxTryDP ("MaxTryDP", "The maximum number of regeneration attempts for an additional hard scattering", &ShowerHandler::maxtryDP_, 10, 0, 100, false, false, Interface::limited); static ParVector interfaceDecayInShower ("DecayInShower", "PDG codes of the particles to be decayed in the shower", &ShowerHandler::inputparticlesDecayInShower_, -1, 0l, -10000000l, 10000000l, false, false, Interface::limited); static Reference interfaceMPIHandler ("MPIHandler", "The object that administers all additional scatterings.", &ShowerHandler::MPIHandler_, false, false, true, true); static Reference interfacePDFA ("PDFA", "The PDF for beam particle A. Overrides the particle's own PDF setting." "By default used for both the shower and forced splitting in the remnant", &ShowerHandler::PDFA_, false, false, true, true, false); static Reference interfacePDFB ("PDFB", "The PDF for beam particle B. Overrides the particle's own PDF setting." "By default used for both the shower and forced splitting in the remnant", &ShowerHandler::PDFB_, false, false, true, true, false); static Reference interfacePDFARemnant ("PDFARemnant", "The PDF for beam particle A used to generate forced splittings of the remnant." " This overrides both the particle's own PDF setting and the value set by PDFA if used.", &ShowerHandler::PDFARemnant_, false, false, true, true, false); static Reference interfacePDFBRemnant ("PDFBRemnant", "The PDF for beam particle B used to generate forced splittings of the remnant." " This overrides both the particle's own PDF setting and the value set by PDFB if used.", &ShowerHandler::PDFBRemnant_, false, false, true, true, false); static Switch interfaceIncludeSpaceTime ("IncludeSpaceTime", "Whether to include the model for the calculation of space-time distances", &ShowerHandler::includeSpaceTime_, false, false, false); static SwitchOption interfaceIncludeSpaceTimeYes (interfaceIncludeSpaceTime, "Yes", "Include the model", true); static SwitchOption interfaceIncludeSpaceTimeNo (interfaceIncludeSpaceTime, "No", "Only include the displacement from the particle-s lifetime for decaying particles", false); static Parameter interfaceMinimumVirtuality ("MinimumVirtuality", "The minimum virtuality for the space-time model", &ShowerHandler::vMin_, GeV2, 0.1*GeV2, 0.0*GeV2, 1000.0*GeV2, false, false, Interface::limited); static Parameter interfaceFactorizationScaleFactor ("FactorizationScaleFactor", "The factorization scale factor.", &ShowerHandler::factorizationScaleFactor_, 1.0, 0.0, 0, false, false, Interface::lowerlim); static Parameter interfaceRenormalizationScaleFactor ("RenormalizationScaleFactor", "The renormalization scale factor.", &ShowerHandler::renormalizationScaleFactor_, 1.0, 0.0, 0, false, false, Interface::lowerlim); static Parameter interfaceHardScaleFactor ("HardScaleFactor", "The hard scale factor.", &ShowerHandler::hardScaleFactor_, 1.0, 0.0, 0, false, false, Interface::lowerlim); static Parameter interfaceMaxTryDecay ("MaxTryDecay", "The maximum number of attempts to generate a decay", &ShowerHandler::maxtryDecay_, 200, 10, 0, false, false, Interface::lowerlim); static Reference interfaceHardScaleProfile ("HardScaleProfile", "The hard scale profile to use.", &ShowerHandler::hardScaleProfile_, false, false, true, true, false); static Switch interfaceMaxPtIsMuF ("MaxPtIsMuF", "", &ShowerHandler::maxPtIsMuF_, false, false, false); static SwitchOption interfaceMaxPtIsMuFYes (interfaceMaxPtIsMuF, "Yes", "", true); static SwitchOption interfaceMaxPtIsMuFNo (interfaceMaxPtIsMuF, "No", "", false); static Switch interfaceRestrictPhasespace ("RestrictPhasespace", "Switch on or off phasespace restrictions", &ShowerHandler::restrictPhasespace_, true, false, false); static SwitchOption interfaceRestrictPhasespaceYes (interfaceRestrictPhasespace, "Yes", "Perform phasespace restrictions", true); static SwitchOption interfaceRestrictPhasespaceNo (interfaceRestrictPhasespace, "No", "Do not perform phasespace restrictions", false); static Command interfaceAddVariation ("AddVariation", "Add a shower variation.", &ShowerHandler::doAddVariation, false); static Switch interfaceDoFSR ("DoFSR", "Switch on or off final state radiation.", &ShowerHandler::doFSR_, true, false, false); static SwitchOption interfaceDoFSRYes (interfaceDoFSR, "Yes", "Switch on final state radiation.", true); static SwitchOption interfaceDoFSRNo (interfaceDoFSR, "No", "Switch off final state radiation.", false); static Switch interfaceDoISR ("DoISR", "Switch on or off initial state radiation.", &ShowerHandler::doISR_, true, false, false); static SwitchOption interfaceDoISRYes (interfaceDoISR, "Yes", "Switch on initial state radiation.", true); static SwitchOption interfaceDoISRNo (interfaceDoISR, "No", "Switch off initial state radiation.", false); static Switch interfaceSplitHardProcess ("SplitHardProcess", "Whether or not to try and split the hard process into production and decay processes", &ShowerHandler::splitHardProcess_, true, false, false); static SwitchOption interfaceSplitHardProcessYes (interfaceSplitHardProcess, "Yes", "Split the hard process", true); static SwitchOption interfaceSplitHardProcessNo (interfaceSplitHardProcess, "No", "Don't split the hard process", false); + + static Switch interfaceSpinCorrelations + ("SpinCorrelations", + "Treatment of spin correlations in the parton shower", + &ShowerHandler::spinOpt_, 1, false, false); + static SwitchOption interfaceSpinCorrelationsNo + (interfaceSpinCorrelations, + "No", + "No spin correlations", + 0); + static SwitchOption interfaceSpinCorrelationsSpin + (interfaceSpinCorrelations, + "Yes", + "Include the azimuthal spin correlations", + 1); } Energy ShowerHandler::hardScale() const { assert(false); } void ShowerHandler::cascade() { useMe(); // Initialise the weights in the event object // so that any variations are output regardless of // whether showering occurs for the given event initializeWeights(); // get the PDF's from ThePEG (if locally overridden use the local versions) tcPDFPtr first = PDFA_ ? tcPDFPtr(PDFA_) : firstPDF().pdf(); tcPDFPtr second = PDFB_ ? tcPDFPtr(PDFB_) : secondPDF().pdf(); resetPDFs(make_pair(first,second)); // set the PDFs for the remnant if( ! rempdfs_.first) rempdfs_.first = PDFARemnant_ ? PDFPtr(PDFARemnant_) : const_ptr_cast(first); if( ! rempdfs_.second) rempdfs_.second = PDFBRemnant_ ? PDFPtr(PDFBRemnant_) : const_ptr_cast(second); // get the incoming partons tPPair incomingPartons = eventHandler()->currentCollision()->primarySubProcess()->incoming(); // and the parton bins PBIPair incomingBins = make_pair(lastExtractor()->partonBinInstance(incomingPartons.first), lastExtractor()->partonBinInstance(incomingPartons.second)); // and the incoming hadrons tPPair incomingHadrons = eventHandler()->currentCollision()->incoming(); remnantDecayer()->setHadronContent(incomingHadrons); // check if incoming hadron == incoming parton // and get the incoming hadron if exists or parton otherwise incoming_ = make_pair(incomingBins.first ? incomingBins.first ->particle() : incomingPartons.first, incomingBins.second ? incomingBins.second->particle() : incomingPartons.second); // check the collision is of the beam particles // and if not boost collision to the right frame // i.e. the hadron-hadron CMF of the collision bool btotal(false); LorentzRotation rtotal; if(incoming_.first != incomingHadrons.first || incoming_.second != incomingHadrons.second ) { btotal = true; boostCollision(false); } // set the current ShowerHandler setCurrentHandler(); // first shower the hard process try { SubProPtr sub = eventHandler()->currentCollision()->primarySubProcess(); incomingPartons = cascade(sub,lastXCombPtr()); } catch(ShowerTriesVeto &veto){ throw Exception() << "Failed to generate the shower after " << veto.tries << " attempts in ShowerHandler::cascade()" << Exception::eventerror; } if(showerHardProcessVeto()) throw Veto(); // if a non-hadron collision return (both incoming non-hadronic) if( ( !incomingBins.first|| !isResolvedHadron(incomingBins.first ->particle()))&& ( !incomingBins.second|| !isResolvedHadron(incomingBins.second->particle()))) { // boost back to lab if needed if(btotal) boostCollision(true); // perform the reweighting for the hard process shower combineWeights(); // unset the current ShowerHandler unSetCurrentHandler(); return; } // get the remnants for hadronic collision pair remnants(getRemnants(incomingBins)); // set the starting scale of the forced splitting to the PDF freezing scale remnantDecayer()->initialize(remnants, incoming_, *currentStep(), pdfFreezingScale()); // do the first forcedSplitting try { remnantDecayer()->doSplit(incomingPartons, make_pair(rempdfs_.first,rempdfs_.second), true); } catch (ExtraScatterVeto) { throw Exception() << "Remnant extraction failed in " << "ShowerHandler::cascade() from primary interaction" << Exception::eventerror; } // perform the reweighting for the hard process shower combineWeights(); // if no MPI return if( !isMPIOn() ) { remnantDecayer()->finalize(); // boost back to lab if needed if(btotal) boostCollision(true); // unset the current ShowerHandler unSetCurrentHandler(); return; } // generate the multiple scatters use modified pdf's now: setMPIPDFs(); // additional "hard" processes unsigned int tries(0); // This is the loop over additional hard scatters (most of the time // only one, but who knows...) for(unsigned int i=1; i <= getMPIHandler()->additionalHardProcs(); i++){ //counter for regeneration unsigned int multSecond = 0; // generate the additional scatters while( multSecond < getMPIHandler()->multiplicity(i) ) { // generate the hard scatter tStdXCombPtr lastXC = getMPIHandler()->generate(i); SubProPtr sub = lastXC->construct(); // add to the Step newStep()->addSubProcess(sub); // increment the counters tries++; multSecond++; if(tries == maxtryDP_) throw Exception() << "Failed to establish the requested number " << "of additional hard processes. If this error " << "occurs often, your selection of additional " << "scatter is probably unphysical" << Exception::eventerror; // Generate the shower. If not possible veto the event try { incomingPartons = cascade(sub,lastXC); } catch(ShowerTriesVeto &veto){ throw Exception() << "Failed to generate the shower of " << "a secondary hard process after " << veto.tries << " attempts in Evolver::showerHardProcess()" << Exception::eventerror; } try { // do the forcedSplitting remnantDecayer()->doSplit(incomingPartons, make_pair(remmpipdfs_.first,remmpipdfs_.second), false); } catch(ExtraScatterVeto){ //remove all particles associated with the subprocess newStep()->removeParticle(incomingPartons.first); newStep()->removeParticle(incomingPartons.second); //remove the subprocess from the list newStep()->removeSubProcess(sub); //regenerate the scattering multSecond--; continue; } // connect with the remnants but don't set Remnant colour, // because that causes problems due to the multiple colour lines. if ( !remnants.first ->extract(incomingPartons.first , false) || !remnants.second->extract(incomingPartons.second, false) ) throw Exception() << "Remnant extraction failed in " << "ShowerHandler::cascade() for additional scatter" << Exception::runerror; } // perform the reweighting for the additional hard scatter shower combineWeights(); } // the underlying event processes unsigned int ptveto(1), veto(0); unsigned int max(getMPIHandler()->multiplicity()); for(unsigned int i=0; i maxtryMPI_) break; //generate PSpoint tStdXCombPtr lastXC = getMPIHandler()->generate(); SubProPtr sub = lastXC->construct(); //If Algorithm=1 additional scatters of the signal type // with pt > ptmin have to be vetoed //with probability 1/(m+1), where m is the number of occurances in this event if( getMPIHandler()->Algorithm() == 1 ){ //get the pT Energy pt = sub->outgoing().front()->momentum().perp(); if(pt > getMPIHandler()->PtForVeto() && UseRandom::rnd() < 1./(ptveto+1) ){ ptveto++; i--; continue; } } // add to the SubProcess to the step newStep()->addSubProcess(sub); // Run the Shower. If not possible veto the scattering try { incomingPartons = cascade(sub,lastXC); } // discard this extra scattering, but try the next one catch(ShowerTriesVeto) { newStep()->removeSubProcess(sub); //regenerate the scattering veto++; i--; continue; } try{ //do the forcedSplitting remnantDecayer()->doSplit(incomingPartons, make_pair(remmpipdfs_.first,remmpipdfs_.second), false); } catch (ExtraScatterVeto) { //remove all particles associated with the subprocess newStep()->removeParticle(incomingPartons.first); newStep()->removeParticle(incomingPartons.second); //remove the subprocess from the list newStep()->removeSubProcess(sub); //regenerate the scattering veto++; i--; continue; } //connect with the remnants but don't set Remnant colour, //because that causes problems due to the multiple colour lines. if ( !remnants.first ->extract(incomingPartons.first , false) || !remnants.second->extract(incomingPartons.second, false) ) throw Exception() << "Remnant extraction failed in " << "ShowerHandler::cascade() for MPI hard scattering" << Exception::runerror; //reset veto counter veto = 0; // perform the reweighting for the MPI process shower combineWeights(); } // finalize the remnants remnantDecayer()->finalize(getMPIHandler()->colourDisrupt(), getMPIHandler()->softMultiplicity()); // boost back to lab if needed if(btotal) boostCollision(true); // unset the current ShowerHandler unSetCurrentHandler(); getMPIHandler()->clean(); resetPDFs(make_pair(first,second)); } void ShowerHandler::initializeWeights() { if ( !showerVariations().empty() ) { tEventPtr event = eventHandler()->currentEvent(); for ( map::const_iterator var = showerVariations().begin(); var != showerVariations().end(); ++var ) { // Check that this is behaving as intended //map::iterator wi = event->optionalWeights().find(var->first); //assert(wi == event->optionalWeights().end() ); event->optionalWeights()[var->first] = 1.0; currentWeights_[var->first] = 1.0; } } reweight_ = 1.0; } void ShowerHandler::resetWeights() { for ( map::iterator w = currentWeights_.begin(); w != currentWeights_.end(); ++w ) { w->second = 1.0; } reweight_ = 1.0; } void ShowerHandler::combineWeights() { tEventPtr event = eventHandler()->currentEvent(); for ( map::const_iterator w = currentWeights_.begin(); w != currentWeights_.end(); ++w ) { map::iterator ew = event->optionalWeights().find(w->first); if ( ew != event->optionalWeights().end() ) ew->second *= w->second; else { assert(false && "Weight name unknown."); //event->optionalWeights()[w->first] = w->second; } } if ( reweight_ != 1.0 ) { Ptr::tptr eh = dynamic_ptr_cast::tptr>(eventHandler()); if ( !eh ) { throw Exception() << "ShowerHandler::combineWeights() : Cross section reweighting " << "through the shower is currently only available with standard " << "event generators" << Exception::runerror; } eh->reweight(reweight_); } } string ShowerHandler::doAddVariation(string in) { if ( in.empty() ) return "expecting a name and a variation specification"; string name = StringUtils::car(in); ShowerVariation var; string res = var.fromInFile(StringUtils::cdr(in)); if ( res.empty() ) { if ( !var.firstInteraction && !var.secondaryInteractions ) { // TODO what about decay showers? return "variation does not apply to any shower"; } if ( var.renormalizationScaleFactor == 1.0 && var.factorizationScaleFactor == 1.0 ) { return "variation does not vary anything"; } /* Repository::clog() << "adding a variation with tag '" << name << "' using\nxir = " << var.renormalizationScaleFactor << " xif = " << var.factorizationScaleFactor << "\napplying to:\n" << "first interaction = " << var.firstInteraction << " " << "secondary interactions = " << var.secondaryInteractions << "\n" << flush; */ showerVariations()[name] = var; } return res; } tPPair ShowerHandler::cascade(tSubProPtr, XCPtr) { assert(false); } ShowerHandler::RemPair ShowerHandler::getRemnants(PBIPair incomingBins) { RemPair remnants; // first beam particle if(incomingBins.first&&!incomingBins.first->remnants().empty()) { remnants.first = dynamic_ptr_cast(incomingBins.first->remnants()[0] ); if(remnants.first) { ParticleVector children=remnants.first->children(); for(unsigned int ix=0;ixdataPtr()==remnants.first->dataPtr()) remnants.first = dynamic_ptr_cast(children[ix]); } //remove existing colour lines from the remnants if(remnants.first->colourLine()) remnants.first->colourLine()->removeColoured(remnants.first); if(remnants.first->antiColourLine()) remnants.first->antiColourLine()->removeAntiColoured(remnants.first); } } // seconnd beam particle if(incomingBins.second&&!incomingBins. second->remnants().empty()) { remnants.second = dynamic_ptr_cast(incomingBins.second->remnants()[0] ); if(remnants.second) { ParticleVector children=remnants.second->children(); for(unsigned int ix=0;ixdataPtr()==remnants.second->dataPtr()) remnants.second = dynamic_ptr_cast(children[ix]); } //remove existing colour lines from the remnants if(remnants.second->colourLine()) remnants.second->colourLine()->removeColoured(remnants.second); if(remnants.second->antiColourLine()) remnants.second->antiColourLine()->removeAntiColoured(remnants.second); } } assert(remnants.first || remnants.second); return remnants; } namespace { void addChildren(tPPtr in,set & particles) { particles.insert(in); for(unsigned int ix=0;ixchildren().size();++ix) addChildren(in->children()[ix],particles); } } void ShowerHandler::boostCollision(bool boost) { // calculate boost from lab to rest if(!boost) { Lorentz5Momentum ptotal=incoming_.first ->momentum()+incoming_.second->momentum(); boost_ = LorentzRotation(-ptotal.boostVector()); Axis axis((boost_*incoming_.first ->momentum()).vect().unit()); if(axis.perp2()>0.) { double sinth(sqrt(sqr(axis.x())+sqr(axis.y()))); boost_.rotate(-acos(axis.z()),Axis(-axis.y()/sinth,axis.x()/sinth,0.)); } } // first call performs the boost and second inverse // get the particles to be boosted set particles; addChildren(incoming_.first,particles); addChildren(incoming_.second,particles); // apply the boost for(set::const_iterator cit=particles.begin(); cit!=particles.end();++cit) { (*cit)->transform(boost_); } if(!boost) boost_.invert(); } void ShowerHandler::setMPIPDFs() { if ( !mpipdfs_.first ) { // first have to check for MinBiasPDF tcMinBiasPDFPtr first = dynamic_ptr_cast(firstPDF().pdf()); if(first) mpipdfs_.first = new_ptr(MPIPDF(first->originalPDF())); else mpipdfs_.first = new_ptr(MPIPDF(firstPDF().pdf())); } if ( !mpipdfs_.second ) { tcMinBiasPDFPtr second = dynamic_ptr_cast(secondPDF().pdf()); if(second) mpipdfs_.second = new_ptr(MPIPDF(second->originalPDF())); else mpipdfs_.second = new_ptr(MPIPDF(secondPDF().pdf())); } if( !remmpipdfs_.first ) { tcMinBiasPDFPtr first = dynamic_ptr_cast(rempdfs_.first); if(first) remmpipdfs_.first = new_ptr(MPIPDF(first->originalPDF())); else remmpipdfs_.first = new_ptr(MPIPDF(rempdfs_.first)); } if( !remmpipdfs_.second ) { tcMinBiasPDFPtr second = dynamic_ptr_cast(rempdfs_.second); if(second) remmpipdfs_.second = new_ptr(MPIPDF(second->originalPDF())); else remmpipdfs_.second = new_ptr(MPIPDF(rempdfs_.second)); } // reset the PDFs stored in the base class resetPDFs(mpipdfs_); } bool ShowerHandler::isResolvedHadron(tPPtr particle) { if(!HadronMatcher::Check(particle->data())) return false; for(unsigned int ix=0;ixchildren().size();++ix) { if(particle->children()[ix]->id()==ParticleID::Remnant) return true; } return false; } namespace { bool decayProduct(tSubProPtr subProcess, tPPtr particle) { // must be time-like and not incoming if(particle->momentum().m2()<=ZERO|| particle == subProcess->incoming().first|| particle == subProcess->incoming().second) return false; // if only 1 outgoing and this is it if(subProcess->outgoing().size()==1 && subProcess->outgoing()[0]==particle) return true; // must not be the s-channel intermediate otherwise if(find(subProcess->incoming().first->children().begin(), subProcess->incoming().first->children().end(),particle)!= subProcess->incoming().first->children().end()&& find(subProcess->incoming().second->children().begin(), subProcess->incoming().second->children().end(),particle)!= subProcess->incoming().second->children().end()&& subProcess->incoming().first ->children().size()==1&& subProcess->incoming().second->children().size()==1) return false; // if non-coloured this is enough if(!particle->dataPtr()->coloured()) return true; // if coloured must be unstable if(particle->dataPtr()->stable()) return false; // must not have same particle type as a child int id = particle->id(); for(unsigned int ix=0;ixchildren().size();++ix) if(particle->children()[ix]->id()==id) return false; // otherwise its a decaying particle return true; } PPtr findParent(PPtr original, bool & isHard, set outgoingset, tSubProPtr subProcess) { PPtr parent=original; isHard |=(outgoingset.find(original) != outgoingset.end()); if(!original->parents().empty()) { PPtr orig=original->parents()[0]; if(decayProduct(subProcess,orig)) parent=findParent(orig,isHard,outgoingset,subProcess); } return parent; } } void ShowerHandler::findDecayProducts(PPtr in,PerturbativeProcessPtr hard, DecayProcessMap & decay) const { ParticleVector children=in->children(); for(ParticleVector::const_iterator it=children.begin(); it!=children.end();++it) { // if decayed or should be decayed in shower make the PerturbaitveProcess bool radiates = false; if(!(**it).children().empty()) { // remove d,u,s,c,b quarks and leptons other than on-shell taus if( StandardQCDPartonMatcher::Check((**it).id()) || ( LeptonMatcher::Check((**it).id()) && !(abs((**it).id())==ParticleID::tauminus && abs((**it).mass()-(**it).dataPtr()->mass())id()==(**it).id()) { foundParticle = true; } else if((**it).children()[iy]->id()==ParticleID::g || (**it).children()[iy]->id()==ParticleID::gamma) { foundGauge = true; } } radiates = foundParticle && foundGauge; } } if(radiates) { findDecayProducts(*it,hard,decay); } else if(!(**it).children().empty()|| (decaysInShower((**it).id())&&!(**it).dataPtr()->stable())) { createDecayProcess(*it,hard,decay); } else { hard->outgoing().push_back(make_pair(*it,PerturbativeProcessPtr())); } } } void ShowerHandler::splitHardProcess(tPVector tagged, PerturbativeProcessPtr & hard, DecayProcessMap & decay) const { // temporary storage of the particles set hardParticles; // tagged particles in a set set outgoingset(tagged.begin(),tagged.end()); bool isHard=false; // loop over the tagged particles for (tParticleVector::const_iterator taggedP = tagged.begin(); taggedP != tagged.end(); ++taggedP) { // skip remnants if (eventHandler()->currentCollision()&& eventHandler()->currentCollision()->isRemnant(*taggedP)) continue; // find the parent and whether its a decaying particle bool isDecayProd=false; // check if hard isHard |=(outgoingset.find(*taggedP) != outgoingset.end()); if(splitHardProcess_) { tPPtr parent = *taggedP; // check if from s channel decaying colourless particle while(parent&&!parent->parents().empty()&&!isDecayProd) { parent = parent->parents()[0]; if(parent == subProcess_->incoming().first || parent == subProcess_->incoming().second ) break; isDecayProd = decayProduct(subProcess_,parent); } if (isDecayProd) hardParticles.insert(findParent(parent,isHard,outgoingset,subProcess_)); } if (!isDecayProd) hardParticles.insert(*taggedP); } // there must be something to shower if(hardParticles.empty()) throw Exception() << "No particles to shower in " << "ShowerHandler::splitHardProcess()" << Exception::eventerror; // must be a hard process if(!isHard) throw Exception() << "Starting on decay not yet implemented in " << "ShowerHandler::splitHardProcess()" << Exception::runerror; // create the hard process hard = new_ptr(PerturbativeProcess()); // incoming particles hard->incoming().push_back(make_pair(subProcess_->incoming().first ,PerturbativeProcessPtr())); hard->incoming().push_back(make_pair(subProcess_->incoming().second,PerturbativeProcessPtr())); // outgoing particles for(set::const_iterator it=hardParticles.begin();it!=hardParticles.end();++it) { // if decayed or should be decayed in shower make the tree PPtr orig = *it; bool radiates = false; if(!orig->children().empty()) { // remove d,u,s,c,b quarks and leptons other than on-shell taus if( StandardQCDPartonMatcher::Check(orig->id()) || ( LeptonMatcher::Check(orig->id()) && !(abs(orig->id())==ParticleID::tauminus && abs(orig->mass()-orig->dataPtr()->mass())children().size();++iy) { if(orig->children()[iy]->id()==orig->id()) { foundParticle = true; } else if(orig->children()[iy]->id()==ParticleID::g || orig->children()[iy]->id()==ParticleID::gamma) { foundGauge = true; } } radiates = foundParticle && foundGauge; } } if(radiates) { findDecayProducts(orig,hard,decay); } else if(!(**it).children().empty()|| (decaysInShower((**it).id())&&!(**it).dataPtr()->stable())) { createDecayProcess(*it,hard,decay); } else { hard->outgoing().push_back(make_pair(*it,PerturbativeProcessPtr())); } } } void ShowerHandler::createDecayProcess(PPtr in,PerturbativeProcessPtr hard, DecayProcessMap & decay) const { // there must be an incoming particle assert(in); // create the new process and connect with the parent PerturbativeProcessPtr newDecay=new_ptr(PerturbativeProcess()); newDecay->incoming().push_back(make_pair(in,hard)); Energy width=in->dataPtr()->generateWidth(in->mass()); decay.insert(make_pair(width,newDecay)); hard->outgoing().push_back(make_pair(in,newDecay)); // we need to deal with the decay products if decayed ParticleVector children = in->children(); if(!children.empty()) { for(ParticleVector::const_iterator it = children.begin(); it!= children.end(); ++it) { // if decayed or should be decayed in shower make the tree in->abandonChild(*it); bool radiates = false; if(!(**it).children().empty()) { if(StandardQCDPartonMatcher::Check((**it).id())|| (LeptonMatcher::Check((**it).id())&& !(abs((**it).id())==ParticleID::tauminus && abs((**it).mass()-(**it).dataPtr()->mass())id()==(**it).id()) { foundParticle = true; } else if((**it).children()[iy]->id()==ParticleID::g || (**it).children()[iy]->id()==ParticleID::gamma) { foundGauge = true; } } radiates = foundParticle && foundGauge; } // finally assume all non-decaying particles are in this class // pr 27/11/15 not sure about this bit // if(!radiates) { // radiates = !decaysInShower((**it).id()); // } } if(radiates) { findDecayProducts(*it,newDecay,decay); } else if(!(**it).children().empty()|| (decaysInShower((**it).id())&&!(**it).dataPtr()->stable())) { createDecayProcess(*it,newDecay,decay); } else { newDecay->outgoing().push_back(make_pair(*it,PerturbativeProcessPtr())); } } } } tDMPtr ShowerHandler::decay(PerturbativeProcessPtr process, DecayProcessMap & decayMap, bool radPhotons ) const { PPtr parent = process->incoming()[0].first; assert(parent); if(parent->spinInfo()) parent->spinInfo()->decay(true); unsigned int ntry = 0; ParticleVector children; tDMPtr dm = DMPtr(); while (true) { // exit if fails if (++ntry>=maxtryDecay_) throw Exception() << "Failed to perform decay in ShowerHandler::decay()" << " after " << maxtryDecay_ << " attempts for " << parent->PDGName() << Exception::eventerror; // select decay mode dm = parent->data().selectMode(*parent); if(!dm) throw Exception() << "Failed to select decay mode in ShowerHandler::decay()" << "for " << parent->PDGName() << Exception::eventerror; if(!dm->decayer()) throw Exception() << "No Decayer for selected decay mode " << " in ShowerHandler::decay()" << Exception::runerror; // start of try block try { children = dm->decayer()->decay(*dm, *parent); // if no children have another go if(children.empty()) continue; if(radPhotons){ // generate radiation in the decay tDecayIntegratorPtr hwdec=dynamic_ptr_cast(dm->decayer()); if (hwdec && hwdec->canGeneratePhotons()) children = hwdec->generatePhotons(*parent,children); } // set up parent parent->decayMode(dm); // add children for (unsigned int i = 0, N = children.size(); i < N; ++i ) { children[i]->setLabVertex(parent->labDecayVertex()); //parent->addChild(children[i]); } // if succeeded break out of loop break; } catch(Veto) { } } assert(!children.empty()); for(ParticleVector::const_iterator it = children.begin(); it!= children.end(); ++it) { if(!(**it).children().empty()|| (decaysInShower((**it).id())&&!(**it).dataPtr()->stable())) { createDecayProcess(*it,process,decayMap); } else { process->outgoing().push_back(make_pair(*it,PerturbativeProcessPtr())); } } return dm; } // Note: The tag must be constructed from an ordered particle container. tDMPtr ShowerHandler::findDecayMode(const string & tag) const { static map cache; map::const_iterator pos = cache.find(tag); if ( pos != cache.end() ) return pos->second; tDMPtr dm = CurrentGenerator::current().findDecayMode(tag); cache[tag] = dm; return dm; } /** * Operator for the particle ordering * @param p1 The first ParticleData object * @param p2 The second ParticleData object */ bool ShowerHandler::ParticleOrdering::operator() (tcPDPtr p1, tcPDPtr p2) { 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() ); } diff --git a/Shower/ShowerHandler.h b/Shower/ShowerHandler.h --- a/Shower/ShowerHandler.h +++ b/Shower/ShowerHandler.h @@ -1,847 +1,880 @@ // -*- C++ -*- // // ShowerHandler.h is a part of Herwig - A multi-purpose Monte Carlo event generator // Copyright (C) 2002-2017 The Herwig Collaboration // // Herwig is licenced under version 3 of the GPL, see COPYING for details. // Please respect the MCnet academic guidelines, see GUIDELINES for details. // #ifndef HERWIG_ShowerHandler_H #define HERWIG_ShowerHandler_H // // This is the declaration of the ShowerHandler class. // #include "ThePEG/Handlers/EventHandler.h" #include "ThePEG/Handlers/CascadeHandler.h" #include "ShowerVariation.h" #include "Herwig/PDF/HwRemDecayer.fh" #include "ThePEG/EventRecord/RemnantParticle.fh" #include "UEBase.h" #include "PerturbativeProcess.h" #include "Herwig/MatrixElement/Matchbox/Matching/HardScaleProfile.h" #include "ShowerHandler.fh" namespace Herwig { using namespace ThePEG; /** \ingroup Shower * * This class is the main driver of the shower: it is responsible for * the proper handling of all other specific collaborating classes * and for the storing of the produced particles in the event record. * * @see \ref ShowerHandlerInterfaces "The interfaces" * * @see ThePEG::CascadeHandler * @see MPIHandler * @see HwRemDecayer */ class ShowerHandler: public CascadeHandler { public: /** * Typedef for a pair of ThePEG::RemnantParticle pointers. */ typedef pair RemPair; public: /** * Default constructor */ ShowerHandler(); /** * Destructor */ virtual ~ShowerHandler(); public: /** * The main method which manages the multiple interactions and starts * the shower by calling cascade(sub, lastXC). */ virtual void cascade(); /** * pointer to "this", the current ShowerHandler. */ static const tShowerHandlerPtr currentHandler() { assert(currentHandler_); return currentHandler_; } + /** + * pointer to "this", the current ShowerHandler. + */ + static bool currentHandlerIsSet() { + return currentHandler_; + } + public: /** * Hook to allow vetoing of event after showering hard sub-process * as in e.g. MLM merging. */ virtual bool showerHardProcessVeto() const { return false; } /** * Return true, if this cascade handler will perform reshuffling from hard * process masses. */ virtual bool isReshuffling() const { return true; } /** * Return true, if the shower handler can generate a truncated * shower for POWHEG style events generated using Matchbox */ virtual bool canHandleMatchboxTrunc() const { return false; } /** * Get the PDF freezing scale */ Energy pdfFreezingScale() const { return pdfFreezingScale_; } /** * Get the local PDFs. */ PDFPtr getPDFA() const {return PDFA_;} /** * Get the local PDFs. */ PDFPtr getPDFB() const {return PDFB_;} /** * Return true if currently the primary subprocess is showered. */ bool firstInteraction() const { if (!eventHandler()->currentCollision())return true; return ( subProcess_ == eventHandler()->currentCollision()->primarySubProcess() ); } /** * Return the remnant decayer. */ tHwRemDecPtr remnantDecayer() const { return remDec_; } /** * Split the hard process into production and decays * @param tagged The tagged particles from the StepHandler * @param hard The hard perturbative process * @param decay The decay particles */ void splitHardProcess(tPVector tagged, PerturbativeProcessPtr & hard, DecayProcessMap & decay) const; /** * Information if the Showerhandler splits the hard process. */ bool doesSplitHardProcess()const {return splitHardProcess_;} /** * Decay a particle. * radPhotons switches the generation of photon * radiation on/off. * Required for Dipole Shower but not QTilde Shower. */ tDMPtr decay(PerturbativeProcessPtr, DecayProcessMap & decay, bool radPhotons = false) const; /** * Cached lookup of decay modes. * Generator::findDecayMode() is not efficient. */ tDMPtr findDecayMode(const string & tag) const; /** * A struct to order the particles in the same way as in the DecayMode's */ struct ParticleOrdering { bool operator() (tcPDPtr p1, tcPDPtr p2); }; /** * A container for ordered particles required * for constructing tags for decay mode lookup. */ typedef multiset OrderedParticles; public: /** * @name Switches for initial- and final-state radiation */ //@{ /** * Switch for any radiation */ bool doRadiation() const {return doFSR_ || doISR_;} /** * Switch on or off final state radiation. */ bool doFSR() const { return doFSR_;} /** * Switch on or off initial state radiation. */ bool doISR() const { return doISR_;} //@} public: /** * @name Switches for scales */ //@{ /** * Return true if maximum pt should be deduced from the factorization scale */ bool hardScaleIsMuF() const { return maxPtIsMuF_; } /** * The factorization scale factor. */ double factorizationScaleFactor() const { return factorizationScaleFactor_; } /** * The renormalization scale factor. */ double renFac() const { return renormalizationScaleFactor_; } /** * The factorization scale factor. */ double facFac() const { return factorizationScaleFactor_; } /** * The renormalization scale factor. */ double renormalizationScaleFactor() const { return renormalizationScaleFactor_; } /** * The scale factor for the hard scale */ double hardScaleFactor() const { return hardScaleFactor_; } /** * Return true, if the phase space restrictions of the dipole shower should * be applied. */ bool restrictPhasespace() const { return restrictPhasespace_; } /** * Return profile scales */ Ptr::tptr profileScales() const { return hardScaleProfile_; } /** * Return the relevant hard scale to be used in the profile scales */ virtual Energy hardScale() const; /** * Return information about shower phase space choices */ virtual int showerPhaseSpaceOption() const { assert(false && "not implemented in general"); return -1; } //@} public: /** * Access the shower variations */ map& showerVariations() { return showerVariations_; } /** * Return the shower variations */ const map& showerVariations() const { return showerVariations_; } /** * Access the current Weights */ map& currentWeights() { return currentWeights_; } /** * Return the current Weights */ const map& currentWeights() const { return currentWeights_; } /** * Change the current reweighting factor */ void reweight(double w) { reweight_ = w; } /** * Return the current reweighting factor */ double reweight() const { return reweight_; } +public : + + /** + * Access to switches for spin correlations + */ + //@{ + /** + * Spin Correlations + */ + unsigned int spinCorrelations() const { + return spinOpt_; + } + + /** + * Any correlations + */ + virtual bool correlations() const { + return spinOpt_!=0; + } + //@} + public: /** * struct that is used to catch exceptions which are thrown * due to energy conservation issues of additional scatters */ struct ExtraScatterVeto {}; /** * struct that is used to catch exceptions which are thrown * due to fact that the Shower has been invoked more than * a defined threshold on a certain configuration */ struct ShowerTriesVeto { /** variable to store the number of attempts */ const int tries; /** constructor */ ShowerTriesVeto(int t) : tries(t) {} }; 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(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(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 Functions to perform the cascade */ //@{ /** * The main method which manages the showering of a subprocess. */ virtual tPPair cascade(tSubProPtr sub, XCPtr xcomb); /** * Set up for the cascade */ void prepareCascade(tSubProPtr sub) { current_ = currentStep(); subProcess_ = sub; } /** * Boost all the particles in the collision so that the collision always occurs * in the rest frame with the incoming particles along the z axis */ void boostCollision(bool boost); //@} protected: /** * Set/unset the current shower handler */ //@{ /** * Set the current handler */ void setCurrentHandler() { currentHandler_ = tShowerHandlerPtr(this); } /** * Unset the current handler */ void unSetCurrentHandler() { currentHandler_ = tShowerHandlerPtr(); } //@} protected: /** * @name Members relating to the underlying event and MPI */ //@{ /** * Return true if multiple parton interactions are switched on * and can be used for this beam setup. */ bool isMPIOn() const { return MPIHandler_ && MPIHandler_->beamOK(); } /** * Access function for the MPIHandler, it should only be called after * checking with isMPIOn. */ tUEBasePtr getMPIHandler() const { assert(MPIHandler_); return MPIHandler_; } /** * Is a beam particle where hadronic structure is resolved */ bool isResolvedHadron(tPPtr); /** * Get the remnants from the ThePEG::PartonBinInstance es and * do some checks. */ RemPair getRemnants(PBIPair incbins); /** * Reset the PDF's after the hard collision has been showered */ void setMPIPDFs(); //@} public: /** * Check if a particle decays in the shower * @param id The PDG code for the particle */ bool decaysInShower(long id) const { return ( particlesDecayInShower_.find( abs(id) ) != particlesDecayInShower_.end() ); } protected: /** * Members to handle splitting up of hard process and decays */ //@{ /** * Find decay products from the hard process and create decay processes * @param parent The parent particle * @param hard The hard process * @param decay The decay processes */ void findDecayProducts(PPtr parent, PerturbativeProcessPtr hard, DecayProcessMap & decay) const; /** * Find decay products from the hard process and create decay processes * @param parent The parent particle * @param hard The parent hard process * @param decay The decay processes */ void createDecayProcess(PPtr parent,PerturbativeProcessPtr hard, DecayProcessMap & decay) const; //@} /** * @name Functions to return information relevant to the process being showered */ //@{ /** * Return the currently used SubProcess. */ tSubProPtr currentSubProcess() const { assert(subProcess_); return subProcess_; } /** * Access to the incoming beam particles */ tPPair incomingBeams() const { return incoming_; } //@} protected: /** * Weight handling for shower variations */ //@ /** * Combine the variation weights which have been encountered */ void combineWeights(); /** * Initialise the weights in currentEvent() */ void initializeWeights(); /** * Reset the current weights */ void resetWeights(); //@} protected: /** * Return the maximum number of attempts for showering * a given subprocess. */ unsigned int maxtry() const { return maxtry_; } protected: /** * Parameters for the space-time model */ //@{ /** * Whether or not to include spa-cetime distances in the shower */ bool includeSpaceTime() const {return includeSpaceTime_;} /** * The minimum virtuality for the space-time model */ Energy2 vMin() const {return vMin_;} //@} protected: /** @name Clone Methods. */ //@{ /** * Make a simple clone of this object. * @return a pointer to the new object. */ virtual 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 IBPtr fullclone() const; //@} protected: /** @name Standard Interfaced functions. */ //@{ /** * Initialize this object after the setup phase before saving an * EventGenerator to disk. * @throws InitException if object could not be initialized properly. */ 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 assignment operator is private and must never be called. * In fact, it should not even be implemented. */ ShowerHandler & operator=(const ShowerHandler &); private: /** * pointer to "this", the current ShowerHandler. */ static tShowerHandlerPtr currentHandler_; /** * a MPIHandler to administer the creation of several (semihard) * partonic interactions. */ UEBasePtr MPIHandler_; /** * Pointer to the HwRemDecayer */ HwRemDecPtr remDec_; private: /** * Maximum tries for various stages of the showering process */ //@{ /** * Maximum number of attempts for the * main showering loop */ unsigned int maxtry_; /** * Maximum number of attempts for the regeneration of an additional * scattering, before the number of scatters is reduced. */ unsigned int maxtryMPI_; /** * Maximum number of attempts for the regeneration of an additional * hard scattering, before this event is vetoed. */ unsigned int maxtryDP_; /** * Maximum number of attempts to generate a decay */ unsigned int maxtryDecay_; //@} private: /** * Factors for the various scales */ //@{ /** * The factorization scale factor. */ double factorizationScaleFactor_; /** * The renormalization scale factor. */ double renormalizationScaleFactor_; /** * The scale factor for the hard scale */ double hardScaleFactor_; /** * True, if the phase space restrictions of the dipole shower should * be applied. */ bool restrictPhasespace_; /** * True if maximum pt should be deduced from the factorization scale */ bool maxPtIsMuF_; /** * The profile scales */ Ptr::ptr hardScaleProfile_; //@} + /** + * Option to include spin correlations + */ + unsigned int spinOpt_; + private: /** * Storage of information about the current event */ //@{ /** * The incoming beam particles for the current collision */ tPPair incoming_; /** * Boost to get back to the lab */ LorentzRotation boost_; /** * Const pointer to the currently handeled ThePEG::SubProcess */ tSubProPtr subProcess_; /** * Const pointer to the current step */ tcStepPtr current_; //@} private: /** * PDFs to be used for the various stages and related parameters */ //@{ /** * The PDF freezing scale */ Energy pdfFreezingScale_; /** * PDFs to be used for the various stages and related parameters */ //@{ /** * The PDF for beam particle A. Overrides the particle's own PDF setting. */ PDFPtr PDFA_; /** * The PDF for beam particle B. Overrides the particle's own PDF setting. */ PDFPtr PDFB_; /** * The PDF for beam particle A for remnant splitting. Overrides the particle's own PDF setting. */ PDFPtr PDFARemnant_; /** * The PDF for beam particle B for remnant splitting. Overrides the particle's own PDF setting. */ PDFPtr PDFBRemnant_; /** * The MPI PDF's to be used for secondary scatters. */ pair mpipdfs_; /** * The MPI PDF's to be used for secondary scatters. */ pair rempdfs_; /** * The MPI PDF's to be used for secondary scatters. */ pair remmpipdfs_; //@} private: /** * @name Parameters for initial- and final-state radiation */ //@{ /** * Switch on or off final state radiation. */ bool doFSR_; /** * Switch on or off initial state radiation. */ bool doISR_; //@} private: /** * @name Parameters for particle decays */ //@{ /** * Whether or not to split into hard and decay trees */ bool splitHardProcess_; /** * PDG codes of the particles which decay during showering * this is fast storage for use during running */ set particlesDecayInShower_; /** * PDG codes of the particles which decay during showering * this is a vector that is interfaced so they can be changed */ vector inputparticlesDecayInShower_; //@} private: /** * Parameters for the space-time model */ //@{ /** * Whether or not to include spa-cetime distances in the shower */ bool includeSpaceTime_; /** * The minimum virtuality for the space-time model */ Energy2 vMin_; //@} private: /** * Parameters relevant for reweight and variations */ //@{ /** * The shower variations */ map showerVariations_; /** * Command to add a shower variation */ string doAddVariation(string); /** * A reweighting factor applied by the showering */ double reweight_; /** * The shower variation weights */ map currentWeights_; //@} }; } #endif /* HERWIG_ShowerHandler_H */ diff --git a/Tests/Makefile.am b/Tests/Makefile.am --- a/Tests/Makefile.am +++ b/Tests/Makefile.am @@ -1,400 +1,397 @@ AM_LDFLAGS += -module -avoid-version -rpath /dummy/path/not/used EXTRA_DIST = Inputs python Rivet EXTRA_LTLIBRARIES = LeptonTest.la GammaTest.la HadronTest.la DISTest.la if WANT_LIBFASTJET EXTRA_LTLIBRARIES += HadronJetTest.la LeptonJetTest.la HadronJetTest_la_SOURCES = \ Hadron/VHTest.h Hadron/VHTest.cc\ Hadron/VTest.h Hadron/VTest.cc\ Hadron/HTest.h Hadron/HTest.cc HadronJetTest_la_CPPFLAGS = $(AM_CPPFLAGS) $(FASTJETINCLUDE) \ -I$(FASTJETPATH) HadronJetTest_la_LIBADD = $(FASTJETLIBS) LeptonJetTest_la_SOURCES = \ Lepton/TopDecay.h Lepton/TopDecay.cc LeptonJetTest_la_CPPFLAGS = $(AM_CPPFLAGS) $(FASTJETINCLUDE) \ -I$(FASTJETPATH) LeptonJetTest_la_LIBADD = $(FASTJETLIBS) endif LeptonTest_la_SOURCES = \ Lepton/VVTest.h Lepton/VVTest.cc \ Lepton/VBFTest.h Lepton/VBFTest.cc \ Lepton/VHTest.h Lepton/VHTest.cc \ Lepton/FermionTest.h Lepton/FermionTest.cc GammaTest_la_SOURCES = \ Gamma/GammaMETest.h Gamma/GammaMETest.cc \ Gamma/GammaPMETest.h Gamma/GammaPMETest.cc DISTest_la_SOURCES = \ DIS/DISTest.h DIS/DISTest.cc HadronTest_la_SOURCES = \ Hadron/HadronVVTest.h Hadron/HadronVVTest.cc\ Hadron/HadronVBFTest.h Hadron/HadronVBFTest.cc\ Hadron/WHTest.h Hadron/WHTest.cc\ Hadron/ZHTest.h Hadron/ZHTest.cc\ Hadron/VGammaTest.h Hadron/VGammaTest.cc\ Hadron/ZJetTest.h Hadron/ZJetTest.cc\ Hadron/WJetTest.h Hadron/WJetTest.cc\ Hadron/QQHTest.h Hadron/QQHTest.cc REPO = $(top_builddir)/src/HerwigDefaults.rpo HERWIG = $(top_builddir)/src/Herwig HWREAD = $(HERWIG) read --repo $(REPO) -L $(builddir)/.libs -i $(top_builddir)/src HWBUILD = $(HERWIG) build --repo $(REPO) -L $(builddir)/.libs -i $(top_builddir)/src HWINTEGRATE = $(HERWIG) integrate HWRUN = $(HERWIG) run -N $${NUMEVENTS:-10000} tests : tests-LEP tests-DIS tests-LHC tests-Gamma LEPDEPS = \ test-LEP-VV \ test-LEP-VH \ test-LEP-VBF \ test-LEP-BB \ test-LEP-Quarks \ test-LEP-Leptons if WANT_LIBFASTJET LEPDEPS += test-LEP-TopDecay endif tests-LEP : $(LEPDEPS) tests-DIS : test-DIS-Charged test-DIS-Neutral LHCDEPS = \ test-LHC-WW test-LHC-WZ test-LHC-ZZ \ test-LHC-ZGamma test-LHC-WGamma \ test-LHC-ZH test-LHC-WH \ test-LHC-ZJet test-LHC-WJet \ test-LHC-Z test-LHC-W \ test-LHC-ZZVBF test-LHC-VBF \ test-LHC-WWVBF \ test-LHC-bbH test-LHC-ttH \ test-LHC-GammaGamma test-LHC-GammaJet \ test-LHC-Higgs test-LHC-HiggsJet \ test-LHC-QCDFast test-LHC-QCD \ test-LHC-Top if WANT_LIBFASTJET LHCDEPS += \ test-LHC-Bottom \ test-LHC-WHJet test-LHC-ZHJet test-LHC-HJet \ test-LHC-ZShower test-LHC-WShower \ test-LHC-WHJet-Powheg test-LHC-ZHJet-Powheg test-LHC-HJet-Powheg \ test-LHC-ZShower-Powheg test-LHC-WShower-Powheg endif tests-LHC : $(LHCDEPS) tests-Gamma : test-Gamma-FF test-Gamma-WW test-Gamma-P LEPLIBS = LeptonTest.la HADLIBS = HadronTest.la if WANT_LIBFASTJET LEPLIBS += LeptonJetTest.la HADLIBS += HadronJetTest.la endif test-LEP-% : Inputs/LEP-%.in $(LEPLIBS) $(HWREAD) $< $(HWRUN) $(notdir $(subst .in,.run,$<)) test-Gamma-% : Inputs/Gamma-%.in GammaTest.la $(HWREAD) $< $(HWRUN) $(notdir $(subst .in,.run,$<)) test-DIS-% : Inputs/DIS-%.in DISTest.la $(HWREAD) $< $(HWRUN) $(notdir $(subst .in,.run,$<)) test-LHC-% : Inputs/LHC-%.in GammaTest.la $(HADLIBS) $(HWREAD) $< $(HWRUN) $(notdir $(subst .in,.run,$<)) tests-Rivet : Rivet-LEP Rivet-BFactory Rivet-DIS Rivet-Star Rivet-SppS \ Rivet-TVT-WZ Rivet-TVT-Photon Rivet-TVT-Jets \ Rivet-LHC-Jets Rivet-LHC-EW Rivet-LHC-Photon Rivet-LHC-Higgs Rivet-%.run : Rivet/%.in $(HWBUILD) -c .cache/$(subst .run,,$@) $< Rivet-Matchbox-%.yoda : Rivet-Matchbox-%.run $(HWINTEGRATE) -c .cache/$(subst .run,,$<) $< $(HWRUN) -c .cache/$(subst .run,,$<) $< Rivet-%.yoda : Rivet-%.run $(HWRUN) $< Rivet/%.in : python/make_input_files.py $(notdir $(subst .in,,$@)) Rivet-inputfiles: $(shell echo Rivet/LEP{,-Powheg,-Matchbox,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox-Powheg,-Merging}-{9.4,12,13,17,27.6,29,30.2,30.7,30.75,30,31.3,34.8,43.6,50,52,55,56,57,60.8,60,61.4,10,12.8,22,26.8,35,44,48.0,91,93.0,130,133,136,161,172,177,183,189,192,196,197,200,202,206,91-nopi}.in) \ $(shell echo Rivet/LEP{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Powheg,-Matchbox-Powheg}-14.in) \ $(shell echo Rivet/LEP{,-Dipole}-{10.5,11.96,12.8,13.96,16.86,21.84,26.8,28.48,35.44,48.0,97.0}-gg.in) \ $(shell echo Rivet/BFactory{,-Powheg,-Matchbox,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox-Powheg}-{10.52,10.52-sym,10.54,10.45}.in) \ $(shell echo Rivet/BFactory{,-Dipole}-{Upsilon,Upsilon2,Upsilon4,Tau,10.58-res}.in) \ $(shell echo Rivet/DIS{,-NoME,-Powheg,-Matchbox,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox-Powheg,-Merging}-{e--LowQ2,e+-LowQ2,e+-HighQ2}.in) \ $(shell echo Rivet/TVT{,-Powheg,-Matchbox,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox-Powheg,-Merging}-{Run-I-Z,Run-I-W,Run-I-WZ,Run-II-Z-e,Run-II-Z-{,LowMass-,HighMass-}mu,Run-II-W}.in) \ $(shell echo Rivet/TVT{,-Dipole}-Run-II-{DiPhoton-GammaGamma,DiPhoton-GammaJet,PromptPhoton}.in) \ $(shell echo Rivet/TVT-Powheg-Run-II-{DiPhoton-GammaGamma,DiPhoton-GammaJet}.in) \ $(shell echo Rivet/TVT{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{Run-II-Jets-{0..11},Run-I-Jets-{1..8}}.in ) \ $(shell echo Rivet/TVT{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{630-Jets-{1..3},300-Jets-1,900-Jets-1}.in ) \ $(shell echo Rivet/TVT{,-Dipole}-{Run-I,Run-II,300,630,900}-UE.in) \ $(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-7-DiJets-{1..7}-{A,B,C}.in ) \ $(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{7,8,13}-Jets-{0..10}.in ) \ $(shell echo Rivet/LHC{,-Dipole}-{900,2360,2760,7,8,13}-UE.in ) \ $(shell echo Rivet/LHC{,-Dipole}-{900,7,13}-UE-Long.in ) \ $(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-7-Charm-{1..5}.in) \ $(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-7-Bottom-{0..8}.in) \ - $(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{7,8,13}-Top-{L,SL}.in) \ - $(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{7,8}-Top.in) \ + $(shell echo Rivet/LHC{,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Matchbox,-Matchbox-Powheg,-Merging}-{7,8,13}-Top-{All,L,SL}.in) \ $(shell echo Rivet/Star{,-Dipole}-{UE,Jets-{1..4}}.in ) \ $(shell echo Rivet/SppS{,-Dipole}-{200,500,900,546}-UE.in ) \ $(shell echo Rivet/LHC{,-Matchbox,-Matchbox-Powheg,-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-{W-{e,mu},13-Z-{e,mu},Z-HighMass{1,2}-e,{8,13}-W-mu,8-Z-Mass{1..4}-{e,mu},Z-{e,mu,mu-SOPHTY},Z-LowMass-{e,mu},Z-MedMass-e,WZ,WW-{emu,ll},ZZ-{ll,lv},{8,13}-WZ,8-ZZ-lv,8-WW-ll,W-Z-{e,mu}}.in) \ $(shell echo Rivet/LHC{,-Dipole}-7-{W,Z}Gamma-{e,mu}.in) \ $(shell echo Rivet/LHC{,-Matchbox,-Matchbox-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-{7-W-Jet-{1..3}-e,7-Z-Jet-{0..3}-e,7-Z-Jet-0-mu}.in) \ - $(shell echo Rivet/LHC{-Matchbox,-Matchbox-Powheg,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-{Z-b,Z-bb,W-b,8-Z-jj}.in) \ + $(shell echo Rivet/LHC{-Matchbox,-Matchbox-Powheg,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-{Z-b,Z-bb,8-Z-b,8-Z-bb,W-b,8-Z-jj}.in) \ $(shell echo Rivet/LHC{,-Dipole}-{7,8}-PromptPhoton-{1..4}.in) Rivet/LHC-GammaGamma-7.in \ $(shell echo Rivet/LHC{,-Powheg}-{7,8}-{DiPhoton-GammaGamma,DiPhoton-GammaJet}.in) \ $(shell echo Rivet/LHC{,-Powheg,-Matchbox,-Matchbox-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-{ggH,VBF,WH,ZH}.in) \ $(shell echo Rivet/LHC{,-Powheg,-Matchbox,-Matchbox-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-8-{{ggH,VBF,WH,ZH}{,-GammaGamma},ggH-WW}.in) \ $(shell echo Rivet/LHC{,-Matchbox,-Matchbox-Powheg,-Dipole,-Dipole-MCatNLO,-Dipole-Matchbox-Powheg,-Merging}-ggHJet.in) # $(shell echo Rivet/ISR-{30,44,53,62}-UE.in ) $(shell echo Rivet/SppS-{53,63}-UE.in ) Rivet-LEP : Rivet-LEP/done touch $@ Rivet-LEP/done : $(shell echo Rivet{,-Powheg,-Matchbox,-Dipole}-LEP-{9.4,12,13,17,27.6,29,30.2,30.7,30.75,30,31.3,34.8,43.6,50,52,55,56,57,60.8,60,61.4,10,12.8,22,26.8,35,44,48.0,91,93.0,130,133,136,161,172,177,183,189,192,196,197,200,202,206,91-nopi}.yoda) \ $(shell echo Rivet-LEP-{10.5,11.96,12.8,13.96,16.86,21.84,26.8,28.48,35.44,48.0,97.0}-gg.yoda) \ $(shell echo Rivet{,-Powheg,-Matchbox,-Matchbox-Powheg,-Dipole}-LEP-14.yoda) rm -rf Rivet-LEP python/merge-LEP --with-gg LEP python/merge-LEP Powheg-LEP python/merge-LEP Matchbox-LEP python/merge-LEP Dipole-LEP rivet-mkhtml -o Rivet-LEP LEP.yoda:Hw Powheg-LEP.yoda:Hw-Powheg Matchbox-LEP.yoda:Hw-Matchbox Dipole-LEP.yoda:Hw-Dipole touch $@ Rivet-BFactory : Rivet-BFactory/done touch $@ Rivet-BFactory/done: $(shell echo Rivet{,-Powheg,-Matchbox,-Dipole}-BFactory-{10.52,10.52-sym,10.54,10.45}.yoda) \ $(shell echo Rivet-BFactory-{Upsilon,Upsilon2,Upsilon4,Tau,10.58-res,10.58}.yoda) rm -rf Rivet-BFactory python/merge-BFactory BFactory python/merge-BFactory Powheg-BFactory python/merge-BFactory Matchbox-BFactory python/merge-BFactory Dipole-BFactory rivet-mkhtml -o Rivet-BFactory BFactory.yoda:Hw Powheg-BFactory.yoda:Hw-Powheg Matchbox-BFactory.yoda:Hw-Matchbox Dipole-BFactory.yoda:Hw-Dipole touch $@ Rivet-DIS : Rivet-DIS/done touch $@ Rivet-DIS/done: $(shell echo Rivet{-DIS,-DIS-NoME,-Powheg-DIS,-Matchbox-DIS,-Dipole-DIS}-{e--LowQ2,e+-LowQ2,e+-HighQ2}.yoda) rm -rf Rivet-DIS python/merge-DIS DIS python/merge-DIS Powheg-DIS python/merge-DIS DIS-NoME python/merge-DIS Matchbox-DIS python/merge-DIS Dipole-DIS rivet-mkhtml -o Rivet-DIS DIS.yoda:Hw Powheg-DIS.yoda:Hw-Powheg DIS-NoME.yoda:Hw-NoME Matchbox-DIS.yoda:Hw-Matchbox Dipole-DIS.yoda:Hw-Dipole touch $@ -Rivet-TVT-WZ : Rivet-TVT-WZ/done +Rivet-TVT-EW : Rivet-TVT-EW/done touch $@ -Rivet-TVT-WZ/done: $(shell echo Rivet{,-Powheg,-Matchbox,-Dipole}-TVT-{Run-I-Z,Run-I-W,Run-I-WZ,Run-II-Z-{e,{,LowMass-,HighMass-}mu},Run-II-W}.yoda) +Rivet-TVT-EW/done: $(shell echo Rivet{,-Powheg,-Matchbox,-Dipole}-TVT-{Run-I-Z,Run-I-W,Run-I-WZ,Run-II-Z-{e,{,LowMass-,HighMass-}mu},Run-II-W}.yoda) rm -rf Rivet-TVT-WZ - python/merge-TVT-EW Rivet-TVT-Run-II-W.yoda Rivet-TVT-Run-II-Z-{e,{,LowMass-,HighMass-}mu}.yoda\ - Rivet-TVT-Run-I-{W,Z,WZ}.yoda -o TVT-WZ.yoda - python/merge-TVT-EW Rivet-TVT-Powheg-Run-II-W.yoda Rivet-TVT-Powheg-Run-II-Z-{e,{,LowMass-,HighMass-}mu}.yoda\ - Rivet-TVT-Powheg-Run-I-{W,Z,WZ}.yoda -o TVT-Powheg-WZ.yoda - python/merge-TVT-EW Rivet-TVT-Matchbox-Run-II-W.yoda Rivet-TVT-Matchbox-Run-II-Z-{e,{,LowMass-,HighMass-}mu}.yoda\ - Rivet-TVT-Matchbox-Run-I-{W,Z,WZ}.yoda -o TVT-Matchbox-WZ.yoda - python/merge-TVT-EW Rivet-TVT-Dipole-Run-II-W.yoda Rivet-TVT-Dipole-Run-II-Z-{e,{,LowMass-,HighMass-}mu}.yoda\ - Rivet-TVT-Dipole-Run-I-{W,Z,WZ}.yoda -o TVT-Dipole-WZ.yoda - rivet-mkhtml -o Rivet-TVT-WZ TVT-WZ.yoda:Hw TVT-Powheg-WZ.yoda:Hw-Powheg TVT-Matchbox-WZ.yoda:Hw-Matchbox TVT-Dipole-WZ.yoda:Hw-Dipole + python/merge-TVT-EW TVT + python/merge-TVT-EW TVT-Powheg + python/merge-TVT-EW TVT-Matchbox + python/merge-TVT-EW TVT-Dipole + rivet-mkhtml -o Rivet-TVT-EW TVT-EW.yoda:Hw TVT-Powheg-EW.yoda:Hw-Powheg TVT-Matchbox-EW.yoda:Hw-Matchbox TVT-Dipole-EW.yoda:Hw-Dipole touch $@ Rivet-TVT-Photon : Rivet-TVT-Photon/done touch $@ Rivet-TVT-Photon/done: $(shell echo Rivet-TVT-Run-II-{DiPhoton-GammaGamma,DiPhoton-GammaJet,PromptPhoton}.yoda) \ $(shell echo Rivet-Powheg-TVT-Run-II-{DiPhoton-GammaGamma,DiPhoton-GammaJet}.yoda) rm -rf Rivet-TVT-Photon python/merge-TVT-Photon TVT -o TVT-Photon.yoda python/merge-TVT-Photon TVT-Powheg -o TVT-Powheg-Photon.yoda rivet-mkhtml -o Rivet-TVT-Photon TVT-Photon.yoda:Hw TVT-Powheg-Photon.yoda:Hw-Powheg touch $@ Rivet-TVT-Jets : Rivet-TVT-Jets/done touch $@ Rivet-TVT-Jets/done: $(shell echo Rivet-TVT-{Run-II-Jets-{0..11},Run-I-Jets-{1..8}}.yoda ) \ $(shell echo Rivet-TVT-{630-Jets-{1..3},300-Jets-1,900-Jets-1}.yoda ) \ $(shell echo Rivet-TVT-{Run-I,Run-II,300,630,900}-UE.yoda) rm -rf Rivet-TVT-Jets python/merge-TVT-Jets TVT rivet-mkhtml -o Rivet-TVT-Jets TVT-Jets.yoda:Hw touch $@ #python/merge-TVT-Energy TVT #rivet-merge-CDF_2012_NOTE10874 TVT-300-Energy.yoda TVT-900-Energy.yoda TVT-1960-Energy.yoda #flat2yoda RatioPlots.dat -o TVT-RatioPlots.yoda Rivet-Star : Rivet-Star/done touch $@ Rivet-Star/done : $(shell echo Rivet-Star-{UE,Jets-{1..4}}.yoda ) rm -rf Rivet-Star python/merge-Star Star ## broken DVI? ## rivet-mkhtml -v -o Rivet-Star Star.yoda mkdir -p Rivet-Star # remove when fixed touch $@ Rivet-SppS : Rivet-SppS/done touch $@ ## $(shell echo Rivet-ISR-{30,44,53,62}-UE.yoda ) \ ## {53,63,200,500,900,546} Rivet-SppS/done : $(shell echo Rivet-SppS-{200,500,900,546}-UE.yoda ) rm -rf Rivet-SppS python/merge-SppS SppS rivet-mkhtml -o Rivet-SppS SppS.yoda touch $@ Rivet-LHC-Jets : Rivet-LHC-Jets/done touch $@ Rivet-LHC-Jets/done : \ $(shell echo Rivet-LHC-7-DiJets-{1..7}-{A,B,C}.yoda ) \ $(shell echo Rivet-LHC-{7,8,13}-Jets-{0..10}.yoda ) \ $(shell echo Rivet-LHC-{900,2360,2760,7,8,13}-UE.yoda ) \ $(shell echo Rivet-LHC-{900,7,13}-UE-Long.yoda ) \ $(shell echo Rivet-LHC-7-Charm-{1..5}.yoda ) \ $(shell echo Rivet-LHC-7-Bottom-{0..8}.yoda ) \ $(shell echo Rivet-LHC-{7,8,13}-Top-{L,SL}.yoda ) \ $(shell echo Rivet-LHC-{7,8}-Top-All.yoda ) rm -rf Rivet-LHC-Jets python/merge-LHC-Jets LHC rivet-mkhtml -o Rivet-LHC-Jets LHC-Jets.yoda:Hw touch $@ Rivet-LHC-EW : Rivet-LHC-EW/done touch $@ Rivet-LHC-EW/done: \ $(shell echo Rivet{,-Matchbox,-Powheg,-Dipole}-LHC-{13-Z-{e,mu},{8,13}-W-mu,Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-SOPHTY},Z-LowMass-{e,mu},Z-MedMass-e,WZ,WW-{emu,ll},ZZ-{ll,lv},{8,13}-WZ,8-ZZ-lv,8-WW-ll,W-Z-{e,mu}}.yoda) \ $(shell echo Rivet{,-Matchbox,-Dipole}-LHC-{7-W-Jet-{1..3}-e,7-Z-Jet-{0..3}-e,7-Z-Jet-0-mu}.yoda) \ - $(shell echo Rivet{-Matchbox,-Dipole}-LHC-{Z-b,Z-bb,W-b,8-Z-jj}.yoda) \ + $(shell echo Rivet{-Matchbox,-Dipole}-LHC-{Z-b,Z-bb,8-Z-b,8-Z-bb,W-b,8-Z-jj}.yoda) \ $(shell echo Rivet-LHC-7-{W,Z}Gamma-{e,mu}.yoda) rm -rf Rivet-LHC-EW; - python/merge-LHC-EW Rivet-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-Short},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},{8,13}-WZ,8-ZZ-lv,8-WW-ll}.yoda Rivet-LHC-7-{W,Z}-Jet-{1,2,3}-e.yoda Rivet-LHC-7-{W,Z}Gamma-{e,mu}.yoda -o LHC-EW.yoda; - python/merge-LHC-EW Rivet-Matchbox-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-Short},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},{8,13}-WZ,{8,13}-WZ,8-ZZ-lv,8-WW-ll}.yoda Rivet-LHC-Matchbox-7-{W,Z}-Jet-{1,2,3}-e.yoda -o LHC-Matchbox-EW.yoda; - python/merge-LHC-EW Rivet-Dipole-LHC-{13-Z-{e,mu},Z-HighMass{1,2}-e,8-Z-Mass{1..4}-{e,mu},W-{e,mu},Z-{e,mu,mu-Short},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},{8,13}-WZ,8-ZZ-lv,8-WW-ll}.yoda Rivet-LHC-Dipole-7-{W,Z}-Jet-{1,2,3}-e.yoda -o LHC-Dipole-EW.yoda; - python/merge-LHC-EW Rivet-Powheg-LHC-{W-{e,mu},Z-{e,mu},Z-LowMass-{e,mu},Z-MedMass-e,W-Z-{e,mu},WW-{emu,ll},WZ,ZZ-{ll,lv},{8,13}-WZ,8-ZZ-lv,8-WW-ll}.yoda -o LHC-Powheg-EW.yoda; + python/merge-LHC-EW LHC + python/merge-LHC-EW LHC-Matchbox + python/merge-LHC-EW LHC-Dipole + python/merge-LHC-EW LHC-Powheg rivet-mkhtml -o Rivet-LHC-EW LHC-EW.yoda:Hw LHC-Powheg-EW.yoda:Hw-Powheg LHC-Matchbox-EW.yoda:Hw-Matchbox LHC-Matchbox-Z-b.yoda:Hw-Matchbox-Zb \ LHC-Matchbox-Z-bb.yoda:Hw-Matchbox-Zbb LHC-Matchbox-W-b.yoda:Hw-Matchbox-W-bb LHC-Dipole-EW.yoda:Hw-Dipole \ LHC-Dipole-Z-b.yoda:Hw-Dipole-Zb LHC-Dipole-Z-bb.yoda:Hw-Dipole-Zbb LHC-Dipole-W-b.yoda:Hw-Dipole-W-bb \ - LHC-Z-mu-SOPHTY.yoda:Hw LHC-Powheg-Z-mu-SOPHTY.yoda:Hw-Powheg LHC-Matchbox-Z-mu-SOPHTY.yoda:Hw-Matchbox + LHC-Z-mu-SOPHTY.yoda:Hw LHC-Powheg-Z-mu-SOPHTY.yoda:Hw-Powheg LHC-Matchbox-Z-mu-SOPHTY.yoda:Hw-Matchbox \ + LHC-Matchbox-8-Z-b.yoda:Hw-Matchbox-Zb LHC-Matchbox-8-Z-bb.yoda:Hw-Matchbox-Zbb \ + LHC-Dipole-8-Z-b.yoda:Hw-Dipole-Zb LHC-Dipole-8-Z-bb.yoda:Hw-Dipole-Zbb touch $@ Rivet-LHC-Photon : Rivet-LHC-Photon/done touch $@ Rivet-LHC-Photon/done: \ $(shell echo Rivet-LHC-{7,8}-PromptPhoton-{1..4}.yoda) \ Rivet-LHC-GammaGamma-7.yoda \ $(shell echo Rivet{,-Powheg}-LHC-{7,8}-{DiPhoton-GammaGamma,DiPhoton-GammaJet}.yoda) rm -rf Rivet-LHC-Photon python/merge-LHC-Photon LHC -o LHC-Photon.yoda python/merge-LHC-Photon LHC-Powheg -o LHC-Powheg-Photon.yoda rivet-mkhtml -o Rivet-LHC-Photon LHC-Photon.yoda:Hw LHC-Powheg-Photon.yoda:Hw-Powheg touch $@ Rivet-LHC-Higgs : Rivet-LHC-Higgs/done touch $@ Rivet-LHC-Higgs/done: \ $(shell echo Rivet{,-Powheg}-LHC-{ggH,VBF,WH,ZH}.yoda) \ $(shell echo Rivet{,-Powheg}-LHC-8-{{ggH,VBF,WH,ZH}{,-GammaGamma},ggH-WW}.yoda) \ Rivet-LHC-ggHJet.yoda rm -rf Rivet-LHC-Higgs rivet-mkhtml -o Rivet-LHC-Higgs LHC-Powheg-ggH.yoda:gg-Powheg LHC-ggH.yoda:gg LHC-ggHJet.yoda:HJet \ LHC-Powheg-VBF.yoda:VBF-Powheg LHC-VBF.yoda:VBF LHC-WH.yoda:WH LHC-ZH.yoda:ZH \ LHC-Powheg-WH.yoda:WH-Powheg LHC-Powheg-ZH.yoda:ZH-Powheg touch $@ clean-local: rm -f *.out *.log *.tex *.top *.run *.dump *.mult *.Bmult *.yoda Rivet/*.in rm -rf Rivet-* distclean-local: rm -rf .cache diff --git a/Tests/Rivet/LHC/LHC-13-Top-All.in b/Tests/Rivet/LHC/LHC-13-Top-All.in --- a/Tests/Rivet/LHC/LHC-13-Top-All.in +++ b/Tests/Rivet/LHC/LHC-13-Top-All.in @@ -1,3 +1,4 @@ ################################################## # select the analyses -################################################## \ No newline at end of file +################################################## +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2018_I1646686 \ No newline at end of file diff --git a/Tests/Rivet/LHC/LHC-13-Top-SL.in b/Tests/Rivet/LHC/LHC-13-Top-SL.in --- a/Tests/Rivet/LHC/LHC-13-Top-SL.in +++ b/Tests/Rivet/LHC/LHC-13-Top-SL.in @@ -1,4 +1,7 @@ ################################################## # select the analyses ################################################## -insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1491950 \ No newline at end of file +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1491950 +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1614149 +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2018_I1662081 +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2018_I1663958 diff --git a/Tests/Rivet/LHC/LHC-13-Z-mu.in b/Tests/Rivet/LHC/LHC-13-Z-mu.in --- a/Tests/Rivet/LHC/LHC-13-Z-mu.in +++ b/Tests/Rivet/LHC/LHC-13-Z-mu.in @@ -1,5 +1,7 @@ ################################################## # select the analyses ################################################## # ATLAS Z insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_CONF_2015_041_MU +# CMS Z UE +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2017_I1635889 \ No newline at end of file diff --git a/Tests/Rivet/LHC/LHC-7-Jets-1.in b/Tests/Rivet/LHC/LHC-7-Jets-1.in --- a/Tests/Rivet/LHC/LHC-7-Jets-1.in +++ b/Tests/Rivet/LHC/LHC-7-Jets-1.in @@ -1,34 +1,36 @@ ################################################## # select the analyses ################################################## # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8924791 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # ATLAS dijet with veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9126244 # CMS jet cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9086218 # CMS 3/2 jet cross section ratio insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9088458 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # CMS UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9120041 # CMS central and forward jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342 # strange particles in underlying event insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_PAS_QCD_11_010 # ATLAS charged particle in min bias insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1125575 # CMS 4-jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1273574 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082009 # CMS Jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1208923 # ATLAS Jet frag insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I929691 +# CMS shapes etc +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1111014 diff --git a/Tests/Rivet/LHC/LHC-7-Jets-10.in b/Tests/Rivet/LHC/LHC-7-Jets-10.in --- a/Tests/Rivet/LHC/LHC-7-Jets-10.in +++ b/Tests/Rivet/LHC/LHC-7-Jets-10.in @@ -1,38 +1,41 @@ ################################################## # select the analyses ################################################## # ATLAS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8971293 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # ATLAS dijet with veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9126244 # CMS jet cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9086218 # CMS 3/2 jet cross section ratio insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9088458 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # CMS central and forward jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342 # ATLAS subjets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1094564 # CMS jet structure insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1224539_DIJET # CMS 4-jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1273574 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # ATLAS jet veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1307243 # ATLAS inclusive jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1325553 # CMS jet ratios insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1298810 # flavour composition of jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1188891 # CMS Jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1208923 # ATLAS Jet frag insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I929691 +# CMS shapes etc +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1111014 + diff --git a/Tests/Rivet/LHC/LHC-7-Jets-2.in b/Tests/Rivet/LHC/LHC-7-Jets-2.in --- a/Tests/Rivet/LHC/LHC-7-Jets-2.in +++ b/Tests/Rivet/LHC/LHC-7-Jets-2.in @@ -1,43 +1,45 @@ ################################################## # select the analyses ################################################## # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8924791 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # ATLAS dijet with veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9126244 # CMS jet cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9086218 # CMS 3/2 jet cross section ratio insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9088458 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # CMS UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9120041 # CMS central and forward jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342 # CMS dijets with large rapidity intervals insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1102908 # strange particles in underlying event insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_PAS_QCD_11_010 # ATLAS charged particle in min bias insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1125575 # CMS 4-jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1273574 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # ATLAS jet veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1307243 # CMS jet ratios insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1298810 # flavour composition of jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1188891 # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082009 # CMS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1208923 # ATLAS Jet frag insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I929691 +# CMS shapes etc +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1111014 diff --git a/Tests/Rivet/LHC/LHC-7-Jets-3.in b/Tests/Rivet/LHC/LHC-7-Jets-3.in --- a/Tests/Rivet/LHC/LHC-7-Jets-3.in +++ b/Tests/Rivet/LHC/LHC-7-Jets-3.in @@ -1,49 +1,51 @@ ################################################## # select the analyses ################################################## # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8924791 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # CMS event shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8957746 # ATLAS dijet with veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9126244 # CMS dijet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8950903 # CMS jet cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9086218 # CMS 3/2 jet cross section ratio insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9088458 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # CMS UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9120041 # CMS central and forward jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342 # strange particles in underlying event insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_PAS_QCD_11_010 # ATLAS charged particle in min bias insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1125575 # CMS 4-jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1273574 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # ATLAS jet veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1307243 # ATLAS inclusive jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1325553 # CMS jet ratios insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1298810 # flavour composition of jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1188891 # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082009 # CMS Jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1208923 # atlas double parton insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1479760 # ATLAS Jet frag insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I929691 +# CMS shapes etc +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1111014 diff --git a/Tests/Rivet/LHC/LHC-7-Jets-4.in b/Tests/Rivet/LHC/LHC-7-Jets-4.in --- a/Tests/Rivet/LHC/LHC-7-Jets-4.in +++ b/Tests/Rivet/LHC/LHC-7-Jets-4.in @@ -1,50 +1,52 @@ ################################################## # select the analyses ################################################## # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8924791 # ATLAS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8971293 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # CMS event shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8957746 # ATLAS multijet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9128077 # ATLAS dijet with veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9126244 # CMS dijet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8950903 # CMS jet cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9086218 # CMS 3/2 jet cross section ratio insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9088458 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # CMS UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9120041 # CMS central and forward jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342 # ATLAS subjets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1094564 # CMS 4-jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1273574 # CMS colour coherence insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1265659 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # ATLAS jet veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1307243 # ATLAS inclusive jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1325553 # CMS jet ratios insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1298810 # flavour composition of jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1188891 # CMS Jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1208923 # CMS event shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1305624 # ATLAS Jet frag insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I929691 +# CMS shapes etc +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1111014 diff --git a/Tests/Rivet/LHC/LHC-7-Jets-5.in b/Tests/Rivet/LHC/LHC-7-Jets-5.in --- a/Tests/Rivet/LHC/LHC-7-Jets-5.in +++ b/Tests/Rivet/LHC/LHC-7-Jets-5.in @@ -1,45 +1,47 @@ ################################################## # select the analyses ################################################## # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8924791 # ATLAS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8971293 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # CMS event shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8957746 # ATLAS dijet with veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9126244 # CMS dijet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8950903 # CMS jet cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9086218 # CMS 3/2 jet cross section ratio insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9088458 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # ATLAS subjets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1094564 # CMS jet structure insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1224539_DIJET # CMS 4-jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1273574 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # ATLAS jet veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1307243 # ATLAS inclusive jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1325553 # CMS jet ratios insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1298810 # flavour composition of jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1188891 # CMS Jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1208923 # CMS event shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1305624 # ATLAS Jet frag insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I929691 +# CMS shapes etc +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1111014 diff --git a/Tests/Rivet/LHC/LHC-7-Jets-6.in b/Tests/Rivet/LHC/LHC-7-Jets-6.in --- a/Tests/Rivet/LHC/LHC-7-Jets-6.in +++ b/Tests/Rivet/LHC/LHC-7-Jets-6.in @@ -1,49 +1,51 @@ ################################################## # select the analyses ################################################## # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8924791 # ATLAS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8971293 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # ATLAS dijet with veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9126244 # CMS dijet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8950903 # CMS jet cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9086218 # CMS 3/2 jet cross section ratio insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9088458 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # CMS central and forward jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342 # ATLAS high pT jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1119557 # ATLAS subjets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1094564 # CMS jet structure insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1224539_DIJET # CMS 4-jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1273574 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # ATLAS jet veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1307243 # ATLAS inclusive jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1325553 # CMS jet ratios insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1298810 # flavour composition of jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1188891 # ATLAS Jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1387176 # CMS Jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1208923 # CMS event shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1305624 # ATLAS Jet frag insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I929691 +# CMS shapes etc +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1111014 diff --git a/Tests/Rivet/LHC/LHC-7-Jets-7.in b/Tests/Rivet/LHC/LHC-7-Jets-7.in --- a/Tests/Rivet/LHC/LHC-7-Jets-7.in +++ b/Tests/Rivet/LHC/LHC-7-Jets-7.in @@ -1,43 +1,45 @@ ################################################## # select the analyses ################################################## # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8924791 # ATLAS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8971293 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # ATLAS dijet with veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9126244 # CMS jet cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9086218 # CMS 3/2 jet cross section ratio insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9088458 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # CMS central and forward jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342 # ATLAS subjets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1094564 # CMS jet structure insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1224539_DIJET # CMS 4-jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1273574 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # ATLAS jet veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1307243 # ATLAS inclusive jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1325553 # CMS jet ratios insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1298810 # flavour composition of jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1188891 # CMS Jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1208923 # CMS event shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1305624 # ATLAS Jet frag insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I929691 +# CMS shapes etc +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1111014 diff --git a/Tests/Rivet/LHC/LHC-7-Jets-8.in b/Tests/Rivet/LHC/LHC-7-Jets-8.in --- a/Tests/Rivet/LHC/LHC-7-Jets-8.in +++ b/Tests/Rivet/LHC/LHC-7-Jets-8.in @@ -1,39 +1,40 @@ ################################################## # select the analyses ################################################## # ATLAS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8971293 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # ATLAS dijet with veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9126244 # CMS jet cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9086218 # CMS 3/2 jet cross section ratio insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9088458 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # CMS central and forward jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342 # ATLAS subjets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1094564 # CMS jet structure insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1224539_DIJET # CMS 4-jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1273574 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # ATLAS jet veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1307243 # ATLAS inclusive jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1325553 # CMS jet ratios insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1298810 # flavour composition of jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1188891 # CMS Jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1208923 # ATLAS Jet frag insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I929691 - +# CMS shapes etc +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1111014 diff --git a/Tests/Rivet/LHC/LHC-7-Jets-9.in b/Tests/Rivet/LHC/LHC-7-Jets-9.in --- a/Tests/Rivet/LHC/LHC-7-Jets-9.in +++ b/Tests/Rivet/LHC/LHC-7-Jets-9.in @@ -1,39 +1,44 @@ ################################################## # select the analyses ################################################## # ATLAS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8971293 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # ATLAS dijet with veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S9126244 # CMS jet cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9086218 # CMS 3/2 jet cross section ratio insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9088458 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # CMS central and forward jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342 # ATLAS subjets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1094564 # CMS jet structure insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1224539_DIJET # CMS 4-jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1273574 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # ATLAS jet veto insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1307243 # ATLAS inclusive jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1325553 # CMS jet ratios insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2014_I1298810 # flavour composition of jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1188891 # CMS Jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1208923 # ATLAS Jet frag insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I929691 +# CMS shapes etc +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1111014 + + + diff --git a/Tests/Rivet/LHC/LHC-7-UE.in b/Tests/Rivet/LHC/LHC-7-UE.in --- a/Tests/Rivet/LHC/LHC-7-UE.in +++ b/Tests/Rivet/LHC/LHC-7-UE.in @@ -1,90 +1,95 @@ ################################################## # select the analyses ################################################## # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8924791 # ATLAS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8817804 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1082936 # ATLAS UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_S8994773 # ATLAS UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8894728 # ATLAS fragmentation function insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_CONF_2010_049 # ATLAS UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2010_S8918562 # ALICE charged particles insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2010_S8625980 # CMS particle spectra insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8978280 # CMS charged particle multiplicity insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S8884919 # CMS charged particle pT and rapidity insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2010_S8656010 # CMS UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9120041 # ATLAS track jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I919017 # LHCB phi production insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2011_I919315 # ATLAS phi production insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1282441 # LHCB promt hadron productiom insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2012_I1119400 # ATLAS rap gap insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1084540 # CMS forward energy flow insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2011_S9215166 # LHC K0s/Lambda insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2011_I917009 # TOTEM at large rapidity insert /Herwig/Analysis/RivetAnalysis:Analyses 0 TOTEM_2012_I1115294 # ATLAS Azimuthal ordering of charged hadrons insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1091481 # ALICE single/double diffractive and inelastic sigma insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2012_I1181770 # ATLAS inelastic cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2011_I894867 # CMS inelastic cross section insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1193338 # total transverse energy insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1183818 # underlying event forward rapidities insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1218372 # strange particles in underlying event insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_PAS_QCD_11_010 # CMS central and forward jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1087342 # CMS dijet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2012_I1184941 # ATLAS charged particle in min bias insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1125575 # ATLAS two particle correlation #insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1094061 # ATLAS correlations insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1093734 # LHCB energy flow insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2013_I1208105 # ATLAS charged particle event shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2012_I1124167 # CMS Jet/UE properties insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2013_I1261026 # ATLAS leading jet UE insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1298811 # LHCB charged particles in min bias insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2014_I1281685 # ALICE identified particle spectra insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2015_I1357424 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2014_I1300380 # LHCB min bias insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCB_2015_I1333223 # ALICE pion and eta pT insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2012_I1116147 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_PAS_FSQ_12_020 # CMS charged particle rapidity insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_QCD_10_024 # diffractive analyses insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCF_2012_I1115479 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2015_I1356998 -insert /Herwig/Analysis/RivetAnalysis:Analyses 0 TOTEM_2012_I1220862 \ No newline at end of file +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 TOTEM_2012_I1220862 +# atlas hadron ordering +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1624693 +# LHCF +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCF_2015_I1351909 +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 LHCF_2016_I1385877 \ No newline at end of file diff --git a/Tests/Rivet/LHC/LHC-8-Jets-10.in b/Tests/Rivet/LHC/LHC-8-Jets-10.in --- a/Tests/Rivet/LHC/LHC-8-Jets-10.in +++ b/Tests/Rivet/LHC/LHC-8-Jets-10.in @@ -1,12 +1,14 @@ # ATLAS tracks in jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070 # ATLAS multijet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679 # ATLAS jet charge insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758 # ATLAS transverse energy correlations insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253 # CMS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1487277 # CMS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1421646 +# CMS jet charge +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2017_I1605749 diff --git a/Tests/Rivet/LHC/LHC-8-Jets-7.in b/Tests/Rivet/LHC/LHC-8-Jets-7.in --- a/Tests/Rivet/LHC/LHC-8-Jets-7.in +++ b/Tests/Rivet/LHC/LHC-8-Jets-7.in @@ -1,14 +1,16 @@ # ATLAS tracks in jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070 # ATLAS multijet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679 # ATLAS jet charge insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758 # ATLAS transverse energy correlations insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253 # CMS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1487277 # CMS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1421646 +# CMS jet charge +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2017_I1605749 diff --git a/Tests/Rivet/LHC/LHC-8-Jets-8.in b/Tests/Rivet/LHC/LHC-8-Jets-8.in --- a/Tests/Rivet/LHC/LHC-8-Jets-8.in +++ b/Tests/Rivet/LHC/LHC-8-Jets-8.in @@ -1,12 +1,14 @@ # ATLAS tracks in jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070 # ATLAS multijet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679 # ATLAS jet charge insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758 # ATLAS transverse energy correlations insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253 # CMS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1487277 # CMS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1421646 +# CMS jet charge +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2017_I1605749 diff --git a/Tests/Rivet/LHC/LHC-8-Jets-9.in b/Tests/Rivet/LHC/LHC-8-Jets-9.in --- a/Tests/Rivet/LHC/LHC-8-Jets-9.in +++ b/Tests/Rivet/LHC/LHC-8-Jets-9.in @@ -1,14 +1,16 @@ # ATLAS tracks in jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1419070 # ATLAS multijet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1394679 # ATLAS jet charge insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1393758 # ATLAS transverse energy correlations insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1609253 # CMS jets insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1487277 # CMS di-jet decorrelation insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1421646 +# CMS jet charge +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2017_I1605749 diff --git a/Tests/Rivet/LHC/LHC-8-Top-SL.in b/Tests/Rivet/LHC/LHC-8-Top-SL.in --- a/Tests/Rivet/LHC/LHC-8-Top-SL.in +++ b/Tests/Rivet/LHC/LHC-8-Top-SL.in @@ -1,15 +1,16 @@ ################################################## # select the analyses ################################################## # ATLAS pull in top events insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1376945 # ATLAS top + b jet insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1390114 # ATLAS boosted t tbar insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1397637 # cms boosted top insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1454211 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2017_I1518399 -insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_PAS_TOP_15_006 +# this cms ones has iffy lepton code which crashes +#insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_PAS_TOP_15_006 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1404878 insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2016_I1473674 \ No newline at end of file diff --git a/Tests/Rivet/LHC/LHC-8-UE.in b/Tests/Rivet/LHC/LHC-8-UE.in --- a/Tests/Rivet/LHC/LHC-8-UE.in +++ b/Tests/Rivet/LHC/LHC-8-UE.in @@ -1,11 +1,13 @@ ################################################## # select the analyses ################################################## # ATLAS jet shapes insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMSTOTEM_2014_I1294140 # tack bassed min bias insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1426695 # diffraction insert /Herwig/Analysis/RivetAnalysis:Analyses 0 TOTEM_2014_I1328627 # charge particle and charged particle jets -insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2015_I1380605 \ No newline at end of file +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2015_I1380605 +# ALICE neutral pions +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ALICE_2017_I1620477 \ No newline at end of file diff --git a/Tests/Rivet/LHC/LHC-8-Z-Mass3-e.in b/Tests/Rivet/LHC/LHC-8-Z-Mass3-e.in --- a/Tests/Rivet/LHC/LHC-8-Z-Mass3-e.in +++ b/Tests/Rivet/LHC/LHC-8-Z-Mass3-e.in @@ -1,9 +1,11 @@ ################################################## # select the analyses ################################################## # ATLAS Z pT and phi* insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2015_I1408516_EL # ATLAS high mass drell-yan insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2016_I1467454_EL # ATLAS splittings -insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1589844_EL \ No newline at end of file +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2017_I1589844_EL +# CMS Z+b +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2017_I1499471 \ No newline at end of file diff --git a/Tests/Rivet/LHC/LHC-Z-b.in b/Tests/Rivet/LHC/LHC-8-Z-b.in copy from Tests/Rivet/LHC/LHC-Z-b.in copy to Tests/Rivet/LHC/LHC-8-Z-b.in --- a/Tests/Rivet/LHC/LHC-Z-b.in +++ b/Tests/Rivet/LHC/LHC-8-Z-b.in @@ -1,4 +1,4 @@ ################################################## # select the analyses ################################################## -insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1306294 +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2017_I1499471 diff --git a/Tests/Rivet/LHC/LHC-Z-bb.in b/Tests/Rivet/LHC/LHC-8-Z-bb.in copy from Tests/Rivet/LHC/LHC-Z-bb.in copy to Tests/Rivet/LHC/LHC-8-Z-bb.in --- a/Tests/Rivet/LHC/LHC-Z-bb.in +++ b/Tests/Rivet/LHC/LHC-8-Z-bb.in @@ -1,4 +1,4 @@ ################################################## # select the analyses ################################################## -insert /Herwig/Analysis/RivetAnalysis:Analyses 0 ATLAS_2014_I1306294 +insert /Herwig/Analysis/RivetAnalysis:Analyses 0 CMS_2017_I1499471 diff --git a/Tests/Rivet/Templates/DIS-Powheg.in b/Tests/Rivet/Templates/DIS-Powheg.in --- a/Tests/Rivet/Templates/DIS-Powheg.in +++ b/Tests/Rivet/Templates/DIS-Powheg.in @@ -1,49 +1,48 @@ # -*- ThePEG-repository -*- # # DO NOT EDIT - autogenerated by make_input_files.py # ################################################## # Example generator based on DIS parameters # usage: Herwig read DIS.in ################################################## read snippets/EPCollider.in -read Matchbox/Powheg-Default-ShowerAlphaSTune.in set /Herwig/Particles/e-:PDF /Herwig/Partons/NoPDF set /Herwig/Particles/e+:PDF /Herwig/Partons/NoPDF ################################################## # Need to use an NLO PDF ################################################## set /Herwig/Particles/p+:PDF /Herwig/Partons/HardNLOPDF set /Herwig/Particles/pbar-:PDF /Herwig/Partons/HardNLOPDF set /Herwig/Shower/ShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF set /Herwig/Partons/MPIExtractor:SecondPDF /Herwig/Partons/MPIPDF set /Herwig/Partons/EPExtractor:SecondPDF /Herwig/Partons/HardNLOPDF ################################################## # Setup the POWHEG shower ################################################## cd /Herwig/Shower set ShowerHandler:IntrinsicPtGaussian 1.9*GeV set ShowerHandler:HardEmission POWHEG cd /Herwig/MatrixElements/ # Neutral current DIS insert SubProcess:MatrixElements[0] /Herwig/MatrixElements/PowhegMEDISNC ${process} cd /Herwig/Generators set EventGenerator:MaxErrors 1000000 set /Herwig/Shower/ShowerHandler:MPIHandler NULL cd /Herwig/Generators create ThePEG::RivetAnalysis /Herwig/Analysis/RivetAnalysis RivetAnalysis.so insert EventGenerator:AnalysisHandlers 0 /Herwig/Analysis/RivetAnalysis read ${parameterFile} ################################################## # Save run for later usage with 'Herwig run' ################################################## cd /Herwig/Generators saverun ${runname} EventGenerator diff --git a/Tests/Rivet/Templates/Hadron-Powheg.in b/Tests/Rivet/Templates/Hadron-Powheg.in --- a/Tests/Rivet/Templates/Hadron-Powheg.in +++ b/Tests/Rivet/Templates/Hadron-Powheg.in @@ -1,50 +1,49 @@ # -*- ThePEG-repository -*- # # DO NOT EDIT - autogenerated by make_input_files.py # ################################################## # Technical parameters for this run ################################################## read snippets/PPCollider.in cd /Herwig/Generators set EventGenerator:MaxErrors 1000000 set /Herwig/Decays/DecayHandler:MaxLifeTime 10*mm ################################################## # Need to use an NLO PDF ################################################## set /Herwig/Particles/p+:PDF /Herwig/Partons/HardNLOPDF set /Herwig/Particles/pbar-:PDF /Herwig/Partons/HardNLOPDF set /Herwig/Shower/ShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF set /Herwig/Shower/ShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF set /Herwig/Partons/MPIExtractor:FirstPDF /Herwig/Partons/MPIPDF set /Herwig/Partons/MPIExtractor:SecondPDF /Herwig/Partons/MPIPDF set /Herwig/Partons/PPExtractor:FirstPDF /Herwig/Partons/HardNLOPDF set /Herwig/Partons/PPExtractor:SecondPDF /Herwig/Partons/HardNLOPDF ################################################## # Setup the POWHEG shower ################################################## cd /Herwig/Shower set ShowerHandler:IntrinsicPtGaussian 1.9*GeV set ShowerHandler:HardEmission POWHEG -read Matchbox/Powheg-Default-ShowerAlphaSTune.in ################################################## # Create the Herwig analysis ################################################## cd /Herwig/Generators create ThePEG::RivetAnalysis /Herwig/Analysis/RivetAnalysis RivetAnalysis.so insert EventGenerator:AnalysisHandlers 0 /Herwig/Analysis/RivetAnalysis cd /Herwig/MatrixElements ${process} cd /Herwig/Generators read ${parameterFile} ################################################## # Save run for later usage with 'Herwig run' ################################################## cd /Herwig/Generators saverun ${runname} EventGenerator diff --git a/Tests/Rivet/Templates/LEP-Powheg.in b/Tests/Rivet/Templates/LEP-Powheg.in --- a/Tests/Rivet/Templates/LEP-Powheg.in +++ b/Tests/Rivet/Templates/LEP-Powheg.in @@ -1,41 +1,40 @@ # -*- ThePEG-repository -*- # # DO NOT EDIT - autogenerated by make_input_files.py # ################################################## # base parameters for LEP analyses ################################################## read snippets/EECollider.in ################################################## # Technical parameters for this run ################################################## cd /Herwig/Generators -read Matchbox/Powheg-Default-ShowerAlphaSTune.in set EventGenerator:MaxErrors 1000000 ################################################## # Switch off ISR ################################################## set /Herwig/Particles/e-:PDF /Herwig/Partons/NoPDF set /Herwig/Particles/e+:PDF /Herwig/Partons/NoPDF ################################################## # Create the Herwig analysis ################################################## create ThePEG::RivetAnalysis /Herwig/Analysis/RivetAnalysis RivetAnalysis.so insert EventGenerator:AnalysisHandlers 0 /Herwig/Analysis/RivetAnalysis ################################################## # Use the NLO q qbar matrix element ################################################## set /Herwig/Shower/ShowerHandler:HardEmission POWHEG insert /Herwig/MatrixElements/SubProcess:MatrixElements 0 /Herwig/MatrixElements/PowhegMEee2gZ2qq ${process} read ${parameterFile} ################################################## # Save run for later usage with 'Herwig run' ################################################## cd /Herwig/Generators saverun ${runname} EventGenerator diff --git a/Tests/python/make_input_files.py b/Tests/python/make_input_files.py --- a/Tests/python/make_input_files.py +++ b/Tests/python/make_input_files.py @@ -1,1801 +1,1832 @@ #! /usr/bin/env python import logging,sys,os from string import strip, Template import sys if sys.version_info[:3] < (2,4,0): print "rivet scripts require Python version >= 2.4.0... exiting" sys.exit(1) if __name__ == "__main__": import logging from optparse import OptionParser, OptionGroup parser = OptionParser(usage="%prog name [...]") simulation="" numberOfAddedProcesses=0 def addProcess(thefactory,theProcess,Oas,Oew,scale,mergedlegs,NLOprocesses): global numberOfAddedProcesses global simulation numberOfAddedProcesses+=1 res ="set "+thefactory+":OrderInAlphaS "+Oas+"\n" res+="set "+thefactory+":OrderInAlphaEW "+Oew+"\n" res+="do "+thefactory+":Process "+theProcess+" " if ( mergedlegs != 0 ): if simulation!="Merging": print "simulation is not Merging, trying to add merged legs." sys.exit(1) res+="[" for j in range(mergedlegs): res+=" j " res+="]" res+="\n" if (NLOprocesses!=0): if simulation!="Merging": print "simulation is not Merging, trying to add NLOProcesses." sys.exit(1) res+="set MergingFactory:NLOProcesses %s \n" % NLOprocesses if ( scale != "" ): res+="set "+thefactory+":ScaleChoice /Herwig/MatrixElements/Matchbox/Scales/"+scale+"\n" return res def addLeptonPairCut(minmass,maxmass): return "set /Herwig/Cuts/LeptonPairMassCut:MinMass "+minmass+"*GeV\nset /Herwig/Cuts/LeptonPairMassCut:MaxMass "+maxmass+"*GeV\n" didaddfirstjet=False def addFirstJet(ptcut): global didaddfirstjet if(didaddfirstjet): logging.error("Can only add jetcut once.") sys.exit(1) res="set /Herwig/Cuts/Cuts:JetFinder /Herwig/Cuts/JetFinder\n" res+="insert /Herwig/Cuts/Cuts:MultiCuts 0 /Herwig/Cuts/JetCuts\n" res+="insert /Herwig/Cuts/JetCuts:JetRegions 0 /Herwig/Cuts/FirstJet\n" if(ptcut!=""): res+="set /Herwig/Cuts/FirstJet:PtMin "+ptcut+".*GeV\n" didaddfirstjet=True return res didaddsecondjet=False def addSecondJet(ptcut): global didaddsecondjet if(didaddsecondjet): logging.error("Can only add second jetcut once.") sys.exit(1) res="insert /Herwig/Cuts/JetCuts:JetRegions 0 /Herwig/Cuts/SecondJet\n" res+="set /Herwig/Cuts/SecondJet:PtMin "+ptcut+".*GeV\n" didaddsecondjet=True return res didaddjetpair=False def addJetPairCut(minmass): global didaddjetpair if(didaddjetpair): logging.error("Can only add second jetcut once.") sys.exit(1) res="""\ create ThePEG::JetPairRegion /Herwig/Cuts/JetPairMass JetCuts.so set /Herwig/Cuts/JetPairMass:FirstRegion /Herwig/Cuts/FirstJet set /Herwig/Cuts/JetPairMass:SecondRegion /Herwig/Cuts/SecondJet insert /Herwig/Cuts/JetCuts:JetPairRegions 0 /Herwig/Cuts/JetPairMass set /Herwig/Cuts/JetPairMass:MassMin {mm}.*GeV """.format(mm=minmass) didaddjetpair=True return res addedBRReweighter=False def addBRReweighter(): global addedBRReweighter if(addedBRReweighter): logging.error("Can only add BRReweighter once.") sys.exit(1) res="create Herwig::BranchingRatioReweighter /Herwig/Generators/BRReweighter\n" res+="insert /Herwig/Generators/EventGenerator:EventHandler:PostHadronizationHandlers 0 /Herwig/Generators/BRReweighter\n" addedBRReweighter=True return res def setHardProcessWidthToZero(list1): res="" for i in list1: res+="set /Herwig/Particles/"+i+":HardProcessWidth 0.\n" return res selecteddecaymode=False def selectDecayMode(particle,decaymodes): global selecteddecaymode res="do /Herwig/Particles/"+particle+":SelectDecayModes" for decay in decaymodes: res+=" /Herwig/Particles/"+particle+"/"+decay res+="\n" selecteddecaymode=True return res def jet_kt_cut(energy): return "set /Herwig/Cuts/JetKtCut:MinKT {E}*GeV\n".format(E=energy) def mhatmin_cut(energy): return "set /Herwig/Cuts/Cuts:MHatMin {E}*GeV\n".format(E=energy) def mhat_minm_maxm(e1,e2,e3): return """\ set /Herwig/Cuts/Cuts:MHatMin {e1}*GeV set /Herwig/Cuts/MassCut:MinM {e2}*GeV set /Herwig/Cuts/MassCut:MaxM {e3}*GeV """.format(**locals()) def collider_lumi(energy): return "set /Herwig/Generators/EventGenerator:EventHandler:LuminosityFunction:Energy {E}*GeV\n".format(E=energy) def insert_ME(me,process=None,ifname='Process'): result = "insert /Herwig/MatrixElements/SubProcess:MatrixElements 0 /Herwig/MatrixElements/{me}\n".format(**locals()) if process is not None: result += "set /Herwig/MatrixElements/{me}:{ifname} {process}".format(**locals()) return result def particlegroup(name,*particles): result = ["do /Herwig/MatrixElements/Matchbox/Factory:StartParticleGroup {n}".format(n=name)] for p in particles: result.append( "insert /Herwig/MatrixElements/Matchbox/Factory:ParticleGroup 0 /Herwig/Particles/{p}".format(p=p) ) result.append("do /Herwig/MatrixElements/Matchbox/Factory:EndParticleGroup") return '\n'.join(result) # settings for four flavour scheme fourFlavour=""" read Matchbox/FourFlavourScheme.in {bjetgroup} set /Herwig/Cuts/MatchboxJetMatcher:Group bjet """.format(bjetgroup=particlegroup('bjet','b','bbar','c', 'cbar', 's','sbar','d','dbar','u','ubar','g')) ME_Upsilon = """\ create Herwig::MEee2VectorMeson /Herwig/MatrixElements/MEUpsilon HwMELepton.so set /Herwig/MatrixElements/MEUpsilon:VectorMeson /Herwig/Particles/Upsilon(4S) set /Herwig/MatrixElements/MEUpsilon:Coupling 0.0004151809 """ + insert_ME("MEUpsilon") (opts, args) = parser.parse_args() ## Check args if len(args) != 1: logging.error("Must specify at least input file") sys.exit(1) name = args[0] print name # select the template to load # collider KNOWN_COLLIDERS = [ "BFactory", "LEP", "DIS", "TVT", "LHC-GammaGamma", "LHC", "ISR", "SppS", "Star", ] collider = "" for cand_collider in KNOWN_COLLIDERS: if cand_collider in name: collider = cand_collider break del cand_collider assert collider have_hadronic_collider = collider in ["TVT","LHC","ISR","SppS","Star"] thefactory="Factory" parameters = { 'shower' : '', 'bscheme' : '', } # istart determines how many name parts need to be skipped istart = 1 # Dipole shower with Matchbox Powheg if "Dipole-Matchbox-Powheg" in name : istart = 4 simulation="Matchbox" parameters["shower"] = "read Matchbox/Powheg-DipoleShower.in\n" # Dipole shower with internal Powheg - Todo: Finish modifying template files. ''' elif "Dipole-Powheg" in name : istart = 3 simulation="Powheg" parameters["shower"] = "set /Herwig/EventHandlers/EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler\nread snippets/Dipole_AutoTune_prel.in\n" ''' # Dipole shower with MCatNLO elif "Dipole-MCatNLO" in name : istart = 3 simulation="Matchbox" parameters["shower"] = "read Matchbox/MCatNLO-DipoleShower.in\n" # Dipole shower with Matchbox LO elif "Dipole-Matchbox-LO" in name : istart = 4 simulation="Matchbox" parameters["shower"] = "read Matchbox/LO-DipoleShower.in\n" # Dipole shower with internal LO elif "Dipole" in name : istart = 2 simulation="" parameters["shower"] = "set /Herwig/EventHandlers/EventHandler:CascadeHandler /Herwig/DipoleShower/DipoleShowerHandler\nread snippets/Dipole_AutoTune_prel.in\n" # AO shower with Matchbox Powheg elif "Matchbox-Powheg" in name : istart = 3 simulation="Matchbox" parameters["shower"] = "read Matchbox/Powheg-DefaultShower.in\n" # AO shower with MCatNLO elif "Matchbox" in name : istart = 2 simulation="Matchbox" parameters["shower"] = "read Matchbox/MCatNLO-DefaultShower.in\n" # AO shower with inernal Powheg elif "Powheg" in name : istart = 2 simulation="Powheg" # Dipole shower with merging elif "Merging" in name : istart = 2 simulation="Merging" thefactory="MergingFactory" # Flavour settings for Matchbox if simulation=="Matchbox" : parameters["bscheme"] = "read Matchbox/FiveFlavourScheme.in\n" if "Dipole" in parameters["shower"] : parameters["bscheme"] += "read Matchbox/FiveFlavourNoBMassScheme.in\n" if collider not in ['DIS','LEP'] : parameters["nlo"] = "read Matchbox/MadGraph-OpenLoops.in\n" # Flavour settings for dipole shower with internal ME if simulation=="" and "Dipole" in parameters["shower"] : parameters["bscheme"] = "read snippets/DipoleShowerFiveFlavours.in" # find the template if simulation=="" : if collider=="LHC-GammaGamma" : istart += 1 templateName="Hadron-Gamma.in" elif have_hadronic_collider : templateName="Hadron.in" elif collider != "BFactory" : templateName= "%s.in" % collider else : templateName= "LEP.in" else : if have_hadronic_collider : templateName= "Hadron-%s.in" % simulation elif collider != "BFactory" : templateName= "%s-%s.in" % (collider,simulation) else : templateName= "LEP-%s.in" % simulation # work out the name of the parameter file parameterName="-".join(name.split("-")[istart:]) del istart class StringBuilder(object): """ Avoid expensive string additions until the end by building up a list first. This helper class avoids rewriting all the += lower down to list operations. """ def __init__(self, init = None): self.lines = [] if init is None else [init] def __iadd__(self, line): self.lines.append(line) return self def __str__(self): return '\n'.join(self.lines) # work out the process and parameters process=StringBuilder() # Bfactory if(collider=="BFactory") : if(simulation=="") : if(parameterName=="10.58-res") : process += ME_Upsilon elif(parameterName=="10.58") : process += ME_Upsilon process += "set /Herwig/MatrixElements/MEee2gZ2qq:MaximumFlavour 4\n" else : process+=insert_ME("MEee2gZ2qq") process+= "set /Herwig/MatrixElements/MEee2gZ2qq:MaximumFlavour 4\n" elif(simulation=="Powheg") : process = StringBuilder("set /Herwig/MatrixElements/PowhegMEee2gZ2qq:MaximumFlavour 4\n") elif(simulation=="Matchbox" ) : process = StringBuilder(addProcess(thefactory,"e- e+ -> u ubar","0","2","",0,0)) process+=addProcess(thefactory,"e- e+ -> d dbar","0","2","",0,0) process+=addProcess(thefactory,"e- e+ -> c cbar","0","2","",0,0) process+=addProcess(thefactory,"e- e+ -> s sbar","0","2","",0,0) elif(simulation=="Merging" ) : logging.warning("BFactory not explicitly tested for %s " % simulation) sys.exit(0) # DIS elif(collider=="DIS") : if(simulation=="") : if "NoME" in parameterName : process = StringBuilder("set /Herwig/Shower/ShowerHandler:HardEmission None") parameterName=parameterName.replace("NoME-","") else : process = StringBuilder("") elif(simulation=="Powheg") : process = StringBuilder("") elif(simulation=="Matchbox" ) : if "e-" in parameterName : process = StringBuilder(addProcess(thefactory,"e- p -> e- j","0","2","",0,0)) else : process = StringBuilder(addProcess(thefactory,"e+ p -> e+ j","0","2","",0,0)) elif(simulation=="Merging" ) : if "e-" in parameterName : process = StringBuilder(addProcess(thefactory,"e- p -> e- j","0","2","",2,2)) else : process = StringBuilder(addProcess(thefactory,"e+ p -> e+ j","0","2","",2,2)) # LEP elif(collider=="LEP") : if(simulation=="") : if "gg" in parameterName : process = StringBuilder("create Herwig::MEee2Higgs2SM /Herwig/MatrixElements/MEee2Higgs2SM\n") process+=insert_ME("MEee2Higgs2SM","Gluon","Allowed") else : process = StringBuilder(insert_ME("MEee2gZ2qq")) if(parameterName=="10") : process+="set /Herwig/MatrixElements/MEee2gZ2qq:MaximumFlavour 4" elif(simulation=="Powheg") : process = StringBuilder() if(parameterName=="10") : process = StringBuilder("set /Herwig/MatrixElements/PowhegMEee2gZ2qq:MaximumFlavour 4") elif(simulation=="Matchbox" ) : if(parameterName=="10") : process = StringBuilder(addProcess(thefactory,"e- e+ -> u ubar","0","2","",0,0)) process+=addProcess(thefactory,"e- e+ -> d dbar","0","2","",0,0) process+=addProcess(thefactory,"e- e+ -> c cbar","0","2","",0,0) process+=addProcess(thefactory,"e- e+ -> s sbar","0","2","",0,0) else : process = StringBuilder(addProcess(thefactory,"e- e+ -> j j","0","2","",0,0)) elif(simulation=="Merging" ) : if(parameterName=="10") : process = StringBuilder(addProcess(thefactory,"e- e+ -> j j","0","2","",2,2)) process+="read Matchbox/FourFlavourScheme.in" else : process = StringBuilder(addProcess(thefactory,"e- e+ -> j j","0","2","",2,2)) # TVT elif(collider=="TVT") : process = StringBuilder("set /Herwig/Generators/EventGenerator:EventHandler:BeamB /Herwig/Particles/pbar-\n") if "Run-II" in parameterName : process+=collider_lumi(1960.0) elif "Run-I" in parameterName : process+=collider_lumi(1800.0) elif "900" in parameterName : process+=collider_lumi(900.0) elif "630" in parameterName : process+=collider_lumi(630.0) elif "300" in parameterName : process+=collider_lumi(300.0) if(simulation=="") : if "PromptPhoton" in parameterName : process+=insert_ME("MEGammaJet") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 15.\n" elif "DiPhoton-GammaGamma" in parameterName : process+=insert_ME("MEGammaGamma") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" parameterName=parameterName.replace("-GammaGamma","") elif "DiPhoton-GammaJet" in parameterName : process+=insert_ME("MEGammaJet") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" parameterName=parameterName.replace("-GammaJet","") elif "UE" in parameterName : if "Dipole" in parameters["shower"]: process+="read snippets/MB-DipoleShower.in\n" else: process+="read snippets/MB.in\n" process+="read snippets/Diffraction.in\n" process += "set /Herwig/Decays/DecayHandler:LifeTimeOption 0\n" process += "set /Herwig/Decays/DecayHandler:MaxLifeTime 10*mm\n" elif "Jets" in parameterName : process+=insert_ME("MEQCD2to2") process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "Run-II-Jets-10" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(500.) elif "Run-II-Jets-11" in parameterName: process+=jet_kt_cut( 30.)+mhatmin_cut(900.) elif "Run-I-Jets-1" in parameterName : process+=jet_kt_cut( 20.) elif "Run-I-Jets-2" in parameterName : process+=jet_kt_cut( 40.) elif "Run-I-Jets-3" in parameterName : process+=jet_kt_cut( 65.) elif "Run-I-Jets-4" in parameterName : process+=jet_kt_cut( 90.) elif "Run-I-Jets-5" in parameterName : process+=jet_kt_cut(160.) elif "Run-I-Jets-6" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(100.) elif "Run-I-Jets-7" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(400.) elif "Run-I-Jets-8" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(700.) elif "Run-II-Jets-0" in parameterName : process+=jet_kt_cut( 15.) elif "Run-II-Jets-1" in parameterName : process+=jet_kt_cut( 25.) elif "Run-II-Jets-2" in parameterName : process+=jet_kt_cut( 40.) elif "Run-II-Jets-3" in parameterName : process+=jet_kt_cut( 60.) elif "Run-II-Jets-4" in parameterName : process+=jet_kt_cut( 85.) elif "Run-II-Jets-5" in parameterName : process+=jet_kt_cut(110.) elif "Run-II-Jets-6" in parameterName : process+=jet_kt_cut(160.) elif "Run-II-Jets-7" in parameterName : process+=jet_kt_cut(250.) elif "Run-II-Jets-8" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(100.) elif "Run-II-Jets-9" in parameterName : process+=jet_kt_cut( 30.)+mhatmin_cut(300.) elif "900-Jets-1" in parameterName : process+=jet_kt_cut( 10.) elif "300-Jets-1" in parameterName : process+=jet_kt_cut( 6.) elif "630-Jets-1" in parameterName : process+=jet_kt_cut( 20.) elif "630-Jets-2" in parameterName : process+=jet_kt_cut( 40.) elif "630-Jets-3" in parameterName : process+=jet_kt_cut( 75.) elif "900-Jets-1" in parameterName : process+=jet_kt_cut( 10.) elif "Run-I-WZ" in parameterName : process+=insert_ME("MEqq2W2ff","Electron") process+=insert_ME("MEqq2gZ2ff","Electron") elif "Run-II-W" in parameterName or "Run-I-W" in parameterName : process+=insert_ME("MEqq2W2ff","Electron") elif "Run-II-Z-e" in parameterName or "Run-I-Z" in parameterName : process +=insert_ME("MEqq2gZ2ff","Electron") elif "Run-II-Z-LowMass-mu" in parameterName : process +=insert_ME("MEqq2gZ2ff","Muon") process+=addLeptonPairCut("25","70") elif "Run-II-Z-HighMass-mu" in parameterName : process +=insert_ME("MEqq2gZ2ff","Muon") process+=addLeptonPairCut("150","600") elif "Run-II-Z-mu" in parameterName : process +=insert_ME("MEqq2gZ2ff","Muon") elif(simulation=="Powheg") : if "Run-I-WZ" in parameterName : process+=insert_ME("PowhegMEqq2W2ff","Electron") process+=insert_ME("PowhegMEqq2gZ2ff","Electron") elif "Run-II-W" in parameterName or "Run-I-W" in parameterName : process+=insert_ME("PowhegMEqq2W2ff","Electron") elif "Run-II-Z-e" in parameterName or "Run-I-Z" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") elif "Run-II-Z-LowMass-mu" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") process+=addLeptonPairCut("25","70") elif "Run-II-Z-HighMass-mu" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") process+=addLeptonPairCut("150","600") elif "Run-II-Z-mu" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "DiPhoton-GammaGamma" in parameterName : process+=insert_ME("MEGammaGammaPowheg","GammaGamma") process+=insert_ME("MEGammaGamma","gg") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" process+=jet_kt_cut(5.) parameterName=parameterName.replace("-GammaGamma","") elif "DiPhoton-GammaJet" in parameterName : process+=insert_ME("MEGammaGammaPowheg","VJet") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" process+=jet_kt_cut(5.) parameterName=parameterName.replace("-GammaJet","") elif(simulation=="Matchbox" or simulation=="Merging" ) : if "Jets" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p -> j j","2","0","MaxJetPtScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p -> j j","2","0","MaxJetPtScale",1,0) process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "Run-II-Jets-10" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("500") elif "Run-II-Jets-11" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("900") elif "Run-II-Jets-12" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("300") elif "Run-I-Jets-1" in parameterName : process+=addFirstJet("20") elif "Run-I-Jets-2" in parameterName : process+=addFirstJet("40") elif "Run-I-Jets-3" in parameterName : process+=addFirstJet("65") elif "Run-I-Jets-4" in parameterName : process+=addFirstJet("90") elif "Run-I-Jets-5" in parameterName : process+=addFirstJet("160") elif "Run-I-Jets-6" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("100") elif "Run-I-Jets-7" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("400") elif "Run-I-Jets-8" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("700") elif "Run-II-Jets-0" in parameterName : process+=addFirstJet("15") elif "Run-II-Jets-1" in parameterName : process+=addFirstJet("25") elif "Run-II-Jets-2" in parameterName : process+=addFirstJet("40") elif "Run-II-Jets-3" in parameterName : process+=addFirstJet("60") elif "Run-II-Jets-4" in parameterName : process+=addFirstJet("85") elif "Run-II-Jets-5" in parameterName : process+=addFirstJet("110") elif "Run-II-Jets-6" in parameterName : process+=addFirstJet("160") elif "Run-II-Jets-7" in parameterName : process+=addFirstJet("250") elif "Run-II-Jets-8" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("100") elif "Run-II-Jets-9" in parameterName : process+=addFirstJet("30")+addSecondJet("25")+addJetPairCut("300") elif "900-Jets-1" in parameterName : process+=addFirstJet("10") elif "300-Jets-1" in parameterName : process+=addFirstJet("6") elif "630-Jets-1" in parameterName : process+=addFirstJet("20") elif "630-Jets-2" in parameterName : process+=addFirstJet("40") elif "630-Jets-3" in parameterName : process+=addFirstJet("75") elif "900-Jets-1" in parameterName : process+=addFirstJet("10") else : logging.error("Exit 00007") sys.exit(1) elif "Run-I-WZ" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar e+ e-","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p pbar e+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p pbar e- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('epm','e+','e-') process+=particlegroup('epmnu','e+','e-','nu_e','nu_ebar') process+=addProcess(thefactory,"p pbar epm epmnu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Run-II-W" in parameterName or "Run-I-W" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar e+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p pbar e- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('epm','e+','e-') process+=addProcess(thefactory,"p pbar epm nu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Run-II-Z-e" in parameterName or "Run-I-Z" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p pbar e+ e-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Run-II-Z-LowMass-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("25","70") elif "Run-II-Z-HighMass-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("150","600") elif "Run-II-Z-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p pbar mu+ mu-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") # Star elif(collider=="Star" ) : process = StringBuilder("set /Herwig/Decays/DecayHandler:LifeTimeOption 0\n") process+= "set /Herwig/Decays/DecayHandler:MaxLifeTime 10*mm\n" process+= "set /Herwig/Generators/EventGenerator:EventHandler:BeamB /Herwig/Particles/p+\n" process+= collider_lumi(200.0) process+= "set /Herwig/Cuts/Cuts:X2Min 0.01\n" if(simulation=="") : if "UE" in parameterName : if "Dipole" in parameters["shower"]: process+="read snippets/MB-DipoleShower.in\n" else: process+="read snippets/MB.in\n" process+="read snippets/Diffraction.in\n" else : process+=insert_ME("MEQCD2to2") process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "Jets-1" in parameterName : process+=jet_kt_cut(2.) elif "Jets-2" in parameterName : process+=jet_kt_cut(5.) elif "Jets-3" in parameterName : process+=jet_kt_cut(20.) elif "Jets-4" in parameterName : process+=jet_kt_cut(25.) else : logging.error("Star not supported for %s " % simulation) sys.exit(1) # ISR and SppS elif(collider=="ISR" or collider =="SppS" ) : process = StringBuilder("set /Herwig/Decays/DecayHandler:LifeTimeOption 0\n") process+="set /Herwig/Decays/DecayHandler:MaxLifeTime 10*mm\n" if(collider=="SppS") : process = StringBuilder("set /Herwig/Generators/EventGenerator:EventHandler:BeamB /Herwig/Particles/pbar-\n") if "30" in parameterName : process+=collider_lumi( 30.4) elif "44" in parameterName : process+=collider_lumi( 44.4) elif "53" in parameterName : process+=collider_lumi( 53.0) elif "62" in parameterName : process+=collider_lumi( 62.2) elif "63" in parameterName : process+=collider_lumi( 63.0) elif "200" in parameterName : process+=collider_lumi(200.0) elif "500" in parameterName : process+=collider_lumi(500.0) elif "546" in parameterName : process+=collider_lumi(546.0) elif "900" in parameterName : process+=collider_lumi(900.0) if(simulation=="") : if "Dipole" in parameters["shower"]: process+="read snippets/MB-DipoleShower.in\n" else: process+="read snippets/MB.in\n" process+="read snippets/Diffraction.in\n" else : logging.error(" SppS and ISR not supported for %s " % simulation) sys.exit(1) # LHC elif(collider=="LHC") : if parameterName.startswith("7-") : process = StringBuilder(collider_lumi(7000.0)) elif parameterName.startswith("8-") : process = StringBuilder(collider_lumi(8000.0)) elif parameterName.startswith("13-") : process = StringBuilder(collider_lumi(13000.0)) elif parameterName.startswith("900") : process = StringBuilder(collider_lumi(900.0)) elif parameterName.startswith("2360") : process = StringBuilder(collider_lumi(2360.0)) elif parameterName.startswith("2760") : process = StringBuilder(collider_lumi(2760.0)) else : process = StringBuilder(collider_lumi(7000.0)) if(simulation=="") : - if "8-VBF" in parameterName : + if "VBF" in parameterName : process+=insert_ME("MEPP2HiggsVBF") - elif "VBF" in parameterName : - process+=selectDecayMode("h0",["h0->tau-,tau+;"]) - process+=addBRReweighter() - process+="set /Herwig/Particles/tau-:Stable Stable\n" - process+=insert_ME("MEPP2HiggsVBF") + if "GammaGamma" in parameterName : + process+=selectDecayMode("h0",["h0->gamma,gamma;"]) + addedBRReweighter = True + elif "WW" in parameterName : + process+=selectDecayMode("h0",["h0->W+,W-;"]) + addedBRReweighter = True + elif "ZZ" in parameterName : + process+=selectDecayMode("h0",["h0->Z0,Z0;"]) + addedBRReweighter = True + elif "8-" not in parameterName : + process+=selectDecayMode("h0",["h0->tau-,tau+;"]) + addedBRReweighter = True + process+="set /Herwig/Particles/tau-:Stable Stable\n" + elif "ggHJet" in parameterName : process+=selectDecayMode("h0",["h0->tau-,tau+;"]) - process+=addBRReweighter() + addedBRReweighter = True process+="set /Herwig/Particles/tau-:Stable Stable\n" process+=insert_ME("MEHiggsJet") process+=jet_kt_cut(20.) - elif "8-ggH" in parameterName : + elif "ggH" in parameterName : process+=insert_ME("MEHiggs") process+=insert_ME("MEHiggsJet","qqbar") process+=jet_kt_cut(0.0) - elif "ggH" in parameterName : - process+=selectDecayMode("h0",["h0->tau-,tau+;"]) - process+=addBRReweighter() - process+="set /Herwig/Particles/tau-:Stable Stable\n" - process+=insert_ME("MEHiggs") - process+=insert_ME("MEHiggsJet","qqbar") - process+=jet_kt_cut(0.0) + if "GammaGamma" in parameterName : + process+=selectDecayMode("h0",["h0->gamma,gamma;"]) + addedBRReweighter = True + elif "WW" in parameterName : + process+=selectDecayMode("h0",["h0->W+,W-;"]) + addedBRReweighter = True + elif "ZZ" in parameterName : + process+=selectDecayMode("h0",["h0->Z0,Z0;"]) + addedBRReweighter = True + elif "8-" not in parameterName : + process+=selectDecayMode("h0",["h0->tau-,tau+;"]) + addedBRReweighter = True + process+="set /Herwig/Particles/tau-:Stable Stable\n" + elif "PromptPhoton" in parameterName : process+=insert_ME("MEGammaJet") if "PromptPhoton-1" in parameterName : process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" elif "PromptPhoton-2" in parameterName : process+="set /Herwig/Cuts/PhotonKtCut:MinKT 25.\n" elif "PromptPhoton-3" in parameterName : process+="set /Herwig/Cuts/PhotonKtCut:MinKT 80.\n" elif "PromptPhoton-4" in parameterName : process+="set /Herwig/Cuts/PhotonKtCut:MinKT 150.\n" elif "DiPhoton-GammaGamma" in parameterName : process+=insert_ME("MEGammaGamma") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" parameterName=parameterName.replace("-GammaGamma","") elif "DiPhoton-GammaJet" in parameterName : process+=insert_ME("MEGammaJet") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" parameterName=parameterName.replace("-GammaJet","") elif "8-WH" in parameterName : process+=insert_ME("MEPP2WH") process+=jet_kt_cut(0.0) + if "GammaGamma" in parameterName : + process+=selectDecayMode("h0",["h0->gamma,gamma;"]) + addedBRReweighter = True + elif "WW" in parameterName : + process+=selectDecayMode("h0",["h0->W+,W-;"]) + addedBRReweighter = True + elif "ZZ" in parameterName : + process+=selectDecayMode("h0",["h0->Z0,Z0;"]) + addedBRReweighter = True elif "8-ZH" in parameterName : process+=insert_ME("MEPP2ZH") process+=jet_kt_cut(0.0) + if "GammaGamma" in parameterName : + process+=selectDecayMode("h0",["h0->gamma,gamma;"]) + addedBRReweighter = True + elif "WW" in parameterName : + process+=selectDecayMode("h0",["h0->W+,W-;"]) + addedBRReweighter = True + elif "ZZ" in parameterName : + process+=selectDecayMode("h0",["h0->Z0,Z0;"]) + addedBRReweighter = True elif "WH" in parameterName : process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;"]) - process+=addBRReweighter() + addedBRReweighter = True process+=insert_ME("MEPP2WH") process+=jet_kt_cut(0.0) elif "ZH" in parameterName : process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;"]) - process+=addBRReweighter() + addedBRReweighter = True process+=insert_ME("MEPP2ZH") process+=jet_kt_cut(0.0) elif "UE" in parameterName : if "Dipole" in parameters["shower"]: process+="read snippets/MB-DipoleShower.in\n" else: process+="set /Herwig/Shower/ShowerHandler:IntrinsicPtGaussian 2.2*GeV\n" process+="read snippets/MB.in\n" process+="read snippets/Diffraction.in\n" if "Long" in parameterName : process += "set /Herwig/Decays/DecayHandler:MaxLifeTime 100*mm\n" elif "8-DiJets" in parameterName or "7-DiJets" in parameterName : process+=insert_ME("MEQCD2to2") process+="set MEQCD2to2:MaximumFlavour 5\n" process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "-A" in parameterName : process+=jet_kt_cut(45.) process+="set /Herwig/Cuts/JetKtCut:MinEta -3.\n" process+="set /Herwig/Cuts/JetKtCut:MaxEta 3.\n" elif "-B" in parameterName : process+=jet_kt_cut(20.) process+="set /Herwig/Cuts/JetKtCut:MinEta -2.7\n" process+="set /Herwig/Cuts/JetKtCut:MaxEta 2.7\n" elif "-C" in parameterName : process+=jet_kt_cut(20.) process+="set /Herwig/Cuts/JetKtCut:MinEta -4.8\n" process+="set /Herwig/Cuts/JetKtCut:MaxEta 4.8\n" if "DiJets-1" in parameterName : process+=mhatmin_cut(90.) elif "DiJets-2" in parameterName : process+=mhatmin_cut(200.) elif "DiJets-3" in parameterName : process+=mhatmin_cut(450.) elif "DiJets-4" in parameterName : process+=mhatmin_cut(750.) elif "DiJets-5" in parameterName : process+=mhatmin_cut(950.) elif "DiJets-6" in parameterName : process+=mhatmin_cut(1550.) elif "DiJets-7" in parameterName : process+=mhatmin_cut(2150.) elif "DiJets-8" in parameterName : process+=mhatmin_cut(2750.) elif( "7-Jets" in parameterName or "8-Jets" in parameterName or "13-Jets" in parameterName ) : process+=insert_ME("MEQCD2to2") process+="set MEQCD2to2:MaximumFlavour 5\n" process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "Jets-10" in parameterName : process+=jet_kt_cut(1800.) elif "Jets-0" in parameterName : process+=jet_kt_cut(5.) elif "Jets-1" in parameterName : process+=jet_kt_cut(10.) elif "Jets-2" in parameterName : process+=jet_kt_cut(20.) elif "Jets-3" in parameterName : process+=jet_kt_cut(40.) elif "Jets-4" in parameterName : process+=jet_kt_cut(70.) elif "Jets-5" in parameterName : process+=jet_kt_cut(150.) elif "Jets-6" in parameterName : process+=jet_kt_cut(200.) elif "Jets-7" in parameterName : process+=jet_kt_cut(300.) elif "Jets-8" in parameterName : process+=jet_kt_cut(500.) elif "Jets-9" in parameterName : process+=jet_kt_cut(800.) elif("7-Charm" in parameterName or "7-Bottom" in parameterName) : if "7-Bottom" in parameterName : process+="cp MEHeavyQuark MEBottom\n" process+="set MEBottom:QuarkType Bottom\n" process+=insert_ME("MEBottom") else : process+="cp MEHeavyQuark MECharm\n" process+="set MECharm:QuarkType Charm\n" process+=insert_ME("MECharm") process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "-0" in parameterName : if "7-Bottom" in parameterName : process+="set MEBottom:Process Pair\n" process+=jet_kt_cut(0.) elif "-1" in parameterName : process+=jet_kt_cut(5.) elif "-2" in parameterName : process+=jet_kt_cut(20.) elif "-3" in parameterName : process+=jet_kt_cut(50.) elif "-4" in parameterName : process+=jet_kt_cut(80.) elif "-5" in parameterName : process+=jet_kt_cut(110.) elif "-6" in parameterName : process+=jet_kt_cut(30.)+mhatmin_cut(90.) elif "-7" in parameterName : process+=jet_kt_cut(30.)+mhatmin_cut(340.) elif "-8" in parameterName : process+=jet_kt_cut(30.)+mhatmin_cut(500.) elif "Top-L" in parameterName : process+="set MEHeavyQuark:QuarkType Top\n" process+=insert_ME("MEHeavyQuark") process+=selectDecayMode("t",["t->nu_e,e+,b;", "t->nu_mu,mu+,b;"]) process+=addBRReweighter() elif "Top-SL" in parameterName : process+="set MEHeavyQuark:QuarkType Top\n" process+=insert_ME("MEHeavyQuark") process+="set /Herwig/Particles/t:Synchronized Not_synchronized\n" process+="set /Herwig/Particles/tbar:Synchronized Not_synchronized\n" process+=selectDecayMode("t",["t->nu_e,e+,b;","t->nu_mu,mu+,b;"]) process+=selectDecayMode("tbar",["tbar->b,bbar,cbar;", "tbar->bbar,cbar,d;", "tbar->bbar,cbar,s;", "tbar->bbar,s,ubar;", "tbar->bbar,ubar,d;"]) process+=addBRReweighter() elif "Top-All" in parameterName : process+="set MEHeavyQuark:QuarkType Top\n" process+=insert_ME("MEHeavyQuark") elif "WZ" in parameterName : process+=insert_ME("MEPP2VV","WZ") process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;"]) process+=selectDecayMode("W-",["W-->nu_ebar,e-;", "W-->nu_mubar,mu-;"]) process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;"]) - process+=addBRReweighter() + addedBRReweighter = True elif "WW-emu" in parameterName : process+=insert_ME("MEPP2VV","WW") process+="set /Herwig/Particles/W+:Synchronized 0\n" process+="set /Herwig/Particles/W-:Synchronized 0\n" process+=selectDecayMode("W+",["W+->nu_e,e+;"]) process+=selectDecayMode("W-",["W-->nu_mubar,mu-;"]) - process+=addBRReweighter() + addedBRReweighter = True elif "WW-ll" in parameterName : process+=insert_ME("MEPP2VV","WW") process+=selectDecayMode("W+",["W+->nu_e,e+;","W+->nu_mu,mu+;","W+->nu_tau,tau+;"]) - process+=addBRReweighter() + addedBRReweighter = True elif "ZZ-ll" in parameterName : process+=insert_ME("MEPP2VV","ZZ") process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;"]) - process+=addBRReweighter() + addedBRReweighter = True elif "ZZ-lv" in parameterName : process+=insert_ME("MEPP2VV","ZZ") process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;", "Z0->nu_e,nu_ebar;", "Z0->nu_mu,nu_mubar;", "Z0->nu_tau,nu_taubar;"]) - process+=addBRReweighter() + addedBRReweighter = True elif "W-Z-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") process+=insert_ME("MEqq2W2ff","Electron") elif "W-Z-mu" in parameterName : process+=insert_ME("MEqq2gZ2ff","Muon") process+=insert_ME("MEqq2W2ff","Muon") elif "W-e" in parameterName : process+=insert_ME("MEqq2W2ff","Electron") elif "W-mu" in parameterName : process+=insert_ME("MEqq2W2ff","Muon") elif "Z-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") elif "Z-mu" in parameterName : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-LowMass-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") process+=mhat_minm_maxm(20,20,70) elif "Z-MedMass-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") process+=mhat_minm_maxm(40,40,130) elif "Z-LowMass-mu" in parameterName : process+=insert_ME("MEqq2gZ2ff","Muon") process+=mhat_minm_maxm(10,10,70) elif "Z-Mass1" in parameterName : process+=mhat_minm_maxm(10,10,35) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-Mass2" in parameterName : process+=mhat_minm_maxm(25,25,70) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-Mass3" in parameterName : process+=mhat_minm_maxm(60,60,120) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-Mass4" in parameterName : process+=mhat_minm_maxm(110,110,8000) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-HighMass1" in parameterName : process+=mhat_minm_maxm(116,116,400) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "Z-HighMass2" in parameterName : process+=mhat_minm_maxm(400,400,7000) if "-e" in parameterName : process+=insert_ME("MEqq2gZ2ff","Electron") else : process+=insert_ME("MEqq2gZ2ff","Muon") elif "W-Jet" in parameterName : process+=insert_ME("MEWJet","Electron","WDecay") if "W-Jet-1-e" in parameterName : process+="set /Herwig/Cuts/WBosonKtCut:MinKT 100.0*GeV\n" parameterName=parameterName.replace("W-Jet-1-e","W-Jet-e") elif "W-Jet-2-e" in parameterName : process+="set /Herwig/Cuts/WBosonKtCut:MinKT 190.0*GeV\n" parameterName=parameterName.replace("W-Jet-2-e","W-Jet-e") elif "W-Jet-3-e" in parameterName : process+="set /Herwig/Cuts/WBosonKtCut:MinKT 270.0*GeV\n" parameterName=parameterName.replace("W-Jet-3-e","W-Jet-e") elif "Z-Jet" in parameterName : if "-e" in parameterName : process+=insert_ME("MEZJet","Electron","ZDecay") if "Z-Jet-0-e" in parameterName : process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 35.0*GeV\n" parameterName=parameterName.replace("Z-Jet-0-e","Z-Jet-e") elif "Z-Jet-1-e" in parameterName : process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 100.0*GeV\n" parameterName=parameterName.replace("Z-Jet-1-e","Z-Jet-e") elif "Z-Jet-2-e" in parameterName : process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 190.0*GeV\n" parameterName=parameterName.replace("Z-Jet-2-e","Z-Jet-e") elif "Z-Jet-3-e" in parameterName : process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 270.0*GeV\n" parameterName=parameterName.replace("Z-Jet-3-e","Z-Jet-e") else : process+=insert_ME("MEZJet","Muon","ZDecay") process+="set /Herwig/Cuts/ZBosonKtCut:MinKT 35.0*GeV\n" parameterName=parameterName.replace("Z-Jet-0-mu","Z-Jet-mu") elif "WGamma" in parameterName : process+=insert_ME("MEPP2VGamma","1") process+="set MEPP2VGamma:MassOption 1" process+="set /Herwig/Cuts/PhotonKtCut:MinKT 10.\n" if "-e" in parameterName : process+=selectDecayMode("W+",["W+->nu_e,e+;"]) process+=addBRReweighter() else : process+=selectDecayMode("W+",["W+->nu_mu,mu+;"]) process+=addBRReweighter() elif "ZGamma" in parameterName : process+=insert_ME("MEPP2VGamma","2") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 10.\n" if "-e" in parameterName : process+=selectDecayMode("Z0",["Z0->e-,e+;"]) process+=addBRReweighter() else : process+=selectDecayMode("Z0",["Z0->mu-,mu+;"]) process+=addBRReweighter() else : logging.error(" Process %s not supported for internal matrix elements" % name) sys.exit(1) elif(simulation=="Powheg") : - if "8-VBF" in parameterName : + if "VBF" in parameterName : process+=insert_ME("PowhegMEPP2HiggsVBF") - elif "VBF" in parameterName : - process+=selectDecayMode("h0",["h0->tau-,tau+;"]) - process+=addBRReweighter() - process+="set /Herwig/Particles/tau-:Stable Stable\n" - process+=insert_ME("PowhegMEPP2HiggsVBF") + if "GammaGamma" in parameterName : + process+=selectDecayMode("h0",["h0->gamma,gamma;"]) + addedBRReweighter = True + elif "WW" in parameterName : + process+=selectDecayMode("h0",["h0->W+,W-;"]) + addedBRReweighter = True + elif "ZZ" in parameterName : + process+=selectDecayMode("h0",["h0->Z0,Z0;"]) + addedBRReweighter = True + elif "8-" not in parameterName : + process+=selectDecayMode("h0",["h0->tau-,tau+;"]) + addedBRReweighter = True + process+="set /Herwig/Particles/tau-:Stable Stable\n" + elif "ggHJet" in parameterName : logging.error(" Process %s not supported for POWHEG matrix elements" % name) sys.exit(1) - elif "8-ggH" in parameterName : + elif "ggH" in parameterName : process+=insert_ME("PowhegMEHiggs") - elif "ggH" in parameterName : - process+=selectDecayMode("h0",["h0->tau-,tau+;"]) - process+=addBRReweighter() - process+="set /Herwig/Particles/tau-:Stable Stable\n" - process+=insert_ME("PowhegMEHiggs") + if "GammaGamma" in parameterName : + process+=selectDecayMode("h0",["h0->gamma,gamma;"]) + addedBRReweighter = True + elif "WW" in parameterName : + process+=selectDecayMode("h0",["h0->W+,W-;"]) + addedBRReweighter = True + elif "ZZ" in parameterName : + process+=selectDecayMode("h0",["h0->Z0,Z0;"]) + addedBRReweighter = True + elif "8-" not in parameterName : + process+=selectDecayMode("h0",["h0->tau-,tau+;"]) + addedBRReweighter = True + process+="set /Herwig/Particles/tau-:Stable Stable\n" elif "8-WH" in parameterName : process+=insert_ME("PowhegMEPP2WH") process+=jet_kt_cut(0.0) + if "GammaGamma" in parameterName : + process+=selectDecayMode("h0",["h0->gamma,gamma;"]) + addedBRReweighter = True + elif "WW" in parameterName : + process+=selectDecayMode("h0",["h0->W+,W-;"]) + addedBRReweighter = True + elif "ZZ" in parameterName : + process+=selectDecayMode("h0",["h0->Z0,Z0;"]) + addedBRReweighter = True elif "8-ZH" in parameterName : process+=insert_ME("PowhegMEPP2ZH") process+=jet_kt_cut(0.0) + if "GammaGamma" in parameterName : + process+=selectDecayMode("h0",["h0->gamma,gamma;"]) + addedBRReweighter = True + elif "WW" in parameterName : + process+=selectDecayMode("h0",["h0->W+,W-;"]) + addedBRReweighter = True + elif "ZZ" in parameterName : + process+=selectDecayMode("h0",["h0->Z0,Z0;"]) + addedBRReweighter = True elif "WH" in parameterName : process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;"]) - process+=addBRReweighter() + addedBRReweighter = True process+=insert_ME("PowhegMEPP2WH") process+=jet_kt_cut(0.0) elif "ZH" in parameterName : process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;"]) - process+=addBRReweighter() + addedBRReweighter = True process+=insert_ME("PowhegMEPP2ZH") process+=jet_kt_cut(0.0) elif "UE" in parameterName : logging.error(" Process %s not supported for powheg matrix elements" % name) sys.exit(1) elif "WZ" in parameterName : process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n" process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n" process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n"; process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n"; process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n"; process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n" process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n" process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n" process+=insert_ME("PowhegMEPP2VV","WZ") process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;"]) process+=selectDecayMode("W-",["W-->nu_ebar,e-;", "W-->nu_mubar,mu-;"]) process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;"]) - process+=addBRReweighter() + addedBRReweighter = True elif "WW-emu" in parameterName : process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n" process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n" process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n"; process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n"; process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n"; process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n" process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n" process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n" process+=insert_ME("PowhegMEPP2VV","WW") process+="set /Herwig/Particles/W+:Synchronized 0\n" process+="set /Herwig/Particles/W-:Synchronized 0\n" process+=selectDecayMode("W+",["W+->nu_e,e+;"]) process+=selectDecayMode("W-",["W-->nu_mubar,mu-;"]) - process+=addBRReweighter() + addedBRReweighter = True elif "WW-ll" in parameterName : process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n" process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n" process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n"; process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n"; process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n"; process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n" process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n" process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n" process+=insert_ME("PowhegMEPP2VV","WW") process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;", "W+->nu_tau,tau+;"]) - process+=addBRReweighter() + addedBRReweighter = True elif "ZZ-ll" in parameterName : process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n" process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n" process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n"; process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n"; process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n"; process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n" process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n" process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n" process+=insert_ME("PowhegMEPP2VV","ZZ") process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;"]) - process+=addBRReweighter() + addedBRReweighter = True elif "ZZ-lv" in parameterName : process+="create Herwig::HwDecayHandler /Herwig/NewPhysics/DecayHandler\n" process+="set /Herwig/NewPhysics/DecayHandler:NewStep No\n" process+="set /Herwig/Shower/ShowerHandler:SplitHardProcess No\n"; process+="set /Herwig/Decays/ZDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/ZPowhegDecayer:PhotonGenerator NULL\n"; process+="set /Herwig/Decays/WDecayer:PhotonGenerator NULL\n"; - process+="set /Herwig/Decays/WPowhegDecayer:PhotonGenerator NULL\n"; process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 0 /Herwig/Particles/tau-\n" process+="insert /Herwig/NewPhysics/DecayHandler:Excluded 1 /Herwig/Particles/tau+\n" process+="insert /Herwig/Generators/EventGenerator:EventHandler:PreCascadeHandlers 0 /Herwig/NewPhysics/DecayHandler\n" process+=insert_ME("PowhegMEPP2VV","ZZ") process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;", "Z0->nu_e,nu_ebar;", "Z0->nu_mu,nu_mubar;", "Z0->nu_tau,nu_taubar;"]) - process+=addBRReweighter() + addedBRReweighter = True elif "W-Z-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") process+=insert_ME("PowhegMEqq2W2ff","Electron") elif "W-Z-mu" in parameterName : process+=insert_ME("MEqq2gZ2ff","Muon") process+=insert_ME("MEqq2W2ff","Muon") elif "W-e" in parameterName : process+=insert_ME("PowhegMEqq2W2ff","Electron") elif "W-mu" in parameterName : process+=insert_ME("PowhegMEqq2W2ff","Muon") elif "Z-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") elif "Z-mu" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-LowMass-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") process+=mhat_minm_maxm(20,20,70) elif "Z-MedMass-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") process+=mhat_minm_maxm(40,40,130) elif "Z-LowMass-mu" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") process+=mhat_minm_maxm(10,10,70) elif "Z-Mass1" in parameterName : process+=mhat_minm_maxm(10,10,35) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-Mass2" in parameterName : process+=mhat_minm_maxm(25,25,70) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-Mass3" in parameterName : process+=mhat_minm_maxm(60,60,120) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-Mass4" in parameterName : process+=mhat_minm_maxm(110,110,8000) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-HighMass1" in parameterName : process+=mhat_minm_maxm(116,116,400) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "Z-HighMass2" in parameterName : process+=mhat_minm_maxm(400,400,7000) if "-e" in parameterName : process+=insert_ME("PowhegMEqq2gZ2ff","Electron") else : process+=insert_ME("PowhegMEqq2gZ2ff","Muon") elif "DiPhoton-GammaGamma" in parameterName : process+=insert_ME("MEGammaGammaPowheg","GammaGamma") process+=insert_ME("MEGammaGamma","gg") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" process+=jet_kt_cut(5.) parameterName=parameterName.replace("-GammaGamma","") elif "DiPhoton-GammaJet" in parameterName : process+=insert_ME("MEGammaGammaPowheg","VJet") process+="set /Herwig/Cuts/PhotonKtCut:MinKT 5.\n" process+=jet_kt_cut(5.) parameterName=parameterName.replace("-GammaJet","") else : logging.error(" Process %s not supported for internal POWHEG matrix elements" % name) sys.exit(1) elif( simulation=="Matchbox" or simulation=="Merging" ) : - if "8-VBF" in parameterName : + if "VBF" in parameterName : parameters["nlo"] = "read Matchbox/VBFNLO.in\n" if(simulation=="Merging"): process+="cd /Herwig/Merging/\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/Z0\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W+\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W-\n" process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/gamma\n" process+="do "+thefactory+":DiagramGenerator:TimeLikeRange 0 0\n" if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",1,1) process+=setHardProcessWidthToZero(["h0"]) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" if "GammaGamma" in parameterName : process+=selectDecayMode("h0",["h0->gamma,gamma;"]) process+=addBRReweighter() elif "WW" in parameterName : process+=selectDecayMode("h0",["h0->W+,W-;"]) process+=addBRReweighter() elif "ZZ" in parameterName : process+=selectDecayMode("h0",["h0->Z0,Z0;"]) process+=addBRReweighter() - - elif "VBF" in parameterName : - process+=selectDecayMode("h0",["h0->tau-,tau+;"]) - process+=addBRReweighter() - process+="set /Herwig/Particles/tau-:Stable Stable\n" - parameters["nlo"] = "read Matchbox/VBFNLO.in\n" - if(simulation=="Merging"): - process+="cd /Herwig/Merging/\n" - process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/Z0\n" - process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W+\n" - process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/W-\n" - process+="insert "+thefactory+":DiagramGenerator:RestrictLines 0 /Herwig/Particles/gamma\n" - process+="do "+thefactory+":DiagramGenerator:TimeLikeRange 0 0\n" - if(simulation=="Matchbox"): - process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",0,0) - elif(simulation=="Merging"): - process+=addProcess(thefactory,"p p h0 j j","0","3","FixedScale",1,1) - process+=setHardProcessWidthToZero(["h0"]) - process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" + elif "8-" not in parameterName : + process+=selectDecayMode("h0",["h0->tau-,tau+;"]) + process+=addBRReweighter() + process+="set /Herwig/Particles/tau-:Stable Stable\n" elif "ggHJet" in parameterName : if(simulation=="Merging"): logging.warning("ggHJet not explicitly tested for %s " % simulation) sys.exit(0) parameters["nlo"] = "read Matchbox/MadGraph-GoSam.in\nread Matchbox/HiggsEffective.in\n" process+=selectDecayMode("h0",["h0->tau-,tau+;"]) process+=addBRReweighter() process+="set /Herwig/Particles/tau-:Stable Stable\n" process+=setHardProcessWidthToZero(["h0"]) process+=addProcess(thefactory,"p p h0 j","3","1","FixedScale",0,0) process+=addFirstJet("20") process+="set "+thefactory+":ScaleChoice /Herwig/MatrixElements/Matchbox/Scales/FixedScale\n" process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" - elif "8-ggH" in parameterName : + elif "ggH" in parameterName : parameters["nlo"] = "read Matchbox/MadGraph-GoSam.in\nread Matchbox/HiggsEffective.in\n" if(simulation=="Merging"): process+= "cd /Herwig/MatrixElements/Matchbox/Amplitudes\nset OpenLoops:HiggsEff On\nset MadGraph:Model heft\n" process+="cd /Herwig/Merging/\n" process+=setHardProcessWidthToZero(["h0"]) if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p h0","2","1","FixedScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p h0","2","1","FixedScale",2,2) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" if "GammaGamma" in parameterName : process+=selectDecayMode("h0",["h0->gamma,gamma;"]) process+=addBRReweighter() elif "WW" in parameterName : process+=selectDecayMode("h0",["h0->W+,W-;"]) process+=addBRReweighter() elif "ZZ" in parameterName : process+=selectDecayMode("h0",["h0->Z0,Z0;"]) process+=addBRReweighter() - - elif "ggH" in parameterName : - parameters["nlo"] = "read Matchbox/MadGraph-GoSam.in\nread Matchbox/HiggsEffective.in\n" - if(simulation=="Merging"): - process+= "cd /Herwig/MatrixElements/Matchbox/Amplitudes\nset OpenLoops:HiggsEff On\nset MadGraph:Model heft\n" - process+="cd /Herwig/Merging/\n" - process+=selectDecayMode("h0",["h0->tau-,tau+;"]) - process+=addBRReweighter() - process+="set /Herwig/Particles/tau-:Stable Stable\n" - process+=setHardProcessWidthToZero(["h0"]) - if(simulation=="Matchbox"): - process+=addProcess(thefactory,"p p h0","2","1","FixedScale",0,0) - elif(simulation=="Merging"): - process+=addProcess(thefactory,"p p h0","2","1","FixedScale",2,2) - - process+="set "+thefactory+":ScaleChoice /Herwig/MatrixElements/Matchbox/Scales/FixedScale\n" - process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" + elif "8-" not in parameterName : + process+=selectDecayMode("h0",["h0->tau-,tau+;"]) + process+=addBRReweighter() + process+="set /Herwig/Particles/tau-:Stable Stable\n" elif "8-WH" in parameterName : if(simulation=="Merging"): logging.warning("8-WH not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["h0","W+","W-"]) process+=addProcess(thefactory,"p p W+ h0","0","2","FixedScale",0,0) process+=addProcess(thefactory,"p p W- h0","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" if "GammaGamma" in parameterName : process+=selectDecayMode("h0",["h0->gamma,gamma;"]) process+=addBRReweighter() elif "WW" in parameterName : process+=selectDecayMode("h0",["h0->W+,W-;"]) process+=addBRReweighter() elif "ZZ" in parameterName : process+=selectDecayMode("h0",["h0->Z0,Z0;"]) process+=addBRReweighter() elif "8-ZH" in parameterName : if(simulation=="Merging"): logging.warning("8-ZH not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["h0","Z0"]) process+=addProcess(thefactory,"p p Z0 h0","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 125.7\n" if "GammaGamma" in parameterName : process+=selectDecayMode("h0",["h0->gamma,gamma;"]) process+=addBRReweighter() elif "WW" in parameterName : process+=selectDecayMode("h0",["h0->W+,W-;"]) process+=addBRReweighter() elif "ZZ" in parameterName : process+=selectDecayMode("h0",["h0->Z0,Z0;"]) process+=addBRReweighter() elif "WH" in parameterName : if(simulation=="Merging"): logging.warning("WH not explicitly tested for %s " % simulation) sys.exit(0) process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=addBRReweighter() process+=setHardProcessWidthToZero(["h0"]) process+=addProcess(thefactory,"p p e+ nu h0","0","3","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p e- nu h0","0","3","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu+ nu h0","0","3","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu- nu h0","0","3","LeptonPairMassScale",0,0) process+=addLeptonPairCut("60","120") elif "ZH" in parameterName : if(simulation=="Merging"): logging.warning("ZH not explicitly tested for %s " % simulation) sys.exit(0) process+=selectDecayMode("h0",["h0->b,bbar;"]) process+=addBRReweighter() process+=setHardProcessWidthToZero(["h0"]) process+=addProcess(thefactory,"p p e+ e- h0","0","3","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu+ mu- h0","0","3","LeptonPairMassScale",0,0) process+=addLeptonPairCut("60","120") elif "UE" in parameterName : logging.error(" Process %s not supported for Matchbox matrix elements" % name) sys.exit(1) elif "8-DiJets" in parameterName or "7-DiJets" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",1,1) process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "-A" in parameterName : process+=addFirstJet("45") process+=addSecondJet("25") process+="set /Herwig/Cuts/FirstJet:YRange -3. 3.\n" process+="set /Herwig/Cuts/SecondJet:YRange -3. 3.\n" elif "-B" in parameterName : process+=addFirstJet("20") process+=addSecondJet("15") process+="set /Herwig/Cuts/FirstJet:YRange -2.7 2.7\n" process+="set /Herwig/Cuts/SecondJet:YRange -2.7 2.7\n" elif "-C" in parameterName : process+=addFirstJet("20") process+=addSecondJet("15") process+="set /Herwig/Cuts/FirstJet:YRange -4.8 4.8\n" process+="set /Herwig/Cuts/SecondJet:YRange -4.8 4.8\n" else : logging.error("Exit 00001") sys.exit(1) if "DiJets-1" in parameterName : process+=addJetPairCut("90") elif "DiJets-2" in parameterName : process+=addJetPairCut("200") elif "DiJets-3" in parameterName : process+=addJetPairCut("450") elif "DiJets-4" in parameterName : process+=addJetPairCut("750") elif "DiJets-5" in parameterName : process+=addJetPairCut("950") elif "DiJets-6" in parameterName : process+=addJetPairCut("1550") elif "DiJets-7" in parameterName : process+=addJetPairCut("2150") elif "DiJets-8" in parameterName : process+=addJetPairCut("2750") else : logging.error("Exit 00002") sys.exit(1) elif( "7-Jets" in parameterName or "8-Jets" in parameterName or "13-Jets" in parameterName ) : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p j j","2","0","MaxJetPtScale",1,1) process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "Jets-10" in parameterName : process+=addFirstJet("1800") elif "Jets-0" in parameterName : process+=addFirstJet("5") elif "Jets-1" in parameterName : process+=addFirstJet("10") elif "Jets-2" in parameterName : process+=addFirstJet("20") elif "Jets-3" in parameterName : process+=addFirstJet("40") elif "Jets-4" in parameterName : process+=addFirstJet("70") elif "Jets-5" in parameterName : process+=addFirstJet("150") elif "Jets-6" in parameterName : process+=addFirstJet("200") elif "Jets-7" in parameterName : process+=addFirstJet("300") elif "Jets-8" in parameterName : process+=addFirstJet("500") elif "Jets-9" in parameterName : process+=addFirstJet("800") else : logging.error("Exit 00003") sys.exit(1) elif( "7-Charm" in parameterName or "7-Bottom" in parameterName) : parameters["bscheme"]=fourFlavour process+="set /Herwig/Particles/b:HardProcessMass 4.2*GeV\n" process+="set /Herwig/Particles/bbar:HardProcessMass 4.2*GeV\n" if "7-Bottom" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p b bbar","2","0","MaxJetPtScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p b bbar","2","0","MaxJetPtScale",1,0) else: if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p c cbar","2","0","MaxJetPtScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p c cbar","2","0","MaxJetPtScale",1,0) process+="set /Herwig/UnderlyingEvent/MPIHandler:IdenticalToUE 0\n" if "-0" in parameterName : process+=addFirstJet("0") elif "-1" in parameterName : process+=addFirstJet("5") elif "-2" in parameterName : process+=addFirstJet("20") elif "-3" in parameterName : process+=addFirstJet("50") elif "-4" in parameterName : process+=addFirstJet("80") elif "-5" in parameterName : process+=addFirstJet("110") elif "-6" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("90") elif "-7" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("340") elif "-8" in parameterName : process+=addFirstJet("30") process+=addSecondJet("25") process+=addJetPairCut("500") else : logging.error("Exit 00004") sys.exit(1) elif "Top-L" in parameterName : process+=setHardProcessWidthToZero(["t","tbar"]) if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",2,2) process+=selectDecayMode("t",["t->nu_e,e+,b;", "t->nu_mu,mu+,b;"]) process+=addBRReweighter() elif "Top-SL" in parameterName : process+=setHardProcessWidthToZero(["t","tbar"]) if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",2,2) process+="set /Herwig/Particles/t:Synchronized Not_synchronized\n" process+="set /Herwig/Particles/tbar:Synchronized Not_synchronized\n" process+=selectDecayMode("t",["t->nu_e,e+,b;", "t->nu_mu,mu+,b;"]) process+=selectDecayMode("tbar",["tbar->b,bbar,cbar;", "tbar->bbar,cbar,d;", "tbar->bbar,cbar,s;", "tbar->bbar,s,ubar;", "tbar->bbar,ubar,d;"]) process+=addBRReweighter() elif "Top-All" in parameterName : process+=setHardProcessWidthToZero(["t","tbar"]) if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p t tbar","2","0","TopPairMTScale",2,2) elif "WZ" in parameterName : if(simulation=="Merging"): logging.warning("WZ not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["W+","W-","Z0"]) process+=addProcess(thefactory,"p p W+ Z0","0","2","FixedScale",0,0) process+=addProcess(thefactory,"p p W- Z0","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 171.6*GeV\n\n" process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;"]) process+=selectDecayMode("W-",["W-->nu_ebar,e-;", "W-->nu_mubar,mu-;"]) process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;"]) process+=addBRReweighter() process+=addLeptonPairCut("60","120") elif "WW-emu" in parameterName : if(simulation=="Merging"): logging.warning("WW-emu not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["W+","W-","Z0"]) process+=addProcess(thefactory,"p p W+ W-","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 160.8*GeV\n" process+="set /Herwig/Particles/W+:Synchronized 0\n" process+="set /Herwig/Particles/W-:Synchronized 0\n" process+=selectDecayMode("W+",["W+->nu_e,e+;"]) process+=selectDecayMode("W-",["W-->nu_mubar,mu-;"]) process+=addBRReweighter() parameters["bscheme"] = "read Matchbox/FourFlavourScheme.in\n" process+=addLeptonPairCut("60","120") elif "WW-ll" in parameterName : if(simulation=="Merging"): logging.warning("WW-ll not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["W+","W-","Z0"]) process+=addProcess(thefactory,"p p W+ W-","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 160.8*GeV\n" process+=selectDecayMode("W+",["W+->nu_e,e+;", "W+->nu_mu,mu+;", "W+->nu_tau,tau+;"]) process+=addBRReweighter() process+=addLeptonPairCut("60","120") parameters["bscheme"] = "read Matchbox/FourFlavourScheme.in\n" elif "ZZ-ll" in parameterName : if(simulation=="Merging"): logging.warning("ZZ-ll not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["W+","W-","Z0"]) process+=addProcess(thefactory,"p p Z0 Z0","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 182.2*GeV\n" process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;"]) process+=addBRReweighter() process+=addLeptonPairCut("60","120") elif "ZZ-lv" in parameterName : if(simulation=="Merging"): logging.warning("ZZ-lv not explicitly tested for %s " % simulation) sys.exit(0) process+=setHardProcessWidthToZero(["W+","W-","Z0"]) process+=addProcess(thefactory,"p p Z0 Z0","0","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 182.2*GeV\n" process+=selectDecayMode("Z0",["Z0->e-,e+;", "Z0->mu-,mu+;", "Z0->tau-,tau+;", "Z0->nu_e,nu_ebar;", "Z0->nu_mu,nu_mubar;", "Z0->nu_tau,nu_taubar;"]) process+=addBRReweighter() process+=addLeptonPairCut("60","120") elif "W-Z-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p e+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p e- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('epm','e+','e-') process+=particlegroup('epmnu','e+','e-','nu_e','nu_ebar') process+=addProcess(thefactory,"p p epm epmnu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "W-Z-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('mupm','mu+','mu-') process+=particlegroup('mupmnu','mu+','mu-','nu_mu','nu_mubar') process+=addProcess(thefactory,"p p mupm mupmnu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "W-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p e- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('epm','e+','e-') process+=addProcess(thefactory,"p p epm nu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "W-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ nu","0","2","LeptonPairMassScale",0,0) process+=addProcess(thefactory,"p p mu- nu","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=particlegroup('mupm','mu+','mu-') process+=addProcess(thefactory,"p p mupm nu","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Z-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Z-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("60","120") elif "Z-jj" in parameterName : if(simulation=="Merging"): logging.warning("Z-jj not explicitly tested for %s " % simulation) sys.exit(0) process+=addProcess(thefactory,"p p e+ e- j j","2","2","LeptonPairMassScale",0,0) process+=addFirstJet("40") process+=addSecondJet("30") process+=addLeptonPairCut("60","120") elif "Z-LowMass-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("20","70") elif "Z-MedMass-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("40","130") elif "Z-LowMass-mu" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) process+=addLeptonPairCut("10","70") elif "Z-Mass1" in parameterName : process+=addLeptonPairCut("10","35") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "Z-Mass2" in parameterName : process+=addLeptonPairCut("25","70") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "Z-Mass3" in parameterName : process+=addLeptonPairCut("60","120") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "Z-Mass4" in parameterName : process+=addLeptonPairCut("115","8000") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "Z-HighMass1" in parameterName : process+=addLeptonPairCut("116","400") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "Z-HighMass2" in parameterName : process+=addLeptonPairCut("400","7000") if "-e" in parameterName : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p e+ e-","0","2","LeptonPairMassScale",2,2) else : if(simulation=="Matchbox"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",0,0) elif(simulation=="Merging"): process+=addProcess(thefactory,"p p mu+ mu-","0","2","LeptonPairMassScale",2,2) elif "W-Jet" in parameterName : if(simulation=="Merging"): logging.warning("W-Jet not explicitly tested for %s " % simulation) sys.exit(0) process+=addProcess(thefactory,"p p e+ nu j","1","2","HTScale",0,0) process+=addProcess(thefactory,"p p e- nu j","1","2","HTScale",0,0) process+=addLeptonPairCut("60","120") if "W-Jet-1-e" in parameterName : process+=addFirstJet("100") parameterName=parameterName.replace("W-Jet-1-e","W-Jet-e") elif "W-Jet-2-e" in parameterName : process+=addFirstJet("190") parameterName=parameterName.replace("W-Jet-2-e","W-Jet-e") elif "W-Jet-3-e" in parameterName : process+=addFirstJet("270") parameterName=parameterName.replace("W-Jet-3-e","W-Jet-e") else : logging.error("Exit 00005") sys.exit(1) elif "Z-Jet" in parameterName : if(simulation=="Merging"): logging.warning("Z-Jet not explicitly tested for %s " % simulation) sys.exit(0) if "-e" in parameterName : process+=addProcess(thefactory,"p p e+ e- j","1","2","HTScale",0,0) if "Z-Jet-0-e" in parameterName : process+=addFirstJet("35") parameterName=parameterName.replace("Z-Jet-0-e","Z-Jet-e") elif "Z-Jet-1-e" in parameterName : process+=addFirstJet("100") parameterName=parameterName.replace("Z-Jet-1-e","Z-Jet-e") elif "Z-Jet-2-e" in parameterName : process+=addFirstJet("190") parameterName=parameterName.replace("Z-Jet-2-e","Z-Jet-e") elif "Z-Jet-3-e" in parameterName : process+=addFirstJet("270") parameterName=parameterName.replace("Z-Jet-3-e","Z-Jet-e") else : logging.error("Exit 00006") sys.exit(1) else : process+=addProcess(thefactory,"p p mu+ mu- j","1","2","HTScale",0,0) process+=addFirstJet("35") parameterName=parameterName.replace("Z-Jet-0-mu","Z-Jet-mu") process+=addLeptonPairCut("60","120") elif "Z-bb" in parameterName : if(simulation=="Merging"): logging.warning("Z-bb not explicitly tested for %s " % simulation) sys.exit(0) parameters["bscheme"]=fourFlavour process+="set /Herwig/Particles/b:HardProcessMass 4.2*GeV\nset /Herwig/Particles/bbar:HardProcessMass 4.2*GeV\n" process+=addProcess(thefactory,"p p e+ e- b bbar","2","2","FixedScale",0,0) process+=addLeptonPairCut("66","116") process+=addFirstJet("18") process+=addSecondJet("15") process+=addLeptonPairCut("60","120") elif "Z-b" in parameterName : if(simulation=="Merging"): logging.warning("Z-b not explicitly tested for %s " % simulation) sys.exit(0) process+=particlegroup('bjet','b','bbar') process+=addProcess(thefactory,"p p e+ e- bjet","1","2","FixedScale",0,0) process+="set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 91.2*GeV\n" process+=addLeptonPairCut("60","120") process+=addFirstJet("15") elif "W-b" in parameterName : if(simulation=="Merging"): logging.warning("W-b not explicitly tested for %s " % simulation) sys.exit(0) parameters["bscheme"]=fourFlavour process += "set /Herwig/Particles/b:HardProcessMass 4.2*GeV\nset /Herwig/Particles/bbar:HardProcessMass 4.2*GeV\n" process+=addProcess(thefactory,"p p e- nu b bbar","2","2","FixedScale",0,0) process+=addProcess(thefactory,"p p mu+ nu b bbar","2","2","FixedScale",0,0) process += "set /Herwig/MatrixElements/Matchbox/Scales/FixedScale:FixedScale 80.4*GeV\n" process+=addFirstJet("30") process+=addLeptonPairCut("60","120") else : logging.error(" Process %s not supported for Matchbox matrix elements" % name) sys.exit(1) # LHC-GammaGamma elif(collider=="LHC-GammaGamma" ) : if "-7-" in parameterName : process = StringBuilder(collider_lumi(7000.0)) elif "-8-" in parameterName : process = StringBuilder(collider_lumi(8000.0)) else : process = StringBuilder(collider_lumi(7000.0)) if(simulation=="") : if "7" in parameterName : process += insert_ME("MEgg2ff","Muon") else : logging.error(" Process %s not supported for default matrix elements" % name) sys.exit(1) else : logging.error("LHC-GammaGamma not supported for %s " % simulation) sys.exit(1) parameters['parameterFile'] = os.path.join(collider,"{c}-{pn}.in".format(c=collider, pn=parameterName)) parameters['runname'] = 'Rivet-%s' % name parameters['process'] = str(process) #check if selecteddecaymode and addedBRReweighter is consistent if selecteddecaymode and not addedBRReweighter: logging.error("Decaymode was selected but no BRReweighter was added.") sys.exit(1) if addedBRReweighter and not selecteddecaymode: logging.error("BRReweighter was added but no Decaymode was selected.") sys.exit(1) # check that we only add one process if in merging mode: if numberOfAddedProcesses > 1 and simulation =="Merging": logging.error("In Merging only one process is allowed at the moment. See ticket #403.") sys.exit(1) # Check if a process was added for Merging or Matchbox: if numberOfAddedProcesses == 0 and (simulation =="Merging" or simulation =="Matchbox"): logging.error("No process was selected.") sys.exit(1) # get template and write the file with open(os.path.join("Rivet/Templates",templateName), 'r') as f: templateText = f.read() template = Template( templateText ) with open(os.path.join("Rivet",name+".in"), 'w') as f: f.write( template.substitute(parameters) ) diff --git a/Tests/python/merge-LHC-EW b/Tests/python/merge-LHC-EW --- a/Tests/python/merge-LHC-EW +++ b/Tests/python/merge-LHC-EW @@ -1,393 +1,401 @@ #! /usr/bin/env python import logging import sys import os, yoda """%prog Script for merging aida files """ def fillAbove(scale,desthisto, sourcehistosbyptmin) : pthigh= 1e100 ptlow =-1e100 for pt, h in sorted(sourcehistosbyptmin.iteritems(),reverse=True): ptlow=pt if(type(desthisto)==yoda.core.Scatter2D) : for i in range(0,h.numPoints) : xMin = h.points[i].x-h.points[i].xErrs.minus if( xMin*scale >= ptlow and xMin*scale < pthigh ) : desthisto.addPoint(h.points[i]) elif(type(desthisto)==yoda.core.Profile1D) : for i in range(0,h.numBins) : if(h.bins[i].xMin*scale >= ptlow and h.bins[i].xMin*scale < pthigh ) : desthisto.bins[i] += h.bins[i] elif(type(desthisto)==yoda.core.Histo1D) : for i in range(0,h.numBins) : if(h.bins[i].xMin*scale >= ptlow and h.bins[i].xMin*scale < pthigh ) : desthisto.bins[i] += h.bins[i] else : logging.error("Can't merge %s, unknown type" % desthisto.path) sys.exit(1) pthigh=pt def mergeByMass(hpath, sqrts, scale=1.): global inhistos_mass global outhistos try: fillAbove(scale,outhistos[hpath], inhistos_mass[hpath][float(sqrts)]) except: pass def useOneMass(hpath, sqrts, ptmin): global inhistos_mass global outhistos try: ## Find best pT_min match ptmins = inhistos_mass[hpath][float(sqrts)].keys() closest_ptmin = None for ptm in ptmins: if closest_ptmin is None or \ abs(ptm-float(ptmin)) < abs(closest_ptmin-float(ptmin)): closest_ptmin = ptm if closest_ptmin != float(ptmin): logging.warning("Inexact match for requested pTmin=%s: " % ptmin + \ "using pTmin=%e instead" % closest_ptmin) outhistos[hpath] = inhistos_mass[hpath][float(sqrts)][closest_ptmin] except: pass import sys if sys.version_info[:3] < (2,4,0): print "rivet scripts require Python version >= 2.4.0... exiting" sys.exit(1) if __name__ == "__main__": import logging from optparse import OptionParser, OptionGroup - parser = OptionParser(usage="%prog aidafile aidafile2 [...]") - parser.add_option("-o", "--out", dest="OUTFILE", default="-") + parser = OptionParser(usage="%prog base") verbgroup = OptionGroup(parser, "Verbosity control") verbgroup.add_option("-v", "--verbose", action="store_const", const=logging.DEBUG, dest="LOGLEVEL", default=logging.INFO, help="print debug (very verbose) messages") verbgroup.add_option("-q", "--quiet", action="store_const", const=logging.WARNING, dest="LOGLEVEL", default=logging.INFO, help="be very quiet") parser.add_option_group(verbgroup) (opts, args) = parser.parse_args() logging.basicConfig(level=opts.LOGLEVEL, format="%(message)s") ## Check args if len(args) < 1: - logging.error("Must specify at least one AIDA histogram file") + logging.error("Must specify at least the name of the files") sys.exit(1) + yodafiles=["-13-Z-e","-13-Z-mu","-Z-HighMass1-e","-Z-HighMass2-e", + "-8-Z-Mass1-e","-8-Z-Mass1-mu","-8-Z-Mass2-e","-8-Z-Mass2-mu","-8-Z-Mass3-e","-8-Z-Mass3-mu","-8-Z-Mass4-e","-8-Z-Mass4-mu", + "-W-e","-W-mu","-Z-e","-Z-mu","-Z-mu-Short","-Z-LowMass-e","-Z-LowMass-mu", + "-Z-MedMass-e","-W-Z-e","-W-Z-mu", + "-WW-emu","-WW-ll","-WZ","-ZZ-ll","-ZZ-lv","-8-WZ","-13-WZ","-8-ZZ-lv","-8-WW-ll", + "-7-W-Jet-1-e","-7-W-Jet-2-e","-7-W-Jet-3-e","-7-Z-Jet-1-e","-7-Z-Jet-2-e","-7-Z-Jet-3-e", + "-7-WGamma-e","-7-WGamma-mu","-7-ZGamma-e","-7-ZGamma-mu"] ## Get histos outhistos={} inhistos_mass = {} - for file in args: + for f in yodafiles: + file='Rivet-'+args[0]+f+".yoda" if not os.access(file, os.R_OK): logging.error("%s can not be read" % file) break try: aos = yoda.read(file) except: - logging.error("%s can not be parsed as XML" % file) + logging.error("%s can not be parsed as yoda" % file) break mass=66 if(file.find("HighMass1")>=0) : mass = 116 elif(file.find("HighMass2")>=0) : mass = 400 elif(file.find("Mass1")>=0) : mass = 12 elif(file.find("Mass2")>=0) : mass = 30 elif(file.find("Mass3")>=0) : mass = 66 elif(file.find("Mass4")>=0) : mass = 116 ## Get histos from this YODA file for aopath, ao in aos.iteritems() : if(aopath.find("ATLAS_2010_S8919674")>0) : if((aopath.find("d01")>0 or aopath.find("d05")>0 or aopath.find("d07")>0) and file.find("-e")>0) : outhistos[aopath] = ao elif((aopath.find("d02")>0 or aopath.find("d06")>0 or aopath.find("d08")>0) and file.find("-mu")>0) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2011_S9131140")>0) : if(aopath.find("d01")>0 and file.find("-e")>0) : outhistos[aopath] = ao elif(aopath.find("d02")>0 and file.find("-mu")>0) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2011_I925932")>0) : if(aopath.find("d01")>0 and file.find("-e")>0) : outhistos[aopath] = ao elif(aopath.find("d02")>0 and file.find("-mu")>0) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2011_I945498")>0) : if(aopath.find("y01")>0 and file.find("-e")>0) : outhistos[aopath] = ao elif(aopath.find("y02")>0 and file.find("-mu")>0) : outhistos[aopath] = ao elif(aopath.find("y03")>0 and file.find("-mu")>0) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2013_I1217867")>0) : if(aopath.find("y01")>0 and file.find("-e")>0) : outhistos[aopath] = ao elif(aopath.find("y02")>0 and file.find("-mu")>0) : outhistos[aopath] = ao elif (aopath.find("CMS_2012_I941555")>0) : if((aopath.find("y01")>0 or aopath.find("y03")>0 ) and file.find("-mu")>0) : outhistos[aopath] = ao elif(aopath.find("y02")>0 and file.find("-e")>0) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2014_I1300647" )>0) : if(aopath.find("y01")>0 and file.find("-e")>0) : outhistos[aopath] = ao elif((not aopath.find("y01")>0) and file.find("-mu")>0) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2014_I1288706" )>0) : if(aopath.find("y02")>0 and file.find("-e")>0) : outhistos[aopath] = ao elif(aopath.find("y01")>0 and file.find("-mu")>0) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2012_I1204784" )>0) : if( file.find("-e")>0 and ( aopath.find("d03")>0 or ((aopath.find("d01")>0 or aopath.find("d02")>0) and aopath.find("y01")>0))) : outhistos[aopath] = ao elif(file.find("-mu")>0 and ( aopath.find("d04")>0 or ((aopath.find("d01")>0 or aopath.find("d02")>0) and aopath.find("y02")>0))) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2014_I1312627_EL") >0) : if(file.find("-e")>0) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2014_I1312627_MU") >0) : if(file.find("-mu")>0) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2014_I1312627") >0) : if(file.find("-e")>0) : outhistos[aopath] = ao elif (aopath.find("CMS_2013_I1224539_WJET" )>0) : if(file.find("-1-e")>0 and (aopath.find("d52")>0 or aopath.find("d53")>0 or aopath.find("d56")>0 or aopath.find("d57")>0 or aopath.find("d60")>0 or aopath.find("d61")>0 or aopath.find("d64")>0 or aopath.find("d65")>0 or aopath.find("d68")>0 or aopath.find("d69")>0 or aopath.find("d72")>0)) : outhistos[aopath] = ao elif(file.find("-2-e")>0 and (aopath.find("d54")>0 or aopath.find("d58")>0 or aopath.find("d62")>0 or aopath.find("d66")>0 or aopath.find("d70")>0 or aopath.find("d73")>0)) : outhistos[aopath] = ao elif(file.find("-3-e")>0 and (aopath.find("d55")>0 or aopath.find("d59")>0 or aopath.find("d63")>0 or aopath.find("d67")>0 or aopath.find("d71")>0 or aopath.find("d74")>0)) : outhistos[aopath] = ao elif (aopath.find("CMS_2013_I1224539_ZJET" )>0) : if(file.find("-1-e")>0 and (aopath.find("d29")>0 or aopath.find("d30")>0 or aopath.find("d33")>0 or aopath.find("d34")>0 or aopath.find("d37")>0 or aopath.find("d38")>0 or aopath.find("d41")>0 or aopath.find("d42")>0 or aopath.find("d45")>0 or aopath.find("d46")>0 or aopath.find("d49")>0)) : outhistos[aopath] = ao elif(file.find("-2-e")>0 and (aopath.find("d31")>0 or aopath.find("d35")>0 or aopath.find("d39")>0 or aopath.find("d43")>0 or aopath.find("d47")>0 or aopath.find("d50")>0)) : outhistos[aopath] = ao elif(file.find("-3-e")>0 and (aopath.find("d32")>0 or aopath.find("d36")>0 or aopath.find("d40")>0 or aopath.find("d44")>0 or aopath.find("d48")>0 or aopath.find("d51")>0)) : outhistos[aopath] = ao elif (aopath.find("CMS_2013_I1258128")>0) : if(aopath.find("d01")>0 or aopath.find("d02")>0 or aopath.find("d03")>0 or aopath.find("d04")>0) : outhistos[aopath] = ao elif (aopath.find("CMS_2013_I1209721" )>0 and file.find("-0")>0 ) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2011_I928289")>0) : if(file.find("-e")>=0 and (aopath.find("y01")>=0 or aopath.find("y02")>=0)) : outhistos[aopath] = ao elif(file.find("-mu")>=0 and (aopath.find("y03")>=0 or aopath.find("y04")>=0)) : outhistos[aopath] = ao elif (aopath.find("CMS_2013_I1122847")>0) : if(file.find("-mu")>=0 and aopath.find("d01")>=0 ) : outhistos[aopath] = ao elif(file.find("-e")>=0 and (aopath.find("d02")>=0 or aopath.find("d03")>=0)) : outhistos[aopath] = ao elif (aopath.find("ATLAS_2016_I1424838")>0) : if(file.find("-mu")>=0 and aopath.find("x02")>=0 ) : outhistos[aopath] = ao elif(file.find("-e")>=0 and (aopath.find("x01")>=0)) : outhistos[aopath] = ao elif (aopath.find("CMS_2015_I1310737")>0) : if aopath in outhistos : outhistos[aopath] += ao else : outhistos[aopath] = ao elif (aopath.find("ATLAS_2015_I1351916")>=0) : if(aopath.find("-y01")>=0) : pathBase = aopath.replace("-y01","") hp = aos[pathBase+"-y02"] hm = aos[pathBase+"-y03"] ratio = (hp-hm)/(hp+hm) hnew = yoda.Scatter2D(aopath,ao.title) hnew.combineWith(ratio) outhistos[aopath] = hnew else : continue elif (aopath.find("ATLAS_2014_I1282447")>=0) : if((aopath.find("/ATLAS_2014_I1282447/d02-x01-y01")>=0 or aopath.find("/ATLAS_2014_I1282447/d08-x01-y01")>=0 or aopath.find("/ATLAS_2014_I1282447/d02-x01-y02")>=0 or aopath.find("/ATLAS_2014_I1282447/d02-x01-y01")>=0 or aopath.find("/ATLAS_2014_I1282447/d05-x01-y02")>=0 or aopath.find("/ATLAS_2014_I1282447/d05-x01-y03")>=0 or aopath.find("/ATLAS_2014_I1282447/d06-x01-y01")>=0 or aopath.find("/ATLAS_2014_I1282447/d06-x01-y02")>=0 or aopath.find("/ATLAS_2014_I1282447/d06-x01-y03")>=0 or aopath.find("/ATLAS_2014_I1282447/d06-x01-y04")>=0) and not (aopath.find("plus")>=0 or aopath.find("minus")>=0 or aopath.find("inc")>=0)) : continue if aopath in outhistos : outhistos[aopath] += ao else : outhistos[aopath] = ao elif (aopath.find("ATLAS_2015_I1408516")>=0) : if not inhistos_mass.has_key(aopath): inhistos_mass[aopath] = {} tmpE = inhistos_mass[aopath] sqrts=8000 if not tmpE.has_key(sqrts): tmpE[sqrts] = {} tmpP = tmpE[sqrts] if not tmpP.has_key(mass): tmpP[mass] = ao else: raise Exception("A set with mass = %s already exists" % ( mass)) elif (aopath.find("ATLAS_2013_I1234228")>=0) : if not inhistos_mass.has_key(aopath): inhistos_mass[aopath] = {} tmpE = inhistos_mass[aopath] sqrts=7000 if not tmpE.has_key(sqrts): tmpE[sqrts] = {} tmpP = tmpE[sqrts] if not tmpP.has_key(mass): tmpP[mass] = ao else: raise Exception("A set with mass = %s already exists" % ( mass)) else : outhistos[aopath] = ao for hpath,hsets in inhistos_mass.iteritems(): if(hpath!="/ATLAS_2015_I1408516_EL/d41-x01-y01" and hpath!="/ATLAS_2015_I1408516_MU/d41-x01-y02" and hpath!="/ATLAS_2013_I1234228/d01-x01-y02" ) : continue if(type(hsets.values()[0].values()[0])==yoda.core.Scatter2D) : outhistos[hpath] = yoda.core.Scatter2D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) elif(type(hsets.values()[0].values()[0])==yoda.core.Profile1D) : outhistos[hpath] = yoda.core.Profile1D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) for i in range(0,hsets.values()[0].values()[0].numBins) : outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin, hsets.values()[0].values()[0].bins[i].xMax) elif(type(hsets.values()[0].values()[0])==yoda.core.Histo1D) : outhistos[hpath] = yoda.core.Histo1D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) for i in range(0,hsets.values()[0].values()[0].numBins) : outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin, hsets.values()[0].values()[0].bins[i].xMax) else : logging.error("Histogram %s is of unknown type" % hpath) sys.exit(1) # sort out mass bins for ATLAS Z-> e,mu at 8 TeV for ltype in ["EL","MU"] : if(ltype=="EL") : y = "y01" mergeByMass("/ATLAS_2015_I1408516_EL/d41-x01-y01", "8000") else : y = "y04" mergeByMass("/ATLAS_2015_I1408516_MU/d41-x01-y02", "8000") for d in [2,3,04,14,26,38]: useOneMass("/ATLAS_2015_I1408516_%s/d%02d-x01-%s" % (ltype,d,y), "8000", "30" ) for d in [5,6,7,8,9,10,15,17,18,19,20,21,22,27,29,30,31,32,33,34,39]: useOneMass("/ATLAS_2015_I1408516_%s/d%02d-x01-%s" % (ltype,d,y), "8000", "66" ) for d in [11,12,13,16,28,40]: useOneMass("/ATLAS_2015_I1408516_%s/d%02d-x01-%s" % (ltype,d,y), "8000", "116" ) for d in [23,35]: useOneMass("/ATLAS_2015_I1408516_%s/d%02d-x01-%s" % (ltype,d,y), "8000", "12" ) for d in [24,36]: useOneMass("/ATLAS_2015_I1408516_%s/d%02d-x01-%s" % (ltype,d,y), "8000", "12" ) for d in [25,37]: useOneMass("/ATLAS_2015_I1408516_%s/d%02d-x01-%s" % (ltype,d,y), "8000", "30" ) # sort out ratios for ATLAS W+c if("/ATLAS_2014_I1282447/d02-x01-y01_plus" in outhistos and "/ATLAS_2014_I1282447/d02-x01-y01_minus" in outhistos) : d02y01_plus = outhistos["/ATLAS_2014_I1282447/d02-x01-y01_plus"] d02y01_minus = outhistos["/ATLAS_2014_I1282447/d02-x01-y01_minus"] ratio_d02y01 = d02y01_plus/d02y01_minus ratio_d02y01.path = "/ATLAS_2014_I1282447/d02-x01-y01" del outhistos["/ATLAS_2014_I1282447/d02-x01-y01_plus"] del outhistos["/ATLAS_2014_I1282447/d02-x01-y01_minus"] outhistos["/ATLAS_2014_I1282447/d02-x01-y01"] = ratio_d02y01 if("/ATLAS_2014_I1282447/d02-x01-y02_plus" in outhistos and "/ATLAS_2014_I1282447/d02-x01-y02_minus" in outhistos) : d02y02_plus = outhistos["/ATLAS_2014_I1282447/d02-x01-y02_plus"] d02y02_minus = outhistos["/ATLAS_2014_I1282447/d02-x01-y02_minus"] ratio_d02y02 = d02y02_plus/d02y02_minus ratio_d02y02.path = "/ATLAS_2014_I1282447/d02-x01-y02" del outhistos["/ATLAS_2014_I1282447/d02-x01-y02_plus"] del outhistos["/ATLAS_2014_I1282447/d02-x01-y02_minus"] outhistos["/ATLAS_2014_I1282447/d02-x01-y02"] = ratio_d02y02 if("/ATLAS_2014_I1282447/d08-x01-y01_plus" in outhistos and "/ATLAS_2014_I1282447/d08-x01-y01_minus" in outhistos) : d08y01_plus = outhistos["/ATLAS_2014_I1282447/d08-x01-y01_plus"] d08y01_minus = outhistos["/ATLAS_2014_I1282447/d08-x01-y01_minus"] ratio_d08y01 = d08y01_plus/d08y01_minus ratio_d08y01.path = "/ATLAS_2014_I1282447/d08-x01-y01" del outhistos["/ATLAS_2014_I1282447/d08-x01-y01_plus"] del outhistos["/ATLAS_2014_I1282447/d08-x01-y01_minus"] outhistos["/ATLAS_2014_I1282447/d08-x01-y01"] = ratio_d08y01 if ("/ATLAS_2014_I1282447/d05-x01-y01" in outhistos and "/ATLAS_2014_I1282447/d01-x01-y02" in outhistos) : h_winc = outhistos["/ATLAS_2014_I1282447/d05-x01-y01"] h_d = outhistos["/ATLAS_2014_I1282447/d01-x01-y02"] ratio_wd = h_d/h_winc ratio_wd.path = "/ATLAS_2014_I1282447/d05-x01-y02" outhistos["/ATLAS_2014_I1282447/d05-x01-y02"] = ratio_wd if ("/ATLAS_2014_I1282447/d05-x01-y01" in outhistos and "/ATLAS_2014_I1282447/d01-x01-y03" in outhistos) : h_winc = outhistos["/ATLAS_2014_I1282447/d05-x01-y01"] h_dstar= outhistos["/ATLAS_2014_I1282447/d01-x01-y03"] ratio_wdstar = h_dstar/h_winc ratio_wdstar.path = "/ATLAS_2014_I1282447/d05-x01-y03" outhistos["/ATLAS_2014_I1282447/d05-x01-y03"] = ratio_wdstar if("/ATLAS_2014_I1282447/d06-x01-y01_winc" in outhistos and "/ATLAS_2014_I1282447/d06-x01-y02_winc" in outhistos) : h_winc_plus = outhistos["/ATLAS_2014_I1282447/d06-x01-y01_winc"] h_winc_minus = outhistos["/ATLAS_2014_I1282447/d06-x01-y02_winc"] if( "/ATLAS_2014_I1282447/d06-x01-y01_wplus" in outhistos ) : h_wd_plus = outhistos["/ATLAS_2014_I1282447/d06-x01-y01_wplus"] ratio_wd_plus = h_wd_plus/h_winc_plus ratio_wd_plus.path = "/ATLAS_2014_I1282447/d06-x01-y01" outhistos["/ATLAS_2014_I1282447/d06-x01-y01"] = ratio_wd_plus del outhistos["/ATLAS_2014_I1282447/d06-x01-y01_wplus"] if( "/ATLAS_2014_I1282447/d06-x01-y02_wminus" in outhistos ) : h_wd_minus = outhistos["/ATLAS_2014_I1282447/d06-x01-y02_wminus"] ratio_wd_minus = h_wd_minus/h_winc_minus ratio_wd_minus.path = "/ATLAS_2014_I1282447/d06-x01-y02" outhistos["/ATLAS_2014_I1282447/d06-x01-y02"] = ratio_wd_minus del outhistos["/ATLAS_2014_I1282447/d06-x01-y02_wminus"] if ( "/ATLAS_2014_I1282447/d06-x01-y03_wplus" in outhistos) : h_wdstar_plus = outhistos["/ATLAS_2014_I1282447/d06-x01-y03_wplus"] ratio_wdstar_plus = h_wdstar_plus/h_winc_plus ratio_wdstar_plus.path = "/ATLAS_2014_I1282447/d06-x01-y03" outhistos["/ATLAS_2014_I1282447/d06-x01-y03"] = ratio_wdstar_plus del outhistos["/ATLAS_2014_I1282447/d06-x01-y03_wplus"] if ( "/ATLAS_2014_I1282447/d06-x01-y04_wminus" in outhistos) : h_wdstar_minus = outhistos["/ATLAS_2014_I1282447/d06-x01-y04_wminus"] ratio_wdstar_minus = h_wdstar_minus/h_winc_minus ratio_wdstar_minus.path = "/ATLAS_2014_I1282447/d06-x01-y04" outhistos["/ATLAS_2014_I1282447/d06-x01-y04"] = ratio_wdstar_minus del outhistos["/ATLAS_2014_I1282447/d06-x01-y04_wminus"] del outhistos["/ATLAS_2014_I1282447/d06-x01-y01_winc"] del outhistos["/ATLAS_2014_I1282447/d06-x01-y02_winc"] mergeByMass("/ATLAS_2013_I1234228/d01-x01-y02", "7000") # Choose output file - yoda.writeYODA(outhistos,opts.OUTFILE) + name = args[0]+"-EW.yoda" + yoda.writeYODA(outhistos,name) sys.exit(0) diff --git a/Tests/python/merge-LHC-Jets b/Tests/python/merge-LHC-Jets --- a/Tests/python/merge-LHC-Jets +++ b/Tests/python/merge-LHC-Jets @@ -1,1462 +1,1502 @@ #! /usr/bin/env python import logging import sys import math if sys.version_info[:3] < (2,4,0): print "rivet scripts require Python version >= 2.4.0... exiting" sys.exit(1) import os, yoda # ############################################# def fillAbove(scale,desthisto, sourcehistosbyptmin) : pthigh= 1e100 ptlow =-1e100 for pt, h in sorted(sourcehistosbyptmin.iteritems(),reverse=True): ptlow=pt if(type(desthisto)==yoda.core.Scatter2D) : for i in range(0,h.numPoints) : xMin = h.points[i].x-h.points[i].xErrs.minus if( xMin*scale >= ptlow and xMin*scale < pthigh ) : desthisto.addPoint(h.points[i]) elif(type(desthisto)==yoda.core.Profile1D) : for i in range(0,h.numBins) : if(h.bins[i].xMin*scale >= ptlow and h.bins[i].xMin*scale < pthigh ) : desthisto.bins[i] += h.bins[i] elif(type(desthisto)==yoda.core.Histo1D) : for i in range(0,h.numBins) : if(h.bins[i].xMin*scale >= ptlow and h.bins[i].xMin*scale < pthigh ) : desthisto.bins[i] += h.bins[i] elif(type(desthisto)==yoda.core.Counter) : desthisto += h else : logging.error("Can't merge %s, unknown type" % desthisto.path) sys.exit(1) pthigh=pt def mergeByPt(hpath, sqrts, scale=1.) : global inhistos_pt global outhistos try: fillAbove(scale,outhistos[hpath], inhistos_pt[hpath][float(sqrts)]) except: pass def mergeByMass(hpath, sqrts, scale=1.): global inhistos_mass global outhistos try: fillAbove(scale,outhistos[hpath], inhistos_mass[hpath][float(sqrts)]) except: pass def useOnePt(hpath, sqrts, ptmin): global inhistos_pt global outhistos try: ## Find best pT_min match ptmins = inhistos_pt[hpath][float(sqrts)].keys() closest_ptmin = None for ptm in ptmins: if closest_ptmin is None or \ abs(ptm-float(ptmin)) < abs(closest_ptmin-float(ptmin)): closest_ptmin = ptm if closest_ptmin != float(ptmin): logging.warning("Inexact match for requested pTmin=%s: " % ptmin + \ "using pTmin=%e instead" % closest_ptmin) outhistos[hpath] = inhistos_pt[hpath][float(sqrts)][closest_ptmin] except: pass def useOneMass(hpath, sqrts, ptmin): global inhistos_pt global outhistos try: ## Find best pT_min match ptmins = inhistos_mass[hpath][float(sqrts)].keys() closest_ptmin = None for ptm in ptmins: if closest_ptmin is None or \ abs(ptm-float(ptmin)) < abs(closest_ptmin-float(ptmin)): closest_ptmin = ptm if closest_ptmin != float(ptmin): logging.warning("Inexact match for requested mass=%s: " % ptmin + \ "using mass=%e instead" % closest_ptmin) outhistos[hpath] = inhistos_mass[hpath][float(sqrts)][closest_ptmin] except: pass # ####################################### if __name__ == "__main__": import logging from optparse import OptionParser, OptionGroup parser = OptionParser(usage="%prog name") verbgroup = OptionGroup(parser, "Verbosity control") parser.add_option("--with-ue", action='store_true' , dest="ue", default=True, help="Include UE analyses") parser.add_option("--without-ue", action='store_false', dest="ue", default=True, help="Don\'t include UE analyses") verbgroup.add_option("-v", "--verbose", action="store_const", const=logging.DEBUG, dest="LOGLEVEL", default=logging.INFO, help="print debug (very verbose) messages") verbgroup.add_option("-q", "--quiet", action="store_const", const=logging.WARNING, dest="LOGLEVEL", default=logging.INFO, help="be very quiet") parser.add_option_group(verbgroup) (opts, args) = parser.parse_args() logging.basicConfig(level=opts.LOGLEVEL, format="%(message)s") (opts, args) = parser.parse_args() ## Check args if len(args) < 1: logging.error("Must specify at least the name of the files") sys.exit(1) yodafiles=["-7-Bottom-0.yoda","-7-Bottom-1.yoda","-7-Bottom-2.yoda", "-7-Bottom-3.yoda","-7-Bottom-4.yoda","-7-Bottom-5.yoda", "-7-Charm-1.yoda","-7-Charm-2.yoda", "-7-Charm-3.yoda","-7-Charm-4.yoda","-7-Charm-5.yoda", "-7-Top-SL.yoda","-7-Top-L.yoda","-7-Top-All.yoda", "-8-Top-SL.yoda","-8-Top-L.yoda","-8-Top-All.yoda", "-13-Top-L.yoda","-13-Top-SL.yoda"] for i in range(1,11) : for j in [7,8,13] : yodafiles.append("-%1.1i-Jets-%1.1i.yoda" % (j,i)) if(opts.ue) : yodafiles += ["-7-Jets-0.yoda" ,"-8-Jets-0.yoda" , "-900-UE.yoda" ,"-2360-UE.yoda" , "-2760-UE.yoda" ,"-7-UE.yoda" ,"-900-UE-Long.yoda", "-900-UE-Short.yoda","-8-UE.yoda" , "-7-UE-Long.yoda","-13-UE.yoda","-13-UE-Long.yoda"] ## Get histos inhistos_pt = {} inhistos_mass = {} outhistos={} weights = {} for f in yodafiles: file='Rivet-'+args[0]+f ptmin=0. sqrts=7000 # CMS energy if(file.find("-900-")>0) : sqrts=900 elif(file.find("-2360-")>0) : sqrts=2360 elif(file.find("-2760-")>0) : sqrts=2760 elif(file.find("-7-")>=0) : sqrts=7000 elif(file.find("-8-")>=0) : sqrts=8000 elif(file.find("-13-")>0) : sqrts=13000 # pT min if(file.find("UE")>0) : ptmin=0. elif(file.find("Jets-0")>0) : ptmin=4. elif(file.find("Jets-10")>0) : ptmin=1900. elif(file.find("Jets-1")>0) : if( not opts.ue) : ptmin = 10. else : ptmin = 20. elif(file.find("Jets-2")>0) : ptmin=40. elif(file.find("Jets-3")>0) : ptmin=80. elif(file.find("Jets-4")>0) : ptmin=110. elif(file.find("Jets-5")>0) : ptmin=210. elif(file.find("Jets-6")>0) : ptmin=260. elif(file.find("Jets-7")>0) : ptmin=400. elif(file.find("Jets-8")>0) : ptmin=600. elif(file.find("Jets-9")>0) : ptmin=900. elif(file.find("Bottom-0")>0) : ptmin=0. elif(file.find("Bottom-1")>0 or file.find("Charm-1")>0) : ptmin=10. elif(file.find("Bottom-2")>0 or file.find("Charm-2")>0) : ptmin=30. elif(file.find("Bottom-3")>0 or file.find("Charm-3")>0) : ptmin=70. elif(file.find("Bottom-4")>0 or file.find("Charm-4")>0) : ptmin=100. elif(file.find("Bottom-5")>0 or file.find("Charm-5")>0) : ptmin=130. elif(file.find("Top-SL.yoda")>0 or file.find("Top-L.yoda")>0 or \ file.find("Top-All.yoda")>0): ptmin=0. if not os.access(file, os.R_OK): logging.error("%s can not be read" % file) continue try: aos = yoda.read(file) except: logging.error("%s can not be parsed as YODA" % file) continue ## Get histos from this YODA file for aopath, ao in aos.iteritems() : if(aopath.find("S8924791")>0 or aopath.find("S8971293")>0 or aopath.find("S8817804")>0 or aopath.find("I1082936")>0 or aopath.find("S8994773")>0 or aopath.find("S8918562")>0 or aopath.find("S8624100")>0 or aopath.find("S8625980")>0 or aopath.find("S8894728")>0 or aopath.find("S8957746")>0 or aopath.find("S9126244")>0 or aopath.find("S9120041")>0 or aopath.find("S8950903")>0 or aopath.find("S9086218")>0 or aopath.find("S9088458")>0 or aopath.find("I919017" )>0 or aopath.find("I926145" )>0 or aopath.find("S8941262")>0 or aopath.find("S8973270")>0 or aopath.find("I1118269")>0 or aopath.find("I1188891")>0 or aopath.find("I1082009")>0 or aopath.find("I1087342")>0 or aopath.find("S9035664")>0 or aopath.find("I1125575")>0 or aopath.find("I1094564")>0 or aopath.find("I930220" )>0 or aopath.find("I1224539")>0 or aopath.find("I1273574")>0 or aopath.find("I1261026")>0 or aopath.find("I1307243")>0 or aopath.find("I1325553")>0 or aopath.find("I1298810")>0 or aopath.find("I1298811")>0 or aopath.find("I1208923")>0 or aopath.find("I1305624")>0 or aopath.find("I1419070")>0 or aopath.find("I1394679")>0 or aopath.find("I929691" )>0 or aopath.find("I1393758")>0 or aopath.find("I1459051")>0 or aopath.find("I1487277")>0 or - aopath.find("I1421646")>0 or + aopath.find("I1421646")>0 or aopath.find("I1111014")>0 or + aopath.find("I1605749")>0 or aopath.find("ATLAS_2016_CONF_2016_092")>0 or aopath.find("CMS_2012_PAS_QCD_11_010")>0) : if not inhistos_pt.has_key(aopath): inhistos_pt[aopath] = {} tmpE = inhistos_pt[aopath] if not tmpE.has_key(sqrts): tmpE[sqrts] = {} if not tmpE[sqrts].has_key(ptmin): tmpE[sqrts][ptmin] = ao else: tmpE[sqrts][ptmin] += ao #raise Exception("A set with ptmin = %s already exists" % ( ptmin)) else : if(aopath.find("I1243871")>0) : if(aopath.find("x01")>0 and file.find("-7-Top-L.yoda")>0 ) : outhistos[aopath] = ao elif(aopath.find("x02")>0 and file.find("-7-Top-SL.yoda")>0 ) : outhistos[aopath] = ao elif(aopath.find("1467230")>0 or aopath.find("1419652")>0) : if(aopath.find("y01")>0 and file.find("Long")>0 ) : outhistos[aopath] = ao elif(aopath.find("y02")>0 and file.find("Long")<0 ) : outhistos[aopath] = ao else : outhistos[aopath] = ao yodafiles=["-7-Bottom-6.yoda","-7-Bottom-7.yoda","-7-Bottom-8.yoda"] for i in range(1,8) : yodafiles.append("-7-DiJets-%1.1i-A.yoda" % i) yodafiles.append("-7-DiJets-%1.1i-B.yoda" % i) yodafiles.append("-7-DiJets-%1.1i-C.yoda" % i) for f in yodafiles: file='Rivet-'+args[0]+f if(file.find("-7-Jets-1")>0) : sqrts=7000 mass=0 if(file.find("-7-DiJets-1")>0) : sqrts=7000 mass=100 elif(file.find("-7-DiJets-2")>0) : sqrts=7000 mass=250 elif(file.find("-7-DiJets-3")>0) : sqrts=7000 mass=500 elif(file.find("-7-DiJets-4")>0) : sqrts=7000 mass=800 elif(file.find("-7-DiJets-5")>0) : sqrts=7000 mass=1000 elif(file.find("-7-DiJets-6")>0) : sqrts=7000 mass=1600 elif(file.find("-7-DiJets-7")>0) : sqrts=7000 mass=2200 elif(file.find("-7-DiJets-8")>0) : sqrts=7000 mass=2800 elif(file.find("-7-Bottom-6")>0) : sqrts=7000 mass=110 elif(file.find("-7-Bottom-7")>0) : sqrts=7000 mass=370 elif(file.find("-7-Bottom-8")>0) : sqrts=7000 mass=550 if not os.access(file, os.R_OK): logging.error("%s can not be read" % file) continue try: aos = yoda.read(file) except: logging.error("%s can not be parsed as YODA" % file) continue ## Get histos from this YODA file for aopath, ao in aos.iteritems() : if(aopath.find("8817804")>0 or aopath.find("8968497")>0 or aopath.find("1082936")>0 or aopath.find("I930220")>0 or aopath.find("1261026")>0 or aopath.find("1090423")>0 or aopath.find("1268975")>0 or aopath.find("CMS_2013_I1208923")>0) : if not inhistos_mass.has_key(aopath): inhistos_mass[aopath] = {} tmpE = inhistos_mass[aopath] if not tmpE.has_key(sqrts): tmpE[sqrts] = {} tmpP = tmpE[sqrts] if not tmpP.has_key(mass): tmpP[mass] = ao else: print aopath raise Exception("A set with mass = %s already exists" % ( mass)) ## Make empty output histos if needed for hpath,hsets in inhistos_pt.iteritems(): if( hpath.find("8924791")>0 or hpath.find("8971293")>0 or hpath.find("8817804")>0 or hpath.find("8968497")>0 or (hpath.find("9120041")>0 and (hpath.find("d01")>0 or hpath.find("d02")>0)) or hpath.find("9126244")>0 or hpath.find("926145") >0 or hpath.find("9086218")>0 or hpath.find("1082936")>0 or hpath.find("8941262")>0 or hpath.find("1118269")>0 or hpath.find("1087342")>0 or hpath.find("1188891")>0 or hpath.find("919017")>0 or hpath.find("9035664")>0 or hpath.find("1125575")>0 or hpath.find("1094564")>0 or hpath.find("I930220")>0 or hpath.find("S9088458")>0 or hpath.find("I1273574")>0 or hpath.find("I1261026")>0 or hpath.find("I1090423")>0 or hpath.find("QCD_11_010")>0 or hpath.find("1298811" )>0 or hpath.find("I1325553" )>0 or hpath.find("I1298810" )>0 or hpath.find("1307243" )>0 or hpath.find("I1419070")>0 or hpath.find("I1394679")>0 or hpath.find("I1487277")>0 or hpath.find("CMS_2013_I1208923")>0 or hpath.find("1393758")>0 or hpath.find("ATLAS_2016_CONF_2016_092")>0 or + hpath.find("1111014" )>0 or hpath.find("1459051")>0) : if(type(hsets.values()[0].values()[0])==yoda.core.Counter) : outhistos[hpath] = yoda.core.Counter(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) elif(type(hsets.values()[0].values()[0])==yoda.core.Scatter2D) : outhistos[hpath] = yoda.core.Scatter2D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) elif(type(hsets.values()[0].values()[0])==yoda.core.Profile1D) : outhistos[hpath] = yoda.core.Profile1D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) for i in range(0,hsets.values()[0].values()[0].numBins) : outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin, hsets.values()[0].values()[0].bins[i].xMax) elif(type(hsets.values()[0].values()[0])==yoda.core.Histo1D) : outhistos[hpath] = yoda.core.Histo1D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) for i in range(0,hsets.values()[0].values()[0].numBins) : outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin, hsets.values()[0].values()[0].bins[i].xMax) else : logging.error("Histogram %s is of unknown type" % hpath) sys.exit(1) ## Make empty output histos if needed for hpath,hsets in inhistos_mass.iteritems(): if(hpath.find("1268975")>0) : if(type(hsets.values()[0].values()[0])==yoda.core.Counter) : outhistos[hpath] = yoda.core.Counter(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) elif(type(hsets.values()[0].values()[0])==yoda.core.Scatter2D) : outhistos[hpath] = yoda.core.Scatter2D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) elif(type(hsets.values()[0].values()[0])==yoda.core.Profile1D) : outhistos[hpath] = yoda.core.Profile1D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) for i in range(0,hsets.values()[0].values()[0].numBins) : outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin, hsets.values()[0].values()[0].bins[i].xMax) elif(type(hsets.values()[0].values()[0])==yoda.core.Histo1D) : outhistos[hpath] = yoda.core.Histo1D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) for i in range(0,hsets.values()[0].values()[0].numBins) : outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin, hsets.values()[0].values()[0].bins[i].xMax) else : logging.error("Histogram %s is of unknown type" % hpath) sys.exit(1) logging.info("Processing CMS_2011_S8957746") useOnePt("/CMS_2011_S8957746/d01-x01-y01", "7000", "80" ) useOnePt("/CMS_2011_S8957746/d02-x01-y01", "7000", "80" ) useOnePt("/CMS_2011_S8957746/d03-x01-y01", "7000", "110" ) useOnePt("/CMS_2011_S8957746/d04-x01-y01", "7000", "110" ) useOnePt("/CMS_2011_S8957746/d05-x01-y01", "7000", "210" ) useOnePt("/CMS_2011_S8957746/d06-x01-y01", "7000", "210" ) logging.info("Processing ATLAS_2010_S8894728") useOnePt("/ATLAS_2010_S8894728/d01-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d01-x01-y02", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d01-x01-y03", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d02-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d02-x01-y02", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d02-x01-y03", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d03-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d03-x01-y02", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d03-x01-y03", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d04-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d04-x01-y02", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d04-x01-y03", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d05-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d06-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d07-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d08-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d09-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d09-x01-y02", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d09-x01-y03", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d10-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d10-x01-y02", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d10-x01-y03", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d11-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d11-x01-y02", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d11-x01-y03", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d12-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d12-x01-y02", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d12-x01-y03", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d13-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d13-x01-y02", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d13-x01-y03", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d13-x01-y04", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d14-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d14-x01-y02", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d14-x01-y03", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d14-x01-y04", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d15-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d15-x01-y02", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d15-x01-y03", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d15-x01-y04", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d16-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d16-x01-y02", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d16-x01-y03", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d16-x01-y04", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d17-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d17-x01-y02", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d17-x01-y03", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d18-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d18-x01-y02", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d18-x01-y03", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d19-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d19-x01-y02", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d19-x01-y03", "900", "0" ) useOnePt("/ATLAS_2010_S8894728/d20-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d20-x01-y02", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d20-x01-y03", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d21-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8894728/d22-x01-y01", "7000", "0" ) logging.info("Processing ATLAS_2011_S8994773") useOnePt("/ATLAS_2011_S8994773/d01-x01-y01", "900", "0" ) useOnePt("/ATLAS_2011_S8994773/d02-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2011_S8994773/d03-x01-y01", "900", "0" ) useOnePt("/ATLAS_2011_S8994773/d04-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2011_S8994773/d13-x01-y01", "900", "0" ) useOnePt("/ATLAS_2011_S8994773/d13-x01-y02", "900", "0" ) useOnePt("/ATLAS_2011_S8994773/d13-x01-y03", "900", "0" ) useOnePt("/ATLAS_2011_S8994773/d14-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2011_S8994773/d14-x01-y02", "7000", "0" ) useOnePt("/ATLAS_2011_S8994773/d14-x01-y03", "7000", "0" ) logging.info("Processing ALICE_2010_S8624100") useOnePt("/ALICE_2010_S8624100/d11-x01-y01", "900", "0" ) useOnePt("/ALICE_2010_S8624100/d12-x01-y01", "900", "0" ) useOnePt("/ALICE_2010_S8624100/d13-x01-y01", "900", "0" ) useOnePt("/ALICE_2010_S8624100/d17-x01-y01","2360", "0" ) useOnePt("/ALICE_2010_S8624100/d18-x01-y01","2360", "0" ) useOnePt("/ALICE_2010_S8624100/d19-x01-y01","2360", "0" ) logging.info("Processing ALICE_2010_S8625980") useOnePt("/ALICE_2010_S8625980/d03-x01-y01", "7000", "0" ) useOnePt("/ALICE_2010_S8625980/d04-x01-y01", "900", "0" ) useOnePt("/ALICE_2010_S8625980/d05-x01-y01", "2360", "0" ) useOnePt("/ALICE_2010_S8625980/d06-x01-y01", "7000", "0" ) logging.info("Processing ATLAS_2010_S8918562") useOnePt("/ATLAS_2010_S8918562/d01-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d02-x01-y01", "2360", "0" ) useOnePt("/ATLAS_2010_S8918562/d03-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d04-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d05-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d06-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d07-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d08-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d09-x01-y01", "2360", "0" ) useOnePt("/ATLAS_2010_S8918562/d10-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d11-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d12-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d13-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d14-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d15-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d16-x01-y01", "2360", "0" ) useOnePt("/ATLAS_2010_S8918562/d17-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d18-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d19-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d20-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d21-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d22-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d23-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d24-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d25-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d26-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d27-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d28-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d29-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d30-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d31-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d32-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d33-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d34-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d35-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d36-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d37-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2010_S8918562/d38-x01-y01", "900", "0" ) useOnePt("/ATLAS_2010_S8918562/d39-x01-y01", "7000", "0" ) logging.info("Processing ATLAS_2011_S8971293") useOnePt("/ATLAS_2011_S8971293/d01-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8971293/d01-x01-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8971293/d01-x01-y03", "7000", "210" ) useOnePt("/ATLAS_2011_S8971293/d01-x01-y04", "7000", "260" ) useOnePt("/ATLAS_2011_S8971293/d01-x01-y05", "7000", "260" ) useOnePt("/ATLAS_2011_S8971293/d01-x01-y06", "7000", "400" ) useOnePt("/ATLAS_2011_S8971293/d01-x01-y07", "7000", "400" ) useOnePt("/ATLAS_2011_S8971293/d01-x01-y08", "7000", "600" ) useOnePt("/ATLAS_2011_S8971293/d01-x01-y09", "7000", "600" ) logging.info("Processing ATLAS_2011_S8924791") if( not opts.ue) : useOnePt("/ATLAS_2011_S8924791/d01-x01-y01", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x01-y02", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x02-y01", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x02-y02", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x03-y01", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x03-y02", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x04-y01", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x04-y02", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x05-y01", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x05-y02", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x06-y01", "7000", "10" ) useOnePt("/ATLAS_2011_S8924791/d01-x06-y02", "7000", "10" ) else : useOnePt("/ATLAS_2011_S8924791/d01-x01-y01", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x01-y02", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x02-y01", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x02-y02", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x03-y01", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x03-y02", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x04-y01", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x04-y02", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x05-y01", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x05-y02", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x06-y01", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d01-x06-y02", "7000", "20" ) useOnePt("/ATLAS_2011_S8924791/d02-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x02-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x02-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x03-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x03-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x04-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x04-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x05-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x05-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x06-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d02-x06-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x02-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x02-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x03-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x03-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x04-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x04-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x05-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x05-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x06-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d03-x06-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S8924791/d04-x01-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x01-y02", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x02-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x02-y02", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x03-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x03-y02", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x04-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x04-y02", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x05-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x05-y02", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x06-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d04-x06-y02", "7000", "80" ) useOnePt("/ATLAS_2011_S8924791/d05-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x01-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x02-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x02-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x03-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x03-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x04-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x04-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x05-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x05-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x06-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d05-x06-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x01-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x02-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x02-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x03-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x03-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x04-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x04-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x05-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x05-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x06-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d06-x06-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S8924791/d07-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x02-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x02-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x03-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x03-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x04-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x04-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x05-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x05-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x06-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d07-x06-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S8924791/d08-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x01-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x02-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x02-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x03-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x03-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x04-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x04-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x05-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x05-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x06-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d08-x06-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x01-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x02-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x02-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x03-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x03-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x04-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x04-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x05-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x05-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x06-y01", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d09-x06-y02", "7000", "260" ) useOnePt("/ATLAS_2011_S8924791/d10-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x01-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x02-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x02-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x03-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x03-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x04-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x04-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x05-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x05-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x06-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d10-x06-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x01-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x02-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x02-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x03-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x03-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x04-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x04-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x05-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x05-y02", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x06-y01", "7000", "400" ) useOnePt("/ATLAS_2011_S8924791/d11-x06-y02", "7000", "400" ) logging.info("Processing ATLAS_2010_S8817804") mergeByPt("/ATLAS_2010_S8817804/d01-x01-y01", "7000") mergeByPt("/ATLAS_2010_S8817804/d02-x01-y01", "7000") mergeByPt("/ATLAS_2010_S8817804/d03-x01-y01", "7000") mergeByPt("/ATLAS_2010_S8817804/d04-x01-y01", "7000") mergeByPt("/ATLAS_2010_S8817804/d05-x01-y01", "7000") mergeByPt("/ATLAS_2010_S8817804/d06-x01-y01", "7000") mergeByPt("/ATLAS_2010_S8817804/d07-x01-y01", "7000") mergeByPt("/ATLAS_2010_S8817804/d08-x01-y01", "7000") mergeByPt("/ATLAS_2010_S8817804/d09-x01-y01", "7000") mergeByPt("/ATLAS_2010_S8817804/d10-x01-y01", "7000") mergeByMass("/ATLAS_2010_S8817804/d11-x01-y01", "7000") mergeByMass("/ATLAS_2010_S8817804/d12-x01-y01", "7000") mergeByMass("/ATLAS_2010_S8817804/d13-x01-y01", "7000") mergeByMass("/ATLAS_2010_S8817804/d14-x01-y01", "7000") mergeByMass("/ATLAS_2010_S8817804/d15-x01-y01", "7000") mergeByMass("/ATLAS_2010_S8817804/d16-x01-y01", "7000") mergeByMass("/ATLAS_2010_S8817804/d17-x01-y01", "7000") mergeByMass("/ATLAS_2010_S8817804/d18-x01-y01", "7000") mergeByMass("/ATLAS_2010_S8817804/d19-x01-y01", "7000") mergeByMass("/ATLAS_2010_S8817804/d20-x01-y01", "7000") useOneMass("/ATLAS_2010_S8817804/d21-x01-y01", "7000", "250" ) useOneMass("/ATLAS_2010_S8817804/d22-x01-y01", "7000", "250" ) useOneMass("/ATLAS_2010_S8817804/d23-x01-y01", "7000", "650" ) useOneMass("/ATLAS_2010_S8817804/d24-x01-y01", "7000", "250" ) useOneMass("/ATLAS_2010_S8817804/d25-x01-y01", "7000", "250" ) useOneMass("/ATLAS_2010_S8817804/d26-x01-y01", "7000", "650" ) logging.info("Processing ATLAS_2011_I930220") mergeByPt("/ATLAS_2011_I930220/d01-x01-y01", "7000" ) mergeByPt("/ATLAS_2011_I930220/d02-x01-y01", "7000" ) mergeByPt("/ATLAS_2011_I930220/d03-x01-y01", "7000" ) mergeByPt("/ATLAS_2011_I930220/d04-x01-y01", "7000" ) mergeByPt("/ATLAS_2011_I930220/d05-x01-y01", "7000" ) mergeByPt("/ATLAS_2011_I930220/d06-x01-y01", "7000" ) mergeByMass("/ATLAS_2011_I930220/d07-x01-y01", "7000") useOneMass("/ATLAS_2011_I930220/d08-x01-y01", "7000", "110" ) useOneMass("/ATLAS_2011_I930220/d09-x01-y01", "7000", "110" ) useOneMass("/ATLAS_2011_I930220/d10-x01-y01", "7000", "370" ) logging.info("Processing ATLAS_2012_I1082936") mergeByPt("/ATLAS_2012_I1082936/d01-x01-y01", "7000") mergeByPt("/ATLAS_2012_I1082936/d01-x01-y02", "7000") mergeByPt("/ATLAS_2012_I1082936/d01-x01-y03", "7000") mergeByPt("/ATLAS_2012_I1082936/d01-x01-y04", "7000") mergeByPt("/ATLAS_2012_I1082936/d01-x01-y05", "7000") mergeByPt("/ATLAS_2012_I1082936/d01-x01-y06", "7000") mergeByPt("/ATLAS_2012_I1082936/d01-x01-y07", "7000") mergeByPt("/ATLAS_2012_I1082936/d02-x01-y01", "7000") mergeByPt("/ATLAS_2012_I1082936/d02-x01-y02", "7000") mergeByPt("/ATLAS_2012_I1082936/d02-x01-y03", "7000") mergeByPt("/ATLAS_2012_I1082936/d02-x01-y04", "7000") mergeByPt("/ATLAS_2012_I1082936/d02-x01-y05", "7000") mergeByPt("/ATLAS_2012_I1082936/d02-x01-y06", "7000") mergeByPt("/ATLAS_2012_I1082936/d02-x01-y07", "7000") mergeByMass("/ATLAS_2012_I1082936/d03-x01-y01", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d03-x01-y02", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d03-x01-y03", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d03-x01-y04", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d03-x01-y05", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d03-x01-y06", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d03-x01-y07", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d03-x01-y08", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d03-x01-y09", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d04-x01-y01", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d04-x01-y02", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d04-x01-y03", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d04-x01-y04", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d04-x01-y05", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d04-x01-y06", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d04-x01-y07", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d04-x01-y08", "7000", 1000.) mergeByMass("/ATLAS_2012_I1082936/d04-x01-y09", "7000", 1000.) logging.info("Processing CMS_2011_S8968497") useOneMass("/CMS_2011_S8968497/d01-x01-y01", "7000", "1700" ) useOneMass("/CMS_2011_S8968497/d02-x01-y01", "7000", "1700" ) useOneMass("/CMS_2011_S8968497/d03-x01-y01", "7000", "1100" ) useOneMass("/CMS_2011_S8968497/d04-x01-y01", "7000", "1100" ) useOneMass("/CMS_2011_S8968497/d05-x01-y01", "7000", "650" ) useOneMass("/CMS_2011_S8968497/d06-x01-y01", "7000", "650" ) useOneMass("/CMS_2011_S8968497/d07-x01-y01", "7000", "250" ) useOneMass("/CMS_2011_S8968497/d08-x01-y01", "7000", "250" ) useOneMass("/CMS_2011_S8968497/d09-x01-y01", "7000", "250" ) logging.info("Processing ATLAS_2011_S9126244") mergeByPt("/ATLAS_2011_S9126244/d01-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9126244/d01-x01-y02", "7000") mergeByPt("/ATLAS_2011_S9126244/d02-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9126244/d02-x01-y02", "7000") mergeByPt("/ATLAS_2011_S9126244/d03-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9126244/d03-x01-y02", "7000") mergeByPt("/ATLAS_2011_S9126244/d04-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9126244/d04-x01-y02", "7000") mergeByPt("/ATLAS_2011_S9126244/d05-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9126244/d05-x01-y02", "7000") useOnePt("/ATLAS_2011_S9126244/d06-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S9126244/d06-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S9126244/d07-x01-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S9126244/d07-x01-y02", "7000", "80" ) useOnePt("/ATLAS_2011_S9126244/d08-x01-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S9126244/d08-x01-y02", "7000", "80" ) useOnePt("/ATLAS_2011_S9126244/d09-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d09-x01-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d10-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d10-x01-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d11-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d11-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d12-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d12-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d13-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S9126244/d13-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S9126244/d14-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S9126244/d14-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S9126244/d15-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d15-x01-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d16-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d16-x01-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d17-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d17-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d18-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d18-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d19-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S9126244/d20-x01-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S9126244/d21-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d22-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d23-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d24-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d25-x01-y01", "7000", "210" ) mergeByPt("/ATLAS_2011_S9126244/d26-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9126244/d26-x01-y02", "7000") mergeByPt("/ATLAS_2011_S9126244/d27-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9126244/d27-x01-y02", "7000") mergeByPt("/ATLAS_2011_S9126244/d28-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9126244/d28-x01-y02", "7000") mergeByPt("/ATLAS_2011_S9126244/d29-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9126244/d29-x01-y02", "7000") useOnePt("/ATLAS_2011_S9126244/d30-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S9126244/d31-x01-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S9126244/d32-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d33-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d34-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d35-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d36-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d37-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2011_S9126244/d37-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2011_S9126244/d38-x01-y01", "7000", "80" ) useOnePt("/ATLAS_2011_S9126244/d38-x01-y02", "7000", "80" ) useOnePt("/ATLAS_2011_S9126244/d39-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d39-x01-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d40-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d40-x01-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d41-x01-y01", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d41-x01-y02", "7000", "110" ) useOnePt("/ATLAS_2011_S9126244/d42-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d42-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d43-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2011_S9126244/d43-x01-y02", "7000", "210" ) # CMS_2011_S9120041 UE analysis logging.info("Processing CMS_2011_S9120041") mergeByPt("/CMS_2011_S9120041/d01-x01-y01", "7000") mergeByPt("/CMS_2011_S9120041/d02-x01-y01", "7000") if(opts.ue) : useOnePt("/CMS_2011_S9120041/d03-x01-y01", "900", "0" ) useOnePt("/CMS_2011_S9120041/d04-x01-y01", "900", "0" ) useOnePt("/CMS_2011_S9120041/d05-x01-y01", "7000", "0" ) useOnePt("/CMS_2011_S9120041/d06-x01-y01", "7000", "0" ) useOnePt("/CMS_2011_S9120041/d07-x01-y01", "7000", "0" ) useOnePt("/CMS_2011_S9120041/d11-x01-y01", "900", "0" ) useOnePt("/CMS_2011_S9120041/d12-x01-y01", "900", "0" ) useOnePt("/CMS_2011_S9120041/d13-x01-y01", "900", "0" ) useOnePt("/CMS_2011_S9120041/d08-x01-y01", "7000", "20" ) useOnePt("/CMS_2011_S9120041/d09-x01-y01", "7000", "20" ) useOnePt("/CMS_2011_S9120041/d10-x01-y01", "7000", "20" ) else : useOnePt("/CMS_2011_S9120041/d08-x01-y01", "7000", "10" ) useOnePt("/CMS_2011_S9120041/d09-x01-y01", "7000", "10" ) useOnePt("/CMS_2011_S9120041/d10-x01-y01", "7000", "10" ) # CMS dijet decorrelation logging.info("Processing CMS_2011_S8950903") useOnePt("/CMS_2011_S8950903/d01-x01-y01", "7000", "80" ) useOnePt("/CMS_2011_S8950903/d02-x01-y01", "7000", "110" ) useOnePt("/CMS_2011_S8950903/d03-x01-y01", "7000", "110" ) useOnePt("/CMS_2011_S8950903/d04-x01-y01", "7000", "210" ) useOnePt("/CMS_2011_S8950903/d05-x01-y01", "7000", "260" ) # CMS jet cross section logging.info("Processing CMS_2011_S9086218") mergeByPt("/CMS_2011_S9086218/d01-x01-y01", "7000") mergeByPt("/CMS_2011_S9086218/d02-x01-y01", "7000") mergeByPt("/CMS_2011_S9086218/d03-x01-y01", "7000") mergeByPt("/CMS_2011_S9086218/d04-x01-y01", "7000") mergeByPt("/CMS_2011_S9086218/d05-x01-y01", "7000") mergeByPt("/CMS_2011_S9086218/d06-x01-y01", "7000") # CMS 2/3 jet cross section ratio logging.info("Processing CMS_2011_S9086218") mergeByPt("/CMS_2011_S9088458/d01-x01-y01", "7000",500.) # ATLAS track jet logging.info("Processing ATLAS_2011_I919017") for d in range(1,3) : for y in range(1,5) : mergeByPt("/ATLAS_2011_I919017/d0%s-x01-y0%s" % (d,y), "7000") if( opts.ue) : for x in range(2,6) : for y in ["01","02","06","07","11","12","16","17","21","22"] : useOnePt("/ATLAS_2011_I919017/d0%s-x0%s-y%s" % (d,x,y), "7000", "0" ) for y in ["03","04","08","09","13","14","18","19","23","24"] : useOnePt("/ATLAS_2011_I919017/d0%s-x0%s-y%s" % (d,x,y), "7000", "4" ) for y in range(5,30,5) : useOnePt("/ATLAS_2011_I919017/d0%s-x%02d-y%02d" % (d,x,y) , "7000", "20" ) else : for x in range(2,6) : for y in range(5,30,5) : useOnePt("/ATLAS_2011_I919017/d0%s-x%02d-y%02d" % (d,x,y) , "7000", "10" ) logging.info("Processing ATLAS_2011_I926145") mergeByPt("/ATLAS_2011_I926145/d01-x01-y01", "7000",1.5) mergeByPt("/ATLAS_2011_I926145/d02-x01-y01", "7000",1.5) mergeByPt("/ATLAS_2011_I926145/d03-x01-y01", "7000",1.5) logging.info("Processing CMS_2011_S8941262") useOnePt("/CMS_2011_S8941262/d01-x01-y01", "7000", "10" ) useOnePt("/CMS_2011_S8941262/d03-x01-y01", "7000", "10" ) mergeByPt("/CMS_2011_S8941262/d02-x01-y01", "7000",1.5) logging.info("Processing CMS_2011_S8973270") useOnePt("/CMS_2011_S8973270/d01-x01-y01", "7000", "70" ) useOnePt("/CMS_2011_S8973270/d02-x01-y01", "7000", "100" ) useOnePt("/CMS_2011_S8973270/d03-x01-y01", "7000", "130" ) useOnePt("/CMS_2011_S8973270/d04-x01-y01", "7000", "70" ) useOnePt("/CMS_2011_S8973270/d05-x01-y01", "7000", "100" ) useOnePt("/CMS_2011_S8973270/d06-x01-y01", "7000", "130" ) logging.info("Processing ATLAS_2012_I1082009") useOnePt("/ATLAS_2012_I1082009/d08-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2012_I1082009/d09-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2012_I1082009/d10-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2012_I1082009/d11-x01-y01", "7000", "80" ) useOnePt("/ATLAS_2012_I1082009/d12-x01-y01", "7000", "80" ) useOnePt("/ATLAS_2012_I1082009/d13-x01-y01", "7000", "40" ) logging.info("Processing ATLAS_2012_I1118269") mergeByPt("/ATLAS_2012_I1118269/d01-x01-y01", "7000") useOnePt("/ATLAS_2012_I1118269/d02-x01-y01", "7000", "10" ) logging.info("Processing ATLAS_2012_I1188891") mergeByPt("/ATLAS_2012_I1188891/d01-x01-y01", "7000") mergeByPt("/ATLAS_2012_I1188891/d02-x01-y01", "7000") mergeByPt("/ATLAS_2012_I1188891/d03-x01-y01", "7000") mergeByPt("/ATLAS_2012_I1188891/d04-x01-y01", "7000") mergeByPt("/ATLAS_2012_I1188891/d05-x01-y01", "7000") mergeByPt("/ATLAS_2012_I1188891/d06-x01-y01", "7000") logging.info("Processing CMS_2012_I1087342") mergeByPt("/CMS_2012_I1087342/d01-x01-y01", "7000") mergeByPt("/CMS_2012_I1087342/d02-x01-y01", "7000") mergeByPt("/CMS_2012_I1087342/d03-x01-y01", "7000") logging.info("Processing CMS_2012_PAS_QCD_11_010") mergeByPt("/CMS_2012_PAS_QCD_11_010/d01-x01-y01", "7000") mergeByPt("/CMS_2012_PAS_QCD_11_010/d02-x01-y01", "7000") mergeByPt("/CMS_2012_PAS_QCD_11_010/d03-x01-y01", "7000") mergeByPt("/CMS_2012_PAS_QCD_11_010/d04-x01-y01", "7000") logging.info("Processing ATLAS_2011_S9035664") mergeByPt("/ATLAS_2011_S9035664/d11-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d12-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d13-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d14-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d15-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d16-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d17-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d18-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d20-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d21-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d22-x01-y01", "7000") mergeByPt("/ATLAS_2011_S9035664/d23-x01-y01", "7000") logging.info("Processing ATLAS_2012_I1125575") mergeByPt("/ATLAS_2012_I1125575/d01-x01-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d01-x01-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d01-x02-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d01-x02-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d01-x03-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d01-x03-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d01-x04-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d01-x04-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d01-x05-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d01-x05-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d02-x01-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d02-x01-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d02-x02-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d02-x02-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d02-x03-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d02-x03-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d02-x04-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d02-x04-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d02-x05-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d02-x05-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d03-x01-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d03-x01-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d03-x02-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d03-x02-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d03-x03-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d03-x03-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d03-x04-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d03-x04-y02", "7000") mergeByPt("/ATLAS_2012_I1125575/d03-x05-y01", "7000") mergeByPt("/ATLAS_2012_I1125575/d03-x05-y02", "7000") for d in range(4,7) : for x in range(1,6) : if(opts.ue) : for y in range(1,9) : useOnePt("/ATLAS_2012_I1125575/d0%s-x0%s-y0%s" % (d,x,y), "7000", "0" ) for y in ["09","10","11","12","13","14","15","16"] : useOnePt("/ATLAS_2012_I1125575/d0%s-x0%s-y%s" % (d,x,y), "7000", "0" ) for y in range(17,19) : useOnePt("/ATLAS_2012_I1125575/d0%s-x0%s-y%s" % (d,x,y), "7000", "20" ) else : for y in range(17,19) : useOnePt("/ATLAS_2012_I1125575/d0%s-x0%s-y%s" % (d,x,y), "7000", "10" ) for y in range(19,21) : useOnePt("/ATLAS_2012_I1125575/d0%s-x0%s-y%s" % (d,x,y), "7000", "40" ) # ATLAS_2012_I1094564 useOnePt("/ATLAS_2012_I1094564/d01-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2012_I1094564/d02-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2012_I1094564/d03-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d04-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d05-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2012_I1094564/d06-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2012_I1094564/d07-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d08-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d09-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2012_I1094564/d10-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2012_I1094564/d11-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d12-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d13-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2012_I1094564/d14-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2012_I1094564/d15-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d16-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d17-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2012_I1094564/d18-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2012_I1094564/d19-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d20-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d21-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2012_I1094564/d22-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2012_I1094564/d23-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d24-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d25-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2012_I1094564/d26-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2012_I1094564/d27-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d28-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d29-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2012_I1094564/d30-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2012_I1094564/d31-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d32-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d33-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2012_I1094564/d34-x01-y01", "7000", "260" ) useOnePt("/ATLAS_2012_I1094564/d35-x01-y01", "7000", "400" ) useOnePt("/ATLAS_2012_I1094564/d36-x01-y01", "7000", "400" ) logging.info("Processing CMS_2013_I1224539_DIJET") useOnePt("/CMS_2013_I1224539_DIJET/d01-x01-y01", "7000", "210" ) useOnePt("/CMS_2013_I1224539_DIJET/d02-x01-y01", "7000", "260" ) useOnePt("/CMS_2013_I1224539_DIJET/d03-x01-y01", "7000", "400" ) useOnePt("/CMS_2013_I1224539_DIJET/d04-x01-y01", "7000", "400" ) useOnePt("/CMS_2013_I1224539_DIJET/d05-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d06-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d07-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d08-x01-y01", "7000", "210" ) useOnePt("/CMS_2013_I1224539_DIJET/d09-x01-y01", "7000", "260" ) useOnePt("/CMS_2013_I1224539_DIJET/d10-x01-y01", "7000", "400" ) useOnePt("/CMS_2013_I1224539_DIJET/d11-x01-y01", "7000", "400" ) useOnePt("/CMS_2013_I1224539_DIJET/d12-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d13-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d14-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d15-x01-y01", "7000", "210" ) useOnePt("/CMS_2013_I1224539_DIJET/d16-x01-y01", "7000", "260" ) useOnePt("/CMS_2013_I1224539_DIJET/d17-x01-y01", "7000", "400" ) useOnePt("/CMS_2013_I1224539_DIJET/d18-x01-y01", "7000", "400" ) useOnePt("/CMS_2013_I1224539_DIJET/d19-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d20-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d21-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d22-x01-y01", "7000", "210" ) useOnePt("/CMS_2013_I1224539_DIJET/d23-x01-y01", "7000", "260" ) useOnePt("/CMS_2013_I1224539_DIJET/d24-x01-y01", "7000", "400" ) useOnePt("/CMS_2013_I1224539_DIJET/d25-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d26-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d27-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1224539_DIJET/d28-x01-y01", "7000", "600" ) useOnePt("/CMS_2013_I1273574/d01-x01-y01", "7000", "80" ) mergeByPt("/CMS_2013_I1273574/d02-x01-y01", "7000",1.) useOnePt("/CMS_2013_I1273574/d03-x01-y01", "7000", "80" ) useOnePt("/CMS_2013_I1273574/d04-x01-y01", "7000", "80" ) useOnePt("/CMS_2013_I1273574/d05-x01-y01", "7000", "80" ) useOnePt("/CMS_2013_I1273574/d06-x01-y01", "7000", "80" ) mergeByPt("/CMS_2013_I1273574/d07-x01-y01", "7000",1.) useOnePt("/CMS_2013_I1273574/d08-x01-y01", "7000", "80" ) mergeByPt("/CMS_2013_I1273574/d09-x01-y01", "7000",1.) useOnePt("/CMS_2013_I1273574/d10-x01-y01", "7000", "80" ) mergeByPt("/CMS_2013_I1273574/d11-x01-y01", "7000",1.) useOnePt("/CMS_2013_I1261026/d01-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d02-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d03-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d04-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d05-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d06-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d07-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d08-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d09-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d10-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d11-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d12-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d13-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d14-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d15-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d16-x01-y01", "7000", "0" ) useOnePt("/CMS_2013_I1261026/d17-x01-y01", "7000", "0" ) logging.info("Processing CMS_2012_I1090423") useOneMass("/CMS_2012_I1090423/d01-x01-y01", "7000", "2900" ) useOneMass("/CMS_2012_I1090423/d02-x01-y01", "7000", "2300" ) useOneMass("/CMS_2012_I1090423/d03-x01-y01", "7000", "1700" ) useOneMass("/CMS_2012_I1090423/d04-x01-y01", "7000", "1100" ) useOneMass("/CMS_2012_I1090423/d05-x01-y01", "7000", "1100" ) useOneMass("/CMS_2012_I1090423/d06-x01-y01", "7000", "650" ) useOneMass("/CMS_2012_I1090423/d07-x01-y01", "7000", "650" ) useOneMass("/CMS_2012_I1090423/d08-x01-y01", "7000", "250" ) useOneMass("/CMS_2012_I1090423/d09-x01-y01", "7000", "250" ) logging.info("Processing ATLAS_2014_I1298811") mergeByPt("/ATLAS_2014_I1298811/d01-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1298811/d01-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1298811/d02-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1298811/d02-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1298811/d03-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1298811/d03-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1298811/d04-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1298811/d04-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1298811/d05-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1298811/d05-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1298811/d06-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1298811/d06-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1298811/d07-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1298811/d07-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1298811/d08-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1298811/d08-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1298811/d09-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1298811/d09-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1298811/d10-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1298811/d10-x01-y02", "7000") useOnePt("/ATLAS_2014_I1298811/d11-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2014_I1298811/d12-x01-y01", "7000", "0" ) useOnePt("/ATLAS_2014_I1298811/d13-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d13-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d14-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d14-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d15-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d15-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d25-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d25-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d26-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d26-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d27-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d27-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d16-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d16-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d17-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d17-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d18-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d18-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d28-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d28-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d29-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d29-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d30-x01-y01", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d30-x01-y02", "7000", "4" ) useOnePt("/ATLAS_2014_I1298811/d19-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d19-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d20-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d20-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d21-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d21-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d31-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d31-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d32-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d32-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d33-x01-y01", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d33-x01-y02", "7000", "40" ) useOnePt("/ATLAS_2014_I1298811/d22-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d22-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d23-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d23-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d24-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d24-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d34-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d34-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d35-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d35-x01-y02", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d36-x01-y01", "7000", "210" ) useOnePt("/ATLAS_2014_I1298811/d36-x01-y02", "7000", "210" ) logging.info("Processing ATLAS_2014_I1268975") mergeByMass("/ATLAS_2014_I1268975/d01-x01-y01", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d01-x01-y02", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d01-x01-y03", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d01-x01-y04", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d01-x01-y05", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d01-x01-y06", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d02-x01-y01", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d02-x01-y02", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d02-x01-y03", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d02-x01-y04", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d02-x01-y05", "7000", 1000.) mergeByMass("/ATLAS_2014_I1268975/d02-x01-y06", "7000", 1000.) logging.info("Processing ATLAS_2014_I1307243") useOnePt( "/ATLAS_2014_I1307243/d01-x01-y01", "7000", "80" ) mergeByPt("/ATLAS_2014_I1307243/d02-x01-y01", "7000") useOnePt( "/ATLAS_2014_I1307243/d03-x01-y01", "7000", "80" ) mergeByPt("/ATLAS_2014_I1307243/d04-x01-y01", "7000") useOnePt( "/ATLAS_2014_I1307243/d05-x01-y01", "7000", "80" ) mergeByPt("/ATLAS_2014_I1307243/d06-x01-y01", "7000") useOnePt( "/ATLAS_2014_I1307243/d07-x01-y01", "7000", "80" ) mergeByPt("/ATLAS_2014_I1307243/d08-x01-y01", "7000") useOnePt( "/ATLAS_2014_I1307243/d09-x01-y01", "7000", "80" ) mergeByPt("/ATLAS_2014_I1307243/d10-x01-y01", "7000") useOnePt( "/ATLAS_2014_I1307243/d11-x01-y01", "7000", "80" ) mergeByPt("/ATLAS_2014_I1307243/d12-x01-y01", "7000") useOnePt( "/ATLAS_2014_I1307243/d13-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d14-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d15-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d16-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d17-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d18-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d19-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d20-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d21-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d22-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d23-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d24-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d25-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d26-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d27-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d28-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d29-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d30-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d31-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d32-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d33-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d34-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d35-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d36-x01-y01", "7000", "80" ) useOnePt( "/ATLAS_2014_I1307243/d37-x01-y01", "7000", "80" ) mergeByPt("/ATLAS_2014_I1307243/d38-x01-y01", "7000") useOnePt( "/ATLAS_2014_I1307243/d39-x01-y01", "7000", "80" ) mergeByPt("/ATLAS_2014_I1307243/d40-x01-y01", "7000") logging.info("Processing ATLAS_2014_I1325553") mergeByPt("/ATLAS_2014_I1325553/d01-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1325553/d01-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1325553/d01-x01-y03", "7000") mergeByPt("/ATLAS_2014_I1325553/d01-x01-y04", "7000") mergeByPt("/ATLAS_2014_I1325553/d01-x01-y05", "7000") mergeByPt("/ATLAS_2014_I1325553/d01-x01-y06", "7000") mergeByPt("/ATLAS_2014_I1325553/d02-x01-y01", "7000") mergeByPt("/ATLAS_2014_I1325553/d02-x01-y02", "7000") mergeByPt("/ATLAS_2014_I1325553/d02-x01-y03", "7000") mergeByPt("/ATLAS_2014_I1325553/d02-x01-y04", "7000") mergeByPt("/ATLAS_2014_I1325553/d02-x01-y05", "7000") mergeByPt("/ATLAS_2014_I1325553/d02-x01-y06", "7000") logging.info("Processing ATLAS_2016_I1419070") for i in range(1,13) : if(i<10) : mergeByPt("/ATLAS_2016_I1419070/d0%s-x01-y01" % i, "8000") else : mergeByPt("/ATLAS_2016_I1419070/d%s-x01-y01" % i, "8000") # remake differences and sums for ihist in range(1,4) : if not ("/ATLAS_2016_I1419070/d0%s-x01-y01" % ihist) in outhistos : continue h1 = outhistos["/ATLAS_2016_I1419070/d0%s-x01-y01" % ihist ] h2 = outhistos["/ATLAS_2016_I1419070/d0%s-x01-y01" % (ihist+3)] sstring = "/ATLAS_2016_I1419070/d%s-x01-y01" % (9+ihist) dstring = "/ATLAS_2016_I1419070/d0%s-x01-y01" % (6+ihist) hdiff = yoda.Scatter2D(dstring,dstring) hsum = yoda.Scatter2D(sstring,sstring) outhistos[dstring]= hdiff outhistos[sstring]= hsum for nbin in range(0,h2.numBins) : bsum = h1.bins[nbin]+h2.bins[nbin] try: ydiff = h2.bins[nbin].mean-h1.bins[nbin].mean except: ydiff = 0 try: ysum = bsum.mean bstderr = bsum.stdErr except: ysum = 0 bstderr = 0 try: yerr = math.sqrt(h1.bins[nbin].stdErr**2+h2.bins[nbin].stdErr**2) except: yerr = 0 x = h1.bins[nbin].xMid xerr = 0.5*h1.bins[nbin].xWidth hdiff.addPoint(x,ydiff,xerr,yerr) hsum.addPoint(x,ysum ,xerr,bstderr) logging.info("ATLAS_2015_I1394679") for i in range(1,5) : mergeByPt("/ATLAS_2015_I1394679/d0%s-x01-y01" % i, "8000") for i in range(5,11) : if(i<10) : useOnePt( "/ATLAS_2015_I1394679/d0%s-x01-y01" % i, "8000", "110" ) else : useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % i, "8000", "110" ) for i in range(0,4) : useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (11+4*i), "8000", "110" ) useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (12+4*i), "8000", "260" ) useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (13+4*i), "8000", "600" ) useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (14+4*i), "8000", "900" ) for i in range(0,5) : useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (27+4*i), "8000", "110" ) useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (28+4*i), "8000", "260" ) useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (29+4*i), "8000", "400" ) useOnePt( "/ATLAS_2015_I1394679/d%s-x01-y01" % (30+4*i), "8000", "400" ) logging.info("Processing CMS_2013_I1208923") for i in range(1,6) : mergeByPt ("/CMS_2013_I1208923/d01-x01-y0%s" % i, "7000") mergeByMass("/CMS_2013_I1208923/d02-x01-y0%s" % i, "7000", 1.) logging.info("Processing CMS_2014_I1298810") for i in range(1,19) : if(i<10) : mergeByPt("/CMS_2014_I1298810/d0"+str(i)+"-x01-y01", "7000") else : mergeByPt("/CMS_2014_I1298810/d"+str(i)+"-x01-y01", "7000") logging.info("Processing CMS_2014_I1305624") for x in range(1,6) : useOnePt( "/CMS_2014_I1305624/d01-x%02d-y01" % x, "7000", "110" ) useOnePt( "/CMS_2014_I1305624/d01-x%02d-y02" % x, "7000", "110" ) useOnePt( "/CMS_2014_I1305624/d01-x%02d-y03" % x, "7000", "260" ) useOnePt( "/CMS_2014_I1305624/d01-x%02d-y04" % x, "7000", "260" ) useOnePt( "/CMS_2014_I1305624/d01-x%02d-y05" % x, "7000", "400" ) logging.info("Processing ATLAS_2011_I929691") for x in range(0,3) : useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 1), "7000", "20" ) useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 2), "7000", "40" ) useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 3), "7000", "40" ) useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 4), "7000", "80" ) useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 5), "7000", "110" ) useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 6), "7000", "110" ) useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 7), "7000", "210" ) useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 8), "7000", "260" ) useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+ 9), "7000", "260" ) useOnePt( "/ATLAS_2011_I929691/d%02d-x01-y01" % (10*x+10), "7000", "400" ) logging.info("Processing ATLAS_2015_I1393758") for i in range(1,13) : mergeByPt("/ATLAS_2015_I1393758/d%02d-x01-y01" % i, "8000") logging.info("Processing CMS_2016_I1459051") for i in range(1,15) : mergeByPt("/CMS_2016_I1459051/d%02d-x01-y01" % i, "13000") logging.info("Processing ATLAS_2016_CONF_2016_092") for i in range(1,7) : mergeByPt("/ATLAS_2016_CONF_2016_092/d%02d-x01-y01" % i, "13000") logging.info("Processing ATLAS_2017_I1609253") useOnePt( "/ATLAS_2017_I1609253/d01-x01-y01", "8000", "260" ) useOnePt( "/ATLAS_2017_I1609253/d02-x01-y01", "8000", "260" ) useOnePt( "/ATLAS_2017_I1609253/d03-x01-y01", "8000", "260" ) useOnePt( "/ATLAS_2017_I1609253/d04-x01-y01", "8000", "260" ) useOnePt( "/ATLAS_2017_I1609253/d05-x01-y01", "8000", "400" ) useOnePt( "/ATLAS_2017_I1609253/d06-x01-y01", "8000", "400" ) useOnePt( "/ATLAS_2017_I1609253/d07-x01-y01", "8000", "400" ) useOnePt( "/ATLAS_2017_I1609253/d08-x01-y01", "8000", "400" ) useOnePt( "/ATLAS_2017_I1609253/d09-x01-y01", "8000", "400" ) useOnePt( "/ATLAS_2017_I1609253/d10-x01-y01", "8000", "400" ) useOnePt( "/ATLAS_2017_I1609253/d11-x01-y01", "8000", "600" ) useOnePt( "/ATLAS_2017_I1609253/d12-x01-y01", "8000", "600" ) logging.info("Processing CMS_2016_I1487277") mergeByPt("/CMS_2016_I1487277/d01-x01-y01", "8000") mergeByPt("/CMS_2016_I1487277/d02-x01-y01", "8000") mergeByPt("/CMS_2016_I1487277/d03-x01-y01", "8000") mergeByPt("/CMS_2016_I1487277/d04-x01-y01", "8000") mergeByPt("/CMS_2016_I1487277/d05-x01-y01", "8000") mergeByPt("/CMS_2016_I1487277/d06-x01-y01", "8000") mergeByPt("/CMS_2016_I1487277/d07-x01-y01", "8000") logging.info("Processing CMS_2016_I1421646") useOnePt( "/CMS_2016_I1421646/d01-x01-y01", "8000", "210" ) useOnePt( "/CMS_2016_I1421646/d02-x01-y01", "8000", "260" ) useOnePt( "/CMS_2016_I1421646/d03-x01-y01", "8000", "400" ) useOnePt( "/CMS_2016_I1421646/d04-x01-y01", "8000", "400" ) useOnePt( "/CMS_2016_I1421646/d05-x01-y01", "8000", "600" ) useOnePt( "/CMS_2016_I1421646/d06-x01-y01", "8000", "900" ) useOnePt( "/CMS_2016_I1421646/d07-x01-y01", "8000", "900" ) + +logging.info("Processing CMS_2017_I1605749") +for i in [1,2,3,4,5,6,7,8,9,10,13,16] : + useOnePt("/CMS_2017_I1605749/d%02d-x01-y01" % i, "8000", "400" ) +for i in [11,14,17]: + useOnePt("/CMS_2017_I1605749/d%02d-x01-y01" % i, "8000", "600" ) +for i in [12,15,18]: + useOnePt("/CMS_2017_I1605749/d%02d-x01-y01" % i, "8000", "900" ) + +def CMS_2012_I1111014_name(i,j) : + if(i+j<100) : + return "/CMS_2012_I1111014/d%02d-x01-y01" % (i+j) + else : + return "/CMS_2012_I1111014/d%03d-x01-y01" % (i+j) + +logging.info("Processing CMS_2012_I1111014") +for j in [0,22,44,66,87,106]: + for i in [1,2,3] : + useOnePt(CMS_2012_I1111014_name(i,j), "7000", "20" ) + for i in [4,5,6,7]: + useOnePt(CMS_2012_I1111014_name(i,j), "7000", "40" ) + for i in [8,9,10]: + useOnePt(CMS_2012_I1111014_name(i,j), "7000", "80" ) + for i in [11,12,13,14,15,16]: + useOnePt(CMS_2012_I1111014_name(i,j), "7000", "110" ) + for i in [17,18]: + useOnePt(CMS_2012_I1111014_name(i,j), "7000", "210" ) + useOnePt(CMS_2012_I1111014_name(19,j), "7000", "260" ) + if(j<87) : + for i in [20,21]: + useOnePt(CMS_2012_I1111014_name(i,j), "7000", "400" ) + if(j<66) : + useOnePt(CMS_2012_I1111014_name(22,j), "7000", "600" ) + +for i in [126,127,128] : + for j in [1,2] : + mergeByPt("/CMS_2012_I1111014/d%03d-x01-y%02d" % (i,j), "7000") + # Choose output file name = args[0]+"-Jets.yoda" yoda.writeYODA(outhistos,name) sys.exit(0) diff --git a/Tests/python/merge-LHC-Photon b/Tests/python/merge-LHC-Photon --- a/Tests/python/merge-LHC-Photon +++ b/Tests/python/merge-LHC-Photon @@ -1,288 +1,288 @@ #! /usr/bin/env python import logging import sys import os, yoda """%prog Script for merging aida files """ def fillAbove(scale,desthisto, sourcehistosbyptmin): pthigh= 1e100 ptlow =-1e100 for pt, h in sorted(sourcehistosbyptmin.iteritems(),reverse=True): ptlow=pt if(type(desthisto)==yoda.core.Scatter2D) : for i in range(0,h.numPoints) : xMin = h.points[i].x-h.points[i].xErrs.minus if( xMin*scale >= ptlow and xMin*scale < pthigh ) : desthisto.addPoint(h.points[i]) elif(type(desthisto)==yoda.core.Profile1D) : for i in range(0,h.numBins) : if(h.bins[i].xMin*scale >= ptlow and h.bins[i].xMin*scale < pthigh ) : desthisto.bins[i] += h.bins[i] elif(type(desthisto)==yoda.core.Histo1D) : for i in range(0,h.numBins) : if(h.bins[i].xMin*scale >= ptlow and h.bins[i].xMin*scale < pthigh ) : desthisto.bins[i] += h.bins[i] else : logging.error("Can't merge %s, unknown type" % desthisto.path) sys.exit(1) pthigh=pt def mergeByPt(hpath, scale=1.): global inhistos global outhistos try: fillAbove(scale,outhistos[hpath], inhistos[hpath]) except: pass def useOnePt(hpath, ptmin): global inhistos global outhistos try: ## Find best pT_min match ptmins = inhistos[hpath].keys() closest_ptmin = None for ptm in ptmins: if closest_ptmin is None or \ abs(ptm-float(ptmin)) < abs(closest_ptmin-float(ptmin)): closest_ptmin = ptm if closest_ptmin != float(ptmin): logging.warning("Inexact match for requested pTmin=%s: " % ptmin + \ "using pTmin=%e instead" % closest_ptmin) outhistos[hpath] = inhistos[hpath][closest_ptmin] except: pass if sys.version_info[:3] < (2,4,0): print "rivet scripts require Python version >= 2.4.0... exiting" sys.exit(1) if __name__ == "__main__": import logging from optparse import OptionParser, OptionGroup - parser = OptionParser(usage="%prog aidafile aidafile2 [...]") - parser.add_option("-o", "--out", dest="OUTFILE", default="-") + parser = OptionParser(usage="%prog base") verbgroup = OptionGroup(parser, "Verbosity control") verbgroup.add_option("-v", "--verbose", action="store_const", const=logging.DEBUG, dest="LOGLEVEL", default=logging.INFO, help="print debug (very verbose) messages") verbgroup.add_option("-q", "--quiet", action="store_const", const=logging.WARNING, dest="LOGLEVEL", default=logging.INFO, help="be very quiet") parser.add_option_group(verbgroup) (opts, args) = parser.parse_args() logging.basicConfig(level=opts.LOGLEVEL, format="%(message)s") ## Check args if len(args) < 1: logging.error("Must specify at least the name of the files") sys.exit(1) files=["-7-PromptPhoton-1.yoda","-7-PromptPhoton-2.yoda", "-7-PromptPhoton-3.yoda","-7-PromptPhoton-4.yoda", "-8-PromptPhoton-1.yoda","-8-PromptPhoton-2.yoda", "-8-PromptPhoton-3.yoda","-8-PromptPhoton-4.yoda", "-7-DiPhoton-GammaGamma.yoda","-7-DiPhoton-GammaJet.yoda","-GammaGamma-7.yoda", "-8-DiPhoton-GammaGamma.yoda","-8-DiPhoton-GammaJet.yoda","-GammaGamma-8.yoda"] ## Get histos inhistos = {} outhistos={} for f in files: file='Rivet-'+args[0]+f if not os.access(file, os.R_OK): logging.error("%s can not be read" % file) continue try: aos = yoda.read(file) except: logging.error("%s can not be parsed as XML" % file) break if(file.find("PromptPhoton")>=0) : if(file.find("PromptPhoton-1")>0) : ptmin=0. elif(file.find("PromptPhoton-2")>0) : ptmin=35. elif(file.find("PromptPhoton-3")>0) : ptmin=90. elif(file.find("PromptPhoton-4")>0) : ptmin=170. ## Get histos from this YODA file for aopath, ao in aos.iteritems() : if not inhistos.has_key(aopath): inhistos[aopath] = {} if (aopath.find("CMS_2013_I1258128")>0) : if(aopath.find("d05")>0 or aopath.find("d06")>0 or aopath.find("d07")>0 or aopath.find("d08")>0) : inhistos[aopath][ptmin] = ao else : inhistos[aopath][ptmin] = ao else : ## Get histos from this YODA file for aopath, ao in aos.iteritems() : if(aopath.find("XSEC")>=0 or aopath.find("EVTCOUNT")>=0) : continue if ( aopath in outhistos ) : aotype = type(ao) if aotype in (yoda.Counter, yoda.Histo1D, yoda.Histo2D, yoda.Profile1D, yoda.Profile2D): outhistos[aopath] += ao else : quit() else: outhistos[aopath] = ao for hpath,hsets in inhistos.iteritems(): if( hpath.find("1263495")>0 or hpath.find("1093738")>0 or hpath.find("921594" )>0 or hpath.find("8914702")>0 or hpath.find("1244522")>0 or hpath.find("1457605")>0 or hpath.find("1632756")>0 or hpath.find("1266056")>0 ) : if(type(hsets.values()[0])==yoda.core.Scatter2D) : outhistos[hpath] = yoda.core.Scatter2D(hsets.values()[0].path, hsets.values()[0].title) elif(type(hsets.values()[0])==yoda.core.Profile1D) : outhistos[hpath] = yoda.core.Profile1D(hsets.values()[0].path, hsets.values()[0].title) for i in range(0,hsets.values()[0].numBins) : outhistos[hpath].addBin(hsets.values()[0].bins[i].xMin, hsets.values()[0].bins[i].xMax) elif(type(hsets.values()[0])==yoda.core.Histo1D) : outhistos[hpath] = yoda.core.Histo1D(hsets.values()[0].path, hsets.values()[0].title) for i in range(0,hsets.values()[0].numBins) : outhistos[hpath].addBin(hsets.values()[0].bins[i].xMin, hsets.values()[0].bins[i].xMax) else : logging.error("Histogram %s is of unknown type" % hpath) print hpath,type(hsets.values()[0]) sys.exit(1) logging.info("Processing ATLAS_2013_I1263495") mergeByPt("/ATLAS_2013_I1263495/d01-x01-y01") mergeByPt("/ATLAS_2013_I1263495/d01-x01-y03") useOnePt("/ATLAS_2013_I1263495/d01-x02-y01", "90" ) logging.info("Processing ATLAS_2012_I1093738") mergeByPt("/ATLAS_2012_I1093738/d01-x01-y01") mergeByPt("/ATLAS_2012_I1093738/d02-x01-y01") mergeByPt("/ATLAS_2012_I1093738/d03-x01-y01") mergeByPt("/ATLAS_2012_I1093738/d04-x01-y01") mergeByPt("/ATLAS_2012_I1093738/d05-x01-y01") mergeByPt("/ATLAS_2012_I1093738/d06-x01-y01") logging.info("Processing ATLAS_2011_I921594") mergeByPt("/ATLAS_2011_I921594/d01-x01-y01") mergeByPt("/ATLAS_2011_I921594/d01-x01-y02") mergeByPt("/ATLAS_2011_I921594/d01-x01-y04") mergeByPt("/ATLAS_2011_I921594/d01-x01-y05") logging.info("Processing ATLAS_2010_S8914702") mergeByPt("/ATLAS_2010_S8914702/d01-x01-y01") mergeByPt("/ATLAS_2010_S8914702/d01-x01-y02") mergeByPt("/ATLAS_2010_S8914702/d01-x01-y03") logging.info("Processing CMS_2013_I1258128") useOnePt("/CMS_2013_I1258128/d05-x01-y01", "35" ) useOnePt("/CMS_2013_I1258128/d06-x01-y01", "35" ) useOnePt("/CMS_2013_I1258128/d07-x01-y01", "35" ) useOnePt("/CMS_2013_I1258128/d08-x01-y01", "35" ) logging.info("Processing ATLAS_2013_I1244522") mergeByPt("/ATLAS_2013_I1244522/d01-x01-y01") mergeByPt("/ATLAS_2013_I1244522/d02-x01-y01") useOnePt("/ATLAS_2013_I1244522/d03-x01-y01", "35" ) useOnePt("/ATLAS_2013_I1244522/d04-x01-y01", "35" ) useOnePt("/ATLAS_2013_I1244522/d05-x01-y01", "35" ) useOnePt("/ATLAS_2013_I1244522/d06-x01-y01", "35" ) useOnePt("/ATLAS_2013_I1244522/d07-x01-y01", "35" ) logging.info("Processing ATLAS_2016_I1457605") mergeByPt("/ATLAS_2016_I1457605/d01-x01-y01") mergeByPt("/ATLAS_2016_I1457605/d02-x01-y01") mergeByPt("/ATLAS_2016_I1457605/d03-x01-y01") mergeByPt("/ATLAS_2016_I1457605/d04-x01-y01") logging.info("Processing ATLAS_2017_I1632756") mergeByPt("/ATLAS_2017_I1632756/d02-x01-y01") mergeByPt("/ATLAS_2017_I1632756/d03-x01-y01") mergeByPt("/ATLAS_2017_I1632756/d04-x01-y01") mergeByPt("/ATLAS_2017_I1632756/d05-x01-y01") logging.info("Processing CMS_2014_I1266056") mergeByPt("/CMS_2014_I1266056/d01-x01-y01") mergeByPt("/CMS_2014_I1266056/d01-x01-y02") mergeByPt("/CMS_2014_I1266056/d02-x01-y01") mergeByPt("/CMS_2014_I1266056/d02-x01-y02") mergeByPt("/CMS_2014_I1266056/d03-x01-y01") mergeByPt("/CMS_2014_I1266056/d03-x01-y02") mergeByPt("/CMS_2014_I1266056/d04-x01-y01") mergeByPt("/CMS_2014_I1266056/d04-x01-y02") logging.info("Processing /MC_PHOTONJETS") useOnePt("/MC_PHOTONJETS/jet_HT","0") useOnePt("/MC_PHOTONJETS/jet_eta_1","0") useOnePt("/MC_PHOTONJETS/jet_eta_2","0") useOnePt("/MC_PHOTONJETS/jet_eta_3","0") useOnePt("/MC_PHOTONJETS/jet_eta_4","0") useOnePt("/MC_PHOTONJETS/jet_eta_pmratio_1","0") useOnePt("/MC_PHOTONJETS/jet_eta_pmratio_2","0") useOnePt("/MC_PHOTONJETS/jet_eta_pmratio_3","0") useOnePt("/MC_PHOTONJETS/jet_eta_pmratio_4","0") useOnePt("/MC_PHOTONJETS/jet_mass_1","0") useOnePt("/MC_PHOTONJETS/jet_mass_2","0") useOnePt("/MC_PHOTONJETS/jet_mass_3","0") useOnePt("/MC_PHOTONJETS/jet_mass_4","0") useOnePt("/MC_PHOTONJETS/jet_multi_exclusive","0") useOnePt("/MC_PHOTONJETS/jet_multi_inclusive","0") useOnePt("/MC_PHOTONJETS/jet_multi_ratio","0") useOnePt("/MC_PHOTONJETS/jet_pT_1","0") useOnePt("/MC_PHOTONJETS/jet_pT_2","0") useOnePt("/MC_PHOTONJETS/jet_pT_3","0") useOnePt("/MC_PHOTONJETS/jet_pT_4","0") useOnePt("/MC_PHOTONJETS/jet_y_1","0") useOnePt("/MC_PHOTONJETS/jet_y_2","0") useOnePt("/MC_PHOTONJETS/jet_y_3","0") useOnePt("/MC_PHOTONJETS/jet_y_4","0") useOnePt("/MC_PHOTONJETS/jet_y_pmratio_1","0") useOnePt("/MC_PHOTONJETS/jet_y_pmratio_2","0") useOnePt("/MC_PHOTONJETS/jet_y_pmratio_3","0") useOnePt("/MC_PHOTONJETS/jet_y_pmratio_4","0") useOnePt("/MC_PHOTONJETS/jets_dR_12","0") useOnePt("/MC_PHOTONJETS/jets_dR_13","0") useOnePt("/MC_PHOTONJETS/jets_dR_23","0") useOnePt("/MC_PHOTONJETS/jets_deta_12","0") useOnePt("/MC_PHOTONJETS/jets_deta_13","0") useOnePt("/MC_PHOTONJETS/jets_deta_23","0") useOnePt("/MC_PHOTONJETS/jets_dphi_12","0") useOnePt("/MC_PHOTONJETS/jets_dphi_13","0") useOnePt("/MC_PHOTONJETS/jets_dphi_23","0") useOnePt("/MC_PHOTONJETS/photon_jet1_dR","0") useOnePt("/MC_PHOTONJETS/photon_jet1_deta","0") useOnePt("/MC_PHOTONJETS/photon_jet1_dphi","0") useOnePt("/MC_PHOTONJETUE/gammajet-dR","0") useOnePt("/MC_PHOTONJETUE/gammajet-dphi","0") useOnePt("/MC_PHOTONJETUE/trans-maxnchg-gamma","0") useOnePt("/MC_PHOTONJETUE/trans-maxnchg-jet","0") useOnePt("/MC_PHOTONJETUE/trans-maxptsum-gamma","0") useOnePt("/MC_PHOTONJETUE/trans-maxptsum-jet","0") useOnePt("/MC_PHOTONJETUE/trans-minnchg-gamma","0") useOnePt("/MC_PHOTONJETUE/trans-minnchg-jet","0") useOnePt("/MC_PHOTONJETUE/trans-minptsum-gamma","0") useOnePt("/MC_PHOTONJETUE/trans-minptsum-jet","0") useOnePt("/MC_PHOTONJETUE/trans-nchg-gamma","0") useOnePt("/MC_PHOTONJETUE/trans-nchg-jet","0") useOnePt("/MC_PHOTONJETUE/trans-ptavg-gamma","0") useOnePt("/MC_PHOTONJETUE/trans-ptavg-jet","0") useOnePt("/MC_PHOTONJETUE/trans-ptsum-gamma","0") useOnePt("/MC_PHOTONJETUE/trans-ptsum-jet","0") # Choose output file -yoda.writeYODA(outhistos,opts.OUTFILE) +name = args[0]+"-Photon.yoda" +yoda.writeYODA(outhistos,name) sys.exit(0) diff --git a/Tests/python/merge-TVT-EW b/Tests/python/merge-TVT-EW --- a/Tests/python/merge-TVT-EW +++ b/Tests/python/merge-TVT-EW @@ -1,69 +1,73 @@ #! /usr/bin/env python import logging import sys import os, yoda """%prog Script for merging yoda files """ import sys if sys.version_info[:3] < (2,4,0): print "rivet scripts require Python version >= 2.4.0... exiting" sys.exit(1) if __name__ == "__main__": import logging from optparse import OptionParser, OptionGroup - parser = OptionParser(usage="%prog aidafile aidafile2 [...]") - parser.add_option("-o", "--out", dest="OUTFILE", default="-") + parser = OptionParser(usage="%prog base") verbgroup = OptionGroup(parser, "Verbosity control") verbgroup.add_option("-v", "--verbose", action="store_const", const=logging.DEBUG, dest="LOGLEVEL", default=logging.INFO, help="print debug (very verbose) messages") verbgroup.add_option("-q", "--quiet", action="store_const", const=logging.WARNING, dest="LOGLEVEL", default=logging.INFO, help="be very quiet") parser.add_option_group(verbgroup) (opts, args) = parser.parse_args() logging.basicConfig(level=opts.LOGLEVEL, format="%(message)s") ## Check args if len(args) < 1: - logging.error("Must specify at least one AIDA histogram file") + logging.error("Must specify at least the name of the files") sys.exit(1) + + yodafiles=["-Run-II-Z-e","-Run-II-Z-mu","-Run-II-Z-LowMass-mu","-Run-II-Z-HighMass-mu","-Run-I-W","-Run-I-Z","-Run-I-WZ"] + ## Get histos outhistos={} - for file in args: + for f in yodafiles: + file='Rivet-'+args[0]+f+".yoda" if not os.access(file, os.R_OK): logging.error("%s can not be read" % file) break try: aos = yoda.read(file) except: logging.error("%s can not be parsed as yoda" % file) break ## Get histos from this YODA file for aopath, ao in aos.iteritems() : if(aopath.find("D0_2010_S8821313")>0) : if(aopath.find("d01")>0 and file.find("-e")>0) : outhistos[aopath] = ao elif(aopath.find("d02")>0 and file.find("-mu")>0) : outhistos[aopath] = ao elif(aopath.find("D0_2015_I1324946")>0) : if(file.find("LowMass")>0) : if(aopath.find("d02")>0) : outhistos[aopath] = ao elif(file.find("HighMass")>0) : if(aopath.find("d03")>0 or aopath.find("d04")>0) : outhistos[aopath] = ao else: if(aopath.find("d01")>0) : outhistos[aopath] = ao else : outhistos[aopath] = ao # output the yoda file - yoda.writeYODA(outhistos,opts.OUTFILE) + name = args[0]+"-EW.yoda" + yoda.writeYODA(outhistos,name) sys.exit(0) diff --git a/Tests/python/merge-TVT-Jets b/Tests/python/merge-TVT-Jets --- a/Tests/python/merge-TVT-Jets +++ b/Tests/python/merge-TVT-Jets @@ -1,557 +1,557 @@ #! /usr/bin/env python import logging import sys if sys.version_info[:3] < (2,4,0): print "rivet scripts require Python version >= 2.4.0... exiting" sys.exit(1) import os, yoda # ############################################# def fillAbove(desthisto, sourcehistosbyptmin): pthigh= 1e100 ptlow =-1e100 for pt, h in sorted(sourcehistosbyptmin.iteritems(),reverse=True): ptlow=pt if(type(desthisto)==yoda.core.Scatter2D) : for i in range(0,h.numPoints) : xMin = h.points[i].x-h.points[i].xErrs.minus if( xMin >= ptlow and xMin < pthigh ) : desthisto.addPoint(h.points[i]) elif(type(desthisto)==yoda.core.Profile1D) : for i in range(0,h.numBins) : if(h.bins[i].xMin >= ptlow and h.bins[i].xMin < pthigh ) : desthisto.bins[i] += h.bins[i] elif(type(desthisto)==yoda.core.Histo1D) : for i in range(0,h.numBins) : if(h.bins[i].xMin >= ptlow and h.bins[i].xMin < pthigh ) : desthisto.bins[i] += h.bins[i] elif(type(desthisto)==yoda.core.Counter) : desthisto += h else : logging.error("Can't merge %s, unknown type" % desthisto.path) sys.exit(1) pthigh=pt def mergeByPt(hpath, sqrts): global inhistos global outhistos try: fillAbove(outhistos[hpath], inhistos[hpath][float(sqrts)]) except: pass def useOnePt(hpath, sqrts, ptmin): global inhistos global outhistos try: ## Find best pT_min match ptmins = inhistos[hpath][float(sqrts)].keys() closest_ptmin = None for ptm in ptmins: if closest_ptmin is None or \ abs(ptm-float(ptmin)) < abs(closest_ptmin-float(ptmin)): closest_ptmin = ptm if closest_ptmin != float(ptmin): logging.warning("Inexact match for requested pTmin=%s: " % ptmin + \ "using pTmin=%e instead" % closest_ptmin) outhistos[hpath] = inhistos[hpath][float(sqrts)][closest_ptmin] except: pass # ####################################### if __name__ == "__main__": import logging from optparse import OptionParser, OptionGroup - parser = OptionParser(usage="%prog name") + parser = OptionParser(usage="%progbase") verbgroup = OptionGroup(parser, "Verbosity control") verbgroup.add_option("-v", "--verbose", action="store_const", const=logging.DEBUG, dest="LOGLEVEL", default=logging.INFO, help="print debug (very verbose) messages") verbgroup.add_option("-q", "--quiet", action="store_const", const=logging.WARNING, dest="LOGLEVEL", default=logging.INFO, help="be very quiet") parser.add_option("--with-ue", action='store_true' , dest="ue", default=True, help="Include UE analyses") parser.add_option("--without-ue", action='store_false', dest="ue", default=True, help="Don\'t include UE analyses") parser.add_option_group(verbgroup) (opts, args) = parser.parse_args() logging.basicConfig(level=opts.LOGLEVEL, format="%(message)s") ## Check args if len(args) < 1: logging.error("Must specify at least the name of the files") sys.exit(1) yodafiles=["-Run-II-Jets-0.yoda","-Run-II-Jets-1.yoda",\ "-Run-II-Jets-2.yoda",\ "-Run-II-Jets-3.yoda","-Run-II-Jets-4.yoda","-Run-II-Jets-5.yoda",\ "-Run-II-Jets-6.yoda","-Run-II-Jets-7.yoda",\ "-Run-I-Jets-1.yoda","-Run-I-Jets-2.yoda",\ "-Run-I-Jets-3.yoda","-Run-I-Jets-4.yoda","-Run-I-Jets-5.yoda",\ "-630-Jets-1.yoda" ,"-630-Jets-2.yoda" ,\ "-630-Jets-3.yoda", "-300-UE.yoda", "-900-UE.yoda" # "-RatioPlots.yoda" ] if(opts.ue) : yodafiles += ["-Run-II-UE.yoda" ,"-Run-I-UE.yoda" ,"-630-UE.yoda" ,] ## Get histos inhistos = {} outhistos={} for f in yodafiles: file='Rivet-'+args[0]+f if(file.find("Run-II-UE")>0) : sqrts=1960 ptmin=0. elif(file.find("Run-II-Jets-0")>0) : sqrts=1960 ptmin=20. elif(file.find("Run-II-Jets-1")>0) : sqrts=1960 ptmin=36. elif(file.find("Run-II-Jets-2")>0) : sqrts=1960 ptmin=55. elif(file.find("Run-II-Jets-3")>0) : sqrts=1960 ptmin=75. elif(file.find("Run-II-Jets-4")>0) : sqrts=1960 ptmin=100. elif(file.find("Run-II-Jets-5")>0) : sqrts=1960 ptmin=125. elif(file.find("Run-II-Jets-6")>0) : ptmin=175. sqrts=1960 elif(file.find("Run-II-Jets-7")>0) : sqrts=1960 ptmin=265. elif(file.find("300-UE")>0) : sqrts=300 ptmin=0. elif(file.find("900-UE")>0) : sqrts=900 ptmin=0. elif(file.find("630-UE")>0) : sqrts=630 ptmin=0. elif(file.find("630-Jets-1")>0) : sqrts=630 ptmin=30. elif(file.find("630-Jets-2")>0) : sqrts=630 ptmin=55. elif(file.find("630-Jets-3")>0) : sqrts=630 ptmin=90. elif(file.find("Run-I-UE")>0) : sqrts=1800 ptmin=0. elif(file.find("Run-I-Jets-1")>0) : sqrts=1800 ptmin=30. elif(file.find("Run-I-Jets-2")>0) : sqrts=1800 ptmin=55. elif(file.find("Run-I-Jets-3")>0) : sqrts=1800 ptmin=80. elif(file.find("Run-I-Jets-4")>0) : sqrts=1800 ptmin=105. elif(file.find("Run-I-Jets-5")>0) : sqrts=1800 ptmin=175. if not os.access(file, os.R_OK): logging.error("%s can not be read" % file) continue try: aos = yoda.read(file) except: logging.error("%s can not be parsed as YODA" % file) continue ## Get histos from this YODA file for aopath, ao in aos.iteritems() : # di-jet decorrelations # jet shapes if(aopath.find("5992206")>0 or aopath.find("6217184")>0 or aopath.find("LEADINGJETS")>0 or aopath.find("7662670")>0 or aopath.find("7057202")>0 or aopath.find("6450792")>0 or aopath.find("7828950")>0 or aopath.find("4751469")>0 or aopath.find("5839831")>0 or aopath.find("4563131")>0 or aopath.find("4517016")>0 or aopath.find("3618439")>0 or aopath.find("8591881")>0 or aopath.find("1388868")>0 or aopath.find("398175")>0) : if not inhistos.has_key(aopath): inhistos[aopath] = {} tmpE = inhistos[aopath] if not tmpE.has_key(sqrts): tmpE[sqrts] = {} tmpP = tmpE[sqrts] if not tmpP.has_key(ptmin): tmpP[ptmin] = ao else: raise Exception("A set with ptmin = %s already exists" % ( ptmin)) elif(aopath.find("8233977")>0 or aopath.find("NOTE_9936")>0 or aopath.find("3905616")>0 or aopath.find("3324664")>0 or aopath.find("4796047")>0 or aopath.find("1865951")>0 or aopath.find("2089246")>0 or aopath.find("3108457")>0 or aopath.find("3349578")>0 or aopath.find("3541940")>0 or aopath.find("3214044")>0 or aopath.find("2952106")>0 or aopath.find("NOTE10874")>0 or aopath.find("895662")>0 ) : if( opts.ue ) : outhistos[aopath] = ao elif (aopath.find("NOTE10874")<0) : outhistos[aopath] = ao else : if(aopath.find("/_EVTCOUNT")>=0 or aopath.find("/_XSEC" )>=0 ) : continue print aopath quit() yodafiles=["-Run-II-Jets-8.yoda","-Run-II-Jets-9.yoda","-Run-II-Jets-10.yoda","-Run-II-Jets-11.yoda",\ "-Run-I-Jets-6.yoda","-Run-I-Jets-7.yoda","-Run-I-Jets-8.yoda"] for f in yodafiles: file='Rivet-'+args[0]+f if(file.find("Run-II-Jets-8")>0) : sqrts=1960 ptmin=0.150 elif(file.find("Run-II-Jets-9")>0) : sqrts=1960 ptmin=0.400 elif(file.find("Run-II-Jets-10")>0) : sqrts=1960 ptmin=0.600 elif(file.find("Run-II-Jets-11")>0) : sqrts=1960 ptmin=1.000 elif(file.find("Run-I-Jets-6")>0) : sqrts=1800 ptmin=0.150 elif(file.find("Run-I-Jets-7")>0) : sqrts=1800 ptmin=0.5 elif(file.find("Run-I-Jets-8")>0) : sqrts=1800 ptmin=0.8 if not os.access(file, os.R_OK): logging.error("%s can not be read" % file) continue try: aos = yoda.read(file) except: logging.error("%s can not be parsed as YODA" % file) continue ## Get histos from this AIDA file for aopath, ao in aos.iteritems() : if(aopath.find("8566488")>0 or aopath.find("8320160")>0) : if not inhistos.has_key(aopath): inhistos[aopath] = {} tmpE = inhistos[aopath] if not tmpE.has_key(sqrts): tmpE[sqrts] = {} tmpP = tmpE[sqrts] if not tmpP.has_key(ptmin): tmpP[ptmin] = ao else: raise Exception("A set with ptmin = %s already exists" % ( ptmin)) elif(aopath.find("8093652")>0 or aopath.find("3418421")>0 or aopath.find("4266730")>0) : if not inhistos.has_key(aopath): inhistos[aopath] = {} tmpE = inhistos[aopath] if not tmpE.has_key(sqrts): tmpE[sqrts] = {} tmpP = tmpE[sqrts] if not tmpP.has_key(1000.*ptmin): tmpP[1000.*ptmin] = ao else: raise Exception("A set with ptmin = %s already exists" % ( 1000.*ptmin)) ## Make empty output histos if needed for hpath,hsets in inhistos.iteritems(): if( (hpath.find("6217184")>0 and hpath.find("d13-x01-y01")>0 ) or hpath.find("LEADINGJETS")>0 or hpath.find("7662670")>0 or hpath.find("7057202")>0 or hpath.find("6450792")>0 or hpath.find("7828950")>0 or hpath.find("8566488")>0 or hpath.find("8320160")>0 or hpath.find("8093652")>0 or hpath.find("4751469")>0 or hpath.find("5839831")>0 or hpath.find("4563131")>0 or hpath.find("4517016")>0 or hpath.find("3618439")>0 or hpath.find("4266730")>0 or hpath.find("3418421")>0 or hpath.find("8591881")>0 or hpath.find("1388868")>0) : if(type(hsets.values()[0].values()[0])==yoda.core.Counter) : outhistos[hpath] = yoda.core.Counter(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) elif(type(hsets.values()[0].values()[0])==yoda.core.Scatter2D) : outhistos[hpath] = yoda.core.Scatter2D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) elif(type(hsets.values()[0].values()[0])==yoda.core.Profile1D) : outhistos[hpath] = yoda.core.Profile1D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) for i in range(0,hsets.values()[0].values()[0].numBins) : outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin, hsets.values()[0].values()[0].bins[i].xMax) elif(type(hsets.values()[0].values()[0])==yoda.core.Histo1D) : outhistos[hpath] = yoda.core.Histo1D(hsets.values()[0].values()[0].path, hsets.values()[0].values()[0].title) for i in range(0,hsets.values()[0].values()[0].numBins) : outhistos[hpath].addBin(hsets.values()[0].values()[0].bins[i].xMin, hsets.values()[0].values()[0].bins[i].xMax) else : logging.error("Histogram %s is of unknown type" % hpath) print hpath,type(hsets.values()[0].values()[0]) sys.exit(1) ## Field analysis logging.info("Processing CDF_2001_S4751469") ## Angular distributions in different pT bins if(opts.ue) : useOnePt("/CDF_2001_S4751469/d01-x01-y01", "1800", "0") useOnePt("/CDF_2001_S4751469/d01-x01-y02", "1800", "0") useOnePt("/CDF_2001_S4751469/d02-x01-y01", "1800", "0") useOnePt("/CDF_2001_S4751469/d02-x01-y02", "1800", "0") useOnePt("/CDF_2001_S4751469/d01-x01-y03", "1800", "30") useOnePt("/CDF_2001_S4751469/d02-x01-y03", "1800", "30") ## Number, profile in pT_lead (True?) if(opts.ue) : useOnePt("/CDF_2001_S4751469/d03-x01-y01", "1800", "0") useOnePt("/CDF_2001_S4751469/d03-x01-y02", "1800", "0") useOnePt("/CDF_2001_S4751469/d03-x01-y03", "1800", "0") useOnePt("/CDF_2001_S4751469/d04-x01-y01", "1800", "30") useOnePt("/CDF_2001_S4751469/d04-x01-y02", "1800", "30") useOnePt("/CDF_2001_S4751469/d04-x01-y03", "1800", "30") ## pT sums, profile in pT_lead (True?) if(opts.ue) : useOnePt("/CDF_2001_S4751469/d05-x01-y01", "1800", "0") useOnePt("/CDF_2001_S4751469/d05-x01-y02", "1800", "0") useOnePt("/CDF_2001_S4751469/d05-x01-y03", "1800", "0") useOnePt("/CDF_2001_S4751469/d06-x01-y01", "1800", "30") useOnePt("/CDF_2001_S4751469/d06-x01-y02", "1800", "30") useOnePt("/CDF_2001_S4751469/d06-x01-y03", "1800", "30") ## pT distributions (use a specific pT cut run) if(opts.ue) : useOnePt("/CDF_2001_S4751469/d07-x01-y01", "1800", "0") useOnePt("/CDF_2001_S4751469/d07-x01-y02", "1800", "0") useOnePt("/CDF_2001_S4751469/d07-x01-y03", "1800", "30") ## Acosta analysis logging.info("Processing CDF_2004_S5839831") ## Mean pT, profile in ET_lead mergeByPt("/CDF_2004_S5839831/d01-x01-y01", "1800") mergeByPt("/CDF_2004_S5839831/d01-x01-y02", "1800") ## pT_max,min, profiles in ET_lead mergeByPt("/CDF_2004_S5839831/d02-x01-y01", "1800") mergeByPt("/CDF_2004_S5839831/d02-x01-y02", "1800") mergeByPt("/CDF_2004_S5839831/d02-x01-y03", "1800") ## pT distributions (want to use a specific pT cut run) useOnePt("/CDF_2004_S5839831/d03-x01-y01", "1800", "30") useOnePt("/CDF_2004_S5839831/d03-x01-y02", "1800", "80") useOnePt("/CDF_2004_S5839831/d03-x01-y03", "1800", "105") useOnePt("/CDF_2004_S5839831/d03-x01-y04", "1800", "105") useOnePt("/CDF_2004_S5839831/d03-x01-y05", "1800", "175") ## N_max,min, profiles in ET_lead mergeByPt("/CDF_2004_S5839831/d04-x01-y01", "1800") mergeByPt("/CDF_2004_S5839831/d04-x01-y02", "1800") ## Min bias dbs (want to use min bias pT cut) if(opts.ue) : useOnePt("/CDF_2004_S5839831/d05-x01-y01", "1800", "0") useOnePt("/CDF_2004_S5839831/d06-x01-y01", "1800", "0") ## Swiss Cheese, profile in ET_lead mergeByPt("/CDF_2004_S5839831/d07-x01-y01", "1800") mergeByPt("/CDF_2004_S5839831/d07-x01-y02", "1800") ## pT_max,min, profiles in ET_lead mergeByPt("/CDF_2004_S5839831/d08-x01-y01", "630") mergeByPt("/CDF_2004_S5839831/d08-x01-y02", "630") mergeByPt("/CDF_2004_S5839831/d08-x01-y03", "630") ## Swiss Cheese, profile in ET_lead mergeByPt("/CDF_2004_S5839831/d09-x01-y01", "630") mergeByPt("/CDF_2004_S5839831/d09-x01-y02", "630") ## Min bias dbs (want to use min bias pT cut) if(opts.ue) : useOnePt("/CDF_2004_S5839831/d10-x01-y01", "630", "0") useOnePt("/CDF_2004_S5839831/d11-x01-y01", "630", "0") ## CDF jet shape analysis logging.info("Processing CDF_2005_S6217184") useOnePt("/CDF_2005_S6217184/d01-x01-y01", "1960", "36" ) useOnePt("/CDF_2005_S6217184/d01-x01-y02", "1960", "36" ) useOnePt("/CDF_2005_S6217184/d01-x01-y03", "1960", "55" ) useOnePt("/CDF_2005_S6217184/d02-x01-y01", "1960", "55" ) useOnePt("/CDF_2005_S6217184/d02-x01-y02", "1960", "55" ) useOnePt("/CDF_2005_S6217184/d02-x01-y03", "1960", "75" ) useOnePt("/CDF_2005_S6217184/d03-x01-y01", "1960", "75" ) useOnePt("/CDF_2005_S6217184/d03-x01-y02", "1960", "100") useOnePt("/CDF_2005_S6217184/d03-x01-y03", "1960", "100") useOnePt("/CDF_2005_S6217184/d04-x01-y01", "1960", "125") useOnePt("/CDF_2005_S6217184/d04-x01-y02", "1960", "125") useOnePt("/CDF_2005_S6217184/d04-x01-y03", "1960", "175") useOnePt("/CDF_2005_S6217184/d05-x01-y01", "1960", "175") useOnePt("/CDF_2005_S6217184/d05-x01-y02", "1960", "175") useOnePt("/CDF_2005_S6217184/d05-x01-y03", "1960", "175") useOnePt("/CDF_2005_S6217184/d06-x01-y01", "1960", "265") useOnePt("/CDF_2005_S6217184/d06-x01-y02", "1960", "265") useOnePt("/CDF_2005_S6217184/d06-x01-y03", "1960", "265") useOnePt("/CDF_2005_S6217184/d07-x01-y01", "1960", "36" ) useOnePt("/CDF_2005_S6217184/d07-x01-y02", "1960", "36" ) useOnePt("/CDF_2005_S6217184/d07-x01-y03", "1960", "55" ) useOnePt("/CDF_2005_S6217184/d08-x01-y01", "1960", "55" ) useOnePt("/CDF_2005_S6217184/d08-x01-y02", "1960", "55" ) useOnePt("/CDF_2005_S6217184/d08-x01-y03", "1960", "75" ) useOnePt("/CDF_2005_S6217184/d09-x01-y01", "1960", "75" ) useOnePt("/CDF_2005_S6217184/d09-x01-y02", "1960", "100") useOnePt("/CDF_2005_S6217184/d09-x01-y03", "1960", "100") useOnePt("/CDF_2005_S6217184/d10-x01-y01", "1960", "125") useOnePt("/CDF_2005_S6217184/d10-x01-y02", "1960", "125") useOnePt("/CDF_2005_S6217184/d10-x01-y03", "1960", "175") useOnePt("/CDF_2005_S6217184/d11-x01-y01", "1960", "175") useOnePt("/CDF_2005_S6217184/d11-x01-y02", "1960", "175") useOnePt("/CDF_2005_S6217184/d11-x01-y03", "1960", "175") useOnePt("/CDF_2005_S6217184/d12-x01-y01", "1960", "265") useOnePt("/CDF_2005_S6217184/d12-x01-y02", "1960", "265") useOnePt("/CDF_2005_S6217184/d12-x01-y03", "1960", "265") mergeByPt("/CDF_2005_S6217184/d13-x01-y01", "1960") # ## CDF dijet mass spectrum mergeByPt("/CDF_2008_S8093652/d01-x01-y01", "1960") # ## Rick Field Run-II Leading Jets analysis # logging.info("Processing CDF_2008_LEADINGJETS") # ## charged particle density # mergeByPt("/CDF_2008_LEADINGJETS/d01-x01-y01", "1960") # mergeByPt("/CDF_2008_LEADINGJETS/d02-x01-y01", "1960") # mergeByPt("/CDF_2008_LEADINGJETS/d03-x01-y01", "1960") # mergeByPt("/CDF_2008_LEADINGJETS/d04-x01-y01", "1960") # ## pT sum density # mergeByPt("/CDF_2008_LEADINGJETS/d05-x01-y01", "1960") # mergeByPt("/CDF_2008_LEADINGJETS/d06-x01-y01", "1960") # mergeByPt("/CDF_2008_LEADINGJETS/d07-x01-y01", "1960") # mergeByPt("/CDF_2008_LEADINGJETS/d08-x01-y01", "1960") # ## mean pT # mergeByPt("/CDF_2008_LEADINGJETS/d09-x01-y01", "1960") ## newer version logging.info("Processing CDF_2010_S8591881_QCD") mergeByPt("/CDF_2010_S8591881_QCD/d10-x01-y01", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d10-x01-y02", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d10-x01-y03", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d11-x01-y01", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d11-x01-y02", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d11-x01-y03", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d12-x01-y01", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d12-x01-y02", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d12-x01-y03", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d13-x01-y01", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d13-x01-y02", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d13-x01-y03", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d14-x01-y01", "1960") mergeByPt("/CDF_2010_S8591881_QCD/d15-x01-y01", "1960") ## D0 dijet correlation analysis logging.info("Processing D0_2004_S5992206") useOnePt("/D0_2004_S5992206/d01-x02-y01", "1960", "75") useOnePt("/D0_2004_S5992206/d02-x02-y01", "1960", "100") useOnePt("/D0_2004_S5992206/d03-x02-y01", "1960", "125") useOnePt("/D0_2004_S5992206/d04-x02-y01", "1960", "175") ## D0 incl jet cross-section analysis logging.info("Processing D0_2008_S7662670") mergeByPt("/D0_2008_S7662670/d01-x01-y01", "1960") mergeByPt("/D0_2008_S7662670/d02-x01-y01", "1960") mergeByPt("/D0_2008_S7662670/d03-x01-y01", "1960") mergeByPt("/D0_2008_S7662670/d04-x01-y01", "1960") mergeByPt("/D0_2008_S7662670/d05-x01-y01", "1960") mergeByPt("/D0_2008_S7662670/d06-x01-y01", "1960") mergeByPt("/D0_2010_S8566488/d01-x01-y01", "1960") mergeByPt("/D0_2010_S8566488/d02-x01-y01", "1960") mergeByPt("/D0_2010_S8566488/d03-x01-y01", "1960") mergeByPt("/D0_2010_S8566488/d04-x01-y01", "1960") mergeByPt("/D0_2010_S8566488/d05-x01-y01", "1960") mergeByPt("/D0_2010_S8566488/d06-x01-y01", "1960") # CDF jet cross section mergeByPt("/CDF_2001_S4563131/d01-x01-y01", "1800") mergeByPt("/CDF_2001_S4517016/d01-x01-y01", "1800") mergeByPt("/CDF_2001_S4517016/d02-x01-y01", "1800") mergeByPt("/CDF_2001_S4517016/d03-x01-y01", "1800") mergeByPt("/CDF_2001_S4517016/d04-x01-y01", "1800") useOnePt("/CDF_1998_S3618439/d01-x01-y01", "1800","105") useOnePt("/CDF_1998_S3618439/d01-x01-y02", "1800","105") mergeByPt("/CDF_2008_S7828950/d01-x01-y01", "1960") mergeByPt("/CDF_2008_S7828950/d02-x01-y01", "1960") mergeByPt("/CDF_2008_S7828950/d03-x01-y01", "1960") mergeByPt("/CDF_2008_S7828950/d04-x01-y01", "1960") mergeByPt("/CDF_2008_S7828950/d05-x01-y01", "1960") mergeByPt("/CDF_2007_S7057202/d01-x01-y01", "1960") mergeByPt("/CDF_2007_S7057202/d02-x01-y01", "1960") mergeByPt("/CDF_2007_S7057202/d03-x01-y01", "1960") mergeByPt("/CDF_2007_S7057202/d04-x01-y01", "1960") mergeByPt("/CDF_2007_S7057202/d05-x01-y01", "1960") mergeByPt("/CDF_2007_S7057202/d06-x01-y01", "1960") mergeByPt("/CDF_2007_S7057202/d07-x01-y01", "1960") mergeByPt("/CDF_2006_S6450792/d01-x01-y01", "1960") mergeByPt("/CDF_2000_S4266730/d01-x01-y01", "1800") useOnePt("/CDF_1996_S3418421/d01-x01-y01","1800","150") useOnePt("/CDF_1996_S3418421/d01-x01-y02","1800","150") useOnePt("/CDF_1996_S3418421/d01-x01-y03","1800","150") useOnePt("/CDF_1996_S3418421/d01-x01-y04","1800","500") useOnePt("/CDF_1996_S3418421/d01-x01-y05","1800","500") mergeByPt("/CDF_1996_S3418421/d02-x01-y01","1800") useOnePt("/D0_2009_S8320160/d01-x01-y01", "1960", "0.15" ) useOnePt("/D0_2009_S8320160/d02-x01-y01", "1960", "0.15" ) useOnePt("/D0_2009_S8320160/d03-x01-y01", "1960", "0.4" ) useOnePt("/D0_2009_S8320160/d04-x01-y01", "1960", "0.4" ) useOnePt("/D0_2009_S8320160/d05-x01-y01", "1960", "0.6" ) useOnePt("/D0_2009_S8320160/d06-x01-y01", "1960", "0.6" ) useOnePt("/D0_2009_S8320160/d07-x01-y01", "1960", "0.6" ) useOnePt("/D0_2009_S8320160/d08-x01-y01", "1960", "0.6" ) useOnePt("/D0_2009_S8320160/d09-x01-y01", "1960", "1.0" ) useOnePt("/D0_2009_S8320160/d10-x01-y01", "1960", "1.0" ) logging.info("Processing CDF_2015_I1388868") for d in range(1,4) : if d == 1 : energy="1960" elif d ==2 : energy = "900" elif d==3 : energy = "300" for y in [1,2,3,4,6,7,8,9]: useOnePt("/CDF_2015_I1388868/d0%s-x01-y0%s" % (d,y) , energy, "0" ) # D0 jet shape logging.info("Processing D0_1995_I398175") useOnePt("/D0_1995_I398175/d01-x01-y01", "1800", "30" ) useOnePt("/D0_1995_I398175/d02-x01-y01", "1800", "55" ) useOnePt("/D0_1995_I398175/d03-x01-y01", "1800", "105" ) useOnePt("/D0_1995_I398175/d04-x01-y01", "1800", "105" ) useOnePt("/D0_1995_I398175/d05-x01-y01", "1800", "30" ) useOnePt("/D0_1995_I398175/d06-x01-y01", "1800", "55" ) # Choose output file name = args[0]+"-Jets.yoda" yoda.writeYODA(outhistos,name) sys.exit(0) diff --git a/Tests/python/merge-TVT-Photon b/Tests/python/merge-TVT-Photon --- a/Tests/python/merge-TVT-Photon +++ b/Tests/python/merge-TVT-Photon @@ -1,65 +1,65 @@ #! /usr/bin/env python import logging import sys import os, yoda """%prog Script for merging aida files """ if sys.version_info[:3] < (2,4,0): print "rivet scripts require Python version >= 2.4.0... exiting" sys.exit(1) if __name__ == "__main__": import logging from optparse import OptionParser, OptionGroup - parser = OptionParser(usage="%prog aidafile aidafile2 [...]") - parser.add_option("-o", "--out", dest="OUTFILE", default="-") + parser = OptionParser(usage="%prog base") verbgroup = OptionGroup(parser, "Verbosity control") verbgroup.add_option("-v", "--verbose", action="store_const", const=logging.DEBUG, dest="LOGLEVEL", default=logging.INFO, help="print debug (very verbose) messages") verbgroup.add_option("-q", "--quiet", action="store_const", const=logging.WARNING, dest="LOGLEVEL", default=logging.INFO, help="be very quiet") parser.add_option_group(verbgroup) (opts, args) = parser.parse_args() logging.basicConfig(level=opts.LOGLEVEL, format="%(message)s") ## Check args if len(args) < 1: logging.error("Must specify at least the name of the files") sys.exit(1) files=["-Run-II-PromptPhoton.yoda", "-Run-II-DiPhoton-GammaGamma.yoda","-Run-II-DiPhoton-GammaJet.yoda"] ## Get histos inhistos = {} outhistos={} for f in files: file='Rivet-'+args[0]+f if not os.access(file, os.R_OK): logging.error("%s can not be read" % file) continue try: aos = yoda.read(file) except: logging.error("%s can not be parsed as XML" % file) break ## Get histos from this YODA file for aopath, ao in aos.iteritems() : if(aopath.find("XSEC")>=0 or aopath.find("EVTCOUNT")>=0) : continue if ( aopath in outhistos ) : aotype = type(ao) if aotype in (yoda.Counter, yoda.Histo1D, yoda.Histo2D, yoda.Profile1D, yoda.Profile2D): outhistos[aopath] += ao else : quit() else: outhistos[aopath] = ao # Choose output file -yoda.writeYODA(outhistos,opts.OUTFILE) +name = args[0]+"-Photon.yoda" +yoda.writeYODA(outhistos,name) sys.exit(0) diff --git a/Utilities/AlphaS.h b/Utilities/AlphaS.h new file mode 100644 --- /dev/null +++ b/Utilities/AlphaS.h @@ -0,0 +1,72 @@ +// -*- C++ -*- +// +// AlphaS.h is a part of Herwig - A multi-purpose Monte Carlo event generator +// Copyright (C) 2018 The Herwig Collaboration +// +// Herwig is licenced under version 3 of the GPL, see COPYING for details. +// Please respect the MCnet academic guidelines, see GUIDELINES for details. +// +#ifndef HERWIG_UtilAlphaS_H +#define HERWIG_UtilAlphaS_H + +namespace Herwig { + +namespace Math { + + /** + * The derivative of \f$\alpha_S\f$ with respect to \f$\ln(Q^2/\Lambda^2)\f$ + * @param q The scale + * @param lam \f$\Lambda_{\rm QCD}\f$ + * @param nf The number of flavours + */ +inline double derivativeAlphaS(Energy q, Energy lam, + unsigned int nf, unsigned int nloop) { + using Constants::pi; + double lx = log(sqr(q/lam)); + double b0 = 11. - 2./3.*nf; + double b1 = 51. - 19./3.*nf; + double b2 = 2857. - 5033./9.*nf + 325./27.*sqr(nf); + if(nloop==1) + return -4.*pi/(b0*sqr(lx)); + else if(nloop==2) + return -4.*pi/(b0*sqr(lx))*(1.+2.*b1/sqr(b0)/lx*(1.-2.*log(lx))); + else + return -4.*pi/(b0*sqr(lx))* + (1. + 2.*b1/sqr(b0)/lx*(1.-2.*log(lx)) + + 4.*sqr(b1)/(sqr(sqr(b0))*sqr(lx))*(1. - 2.*log(lx) + + 3.*(sqr(log(lx) - 0.5)+b2*b0/(8.*sqr(b1))-1.25))); +} + + /** + * The 1,2,3-loop parametrization of \f$\alpha_S\f$. + * @param q The scale + * @param lam \f$\Lambda_{\rm QCD}\f$ + * @param nf The number of flavours + */ +inline double alphaS(Energy q, Energy lam, + unsigned int nf, unsigned int nloop) { + using Constants::pi; + double lx(log(sqr(q/lam))); + double b0 = 11. - 2./3.*nf; + double b1 = 51. - 19./3.*nf; + double b2 = 2857. - 5033./9.*nf + 325./27.*sqr(nf); + // one loop + if(nloop==1) + {return 4.*pi/(b0*lx);} + // two loop + else if(nloop==2) { + return 4.*pi/(b0*lx)*(1.-2.*b1/sqr(b0)*log(lx)/lx); + } + // three loop + else + {return 4.*pi/(b0*lx)*(1.-2.*b1/sqr(b0)*log(lx)/lx + + 4.*sqr(b1)/(sqr(sqr(b0))*sqr(lx))* + (sqr(log(lx) - 0.5) + b2*b0/(8.*sqr(b1)) - 5./4.));} +} + + +} + +} + +#endif \ No newline at end of file diff --git a/Utilities/Makefile.am b/Utilities/Makefile.am --- a/Utilities/Makefile.am +++ b/Utilities/Makefile.am @@ -1,46 +1,46 @@ SUBDIRS = XML Statistics noinst_LTLIBRARIES = libHwUtils.la libHwUtils_la_SOURCES = \ EnumParticles.h \ Interpolator.tcc Interpolator.h \ Kinematics.cc Kinematics.h \ Progress.h Progress.cc \ Maths.h Maths.cc \ StandardSelectors.cc StandardSelectors.h\ Histogram.cc Histogram.fh Histogram.h \ GaussianIntegrator.cc GaussianIntegrator.h \ GaussianIntegrator.tcc \ Statistic.h HerwigStrategy.cc HerwigStrategy.h \ GSLIntegrator.h GSLIntegrator.tcc \ GSLBisection.h GSLBisection.tcc GSLHelper.h \ expm-1.h \ -HiggsLoopFunctions.h +HiggsLoopFunctions.h AlphaS.h nodist_libHwUtils_la_SOURCES = hgstamp.inc BUILT_SOURCES = hgstamp.inc CLEANFILES = hgstamp.inc HGVERSION := $(shell hg -R $(top_srcdir) parents --template '"Herwig {node|short} ({branch})"' 2> /dev/null || echo \"$(PACKAGE_STRING)\" || true ) .PHONY: update_hgstamp hgstamp.inc: update_hgstamp @[ -f $@ ] || touch $@ @echo '$(HGVERSION)' | cmp -s $@ - || echo '$(HGVERSION)' > $@ libHwUtils_la_LIBADD = \ XML/libHwXML.la \ Statistics/libHwStatistics.la check_PROGRAMS = utilities_test utilities_test_SOURCES = \ tests/utilitiesTestsMain.cc \ tests/utilitiesTestsGlobalFixture.h \ tests/utilitiesTestsKinematics.h \ tests/utilitiesTestMaths.h \ tests/utilitiesTestsStatistic.h utilities_test_LDADD = $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) $(THEPEGLIB) -ldl libHwUtils.la utilities_test_LDFLAGS = $(AM_LDFLAGS) -export-dynamic $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS) $(THEPEGLDFLAGS) utilities_test_CPPFLAGS = $(AM_CPPFLAGS) $(BOOST_CPPFLAGS) TESTS = utilities_test diff --git a/lib/Makefile.am b/lib/Makefile.am --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,49 +1,49 @@ pkglib_LTLIBRARIES = Herwig.la Herwig_la_SOURCES = Herwig_la_LIBTOOLFLAGS = --tag=CXX -Herwig_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 24:0:0 +Herwig_la_LDFLAGS = $(AM_LDFLAGS) -module -version-info 25:0:0 Herwig_la_LDFLAGS += $(THEPEGLDFLAGS) $(BOOST_SYSTEM_LDFLAGS) $(BOOST_FILESYSTEM_LDFLAGS) $(FCLIBS) Herwig_la_LIBADD = \ $(top_builddir)/Hadronization/libHwHadronization.la \ $(top_builddir)/Models/libHwStandardModel.la \ $(top_builddir)/Decay/libHwDecay.la \ $(top_builddir)/Decay/libHwFormFactor.la \ $(top_builddir)/Decay/libHwDecRad.la \ $(top_builddir)/Utilities/libHwUtils.la \ $(top_builddir)/Models/libHwModelGenerator.la \ $(top_builddir)/Decay/General/libHwGeneralDecay.la \ $(top_builddir)/MatrixElement/General/libHwGeneralME.la \ $(top_builddir)/MatrixElement/libHwME.la \ $(top_builddir)/MatrixElement/Reweighters/libHwReweighters.la \ $(top_builddir)/MatrixElement/Matchbox/libHwMatchbox.la \ $(top_builddir)/Decay/libHwWeakCurrent.la \ $(top_builddir)/Looptools/libHwLooptools.la \ $(top_builddir)/Shower/libHwShower.la \ $(THEPEGLIB) -ldl dist_noinst_SCRIPTS = fix-osx-path POSTPROCESSING = done-all-links if NEED_APPLE_FIXES POSTPROCESSING += apple-fixes endif all-local: $(POSTPROCESSING) done-all-links: Herwig.la find $(top_builddir) \( -name '*.so.*' -or -name '*.so' \) \ -not -name 'lib*' -not -path '$(top_builddir)/lib/*' \ -not -path '$(top_builddir)/.hg/*' -exec $(LN_S) -f \{\} \; $(LN_S) -f .libs/Herwig*so* . echo "stamp" > $@ apple-fixes: fix-osx-path done-all-links ./$< echo "stamp" > $@ clean-local: rm -f *.so *.so.* done-all-links apple-fixes diff --git a/src/DIS.in b/src/DIS.in --- a/src/DIS.in +++ b/src/DIS.in @@ -1,75 +1,77 @@ # -*- ThePEG-repository -*- ################################################## # Example generator based on DIS parameters # usage: Herwig read DIS.in ################################################## read snippets/EPCollider.in +# for fixed target +# read snippets/FixedTarget.in ################################################## # Technical parameters for this run ################################################## cd /Herwig/Generators # no pdfs for leptons set /Herwig/Shower/ShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF set /Herwig/Partons/MPIExtractor:SecondPDF /Herwig/Partons/MPIPDF set /Herwig/Partons/EPExtractor:SecondPDF /Herwig/Partons/HardNLOPDF ################################################## # DIS physics parameters (override defaults here) ################################################## ################################################## # Matrix Elements for lepton-hadron collisions # (by default only neutral-current switched on) ################################################## cd /Herwig/MatrixElements/ # Neutral current DIS insert SubProcess:MatrixElements[0] MEDISNC # Charged current matrix element insert SubProcess:MatrixElements[0] MEDISCC ################################################## # NLO IN POWHEG SCHEME ################################################## ################################################### ## Need to use an NLO PDF ################################################### # set /Herwig/Particles/p+:PDF /Herwig/Partons/HardNLOPDF # set /Herwig/Particles/pbar-:PDF /Herwig/Partons/HardNLOPDF # set /Herwig/Partons/EPExtractor:SecondPDF /Herwig/Partons/HardNLOPDF # ################################################### ## Setup the POWHEG shower ################################################### #cd /Herwig/Shower #set ShowerHandler:HardEmission POWHEG ################################################### ## NLO Matrix Elements for lepton-hadron collisions ## in the POWHEG approach ################################################### # #cd /Herwig/MatrixElements/ # ## Neutral current DIS #insert SubProcess:MatrixElements[0] PowhegMEDISNC ## Charged current matrix element #insert SubProcess:MatrixElements[0] PowhegMEDISCC ################################################## ## prepare for Rivet analysis or HepMC output ## when running with parton shower ################################################## #read snippets/Rivet.in #insert /Herwig/Analysis/Rivet:Analyses 0 XXX_2015_ABC123 #read snippets/HepMC.in #set /Herwig/Analysis/HepMC:PrintEvent NNN ################################################## # Save run for later usage with 'Herwig run' ################################################## cd /Herwig/Generators saverun DIS EventGenerator diff --git a/src/defaults/Shower.in b/src/defaults/Shower.in --- a/src/defaults/Shower.in +++ b/src/defaults/Shower.in @@ -1,353 +1,354 @@ # -*- ThePEG-repository -*- ############################################################ # Setup of default parton shower # # Useful switches for users are marked near the top of # this file. # # Don't edit this file directly, but reset the switches # in your own input files! ############################################################ library HwMPI.so library HwShower.so library HwMatching.so mkdir /Herwig/Shower cd /Herwig/Shower create Herwig::QTildeShowerHandler ShowerHandler newdef ShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler newdef ShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer # use LO PDFs for Shower, can be changed later newdef ShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF newdef ShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF newdef ShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF newdef ShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF ##################################### # initial setup, don't change these! ##################################### create Herwig::SplittingGenerator SplittingGenerator create Herwig::ShowerAlphaQCD AlphaQCD create Herwig::ShowerAlphaQED AlphaQED set AlphaQED:CouplingSource Thompson create Herwig::ShowerAlphaQED AlphaEW set AlphaEW:CouplingSource MZ -create Herwig::QTildeModel ShowerModel -create Herwig::QTildeFinder PartnerFinder +create Herwig::PartnerFinder PartnerFinder newdef PartnerFinder:PartnerMethod 1 newdef PartnerFinder:ScaleChoice 1 -create Herwig::QTildeReconstructor KinematicsReconstructor +create Herwig::KinematicsReconstructor KinematicsReconstructor newdef KinematicsReconstructor:ReconstructionOption Colour3 newdef KinematicsReconstructor:InitialStateReconOption SofterFraction newdef KinematicsReconstructor:InitialInitialBoostOption LongTransBoost newdef /Herwig/Partons/RemnantDecayer:AlphaS AlphaQCD newdef /Herwig/Partons/RemnantDecayer:AlphaEM AlphaQED -newdef ShowerModel:PartnerFinder PartnerFinder -newdef ShowerModel:KinematicsReconstructor KinematicsReconstructor -newdef ShowerHandler:ShowerModel ShowerModel +newdef ShowerHandler:PartnerFinder PartnerFinder +newdef ShowerHandler:KinematicsReconstructor KinematicsReconstructor newdef ShowerHandler:SplittingGenerator SplittingGenerator newdef ShowerHandler:Interactions QEDQCD newdef ShowerHandler:SpinCorrelations Yes newdef ShowerHandler:SoftCorrelations Singular ################################################################## # Intrinsic pT # # Recommended: # 1.9 GeV for Tevatron W/Z production. # 2.1 GeV for LHC W/Z production at 10 TeV # 2.2 GeV for LHC W/Z production at 14 TeV # # Set all parameters to 0 to disable ################################################################## newdef ShowerHandler:IntrinsicPtGaussian 1.3*GeV newdef ShowerHandler:IntrinsicPtBeta 0 newdef ShowerHandler:IntrinsicPtGamma 0*GeV newdef ShowerHandler:IntrinsicPtIptmax 0*GeV ############################################################# # Set up truncated shower handler. ############################################################# create Herwig::PowhegShowerHandler PowhegShowerHandler set PowhegShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler set PowhegShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer newdef PowhegShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF newdef PowhegShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF newdef PowhegShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF newdef PowhegShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF newdef PowhegShowerHandler:MPIHandler /Herwig/UnderlyingEvent/MPIHandler newdef PowhegShowerHandler:RemDecayer /Herwig/Partons/RemnantDecayer newdef PowhegShowerHandler:PDFA /Herwig/Partons/ShowerLOPDF newdef PowhegShowerHandler:PDFB /Herwig/Partons/ShowerLOPDF newdef PowhegShowerHandler:PDFARemnant /Herwig/Partons/RemnantPDF newdef PowhegShowerHandler:PDFBRemnant /Herwig/Partons/RemnantPDF -newdef PowhegShowerHandler:ShowerModel ShowerModel +newdef PowhegShowerHandler:PartnerFinder PartnerFinder +newdef PowhegShowerHandler:KinematicsReconstructor KinematicsReconstructor newdef PowhegShowerHandler:SplittingGenerator SplittingGenerator newdef PowhegShowerHandler:Interactions QEDQCD newdef PowhegShowerHandler:SpinCorrelations Yes newdef PowhegShowerHandler:SoftCorrelations Singular newdef PowhegShowerHandler:IntrinsicPtGaussian 1.3*GeV newdef PowhegShowerHandler:IntrinsicPtBeta 0 newdef PowhegShowerHandler:IntrinsicPtGamma 0*GeV newdef PowhegShowerHandler:IntrinsicPtIptmax 0*GeV newdef PowhegShowerHandler:ReconstructionOption OffShell5 ############################################################# # End of interesting user servicable section. # # Anything that follows below should only be touched if you # know what you're doing. # # Really. ############################################################# # # a few default values newdef ShowerHandler:MECorrMode 1 newdef ShowerHandler:ReconstructionOption OffShell5 newdef AlphaQCD:ScaleFactor 1.0 newdef AlphaQCD:NPAlphaS 2 newdef AlphaQCD:Qmin 0.935 newdef AlphaQCD:NumberOfLoops 2 -newdef AlphaQCD:InputOption 1 -newdef AlphaQCD:AlphaMZ 0.126234 +newdef AlphaQCD:AlphaIn 0.126234 # # # Lets set up all the splittings create Herwig::HalfHalfOneSplitFn QtoQGammaSplitFn set QtoQGammaSplitFn:InteractionType QED set QtoQGammaSplitFn:ColourStructure ChargedChargedNeutral set QtoQGammaSplitFn:AngularOrdered Yes create Herwig::HalfHalfOneSplitFn QtoQGSplitFn newdef QtoQGSplitFn:InteractionType QCD newdef QtoQGSplitFn:ColourStructure TripletTripletOctet set QtoQGSplitFn:AngularOrdered Yes create Herwig::OneOneOneSplitFn GtoGGSplitFn newdef GtoGGSplitFn:InteractionType QCD newdef GtoGGSplitFn:ColourStructure OctetOctetOctet set GtoGGSplitFn:AngularOrdered Yes create Herwig::OneOneOneMassiveSplitFn WtoWGammaSplitFn newdef WtoWGammaSplitFn:InteractionType QED newdef WtoWGammaSplitFn:ColourStructure ChargedChargedNeutral set WtoWGammaSplitFn:AngularOrdered Yes create Herwig::OneHalfHalfSplitFn GtoQQbarSplitFn newdef GtoQQbarSplitFn:InteractionType QCD newdef GtoQQbarSplitFn:ColourStructure OctetTripletTriplet set GtoQQbarSplitFn:AngularOrdered Yes create Herwig::OneHalfHalfSplitFn GammatoQQbarSplitFn newdef GammatoQQbarSplitFn:InteractionType QED newdef GammatoQQbarSplitFn:ColourStructure NeutralChargedCharged set GammatoQQbarSplitFn:AngularOrdered Yes create Herwig::HalfOneHalfSplitFn QtoGQSplitFn newdef QtoGQSplitFn:InteractionType QCD newdef QtoGQSplitFn:ColourStructure TripletOctetTriplet set QtoGQSplitFn:AngularOrdered Yes create Herwig::HalfOneHalfSplitFn QtoGammaQSplitFn newdef QtoGammaQSplitFn:InteractionType QED newdef QtoGammaQSplitFn:ColourStructure ChargedNeutralCharged set QtoGammaQSplitFn:AngularOrdered Yes create Herwig::HalfHalfOneEWSplitFn QtoQWZSplitFn newdef QtoQWZSplitFn:InteractionType EW newdef QtoQWZSplitFn:ColourStructure EW # # Now the Sudakovs -create Herwig::QTildeSudakov SudakovCommon +create Herwig::PTCutOff PTCutOff +newdef PTCutOff:pTmin 1.222798*GeV + +create Herwig::SudakovFormFactor SudakovCommon newdef SudakovCommon:Alpha AlphaQCD -newdef SudakovCommon:cutoffKinScale 0.0*GeV +newdef SudakovCommon:Cutoff PTCutOff newdef SudakovCommon:PDFmax 1.0 -newdef SudakovCommon:CutOffOption pT -newdef SudakovCommon:pTmin 1.222798*GeV cp SudakovCommon QtoQGSudakov newdef QtoQGSudakov:SplittingFunction QtoQGSplitFn newdef QtoQGSudakov:PDFmax 1.9 cp SudakovCommon QtoQGammaSudakov set QtoQGammaSudakov:SplittingFunction QtoQGammaSplitFn set QtoQGammaSudakov:Alpha AlphaQED set QtoQGammaSudakov:PDFmax 1.9 cp QtoQGammaSudakov LtoLGammaSudakov +cp PTCutOff LtoLGammaPTCutOff # Technical parameter to stop evolution. -set LtoLGammaSudakov:pTmin 0.000001 +set LtoLGammaPTCutOff:pTmin 0.000001 +set LtoLGammaSudakov:Cutoff LtoLGammaPTCutOff cp SudakovCommon QtoQWZSudakov set QtoQWZSudakov:SplittingFunction QtoQWZSplitFn set QtoQWZSudakov:Alpha AlphaEW set QtoQWZSudakov:PDFmax 1.9 cp QtoQWZSudakov LtoLWZSudakov cp SudakovCommon GtoGGSudakov newdef GtoGGSudakov:SplittingFunction GtoGGSplitFn newdef GtoGGSudakov:PDFmax 2.0 cp SudakovCommon WtoWGammaSudakov newdef WtoWGammaSudakov:SplittingFunction WtoWGammaSplitFn set WtoWGammaSudakov:Alpha AlphaQED cp SudakovCommon GtoQQbarSudakov newdef GtoQQbarSudakov:SplittingFunction GtoQQbarSplitFn newdef GtoQQbarSudakov:PDFmax 120.0 cp SudakovCommon GammatoQQbarSudakov newdef GammatoQQbarSudakov:SplittingFunction GammatoQQbarSplitFn set GammatoQQbarSudakov:Alpha AlphaQED newdef GammatoQQbarSudakov:PDFmax 120.0 cp SudakovCommon GtobbbarSudakov newdef GtobbbarSudakov:SplittingFunction GtoQQbarSplitFn newdef GtobbbarSudakov:PDFmax 40000.0 cp SudakovCommon GtoccbarSudakov newdef GtoccbarSudakov:SplittingFunction GtoQQbarSplitFn newdef GtoccbarSudakov:PDFmax 2000.0 cp SudakovCommon QtoGQSudakov newdef QtoGQSudakov:SplittingFunction QtoGQSplitFn cp SudakovCommon QtoGammaQSudakov newdef QtoGammaQSudakov:SplittingFunction QtoGammaQSplitFn set QtoGammaQSudakov:Alpha AlphaQED cp SudakovCommon utoGuSudakov newdef utoGuSudakov:SplittingFunction QtoGQSplitFn newdef utoGuSudakov:PDFFactor OverOneMinusZ newdef utoGuSudakov:PDFmax 5.0 cp SudakovCommon dtoGdSudakov newdef dtoGdSudakov:SplittingFunction QtoGQSplitFn newdef dtoGdSudakov:PDFFactor OverOneMinusZ # # Now add the final splittings # do SplittingGenerator:AddFinalSplitting u->u,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting d->d,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting s->s,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting c->c,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting b->b,g; QtoQGSudakov do SplittingGenerator:AddFinalSplitting t->t,g; QtoQGSudakov # do SplittingGenerator:AddFinalSplitting g->g,g; GtoGGSudakov # do SplittingGenerator:AddFinalSplitting g->u,ubar; GtoQQbarSudakov do SplittingGenerator:AddFinalSplitting g->d,dbar; GtoQQbarSudakov do SplittingGenerator:AddFinalSplitting g->s,sbar; GtoQQbarSudakov do SplittingGenerator:AddFinalSplitting g->c,cbar; GtoccbarSudakov do SplittingGenerator:AddFinalSplitting g->b,bbar; GtobbbarSudakov do SplittingGenerator:AddFinalSplitting g->t,tbar; GtoQQbarSudakov # do SplittingGenerator:AddFinalSplitting gamma->u,ubar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->d,dbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->s,sbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->c,cbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->b,bbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->t,tbar; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->e-,e+; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->mu-,mu+; GammatoQQbarSudakov do SplittingGenerator:AddFinalSplitting gamma->tau-,tau+; GammatoQQbarSudakov # do SplittingGenerator:AddFinalSplitting u->u,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting d->d,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting s->s,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting c->c,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting b->b,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting t->t,gamma; QtoQGammaSudakov do SplittingGenerator:AddFinalSplitting e-->e-,gamma; LtoLGammaSudakov do SplittingGenerator:AddFinalSplitting mu-->mu-,gamma; LtoLGammaSudakov do SplittingGenerator:AddFinalSplitting tau-->tau-,gamma; LtoLGammaSudakov do SplittingGenerator:AddFinalSplitting W+->W+,gamma; WtoWGammaSudakov # # Now lets add the initial splittings. Remember the form a->b,c; means # that the current particle b is given and we backward branch to new # particle a which is initial state and new particle c which is final state # do SplittingGenerator:AddInitialSplitting u->u,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting d->d,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting s->s,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting c->c,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting b->b,g; QtoQGSudakov do SplittingGenerator:AddInitialSplitting u->u,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting d->d,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting s->s,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting c->c,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting b->b,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting t->t,gamma; QtoQGammaSudakov do SplittingGenerator:AddInitialSplitting g->g,g; GtoGGSudakov # do SplittingGenerator:AddInitialSplitting g->d,dbar; GtoQQbarSudakov do SplittingGenerator:AddInitialSplitting g->u,ubar; GtoQQbarSudakov do SplittingGenerator:AddInitialSplitting g->s,sbar; GtoQQbarSudakov do SplittingGenerator:AddInitialSplitting g->c,cbar; GtoccbarSudakov do SplittingGenerator:AddInitialSplitting g->b,bbar; GtobbbarSudakov # do SplittingGenerator:AddInitialSplitting gamma->d,dbar; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->u,ubar; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->s,sbar; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->c,cbar; GammatoQQbarSudakov do SplittingGenerator:AddInitialSplitting gamma->b,bbar; GammatoQQbarSudakov # do SplittingGenerator:AddInitialSplitting d->g,d; dtoGdSudakov do SplittingGenerator:AddInitialSplitting u->g,u; utoGuSudakov do SplittingGenerator:AddInitialSplitting s->g,s; QtoGQSudakov do SplittingGenerator:AddInitialSplitting c->g,c; QtoGQSudakov do SplittingGenerator:AddInitialSplitting b->g,b; QtoGQSudakov do SplittingGenerator:AddInitialSplitting dbar->g,dbar; dtoGdSudakov do SplittingGenerator:AddInitialSplitting ubar->g,ubar; utoGuSudakov do SplittingGenerator:AddInitialSplitting sbar->g,sbar; QtoGQSudakov do SplittingGenerator:AddInitialSplitting cbar->g,cbar; QtoGQSudakov do SplittingGenerator:AddInitialSplitting bbar->g,bbar; QtoGQSudakov # do SplittingGenerator:AddInitialSplitting d->gamma,d; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting u->gamma,u; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting s->gamma,s; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting c->gamma,c; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting b->gamma,b; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting dbar->gamma,dbar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting ubar->gamma,ubar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting sbar->gamma,sbar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting cbar->gamma,cbar; QtoGammaQSudakov do SplittingGenerator:AddInitialSplitting bbar->gamma,bbar; QtoGammaQSudakov # # Electroweak # do SplittingGenerator:AddFinalSplitting u->u,Z0; QtoQWZSudakov do SplittingGenerator:AddFinalSplitting d->d,Z0; QtoQWZSudakov do SplittingGenerator:AddFinalSplitting s->s,Z0; QtoQWZSudakov do SplittingGenerator:AddFinalSplitting c->c,Z0; QtoQWZSudakov do SplittingGenerator:AddFinalSplitting b->b,Z0; QtoQWZSudakov do SplittingGenerator:AddFinalSplitting t->t,Z0; QtoQWZSudakov do SplittingGenerator:AddInitialSplitting u->u,Z0; QtoQWZSudakov do SplittingGenerator:AddInitialSplitting d->d,Z0; QtoQWZSudakov do SplittingGenerator:AddInitialSplitting s->s,Z0; QtoQWZSudakov do SplittingGenerator:AddInitialSplitting c->c,Z0; QtoQWZSudakov do SplittingGenerator:AddInitialSplitting b->b,Z0; QtoQWZSudakov do SplittingGenerator:AddInitialSplitting t->t,Z0; QtoQWZSudakov do SplittingGenerator:AddFinalSplitting u->d,W+; QtoQWZSudakov do SplittingGenerator:AddFinalSplitting c->s,W+; QtoQWZSudakov do SplittingGenerator:AddFinalSplitting d->u,W-; QtoQWZSudakov do SplittingGenerator:AddFinalSplitting s->c,W-; QtoQWZSudakov do SplittingGenerator:AddInitialSplitting u->d,W+; QtoQWZSudakov do SplittingGenerator:AddInitialSplitting c->s,W+; QtoQWZSudakov do SplittingGenerator:AddInitialSplitting d->u,W-; QtoQWZSudakov do SplittingGenerator:AddInitialSplitting s->c,W-; QtoQWZSudakov diff --git a/src/snippets/FixedTarget.in b/src/snippets/FixedTarget.in new file mode 100644 --- /dev/null +++ b/src/snippets/FixedTarget.in @@ -0,0 +1,7 @@ +# -*- ThePEG-repository -*- +cd /Herwig/EventHandlers +create ThePEG::FixedTargetLuminosity FixedTargetLuminosity FixedTargetLuminosity.so +set FixedTargetLuminosity:BeamParticle /Herwig/Particles/e- +set FixedTargetLuminosity:BeamEMaxA 200.*GeV +set FixedTargetLuminosity:TargetParticle /Herwig/Particles/p+ +set EventHandler:LuminosityFunction FixedTargetLuminosity