Hammer  1.0.0
Helicity Amplitude Module for Matrix Element Reweighting
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ProcGraph.cc
Go to the documentation of this file.
1 ///
2 /// @file ProcGraph.cc
3 /// @brief Container class for process tree structure and its amplitudes associations
4 ///
5 
6 //**** This file is a part of the HAMMER library
7 //**** Copyright (C) 2016 - 2020 The HAMMER Collaboration
8 //**** HAMMER is licensed under version 3 of the GPL; see COPYING for details
9 //**** Please note the MCnet academic guidelines; see GUIDELINES for details
10 
11 // -*- C++ -*-
12 #include "Hammer/ProcGraph.hh"
13 #include "Hammer/AmplitudeBase.hh"
16 #include "Hammer/ProvidersRepo.hh"
18 #include "Hammer/Tools/Logging.hh"
19 #include "Hammer/Process.hh"
20 
21 #include <iostream>
22 
23 using namespace std;
24 
25 namespace Hammer {
26 
27  AmplEntry AmplTriplet::resolvePurePS(bool parentPS, bool daughterPS) const {
28  int switchVal = (parent == nullptr ? 0 : 1) * 8 + (daughter == nullptr ? 0 : 1) * 4 + (parentPS ? 1 : 0) * 2 +
29  (daughterPS ? 1 : 0);
30  if (switchVal % 4 == 0) { // no PS
31  return AmplEntry{edge, AmplType::FULLEDGE};
32  }
33  if (switchVal % 4 == 3) { // pure PS edge
34  return AmplEntry{nullptr, AmplType::FULLEDGE};
35  }
36  if ((abs(switchVal - 3) == 2)) { // daughter declared PS, but not enforced
37  MSG_ERROR("Daughter of an edge declared PS with undeclared parent. You can't touch this!");
38  return AmplEntry{edge, AmplType::FULLEDGE};
39  }
40  if ((abs(switchVal - 6) == 4)) { // parent declared PS, but not enforced
41  MSG_ERROR("Parent of an edge declared PS with undeclared daughter. You can't touch this!");
42  return AmplEntry{edge, AmplType::FULLEDGE};
43  }
44  if ((abs(switchVal - 11) == 2)) { // daughter declared PS; only parent partial edge returned
45  return AmplEntry{parent, AmplType::PARENTEDGE};
46  }
47  if ((abs(switchVal - 10) == 4)) { // parent declared PS; only daughter partial edge returned
48  return AmplEntry{daughter, AmplType::DAUGHTEREDGE};
49  }
50  MSG_ERROR("I can't count!");
51  return AmplEntry{edge, AmplType::FULLEDGE};
52  }
53 
54  Log& AmplTriplet::getLog() const {
55  return Log::getLog("Hammer.AmplTriplet");
56  }
57 
58  ProcGraph::ProcGraph() {
59  }
60 
61  void ProcGraph::initialize(const DictionaryManager* dictionaries, const Process* proc) {
62  _dictionaries = dictionaries;
63  _inputs = proc;
64  makeDepthMap(_inputs->getFirstVertex(), 0ul);
65  makeVertexEdgeTrees();
66  selectEdgeVertices();
67  }
68 
69  const ProcGraph::SelAmplitudeDict& ProcGraph::selectedAmplitudes() const {
70  return _selectedAmplitudes;
71  }
72  const UniqueParticleIndices& ProcGraph::assignedVertices() const {
73  return _assignedVertices;
74  }
75 
76  void ProcGraph::makeDepthMap(ParticleIndex parent, size_t seed){
77  auto it = _inputs->find(parent);
78  if(it == _inputs->end()){
79  return;
80  } else {
81  _depthMap.insert({parent, seed});
82  for(auto& daughter : it->second){
83  makeDepthMap(daughter, seed + 1ul);
84  }
85  }
86  return;
87  }
88 
89  void ProcGraph::makeVertexEdgeTrees() {
90  _implementedVertices.clear();
91  _implementedEdges.clear();
92  //std::map<ParticleIndex, size_t> depthMap;
93  //depthMap.clear();
94  ////starts from topmost vertex in the processTree
95  //depthMap.insert({_inputs->getFirstVertex(), 0ul});
96  for(auto& elem: *_inputs) {
97  vector<PdgId> daughterPdgs;
98  size_t parWeight = 0ul;
99  for(auto elem2: elem.second) {
100  daughterPdgs.push_back(_inputs->getParticle(elem2).pdgId());
101  }
102  //check and fill implemented vertex, whether to be evaluated or purePS
103  PdgId pdgParent = _inputs->getParticle(elem.first).pdgId();
104  auto ampl = _dictionaries->providers().getAmplitude(pdgParent, daughterPdgs);
105  auto purePS = _dictionaries->purePSDefs().isPurePhaseSpace(pdgParent, daughterPdgs);
106  if (ampl != nullptr) {
107  VertexEntry amplTupl{elem.first, ampl, purePS};
108  _implementedVertices.push_back(amplTupl);
109  parWeight = 1ul;
110  }
111  //check and fill implemented edge, whether to be evaluated or purePS
112  for(auto elem2: elem.second) {
113  auto it = _inputs->find(elem2);
114  if (it != _inputs->end()) {
115  size_t edgeWeight = parWeight;
116  vector<PdgId> granddaughterPdgs;
117  //depthMap.insert({it->first, depthMap.find(elem.first)->second + 1ul});
118  for(auto elem3: it->second) {
119  PdgId pdgCodeGrandDaughter = _inputs->getParticle(elem3).pdgId();
120  granddaughterPdgs.push_back(pdgCodeGrandDaughter);
121  }
122  auto edgeAmpl = _dictionaries->providers().getAmplitude(pdgParent, daughterPdgs, granddaughterPdgs);
123  if (edgeAmpl != nullptr) {
124  edgeWeight += 1ul;
125  PdgId pdgCodeDaughter = _inputs->getParticle(elem2).pdgId();
126  auto daughterAmpl = _dictionaries->providers().getAmplitude(pdgCodeDaughter, granddaughterPdgs);
127  auto daughterPurePS = _dictionaries->purePSDefs().isPurePhaseSpace(pdgCodeDaughter, granddaughterPdgs);
128  if (daughterAmpl != nullptr) {
129  edgeWeight += 1ul;
130  }
131  AmplTriplet amplTriplet{ampl, daughterAmpl, edgeAmpl};
132  EdgeEntry edgeTupl{elem.first, elem2, amplTriplet, purePS, daughterPurePS};
133  _implementedEdges[edgeWeight][_depthMap.find(elem2)->second].push_back(edgeTupl);
134  }
135  }
136  }
137  }
138  }
139 
140  bool ProcGraph::isAssignedVertex(ParticleIndex index) const {
141  return _assignedVertices.find(index) != _assignedVertices.end();
142  }
143 
144  void ProcGraph::selectEdgeVertices() {
145  _assignedVertices.clear();
146  _selectedAmplitudes.clear();
147  for(auto& edgeWeight : _implementedEdges) {
148  for(auto& depthLevel : edgeWeight.second) { //this map is ordered largest to smallest
149  for(auto& amplTuple : depthLevel.second) {
150  if (!isAssignedVertex(amplTuple.parentIdx) && !isAssignedVertex(amplTuple.daughterIdx)) {
151  auto amplTriplet = amplTuple.amplitudes; // this is a struct of 3 AmplitudeBase ptrs
152  AmplEntry numAmpl = amplTriplet.resolvePurePS(amplTuple.parentPSFlags.numerator,
153  amplTuple.daughterPSFlags.numerator);
154  AmplEntry denAmpl = amplTriplet.resolvePurePS(amplTuple.parentPSFlags.denominator,
155  amplTuple.daughterPSFlags.denominator);
156  SelectedAmplEntry tmpampl{NumDenPair<AmplEntry>{numAmpl, denAmpl}, amplTuple.daughterIdx};
157  _selectedAmplitudes.insert({amplTuple.parentIdx, tmpampl});
158  _assignedVertices.insert(amplTuple.parentIdx);
159  _assignedVertices.insert(amplTuple.daughterIdx);
160  }
161  }
162  }
163  }
164  for(auto& amplTuple : _implementedVertices) {
165  if (!isAssignedVertex(amplTuple.parentIdx)) {
166  AmplEntry numAmpl{amplTuple.parentPSFlags.numerator ? nullptr : amplTuple.amplitude, AmplType::VERTEX};
167  AmplEntry denAmpl{amplTuple.parentPSFlags.denominator ? nullptr : amplTuple.amplitude, AmplType::VERTEX};
168  SelectedAmplEntry tmpampl{NumDenPair<AmplEntry>{numAmpl, denAmpl}, _inputs->getFirstVertex()};
169  _selectedAmplitudes.insert({amplTuple.parentIdx, tmpampl});
170  _assignedVertices.insert(amplTuple.parentIdx);
171  }
172  }
173  }
174 
175  tuple<Particle, ParticleList, ParticleList> ProcGraph::getParticleVectors(AmplType ampltype, ParticleIndex parent,
176  ParticleIndex daughter) const {
177  if (!_inputs->isParent(parent) || !_inputs->isParent(daughter)) {
178  MSG_ERROR("Something really stinky just happened in CalcAmplitudes. Can you smell it?");
179  }
180  switch (ampltype) {
181  case AmplType::VERTEX: {
182  return tuple<Particle, ParticleList, ParticleList>{
183  _inputs->getParticle(parent), _inputs->getDaughters(parent, true), _inputs->getSiblings(parent, true)};
184  }
185  case AmplType::FULLEDGE: {
186  auto daughters = _inputs->getDaughters(parent, true);
187  auto tmp = _inputs->getDaughters(daughter, true);
188  daughters.insert(daughters.end(), tmp.begin(), tmp.end());
189  return tuple<Particle, ParticleList, ParticleList>{_inputs->getParticle(parent), daughters,
190  _inputs->getSiblings(parent, true)};
191  }
192  case AmplType::PARENTEDGE: {
193  return tuple<Particle, ParticleList, ParticleList>{
194  _inputs->getParticle(parent), _inputs->getDaughters(parent, true), _inputs->getSiblings(parent, true)};
195  }
196  case AmplType::DAUGHTEREDGE: {
197  return tuple<Particle, ParticleList, ParticleList>{_inputs->getParticle(daughter),
198  _inputs->getDaughters(daughter, true),
199  _inputs->getSiblings(daughter, true)};
200  }
201  }
202  MSG_ERROR("Something really stinky just happened in CalcAmplitudes. Can you smell it?");
203  return tuple<Particle, ParticleList, ParticleList>{
204  _inputs->getParticle(parent), _inputs->getDaughters(parent, true), _inputs->getSiblings(parent, true)};
205  }
206 
207  double ProcGraph::getMassFactor(AmplEntry ampl, ParticleIndex parent, ParticleIndex daughter) const {
208  if (!_inputs->isParent(parent) || !_inputs->isParent(daughter)) {
209  MSG_ERROR("Something really stinky just happened in getMassFactor. Can you smell it?");
210  }
211  auto pmass = _inputs->getParticle(parent).p().mass();
212  auto dsize = static_cast<double>(_inputs->getDaughters(parent).size());
213  switch (ampl.type) {
214  case AmplType::VERTEX: {
215  if (ampl.ptr == nullptr) { // check if PS vertex
216  return pow(pmass, 6. - 2. * dsize);
217  }
218  break;
219  }
220  case AmplType::FULLEDGE: {
221  if (ampl.ptr == nullptr) { // check if PS edge, i.e. both vertices are PS
222  auto dmass = _inputs->getParticle(daughter).p().mass();
223  auto gdsize = static_cast<double>(_inputs->getDaughters(daughter).size());
224  return pow(pmass, 6. - 2. * dsize) * pow(dmass, 6. - 2. * gdsize);
225  }
226  break;
227  }
228  case AmplType::PARENTEDGE: {
229  auto dmass = _inputs->getParticle(daughter).p().mass();
230  auto gdsize = static_cast<double>(_inputs->getDaughters(daughter).size());
231  return pow(dmass, 6. - 2. * gdsize);
232  }
233  case AmplType::DAUGHTEREDGE: {
234  return pow(pmass, 6. - 2. * dsize);
235  }
236  }
237  return 1.;
238  }
239 
240  double ProcGraph::getMultFactor(AmplEntry ampl, AmplEntry ancestorAmpl, bool isAncestorGrandparent) const {
241  double val = static_cast<double>(ampl.ptr->multiplicityFactor());
242  if (ampl.type == AmplType::DAUGHTEREDGE) { // No matter the antecedent in the process tree, inside the edge, the
243  // daughter has PS parent.
244  return 1. / val;
245  }
246  if (isAncestorGrandparent) { // Amplitude is connected to the daughter vertex of an edge
247  if (ancestorAmpl.ptr == nullptr || ancestorAmpl.type == AmplType::PARENTEDGE) {
248  return 1. / val;
249  }
250  } else { // Amplitude is connected to the parent vertex of a daughter edge or just a simple vertex
251  if (ancestorAmpl.ptr == nullptr || ancestorAmpl.type == AmplType::DAUGHTEREDGE) {
252  return 1. / val;
253  }
254  }
255  return 1.;
256  }
257 
258  Log& ProcGraph::getLog() const {
259  return Log::getLog("Hammer.ProcGraph");
260  }
261 
262 } // namespace Hammer
PDG codes to UID functions.
Decay process class.
Definition: Process.hh:34
Interface class for amplitudes, rates, FFs dictionary container.
Message logging routines.
Hammer base amplitude class.
Container class for process tree structure and its amplitudes associations.
AmplTriplet amplitudes
Definition: ProcGraph.hh:53
Hammer process class.
Logging class.
Definition: Logging.hh:33
Container class for pure phase space vertices definitions.
AmplitudeBase * ptr
Definition: ProcGraph.fhh:25
VertexDict< SelectedAmplEntry > SelAmplitudeDict
Definition: ProcGraph.hh:84
size_t ParticleIndex
Definition: IndexTypes.hh:27
#define MSG_ERROR(x)
Definition: Logging.hh:367
size_t multiplicityFactor() const
std::set< ParticleIndex > UniqueParticleIndices
Definition: IndexTypes.hh:29
int PdgId
Definition: Pdg.fhh:17
Global container class for amplitudes, rates, FFs, data.