diff --git a/t/check_fifo.py b/t/check_fifo.py new file mode 100644 index 0000000..2f891a1 --- /dev/null +++ b/t/check_fifo.py @@ -0,0 +1,234 @@ +""" +Unit test for running HEJ with named pipes (fifo) + + +Author: CE +Date: 04/11/22 +""" +from __future__ import print_function +import math +import os +import sys +import subprocess as sp + +# Import CE custom yofor testing dafile library +sys.path.append("/home/s1533104/Documents/yodatools/yodafile/") +from yodafile import Yodafile + +def get_integral(histo): + """ + Get XS of a yodafile histogram. Different functions depending on if + histoND or ScatterND. + """ + try: + #HistoND + total = histo.sumW() + except: + try: + #ScatterND + total = 0. + for i in range(len(histo.points())): + total += histo.yVals()[i] * (histo.xMaxs()[i]-histo.xMins()[i]) + except: + print("[-] Could not test", histo.name(),"of type",histo.type()) + return total + +def get_xs(hej_output): + """ + Search HEJ output for xs and error + """ + results = [] + for line in hej_output.split("\n"): + if "+-" in line: + tokens = line.split(" ") + idl = 0 + ids = 10000 + for idx,token in enumerate(tokens): + if token == "+-": + idl = idx + elif len(token) > 1: + ids = min(ids, idx) + results.append([tokens[ids],float(tokens[idl-1]),\ + float(tokens[idl+1])]) + return results + +def check_yoda(yodafile): + """ + Returns the content of a yodafile in a way which can then be compared + with other files to check equality. + + Input expects a yodafile type object. + """ + # Need to check multiple histo types + results = [] + for histo in yodafile.histos: + if not histo.name().startswith("_") and not math.isnan(get_integral(histo)): + results.append([histo.name(), get_integral(histo)]) + return results + +def make_fifo(fifoname): + """ + Function to create a fifo file with name specified. + """ + sp.call(["mkfifo", fifoname], shell=False) + return None + +def run_hej_with_fifo(fifoname, lhefile, ymlconfig, checkyoda): + """ + Stream the contents of an lhefile to the fifo file + and at the same time read the lhefile in HEJ2. + """ + print("[+] Starting to cat LHE file") + sp.Popen(["cat " + lhefile + " >> " +\ + fifoname +" && echo [+] Finished cating file"], shell=True) + print("[+] Starting to read LHE file") + proc = sp.Popen(["HEJ", ymlconfig, fifoname], stdout=sp.PIPE) + stdout, stderr = proc.communicate() + results = stdout.decode('utf-8') + print(results) + results = results[results.find("Events processed"): results.find("Finished")] + print("\033[92m[+] Fifo XS results:",get_xs(results),"\033[0m") + + # Wait for HEJto finish and then tidy up files + proc.wait() + sp.call(["rm", fifoname]) + + if checkyoda: + yodares = check_yoda(Yodafile.readfile("HEJ.yoda")) + print("\033[92m[+] Fifo yodafile results:",yodares,"\033[0m") + + return get_xs(results) + +def run_hej_without_fifo(lhefile, ymlconfig, checkyoda): + """ + Run HEJ "normally" without using fifo pipes to make sure result is the + same as when using the pipes. + """ + print("[+] Running HEJ from LHE file") + proc = sp.Popen(["HEJ", ymlconfig, lhefile], stdout=sp.PIPE) + stdout, stderr = proc.communicate() + results = stdout.decode('utf-8') + results = results[results.find("Events processed"): results.find("Finished")] + print("\033[94m[+] Baseline XS results:",get_xs(results),"\033[0m") + + # Wait for HEJto finish + proc.wait() + + if checkyoda: + yodares = check_yoda(Yodafile.readfile("HEJ.yoda")) + print("\033[94m[+] Baseline yodafile results:",yodares,"\033[0m") + return get_xs(results) + +def test_fifo(fifoname, lhefile, ymlconfig, checkyoda=False): + """ + Main method to test all fifo related changes + """ + make_fifo(fifoname) + run_hej_with_fifo(fifoname, lhefile, ymlconfig, checkyoda) + return None + +def test_nofifo(lhefile, ymlconfig, checkyoda=False): + """ + Main method to test all fifo related changes + """ + run_hej_without_fifo(lhefile, ymlconfig, checkyoda) + return None + +def test_hepmc(lhefile, ymlconfig, checkyoda=False): + ymlconfig_hepmc = "config.yml"[0:-3]+"hepmc.yml" + make_hepmc_ymlfile(lhefile, ymlconfig, ymlconfig_hepmc) + run_hej_without_fifo("Sherpa.lhe", ymlconfig_hepmc, False) + proc = sp.Popen(["rivet","-q", "-a","MC_WJETS","-a","MC_XS","HEJ.hepmc3"],stdout=sp.PIPE) + stdout, stderr = proc.communicate() + results = stdout.decode('utf-8') + + proc.wait() + sp.call(["rm", ymlconfig_hepmc]) + if checkyoda: + yodares = check_yoda(Yodafile.readfile("Rivet.yoda")) + print("\033[96m[+] Baseline yodafile results:",yodares,"\033[0m") + + return None + + +def test_hepmc_fifo(fifoname, lhefile, ymlconfig, checkyoda=False): + ymlconfig_hepmc = "config.yml"[0:-3]+"hepmc.yml" + make_hepmc_ymlfile(lhefile, ymlconfig, ymlconfig_hepmc) + make_fifo("HEJ.hepmc3") + + print("[+] Starting HEJ with rivet output") + #sp.Popen(["cat " + lhefile + " >> " +\ + # fifoname +" && echo [+] Finished cating file"], shell=True) + #print("[+] Starting to read LHE file") + proc = sp.Popen(["HEJ", ymlconfig_hepmc, lhefile], stdout=sp.PIPE) + #proc2 = sp.Popen(["cat HEJ.hepmc3 >> op.hepmc3"], stdout=sp.PIPE, shell=True) + proc2 = sp.Popen(["rivet","-v","-a","MC_WJETS","-a","MC_XS", "HEJ.hepmc3"],stdout=sp.PIPE) + + stdout, stderr = proc.communicate() + results = stdout.decode('utf-8') + results = results[results.find("Events processed"): results.find("Finished")] + print("\033[92m[+] HEPMC Fifo XS results:",get_xs(results),"\033[0m") + + # Wait for HEJto finish and then tidy up files + proc.wait() + proc2.wait() + #sp.call(["rm", fifoname, "HEJ.hepmc3", ymlconfig_hepmc]) + + if checkyoda: + yodares = check_yoda(Yodafile.readfile("Rivet.yoda")) + print("\033[92m[+] Fifo yodafile results:",yodares,"\033[0m") + + return None + + +def make_hepmc_ymlfile(lhefile, ymlconfig, hepmcconfig): + """ + Run HEJ with hepmc output in serial without pipes + """ + + # Modify config file to include hepmc output + with open(ymlconfig, "r") as f: + contents = f.readlines() + + contents.insert(20, "event output:\n") + contents.insert(21, " - HEJ.hepmc3\n") + contents.insert(22, "\n") + + with open(hepmcconfig, "w") as f: + contents = "".join(contents) + f.write(contents) + return None + + +def force_clean(): + sp.call(["rm -rf *.yoda *.hepmc3"], shell=True) + return None + +def main(): + """ + Main test method + """ + print("[+] Checking total XS from HEJ") + test_fifo("fifo.lhe", "Sherpa.lhe", "config.yml") + force_clean() + test_nofifo("Sherpa.lhe", "config.yml") + force_clean() + + print("[+] Checking rivet output from HEJ") + test_fifo("fifo.lhe", "Sherpa.lhe", "config.yml", checkyoda=True) + force_clean() + test_nofifo( "Sherpa.lhe", "config.yml", checkyoda=True) + force_clean() + + + #HepMC output not working due to a problem in rivet. + + #print("[+] Checking rivet output from hepmc") + #test_hepmc("Sherpa.lhe", "config.yml", checkyoda=True) + #force_clean() + #test_hepmc_fifo("Sherpa.lhe","Sherpa.lhe", "config.yml", checkyoda=True) + #force_clean() + +if __name__ == "__main__": + + main()