file frontends/CalcHEP_3_6_27.cpp
[No description available] More…
Functions
Name | |
---|---|
if(scan_level ) | |
if(ModelInUse(“ScalarSingletDM_Z2”) ) | |
if(ModelInUse(“DMEFT”) ) | |
if(ModelInUse(“DMsimpVectorMedDiracDM”) ) | |
if(ModelInUse(“DMsimpVectorMedMajoranaDM”) ) | |
if(ModelInUse(“DMsimpVectorMedScalarDM”) ) | |
if(ModelInUse(“DMsimpVectorMedVectorDM”) ) |
Attributes
Name | |
---|---|
BE_INI_FUNCTION | |
scan_level |
Detailed Description
Author: Sanjay Bloor (sanjay.bloor12@imperial.ac.uk)
Date: 2017 May, Oct 2018 Sep
Frontend for CalcHEP Backend
Authors (add name and date if you modify):
Functions Documentation
function if
if(
scan_level
)
function if
if(
ModelInUse("ScalarSingletDM_Z2")
)
function if
if(
ModelInUse("DMEFT")
)
function if
if(
ModelInUse("DMsimpVectorMedDiracDM")
)
function if
if(
ModelInUse("DMsimpVectorMedMajoranaDM")
)
function if
if(
ModelInUse("DMsimpVectorMedScalarDM")
)
function if
if(
ModelInUse("DMsimpVectorMedVectorDM")
)
Attributes Documentation
variable BE_INI_FUNCTION
BE_INI_FUNCTION {
static bool scan_level = true;
variable scan_level
scan_level = false;
Source code
// GAMBIT: Global and Modular BSM Inference Tool
// *********************************************
/// \file
///
/// Frontend for CalcHEP Backend
///
/// *********************************************
///
/// Authors (add name and date if you modify):
///
/// \author Sanjay Bloor
/// (sanjay.bloor12@imperial.ac.uk)
/// \date 2017 May, Oct
/// 2018 Sep
///
/// *****************************************
#include <fstream>
#include <boost/algorithm/string/replace.hpp>
#include "gambit/Backends/frontend_macros.hpp"
#include "gambit/Models/partmap.hpp"
#include "gambit/Backends/frontends/CalcHEP_3_6_27.hpp"
#include "gambit/Models/SpectrumContents/RegisteredSpectra.hpp"
#include "gambit/Elements/decay_table.hpp"
#include "gambit/Utils/file_lock.hpp"
#include <unistd.h>
BE_INI_FUNCTION
{
// Scan-level.
static bool scan_level = true;
if (scan_level)
{
// Declare backend path variables
str BEpath;
const char *path;
char *modeltoset;
std::string model;
// All decays and xsecs added to a new model
std::map< str, std::vector< std::vector<str> > > decays;
std::map< std::vector<str>, std::vector< std::vector<str> > > xsecs;
if (ModelInUse("ScalarSingletDM_Z2"))
{
// Set model within CalcHEP
BEpath = backendDir + "/../models/ScalarSingletDM_Z2";
path = BEpath.c_str();
modeltoset = (char*)malloc(strlen(path)+11);
sprintf(modeltoset, "%s", path);
decays["h"] = std::vector< std::vector<str> >{ {"~S","~S"} };
xsecs[std::vector<str>{"~S","~S"}] = std::vector< std::vector<str> >{ {"d'", "D'"}, {"u", "U"}, {"B", "b"}, {"h", "h"}, {"e", "E"}, {"Z", "Z"}, {"c", "C"}, {"s'", "S'"}, {"m", "M"}, {"t", "T"}, {"W+", "W-"}, {"ta+", "ta-"} };
model = "ScalarSingletDM_Z2";
}
if (ModelInUse("DMEFT"))
{
BEpath = backendDir + "/../models/DMEFT";
path = BEpath.c_str();
modeltoset = (char*)malloc(strlen(path)+11);
sprintf(modeltoset, "%s", path);
}
if (ModelInUse("DMsimpVectorMedDiracDM"))
{
BEpath = backendDir + "/../models/DMsimpVectorMedDiracDM";
path = BEpath.c_str();
modeltoset = (char*)malloc(strlen(path)+11);
sprintf(modeltoset, "%s", path);
decays["Y1"] = std::vector< std::vector<str> >{ {"b~","b"}, {"c~","c"}, {"d~","d"}, {"s~","s"}, {"t~","t"}, {"u~","u"}, {"Xd~","Xd"} };
xsecs[std::vector<str>{"Xd", "Xd~"}] = std::vector< std::vector<str> >{ {"c~","c"}, {"d~","d"}, {"s~","s"}, {"t~","t"}, {"b~","b"}, {"u~","u"}, {"Y1","Y1"} };
model = "DMsimpVectorMedDiracDM";
}
if (ModelInUse("DMsimpVectorMedMajoranaDM"))
{
BEpath = backendDir + "/../models/DMsimpVectorMedMajoranaDM";
path = BEpath.c_str();
modeltoset = (char*)malloc(strlen(path)+11);
sprintf(modeltoset, "%s", path);
decays["Y1"] = std::vector< std::vector<str> >{ {"b~","b"}, {"c~","c"}, {"d~","d"}, {"s~","s"}, {"t~","t"}, {"u~","u"}, {"Xm","Xm"} };
xsecs[std::vector<str>{"Xm", "Xm"}] = std::vector< std::vector<str> >{ {"c~","c"}, {"d~","d"}, {"s~","s"}, {"t~","t"}, {"b~","b"}, {"u~","u"}, {"Y1","Y1"} };
model = "DMsimpVectorMedMajoranaDM";
}
if (ModelInUse("DMsimpVectorMedScalarDM"))
{
BEpath = backendDir + "/../models/DMsimpVectorMedScalarDM";
path = BEpath.c_str();
modeltoset = (char*)malloc(strlen(path)+11);
sprintf(modeltoset, "%s", path);
decays["Y1"] = std::vector< std::vector<str> >{ {"Xc","Xc~"}, {"b~","b"}, {"c~","c"}, {"d~","d"}, {"s~","s"}, {"t~","t"}, {"u~","u"} };
xsecs[std::vector<str>{"Xc", "Xc~"}] = std::vector< std::vector<str> >{ {"c~","c"}, {"d~","d"}, {"s~","s"}, {"t~","t"}, {"b~","b"}, {"u~","u"}, {"Y1","Y1"} };
model = "DMsimpVectorMedScalarDM";
}
if (ModelInUse("DMsimpVectorMedVectorDM"))
{
BEpath = backendDir + "/../models/DMsimpVectorMedVectorDM";
path = BEpath.c_str();
modeltoset = (char*)malloc(strlen(path)+11);
sprintf(modeltoset, "%s", path);
decays["Y1"] = std::vector< std::vector<str> >{ {"d~","d"}, {"s~","s"}, {"b~","b"}, {"u~","u"}, {"c~","c"}, {"t~","t"}, {"~Xv","~Xva"} };
xsecs[std::vector<str>{"~Xv", "~Xva"}] = std::vector< std::vector<str> >{ {"c~","c"}, {"d~","d"}, {"s~","s"}, {"t~","t"}, {"b~","b"}, {"u~","u"}, {"Y1","Y1"} };
model = "DMsimpVectorMedVectorDM";
}
else
{
int error = setModel(modeltoset, 1);
if (error != 0) backend_error().raise(LOCAL_INFO, "Unable to set model" + std::string(modeltoset) +
" in CalcHEP. CalcHEP error code: " + std::to_string(error) + ". Please check your model files.\n");
}
// Create a process lock to allow only one process in
{
Utils::ProcessLock mylock("CH_decays");
mylock.get_lock();
// Only first process to get here creates the libraries
if (not mylock.exhausted())
{
// Decays first
for (auto d : decays)
for (auto fs : d.second)
generate_decay_code(model, d.first, fs);
// And two to twos
for (auto x : xsecs)
for (auto fs : x.second)
generate_xsec_code(model, x.first, fs);
}
// Release the lock, which will exhaust it first
mylock.release_lock();
}
free(modeltoset);
}
// Point-level.
scan_level = false;
if (ModelInUse("ScalarSingletDM_Z2"))
{
// Obtain model contents
static const SpectrumContents::ScalarSingletDM_Z2 ScalarSingletDM_Z2_contents;
// Obtain list of all parameters within model
static const std::vector<SpectrumParameter> ScalarSingletDM_Z2_params = ScalarSingletDM_Z2_contents.all_parameters();
// Obtain spectrum information to pass to CalcHEP
const Spectrum& spec = *Dep::ScalarSingletDM_Z2_spectrum;
Assign_All_Values(spec, ScalarSingletDM_Z2_params);
}
if (ModelInUse("DMEFT"))
{
// Obtain model contents
static const SpectrumContents::DMEFT DMEFT_contents;
// Obtain list of all parameters within model
static const std::vector<SpectrumParameter> DMEFT_params = DMEFT_contents.all_parameters();
// Obtain spectrum information to pass to CalcHEP
const Spectrum& spec = *Dep::DMEFT_spectrum;
Assign_All_Values(spec, DMEFT_params);
}
if (ModelInUse("DMsimpVectorMedDiracDM"))
{
// Obtain spectrum information to pass to CalcHEP
const Spectrum& spec = *Dep::DMsimpVectorMedDiracDM_spectrum;
// Obtain model contents
static const SpectrumContents::DMsimpVectorMedDiracDM DMsimpVectorMedDiracDM_contents;
// Obtain list of all parameters within model
static const std::vector<SpectrumParameter> DMsimpVectorMedDiracDM_params = DMsimpVectorMedDiracDM_contents.all_parameters();
Assign_All_Values(spec, DMsimpVectorMedDiracDM_params);
}
if (ModelInUse("DMsimpVectorMedMajoranaDM"))
{
// Obtain spectrum information to pass to CalcHEP
const Spectrum& spec = *Dep::DMsimpVectorMedMajoranaDM_spectrum;
// Obtain model contents
static const SpectrumContents::DMsimpVectorMedMajoranaDM DMsimpVectorMedMajoranaDM_contents;
// Obtain list of all parameters within model
static const std::vector<SpectrumParameter> DMsimpVectorMedMajoranaDM_params = DMsimpVectorMedMajoranaDM_contents.all_parameters();
Assign_All_Values(spec, DMsimpVectorMedMajoranaDM_params);
}
if (ModelInUse("DMsimpVectorMedScalarDM"))
{
// Obtain spectrum information to pass to CalcHEP
const Spectrum& spec = *Dep::DMsimpVectorMedScalarDM_spectrum;
// Obtain model contents
static const SpectrumContents::DMsimpVectorMedScalarDM DMsimpVectorMedScalarDM_contents;
// Obtain list of all parameters within model
static const std::vector<SpectrumParameter> DMsimpVectorMedScalarDM_params = DMsimpVectorMedScalarDM_contents.all_parameters();
Assign_All_Values(spec, DMsimpVectorMedScalarDM_params);
}
if (ModelInUse("DMsimpVectorMedVectorDM"))
{
// Obtain spectrum information to pass to CalcHEP
const Spectrum& spec = *Dep::DMsimpVectorMedVectorDM_spectrum;
// Obtain model contents
static const SpectrumContents::DMsimpVectorMedVectorDM DMsimpVectorMedVectorDM_contents;
// Obtain list of all parameters within model
static const std::vector<SpectrumParameter> DMsimpVectorMedVectorDM_params = DMsimpVectorMedVectorDM_contents.all_parameters();
Assign_All_Values(spec, DMsimpVectorMedVectorDM_params);
}
}
END_BE_INI_FUNCTION
BE_NAMESPACE
{
/// Create matrix element code for a decay
numout* generate_decay_code(str model, str in, std::vector<str> out)
{
// Generate process from in and out states
char *process = new char[(in + " -> " + out[0] + "," + out[1]).length() + 1];
strcpy(process, (in + " -> " + out[0] + "," + out[1]).c_str());
std::string incpy = in;
std::string out0cpy = out[0];
std::string out1cpy = out[1];
// Replace any instance of a tilde with "bar"
boost::replace_all(incpy, "~", "bar");
boost::replace_all(out0cpy, "~", "bar");
boost::replace_all(out1cpy, "~", "bar");
// Remove all non-alpha numeric characters from the library names
incpy.resize(std::remove_if(incpy.begin(), incpy.end(), [](char x) {return !isalnum(x) && !isspace(x);})-incpy.begin());
out0cpy.resize(std::remove_if(out0cpy.begin(), out0cpy.end(), [](char x) {return !isalnum(x) && !isspace(x);})-out0cpy.begin());
out1cpy.resize(std::remove_if(out1cpy.begin(), out1cpy.end(), [](char x) {return !isalnum(x) && !isspace(x);})-out1cpy.begin());
// Generate libname from model and process name
char *libname = new char[(model + "_" + incpy + "_to_" + out0cpy + out1cpy).length() + 1];
strcpy(libname, (model + "_" + incpy + "_to_" + out0cpy + out1cpy).c_str());
char *excludeVirtual = NULL; // Exclude any internal particles
char *excludeOut = NULL; // Exclude any products
int twidth = 0; // T-channel propagator width
int UG = 0; // Unitary gauge
// Generates shared object file based on libName - unless it already exists.
numout* cc = getMEcode(twidth, UG, process, excludeVirtual, excludeOut, libname);
// Release all memory allocated by "new" before returning
delete[] process;
delete[] libname;
return cc;
}
/// For cross-sections, just wrap the decay code
numout* generate_xsec_code(str model, std::vector<str> in, std::vector<str> out)
{
str newin = in[0] + "," + in[1];
return generate_decay_code(model, newin, out);
}
/// Assigns gambit value to parameter, with error-checking.
void Assign_Value(char *parameter, double value)
{
int error;
error = assignVal(parameter, value);
if (error != 0) backend_error().raise(LOCAL_INFO, "Unable to set " + std::string(parameter) +
" in CalcHEP. CalcHEP error code: " + std::to_string(error) + ". Please check your model files.\n");
}
/// Assigns gambit value to parameter, with error-checking, for parameters that may
/// have two different names in CalcHEP, such as alphainv : aEWM1 (FeynRules) / aEWinv (SARAH)
void Assign_Value(char *parameter1, char *parameter2, double value)
{
int error;
error = assignVal(parameter1, value);
// If name 1 is successful, awesome.
if (error == 0) return;
// If not, then try the second one
error = assignVal(parameter2, value);
// If that doesn't work, we can throw an error, eh.
if (error != 0) backend_error().raise(LOCAL_INFO, "Unable to set " + std::string(parameter1) +
" or " + std::string(parameter2) + " in CalcHEP. " +
" CalcHEP error code: " + std::to_string(error) + ". Please check your model files.\n");
}
/// Takes all parameters in a model, and assigns them by
/// value to the appropriate CalcHEP parameter names.
void Assign_All_Values(const Spectrum& spec, std::vector<SpectrumParameter> params)
{
// Iterate through the expected spectrum parameters of the model. Pass the value of pole masses
// to CalcHEP from the spectrum, by PDG code.
for (auto it = params.begin(); it != params.end(); ++it)
{
// Don't add the SM vev, Gauge couplings, Yukawas,
// as CalcHEP computes these internally.
std::list<std::string> doNotAssign = {"g1", "g2", "g3", "v", "Yu", "Ye", "Yd", "sinW2", "vev"};
// Fetch the iterator of element with the parameter name
std::list<std::string>::iterator it2 = std::find(doNotAssign.begin(), doNotAssign.end(), it->name());
// If we find the parameter in the "do not assign" list, then don't try and assign it,
// or this will throw an error.
if (it2 != doNotAssign.end())
{
continue;
}
// Pole masses
if (it->tag() == Par::Pole_Mass)
{
// Scalar case
if (it->shape()[0] == 1)
{
std::pair<int,int> PDG_code = Models::ParticleDB().partmap::pdg_pair(it->name());
Assign_Value(pdg2mass(PDG_code.first), spec.get(Par::Pole_Mass, PDG_code.first, PDG_code.second));
}
// Vector case
else
{
for (int i=0; i<it->shape()[0]; ++i)
{
str long_name = it->name() + "_" + std::to_string(i+1);
std::pair<int,int> PDG_code = Models::ParticleDB().partmap::pdg_pair(long_name);
Assign_Value(pdg2mass(PDG_code.first), spec.get(Par::Pole_Mass, PDG_code.first, PDG_code.second));
}
}
// Ignore any matrix cases, as Par::Pole_Mass should only be scalars or vectors
}
// Otherwise, should all have the right names
else
{
const SubSpectrum& HE = spec.get_HE();
// Scalar case
if (it->shape().size()==1 and it->shape()[0] == 1)
{
str name = it->name();
char *chepname = const_cast<char*> ( name.c_str() );
Assign_Value(chepname, HE.get(it->tag(), it->name()));
}
// Vector case
else if (it->shape().size()==1 and it->shape()[0] > 1)
{
for (int i=0; i<it->shape()[0]; ++i)
{
str long_name = it->name() + std::to_string(i+1);
char *chepname = const_cast<char*> ( long_name.c_str() );
Assign_Value(chepname, HE.get(it->tag(), it->name(), i+1));
}
}
// Matrix
else if(it->shape().size()==2)
{
for (int i=0; i<it->shape()[0]; ++i)
{
for (int j=0; j<it->shape()[0]; ++j)
{
str long_name = it->name() + std::to_string(i+1) + "x" + std::to_string(j+1);
char *chepname = const_cast<char*> ( long_name.c_str() );
Assign_Value(chepname, HE.get(it->tag(), it->name(), i+1, j+1));
}
}
}
}
}
// Now go through the input parameters of the model. **NOTE**: this structure will only work for the case
// where we want to scan over fundamental Lagrangian parameters. This will change post-SpecBit redesign.
// Create SMInputs struct from spectrum
const SMInputs& sminputs = spec.get_SMInputs();
// Assign SMInputs
Assign_Value((char*)"Gf", (char*)"GF", sminputs.GF); // Fermi
Assign_Value((char*)"aS", sminputs.alphaS); // Strong coupling (unspecified scale if SARAH)
Assign_Value((char*)"alfSMZ", (char*)"aS", sminputs.alphaS); // Strong coupling (mZ) for both.
Assign_Value((char*)"aEWM1", (char*)"aEWinv", sminputs.alphainv); // Inverse EM coupling
// Then, SM particle masses (by PDG code)
Assign_Value(pdg2mass(1), sminputs.mD); // Down
Assign_Value(pdg2mass(2), sminputs.mU); // Up
Assign_Value(pdg2mass(3), sminputs.mS); // Strange
Assign_Value(pdg2mass(4), sminputs.mCmC); // Charm (mC) MSbar
Assign_Value(pdg2mass(11), spec.get(Par::Pole_Mass, "e-")); // Electron
Assign_Value(pdg2mass(13), spec.get(Par::Pole_Mass, "mu-")); // Muon
Assign_Value(pdg2mass(15), spec.get(Par::Pole_Mass, "tau-")); // Tau
Assign_Value(pdg2mass(23), spec.get(Par::Pole_Mass, "Z0")); // Z
Assign_Value(pdg2mass(5), spec.get(Par::Pole_Mass, "d_3")); // mB(mB) MSbar
Assign_Value(pdg2mass(6), spec.get(Par::Pole_Mass, "u_3")); // mT(mT) MSbar
}
/// Passes the width of each BSM particle in the model, from DecayTable to CalcHEP.
/// Don't set the widths of anything SM, except the top, which can get BSM contributions.
void Assign_Widths(const DecayTable& tbl)
{
// Obtain all generic pdg codes. We can't set these widths..
const std::vector<std::pair<int, int>> generic_particles = Models::ParticleDB().partmap::get_generic_particles();
const std::vector<std::pair<int, int>> SM_particles = Models::ParticleDB().partmap::get_SM_particles();
// Iterate through DecayTable. If it is not in the generic particles, or the SM, then go for it.
for (std::map<std::pair<int, int>, Gambit::DecayTable::Entry>::const_iterator it = tbl.particles.begin();
it != tbl.particles.end(); ++it)
{
if (std::find(generic_particles.begin(), generic_particles.end(), it->first) != generic_particles.end())
{
continue;
}
if (std::find(SM_particles.begin(), SM_particles.end(), it->first) != SM_particles.end())
{
continue;
}
Assign_Value(pdg2width(it->first.first), tbl.at(it->first).width_in_GeV);
}
// Assign the top separately as they can have BSM contributions e.g. decaying to charged higgses
Assign_Value(pdg2width(6), tbl.at("t").width_in_GeV);
}
/// Provides spin-averaged decay width for 2 body decay process in CM frame at tree-level.
// TODO: remove dependence on g3 (for alphaS(mZ)).
double CH_Decay_Width(str& model, str& in, std::vector<str>& out)
{
// Check size of in and out states;
if (out.size() != 2) backend_error().raise(LOCAL_INFO, "Output vector"
" must have only 2 entries for a 1 to 2 process.");
// Calculates and updates all PUBLIC (model-dependent) parameters. These come from $CALCHEP/aux/VandP.c, generated by setModel() in the INI_FUNCTION.
int err = calcMainFunc();
if(err != 0) backend_error().raise(LOCAL_INFO, "Unable to calculate parameter " + std::string(varNames[err]) +
" in CalcHEP. Please check your model files.\n");
// Check if channel is kinematically open before doing anything. No need to compile processes that are not relevant.
char *inbound = new char[(in).length() + 1];
strcpy(inbound, (in).c_str());
char *outbound_1 = new char[(out[0]).length() + 1];
strcpy(outbound_1, (out[0]).c_str());
char *outbound_2 = new char[(out[1]).length() + 1];
strcpy(outbound_2, (out[1]).c_str());
// Obtain mass of decaying particle
double M = pMass(inbound);
double m1 = pMass(outbound_1);
double m2 = pMass(outbound_2);
// If channel is kinematically closed, return 0.
if (m1 + m2 > M) { return 0; }
// Generate process from in and out states
char *process = new char[(in + " -> " + out[0] + "," + out[1]).length() + 1];
strcpy(process, (in + " -> " + out[0] + "," + out[1]).c_str());
std::string incpy = in;
std::string out0cpy = out[0];
std::string out1cpy = out[1];
// Replace any instance of a tilde with "bar"
boost::replace_all(incpy, "~", "bar");
boost::replace_all(out0cpy, "~", "bar");
boost::replace_all(out1cpy, "~", "bar");
// Remove all non-alpha numeric characters from the library names
incpy.resize(std::remove_if(incpy.begin(), incpy.end(), [](char x) {return !isalnum(x) && !isspace(x);})-incpy.begin());
out0cpy.resize(std::remove_if(out0cpy.begin(), out0cpy.end(), [](char x) {return !isalnum(x) && !isspace(x);})-out0cpy.begin());
out1cpy.resize(std::remove_if(out1cpy.begin(), out1cpy.end(), [](char x) {return !isalnum(x) && !isspace(x);})-out1cpy.begin());
// Generate libname from model and process name
char *libname = new char[(model + "_" + incpy + "_to_" + out0cpy + out1cpy).length() + 1];
strcpy(libname, (model + "_" + incpy + "_to_" + out0cpy + out1cpy).c_str());
char *excludeVirtual = NULL; // Exclude any internal particles
char *excludeOut = NULL; // Exclude any products
int twidth = 0; // T-channel propagator width
int UG = 0; // Unitary gauge
// Generates shared object file based on libName - unless it already exists.
numout* cc = getMEcode(twidth, UG, process, excludeVirtual, excludeOut, libname);
// Export numerical values of parameters to link to dynamical code
err=passParameters(cc);
if(err != 0) backend_error().raise(LOCAL_INFO, "Unable to calculate parameter " + std::string(varNames[err]) +
" in CalcHEP. Please check your model files.\n");
// Kinematic factors.
double m_plus = m1+m2;
double m_minus = m1-m2;
double Msquared = M*M;
double p = sqrt((Msquared - m_plus*m_plus)*(Msquared - m_minus*m_minus))/(2*M); // Magnitude of momentum in CM frame
double E_1 = (Msquared + m1*m1 - m2*m2)/(2*M); // Energy of first particle
// Momentum vector for decay. This is 3 4-vectors, for the decaying particle and the products, respectively. 1 <--- M ---> 2
double pvect[12] = {M, 0, 0, 0, E_1, 0, 0, p, (M-E_1), 0, 0, -p};
// Compute squared matrix element
double matElement = cc -> interface -> sqme(1, 0, pvect, NULL, &err);
if(err != 0) backend_error().raise(LOCAL_INFO, "Unable to calculate matrix element associated with " + std::string(process) +
" in CalcHEP. Please check your model files.\n");
// Compute kinematic prefactor for X -> Y, Z decay
double prefactor = p/(8*pi*Msquared);
// Release all memory allocated by "new" before returning
delete[] libname;
delete[] inbound;
delete[] outbound_1;
delete[] outbound_2;
// Return partial width
return prefactor*matElement;
}
/// Computes annihilation cross-section for 2->2 process, DM+DMbar -> X + Y at tree level.
/// Coannihilations not currently supported; we require the mass of both in states are equal.
double CH_Sigma_V(str& model, std::vector<str>& in, std::vector<str>& out, double& v_rel, const DecayTable& decays)
{
// Check size of in and out states;
if (in.size() != 2 or out.size() != 2) backend_error().raise(LOCAL_INFO, "Input and output vectors"
" must have only 2 entries for a 2 to 2 process.");
// Calculates and updates all PUBLIC (model-dependent) parameters. These come from $CALCHEP/aux/VandP.c, generated by setModel() in the INI_FUNCTION.
int err = calcMainFunc();
if(err != 0) backend_error().raise(LOCAL_INFO, "Unable to calculate parameter " + std::string(varNames[err]) +
" in CalcHEP. Please check your model files.\n");
// Check if channel is kinematically open before doing anything. No need to compile processes that are not relevant.
char *inbound_1 = new char[(in[0]).length() + 1];
strcpy(inbound_1, (in[0]).c_str());
char *inbound_2 = new char[(in[1]).length() + 1];
strcpy(inbound_2, (in[1]).c_str());
char *outbound_1 = new char[(out[0]).length() + 1];
strcpy(outbound_1, (out[0]).c_str());
char *outbound_2 = new char[(out[1]).length() + 1];
strcpy(outbound_2, (out[1]).c_str());
// Obtain mass of in & out states
double m_DM = pMass(inbound_1);
if (pMass(inbound_2) != m_DM) backend_error().raise(LOCAL_INFO, "Mass for both in states must be identical for CH_Sigma_V. "
"Coannihilations not currently supported.");
double m3 = pMass(outbound_1);
double m4 = pMass(outbound_2);
// Kinematics (in states)
double s = 16*m_DM*m_DM/(4-v_rel*v_rel);
double E_cm = sqrt(s);
double E_1 = E_cm/2;
double E_2 = E_1;
double p_in = m_DM*v_rel/(sqrt(4-v_rel*v_rel));
// Not enough energy for the process. Closed.
if (m3+m4 > E_cm) { return 0; }
// Pass particle widths - for propagators.
Assign_Widths(decays);
// Generate process from in and out states
char *process = new char[(in[0]+ "," + in[1] + " -> " + out[0] + "," + out[1]).length() + 1];
strcpy(process, (in[0] + "," + in[1] + " -> " + out[0] + "," + out[1]).c_str());
str DM = in[0]; // Create copy of the string, as we are about to manipulate.
str DMbar = in[1];
// Remove all non-alpha numeric characters from the library names
DM.resize(std::remove_if(DM.begin(), DM.end(), [](char x) {return !isalnum(x) && !isspace(x);})-DM.begin());
DMbar.resize(std::remove_if(DMbar.begin(), DMbar.end(), [](char x) {return !isalnum(x) && !isspace(x);})-DMbar.begin());
out[0].resize(std::remove_if(out[0].begin(), out[0].end(), [](char x) {return !isalnum(x) && !isspace(x);})-out[0].begin());
out[1].resize(std::remove_if(out[1].begin(), out[1].end(), [](char x) {return !isalnum(x) && !isspace(x);})-out[1].begin());
// Generate libname from model and process name
char *libname = new char[(model + "_" + DM + DMbar + "_to_" + out[0] + out[1]).length() + 1];
strcpy(libname, (model + "_" + DM + DMbar + "_to_" + out[0] + out[1]).c_str());
/// TODO: are these options for the function..?
char *excludeVirtual = NULL; // Exclude any internal particles
char *excludeOut = NULL; // Exclude any products
int twidth = 0; // T-channel propagator width
int UG = 0; // Unitary gauge
// Generates shared object file based on libName - unless it already exists.
numout* cc = getMEcode(twidth, UG, process, excludeVirtual, excludeOut, libname);
// Release all memory allocated by "new" before returning
delete[] libname;
delete[] inbound_1;
delete[] inbound_2;
delete[] outbound_1;
delete[] outbound_2;
// Export numerical values of parameters to link to dynamical code
err=passParameters(cc);
if(err != 0) backend_error().raise(LOCAL_INFO, "Unable to calculate parameter " + std::string(varNames[err]) +
" in CalcHEP. Please check your model files.\n");
// Kinematic factors (out states)
double E_3 = (s - (m4*m4) + (m3*m3))/(2*E_cm);
double E_4 = E_cm - E_3;
double m_out_plus = m3+m4;
double m_out_minus = m3-m4;
double p_out = sqrt((s - m_out_plus*m_out_plus)*(s - m_out_minus*m_out_minus))/(2*E_cm); // Magnitude of outbound momentum in CM frame
// Momentum vector for 2->2. This is 4 4-vectors, for particles 1->4 respectively.
double pvect[16] = {E_1, 0, 0, p_in, E_2, 0, 0, -p_in, E_3, 0, 0, p_out, E_4, 0, 0, -p_out};
// Kinematic prefactor
double prefactor = p_out/(32*pi*m_DM*s/sqrt(4-v_rel*v_rel));
// Squared matrix element - f(p(theta)) - to be integrated over.
double M_squared = 0.0;
int numsteps = 200;
// Integrate between -1 < cos(theta) < 1
for (int i=0; i < numsteps; i++)
{
double dcos = 2. / numsteps;
double cosT = -1 + dcos*i;
double sinT = sqrt(1-cosT*cosT);
pvect[9] = p_out*sinT;
pvect[11] = p_out*cosT;
pvect[13] = -pvect[9];
pvect[15] = -pvect[11];
M_squared += dcos*(cc -> interface -> sqme(1, 0, pvect, NULL, &err)); // dcos * dM_squared/dcos
}
// If we get a negative ME (or a NaN), and the relative velocity is zero, then try
// putting in an arbitrarily small value for the velocity.
if ((M_squared < 0 or std::isnan(M_squared)) and v_rel == 0.)
{
// Choose velocity to be non-zero (but effectively zero) to avoid
// potential unphysical values for p-wave suppressed xsecs.
double newvel = 1e-6;
logger() << "Square matrix element returned a negative value, but velocity is zero." << std::endl;
logger() << "Trying with v = 1e-6 for final states " << out[0] << " " << out[1] << std::endl;
// Compute new values for the kinematics
s = 16*m_DM*m_DM/(4-newvel*newvel);
E_cm = sqrt(s);
E_1 = E_cm/2;
E_2 = E_1;
p_in = m_DM*newvel/(sqrt(4-newvel*newvel));
E_3 = (s - (m4*m4) + (m3*m3))/(2*E_cm);
E_4 = E_cm - E_3;
p_out = sqrt((s - m_out_plus*m_out_plus)*(s - m_out_minus*m_out_minus))/(2*E_cm);
pvect[0] = E_1;
pvect[3] = p_in;
pvect[4] = E_2;
pvect[7] = -p_in;
pvect[8] = E_3;
pvect[9] = p_out;
pvect[12] = E_4;
pvect[15] = -p_out;
prefactor = p_out/(32*pi*m_DM*s/sqrt(4-newvel*newvel));
M_squared = 0.0;
// Integrate again.
for (int i=0; i < numsteps; i++)
{
double dcos = 2. / numsteps;
double cosT = -1 + dcos*i;
double sinT = sqrt(1-cosT*cosT);
pvect[9] = p_out*sinT;
pvect[11] = p_out*cosT;
pvect[13] = -pvect[9];
pvect[15] = -pvect[11];
M_squared += dcos*(cc -> interface -> sqme(1, 0, pvect, NULL, &err)); // dcos * dM_squared/dcos
}
}
// If it's a NaN, throw an error
else if (std::isnan(M_squared))
{
std::ostringstream err;
err << "ERROR: CalcHEP returned a NaN matrix element for the process "
<< in[0] << " " << in[1] << " to "
<< out[0] << " " << out[1] << " for relative velocity " << v_rel << ".";
backend_error().raise(LOCAL_INFO, err.str());
}
// If it's negative, just return 0. We'll conservatively assume it's just numerical noise.
else if (M_squared < 0)
{
logger() << "Squared matrix element has returned a negative value from CalcHEP." << std::endl;
logger() << "Final states are " << out[0] << " " << out[1] << " for relative velocity " << v_rel << std::endl;
logger() << "Returning 0 instead, assuming it's numerical noise from the crude integration." << EOM;
return 0.;
}
// Total sigma_v
return prefactor*M_squared;
}
}
END_BE_NAMESPACE
Updated on 2024-07-18 at 13:53:35 +0000