Hammer  1.0.0
Helicity Amplitude Module for Matrix Element Reweighting
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Process.cc
Go to the documentation of this file.
1 ///
2 /// @file Process.cc
3 /// @brief Hammer process class
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++ -*-
13 #include "Hammer/Process.hh"
15 #include "Hammer/Tools/Logging.hh"
16 #include "Hammer/Math/Utils.hh"
17 #include "Hammer/Tools/Pdg.hh"
18 #include "Hammer/Tools/Utils.hh"
19 
20 #include <boost/functional/hash.hpp>
21 #include <iostream>
22 
23 using namespace std;
24 
25 namespace Hammer {
26 
27  Process::Process() {
28  // initSettings();
29  }
30 
31  // Process::~Process() noexcept {
32  // _processTree.clear();
33  // _particles.clear();
34  // _parentDict.clear();
35  // _idTree.clear();
36  // _fullId.clear();
37  // _erasedGammas.clear();
38  // }
39 
41  return _processTree.begin();
42  }
43 
45  return _processTree.end();
46  }
47 
48  Process::const_iterator Process::find(ParticleIndex particle) const {
49  return _processTree.find(particle);
50  }
51 
52  ParticleIndex Process::addParticle(const Particle& p) {
53  _initialized = false;
54  ParticleIndex tmp = _particles.size();
55  _particles.push_back(p);
56  return tmp;
57  }
58 
59  void Process::addVertex(ParticleIndex parent, const ParticleIndices& daughters) {
60  _initialized = false;
61  bool can_add = parent < _particles.size();
62  for (auto elem : daughters) {
63  can_add &= elem < _particles.size();
64  }
65  if (can_add) {
66  _processTree[parent] = daughters;
67  } else {
68  MSG_ERROR("One or more particle index is invalid: vertex NOT added.");
69  }
70  }
71 
72  void Process::removeVertex(ParticleIndex parent, bool prune) {
73  _initialized = false;
74  auto it = _processTree.find(parent);
75  if(it != _processTree.end()) {
76  auto daughters = daughtersId(it);
77  if(prune) {
78  for(auto elem: daughters) {
79  removeVertex(elem, true);
80  }
81  }
82  else {
83  if(parent == 0) {
84  MSG_ERROR("You can't collapse after removing the tree head!");
85  return;
86  }
87  auto it2 = _processTree.find(getParentId(parent));
88  if(it2 != _processTree.end()) {
89  it2->second.insert(it2->second.end(), daughters.begin(), daughters.end());
90  }
91  }
92  _processTree.erase(parent);
93  }
94  }
95 
96  const ParticleIndices& Process::getDaughtersIds(ParticleIndex parent) const {
97  return getOrThrow(_processTree, parent, RangeError("Index not found"));
98  }
99 
100  ParticleIndices Process::getSiblingsIds(ParticleIndex particle) const {
101  ParticleIndices temps;
102  ParticleIndex parent = getParentId(particle);
103  if(parent >= _particles.size()) {
104  return temps;
105  }
106  auto res = getDaughtersIds(parent);
107  for (auto& elem : res) {
108  if(elem != particle) {
109  temps.push_back(elem);
110  }
111  }
112  return temps;
113  }
114 
115  ParticleIndex Process::getParentId(ParticleIndex daughter) const {
116  if(_initialized) {
117  return getOrDefault(_parentDict, daughter, numeric_limits<size_t>::max());
118  }
119  for (auto& elem : _processTree) {
120  if (::find(elem.second.begin(), elem.second.end(), daughter) != elem.second.end()) {
121  return elem.first;
122  }
123  }
124  return numeric_limits<size_t>::max();
125  }
126 
127  const Particle& Process::getParticle(ParticleIndex id) const {
128  if (id < _particles.size()) {
129  return _particles[id];
130  } else {
131  throw Error("Index out of range. You're gonna need a bigger boat, or a smaller shark.");
132  }
133  }
134 
135  ParticleList Process::sortByParent(ParticleIndex parent, ParticleList parts) const {
136  PdgId parentId = _particles[parent].pdgId();
137  function<PdgId(const Particle&)> getter = [parentId](const Particle& a) -> PdgId {
138  return (parentId > 0) ? a.pdgId() : -a.pdgId();
139  };
140  auto sorter = bind(particlesByPdg, getter, placeholders::_1, placeholders::_2);
141  sort(parts.begin(), parts.end(), sorter);
142  return parts;
143  }
144 
145  ParticleList Process::getDaughters(ParticleIndex parent, bool sorted) const {
146  ParticleList temps;
147  auto res = getDaughtersIds(parent);
148  temps.reserve(res.size());
149  for (auto& elem : res) {
150  temps.push_back(_particles[elem]);
151  }
152  if(sorted) {
153  return sortByParent(parent, temps);
154  }
155  return temps;
156  }
157 
158  const Particle& Process::getParent(ParticleIndex daughter) const {
159  ParticleIndex tmp = getParentId(daughter);
160  return _particles[tmp];
161  }
162 
163  ParticleList Process::getSiblings(ParticleIndex particle, bool sorted) const {
164  ParticleIndex parent = getParentId(particle);
165  if(parent >= _particles.size()) {
166  return {};
167  }
168  ParticleList temps;
169  auto res = getDaughtersIds(parent);
170  temps.reserve(res.size()-1);
171  for (auto& elem : res) {
172  if(elem != particle) {
173  temps.push_back(_particles[elem]);
174  }
175  }
176  if(sorted) {
177  return sortByParent(parent, temps);
178  }
179  return temps;
180  }
181 
182  bool Process::isParent(ParticleIndex particle) const {
183  return _processTree.find(particle) != _processTree.end();
184  }
185 
186  pair<Particle, ParticleList> Process::getParticlesByVertex(PdgId parent, vector<PdgId> daughters) const {
187  HashId vertexId = processID(parent, combineDaughters(daughters));
188  auto it = _idTree.find(vertexId);
189  if (it != _idTree.end()){
190  return {_particles[it->second],getDaughters(it->second, true)};
191  }
192  vertexId = processID(flipSign(parent), flipSigns(combineDaughters(daughters)));
193  it = _idTree.find(vertexId);
194  if (it != _idTree.end()){
195  return {_particles[it->second],getDaughters(it->second, true)};
196  }
197  return {};
198  }
199 
200  pair<Particle, ParticleList> Process::getParticlesByVertex(string vertex) const {
201  PID& pdg = PID::instance();
202  auto temp = pdg.expandToValidVertexUIDs(vertex);
203  for (auto& elem : temp) {
204  auto it = _idTree.find(elem);
205  if (it != _idTree.end()){
206  return {_particles[it->second],getDaughters(it->second, true)};
207  }
208  }
209  return {};
210  }
211 
212  HashId Process::getVertexId(string vertex) const {
213  PID& pdg = PID::instance();
214  auto temp = pdg.expandToValidVertexUIDs(vertex);
215  auto it =
216  find_if(temp.begin(), temp.end(), [&](HashId val) -> bool { return _fullId.find(val) != _fullId.end(); });
217  if (it == temp.end()) {
218  return 0;
219  } else {
220  return *it;
221  }
222  // for (auto& elem : temp) {
223  // auto it = _fullId.find(elem);
224  // if (it != _fullId.end()){
225  // return *it;
226  // }
227  // }
228  // return 0;
229  }
230 
231  size_t Process::numParticles(bool withoutPhotons) const {
232  return _particles.size() - (withoutPhotons ? _erasedGammas.size() : 0ul);
233  }
234 
235  ParticleIndex Process::getFirstVertex() const {
236  if(!_initialized) {
237  return findFirstVertex();
238  }
239  return _firstVertexIdx;
240  }
241 
242  ParticleIndex Process::findFirstVertex() const {
243  UniqueParticleIndices used = _erasedGammas;
244  for (auto& elem : _processTree) {
245  for (auto& elem2 : elem.second) {
246  used.insert(elem2);
247  }
248  }
249  for (ParticleIndex i = 0; i < _particles.size(); ++i) {
250  if (used.find(i) == used.end()) {
251  return i;
252  }
253  }
254  return numeric_limits<size_t>::max();
255  }
256 
257  void Process::cacheParticleDependencies() {
258  UniqueParticleIndices used = _erasedGammas;
259  _parentDict.reserve(_particles.size()-1);
260  for(auto& elem: _processTree) {
261  for(auto& elem2: elem.second) {
262  _parentDict.insert({elem2, elem.first});
263  used.insert(elem2);
264  }
265  }
266  for(ParticleIndex i=0; i<_particles.size(); ++i) {
267  if(used.find(i) == used.end()) {
268  _firstVertexIdx = i;
269  break;
270  }
271  }
272  }
273 
274 
275  bool Process::initialize() {
276  if(_particles.size() == 0) {
277  return false;
278  }
279  if(!_initialized) {
280  pruneSoftPhotons();
281  calcSignatures();
282  cacheParticleDependencies();
283  _initialized = true;
284  }
285  return true;
286  /// @todo what else needs to be done here?
287  //The 'else'. We'll never get that two hours back.
288  }
289 
290  void Process::pruneSoftPhotons() {
291  PID& pdg = PID::instance();
292  auto firstvertex = findFirstVertex();
293  for (auto& elem : _processTree) {
294  auto& daughters = elem.second;
295  UniqueParticleIndices erasedgammas = _erasedGammas; //includes gammas deleted at other vertices
296  while (daughters.size() > 2 && find_if(daughters.begin(), daughters.end(), [&](ParticleIndex& idx)-> bool {return (_particles[idx].pdgId() == PID::PHOTON);}) != daughters.end()){
297  // get softest photon
298  map<double, pair<ParticleIndex, Particle>> gammas;
299  for(auto idx : daughters){
300  if(_particles[idx].pdgId() == PID::PHOTON) {
301  gammas.insert({_particles[idx].p().E(), make_pair(idx, _particles[idx])});
302  }
303  }
304  pair<ParticleIndex, Particle> gamma = gammas.begin()->second;
305  // get nearest charged particle
306  map<double, pair<ParticleIndex, Particle>, std::greater<double>> chps;
307  for(auto idx : daughters){
308  if(pdg.getThreeCharge(_particles[idx].pdgId()) != 0) {
309  const auto& mom1 = _particles[idx].p();
310  const auto& mom2 = gamma.second.p();
311  chps.insert({costheta(mom1.pVec(),mom2.pVec()), make_pair(idx, _particles[idx])});
312  }
313  }
314  pair<ParticleIndex, Particle> nchp = chps.begin()->second;
315  // get 'Y' constituents
316  set<ParticleIndex> chTree{nchp.first};
317  ParticleIndices siblings = getSiblingsIds(nchp.first);
318  siblings.erase(remove(siblings.begin(), siblings.end(), gamma.first), siblings.end());
319  set<ParticleIndex> YTree(siblings.begin(), siblings.end());
320  //Momenta
321  FourMomentum pY;
322  for (auto elemY : YTree){
323  pY += _particles[elemY].p();
324  }
325  FourMomentum pCh = nchp.second.p();
326  //Get sub tree members
327  for (ParticleIndex idx = 0; idx < _particles.size(); ++idx){
328  auto ix = idx;
329  while ( (ix != firstvertex) && (::find(daughters.begin(), daughters.end(), ix) == daughters.end()) &&
330  (erasedgammas.find(ix) == erasedgammas.end()) ){
331  ix = getParentId(ix);
332  }
333  if (ix == nchp.first) {
334  chTree.insert(idx);
335  }
336  if (::find(siblings.begin(), siblings.end(), ix) != siblings.end() && ix != gamma.first) {
337  YTree.insert(idx);
338  }
339  }
340  //Now apply boosts. P rest frame objects
341  FourMomentum pP = _particles[elem.first].p();
342  double pYCh = 0.5*pP.mass()*sqrt((1. - pow((pCh.mass() + pY.mass()),2.)/pP.mass2())*(1. - pow((pCh.mass() - pY.mass()),2.)/pP.mass2()));
343  double EY = (pP.mass2() - pCh.mass2() + pY.mass2())/(2.*pP.mass());
344  double ECh = (pP.mass2() + pCh.mass2() - pY.mass2())/(2.*pP.mass());
345  //Boost to P frame
346  auto boostP = pY + pCh;
347  pY.boostToRestFrameOf(boostP);
348  pCh.boostToRestFrameOf(boostP);
349  //Construct separate boosts on Ch and Y to restore momentum conservation
350  double betagammaCh = (pYCh*pCh.E() - ECh*pCh.p())/pCh.mass2();
351  double betagammaY = (pYCh*pY.E() - EY*pY.p())/pY.mass2();
352  double betaCh = (betagammaCh > 0.0) ? 1./sqrt(1. + 1./pow(betagammaCh,2.)) : -1./sqrt(1. + 1./pow(betagammaCh,2.));
353  double betaY = (betagammaY > 0.0) ? 1./sqrt(1. + 1./pow(betagammaY,2.)) : -1./sqrt(1. + 1./pow(betagammaY,2.));
354  FourMomentum boostCh{1., betaCh*pCh.px()/pCh.p(),betaCh*pCh.py()/pCh.p(),betaCh*pCh.pz()/pCh.p()};
355  FourMomentum boostY{1., betaY*pY.px()/pY.p(),betaY*pY.py()/pY.p(),betaY*pY.pz()/pY.p()};
356  for (auto elemCh : chTree) {
357  _particles[elemCh].p().boostToRestFrameOf(boostP).boostFromRestFrameOf(boostCh).boostFromRestFrameOf(pP);
358  }
359  for (auto elemY : YTree) {
360  _particles[elemY].p().boostToRestFrameOf(boostP).boostFromRestFrameOf(boostY).boostFromRestFrameOf(pP);
361  }
362  daughters.erase(remove(daughters.begin(), daughters.end(), gamma.first), daughters.end());
363  erasedgammas.insert(gamma.first);
364  }
365  _erasedGammas.insert(erasedgammas.begin(),erasedgammas.end());
366  }
367  }
368 
369 
370 
371  void Process::calcSignatures() {
372  _fullId.clear();
373  _idTree.clear();
374  for(auto& elem: _processTree) {
375  vector<PdgId> daughterPdgs;
376  for(auto elem2: elem.second) {
377  daughterPdgs.push_back(_particles[elem2].pdgId());
378  }
379  if (::find(daughterPdgs.begin(), daughterPdgs.end(), _particles[elem.first].pdgId()) != daughterPdgs.end()) {
380  continue;
381  }
382  HashId decayId = processID(_particles[elem.first].pdgId(),combineDaughters(daughterPdgs));
383  _fullId.insert(decayId);
384  _idTree.insert({decayId, elem.first});
385  }
386  _hashId = combineProcessIDs(_fullId);
387  }
388 
389  HashId Process::getId() const {
390  return _hashId;
391  }
392 
393  const set<HashId>& Process::fullId() const {
394  return _fullId;
395  }
396 
397  void Process::disable() {
398  _hashId = 0;
399  }
400 
401 
402  void Process::write(flatbuffers::FlatBufferBuilder* msgwriter, flatbuffers::Offset<Serial::FBProcIDs>* msg) const {
403  vector<uint64_t> idfull;
404  for (auto elem : _fullId) {
405  idfull.push_back(elem);
406  }
407  auto serialfull = msgwriter->CreateVector(idfull);
408  Serial::FBProcIDsBuilder serialprocess{*msgwriter};
409  serialprocess.add_id(_hashId);
410  serialprocess.add_idfull(serialfull);
411  *msg = serialprocess.Finish();
412  }
413 
414  void Process::read(const Serial::FBProcIDs* msgreader) {
415  if (msgreader != nullptr) {
416  _hashId = msgreader->id();
417  auto idfull = msgreader->idfull();
418  _fullId.clear();
419  for (unsigned int i = 0; i < idfull->size(); ++i) {
420  _fullId.insert(idfull->Get(i));
421  }
422  }
423  }
424 
425  void Process::defineSettings() {
426  setPath("Process");
427  }
428 
429  Log& Process::getLog() const {
430  return Log::getLog("Hammer.Process");
431  }
432 
433 } // namespace Hammer
PDG codes to UID functions.
auto const & getOrThrow(const std::map< KeyType, ValueType > &data, KeyType key, std::exception error)
Definition: Tools/Utils.hh:51
TensorData read(const Serial::FBTensor *msgreader)
Definition: Operations.cc:76
const ParticleIndices & daughtersId(Process::const_iterator it)
Definition: Process.hh:195
std::vector< PdgId > combineDaughters(const std::vector< PdgId > &daughters, const std::vector< PdgId > &subDaughters)
combine list of codes of daughters and grandaughters (for processes which parameterise two subsequent...
double p() const
returns the absolute value of the 3-momentum
std::vector< HashId > expandToValidVertexUIDs(const std::string &name, const bool &hadOnly=false) const
Definition: Pdg.cc:833
bool particlesByPdg(const std::function< PdgId(const Particle &)> &pdgGetter, const Particle &a, const Particle &b)
checks whether two particles are ordered according to the PDG code ordering used in computing hashes ...
Message logging routines.
double costheta(const std::array< double, 3 > &a, const std::array< double, 3 > &b)
double mass2() const
returns the squared invariant mass
double mass() const
returns the invariant mass if the invariant mass squared is negative returns
std::vector< PdgId > flipSigns(const std::vector< PdgId > &list)
return the PDG codes of the conjugate particles (itself if self-conjugate) for all the PDG codes in a...
ValueType getOrDefault(const std::map< KeyType, ValueType > &data, KeyType key, ValueType fallback)
Definition: Tools/Utils.hh:39
auto begin(reversion_wrapper< T > w)
Definition: Tools/Utils.hh:79
std::vector< Particle > ParticleList
Definition: Particle.fhh:20
int getThreeCharge(PdgId id) const
return where q is the particle electric charge from a PDG code
Definition: Pdg.cc:149
HashId combineProcessIDs(const std::set< HashId > &allIds)
PdgId flipSign(const PdgId &id)
return the PDG code of the conjugate particle (itself if self-conjugate)
Hammer process class.
Logging class.
Definition: Logging.hh:33
Particle class.
Definition: Particle.hh:30
Hammer class for dealing with particle data.
Definition: Pdg.hh:32
ParticleIndex parentId(Process::const_iterator it)
Definition: Process.hh:191
Generic error class.
Definition: Exceptions.hh:23
std::vector< ParticleIndex > ParticleIndices
Definition: IndexTypes.hh:28
Hammer particle data class.
size_t ParticleIndex
Definition: IndexTypes.hh:27
#define MSG_ERROR(x)
Definition: Logging.hh:367
HashId processID(PdgId parent, const std::vector< PdgId > &allDaughters)
compute a unique ID for a given process based on the PDG codes of the parent particle and the ordered...
std::set< ParticleIndex > UniqueParticleIndices
Definition: IndexTypes.hh:29
size_t HashId
Definition: IndexTypes.hh:31
TreeMap::const_iterator const_iterator
Definition: Process.hh:49
int PdgId
Definition: Pdg.fhh:17
Out-of-range error class.
Definition: Exceptions.hh:49
auto end(reversion_wrapper< T > w)
Definition: Tools/Utils.hh:84
Serialization related typedefs and includes.
4-momentum class
Definition: FourMomentum.hh:30
double px() const
returns the momentum x component