gambit is hosted by Hepforge, IPPP Durham
GAMBIT  v1.5.0-2191-ga4742ac
a Global And Modular Bsm Inference Tool
GamYields.cpp
Go to the documentation of this file.
1 // GAMBIT: Global and Modular BSM Inference Tool
2 // *********************************************
25 
30 
31 //#define DARKBIT_DEBUG
32 
33 namespace Gambit
34 {
35  namespace DarkBit
36  {
37 
39  //
40  // Gamma-ray yields
41  //
43 
44 
61  void GA_missingFinalStates(std::vector<std::string> &result)
62  {
63  using namespace Pipes::GA_missingFinalStates;
64  std::set<std::string> missingFinalStates;
65  std::string DMid= *Dep::DarkMatter_ID;
66  std::string DMbarid = *Dep::DarkMatterConj_ID;
67 
69  if ( runOptions->getValueOrDef(false, "ignore_all") ) return;
70 
71  // What type of process are we dealing with?
72  std::string processtype = *Dep::DM_process;
73  TH_Process process = (*Dep::DM_process == "annihilation") ?
74  (*Dep::TH_ProcessCatalog).getProcess(DMid, DMbarid) : (*Dep::TH_ProcessCatalog).getProcess(DMid);
75 
76  // Add only gamma-ray spectra for two and three body final states
77  for (std::vector<TH_Channel>::iterator it = process.channelList.begin();
78  it != process.channelList.end(); ++it)
79  {
80  if ( it->nFinalStates == 2 )
81  {
83  if ( not runOptions->getValueOrDef(false, "ignore_two_body") )
84  {
85  #ifdef DARKBIT_DEBUG
86  std::cout << "Checking for missing two-body final states: "
87  << it->finalStateIDs[0] << " " << it->finalStateIDs[1] << std::endl;
88  #endif
89  if ( not Dep::SimYieldTable->hasChannel(it->finalStateIDs[0], it->finalStateIDs[1], "gamma") )
90  {
91  if ( not Dep::SimYieldTable->hasChannel(it->finalStateIDs[0], "gamma") )
92  missingFinalStates.insert(it->finalStateIDs[0]);
93  if ( not Dep::SimYieldTable->hasChannel(it->finalStateIDs[1], "gamma") )
94  missingFinalStates.insert(it->finalStateIDs[1]);
95  }
96  }
97  }
98  else if ( it->nFinalStates == 3 )
99  {
101  if ( not runOptions->getValueOrDef(false, "ignore_three_body") )
102  {
103  #ifdef DARKBIT_DEBUG
104  std::cout << "Checking for missing three-body final states: "
105  << it->finalStateIDs[0] << " " << it->finalStateIDs[1]
106  << " " << it->finalStateIDs[2] << std::endl;
107  #endif
108  if (not Dep::SimYieldTable->hasChannel(it->finalStateIDs[0], "gamma") )
109  missingFinalStates.insert(it->finalStateIDs[0]);
110  if (not Dep::SimYieldTable->hasChannel(it->finalStateIDs[1], "gamma") )
111  missingFinalStates.insert(it->finalStateIDs[1]);
112  if (not Dep::SimYieldTable->hasChannel(it->finalStateIDs[2], "gamma") )
113  missingFinalStates.insert(it->finalStateIDs[2]);
114  }
115  }
116  }
117  // Remove particles we don't have decays for.
118  for (auto it = missingFinalStates.begin(); it != missingFinalStates.end();)
119  {
120  if ((*Dep::TH_ProcessCatalog).find(*it, "") == NULL)
121  {
122  #ifdef DARKBIT_DEBUG
123  std::cout << "Erasing (because no decays known): " << *it << std::endl;
124  #endif
125  missingFinalStates.erase(it++);
126  }
127  else
128  {
129  #ifdef DARKBIT_DEBUG
130  std::cout << "Keeping (because decay known): " << *it << std::endl;
131  #endif
132  ++it;
133  }
134  }
135 
136  #ifdef DARKBIT_DEBUG
137  std::cout << "Number of missing final states: " << missingFinalStates.size() << std::endl;
138  for (auto it = missingFinalStates.begin(); it != missingFinalStates.end(); it++)
139  {
140  std::cout << *it << std::endl;
141  }
142  #endif
143 
144  result.assign(missingFinalStates.begin(), missingFinalStates.end());
145  }
146 
154  daFunk::Funk boost_dNdE(daFunk::Funk dNdE, double gamma, double mass)
155  {
156  if ( gamma < 1.0 + .02 ) // Ignore less than 2% boosts
157  {
158  if (gamma < 1.0)
159  DarkBit_error().raise(LOCAL_INFO,
160  "boost_dNdE: Requested Lorentz boost with gamma < 1");
161  return dNdE;
162  }
163  double betaGamma = sqrt(gamma*gamma-1);
164  daFunk::Funk E = daFunk::var("E");
165  daFunk::Funk lnE = daFunk::var("lnE");
166  daFunk::Funk Ep = daFunk::var("Ep");
167  daFunk::Funk halfBox_int = betaGamma*sqrt(E*E-mass*mass);
168  daFunk::Funk halfBox_bound = betaGamma*sqrt(Ep*Ep-mass*mass);
169  daFunk::Funk integrand = dNdE/(2*halfBox_int);
170  return integrand->gsl_integration("E", Ep*gamma-halfBox_bound, Ep*gamma+halfBox_bound)
171  ->set_epsabs(0)->set_limit(100)->set_epsrel(1e-3)->set_use_log_fallback(true)->set("Ep", daFunk::var("E"));
172  //
173  // Note: integration over lnE causes problems in the WIMP example (3) as the singularity is dropped.
174  // return (integrand*E)->set("E", exp(lnE))->gsl_integration("lnE", log(Ep*gamma-halfBox_bound), log(Ep*gamma+halfBox_bound))
175  // ->set_epsabs(0)->set_epsrel(1e-3)->set("Ep", daFunk::var("E"));
176  }
177 
178 
182  daFunk::Funk getYield(TH_Process process, double Ecm, double mass, TH_ProcessCatalog catalog,
183  SimYieldTable table, double line_width, stringFunkMap cascadeMC_gammaSpectra)
184  {
186 
187  // Set the daFunk object based on the type of process.
188  daFunk::Funk Yield;
189  if (process.isAnnihilation)
190  {
191  Yield = daFunk::zero("E", "v");
192  }
193  else
194  {
195  Yield = daFunk::zero("E");
196  }
197 
198  // Adding two-body channels
199  for (std::vector<TH_Channel>::iterator it = process.channelList.begin();
200  it != process.channelList.end(); ++it)
201  {
202  bool added = false; // If spectrum is not available from any source
203 
204  // Here only take care of two-body final states
205  if (it->nFinalStates != 2) continue;
206 
207  // Get final state masses
208  double m0 = catalog.getParticleProperty(it->finalStateIDs[0]).mass;
209  double m1 = catalog.getParticleProperty(it->finalStateIDs[1]).mass;
210 
211  // Ignore channels that are kinematically closed for v=0
212  if ( m0 + m1 > Ecm ) continue;
213 
214  // Ignore channels with 0 BR in v=0 limit (if "v" is a variable of genRate, i.e. not a decay).
215  if (it->genRate->hasArg("v") && it->genRate->bind("v")->eval(0.) <= 0.0) continue;
216  else if ( !(it->genRate->hasArgs()) && it->genRate->bind()->eval() <=0.0) continue;
217 
218  double E0 = 0.5*(Ecm*Ecm+m0*m0-m1*m1)/Ecm;
219  double E1 = Ecm-E0;
220 
221  // Check whether two-body final state is in SimYield table
222  if ( table.hasChannel(it->finalStateIDs[0], it->finalStateIDs[1], "gamma") )
223  {
224  Yield = Yield +
225  it->genRate*(table)(
226  it->finalStateIDs[0], it->finalStateIDs[1], "gamma", Ecm);
227  added = true;
228  }
229  // Deal with composite final states
230  else
231  {
232  daFunk::Funk spec0 = daFunk::zero("E");
233  daFunk::Funk spec1 = daFunk::zero("E");
234  added = true;
235 
236  // Final state particle one
237  // Tabulated spectrum available?
238  if ( table.hasChannel(it->finalStateIDs[0], "gamma") )
239  {
240  spec0 = (table)(it->finalStateIDs[0], "gamma")->set("Ecm",E0);
241  }
242  // Gamma-ray line?
243  else if ( it->finalStateIDs[0] == "gamma" )
244  {
245  daFunk::Funk E = daFunk::var("E");
246  spec0 = exp(-pow((E-E0)/line_width/E0,2)/2)/E0/sqrt(2*M_PI)/line_width;
247  }
248  // MC spectra available?
249  else if ( cascadeMC_gammaSpectra.count(it->finalStateIDs[0]) )
250  {
251  double gamma0 = E0/m0;
252  //std::cout << it->finalStateIDs[0] << " " << gamma0 << std::endl;
253  spec0 = boost_dNdE(cascadeMC_gammaSpectra.at(it->finalStateIDs[0]), gamma0, 0.0);
254  }
255  else added = false;
256 
257  // Final state particle two
258  if ( table.hasChannel(it->finalStateIDs[1], "gamma") )
259  {
260  spec1 = (table)(it->finalStateIDs[1], "gamma")->set("Ecm", E1);
261  }
262  else if ( it->finalStateIDs[1] == "gamma" )
263  {
264  daFunk::Funk E = daFunk::var("E");
265  spec1 = exp(-pow((E-E1)/line_width/E1,2)/2)/E1/sqrt(2*M_PI)/line_width;
266  }
267  else if ( cascadeMC_gammaSpectra.count(it->finalStateIDs[1]) )
268  {
269  double gamma1 = E1/m1;
270  //std::cout << it->finalStateIDs[1] << " " << gamma1 << std::endl;
271  spec1 = boost_dNdE(cascadeMC_gammaSpectra.at(it->finalStateIDs[1]), gamma1, 0.0);
272  }
273  else added = false;
274 
275  #ifdef DARKBIT_DEBUG
276  std::cout << it->finalStateIDs[0] << " " << it->finalStateIDs[1] << std::endl;
277  //std::cout << "gammas: " << gamma0 << ", " << gamma1 << std::endl;
278  daFunk::Funk chnSpec = (daFunk::zero("v", "E")
279  + spec0
280  + spec1)-> set("v", 0.);
281  auto x = daFunk::logspace(0, 3, 10);
282  std::vector<double> y = chnSpec->bind("E")->vect(x);
283  std::cout << it->finalStateIDs[0] << it->finalStateIDs[1] << ":\n";
284  std::cout << " E: [";
285  for (std::vector<double>::iterator it2 = x.begin(); it2 != x.end(); it2++)
286  std::cout << *it2 << ", ";
287  std::cout << "]\n";
288  std::cout << " dNdE: [";
289  for (std::vector<double>::iterator it2 = y.begin(); it2 != y.end(); it2++)
290  std::cout << *it2 << ", ";
291  std::cout << "]\n";
292  #endif
293 
294  if (!added)
295  {
296  DarkBit_warning().raise(LOCAL_INFO,
297  "GA_AnnYield_General: cannot find spectra for "
298  + it->finalStateIDs[0] + " " + it->finalStateIDs[1]);
299  }
300 
301  Yield = Yield + (spec0 + spec1) * it->genRate;
302  }
303  } // End adding two-body final states
304 
305  #ifdef DARKBIT_DEBUG
306  std::vector<std::string> test1 = initVector<std::string> ("h0_1_test","h0_2_test","h0_2_test","h0_1_test","WH_test", "A0_test", "h0_1_test", "W+");
307  std::vector<std::string> test2 = initVector<std::string> ("A0_test", "A0_test", "Z0_test", "Z0_test", "WH_test", "Z0_test", "h0_2_test", "W-");
308 
309  for(size_t i=0; i<test1.size();i++)
310  {
311  daFunk::Funk chnSpec = (table)(test1[i], test2[i], "gamma", Ecm);
312  std::vector<double> y = chnSpec->bind("E")->vect(x);
313  os << test1[i] << test2[i] << ":\n";
314  os << " E: [";
315  for (std::vector<double>::iterator it2 = x.begin(); it2 != x.end(); it2++)
316  os << *it2 << ", ";
317  os << "]\n";
318  os << " dNdE: [";
319  for (std::vector<double>::iterator it2 = y.begin(); it2 != y.end(); it2++)
320  os << *it2 << ", ";
321  os << "]\n";
322  }
323  #endif
324 
325  // Adding three-body final states
326  //
327  // NOTE: Three body processes are added even if they are closed for at v=0
328  for (std::vector<TH_Channel>::iterator it = process.channelList.begin();
329  it != process.channelList.end(); ++it)
330  {
331  bool added = true;
332 
333  // Here only take care of three-body final states
334  if (it->nFinalStates != 3) continue;
335 
336  // Implement tabulated three-body final states
337  /*
338  if ( it->nFinalStates == 3
339  and table->hasChannel(it->finalStateIDs[0], "gamma")
340  and table->hasChannel(it->finalStateIDs[1], "gamma")
341  and table->hasChannel(it->finalStateIDs[2], "gamma")
342  )
343  {
344  daFunk::Funk dNdE1dE2 = it->genRate->set("v",0.);
345  daFunk::Funk spec0 =
346  (table)(it->finalStateIDs[0], "gamma");
347  daFunk::Funk spec1 =
348  (table)(it->finalStateIDs[1], "gamma");
349  daFunk::Funk spec2 =
350  (table)(it->finalStateIDs[2], "gamma");
351  Yield = Yield + convspec(spec0, spec1, spec2, dNdE1dE2);
352  }
353  */
354 
355  if ( it->finalStateIDs[0] == "gamma" )
356  {
357  if ( it->finalStateIDs[1] == "gamma" or it->finalStateIDs[2] == "gamma")
358  {
359  DarkBit_warning().raise(LOCAL_INFO, "Second and/or third primary gamma rays in three-body final states ignored.");
360  }
361  double m1 = catalog.getParticleProperty(it->finalStateIDs[1]).mass;
362  double m2 = catalog.getParticleProperty(it->finalStateIDs[2]).mass;
364  mass, m1, m2);
366  mass, m1, m2);
367  daFunk::Funk dsigmavde = it->genRate->gsl_integration(
368  "E1", E1_low, E1_high);
369 
370  #ifdef DARKBIT_DEBUG
371  daFunk::Funk chnSpec = (daFunk::zero("v", "E") + dsigmavde)-> set("v", 0.);
372  std::vector<double> y = chnSpec->bind("E")->vect(x);
373  os << it->finalStateIDs[0] << it->finalStateIDs[1] << it->finalStateIDs[2] << ":\n";
374  os << " E: [";
375  for (std::vector<double>::iterator it2 = x.begin(); it2 != x.end(); it2++)
376  os << *it2 << ", ";
377  os << "]\n";
378  os << " dNdE: [";
379  for (std::vector<double>::iterator it2 = y.begin(); it2 != y.end(); it2++)
380  os << *it2 << ", ";
381  os << "]\n";
382  #endif
383 
384  Yield = Yield + dsigmavde;
385  }
386  else added = false;
387 
388  if (!added)
389  {
390  DarkBit_warning().raise(LOCAL_INFO,
391  "GA_AnnYield_General: ignoring final state "
392  + it->finalStateIDs[0] + " " + it->finalStateIDs[1] + " " + it->finalStateIDs[2]);
393  }
394  }
395  #ifdef DARKBIT_DEBUG
396  if(debug) os.close();
397  #endif
398 
399  return Yield;
400 
401  }
402 
421  {
422  using namespace Pipes::GA_AnnYield_General;
423 
424  std::string DMid= *Dep::DarkMatter_ID;
425  std::string DMbarid = *Dep::DarkMatterConj_ID;
426 
428  double line_width = runOptions->getValueOrDef<double>(0.03, "line_width");
429 
430  // Check that the ProcessCatalog process *is* an annihilation, not a decay.
431  const TH_Process* p = (*Dep::TH_ProcessCatalog).find(DMid, DMbarid);
432  if (p == NULL)
433  DarkBit_error().raise(LOCAL_INFO, "Annihilation process not found. For decaying DM please use GA_DecayYield_General.");
434 
435  // if (not *Dep::TH_ProcessCatalog.isAnnihilation)
436  // DarkBit_error().raise(LOCAL_INFO, "Process is not an annihilation. Please use GA_DecayYield_General.");
437 
438  // Get annihilation process from process catalog
439  TH_Process annProc = (*Dep::TH_ProcessCatalog).getProcess(DMid, DMbarid);
440 
441  // If process involves non-self-conjugate DM then we need to add a factor of 1/2
442  // to the final spectrum. This must be explicitly set in the process catalog.
443  double k = (annProc.isSelfConj) ? 1. : 0.5;
444 
445  // Get particle mass from process catalog
446  const double mass = (*Dep::TH_ProcessCatalog).getParticleProperty(DMid).mass;
447  const double Ecm = 2*mass;
448 
449  // Loop over all channels for that process
450  daFunk::Funk Yield = getYield(annProc, Ecm, mass, *Dep::TH_ProcessCatalog, *Dep::SimYieldTable,
451  line_width, *Dep::cascadeMC_gammaSpectra);
452 
453  result = k*daFunk::ifelse(1e-6 - daFunk::var("v"), Yield/(mass*mass),
454  daFunk::throwError("Spectrum currently only defined for v=0."));
455  }
456 
474  {
475  using namespace Pipes::GA_DecayYield_General;
476 
477  std::string DMid= *Dep::DarkMatter_ID;
478 
480  double line_width = runOptions->getValueOrDef<double>(0.03, "line_width");
481 
482  // // Check that the ProcessCatalog process *is* a decay, not an annihilation.
483  const TH_Process* p = (*Dep::TH_ProcessCatalog).find(DMid);
484  if (p == NULL)
485  DarkBit_error().raise(LOCAL_INFO, "Decay process not found. For annihilating DM please use GA_AnnYield_General.");
486 
487  // // Check that the ProcessCatalog process *is* a decay, not an annihilation.
488  // if (*Dep::TH_ProcessCatalog.isAnnihilation)
489  // DarkBit_error().raise(LOCAL_INFO, "Process is not a decay. Please use GA_AnnYield_General.");
490 
491  // Get annihilation process from process catalog
492  TH_Process decayProc = (*Dep::TH_ProcessCatalog).getProcess(DMid);
493 
494  // Get particle mass from process catalog
495  const double mass = (*Dep::TH_ProcessCatalog).getParticleProperty(DMid).mass;
496  double Ecm = mass;
497 
498  // Loop over all channels for that process
499  daFunk::Funk Yield = getYield(decayProc, Ecm, mass, *Dep::TH_ProcessCatalog, *Dep::SimYieldTable,
500  line_width, *Dep::cascadeMC_gammaSpectra);
501 
502  // Rescale the yield by the correct kinematic factor
503  result = Yield/(mass);
504  }
505 
508  {
509  using namespace Pipes::SimYieldTable_DS5;
510 
511  static bool initialized = false;
512  if ( not initialized )
513  {
514  int flag = 0; // some flag
515  int yieldk = 152; // gamma ray yield
516 
518 
519  double mDM_min, mDM_max;
521  bool allow_yield_extrapolation = runOptions->getValueOrDef(false, "allow_yield_extrapolation");
522  if ( allow_yield_extrapolation )
523  {
524  mDM_min = 0.0; // in this case, the minimally allowed dark matter mass will later be set to be the mass of the final state particle,
525  // with an additional factor 0.99 for the case of Z, W or t final states (following DarkSUSY)
526  mDM_max = 1.0e6;
527  }
528  else
529  {
530  mDM_min = 10.0; // minimal dark matter mass simulated in DarkSUSY.
531  mDM_max = 5000.; // maximal dark matter mass simulated in DarkSUSY.
532  }
533 
534  auto add_channel = [&](int ch, str P1, str P2, str FINAL, double EcmMin, double EcmMax)
535  {
536  daFunk::Funk dNdE = daFunk::func_fromThreadsafe(BEreq::dshayield.pointer(), daFunk::var("mwimp"),
537  daFunk::var("E"), ch, yieldk, flag)->set("mwimp", daFunk::var("Ecm")/2);
538  result.addChannel(dNdE, str_flav_to_mass(P1), str_flav_to_mass(P2), FINAL, EcmMin, EcmMax);
539  };
540 
541  // The following routine adds an annihilation channel, for which the yields are extrapolated below Ecm_ToScale
542  // using the approximation that x*dN/dx is a constant function of the dark matter mass.
543  auto add_channel_with_scaling = [&](int ch, str P1, str P2, str FINAL, double EcmMin, double EcmMax, double Ecm_ToScale)
544  {
545  daFunk::Funk Ecm_ToUse = fmax(Ecm_ToScale, daFunk::var("Ecm"));
546  daFunk::Funk ScalingFactor = Ecm_ToUse/daFunk::var("Ecm");
547  daFunk::Funk dNdE = ScalingFactor * daFunk::func_fromThreadsafe(BEreq::dshayield.pointer(), daFunk::var("mwimp"),
548  ScalingFactor * daFunk::var("E"), ch, yieldk, flag)->set("mwimp", Ecm_ToUse/2);
549  result.addChannel(dNdE, str_flav_to_mass(P1), str_flav_to_mass(P2), FINAL, EcmMin, EcmMax);
550  };
551 
552  // Specifies also center of mass energy range
553  add_channel(12, "Z0", "Z0", "gamma", 2*90.288, 2*mDM_max);
554  add_channel(13, "W+", "W-", "gamma", 2*79.4475, 2*mDM_max);
555  add_channel(14, "nu_e", "nubar_e", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max); // Zero
556  add_channel(15, "e+", "e-", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max); // Zero
557  add_channel(16, "nu_mu", "nubar_mu", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max); // Zero
558  add_channel(17, "mu+", "mu-", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max);
559  add_channel(18, "nu_tau", "nubar_tau", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max); // Zero
560  add_channel(19, "tau+", "tau-", "gamma", 2*std::max(mDM_min, 1.7841), 2*mDM_max);
561  //add_channel(20, "u", "ubar", "gamma", 0., 2*mDM_max); // Zero
562  add_channel(22, "u", "ubar", "gamma", 2*std::max(mDM_min, 1.35), 2*mDM_max); // approx by cc
563  //add_channel(21, "d", "dbar", "gamma", 0., 2*mDM_max); // Zero
564  add_channel(22, "d", "dbar", "gamma", 2*std::max(mDM_min, 1.35), 2*mDM_max); // approx by cc
565  add_channel(22, "c", "cbar", "gamma", 2*std::max(mDM_min, 1.35), 2*mDM_max);
566  //add_channel(23, "s", "sbar", "gamma", 0., 2*mDM_max); // Zero
567  add_channel(22, "s", "sbar", "gamma", 2*std::max(mDM_min, 1.35), 2*mDM_max); // approx by cc
568  add_channel_with_scaling(24, "t", "tbar", "gamma", 2*160.0, 2*mDM_max, 2*173.3);
569  add_channel(25, "b", "bbar", "gamma", 2*std::max(mDM_min, 5.0), 2*mDM_max);
570  add_channel(26, "g", "g", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max);
571 
572  // Add approximations for single-particle cases.
573  // TODO: Replace by boosted rest frame spectrum Z0
574  daFunk::Funk dNdE;
575  dNdE = daFunk::func_fromThreadsafe(BEreq::dshayield.pointer(), daFunk::var("Ecm"), daFunk::var("E"), 12, yieldk, flag);
576  result.addChannel(dNdE/2, "Z0", "gamma", 90.288, mDM_max);
577  dNdE = daFunk::func_fromThreadsafe(BEreq::dshayield.pointer(), daFunk::var("Ecm"), daFunk::var("E"), 13, yieldk, flag);
578  result.addChannel(dNdE/2, "W+", "gamma", 79.4475, mDM_max);
579  result.addChannel(dNdE/2, "W-", "gamma", 79.4475, mDM_max);
580  dNdE = daFunk::func_fromThreadsafe(BEreq::dshayield.pointer(), daFunk::var("Ecm"), daFunk::var("E"), 15, yieldk, flag);
581  result.addChannel(dNdE/2, str_flav_to_mass("e+"), "gamma", std::max(mDM_min, 0.0), mDM_max);
582  result.addChannel(dNdE/2, str_flav_to_mass("e-"), "gamma", std::max(mDM_min, 0.0), mDM_max);
583  dNdE = daFunk::func_fromThreadsafe(BEreq::dshayield.pointer(), daFunk::var("Ecm"), daFunk::var("E"), 17, yieldk, flag);
584  result.addChannel(dNdE/2, str_flav_to_mass("mu+"), "gamma", std::max(mDM_min, 0.0), mDM_max);
585  result.addChannel(dNdE/2, str_flav_to_mass("mu-"), "gamma", std::max(mDM_min, 0.0), mDM_max);
586  dNdE = daFunk::func_fromThreadsafe(BEreq::dshayield.pointer(), daFunk::var("Ecm"), daFunk::var("E"), 19, yieldk, flag);
587  result.addChannel(dNdE/2, str_flav_to_mass("tau+"), "gamma", std::max(mDM_min, 1.7841), mDM_max);
588  result.addChannel(dNdE/2, str_flav_to_mass("tau-"), "gamma", std::max(mDM_min, 1.7841), mDM_max);
589 
590  double Ecm_ToScale_top = 173.3;
591  daFunk::Funk Ecm_ToUse_top = fmax(Ecm_ToScale_top, daFunk::var("Ecm"));
592  daFunk::Funk ScalingFactor_top = Ecm_ToUse_top/daFunk::var("Ecm");
593  dNdE = ScalingFactor_top * daFunk::func_fromThreadsafe(BEreq::dshayield.pointer(), Ecm_ToUse_top,
594  ScalingFactor_top * daFunk::var("E"), 24, yieldk, flag);
595  result.addChannel(dNdE/2, str_flav_to_mass("t"), "gamma", 160.0, mDM_max);
596  result.addChannel(dNdE/2, str_flav_to_mass("tbar"), "gamma", 160.0, mDM_max);
597 
598  // add channels with "mixed final states", i.e. final state particles with (potentially) different masses
599  daFunk::Funk Ecm = daFunk::var("Ecm");
600  auto add_channel_mixedmasses = [&](int ch1, int ch2, str P1, str P2, str FINAL, double m1, double m2, double EcmMin, double EcmMax)
601  {
602  daFunk::Funk dNdE_1 = daFunk::func_fromThreadsafe(BEreq::dshayield.pointer(), daFunk::var("E1"),
603  daFunk::var("E"), ch1, yieldk, flag)->set("E1", Ecm/2 + (m1*m1 - m2*m2)/(2*Ecm));
604  daFunk::Funk dNdE_2 = daFunk::func_fromThreadsafe(BEreq::dshayield.pointer(), daFunk::var("E2"),
605  daFunk::var("E"), ch2, yieldk, flag)->set("E2", Ecm/2 + (m2*m2 - m1*m1)/(2*Ecm));
606  result.addChannel(0.5*(dNdE_1 + dNdE_2), str_flav_to_mass(P1), str_flav_to_mass(P2), FINAL, EcmMin, EcmMax);
607  };
608 
609  // - In the following: approximate spectra from u,d,s (20,21,23) by spectrum from c (22).
610  // - The numerical values for EcmMin and EcmMax are obtained from applying the corresponding two-body kinematics
611  // to the minimally/maximally allowed center-of-mass energies. Hence, EcmMin depends on the flag allow_yield_extrapolation.
612  // If it is false, the assigmnents of Ecm_min assume the value mDM_min = 10.0.
613 
614  add_channel_mixedmasses(22, 22, "u", "dbar", "gamma", 0.0, 0.0, (allow_yield_extrapolation ? 2*1.35 : 20.0), 2*mDM_max);
615  add_channel_mixedmasses(22, 22, "d", "ubar", "gamma", 0.0, 0.0, (allow_yield_extrapolation ? 2*1.35 : 20.0), 2*mDM_max);
616  add_channel_mixedmasses(22, 22, "u", "sbar", "gamma", 0.0, 0.0, (allow_yield_extrapolation ? 2*1.35 : 20.0), 2*mDM_max);
617  add_channel_mixedmasses(22, 22, "s", "ubar", "gamma", 0.0, 0.0, (allow_yield_extrapolation ? 2*1.35 : 20.0), 2*mDM_max);
618  add_channel_mixedmasses(22, 25, "u", "bbar", "gamma", 0.0, 5.0, (allow_yield_extrapolation ? 6.530 : 21.181), 2*mDM_max);
619  add_channel_mixedmasses(25, 22, "b", "ubar", "gamma", 5.0, 0.0, (allow_yield_extrapolation ? 6.530 : 21.181), 2*mDM_max);
620 
621  add_channel_mixedmasses(22, 22, "c", "dbar", "gamma", 1.35, 0.0, (allow_yield_extrapolation ? 3.260 : 20.091), 2*mDM_max);
622  add_channel_mixedmasses(22, 22, "d", "cbar", "gamma", 0.0, 1.35, (allow_yield_extrapolation ? 3.260 : 20.091), 2*mDM_max);
623  add_channel_mixedmasses(22, 22, "c", "sbar", "gamma", 1.35, 0.0, (allow_yield_extrapolation ? 3.260 : 20.091), 2*mDM_max);
624  add_channel_mixedmasses(22, 22, "s", "cbar", "gamma", 0.0, 1.35, (allow_yield_extrapolation ? 3.260 : 20.091), 2*mDM_max);
625  add_channel_mixedmasses(22, 25, "c", "bbar", "gamma", 1.35, 5.0, (allow_yield_extrapolation ? 6.35 : 21.099), 2*mDM_max);
626  add_channel_mixedmasses(25, 22, "b", "cbar", "gamma", 5.0, 1.35, (allow_yield_extrapolation ? 6.35 : 21.099), 2*mDM_max);
627 
628  add_channel_mixedmasses(24, 22, "t", "dbar", "gamma", 175.0, 0.0, (allow_yield_extrapolation ? 176.355 : 185.285), 2*mDM_max);
629  add_channel_mixedmasses(22, 24, "d", "tbar", "gamma", 0.0, 175.0, (allow_yield_extrapolation ? 176.355 : 185.285), 2*mDM_max);
630  add_channel_mixedmasses(24, 22, "t", "sbar", "gamma", 175.0, 0.0, (allow_yield_extrapolation ? 176.355 : 185.285), 2*mDM_max);
631  add_channel_mixedmasses(22, 24, "s", "tbar", "gamma", 0.0, 175.0, (allow_yield_extrapolation ? 176.355 : 185.285), 2*mDM_max);
632  add_channel_mixedmasses(24, 25, "t", "bbar", "gamma", 175.0, 5.0, (allow_yield_extrapolation ? 180.0 : 185.214), 2*mDM_max);
633  add_channel_mixedmasses(25, 24, "b", "tbar", "gamma", 5.0, 175.0, (allow_yield_extrapolation ? 180.0 : 185.214), 2*mDM_max);
634 
635  initialized = true;
636  }
637  }
638 
641  {
642  using namespace Pipes::SimYieldTable_DarkSUSY;
643 
644  static bool initialized = false;
645  if ( not initialized )
646  {
647  int flag = 0; // some flag
648  int yieldpdg = 22; // gamma ray yield (pdg code)
649  int diff=1; // differential yields (=1)
650  char*hel = (char *)"0"; //helicity
651 
653 
654  double mDM_min, mDM_max;
656  bool allow_yield_extrapolation = runOptions->getValueOrDef(false, "allow_yield_extrapolation");
657  if ( allow_yield_extrapolation )
658  {
659  mDM_min = 0.0; // in this case, the minimally allowed dark matter mass will later be set to be the mass of the final state particle,
660  // with an additional factor 0.99 for the case of Z, W or t final states (following DarkSUSY)
661  mDM_max = 1.0e6;
662  }
663  else
664  {
665  mDM_min = 3.0; // minimal dark matter mass simulated in DarkSUSY6.
666  mDM_max = 20000.; // maximal dark matter mass simulated in DarkSUSY6.
667  }
668 
669  auto add_channel = [&](int pdg, str P1, str P2, str FINAL, double EcmMin, double EcmMax)
670  {
671  daFunk::Funk dNdE = daFunk::func_fromThreadsafe(BEreq::dsanyield_sim.pointer(), daFunk::var("mwimp"),
672  daFunk::var("E"), pdg, hel,yieldpdg, diff, flag)->set("mwimp", daFunk::var("Ecm")/2);
673  result.addChannel(dNdE, str_flav_to_mass(P1), str_flav_to_mass(P2), FINAL, EcmMin, EcmMax);
674  };
675 
676  // The following routine adds an annihilation channel, for which the yields are extrapolated below Ecm_ToScale
677  // using the approximation that x*dN/dx is a constant function of the dark matter mass.
678  auto add_channel_with_scaling = [&](int pdg, str P1, str P2, str FINAL, double EcmMin, double EcmMax, double Ecm_ToScale)
679  {
680  daFunk::Funk Ecm_ToUse = fmax(Ecm_ToScale, daFunk::var("Ecm"));
681  daFunk::Funk ScalingFactor = Ecm_ToUse/daFunk::var("Ecm");
682  daFunk::Funk dNdE = ScalingFactor * daFunk::func_fromThreadsafe(BEreq::dsanyield_sim.pointer(), daFunk::var("mwimp"),
683  ScalingFactor * daFunk::var("E"), pdg, hel, yieldpdg, diff, flag)->set("mwimp", Ecm_ToUse/2);
684  result.addChannel(dNdE, str_flav_to_mass(P1), str_flav_to_mass(P2), FINAL, EcmMin, EcmMax);
685  };
686 
687  // specifies also center of mass energy range
688  add_channel(23, "Z0", "Z0", "gamma", 2*90.288, 2*mDM_max);
689  add_channel(24, "W+", "W-", "gamma", 2*79.4475, 2*mDM_max);
690  add_channel(12, "nu_e", "nubar_e", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max); // Zero
691  add_channel(11, "e+", "e-", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max); // Zero
692  add_channel(14, "nu_mu", "nubar_mu", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max); // Zero
693  add_channel(13, "mu+", "mu-", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max);
694  add_channel(16, "nu_tau", "nubar_tau", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max); // Zero
695  add_channel(15, "tau+", "tau-", "gamma", 2*std::max(mDM_min, 1.7841), 2*mDM_max);
696  //add_channel(2, "u", "ubar", "gamma", 0., 2*mDM_max); // Zero
697  add_channel(2, "u", "ubar", "gamma", 2*std::max(mDM_min, 1.35), 2*mDM_max); // approx by cc
698  //add_channel(1, "d", "dbar", "gamma", 0., 2*mDM_max); // Zero
699  add_channel(1, "d", "dbar", "gamma", 2*std::max(mDM_min, 1.35), 2*mDM_max); // approx by cc
700  add_channel(4, "c", "cbar", "gamma", 2*std::max(mDM_min, 1.35), 2*mDM_max);
701  //add_channel(3, "s", "sbar", "gamma", 0., 2*mDM_max); // Zero
702  add_channel(3, "s", "sbar", "gamma", 2*std::max(mDM_min, 1.35), 2*mDM_max); // approx by cc
703  add_channel_with_scaling(6, "t", "tbar", "gamma", 2*160.0, 2*mDM_max, 2*173.3);
704  add_channel(5, "b", "bbar", "gamma", 2*std::max(mDM_min, 5.0), 2*mDM_max);
705  add_channel(21, "g", "g", "gamma", 2*std::max(mDM_min, 0.0), 2*mDM_max);
706 
707  // Add approximations for single-particle cases.
708  // TODO: Replace by boosted rest frame spectrum Z0
709  daFunk::Funk dNdE;
710  dNdE = daFunk::func_fromThreadsafe(BEreq::dsanyield_sim.pointer(), daFunk::var("Ecm"), daFunk::var("E"), 23, hel,yieldpdg, diff,flag);
711  result.addChannel(dNdE/2, "Z0", "gamma", 90.288, mDM_max);
712  dNdE = daFunk::func_fromThreadsafe(BEreq::dsanyield_sim.pointer(), daFunk::var("Ecm"), daFunk::var("E"), 24, hel,yieldpdg, diff, flag);
713  result.addChannel(dNdE/2, "W+", "gamma", 79.4475, mDM_max);
714  result.addChannel(dNdE/2, "W-", "gamma", 79.4475, mDM_max);
715  dNdE = daFunk::func_fromThreadsafe(BEreq::dsanyield_sim.pointer(), daFunk::var("Ecm"), daFunk::var("E"), 11, hel, yieldpdg, diff, flag);
716  result.addChannel(dNdE/2, str_flav_to_mass("e+"), "gamma", std::max(mDM_min, 0.0), mDM_max);
717  result.addChannel(dNdE/2, str_flav_to_mass("e-"), "gamma", std::max(mDM_min, 0.0), mDM_max);
718  dNdE = daFunk::func_fromThreadsafe(BEreq::dsanyield_sim.pointer(), daFunk::var("Ecm"), daFunk::var("E"), 13, hel, yieldpdg, diff, flag);
719  result.addChannel(dNdE/2, str_flav_to_mass("mu+"), "gamma", std::max(mDM_min, 0.0), mDM_max);
720  result.addChannel(dNdE/2, str_flav_to_mass("mu-"), "gamma", std::max(mDM_min, 0.0), mDM_max);
721  dNdE = daFunk::func_fromThreadsafe(BEreq::dsanyield_sim.pointer(), daFunk::var("Ecm"), daFunk::var("E"), 15, hel, yieldpdg, diff, flag);
722  result.addChannel(dNdE/2, str_flav_to_mass("tau+"), "gamma", std::max(mDM_min, 1.7841), mDM_max);
723  result.addChannel(dNdE/2, str_flav_to_mass("tau-"), "gamma", std::max(mDM_min, 1.7841), mDM_max);
724 
725  double Ecm_ToScale_top = 173.3;
726  daFunk::Funk Ecm_ToUse_top = fmax(Ecm_ToScale_top, daFunk::var("Ecm"));
727  daFunk::Funk ScalingFactor_top = Ecm_ToUse_top/daFunk::var("Ecm");
728  dNdE = ScalingFactor_top * daFunk::func_fromThreadsafe(BEreq::dsanyield_sim.pointer(), Ecm_ToUse_top,
729  ScalingFactor_top * daFunk::var("E"), 6, hel, yieldpdg, diff, flag);
730  result.addChannel(dNdE/2, str_flav_to_mass("t"), "gamma", 160.0, mDM_max);
731  result.addChannel(dNdE/2, str_flav_to_mass("tbar"), "gamma", 160.0, mDM_max);
732 
733  // Add channels with "mixed final states", i.e. final state particles with (potentially) different masses
734  daFunk::Funk Ecm = daFunk::var("Ecm");
735  auto add_channel_mixedmasses = [&](int pdg1, int pdg2, str P1, str P2, str FINAL, double m1, double m2, double EcmMin, double EcmMax)
736  {
737  daFunk::Funk dNdE_1 = daFunk::func_fromThreadsafe(BEreq::dsanyield_sim.pointer(), daFunk::var("E1"),
738  daFunk::var("E"), pdg1, hel, yieldpdg, diff, flag)->set("E1", Ecm/2 + (m1*m1 - m2*m2)/(2*Ecm));
739  daFunk::Funk dNdE_2 = daFunk::func_fromThreadsafe(BEreq::dsanyield_sim.pointer(), daFunk::var("E2"),
740  daFunk::var("E"), pdg2, hel, yieldpdg, diff, flag)->set("E2", Ecm/2 + (m2*m2 - m1*m1)/(2*Ecm));
741  result.addChannel(0.5*(dNdE_1 + dNdE_2), str_flav_to_mass(P1), str_flav_to_mass(P2), FINAL, EcmMin, EcmMax);
742  };
743 
744  // - The numerical values for EcmMin and EcmMax are obtained from applying the corresponding two-body kinematics
745  // to the minimally/maximally allowed center-of-mass energies. Hence, EcmMin depends on the flag allow_yield_extrapolation.
746 
747  add_channel_mixedmasses(2, -1, "u", "dbar", "gamma", 0.0, 0.0, (allow_yield_extrapolation ? 2*1.35 : 20.0), 2*mDM_max);
748  add_channel_mixedmasses(1, -2, "d", "ubar", "gamma", 0.0, 0.0, (allow_yield_extrapolation ? 2*1.35 : 20.0), 2*mDM_max);
749  add_channel_mixedmasses(2, -3, "u", "sbar", "gamma", 0.0, 0.0, (allow_yield_extrapolation ? 2*1.35 : 20.0), 2*mDM_max);
750  add_channel_mixedmasses(3, -2, "s", "ubar", "gamma", 0.0, 0.0, (allow_yield_extrapolation ? 2*1.35 : 20.0), 2*mDM_max);
751  add_channel_mixedmasses(2, -5, "u", "bbar", "gamma", 0.0, 5.0, (allow_yield_extrapolation ? 6.530 : 21.181), 2*mDM_max);
752  add_channel_mixedmasses(5, -2, "b", "ubar", "gamma", 5.0, 0.0, (allow_yield_extrapolation ? 6.530 : 21.181), 2*mDM_max);
753 
754  add_channel_mixedmasses(4, -1, "c", "dbar", "gamma", 1.35, 0.0, (allow_yield_extrapolation ? 3.260 : 20.091), 2*mDM_max);
755  add_channel_mixedmasses(1, -4, "d", "cbar", "gamma", 0.0, 1.35, (allow_yield_extrapolation ? 3.260 : 20.091), 2*mDM_max);
756  add_channel_mixedmasses(4, -3, "c", "sbar", "gamma", 1.35, 0.0, (allow_yield_extrapolation ? 3.260 : 20.091), 2*mDM_max);
757  add_channel_mixedmasses(3, -4, "s", "cbar", "gamma", 0.0, 1.35, (allow_yield_extrapolation ? 3.260 : 20.091), 2*mDM_max);
758  add_channel_mixedmasses(4, -5, "c", "bbar", "gamma", 1.35, 5.0, (allow_yield_extrapolation ? 6.35 : 21.099), 2*mDM_max);
759  add_channel_mixedmasses(5, -4, "b", "cbar", "gamma", 5.0, 1.35, (allow_yield_extrapolation ? 6.35 : 21.099), 2*mDM_max);
760 
761  add_channel_mixedmasses(6, -1, "t", "dbar", "gamma", 175.0, 0.0, (allow_yield_extrapolation ? 176.355 : 185.285), 2*mDM_max);
762  add_channel_mixedmasses(1, -6, "d", "tbar", "gamma", 0.0, 175.0, (allow_yield_extrapolation ? 176.355 : 185.285), 2*mDM_max);
763  add_channel_mixedmasses(6, -3, "t", "sbar", "gamma", 175.0, 0.0, (allow_yield_extrapolation ? 176.355 : 185.285), 2*mDM_max);
764  add_channel_mixedmasses(3, -6, "s", "tbar", "gamma", 0.0, 175.0, (allow_yield_extrapolation ? 176.355 : 185.285), 2*mDM_max);
765  add_channel_mixedmasses(6, -5, "t", "bbar", "gamma", 175.0, 5.0, (allow_yield_extrapolation ? 180.0 : 185.214), 2*mDM_max);
766  add_channel_mixedmasses(5, -6, "b", "tbar", "gamma", 5.0, 175.0, (allow_yield_extrapolation ? 180.0 : 185.214), 2*mDM_max);
767 
768  initialized = true;
769  }
770  }
771 
774  {
775  using namespace Pipes::SimYieldTable_MicrOmegas;
777 
778  static bool initialized = false;
779  const int outN = 0; // gamma
780 
781  if ( not initialized )
782  {
783  double mDM_max;
784  if ( runOptions->getValueOrDef(false, "allow_yield_extrapolation") )
785  {
786  mDM_max = 1.0e6;
787  }
788  else
789  {
790  mDM_max = 5000.; // maximal dark matter mass simulated in micromegas.
791  }
792 
793  auto add_channel = [&](int inP, str P1, str P2, str FINAL, double EcmMin, double EcmMax)
794  {
795  daFunk::Funk dNdE = daFunk::func_fromThreadsafe(BEreq::dNdE.pointer(), daFunk::var("Ecm"), daFunk::var("E"), inP, outN)/daFunk::var("E");
796  result.addChannel(dNdE, str_flav_to_mass(P1), str_flav_to_mass(P2), FINAL, EcmMin, EcmMax); // specifies also center of mass energy range
797  };
798 
799  // The following routine adds an annihilation channel, for which the yields are extrapolated below Ecm_ToScale
800  // using the approximation that x*dN/dx is a constant function of the dark matter mass.
801  auto add_channel_with_scaling = [&](int inP, str P1, str P2, str FINAL, double EcmMin, double EcmMax, double Ecm_ToScale)
802  {
803  daFunk::Funk Ecm_ToUse = fmax(Ecm_ToScale, daFunk::var("Ecm"));
804  daFunk::Funk ScalingFactor = Ecm_ToUse/daFunk::var("Ecm");
805  daFunk::Funk dNdE = ScalingFactor * daFunk::func_fromThreadsafe(BEreq::dNdE.pointer(), Ecm_ToUse,
806  ScalingFactor * daFunk::var("E"), inP, outN)/(ScalingFactor * daFunk::var("E"));
807  result.addChannel(dNdE, str_flav_to_mass(P1), str_flav_to_mass(P2), FINAL, EcmMin, EcmMax);
808  };
809 
810  add_channel(0, "g", "g", "gamma", 2*2., 2*mDM_max);
811  add_channel(1, "d", "dbar", "gamma", 2*2., 2*mDM_max);
812  add_channel(2, "u", "ubar", "gamma", 2*2., 2*mDM_max);
813  add_channel(3, "s", "sbar", "gamma", 2*2., 2*mDM_max);
814  add_channel(4, "c", "cbar", "gamma", 2*2., 2*mDM_max);
815  add_channel(5, "b", "bbar", "gamma", 2*5., 2*mDM_max);
816  add_channel_with_scaling(6, "t", "tbar", "gamma", 2*160.0, 2*mDM_max, 2.0*176.0);
817  add_channel(7, "e+", "e-", "gamma", 2*2., 2*mDM_max);
818  add_channel(8, "mu+", "mu-", "gamma", 2*2., 2*mDM_max);
819  add_channel(9, "tau+", "tau-", "gamma", 2*2., 2*mDM_max);
820  add_channel(10, "Z0", "Z0", "gamma", 2*90.288, 2*mDM_max);
821  add_channel(13, "W+", "W-", "gamma", 2*79.497, 2*mDM_max);
822 
823  result.addChannel(daFunk::zero("Ecm", "E"), "nu_e", "nubar_e", "gamma", 2*2., 2*mDM_max);
824  result.addChannel(daFunk::zero("Ecm", "E"), "nu_mu", "nubar_mu", "gamma", 2*2., 2*mDM_max);
825  result.addChannel(daFunk::zero("Ecm", "E"), "nu_tau", "nubar_tau", "gamma", 2*2., 2*mDM_max);
826 
827  // Add approximations for single-particle cases.
828  daFunk::Funk dNdE;
829  dNdE = (daFunk::func_fromThreadsafe(BEreq::dNdE.pointer(), daFunk::var("_Ecm"), daFunk::var("E"), 8, outN)
830  /daFunk::var("E"))->set("_Ecm", daFunk::var("Ecm")*2);
831  result.addChannel(dNdE/2, str_flav_to_mass("mu+"), "gamma", 2., mDM_max);
832  result.addChannel(dNdE/2, str_flav_to_mass("mu-"), "gamma", 2., mDM_max);
833  dNdE = (daFunk::func_fromThreadsafe(BEreq::dNdE.pointer(), daFunk::var("_Ecm"), daFunk::var("E"), 9, outN)
834  /daFunk::var("E"))->set("_Ecm", daFunk::var("Ecm")*2);
835  result.addChannel(dNdE/2, str_flav_to_mass("tau+"), "gamma", 2., mDM_max);
836  result.addChannel(dNdE/2, str_flav_to_mass("tau-"), "gamma", 2., mDM_max);
837  dNdE = (daFunk::func_fromThreadsafe(BEreq::dNdE.pointer(), daFunk::var("_Ecm"), daFunk::var("E"), 10, outN)
838  /daFunk::var("E"))->set("_Ecm", daFunk::var("Ecm")*2);
839  result.addChannel(dNdE/2, "Z0", "gamma", 90.288, mDM_max);
840  dNdE = (daFunk::func_fromThreadsafe(BEreq::dNdE.pointer(), daFunk::var("_Ecm"), daFunk::var("E"), 13, outN)
841  /daFunk::var("E"))->set("_Ecm", daFunk::var("Ecm")*2);
842  result.addChannel(dNdE/2, "W+", "gamma", 79.497, mDM_max);
843  result.addChannel(dNdE/2, "W-", "gamma", 79.497, mDM_max);
844 
845  // Add single particle lookup for t tbar to prevent them from being tagged as missing final states for cascades.
846  double Ecm_ToScale_top = 176.0;
847  daFunk::Funk Ecm_ToUse_top = fmax(Ecm_ToScale_top, daFunk::var("Ecm"));
848  daFunk::Funk ScalingFactor_top = Ecm_ToUse_top/daFunk::var("Ecm");
849  dNdE = ScalingFactor_top * (daFunk::func_fromThreadsafe(BEreq::dNdE.pointer(), daFunk::var("_Ecm"), ScalingFactor_top * daFunk::var("E"), 6, outN)
850  /(ScalingFactor_top * daFunk::var("E")))->set("_Ecm", Ecm_ToUse_top*2.0);
851  result.addChannel(dNdE/2, str_flav_to_mass("t"), "gamma", 160.0, mDM_max);
852  result.addChannel(dNdE/2, str_flav_to_mass("tbar"), "gamma", 160.0, mDM_max);
853 
854  // Add channels with "mixed final states", i.e. final state particles with (potentially) different masses
855  daFunk::Funk Ecm = daFunk::var("Ecm");
856  auto add_channel_mixedmasses = [&](int inP1, int inP2, str P1, str P2, str FINAL, double m1, double m2, double EcmMin, double EcmMax)
857  {
858  daFunk::Funk dNdE_1 = (daFunk::func_fromThreadsafe(BEreq::dNdE.pointer(), daFunk::var("Ecm1"),
859  daFunk::var("E"), inP1, outN)->set("Ecm1", Ecm + (m1*m1 - m2*m2)/Ecm))/daFunk::var("E");
860  daFunk::Funk dNdE_2 = (daFunk::func_fromThreadsafe(BEreq::dNdE.pointer(), daFunk::var("Ecm2"),
861  daFunk::var("E"), inP2, outN)->set("Ecm2", Ecm + (m2*m2 - m1*m1)/Ecm))/daFunk::var("E");
862  result.addChannel(0.5*(dNdE_1 + dNdE_2), str_flav_to_mass(P1), str_flav_to_mass(P2), FINAL, EcmMin, EcmMax);
863  };
864 
865  // - The numerical values for EcmMin and EcmMax are obtained from applying the corresponding two-body kinematics
866  // to the minimal/maximal center-of-mass energies allowed by the micromegas tables
867  add_channel_mixedmasses(2, 1, "u", "dbar", "gamma", 0.0, 0.0, 2*2., 2*mDM_max);
868  add_channel_mixedmasses(1, 2, "d", "ubar", "gamma", 0.0, 0.0, 2*2., 2*mDM_max);
869  add_channel_mixedmasses(2, 3, "u", "sbar", "gamma", 0.0, 0.0, 2*2., 2*mDM_max);
870  add_channel_mixedmasses(3, 2, "s", "ubar", "gamma", 0.0, 0.0, 2*2., 2*mDM_max);
871  add_channel_mixedmasses(2, 5, "u", "bbar", "gamma", 0.0, 5.0, 7.386, 2*mDM_max);
872  add_channel_mixedmasses(5, 2, "b", "ubar", "gamma", 5.0, 0.0, 7.386, 2*mDM_max);
873 
874  add_channel_mixedmasses(4, 1, "c", "dbar", "gamma", 1.35, 0.0, 4.413, 2*mDM_max);
875  add_channel_mixedmasses(1, 4, "d", "cbar", "gamma", 0.0, 1.35, 4.413, 2*mDM_max);
876  add_channel_mixedmasses(4, 3, "c", "sbar", "gamma", 1.35, 0.0, 4.413, 2*mDM_max);
877  add_channel_mixedmasses(3, 4, "s", "cbar", "gamma", 0.0, 1.35, 4.413, 2*mDM_max);
878  add_channel_mixedmasses(4, 5, "c", "bbar", "gamma", 1.35, 5.0, 7.214, 2*mDM_max);
879  add_channel_mixedmasses(5, 4, "b", "cbar", "gamma", 5.0, 1.35, 7.214, 2*mDM_max);
880 
881  add_channel_mixedmasses(6, 1, "t", "dbar", "gamma", 176.0, 0.0, 178.011, 2*mDM_max);
882  add_channel_mixedmasses(1, 6, "d", "tbar", "gamma", 0.0, 176.0, 178.011, 2*mDM_max);
883  add_channel_mixedmasses(6, 3, "t", "sbar", "gamma", 176.0, 0.0, 178.011, 2*mDM_max);
884  add_channel_mixedmasses(3, 6, "s", "tbar", "gamma", 0.0, 176.0, 178.011, 2*mDM_max);
885  add_channel_mixedmasses(6, 5, "t", "bbar", "gamma", 176.0, 5.0, 181.0, 2*mDM_max);
886  add_channel_mixedmasses(5, 6, "b", "tbar", "gamma", 5.0, 176.0, 181.0, 2*mDM_max);
887 
888  initialized = true;
889  }
890  }
891 
892  class PPPC_interpolation
893  {
894  public:
895  PPPC_interpolation(std::string filename)
896  {
897  table = ASCIItableReader(filename);
898  std::vector<std::string> colnames = initVector<std::string>(
899  "mass", "log10x", "ee", "mumu", "tautau", "qq", "cc", "bb", "tt",
900  "WW", "ZZ", "gg", "gammagamma", "hh");
901  table.setcolnames(colnames);
902  // log10x = log10(E_gamma/m);
903  log10x = std::vector<double>(table["log10x"].begin(), table["log10x"].begin()+180);
904  }
905  PPPC_interpolation() {} // Dummy initializer
906 
907  double operator()(std::string channel, double /*m*/, double /*e*/)
908  {
909  // Not yet implemented
910  std::vector<double> y(table[channel].begin(), table[channel].end());
911  return 0;
912  }
913 
914  private:
915  std::vector<double> log10x;
916  ASCIItableReader table;
917  };
918 
921  {
922  using namespace Pipes::SimYieldTable_PPPC;
923  static bool initialized = false;
924  static PPPC_interpolation PPPC_gam_object;
925 
926  if ( not initialized )
927  {
928  std::string filename = "DarkBit/data/AtProductionNoEW_gammas.dat";
929  PPPC_gam_object = PPPC_interpolation(filename);
930  initialized = true;
931  DarkBit_error().raise(LOCAL_INFO,
932  "SimYieldTable_PPPC is not implemented yet. Use e.g. SimYieldTable_DarkSUSY instead.");
933  }
934  }
935  }
936 }
std::vector< TH_Channel > channelList
List of channels.
error & DarkBit_error()
void GA_missingFinalStates(std::vector< std::string > &result)
Identification of final states that are not yet tabulated.
Definition: GamYields.cpp:61
Funk throwError(std::string msg)
Definition: daFunk.hpp:1411
TH_ParticleProperty getParticleProperty(str) const
Retrieve properties of a given particle involved in one or more processes in this catalog...
template double gamma3bdy_limits< 0 >(double, double, double, double)
void SimYieldTable_DS5(SimYieldTable &result)
SimYieldTable based on DarkSUSY5 tabulated results. (DS6 below)
Definition: GamYields.cpp:507
Simple reader for ASCII tables.
#define LOCAL_INFO
Definition: local_info.hpp:34
void SimYieldTable_DarkSUSY(SimYieldTable &result)
SimYieldTable based on DarkSUSY6 tabulated results.
Definition: GamYields.cpp:640
void SimYieldTable_MicrOmegas(SimYieldTable &result)
SimYieldTable based on MicrOmegas tabulated results.
Definition: GamYields.cpp:773
void addChannel(daFunk::Funk dNdE, std::string p1, std::string p2, std::string finalState, double Ecm_min, double Ecm_max)
void cascadeMC_gammaSpectra(std::map< std::string, daFunk::Funk > &spectra)
Function requesting and returning gamma ray spectra from cascade decays.
Definition: Cascades.cpp:687
Funk var(std::string arg)
Definition: daFunk.hpp:921
bool hasChannel(std::string p1, std::string p2, std::string finalState) const
bool isSelfConj
Does the process contain self-conjugate DM? (accounting for correct factors of 1/2 in annihilation sp...
std::map< str, daFunk::Funk > stringFunkMap
Definition: SimpleHist.hpp:101
double mass
Particle mass (GeV)
Funk func_fromThreadsafe(double(*f)(funcargs...), Args... args)
Definition: daFunk.hpp:773
daFunk::Funk boost_dNdE(daFunk::Funk dNdE, double gamma, double mass)
Boosts an energy spectrum of isotropic particles into another frame (and isotropizes again)...
Definition: GamYields.cpp:154
void GA_AnnYield_General(daFunk::Funk &result)
General routine to derive annihilation yield.
Definition: GamYields.cpp:420
const TH_Channel * find(std::vector< str >) const
Check for given channel. Return a pointer to it if found, NULL if not.
A container holding all annihilation and decay initial states relevant for DarkBit.
std::vector< double > logspace(double x0, double x1, unsigned int n)
Definition: daFunk.hpp:186
Funk func(double(*f)(funcargs...), Args... args)
Definition: daFunk.hpp:768
template double gamma3bdy_limits< 1 >(double, double, double, double)
Header file that includes all GAMBIT headers required for a module source file.
void GA_DecayYield_General(daFunk::Funk &result)
General routine to derive yield from decaying DM.
Definition: GamYields.cpp:473
std::string str
Shorthand for a standard string.
Definition: Analysis.hpp:35
daFunk::Funk getYield(TH_Process process, double Ecm, double mass, TH_ProcessCatalog catalog, SimYieldTable table, double line_width, stringFunkMap cascadeMC_gammaSpectra)
Helper function returning yield from a given DM process.
Definition: GamYields.cpp:182
double gamma3bdy_limits(double Eg, double M_DM, double m1, double m2)
Calculate kinematical limits for three-body final states.
bool isAnnihilation
Annihilation or decay?
Rollcall header for module DarkBit.
warning & DarkBit_warning()
double pow(const double &a)
Outputs a^i.
Channel container Object containing tabularized yields for particle decay and two-body final states...
std::string str_flav_to_mass(std::string flav)
void SimYieldTable_PPPC(SimYieldTable &)
SimYieldTable based on PPPC4DMID Cirelli et al. 2010.
Definition: GamYields.cpp:920
Funk zero(Args... argss)
Definition: daFunk.hpp:604
A container for a single process.
Funk ifelse(Funk f, Funk g, Funk h)
Definition: daFunk.hpp:1373
shared_ptr< FunkBase > Funk
Definition: daFunk.hpp:113
TODO: see if we can use this one:
Definition: Analysis.hpp:33
double E(const double x, const double y)
Utility functions for DarkBit.