file src/SubGeVDM_SelfInteractions.cpp

[No description available] More…

Namespaces

Name
Gambit
TODO: see if we can use this one:
Gambit::DarkBit

Classes

Name
classGambit::DarkBit::subgev_self_interactions
classGambit::DarkBit::bullet_cluster_lnL

Detailed Description

Author: Sowmiya Balan (sowmiya.balan@kit.edu)

Date: 2023 December

Likelihood for angular and velocity-dependent self-scattering cross-section based on evaporation of sub-cluster in Bullet cluster collision.


Authors (add name and date if you modify):


Source code

//   GAMBIT: Global and Modular BSM Inference Tool
//   *********************************************
///  \file
///
///  Likelihood for angular and velocity-dependent self-scattering
///  cross-section based on evaporation of sub-cluster
///  in Bullet cluster collision.
///
///  *********************************************
///
///  Authors (add name and date if you modify):
///
///  \author Sowmiya Balan
///          (sowmiya.balan@kit.edu)
///  \date 2023 December
///
///
///  *********************************************

#include <iostream>
#include <fstream>
#include <cmath>
#include <vector>

#include "gambit/Elements/gambit_module_headers.hpp"
#include "gambit/Utils/util_functions.hpp"
#include "gambit/Utils/ascii_table_reader.hpp"
#include "gambit/DarkBit/DarkBit_rollcall.hpp"
#include "gambit/DarkBit/DarkBit_utils.hpp"


namespace Gambit
{
  namespace DarkBit
  {
    class subgev_self_interactions
    {
      private:

        // Cluster dynamics measurements required for immediate evaporation cross-section calculation
        const double beta_rel = 0.013;
        const double kappa = 0.7627;

        //Cross-sections for SubGeV_fermion model
        double sigma_imd_rep_f(double sigma0, double w)
        {
          double r = pow(w*beta_rel,2);
          double r2 = pow(r,2);
          double factor = 8*M_PI*sigma0;
          double temp1 = (4*(-1+kappa)*r*(2+r));
          double temp2 = ((4+4*r-(-2+kappa)*kappa*r2)*log(2-(-2+kappa)*r));
          double temp3 = ((-2+(-2+kappa)*r)*(2+kappa*r)*log(2+kappa*r));
          double denominator = (r*(2+r)*(-4-4*r+(-2+kappa)*kappa*r2));
          return (factor*(temp1 + temp2 + temp3))/denominator;
        }

        double sigma_imd_att_f(double sigma0, double w, double m_Ap, double gamma_Ap)
        {
          double r = pow(w*beta_rel,2);
          double r2 = pow(r,2);
          double factor = 2*M_PI*sigma0;
          double temp1 = ((2*(-1+kappa)*r)*\
                          (pow(m_Ap,2)*(-16+4*pow(w,2)*(8-3*pow(beta_rel,2))\
                                              +pow(w,4)*(-64+3*(-2+kappa)*kappa*pow(beta_rel,4)))\
                            -(4*pow(gamma_Ap,2))));
          double temp2 = (-4-4*r+(-2+kappa)*kappa*r2);
          double temp3 = ((6*pow(m_Ap,2)*(-1+4*pow(w,2)))*(log((2+(2-kappa)*r)/(2+kappa*r))));
          double denominator = (r*(pow((m_Ap-4*m_Ap*pow(w,2)),2)+pow(gamma_Ap,2)));
          return (factor*(-temp1/temp2 + temp3))/denominator;
        }

        double sigma_tc_rep_f(double sigma0, double w)
        {
          double r = pow(w*beta_rel,2);
          double r2 = pow(r,2);
          double factor = -16*M_PI*sigma0;
          double temp1 = (r*log(2)+log(8));
          double temp2 = (-3*(2+r)*log(2+r));
          double temp3 = ((3+2*r)*log(2+2*r));
          double denominator = (r2*(2+r));
          return (factor*(temp1 + temp2 + temp3))/denominator;
        }

        double sigma_tc_att_f(double sigma0, double w, double m_Ap, double gamma_Ap)
        {
          double r = pow(w*beta_rel,2);
          double r2 = pow(r,2);
          double factor = 2*M_PI*sigma0;
          double temp1 = (3*pow(m_Ap,2)*r2 - 4*(4*pow(m_Ap,2)*(1-5*pow(w,2)+4*pow(w,4))+pow(gamma_Ap,2))*log(2));
          double temp2 = (4*(-pow(m_Ap,2)*(-1+4*pow(w,2))*(8+pow(w,2)*(-8+3*pow(beta_rel,2)))+2*pow(gamma_Ap,2))*log(2+r));
          double temp3 = (4*(pow(m_Ap,2)*(-1+4*pow(w,2))*(4+pow(w,2)*(-4+3*pow(beta_rel,2)))- pow(gamma_Ap,2))*log(2+2*r));
          double denominator = (r2*(pow((m_Ap-4*m_Ap*pow(w,2)),2)+pow(gamma_Ap,2)));
          return (factor*(temp1 + temp2 + temp3))/denominator;
        }

        //Cross-sections for SubGeV_scalar model
        double sigma_imd_rep_s(double sigma0, double w)
        {
          double r = pow(w*beta_rel,2);
          double r2 = pow(r,2);
          double factor = 16*M_PI*sigma0;
          double temp1 = (2*(-1+kappa)*r*(2+r));
          double temp2 = ((-2+(-2+kappa)*r)*(2+kappa*r)*log(2-(-2+kappa)*r));
          double temp3 = ((4+4*r-(-2+kappa)*kappa*r2)*log(2+kappa*r));
          double denominator = (r*(2+r)*(-4-4*r+(-2+kappa)*kappa*r2));
          return (factor*(temp1 + temp2 + temp3))/denominator;
        }

        double sigma_imd_att_s(double sigma0, double w, double m_Ap, double gamma_Ap)
        {
          double r = pow(w*beta_rel,2);
          double r2 = pow(r,2);

          // only t-channel
          double factor = 16*M_PI*sigma0;
          double temp1 = (-1+kappa);
          double denominator = (-4-4*r+(-2+kappa)*kappa*r2);
          return (factor*temp1)/denominator;
        }

        double sigma_tc_rep_s(double sigma0, double w)
        {
          double r = pow(w*beta_rel,2);
          double r2 = pow(r,2);
          double factor = 16*M_PI*sigma0;
          double temp1 = (log(1+r));
          double denominator = (r*(2+r));
          return (factor*temp1)/denominator;
        }

        double sigma_tc_att_s(double sigma0, double w, double m_Ap, double gamma_Ap)
        {
          double r = pow(w*beta_rel,2);
          double r2 = pow(r,2);

          // only t-channel
          double factor = 8*M_PI*sigma0 ;
          double temp1 = (2*log(1+r/2));
          double temp2 = (log(1+r));
          double denominator = r2;
          return (factor*(temp1-temp2))/denominator;
        }

      public:

        double (subgev_self_interactions::*sigma_imd_rep)(double, double);
        double (subgev_self_interactions::*sigma_imd_att)(double, double, double, double);
        double (subgev_self_interactions::*sigma_tc_rep)(double, double);
        double (subgev_self_interactions::*sigma_tc_att)(double, double, double, double);

        // Defining cross-sections corresponding to model in use
        subgev_self_interactions(std::string model)
        {
          logger() << LogTags::debug << "\nInitiating subgev_self_interactions class\n" << EOM;

          if(model=="SubGeVDM_fermion")
          {
            sigma_imd_rep = &subgev_self_interactions::sigma_imd_rep_f;
            sigma_imd_att = &subgev_self_interactions::sigma_imd_att_f;
            sigma_tc_rep  = &subgev_self_interactions::sigma_tc_rep_f;
            sigma_tc_att  = &subgev_self_interactions::sigma_tc_att_f;
          }
          else if(model=="SubGeVDM_scalar")
          {
            sigma_imd_rep = &subgev_self_interactions::sigma_imd_rep_s;
            sigma_imd_att = &subgev_self_interactions::sigma_imd_att_s;
            sigma_tc_rep  = &subgev_self_interactions::sigma_tc_rep_s;
            sigma_tc_att  = &subgev_self_interactions::sigma_tc_att_s;
          }
        }
    };

    class bullet_cluster_lnL
    {
      private:

        // Observed MLR of the Bullet Cluster in I-band (units: M_o/L_o)
        const double mlr_obs_i = 179;
        const double error_obs_i = 11;

        // Fraction of gas within within 250kpc of MC mass peak (10.1086/508601)
        const double fg_mc = 0.09;
        const double error_fg_mc = 0.01;

        // Gas to DM ratio derived from gas fractions
        const double g_i = 0.0989;
        const double error_g_i = 0.0101;
        const double g_f = 0.0417;
        const double error_g_f = 0.01;

      public:

        std::vector<double> mlr_sample;

        // Constructor
        bullet_cluster_lnL(std::string file)
        {
          logger() << LogTags::debug << "\nInitiating bullet_cluster_lnL class\n" << EOM;

          // Loading initial mlr sample over which likelihood is marginalized
          // Check if file exists.
          if (not(Utils::file_exists(file)))
          {
            DarkBit_error().raise(LOCAL_INFO, "ERROR! File '"+file+"' not found!");
          } else {
            logger() << LogTags::debug << "Reading data from file '"+file+"." << EOM;
          }

          // Read numerical values from data file.
          ASCIItableReader tab (file);
          tab.setcolnames("x");
          mlr_sample = tab["x"];
        }

        // Destructor
        ~bullet_cluster_lnL()
        {
        }

        //Gas mass loss
        double mgf_to_mgi(double dm_mass_loss)
        {
          return g_f/g_i * (1-dm_mass_loss);
        }

        //Errors
        double error_gfgi(double dm_mass_loss)
        {
          double x = mgf_to_mgi(dm_mass_loss);
          return sqrt( pow((error_g_f * x/g_f),2) + \
                       pow((error_g_i * x/g_i),2));
        }

        double error_tml(double dm_mass_loss)
        {
          double x = mgf_to_mgi(dm_mass_loss);
          double error_x = error_gfgi(dm_mass_loss);
          return sqrt(pow((error_fg_mc * (1-x-dm_mass_loss)),2) + pow((error_x * fg_mc),2));
        }

        double error_tot(double dm_mass_loss)
        {
          double error_theory = error_tml(dm_mass_loss);
          return sqrt(pow(error_obs_i,2) + pow(error_theory,2));
        }

        // Likelihood evaluator
        double margloglike(double dm_loss)
        {
          // likelihood for "total" mass loss "within 150kpc" (including "imd and cml" evap) marginalized over prior for mlr_ini
          double x = mgf_to_mgi(dm_loss);
          double total_mass_loss = dm_loss*(1-fg_mc) + fg_mc*(1-x);
          double error_total = error_tot(dm_loss);
          double margLike = 0;
          for (int i = 0; i < mlr_sample.size(); i++) {
          margLike += exp(-1/(2*pow((error_total),2))*pow((mlr_obs_i- mlr_sample[i]*(1-total_mass_loss)),2));
          }
          double margLike_c = std::max(1e-30, std::min(margLike, 1e30));

          return log(margLike_c);
        }
    };

    void calc_bullet_cluster_DMmassLoss(double& result)
    {
      using namespace Pipes::calc_bullet_cluster_DMmassLoss;

      double depth = 6.432e-05; // GeV^3

      // Import Spectrum objects
      const Spectrum& spec = *Dep::SubGeVDM_spectrum;
      const SubSpectrum& he = spec.get_HE();

      // Import coupling
      double gDM = he.get(Par::dimensionless,"gDM");
      double alphaDM = pow(gDM,2)/(4*M_PI);

      // Import masses
      double mDM = spec.get(Par::Pole_Mass, "DM");
      double mAp = spec.get(Par::Pole_Mass, "Ap");

      // Define self-scaterring parameters
      double sigma0 = pow(alphaDM*mDM,2)/pow(mAp,4);
      double w = mDM/mAp;

      double fDM = *Dep::RD_fraction;
      ddpair aDM_pair = *Dep::RD_oh2_aDM;
      double fChiBar = (aDM_pair.second*fDM)/2; // (fsym/fDM * fDM)/2
      double fChi = fDM - fChiBar;

      // Import decay table from DecayBit
      const DecayTable* tbl = &(*Dep::decay_rates);
      // Save dark photon width for later
      double gammaAp = tbl->at("Ap").width_in_GeV;

      static std::string model;
      if (ModelInUse("SubGeVDM_scalar")){
        model = "SubGeVDM_scalar";
      }
      else if (ModelInUse("SubGeVDM_fermion")){
        model = "SubGeVDM_fermion";
      }
      else
      {
        DarkBit_error().raise(LOCAL_INFO, "ERROR! Model not compatible with implementation of bullet cluster likelihood.");
      }

      //Initializing class for cross-section evaluations corresponding to model in use
      static subgev_self_interactions subgev_self_interactions_obj(model);

      double sigmaImdRep = (subgev_self_interactions_obj.*(subgev_self_interactions_obj.sigma_imd_rep))(sigma0,w);
      double sigmaImdAtt = (subgev_self_interactions_obj.*(subgev_self_interactions_obj.sigma_imd_att))(sigma0,w,mAp,gammaAp);
      double sigmaTcRep  = (subgev_self_interactions_obj.*(subgev_self_interactions_obj.sigma_tc_rep))(sigma0,w);
      double sigmaTCAtt  = (subgev_self_interactions_obj.*(subgev_self_interactions_obj.sigma_tc_att))(sigma0,w,mAp,gammaAp);

      double sigmaRep = sigmaImdRep+sigmaTcRep;
      double sigmaAtt = sigmaImdAtt+sigmaTCAtt;
      double sigma_eff_chi = fChi*sigmaRep + fChiBar*sigmaAtt;
      double sigma_eff_chibar = fChiBar*sigmaRep + fChi*sigmaAtt;

      double dm_loss = fChi*(1-exp(-depth*sigma_eff_chi/mDM)) +\
                fChiBar*(1-exp(-depth*sigma_eff_chibar/mDM));

      result = dm_loss;
    }

    void calc_bullet_cluster_lnL(double& result)
    {
      using namespace Pipes::calc_bullet_cluster_lnL;
      double DMmassLoss = *Dep::DM_mass_loss;

      static std::string inital_mlr_prior = runOptions->getValueOrDef<std::string>("lognormal_mlr","initial_mlr_prior");

      static std::string lnL_file_path;

      if (inital_mlr_prior == "lognormal_mlr")
      {
        lnL_file_path = GAMBIT_DIR "/DarkBit/data/BulletCluster/mlr_sample_pessimistic.dat";
      }
      else if (inital_mlr_prior == "main_cluster_mlr")
      {
        lnL_file_path = GAMBIT_DIR "/DarkBit/data/BulletCluster/mlr_sample_optimistic.dat";
      }
      else
      {
        DarkBit_error().raise(LOCAL_INFO, "ERROR! Prior for initial MLR marginalisation can only be over the observed \
        I-band MLR distribution ('mlr_distribution') or over a Gaussian defined by observed main cluster MLR \
        ('main_cluster_mlr').");
      }

      static bullet_cluster_lnL bullet_cluster_lnL_obj(lnL_file_path);

      result = bullet_cluster_lnL_obj.margloglike(DMmassLoss);
    }
  }
}

Updated on 2024-07-18 at 13:53:34 +0000