diff --git a/madanalysis/IOinterface/job_writer.py b/madanalysis/IOinterface/job_writer.py index 8a7fd8fe..662bacd1 100644 --- a/madanalysis/IOinterface/job_writer.py +++ b/madanalysis/IOinterface/job_writer.py @@ -676,8 +676,9 @@ def CreateMainFct(self, file, analysisName, outputName): file.write("\n\n /// Setting the random seed\n") file.write(f" RANDOM->SetSeed({self.main.random_seed});\n\n") - # Add default hadrons and invisible particles for Reco mode - if self.main.mode == MA5RunningType.RECO: + # Add default hadrons and invisible particles for RECO and HADRON mode + # The invisible container may also be changed when runnign the code in HADRON mode. + if self.main.mode in [MA5RunningType.RECO, MA5RunningType.HADRON]: file.write("\n // Initializing PhysicsService for MC\n") file.write(" PHYSICS->mcConfig().Reset();\n") file.write(' // definition of the multiparticle "hadronic"\n') @@ -735,6 +736,7 @@ def CreateMainFct(self, file, analysisName, outputName): file.write(" fastsim1->Execute(mySample,myEvent);\n") elif self.main.fastsim.package == "delphesMA5tune": file.write(" fastsim1->Execute(mySample,myEvent);\n") + file.write(" manager.PrepareForExecution(mySample, myEvent);\n") file.write(" if (!analyzer1->Execute(mySample,myEvent)) continue;\n") if self.output != "" and not self.output.lower().endswith("root"): file.write(" writer1->WriteEvent(myEvent,mySample);\n") diff --git a/madanalysis/install/install_fastjet.py b/madanalysis/install/install_fastjet.py index 4ef2211f..3ba763a5 100644 --- a/madanalysis/install/install_fastjet.py +++ b/madanalysis/install/install_fastjet.py @@ -31,6 +31,8 @@ from madanalysis.install.install_service import InstallService +log = logging.getLogger("MA5") + class InstallFastjet: def __init__(self, main): @@ -47,14 +49,10 @@ def __init__(self, main): def Detect(self): if not os.path.isdir(self.toolsdir): - logging.getLogger("MA5").debug( - "The folder '" + self.toolsdir + "' is not found" - ) + log.debug("The folder '" + self.toolsdir + "' is not found") return False if not os.path.isdir(self.installdir): - logging.getLogger("MA5").debug( - "The folder " + self.installdir + "' is not found" - ) + log.debug("The folder " + self.installdir + "' is not found") return False return True @@ -124,9 +122,11 @@ def Configure(self): "--prefix=" + self.installdir, "--enable-allplugins", ] + log.debug("Configuring fastjet with prefix %s", self.installdir) + log.debug("Configuring fastjet with CXXFLAGS %s", os.environ["CXXFLAGS"]) logname = os.path.normpath(self.installdir + "/configuration.log") # Execute - logging.getLogger("MA5").debug("shell command: " + " ".join(theCommands)) + log.debug("shell command: " + " ".join(theCommands)) ok, out = ShellCommand.ExecuteWithLog( theCommands, logname, self.tmpdir, silent=False ) @@ -137,10 +137,10 @@ def Configure(self): os.environ["CXXFLAGS"] = initial_env # return result if not ok: - logging.getLogger("MA5").error( + log.error( "impossible to configure the project. For more details, see the log file:" ) - logging.getLogger("MA5").error(logname) + log.error(logname) return ok def Build(self): @@ -148,16 +148,16 @@ def Build(self): theCommands = ["make", "-j" + str(self.ncores)] logname = os.path.normpath(self.installdir + "/compilation.log") # Execute - logging.getLogger("MA5").debug("shell command: " + " ".join(theCommands)) + log.debug("shell command: " + " ".join(theCommands)) ok, out = ShellCommand.ExecuteWithLog( theCommands, logname, self.tmpdir, silent=False ) # return result if not ok: - logging.getLogger("MA5").error( + log.error( "impossible to build the project. For more details, see the log file:" ) - logging.getLogger("MA5").error(logname) + log.error(logname) return ok def Install(self): @@ -165,16 +165,16 @@ def Install(self): theCommands = ["make", "install"] logname = os.path.normpath(self.installdir + "/installation.log") # Execute - logging.getLogger("MA5").debug("shell command: " + " ".join(theCommands)) + log.debug("shell command: " + " ".join(theCommands)) ok, out = ShellCommand.ExecuteWithLog( theCommands, logname, self.tmpdir, silent=False ) # return result if not ok: - logging.getLogger("MA5").error( + log.error( "impossible to build the project. For more details, see the log file:" ) - logging.getLogger("MA5").error(logname) + log.error(logname) return ok def Check(self): @@ -186,52 +186,38 @@ def Check(self): ] for dir in dirs: if not os.path.isdir(dir): - logging.getLogger("MA5").error("folder " + dir + " is missing.") + log.error("folder " + dir + " is missing.") self.display_log() return False # Check fastjet executable if not os.path.isfile(self.installdir + "/bin/fastjet-config"): - logging.getLogger("MA5").error("binary labeled 'fastjet-config' is missing.") + log.error("binary labeled 'fastjet-config' is missing.") self.display_log() return False # Check one header file if not os.path.isfile(self.installdir + "/include/fastjet/PseudoJet.hh"): - logging.getLogger("MA5").error( - "header labeled 'include/fastjet/PseudoJet.hh' is missing." - ) + log.error("header labeled 'include/fastjet/PseudoJet.hh' is missing.") self.display_log() return False if (not os.path.isfile(self.installdir + "/lib/libfastjet.so")) and ( not os.path.isfile(self.installdir + "/lib/libfastjet.a") ): - logging.getLogger("MA5").error( - "library labeled 'libfastjet.so' or 'libfastjet.a' is missing." - ) + log.error("library labeled 'libfastjet.so' or 'libfastjet.a' is missing.") self.display_log() return False return True def display_log(self): - logging.getLogger("MA5").error("More details can be found into the log files:") - logging.getLogger("MA5").error( - " - " + os.path.normpath(self.installdir + "/wget.log") - ) - logging.getLogger("MA5").error( - " - " + os.path.normpath(self.installdir + "/unpack.log") - ) - logging.getLogger("MA5").error( - " - " + os.path.normpath(self.installdir + "/configuration.log") - ) - logging.getLogger("MA5").error( - " - " + os.path.normpath(self.installdir + "/compilation.log") - ) - logging.getLogger("MA5").error( - " - " + os.path.normpath(self.installdir + "/installation.log") - ) + log.error("More details can be found into the log files:") + log.error(" - " + os.path.normpath(self.installdir + "/wget.log")) + log.error(" - " + os.path.normpath(self.installdir + "/unpack.log")) + log.error(" - " + os.path.normpath(self.installdir + "/configuration.log")) + log.error(" - " + os.path.normpath(self.installdir + "/compilation.log")) + log.error(" - " + os.path.normpath(self.installdir + "/installation.log")) def NeedToRestart(self): return True diff --git a/madanalysis/install/install_service.py b/madanalysis/install/install_service.py index 912bdd8a..d04f272e 100644 --- a/madanalysis/install/install_service.py +++ b/madanalysis/install/install_service.py @@ -23,14 +23,18 @@ from __future__ import absolute_import -from shell_command import ShellCommand + +import glob import logging import os -import sys import shutil -from six.moves import range -from six.moves import input +import sys + import six +from shell_command import ShellCommand +from six.moves import input, range + +log = logging.getLogger("MA5") class InstallService: @@ -80,20 +84,16 @@ def reporthook(numblocks, blocksize, filesize): return try: percent = min(((numblocks + 1) * blocksize * 100) / filesize, 100) - except: + except Exception: percent = 100 theString = "% 3.1f%%" % percent - logging.getLogger("MA5").info( - " " + theString + " of " + InstallService.convert_bytes(filesize) - ) + log.info(" " + theString + " of " + InstallService.convert_bytes(filesize)) @staticmethod def get_ncores(nmaxcores, forced): - logging.getLogger("MA5").info( - " How many cores would you like " - + "to use for the compilation ? default = max = " - + str(nmaxcores) - + "" + log.info( + " How many cores would you like to use for the compilation ? default = max = %s", + nmaxcores, ) if not forced: @@ -106,7 +106,7 @@ def get_ncores(nmaxcores, forced): break try: ncores = int(answer) - except: + except Exception: test = False continue if ncores <= nmaxcores and ncores > 0: @@ -114,40 +114,25 @@ def get_ncores(nmaxcores, forced): else: ncores = nmaxcores - logging.getLogger("MA5").info( - " => Number of cores used for the compilation = " + str(ncores) - ) + log.info(" => Number of cores used for the compilation = %s", str(ncores)) return ncores @staticmethod def untar(logname, downloaddir, installdir, tarball): # Unpacking the folder theCommands = ["tar", "xzf", tarball, "-C", installdir] - logging.getLogger("MA5").debug("shell command: " + " ".join(theCommands)) - logging.getLogger("MA5").debug("exected dir: " + downloaddir) + log.debug("shell command: " + " ".join(theCommands)) + log.debug("exected dir: %s", downloaddir) ok, out = ShellCommand.ExecuteWithLog( theCommands, logname, downloaddir, silent=False ) if not ok: return False, "" - # # Removing the tarball - # toRemove=installdir+'/'+tarball - # logging.getLogger('MA5').debug('removing the file: '+toRemove) - # try: - # os.remove(toRemove) - # except: - # logging.getLogger('MA5').debug('impossible to remove the tarball: '+tarball) - - # Getting the good folder - import glob - folder_content = glob.glob(installdir + "/*") - logging.getLogger("MA5").debug( - "content of " + installdir + ": " + str(folder_content) - ) + log.debug("content of " + installdir + ": " + str(folder_content)) if len(folder_content) == 0: - logging.getLogger("MA5").error("The content of the tarball is empty") + log.error("The content of the tarball is empty") return False, "" elif len(folder_content) == 1: return True, folder_content[0] @@ -158,50 +143,36 @@ def untar(logname, downloaddir, installdir, tarball): def prepare_tmp(untardir, downloaddir): # Removing previous temporary folder path if os.path.isdir(untardir): - logging.getLogger("MA5").debug( - "This temporary folder '" + untardir + "' is found. Try to remove it ..." + log.debug( + "This temporary folder '%s' is found. Try to remove it ...", untardir ) try: shutil.rmtree(untardir) - except: - logging.getLogger("MA5").error( - "impossible to remove the folder '" + untardir + "'" - ) + except Exception: + log.error("impossible to remove the folder '%s'", untardir) return False # Creating the temporary folder - logging.getLogger("MA5").debug( - "Creating a temporary folder '" + untardir + "' ..." - ) + log.debug("Creating a temporary folder '%s' ...", untardir) try: os.mkdir(untardir) - except: - logging.getLogger("MA5").error( - "impossible to create the folder '" + untardir + "'" - ) + except Exception: + log.error("impossible to create the folder '%s' ...", untardir) return False # Creating the downloaddir folder - logging.getLogger("MA5").debug( - "Creating a temporary download folder '" + downloaddir + "' ..." - ) + log.debug("Creating a temporary download folder '%s' ...", downloaddir) if not os.path.isdir(downloaddir): try: os.mkdir(downloaddir) - except: - logging.getLogger("MA5").error( - "impossible to create the folder '" + downloaddir + "'" - ) + except Exception: + log.error("impossible to create the folder '%s' ...", downloaddir) return False else: - logging.getLogger("MA5").debug("folder '" + downloaddir + "'" + " exists.") + log.debug("folder '%s' exists.", downloaddir) # Ok - logging.getLogger("MA5").debug( - "Name of the temporary untar folder: " + untardir - ) - logging.getLogger("MA5").debug( - "Name of the temporary download folder: " + downloaddir - ) + log.debug("Name of the temporary untar folder: %s", untardir) + log.debug("Name of the temporary download folder: %s", downloaddir) return True @staticmethod @@ -209,9 +180,9 @@ def wget(filesToDownload, logFileName, installdir, **kwargs): # Opening log file try: - log = open(logFileName, "w") - except: - logging.getLogger("MA5").error("impossible to create the file " + logFileName) + logfile = open(logFileName, "w") + except Exception: + log.error("impossible to create the file %s", logFileName) return False # Parameters @@ -222,65 +193,57 @@ def wget(filesToDownload, logFileName, installdir, **kwargs): for file, url in filesToDownload.items(): ind += 1 result = "OK" - logging.getLogger("MA5").info( - " - " - + str(ind) - + "/" - + str(len(list(filesToDownload.keys()))) - + " " - + url - + " ..." - ) + log.info(" - %s/%s %s ...", ind, len(list(filesToDownload.keys())), url) output = installdir + "/" + file # Try to connect the file info = InstallService.UrlAccess(url, headers=kwargs.get("headers", None)) - ok = info != None + ok = info is not None # Check if the connection is OK if not ok: - logging.getLogger("MA5").warning( + log.warning( "Impossible to download the package from " + url + " to " + output ) result = "ERROR" error = True # Write download status in the log file - log.write(url + " : " + result + "\n") + logfile.write(url + " : " + result + "\n") # skip the file continue # Decoding the size of the remote file - logging.getLogger("MA5").debug("Decoding the size of the remote file...") - sizeURLFile = 0 + log.debug("Decoding the size of the remote file...") + sizeURLFile = -1 try: if six.PY2: sizeURLFile = int(info.info().getheaders("Content-Length")[0]) else: sizeURLFile = int(info.info().get("Content-Length")) except Exception as err: - print(err) - logging.getLogger("MA5").debug("-> Problem to decode it") - logging.getLogger("MA5").warning("Bad description for " + url) - result = "ERROR" - error = True + log.debug(err) + log.debug("-> Problem to decode it") + log.debug( + "Bad description for %s, can not read the size of the file.", url + ) + # result = "ERROR" + # error = True # Write download status in the log file - log.write(url + " : " + result + "\n") + logfile.write(url + " : " + result + "\n") # skip the file - continue - logging.getLogger("MA5").debug("-> size=" + str(sizeURLFile)) + # pass + log.debug("-> size=%s", str(sizeURLFile)) # Does the file exist locally? ok = False if not os.path.isfile(output): - logging.getLogger("MA5").debug( - "No file with the name '" + output + "' exists locally." - ) + log.debug("No file with the name '" + output + "' exists locally.") else: - logging.getLogger("MA5").debug( + log.debug( "A file with the same name '" + output + "' has been found on the machine." @@ -290,23 +253,21 @@ def wget(filesToDownload, logFileName, installdir, **kwargs): # Decoding the size of the local file if ok: - logging.getLogger("MA5").debug( - "Decoding the size of the local file..." - ) + log.debug("Decoding the size of the local file...") sizeSYSFile = 0 try: sizeSYSFile = os.path.getsize(output) except: - logging.getLogger("MA5").debug("-> Problem to decode it") + log.debug("-> Problem to decode it") ok = False # Comparing the sizes of two files if ok: - logging.getLogger("MA5").debug("-> size=" + str(sizeSYSFile)) - logging.getLogger("MA5").debug("Comparing the sizes of two files...") + log.debug("-> size=" + str(sizeSYSFile)) + log.debug("Comparing the sizes of two files...") if sizeURLFile != sizeSYSFile: - logging.getLogger("MA5").debug("-> Difference detected!") - logging.getLogger("MA5").info( + log.debug("-> Difference detected!") + log.info( " '" + file + "' is corrupted or is an old version." @@ -317,8 +278,8 @@ def wget(filesToDownload, logFileName, installdir, **kwargs): # Case where the two files are identifical -> do nothing if ok: - logging.getLogger("MA5").debug("-> NO difference detected!") - logging.getLogger("MA5").info( + log.debug("-> NO difference detected!") + log.info( " --> '" + file + "' already exists. Package not downloaded." @@ -326,22 +287,20 @@ def wget(filesToDownload, logFileName, installdir, **kwargs): # Other cases: download is necessary if not ok: - logging.getLogger("MA5").debug( + log.debug( "Fail to get info about the local file. It will be overwritten." ) # Download of the package if not ok: - logging.getLogger("MA5").debug("Downloading the file ...") + log.debug("Downloading the file ...") # Open the output file [write mode] try: outfile = open(output, "wb") except: info.close() - logging.getLogger("MA5").warning( - "Impossible to write the file " + output - ) + log.warning("Impossible to write the file " + output) result = "ERROR" error = True @@ -366,24 +325,22 @@ def wget(filesToDownload, logFileName, installdir, **kwargs): outfile.close() info.close() except: - logging.getLogger("MA5").warning( - "Impossible to close the file " + output - ) + log.warning("Impossible to close the file " + output) result = "ERROR" error = True # Write download status in the log file - log.write(url + " : " + result + "\n") + logfile.write(url + " : " + result + "\n") # Close the log file try: - log.close() + logfile.close() except: - logging.getLogger("MA5").error("impossible to close the file " + logFileName) + log.error("impossible to close the file " + logFileName) # Result if error: - logging.getLogger("MA5").warning("Error(s) occured during the installation.") + log.warning("Error(s) occured during the installation.") return False else: return True @@ -391,10 +348,13 @@ def wget(filesToDownload, logFileName, installdir, **kwargs): @staticmethod def UrlAccess(url, headers: dict[str, str] = None): - import six.moves.urllib.request, six.moves.urllib.error, six.moves.urllib.parse import ssl import time + import six.moves.urllib.error + import six.moves.urllib.parse + import six.moves.urllib.request + # max of attempts when impossible to access a file nMaxAttempts = 3 @@ -409,19 +369,17 @@ def UrlAccess(url, headers: dict[str, str] = None): and sys.version_info[2] >= 9 ) or (sys.version_info[0] == 3) except: - logging.getLogger("MA5").warning("Problem with Python version decoding!") + log.warning("Problem with Python version decoding!") modeSSL = False # Try to access ok = True for nAttempt in range(0, nMaxAttempts): if nAttempt > 0: - logging.getLogger("MA5").warning("New attempt to access the url: " + url) - logging.getLogger("MA5").debug( - "Waiting " + str(nSeconds) + " seconds ..." - ) + log.warning("New attempt to access the url: " + url) + log.debug("Waiting " + str(nSeconds) + " seconds ...") time.sleep(nSeconds) - logging.getLogger("MA5").debug( + log.debug( "Attempt " + str(nAttempt + 1) + "/" @@ -438,8 +396,8 @@ def UrlAccess(url, headers: dict[str, str] = None): else: info = six.moves.urllib.request.urlopen(url) except Exception as err: - logging.getLogger("MA5").debug(err) - logging.getLogger("MA5").warning("Impossible to access the url: " + url) + log.debug(err) + log.warning("Impossible to access the url: " + url) ok = False if ok: break @@ -448,7 +406,7 @@ def UrlAccess(url, headers: dict[str, str] = None): return None # Display - logging.getLogger("MA5").debug( + log.debug( "Info about the url: --------------------------------------------------------" ) words = str(info.info()).split("\n") @@ -456,8 +414,8 @@ def UrlAccess(url, headers: dict[str, str] = None): word = word.lstrip() word = word.rstrip() if word != "": - logging.getLogger("MA5").debug("Info about the url: " + word) - logging.getLogger("MA5").debug( + log.debug("Info about the url: " + word) + log.debug( "Info about the url: --------------------------------------------------------" ) @@ -466,9 +424,7 @@ def UrlAccess(url, headers: dict[str, str] = None): @staticmethod def check_ma5site(): url = "http://madanalysis.irmp.ucl.ac.be" - logging.getLogger("MA5").debug( - "Testing the access to MadAnalysis 5 website: " + url + " ..." - ) + log.debug("Testing the access to MadAnalysis 5 website: " + url + " ...") info = InstallService.UrlAccess(url) # Close the access if info != None: @@ -478,9 +434,7 @@ def check_ma5site(): @staticmethod def check_dataverse(): url = "http://dataverse.uclouvain.be" - logging.getLogger("MA5").debug( - "Testing access to the MadAnalysis5 dataverse: " + url + " ..." - ) + log.debug("Testing access to the MadAnalysis5 dataverse: " + url + " ...") info = InstallService.UrlAccess(url) # Close the access if info != None: @@ -490,15 +444,13 @@ def check_dataverse(): @staticmethod def create_tools_folder(path): if os.path.isdir(path): - logging.getLogger("MA5").debug( - " The installation folder 'tools' is already created." - ) + log.debug(" The installation folder 'tools' is already created.") else: - logging.getLogger("MA5").debug(" Creating the 'tools' folder ...") + log.debug(" Creating the 'tools' folder ...") try: os.mkdir(path) except: - logging.getLogger("MA5").error("impossible to create the folder 'tools'.") + log.error("impossible to create the folder 'tools'.") return False return True @@ -507,20 +459,14 @@ def create_package_folder(toolsdir, package): # Removing the folder package if os.path.isdir(os.path.join(toolsdir, package)): - logging.getLogger("MA5").error( - "impossible to remove the folder 'tools/" + package + "'" - ) + log.error("impossible to remove the folder 'tools/" + package + "'") return False # Creating the folder package try: os.mkdir(os.path.join(toolsdir, package)) except: - logging.getLogger("MA5").error( - "impossible to create the folder 'tools/" + package + "'" - ) + log.error("impossible to create the folder 'tools/" + package + "'") return False - logging.getLogger("MA5").debug( - " Creation of the directory 'tools/" + package + "'" - ) + log.debug(" Creation of the directory 'tools/" + package + "'") return True diff --git a/madanalysis/interpreter/cmd_install.py b/madanalysis/interpreter/cmd_install.py index e9ef4760..0ef33771 100644 --- a/madanalysis/interpreter/cmd_install.py +++ b/madanalysis/interpreter/cmd_install.py @@ -145,35 +145,10 @@ def UpdatePaths(): self.logger.warning('DelphesMA5tune is not installed... please exit the program and install the pad') return True elif args[0]=='PAD': - pad_install_check, padsfs_install_check = False, False - # First check if PAD4SFS is installed - if not self.main.session_info.has_padsfs: - # check if FastJet is installed - if not self.main.archi_info.has_fastjet: - answer = "y" - if not self.main.forced: - self.logger.warning("PADForSFS requires FastJet to be installed.") - self.logger.info("Would you like to install FastJet? [Y/N]") - while True: - answer = input("Answer : ") - if answer.lower() in ['y','n','yes','no', "yeap", "nope"]: - break - if answer.lower() in ['y','yes',"yeap"]: - for package in ["fastjet", "fastjet-contrib", "PADForSFS"]: - if not installer.Execute(package): - return False - padsfs_install_check = 'restart' - else: - padsfs_install_check = installer.Execute('PADForSFS') - - if inst_delphes(self.main,installer,'delphes',True): - pad_install_check = installer.Execute('PAD') - else: - self.logger.warning('Delphes is not installed (and will be installed). '+ - 'Then please exit MA5 and re-install the PAD') - if 'restart' in [pad_install_check, padsfs_install_check]: - return 'restart' - return any([pad_install_check, padsfs_install_check]) + if not self.main.archi_info.has_delphes: + self.logger.warning("PAD requires delphes installation, installing it...") + return installer.Execute('Delphes') + return installer.Execute('PAD') elif args[0]=='PADForSFS': padsfs_install_check = False if self.main.archi_info.has_fastjet: diff --git a/madanalysis/misc/run_recast.py b/madanalysis/misc/run_recast.py index 03180760..351ec0af 100644 --- a/madanalysis/misc/run_recast.py +++ b/madanalysis/misc/run_recast.py @@ -21,7 +21,6 @@ # ################################################################################ - from __future__ import absolute_import import copy @@ -29,14 +28,14 @@ import logging import math import os -import re import shutil import time from pathlib import Path +from typing import Union import numpy as np from shell_command import ShellCommand # pylint: disable=import-error -from six.moves import input, range +from six.moves import range from string_tools import StringTools # pylint: disable=import-error from madanalysis.configuration.delphes_configuration import DelphesConfiguration @@ -44,6 +43,7 @@ DelphesMA5tuneConfiguration, ) from madanalysis.core.main import Main +from madanalysis.dataset.dataset_collection import DatasetCollection from madanalysis.install.detector_manager import DetectorManager from madanalysis.IOinterface.folder_writer import FolderWriter from madanalysis.IOinterface.job_writer import JobWriter @@ -54,6 +54,12 @@ construct_histfactory_dictionary, ) from madanalysis.misc.theoretical_error_setup import error_dict_setup +from madanalysis.misc.utils import ( + clean_region_name, + edit_recasting_card, + get_runs, + read_xsec, +) # pylint: disable=logging-fstring-interpolation,import-outside-toplevel @@ -61,6 +67,20 @@ class RunRecast: + """ + One-line summary + Initialize the RunRecast controller holding runtime state for recasting runs. + + Extended summary + Stores references to the main application object, directory paths and + internal configuration derived from the architecture and recasting + settings. Prepares PAD <-> detector mapping and Delphes include paths. + + Args: + main (``Main``): The main MadAnalysis application object providing configuration. + dirname (``str``): Base working directory used for the recasting jobs. + """ + def __init__(self, main: Main, dirname: str): self.dirname: str = dirname self.main: Main = main @@ -74,6 +94,14 @@ def __init__(self, main: Main, dirname: str): self.pyhf_config = {} # initialize and configure histfactory self.cov_config = {} self.TACO_output = self.main.recasting.TACO_output + self.pad_dict = {} + + if self.main.recasting.ma5tune: + self.pad_dict.update({"v1.1": ("PADForMA5tune", "delphesMA5tune")}) + if self.main.recasting.delphes: + self.pad_dict.update({"v1.2": ("PAD", "delphes")}) + if self.main.archi_info.has_fastjet: + self.pad_dict.update({"vSFS": ("PADForSFS", "fastjet")}) self.delphes_inc_pths = [] if len(self.main.archi_info.delphes_inc_paths) != 0: @@ -83,13 +111,27 @@ def __init__(self, main: Main, dirname: str): + "/modules" ) - def init(self): + def init(self) -> bool: + """ + One-line summary + Prepare and validate the recasting runs by editing the recasting card and collecting runs. + + Extended summary + Optionally opens an editor for the recasting card (unless forced or in script mode), + then obtains the list of delphes and analysis runs from the recasting card and + verifies there is work to do. + + Returns: + ``bool``: + True if at least one delphes run was found and initialization succeeded, False otherwise. + """ ### First, the analyses to take care off log.debug(" Inviting the user to edit the recasting card...") - self.edit_recasting_card() + if not self.forced or not self.main.script: + edit_recasting_card(self.main.session_info.editor, self.dirname) ### Getting the list of analyses to recast log.info(" Getting the list of delphes simulation to be performed...") - self.get_runs() + self.delphes_runcard, self.analysis_runcard = get_runs(self.dirname) ### Check if we have anything to do if len(self.delphes_runcard) == 0: log.warning("No recasting to do... Please check the recasting card") @@ -103,20 +145,27 @@ def init(self): ################################################ ## Running the machinery - def execute(self): + def execute(self) -> bool: + """ + One-line summary + Execute all configured PAD runs for the collected delphes runcard entries. + + Extended summary + Iterates over the configured delphes runs, maps version to PAD/detector, runs the + analysis for each entry and performs cleanup. Restores main.forced at exit. + + Returns: + ``bool``: + True if execution completed successfully for all runs, False on error or unsupported version. + """ self.main.forced = True - for delphescard in list(set(sorted(self.delphes_runcard))): + for version, card in self.delphes_runcard: ## Extracting run infos and checks - version = delphescard[:4] - card = delphescard[5:] - if not self.check_run(version): - self.main.forced = self.forced - return False - - ## Running the fastsim - if not self.fastsim_single(version, card): + if not self.pad_dict.get(version, False): self.main.forced = self.forced return False + pad, self.detector = self.pad_dict[version] + self.pad = f"{self.main.archi_info.ma5dir}/tools/{pad}" self.main.fastsim.package = self.detector ## Running the analyses @@ -125,404 +174,481 @@ def execute(self): return False ## Cleaning - if not FolderWriter.RemoveDirectory( - os.path.normpath(self.dirname + "_RecastRun") - ): - return False + pth = Path(os.path.normpath(self.dirname + "_RecastRun")) + if not self.main.developer_mode: + if not FolderWriter.RemoveDirectory(str(pth)): + log.error("Cannot remove directory: %s", str(pth)) + else: + log.debug("Analysis kept in %s folder.", str(pth)) # exit self.main.forced = self.forced return True - ## Prompt to edit the recasting card - def edit_recasting_card(self): - if self.forced or self.main.script: - return - log.info("Would you like to edit the recasting Card ? (Y/N)") - allowed_answers = ["n", "no", "y", "yes"] - answer = "" - while answer not in allowed_answers: - answer = input("Answer: ") - answer = answer.lower() - if answer in ["no", "n"]: - return - else: - err = os.system( - self.main.session_info.editor - + " " - + self.dirname - + "/Input/recasting_card.dat" - ) - - return - - ## Checking the recasting card to get the analysis to run - def get_runs(self): - del_runs = [] - ana_runs = [] - ## decoding the card - runcard = open(self.dirname + "/Input/recasting_card.dat", "r") - for line in runcard: - if len(line.strip()) == 0 or line.strip().startswith("#"): - continue - myline = line.split() - if myline[2].lower() == "on" and myline[3] not in del_runs: - del_runs.append(myline[1] + "_" + myline[3]) - if myline[2].lower() == "on": - ana_runs.append(myline[1] + "_" + myline[0]) - ## saving the information and exti - self.delphes_runcard = del_runs - self.analysis_runcard = ana_runs - return - - def check_run(self, version): - ## setup - check = False - if version == "v1.1": - self.detector = "delphesMA5tune" - self.pad = self.main.archi_info.ma5dir + "/tools/PADForMA5tune" - check = self.main.recasting.ma5tune - elif version == "v1.2": - self.detector = "delphes" - self.pad = self.main.archi_info.ma5dir + "/tools/PAD" - check = self.main.recasting.delphes - elif version == "vSFS": - self.detector = "fastjet" - self.pad = self.main.archi_info.ma5dir + "/tools/PADForSFS" - check = True - ## Check and exit - if not check: - log.error( - "The %s library is not present -> the associated analyses cannot be used", - self.detector, - ) - return False - return True - ################################################ - ### DELPHES RUN + ### FastSim RUN ################################################ - def fastsim_single(self, version, delphescard): - log.debug("Launch a bunch of fastsim with the delphes card: %s", delphescard) - - # Init and header - self.fastsim_header(version) - - # Activating the right delphes - if self.detector != "fastjet": - log.debug("Activating the detector (switch delphes/delphesMA5tune)") - self.main.fastsim.package = self.detector - detector_handler = DetectorManager(self.main) - if not detector_handler.manage(self.detector): - log.error("Problem with the activation of delphesMA5tune") - return False - - # Checking whether events have already been generated and if not, event generation - log.debug("Loop over the datasets...") - evtfile = None - for item in self.main.datasets: - if self.detector == "delphesMA5tune": - evtfile = ( - self.dirname - + "/Output/SAF/" - + item.name - + "/RecoEvents/RecoEvents_v1x1_" - + delphescard.replace(".tcl", "") - + ".root" - ) - elif self.detector == "delphes": - evtfile = ( - self.dirname - + "/Output/SAF/" - + item.name - + "/RecoEvents/RecoEvents_v1x2_" - + delphescard.replace(".tcl", "") - + ".root" - ) - elif self.detector == "fastjet": - return True - - log.debug("- applying fastsim and producing %s ...", evtfile) - if not os.path.isfile(os.path.normpath(evtfile)): - if not self.generate_events(item, delphescard): - return False + def run_delphes_analysis( + self, dataset: DatasetCollection, card: str, analysislist: list[str] + ) -> bool: + """ + One-line summary + Build, compile and run a PAD-based Delphes analysis for a dataset. + + Extended summary + Prepares the run directory, writes analyzer sources and Makefiles, patches main.cpp, + fixes pileup references, compiles, links and executes the SampleAnalyzer job and moves + any produced Delphes events back to the main output layout. + + Args: + dataset (``DatasetCollection``): Dataset collection to process. + card (``str``): Delphes card filename (relative to PAD Input). + analysislist (``list[str]``): List of analyzer names to include in the run. + + Returns: + ``bool``: + True on success, False on any failure during preparation, compilation or execution. + """ + # Preparing the run + self.main.recasting.status = "off" + self.main.fastsim.package = self.detector + self.main.fastsim.clustering = 0 - # Exit - return True + pad_name = "PAD" if self.detector == "delphes" else "PADForMA5tune" + card_path = Path(f"../../../../tools/{pad_name}/Input/Cards/{card}") + version = "" + if self.detector == "delphesMA5tune": + version = "v1x1" + self.main.fastsim.delphes = 0 + self.main.fastsim.delphesMA5tune = DelphesMA5tuneConfiguration() + self.main.fastsim.delphesMA5tune.card = str(card_path) + elif self.detector == "delphes": + self.main.fastsim.delphesMA5tune = 0 + self.main.fastsim.delphes = DelphesConfiguration() + self.main.fastsim.delphes.card = str(card_path) + version = "v1x2" - def fastsim_header(self, version): - ## Gettign the version dependent stuff - to_print = False - tag = None - if version == "v1.1" and self.first11: - to_print = True - tag = version - self.first11 = False - elif version != "v1.1" and self.first12: - to_print = True - tag = "v1.2+" - self.first12 = False - ## Printing - if to_print: - log.info(" **********************************************************") - log.info(" %s", StringTools.Center(f"{tag} detector simulations", 57)) - log.info(" **********************************************************") - - def run_delphes(self, dataset, card): - # Initializing the JobWriter - if os.path.isdir(self.dirname + "_RecastRun"): - if not FolderWriter.RemoveDirectory( - os.path.normpath(self.dirname + "_RecastRun") - ): - return False - jobber = JobWriter(self.main, self.dirname + "_RecastRun") + recast_path = Path(self.dirname + "_RecastRun").absolute() + org_rel = Path("Build/SampleAnalyzer/User/Analyzer") + jobber = JobWriter(self.main, str(recast_path)) - # Writing process - log.info(" Creating folder '" + self.dirname.split("/")[-1] + "_RecastRun'...") + log.info(" Creating folder '%s'", recast_path.stem) if not jobber.Open(): return False log.info(" Copying 'SampleAnalyzer' source files...") if not jobber.CopyLHEAnalysis(): return False - if not jobber.CreateBldDir(): + if not jobber.CreateBldDir( + analysisName="DelphesRun", outputName="DelphesRun.saf" + ): return False - log.info(" Inserting your selection into 'SampleAnalyzer'...") if not jobber.WriteSelectionHeader(self.main): return False if not jobber.WriteSelectionSource(self.main): return False + + # remove default user selection files if present + try: + (recast_path / org_rel / "user.h").unlink(missing_ok=True) + (recast_path / org_rel / "user.cpp").unlink(missing_ok=True) + except Exception as err: + log.debug("Could not remove user files: %s", err) + log.info(" Writing the list of datasets...") jobber.WriteDatasetList(dataset) log.info(" Creating Makefiles...") if not jobber.WriteMakefiles(ma5_fastjet_mode=False): return False - log.debug(" Fixing the pileup path...") - self.fix_pileup(self.dirname + "_RecastRun/Input/" + card) - # Creating executable + # Build analysisList.h and copy analyzer files from the pad + analysis_list_path = recast_path / org_rel / "analysisList.h" + pad_path = Path(self.pad) + pad_org = pad_path / org_rel + recast_org = recast_path / org_rel + + try: + with analysis_list_path.open("w", encoding="utf-8") as f: + for ana in analysislist: + f.write(f'#include "SampleAnalyzer/User/Analyzer/{ana}.h"\n') + f.write('#include "SampleAnalyzer/Process/Analyzer/AnalyzerManager.h"\n') + f.write('#include "SampleAnalyzer/Commons/Service/LogStream.h"\n\n') + f.write( + "// -----------------------------------------------------------------------------\n" + ) + f.write("// BuildUserTable\n") + f.write( + "// -----------------------------------------------------------------------------\n" + ) + f.write("void BuildUserTable(MA5::AnalyzerManager& manager)\n{\n") + f.write(" using namespace MA5;\n") + for ana in analysislist: + pad_cpp = pad_org / f"{ana}.cpp" + pad_h = pad_org / f"{ana}.h" + rec_cpp = recast_org / f"{ana}.cpp" + rec_h = recast_org / f"{ana}.h" + # require header, cpp may be optional (but typically present) + if not pad_h.exists(): + log.error("Missing analysis header in PAD: %s", pad_h) + return False + shutil.copyfile(str(pad_h), str(rec_h)) + if pad_cpp.exists(): + shutil.copyfile(str(pad_cpp), str(rec_cpp)) + else: + log.debug( + "No .cpp for %s in PAD; continuing with header only.", ana + ) + f.write(f' manager.Add("{ana}", new {ana});\n') + f.write("}\n") + except Exception as err: + log.error("Cannot prepare analysisList.h: %s", err) + return False + + # Update main executable: backup and create modified main.cpp + main_base = recast_path / "Build" / "Main" / "main" + main_cpp = main_base.with_suffix(".cpp") + main_bak = main_base.with_suffix(".bak") + try: + shutil.move(str(main_cpp), str(main_bak)) + except Exception as err: + log.error("Cannot backup main.cpp: %s", err) + return False + + try: + with main_bak.open("r", encoding="utf-8") as infile: + lines = infile.readlines() + except Exception as err: + log.error("Cannot read main.bak: %s", err) + return False + + new_lines = [] + ignore = False + for line in lines: + if "// Getting pointer to the analyzer" in line: + ignore = True + new_lines.append(line) + for analysis in analysislist: + new_lines.append( + f" std::map param_{analysis};\n" + ) + new_lines.append(f" AnalyzerBase* analyzer_{analysis}=\n") + new_lines.append( + f' manager.InitializeAnalyzer("{analysis}", "{analysis}.saf", param_{analysis});\n' + ) + new_lines.append(f" if (analyzer_{analysis}==0) return 1;\n\n") + continue + if ( + "// Post initialization (creates the new output directory structure)" + in line + and self.TACO_output != "" + ): + new_lines.append(line) + new_lines.append( + f' std::ofstream out;\n out.open("../Output/{self.TACO_output}");\n' + ) + new_lines.append(" manager.HeadSR(out);\n out << std::endl;\n") + continue + if "//Getting pointer to fast-simulation package" in line: + ignore = False + new_lines.append(line) + continue + if "!analyzer1" in line and not ignore: + ignore = True + for analysis in analysislist: + new_lines.append( + f" if (!analyzer_{analysis}->Execute(mySample,myEvent)) continue;\n" + ) + if self.TACO_output != "": + new_lines.append("\n manager.DumpSR(out);\n") + continue + if " }" in line: + new_lines.append(line) + ignore = False + continue + if "manager.Finalize(mySamples,myEvent);" in line and self.TACO_output != "": + new_lines.append(line) + new_lines.append(" out.close();\n") + continue + if not ignore: + new_lines.append(line) + + try: + with main_cpp.open("w", encoding="utf-8") as outfile: + outfile.writelines(new_lines) + except Exception as err: + log.error("Cannot write new main.cpp: %s", err) + return False + + # Fix pileup in the card copied into the run folder + if not self.fix_pileup(str(recast_path / "Input" / card)): + return False + + # Compile / Link / Run log.info(" Compiling 'SampleAnalyzer'...") - # os.environ["ROOT_INCLUDE_PATH"] = ":".join(self.delphes_inc_pths) - # os.environ["FASTJET_FLAG"] = "" if not jobber.CompileJob(): + log.error("job submission aborted.") return False log.info(" Linking 'SampleAnalyzer'...") if not jobber.LinkJob(): + log.error("job submission aborted.") return False - # Running - log.info(" Running 'SampleAnalyzer' over dataset '" + dataset.name + "'...") + log.info(" Running 'SampleAnalyzer' over dataset '%s'...", dataset.name) log.info(" *******************************************************") if not jobber.RunJob(dataset): - log.error("run over '" + dataset.name + "' aborted.") + log.error("run over '%s' aborted.", dataset.name) + return False log.info(" *******************************************************") - # Exit - return True - - def run_SimplifiedFastSim(self, dataset, card, analysislist): - """ + # Restoring the run + self.main.recasting.status = "on" + self.main.fastsim.package = "none" - Parameters - ---------- - dataset : MA5 Dataset - one of the datasets from self.main.dataset - card : SFS Run Card - SFS description for the detector simulation - analysislist : LIST of STR - list of analysis names + event_path = next( + ( + x + for x in (recast_path / f"Output/SAF/_{dataset.name}").iterdir() + if "RecoEvents" in str(x) + ), + None, + ) + if event_path is not None: + root_path = event_path / "DelphesEvents.root" + if root_path.is_file(): + main_event_path = ( + Path(self.dirname) / f"Output/SAF/{dataset.name}/RecoEvents" + ) + main_event_path.mkdir(parents=True, exist_ok=True) + moved_smp = ( + main_event_path + / f"RecoEvents_{version}_{card.replace('.tcl', '')}.root" + ) + shutil.move(str(root_path), str(moved_smp)) - Returns - ------- - bool - SFS run correctly (True), there was a mistake (False) + return True + def run_SimplifiedFastSim( + self, dataset: DatasetCollection, card: str, analysislist: list[str] + ) -> bool: + """ + One-line summary + Run the Simplified Fast Simulation (SFS) workflow for a dataset. + + Extended summary + Rejects already reconstructed inputs, loads the analysis card into the interpreter, + prepares a SFS run directory, writes analyzers from PAD, patches main, compiles, links + and runs the analysis and moves produced outputs into the main Output/SAF layout. + + Args: + dataset (``DatasetCollection``): Dataset collection to process. + card (``str``): Path to the analysis card to load. + analysislist (``list[str]``): List of analyzers to include. + + Returns: + ``bool``: + True on success, False on error. """ + # Reject already-reconstructed inputs if any( - any(x.endswith(y) for y in ["root", "lhco", "lhco.gz"]) + any(x.endswith(ext) for ext in ("root", "lhco", "lhco.gz")) for x in dataset.filenames ): log.error(" Dataset can not contain reconstructed file type.") return False - # Load the analysis card + + # Load the analysis card and configure interpreter / fastsim temporarily from madanalysis.core.script_stack import ScriptStack ScriptStack.AddScript(card) + self.main.recasting.status = "off" self.main.superfastsim.Reset() - script_mode = self.main.script + + old_script_mode = self.main.script self.main.script = True - from madanalysis.interpreter.interpreter import Interpreter + try: + from madanalysis.interpreter.interpreter import Interpreter + + interpreter = Interpreter(self.main) + interpreter.load(verbose=self.main.developer_mode) + except Exception as err: + log.debug(err) + self.main.script = old_script_mode + return False + finally: + self.main.script = old_script_mode - interpreter = Interpreter(self.main) - interpreter.load(verbose=self.main.developer_mode) - self.main.script = script_mode old_fastsim = self.main.fastsim.package self.main.fastsim.package = "fastjet" + + output_name = None if self.main.recasting.store_events: output_name = "SFS_events.lhe" if self.main.archi_info.has_zlib: output_name += ".gz" - log.debug(" Setting the output LHE file :" + output_name) + log.debug(" Setting the output LHE file: %s", output_name) - # Initializing the JobWriter - jobber = JobWriter(self.main, self.dirname + "_SFSRun") + run_dir = Path(self.dirname + "_SFSRun") + jobber = JobWriter(self.main, str(run_dir)) - # Writing process - log.info(" Creating folder '" + self.dirname.split("/")[-1] + "'...") + # Prepare build/run directory and analysis sources + log.info(" Creating folder '%s'...", Path(self.dirname).name) if not jobber.Open(): + self.main.fastsim.package = old_fastsim return False log.info(" Copying 'SampleAnalyzer' source files...") if not jobber.CopyLHEAnalysis(): + self.main.fastsim.package = old_fastsim return False if not jobber.CreateBldDir(analysisName="SFSRun", outputName="SFSRun.saf"): + self.main.fastsim.package = old_fastsim return False if not jobber.WriteSelectionHeader(self.main): + self.main.fastsim.package = old_fastsim return False - os.remove(self.dirname + "_SFSRun/Build/SampleAnalyzer/User/Analyzer/user.h") + # remove potentially generated user files safely + (run_dir / "Build/SampleAnalyzer/User/Analyzer/user.h").unlink(missing_ok=True) if not jobber.WriteSelectionSource(self.main): + self.main.fastsim.package = old_fastsim return False - os.remove(self.dirname + "_SFSRun/Build/SampleAnalyzer/User/Analyzer/user.cpp") - ####### + (run_dir / "Build/SampleAnalyzer/User/Analyzer/user.cpp").unlink(missing_ok=True) + log.info(" Writing the list of datasets...") jobber.WriteDatasetList(dataset) log.info(" Creating Makefiles...") if not jobber.WriteMakefiles(): + self.main.fastsim.package = old_fastsim return False - # Copying the analysis files - analysisList = open( - self.dirname + "_SFSRun/Build/SampleAnalyzer/User/Analyzer/analysisList.h", - "w", - ) - for ana in analysislist: - analysisList.write('#include "SampleAnalyzer/User/Analyzer/' + ana + '.h"\n') - analysisList.write( - '#include "SampleAnalyzer/Process/Analyzer/AnalyzerManager.h"\n' - ) - analysisList.write('#include "SampleAnalyzer/Commons/Service/LogStream.h"\n\n') - if self.main.superfastsim.isTaggerOn(): - analysisList.write('#include "new_tagger.h"\n') - if self.main.superfastsim.isNewSmearerOn(): - analysisList.write('#include "new_smearer_reco.h"\n') - analysisList.write( - "// -----------------------------------------------------------------------------\n" - ) - analysisList.write("// BuildUserTable\n") - analysisList.write( - "// -----------------------------------------------------------------------------\n" - ) - analysisList.write("void BuildUserTable(MA5::AnalyzerManager& manager)\n") - analysisList.write("{\n") - analysisList.write(" using namespace MA5;\n") + + # Create analysisList.h and copy analyzer files from PAD + analysis_list_path = run_dir / "Build/SampleAnalyzer/User/Analyzer/analysisList.h" + pad_analyzer_dir = Path(self.pad) / "Build/SampleAnalyzer/User/Analyzer" + analyzer_dest = run_dir / "Build/SampleAnalyzer/User/Analyzer" try: - for ana in analysislist: - shutil.copyfile( - self.pad + "/Build/SampleAnalyzer/User/Analyzer/" + ana + ".cpp", - self.dirname - + "_SFSRun/Build/SampleAnalyzer/User/Analyzer/" - + ana - + ".cpp", + analyzer_dest.mkdir(parents=True, exist_ok=True) + with analysis_list_path.open("w", encoding="utf-8") as f: + for ana in analysislist: + f.write(f'#include "SampleAnalyzer/User/Analyzer/{ana}.h"\n') + f.write('#include "SampleAnalyzer/Process/Analyzer/AnalyzerManager.h"\n') + f.write('#include "SampleAnalyzer/Commons/Service/LogStream.h"\n\n') + if self.main.superfastsim.isTaggerOn(): + f.write('#include "new_tagger.h"\n') + if self.main.superfastsim.isNewSmearerOn(): + f.write('#include "new_smearer_reco.h"\n') + f.write( + "// -----------------------------------------------------------------------------\n" ) - shutil.copyfile( - self.pad + "/Build/SampleAnalyzer/User/Analyzer/" + ana + ".h", - self.dirname - + "_SFSRun/Build/SampleAnalyzer/User/Analyzer/" - + ana - + ".h", + f.write("// BuildUserTable\n") + f.write( + "// -----------------------------------------------------------------------------\n" ) - analysisList.write(' manager.Add("' + ana + '", new ' + ana + ");\n") + f.write("void BuildUserTable(MA5::AnalyzerManager& manager)\n{\n") + f.write(" using namespace MA5;\n") + for ana in analysislist: + src_cpp = pad_analyzer_dir / f"{ana}.cpp" + src_h = pad_analyzer_dir / f"{ana}.h" + dst_cpp = analyzer_dest / f"{ana}.cpp" + dst_h = analyzer_dest / f"{ana}.h" + if not src_h.exists(): + log.error("Missing analysis header in PAD: %s", src_h) + return False + shutil.copyfile(str(src_h), str(dst_h)) + if src_cpp.exists(): + shutil.copyfile(str(src_cpp), str(dst_cpp)) + else: + log.debug( + "No .cpp for %s in PAD; continuing with header only.", ana + ) + f.write(f' manager.Add("{ana}", new {ana});\n') + f.write("}\n") except Exception as err: - log.debug(str(err)) - log.error("Cannot copy the analysis: " + ana) - log.error( - "Please make sure that corresponding analysis downloaded propoerly." - ) + log.error("Error preparing analysisList.h or copying analyzers: %s", err) + self.main.fastsim.package = old_fastsim return False - analysisList.write("}\n") - analysisList.close() - # Update Main - log.info(" Updating the main executable") - shutil.move( - self.dirname + "_SFSRun/Build/Main/main.cpp", - self.dirname + "_SFSRun/Build/Main/main.bak", - ) - mainfile = open(self.dirname + "_SFSRun/Build/Main/main.bak", "r") - newfile = open(self.dirname + "_SFSRun/Build/Main/main.cpp", "w") - ignore = False - for line in mainfile: - if "// Getting pointer to the analyzer" in line: - ignore = True - newfile.write(line) - for analysis in analysislist: - newfile.write( - " std::map prm" + analysis + ";\n" - ) - newfile.write(" AnalyzerBase* analyzer_" + analysis + "=\n") - newfile.write( - ' manager.InitializeAnalyzer("' - + analysis - + '","' - + analysis - + '.saf",' - + "prm" - + analysis - + ");\n" - ) - newfile.write(" if (analyzer_" + analysis + "==0) return 1;\n\n") - if self.main.recasting.store_events: - newfile.write(" //Getting pointer to the writer\n") - newfile.write(" WriterBase* writer1 = \n") - newfile.write( - ' manager.InitializeWriter("lhe","' + output_name + '");\n' - ) - newfile.write(" if (writer1==0) return 1;\n\n") - elif ( - "// Post initialization (creates the new output directory structure)" - in line - and self.TACO_output != "" - ): - newfile.write( - ' std::ofstream out;\n out.open("../Output/' - + self.TACO_output - + '");\n' - ) - newfile.write("\n manager.HeadSR(out);\n out << std::endl;\n") - elif "//Getting pointer to the clusterer" in line: - ignore = False - newfile.write(line) - elif "!analyzer1" in line and not ignore: - ignore = True - if self.main.recasting.store_events: - newfile.write(" writer1->WriteEvent(myEvent,mySample);\n") - for analysis in analysislist: - newfile.write( - " if (!analyzer_" - + analysis - + "->Execute(mySample,myEvent)) continue;\n" - ) - if self.TACO_output != "": - newfile.write("\n manager.DumpSR(out);\n") - elif " }" in line: - newfile.write(line) + # Modify main to register analyzers / optional writer / TACO output + try: + main_path = run_dir / "Build/Main" + main_cpp = main_path / "main.cpp" + main_bak = main_path / "main.bak" + shutil.move(str(main_cpp), str(main_bak)) + with main_bak.open("r", encoding="utf-8") as infile, main_cpp.open( + "w", encoding="utf-8" + ) as outfile: ignore = False - elif ( - "manager.Finalize(mySamples,myEvent);" in line and self.TACO_output != "" - ): - newfile.write(line) - newfile.write(" out.close();\n") - elif not ignore: - newfile.write(line) - mainfile.close() - newfile.close() - # restore + for line in infile: + if "// Getting pointer to the analyzer" in line: + ignore = True + outfile.write(line) + for analysis in analysislist: + outfile.write( + f" std::map prm{analysis};\n" + ) + outfile.write(f" AnalyzerBase* analyzer_{analysis}=\n") + outfile.write( + f' manager.InitializeAnalyzer("{analysis}","{analysis}.saf",prm{analysis});\n' + ) + outfile.write(f" if (analyzer_{analysis}==0) return 1;\n\n") + if output_name: + outfile.write(" //Getting pointer to the writer\n") + outfile.write(" WriterBase* writer1 = \n") + outfile.write( + f' manager.InitializeWriter("lhe","{output_name}");\n' + ) + outfile.write(" if (writer1==0) return 1;\n\n") + continue + if ( + "// Post initialization (creates the new output directory structure)" + in line + and self.TACO_output != "" + ): + outfile.write(line) + outfile.write( + f' std::ofstream out;\n out.open("../Output/{self.TACO_output}");\n' + ) + outfile.write( + " manager.HeadSR(out);\n out << std::endl;\n" + ) + continue + if "//Getting pointer to the clusterer" in line: + ignore = False + outfile.write(line) + continue + if "!analyzer1" in line and not ignore: + ignore = True + if output_name: + outfile.write( + " writer1->WriteEvent(myEvent,mySample);\n" + ) + for analysis in analysislist: + outfile.write( + f" if (!analyzer_{analysis}->Execute(mySample,myEvent)) continue;\n" + ) + if self.TACO_output != "": + outfile.write("\n manager.DumpSR(out);\n") + continue + if " }" in line: + outfile.write(line) + ignore = False + continue + if ( + "manager.Finalize(mySamples,myEvent);" in line + and self.TACO_output != "" + ): + outfile.write(line) + outfile.write(" out.close();\n") + continue + if not ignore: + outfile.write(line) + except Exception as err: + log.error("Cannot update main.cpp: %s", err) + self.main.fastsim.package = old_fastsim + return False + + # Restore recasting status and fastsim package self.main.recasting.status = "on" self.main.fastsim.package = old_fastsim - # @Jack: new setup configuration. In order to run the code in SFS-FastJet mode analysis - # has to be compiled with `-DMA5_FASTJET_MODE` flag but this needs to be deactivated for - # Delphes-ROOT based analyses. - - # Creating executable + # Compile, link and run log.info(" Compiling 'SampleAnalyzer'...") if not jobber.CompileJob(): log.error("job submission aborted.") @@ -531,260 +657,99 @@ def run_SimplifiedFastSim(self, dataset, card, analysislist): if not jobber.LinkJob(): log.error("job submission aborted.") return False - # Running - log.info(" Running 'SampleAnalyzer' over dataset '" + dataset.name + "'...") + + log.info(" Running 'SampleAnalyzer' over dataset '%s'...", dataset.name) log.info(" *******************************************************") if not jobber.RunJob(dataset): - log.error("run over '" + dataset.name + "' aborted.") + log.error("run over '%s' aborted.", dataset.name) return False log.info(" *******************************************************") - if not os.path.isdir(self.dirname + "/Output/SAF/" + dataset.name): - os.mkdir(self.dirname + "/Output/SAF/" + dataset.name) + # Move produced SAF/cutflows/histograms/events into main Output/SAF layout + out_base = Path(self.dirname) / "Output/SAF" / dataset.name + out_base.mkdir(parents=True, exist_ok=True) + + sfs_out_base = run_dir / "Output/SAF" / f"_{dataset.name}" for analysis in analysislist: - if not os.path.isdir( - self.dirname + "/Output/SAF/" + dataset.name + "/" + analysis - ): - os.mkdir(self.dirname + "/Output/SAF/" + dataset.name + "/" + analysis) - if not os.path.isdir( - self.dirname - + "/Output/SAF/" - + dataset.name - + "/" - + analysis - + "/CutFlows" - ): - os.mkdir( - self.dirname - + "/Output/SAF/" - + dataset.name - + "/" - + analysis - + "/Cutflows" - ) - if not os.path.isdir( - self.dirname - + "/Output/SAF/" - + dataset.name - + "/" - + analysis - + "/Histograms" - ): - os.mkdir( - self.dirname - + "/Output/SAF/" - + dataset.name - + "/" - + analysis - + "/Histograms" - ) - if ( - not os.path.isdir( - self.dirname - + "/Output/SAF/" - + dataset.name - + "/" - + analysis - + "/RecoEvents" - ) - and self.main.recasting.store_events - ): - os.mkdir( - self.dirname - + "/Output/SAF/" - + dataset.name - + "/" - + analysis - + "/RecoEvents" - ) - cutflow_list = os.listdir( - self.dirname - + "_SFSRun/Output/SAF/_" - + dataset.name - + "/" - + analysis - + "_0/Cutflows" - ) - histogram_list = os.listdir( - self.dirname - + "_SFSRun/Output/SAF/_" - + dataset.name - + "/" - + analysis - + "_0/Histograms" - ) - # Copy dataset info file - if os.path.isfile( - self.dirname - + "_SFSRun/Output/SAF/_" - + dataset.name - + "/_" - + dataset.name - + ".saf" - ): - shutil.move( - self.dirname - + "_SFSRun/Output/SAF/_" - + dataset.name - + "/_" - + dataset.name - + ".saf", - self.dirname - + "/Output/SAF/" - + dataset.name - + "/" - + dataset.name - + ".saf", - ) - for cutflow in cutflow_list: - shutil.move( - self.dirname - + "_SFSRun/Output/SAF/_" - + dataset.name - + "/" - + analysis - + "_0/Cutflows/" - + cutflow, - self.dirname - + "/Output/SAF/" - + dataset.name - + "/" - + analysis - + "/Cutflows/" - + cutflow, - ) - for histos in histogram_list: - shutil.move( - self.dirname - + "_SFSRun/Output/SAF/_" - + dataset.name - + "/" - + analysis - + "_0/Histograms/" - + histos, - self.dirname - + "/Output/SAF/" - + dataset.name - + "/" - + analysis - + "/Histograms/" - + histos, - ) + dest_analysis = out_base / analysis + (dest_analysis / "Cutflows").mkdir(parents=True, exist_ok=True) + (dest_analysis / "Histograms").mkdir(parents=True, exist_ok=True) if self.main.recasting.store_events: - event_list = os.listdir( - self.dirname - + "_SFSRun/Output/SAF/_" - + dataset.name - + "/lheEvents0_0/" - ) - if len(event_list) > 0: - shutil.move( - self.dirname - + "_SFSRun/Output/SAF/_" - + dataset.name - + "/lheEvents0_0/" - + event_list[0], - self.dirname - + "/Output/SAF/" - + dataset.name - + "/" - + analysis - + "/RecoEvents/" - + event_list[0], - ) - if self.TACO_output != "": + (dest_analysis / "RecoEvents").mkdir(parents=True, exist_ok=True) + + src_analysis_dir = sfs_out_base / f"{analysis}_0" + # Cutflows + src_cutflows = src_analysis_dir / "Cutflows" + if src_cutflows.is_dir(): + for src in src_cutflows.iterdir(): + shutil.move(str(src), str(dest_analysis / "Cutflows" / src.name)) + # Histograms + src_histos = src_analysis_dir / "Histograms" + if src_histos.is_dir(): + for src in src_histos.iterdir(): + shutil.move(str(src), str(dest_analysis / "Histograms" / src.name)) + + # Move event file if any + if self.main.recasting.store_events: + src_event_dir = sfs_out_base / "lheEvents0_0" + if src_event_dir.is_dir(): + # move first event file found + try: + first = next(src_event_dir.iterdir()) + shutil.move( + str(first), + str(dest_analysis / "RecoEvents" / first.name), + ) + except StopIteration: + pass + + # Move dataset .saf if produced + saf_src = sfs_out_base / f"_{dataset.name}.saf" + if saf_src.exists(): + shutil.move(str(saf_src), str(out_base / f"{dataset.name}.saf")) + + # Move TACO_output if requested + if self.TACO_output: + taco_src = run_dir / "Output" / self.TACO_output + if taco_src.exists(): filename = ( ".".join(self.TACO_output.split(".")[:-1]) + "_" - + card.split("/")[-1].replace("ma5", "") + + Path(card).name.replace("ma5", "") + self.TACO_output.split(".")[-1] ) - shutil.move( - self.dirname + "_SFSRun/Output/" + self.TACO_output, - self.dirname + "/Output/SAF/" + dataset.name + "/" + filename, - ) + shutil.move(str(taco_src), str(out_base / filename)) + # Cleanup the SFS run directory unless in developer mode if not self.main.developer_mode: - # Remove the analysis folder - if not FolderWriter.RemoveDirectory( - os.path.normpath(self.dirname + "_SFSRun") - ): - log.error("Cannot remove directory: " + self.dirname + "_SFSRun") + if not FolderWriter.RemoveDirectory(str(run_dir)): + log.error("Cannot remove directory: %s", run_dir) else: - log.debug("Analysis kept in " + self.dirname + "_SFSRun folder.") + log.debug("Analysis kept in %s folder.", run_dir) - if dataset.xsection == 0.0: - dataset.xsection = self.read_xsec( - f"{self.dirname}/Output/SAF/{dataset.name}/{dataset.name}.saf" - ) - log.debug(f"Cross-section has been set to {dataset.xsection} pb.") - - return True - - def generate_events(self, dataset, card): - # Preparing the run - self.main.recasting.status = "off" - self.main.fastsim.package = self.detector - self.main.fastsim.clustering = 0 - if self.detector == "delphesMA5tune": - self.main.fastsim.delphes = 0 - self.main.fastsim.delphesMA5tune = DelphesMA5tuneConfiguration() - self.main.fastsim.delphesMA5tune.card = os.path.normpath( - "../../../../tools/PADForMA5tune/Input/Cards/" + card - ) - elif self.detector == "delphes": - self.main.fastsim.delphesMA5tune = 0 - self.main.fastsim.delphes = DelphesConfiguration() - self.main.fastsim.delphes.card = os.path.normpath( - "../../../../tools/PAD/Input/Cards/" + card - ) - # Execution - if not self.run_delphes(dataset, card): - log.error("The " + self.detector + " problem with the running of the fastsim") - return False - # Restoring the run - self.main.recasting.status = "on" - self.main.fastsim.package = "none" - ## Saving the output - if not os.path.isdir(self.dirname + "/Output/SAF/" + dataset.name): - os.mkdir(self.dirname + "/Output/SAF/" + dataset.name) - if not os.path.isdir( - self.dirname + "/Output/SAF/" + dataset.name + "/RecoEvents" - ): - os.mkdir(self.dirname + "/Output/SAF/" + dataset.name + "/RecoEvents") - if self.detector == "delphesMA5tune": - shutil.move( - self.dirname - + "_RecastRun/Output/SAF/_" - + dataset.name - + "/RecoEvents0_0/DelphesMA5tuneEvents.root", - self.dirname - + "/Output/SAF/" - + dataset.name - + "/RecoEvents/RecoEvents_v1x1_" - + card.replace(".tcl", "") - + ".root", - ) - elif self.detector == "delphes": - shutil.move( - self.dirname - + "_RecastRun/Output/SAF/_" - + dataset.name - + "/RecoEvents0_0/DelphesEvents.root", - self.dirname - + "/Output/SAF/" - + dataset.name - + "/RecoEvents/RecoEvents_v1x2_" - + card.replace(".tcl", "") - + ".root", - ) - ## Exit return True ################################################ ### ANALYSIS EXECUTION ################################################ - def analysis_single(self, version, card): + def analysis_single(self, version: str, card: str) -> bool: + """ + One-line summary + Perform a single analysis version/card recasting including PAD execution and CLs. + + Extended summary + Selects the appropriate detector, prepares analyzer list for the given card, + executes the PAD or SFS runs over all datasets, manages eventfile postprocessing + and optionally triggers CLs computation. + + Args: + version (``str``): PAD version identifier (e.g. 'v1.2'). + card (``str``): Analysis card name. + + Returns: + ``bool``: + True on success for all datasets and CLs calculations, False otherwise. + """ ## Init and header self.analysis_header(version, card) @@ -795,9 +760,7 @@ def analysis_single(self, version, card): return False ## Getting the analyses associated with the given card - analyses = [ - x.replace(version + "_", "") for x in self.analysis_runcard if version in x - ] + analyses = [ana for v, ana in self.analysis_runcard if version == v] for del_card, ana_list in self.main.recasting.DelphesDic.items(): if card == del_card: analyses = [x for x in analyses if x in ana_list] @@ -805,17 +768,9 @@ def analysis_single(self, version, card): # Executing the PAD for myset in self.main.datasets: - xsec_check = True if not self.main.recasting.stat_only_mode: if version in ["v1.1", "v1.2"]: - # os.environ["ROOT_INCLUDE_PATH"] = ":".join(self.delphes_inc_pths) - # os.environ["FASTJET_FLAG"] = "" - if myset.xsection == 0.0: - xsec_check = False - ## Preparing the PAD - self.update_pad_main(analyses) - if not self.make_pad(): - self.main.forced = self.forced + if not self.run_delphes_analysis(myset, card, analyses): return False ## Getting the file name corresponding to the events eventfile = os.path.normpath( @@ -831,10 +786,7 @@ def analysis_single(self, version, card): if not os.path.isfile(eventfile): log.error(f"The file called {eventfile} is not found...") return False - ## Running the PAD - if not self.run_pad(eventfile): - self.main.forced = self.forced - return False + ## Saving the output and cleaning if not self.save_output( '"' + eventfile + '"', myset.name, analyses, card @@ -849,9 +801,7 @@ def analysis_single(self, version, card): # Run SFS if not self.run_SimplifiedFastSim( myset, - self.main.archi_info.ma5dir - + "/tools/PADForSFS/Input/Cards/" - + card, + f"{self.main.archi_info.ma5dir}/tools/PADForSFS/Input/Cards/{card}", analyses, ): return False @@ -859,20 +809,40 @@ def analysis_single(self, version, card): log.warning( "Simplified-FastSim does not use root, hence file will not be stored." ) + + if myset.xsection == 0.0: + myset.xsection = read_xsec( + f"{self.dirname}/Output/SAF/{myset.name}/{myset.name}.saf" + ) + log.debug(f"Cross-section has been set to {myset.xsection} pb.") else: self.dirname = self.main.recasting.stat_only_dir ## Running the CLs exclusion script (if available) - if xsec_check: - if not self.main.recasting.analysis_only_mode: - log.debug(f"Compute CLs exclusion for {myset.name}") - if not self.compute_cls(analyses, myset): - self.main.forced = self.forced - return False + if not self.main.recasting.analysis_only_mode: + log.debug(f"Compute CLs exclusion for {myset.name}") + if not self.compute_cls(analyses, myset): + self.main.forced = self.forced + return False # Exit return True - def analysis_header(self, version, card): + def analysis_header(self, version: str, card: str) -> None: + """ + One-line summary + Log a standardized header for a PAD run. + + Extended summary + Prints a nicely formatted banner with the PAD version and card name to the log. + + Args: + version (``str``): PAD version string. + card (``str``): Card filename or identifier. + + Returns: + ``None``: + Pure logging side-effect. + """ ## Printing log.info(" **********************************************************") log.info( @@ -884,7 +854,23 @@ def analysis_header(self, version, card): log.info(" " + StringTools.Center(card, 57)) log.info(" **********************************************************") - def update_pad_main(self, analysislist): + def update_pad_main(self, analysislist: list[str]) -> bool: + """ + One-line summary + Update the PAD main.cpp for a set of analyzers and copy required analyzer sources. + + Extended summary + Creates/overwrites the analysisList.h and a modified main.cpp inside the RecastRun + directory to register the specified analyzers. Also copies analyzer headers and + sources from the PAD into the run directory. + + Args: + analysislist (``list[str]``): List of analyzer names to include in the PAD run. + + Returns: + ``bool``: + True on success, False if required files are missing or on I/O errors. + """ ## Migrating the necessary files to the working directory log.info(" Writing the PAD analyses") ## Safety (for backwards compatibility) @@ -1009,9 +995,21 @@ def update_pad_main(self, analysislist): time.sleep(1.0) return True - def make_pad(self): + def make_pad(self) -> bool: + """ + One-line summary + Compile the PAD library within the RecastRun build directory. + + Extended summary + Invokes 'make' with an appropriate core count and captures the compilation log. + Returns False if compilation fails. + + Returns: + ``bool``: + True if make succeeded, False otherwise. + """ # Initializing the compiler - log.info(" Compiling the PAD located in " + self.dirname + "_RecastRun") + log.info(" Compiling the PAD located in %s_RecastRun", self.dirname) compiler = LibraryWriter("lib", self.main) ncores = compiler.get_ncores2() # compiling @@ -1034,41 +1032,31 @@ def make_pad(self): return False return True - def run_pad(self, eventfile): - ## input file - if os.path.isfile(self.dirname + "_RecastRun/Input/PADevents.list"): - os.remove(self.dirname + "_RecastRun/Input/PADevents.list") - infile = open(self.dirname + "_RecastRun/Input/PADevents.list", "w") - infile.write(eventfile) - infile.close() - jobber = JobWriter(self.main, self.dirname + "_RecastRun") - if not jobber.WriteMakefiles(ma5_fastjet_mode=False): - return False - ## cleaning the output directory - if os.path.isdir( - os.path.normpath(self.dirname + "_RecastRun/Output/SAF/PADevents") - ): - if not FolderWriter.RemoveDirectory( - os.path.normpath(self.dirname + "_RecastRun/Output/SAF/PADevents") - ): - return False - ## running - command = ["./MadAnalysis5job", "../Input/PADevents.list"] - ok = ShellCommand.Execute(command, self.dirname + "_RecastRun/Build") - ## checks - if not ok: - log.error("Problem with the run of the PAD on the file: %s", eventfile) - return False - os.remove(self.dirname + "_RecastRun/Input/PADevents.list") - ## exit - time.sleep(1.0) - return True - - def save_output(self, eventfile, setname, analyses, card): + def save_output( + self, eventfile: str, setname: str, analyses: list[str], card: str + ) -> bool: + """ + One-line summary + Save and merge produced SAF outputs and move analyzer outputs to the main Output/SAF. + + Extended summary + If the target SAF doesn't exist, moves the produced SAF file; otherwise merges + file entries. Moves analyzer-specific directories and TACO outputs if requested. + + Args: + eventfile (``str``): Event file path string (may include quotes). + setname (``str``): Dataset name. + analyses (``list[str]``): List of analyses to move into Output/SAF. + card (``str``): Card name used to generate TACO outputs. + + Returns: + ``bool``: + True when outputs were moved/merged successfully. + """ outfile = self.dirname + "/Output/SAF/" + setname + "/" + setname + ".saf" if not os.path.isfile(outfile): shutil.move( - self.dirname + "_RecastRun/Output/SAF/PADevents/PADevents.saf", outfile + self.dirname + f"_RecastRun/Output/SAF/_{setname}/_{setname}.saf", outfile ) else: inp = open(outfile, "r") @@ -1110,7 +1098,7 @@ def save_output(self, eventfile, setname, analyses, card): shutil.move(outfile + ".2", outfile) for analysis in analyses: shutil.move( - self.dirname + "_RecastRun/Output/SAF/PADevents/" + analysis + "_0", + self.dirname + f"_RecastRun/Output/SAF/_{setname}/" + analysis + "_0", self.dirname + "/Output/SAF/" + setname + "/" + analysis, ) if self.TACO_output != "": @@ -1130,7 +1118,24 @@ def save_output(self, eventfile, setname, analyses, card): ### CLS CALCULATIONS AND OUTPUT ################################################ - def compute_cls(self, analyses, dataset): + def compute_cls(self, analyses: list[str], dataset: DatasetCollection) -> bool: + """ + One-line summary + Compute CLs exclusion limits for the provided analyses and dataset. + + Extended summary + Validates XML parsing support, writes bibliography, iterates over requested + extrapolated luminosities and analyses, parses analysis info files, reads cutflows, + constructs statistical models and computes limits. Writes results into CLs output files. + + Args: + analyses (``list[str]``): List of analysis names to compute CLs for. + dataset (``DatasetCollection``): Dataset metadata used for the computation. + + Returns: + ``bool``: + True on success for all computations, False on any encountered error. + """ import spey from spey.system.webutils import get_bibtex @@ -1373,6 +1378,18 @@ def compute_cls(self, analyses, dataset): return True def check_xml_scipy_methods(self): + """ + One-line summary + Determine an XML parsing module to use (lxml or xml.etree.ElementTree). + + Extended summary + Tries to import lxml.etree first and falls back to xml.etree.ElementTree. + Logs and returns False if neither is available. + + Returns: + ``module``: + The imported XML module on success, or False on failure. + """ ## Checking XML parsers try: from lxml import ET @@ -1387,7 +1404,26 @@ def check_xml_scipy_methods(self): # exit return ET - def parse_info_file(self, etree, analysis, extrapolated_lumi): + def parse_info_file( + self, etree, analysis: str, extrapolated_lumi: Union[str, float] + ) -> tuple[float, list, dict]: + """ + One-line summary + Parse an analysis .info XML file and extract header information. + + Extended summary + Opens and parses the analysis.info file using the provided etree module and + delegates extraction to header_info_file. Returns (-1,-1,-1) on errors. + + Args: + etree (``module``): XML parsing module (e.g. xml.etree.ElementTree). + analysis (``str``): Analyzer name (without extension) to parse. + extrapolated_lumi (``str`` or ``float``): 'default' or a numeric extrapolated luminosity. + + Returns: + ``tuple``: + (lumi (float), regions (list), regiondata (dict)) on success or (-1,-1,-1) on error. + """ ## Is file existing? filename = ( self.pad + "/Build/SampleAnalyzer/User/Analyzer/" + analysis + ".info" @@ -1412,16 +1448,33 @@ def parse_info_file(self, etree, analysis, extrapolated_lumi): log.warning("Cannot parse the info file") return -1, -1, -1 - def fix_pileup(self, filename): + def fix_pileup(self, filename: str) -> bool: + """ + One-line summary + Ensure Delphes card references point to local PAD pileup files. + + Extended summary + Backs up the provided tcl card, scans for 'set PileUpFile' directives and rewrites + the referenced path to point to the PAD/Input/Pileup directory inside the MA5 installation. + Verifies that the referenced pileup files exist after modification. + + Args: + filename (``str``): Path to the Delphes .tcl card file to fix. + + Returns: + ``bool``: + True if pileup entries were fixed and referenced files exist, False on error. + """ # x - log.debug("delphes card is here: " + filename) + filename = str(filename) + log.debug("delphes card is here: %s", filename) # Container for pileup FoundPileup = [] # Safe if not os.path.isfile(filename): - log.error("internal error: file " + filename + " is not found") + log.error("internal error: file %s is not found", filename) return False # Estimate the newpath of pileup @@ -1465,15 +1518,35 @@ def fix_pileup(self, filename): return True - def header_info_file(self, etree, analysis, extrapolated_lumi): - log.debug("Reading info from the file related to " + analysis + "...") + def header_info_file( + self, etree, analysis: str, extrapolated_lumi: Union[str, float] + ): + """ + One-line summary + Extract header-level information from a parsed analysis info XML tree. + + Extended summary + Validates root tags, extracts the analysis luminosity and region definitions, handles + covariance and pyhf blocks, rescales rates for extrapolated luminosities and + returns (lumi, regions, regiondata). Performs extensive validation and returns -1 triplet on error. + + Args: + etree (``xml.etree.ElementTree.ElementTree``): Parsed XML tree (root accessible via getroot()). + analysis (``str``): Analyzer name (for logging and validation). + extrapolated_lumi (``str`` or ``float``): 'default' or numeric target luminosity for rescaling. + + Returns: + ``tuple``: + (lumi (float), regions (list), regiondata (dict)) on success or (-1,-1,-1) on failure. + """ + log.debug("Reading info from the file related to %s...", analysis) ## checking the header of the file info_root = etree.getroot() if info_root.tag != "analysis": - log.warning("Invalid info file (" + analysis + "): tag.") + log.warning("Invalid info file (%s): tag.", analysis) return -1, -1, -1 if info_root.attrib["id"].lower() != analysis.lower(): - log.warning("Invalid info file (" + analysis + "): tag.") + log.warning("Invalid info file (%s): tag.", analysis) return -1, -1, -1 ## extracting the information lumi = 0 @@ -1676,12 +1749,22 @@ def header_info_file(self, etree, analysis, extrapolated_lumi): return lumi, regions, regiondata - def pyhf_info_file(self, info_root): - """In order to make use of HistFactory, we need some pieces of information. First, - the location of the specific background-only likelihood json files that are given - in the info file. The collection of SR contributing to a given profile must be - provided. One can process multiple likelihood profiles dedicated to different sets - of SRs. + def pyhf_info_file(self, info_root) -> dict: + """ + One-line summary + Extract and validate pyhf-related configuration from an analysis info XML root. + + Extended summary + If blocks are present, attempts to import spey_pyhf, constructs the + HistFactory dictionary and validates likelihood profiles. Returns an empty dict + if pyhf support is missing or validation fails. + + Args: + info_root (``xml.etree.ElementTree.Element``): Root element of the parsed info file. + + Returns: + ``dict``: + A validated pyhf configuration dictionary, or {} if none or invalid. """ self.pyhf_config = {} # reset if any(x.tag == "pyhf" for x in info_root): @@ -1736,7 +1819,23 @@ def pyhf_info_file(self, info_root): return pyhf_config - def write_cls_header(self, xs, out): + def write_cls_header(self, xs: float, out) -> None: + """ + One-line summary + Write the header of a CLs output file depending on whether signal xsec is known. + + Extended summary + Produces a human-readable header describing columns written in CLs output .dat files. + If systematics are configured, the header includes corresponding columns. + + Args: + xs (``float``): Signal cross section, used to select header format. + out (``file``): Open file-like object to write the header into. + + Returns: + ``None``: + Writes into the provided file object. + """ if xs <= 0: log.info( " Signal xsection not defined. The 95% excluded xsection will be calculated." @@ -1785,24 +1884,25 @@ def write_cls_header(self, xs, out): ) out.write("\n") - @staticmethod - def read_xsec(path: str) -> float: - """Read cross section value from SAF file""" - saf_file = Path(path) - if not saf_file.exists(): - return 0.0 - with saf_file.open("r", encoding="utf-8") as f: - smp_info = ( - [ - match.group(1) - for match in re.finditer(r"(.*?)<", f.read(), re.S) - ][0] - .splitlines()[-1] - .split() - ) - return float(smp_info[0]) - - def read_cutflows(self, path, regions, regiondata): + def read_cutflows(self, path: str, regions: list[str], regiondata: dict) -> dict: + """ + One-line summary + Read per-region SAF cutflow files and populate regiondata with initial and final counts. + + Extended summary + For each requested signal region (or combined regions), opens the corresponding .saf + file, extracts initial and final sums of weights and updates regiondata with N0 and Nf. + Returns -1 on any validation or parsing error. + + Args: + path (``str``): Directory containing region .saf cutflow files. + regions (``list[str]``): List of region identifiers to read. + regiondata (``dict``): Pre-initialized region data dictionary to update. + + Returns: + ``dict``: + Updated regiondata on success, or -1 on failure. + """ log.debug("Read the cutflow from the files:") for reg in regions: regname = clean_region_name(reg) @@ -1882,6 +1982,26 @@ def extract_cls( lumi: float, is_extrapolated: bool, ) -> dict: + """ + One-line summary + Compute CLs and related quantities for each region using provided statistical models. + + Extended summary + Uses the different statistical model containers (uncorrelated, simplified, pyhf) + to compute rSR, CLs and mark the best region(s). Also handles covariant subsets and pyhf + results. Returns the enriched regiondata dictionary. + + Args: + regiondata (``dict``): Per-region data with N0/Nf and other entries. + stat_models (``dict``): Statistical model objects keyed by model type. + xsection (``float``): Signal cross section used to compute expected counts. + lumi (``float``): Luminosity used to scale expected signals. + is_extrapolated (``bool``): Whether the computation is for an extrapolated luminosity. + + Returns: + ``dict``: + Updated regiondata with CLs, rSR, best flags and related fields. + """ from .statistical_models import APRIORI, OBSERVED log.debug("Compute CLs...") @@ -1956,7 +2076,29 @@ def extract_cls( def write_cls_output( self, analysis, regions, regiondata, errordata, summary, xsflag, lumi - ): + ) -> None: + """ + One-line summary + Write final CLs tabulated output for each region and optional global results. + + Extended summary + Formats efficiency, statistical and systematic bands, global likelihoods (SL/pyhf) + and writes them into the provided summary file object. When in developer_mode, + optionally dumps json debug files for pyhf. + + Args: + analysis (``str``): Analysis name. + regions (``list[str]``): Ordered list of regions to write. + regiondata (``dict``): Computed per-region results (CLs, N0, Nf, etc.). + errordata (``dict``): Error-variation results keyed by variation names. + summary (``file``): Open file-like object to append the CLs results. + xsflag (``bool``): Indicates whether signal x-section is undefined (True) or present (False). + lumi (``float``): Luminosity used in the computation (fb^-1). + + Returns: + ``None``: + Writes formatted results to 'summary'. + """ log.debug("Write CLs...") if self.main.developer_mode: to_save = {analysis: {"regiondata": regiondata, "errordata": errordata}} @@ -1977,7 +2119,7 @@ def write_cls_output( if self.pyhf_config != {}: iterator = copy.deepcopy(list(self.pyhf_config.items())) for n, (likelihood_profile, config) in enumerate(iterator): - if regiondata.get("pyhf", {}).get(likelihood_profile, False) == False: + if not regiondata.get("pyhf", {}).get(likelihood_profile, False): continue signal = HF_Signal(config, regiondata, xsection=1.0) name = summary.name.split(".dat")[0] @@ -1991,9 +2133,7 @@ def write_cls_output( ["TH_up", "TH_dn", "TH error"], ] for reg in regions: - eff = regiondata[reg]["Nf"] / regiondata[reg]["N0"] - if eff < 0: - eff = 0 + eff = max(regiondata[reg]["Nf"] / regiondata[reg]["N0"], 0.0) stat = round( math.sqrt(eff * (1 - eff) / (abs(regiondata[reg]["N0"]) * lumi)), 10 ) @@ -2003,16 +2143,16 @@ def write_cls_output( syst.append(round(0.5 * (unc[0] + unc[1]) * eff, 8)) else: syst = [0] - myeff = "%.7f" % eff - mystat = "%.7f" % stat - mysyst = ["%.7f" % x for x in syst] + myeff = f"{eff:.7f}" + mystat = f"{stat:.7f}" + mysyst = [f"{x:.7f}" for x in syst] myxsexp = regiondata[reg]["s95exp"] if "s95obs" in list(regiondata[reg].keys()): myxsobs = regiondata[reg]["s95obs"] else: myxsobs = "-1" if not xsflag: - mycls = "%.10f" % regiondata[reg]["CLs"] + mycls = f"{regiondata[reg]['CLs']:.7f}" summary.write( analysis.ljust(30, " ") + reg.ljust(60, " ") @@ -2041,9 +2181,9 @@ def write_cls_output( "".ljust(90, " ") + error_set[2] + " band: [" - + ("%.4f" % min(band)) + + (f"{min(band):.4f}") + ", " - + ("%.4f" % max(band)) + + (f"{max(band):.4f}") + "]\n" ) for i, sys in enumerate(self.main.recasting.systematics): @@ -2241,19 +2381,3 @@ def write_cls_output( + "".ljust(15, " ") ) summary.write("\n") - - -def clean_region_name(mystr): - newstr = mystr.replace("/", "_slash_") - newstr = newstr.replace("->", "_to_") - newstr = newstr.replace(">=", "_greater_than_or_equal_to_") - newstr = newstr.replace(">", "_greater_than_") - newstr = newstr.replace("<=", "_smaller_than_or_equal_to_") - newstr = newstr.replace("<", "_smaller_than_") - newstr = newstr.replace(" ", "_") - newstr = newstr.replace(",", "_") - newstr = newstr.replace("+", "_") - newstr = newstr.replace("-", "_") - newstr = newstr.replace("(", "_lp_") - newstr = newstr.replace(")", "_rp_") - return newstr diff --git a/madanalysis/misc/statistical_models.py b/madanalysis/misc/statistical_models.py index 8663403b..191d39d9 100644 --- a/madanalysis/misc/statistical_models.py +++ b/madanalysis/misc/statistical_models.py @@ -135,10 +135,10 @@ def compute_poi_upper_limits( s95 = -1 if isinf(s95) or isnan(s95) else s95 if record_to is None: logger.debug("region %s s95%s = %.5f pb", reg, label, s95) - regiondata[reg][f"s95{label}"] = f"{s95:20.7f}" + regiondata[reg][f"s95{label}"] = f"{s95:.7f}" else: if reg not in regiondata[record_to]: regiondata[record_to][reg] = {} logger.debug("%s:: region %s s95%s = %.5f pb", record_to, reg, label, s95) - regiondata[record_to][reg][f"s95{label}"] = f"{s95:20.7f}" + regiondata[record_to][reg][f"s95{label}"] = f"{s95:.7f}" return regiondata diff --git a/madanalysis/misc/test_run_recast.py b/madanalysis/misc/test_run_recast.py new file mode 100644 index 00000000..48479357 --- /dev/null +++ b/madanalysis/misc/test_run_recast.py @@ -0,0 +1,168 @@ +# python +import os +import sys +import xml.etree.ElementTree as ET + +import pytest + +# Absolute path to the directory where THIS script lives +script_dir = os.path.dirname(os.path.abspath(__file__)) + +# Build the absolute path to ../../tools/ReportGenerator/Services +relative_path = os.path.join( + script_dir, "..", "..", "tools", "ReportGenerator", "Services" +) +absolute_path = os.path.abspath(relative_path) + +# Add to sys.path +sys.path.append(absolute_path) + +from .run_recast import RunRecast + + +class _DummyRecasting: + def __init__(self): + self.TACO_output = "" + self.ma5tune = False + self.delphes = False + self.global_likelihoods_switch = False + self.systematics = [] + self.extrapolated_luminosities = [] + self.store_events = False + self.store_root = False + self.stat_only_mode = False + self.analysis_only_mode = False + self.error_extrapolation = "sqrt" + + +class _DummyArchi: + def __init__(self, ma5dir): + self.ma5dir = str(ma5dir) + self.has_fastjet = False + self.delphes_inc_paths = [] + self.has_zlib = False + + +class _DummySession: + def __init__(self): + self.editor = "vi" + self.has_simplify = False + + +class _DummyMain: + def __init__(self, ma5dir): + self.forced = False + self.recasting = _DummyRecasting() + self.archi_info = _DummyArchi(ma5dir) + self.session_info = _DummySession() + self.developer_mode = False + # placeholders referenced by code but not used in tests + class _FS: + pass + + self.fastsim = _FS() + self.superfastsim = _FS() + self.datasets = [] + self.script = False + + +def test_fix_pileup_success(tmp_path): + # Setup directories + ma5dir = tmp_path / "ma5" + pad_pileup_dir = ma5dir / "tools" / "PAD" / "Input" / "Pileup" + pad_pileup_dir.mkdir(parents=True, exist_ok=True) + + # Create pileup file in expected new path + pileup_file = pad_pileup_dir / "pileup1.root" + pileup_file.write_text("dummy pileup content") + + # Create a delphes card file with a set PileUpFile line referencing an external path + card_file = tmp_path / "card.tcl" + card_content = ( + "# some header\n" " set PileUpFile /old/location/pileup1.root\n" " other stuff\n" + ) + card_file.write_text(card_content) + + main = _DummyMain(ma5dir) + rc = RunRecast(main, str(tmp_path)) + # default detector -> not delphesMA5tune -> use PAD path + rc.detector = "delphes" + # call fix_pileup + ok = rc.fix_pileup(str(card_file)) + assert ok is True + + # original saved and new file updated + assert (str(card_file) + ".original") and os.path.exists(str(card_file) + ".original") + new_text = card_file.read_text() + assert "PileUpFile" in new_text + # new path should point to our pileup file basename replaced into newpath + assert "Pileup/pileup1.root" in new_text + + +def test_fix_pileup_missing_pileup_returns_false(tmp_path): + # Setup ma5dir but do NOT create pileup file + ma5dir = tmp_path / "ma5" + pad_pileup_dir = ma5dir / "tools" / "PAD" / "Input" / "Pileup" + pad_pileup_dir.mkdir(parents=True, exist_ok=True) + + # Create a delphes card file referencing a pileup that does not exist + card_file = tmp_path / "card2.tcl" + card_content = " set PileUpFile /somewhere/missing.root\n" + card_file.write_text(card_content) + + main = _DummyMain(ma5dir) + rc = RunRecast(main, str(tmp_path)) + rc.detector = "delphes" + ok = rc.fix_pileup(str(card_file)) + assert ok is False + + +def test_check_xml_scipy_methods_returns_et_module(tmp_path): + main = _DummyMain(tmp_path) + rc = RunRecast(main, str(tmp_path)) + ET_module = rc.check_xml_scipy_methods() + # Should return a module (either lxml.etree or xml.etree.ElementTree) + assert ET_module is not False + # Ensure parse works on a simple xml string via a temp file + xml_file = tmp_path / "tmp.xml" + xml_file.write_text("1") + parsed = ET_module.parse(str(xml_file)) + root = parsed.getroot() + assert root.tag == "root" + assert root.find("child").text == "1" + + +def test_parse_info_file_and_header_info_file(tmp_path): + # Create pad analyzer info file structure + pad = tmp_path / "pad" + ana_dir = pad / "Build" / "SampleAnalyzer" / "User" / "Analyzer" + ana_dir.mkdir(parents=True, exist_ok=True) + + info_path = ana_dir / "testana.info" + # simple info xml content with one region + info_xml = ( + '\n' + " 36.1\n" + ' \n' + " 10\n" + " 8\n" + " 1\n" + " \n" + "\n" + ) + info_path.write_text(info_xml) + + main = _DummyMain(tmp_path) + rc = RunRecast(main, str(tmp_path)) + # set rc.pad to our pad directory + rc.pad = str(pad) + + lumi, regions, regiondata = rc.parse_info_file(ET, "testana", "default") + assert isinstance(lumi, float) + assert abs(lumi - 36.1) < 1e-6 + assert regions == ["SR1"] + assert "SR1" in regiondata + # header_info_file stores scaled nobs/nb according to lumi_scaling (default -> unchanged) + assert regiondata["SR1"]["nobs"] == pytest.approx(10.0) + assert regiondata["SR1"]["nb"] == pytest.approx(8.0) + assert regiondata["SR1"]["deltanb"] == pytest.approx(1.0) # python diff --git a/madanalysis/misc/utils.py b/madanalysis/misc/utils.py new file mode 100644 index 00000000..97ddb605 --- /dev/null +++ b/madanalysis/misc/utils.py @@ -0,0 +1,70 @@ +import logging +import os +import re +from pathlib import Path + +log = logging.getLogger("MA5") + + +def get_runs(dirname: str) -> None: + """Retreive analyses from recasting card""" + del_runs = [] + ana_runs = [] + ## decoding the card + card = Path(dirname).joinpath("Input/recasting_card.dat").absolute() + with card.open("r", encoding="utf-8") as f: + for line in f.readlines(): + if len(line.strip()) == 0 or line.strip().startswith("#"): + continue + myline = line.split() + if myline[2].lower() == "on" and (myline[1], myline[3]) not in del_runs: + del_runs.append((myline[1], myline[3])) + if myline[2].lower() == "on": + ana_runs.append((myline[1], myline[0])) + ## saving the information and exti + return del_runs, ana_runs + + +def edit_recasting_card(editor: str, dirname: str) -> None: + """Prompt to edit the recasting card""" + log.info("Would you like to edit the recasting Card ? (Y/N)") + allowed_answers = ["n", "no", "nope", "y", "yes", "yeap"] + answer = "" + while answer not in allowed_answers: + answer = input("Answer: ") + answer = answer.lower() + if answer not in ["no", "n", "nope"]: + os.system(editor + " " + dirname + "/Input/recasting_card.dat") + + +def read_xsec(path: str) -> float: + """Read cross section value from SAF file""" + saf_file = Path(path) + if not saf_file.exists(): + return 0.0 + with saf_file.open("r", encoding="utf-8") as f: + smp_info = ( + [ + match.group(1) + for match in re.finditer(r"(.*?)<", f.read(), re.S) + ][0] + .splitlines()[-1] + .split() + ) + return float(smp_info[0]) + + +def clean_region_name(mystr): + newstr = mystr.replace("/", "_slash_") + newstr = newstr.replace("->", "_to_") + newstr = newstr.replace(">=", "_greater_than_or_equal_to_") + newstr = newstr.replace(">", "_greater_than_") + newstr = newstr.replace("<=", "_smaller_than_or_equal_to_") + newstr = newstr.replace("<", "_smaller_than_") + newstr = newstr.replace(" ", "_") + newstr = newstr.replace(",", "_") + newstr = newstr.replace("+", "_") + newstr = newstr.replace("-", "_") + newstr = newstr.replace("(", "_lp_") + newstr = newstr.replace(")", "_rp_") + return newstr diff --git a/madanalysis/system/architecture_info.py b/madanalysis/system/architecture_info.py index 41f4e264..7c861333 100644 --- a/madanalysis/system/architecture_info.py +++ b/madanalysis/system/architecture_info.py @@ -1,104 +1,107 @@ ################################################################################ -# +# # Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: -# +# # This file is part of MadAnalysis 5. # Official website: -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see -# +# ################################################################################ from __future__ import absolute_import import logging -class ArchitectureInfo: +log = logging.getLogger("MA5") + + +class ArchitectureInfo: def __init__(self): self.ma5_version = "" - self.ma5_date = "" - self.ma5dir = "" + self.ma5_date = "" + self.ma5dir = "" self.platform = "" - self.release = "" + self.release = "" # Main flags self.isMac = False # Is there optional package? - self.has_root = False - self.has_fastjet = False - self.has_fjcontrib = False - self.has_heptoptagger = False - self.has_zlib = False - self.has_delphes = False + self.has_root = False + self.has_fastjet = False + self.has_fjcontrib = False + self.has_heptoptagger = False + self.has_zlib = False + self.has_delphes = False self.has_delphesMA5tune = False self.has_spey = False # Library to put before all the others? - self.root_priority = False - self.zlib_priority = False - self.delphes_priority = False + self.root_priority = False + self.zlib_priority = False + self.delphes_priority = False self.delphesMA5tune_priority = False - self.fastjet_priority = False + self.fastjet_priority = False # Library files - self.zlib_original_libs = [] - self.fastjet_original_bins = [] - self.root_original_bins = [] - self.delphes_original_libs = [] + self.zlib_original_libs = [] + self.fastjet_original_bins = [] + self.root_original_bins = [] + self.delphes_original_libs = [] self.delphesMA5tune_original_libs = [] # Version - self.python_version = "" - self.gcc_version = "" - self.make_version = "" + self.python_version = "" + self.gcc_version = "" + self.make_version = "" self.gfortran_version = "" - self.root_version = "" - self.fastjet_version = "" + self.root_version = "" + self.fastjet_version = "" # Some library information to detect any change - self.libraries = {} - self.headers = {} - self.ncores = 0 + self.libraries = {} + self.headers = {} + self.ncores = 0 # Library to put before all the others - self.toPATH1 = [] + self.toPATH1 = [] self.toLDPATH1 = [] # Library to put after all the others - self.toPATH2 = [] + self.toPATH2 = [] self.toLDPATH2 = [] - self.root_compiler='' - self.root_bin_path="" - self.root_inc_path="" - self.root_lib_path="" - self.root_features=[] - self.zlib_inc_path="" - self.zlib_lib_path="" - self.zlib_lib="" - self.delphes_inc_paths=[] - self.delphes_lib_paths=[] - self.delphes_lib="" - self.delphesMA5tune_inc_paths=[] - self.delphesMA5tune_lib_paths=[] - self.delphesMA5tune_lib="" - self.fastjet_bin_path="" - self.fastjet_lib_paths=[] + self.root_compiler = "" + self.root_bin_path = "" + self.root_inc_path = "" + self.root_lib_path = "" + self.root_features = [] + self.zlib_inc_path = "" + self.zlib_lib_path = "" + self.zlib_lib = "" + self.delphes_inc_paths = [] + self.delphes_lib_paths = [] + self.delphes_lib = "" + self.delphesMA5tune_inc_paths = [] + self.delphesMA5tune_lib_paths = [] + self.delphesMA5tune_lib = "" + self.fastjet_bin_path = "" + self.fastjet_lib_paths = [] # C++ compiler versions self.cpp11 = False @@ -110,82 +113,83 @@ def __init__(self): # 0 = normal, Other possible values: 1, 2, 3 and 4 (4=ultra strict compilation) self.compilation_severity = 0 - def dump(self): for item in self.__dict__: - logging.getLogger('MA5').debug(item+'\t'+str(self.__dict__[item])) - - def __eq__(self,other): - logging.getLogger('MA5').debug("Compare 2 ArchitureInfo objects:") - logging.getLogger('MA5').debug("The current one (number of items="+str(len(self.__dict__))+"):") - logging.getLogger('MA5').debug(str(self.__dict__)) - logging.getLogger('MA5').debug("The other one (number of items="+str(len(other.__dict__))+"):") - logging.getLogger('MA5').debug(str(other.__dict__)) + log.debug(item + "\t" + str(self.__dict__[item])) + + def __eq__(self, other): + log.debug("Compare 2 ArchitureInfo objects:") + log.debug("The current one (number of items=" + str(len(self.__dict__)) + "):") + log.debug(str(self.__dict__)) + log.debug("The other one (number of items=" + str(len(other.__dict__)) + "):") + log.debug(str(other.__dict__)) items_ok = list(self.__dict__.keys()) == list(other.__dict__.keys()) if not items_ok: diff = list(set(self.__dict__.keys()) - set(other.__dict__.keys())) - logging.getLogger('MA5').debug("The comparison of categories -> differences detected: "+str(diff)) + log.debug( + "The comparison of categories -> differences detected: " + str(diff) + ) return False - logging.getLogger('MA5').debug("The comparison of categorie names -> OK") - logging.getLogger('MA5').debug("The comparison of categorie values:") - diff=False + log.debug("The comparison of categorie names -> OK") + log.debug("The comparison of categorie values:") + diff = False for key in self.__dict__.keys(): if self.__dict__[key] != other.__dict__[key]: - logging.getLogger('MA5').debug(" -> difference here: "+str(key)) - diff=True + log.debug(" -> difference here: " + str(key)) + diff = True if not diff: - logging.getLogger('MA5').debug(" -> OK") + log.debug(" -> OK") - return self.__dict__==other.__dict__ + return self.__dict__ == other.__dict__ - def __neq__(self,other): + def __neq__(self, other): return not self.__eq__(other) - def save(self,filename): + def save(self, filename): # Open the file try: - file = open(filename,"wb") + file = open(filename, "wb") except: - logging.getLogger('MA5').error("impossible to write the configuration file '" + \ - filename + "'") + log.error("impossible to write the configuration file '" + filename + "'") return False # Dump data import pickle + try: - pickle.dump(self,file) - test=True + pickle.dump(self, file) + test = True except: - logging.getLogger('MA5').error("error occured during saving data to "+filename) - test=False + log.error("error occured during saving data to " + filename) + test = False # Close the file file.close() # Return the operation status return test - - def load(self,filename): + + def load(self, filename): # Open the file try: - file = open(filename,"rb") + file = open(filename, "rb") except: - logging.getLogger('MA5').error("impossible to read the configuration file '" + \ - filename + "'") + log.error("impossible to read the configuration file '" + filename + "'") return False # Import data import pickle + try: newone = pickle.load(file) - test=True + test = True except Exception as error: if __debug__: - print('PICKLE ERROR:', error) - logging.getLogger('MA5').error("error occured during reading data from "+filename) - test=False + print("PICKLE ERROR:", error) + log.error("error occured during reading data from " + filename) + test = False # Close the file file.close() @@ -195,16 +199,16 @@ def load(self,filename): # Fill the class variables import copy + try: for item in self.__dict__: - self.__dict__[item]=copy.copy(newone.__dict__[item]) + self.__dict__[item] = copy.copy(newone.__dict__[item]) except: - logging.getLogger('MA5').error("error occured during copying data from "+filename) - test=False + log.error("error occured during copying data from " + filename) + test = False # Return the operation status return test def Compare(self, other): - return self==other - + return self == other diff --git a/madanalysis/system/detect_root.py b/madanalysis/system/detect_root.py index 9fc14b55..8e48a5fb 100644 --- a/madanalysis/system/detect_root.py +++ b/madanalysis/system/detect_root.py @@ -1,59 +1,56 @@ ################################################################################ -# +# # Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: -# +# # This file is part of MadAnalysis 5. # Official website: -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see -# +# ################################################################################ from __future__ import absolute_import + import logging -import glob import os -import sys -import re -import platform -from shell_command import ShellCommand -from madanalysis.enumeration.detect_status_type import DetectStatusType + import six +from shell_command import ShellCommand +from madanalysis.enumeration.detect_status_type import DetectStatusType -class DetectRoot: - def __init__(self,archi_info, user_info, session_info, debug): - self.archi_info = archi_info - self.user_info = user_info +class DetectRoot: + def __init__(self, archi_info, user_info, session_info, debug): + self.archi_info = archi_info + self.user_info = user_info self.session_info = session_info - self.debug = debug - self.name = 'Root' + self.debug = debug + self.name = "Root" self.mandatory = False - self.force = False - self.bin_file = '' - self.bin_path = '' - self.inc_path = '' - self.lib_path = '' + self.force = False + self.bin_file = "" + self.bin_path = "" + self.inc_path = "" + self.lib_path = "" self.libraries = {} - self.features = [] - self.compiler = '' - self.version = [] - self.logger = logging.getLogger('MA5') - + self.features = [] + self.compiler = "" + self.version = [] + self.logger = logging.getLogger("MA5") def IsItVetoed(self): if self.user_info.root_veto: @@ -63,138 +60,160 @@ def IsItVetoed(self): self.logger.debug("no user veto") return False - def ManualDetection(self): - msg = '' + msg = "" # User setting - if self.user_info.root_bin==None: + if self.user_info.root_bin == None: return DetectStatusType.UNFOUND, msg self.logger.debug("User setting: root bin path is specified.") - folder=os.path.normpath(self.user_info.root_bin) - self.logger.debug("root-config program found in: "+folder) + folder = os.path.normpath(self.user_info.root_bin) + self.logger.debug("root-config program found in: " + folder) # Detection of root-config self.logger.debug("Detecting root-config in the path specified by the user ...") - if not os.path.isfile(folder+'/root-config'): - msg = "root-config program is not found in folder: "+folder+"\n" + if not os.path.isfile(folder + "/root-config"): + msg = "root-config program is not found in folder: " + folder + "\n" msg += "Please check that ROOT is properly installed." return DetectStatusType.UNFOUND, msg # Ok - self.bin_path=folder - self.bin_file=folder+'/root-config' - self.logger.debug("root-config program found in: "+self.bin_path) + self.bin_path = folder + self.bin_file = folder + "/root-config" + self.logger.debug("root-config program found in: " + self.bin_path) return DetectStatusType.FOUND, msg def ToolsDetection(self): - msg = '' + msg = "" # Detection of root-config self.logger.debug("Detecting root-config in the tools folder ...") - folder = os.path.normpath(self.archi_info.ma5dir+'/tools/root/bin') - if not os.path.isfile(folder+'/root-config'): - msg = "root-config program is not found in folder: "+folder+"\n" + folder = os.path.normpath(self.archi_info.ma5dir + "/tools/root/bin") + if not os.path.isfile(folder + "/root-config"): + msg = "root-config program is not found in folder: " + folder + "\n" msg += "Please check that ROOT is properly installed." return DetectStatusType.UNFOUND, msg # Ok - self.bin_path=folder - self.bin_file=folder+'/root-config' + self.bin_path = folder + self.bin_file = folder + "/root-config" return DetectStatusType.FOUND, msg - def AutoDetection(self): - msg = '' + msg = "" # Trying to call root-config with which - result = ShellCommand.Which('root-config', mute = True) - if len(result)==0: - msg = 'ROOT module called "root-config" is not detected.\n'\ - +'Two explanations :n'\ - +' - ROOT is not installed. You can download it '\ - +'from http://root.cern.ch\n'\ - +' - ROOT binary folder must be placed in the '\ - +'global environment variable $PATH' + result = ShellCommand.Which("root-config", mute=True) + if len(result) == 0: + msg = ( + 'ROOT module called "root-config" is not detected.\n' + + "Two explanations :n" + + " - ROOT is not installed. You can download it " + + "from http://root.cern.ch\n" + + " - ROOT binary folder must be placed in the " + + "global environment variable $PATH" + ) return DetectStatusType.UNFOUND, msg islink = os.path.islink(result[0]) if not islink: - self.bin_file=os.path.normpath(result[0]) + self.bin_file = os.path.normpath(result[0]) else: - self.bin_file=os.path.normpath(os.path.realpath(result[0])) - self.bin_path=os.path.dirname(self.bin_file) + self.bin_file = os.path.normpath(os.path.realpath(result[0])) + self.bin_path = os.path.dirname(self.bin_file) # Debug mode if self.debug: - self.logger.debug(" which: " + str(result[0]) + " [is it a link? "+str(islink)+"]") + self.logger.debug( + " which: " + + str(result[0]) + + " [is it a link? " + + str(islink) + + "]" + ) if islink: - self.logger.debug(" -> "+os.path.realpath(result[0])) + self.logger.debug(" -> " + os.path.realpath(result[0])) # Which all if self.debug: - result = ShellCommand.Which('root-config',all=True,mute=True) - if len(result)==0: - msg = 'ROOT module called "root-config" is not detected.\n'\ - +'Two explanations :n'\ - +' - ROOT is not installed. You can download it '\ - +'from http://root.cern.ch\n'\ - +' - ROOT binary folder must be placed in the '\ - +'global environment variable $PATH' + result = ShellCommand.Which("root-config", all=True, mute=True) + if len(result) == 0: + msg = ( + 'ROOT module called "root-config" is not detected.\n' + + "Two explanations :n" + + " - ROOT is not installed. You can download it " + + "from http://root.cern.ch\n" + + " - ROOT binary folder must be placed in the " + + "global environment variable $PATH" + ) DetectStatusType.ISSUE, msg self.logger.debug(" which-all: ") for file in result: - self.logger.debug(" - "+str(file)) + self.logger.debug(" - " + str(file)) return DetectStatusType.FOUND, msg - def ExtractInfo(self): # Using root-config for getting lib and header paths as well as the version number - self.logger.debug("Trying to get library and header paths ...") - theCommands = [self.bin_path+'/root-config','--libdir','--incdir', '--version'] - ok, out, err = ShellCommand.ExecuteWithCapture(theCommands,'./') + self.logger.debug("Trying to get library and header paths ...") + theCommands = [ + self.bin_path + "/root-config", + "--libdir", + "--incdir", + "--version", + ] + ok, out, err = ShellCommand.ExecuteWithCapture(theCommands, "./") if not ok: - msg = 'ROOT module called "root-config" is not detected.\n'\ - +'Two explanations :n'\ - +' - ROOT is not installed. You can download it '\ - +'from http://root.cern.ch\n'\ - +' - ROOT binary folder must be placed in the '\ - +'global environment variable $PATH' - return False,msg + msg = ( + 'ROOT module called "root-config" is not detected.\n' + + "Two explanations :n" + + " - ROOT is not installed. You can download it " + + "from http://root.cern.ch\n" + + " - ROOT binary folder must be placed in the " + + "global environment variable $PATH" + ) + return False, msg # Extracting ROOT library and header path - out=out.lstrip() - out=out.rstrip() + out = out.lstrip() + out = out.rstrip() root_tmp = out.split() - self.version = root_tmp[2].replace('/','.').split('.') + self.version = root_tmp[2].replace("/", ".").split(".") self.inc_path = os.path.normpath(root_tmp[1]) self.lib_path = os.path.normpath(root_tmp[0]) self.logger.debug("-> root-config found") - self.logger.debug("-> root version: "+'.'.join(self.version)) - self.logger.debug("-> root header folder: "+self.inc_path) - self.logger.debug("-> root library folder: "+self.lib_path) + self.logger.debug("-> root version: " + ".".join(self.version)) + self.logger.debug("-> root header folder: " + self.inc_path) + self.logger.debug("-> root library folder: " + self.lib_path) # Check: looking for files - FilesToFind=[os.path.normpath(self.lib_path+'/libCore.so'), \ - os.path.normpath(self.inc_path+'/TH1F.h')] + FilesToFind = [ + os.path.normpath(self.lib_path + "/libCore.so"), + os.path.normpath(self.inc_path + "/TH1F.h"), + ] for file in FilesToFind: - self.logger.debug("Try to find "+file+" ...") + self.logger.debug("Try to find " + file + " ...") if os.path.isfile(file): - self.libraries[file.split('/')[-1]]=file+":"+str(os.stat(file).st_mtime) + self.libraries[file.split("/")[-1]] = ( + file + ":" + str(os.stat(file).st_mtime) + ) else: - msg = "ROOT file called '"+file+"' is not found\n"\ - + "Please check that ROOT is properly installed." - return False,msg + msg = ( + "ROOT file called '" + + file + + "' is not found\n" + + "Please check that ROOT is properly installed." + ) + return False, msg # Getting the features - theCommands = [self.bin_path+'/root-config','--features'] - ok, out, err = ShellCommand.ExecuteWithCapture(theCommands,'./') + theCommands = [self.bin_path + "/root-config", "--features"] + ok, out, err = ShellCommand.ExecuteWithCapture(theCommands, "./") if not ok: - self.logger.error('problem with root-config') + self.logger.error("problem with root-config") return False - out=out.lstrip() - out=out.rstrip() + out = out.lstrip() + out = out.rstrip() features = str(out).split() features.sort() for feature in features: @@ -203,13 +222,13 @@ def ExtractInfo(self): self.logger.debug(" features: " + str(self.features)) # Getting the compiler - theCommands = [self.bin_path+'/root-config','--cxx'] - ok, out, err = ShellCommand.ExecuteWithCapture(theCommands,'./') + theCommands = [self.bin_path + "/root-config", "--cxx"] + ok, out, err = ShellCommand.ExecuteWithCapture(theCommands, "./") if not ok: - self.logger.error('impossible to get C++ compiler from root-config') + self.logger.error("impossible to get C++ compiler from root-config") return False - out=out.lstrip() - out=out.rstrip() + out = out.lstrip() + out = out.rstrip() self.compiler = out if self.debug: self.logger.debug(" C++ compiler: " + str(self.compiler)) @@ -217,29 +236,25 @@ def ExtractInfo(self): # Ok return True - def SaveInfo(self): # archi_info - self.archi_info.has_root = True - self.archi_info.root_priority = self.force - self.archi_info.root_version = self.version - self.archi_info.root_bin_path = self.bin_path + self.archi_info.has_root = True + self.archi_info.root_priority = self.force + self.archi_info.root_version = self.version + self.archi_info.root_bin_path = self.bin_path self.archi_info.root_original_bins = [self.bin_file] - self.archi_info.root_inc_path = self.inc_path - self.archi_info.root_lib_path = self.lib_path - self.archi_info.root_compiler = self.compiler - + self.archi_info.root_inc_path = self.inc_path + self.archi_info.root_lib_path = self.lib_path + self.archi_info.root_compiler = self.compiler for k, v in six.iteritems(self.libraries): - self.archi_info.libraries[k]=v + self.archi_info.libraries[k] = v for feature in self.features: if not feature in self.archi_info.root_features: self.archi_info.root_features.append(feature) # Adding ROOT library path to Python path -# sys.path.append(self.archi_info.root_lib_path) + # sys.path.append(self.archi_info.root_lib_path) # Ok return True - - diff --git a/tools/SampleAnalyzer/Commons/Base/HistoStructures.h b/tools/SampleAnalyzer/Commons/Base/HistoStructures.h new file mode 100644 index 00000000..8c0281d2 --- /dev/null +++ b/tools/SampleAnalyzer/Commons/Base/HistoStructures.h @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef BASICS_h +#define BASICS_h + +#include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" + +namespace MA5 +{ + struct ENTRIES + { + MAint32 positive = 0; + MAint32 negative = 0; + }; + + struct WEIGHTS + { + MAdouble64 positive = 0.0; + MAdouble64 negative = 0.0; + }; +} + +#endif \ No newline at end of file diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h index 6234b7b2..e5900b16 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCEventFormat.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef MCEventFormat_h #define MCEventFormat_h - // STL headers #include #include @@ -37,206 +35,205 @@ #include "SampleAnalyzer/Commons/DataFormat/WeightCollection.h" #include "SampleAnalyzer/Commons/Service/LogService.h" - namespace MA5 { -class LHEReader; -class LHCOReader; -class STDHEPreader; -class HEPMCReader; -class LHEWriter; -class ROOTReader; -class DelphesTreeReader; -class DelphesMA5tuneTreeReader; - -class MCEventFormat -{ - friend class LHEReader; - friend class LHCOReader; - friend class STDHEPreader; - friend class HEPMCReader; - friend class ROOTReader; - friend class LHEWriter; - friend class DelphesTreeReader; - friend class DelphesMA5tuneTreeReader; - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private : - - MAuint32 processId_; /// identity of the current process - mutable MAfloat64 weight_; /// event weight - MAfloat64 scale_; /// scale Q of the event - MAfloat64 alphaQED_; /// ALPHA_em value used - MAfloat64 alphaQCD_; /// ALPHA_s value used - MAfloat64 PDFscale_; /// scale for PDF - std::pair x_; /// x values - std::pair xpdf_; /// xpdf values - - /// List of generated particles - std::vector particles_; - - /// Computed Missing Transverse Energy - MCParticleFormat MET_; - - /// Computed Missing Hadronic Transverse Energy - MCParticleFormat MHT_; - - /// Computed Scalar sum of transverse energy - MAfloat64 TET_; - - /// Computed Scalar sum of hadronic transverse energy - MAfloat64 THT_; - - /// Computed total effective mass (sum of jet's PT + MET - MAfloat64 Meff_; - - /// List of weights - WeightCollection multiweights_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor withtout arguments - MCEventFormat() - { - processId_=0; - weight_=1.; - scale_=0.; - alphaQED_=0.; - alphaQCD_=0.; - TET_ = 0.; - THT_ = 0.; - Meff_= 0.; - } - - /// Destructor - ~MCEventFormat() - { } - - /// Accessor to the Missing Transverse Energy (read-only) - const MCParticleFormat& MET() const {return MET_;} - - /// Accessor to the Missing Hadronic Transverse Energy (read-only) - const MCParticleFormat& MHT() const {return MHT_;} - - /// Accessor to the Total Transverse Energy (read-only) - const MAfloat64& TET() const {return TET_;} - - /// Accessor to the Total Hadronic Transverse Energy (read-only) - const MAfloat64& THT() const {return THT_;} - - /// Accessor to the Total effective mass (read-only) - const MAfloat64& Meff() const {return Meff_;} - - /// Accessor to the Missing Transverse Energy - MCParticleFormat& MET() {return MET_;} - - /// Accessor to the Missing Hadronic Transverse Energy - MCParticleFormat& MHT() {return MHT_;} - - /// Accessor to the Total Transverse Energy - MAfloat64& TET() {return TET_;} - - /// Accessor to the Total Hadronic Transverse Energy - MAfloat64& THT() {return THT_;} - - /// Accessor to the Total effective mass - MAfloat64& Meff() {return Meff_;} - - /// Accessor to the process identity - const MAuint32& processId() const {return processId_;} - - /// Accessor to the event weight - const MAfloat64& weight() const {return weight_; } - - /// Accessor to the scale - const MAfloat64& scale() const {return scale_; } - - /// Accessor to alpha_QED - const MAfloat64& alphaQED() const {return alphaQED_; } - - /// Accessor to alpha_QCD - const MAfloat64& alphaQCD() const {return alphaQCD_; } - - /// Accessor to multiweights - const WeightCollection& multiweights() const {return multiweights_; } - - /// Accessor to multiweights - WeightCollection& multiweights() {return multiweights_; } - - /// Accessor to multiweights - const MAfloat64& multiweights(MAuint32 weight) const {return multiweights_[weight]; } - - /// Accessor to the generated particle collection (read-only) - const std::vector& particles() const {return particles_;} - - /// Accessor to the generated particle collection - std::vector& particles() {return particles_;} + class LHEReader; + class LHCOReader; + class STDHEPreader; + class HEPMCReader; + class LHEWriter; + class ROOTReader; + class DelphesTreeReader; + class DelphesMA5tuneTreeReader; + + class MCEventFormat + { + friend class LHEReader; + friend class LHCOReader; + friend class STDHEPreader; + friend class HEPMCReader; + friend class ROOTReader; + friend class LHEWriter; + friend class DelphesTreeReader; + friend class DelphesMA5tuneTreeReader; + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + MAuint32 processId_; /// identity of the current process + // mutable MAfloat64 weight_; /// event weight + MAfloat64 scale_; /// scale Q of the event + MAfloat64 alphaQED_; /// ALPHA_em value used + MAfloat64 alphaQCD_; /// ALPHA_s value used + MAfloat64 PDFscale_; /// scale for PDF + std::pair x_; /// x values + std::pair xpdf_; /// xpdf values + + /// List of generated particles + std::vector particles_; + + /// Computed Missing Transverse Energy + MCParticleFormat MET_; + + /// Computed Missing Hadronic Transverse Energy + MCParticleFormat MHT_; - /// Setting the process identity - void setProcessId(MAuint32 v) {processId_=v;} + /// Computed Scalar sum of transverse energy + MAfloat64 TET_; - /// Setting the event weight - void setWeight (MAfloat64 v) const {weight_=v; } + /// Computed Scalar sum of hadronic transverse energy + MAfloat64 THT_; - /// Setting the scale - void setScale (MAfloat64 v) {scale_=v; } + /// Computed total effective mass (sum of jet's PT + MET + MAfloat64 Meff_; - /// Setting AlphaQED - void setAlphaQED (MAfloat64 v) {alphaQED_=v; } + /// List of weights + WeightCollection multiweights_; - /// Setting AlphaQCD - void setAlphaQCD (MAfloat64 v) {alphaQCD_=v; } + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor withtout arguments + MCEventFormat() + { + processId_ = 0; + scale_ = 0.; + alphaQED_ = 0.; + alphaQCD_ = 0.; + TET_ = 0.; + THT_ = 0.; + Meff_ = 0.; + multiweights_.clear(); + } + + /// Destructor + ~MCEventFormat() {} + + /// Accessor to the Missing Transverse Energy (read-only) + const MCParticleFormat &MET() const { return MET_; } + + /// Accessor to the Missing Hadronic Transverse Energy (read-only) + const MCParticleFormat &MHT() const { return MHT_; } + + /// Accessor to the Total Transverse Energy (read-only) + const MAfloat64 &TET() const { return TET_; } + + /// Accessor to the Total Hadronic Transverse Energy (read-only) + const MAfloat64 &THT() const { return THT_; } + + /// Accessor to the Total effective mass (read-only) + const MAfloat64 &Meff() const { return Meff_; } + + /// Accessor to the Missing Transverse Energy + MCParticleFormat &MET() { return MET_; } + + /// Accessor to the Missing Hadronic Transverse Energy + MCParticleFormat &MHT() { return MHT_; } + + /// Accessor to the Total Transverse Energy + MAfloat64 &TET() { return TET_; } + + /// Accessor to the Total Hadronic Transverse Energy + MAfloat64 &THT() { return THT_; } + + /// Accessor to the Total effective mass + MAfloat64 &Meff() { return Meff_; } + + /// Accessor to the process identity + const MAuint32 &processId() const { return processId_; } + + /// Accessor to the event weight + const MAfloat64 &weight() const { return multiweights_.Get(0); } + + /// Accessor to the scale + const MAfloat64 &scale() const { return scale_; } + + /// Accessor to alpha_QED + const MAfloat64 &alphaQED() const { return alphaQED_; } + + /// Accessor to alpha_QCD + const MAfloat64 &alphaQCD() const { return alphaQCD_; } + + /// Accessor to multiweights + WeightCollection &weights() { return multiweights_; } + + /// Accessor to multiweights + const WeightCollection &weights() const { return multiweights_; } + + /// Accessor to multiweights + const MAfloat64 &GetWeight(MAuint32 id) const { return multiweights_.Get(id); } + + /// Accessor to the generated particle collection (read-only) + const std::vector &particles() const { return particles_; } - /// Clearing all information - void Reset() - { - processId_=0; weight_=1.; - scale_=0.; alphaQED_=0.; alphaQCD_=0.; - particles_.clear(); - multiweights_.Reset(); - MET_.Reset(); - MHT_.Reset(); - TET_ = 0.; - THT_ = 0.; - Meff_ = 0.; - } + /// Accessor to the generated particle collection + std::vector &particles() { return particles_; } - /// Displaying data member values - void Print() const - { - INFO << "nparts=" << particles_.size() - << " - processId=" << processId_ - << " - weight=" << weight_ - << " - scale=" << scale_ - << " - alphaQED=" << alphaQED_ - << " - alphaQCD=" << alphaQCD_ << endmsg; - INFO << "nweights=" << multiweights_.size() << endmsg; - } + /// Setting the process identity + void setProcessId(MAuint32 v) { processId_ = v; } + + /// Setting the event weight + void setWeight(MAuint32 id, MAfloat64 value) { multiweights_.Add(id, value); } + + /// Setting the event weight + void setWeights(std::vector &v) { multiweights_.SetWeights(v); } + + /// Setting the scale + void setScale(MAfloat64 v) { scale_ = v; } + + /// Setting AlphaQED + void setAlphaQED(MAfloat64 v) { alphaQED_ = v; } + + /// Setting AlphaQCD + void setAlphaQCD(MAfloat64 v) { alphaQCD_ = v; } + + /// Clearing all information + void Reset() + { + processId_ = 0; + scale_ = 0.; + alphaQED_ = 0.; + alphaQCD_ = 0.; + particles_.clear(); + multiweights_.Reset(); + MET_.Reset(); + MHT_.Reset(); + TET_ = 0.; + THT_ = 0.; + Meff_ = 0.; + } - /// Displaying data - void PrintVertices() const; + /// Displaying data member values + void Print() const + { + INFO << "nparts=" << particles_.size() + << " - processId=" << processId_ + << " - weight=" << multiweights_.Get(0) + << " - scale=" << scale_ + << " - alphaQED=" << alphaQED_ + << " - alphaQCD=" << alphaQCD_ << endmsg; + INFO << "nweights=" << multiweights_.size() << endmsg; + } - /// Displaying mothers - void PrintMothers() const; + /// Displaying data + void PrintVertices() const; - /// Displaying daughters - void PrintDaughters() const; + /// Displaying mothers + void PrintMothers() const; - /// Giving a new particle - MCParticleFormat* GetNewParticle() - { - particles_.push_back(MCParticleFormat()); - return &particles_.back(); - } + /// Displaying daughters + void PrintDaughters() const; -}; + /// Giving a new particle + MCParticleFormat *GetNewParticle() + { + particles_.push_back(MCParticleFormat()); + return &particles_.back(); + } + }; } diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h index 4a202bfe..522ba187 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCSampleFormat.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef MCSAMPLE_DATAFORMAT_H #define MCSAMPLE_DATAFORMAT_H - // STL headers #include #include @@ -38,7 +36,6 @@ #include "SampleAnalyzer/Commons/DataFormat/WeightDefinition.h" #include "SampleAnalyzer/Commons/Service/LogService.h" - namespace MA5 { @@ -51,7 +48,6 @@ namespace MA5 class LHEWriter; class SampleAnalyzer; - class MCSampleFormat { friend class LHEReader; @@ -63,182 +59,160 @@ namespace MA5 friend class STDHEPReader; friend class STDHEPreader; - // ------------------------------------------------------------- // data members // ------------------------------------------------------------- private: - // ---------------------- physics info ------------------------- - std::pair beamPDGID_; - std::pair beamE_; - std::pair beamPDFauthor_; - std::pair beamPDFID_; - MAint32 weightMode_; - std::vector processes_; - const MA5GEN::GeneratorType* sample_generator_; - MAfloat32 length_unit_; /// Length unit: mm=1 cm=0.1 - MAfloat32 energy_unit_; /// Energy unit: GeV=1 MeV=0.001 keV=0.000001 + std::pair beamPDGID_; + std::pair beamE_; + std::pair beamPDFauthor_; + std::pair beamPDFID_; + MAint32 weightMode_; + std::vector processes_; + const MA5GEN::GeneratorType *sample_generator_; + MAfloat32 length_unit_; /// Length unit: mm=1 cm=0.1 + MAfloat32 energy_unit_; /// Energy unit: GeV=1 MeV=0.001 keV=0.000001 // ----------------------- multiweights ------------------------ - WeightDefinition weight_definition_; + /// @brief store weight names + std::map weight_names_; // ----------------------- file info --------------------------- MAfloat64 xsection_; MAfloat64 xsection_error_; - MAfloat64 sumweight_positive_; // all events with positive weights - MAfloat64 sumweight_negative_; // all events with negative weights - + MAfloat64 sumweight_positive_; // all events with positive weights + MAfloat64 sumweight_negative_; // all events with negative weights // ------------------------------------------------------------- // method members // ------------------------------------------------------------- - public : - + public: /// Constructor withtout arguments - MCSampleFormat(const MA5GEN::GeneratorType* gen) + MCSampleFormat(const MA5GEN::GeneratorType *gen) { - sample_generator_=gen; + sample_generator_ = gen; Reset(); } /// Destructor - ~MCSampleFormat() - { } + ~MCSampleFormat() {} /// Clear all the content void Reset() { // Physics info - beamPDGID_ = std::make_pair(0,0); - beamE_ = std::make_pair(0,0); - beamPDFauthor_ = std::make_pair(0,0); - beamPDFID_ = std::make_pair(0,0); - weightMode_ = 0; + beamPDGID_ = std::make_pair(0, 0); + beamE_ = std::make_pair(0, 0); + beamPDFauthor_ = std::make_pair(0, 0); + beamPDFID_ = std::make_pair(0, 0); + weightMode_ = 0; processes_.clear(); length_unit_ = 1.0; energy_unit_ = 1.0; - // WeightDefinition - weight_definition_.Reset(); + weight_names_.clear(); // File info - xsection_ = 0.; - xsection_error_ = 0.; + xsection_ = 0.; + xsection_error_ = 0.; sumweight_positive_ = 0.; sumweight_negative_ = 0.; } /// Accessoir to the generator type - const MA5GEN::GeneratorType* GeneratorType() const - { return sample_generator_; } + const MA5GEN::GeneratorType *GeneratorType() const { return sample_generator_; } /// Accessor to PDG ID of the intial partons - const std::pair& beamPDGID() const - { return beamPDGID_; } + const std::pair &beamPDGID() const { return beamPDGID_; } /// Accessor to the beam energy - const std::pair& beamE() const - { return beamE_; } + const std::pair &beamE() const { return beamE_; } /// Accessor to the PDF authors - const std::pair& beamPDFauthor() const - { return beamPDFauthor_; } + const std::pair &beamPDFauthor() const { return beamPDFauthor_; } /// Accessor to the PDF identity - const std::pair& beamPDFID() const - { return beamPDFID_; } + const std::pair &beamPDFID() const { return beamPDFID_; } /// Accessor to the weight mode - const MAint32& weightMode() const - { return weightMode_; } + const MAint32 &weightMode() const { return weightMode_; } /// Accessor to the xsection mean - const MAfloat64& xsection() const - { return xsection_; } + const MAfloat64 &xsection() const { return xsection_; } /// Accessor to the xsection mean - const MAfloat64& xsection_mean() const - { return xsection_; } + const MAfloat64 &xsection_mean() const { return xsection_; } /// Accessor to the xsection error - const MAfloat64& xsection_error() const - { return xsection_error_; } + const MAfloat64 &xsection_error() const { return xsection_error_; } /// Accessor to the number of events with positive weight - const MAfloat64& sumweight_positive() const - { return sumweight_positive_; } + const MAfloat64 &sumweight_positive() const { return sumweight_positive_; } /// Accessor to the number of events with negative weight - const MAfloat64& sumweight_negative() const - { return sumweight_negative_; } + const MAfloat64 &sumweight_negative() const { return sumweight_negative_; } /// Accessor to the process collection (read-only) - const std::vector& processes() const - { return processes_; } + const std::vector &processes() const { return processes_; } /// Accessor to the process collection - std::vector& processes() - { return processes_; } - - /// Accessor to the weight definition (read-only) - const WeightDefinition& weight_definition() const - { return weight_definition_; } - - /// Accessor to the weight definition - WeightDefinition& weight_definition() - { return weight_definition_; } + std::vector &processes() { return processes_; } /// Set the PDG ID of the intial partons - void setBeamPDGID(MAint32 a, MAint32 b) - {beamPDGID_=std::make_pair(a,b); } + void setBeamPDGID(MAint32 a, MAint32 b) { beamPDGID_ = std::make_pair(a, b); } /// Set the beam energy - void setBeamE(MAfloat64 a, MAfloat64 b) - {beamE_=std::make_pair(a,b); } + void setBeamE(MAfloat64 a, MAfloat64 b) { beamE_ = std::make_pair(a, b); } /// Set the PDF authors - void setBeamPDFauthor(MAuint32 a, MAuint32 b) - {beamPDFauthor_=std::make_pair(a,b); } + void setBeamPDFauthor(MAuint32 a, MAuint32 b) { beamPDFauthor_ = std::make_pair(a, b); } /// Set the the PDF identity - void setBeamPDFid(MAuint32 a, MAuint32 b) - {beamPDFID_=std::make_pair(a,b); } + void setBeamPDFid(MAuint32 a, MAuint32 b) { beamPDFID_ = std::make_pair(a, b); } /// Set the weight mode - void setWeightMode(MAint32 v) - {weightMode_=v;} + void setWeightMode(MAint32 v) { weightMode_ = v; } /// Set the cross section mean // BENJ: the normalization in the pythia lhe output by madgraph has been changed // the 1e9 factor is not needed anymore - void setXsection(MAfloat64 value) -// { xsection_=value*getXsectionUnitFactor();} - { xsection_=value;} + void setXsection(MAfloat64 value) { xsection_ = value; } /// Set the cross section mean - void setXsectionMean(MAfloat64 value) - { xsection_=value;} + void setXsectionMean(MAfloat64 value) { xsection_ = value; } /// Set the cross section mean - void setXsectionError(MAfloat64 value) - { xsection_error_=value;} + void setXsectionError(MAfloat64 value) { xsection_error_ = value; } + + /// @brief set weight names + /// @param id location of the weight + /// @param name name of the weight + void SetWeightName(int id, std::string name) { weight_names_[id] = name; } + + /// @brief accessor to weight names + const std::map &WeightNames() const { return weight_names_; } /// Adding a weight void addWeightedEvents(MAfloat64 weight) - { if (weight>=0) sumweight_positive_ += std::abs(weight); - else sumweight_negative_ += std::abs(weight); } + { + if (weight >= 0) + sumweight_positive_ += std::abs(weight); + else + sumweight_negative_ += std::abs(weight); + } /// Accessor to the number of events with positive weight void setSumweight_positive(MAfloat64 sum) - { sumweight_positive_ += sum; } + { + sumweight_positive_ += sum; + } /// Accessor to the number of events with negative weight - void setSumweight_negative(MAfloat64 sum) - { sumweight_negative_ += sum; } + void setSumweight_negative(MAfloat64 sum) { sumweight_negative_ += sum; } /// Giving a new process entry - ProcessFormat* GetNewProcess() + ProcessFormat *GetNewProcess() { processes_.push_back(ProcessFormat()); return &processes_.back(); @@ -247,30 +221,32 @@ namespace MA5 /// Get scale factor required to set the cross section in pb unit MAfloat64 getXsectionUnitFactor() { - if (*sample_generator_==MA5GEN::PYTHIA6) return 1e9; - else return 1.; + if (*sample_generator_ == MA5GEN::PYTHIA6) + return 1e9; + else + return 1.; } /// Length unit setter void SetLengthUnit(MAfloat32 val) { length_unit_ = val; } /// Accessor to the length unit - MAfloat32 LengthUnit() {return length_unit_;} + MAfloat32 LengthUnit() { return length_unit_; } /// Accessor to the length unit - const MAfloat32 LengthUnit() const {return length_unit_;} + const MAfloat32 LengthUnit() const { return length_unit_; } /// Energy unit setter void SetEnergyUnit(MAfloat32 val) { energy_unit_ = val; } /// Accessor to the energy unit - MAfloat32 EnergyUnit() {return energy_unit_;} + MAfloat32 EnergyUnit() { return energy_unit_; } /// Accessor to the energy unit - const MAfloat32 EnergyUnit() const {return energy_unit_;} - + const MAfloat32 EnergyUnit() const { return energy_unit_; } }; } #endif +// MCSAMPLE_DATAFORMAT_H \ No newline at end of file diff --git a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h index de4bbd73..ce5c85ce 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: // @@ -38,139 +38,245 @@ namespace MA5 { - - class WeightCollection - { - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private: - std::map weights_; - static const MAfloat64 emptyvalue_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public: - /// Constructor withtout arguments - WeightCollection() + class WeightCollection { - } - /// Destructor - ~WeightCollection() - { - } + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + std::vector weights_; + static const MAfloat64 emptyvalue_; - /// Clear all the content - void Reset() - { - weights_.clear(); - } - void clear() { Reset(); } + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor withtout arguments + WeightCollection() {} - /// Size - MAuint32 size() const - { - return weights_.size(); - } + // copy constructor + WeightCollection(const WeightCollection &rhs) + { + weights_.clear(); + weights_ = rhs.weights_; + } - /// Add a new weight group - MAbool Add(MAuint32 id, MAfloat64 value) - { - // Try to add the item - std::pair::iterator, bool> ret; - ret = weights_.insert(std::pair(id, value)); - - // Is it added? - try - { - if (!ret.second) + /// @brief Initialise weights with a certain size and default value + /// @param size number of weights + /// @param default_value default value for each weight + WeightCollection(const MAuint32 &size, MAdouble64 default_value = 0.0) : weights_(size, default_value) {} + + /// Destructor + ~WeightCollection() {} + + /// Clear all the content + void Reset() { weights_.clear(); } + void clear() { Reset(); } + + /// Size + MAuint32 size() const { return weights_.size(); } + + /// Size + MAuint32 size() { return weights_.size(); } + + void resize(MAuint32 n) { weights_.resize(n); } + + /// Add a new weight group + MAbool Add(MAuint32 id, MAfloat64 value) { - std::stringstream str; - str << id; - std::string idname; - str >> idname; - throw EXCEPTION_WARNING("The Weight '" + idname + - "' is defined at two times. Redundant values are skipped.", - "", 0); + if (id < size()) + { + weights_.at(id) = value; + return true; + } + else + { + try + { + std::stringstream str; + str << id; + std::string idname; + str >> idname; + throw EXCEPTION_ERROR("The Weight '" + idname + + "' is not defined. A null value is returned.", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return false; + } + } } - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - return false; - } - - return true; - } - /// Get all the Weight Collection - const std::map &GetWeights() const - { - return weights_; - } + /// Get all the Weight Collection + const std::vector &GetWeights() const { return weights_; } - /// Get a weight - const MAfloat64 &Get(MAuint32 id) const - { - // Try to get the item - std::map::const_iterator it = weights_.find(id); - try - { - if (it == weights_.end()) + /// Get all the Weights + const std::vector &values() const { return weights_; } + + /// Get a weight + const MAfloat64 &Get(MAuint32 id) const { - std::stringstream str; - str << id; - std::string idname; - str >> idname; - throw EXCEPTION_ERROR("The Weight '" + idname + - "' is not defined. Return null value.", - "", 0); + if (id >= 0 && id < size()) + return weights_[id]; + + try + { + std::stringstream str; + str << id; + std::string idname; + str >> idname; + throw EXCEPTION_ERROR("The Weight '" + idname + + "' is not defined. A null value is returned.", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return emptyvalue_; + } } - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - return emptyvalue_; - } - - return it->second; + + /// Get a weight + const MAfloat64 &operator[](MAuint32 id) const { return Get(id); } + + /// @brief Print weight information + void Print() const + { + if (!weights_.empty()) + for (MAuint32 i = 0; i < size(); i++) + INFO << "ID=" << i << " : " << weights_[i] << endmsg; + } + + /// @brief add weight to specific location + /// @param idx location + /// @param weight weight value + void add_weight_to(MAint32 idx, MAdouble64 weight) { weights_[idx] += weight; } + + // explicit setter from same-typed vector (if you need it) + void SetWeights(const std::vector &v) { weights_ = v; } + + /// @brief multiply operator + /// @param multiple + WeightCollection &operator*=(const MAdouble64 &multiple) + { + for (auto &x : weights_) + x *= multiple; + return *this; + } + + WeightCollection operator*(const MAdouble64 &multiple) const + { + WeightCollection result(*this); // copy + for (auto &x : result.weights_) + x *= multiple; + return result; + } + + WeightCollection operator/(const MAdouble64 &multiple) const + { + WeightCollection result(*this); // copy + for (auto &x : result.weights_) + x /= multiple; + return result; + } + + WeightCollection operator+(const MAdouble64 &multiple) const + { + WeightCollection result(*this); // copy + for (auto &x : result.weights_) + x += multiple; + return result; + } + + WeightCollection operator-(const MAdouble64 &multiple) const + { + WeightCollection result(*this); // copy + for (auto &x : result.weights_) + x -= multiple; + return result; + } + + /// @brief add operator + /// @param input + WeightCollection &operator+=(const MAfloat64 &input) + { + for (auto &x : weights_) + x += input; + return *this; + } + + /// @brief add operator + /// @param input + WeightCollection &operator+=(const std::vector &input) + { + if (size() != input.size()) + throw std::invalid_argument("Size mismatch in WeightCollection::operator+= (weights_ and input must have the same size)"); + std::transform(weights_.begin(), weights_.end(), input.begin(), weights_.begin(), + [](MAdouble64 a, MAdouble64 b) + { return a + b; }); + return *this; + } + + /// @brief subtract operator + /// @param input + WeightCollection &operator-=(const MAfloat64 &input) + { + for (auto &x : weights_) + x -= input; + return *this; + } + + /// @brief divide operator + /// @param input + WeightCollection &operator/=(const MAfloat64 &input) + { + for (auto &x : weights_) + x /= input; + return *this; + } + + /// @brief assignment operator + /// @param input + WeightCollection &operator=(const MAfloat64 &input) + { + for (auto &x : weights_) + x = input; + return *this; + } + + /// @brief assignment operator + /// @param input + WeightCollection &operator=(const WeightCollection &w) + { + if (this == &w) + return *this; + weights_ = w.weights_; + return *this; + } + }; + + inline WeightCollection operator*(const MAdouble64 &multiple, const WeightCollection &w) + { + return w * multiple; } - /// Get a weight - const MAfloat64 &operator[](MAuint32 id) const + inline WeightCollection operator/(const MAdouble64 &multiple, const WeightCollection &w) { - return Get(id); + return w / multiple; } - /// Add a new weight group - void Print() const + inline WeightCollection operator+(const MAdouble64 &multiple, const WeightCollection &w) { - if (weights_.empty()) - return; - - // Loop over weights for getting max - MAuint32 maxi = 0; - for (std::map::const_iterator - it = weights_.begin(); - it != weights_.end(); it++) - { - if (it->first > maxi) - maxi = it->first; - } - - // Loop over weights - for (std::map::const_iterator - it = weights_.begin(); - it != weights_.end(); it++) - { - INFO << "ID=" << it->first << " : " << it->second << endmsg; - } + return w + multiple; } - }; + inline WeightCollection operator-(const MAdouble64 &multiple, const WeightCollection &w) + { + return w - multiple; + } } #endif diff --git a/tools/SampleAnalyzer/Commons/Service/IsolationBase.cpp b/tools/SampleAnalyzer/Commons/Service/IsolationBase.cpp index 6e6025bf..558f4017 100644 --- a/tools/SampleAnalyzer/Commons/Service/IsolationBase.cpp +++ b/tools/SampleAnalyzer/Commons/Service/IsolationBase.cpp @@ -1,219 +1,219 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleAnalyzer headers #include "SampleAnalyzer/Commons/Service/IsolationBase.h" - using namespace MA5; - - /// ----------------------------------------------- /// sumPT Lepton vs Tracks /// ----------------------------------------------- -MAfloat64 IsolationBase::sumPT(const RecLeptonFormat* part, - const std::vector& tracks, - const MAfloat64& DR, - MAfloat64 PTmin) const +MAfloat64 IsolationBase::sumPT(const RecLeptonFormat *part, + const std::vector &tracks, + const MAfloat64 &DR, + MAfloat64 PTmin) const { - MAfloat64 sumPT=0.; + MAfloat64 sumPT = 0.; - // Loop over the towers - for (MAuint32 i=0;imomentum().DeltaR(track.momentum()) > DR) continue; + // Cut on the DR + if (part->momentum().DeltaR(track.momentum()) > DR) + continue; - // Cut on id - // if (track.isDelphesUnique(part->delphesTags())) continue; + // Cut on id + // if (track.isDelphesUnique(part->delphesTags())) continue; - // Sum - sumPT += track.pt(); - } + // Sum + sumPT += track.pt(); + } - // return PT sum of tracks in the cone - return sumPT; + // return PT sum of tracks in the cone + return sumPT; } - /// ----------------------------------------------- /// sumPT Lepton vs Towers /// ----------------------------------------------- -MAfloat64 IsolationBase::sumPT(const RecLeptonFormat* part, - const std::vector& towers, - const MAfloat64& DR, - MAfloat64 PTmin) const +MAfloat64 IsolationBase::sumPT(const RecLeptonFormat *part, + const std::vector &towers, + const MAfloat64 &DR, + MAfloat64 PTmin) const { - MAfloat64 sumPT=0.; + MAfloat64 sumPT = 0.; - // Loop over the tracks - for (MAuint32 i=0;imomentum().DeltaR(tower.momentum()) > DR) continue; + // Cut on the DR + if (part->momentum().DeltaR(tower.momentum()) > DR) + continue; - // Sum - sumPT += tower.pt(); - } + // Sum + sumPT += tower.pt(); + } - // return PT sum of towers in the cone - return sumPT; + // return PT sum of towers in the cone + return sumPT; } - /// ----------------------------------------------- /// sumPT Lepton vs Eflow object /// ----------------------------------------------- -MAfloat64 IsolationBase::sumPT(const RecLeptonFormat* part, - const std::vector& towers, - const MAfloat64& DR, - MAfloat64 PTmin) const +MAfloat64 IsolationBase::sumPT(const RecLeptonFormat *part, + const std::vector &towers, + const MAfloat64 &DR, + MAfloat64 PTmin) const { - MAfloat64 sumPT=0.; + MAfloat64 sumPT = 0.; - // Loop over the tracks - for (MAuint32 i=0;imomentum().DeltaR(tower.momentum()) > DR) continue; + // Cut on the DR + if (part->momentum().DeltaR(tower.momentum()) > DR) + continue; - // Sum - sumPT += tower.pt(); - } + // Sum + sumPT += tower.pt(); + } - // return PT sum of towers in the cone - return sumPT; + // return PT sum of towers in the cone + return sumPT; } - /// ----------------------------------------------- /// sumPT Photon vs Tracks /// ----------------------------------------------- -MAfloat64 IsolationBase::sumPT(const RecPhotonFormat* part, - const std::vector& tracks, - const MAfloat64& DR, - MAfloat64 PTmin) const +MAfloat64 IsolationBase::sumPT(const RecPhotonFormat *part, + const std::vector &tracks, + const MAfloat64 &DR, + MAfloat64 PTmin) const { - MAfloat64 sumPT=0.; + MAfloat64 sumPT = 0.; - // Loop over the towers - for (MAuint32 i=0;imomentum().DeltaR(track.momentum()) > DR) continue; + // Cut on the DR + if (part->momentum().DeltaR(track.momentum()) > DR) + continue; - // Sum - sumPT += track.pt(); - } + // Sum + sumPT += track.pt(); + } - // return PT sum of tracks in the cone - return sumPT; + // return PT sum of tracks in the cone + return sumPT; } - /// ----------------------------------------------- /// sumPT Photon vs Towers /// ----------------------------------------------- -MAfloat64 IsolationBase::sumPT(const RecPhotonFormat* part, - const std::vector& towers, - const MAfloat64& DR, - MAfloat64 PTmin) const +MAfloat64 IsolationBase::sumPT(const RecPhotonFormat *part, + const std::vector &towers, + const MAfloat64 &DR, + MAfloat64 PTmin) const { - MAfloat64 sumPT=0.; + MAfloat64 sumPT = 0.; - // Loop over the tracks - for (MAuint32 i=0;imomentum().DeltaR(tower.momentum()) > DR) continue; + // Cut on the DR + if (part->momentum().DeltaR(tower.momentum()) > DR) + continue; - // Sum - sumPT += tower.pt(); - } + // Sum + sumPT += tower.pt(); + } - // return PT sum of towers in the cone - return sumPT; + // return PT sum of towers in the cone + return sumPT; } - /// ----------------------------------------------- /// sumPT Photon vs Eflow object /// ----------------------------------------------- -MAfloat64 IsolationBase::sumPT(const RecPhotonFormat* part, - const std::vector& towers, - const MAfloat64& DR, - MAfloat64 PTmin) const +MAfloat64 IsolationBase::sumPT(const RecPhotonFormat *part, + const std::vector &towers, + const MAfloat64 &DR, + MAfloat64 PTmin) const { - MAfloat64 sumPT=0.; + MAfloat64 sumPT = 0.; - // Loop over the tracks - for (MAuint32 i=0;imomentum().DeltaR(tower.momentum()) > DR) continue; + // Cut on the DR + if (part->momentum().DeltaR(tower.momentum()) > DR) + continue; - // Cut on id - // if (tower.isDelphesUnique(part->delphesTags())) continue; + // Cut on id + // if (tower.isDelphesUnique(part->delphesTags())) continue; - // Sum - sumPT += tower.pt(); - } + // Sum + sumPT += tower.pt(); + } - // return PT sum of towers in the cone - return sumPT; + // return PT sum of towers in the cone + return sumPT; } - - - diff --git a/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp b/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp index 561dbe55..c465a839 100644 --- a/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp +++ b/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp @@ -212,17 +212,16 @@ void DelphesTreeReader::FillEvent(EventFormat &myEvent, SampleFormat &mySample) { // Number of generated particles MAuint32 nweights = static_cast(data_.Weight_->GetEntries()); - + std::vector w(nweights, 0.); for (MAuint32 i = 0; i < nweights; i++) { // getting the i-th particle LHEFWeight *weight = dynamic_cast(data_.Weight_->At(i)); if (weight == 0) continue; - - // creating new particle and filling particle info - myEvent.mc()->multiweights().Add(weight->ID, weight->Weight); + w.at(weight->ID) = weight->Weight; } + myEvent.mc()->setWeights(w); } // --------------------------------------------------------------------------- @@ -406,7 +405,8 @@ void DelphesTreeReader::FillEvent(EventFormat &myEvent, SampleFormat &mySample) if (header1 != 0) { // Set event-weight - myEvent.mc()->setWeight(header1->Weight); + INFO << " FIX ME " << header1->Weight << endmsg; + myEvent.mc()->setWeight(0, header1->Weight); } else { @@ -414,7 +414,8 @@ void DelphesTreeReader::FillEvent(EventFormat &myEvent, SampleFormat &mySample) if (header2 == 0) continue; // Set event-weight - myEvent.mc()->setWeight(header2->Weight); + INFO << " FIX ME " << header2->Weight << endmsg; + myEvent.mc()->setWeight(0, header2->Weight); } } } diff --git a/tools/SampleAnalyzer/Interfaces/delphesMA5tune/DelphesMA5tuneTreeReader.cpp b/tools/SampleAnalyzer/Interfaces/delphesMA5tune/DelphesMA5tuneTreeReader.cpp index bb496e91..24d3b112 100644 --- a/tools/SampleAnalyzer/Interfaces/delphesMA5tune/DelphesMA5tuneTreeReader.cpp +++ b/tools/SampleAnalyzer/Interfaces/delphesMA5tune/DelphesMA5tuneTreeReader.cpp @@ -403,14 +403,14 @@ void DelphesMA5tuneTreeReader::FillEvent(EventFormat& myEvent, SampleFormat& myS if (header1!=0) { // Set event-weight - myEvent.mc()->setWeight(header1->Weight); + myEvent.mc()->setWeight(i, header1->Weight); } else { HepMCEvent* header2 = dynamic_cast(branchEvent_->At(i)); if (header2==0) continue; // Set event-weight - myEvent.mc()->setWeight(header2->Weight); + myEvent.mc()->setWeight(i, header2->Weight); } } } diff --git a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp index 9ee7b324..cb4cfd5c 100644 --- a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp +++ b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp @@ -189,15 +189,13 @@ void SampleAnalyzer::CheckDatatypes() const } /// Initialization of the SampleAnalyzer -MAbool SampleAnalyzer::Initialize(MAint32 argc, MAchar **argv, - const std::string &pdgFileName) +MAbool SampleAnalyzer::Initialize(MAint32 argc, MAchar **argv, const std::string &pdgFileName) { - // Initializing general pointers - myReader_ = 0; + // Initializing general pointers + myReader_ = 0; - // Configuration - if (!cfg_.Initialize(argc, argv)) - return false; + // Configuration + if (!cfg_.Initialize(argc, argv)) return false; // Displaying configuration cfg_.Display(); @@ -789,6 +787,16 @@ StatusCode::Type SampleAnalyzer::NextEvent(SampleFormat &mySample, EventFormat & return StatusCode::KEEP; } +/// @brief Prepare analyzers for the execution by initialising the weights +/// @param mySample sample dataset +/// @param myEvent event dataset +void SampleAnalyzer::PrepareForExecution(SampleFormat &mySample, EventFormat &myEvent) +{ + if (myEvent.mc() != 0) + for (auto &analyzer : analyzers_) + analyzer->Manager()->InitializeForNewEvent(myEvent.mc()->weights()); +} + /// Home made functions to make reasonnable filenames inline void ReplaceAll(std::string &name, const std::string &In, const std::string &Out) { @@ -994,6 +1002,10 @@ void SampleAnalyzer::FillSummary(SampleFormat &summary, summary.mc()->xsection_ = 0; summary.mc()->xsection_error_ = 0; } + + /// ! this assumes all the weight identifiers are the same through out the sample set + for (auto &name_map : samples.back().mc()->WeightNames()) + summary.mc()->SetWeightName(name_map.first, name_map.second); } /// Updating the progress bar diff --git a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.h b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.h index fcff1f16..adb39d14 100644 --- a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.h +++ b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef SAMPLE_ANALYZER_H #define SAMPLE_ANALYZER_H - // STL headers #include #include @@ -43,139 +41,131 @@ #include "SampleAnalyzer/Process/JetClustering/JetClustererManager.h" #include "SampleAnalyzer/Process/Detector/DetectorManager.h" - namespace MA5 { -class ProgressBar; -class Configuration; - -class SampleAnalyzer -{ - private : - - std::string analysisName_; - std::string datasetName_; - MAbool LastFileFail_; - - /// Configuration of SampleAnalyzer - Configuration cfg_; - - /// List of input files - std::vector inputs_; - - /// List of managers - WriterManager fullWriters_; - ReaderManager fullReaders_; - AnalyzerManager fullAnalyses_; - JetClustererManager fullJetClusterers_; - DetectorManager fullDetectors_; + class ProgressBar; + class Configuration; - /// List of managers - std::vector writers_; - std::vector readers_; - std::vector analyzers_; - std::vector clusters_; - std::vector detectors_; + class SampleAnalyzer + { + private: + std::string analysisName_; + std::string datasetName_; + MAbool LastFileFail_; - /// Reading status - MAuint32 file_index_; - MAbool next_file_; + /// Configuration of SampleAnalyzer + Configuration cfg_; - /// Counters - std::vector counter_read_; - std::vector counter_passed_; + /// List of input files + std::vector inputs_; - /// The only one pointer to the reader - ReaderBase* myReader_; + /// List of managers + WriterManager fullWriters_; + ReaderManager fullReaders_; + AnalyzerManager fullAnalyses_; + JetClustererManager fullJetClusterers_; + DetectorManager fullDetectors_; - /// Progress bar for event reading - ProgressBar* progressBar_; + /// List of managers + std::vector writers_; + std::vector readers_; + std::vector analyzers_; + std::vector clusters_; + std::vector detectors_; - - public: + /// Reading status + MAuint32 file_index_; + MAbool next_file_; - /// Constructor withtout arguments - SampleAnalyzer(); + /// Counters + std::vector counter_read_; + std::vector counter_passed_; - /// Adding Analyzer - AnalyzerManager& AnalyzerList() - { return fullAnalyses_; } - ReaderManager& ReaderList() - { return fullReaders_; } - WriterManager& WriterList() - { return fullWriters_; } - JetClustererManager& JetClustererList() - { return fullJetClusterers_; } - DetectorManager& DetectorSimList() - { return fullDetectors_; } + /// The only one pointer to the reader + ReaderBase *myReader_; - /// Initialization of the SampleAnalyzer - MAbool Initialize(MAint32 argc, MAchar **argv, const std::string& filename); + /// Progress bar for event reading + ProgressBar *progressBar_; - /// Getting pointer to an analyzer - AnalyzerBase* InitializeAnalyzer(const std::string& name, - const std::string& outputname, - const std::map& parameters); + public: + /// Constructor withtout arguments + SampleAnalyzer(); - AnalyzerBase* InitializeAnalyzer(const std::string& name, - const std::string& outputname); + /// Adding Analyzer + AnalyzerManager &AnalyzerList() { return fullAnalyses_; } + ReaderManager &ReaderList() { return fullReaders_; } + WriterManager &WriterList() { return fullWriters_; } + JetClustererManager &JetClustererList() { return fullJetClusterers_; } + DetectorManager &DetectorSimList() { return fullDetectors_; } - /// Getting pointer to a writer - WriterBase* InitializeWriter(const std::string& name, - const std::string& outputname); + /// Initialization of the SampleAnalyzer + MAbool Initialize(MAint32 argc, MAchar **argv, const std::string &filename); - /// Getting pointer to a jet clusterer - JetClusterer* InitializeJetClusterer(const std::string& name, - const std::map& parameters); + /// Getting pointer to an analyzer + AnalyzerBase *InitializeAnalyzer(const std::string &name, + const std::string &outputname, + const std::map ¶meters); - /// Getting pointer to a detector - DetectorBase* InitializeDetector(const std::string& name, - const std::string& configFile, - const std::map& parameters); + AnalyzerBase *InitializeAnalyzer(const std::string &name, + const std::string &outputname); - /// Reading the next event - StatusCode::Type NextEvent(SampleFormat& mysample, EventFormat& myevent); + /// Getting pointer to a writer + WriterBase *InitializeWriter(const std::string &name, + const std::string &outputname); - /// Reading the next file - StatusCode::Type NextFile(SampleFormat& mysample); + /// Getting pointer to a jet clusterer + JetClusterer *InitializeJetClusterer(const std::string &name, + const std::map ¶meters); - /// Finalization of the SampleAnalyzer - MAbool Finalize(std::vector& mysamples, EventFormat& myevent); + /// Getting pointer to a detector + DetectorBase *InitializeDetector(const std::string &name, + const std::string &configFile, + const std::map ¶meters); - /// Updating the progress bar - void UpdateProgressBar(); + /// Reading the next event + StatusCode::Type NextEvent(SampleFormat &mysample, EventFormat &myevent); - /// Creating the directory structure associated with the SRM - MAbool PostInitialize(); + /// @brief Prepare the analyses for execution by initialising the weights + /// @param mysample sample data + /// @param myevent event data + void PrepareForExecution(SampleFormat &mysample, EventFormat &myevent); - /// Dumping the content of the counters - void DumpSR(std::ostream &); - void HeadSR(std::ostream &); + /// Reading the next file + StatusCode::Type NextFile(SampleFormat &mysample); - std::map options() {return cfg_.Options();} + /// Finalization of the SampleAnalyzer + MAbool Finalize(std::vector &mysamples, EventFormat &myevent); - // Default Hadronic particles - void AddDefaultHadronic(); + /// Updating the progress bar + void UpdateProgressBar(); - // Default Hadronic particles - void AddDefaultInvisible(); + /// Creating the directory structure associated with the SRM + MAbool PostInitialize(); - private: + /// Dumping the content of the counters + void DumpSR(std::ostream &); + void HeadSR(std::ostream &); - /// CheckDatatypes - void CheckDatatypes() const; + std::map options() { return cfg_.Options(); } - /// Filling the summary format - void FillSummary(SampleFormat& summary, - const std::vector& mysamples); + // Default Hadronic particles + void AddDefaultHadronic(); + // Default Hadronic particles + void AddDefaultInvisible(); - /// Creating the directory structure associated with the SRM - MAbool CreateDirectoryStructure(); + private: + /// CheckDatatypes + void CheckDatatypes() const; + /// Filling the summary format + void FillSummary(SampleFormat &summary, + const std::vector &mysamples); -}; + /// Creating the directory structure associated with the SRM + MAbool CreateDirectoryStructure(); + }; } diff --git a/tools/SampleAnalyzer/Process/Counter/Counter.h b/tools/SampleAnalyzer/Process/Counter/Counter.h index 0f3b9993..a750bd26 100644 --- a/tools/SampleAnalyzer/Process/Counter/Counter.h +++ b/tools/SampleAnalyzer/Process/Counter/Counter.h @@ -1,114 +1,124 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef COUNTER_h #define COUNTER_h - // SampleAnalyzer headers #include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" +#include "SampleAnalyzer/Commons/Base/HistoStructures.h" +#include "SampleAnalyzer/Commons/DataFormat/WeightCollection.h" // STL headers #include #include #include - namespace MA5 { + class CounterManager; -class CounterCollection; - -class Counter -{ - friend class CounterCollection; - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - public : - - /// name of the analysis - std::string name_; - - /// number of times the function Increment is called - /// first = positive weight ; second = negative weight - std::pair nentries_; - - /// sum of weights - /// first = positive weight ; second = negative weight - std::pair sumweight_; - - /// sum of squared weights - /// first = positive weight ; second = negative weight - std::pair sumweight2_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - Counter(const std::string& name = "unkwown") - { - name_ = name; - nentries_ = std::make_pair(0,0); - sumweight_ = std::make_pair(0.,0.); - sumweight2_ = std::make_pair(0.,0.); - } - - /// Destructor - ~Counter() - { } - - /// Reset - void Reset() - { - nentries_ = std::make_pair(0,0); - sumweight_ = std::make_pair(0.,0.); - sumweight2_ = std::make_pair(0.,0.); - } - - /// Increment the counter - void Increment(const MAfloat32& weight=1.) - { - if (weight>0) - { - nentries_.first++; - sumweight_.first+=weight; - sumweight2_.first+=weight*weight; - } - else if (weight<0) + class Counter { - nentries_.second++; - sumweight_.second+=weight; - sumweight2_.second+=weight*weight; - } - } - -}; + friend class CounterManager; + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + public: + /// name of the analysis + std::string name_; + + /// number of times the function Increment is called + /// first = positive weight ; second = negative weight + std::vector nentries_; + + /// sum of weights + /// first = positive weight ; second = negative weight + std::vector sumweights_; + + /// sum of squared weights + /// first = positive weight ; second = negative weight + std::vector sumweights2_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + Counter(const std::string &name = "unkwown") + { + name_ = name; + Reset(); + } + + /// Destructor + ~Counter() {} + + /// Reset + void Reset() + { + nentries_.clear(); + sumweights_.clear(); + sumweights2_.clear(); + } + + MAint32 size() { return nentries_.size(); } + + void Initialise(const WeightCollection &multiweight) + { + Reset(); + MAuint32 n = multiweight.GetWeights().size(); + nentries_.resize(n); + sumweights_.resize(n); + sumweights2_.resize(n); + } + + std::vector nentries() { return nentries_; } + std::vector sumW() { return sumweights_; } + std::vector sumW2() { return sumweights2_; } + + /// Increment the counter + void Increment(const WeightCollection &multiweight) + { + for (MAuint32 idx = 0; idx < multiweight.size(); idx++) + { + MAfloat64 w = multiweight[idx]; + if (w >= 0.0) + { + nentries_[idx].positive++; + sumweights_[idx].positive += w; + sumweights2_[idx].positive += w * w; + } + else + { + nentries_[idx].negative++; + sumweights_[idx].negative += w; + sumweights2_[idx].negative += w * w; + } + } + } + }; } diff --git a/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp b/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp index b3cb7fce..d8de25f0 100644 --- a/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp +++ b/tools/SampleAnalyzer/Process/Counter/CounterManager.cpp @@ -1,157 +1,127 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Counter/CounterManager.h" - using namespace MA5; -/* -/// Write the counters in a ROOT file -void CounterManager::Write_RootFormat(TFile* output) const -{ - // Creating ROOT containers - TVector nentries_pos (counters_.size()); - TVector sumweight_pos (counters_.size()); - TVector sumweight2_pos (counters_.size()); - TVector nentries_neg (counters_.size()); - TVector sumweight_neg (counters_.size()); - TVector sumweight2_neg (counters_.size()); - TVector initial_pos (1); - TVector initial_neg (1); - TVector initial2_pos (1); - TVector initial2_neg (1); - - // Filling ROOT containers with info - for (MAuint32 i=0; i" << std::endl; - - // name - *output.GetStream() << "\"Initial number of events\" #" << std::endl; - - // nentries - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.nentries_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.nentries_.second; - *output.GetStream() << " # nentries" << std::endl; - - // sum of weights - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight_.second; - *output.GetStream() << " # sum of weights" << std::endl; - - // sum of weights^2 - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight2_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << initial_.sumweight2_.second; - *output.GetStream() << " # sum of weights^2" << std::endl; - - // foot - *output.GetStream() << "" << std::endl; - *output.GetStream() << std::endl; - - - - // Loop over the counters - for (MAuint32 i=0;i" << std::endl; + *output.GetStream() << "" << std::endl; // name - MAint32 nsp = 30-counters_[i].name_.size(); - if(nsp<0) nsp=0; - *output.GetStream() << "\"" << counters_[i].name_ << "\""; - for (MAuint32 jj=0; jj(nsp);jj++) *output.GetStream() << " "; - *output.GetStream() << "# " << i+1 <<"st cut" << std::endl; + *output.GetStream() << "\"Initial number of events\" #" << std::endl; // nentries - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].nentries_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].nentries_.second; + for (auto &event : initial_.nentries_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.negative; + } *output.GetStream() << " # nentries" << std::endl; // sum of weights - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight_.second; + for (auto &event : initial_.sumweights_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.negative; + } *output.GetStream() << " # sum of weights" << std::endl; // sum of weights^2 - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight2_.first; - *output.GetStream() << " "; - output.GetStream()->width(15); - *output.GetStream() << std::left << std::scientific << counters_[i].sumweight2_.second; + for (auto &event : initial_.sumweights2_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.negative; + } *output.GetStream() << " # sum of weights^2" << std::endl; // foot - *output.GetStream() << "" << std::endl; + *output.GetStream() << "" << std::endl; *output.GetStream() << std::endl; - } + + // Loop over the counters + for (MAuint32 i = 0; i < counters_.size(); i++) + { + // header + *output.GetStream() << "" << std::endl; + + // name + MAint32 nsp = 30 - counters_[i].name_.size(); + if (nsp < 0) + nsp = 0; + *output.GetStream() << "\"" << counters_[i].name_ << "\""; + for (MAuint32 jj = 0; jj < static_cast(nsp); jj++) + *output.GetStream() << " "; + *output.GetStream() << "# " << i + 1 << "st cut" << std::endl; + + // nentries + for (auto &event : counters_[i].nentries_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.negative; + } + *output.GetStream() << " # nentries" << std::endl; + + // sum of weights + for (auto &event : counters_[i].sumweights_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.negative; + } + *output.GetStream() << " # sum of weights" << std::endl; + + // sum of weights^2 + for (auto &event : counters_[i].sumweights2_) + { + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.positive; + *output.GetStream() << " "; + output.GetStream()->width(15); + *output.GetStream() << std::left << std::scientific << event.negative; + } + *output.GetStream() << " # sum of weights^2" << std::endl; + + // foot + *output.GetStream() << "" << std::endl; + *output.GetStream() << std::endl; + } } diff --git a/tools/SampleAnalyzer/Process/Counter/CounterManager.h b/tools/SampleAnalyzer/Process/Counter/CounterManager.h index 01dd8f18..a1b1da0c 100644 --- a/tools/SampleAnalyzer/Process/Counter/CounterManager.h +++ b/tools/SampleAnalyzer/Process/Counter/CounterManager.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef COUNTER_MANAGER_H #define COUNTER_MANAGER_H - // STL headers #include #include @@ -35,80 +33,76 @@ #include "SampleAnalyzer/Process/Counter/Counter.h" #include "SampleAnalyzer/Process/Writer/SAFWriter.h" - namespace MA5 { -class CounterManager -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private : - - // Collection of counters - std::vector counters_; - - // Initial number of events - Counter initial_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - CounterManager() - { } - - /// Destructor - ~CounterManager() - { } - - /// Initialize - void Initialize(const MAuint32& n) - { counters_.resize(n); } - - - // Specifying a cut name - void InitCut(const std::string myname) - { - Counter tmpcnt(myname); - counters_.push_back(tmpcnt); - } - - /// Reset - void Reset() - { counters_.clear(); } - - /// Overloading operator [] - const Counter& operator[] (const MAuint32& index) const - { return counters_[index];} - Counter& operator[] (const MAuint32& index) - { return counters_[index];} - - /// Incrementing the initial number of events - void IncrementNInitial(MAfloat32 weight=1.0) - { initial_.Increment(weight); } - - /// Incrementing the initial number of events - Counter& GetInitial() - { return initial_; } - const Counter& GetInitial() const - { return initial_; } - - /// Write the counters in a Text file - void Write_TextFormat(SAFWriter& output) const; - - /// Write the counters in a ROOT file - // void Write_RootFormat(TFile* output) const; - - /// Finalizing - void Finalize() - { Reset(); } - -}; + class CounterManager + { + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + /// @brief intialisation indicator + MAbool initialised_; + + // Collection of counters + std::vector counters_; + + // Initial number of events + Counter initial_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + CounterManager() { initialised_ = false; } + + /// Destructor + ~CounterManager() {} + + /// Initialize + void Initialize(const MAuint32 &n) { counters_.resize(n); } + + // Specifying a cut name + void InitCut(const std::string myname) + { + Counter tmpcnt(myname); + counters_.push_back(tmpcnt); + } + + /// Reset + void Reset() { counters_.clear(); } + + /// Overloading operator [] + const Counter &operator[](const MAuint32 &index) const { return counters_[index]; } + Counter &operator[](const MAuint32 &index) { return counters_[index]; } + + /// Incrementing the initial number of events + void IncrementNInitial(const WeightCollection &weight) + { + if (!initialised_) + { + for (auto &counter : counters_) + counter.Initialise(weight); + initial_.Initialise(weight); + initialised_ = true; + } + initial_.Increment(weight); + } + + /// Incrementing the initial number of events + Counter &GetInitial() { return initial_; } + + const Counter &GetInitial() const { return initial_; } + + /// Write the counters in a Text file + void Write_TextFormat(SAFWriter &output) const; + + /// Finalizing + void Finalize() { Reset(); } + }; } diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.cpp b/tools/SampleAnalyzer/Process/Plot/Histo.cpp index f9ef761d..ad1558f4 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.cpp +++ b/tools/SampleAnalyzer/Process/Plot/Histo.cpp @@ -1,141 +1,260 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Plot/Histo.h" using namespace MA5; - /// Write the plot in a Text file -void Histo::Write_TextFormat(std::ostream* output) +void Histo::Write_TextFormat(std::ostream *output) { - // Header - *output << "" << std::endl; + // Header + *output << "" << std::endl; - // Write the body - Write_TextFormatBody(output); + // Write the body + Write_TextFormatBody(output); - // Foot - *output << "" << std::endl; - *output << std::endl; + // Foot + *output << "" << std::endl; + *output << std::endl; } - /// Write the plot in a Text file -void Histo::Write_TextFormatBody(std::ostream* output) +void Histo::Write_TextFormatBody(std::ostream *output) { - // Description - *output << " " << std::endl; - - // Name - *output << " \"" << name_ << "\"" << std::endl; - - // Title - *output << " "; - output->width(10); - *output << std::left << "# nbins"; - output->width(15); - *output << std::left << "xmin"; - output->width(15); - *output << std::left << "xmax" << std::endl; - - // Data - *output << " "; - output->width( 8); *output << std::left << nbins_; - output->width(15); *output << std::left << std::scientific << xmin_; - output->width(15); *output << std::left << std::scientific << xmax_ << std::endl; - - // SelectionRegions - if(regions_.size()!=0) - { - MAuint32 maxlength=0; - for(MAuint32 i=0; i < regions_.size(); i++) - if (regions_[i]->GetName().size()>maxlength) maxlength=regions_[i]->GetName().size(); - *output << std::left << " # Defined regions" << std::endl; - for(MAuint32 i=0; i < regions_.size(); i++) + // Description + *output << " " << std::endl; + + // Name + *output << " \"" << name_ << "\"" << std::endl; + + // Title + *output << " "; + output->width(10); + *output << std::left << "# nbins"; + output->width(15); + *output << std::left << "xmin"; + output->width(15); + *output << std::left << "xmax" << std::endl; + + // Data + *output << " "; + output->width(8); + *output << std::left << nbins_; + output->width(15); + *output << std::left << std::scientific << xmin_; + output->width(15); + *output << std::left << std::scientific << xmax_ << std::endl; + + // SelectionRegions + if (regions_.size() != 0) { - *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); - *output << " # Region nr. " << std::fixed << i+1 << std::endl; + MAuint32 maxlength = 0; + for (MAuint32 i = 0; i < regions_.size(); i++) + if (regions_[i]->GetName().size() > maxlength) + maxlength = regions_[i]->GetName().size(); + *output << std::left << " # Defined regions" << std::endl; + for (MAuint32 i = 0; i < regions_.size(); i++) + { + *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); + *output << " # Region nr. " << std::fixed << i + 1 << std::endl; + } } - } - - // End description - *output << " " << std::endl; - - // Statistics - *output << " " << std::endl; - - *output << " "; - output->width(15); *output << std::fixed << nevents_.first; - output->width(15); *output << std::fixed << nevents_.second; - *output << " # nevents" << std::endl; - *output << " "; - output->width(15); *output << std::scientific << nevents_w_.first; - output->width(15); *output << std::scientific << nevents_w_.second; - *output << " # sum of event-weights over events" << std::endl; - *output << " "; - output->width(15); *output << std::fixed << nentries_.first; - output->width(15); *output << std::fixed << nentries_.second; - *output << " # nentries" << std::endl; - *output << " "; - output->width(15); *output << std::scientific << sum_w_.first; - output->width(15); *output << std::scientific << sum_w_.second; - *output << " # sum of event-weights over entries" << std::endl; - *output << " "; - output->width(15); *output << std::scientific << sum_ww_.first; - output->width(15); *output << std::scientific << sum_ww_.second; - *output << " # sum weights^2" << std::endl; - *output << " "; - output->width(15); *output << std::scientific << sum_xw_.first; - output->width(15); *output << std::scientific << sum_xw_.second; - *output << " # sum value*weight" << std::endl; - *output << " "; - output->width(15); *output << std::scientific << sum_xxw_.first; - output->width(15); *output << std::scientific << sum_xxw_.second; - *output << " # sum value^2*weight" << std::endl; - *output << " " << std::endl; - - // Data - *output << " " << std::endl; - *output << " "; - output->width(15); *output << std::scientific << underflow_.first; - output->width(15); *output << std::scientific << underflow_.second; - *output << " # underflow" << std::endl; - for (MAuint32 i=0;i" << std::endl; + + // Statistics + *output << " " << std::endl; + *output << " "; - output->width(15); *output << std::scientific << histo_[i].first; - output->width(15); *output << std::scientific << histo_[i].second; - if (i<2 || i>=(histo_.size()-2)) - *output << " # bin " << i+1 << " / " << histo_.size(); - *output << std::endl; - } - *output << " "; - output->width(15); *output << std::scientific << overflow_.first; - output->width(15); *output << std::scientific << overflow_.second; - *output << " # overflow" << std::endl; - *output << " " << std::endl; + for (auto &event : nevents_) + { + output->width(15); + *output << std::fixed << event.positive; + output->width(15); + *output << std::fixed << event.negative; + } + *output << " # nevents" << std::endl; + *output << " "; + for (auto &event : nevents_w_) + { + output->width(15); + *output << std::scientific << event.positive; + output->width(15); + *output << std::scientific << event.negative; + } + *output << " # sum of event-weights over events" << std::endl; + *output << " "; + for (auto &event : nentries_) + { + output->width(15); + *output << std::fixed << event.positive; + output->width(15); + *output << std::fixed << event.negative; + } + *output << " # nentries" << std::endl; + *output << " "; + for (auto &event : sum_w_) + { + output->width(15); + *output << std::scientific << event.positive; + output->width(15); + *output << std::scientific << event.negative; + } + *output << " # sum of event-weights over entries" << std::endl; + *output << " "; + for (auto &event : sum_ww_) + { + output->width(15); + *output << std::scientific << event.positive; + output->width(15); + *output << std::scientific << event.negative; + } + *output << " # sum weights^2" << std::endl; + *output << " "; + for (auto &event : sum_xw_) + { + output->width(15); + *output << std::scientific << event.positive; + output->width(15); + *output << std::scientific << event.negative; + } + *output << " # sum value*weight" << std::endl; + *output << " "; + for (auto &event : sum_xxw_) + { + output->width(15); + *output << std::scientific << event.positive; + output->width(15); + *output << std::scientific << event.negative; + } + *output << " # sum value^2*weight" << std::endl; + *output << " " << std::endl; + + // Data + *output << " " << std::endl; + *output << " "; + for (auto &event : underflow_) + { + output->width(15); + *output << std::scientific << event.positive; + output->width(15); + *output << std::scientific << event.negative; + } + *output << " # underflow" << std::endl; + for (MAuint32 ibin = 0; ibin < histo_.size(); ibin++) + { + *output << " "; + for (auto &bin : histo_[ibin]) + { + output->width(15); + *output << std::scientific << bin.positive; + output->width(15); + *output << std::scientific << bin.negative; + } + if (ibin < 2 || ibin >= (histo_.size() - 2)) + *output << " # bin " << ibin + 1 << " / " << histo_.size(); + *output << std::endl; + } + *output << " "; + for (auto &event : overflow_) + { + output->width(15); + *output << std::scientific << event.positive; + output->width(15); + *output << std::scientific << event.negative; + } + *output << " # overflow" << std::endl; + *output << " " << std::endl; } +/// @brief Initialise the containers +/// @param weights weight collection +void Histo::_initialize(const WeightCollection &weights) +{ + MAuint32 n = weights.size(); + underflow_.resize(n); + overflow_.resize(n); + sum_w_.resize(n); + sum_ww_.resize(n); + sum_xw_.resize(n); + sum_xxw_.resize(n); + for (MAuint32 idb = 0; idb < nbins_; idb++) + histo_[idb].resize(n); +} + +/// Filling histogram +void Histo::Fill(MAfloat64 value, const WeightCollection &weights) +{ + // Safety : nan or isinf + try + { + if (std::isnan(value)) + throw EXCEPTION_WARNING("Skipping a NaN (Not a Number) value in an histogram.", "", 0); + if (std::isinf(value)) + throw EXCEPTION_WARNING("Skipping a Infinity value in an histogram.", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + for (MAuint32 idx = 0; idx < weights.size(); idx++) + { + MAfloat64 weight = weights[idx]; + // Positive weight + if (weight >= 0) + { + nentries_[idx].positive++; + sum_w_[idx].positive += weight; + sum_ww_[idx].positive += weight * weight; + sum_xw_[idx].positive += value * weight; + sum_xxw_[idx].positive += value * value * weight; + if (value < xmin_) + underflow_[idx].positive += weight; + else if (value >= xmax_) + overflow_[idx].positive += weight; + else + histo_[std::floor((value - xmin_) / step_)][idx].positive += weight; + } + + // Negative weight + else + { + MAdouble64 pw = std::fabs(weight); + nentries_[idx].negative++; + sum_w_[idx].negative += pw; + sum_ww_[idx].negative += pw * pw; + sum_xw_[idx].negative += value * pw; + sum_xxw_[idx].negative += value * value * pw; + if (value < xmin_) + underflow_[idx].negative += pw; + else if (value >= xmax_) + overflow_[idx].negative += pw; + else + histo_[std::floor((value - xmin_) / step_)][idx].negative += pw; + } + } +} diff --git a/tools/SampleAnalyzer/Process/Plot/Histo.h b/tools/SampleAnalyzer/Process/Plot/Histo.h index 4b08e0bd..22c6d94f 100644 --- a/tools/SampleAnalyzer/Process/Plot/Histo.h +++ b/tools/SampleAnalyzer/Process/Plot/Histo.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef HISTO_H #define HISTO_H - // STL headers #include #include @@ -36,186 +34,141 @@ #include "SampleAnalyzer/Process/RegionSelection/RegionSelection.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - namespace MA5 { -class Histo : public PlotBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected : - - /// Histogram arrays - std::vector< std::pair > histo_; - std::pair underflow_; - std::pair overflow_; - - /// Histogram description - MAuint32 nbins_; - MAfloat64 xmin_; - MAfloat64 xmax_; - MAfloat64 step_; - - /// Sum of event-weights over entries - std::pair sum_w_; - - /// Sum of squared weights - std::pair sum_ww_; - - /// Sum of value * weight - std::pair sum_xw_; - - /// Sum of value * value * weight - std::pair sum_xxw_; - - /// RegionSelections attached to the histo - std::vector regions_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - Histo() : PlotBase() - { - nbins_=100; xmin_=0; xmax_=100; - step_ = (xmax_ - xmin_)/static_cast(nbins_); - } - - /// Constructor with argument - Histo(const std::string& name) : PlotBase(name) - { } - - /// Constructor with argument - Histo(const std::string& name, MAuint32 nbins, MAfloat64 xmin, MAfloat64 xmax) : - PlotBase(name) - { - // Setting the description: nbins - try - { - if (nbins==0) throw EXCEPTION_WARNING("nbins cannot be equal to 0. Set 100.","",0); - nbins_ = nbins; - } - catch (const std::exception& e) + class Histo : public PlotBase { - MANAGE_EXCEPTION(e); - nbins_ = 100; - } - // Setting the description: min & max - try - { - if (xmin>=xmax) throw EXCEPTION_WARNING("xmin cannot be equal to or greater than xmax. Setting xmin to 0 and xmax to 100.","",0); - xmin_ = xmin; - xmax_ = xmax; - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - xmin_=0.; - xmax_=100.; - } - - step_ = (xmax_ - xmin_)/static_cast(nbins_); - - // Reseting the histogram array - histo_.resize(nbins_,std::make_pair(0.,0.)); - underflow_ = std::make_pair(0.,0.); - overflow_ = std::make_pair(0.,0.); - - // Reseting statistical counters - sum_w_ = std::make_pair(0.,0.); - sum_ww_ = std::make_pair(0.,0.); - sum_xw_ = std::make_pair(0.,0.); - sum_xxw_ = std::make_pair(0.,0.); - } - - /// Destructor - virtual ~Histo() - { } - - /// Setting the linked regions - void SetSelectionRegions(std::vector myregions) - { regions_.insert(regions_.end(), myregions.begin(), myregions.end()); } - - /// Checking that all regions of the histo are surviving - /// Returns 0 if all regions are failing (includes te case with 0 SR) - /// Returns 1 if all regions are passing - // returns -1 otherwise - MAint32 AllSurviving() - { - if (regions_.size() == 0) return 0; - MAbool FirstRegionSurvival = regions_[0]->IsSurviving(); - for(MAuint32 ii=1; ii < regions_.size(); ii++) - if(regions_[ii]->IsSurviving() != FirstRegionSurvival) return -1; - if(FirstRegionSurvival) return 1; - else return 0; - } - - /// Filling histogram - void Fill(MAfloat64 value, MAfloat64 weight=1.0) - { - // Safety : nan or isinf - try - { - if (std::isnan(value)) throw EXCEPTION_WARNING("Skipping a NaN (Not a Number) value in an histogram.","",0); - if (std::isinf(value)) throw EXCEPTION_WARNING("Skipping a Infinity value in an histogram.","",0); - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - // Positive weight - if (weight>=0) - { - nentries_.first++; - sum_w_.first +=weight; - sum_ww_.first +=weight*weight; - sum_xw_.first +=value*weight; - sum_xxw_.first +=value*value*weight; - if (value < xmin_) underflow_.first+=weight; - else if (value >= xmax_) overflow_.first+=weight; - else - { - histo_[std::floor((value-xmin_)/step_)].first+=weight; - } - } - - // Negative weight - else - { - nentries_.second++; - weight=std::abs(weight); - sum_w_.second += weight; - sum_ww_.second += weight*weight; - sum_xw_.second += value*weight; - sum_xxw_.second += value*value*weight; - if (value < xmin_) underflow_.second+=weight; - else if (value >= xmax_) overflow_.second+=weight; - else - { - histo_[std::floor((value-xmin_)/step_)].second+=weight; - } - } - } - - /// Write the plot in a ROOT file - virtual void Write_TextFormat(std::ostream* output); - - /// Write the plot in a ROOT file - // virtual void Write_RootFormat(std::pair& histos); - - protected: - - /// Write the plot in a ROOT file - virtual void Write_TextFormatBody(std::ostream* output); - -}; + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + /// Each variable is defined with WEIGHTS object which includes positive and negative accessors + /// these are for positive and negative bins. std::map contains a map of + /// different PDF and their corresponding positive and negative weights. + + /// Histogram arrays + std::vector> histo_; + std::vector underflow_; + std::vector overflow_; + + /// Histogram description + MAuint32 nbins_; + MAfloat64 xmin_; + MAfloat64 xmax_; + MAfloat64 step_; + + /// Sum of event-weights over entries + std::vector sum_w_; + + /// Sum of squared weights + std::vector sum_ww_; + + /// Sum of value * weight + std::vector sum_xw_; + + /// Sum of value * value * weight + std::vector sum_xxw_; + + /// RegionSelections attached to the histo + std::vector regions_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + Histo() : PlotBase() + { + nbins_ = 100; + xmin_ = 0; + xmax_ = 100; + step_ = (xmax_ - xmin_) / static_cast(nbins_); + } + + /// Constructor with argument + Histo(const std::string &name) : PlotBase(name) {} + + /// Constructor with argument + Histo(const std::string &name, MAuint32 nbins, MAfloat64 xmin, MAfloat64 xmax) : PlotBase(name) + { + // Setting the description: nbins + try + { + if (nbins == 0) + throw EXCEPTION_WARNING("nbins cannot be equal to 0. 100 bins will be used.", "", 0); + nbins_ = nbins; + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + nbins_ = 100; + } + + // Setting the description: min & max + try + { + if (xmin >= xmax) + throw EXCEPTION_WARNING("xmin cannot be equal to or greater than xmax. Setting xmin to 0 and xmax to 100.", "", 0); + xmin_ = xmin; + xmax_ = xmax; + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + xmin_ = 0.; + xmax_ = 100.; + } + + step_ = (xmax_ - xmin_) / static_cast(nbins_); + + /// resize takes care of initialisation + histo_.resize(nbins_); + } + + /// Destructor + virtual ~Histo() {} + + /// Setting the linked regions + void SetSelectionRegions(std::vector myregions) + { + regions_.insert(regions_.end(), myregions.begin(), myregions.end()); + } + + /// Checking that all regions of the histo are surviving + /// Returns 0 if all regions are failing (includes te case with 0 SR) + /// Returns 1 if all regions are passing + // returns -1 otherwise + MAint32 AllSurviving() + { + if (regions_.size() == 0) + return 0; + MAbool FirstRegionSurvival = regions_[0]->IsSurviving(); + for (MAuint32 ii = 1; ii < regions_.size(); ii++) + if (regions_[ii]->IsSurviving() != FirstRegionSurvival) + return -1; + if (FirstRegionSurvival) + return 1; + else + return 0; + } + + /// Initialise the class + /// @brief Initialise the containers + /// @param weights weight collection + virtual void _initialize(const WeightCollection &multiweight); + + /// Filling histogram + void Fill(MAfloat64 value, const WeightCollection &weights); + + /// Write the plot in a text file + virtual void Write_TextFormat(std::ostream *output); + + protected: + /// Write the plot in a text file + virtual void Write_TextFormatBody(std::ostream *output); + }; } diff --git a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.cpp b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.cpp new file mode 100644 index 00000000..29d037ad --- /dev/null +++ b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.cpp @@ -0,0 +1,147 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +// SampleAnalyzer headers +#include "SampleAnalyzer/Process/Plot/HistoFrequency.h" + +using namespace MA5; + +/// Adding an entry for a given observable +void HistoFrequency::Fill(const MAint32 &obs, WeightCollection &weights) +{ + // value not found, extend the stack + if (stack_.find(obs) == stack_.end()) + stack_[obs].resize(weights.size()); + for (MAuint32 idx = 0; idx < weights.size(); idx++) + { + MAdouble64 w = weights[idx]; + if (w >= 0) + { + nentries_[idx].positive++; + sum_w_[idx].positive += w; + stack_[obs][idx].positive += w; + } + else + { + nentries_[idx].negative++; + sum_w_[idx].negative += std::fabs(w); + stack_[obs][idx].negative += std::fabs(w); + } + } +} + +/// Write the plot in a text file +void HistoFrequency::Write_TextFormat(std::ostream *output) +{ + // Header + *output << "" << std::endl; + + // Description + *output << " " << std::endl; + *output << " \"" << name_ << "\"" << std::endl; + + // SelectionRegions + if (regions_.size() != 0) + { + MAuint32 maxlength = 0; + for (MAuint32 i = 0; i < regions_.size(); i++) + if (regions_[i]->GetName().size() > maxlength) + maxlength = regions_[i]->GetName().size(); + *output << std::left << " # Defined regions" << std::endl; + for (MAuint32 i = 0; i < regions_.size(); i++) + { + *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); + *output << " # Region nr. " << std::fixed << i + 1 << std::endl; + } + } + + // End description + *output << " " << std::endl; + + // Statistics + *output << " " << std::endl; + *output << " "; + for (auto &event : nevents_) + { + output->width(15); + *output << std::fixed << event.positive; + output->width(15); + *output << std::fixed << event.negative; + } + *output << " # nevents" << std::endl; + *output << " "; + for (auto &event : nevents_w_) + { + output->width(15); + *output << std::scientific << event.positive; + output->width(15); + *output << std::scientific << event.negative; + } + *output << " # sum of event-weights over events" << std::endl; + *output << " "; + for (auto &event : nentries_) + { + output->width(15); + *output << std::fixed << event.positive; + output->width(15); + *output << std::fixed << event.negative; + } + *output << " # nentries" << std::endl; + *output << " "; + for (auto &event : sum_w_) + { + output->width(15); + *output << std::scientific << event.positive; + output->width(15); + *output << std::scientific << event.negative; + } + *output << " # sum of event-weights over entries" << std::endl; + *output << " " << std::endl; + + // Data + *output << " " << std::endl; + MAuint32 i = 0; + for (auto &it : stack_) + { + *output << " "; + output->width(15); + *output << std::left << std::fixed << it.first; + + for (auto &weight : it.second) + { + output->width(15); + *output << std::left << std::scientific << weight.positive; + output->width(15); + *output << std::left << std::scientific << weight.negative; + } + if (i < 2 || i >= (stack_.size() - 2)) + *output << " # bin " << i + 1 << " / " << stack_.size(); + *output << std::endl; + i++; + } + *output << " " << std::endl; + + // Footer + *output << "" << std::endl; + *output << std::endl; +} diff --git a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h index 0621881a..4dcc13cb 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoFrequency.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef HISTO_FREQUENCY_H #define HISTO_FREQUENCY_H - // STL headers #include #include @@ -33,212 +31,70 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Process/Plot/PlotBase.h" - +#include "SampleAnalyzer/Process/RegionSelection/RegionSelection.h" namespace MA5 { -class HistoFrequency : public PlotBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected : - - /// Collection of observables - std::map > stack_; - - /// Sum of event-weights over entries - std::pair sum_w_; - - /// RegionSelections attached to the histo - std::vector regions_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - typedef std::map >::iterator iterator; - typedef std::map >::const_iterator const_iterator; - typedef std::map >::size_type size_type; - - /// Constructor with argument - HistoFrequency(const std::string& name) : PlotBase(name) - { - // Reseting statistical counters - sum_w_ = std::make_pair(0.,0.); - } - - /// Destructor - virtual ~HistoFrequency() - { } - - /// Setting the linked regions - void SetSelectionRegions(std::vector myregions) - { regions_.insert(regions_.end(), myregions.begin(), myregions.end()); } - - /// Checking that all regions of the histo are surviving - /// Returns 0 if all regions are failing (includes te case with 0 SR) - /// Returns 1 if all regions are passing - // returns -1 otherwise - MAint32 AllSurviving() - { - if (regions_.size() == 0) return 0; - MAbool FirstRegionSurvival = regions_[0]->IsSurviving(); - for(MAuint32 ii=1; ii < regions_.size(); ii++) - if(regions_[ii]->IsSurviving() != FirstRegionSurvival) return -1; - if(FirstRegionSurvival) return 1; - else return 0; - } - - - /// Adding an entry for a given observable - void Fill(const MAint32& obs, MAfloat64 weight=1.0) - { - // Looking for the value - iterator it = stack_.find(obs); - - // Value not found - if (it==stack_.end()) + class HistoFrequency : public PlotBase { - stack_[obs]=std::make_pair(0.,0.); - } - // Value found - else - { - if (weight>=0) - { - nentries_.first++; - sum_w_.first+=weight; - stack_[obs].first+=weight; - } - else - { - nentries_.second++; - weight=std::abs(weight); - sum_w_.second+=weight; - stack_[obs].second+=weight; - } - } - } - - /// Write the plot in a ROOT file - virtual void Write_TextFormat(std::ostream* output) - { - // Header - *output << "" << std::endl; - - // Description - *output << " " << std::endl; - *output << " \"" << name_ << "\"" << std::endl; - - // SelectionRegions - if(regions_.size()!=0) - { - MAuint32 maxlength=0; - for(MAuint32 i=0; i < regions_.size(); i++) - if (regions_[i]->GetName().size()>maxlength) maxlength=regions_[i]->GetName().size(); - *output << std::left << " # Defined regions" << std::endl; - for(MAuint32 i=0; i < regions_.size(); i++) - { - *output << " " << std::setw(maxlength) << std::left << regions_[i]->GetName(); - *output << " # Region nr. " << std::fixed << i+1 << std::endl; - } - } - - // End description - *output << " " << std::endl; - - // Statistics - *output << " " << std::endl; - *output << " "; - output->width(15); *output << std::fixed << nevents_.first; - output->width(15); *output << std::fixed << nevents_.second; - *output << " # nevents" << std::endl; - *output << " "; - output->width(15); *output << std::scientific << nevents_w_.first; - output->width(15); *output << std::scientific << nevents_w_.second; - *output << " # sum of event-weights over events" << std::endl; - *output << " "; - output->width(15); *output << std::fixed << nentries_.first; - output->width(15); *output << std::fixed << nentries_.second; - *output << " # nentries" << std::endl; - *output << " "; - output->width(15); *output << std::scientific << sum_w_.first; - output->width(15); *output << std::scientific << sum_w_.second; - *output << " # sum of event-weights over entries" << std::endl; - *output << " " << std::endl; - - // Data - *output << " " << std::endl; - MAuint32 i=0; - for (const_iterator it = stack_.begin(); it!=stack_.end(); it++) - { - *output << " "; - output->width(15); *output << std::left << std::fixed << it->first; - output->width(15); *output << std::left << std::scientific << it->second.first; - output->width(15); *output << std::left << std::scientific << it->second.second; - if (i<2 || i>=(stack_.size()-2)) - *output << " # bin " << i+1 << " / " << stack_.size(); - *output << std::endl; - i++; - } - *output << " " << std::endl; - - // Footer - *output << "" << std::endl; - *output << std::endl; - } - - /// Write the plot in a ROOT file - /* - virtual void Write_RootFormat(std::pair& histo) - { - - if (stack_.size()==0) - { - // Creating ROOT histograms - histo.first -> SetBins(1,0.,1.); - histo.second -> SetBins(1,0.,1.); - histo.first -> SetBinContent(1,0); - histo.first->GetXaxis()->SetBinLabel(1,"666"); - histo.second -> SetBinContent(1,0); - histo.second->GetXaxis()->SetBinLabel(1,"666"); - return; - } - - // Creating ROOT histograms - histo.first -> SetBins(stack_.size(),0., - static_cast(stack_.size())); - histo.second -> SetBins(stack_.size(),0., - static_cast(stack_.size())); - - // Layouting the histogram - MAuint32 i=0; - for (const_iterator it=stack_.begin();it!=stack_.end();it++) - { - std::string tmp; - std::stringstream str; - str << it->first; - str >> tmp; - - histo.first -> SetBinContent(i+1,it->second.first); - histo.first->GetXaxis()->SetBinLabel(i+1,tmp.c_str()); - - histo.second -> SetBinContent(i+1,it->second.second); - histo.second->GetXaxis()->SetBinLabel(i+1,tmp.c_str()); - - i++; - } - } - */ - -}; + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + /// Collection of observables + std::map> stack_; + + /// Sum of event-weights over entries + std::vector sum_w_; + + /// RegionSelections attached to the histo + std::vector regions_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor with argument + HistoFrequency(const std::string &name) : PlotBase(name) { initialised_ = false; } + + /// Destructor + virtual ~HistoFrequency() {} + + void _initialize(const WeightCollection &multiweight) { sum_w_.resize(multiweight.size()); } + + /// Setting the linked regions + void SetSelectionRegions(std::vector myregions) + { + regions_.insert(regions_.end(), myregions.begin(), myregions.end()); + } + + /// Checking that all regions of the histo are surviving + /// Returns 0 if all regions are failing (includes te case with 0 SR) + /// Returns 1 if all regions are passing + // returns -1 otherwise + MAint32 AllSurviving() + { + if (regions_.size() == 0) + return 0; + MAbool FirstRegionSurvival = regions_[0]->IsSurviving(); + for (MAuint32 ii = 1; ii < regions_.size(); ii++) + if (regions_[ii]->IsSurviving() != FirstRegionSurvival) + return -1; + if (FirstRegionSurvival) + return 1; + else + return 0; + } + + /// Adding an entry for a given observable + void Fill(const MAint32 &obs, WeightCollection &weights); + + /// Write the plot in a text file + virtual void Write_TextFormat(std::ostream *output); + }; } - #endif diff --git a/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp b/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp index 54d025bc..27b5e2d5 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp +++ b/tools/SampleAnalyzer/Process/Plot/HistoLogX.cpp @@ -1,89 +1,94 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Plot/HistoLogX.h" using namespace MA5; /// Write the plot in a Text file -void HistoLogX::Write_TextFormat(std::ostream* output) +void HistoLogX::Write_TextFormat(std::ostream *output) { - // Header - *output << "" << std::endl; + // Header + *output << "" << std::endl; - // Write the body - Write_TextFormatBody(output); + // Write the body + Write_TextFormatBody(output); - // Foot - *output << "" << std::endl; - *output << std::endl; + // Foot + *output << "" << std::endl; + *output << std::endl; } - -/// Write the plot in a ROOT file -/* -void HistoLogX::Write_RootFormat(std::pair& histo) +void HistoLogX::Fill(MAfloat64 value, const WeightCollection &weights) { - // Creating binning for histograms - MAfloat64 binnings[histo_.size()+1]; - for (MAuint32 i=0;i(10.),static_cast(log_xmin_+i*step_)); - } - binnings[histo_.size()]=xmax_; - - // Creating ROOT histograms - histo.first -> SetBins(nbins_,binnings); - histo.second -> SetBins(nbins_,binnings); + // Safety : nan or isinf + try + { + if (std::isnan(value)) + throw EXCEPTION_WARNING("Skipping a NaN (Not a Number) value in an histogram.", "", 0); + if (std::isinf(value)) + throw EXCEPTION_WARNING("Skipping a Infinity value in an histogram.", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } - // Filling histos - for (MAuint32 i=0;i SetBinContent(i+1,histo_[i].first); - histo.second -> SetBinContent(i+1,histo_[i].second); - } - histo.first -> SetBinContent(0,underflow_.first); - histo.second -> SetBinContent(0,underflow_.second); - histo.first -> SetBinContent(histo_.size()+1,overflow_.first); - histo.second -> SetBinContent(histo_.size()+1,overflow_.second); + for (MAuint32 idx = 0; idx < weights.size(); idx++) + { + MAdouble64 weight = weights[idx]; + // Positive weight + if (weight >= 0) + { + nentries_[idx].positive++; + sum_w_[idx].positive += weight; + sum_ww_[idx].positive += weight * weight; + sum_xw_[idx].positive += value * weight; + sum_xxw_[idx].positive += value * value * weight; + if (value < xmin_) + underflow_[idx].positive += weight; + else if (value >= xmax_) + overflow_[idx].positive += weight; + else + histo_[std::floor((std::log10(value) - log_xmin_) / step_)][idx].positive += weight; + } - // Filling statistics for histo with positive weight - histo.first -> SetEntries(nentries_.first); - MAfloat64 stats[4]; - stats[0]=sum_w_.first; - stats[1]=sum_ww_.first; - stats[2]=sum_xw_.first; - stats[3]=sum_xxw_.first; - histo.first -> PutStats(stats); - - histo.second -> SetEntries(nentries_.second); - stats[0]=sum_w_.second; - stats[1]=sum_ww_.second; - stats[2]=sum_xw_.second; - stats[3]=sum_xxw_.second; - histo.second -> PutStats(stats); + // Negative weight + else + { + nentries_[idx].negative++; + weight = std::fabs(weight); + sum_w_[idx].negative += weight; + sum_ww_[idx].negative += weight * weight; + sum_xw_[idx].negative += value * weight; + sum_xxw_[idx].negative += value * value * weight; + if (value < xmin_) + underflow_[idx].negative += weight; + else if (value >= xmax_) + overflow_[idx].negative += weight; + else + histo_[std::floor((std::log10(value) - log_xmin_) / step_)][idx].negative += weight; + } + } } - -*/ diff --git a/tools/SampleAnalyzer/Process/Plot/HistoLogX.h b/tools/SampleAnalyzer/Process/Plot/HistoLogX.h index 8f992bc8..77bc608a 100644 --- a/tools/SampleAnalyzer/Process/Plot/HistoLogX.h +++ b/tools/SampleAnalyzer/Process/Plot/HistoLogX.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef HISTO_LOGX_H #define HISTO_LOGX_H - // STL headers #include @@ -33,146 +31,92 @@ #include "SampleAnalyzer/Process/Plot/Histo.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - namespace MA5 { -class HistoLogX : public Histo -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected : - - // Histogram boundaries in Log scale - MAfloat64 log_xmin_; - MAfloat64 log_xmax_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor withtout argument - HistoLogX() - { } - - /// Constructor with argument - HistoLogX(const std::string& name, MAuint32 nbins, - MAfloat64 xmin, MAfloat64 xmax) : Histo(name) - { - // Setting the description: nbins - try - { - if (nbins==0) throw EXCEPTION_WARNING("nbins cannot be equal to 0. Set 100.","",0); - nbins_ = nbins; - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - nbins_ = 100; - } - - // Setting the description: min - try + class HistoLogX : public Histo { - if (xmin<=0) throw EXCEPTION_WARNING("xmin cannot be less than or equal to zero. Setting xmin to 0.1","",0); - xmin_ = xmin; - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - xmin_=.1; - } - - // Setting the description: max - try - { - if (xmin>=xmax) throw EXCEPTION_WARNING("xmin cannot be equal to or greater than xmax. Setting xmin to 0.1 and xmax to 100.","",0); - xmax_ = xmax; - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - xmin_=.1; - xmax_=100.; - } - - - log_xmin_=std::log10(xmin_); - log_xmax_=std::log10(xmax_); - step_ = (log_xmax_ - log_xmin_)/static_cast(nbins_); - - // Reseting the histogram array - histo_.resize(nbins_,std::make_pair(0.,0.)); - underflow_ = std::make_pair(0.,0.); - overflow_ = std::make_pair(0.,0.); - - // Reseting statistical counters - sum_w_ = std::make_pair(0.,0.); - sum_ww_ = std::make_pair(0.,0.); - sum_xw_ = std::make_pair(0.,0.); - } - - /// Destructor - virtual ~HistoLogX() - { } - - /// Filling histogram - void Fill(MAfloat64 value, MAfloat64 weight=1.0) - { - // Safety : nan or isinf - try - { - if (std::isnan(value)) throw EXCEPTION_WARNING("Skipping a NaN (Not a Number) value in an histogram.","",0); - if (std::isinf(value)) throw EXCEPTION_WARNING("Skipping a Infinity value in an histogram.","",0); - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - // Positive weight - if (weight>=0) - { - nentries_.first++; - sum_w_.first +=weight; - sum_ww_.first +=weight*weight; - sum_xw_.first +=value*weight; - if (value < xmin_) underflow_.first+=weight; - else if (value >= xmax_) overflow_.first+=weight; - else - { - histo_[std::floor((std::log10(value)-log_xmin_)/step_)].first+=weight; - } - } - - // Negative weight - else - { - nentries_.second++; - weight=std::abs(weight); - sum_w_.second += weight; - sum_ww_.second += weight*weight; - sum_xw_.second += value*weight; - if (value < xmin_) underflow_.second+=weight; - else if (value >= xmax_) overflow_.second+=weight; - else - { - histo_[std::floor((std::log10(value)-log_xmin_)/step_)].second+=weight; - } - } - } - - - /// Write the plot in a Text file - virtual void Write_TextFormat(std::ostream* output); - - // Write the plot in a ROOT file - // virtual void Write_RootFormat(std::pair& histos); - -}; + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + // Histogram boundaries in Log scale + MAfloat64 log_xmin_; + MAfloat64 log_xmax_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor withtout argument + HistoLogX() { initialised_ = false; } + + /// Constructor with argument + HistoLogX(const std::string &name, MAuint32 nbins, + MAfloat64 xmin, MAfloat64 xmax) : Histo(name) + { + // Setting the description: nbins + try + { + if (nbins == 0) + throw EXCEPTION_WARNING("nbins cannot be equal to 0. Using 100 bins.", "", 0); + nbins_ = nbins; + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + nbins_ = 100; + } + + // Setting the description: min + try + { + if (xmin <= 0) + throw EXCEPTION_WARNING("xmin cannot be less than or equal to zero. Setting xmin to 0.1", "", 0); + xmin_ = xmin; + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + xmin_ = .1; + } + + // Setting the description: max + try + { + if (xmin >= xmax) + throw EXCEPTION_WARNING("xmin cannot be equal to or greater than xmax. Setting xmin to 0.1 and xmax to 100.", "", 0); + xmax_ = xmax; + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + xmin_ = .1; + xmax_ = 100.; + } + + log_xmin_ = std::log10(xmin_); + log_xmax_ = std::log10(xmax_); + step_ = (log_xmax_ - log_xmin_) / static_cast(nbins_); + + // Reseting the histogram array + histo_.resize(nbins_); + initialised_ = false; + } + + /// Destructor + virtual ~HistoLogX() {} + + /// Filling histogram + void Fill(MAfloat64 value, const WeightCollection &weights); + + /// Write the plot in a Text file + virtual void Write_TextFormat(std::ostream *output); + + /// @brief initialise the class + virtual void _initialize(const WeightCollection &weights) {} + }; } diff --git a/tools/SampleAnalyzer/Process/Plot/PlotBase.h b/tools/SampleAnalyzer/Process/Plot/PlotBase.h index ea7b203e..ff58aa70 100644 --- a/tools/SampleAnalyzer/Process/Plot/PlotBase.h +++ b/tools/SampleAnalyzer/Process/Plot/PlotBase.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef PLOT_BASE_H #define PLOT_BASE_H - // STL headers #include #include @@ -34,99 +32,117 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Commons/Service/LogService.h" - +#include "SampleAnalyzer/Commons/Base/HistoStructures.h" +#include "SampleAnalyzer/Commons/DataFormat/WeightCollection.h" namespace MA5 { -class PlotBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected : - - /// Name of the plots - std::string name_; - - /// Number of events - std::pair nevents_; - - /// Number of entries - std::pair nentries_; - - /// Sum of event-weight over events - std::pair nevents_w_; - - /// Flag telling whether a given histo has already been modified for an event - MAbool fresh_event_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - PlotBase() - { - // Reseting statistical counters - nevents_ = std::make_pair(0,0); - nentries_ = std::make_pair(0,0); - nevents_w_ = std::make_pair(0,0); - fresh_event_ = true; - } - - /// Constructor with argument - PlotBase(const std::string& name) - { - name_ = name; - nevents_ = std::make_pair(0,0); - nevents_w_ = std::make_pair(0,0); - nentries_ = std::make_pair(0,0); - fresh_event_ = true; - } - - /// Destructor - virtual ~PlotBase() - { } - - /// Accesor for fresh_event - MAbool FreshEvent() { return fresh_event_;} - - /// Modifier for fresh_event - void SetFreshEvent(MAbool tag) { fresh_event_ = tag;} - - /// Write the plot in a ROOT file - virtual void Write_TextFormat(std::ostream* output) = 0; - - /// Increment number of events - void IncrementNEvents(MAfloat64 weight=1.0) - { - if (weight>=0) - { - nevents_.first++; - nevents_w_.first+=weight; - } - else + class PlotBase { - weight = std::abs(weight); - nevents_.second++; - nevents_w_.second+=weight; - } - SetFreshEvent(false); - } - - /// Return Number of events - const std::pair& GetNEvents() - { return nevents_; } - - // Return the name - std::string GetName() - { return name_; } - -}; + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + /// Name of the plots + std::string name_; + + /// @brief number of events. entries object includes positive and negative accessors + std::vector nevents_; + + /// @brief Number of entries + std::vector nentries_; + + /// @brief Sum of event-weight over events + std::vector nevents_w_; + + /// Flag telling whether a given histo has already been modified for an event + MAbool fresh_event_; + + /// @brief is the plot initialised + MAbool initialised_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + PlotBase() + { + // Reseting statistical counters + fresh_event_ = true; + initialised_ = false; + } + + /// Constructor with argument + PlotBase(const std::string &name) + { + name_ = name; + fresh_event_ = true; + initialised_ = false; + } + + /// Destructor + virtual ~PlotBase() {} + + /// Accesor for fresh_event + MAbool FreshEvent() { return fresh_event_; } + + /// Modifier for fresh_event + void SetFreshEvent(MAbool tag, const WeightCollection &EventWeight) + { + Initialize(EventWeight); + fresh_event_ = tag; + } + + /// Write the plot in a ROOT file + virtual void Write_TextFormat(std::ostream *output) = 0; + + /// @brief Initialiser for the classes that inherits this class + virtual void _initialize(const WeightCollection &multiweight) = 0; + + /// @brief Initialise the containers + /// @param multiweight multiweight collection + void Initialize(const WeightCollection &multiweight) + { + if (!initialised_) + { + MAuint32 n = multiweight.size(); + nevents_.resize(n); + nentries_.resize(n); + nevents_w_.resize(n); + _initialize(multiweight); + initialised_ = true; + } + } + + /// Increment number of events + void IncrementNEvents(const WeightCollection &weights) + { + for (MAuint32 idx = 0; idx < weights.size(); idx++) + { + MAdouble64 w = weights[idx]; + if (w >= 0) + { + nevents_[idx].positive++; + nevents_w_[idx].positive += w; + } + else + { + nevents_[idx].negative++; + nevents_w_[idx].negative += std::fabs(w); + } + } + fresh_event_ = false; + } + + /// Return Number of events + const std::vector &GetNEvents() { return nevents_; } + + // Return the name + std::string GetName() { return name_; } + }; } diff --git a/tools/SampleAnalyzer/Process/Plot/PlotManager.h b/tools/SampleAnalyzer/Process/Plot/PlotManager.h index 90a1d987..d5283561 100644 --- a/tools/SampleAnalyzer/Process/Plot/PlotManager.h +++ b/tools/SampleAnalyzer/Process/Plot/PlotManager.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef PLOT_MANAGER_H #define PLOT_MANAGER_H - // STL headers #include #include @@ -39,111 +37,102 @@ #include "SampleAnalyzer/Process/Writer/SAFWriter.h" #include "SampleAnalyzer/Process/RegionSelection/RegionSelection.h" - namespace MA5 { -class PlotManager -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected : - - /// Collection of plots - std::vector plots_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - PlotManager() - { } - - /// Destructor - ~PlotManager() - { } - - /// Reset - void Reset() - { - for (MAuint32 i=0;i GetHistos() - { return plots_; } - - /// Getting thenumber of plots - MAuint32 GetNplots() - { return plots_.size(); } - - /// Adding a 1D histogram with fixed bins - Histo* Add_Histo(const std::string& name, MAuint32 bins, - MAfloat64 xmin, MAfloat64 xmax) - { - Histo* myhisto = new Histo(name, bins, xmin, xmax); - plots_.push_back(myhisto); - return myhisto; - } - - Histo* Add_Histo(const std::string& name, MAuint32 bins, - MAfloat64 xmin, MAfloat64 xmax, std::vector regions) - { - Histo* myhisto = new Histo(name, bins, xmin, xmax); - myhisto->SetSelectionRegions(regions); - plots_.push_back(myhisto); - return myhisto; - } - - /// Adding a 1D histogram with a log binning - HistoLogX* Add_HistoLogX(const std::string& name, MAuint32 bins, - MAfloat64 xmin, MAfloat64 xmax) - { - HistoLogX* myhisto = new HistoLogX(name, bins, xmin, xmax); - plots_.push_back(myhisto); - return myhisto; - } - - HistoLogX* Add_HistoLogX(const std::string& name, MAuint32 bins, - MAfloat64 xmin, MAfloat64 xmax, std::vector regions) - { - HistoLogX* myhisto = new HistoLogX(name, bins, xmin, xmax); - myhisto->SetSelectionRegions(regions); - plots_.push_back(myhisto); - return myhisto; - } - - /// Adding a 1D histogram for frequency - HistoFrequency* Add_HistoFrequency(const std::string& name) - { - HistoFrequency* myhisto = new HistoFrequency(name); - plots_.push_back(myhisto); - return myhisto; - } - - HistoFrequency* Add_HistoFrequency(const std::string& name, std::vector regions) - { - HistoFrequency* myhisto = new HistoFrequency(name); - myhisto->SetSelectionRegions(regions); - plots_.push_back(myhisto); - return myhisto; - } - - /// Write the counters in a Text file - void Write_TextFormat(SAFWriter& output); - - /// Finalizing - void Finalize() - { Reset(); } - -}; + class PlotManager + { + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + /// Collection of plots + std::vector plots_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + PlotManager() {} + + /// Destructor + ~PlotManager() {} + + /// Reset + void Reset() + { + for (MAuint32 i = 0; i < plots_.size(); i++) + if (plots_[i] != 0) + delete plots_[i]; + plots_.clear(); + } + + /// Get method + std::vector GetHistos() { return plots_; } + + /// Getting thenumber of plots + MAuint32 GetNplots() { return plots_.size(); } + + /// Adding a 1D histogram with fixed bins + Histo *Add_Histo(const std::string &name, MAuint32 bins, + MAfloat64 xmin, MAfloat64 xmax) + { + Histo *myhisto = new Histo(name, bins, xmin, xmax); + plots_.push_back(myhisto); + return myhisto; + } + + Histo *Add_Histo(const std::string &name, MAuint32 bins, + MAfloat64 xmin, MAfloat64 xmax, std::vector regions) + { + Histo *myhisto = new Histo(name, bins, xmin, xmax); + myhisto->SetSelectionRegions(regions); + plots_.push_back(myhisto); + return myhisto; + } + + /// Adding a 1D histogram with a log binning + HistoLogX *Add_HistoLogX(const std::string &name, MAuint32 bins, + MAfloat64 xmin, MAfloat64 xmax) + { + HistoLogX *myhisto = new HistoLogX(name, bins, xmin, xmax); + plots_.push_back(myhisto); + return myhisto; + } + + HistoLogX *Add_HistoLogX(const std::string &name, MAuint32 bins, + MAfloat64 xmin, MAfloat64 xmax, std::vector regions) + { + HistoLogX *myhisto = new HistoLogX(name, bins, xmin, xmax); + myhisto->SetSelectionRegions(regions); + plots_.push_back(myhisto); + return myhisto; + } + + /// Adding a 1D histogram for frequency + HistoFrequency *Add_HistoFrequency(const std::string &name) + { + HistoFrequency *myhisto = new HistoFrequency(name); + plots_.push_back(myhisto); + return myhisto; + } + + HistoFrequency *Add_HistoFrequency(const std::string &name, std::vector regions) + { + HistoFrequency *myhisto = new HistoFrequency(name); + myhisto->SetSelectionRegions(regions); + plots_.push_back(myhisto); + return myhisto; + } + + /// Write the counters in a Text file + void Write_TextFormat(SAFWriter &output); + + /// Finalizing + void Finalize() { Reset(); } + }; } diff --git a/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp b/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp index 6825bc58..bfe3d0b4 100644 --- a/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp +++ b/tools/SampleAnalyzer/Process/Reader/HEPMCReader.cpp @@ -1,27 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // STL headers #include @@ -30,32 +29,31 @@ #include "SampleAnalyzer/Commons/Service/LogService.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - using namespace MA5; - // ----------------------------------------------------------------------------- // ReadHeader // ----------------------------------------------------------------------------- -MAbool HEPMCReader::ReadHeader(SampleFormat& mySample) +MAbool HEPMCReader::ReadHeader(SampleFormat &mySample) { // Reset the saved line - savedline_=""; + savedline_ = ""; // Initialize MC mySample.InitializeMC(); mySample.SetSampleFormat(MA5FORMAT::HEPMC); mySample.SetSampleGenerator(MA5GEN::UNKNOWN); - warnmother_=true; + warnmother_ = true; // Skipping header line until first event line std::string firstWord; std::string line; - while(firstWord!="E") + while (firstWord != "E") { // Getting the next non-empty line - if (!ReadLine(line)) return false; + if (!ReadLine(line)) + return false; // Splitting the line in words std::stringstream str; @@ -65,17 +63,16 @@ MAbool HEPMCReader::ReadHeader(SampleFormat& mySample) str >> firstWord; } - savedline_ = line; + savedline_ = line; // Normal end return true; } - // ----------------------------------------------------------------------------- // FinalizeHeader // ----------------------------------------------------------------------------- -MAbool HEPMCReader::FinalizeHeader(SampleFormat& mySample) +MAbool HEPMCReader::FinalizeHeader(SampleFormat &mySample) { return true; } @@ -83,7 +80,7 @@ MAbool HEPMCReader::FinalizeHeader(SampleFormat& mySample) // ----------------------------------------------------------------------------- // ReadEvent // ----------------------------------------------------------------------------- -StatusCode::Type HEPMCReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySample) +StatusCode::Type HEPMCReader::ReadEvent(EventFormat &myEvent, SampleFormat &mySample) { // Initializing MC event myEvent.InitializeMC(); @@ -91,27 +88,30 @@ StatusCode::Type HEPMCReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySa // Allocating memory for all particles myEvent.mc()->particles_.reserve(nparts_max_); - MAbool eventOnGoing=false; + MAbool eventOnGoing = false; // Read the saved line - if (savedline_!="") + if (savedline_ != "") { FillEvent(savedline_, myEvent, mySample); - eventOnGoing=true; - savedline_=""; + eventOnGoing = true; + savedline_ = ""; } - MAbool endEvent=false; + MAbool endEvent = false; // Loop over particle - while(!endEvent) + while (!endEvent) { std::string line; // Getting a line from the file if (!ReadLine(line)) { - if (eventOnGoing) return StatusCode::KEEP; else return StatusCode::FAILURE; + if (eventOnGoing) + return StatusCode::KEEP; + else + return StatusCode::FAILURE; } // Splitting the line in words @@ -123,16 +123,16 @@ StatusCode::Type HEPMCReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySa str >> firstWord; // Is next event ? - if (firstWord=="E") + if (firstWord == "E") { - savedline_ = line; + savedline_ = line; return StatusCode::KEEP; } else { // Decoding the line - endEvent=!FillEvent(line, myEvent, mySample); - eventOnGoing=true; + endEvent = !FillEvent(line, myEvent, mySample); + eventOnGoing = true; } } @@ -140,67 +140,74 @@ StatusCode::Type HEPMCReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySa return StatusCode::KEEP; } - - // ----------------------------------------------------------------------------- // FinalizeEvent // ----------------------------------------------------------------------------- -MAbool HEPMCReader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) +MAbool HEPMCReader::FinalizeEvent(SampleFormat &mySample, EventFormat &myEvent) { // Compute max numbers of particles & vertices - if (myEvent.mc()->particles_.size()>nparts_max_) nparts_max_=myEvent.mc()->particles_.size(); - + if (myEvent.mc()->particles_.size() > nparts_max_) + nparts_max_ = myEvent.mc()->particles_.size(); // Fill vertices information - for (std::map::iterator it=vertices_.begin(); it!=vertices_.end(); it++) + for (std::map::iterator it = vertices_.begin(); it != vertices_.end(); it++) { // Decay position & lifetime - for (MAuint32 i=0;isecond.in_.size();i++) + for (MAuint32 i = 0; i < it->second.in_.size(); i++) { - MCParticleFormat* part = &(myEvent.mc()->particles_[it->second.in_[i]]); - part->decay_vertex_.SetXYZT(it->second.x_,it->second.y_,it->second.z_,it->second.ctau_); + MCParticleFormat *part = &(myEvent.mc()->particles_[it->second.in_[i]]); + part->decay_vertex_.SetXYZT(it->second.x_, it->second.y_, it->second.z_, it->second.ctau_); } // Mother+daughter relations - for (MAuint32 i=0;isecond.in_.size();i++) + for (MAuint32 i = 0; i < it->second.in_.size(); i++) { - for (MAuint32 j=0;jsecond.out_.size();j++) + for (MAuint32 j = 0; j < it->second.out_.size(); j++) { - MCParticleFormat* mum = &(myEvent.mc()->particles_[it->second.in_[i]]); - MCParticleFormat* dau = &(myEvent.mc()->particles_[it->second.out_[j]]); + MCParticleFormat *mum = &(myEvent.mc()->particles_[it->second.in_[i]]); + MCParticleFormat *dau = &(myEvent.mc()->particles_[it->second.out_[j]]); // Deal with HERWIG initial particle : initial part = part whose mother is itself - if (mum!=dau) + if (mum != dau) { // Safety: be sure to have not 2 same daughters - MAbool found=false; - for (MAuint32 h=0;hdaughters().size();h++) + MAbool found = false; + for (MAuint32 h = 0; h < mum->daughters().size(); h++) { - if (mum->daughters()[h]==dau) {found=true; break;} + if (mum->daughters()[h] == dau) + { + found = true; + break; + } } - if (!found) mum -> daughters().push_back(dau); + if (!found) + mum->daughters().push_back(dau); // Safety: be sure to have not 2 same mothers - found=false; - for (MAuint32 h=0;hmothers().size();h++) + found = false; + for (MAuint32 h = 0; h < dau->mothers().size(); h++) { - if (dau->mothers()[h]==mum) {found=true; break;} + if (dau->mothers()[h] == mum) + { + found = true; + break; + } } - if (!found) dau -> mothers().push_back(mum); + if (!found) + dau->mothers().push_back(mum); } } } } vertices_.clear(); - // Computing met, mht, ... - for (MAuint32 i=0; iparticles_.size();i++) + for (MAuint32 i = 0; i < myEvent.mc()->particles_.size(); i++) { - MCParticleFormat& part = myEvent.mc()->particles_[i]; + MCParticleFormat &part = myEvent.mc()->particles_[i]; // MET, MHT, TET, THT - if (part.statuscode()==1 && !PHYSICS->Id->IsInvisible(part)) + if (part.statuscode() == 1 && !PHYSICS->Id->IsInvisible(part)) { myEvent.mc()->MET_ -= part.momentum(); myEvent.mc()->TET_ += part.pt(); @@ -224,15 +231,14 @@ MAbool HEPMCReader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) return true; } - //------------------------------------------------------------------------------ // FillWeightNames //------------------------------------------------------------------------------ -MAbool HEPMCReader::FillWeightNames(const std::string& line) +MAbool HEPMCReader::FillWeightNames(const std::string &line, SampleFormat &mySample) { // Splitting line in words std::stringstream str; - str << line ; + str << line; // Getting the first word std::string firstWord; @@ -246,80 +252,92 @@ MAbool HEPMCReader::FillWeightNames(const std::string& line) std::vector weight_names(nweights); // Filling weight names - for (MAuint32 i=0;i> tmp; - if (tmp=="") continue; + if (tmp == "") + continue; - if (tmp[0]=='"' && tmp[tmp.size()-1]=='"') tmp=tmp.substr(1,tmp.size()-2); - weight_names[i]=tmp; + if (tmp[0] == '"' && tmp[tmp.size() - 1] == '"') + tmp = tmp.substr(1, tmp.size() - 2); + weight_names[i] = tmp; + mySample.mc()->SetWeightName(i, tmp); } // Ok return true; } - //------------------------------------------------------------------------------ // FillHeavyIons //------------------------------------------------------------------------------ -MAbool HEPMCReader::FillHeavyIons(const std::string& line) +MAbool HEPMCReader::FillHeavyIons(const std::string &line) { try { - if (line!="") if (firstHeavyIons_) throw EXCEPTION_WARNING("HeavyIons block is not read by SampleAnalyzer","",0); + if (line != "") + if (firstHeavyIons_) + throw EXCEPTION_WARNING("HeavyIons block is not read by SampleAnalyzer", "", 0); } - catch(const std::exception& e) + catch (const std::exception &e) { MANAGE_EXCEPTION(e); } - firstHeavyIons_=false; + firstHeavyIons_ = false; return false; } - //------------------------------------------------------------------------------ // FillEventHeader //------------------------------------------------------------------------------ -MAbool HEPMCReader::FillEvent(const std::string& line, - EventFormat& myEvent, - SampleFormat& mySample) +MAbool HEPMCReader::FillEvent(const std::string &line, + EventFormat &myEvent, + SampleFormat &mySample) { // Splitting line in words std::stringstream str; - str << line ; + str << line; // Getting the first word std::string firstWord; str >> firstWord; // Event global info - if(firstWord=="E") FillEventInformations(line, myEvent); + if (firstWord == "E") + FillEventInformations(line, myEvent); // Weight names - else if (firstWord=="N") FillWeightNames(line); + else if (firstWord == "N") + FillWeightNames(line, mySample); // Event units - else if (firstWord=="U") FillUnits(line, mySample); + else if (firstWord == "U") + FillUnits(line, mySample); // Cross section - else if (firstWord=="C") FillCrossSection(line,mySample); + else if (firstWord == "C") + FillCrossSection(line, mySample); // HeavyIon line - else if (firstWord=="H") FillHeavyIons(line); + else if (firstWord == "H") + FillHeavyIons(line); // PDF Info - else if (firstWord=="F") FillEventPDFInfo(line,mySample,myEvent); + else if (firstWord == "F") + FillEventPDFInfo(line, mySample, myEvent); // Vertex line - else if (firstWord=="V") FillEventVertexLine(line,myEvent); + else if (firstWord == "V") + FillEventVertexLine(line, myEvent); // Particle Line - else if (firstWord=="P") FillEventParticleLine(line,myEvent); + else if (firstWord == "P") + FillEventParticleLine(line, myEvent); // End - else if (firstWord=="HepMC::IO_GenEvent-END_EVENT_LISTING") return false; + else if (firstWord == "HepMC::IO_GenEvent-END_EVENT_LISTING") + return false; // Other cases else @@ -327,9 +345,9 @@ MAbool HEPMCReader::FillEvent(const std::string& line, // ignore other cases try { - throw EXCEPTION_WARNING("HEPMC linecode unknown","",0); + throw EXCEPTION_WARNING("HEPMC linecode unknown", "", 0); } - catch(const std::exception& e) + catch (const std::exception &e) { MANAGE_EXCEPTION(e); } @@ -342,14 +360,14 @@ MAbool HEPMCReader::FillEvent(const std::string& line, // ----------------------------------------------------------------------------- // FillEventInformations // ----------------------------------------------------------------------------- -void HEPMCReader::FillEventInformations(const std::string& line, - EventFormat& myEvent) +void HEPMCReader::FillEventInformations(const std::string &line, + EventFormat &myEvent) { std::stringstream str; str << line; std::string firstc; - MAint32 tmp=0; + MAint32 tmp = 0; // Filling general info str >> firstc; // character 'E' @@ -366,32 +384,33 @@ void HEPMCReader::FillEventInformations(const std::string& line, // Extracting random state list str >> tmp; - if (tmp>0) + if (tmp > 0) { std::vector randoms(static_cast(tmp)); - for (MAuint32 i=0;i> randoms[i]; + for (MAuint32 i = 0; i < randoms.size(); i++) + str >> randoms[i]; } // Extracting weight lists str >> tmp; - if (tmp>0) + if (tmp > 0) { - MAuint32 nweights=static_cast(tmp); - for (MAuint32 i=0;i(tmp); + std::vector w(nweights, 0.0); + for (MAuint32 i = 0; i < nweights; i++) { MAfloat64 value; str >> value; - if (i==0) myEvent.mc()->weight_=value; - myEvent.mc()->multiweights().Add(i+1,value); + w.at(i) = value; + } + myEvent.mc()->setWeights(w); } - } - } // ----------------------------------------------------------------------------- // FillUnits // ----------------------------------------------------------------------------- -void HEPMCReader::FillUnits(const std::string& line, SampleFormat& mySample) +void HEPMCReader::FillUnits(const std::string &line, SampleFormat &mySample) { std::stringstream str; str << line; @@ -402,29 +421,34 @@ void HEPMCReader::FillUnits(const std::string& line, SampleFormat& mySample) // Unit of energy str >> tmp; - if (tmp=="GEV") energy_unit_=1; - else if (tmp=="MEV") energy_unit_=0.001; - else if (tmp=="KEV") energy_unit_=0.000001; - else ERROR << "Unknown unit of energy: " << tmp << endmsg; + if (tmp == "GEV") + energy_unit_ = 1; + else if (tmp == "MEV") + energy_unit_ = 0.001; + else if (tmp == "KEV") + energy_unit_ = 0.000001; + else + ERROR << "Unknown unit of energy: " << tmp << endmsg; // Unit of length str >> tmp; - if (tmp=="MM") length_unit_=1; - else if (tmp=="CM") length_unit_=0.1; - else ERROR << "Unknown unit of length: " << tmp << endmsg; + if (tmp == "MM") + length_unit_ = 1; + else if (tmp == "CM") + length_unit_ = 0.1; + else + ERROR << "Unknown unit of length: " << tmp << endmsg; /// Set length and energy units mySample.mc()->SetLengthUnit(length_unit_); mySample.mc()->SetEnergyUnit(energy_unit_); - } - // ----------------------------------------------------------------------------- // FillCrossSection // ----------------------------------------------------------------------------- -void HEPMCReader::FillCrossSection(const std::string& line, - SampleFormat& mySample) +void HEPMCReader::FillCrossSection(const std::string &line, + SampleFormat &mySample) { // Splitting the line in words std::stringstream str; @@ -435,15 +459,15 @@ void HEPMCReader::FillCrossSection(const std::string& line, str >> firstc; // xsection mean - MAfloat64 xsectmp=0; + MAfloat64 xsectmp = 0; str >> xsectmp; // xsection error - MAfloat64 xsectmp_err=0; + MAfloat64 xsectmp_err = 0; str >> xsectmp_err; // saving xsection mean & error - if (mySample.mc()!=0) + if (mySample.mc() != 0) { mySample.mc()->setXsectionMean(xsectmp); mySample.mc()->setXsectionError(xsectmp_err); @@ -453,9 +477,9 @@ void HEPMCReader::FillCrossSection(const std::string& line, // ----------------------------------------------------------------------------- // FillEventPDFInfo // ----------------------------------------------------------------------------- -void HEPMCReader::FillEventPDFInfo(const std::string& line, - SampleFormat& mySample, - EventFormat& myEvent) +void HEPMCReader::FillEventPDFInfo(const std::string &line, + SampleFormat &mySample, + EventFormat &myEvent) { std::stringstream str; str << line; @@ -475,23 +499,23 @@ void HEPMCReader::FillEventPDFInfo(const std::string& line, // ----------------------------------------------------------------------------- // FillEventParticleLine // ----------------------------------------------------------------------------- -void HEPMCReader::FillEventParticleLine(const std::string& line, - EventFormat& myEvent) +void HEPMCReader::FillEventParticleLine(const std::string &line, + EventFormat &myEvent) { std::stringstream str; str << line; - MAfloat64 tmp; // temporary variable to fill in LorentzVector + MAfloat64 tmp; // temporary variable to fill in LorentzVector // Get a new particle - MCParticleFormat * part = myEvent.mc()->GetNewParticle(); + MCParticleFormat *part = myEvent.mc()->GetNewParticle(); MAchar linecode; - MAfloat64 px=0.; - MAfloat64 py=0.; - MAfloat64 pz=0.; - MAfloat64 e=0.; - MAuint32 partnum; - MAint32 decay_barcode; + MAfloat64 px = 0.; + MAfloat64 py = 0.; + MAfloat64 pz = 0.; + MAfloat64 e = 0.; + MAuint32 partnum; + MAint32 decay_barcode; str >> linecode; // letter 'P' str >> partnum; // particle number @@ -509,21 +533,20 @@ void HEPMCReader::FillEventParticleLine(const std::string& line, // MAuint32 barcode; // barcode = an integer which uniquely // str >> barcode; // identifies the GenParticle within the event. + part->momentum_.SetPxPyPzE(px * energy_unit_, + py * energy_unit_, + pz * energy_unit_, + e * energy_unit_); - part->momentum_.SetPxPyPzE (px * energy_unit_, - py * energy_unit_, - pz * energy_unit_, - e * energy_unit_); - - MAuint32 part_index = myEvent.mc()->particles_.size()-1; + MAuint32 part_index = myEvent.mc()->particles_.size() - 1; // Set production vertex - std::pair::iterator,MAbool> ret; - ret = vertices_.insert(std::make_pair(currentvertex_,HEPVertex())); + std::pair::iterator, MAbool> ret; + ret = vertices_.insert(std::make_pair(currentvertex_, HEPVertex())); ret.first->second.out_.push_back(part_index); // Set decay vertex - ret = vertices_.insert(std::make_pair(decay_barcode,HEPVertex())); + ret = vertices_.insert(std::make_pair(decay_barcode, HEPVertex())); ret.first->second.in_.push_back(part_index); // Ok @@ -533,7 +556,7 @@ void HEPMCReader::FillEventParticleLine(const std::string& line, // ----------------------------------------------------------------------------- // FillEventVertexLine // ----------------------------------------------------------------------------- -void HEPMCReader::FillEventVertexLine(const std::string& line, EventFormat& myEvent) +void HEPMCReader::FillEventVertexLine(const std::string &line, EventFormat &myEvent) { std::stringstream str; str << line; @@ -542,26 +565,25 @@ void HEPMCReader::FillEventVertexLine(const std::string& line, EventFormat& myEv MAint32 barcode; HEPVertex vertex; - str >> linecode; // character 'V' - str >> barcode; // barcode - str >> vertex.id_; // id - str >> vertex.x_; // x - str >> vertex.y_; // y - str >> vertex.z_; // z - str >> vertex.ctau_; // ctau + str >> linecode; // character 'V' + str >> barcode; // barcode + str >> vertex.id_; // id + str >> vertex.x_; // x + str >> vertex.y_; // y + str >> vertex.z_; // z + str >> vertex.ctau_; // ctau // Adding this vertex to the vertex collection - std::pair::iterator,MAbool> res = vertices_.insert(std::make_pair(barcode,vertex)); + std::pair::iterator, MAbool> res = vertices_.insert(std::make_pair(barcode, vertex)); if (!res.second) { - res.first->second.id_ = vertex.id_; - res.first->second.x_ = vertex.x_; - res.first->second.y_ = vertex.y_; - res.first->second.z_ = vertex.z_; + res.first->second.id_ = vertex.id_; + res.first->second.x_ = vertex.x_; + res.first->second.y_ = vertex.y_; + res.first->second.z_ = vertex.z_; res.first->second.ctau_ = vertex.ctau_; } // Set the current vertex barcode currentvertex_ = barcode; } - diff --git a/tools/SampleAnalyzer/Process/Reader/HEPMCReader.h b/tools/SampleAnalyzer/Process/Reader/HEPMCReader.h index 1e9e594d..10a30d85 100644 --- a/tools/SampleAnalyzer/Process/Reader/HEPMCReader.h +++ b/tools/SampleAnalyzer/Process/Reader/HEPMCReader.h @@ -1,122 +1,123 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef HEPMC_READER_h #define HEPMC_READER_h - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Reader/ReaderTextBase.h" - namespace MA5 { -class HEPMCReader : public ReaderTextBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected: - - MAbool firstevent_; - MAbool endevent_; - MAbool saved_; - MAbool EndOfFile_; - MAbool warnmother_; - MAint32 partcode_; - MAint32 vertcode_; - MAfloat32 energy_unit_; - MAfloat32 length_unit_; - std::string savedline_; // last saved line - MAbool firstHeavyIons_; - MAuint64 nparts_max_; - MAuint64 nvertices_max_; - - struct HEPVertex - { - MAfloat64 ctau_; - MAfloat64 id_; - MAfloat64 x_; - MAfloat64 y_; - MAfloat64 z_; - MAint32 barcode_; - std::vector in_; - std::vector out_; - HEPVertex() - { ctau_=0; id_=0; x_=0; y_=0; z_=0; barcode_=0; } - }; - - std::map vertices_; - MAint32 currentvertex_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public: - - /// Constructor without argument - HEPMCReader() - { - firstevent_=false; - firstHeavyIons_=true; - nparts_max_=0; - nvertices_max_=0; - energy_unit_ = 1.0; - length_unit_ = 1.0; - } - - /// Destructor - virtual ~HEPMCReader() - { } - - /// Read the header - virtual MAbool ReadHeader(SampleFormat& mySample); - - /// Finalize the header - virtual MAbool FinalizeHeader(SampleFormat& mySample); - - /// Read the event - virtual StatusCode::Type ReadEvent(EventFormat& myEvent, SampleFormat& mySample); - - /// Finalize the event - virtual MAbool FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent); - - private: - - MAbool FillEvent(const std::string& line, EventFormat& myEvent, SampleFormat& mySample); - void FillEventInformations(const std::string& line, EventFormat& myEvent); - void FillCrossSection(const std::string& line, SampleFormat& mySample); - void FillUnits(const std::string& line, SampleFormat& mySample); - void FillEventPDFInfo(const std::string& line, SampleFormat& mySample, EventFormat& myEvent); - void FillEventParticleLine(const std::string& line, EventFormat& myEvent); - void FillEventVertexLine(const std::string& line, EventFormat& myEvent); - MAbool FillWeightNames(const std::string& line); - MAbool FillHeavyIons(const std::string& line); - -}; + class HEPMCReader : public ReaderTextBase + { + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + MAbool firstevent_; + MAbool endevent_; + MAbool saved_; + MAbool EndOfFile_; + MAbool warnmother_; + MAint32 partcode_; + MAint32 vertcode_; + MAfloat32 energy_unit_; + MAfloat32 length_unit_; + std::string savedline_; // last saved line + MAbool firstHeavyIons_; + MAuint64 nparts_max_; + MAuint64 nvertices_max_; + + struct HEPVertex + { + MAfloat64 ctau_; + MAfloat64 id_; + MAfloat64 x_; + MAfloat64 y_; + MAfloat64 z_; + MAint32 barcode_; + std::vector in_; + std::vector out_; + HEPVertex() + { + ctau_ = 0; + id_ = 0; + x_ = 0; + y_ = 0; + z_ = 0; + barcode_ = 0; + } + }; + + std::map vertices_; + MAint32 currentvertex_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + HEPMCReader() + { + firstevent_ = false; + firstHeavyIons_ = true; + nparts_max_ = 0; + nvertices_max_ = 0; + energy_unit_ = 1.0; + length_unit_ = 1.0; + } + + /// Destructor + virtual ~HEPMCReader() + { + } + + /// Read the header + virtual MAbool ReadHeader(SampleFormat &mySample); + + /// Finalize the header + virtual MAbool FinalizeHeader(SampleFormat &mySample); + + /// Read the event + virtual StatusCode::Type ReadEvent(EventFormat &myEvent, SampleFormat &mySample); + + /// Finalize the event + virtual MAbool FinalizeEvent(SampleFormat &mySample, EventFormat &myEvent); + + private: + MAbool FillEvent(const std::string &line, EventFormat &myEvent, SampleFormat &mySample); + void FillEventInformations(const std::string &line, EventFormat &myEvent); + void FillCrossSection(const std::string &line, SampleFormat &mySample); + void FillUnits(const std::string &line, SampleFormat &mySample); + void FillEventPDFInfo(const std::string &line, SampleFormat &mySample, EventFormat &myEvent); + void FillEventParticleLine(const std::string &line, EventFormat &myEvent); + void FillEventVertexLine(const std::string &line, EventFormat &myEvent); + MAbool FillWeightNames(const std::string &line, SampleFormat &mySample); + MAbool FillHeavyIons(const std::string &line); + }; } diff --git a/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp b/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp index d3bed1a6..e1c33b5b 100644 --- a/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp +++ b/tools/SampleAnalyzer/Process/Reader/LHEReader.cpp @@ -1,27 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // STL headers #include #include @@ -31,264 +30,275 @@ #include "SampleAnalyzer/Commons/Service/LogService.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - using namespace MA5; // ----------------------------------------------------------------------------- // ReadHeader // ----------------------------------------------------------------------------- -MAbool LHEReader::ReadHeader(SampleFormat& mySample) +MAbool LHEReader::ReadHeader(SampleFormat &mySample) { - // Initiliaze MC - mySample.InitializeMC(); + // Initiliaze MC + mySample.InitializeMC(); - // Declaring a new string for line - std::string line; + // Declaring a new string for line + std::string line; - // Generator tags - MAbool tag_calchep = false; - MAbool tag_mg5 = false; - MAbool tag_ma5 = false; - MAbool tag_simplified_pythia = false; - MAbool tag_simplified_ma5 = false; + // Generator tags + MAbool tag_calchep = false; + MAbool tag_mg5 = false; + MAbool tag_ma5 = false; + MAbool tag_simplified_pythia = false; + MAbool tag_simplified_ma5 = false; - // Read line by line the file until tag
- // Note from Benj: the header tags are optional according to LHE standards - // the init tags are alsways the last ones before the events - MAbool EndOfLoop=false, GoodInit = false; + // Read line by line the file until tag
+ // Note from Benj: the header tags are optional according to LHE standards + // the init tags are always the last ones before the events + MAbool EndOfLoop = false, GoodInit = false; - while(!GoodInit) - { - MAbool HeaderFound = false, InitFound = false; - do + while (!GoodInit) { - if (!ReadLine(line)) return false; - HeaderFound = (line.find("
")!=std::string::npos); - InitFound = (line.find("")!=std::string::npos); - EndOfLoop = HeaderFound || InitFound; + MAbool HeaderFound = false, InitFound = false; + do + { + if (!ReadLine(line)) + return false; + HeaderFound = (line.find("
") != std::string::npos); + InitFound = (line.find("") != std::string::npos); + EndOfLoop = HeaderFound || InitFound; + } while (!EndOfLoop); + + // Read line by line the file until tag
+ // Store the header + if (HeaderFound) + { + EndOfLoop = false; + MAbool in_weights = false; + do + { + if (!ReadLine(line, false)) + return false; + EndOfLoop = (line.find("
") != std::string::npos); + if (EndOfLoop) + continue; + else + mySample.AddHeader(line); + + // Weight initialisation + if (line.find("") != std::string::npos) + in_weights = true; + if (line.find("") != std::string::npos) + in_weights = false; + if (in_weights) + FillWeightNames(line, mySample); + + if ((line.find("") != std::string::npos) || + (line.find("") != std::string::npos) || + (line.find("") != std::string::npos)) + tag_mg5 = true; + if ((line.find(" LHE format ") != std::string::npos)) + tag_ma5 = true; + if ((line.find("CalcHEP") != std::string::npos)) + tag_calchep = true; + if ((line.find("") != std::string::npos) || + (line.find("") != std::string::npos)) + tag_simplified_pythia = true; + if ((line.find(" Simplified LHE format ") != std::string::npos)) + tag_simplified_ma5 = true; + } while (!EndOfLoop); + } + + if (InitFound) + { + // Read line by line the file until tag + EndOfLoop = false; + MAbool first = true; + do + { + if (!ReadLine(line)) + return false; + EndOfLoop = (line.find("") != std::string::npos); + if (!EndOfLoop) + { + if (first) + FillHeaderInitLine(line, mySample); + else + FillHeaderProcessLine(line, mySample); + } + first = false; + } while (!EndOfLoop); + GoodInit = true; + } } - while(!EndOfLoop); - // Read line by line the file until tag
- // Store the header - if(HeaderFound) + // Read line by line the file until tag + EndOfLoop = false; + do { - EndOfLoop=false; - do - { - if (!ReadLine(line,false)) return false; - EndOfLoop = (line.find("
")!=std::string::npos); - if (EndOfLoop) continue; - else mySample.AddHeader(line); - if ( (line.find("")!=std::string::npos) || - (line.find("")!=std::string::npos) || - (line.find("")!=std::string::npos) ) - tag_mg5=true; - if ( (line.find(" LHE format ")!=std::string::npos) ) - tag_ma5=true; - if ( (line.find("CalcHEP")!=std::string::npos) ) tag_calchep=true; - if ( (line.find("")!=std::string::npos) || - (line.find("")!=std::string::npos) ) - tag_simplified_pythia=true; - if ( (line.find(" Simplified LHE format ")!=std::string::npos) ) - tag_simplified_ma5=true; - } - while(!EndOfLoop); + if (!ReadLine(line)) + return false; + if ((line.find("") != std::string::npos) || + (line.find("") != std::string::npos) || + (line.find("") != std::string::npos)) + tag_mg5 = true; + if ((line.find(" LHE format ") != std::string::npos)) + tag_ma5 = true; + if ((line.find("") != std::string::npos) || + (line.find("") != std::string::npos)) + tag_simplified_pythia = true; + if ((line.find(" Simplified LHE format ") != std::string::npos)) + tag_simplified_ma5 = true; + EndOfLoop = (line.find("") != std::string::npos); + } while (!EndOfLoop); + + // Determining sample format + if (tag_simplified_pythia || tag_simplified_ma5) + { + mySample.SetSampleFormat(MA5FORMAT::SIMPLIFIED_LHE); } - - if(InitFound) + else { - // Read line by line the file until tag - EndOfLoop=false; - MAbool first=true; - do - { - if (!ReadLine(line)) return false; - EndOfLoop = (line.find("")!=std::string::npos); - if (!EndOfLoop) - { - if (first) FillHeaderInitLine(line,mySample); - else FillHeaderProcessLine(line,mySample); - } - first=false; - } - while(!EndOfLoop); - GoodInit = true; + mySample.SetSampleFormat(MA5FORMAT::LHE); } - } - - // Read line by line the file until tag - EndOfLoop=false; - do - { - if (!ReadLine(line)) return false; - if ( (line.find("")!=std::string::npos) || - (line.find("")!=std::string::npos) || - (line.find("")!=std::string::npos) ) - tag_mg5=true; - if ( (line.find(" LHE format ")!=std::string::npos) ) - tag_ma5=true; - if ( (line.find("")!=std::string::npos) || - (line.find("")!=std::string::npos) ) - tag_simplified_pythia=true; - if ( (line.find(" Simplified LHE format ")!=std::string::npos) ) - tag_simplified_ma5=true; - EndOfLoop = (line.find("processes().size();i++) - { - xsection += mySample.mc()->processes()[i].xsectionMean(); - xerror += mySample.mc()->processes()[i].xsectionError() * - mySample.mc()->processes()[i].xsectionError(); - } + // Computing xsection an its error for the sample + MAfloat64 xsection = 0.; + MAfloat64 xerror = 0.; + for (MAuint32 i = 0; i < mySample.mc()->processes().size(); i++) + { + xsection += mySample.mc()->processes()[i].xsectionMean(); + xerror += mySample.mc()->processes()[i].xsectionError() * + mySample.mc()->processes()[i].xsectionError(); + } - // Filling xsection and its error - mySample.mc()->setXsection(xsection); - mySample.mc()->setXsectionError(std::sqrt(xerror)); + // Filling xsection and its error + mySample.mc()->setXsection(xsection); + mySample.mc()->setXsectionError(std::sqrt(xerror)); - // Normal end - return true; + // Normal end + return true; } - // ----------------------------------------------------------------------------- // ReadEvent // ----------------------------------------------------------------------------- -StatusCode::Type LHEReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySample) +StatusCode::Type LHEReader::ReadEvent(EventFormat &myEvent, SampleFormat &mySample) { - // Initiliaze MC - myEvent.InitializeMC(); - - // Declaring a new string for line - std::string line; - MAbool EndOfEvent=false; - MAbool event_block=false; - MAbool event_header=false; - MAbool multiweight_block = false; - MAbool clustering_block = false; - - // Loop over the LHE lines - while(!EndOfEvent) - { - // Read the line - if (!firstevent_ && !ReadLine(line)) return StatusCode::FAILURE; - // Detect tags - if (line.find("")!=std::string::npos) - { - event_block=false; - EndOfEvent=true; - continue; - } - else if (line.find("")!=std::string::npos || line.find("mgrwt")!=std::string::npos) - { - multiweight_block=true; - continue; - } - else if (line.find("")!=std::string::npos || line.find("/mgrwt")!=std::string::npos) - { - multiweight_block=false; - continue; - } - else if (line.find("")!=std::string::npos || line.find("") != std::string::npos || firstevent_) + { + event_block = true; + event_header = true; + firstevent_ = false; + continue; + } + else if (line.find("") != std::string::npos) + { + event_block = false; + EndOfEvent = true; + continue; + } + else if (line.find("") != std::string::npos || line.find("mgrwt") != std::string::npos) + { + multiweight_block = true; + continue; + } + else if (line.find("") != std::string::npos || line.find("/mgrwt") != std::string::npos) + { + multiweight_block = false; + continue; + } + else if (line.find("") != std::string::npos || line.find(" if (!firstevent_) { EndOfLoop=false; - do - { + do + { if (!ReadLine(line)) return StatusCode::FAILURE; - EndOfLoop = (line.find("")!=std::string::npos); } while(!EndOfLoop); } @@ -297,14 +307,14 @@ StatusCode::Type LHEReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySamp EndOfLoop=false; firstevent_=false; MAbool first=true; - do - { + do + { if (!ReadLine(line)) return StatusCode::FAILURE; - if (line.find("")!=std::string::npos) + if (line.find("")!=std::string::npos) { MAbool EndReweighting = false; do - { + { if (!ReadLine(line)) return StatusCode::FAILURE; EndReweighting = (line.find("")!=std::string::npos); FillWeightLine(line,myEvent); @@ -323,272 +333,302 @@ StatusCode::Type LHEReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySamp while(!EndOfLoop); */ - // Normal end - return StatusCode::KEEP; + // Normal end + return StatusCode::KEEP; } - // ----------------------------------------------------------------------------- // FinalizeEvent // ----------------------------------------------------------------------------- -MAbool LHEReader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) +MAbool LHEReader::FinalizeEvent(SampleFormat &mySample, EventFormat &myEvent) { - // Traditional LHE or simplified LHE ? - MAbool simplified = (mySample.sampleFormat()==MA5FORMAT::SIMPLIFIED_LHE); + // Traditional LHE or simplified LHE ? + MAbool simplified = (mySample.sampleFormat() == MA5FORMAT::SIMPLIFIED_LHE); - // Mother-daughter relations - for (MAuint32 i=0; iparticles_[i]); - MAint32& mothup1 = mothers_[i].first; - MAint32& mothup2 = mothers_[i].second; + // Mother-daughter relations + for (MAuint32 i = 0; i < mothers_.size(); i++) + { + MCParticleFormat *part = &(myEvent.mc()->particles_[i]); + MAint32 &mothup1 = mothers_[i].first; + MAint32 &mothup2 = mothers_[i].second; - if (mothup1>0) - { - if (static_cast(mothup1)<=myEvent.mc()->particles().size()) - { - MCParticleFormat* mum = &(myEvent.mc()->particles()[static_cast(mothup1-1)]); - if (mum!=part) - { - part->mothers().push_back(mum); - mum->daughters().push_back(part); - } - } - else - { - std::stringstream str; - str << "index=" << mothup1 << " but #particles=" << myEvent.mc()->particles().size(); - try + if (mothup1 > 0) { - throw EXCEPTION_WARNING("internal problem with mother-daughter particles",str.str(),0); + if (static_cast(mothup1) <= myEvent.mc()->particles().size()) + { + MCParticleFormat *mum = &(myEvent.mc()->particles()[static_cast(mothup1 - 1)]); + if (mum != part) + { + part->mothers().push_back(mum); + mum->daughters().push_back(part); + } + } + else + { + std::stringstream str; + str << "index=" << mothup1 << " but #particles=" << myEvent.mc()->particles().size(); + try + { + throw EXCEPTION_WARNING("internal problem with mother-daughter particles", str.str(), 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } } - catch(const std::exception& e) + if (mothup2 > 0 && mothup1 != mothup2) { - MANAGE_EXCEPTION(e); + if (static_cast(mothup2) <= myEvent.mc()->particles().size()) + { + MCParticleFormat *mum = &(myEvent.mc()->particles()[static_cast(mothup2 - 1)]); + if (mum != part) + { + part->mothers().push_back(mum); + mum->daughters().push_back(part); + } + } + else + { + std::stringstream str; + str << "index=" << mothup2 << " but #particles=" << myEvent.mc()->particles().size(); + try + { + throw EXCEPTION_WARNING("internal problem with mother-daughter particles", str.str(), 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } } - } } - if (mothup2>0 && mothup1!=mothup2) + mothers_.clear(); + + // Global event observable + for (MAuint32 i = 0; i < myEvent.mc()->particles_.size(); i++) { - if (static_cast(mothup2)<=myEvent.mc()->particles().size()) - { - MCParticleFormat* mum = &(myEvent.mc()->particles()[static_cast(mothup2-1)]); - if (mum!=part) - { - part->mothers().push_back(mum); - mum->daughters().push_back(part); - } - } - else - { - std::stringstream str; - str << "index=" << mothup2 << " but #particles=" << myEvent.mc()->particles().size(); - try + MCParticleFormat &part = myEvent.mc()->particles_[i]; + + // MET in case of simplified LHE + if (((part.pdgid() == 12 && part.statuscode() == 1) || (part.statuscode() == 1 && PHYSICS->Id->IsInvisible(part))) && simplified) { - throw EXCEPTION_WARNING("internal problem with mother-daughter particles",str.str(),0); + myEvent.mc()->MET_ += part.momentum(); } - catch(const std::exception& e) + + // MET, MHT, TET, THT + if (part.statuscode() == 1 && !PHYSICS->Id->IsInvisible(part)) { - MANAGE_EXCEPTION(e); + if (!simplified) + { + myEvent.mc()->MET_ -= part.momentum(); + } + myEvent.mc()->TET_ += part.pt(); + if (PHYSICS->Id->IsHadronic(part)) + { + myEvent.mc()->MHT_ -= part.momentum(); + myEvent.mc()->THT_ += part.pt(); + myEvent.mc()->Meff_ += part.pt(); + } } - } } - } - mothers_.clear(); - // Global event observable - for (MAuint32 i=0; iparticles_.size();i++) - { - MCParticleFormat& part = myEvent.mc()->particles_[i]; + // Finalize event + myEvent.mc()->MET_.momentum().SetPz(0.); + myEvent.mc()->MET_.momentum().SetE(myEvent.mc()->MET_.momentum().Pt()); + myEvent.mc()->MHT_.momentum().SetPz(0.); + myEvent.mc()->MHT_.momentum().SetE(myEvent.mc()->MHT_.momentum().Pt()); + myEvent.mc()->Meff_ += myEvent.mc()->MET_.pt(); - // MET in case of simplified LHE - if ( ( (part.pdgid()==12 && part.statuscode()==1) || (part.statuscode()==1 && PHYSICS->Id->IsInvisible(part)) ) && simplified) - { - myEvent.mc()->MET_ += part.momentum(); - } - - // MET, MHT, TET, THT - if (part.statuscode()==1 && !PHYSICS->Id->IsInvisible(part)) - { - if (!simplified) - { - myEvent.mc()->MET_ -= part.momentum(); - } - myEvent.mc()->TET_ += part.pt(); - if (PHYSICS->Id->IsHadronic(part)) - { - myEvent.mc()->MHT_ -= part.momentum(); - myEvent.mc()->THT_ += part.pt(); - myEvent.mc()->Meff_ += part.pt(); - } - } - } - - // Finalize event - myEvent.mc()->MET_.momentum().SetPz(0.); - myEvent.mc()->MET_.momentum().SetE(myEvent.mc()->MET_.momentum().Pt()); - myEvent.mc()->MHT_.momentum().SetPz(0.); - myEvent.mc()->MHT_.momentum().SetE(myEvent.mc()->MHT_.momentum().Pt()); - myEvent.mc()->Meff_ += myEvent.mc()->MET_.pt(); - - // Normal end - return true; + // Normal end + return true; } - // ----------------------------------------------------------------------------- // FillHeaderInitLine // ----------------------------------------------------------------------------- -void LHEReader::FillHeaderInitLine(const std::string& line, - SampleFormat& mySample) +void LHEReader::FillHeaderInitLine(const std::string &line, + SampleFormat &mySample) { - std::stringstream str; - str << line; - - str >> mySample.mc()->beamPDGID_.first; - str >> mySample.mc()->beamPDGID_.second; - str >> mySample.mc()->beamE_.first; - str >> mySample.mc()->beamE_.second; - str >> mySample.mc()->beamPDFauthor_.first; - str >> mySample.mc()->beamPDFauthor_.second; - str >> mySample.mc()->beamPDFID_.first; - str >> mySample.mc()->beamPDFID_.second; - str >> mySample.mc()->weightMode_; - // str >> mySample.mc()->nProcesses_; UNUSED + std::stringstream str; + str << line; + + str >> mySample.mc()->beamPDGID_.first; + str >> mySample.mc()->beamPDGID_.second; + str >> mySample.mc()->beamE_.first; + str >> mySample.mc()->beamE_.second; + str >> mySample.mc()->beamPDFauthor_.first; + str >> mySample.mc()->beamPDFauthor_.second; + str >> mySample.mc()->beamPDFID_.first; + str >> mySample.mc()->beamPDFID_.second; + str >> mySample.mc()->weightMode_; + // str >> mySample.mc()->nProcesses_; UNUSED } - // ----------------------------------------------------------------------------- // FillHeaderProcessLine // ----------------------------------------------------------------------------- -void LHEReader::FillHeaderProcessLine(const std::string& line, - SampleFormat& mySample) +void LHEReader::FillHeaderProcessLine(const std::string &line, + SampleFormat &mySample) { - std::string tmpline=line; - size_t posi = 0; - while( (posi = tmpline.find("D", posi)) != std::string::npos) - tmpline=tmpline.replace(posi, 1, "E"); - posi=0; - while( (posi = tmpline.find("d", posi)) != std::string::npos) - tmpline=tmpline.replace(posi, 1, "E"); - - std::stringstream str; - str << tmpline; - - // Get a new process - ProcessFormat * proc = mySample.mc()->GetNewProcess(); - - str >> proc->xsectionMean_; - str >> proc->xsectionError_; - str >> proc->weightMax_; - str >> proc->processId_; + std::string tmpline = line; + size_t posi = 0; + while ((posi = tmpline.find("D", posi)) != std::string::npos) + tmpline = tmpline.replace(posi, 1, "E"); + posi = 0; + while ((posi = tmpline.find("d", posi)) != std::string::npos) + tmpline = tmpline.replace(posi, 1, "E"); + + std::stringstream str; + str << tmpline; + + // Get a new process + ProcessFormat *proc = mySample.mc()->GetNewProcess(); + + str >> proc->xsectionMean_; + str >> proc->xsectionError_; + str >> proc->weightMax_; + str >> proc->processId_; } - // ----------------------------------------------------------------------------- // FillEventInitLine // ----------------------------------------------------------------------------- -void LHEReader::FillEventInitLine(const std::string& line, - EventFormat& myEvent) +void LHEReader::FillEventInitLine(const std::string &line, + EventFormat &myEvent) { - std::stringstream str; - str << line; - MAuint32 nparts; - str >> nparts; - str >> myEvent.mc()->processId_; - str >> myEvent.mc()->weight_; - str >> myEvent.mc()->scale_; - str >> myEvent.mc()->alphaQED_; - str >> myEvent.mc()->alphaQCD_; - myEvent.mc()->particles_.reserve(nparts); - mothers_.reserve(nparts); + MAdouble64 weight; + std::stringstream str; + str << line; + MAuint32 nparts; + str >> nparts; + str >> myEvent.mc()->processId_; + str >> weight; + str >> myEvent.mc()->scale_; + str >> myEvent.mc()->alphaQED_; + str >> myEvent.mc()->alphaQCD_; + myEvent.mc()->particles_.reserve(nparts); + myEvent.mc()->multiweights_.Add(0, weight); + mothers_.reserve(nparts); } - // ----------------------------------------------------------------------------- // FillEventParticleLine // ----------------------------------------------------------------------------- -void LHEReader::FillEventParticleLine(const std::string& line, - EventFormat& myEvent) +void LHEReader::FillEventParticleLine(const std::string &line, + EventFormat &myEvent) { - std::string tmpline=line; - size_t posi = 0; - while( (posi = tmpline.find("D", posi)) != std::string::npos) - tmpline=tmpline.replace(posi, 1, "E"); - posi=0; - while( (posi = tmpline.find("d", posi)) != std::string::npos) - tmpline=tmpline.replace(posi, 1, "E"); - - std::stringstream str; - str << tmpline; - - MAint32 color1; // color 1 not stored - MAint32 color2; // color 2 not stored - MAfloat64 tmp; // temporary - MAfloat64 px; // temporary variable to fill in LorentzVector - MAfloat64 py; // temporary variable to fill in LorentzVector - MAfloat64 pz; // temporary variable to fill in LorentzVector - MAfloat64 e; // temporary variable to fill in LorentzVector - MAfloat64 ctau; // temporary variable to fill in LorentzVector - MAint32 mothup1; // mother1 - MAint32 mothup2; // mother2 - - // Get a new particle - MCParticleFormat * part = myEvent.mc()->GetNewParticle(); - - str >> part->pdgid_; - str >> part->statuscode_; - str >> mothup1; - str >> mothup2; - str >> color1; - str >> color2; - str >> px; - str >> py; - str >> pz; - str >> e; - str >> tmp; - str >> ctau; - str >> part->spin_; - part->momentum_.SetPxPyPzE(px,py,pz,e); - part->decay_vertex_.SetT(ctau); - mothers_.push_back(std::make_pair(mothup1,mothup2)); + std::string tmpline = line; + size_t posi = 0; + while ((posi = tmpline.find("D", posi)) != std::string::npos) + tmpline = tmpline.replace(posi, 1, "E"); + posi = 0; + while ((posi = tmpline.find("d", posi)) != std::string::npos) + tmpline = tmpline.replace(posi, 1, "E"); + + std::stringstream str; + str << tmpline; + + MAint32 color1; // color 1 not stored + MAint32 color2; // color 2 not stored + MAfloat64 tmp; // temporary + MAfloat64 px; // temporary variable to fill in LorentzVector + MAfloat64 py; // temporary variable to fill in LorentzVector + MAfloat64 pz; // temporary variable to fill in LorentzVector + MAfloat64 e; // temporary variable to fill in LorentzVector + MAfloat64 ctau; // temporary variable to fill in LorentzVector + MAint32 mothup1; // mother1 + MAint32 mothup2; // mother2 + + // Get a new particle + MCParticleFormat *part = myEvent.mc()->GetNewParticle(); + + str >> part->pdgid_; + str >> part->statuscode_; + str >> mothup1; + str >> mothup2; + str >> color1; + str >> color2; + str >> px; + str >> py; + str >> pz; + str >> e; + str >> tmp; + str >> ctau; + str >> part->spin_; + part->momentum_.SetPxPyPzE(px, py, pz, e); + part->decay_vertex_.SetT(ctau); + mothers_.push_back(std::make_pair(mothup1, mothup2)); } +//------------------------------------------------------------------------------ +// FillWeightNames +//------------------------------------------------------------------------------ +void LHEReader::FillWeightNames(const std::string &line, SampleFormat &mySample) +{ + // Parsing + std::stringstream str(line); + std::size_t startTagPos = line.find(""); + if (startTagPos != std::string::npos && endTagPos != std::string::npos) + { + // Extract the weight id + std::size_t idPos = line.find("id='", startTagPos); + std::size_t idEndPos = line.find("'", idPos + 4); + std::string id = line.substr(idPos + 4, idEndPos - (idPos + 4)); + + // Extract the content between the tags + std::size_t nameStart = line.find(">", startTagPos) + 1; + std::string weight_name = line.substr(nameStart, endTagPos - nameStart); + + // Trim the weight_name string + weight_name.erase(0, weight_name.find_first_not_of(" \t\n\r")); + weight_name.erase(weight_name.find_last_not_of(" \t\n\r") + 1); + + // Print the id and weight_name + mySample.mc()->SetWeightName(std::stoi(id), weight_name); + } +} // ----------------------------------------------------------------------------- // FillWeightLine // ----------------------------------------------------------------------------- -void LHEReader::FillWeightLine(const std::string& line, - EventFormat& myEvent) +void LHEReader::FillWeightLine(const std::string &line, + EventFormat &myEvent) { - std::stringstream str; - str << line; - - std::string tmp; - str >> tmp; - if (tmp!=">id; - - found1 = line.find(">"); - if (found1==std::string::npos) return; - found2 = line.find("<",found1+1); - if (found2==std::string::npos) return; - std::string valuestring = line.substr(found1+1,found2-found1-1); - - std::stringstream str3; - str3<>value; - - myEvent.mc()->multiweights().Add(id,value); + std::stringstream str; + str << line; + + std::string tmp; + str >> tmp; + if (tmp != "> id; + found1 = line.find(">"); + if (found1 == std::string::npos) + return; + found2 = line.find("<", found1 + 1); + if (found2 == std::string::npos) + return; + std::string valuestring = line.substr(found1 + 1, found2 - found1 - 1); + + std::stringstream str3; + str3 << valuestring; + MAfloat64 value; + str3 >> value; + myEvent.mc()->weights().Add(id, value); } diff --git a/tools/SampleAnalyzer/Process/Reader/LHEReader.h b/tools/SampleAnalyzer/Process/Reader/LHEReader.h index e655ad98..0fb778ec 100644 --- a/tools/SampleAnalyzer/Process/Reader/LHEReader.h +++ b/tools/SampleAnalyzer/Process/Reader/LHEReader.h @@ -1,99 +1,89 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef LHE_READER_h #define LHE_READER_h - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Reader/ReaderTextBase.h" - namespace MA5 { -class LHEReader : public ReaderTextBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected: - - MAbool firstevent_; - std::vector< std::pair > mothers_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public: - - //! Constructor without argument - LHEReader() - { firstevent_=false; } - - //! Destructor - virtual ~LHEReader() - { } - - /// Initialize - virtual MAbool Initialize(const std::string& rawfilename, - const Configuration& cfg) - { - firstevent_=false; - return ReaderTextBase::Initialize(rawfilename,cfg); - } - - /// Finalize - virtual MAbool Finalize() - { return ReaderTextBase::Finalize(); } - - //! Read the header - virtual MAbool ReadHeader(SampleFormat& mySample); - - //! Finalize the header - virtual MAbool FinalizeHeader(SampleFormat& mySample); - - //! Read the event - virtual StatusCode::Type ReadEvent(EventFormat& myEvent, SampleFormat& mySample); - - //! Finalize the event - virtual MAbool FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent); - - - private: - - //! Fill the header from text line - void FillHeaderProcessLine(const std::string& line, SampleFormat& mySample); - void FillHeaderInitLine (const std::string& line, SampleFormat& mySample); - - //! Fill the event from text line - void FillEventInitLine(const std::string& line, EventFormat& myFormat); - void FillEventParticleLine(const std::string& line, EventFormat& myFormat); - void FillWeightLine(const std::string& line, EventFormat& myEvent); - -}; + class LHEReader : public ReaderTextBase + { + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + MAbool firstevent_; + std::vector> mothers_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + //! Constructor without argument + LHEReader() { firstevent_ = false; } + + //! Destructor + virtual ~LHEReader() {} + + /// Initialize + virtual MAbool Initialize(const std::string &rawfilename, + const Configuration &cfg) + { + firstevent_ = false; + return ReaderTextBase::Initialize(rawfilename, cfg); + } + + /// Finalize + virtual MAbool Finalize() { return ReaderTextBase::Finalize(); } + + //! Read the header + virtual MAbool ReadHeader(SampleFormat &mySample); + + //! Finalize the header + virtual MAbool FinalizeHeader(SampleFormat &mySample); + + //! Read the event + virtual StatusCode::Type ReadEvent(EventFormat &myEvent, SampleFormat &mySample); + + //! Finalize the event + virtual MAbool FinalizeEvent(SampleFormat &mySample, EventFormat &myEvent); + + private: + //! Fill the header from text line + void FillHeaderProcessLine(const std::string &line, SampleFormat &mySample); + void FillHeaderInitLine(const std::string &line, SampleFormat &mySample); + + //! Fill the event from text line + void FillEventInitLine(const std::string &line, EventFormat &myFormat); + void FillEventParticleLine(const std::string &line, EventFormat &myFormat); + void FillWeightNames(const std::string &line, SampleFormat &mySample); + void FillWeightLine(const std::string &line, EventFormat &myEvent); + }; } diff --git a/tools/SampleAnalyzer/Process/Reader/STDHEPreader.cpp b/tools/SampleAnalyzer/Process/Reader/STDHEPreader.cpp index 3202c81f..83df312c 100644 --- a/tools/SampleAnalyzer/Process/Reader/STDHEPreader.cpp +++ b/tools/SampleAnalyzer/Process/Reader/STDHEPreader.cpp @@ -1,842 +1,851 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleAnalyzer headers #include "SampleAnalyzer/Process/Reader/STDHEPreader.h" #include "SampleAnalyzer/Commons/Service/LogService.h" #include "SampleAnalyzer/Commons/Service/ConvertService.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - using namespace MA5; // ----------------------------------------------------------------------------- // Initialize // ----------------------------------------------------------------------------- -MAbool STDHEPreader::Initialize(const std::string& rawfilename, - const Configuration& cfg) +MAbool STDHEPreader::Initialize(const std::string &rawfilename, + const Configuration &cfg) { - nevhept_before_ = 0; - firstevent=true; + nevhept_before_ = 0; + firstevent = true; - if (!ReaderTextBase::Initialize(rawfilename, cfg)) return false; - xdrinput_=new xdr_istream(*input_); + if (!ReaderTextBase::Initialize(rawfilename, cfg)) + return false; + xdrinput_ = new xdr_istream(*input_); - return true; + return true; } - // ----------------------------------------------------------------------------- // ReadHeader // ----------------------------------------------------------------------------- void STDHEPreader::Reset() { - nevhept_=0; - nhept_=0; - isthept_.clear(); - idhept_.clear(); - jmohept_.clear(); - jdahept_.clear(); - phept_.clear(); - vhept_.clear(); + nevhept_ = 0; + nhept_ = 0; + isthept_.clear(); + idhept_.clear(); + jmohept_.clear(); + jdahept_.clear(); + phept_.clear(); + vhept_.clear(); } // ----------------------------------------------------------------------------- // ReadHeader // ----------------------------------------------------------------------------- -MAbool STDHEPreader::ReadHeader(SampleFormat& mySample) +MAbool STDHEPreader::ReadHeader(SampleFormat &mySample) { - // Initiliaze MC - mySample.InitializeMC(); - mySample.SetSampleFormat(MA5FORMAT::STDHEP); + // Initiliaze MC + mySample.InitializeMC(); + mySample.SetSampleFormat(MA5FORMAT::STDHEP); - if (!DecodeFileHeader(mySample)) return false; + if (!DecodeFileHeader(mySample)) + return false; - return true; + return true; } - // ----------------------------------------------------------------------------- // ReadEvent // ----------------------------------------------------------------------------- -StatusCode::Type STDHEPreader::ReadEvent(EventFormat& myEvent, SampleFormat& mySample) +StatusCode::Type STDHEPreader::ReadEvent(EventFormat &myEvent, SampleFormat &mySample) { - // Initiliaze MC - myEvent.InitializeMC(); - - MAbool eventRead=false; - MAbool eventskip=false; - while(!eventRead) - { - // Read blockid - MAint32 blockid=0; - *xdrinput_ >> blockid; - if (xdrinput_->eof()) return StatusCode::FAILURE; - - MAint32 ntot=0; - *xdrinput_ >> ntot; - - std::string version; - *xdrinput_ >> version; - - if (blockid==EVENTTABLE ) DecodeEventTable (version); - else if (blockid==EVENTHEADER) DecodeEventHeader(version); - else if (blockid==MCFIO_STDHEPBEG || - blockid==MCFIO_STDHEPEND) {DecodeSTDCM1 (version,mySample); } - else if (blockid==MCFIO_STDHEP) + // Initiliaze MC + myEvent.InitializeMC(); + + MAbool eventRead = false; + MAbool eventskip = false; + while (!eventRead) { - eventskip = !DecodeEventData(version, myEvent); - eventRead = true; + // Read blockid + MAint32 blockid = 0; + *xdrinput_ >> blockid; + if (xdrinput_->eof()) + return StatusCode::FAILURE; + + MAint32 ntot = 0; + *xdrinput_ >> ntot; + + std::string version; + *xdrinput_ >> version; + + if (blockid == EVENTTABLE) + DecodeEventTable(version); + else if (blockid == EVENTHEADER) + DecodeEventHeader(version); + else if (blockid == MCFIO_STDHEPBEG || + blockid == MCFIO_STDHEPEND) + { + DecodeSTDCM1(version, mySample); + } + else if (blockid == MCFIO_STDHEP) + { + eventskip = !DecodeEventData(version, myEvent); + eventRead = true; + } + else if (blockid == MCFIO_STDHEP4) + { + eventskip = !DecodeSTDHEP4(version, myEvent); + eventRead = true; + } + else + { + ERROR << "Block with the ID=" << blockid + << " is not managed by SampleAnalyzer" << endmsg; + return StatusCode::SKIP; + } } - else if (blockid==MCFIO_STDHEP4) + + // return + if (eventskip) + return StatusCode::SKIP; + return StatusCode::KEEP; +} + +// ----------------------------------------------------------------------------- +// DecodeFileHeader +// ----------------------------------------------------------------------------- +MAbool STDHEPreader::DecodeFileHeader(SampleFormat &mySample) +{ + // temporary variables used for reading the xdr format file + std::string tmps; + MAint32 tmpi = 0; + MAuint32 tmpui = 0; + + // BlockID + *xdrinput_ >> tmpi; + if (tmpi != FILEHEADER) + { + ERROR << "header block not found" << endmsg; + return false; + } + + // Ntot + *xdrinput_ >> tmpi; + + // STDHEP version + *xdrinput_ >> tmps; + SetVersion(tmps); + if (version_ == UNKNOWN) + { + ERROR << "stdhep version unknown : '" << tmps << endmsg; + return false; + } + + // Title + tmps = ""; + *xdrinput_ >> tmps; + // std::cout << "title=" << tmps << std::cout; + + // Set the title in lower case + tmps = CONVERT->ToLower(tmps); + if (tmps.find("pythia") != std::string::npos) { - eventskip = !DecodeSTDHEP4 (version, myEvent); - eventRead = true; + mySample.SetSampleGenerator(MA5GEN::PYTHIA6); + } + else if (tmps.find("herwig") != std::string::npos) + { + mySample.SetSampleGenerator(MA5GEN::HERWIG6); } else { - ERROR << "Block with the ID=" << blockid - << " is not managed by SampleAnalyzer" << endmsg; - return StatusCode::SKIP; + mySample.SetSampleGenerator(MA5GEN::UNKNOWN); } - } - // return - if(eventskip) return StatusCode::SKIP; - return StatusCode::KEEP; -} + // std::cout << "title=" << tmps << std::endl; + // Comment + *xdrinput_ >> tmps; + // std::cout << "comment=" << tmps << std::endl; -// ----------------------------------------------------------------------------- -// DecodeFileHeader -// ----------------------------------------------------------------------------- -MAbool STDHEPreader::DecodeFileHeader(SampleFormat& mySample) -{ - // temporary variables used for reading the xdr format file - std::string tmps; - MAint32 tmpi = 0; - MAuint32 tmpui = 0; - - // BlockID - *xdrinput_ >> tmpi; - if (tmpi != FILEHEADER) - { - ERROR << "header block not found" << endmsg; - return false; - } - - // Ntot - *xdrinput_ >> tmpi; - - // STDHEP version - *xdrinput_ >> tmps; - SetVersion(tmps); - if (version_==UNKNOWN) - { - ERROR << "stdhep version unknown : '" << tmps << endmsg; - return false; - } - - // Title - tmps=""; - *xdrinput_ >> tmps; - // std::cout << "title=" << tmps << std::cout; - - // Set the title in lower case - tmps = CONVERT->ToLower(tmps); - if (tmps.find("pythia")!=std::string::npos) - { - mySample.SetSampleGenerator(MA5GEN::PYTHIA6); - } - else if (tmps.find("herwig")!=std::string::npos) - { - mySample.SetSampleGenerator(MA5GEN::HERWIG6); - } - else - { - mySample.SetSampleGenerator(MA5GEN::UNKNOWN); - } - - //std::cout << "title=" << tmps << std::endl; - - // Comment - *xdrinput_ >> tmps; - //std::cout << "comment=" << tmps << std::endl; - - // Creation date - *xdrinput_ >> tmps; - //std::cout << "date=" << tmps << endmsg; - - // Closing date (only in version 2.01) - if (version_==V21) - { + // Creation date *xdrinput_ >> tmps; - //std::cout << "cdate=" << tmps << endmsg; - } - - // Expected number of events - *xdrinput_ >> tmpui; - //std::cout << "Nevents = " << tmpui << endmsg; - - // Number of events - *xdrinput_ >> tmpui; - //std::cout << "Nevents = " << tmpui << endmsg; - - // First table - *xdrinput_ >> tmpui; - //std::cout << "First table=" << tmpui << endmsg; - - // Dim Table - MAuint32 dimTable; - *xdrinput_ >> dimTable; - //std::cout << "Dim table=" << dimTable << endmsg; - - // Number of blocks - MAuint32 nBlocks; - *xdrinput_ >> nBlocks; - //std::cout << "N blocks = " << nBlocks << endmsg; - - // Number of NTuples - MAuint32 nNTuples = 0; - if (version_!=V1) - { - *xdrinput_ >> nNTuples; - //std::cout << "Nb NTuples = " << nNTuples << endmsg; - } - - // Processing blocks extraction - if (nBlocks!=0) - { - // Extracting blocks - std::vector blocks; - *xdrinput_ >> blocks; - - // Extracting block names - for (MAuint32 i=0;i> idat; + // Decoding the event + // Case: classical + if (evt_version == "1.00") + { + MAint32 idat = 0; + *xdrinput_ >> idat; - MAuint32 uidat=0; - *xdrinput_ >> uidat; + MAuint32 uidat = 0; + *xdrinput_ >> uidat; - // Extracting evtnums - std::vector evtnums; - *xdrinput_ >> evtnums; + // Extracting evtnums + std::vector evtnums; + *xdrinput_ >> evtnums; - // Extracting storenums - std::vector storenums; - *xdrinput_ >> storenums; + // Extracting storenums + std::vector storenums; + *xdrinput_ >> storenums; - // Extracting runnums - std::vector runnums; - *xdrinput_ >> runnums; + // Extracting runnums + std::vector runnums; + *xdrinput_ >> runnums; - // Extracting trigMasks - std::vector NtrigMasks; - *xdrinput_ >> NtrigMasks; + // Extracting trigMasks + std::vector NtrigMasks; + *xdrinput_ >> NtrigMasks; - // Extracting prtEvents - std::vector NptrEvents; - *xdrinput_ >> NptrEvents; - } + // Extracting prtEvents + std::vector NptrEvents; + *xdrinput_ >> NptrEvents; + } - // Pavel's adding: 64-bit adress - else if (evt_version=="2.00") - { - MAint32 idat=0; - *xdrinput_ >> idat; + // Pavel's adding: 64-bit adress + else if (evt_version == "2.00") + { + MAint32 idat = 0; + *xdrinput_ >> idat; - MAuint64 uidat=0; - *xdrinput_ >> uidat; + MAuint64 uidat = 0; + *xdrinput_ >> uidat; - // Extracting evtnums - std::vector evtnums; - *xdrinput_ >> evtnums; + // Extracting evtnums + std::vector evtnums; + *xdrinput_ >> evtnums; - // Extracting storenums - std::vector storenums; - *xdrinput_ >> storenums; + // Extracting storenums + std::vector storenums; + *xdrinput_ >> storenums; - // Extracting runnums - std::vector runnums; - *xdrinput_ >> runnums; + // Extracting runnums + std::vector runnums; + *xdrinput_ >> runnums; - // Extracting trigMasks - std::vector NtrigMasks; - *xdrinput_ >> NtrigMasks; + // Extracting trigMasks + std::vector NtrigMasks; + *xdrinput_ >> NtrigMasks; - // Extracting prtEvents - std::vector NptrEvents; - *xdrinput_ >> NptrEvents; - } + // Extracting prtEvents + std::vector NptrEvents; + *xdrinput_ >> NptrEvents; + } - // Case: other version? - else - { - ERROR << "version '" << evt_version << "' is not supported" << endmsg; - return false; - } + // Case: other version? + else + { + ERROR << "version '" << evt_version << "' is not supported" << endmsg; + return false; + } - return true; + return true; } - // ----------------------------------------------------------------------------- // DecodeEventHeader // ----------------------------------------------------------------------------- -MAbool STDHEPreader::DecodeEventHeader(const std::string& evt_version) +MAbool STDHEPreader::DecodeEventHeader(const std::string &evt_version) { - MAint32 evtnum=0; - *xdrinput_ >> evtnum; + MAint32 evtnum = 0; + *xdrinput_ >> evtnum; - MAint32 storenums=0; - *xdrinput_ >> storenums; - - MAint32 runnum=0; - *xdrinput_ >> runnum; - - MAint32 trigMask=0; - *xdrinput_ >> trigMask; + MAint32 storenums = 0; + *xdrinput_ >> storenums; - MAuint32 nBlocks=0; - *xdrinput_ >> nBlocks; + MAint32 runnum = 0; + *xdrinput_ >> runnum; - MAuint32 dimBlocks=0; - *xdrinput_ >> dimBlocks; + MAint32 trigMask = 0; + *xdrinput_ >> trigMask; - MAuint32 nNTuples=0; - MAuint32 dimNTuples=0; + MAuint32 nBlocks = 0; + *xdrinput_ >> nBlocks; - // Is there NTuple - MAbool skipNTuples = false; - MAbool add64bit=false; - if (evt_version=="2.00" || evt_version=="3.00") skipNTuples=true; - if (evt_version=="3.00") add64bit=true; + MAuint32 dimBlocks = 0; + *xdrinput_ >> dimBlocks; - // NTuple - if (skipNTuples) - { - *xdrinput_ >> nNTuples; - *xdrinput_ >> dimNTuples; - } + MAuint32 nNTuples = 0; + MAuint32 dimNTuples = 0; - // Processing blocks extraction - if (dimBlocks>0) - { - // Extracting blocks - std::vector blocks; - *xdrinput_ >> blocks; + // Is there NTuple + MAbool skipNTuples = false; + MAbool add64bit = false; + if (evt_version == "2.00" || evt_version == "3.00") + skipNTuples = true; + if (evt_version == "3.00") + add64bit = true; - // Extracting blocks - if (!add64bit) - { - std::vector ptrBlocks; - *xdrinput_ >> ptrBlocks; - } - else + // NTuple + if (skipNTuples) { - std::vector ptrBlocks; - *xdrinput_ >> ptrBlocks; + *xdrinput_ >> nNTuples; + *xdrinput_ >> dimNTuples; } - } - - // Processing blocks extraction - if (skipNTuples && dimNTuples>0) - { - // Extracting blocks - std::vector nTupleIds; - *xdrinput_ >> nTupleIds; - // Extracting blocks - if (!add64bit) + // Processing blocks extraction + if (dimBlocks > 0) { - std::vector ptrNTuples; - *xdrinput_ >> ptrNTuples; + // Extracting blocks + std::vector blocks; + *xdrinput_ >> blocks; + + // Extracting blocks + if (!add64bit) + { + std::vector ptrBlocks; + *xdrinput_ >> ptrBlocks; + } + else + { + std::vector ptrBlocks; + *xdrinput_ >> ptrBlocks; + } } - else + + // Processing blocks extraction + if (skipNTuples && dimNTuples > 0) { - std::vector ptrNTuples; - *xdrinput_ >> ptrNTuples; + // Extracting blocks + std::vector nTupleIds; + *xdrinput_ >> nTupleIds; + + // Extracting blocks + if (!add64bit) + { + std::vector ptrNTuples; + *xdrinput_ >> ptrNTuples; + } + else + { + std::vector ptrNTuples; + *xdrinput_ >> ptrNTuples; + } } - } - return true; + return true; } - // ----------------------------------------------------------------------------- // DecodeSTDCM1 // ----------------------------------------------------------------------------- -MAbool STDHEPreader::DecodeSTDCM1(const std::string& version, SampleFormat& mySample) +MAbool STDHEPreader::DecodeSTDCM1(const std::string &version, SampleFormat &mySample) { - MAint32 nevtreq; - *xdrinput_ >> nevtreq; - - MAint32 nevtgen; - *xdrinput_ >> nevtgen; + MAint32 nevtreq; + *xdrinput_ >> nevtreq; - MAint32 nevtwrt; - *xdrinput_ >> nevtwrt; + MAint32 nevtgen; + *xdrinput_ >> nevtgen; - MAfloat32 stdecom; - *xdrinput_ >> stdecom; + MAint32 nevtwrt; + *xdrinput_ >> nevtwrt; - MAfloat32 stdxsec; - *xdrinput_ >> stdxsec; - if (mySample.mc()!=0) - { - mySample.mc()->setXsectionMean(stdxsec); - mySample.mc()->setXsectionError(0); - } + MAfloat32 stdecom; + *xdrinput_ >> stdecom; - MAfloat64 stdseed1; - *xdrinput_ >> stdseed1; + MAfloat32 stdxsec; + *xdrinput_ >> stdxsec; + if (mySample.mc() != 0) + { + mySample.mc()->setXsectionMean(stdxsec); + mySample.mc()->setXsectionError(0); + } - MAfloat64 stdseed2; - *xdrinput_ >> stdseed2; + MAfloat64 stdseed1; + *xdrinput_ >> stdseed1; - if (version.find("1.")==0 || version.find("2.")==0 || - version.find("3.")==0 || version.find("4.")==0 || - version.find("5.00")==0) return true; + MAfloat64 stdseed2; + *xdrinput_ >> stdseed2; - std::string tmps; - *xdrinput_ >> tmps; - *xdrinput_ >> tmps; + if (version.find("1.") == 0 || version.find("2.") == 0 || + version.find("3.") == 0 || version.find("4.") == 0 || + version.find("5.00") == 0) + return true; - if (version.find("5.00")==0 || version.find("5.01")==0 ) - return true; + std::string tmps; + *xdrinput_ >> tmps; + *xdrinput_ >> tmps; - MAint32 nevtlh=0; - *xdrinput_ >> nevtlh; + if (version.find("5.00") == 0 || version.find("5.01") == 0) + return true; - return true; + MAint32 nevtlh = 0; + *xdrinput_ >> nevtlh; + return true; } - // ----------------------------------------------------------------------------- // DecodeEventFormat // ----------------------------------------------------------------------------- -MAbool STDHEPreader::DecodeEventData(const std::string& version, - EventFormat& myEvent) +MAbool STDHEPreader::DecodeEventData(const std::string &version, + EventFormat &myEvent) { - Reset(); - - // Extracting the event number - *xdrinput_ >> nevhept_; - - // Extracting the number of particles - *xdrinput_ >> nhept_; + Reset(); - // Extracting isthept - *xdrinput_ >> isthept_; + // Extracting the event number + *xdrinput_ >> nevhept_; - // Extracting idhept - *xdrinput_ >> idhept_; + // Extracting the number of particles + *xdrinput_ >> nhept_; - // Extracting jmohept - *xdrinput_ >> jmohept_; + // Extracting isthept + *xdrinput_ >> isthept_; - // Extracting jdahept - *xdrinput_ >> jdahept_; + // Extracting idhept + *xdrinput_ >> idhept_; - // Extracting - *xdrinput_ >> phept_; + // Extracting jmohept + *xdrinput_ >> jmohept_; - // Extracting - *xdrinput_ >> vhept_; + // Extracting jdahept + *xdrinput_ >> jdahept_; - // Check the consistency of the event - if(!CheckEvent(myEvent,"STDHEP")) return false; + // Extracting + *xdrinput_ >> phept_; - // Reserve memory for all particles - myEvent.mc()->particles_.reserve(nhept_); - mothers_.reserve(nhept_); + // Extracting + *xdrinput_ >> vhept_; - // Loop over particles - for (MAuint32 i=0;i(nhept_);i++) - { - // Get a new particle - MCParticleFormat * part = myEvent.mc()->GetNewParticle(); + // Check the consistency of the event + if (!CheckEvent(myEvent, "STDHEP")) + return false; - MAuint32 mothup1=0; - MAuint32 mothup2=0; + // Reserve memory for all particles + myEvent.mc()->particles_.reserve(nhept_); + mothers_.reserve(nhept_); - // Fill the data format - part->pdgid_ = idhept_[i]; - part->statuscode_ = isthept_[i]; - mothup1 = jmohept_[2*i]; - mothup2 = jmohept_[2*i+1]; - // daughter1_ = jdahept_[2*i]; - // daughter2_ = jdahept_[2*i+1]; - part->momentum_.SetPxPyPzE(phept_[5*i],phept_[5*i+1],phept_[5*i+2],phept_[5*i+3]); - mothers_.push_back(std::make_pair(mothup1,mothup2)); - - // For debug - // std::cout << "pdgid=" << part->pdgid_ << " status=" << part->statuscode_ - // << " mothup1=" << mothup1 <<" mothup2=" << mothup2 << std::endl; - } + // Loop over particles + for (MAuint32 i = 0; i < static_cast(nhept_); i++) + { + // Get a new particle + MCParticleFormat *part = myEvent.mc()->GetNewParticle(); + + MAuint32 mothup1 = 0; + MAuint32 mothup2 = 0; + + // Fill the data format + part->pdgid_ = idhept_[i]; + part->statuscode_ = isthept_[i]; + mothup1 = jmohept_[2 * i]; + mothup2 = jmohept_[2 * i + 1]; + // daughter1_ = jdahept_[2*i]; + // daughter2_ = jdahept_[2*i+1]; + part->momentum_.SetPxPyPzE(phept_[5 * i], phept_[5 * i + 1], phept_[5 * i + 2], phept_[5 * i + 3]); + mothers_.push_back(std::make_pair(mothup1, mothup2)); + + // For debug + // std::cout << "pdgid=" << part->pdgid_ << " status=" << part->statuscode_ + // << " mothup1=" << mothup1 <<" mothup2=" << mothup2 << std::endl; + } - return true; + return true; } -MAbool STDHEPreader::CheckEvent(const EventFormat& myEvent, - const std::string& blk) +MAbool STDHEPreader::CheckEvent(const EventFormat &myEvent, + const std::string &blk) { - if(nhept_<0) - { - ERROR << "Corrupted " << blk << " block: negative number of particles." - << " Event ignored ." << endmsg; - return false; - } - if(nhept_!=static_cast(isthept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing status codes." - << " Event ignored." << endmsg; - return false; - } - if(nhept_!=static_cast(idhept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing PDG codes." - << " Event ignored." << endmsg; - return false; - } - if((2*nhept_)!=static_cast(jmohept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing mother information." - << " Event ignored." << endmsg; - return false; - } - if((2*nhept_)!=static_cast(jdahept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing daughter information." - << " Event ignored." << endmsg; - return false; - } - if((5*nhept_)!=static_cast(phept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing 4-momentum " << - "information." << " Event ignored." << endmsg; - return false; - } - if((4*nhept_)!=static_cast(vhept_.size())) - { - ERROR << "Corrupted " << blk << " block: missing vertex information." - << " Event ignored." << endmsg; - return false; - } - return true; + if (nhept_ < 0) + { + ERROR << "Corrupted " << blk << " block: negative number of particles." + << " Event ignored ." << endmsg; + return false; + } + if (nhept_ != static_cast(isthept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing status codes." + << " Event ignored." << endmsg; + return false; + } + if (nhept_ != static_cast(idhept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing PDG codes." + << " Event ignored." << endmsg; + return false; + } + if ((2 * nhept_) != static_cast(jmohept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing mother information." + << " Event ignored." << endmsg; + return false; + } + if ((2 * nhept_) != static_cast(jdahept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing daughter information." + << " Event ignored." << endmsg; + return false; + } + if ((5 * nhept_) != static_cast(phept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing 4-momentum " + << "information." + << " Event ignored." << endmsg; + return false; + } + if ((4 * nhept_) != static_cast(vhept_.size())) + { + ERROR << "Corrupted " << blk << " block: missing vertex information." + << " Event ignored." << endmsg; + return false; + } + return true; } -MAbool STDHEPreader::DecodeSTDHEP4(const std::string& version, - EventFormat& myEvent) +MAbool STDHEPreader::DecodeSTDHEP4(const std::string &version, + EventFormat &myEvent) { - Reset(); - - // Extracting the event number - *xdrinput_ >> nevhept_; + Reset(); - // Extracting the number of particles - *xdrinput_ >> nhept_; + // Extracting the event number + *xdrinput_ >> nevhept_; - // Extracting isthept - *xdrinput_ >> isthept_; + // Extracting the number of particles + *xdrinput_ >> nhept_; - // Extracting idhept - *xdrinput_ >> idhept_; + // Extracting isthept + *xdrinput_ >> isthept_; - // Extracting jmohept - *xdrinput_ >> jmohept_; + // Extracting idhept + *xdrinput_ >> idhept_; - // Extracting jdahept - *xdrinput_ >> jdahept_; + // Extracting jmohept + *xdrinput_ >> jmohept_; - // Extracting - *xdrinput_ >> phept_; + // Extracting jdahept + *xdrinput_ >> jdahept_; - // Extracting - *xdrinput_ >> vhept_; + // Extracting + *xdrinput_ >> phept_; - // Extracting the event weight - MAfloat64 eventweight=1; - *xdrinput_ >> eventweight; - myEvent.mc()->setWeight(eventweight); + // Extracting + *xdrinput_ >> vhept_; - // Extracting alpha QED - MAfloat64 alphaQED=0; - *xdrinput_ >> alphaQED; + // Extracting the event weight + MAfloat64 eventweight = 1; + *xdrinput_ >> eventweight; + myEvent.mc()->weights().Add(0, eventweight); - // Extracting alpha QCD - MAfloat64 alphaQCD=0; - *xdrinput_ >> alphaQCD; + // Extracting alpha QED + MAfloat64 alphaQED = 0; + *xdrinput_ >> alphaQED; - // Extracing dat - std::vector dat; - *xdrinput_ >> dat; + // Extracting alpha QCD + MAfloat64 alphaQCD = 0; + *xdrinput_ >> alphaQCD; - // Extracing dat - std::vector spint; - *xdrinput_ >> spint; + // Extracing dat + std::vector dat; + *xdrinput_ >> dat; - // Extracting idat - std::vector idat; - *xdrinput_ >> idat; + // Extracing dat + std::vector spint; + *xdrinput_ >> spint; - // Extracting idrupt - MAint32 idrupt; - *xdrinput_ >> idrupt; - - // Check the consistency of the entries in the event table - if(!CheckEvent(myEvent, "STDHEP4")) return false; + // Extracting idat + std::vector idat; + *xdrinput_ >> idat; - // Reserve memory for all particles - myEvent.mc()->particles_.reserve(nhept_); + // Extracting idrupt + MAint32 idrupt; + *xdrinput_ >> idrupt; - // Loop over particles - for (MAuint32 i=0;i(nhept_);i++) - { - // Get a new particle - MCParticleFormat * part = myEvent.mc()->GetNewParticle(); - - MAuint32 mothup1=0; - MAuint32 mothup2=0; + // Check the consistency of the entries in the event table + if (!CheckEvent(myEvent, "STDHEP4")) + return false; - // Fill the data format - part->pdgid_ = idhept_[i]; - part->statuscode_ = isthept_[i]; - mothup1 = jmohept_[2*i]; - mothup2 = jmohept_[2*i+1]; - // daughter1_ = jdahept_[2*i]; - // daughter2_ = jdahept_[2*i+1]; - part->momentum_.SetPxPyPzE(phept_[5*i],phept_[5*i+1],phept_[5*i+2],phept_[5*i+3]); - mothers_.push_back(std::make_pair(mothup1,mothup2)); + // Reserve memory for all particles + myEvent.mc()->particles_.reserve(nhept_); - // For debug - // std::cout << "pdgid=" << part->pdgid_ << " status=" << part->statuscode_ - // << " mothup1=" << mothup1 <<" mothup2=" << mothup2 << std::endl; - } + // Loop over particles + for (MAuint32 i = 0; i < static_cast(nhept_); i++) + { + // Get a new particle + MCParticleFormat *part = myEvent.mc()->GetNewParticle(); + + MAuint32 mothup1 = 0; + MAuint32 mothup2 = 0; + + // Fill the data format + part->pdgid_ = idhept_[i]; + part->statuscode_ = isthept_[i]; + mothup1 = jmohept_[2 * i]; + mothup2 = jmohept_[2 * i + 1]; + // daughter1_ = jdahept_[2*i]; + // daughter2_ = jdahept_[2*i+1]; + part->momentum_.SetPxPyPzE(phept_[5 * i], phept_[5 * i + 1], phept_[5 * i + 2], phept_[5 * i + 3]); + mothers_.push_back(std::make_pair(mothup1, mothup2)); + + // For debug + // std::cout << "pdgid=" << part->pdgid_ << " status=" << part->statuscode_ + // << " mothup1=" << mothup1 <<" mothup2=" << mothup2 << std::endl; + } - return true; + return true; } - // ----------------------------------------------------------------------------- // AddMothers // ----------------------------------------------------------------------------- -MAbool AddMothers(MCParticleFormat* part,MCParticleFormat* mum) +MAbool AddMothers(MCParticleFormat *part, MCParticleFormat *mum) { - for (MAuint32 i=0;imothers().size();i++) - { - MCParticleFormat* m = part->mothers()[i]; - if (m==mum) return false; - } - part->mothers().push_back(mum); - return true; + for (MAuint32 i = 0; i < part->mothers().size(); i++) + { + MCParticleFormat *m = part->mothers()[i]; + if (m == mum) + return false; + } + part->mothers().push_back(mum); + return true; } - // ----------------------------------------------------------------------------- // AddDaughters // ----------------------------------------------------------------------------- -MAbool AddDaughters(MCParticleFormat* part,MCParticleFormat* dau) +MAbool AddDaughters(MCParticleFormat *part, MCParticleFormat *dau) { - for (MAuint32 i=0;idaughters().size();i++) - { - MCParticleFormat* d = part->daughters()[i]; - if (d==dau) return false; - } - part->daughters().push_back(dau); - return true; + for (MAuint32 i = 0; i < part->daughters().size(); i++) + { + MCParticleFormat *d = part->daughters()[i]; + if (d == dau) + return false; + } + part->daughters().push_back(dau); + return true; } - // ----------------------------------------------------------------------------- // FinalizeEvent // ----------------------------------------------------------------------------- -MAbool STDHEPreader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) +MAbool STDHEPreader::FinalizeEvent(SampleFormat &mySample, EventFormat &myEvent) { - // Is it a bugged event ? - if (!firstevent && nevhept_ == nevhept_before_) return false; - nevhept_before_ = nevhept_; - firstevent=false; - - // BUG FIX HERE : myEvent.mc()->particles()[i] LEADs TO CRASH - // MUST USE myEvent.mc()->particles_[i]; - // WHY????? - - // Mother-daughter relations - for (MAuint32 i=0; iparticles_.size();i++) - { - MCParticleFormat* part = &(myEvent.mc()->particles_[i]); - MAint32& mothup1 = mothers_[i].first; - MAint32& mothup2 = mothers_[i].second; - - if (mothup1>0) + // Is it a bugged event ? + if (!firstevent && nevhept_ == nevhept_before_) + return false; + nevhept_before_ = nevhept_; + firstevent = false; + + // BUG FIX HERE : myEvent.mc()->particles()[i] LEADs TO CRASH + // MUST USE myEvent.mc()->particles_[i]; + // WHY????? + + // Mother-daughter relations + for (MAuint32 i = 0; i < myEvent.mc()->particles_.size(); i++) { - if (static_cast(mothup1)<=myEvent.mc()->particles_.size()) - { - MCParticleFormat* mum = &(myEvent.mc()->particles_[static_cast(mothup1-1)]); - if (part!=mum) + MCParticleFormat *part = &(myEvent.mc()->particles_[i]); + MAint32 &mothup1 = mothers_[i].first; + MAint32 &mothup2 = mothers_[i].second; + + if (mothup1 > 0) { - AddMothers(part,mum); - AddDaughters(mum,part); + if (static_cast(mothup1) <= myEvent.mc()->particles_.size()) + { + MCParticleFormat *mum = &(myEvent.mc()->particles_[static_cast(mothup1 - 1)]); + if (part != mum) + { + AddMothers(part, mum); + AddDaughters(mum, part); + } + } + else + { + std::cout << "ERROR: a particle is its own mother" << std::endl; + } } - } - else - { - std::cout << "ERROR: a particle is its own mother" << std::endl; - } - } - if (mothup2>0) - { - if (static_cast(mothup2)<=myEvent.mc()->particles_.size()) - { - MCParticleFormat* mum = &(myEvent.mc()->particles_[static_cast(mothup2-1)]); - if (mum!=part) + if (mothup2 > 0) { - AddMothers(part,mum); - AddDaughters(mum,part); + if (static_cast(mothup2) <= myEvent.mc()->particles_.size()) + { + MCParticleFormat *mum = &(myEvent.mc()->particles_[static_cast(mothup2 - 1)]); + if (mum != part) + { + AddMothers(part, mum); + AddDaughters(mum, part); + } + } + else + { + std::cout << "ERROR: a particle is its own mother" << std::endl; + } } - } - else - { - std::cout << "ERROR: a particle is its own mother" << std::endl; - } } - } - mothers_.clear(); + mothers_.clear(); - // Global event observable - for (MAuint32 i=0; iparticles_.size();i++) - { - MCParticleFormat& part = myEvent.mc()->particles_[i]; - - // MET, MHT, TET, THT - if (part.statuscode()==1 && !PHYSICS->Id->IsInvisible(part)) + // Global event observable + for (MAuint32 i = 0; i < myEvent.mc()->particles_.size(); i++) { - myEvent.mc()->MET_ -= part.momentum(); - myEvent.mc()->TET_ += part.pt(); - if (PHYSICS->Id->IsHadronic(part)) - { - myEvent.mc()->MHT_ -= part.momentum(); - myEvent.mc()->THT_ += part.pt(); - myEvent.mc()->Meff_ += part.pt(); - } + MCParticleFormat &part = myEvent.mc()->particles_[i]; + + // MET, MHT, TET, THT + if (part.statuscode() == 1 && !PHYSICS->Id->IsInvisible(part)) + { + myEvent.mc()->MET_ -= part.momentum(); + myEvent.mc()->TET_ += part.pt(); + if (PHYSICS->Id->IsHadronic(part)) + { + myEvent.mc()->MHT_ -= part.momentum(); + myEvent.mc()->THT_ += part.pt(); + myEvent.mc()->Meff_ += part.pt(); + } + } } - } - // Finalize event - myEvent.mc()->MET_.momentum().SetPz(0.); - myEvent.mc()->MET_.momentum().SetE(myEvent.mc()->MET_.momentum().Pt()); - myEvent.mc()->MHT_.momentum().SetPz(0.); - myEvent.mc()->MHT_.momentum().SetE(myEvent.mc()->MHT_.momentum().Pt()); - myEvent.mc()->Meff_ += myEvent.mc()->MET_.pt(); + // Finalize event + myEvent.mc()->MET_.momentum().SetPz(0.); + myEvent.mc()->MET_.momentum().SetE(myEvent.mc()->MET_.momentum().Pt()); + myEvent.mc()->MHT_.momentum().SetPz(0.); + myEvent.mc()->MHT_.momentum().SetE(myEvent.mc()->MHT_.momentum().Pt()); + myEvent.mc()->Meff_ += myEvent.mc()->MET_.pt(); - // Normal end - return true; + // Normal end + return true; } - // ----------------------------------------------------------------------------- // Finalize // ----------------------------------------------------------------------------- MAbool STDHEPreader::Finalize() { - if (!ReaderTextBase::Finalize()) return false; - if (xdrinput_!=0) delete xdrinput_; - return true; + if (!ReaderTextBase::Finalize()) + return false; + if (xdrinput_ != 0) + delete xdrinput_; + return true; } - // ----------------------------------------------------------------------------- // SetVersion // ----------------------------------------------------------------------------- -void STDHEPreader::SetVersion(const std::string& version) +void STDHEPreader::SetVersion(const std::string &version) { - if (version.size()<2) version_=UNKNOWN; - else if (version[0]==1) version_=V1; - else if (version=="2.01") version_=V21; - else if (version[0]==2) version_=V2; - else version_=UNKNOWN; + if (version.size() < 2) + version_ = UNKNOWN; + else if (version[0] == 1) + version_ = V1; + else if (version == "2.01") + version_ = V21; + else if (version[0] == 2) + version_ = V2; + else + version_ = UNKNOWN; } diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h index 184b8deb..6b04cf01 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelection.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef __REGIONSELECTION_H #define __REGIONSELECTION_H - // STL headers #include #include @@ -34,90 +32,75 @@ #include "SampleAnalyzer/Process/Counter/CounterManager.h" #include "SampleAnalyzer/Process/Writer/SAFWriter.h" - namespace MA5 { -class RegionSelection -{ - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private: - std::string name_; - MAbool surviving_; - MAuint32 NumberOfCutsAppliedSoFar_; - MAfloat64 weight_; - - CounterManager cutflow_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - /// Constructor without argument - RegionSelection() {name_ = "";}; - - /// Constructor with argument - RegionSelection(const std::string& name) { name_=name; }; - - /// Destructor - ~RegionSelection() { }; - - /// Get methods - std::string GetName() - { return name_; } - - MAbool IsSurviving() - { return surviving_; } - - MAuint32 GetNumberOfCutsAppliedSoFar() - { return NumberOfCutsAppliedSoFar_; } - - /// Printing the list of histograms - void WriteDefinition(SAFWriter &output); - - /// Printing the cutflow - void WriteCutflow(SAFWriter& output) - { cutflow_.Write_TextFormat(output); } - - /// Set methods - void SetName(std::string name) - { name_ = name; } - - /// Set weight - void SetWeight(MAfloat64 weight) { weight_=weight;} - - /// Set weight - MAfloat64 GetWeight() { return weight_;} - - void SetSurvivingTest(MAbool surviving) - { surviving_ = surviving; } - - void SetNumberOfCutsAppliedSoFar(MAuint32 NumberOfCutsAppliedSoFar) - { NumberOfCutsAppliedSoFar_ = NumberOfCutsAppliedSoFar; } - - // Increment CutFlow (when this region passes a cut) - void IncrementCutFlow(MAfloat64 weight) - { - cutflow_[NumberOfCutsAppliedSoFar_].Increment(weight); - NumberOfCutsAppliedSoFar_++; - } - - // Add a cut to the CutFlow - void AddCut(std::string const &CutName) - { cutflow_.InitCut(CutName); } - - /// Getting ready for a new event - void InitializeForNewEvent(const MAfloat64 &weight) - { - SetSurvivingTest(true); - SetNumberOfCutsAppliedSoFar(0); - cutflow_.IncrementNInitial(weight); - weight_=weight; - } - -}; + class RegionSelection + { + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + std::string name_; + MAbool surviving_; + MAuint32 NumberOfCutsAppliedSoFar_; + + CounterManager cutflow_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + RegionSelection() { name_ = ""; }; + + /// Constructor with argument + RegionSelection(const std::string &name) { name_ = name; }; + + /// Destructor + ~RegionSelection() {}; + + /// Get methods + std::string GetName() { return name_; } + + MAbool IsSurviving() { return surviving_; } + + MAuint32 GetNumberOfCutsAppliedSoFar() { return NumberOfCutsAppliedSoFar_; } + + /// Printing the list of histograms + void WriteDefinition(SAFWriter &output); + + /// Printing the cutflow + void WriteCutflow(SAFWriter &output) { cutflow_.Write_TextFormat(output); } + + /// Set methods + void SetName(std::string name) { name_ = name; } + + void SetSurvivingTest(MAbool surviving) { surviving_ = surviving; } + + void SetNumberOfCutsAppliedSoFar(MAuint32 NumberOfCutsAppliedSoFar) + { + NumberOfCutsAppliedSoFar_ = NumberOfCutsAppliedSoFar; + } + + // Increment CutFlow (when this region passes a cut) + void IncrementCutFlow(const WeightCollection &weight) + { + cutflow_[NumberOfCutsAppliedSoFar_].Increment(weight); + NumberOfCutsAppliedSoFar_++; + } + + // Add a cut to the CutFlow + void AddCut(std::string const &CutName) { cutflow_.InitCut(CutName); } + + /// Getting ready for a new event + void InitializeForNewEvent(const WeightCollection &weights) + { + SetSurvivingTest(true); + SetNumberOfCutsAppliedSoFar(0); + cutflow_.IncrementNInitial(weights); + } + }; } diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp index 58022686..5365ecbf 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp @@ -1,5 +1,5 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: // @@ -33,179 +33,181 @@ using namespace MA5; /// Apply a cut MAbool RegionSelectionManager::ApplyCut(MAbool condition, std::string const &cut) { - /// Skip the cut if all regions are already failing the previous cut - if (NumberOfSurvivingRegions_ == 0) - { - return false; - } - - /// Get the cut under consideration - MultiRegionCounter *mycut = 0; - for (MAuint32 i = 0; i < cutmanager_.GetNcuts(); i++) - { - if (cut.compare(cutmanager_.GetCuts()[i]->GetName()) == 0) - { - mycut = cutmanager_.GetCuts()[i]; - break; - } - } - // Trying to apply a non-existing cut - try - { - if (mycut == 0) - throw EXCEPTION_WARNING("Trying to apply the non-declared cut \"" + cut + "\"", "", 0); - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - return true; - } - - // Looping over all regions the cut needs to be applied - std::vector RegionsForThisCut = mycut->Regions(); - for (MAuint32 i = 0; i < RegionsForThisCut.size(); i++) - { - RegionSelection *ThisRegion = RegionsForThisCut[i]; - - /// Skip the current region if it has failed a previous cut - if (!ThisRegion->IsSurviving()) - { - continue; - } - - /// Check the current cut: - if (condition) - { - ThisRegion->IncrementCutFlow(ThisRegion->GetWeight()); - } - else - { - ThisRegion->SetSurvivingTest(false); - NumberOfSurvivingRegions_--; - if (NumberOfSurvivingRegions_ == 0) - { - return false; - } - } - } - - /// If we're here, we've looped through all RegionsForThisCut and - /// NumberOfSurvivingRegions is still greater than zero, so return true. - return true; + /// Skip the cut if all regions are already failing the previous cut + if (NumberOfSurvivingRegions_ == 0) + return false; + + /// Get the cut under consideration + MultiRegionCounter *mycut = 0; + for (MAuint32 i = 0; i < cutmanager_.GetNcuts(); i++) + { + if (cut.compare(cutmanager_.GetCuts()[i]->GetName()) == 0) + { + mycut = cutmanager_.GetCuts()[i]; + break; + } + } + // Trying to apply a non-existing cut + try + { + if (mycut == 0) + throw EXCEPTION_WARNING("Trying to apply the non-declared cut \"" + cut + "\"", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return true; + } + + // Looping over all regions the cut needs to be applied + std::vector RegionsForThisCut = mycut->Regions(); + for (MAuint32 i = 0; i < RegionsForThisCut.size(); i++) + { + RegionSelection *ThisRegion = RegionsForThisCut[i]; + + /// Skip the current region if it has failed a previous cut + if (!ThisRegion->IsSurviving()) + continue; + + WeightCollection current_region_weight; + if (region_weight_.find(ThisRegion->GetName()) != region_weight_.end()) + current_region_weight = region_weight_[ThisRegion->GetName()]; + else + current_region_weight = weight_; + + /// Check the current cut: + if (condition) + { + ThisRegion->IncrementCutFlow(current_region_weight); + } + else + { + ThisRegion->SetSurvivingTest(false); + NumberOfSurvivingRegions_--; + if (NumberOfSurvivingRegions_ == 0) + return false; + } + } + + /// If we're here, we've looped through all RegionsForThisCut and + /// NumberOfSurvivingRegions is still greater than zero, so return true. + return true; } /// Filling an histo with a value val void RegionSelectionManager::FillHisto(std::string const &histname, MAfloat64 val) { - // Current histo - Histo *myhisto = 0; - HistoFrequency *myhistof = 0; - HistoLogX *myhistoX = 0; - // Looping over all histos - for (MAuint32 i = 0; i < plotmanager_.GetNplots(); i++) - { - if (histname.compare(plotmanager_.GetHistos()[i]->GetName()) == 0) - { - // HistoFrequency - if (dynamic_cast(plotmanager_.GetHistos()[i]) != 0) - { - myhistof = dynamic_cast(plotmanager_.GetHistos()[i]); - if (myhistof->AllSurviving() == 0) - return; - try - { - if (myhistof->AllSurviving() == -1) - throw EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far", "", 0); - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - } - // Filling the histo - if (myhistof->FreshEvent()) - myhistof->IncrementNEvents(weight_); - myhistof->Fill(val, weight_); - } - // LogX histo - else if (dynamic_cast(plotmanager_.GetHistos()[i]) != 0) - { - myhistoX = dynamic_cast(plotmanager_.GetHistos()[i]); - if (myhistoX->AllSurviving() == 0) - return; - try - { - if (myhistoX->AllSurviving() == -1) - throw EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far", "", 0); - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - } - // Filling the histo - if (myhistoX->FreshEvent()) - myhistoX->IncrementNEvents(weight_); - myhistoX->Fill(val, weight_); - } - // Normal histo - else if (dynamic_cast(plotmanager_.GetHistos()[i]) != 0) - { - myhisto = dynamic_cast(plotmanager_.GetHistos()[i]); - if (myhisto->AllSurviving() == 0) - return; - try - { - if (myhisto->AllSurviving() == -1) - throw EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far", "", 0); - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - } - // Filling the histo - if (myhisto->FreshEvent()) - myhisto->IncrementNEvents(weight_); - myhisto->Fill(val, weight_); - } - break; - } - } - // Trying to fill a non-existing histo - try - { - if ((myhisto == 0) && (myhistof == 0) && (myhistoX == 0)) - throw EXCEPTION_WARNING("Trying to fill non-declared histogram \"" + histname + "\"", "", 0); - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - return; - } + // Current histo + Histo *myhisto = 0; + HistoFrequency *myhistof = 0; + HistoLogX *myhistoX = 0; + // Looping over all histos + for (MAuint32 i = 0; i < plotmanager_.GetNplots(); i++) + { + if (histname.compare(plotmanager_.GetHistos()[i]->GetName()) == 0) + { + // HistoFrequency + if (dynamic_cast(plotmanager_.GetHistos()[i]) != 0) + { + myhistof = dynamic_cast(plotmanager_.GetHistos()[i]); + + if (myhistof->AllSurviving() == 0) + return; + try + { + if (myhistof->AllSurviving() == -1) + throw EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + // Filling the histo + if (myhistof->FreshEvent()) + myhistof->IncrementNEvents(weight_); + myhistof->Fill(val, weight_); + } + // LogX histo + else if (dynamic_cast(plotmanager_.GetHistos()[i]) != 0) + { + myhistoX = dynamic_cast(plotmanager_.GetHistos()[i]); + if (myhistoX->AllSurviving() == 0) + return; + try + { + if (myhistoX->AllSurviving() == -1) + throw EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + // Filling the histo + if (myhistoX->FreshEvent()) + myhistoX->IncrementNEvents(weight_); + myhistoX->Fill(val, weight_); + } + // Normal histo + else if (dynamic_cast(plotmanager_.GetHistos()[i]) != 0) + { + myhisto = dynamic_cast(plotmanager_.GetHistos()[i]); + if (myhisto->AllSurviving() == 0) + return; + try + { + if (myhisto->AllSurviving() == -1) + throw EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + // Filling the histo + if (myhisto->FreshEvent()) + myhisto->IncrementNEvents(weight_); + myhisto->Fill(val, weight_); + } + break; + } + } + // Trying to fill a non-existing histo + try + { + if ((myhisto == 0) && (myhistof == 0) && (myhistoX == 0)) + throw EXCEPTION_WARNING("Trying to fill non-declared histogram \"" + histname + "\"", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return; + } } void RegionSelectionManager::WriteHistoDefinition(SAFWriter &output) { - *output.GetStream() << "" << std::endl; - for (MAuint32 i = 0; i < regions_.size(); i++) - regions_[i]->WriteDefinition(output); - *output.GetStream() << "" << std::endl - << std::endl; + *output.GetStream() << "" << std::endl; + for (MAuint32 i = 0; i < regions_.size(); i++) + regions_[i]->WriteDefinition(output); + *output.GetStream() << "" << std::endl + << std::endl; } void RegionSelectionManager::HeadSR(std::ostream &outwriter, const std::string &ananame, MAbool &is_first) { - // Set first SR out of the for loop to avoid many if executions - // use :: instead of - since - is generally used in SR names - if (regions_.size() > 0 && is_first) - outwriter << ananame << "::" << regions_[0]->GetName(); + // Set first SR out of the for loop to avoid many if executions + // use :: instead of - since - is generally used in SR names + if (regions_.size() > 0 && is_first) + outwriter << ananame << "::" << regions_[0]->GetName(); - for (MAuint32 i = is_first ? 1 : 0; i < regions_.size(); i++) - outwriter << "," << ananame << "::" << regions_[i]->GetName(); + for (MAuint32 i = is_first ? 1 : 0; i < regions_.size(); i++) + outwriter << "," << ananame << "::" << regions_[i]->GetName(); } void RegionSelectionManager::DumpSR(std::ostream &outwriter, MAbool &is_first) { - // Set first SR out of the for loop to avoid many if executions - if (regions_.size() > 0 && is_first) outwriter << regions_[0]->IsSurviving(); + // Set first SR out of the for loop to avoid many if executions + if (regions_.size() > 0 && is_first) + outwriter << regions_[0]->IsSurviving(); for (MAuint32 i = is_first ? 1 : 0; i < regions_.size(); i++) outwriter << "," << regions_[i]->IsSurviving(); diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h index e9afe9a2..dcadd682 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h @@ -29,6 +29,8 @@ #include #include +#define assertm(exp, msg) assert(((void)msg, exp)) + // SampleAnalyzer headers #include "SampleAnalyzer/Process/Counter/MultiRegionCounterManager.h" #include "SampleAnalyzer/Process/Plot/PlotManager.h" @@ -59,7 +61,10 @@ namespace MA5 MAuint32 NumberOfSurvivingRegions_; /// Weight associated with the processed event - MAfloat64 weight_; + WeightCollection weight_; + + /// Weight associated with specific regions + std::map region_weight_; // ------------------------------------------------------------- // method members @@ -72,69 +77,52 @@ namespace MA5 ~RegionSelectionManager() { for (auto ®ion_pointer : regions_) - { delete region_pointer; - } }; /// Reset void Reset() { - for (MAuint32 i = 0; i < regions_.size(); i++) - { - if (regions_[i] != 0) - delete regions_[i]; - } regions_.clear(); cutmanager_.Finalize(); plotmanager_.Finalize(); + weight_.clear(); + region_weight_.clear(); } /// Finalizing void Finalize() { Reset(); } /// Get methods - std::vector Regions() - { - return regions_; - } + std::vector Regions() { return regions_; } - MultiRegionCounterManager *GetCutManager() - { - return &cutmanager_; - } + MultiRegionCounterManager *GetCutManager() { return &cutmanager_; } - PlotManager *GetPlotManager() - { - return &plotmanager_; - } + PlotManager *GetPlotManager() { return &plotmanager_; } - MAfloat64 GetCurrentEventWeight() - { - return weight_; - } + /// @brief Accessor to the current event weight + /// @return weight collection object + const WeightCollection GetCurrentEventWeights() const { return weight_; } - /// Set method - void SetCurrentEventWeight(MAfloat64 weight) - { - weight_ = weight; - for (MAuint16 i = 0; i < regions_.size(); i++) - { - regions_[i]->SetWeight(weight); - } - } + /// @brief Accessor to the current event weight + /// @return weight collection object + /// This function is for backwards compatibility + const MAdouble64 GetCurrentEventWeight() const { return weight_[0]; } + + /// @brief Set current event weight with a weight map + /// @param weight weight index and value + void SetCurrentEventWeight(WeightCollection &weight) { weight_ = WeightCollection(weight); } + + /// @brief Set current event weight with a weight map + /// @param weight weight index and value + void SetCurrentEventWeight(const WeightCollection &weight) { weight_ = WeightCollection(weight); } - /// Set method - void SetRegionWeight(std::string name, MAfloat64 weight) + /// @brief Set a specific weight to a region different than the others + /// @param name region name + /// @param weight weight collection object + void SetRegionWeight(std::string name, WeightCollection &weight) { - for (MAuint16 i = 0; i < regions_.size(); i++) - { - if (regions_[i]->GetName() == name) - { - regions_[i]->SetWeight(weight); - break; - } - } + region_weight_.insert(std::make_pair(name, WeightCollection(weight))); } /// Adding a RegionSelection to the manager @@ -151,15 +139,19 @@ namespace MA5 regions_.push_back(myregion); } - /// Getting ready for a new event - void InitializeForNewEvent(MAfloat64 EventWeight) + /// THIS FUNCTION HAS BEEN DEPRECATED + void InitializeForNewEvent(MAfloat64 EventWeight) {} + + /// @brief initialise new event with multiweight definition + /// @param EventWeight weight map + void InitializeForNewEvent(const WeightCollection &EventWeight) { - weight_ = EventWeight; + weight_.SetWeights(EventWeight.GetWeights()); NumberOfSurvivingRegions_ = regions_.size(); - for (MAuint32 i = 0; i < regions_.size(); i++) - regions_[i]->InitializeForNewEvent(EventWeight); + for (auto ® : regions_) + reg->InitializeForNewEvent(EventWeight); for (MAuint32 i = 0; i < plotmanager_.GetNplots(); i++) - plotmanager_.GetHistos()[i]->SetFreshEvent(true); + plotmanager_.GetHistos()[i]->SetFreshEvent(true, EventWeight); } /// This method associates all regions with a cut diff --git a/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp b/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp index add6b44c..f60814ff 100644 --- a/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp +++ b/tools/SampleAnalyzer/Process/Writer/LHEWriter.cpp @@ -1,27 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // STL headers #include @@ -29,713 +28,774 @@ #include "SampleAnalyzer/Process/Writer/LHEWriter.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - using namespace MA5; - -MAbool MCParticleToSave(const MCParticleFormat& part, const SampleFormat& sample) +MAbool MCParticleToSave(const MCParticleFormat &part, const SampleFormat &sample) { - // Special Herwig6 - if (sample.sampleGenerator()==MA5GEN::HERWIG6) - { - return part.statuscode()>=110 && - part.statuscode()<=125; - } - - // Else Herwig6 - else - { - return part.statuscode()==3 || - ( part.statuscode()>=21 && - part.statuscode()<=29); - } -} - + // Special Herwig6 + if (sample.sampleGenerator() == MA5GEN::HERWIG6) + { + return part.statuscode() >= 110 && + part.statuscode() <= 125; + } -MAbool InitialMCParticleToSave(const MCParticleFormat& part, const SampleFormat& sample) -{ - // Special Herwig6 - if (sample.sampleGenerator()==MA5GEN::HERWIG6) - { - return part.statuscode()>=101 && - part.statuscode()<=102; - } - - // Else Herwig6 - else - { - return (part.statuscode()==3 && part.pt()==0) || - (part.statuscode()>=11 && part.statuscode()<=19) || - (part.statuscode()==21 && part.pt()==0); - } + // Else Herwig6 + else + { + return part.statuscode() == 3 || + (part.statuscode() >= 21 && + part.statuscode() <= 29); + } } +MAbool InitialMCParticleToSave(const MCParticleFormat &part, const SampleFormat &sample) +{ + // Special Herwig6 + if (sample.sampleGenerator() == MA5GEN::HERWIG6) + { + return part.statuscode() >= 101 && + part.statuscode() <= 102; + } + // Else Herwig6 + else + { + return (part.statuscode() == 3 && part.pt() == 0) || + (part.statuscode() >= 11 && part.statuscode() <= 19) || + (part.statuscode() == 21 && part.pt() == 0); + } +} -MAuint32 Find(const MCParticleFormat* part, - const std::vector& collection) +MAuint32 Find(const MCParticleFormat *part, + const std::vector &collection) { - if (part==0) return 0; - for (MAuint32 i=0;i& collection) +MAuint32 FindDeeply(const MCParticleFormat *part, + const std::vector &collection) { - if (part==0) return 0; - MAbool test=false; - const MCParticleFormat* thepart = part; - MAuint32 counter=0; - - while(!test) - { - counter++; - if (counter>=100000) + if (part == 0) + return 0; + MAbool test = false; + const MCParticleFormat *thepart = part; + MAuint32 counter = 0; + + while (!test) { - try - { - throw EXCEPTION_ERROR("Number of calls exceed: infinite loop is detected","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - break; - } + counter++; + if (counter >= 100000) + { + try + { + throw EXCEPTION_ERROR("Number of calls exceed: infinite loop is detected", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + break; + } + } + if (thepart->mothers().size() == 0) + { + test = true; + thepart = 0; + } + else if (thepart->mothers()[0]->statuscode() == 3 || + (thepart->mothers()[0]->statuscode() >= 11 && + thepart->mothers()[0]->statuscode() <= 29)) + { + test = true; + thepart = thepart->mothers()[0]; + } + else + { + thepart = thepart->mothers()[0]; + } } - if (thepart->mothers().size()==0) + if (thepart == 0) + return 0; + for (MAuint32 i = 0; i < collection.size(); i++) + if (collection[i] == thepart) + return i + 1; + return 0; +} + +std::string LHEWriter::FortranFormat_SimplePrecision(MAfloat32 value, MAuint32 precision) +{ + std::stringstream str; + str.precision(precision); + std::string word; + + MAbool negative = false; + if (value < 0.) { - test=true; - thepart=0; + negative = true; + value *= -1.; } - else if (thepart->mothers()[0]->statuscode()==3 || - ( thepart->mothers()[0]->statuscode()>=11 && - thepart->mothers()[0]->statuscode()<=29) ) + + MAint32 exponent = 0; + if (value != 0.) { - test=true; - thepart=thepart->mothers()[0]; + for (; value >= 10.; exponent++) + value /= 10.; + for (; value < 1.; exponent--) + value *= 10.; } + + str << std::uppercase << std::fixed << value << "E"; + if (exponent >= 0) + str << "+"; else - { - thepart=thepart->mothers()[0]; - } - } - if (thepart==0) return 0; - for (MAuint32 i=0;i> word; + if (!negative) + return word; + else + return "-" + word; } - -std::string LHEWriter::FortranFormat_SimplePrecision(MAfloat32 value,MAuint32 precision) +std::string LHEWriter::FortranFormat_DoublePrecision(MAfloat64 value, MAuint32 precision) { - std::stringstream str; - str.precision(precision); - std::string word; - - MAbool negative=false; - if (value<0.) {negative=true; value*=-1.;} - - MAint32 exponent = 0; - if (value!=0.) - { - for (; value >= 10.; exponent++) value/=10.; - for (; value < 1. ; exponent--) value*=10.; - } - - str << std::uppercase << std::fixed << value << "E"; - if (exponent>=0) str << "+"; else str << "-"; - if (abs(exponent)<10) str << "0"; - str << abs(exponent); - str >> word; - if (!negative) return word; - else return "-"+word; -} + std::stringstream str; + str.precision(precision); + std::string word; + MAbool negative = false; + if (value < 0.) + { + negative = true; + value *= -1.; + } -std::string LHEWriter::FortranFormat_DoublePrecision(MAfloat64 value,MAuint32 precision) -{ - std::stringstream str; - str.precision(precision); - std::string word; - - MAbool negative=false; - if (value<0.) {negative=true; value*=-1.;} - - MAint32 exponent = 0.; - if (value!=0.) - { - for (; value >= 10.; exponent++) value/=10.; - for (; value < 1. ; exponent--) value*=10.; - } - - str << std::uppercase << std::fixed << value << "E"; - if (exponent>=0) str << "+"; else str << "-"; - if (abs(exponent)<10) str << "0"; - str << abs(exponent); - str >> word; - if (!negative) return word; - else return "-"+word; -} + MAint32 exponent = 0.; + if (value != 0.) + { + for (; value >= 10.; exponent++) + value /= 10.; + for (; value < 1.; exponent--) + value *= 10.; + } + str << std::uppercase << std::fixed << value << "E"; + if (exponent >= 0) + str << "+"; + else + str << "-"; + if (abs(exponent) < 10) + str << "0"; + str << abs(exponent); + str >> word; + if (!negative) + return word; + else + return "-" + word; +} /// Read the sample -MAbool LHEWriter::WriteHeader(const SampleFormat& mySample) +MAbool LHEWriter::WriteHeader(const SampleFormat &mySample) { - // Opening tag - *output_ << "" << std::endl; - - // Header tag - *output_ << "
" << std::endl; - *output_ << "" << std::endl; - *output_ << "
" << std::endl; - - // Init block - *output_ << "" << std::endl; - - // To fill - if (mySample.mc()==0) - { - *output_ << std::setw(9) << std::right << 0 << " "; // PDGID1 - *output_ << std::setw(8) << std::right << 0 << " "; // PDGID2 - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; // E1 - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; // E2 - *output_ << std::setw(1) << std::right << 0 << " "; // PDF1 - *output_ << std::setw(1) << std::right << 0 << " "; // PDF2 - *output_ << std::setw(5) << std::right << 0 << " "; // PDFID1 - *output_ << std::setw(5) << std::right << 0 << " "; // PDFID2 - *output_ << std::setw(1) << std::right << 1 << " "; // WEIGHT - *output_ << std::setw(2) << std::right << 1; // NPROCESSES - *output_ << std::endl; - - // one process - *output_ << std::setw(19) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0.0) << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; - *output_ << std::setw(3) << std::right << 1; - *output_ << std::endl; - } - else - { - *output_ << std::setw(9) << std::right << mySample.mc()->beamPDGID_.first << " "; - *output_ << std::setw(8) << std::right << mySample.mc()->beamPDGID_.second << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->beamE_.first) << " "; - *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->beamE_.second) << " "; - *output_ << std::setw(1) << std::right << mySample.mc()->beamPDFauthor_.first << " "; - *output_ << std::setw(1) << std::right << mySample.mc()->beamPDFauthor_.second << " "; - *output_ << std::setw(5) << std::right << mySample.mc()->beamPDFID_.first << " "; - *output_ << std::setw(5) << std::right << mySample.mc()->beamPDFID_.second << " "; - *output_ << std::setw(1) << std::right << mySample.mc()->weightMode_ << " "; - if (mySample.mc()->processes().size()==0) + // Opening tag + *output_ << "" << std::endl; + + // Header tag + *output_ << "
" << std::endl; + *output_ << "" << std::endl; + *output_ << "
" << std::endl; + // Init block + *output_ << "" << std::endl; + + // To fill + if (mySample.mc() == 0) + { + *output_ << std::setw(9) << std::right << 0 << " "; // PDGID1 + *output_ << std::setw(8) << std::right << 0 << " "; // PDGID2 + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; // E1 + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; // E2 + *output_ << std::setw(1) << std::right << 0 << " "; // PDF1 + *output_ << std::setw(1) << std::right << 0 << " "; // PDF2 + *output_ << std::setw(5) << std::right << 0 << " "; // PDFID1 + *output_ << std::setw(5) << std::right << 0 << " "; // PDFID2 + *output_ << std::setw(1) << std::right << 1 << " "; // WEIGHT + *output_ << std::setw(2) << std::right << 1; // NPROCESSES + *output_ << std::endl; + + // one process + *output_ << std::setw(19) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0.0) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; + *output_ << std::setw(3) << std::right << 1; + *output_ << std::endl; + } + else + { + *output_ << std::setw(9) << std::right << mySample.mc()->beamPDGID_.first << " "; + *output_ << std::setw(8) << std::right << mySample.mc()->beamPDGID_.second << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->beamE_.first) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->beamE_.second) << " "; + *output_ << std::setw(1) << std::right << mySample.mc()->beamPDFauthor_.first << " "; + *output_ << std::setw(1) << std::right << mySample.mc()->beamPDFauthor_.second << " "; + *output_ << std::setw(5) << std::right << mySample.mc()->beamPDFID_.first << " "; + *output_ << std::setw(5) << std::right << mySample.mc()->beamPDFID_.second << " "; + *output_ << std::setw(1) << std::right << mySample.mc()->weightMode_ << " "; + if (mySample.mc()->processes().size() == 0) + { + *output_ << std::setw(2) << std::right << 1; + } + else + { + *output_ << std::setw(2) << std::right << mySample.mc()->processes().size(); + } + *output_ << std::endl; + for (MAuint32 i = 0; i < mySample.mc()->processes().size(); i++) + { + *output_ << std::setw(19) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->processes_[i].xsectionMean_) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->processes_[i].xsectionError_) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(mySample.mc()->processes_[i].weightMax_) << " "; + *output_ << std::setw(3) << std::right << mySample.mc()->processes_[i].processId_; + *output_ << std::endl; + } - } + if (mySample.mc()->processes().size() == 0) + { + *output_ << std::setw(19) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(0) << " "; + *output_ << std::setw(18) << std::right << LHEWriter::FortranFormat_DoublePrecision(1.0) << " "; + *output_ << std::setw(3) << std::right << 1; + *output_ << std::endl; + } + } - *output_ << "" << std::endl; + *output_ << "
" << std::endl; - return true; + return true; } - MAint32 GetMotherIndex(MAint32 index) { - if (index==0) return 0; - if (index==1 || index==3 || index==5) return 1; - else if (index==2 || index==4 || index==6) return 2; - else return index-4; + if (index == 0) + return 0; + if (index == 1 || index == 3 || index == 5) + return 1; + else if (index == 2 || index == 4 || index == 6) + return 2; + else + return index - 4; } /// Read the event -MAbool LHEWriter::WriteEvent(const EventFormat& myEvent, - const SampleFormat& mySample) +MAbool LHEWriter::WriteEvent(const EventFormat &myEvent, + const SampleFormat &mySample) { - // FirstEvent - if (FirstEvent_) - { - FirstEvent_=false; - WriteHeader(mySample); - } - - // Event header - *output_ << "" << std::endl; - - // Container for particles - std::vector particles; - std::vector pointers; - MAuint32 counter=0; - - // Writing MC particles : only MC info case - // -> hypothesis : input = LHE - if (myEvent.mc()!=0 && myEvent.rec()==0) - { - counter += myEvent.mc()->particles().size(); - } - - // Writing MC particles : MC+REC info case - // -> hypothesis : input = HEP - else if (myEvent.mc()!=0 && myEvent.rec()!=0) - { - for (MAuint32 i=0;iparticles().size();i++) - { - if ( InitialMCParticleToSave(myEvent.mc()->particles()[i],mySample) || - MCParticleToSave(myEvent.mc()->particles()[i],mySample) ) counter++; - } - } - - // Writing REC particles - if (myEvent.rec()!=0) - { - counter += myEvent.rec()->muons().size() + - myEvent.rec()->electrons().size() + - myEvent.rec()->taus().size() + - myEvent.rec()->photons().size() + - myEvent.rec()->jets().size() + 1 /*MET*/; - } - - // Writing event global information - particles.reserve(counter); - pointers.reserve(counter); - WriteEventHeader(myEvent,counter); - - // Writing MC particles : only MC info case - // -> hypothesis : input = LHE - if (myEvent.mc()!=0 && myEvent.rec()==0) - { - // Filling the temporary gen table for mother-daughter relation - std::map gentable; - for (MAuint32 i=0;iparticles().size();i++) + // FirstEvent + if (FirstEvent_) { - gentable[&(myEvent.mc()->particles()[i])]=i+1; + FirstEvent_ = false; + WriteHeader(mySample); } - - // Writing each particle - for (MAuint32 i=0;iparticles().size();i++) + + // Event header + *output_ << "" << std::endl; + + // Container for particles + std::vector particles; + std::vector pointers; + MAuint32 counter = 0; + + // Writing MC particles : only MC info case + // -> hypothesis : input = LHE + if (myEvent.mc() != 0 && myEvent.rec() == 0) { - particles.push_back(LHEParticleFormat()); - const MCParticleFormat* part = &(myEvent.mc()->particles()[i]); - std::vector mothup(2,0); - for (MAuint32 m=0;mmothers().size();m++) - { - if (m>=2) continue; - mothup[m]=gentable[part->mothers()[m]]; - } - if (part->mothers().size()==1) mothup[1]=mothup[0]; - WriteParticle(myEvent.mc()->particles()[i], - mothup[0], - mothup[1], - 0, - particles.back()); + counter += myEvent.mc()->particles().size(); } - } - - // Writing MC particles : MC+REC info case - // -> hypothesis : input = HEP - if (myEvent.mc()!=0 && myEvent.rec()!=0) - { - MAbool firstpart=true; - for (MAuint32 i=0;iparticles().size();i++) - { - const MCParticleFormat* part = &(myEvent.mc()->particles()[i]); - - if ( firstpart && InitialMCParticleToSave(*part,mySample) ) - { - particles.push_back(LHEParticleFormat()); - pointers.push_back(part); - WriteParticle(myEvent.mc()->particles()[i],0,0,-1, particles.back()); - } - else if ( InitialMCParticleToSave(*part,mySample) ) - { - firstpart=false; - particles.push_back(LHEParticleFormat()); - pointers.push_back(part); - WriteParticle(myEvent.mc()->particles()[i],0,0,-1, particles.back()); - } - else if (MCParticleToSave(*part,mySample)) - { - firstpart=false; - particles.push_back(LHEParticleFormat()); - pointers.push_back(part); - std::vector mothers(2,0); - for (MAuint32 m=0;mmothers().size();m++) + // Writing MC particles : MC+REC info case + // -> hypothesis : input = HEP + else if (myEvent.mc() != 0 && myEvent.rec() != 0) + { + for (MAuint32 i = 0; i < myEvent.mc()->particles().size(); i++) { - if (m>=2) continue; - mothers[m]=Find(part->mothers()[m],pointers); + if (InitialMCParticleToSave(myEvent.mc()->particles()[i], mySample) || + MCParticleToSave(myEvent.mc()->particles()[i], mySample)) + counter++; } - WriteParticle(myEvent.mc()->particles()[i],mothers[0],mothers[1],3, particles.back()); - } - else - { - firstpart=false; - } - } - } - - // Writing REC particles - if (myEvent.rec()!=0) - { - for (MAuint32 i=0;imuons().size();i++) + } + + // Writing REC particles + if (myEvent.rec() != 0) { - particles.push_back(LHEParticleFormat()); - MAint32 mother = 0; - if (mySample.sampleGenerator()!=MA5GEN::HERWIG6) mother=FindDeeply(myEvent.rec()->muons()[i].mc(),pointers); - WriteMuon(myEvent.rec()->muons()[i],particles.back(),mother); + counter += myEvent.rec()->muons().size() + + myEvent.rec()->electrons().size() + + myEvent.rec()->taus().size() + + myEvent.rec()->photons().size() + + myEvent.rec()->jets().size() + 1 /*MET*/; } - for (MAuint32 i=0;ielectrons().size();i++) + + // Writing event global information + particles.reserve(counter); + pointers.reserve(counter); + WriteEventHeader(myEvent, counter); + + // Writing MC particles : only MC info case + // -> hypothesis : input = LHE + if (myEvent.mc() != 0 && myEvent.rec() == 0) { - particles.push_back(LHEParticleFormat()); - MAint32 mother = 0; - if (mySample.sampleGenerator()!=MA5GEN::HERWIG6) mother=FindDeeply(myEvent.rec()->electrons()[i].mc(),pointers); - WriteElectron(myEvent.rec()->electrons()[i],particles.back(),mother); + // Filling the temporary gen table for mother-daughter relation + std::map gentable; + for (MAuint32 i = 0; i < myEvent.mc()->particles().size(); i++) + { + gentable[&(myEvent.mc()->particles()[i])] = i + 1; + } + + // Writing each particle + for (MAuint32 i = 0; i < myEvent.mc()->particles().size(); i++) + { + particles.push_back(LHEParticleFormat()); + const MCParticleFormat *part = &(myEvent.mc()->particles()[i]); + std::vector mothup(2, 0); + for (MAuint32 m = 0; m < part->mothers().size(); m++) + { + if (m >= 2) + continue; + mothup[m] = gentable[part->mothers()[m]]; + } + if (part->mothers().size() == 1) + mothup[1] = mothup[0]; + WriteParticle(myEvent.mc()->particles()[i], + mothup[0], + mothup[1], + 0, + particles.back()); + } } - for (MAuint32 i=0;itaus().size();i++) + + // Writing MC particles : MC+REC info case + // -> hypothesis : input = HEP + if (myEvent.mc() != 0 && myEvent.rec() != 0) { - particles.push_back(LHEParticleFormat()); - MAint32 mother = 0; - if (mySample.sampleGenerator()!=MA5GEN::HERWIG6) mother=FindDeeply(myEvent.rec()->taus()[i].mc(),pointers); - WriteTau(myEvent.rec()->taus()[i],particles.back(),mother); + MAbool firstpart = true; + for (MAuint32 i = 0; i < myEvent.mc()->particles().size(); i++) + { + const MCParticleFormat *part = &(myEvent.mc()->particles()[i]); + + if (firstpart && InitialMCParticleToSave(*part, mySample)) + { + particles.push_back(LHEParticleFormat()); + pointers.push_back(part); + WriteParticle(myEvent.mc()->particles()[i], 0, 0, -1, particles.back()); + } + else if (InitialMCParticleToSave(*part, mySample)) + { + firstpart = false; + particles.push_back(LHEParticleFormat()); + pointers.push_back(part); + WriteParticle(myEvent.mc()->particles()[i], 0, 0, -1, particles.back()); + } + + else if (MCParticleToSave(*part, mySample)) + { + firstpart = false; + particles.push_back(LHEParticleFormat()); + pointers.push_back(part); + std::vector mothers(2, 0); + for (MAuint32 m = 0; m < part->mothers().size(); m++) + { + if (m >= 2) + continue; + mothers[m] = Find(part->mothers()[m], pointers); + } + WriteParticle(myEvent.mc()->particles()[i], mothers[0], mothers[1], 3, particles.back()); + } + else + { + firstpart = false; + } + } } - for (MAuint32 i=0;ijets().size();i++) + + // Writing REC particles + if (myEvent.rec() != 0) { - particles.push_back(LHEParticleFormat()); - MAint32 mother = 0; - if (mySample.sampleGenerator()!=MA5GEN::HERWIG6) mother=FindDeeply(myEvent.rec()->jets()[i].mc(),pointers); - WriteJet(myEvent.rec()->jets()[i],particles.back(),mother); + for (MAuint32 i = 0; i < myEvent.rec()->muons().size(); i++) + { + particles.push_back(LHEParticleFormat()); + MAint32 mother = 0; + if (mySample.sampleGenerator() != MA5GEN::HERWIG6) + mother = FindDeeply(myEvent.rec()->muons()[i].mc(), pointers); + WriteMuon(myEvent.rec()->muons()[i], particles.back(), mother); + } + for (MAuint32 i = 0; i < myEvent.rec()->electrons().size(); i++) + { + particles.push_back(LHEParticleFormat()); + MAint32 mother = 0; + if (mySample.sampleGenerator() != MA5GEN::HERWIG6) + mother = FindDeeply(myEvent.rec()->electrons()[i].mc(), pointers); + WriteElectron(myEvent.rec()->electrons()[i], particles.back(), mother); + } + for (MAuint32 i = 0; i < myEvent.rec()->taus().size(); i++) + { + particles.push_back(LHEParticleFormat()); + MAint32 mother = 0; + if (mySample.sampleGenerator() != MA5GEN::HERWIG6) + mother = FindDeeply(myEvent.rec()->taus()[i].mc(), pointers); + WriteTau(myEvent.rec()->taus()[i], particles.back(), mother); + } + for (MAuint32 i = 0; i < myEvent.rec()->jets().size(); i++) + { + particles.push_back(LHEParticleFormat()); + MAint32 mother = 0; + if (mySample.sampleGenerator() != MA5GEN::HERWIG6) + mother = FindDeeply(myEvent.rec()->jets()[i].mc(), pointers); + WriteJet(myEvent.rec()->jets()[i], particles.back(), mother); + } + for (MAuint32 i = 0; i < myEvent.rec()->photons().size(); i++) + { + particles.push_back(LHEParticleFormat()); + MAint32 mother = 0; + if (mySample.sampleGenerator() != MA5GEN::HERWIG6) + mother = FindDeeply(myEvent.rec()->photons()[i].mc(), pointers); + WritePhoton(myEvent.rec()->photons()[i], particles.back(), mother); + } + particles.push_back(LHEParticleFormat()); + WriteMET(myEvent.rec()->MET(), particles.back()); } - for (MAuint32 i=0;iphotons().size();i++) + + // Particle list + for (MAuint32 i = 0; i < particles.size(); i++) + particles[i].Print(i + 1, output_); + + // Weights + if (mySample.mc()->WeightNames().size() > 0) { - particles.push_back(LHEParticleFormat()); - MAint32 mother = 0; - if (mySample.sampleGenerator()!=MA5GEN::HERWIG6) mother=FindDeeply(myEvent.rec()->photons()[i].mc(),pointers); - WritePhoton(myEvent.rec()->photons()[i],particles.back(),mother); + *output_ << " " << std::endl; + for (MAuint32 idx = 0; idx < myEvent.mc()->weights().size(); idx++) + *output_ << " " << std::setw(18) << std::right + << FortranFormat_DoublePrecision(myEvent.mc()->weights()[idx]) << " " << std::endl; + *output_ << " " << std::endl; } - particles.push_back(LHEParticleFormat()); - WriteMET(myEvent.rec()->MET(),particles.back()); - } - - // Event foot - for (MAuint32 i=0;i" << std::endl; - return true; -} + // Footer + *output_ << "" << std::endl; + return true; +} /// Finalize the event -MAbool LHEWriter::WriteFoot(const SampleFormat& mySample) +MAbool LHEWriter::WriteFoot(const SampleFormat &mySample) { - // FirstEvent - if (FirstEvent_) return false; + // FirstEvent + if (FirstEvent_) + return false; - // Foot - *output_ << "
" << std::endl; - return true; + // Foot + *output_ << "" << std::endl; + return true; } - /// Writing event global information -MAbool LHEWriter::WriteEventHeader(const EventFormat& myEvent, - MAuint32 nevents) +MAbool LHEWriter::WriteEventHeader(const EventFormat &myEvent, + MAuint32 nevents) { - if (myEvent.mc()!=0) - { - *output_ << std::setw(2) << std::right << nevents << " "; - *output_ << std::setw(3) << std::right << myEvent.mc()->processId_ << " "; - MAfloat64 myweight = myEvent.mc()->weight_; - if (myweight==0) myweight=1; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myweight) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->scale_) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->alphaQED_) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->alphaQCD_) << std::endl; - } - else - { - *output_ << std::setw(2) << std::right << nevents << " "; - *output_ << std::setw(3) << std::right << 1 << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(1.0) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << " "; - *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << std::endl; - } - return true; + if (myEvent.mc() != 0) + { + *output_ << std::setw(2) << std::right << nevents << " "; + *output_ << std::setw(3) << std::right << myEvent.mc()->processId_ << " "; + MAfloat64 myweight = myEvent.mc()->GetWeight(0); + if (myweight == 0) + myweight = 1; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myweight) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->scale_) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->alphaQED_) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(myEvent.mc()->alphaQCD_) << std::endl; + } + else + { + *output_ << std::setw(2) << std::right << nevents << " "; + *output_ << std::setw(3) << std::right << 1 << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(1.0) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << " "; + *output_ << std::setw(14) << std::right << LHEWriter::FortranFormat_SimplePrecision(0.0) << std::endl; + } + return true; } - /// Writing a particle -void LHEWriter::WriteParticle(const MCParticleFormat& myPart, - MAint32 mother1, MAint32 mother2, - MAint32 statuscode, LHEParticleFormat& lhe) +void LHEWriter::WriteParticle(const MCParticleFormat &myPart, + MAint32 mother1, MAint32 mother2, + MAint32 statuscode, LHEParticleFormat &lhe) { - if (statuscode!=0) lhe.status = statuscode; - else lhe.status = myPart.statuscode_; - lhe.id = myPart.pdgid_; - lhe.mother1 = mother1; - lhe.mother2 = mother2; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = myPart.momentum().Px(); - lhe.py = myPart.momentum().Py(); - lhe.pz = myPart.momentum().Pz(); - lhe.e = myPart.momentum().E(); - lhe.m = myPart.momentum().M(); - lhe.ctau = myPart.decay_vertex().T(); - lhe.spin = myPart.spin_; + if (statuscode != 0) + lhe.status = statuscode; + else + lhe.status = myPart.statuscode_; + lhe.id = myPart.pdgid_; + lhe.mother1 = mother1; + lhe.mother2 = mother2; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = myPart.momentum().Px(); + lhe.py = myPart.momentum().Py(); + lhe.pz = myPart.momentum().Pz(); + lhe.e = myPart.momentum().E(); + lhe.m = myPart.momentum().M(); + lhe.ctau = myPart.decay_vertex().T(); + lhe.spin = myPart.spin_; } - -void LHEWriter::WriteJet(const RecJetFormat& jet, LHEParticleFormat& lhe, MAint32& mother) +void LHEWriter::WriteJet(const RecJetFormat &jet, LHEParticleFormat &lhe, MAint32 &mother) { - if (jet.btag()) lhe.id = 5; - else if (jet.ctag()) lhe.id = 4; - else lhe.id = 21; - lhe.status = 1; - lhe.mother1 = mother; - lhe.mother2 = mother; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = jet.momentum().Px(); - lhe.py = jet.momentum().Py(); - lhe.pz = jet.momentum().Pz(); - lhe.e = jet.momentum().E(); - lhe.m = jet.momentum().M(); - lhe.ctau = 0.; - lhe.spin = 0.; + if (jet.btag()) + lhe.id = 5; + else if (jet.ctag()) + lhe.id = 4; + else + lhe.id = 21; + lhe.status = 1; + lhe.mother1 = mother; + lhe.mother2 = mother; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = jet.momentum().Px(); + lhe.py = jet.momentum().Py(); + lhe.pz = jet.momentum().Pz(); + lhe.e = jet.momentum().E(); + lhe.m = jet.momentum().M(); + lhe.ctau = 0.; + lhe.spin = 0.; } - -void LHEWriter::WriteMuon(const RecLeptonFormat& muon, LHEParticleFormat& lhe, MAint32& mother) +void LHEWriter::WriteMuon(const RecLeptonFormat &muon, LHEParticleFormat &lhe, MAint32 &mother) { - if (muon.charge()>0) lhe.id = -13; else lhe.id = +13; - lhe.status = 1; - lhe.mother1 = mother; - lhe.mother2 = mother; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = muon.momentum().Px(); - lhe.py = muon.momentum().Py(); - lhe.pz = muon.momentum().Pz(); - lhe.e = muon.momentum().E(); - lhe.m = muon.momentum().M(); - lhe.ctau = 0.; - lhe.spin = 0.; + if (muon.charge() > 0) + lhe.id = -13; + else + lhe.id = +13; + lhe.status = 1; + lhe.mother1 = mother; + lhe.mother2 = mother; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = muon.momentum().Px(); + lhe.py = muon.momentum().Py(); + lhe.pz = muon.momentum().Pz(); + lhe.e = muon.momentum().E(); + lhe.m = muon.momentum().M(); + lhe.ctau = 0.; + lhe.spin = 0.; } -void LHEWriter::WriteElectron(const RecLeptonFormat& electron, LHEParticleFormat& lhe, MAint32& mother) +void LHEWriter::WriteElectron(const RecLeptonFormat &electron, LHEParticleFormat &lhe, MAint32 &mother) { - if (electron.charge()>0) lhe.id = -11; else lhe.id = +11; - lhe.status = 1; - lhe.mother1 = mother; - lhe.mother2 = mother; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = electron.momentum().Px(); - lhe.py = electron.momentum().Py(); - lhe.pz = electron.momentum().Pz(); - lhe.e = electron.momentum().E(); - lhe.m = electron.momentum().M(); - lhe.ctau = 0.; - lhe.spin = 0.; + if (electron.charge() > 0) + lhe.id = -11; + else + lhe.id = +11; + lhe.status = 1; + lhe.mother1 = mother; + lhe.mother2 = mother; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = electron.momentum().Px(); + lhe.py = electron.momentum().Py(); + lhe.pz = electron.momentum().Pz(); + lhe.e = electron.momentum().E(); + lhe.m = electron.momentum().M(); + lhe.ctau = 0.; + lhe.spin = 0.; } - -void LHEWriter::WritePhoton(const RecPhotonFormat& photon, LHEParticleFormat& lhe, MAint32& mother) +void LHEWriter::WritePhoton(const RecPhotonFormat &photon, LHEParticleFormat &lhe, MAint32 &mother) { - lhe.id = 22; - lhe.status = 1; - lhe.mother1 = mother; - lhe.mother2 = mother; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = photon.momentum().Px(); - lhe.py = photon.momentum().Py(); - lhe.pz = photon.momentum().Pz(); - lhe.e = photon.momentum().E(); - lhe.m = photon.momentum().M(); - lhe.ctau = 0.; - lhe.spin = 0.; + lhe.id = 22; + lhe.status = 1; + lhe.mother1 = mother; + lhe.mother2 = mother; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = photon.momentum().Px(); + lhe.py = photon.momentum().Py(); + lhe.pz = photon.momentum().Pz(); + lhe.e = photon.momentum().E(); + lhe.m = photon.momentum().M(); + lhe.ctau = 0.; + lhe.spin = 0.; } - -void LHEWriter::WriteTau(const RecTauFormat& tau, LHEParticleFormat& lhe, MAint32& mother) +void LHEWriter::WriteTau(const RecTauFormat &tau, LHEParticleFormat &lhe, MAint32 &mother) { - if (tau.charge()>0) lhe.id = -15; else lhe.id = +15; - lhe.status = 1; - lhe.mother1 = mother; - lhe.mother2 = mother; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = tau.momentum().Px(); - lhe.py = tau.momentum().Py(); - lhe.pz = tau.momentum().Pz(); - lhe.e = tau.momentum().E(); - lhe.m = tau.momentum().M(); - lhe.ctau = 0.; - lhe.spin = 0.; + if (tau.charge() > 0) + lhe.id = -15; + else + lhe.id = +15; + lhe.status = 1; + lhe.mother1 = mother; + lhe.mother2 = mother; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = tau.momentum().Px(); + lhe.py = tau.momentum().Py(); + lhe.pz = tau.momentum().Pz(); + lhe.e = tau.momentum().E(); + lhe.m = tau.momentum().M(); + lhe.ctau = 0.; + lhe.spin = 0.; } - -void LHEWriter::WriteMET(const ParticleBaseFormat& met, LHEParticleFormat& lhe) +void LHEWriter::WriteMET(const ParticleBaseFormat &met, LHEParticleFormat &lhe) { - lhe.id = 12; - lhe.status = 1; - lhe.mother1 = 0; - lhe.mother2 = 0; - lhe.color1 = 0; - lhe.color2 = 0; - lhe.px = met.px(); - lhe.py = met.py(); - lhe.pz = 0.; - lhe.e = met.pt(); - lhe.m = 0.; - lhe.ctau = 0.; - lhe.spin = 0.; + lhe.id = 12; + lhe.status = 1; + lhe.mother1 = 0; + lhe.mother2 = 0; + lhe.color1 = 0; + lhe.color2 = 0; + lhe.px = met.px(); + lhe.py = met.py(); + lhe.pz = 0.; + lhe.e = met.pt(); + lhe.m = 0.; + lhe.ctau = 0.; + lhe.spin = 0.; } diff --git a/tools/SampleAnalyzer/Process/Writer/SAFWriter.cpp b/tools/SampleAnalyzer/Process/Writer/SAFWriter.cpp index a3166892..8cab04ee 100644 --- a/tools/SampleAnalyzer/Process/Writer/SAFWriter.cpp +++ b/tools/SampleAnalyzer/Process/Writer/SAFWriter.cpp @@ -1,27 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleHeader headers #include "SampleAnalyzer/Process/Writer/SAFWriter.h" @@ -32,192 +31,200 @@ using namespace MA5; // ----------------------------------------------------------------------------- MAbool SAFWriter::WriteHeader() { - // Header - *output_ << "" << std::endl; - *output_ << "" << std::endl; - *output_ << std::endl; - return true; + // Header + *output_ << "" << std::endl; + *output_ << "" << std::endl; + *output_ << std::endl; + return true; } -MAbool SAFWriter::WriteHeader(const SampleFormat& mySample) +MAbool SAFWriter::WriteHeader(const SampleFormat &mySample) { - // Header - *output_ << "" << std::endl; - *output_ << "" << std::endl; - *output_ << std::endl; - - // SampleGlobalInfo - *output_ << "" << std::endl; - - // title line - output_->width(15); - *output_ << std::left << "# xsection "; - output_->width(15); - *output_ << std::left << "xsection_error "; - output_->width(15); - *output_ << std::left << "nevents "; - output_->width(15); - *output_ << std::left << "sum_weight+ "; - output_->width(15); - *output_ << std::left << "sum_weight- "; - *output_ << std::endl; - - // data - if (mySample.mc()!=0) - { - output_->width(15); - *output_ << std::left << std::scientific - << mySample.mc()->xsection(); - output_->width(15); - *output_ << std::left << std::scientific - << mySample.mc()->xsection_error(); - output_->width(15); - *output_ << std::left << std::scientific - << mySample.nevents(); - output_->width(15); - *output_ << std::left << std::scientific - << mySample.mc()->sumweight_positive(); - output_->width(15); - *output_ << std::left << std::scientific - << mySample.mc()->sumweight_negative(); + // Header + *output_ << "" << std::endl; + *output_ << "" << std::endl; *output_ << std::endl; - } - else - { + + // SampleGlobalInfo + *output_ << "" << std::endl; + + // title line output_->width(15); - *output_ << std::left << std::scientific - << 0; + *output_ << std::left << "# xsection "; output_->width(15); - *output_ << std::left << std::scientific - << 0; + *output_ << std::left << "xsection_error "; output_->width(15); - *output_ << std::left << std::scientific - << mySample.nevents(); + *output_ << std::left << "nevents "; output_->width(15); - *output_ << std::left << std::scientific - << 0; + *output_ << std::left << "sum_weight+ "; output_->width(15); - *output_ << std::left << std::scientific - << 0; + *output_ << std::left << "sum_weight- "; *output_ << std::endl; - } - *output_ << "" << std::endl; - *output_ << std::endl; - return true; -} + // data + if (mySample.mc() != 0) + { + output_->width(15); + *output_ << std::left << std::scientific + << mySample.mc()->xsection(); + output_->width(15); + *output_ << std::left << std::scientific + << mySample.mc()->xsection_error(); + output_->width(15); + *output_ << std::left << std::scientific + << mySample.nevents(); + output_->width(15); + *output_ << std::left << std::scientific + << mySample.mc()->sumweight_positive(); + output_->width(15); + *output_ << std::left << std::scientific + << mySample.mc()->sumweight_negative(); + *output_ << std::endl; + *output_ << ""; + for (auto &name_map : mySample.mc()->WeightNames()) + { + *output_ << std::endl; + output_->width(15); + *output_ << name_map.first; + output_->width(15); + *output_ << name_map.second; + } + *output_ << std::endl; + *output_ << "" << std::endl; + } + else + { + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << mySample.nevents(); + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << 0; + *output_ << std::endl; + } + *output_ << "" << std::endl; + *output_ << std::endl; + return true; +} // ----------------------------------------------------------------------------- // WriteFiles // ----------------------------------------------------------------------------- -MAbool SAFWriter::WriteFiles(const std::vector& mySamples) +MAbool SAFWriter::WriteFiles(const std::vector &mySamples) { - // FileInfo - *output_ << "" << std::endl; - for (MAuint32 i=0;iwidth(40); - *output_ << std::left << "\""+mySamples[i].name()+"\""; - if (i<2 || i>=(mySamples.size()-2)) - *output_ << " # file " << i+1 << " / " << mySamples.size(); - *output_ << std::endl; - } - *output_ << "" << std::endl; - *output_ << std::endl; - - // SampleDetailedInfo - *output_ << "" << std::endl; - - // title line - output_->width(15); - *output_ << std::left << "# xsection "; - output_->width(15); - *output_ << std::left << "xsection_error "; - output_->width(15); - *output_ << std::left << "nevents "; - output_->width(15); - *output_ << std::left << "sum_weight+ "; - output_->width(15); - *output_ << std::left << "sum_weight- "; - *output_ << std::endl; - - // data - for (MAuint32 i=0;i" << std::endl; + for (MAuint32 i = 0; i < mySamples.size(); i++) { - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].mc()->xsection(); - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].mc()->xsection_error(); - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].nevents(); - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].mc()->sumweight_positive(); - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].mc()->sumweight_negative(); + output_->width(40); + *output_ << std::left << "\"" + mySamples[i].name() + "\""; + if (i < 2 || i >= (mySamples.size() - 2)) + *output_ << " # file " << i + 1 << " / " << mySamples.size(); + *output_ << std::endl; } - else - { - output_->width(15); - *output_ << std::left << std::scientific - << 0; - output_->width(15); - *output_ << std::left << std::scientific - << 0; - output_->width(15); - *output_ << std::left << std::scientific - << mySamples[i].nevents(); - output_->width(15); - *output_ << std::left << std::scientific - << 0; - output_->width(15); - *output_ << std::left << std::scientific - << 0; - } - if (i<2 || i>=(mySamples.size()-2)) - *output_ << " # file " << i+1 << " / " << mySamples.size(); + *output_ << "" << std::endl; *output_ << std::endl; - } - *output_ << "" << std::endl; - *output_ << std::endl; + // SampleDetailedInfo + *output_ << "" << std::endl; - return true; -} + // title line + output_->width(15); + *output_ << std::left << "# xsection "; + output_->width(15); + *output_ << std::left << "xsection_error "; + output_->width(15); + *output_ << std::left << "nevents "; + output_->width(15); + *output_ << std::left << "sum_weight+ "; + output_->width(15); + *output_ << std::left << "sum_weight- "; + *output_ << std::endl; + + // data + for (MAuint32 i = 0; i < mySamples.size(); i++) + { + if (mySamples[i].mc() != 0) + { + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].mc()->xsection(); + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].mc()->xsection_error(); + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].nevents(); + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].mc()->sumweight_positive(); + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].mc()->sumweight_negative(); + } + else + { + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << mySamples[i].nevents(); + output_->width(15); + *output_ << std::left << std::scientific + << 0; + output_->width(15); + *output_ << std::left << std::scientific + << 0; + } + if (i < 2 || i >= (mySamples.size() - 2)) + *output_ << " # file " << i + 1 << " / " << mySamples.size(); + *output_ << std::endl; + } + *output_ << "" << std::endl; + *output_ << std::endl; + return true; +} // ----------------------------------------------------------------------------- // WriteEvent // ----------------------------------------------------------------------------- -MAbool SAFWriter::WriteEvent(const EventFormat& myEvent, - const SampleFormat& mySample) +MAbool SAFWriter::WriteEvent(const EventFormat &myEvent, + const SampleFormat &mySample) { - if (myEvent.mc()==0 && mySample.mc()==0) return true; - return true; + if (myEvent.mc() == 0 && mySample.mc() == 0) + return true; + return true; } - // ----------------------------------------------------------------------------- // WriteFoot // ----------------------------------------------------------------------------- -MAbool SAFWriter::WriteFoot(const SampleFormat& mySample) +MAbool SAFWriter::WriteFoot(const SampleFormat &mySample) { - *output_ << "" << std::endl; - *output_ << "" << std::endl; - return true; + *output_ << "" << std::endl; + *output_ << "" << std::endl; + return true; } MAbool SAFWriter::WriteFoot() { - *output_ << "" << std::endl; - *output_ << "" << std::endl; - return true; + *output_ << "" << std::endl; + *output_ << "" << std::endl; + return true; } diff --git a/tools/SampleAnalyzer/Process/Writer/SAFWriter.h b/tools/SampleAnalyzer/Process/Writer/SAFWriter.h index 3d29e5f7..fe294023 100644 --- a/tools/SampleAnalyzer/Process/Writer/SAFWriter.h +++ b/tools/SampleAnalyzer/Process/Writer/SAFWriter.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef WRITER_SAF_h #define WRITER_SAF_h - // STL headers #include #include @@ -34,52 +32,44 @@ // SampleAnalyzer headers #include "SampleAnalyzer/Process/Writer/WriterTextBase.h" - namespace MA5 { -class SAFWriter : public WriterTextBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected: - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public: - - /// Constructor without argument - SAFWriter() - { } - - /// Destructor - virtual ~SAFWriter() - { } - - /// Read the sample (virtual pure) - virtual MAbool WriteHeader(const SampleFormat& mySample); - virtual MAbool WriteHeader(); - - /// Read the sample (virtual pure) - MAbool WriteFiles(const std::vector& mySample); - - /// Read the event (virtual pure) - virtual MAbool WriteEvent(const EventFormat& myEvent, - const SampleFormat& mySample); - - /// Finalize the event (virtual pure) - virtual MAbool WriteFoot(const SampleFormat& mySample); - virtual MAbool WriteFoot(); - - /// Getting stream - std::ostream* GetStream() - { return output_; } - -}; + class SAFWriter : public WriterTextBase + { + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor without argument + SAFWriter() {} + + /// Destructor + virtual ~SAFWriter() {} + + /// Read the sample (virtual pure) + virtual MAbool WriteHeader(const SampleFormat &mySample); + virtual MAbool WriteHeader(); + + /// Read the sample (virtual pure) + MAbool WriteFiles(const std::vector &mySample); + + /// Read the event (virtual pure) + virtual MAbool WriteEvent(const EventFormat &myEvent, + const SampleFormat &mySample); + + /// Finalize the event (virtual pure) + virtual MAbool WriteFoot(const SampleFormat &mySample); + virtual MAbool WriteFoot(); + + /// Getting stream + std::ostream *GetStream() { return output_; } + }; } diff --git a/tools/SampleAnalyzer/Test/Process/Test.cpp b/tools/SampleAnalyzer/Test/Process/Test.cpp index d774f388..4239b238 100644 --- a/tools/SampleAnalyzer/Test/Process/Test.cpp +++ b/tools/SampleAnalyzer/Test/Process/Test.cpp @@ -1,70 +1,129 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2025 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include // SampleHeader header #include "SampleAnalyzer/Process/Core/SampleAnalyzer.h" +#include "SampleAnalyzer/Process/JetClustering/JetClusterer.h" + using namespace MA5; +// simple test helper +static int g_failures = 0; +static void CHECK(const char *name, bool cond) +{ + if (cond) + { + std::cout << "[ OK ] " << name << std::endl; + } + else + { + std::cout << "[FAILED] " << name << std::endl; + ++g_failures; + } +} // ----------------------------------------------------------------------- // main program // ----------------------------------------------------------------------- MAint32 main(MAint32 argc, MAchar *argv[]) { - std::cout << "BEGIN-SAMPLEANALYZER-TEST" << std::endl; - std::cout << std::endl; - - // Creating a manager - SampleAnalyzer manager; - if (!manager.Initialize(argc,argv,"pdg.ma5")) return 1; - std::cout << std::endl; - - // List of available analyzers - INFO << "List of available analyzers:" << endmsg; - manager.AnalyzerList().Print(); - INFO << endmsg; - - // List of available readers - INFO << "List of available readers:" << endmsg; - manager.ReaderList().Print(); - INFO << endmsg; - - // List of available writers - INFO << "List of available writers:" << endmsg; - manager.WriterList().Print(); - INFO << endmsg; - - // List of available JetClusterer - INFO << "List of available JetClusterer:" << endmsg; - manager.JetClustererList().Print(); - INFO << endmsg; - - // List of available detector simulation - INFO << "List of available DetectorSimList:" << endmsg; - manager.DetectorSimList().Print(); - INFO << endmsg; - - std::cout << "END-SAMPLEANALYZER-TEST" << std::endl; - return 0; -} + std::cout << "BEGIN-SAMPLEANALYZER-TEST" << std::endl; + std::cout << std::endl; + + // Creating a manager + SampleAnalyzer manager; + if (!manager.Initialize(argc, argv, "pdg.ma5")) + return 1; + std::cout << std::endl; + + // List of available analyzers + INFO << "List of available analyzers:" << endmsg; + manager.AnalyzerList().Print(); + INFO << endmsg; + + // List of available readers + INFO << "List of available readers:" << endmsg; + manager.ReaderList().Print(); + INFO << endmsg; + + // List of available writers + INFO << "List of available writers:" << endmsg; + manager.WriterList().Print(); + INFO << endmsg; + + // List of available JetClusterer + INFO << "List of available JetClusterer:" << endmsg; + manager.JetClustererList().Print(); + INFO << endmsg; + + // List of available detector simulation + INFO << "List of available DetectorSimList:" << endmsg; + manager.DetectorSimList().Print(); + INFO << endmsg; + + std::cout << std::endl + << "BEGIN-PROCESS-SMOKE-TESTS" << std::endl; + + // JetClusterer smoke tests (safe, do not require full runtime) + { + JetClusterer jc(nullptr); + // GetName should handle null algo pointer safely + std::string name = jc.GetName(); + CHECK("JetClusterer::GetName() with null algo returns non-empty", !name.empty()); + // Initialize should detect missing algo and return false + std::map opts; + bool init_ok = jc.Initialize(opts); + CHECK("JetClusterer::Initialize() with null algo returns false", init_ok == false); + } + + // Basic SampleAnalyzer lists existence checks + { + bool ok = true; + // Ensure lists can be queried and have Print() callable (no exception) + try + { + manager.AnalyzerList().Print(); + manager.ReaderList().Print(); + manager.WriterList().Print(); + manager.JetClustererList().Print(); + manager.DetectorSimList().Print(); + } + catch (...) + { + ok = false; + } + CHECK("SampleAnalyzer lists printable without throwing", ok); + } + + std::cout << "END-PROCESS-SMOKE-TESTS" << std::endl + << std::endl; + + std::cout << "END-SAMPLEANALYZER-TEST" << std::endl; + + return (g_failures == 0) ? 0 : 1; +} \ No newline at end of file