Source code for bsmart.tools.MicrOmegas
"""
Tool to run MicrOMEGAs
"""
__meta__ = {
"name": "MicrOmegas",
"requires": [],
"settings": {
"Command": "Path to MicrOmegas executable",
"LSP": "List of allowed LSP PIDs",
"DD_Limits": "Boolean",
"Cross-sections": "Boolean",
"OutputFile": "Path to output file",
"InputFile": "Path to input SLHA file"
}
}
import os
import shutil
#import subprocess
from bsmart import debug
from bsmart.HEPRun import HepTool, DataPoint
from bsmart.dmlimits import DMlimits
from bsmart import zslha
# def noshell_command_log_withpid(command, wdir, log):
# log.debug('Terminal command: %s' % command)
# command_line = subprocess.Popen(command, shell=False, cwd=wdir,
# stdout=subprocess.PIPE,
# stderr=subprocess.PIPE)
# pid=command_line.pid
# out, err = command_line.communicate()
# # log.debug(out)
# if err != b'':
# log.error(err.decode("utf-8"))
# return str(pid)
references=r'''@article{Alguero:2023zol,
author = "Alguero, G. and Belanger, G. and Boudjema, F. and Chakraborti, S. and Goudelis, A. and Kraml, S. and Mjallal, A. and Pukhov, A.",
title = "{micrOMEGAs 6.0: N-component dark matter}",
eprint = "2312.14894",
archivePrefix = "arXiv",
primaryClass = "hep-ph",
doi = "10.1016/j.cpc.2024.109133",
journal = "Comput. Phys. Commun.",
volume = "299",
pages = "109133",
year = "2024"
}
@article{Alguero:2022inz,
author = "Alguero, Gael and Belanger, Genevieve and Kraml, Sabine and Pukhov, Alexander",
title = "{Co-scattering in micrOMEGAs: A case study for the singlet-triplet dark matter model}",
eprint = "2207.10536",
archivePrefix = "arXiv",
primaryClass = "hep-ph",
doi = "10.21468/SciPostPhys.13.6.124",
journal = "SciPost Phys.",
volume = "13",
pages = "124",
year = "2022"
}
@article{Belanger:2021smw,
author = "Belanger, Genevi\`eve and others",
title = "{Leptoquark manoeuvres in the dark: a simultaneous solution of the dark matter problem and the $ {R}_{D^{\left(\ast \right)}} $ anomalies}",
eprint = "2111.08027",
archivePrefix = "arXiv",
primaryClass = "hep-ph",
reportNumber = "KIAS-Q21013, MSUHEP-21-031, IFIC/21-46, TTK-21-44, P3H-21-091",
doi = "10.1007/JHEP02(2022)042",
journal = "JHEP",
volume = "02",
pages = "042",
year = "2022"
}
@article{Belanger:2020gnr,
author = "Belanger, Genevieve and Mjallal, Ali and Pukhov, Alexander",
title = "{Recasting direct detection limits within micrOMEGAs and implication for non-standard Dark Matter scenarios}",
eprint = "2003.08621",
archivePrefix = "arXiv",
primaryClass = "hep-ph",
doi = "10.1140/epjc/s10052-021-09012-z",
journal = "Eur. Phys. J. C",
volume = "81",
number = "3",
pages = "239",
year = "2021"
}
@article{Belanger:2018ccd,
author = "B\'elanger, Genevi\`eve and Boudjema, Fawzi and Goudelis, Andreas and Pukhov, Alexander and Zaldivar, Bryan",
title = "{micrOMEGAs5.0 : Freeze-in}",
eprint = "1801.03509",
archivePrefix = "arXiv",
primaryClass = "hep-ph",
doi = "10.1016/j.cpc.2018.04.027",
journal = "Comput. Phys. Commun.",
volume = "231",
pages = "173--186",
year = "2018"
}
@article{Barducci:2016pcb,
author = "Barducci, D. and Belanger, G. and Bernon, J. and Boudjema, F. and Da Silva, J. and Kraml, S. and Laa, U. and Pukhov, A.",
title = "{Collider limits on new physics within micrOMEGAs$\_$4.3}",
eprint = "1606.03834",
archivePrefix = "arXiv",
primaryClass = "hep-ph",
doi = "10.1016/j.cpc.2017.08.028",
journal = "Comput. Phys. Commun.",
volume = "222",
pages = "327--338",
year = "2018"
}
@article{Belanger:2014vza,
author = "B\'elanger, G. and Boudjema, F. and Pukhov, A. and Semenov, A.",
title = "{micrOMEGAs4.1: two dark matter candidates}",
eprint = "1407.6129",
archivePrefix = "arXiv",
primaryClass = "hep-ph",
doi = "10.1016/j.cpc.2015.03.003",
journal = "Comput. Phys. Commun.",
volume = "192",
pages = "322--329",
year = "2015"
}
@article{Belanger:2013oya,
author = "Belanger, G. and Boudjema, F. and Pukhov, A. and Semenov, A.",
title = "{micrOMEGAs$\_$3: A program for calculating dark matter observables}",
eprint = "1305.0237",
archivePrefix = "arXiv",
primaryClass = "hep-ph",
reportNumber = "LAPTH-023-13",
doi = "10.1016/j.cpc.2013.10.016",
journal = "Comput. Phys. Commun.",
volume = "185",
pages = "960--985",
year = "2014"
}
@article{Belanger:2010gh,
author = "Belanger, G. and Boudjema, F. and Brun, P. and Pukhov, A. and Rosier-Lees, S. and Salati, P. and Semenov, A.",
title = "{Indirect search for dark matter with micrOMEGAs2.4}",
eprint = "1004.1092",
archivePrefix = "arXiv",
primaryClass = "hep-ph",
reportNumber = "IRFU-10-24, LAPTH-012-10.",
doi = "10.1016/j.cpc.2010.11.033",
journal = "Comput. Phys. Commun.",
volume = "182",
pages = "842--856",
year = "2011"
}
'''
[docs]
class NewTool(HepTool):
""" overload the init to initialise the DM limit calculator, but name and settings are already given in HepTool """
def __init__(self, name, settings,global_settings=None):
HepTool.__init__(self, name, settings,global_settings)
self.citations=references
"""
Need to set the hidden envirnoment variable 'nParProc' to 1 or less
so that MicrOMEGAs doesn't run many processes at once.
But we leave it unset if the user specifies single core running, so that
they can generate the libraries as quickly as possible.
"""
if (hasattr(global_settings,'cores') and global_settings.cores > 1) or (hasattr(global_settings,'use_MPI') and global_settings.use_MPI):
os.environ['nParProc'] = '0'
self.MOworkdir=os.path.join(os.path.dirname(self.settings['Command']),'work')
self.MOstub='_'+os.uname()[1]+'_'
self.check_LSP=False
if 'LSP' in settings:
self.list_LSP=list(settings['LSP'])
if len(self.list_LSP) > 0:
self.check_LSP=True
self.ddlimits=False
if 'DD_Limits' in self.settings:
if eval(self.settings['DD_Limits']):
self.ddlimits=True
self.limitclass=DMlimits()
else:
self.ddlimits=False
else:
self.ddlimits=False
self.command=os.path.expanduser(self.settings['Command'])
if not os.path.isfile(self.command):
#fdir=os.path.dirname
raise NameError("Cannot identify MicrOmegas executable. Please give it (without additional command line parameters) under MicrOmegas->settings->Command")
if 'Cross-sections' in self.settings:
if eval(self.settings['Cross-sections']):
self.command=[self.command,'--xsections']
if 'OutputFile' in self.settings:
self.output_file=self.settings['OutputFile']
else:
self.output_file='omg.out'
[docs]
def run(self, spc_file, temp_dir, log,data_point):
if self.check_LSP and data_point.spc is not None: ### check that the LSP is in the allowed list, e.g. if it is not charged ...
if 'LSP' in data_point.spc.blocks:
LSP=int(data_point.spc.Value('LSP',[1]))
if LSP not in self.list_LSP:
log.debug('Forbidden LSP found %d! Not running MircOMEGAs' % LSP)
raise
else:
log.debug('LSP %d ok, running MicrOMEGAs' % LSP)
if os.path.exists(self.output_file):
os.remove(self.output_file)
#print(spc_file+', '+self.settings['InputFile'])
if spc_file != self.settings['InputFile']:
try:
shutil.copyfile(spc_file,self.settings['InputFile'])
except:
log.debug('File '+spc_file+' not copied')
# Run MO
ppid=debug.noshell_command_log_PID(self.command, temp_dir, log)
#ppid=debug.command_line_log_PID(self.command, temp_dir, log)
## do clearup on temporary MO dir
tdir=os.path.join(self.MOworkdir,self.MOstub+ppid+'_')
log.debug("Guessing temporary dir: "+tdir)
if os.path.isdir(tdir):
log.debug("MO temp directory still exists! Removing it ...")
shutil.rmtree(tdir)
# Glue output to the SPheno file
if os.path.exists(self.output_file):
debug.command_line_log('sed -i "1 i\\BLOCK DARKMATTER #" '
+ self.output_file, log)
micrOMEGAS_spc=zslha.read(self.output_file)
if self.ddlimits:
try:
Mdm=float(micrOMEGAS_spc.Value("DARKMATTER",[3]))
Oh2=float(micrOMEGAS_spc.Value("DARKMATTER",[1]))
SDp=float(micrOMEGAS_spc.Value("DARKMATTER",[202]))
SDn=float(micrOMEGAS_spc.Value("DARKMATTER",[204]))
SIp=float(micrOMEGAS_spc.Value("DARKMATTER",[201]))
SIn=float(micrOMEGAS_spc.Value("DARKMATTER",[203]))
SI=(54.0*SIp+(131.0-54.0)*SIn)*1e-36/131.0
#print(f"{Mdm}, {Oh2}, {SI}, {SDp}, {SDn}")
exclusion=self.limitclass.DMexclusion(Mdm,Oh2,SI,SDp,SDn)
micrOMEGAS_spc.blocks['DARKMATTER']['501'] = exclusion
micrOMEGAS_spc.blockcomments['DARKMATTER']['501'] = 'BSMArt Direct detection exclusion'
strex='%10.6E' % float(exclusion)
#debug.command_line_log('echo \"501 '+strex+' # BSMArt Direct detection exclusion \" >> '+ self.output_file, log)
except Exception as e:
log.debug('Exception in runnng ddlimits: '+str(e))
pass
#ata_point.spc=micrOMEGAS_spc
"""
if self.ddlimits:
try:
exclusion=self.limitclass.excludefile(self.output_file)
strex='%10.6E' % float(exclusion)
debug.command_line_log('echo \"501 '+strex+' # BSMArt Direct detection exclusion \" >> '+ self.output_file, log)
except Exception as e:
log.debug('Exception in runnng ddlimits: '+str(e))
pass
## lazy. We should do this further up
micrOMEGAS_spc=zslha.read(self.output_file)
if data_point.spc is None:
data_point.spc=zslha.read(spc_file)
#ata_point.spc=micrOMEGAS_spc
"""
#else:
if data_point.spc is None:
data_point.spc=zslha.read(spc_file)
data_point.spc.add(micrOMEGAS_spc)
if self.check_LSP: ### check that the LSP is in the allowed list, e.g. if it is not charged ...
LSP=int(micrOMEGAS_spc.Value('DARKMATTER',[2]))
"""
LSP=0
with open(self.output_file,'r') as IF:
for line in IF:
if line.startswith('#'):
continue
data=line.split()
if len(data) < 2:
continue
if data_point.spc is not None:
data_point.blocks["DARKMATTER"][data[0]] = float(data[1])
if '# CDM1' in line:
#data=line.split()
if int(data[0]) == 2:
LSP=int(data[1])
break
"""
if LSP not in self.list_LSP:
log.debug('Forbidden LSP found %d!' % LSP)
raise
else:
log.debug('LSP %d ok' % LSP)
#debug.command_line_log("echo \"Block DARKMATTER # \" >> "
# + os.path.join(temp_dir, spc_file), log)
#if os.path.exists(os.path.join(temp_dir, spc_file)):
# # append result to it
# append results to spc file
debug.command_line_log("cat " + self.output_file + " >> "
+ os.path.join(temp_dir, spc_file), log)
else:
log.error("MicrOmegas output not written!")
raise
# if self.ddlimits:
# try:
# exclusion=self.limitclass.excludefile(output_file)
# debug.command_line_log('echo \"501 '+str(exclusion)+' # Direct detection exclusion \" >> '+ os.path.join(temp_dir, spc_file), log)
# except:
# pass