Source code for pyfc.config

"""
Configuration and Argument Parsing Module

This file defines the configuration management system for the PyFC framework. 
It establishes a hierarchical parameter loading mechanism (Hardcoded Defaults -> 
JSON Configuration File -> Command Line Arguments) to control the execution 
of the Feldman-Cousins confidence interval construction.

While this file does not execute the mathematical routines, it defines the 
statistical, algorithmic, and computational parameters that govern the 
underlying profile likelihood ratio tests and Monte Carlo toy generation.

Created: v0.1.0 (July 24, 2026)
Author: Mauricio Bustamante (mbustamante@gmail.com)

This file was released as part of the PyFC code, stored at 
https://github.com/mbustama/FeldmanCousins, which exists under a GNU GPL v3 License.
"""

import argparse
import json
import os
import sys


[docs] def generate_sample_config(filename="../config/example_fc_config.json"): """ Generates a sample JSON configuration file containing default execution parameters. Statistical & Algorithmic Context: The default configuration initializes a standard binned likelihood analysis calculating confidence intervals at 68% and 90% Confidence Levels (CL). It enables the finite Monte Carlo correction (assuming template statistical uncertainties require a Poisson-Gamma mixture likelihood) and utilizes an adaptive Monte Carlo toy generation strategy to optimize computational resources when empirical p-values are far from the critical threshold alpha. Parameters: ----------- filename : str, optional The destination file path where the JSON configuration will be written. Defaults to "../config/example_fc_config.json". Returns: -------- None The function writes a file to disk and prints a confirmation message. """ default_config = { "likelihood_type": "binned", "cl": [0.68, 0.90], "n_toys": 500, "strategy": "scipy", "num_cores": 8, "verbose": 1, "adaptive_toys": True, "toy_batch_size": 200, "sparsify_grid": False, "warm_start": True, "output_file": "fc_results", "save_log": True, "save_directory": "output/example_fc_output", "use_finite_mc_correction_binned": True, "compute_1D_intervals": True, "compute_2D_intervals": True, "param_names": ["param1", "param2", "param3"], "smooth_1d": True, "smooth_2d": True, "scipy_method": None, "n_restarts": 1, "neighbor_seeding": True } with open(filename, 'w') as f: json.dump(default_config, f, indent=4) print(f"Sample configuration written to {filename}")
[docs] def parse_arguments(): """ Parses execution parameters using a strict hierarchy: Defaults -> JSON Config File -> CLI Arguments. Statistical Theory & Configuration Parameters: - likelihood_type: Defines the probability density function (PDF) form. 'binned' uses Poisson/Negative Binomial counting statistics; 'unbinned' uses continuous event likelihoods. - cl: The target Confidence Level(s) (1 - alpha), defining the required frequentist coverage probability (e.g., 0.90 for 90% coverage). - n_toys: The baseline number of parametric bootstrap pseudo-experiments used to build the empirical Profile Likelihood Ratio (PLR) distribution. - use_finite_mc_correction_binned: If True, convolves the standard Poisson likelihood with a Gamma prior to account for limited statistics in MC templates. - strategy: The optimization algorithm used to minimize the Negative Log-Likelihood (NLL). Options include exhaustive 'grid', gradient-based 'scipy', or nested sampling 'ultranest'. Parameters: ----------- None (Reads directly from command line via sys.argv) Returns: -------- config : dict A dictionary containing the fully resolved configuration parameters necessary to execute the Feldman-Cousins orchestrator. """ parser = argparse.ArgumentParser(description="Feldman-Cousins Confidence Intervals (N Parameter Model)") parser.add_argument('--config_file', type=str, help="Path to JSON config file", default=argparse.SUPPRESS) parser.add_argument('--generate_config', action='store_true', help="Generate a sample JSON config and exit") parser.add_argument('--likelihood_type', type=str, choices=["binned", "unbinned"], default=argparse.SUPPRESS) parser.add_argument('--cl', type=float, nargs='+', help="Confidence level(s) (e.g., 0.90 0.95)", default=argparse.SUPPRESS) parser.add_argument('--n_toys', type=int, default=argparse.SUPPRESS) parser.add_argument('--strategy', type=str, choices=["grid", "scipy", "ultranest", "hybrid"], default=argparse.SUPPRESS) parser.add_argument('--scipy_method', type=str, choices=["L-BFGS-B", "SLSQP", "trust-constr"], help="Override scipy.optimize.minimize's method (default: L-BFGS-B, or SLSQP automatically when constraints are supplied programmatically)", default=argparse.SUPPRESS) parser.add_argument('--num_cores', type=int, default=argparse.SUPPRESS) parser.add_argument('--verbose', type=int, default=argparse.SUPPRESS) parser.add_argument('--adaptive_toys', type=lambda x: str(x).lower() in ['true', '1', 'yes'], default=argparse.SUPPRESS) parser.add_argument('--toy_batch_size', type=int, default=argparse.SUPPRESS) parser.add_argument('--sparsify_grid', type=lambda x: str(x).lower() in ['true', '1', 'yes'], default=argparse.SUPPRESS) parser.add_argument('--warm_start', type=lambda x: str(x).lower() in ['true', '1', 'yes'], default=argparse.SUPPRESS) parser.add_argument('--output_file', type=str, default=argparse.SUPPRESS) parser.add_argument('--save_log', type=lambda x: str(x).lower() in ['true', '1', 'yes'], default=argparse.SUPPRESS) parser.add_argument('--save_directory', type=str, default=argparse.SUPPRESS) parser.add_argument('--use_finite_mc_correction_binned', type=lambda x: str(x).lower() in ['true', '1', 'yes'], default=argparse.SUPPRESS) parser.add_argument('--compute_1D_intervals', type=lambda x: str(x).lower() in ['true', '1', 'yes'], default=argparse.SUPPRESS) parser.add_argument('--compute_2D_intervals', type=lambda x: str(x).lower() in ['true', '1', 'yes'], default=argparse.SUPPRESS) parser.add_argument('--param_names', type=str, nargs='+', default=argparse.SUPPRESS) parser.add_argument('--smooth_1d', type=lambda x: str(x).lower() in ['true', '1', 'yes'], default=argparse.SUPPRESS) parser.add_argument('--smooth_2d', type=lambda x: str(x).lower() in ['true', '1', 'yes'], default=argparse.SUPPRESS) parser.add_argument('--n_restarts', type=int, help="Number of distinct starting points to try per DATA fit (scipy strategy), keeping whichever converges to the lowest NLL", default=argparse.SUPPRESS) parser.add_argument('--neighbor_seeding', type=lambda x: str(x).lower() in ['true', '1', 'yes'], help="Seed each DATA fit (scipy strategy) from an adjacent grid point's profiled parameters instead of always starting from the bounds midpoint", default=argparse.SUPPRESS) args = parser.parse_args() if args.generate_config: generate_sample_config() sys.exit(0) # Base Hardcoded Defaults config = { "likelihood_type": "binned", "cl": [0.68, 0.90], "n_toys": 500, "strategy": "scipy", "num_cores": 8, "verbose": 1, "adaptive_toys": True, "toy_batch_size": 200, "sparsify_grid": False, "warm_start": True, "output_file": "fc_results", "save_log": True, "save_directory": "output/example_fc_output", "use_finite_mc_correction_binned": True, "compute_1D_intervals": True, "compute_2D_intervals": True, "param_names": ["param1", "param2", "param3"], "smooth_1d": True, "smooth_2d": True, "scipy_method": None, "n_restarts": 1, "neighbor_seeding": True } if hasattr(args, 'config_file'): if os.path.exists(args.config_file): with open(args.config_file, 'r') as f: config.update(json.load(f)) else: print(f"Warning: Config file {args.config_file} not found. Proceeding with defaults.") cli_args = vars(args) for key, value in cli_args.items(): if key not in ['config_file', 'generate_config']: config[key] = value return config