Source code for DaVinci.LbExec

###############################################################################
# (c) Copyright 2022-2024 CERN for the benefit of the LHCb Collaboration      #
#                                                                             #
# This software is distributed under the terms of the GNU General Public      #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING".   #
#                                                                             #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization  #
# or submit itself to any jurisdiction.                                       #
###############################################################################
from contextlib import contextmanager
from typing import Optional, Any
from pydantic import root_validator, PrivateAttr  # type: ignore[import]
import logging
from GaudiConf.LbExec import Options as DefaultOptions, TestOptionsBase  # type: ignore[import]
from GaudiConf.LbExec import FileFormats, InputProcessTypes  # type: ignore[import]
from PyConf.application import default_raw_event, configure_input  # type: ignore[import]

from PyConf.reading import tes_root, tes_root_for_tistos, reconstruction as reconstruction_reading  # type: ignore[import]

from PyConf.packing import persistreco_version  # type: ignore[import]

from RecoConf.reconstruction_objects import reconstruction  # type: ignore[import]


[docs] class Options(DefaultOptions): """ A class that holds the user-specified DaVinci options. This class inherits from the default `GaudiConf.LbExec.Options`. This class also configures several PyConf functions, see the list in the `apply_binds` method, where their keyword arguments are globally bound to the user-specified values. This way, users do not have to manually configure these functions themselves. The optional parameters that need to be set are : - input_stream (str): Stream name, internally converted to lowercase. Default is "default". (Note: for `input_process=Hlt2` the stream must be strictly empty. The default value is overwritten in this case.) - lumi (bool): Flag to store luminosity information. Default value is True and if Data the "lumiTree" is written by default. If MC the "lumiTree" is not written, EventAccounting is scheduled instead. - write_fsr (bool): Flag to write the file summary record. Requires also output_file != None. Default is False. - merge_genfsr (bool): Flag to merge the file summary record. Only applies to simulation. Default is False. - metainfo_additional_tags: (list): Additional central tags for `PyConf.filecontent_metadata.metainfo_repos`. Default is []. _input_config is an ugly hack so that the configuration can be retrieved in config.py This is needed due to the way DaVinci configures itself, which is kind of not compatible with the PyConf spirit """
[docs] input_stream: Optional[str] = "default"
[docs] lumi: bool = True
[docs] write_fsr: bool = False
[docs] merge_genfsr: bool = False
[docs] metainfo_additional_tags: Optional[list] = []
[docs] _input_config: Any = PrivateAttr()
@root_validator(pre=False, skip_on_failure=True)
[docs] def _stream_default(cls, values): """ This is a validator that sets the default "stream" value based on "input_process" Args: values (dict): User-specified attributes of the Options object. Returns: dict: Modified attributes of the Options object. """ input_process = values.get("input_process") input_stream = values.get("input_stream") if not input_stream.islower(): logging.getLogger(__name__).warning( f"input_stream is set to '{input_stream}', input_stream should be lower case. It will be made lower case for you in the next step. If you think this is wrong contact DaVinci maintainers." ) values["input_stream"] = input_stream.lower() if ( input_process not in {InputProcessTypes.Spruce, InputProcessTypes.TurboPass} and input_stream != "" ): logging.getLogger(__name__).warning( f"input_stream is set to '{input_stream}', but will be reset to '' because current input_process = {input_process}" ) values["input_stream"] = "" return values
@root_validator(pre=False, skip_on_failure=True)
[docs] def validate_input_output(cls, values): """ Validator for the consistency of the input process and input/output file formats for Sprucing jobs. Args: values (dict): User-specified attributes of the Options object. Returns: dict: Modified attributes of the Options object. """ input_process = values.get("input_process", None) input_type = values.get("input_type", FileFormats.NONE) output_type = values.get("output_type", FileFormats.ROOT) # Jobs on Spruced samples are DST -> DST only if input_process in {InputProcessTypes.TurboPass, InputProcessTypes.Spruce}: if input_type != FileFormats.ROOT: raise ValueError( f"Jobs on Spruced data are DST -> ROOT but input_type={input_type!r} was given." ) if output_type != FileFormats.ROOT: raise ValueError( f"Jobs on Spruced data are DST -> ROOT but output_type={output_type!r} was given." ) return values
@root_validator(pre=False, skip_on_failure=True)
[docs] def validate_fsr_options(cls, values): """ Validator for the consistency of writing FSRs and other settings. Args: values (dict): User-specified attributes of the Options object. Returns: dict: Modified attributes of the Options object. """ write_fsr = values.get("write_fsr", False) merge_genfsr = values.get("merge_genfsr", False) output_file = values.get("output_file", None) simulation = values.get("simulation", False) if write_fsr: if not output_file: # Catch the default None but also "" raise ValueError( "FSRs requested to be written but no output file was provided." ) if merge_genfsr: if not simulation: raise ValueError( "Merging of Generator FSRs is only relevant/valid for simulation." ) if not output_file: # Catch the default None but also "" raise ValueError( "Merging of Generator FSRs requested to be written but no output file was provided." ) return values
@contextmanager
[docs] def apply_binds(self): """ This function configures the following PyConf functions, where their keyword arguments are globally bound to the user-specified values: - default_raw_event - reconstruction - tes_root - tes_root_for_tistos This way users do not have to manually configure these functions themselves. """ default_raw_event.global_bind( raw_event_format=self.input_raw_format, stream=self.input_stream ) if self.input_process in [ InputProcessTypes.Hlt2, InputProcessTypes.Spruce, InputProcessTypes.TurboPass, ]: reconstruction.global_bind(from_file=True, spruce=True) if self.input_process in [ InputProcessTypes.Hlt2, InputProcessTypes.Spruce, InputProcessTypes.TurboPass, InputProcessTypes.Brunel, ]: reconstruction_reading.global_bind(input_process=self.input_process) tes_root.global_bind(input_process=self.input_process) tes_root_for_tistos.global_bind(input_process=self.input_process) persistreco_version.global_bind(version=self.persistreco_version) self._input_config = configure_input(self) with super().apply_binds(): yield
[docs] class TestOptions(Options, TestOptionsBase): """Specialized Options class for Davinci Tests""" pass