diff --git a/quickstats/clis/core.py b/quickstats/clis/core.py index af0e799dc469c47aa2830b9583b1c172d1f1b004..5ff53e5e8361dfcd012e4cccebbde9f72ea0a960 100644 --- a/quickstats/clis/core.py +++ b/quickstats/clis/core.py @@ -275,6 +275,8 @@ def compile_macros(macros): help='Path to the directory containing the source file for the macro.') @click.option('-n', '--name', help='Name of the macro. By default, the name of the input directory is used.') +@click.option('-f', '--force', is_flag=True, + help='Force overwrite existing files.') @click.option('--copy-files/--do-not-copy-files', 'copy_files', default=True, help='Whether to copy files from the input directory (required if not already copied).') @click.option('--add-to-workspace-extension/--do-not-add-to-workspace-extension', 'workspace_extension', @@ -290,6 +292,8 @@ def add_macro(**kwargs): @click.command(name='remove_macro') @click.option('-n', '--name', required=True, help='Name of the macro.') +@click.option('-f', '--force', is_flag=True, + help='Force remove files without notification.') @click.option('--remove-files/--do-not-remove-files', 'remove_files', default=False, show_default=True, help='Whether to remove the macro from the workspace extension list only or also remove the files.') diff --git a/quickstats/components/likelihood.py b/quickstats/components/likelihood.py index dbc29a81585dcfdd88fd162e7ea62e4ad1136405..47e78f80b6abd568dc40c48ebbec8126fe73f31a 100644 --- a/quickstats/components/likelihood.py +++ b/quickstats/components/likelihood.py @@ -162,7 +162,7 @@ class Likelihood(AnalysisObject): fit_result = {} self.stdout.info("INFO: NLL evaluation completed with") if mode in [FitMode.HYBRID, FitMode.UNCOND, FitMode.NOFIT]: - best_fit_str = ", ".join([f"{name}={value:.5f}" for name, value in muhat.items()]) + best_fit_str = ", ".join([f"{name} = {value:.5f}" for name, value in muhat.items()]) self.stdout.info("best fit : ".rjust(15) + f"{best_fit_str}") self.stdout.info("uncond NLL = ".rjust(15) + f"{nll_uncond:.5f}") fit_result['uncond_fit'] = { diff --git a/quickstats/core/methods.py b/quickstats/core/methods.py index 6b30e678499b41fd21f2e109dff3aaab5c66bd5d..d1c1114c4fb412a109c5ffe1bb50a0615de7e365 100644 --- a/quickstats/core/methods.py +++ b/quickstats/core/methods.py @@ -75,7 +75,8 @@ def get_workspace_extension_config(): extension_config = json.load(file) return extension_config -def add_macro(path:str, name:Optional[str]=None, copy_files:bool=True, workspace_extension:bool=True): +def add_macro(path:str, name:Optional[str]=None, copy_files:bool=True, + workspace_extension:bool=True, force:bool=False): if not os.path.isdir(path): raise ValueError("macro path must be a directory") if name is None: @@ -87,8 +88,7 @@ def add_macro(path:str, name:Optional[str]=None, copy_files:bool=True, workspace if copy_files: dest_path = os.path.join(macro_path, name) if os.path.exists(dest_path): - answer = input(f'WARNING: The macro already exists in {dest_path}, overwrite? [Y/N]') - if answer == "Y": + if force or input(f'WARNING: The macro already exists in {dest_path}, overwrite? [Y/N]') == "Y": shutil.rmtree(dest_path) shutil.copytree(path, dest_path) quickstats._PRINT_.info(f'INFO: Overwritten contents for the macro "{name}" from {path} to {dest_path}.') @@ -107,26 +107,25 @@ def add_macro(path:str, name:Optional[str]=None, copy_files:bool=True, workspace json.dump(extension_config, file, indent=2) quickstats._PRINT_.info(f'INFO: The macro "{name}" has been added to the workspace extension list.') -def remove_macro(name:str, remove_files:bool=True): +def remove_macro(name:str, remove_files:bool=True, force:bool=False): resource_path = quickstats.resource_path extension_config_file = os.path.join(resource_path, "workspace_extensions.json") extension_config = get_workspace_extension_config() if (name not in extension_config): - quickstats.__PRINT__.info(f'WARNING: Extension "{name}" not found in the workspace extension list. Skipped.') + quickstats._PRINT_.info(f'WARNING: Extension "{name}" not found in the workspace extension list. Skipped.') else: extension_config.remove(name) with open(extension_config_file, "w") as file: json.dump(extension_config, file, indent=2) - quickstats.__PRINT__.info(f'INFO: The extension "{name}" has been removed from the workspace extension list.') + quickstats._PRINT_.info(f'INFO: The extension "{name}" has been removed from the workspace extension list.') if remove_files: macro_path = quickstats.macro_path extension_path = os.path.abspath(os.path.join(macro_path, name)) - answer = input(f'WARNING: Attempting to remove files from {extension_path}, confirm? [Y/N]') - if answer == "Y": - quickstats._PRINT_.info(f'INFO: Removal confirmed.') + if force or input(f'WARNING: Attempting to remove files from {extension_path}, confirm? [Y/N]') == "Y": + quickstats._PRINT_.info(f'INFO: Files for the macro "{name}" has been removed from {extension_path}.') shutil.rmtree(extension_path) else: - quickstats._PRINT_.info(f'INFO: Removal cancelled.') + quickstats._PRINT_.info(f'INFO: Macro files removal cancelled.') def load_corelib(): if not quickstats.corelib_loaded: diff --git a/quickstats/utils/roofit_utils.py b/quickstats/utils/roofit_utils.py index d70878012f4c1778d7726516d3efce40ade6a3f4..e86d4f5a3a15223aa72929492ef7c0a54bd3b742 100644 --- a/quickstats/utils/roofit_utils.py +++ b/quickstats/utils/roofit_utils.py @@ -321,5 +321,21 @@ def translate_formula(name:str, formula:str): expr = formula for i, variable in enumerate(variables): expr = re.sub(r"\b" + variable + r"\b", f"@{i}", expr) - translated_formula = f"expr::{name}('{expr}', {','.join(variables)})" - return translated_formula, variables \ No newline at end of file + translated_formula = f"expr::{name}('{expr}', {', '.join(variables)})" + return translated_formula, variables + +def recover_formula(formula:str): + expr_regex = re.compile(r"'(.*?)'") + expressions = expr_regex.findall(formula) + if len(expressions) != 1: + raise RuntimeError("invalid RooFit factory expression") + expression = expressions[0] + variables_regex = re.compile(r"\('.*?',(.*)\)") + variables = variables_regex.findall(formula) + if len(variables) != 1: + raise RuntimeError("invalid RooFit factory expression") + variables = [i.strip() for i in variables[0].split(",") if i.strip()] + recovered_formula = expression + for i, variable in enumerate(variables): + recovered_formula = re.sub(f"@{i}(?![0-9])", variable, recovered_formula) + return recovered_formula \ No newline at end of file diff --git a/setup.sh b/setup.sh index 1469d468d934cdcdce6123cfabcd8c1e4537aff6..e6afb916006458922a82f930ed0430bff344ecd8 100644 --- a/setup.sh +++ b/setup.sh @@ -37,4 +37,23 @@ elif [[ "$EnvironmentName" = "conda" ]]; then echo Entering default conda environment export PATH=/afs/cern.ch/work/c/chlcheng/local/miniconda/envs/root-latest/bin:$PATH -fi \ No newline at end of file +elif [[ "$EnvironmentName" = "nightly" ]]; +then +setupATLAS +source /cvmfs/sft.cern.ch/lcg/views/dev3/latest/x86_64-centos7-gcc11-opt/setup.sh + export PATH=${DIR}/bin:${PATH} + export PYTHONPATH=${DIR}:${PYTHONPATH} +elif [[ "$EnvironmentName" = "102b" ]]; +then +setupATLAS +source /cvmfs/sft.cern.ch/lcg/views/LCG_102b/x86_64-centos7-gcc11-opt/setup.sh + export PATH=${DIR}/bin:${PATH} + export PYTHONPATH=${DIR}:${PYTHONPATH} +elif [[ "$EnvironmentName" = "102a" ]]; +then +setupATLAS +source /cvmfs/sft.cern.ch/lcg/views/LCG_102a/x86_64-centos7-gcc11-opt/setup.sh + export PATH=${DIR}/bin:${PATH} + export PYTHONPATH=${DIR}:${PYTHONPATH} +fi +