Module flarefly.pdf_builder
PDFBuilder class to create signal and background PDFs using zfit.
Classes
class PDFBuilder-
Expand source code
class PDFBuilder: """Class to build signal and background PDFs using zfit.""" def __init__(self): self.pdg_api = pdg.connect() @staticmethod def build_signal_pdf( pdf: F2PDFBase, obs: zfit.Space, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a signal PDF with configurable parameters. Args: pdf: The PDF to build obs: The observable space for the PDF name: Base name for parameters ipdf: Index of the PDF """ if pdf.is_kde(): pdf = PDFBuilder.build_signal_kde( pdf, name, ipdf ) return if pdf.is_hist(): pdf = PDFBuilder.build_signal_hist( pdf, obs, name, ipdf ) return config = get_signal_pdf_config(pdf.kind) # Update the input dictionaries with default values PDFBuilder._update_with_defaults(config, pdf) parameters = {} for par_name in config['parameters'].keys(): param_name = f'{name}_{par_name}_signal{ipdf}' parameters[param_name] = zfit.Parameter( name=param_name, value=pdf.get_init_par(par_name), lower=pdf.get_limits_par(par_name)[0], upper=pdf.get_limits_par(par_name)[1], floating=not pdf.get_fix_par(par_name) ) pdf_args = {'obs': obs} for arg_name in config['pdf_args']: if 'args_mapping' in config: # flarefly -> zfit argument name mapping param_key = f"{name}_{config['args_mapping'][arg_name]}_signal{ipdf}" else: param_key = f'{name}_{arg_name}_signal{ipdf}' pdf_args[arg_name] = parameters[param_key] pdf.pdf = config['pdf_class'](**pdf_args) pdf.parameters = parameters if pdf.at_threshold: # pion mass as default pdf.set_default_par( 'massthr', init=pdf.pdg_api.get_particle_by_mcid(211).mass, fix=True, limits=[None, None] ) pdf.set_default_par('powerthr', init=1., fix=False, limits=[None, None]) pdf.parameters[f'{name}_massthr_signal{ipdf}'] = zfit.Parameter( f'{name}_massthr_signal{ipdf}', pdf.get_init_par('massthr'), pdf.get_limits_par('massthr')[0], pdf.get_limits_par('massthr')[1], floating=not pdf.get_fix_par('massthr')) pdf.parameters[f'{name}_powerthr_signal{ipdf}'] = zfit.Parameter( f'{name}_powerthr_signal{ipdf}', pdf.get_init_par('powerthr'), pdf.get_limits_par('powerthr')[0], pdf.get_limits_par('powerthr')[1], floating=not pdf.get_fix_par('powerthr')) signalthr_pdf = cpdf.Pow( obs=obs, mass=pdf.parameters[f'{name}_massthr_signal{ipdf}'], power=pdf.parameters[f'{name}_powerthr_signal{ipdf}'] ) pdf.pdf = zfit.pdf.ProductPDF([pdf.pdf, signalthr_pdf], obs=obs) @staticmethod def build_signal_kde( pdf: F2PDFBase, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a signal KDE PDF. Args: pdf: The PDF to build name: Base name for the PDF ipdf: Index of the PDF """ if not pdf.kde_sample: Logger(f'Missing datasample for Kernel Density Estimation of signal {ipdf}!', 'FATAL') kde_options = pdf.kde_option or {} pdf.pdf = get_kde_pdf(pdf.kind)( data=pdf.kde_sample.get_data(), obs=pdf.kde_sample.get_obs(), name=f'{name}_kde_signal{ipdf}', **kde_options ) @staticmethod def build_signal_hist( pdf: F2PDFBase, obs: zfit.Space, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a signal PDF from a histogram template. Args: pdf: The PDF to build obs: The observable space for the PDF name: Base name for the PDF ipdf: Index of the PDF Returns: The constructed PDF """ if not pdf.hist_sample: Logger(f'Missing datasample for histogram template of signal {ipdf}!', 'FATAL') pdf.pdf = zfit.pdf.SplinePDF( zfit.pdf.HistogramPDF( pdf.hist_sample.get_binned_data(), name=f'{name}_hist_signal{ipdf}' ), order=3, obs=obs ) @staticmethod def build_bkg_pdf( pdf: F2PDFBase, obs: zfit.Space, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a background PDF with configurable parameters. Args: pdf: The PDF to build obs: The observable space for the PDF name: Base name for parameters ipdf: Index of the PDF """ if pdf.is_kde(): pdf = PDFBuilder.build_bkg_kde( pdf, name, ipdf ) return if pdf.is_hist(): pdf = PDFBuilder.build_bkg_hist( pdf, obs, name, ipdf ) return if pdf.kind == PDFType.CHEBPOL: # Handle Chebyshev polynomials specially PDFBuilder._build_chebyshev_pdf( pdf, obs, name, ipdf ) return config = get_bkg_pdf_config(pdf.kind) # Update the input dictionaries with default values PDFBuilder._update_with_defaults(config, pdf) parameters = {} for par_name in config['parameters'].keys(): param_name = f'{name}_{par_name}_bkg{ipdf}' parameters[param_name] = zfit.Parameter( name=param_name, value=pdf.get_init_par(par_name), lower=pdf.get_limits_par(par_name)[0], upper=pdf.get_limits_par(par_name)[1], floating=not pdf.get_fix_par(par_name) ) pdf_args = {'obs': obs} for arg_name in config['pdf_args']: if 'args_mapping' in config: # flarefly -> zfit argument name mapping param_key = f"{name}_{config['args_mapping'][arg_name]}_bkg{ipdf}" else: param_key = f'{name}_{arg_name}_bkg{ipdf}' pdf_args[arg_name] = parameters[param_key] pdf.pdf = config['pdf_class'](**pdf_args) pdf.parameters = parameters @staticmethod def _build_chebyshev_pdf( pdf: F2PDFBase, obs: zfit.Space, name: str, ipdf: int, ) -> Tuple[zfit.pdf.BasePDF, Dict[str, zfit.Parameter]]: """Build a Chebyshev polynomial background PDF.""" # Create parameters for each coefficient parameters = {} for deg in range(pdf.kind.order + 1): par_name = f'c{deg}' pdf.set_default_init_par(par_name, 0.1) pdf.set_default_limits_par(par_name, [None, None]) pdf.set_default_fix_par(par_name, False) param_name = f'{name}_{par_name}_bkg{ipdf}' parameters[param_name] = zfit.Parameter( name=param_name, value=pdf.get_init_par(par_name), lower=pdf.get_limits_par(par_name)[0], upper=pdf.get_limits_par(par_name)[1], floating=not pdf.get_fix_par(par_name) ) # Prepare Chebyshev arguments coeff0 = parameters[f'{name}_c0_bkg{ipdf}'] bkg_coeffs = [parameters[f'{name}_c{deg}_bkg{ipdf}'] for deg in range(1, pdf.kind.order + 1)] pdf.pdf = zfit.pdf.Chebyshev(obs=obs, coeff0=coeff0, coeffs=bkg_coeffs) pdf.parameters = parameters @staticmethod def build_bkg_kde( pdf: F2PDFBase, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a background KDE PDF. Args: pdf_kind: Kind of KDE ('kde_exact', 'kde_grid', 'kde_fft', 'kde_isj') kde_sample: The sample data for KDE estimation name: Base name for the PDF ipdf: Index of the PDF kde_options: Additional options for the KDE Returns: The constructed KDE PDF """ if not pdf.kde_sample: Logger(f'Missing datasample for Kernel Density Estimation of background {ipdf}!', 'FATAL') kde_options = pdf.kde_option or {} pdf.pdf = get_kde_pdf(pdf.kind)( data=pdf.kde_sample.get_data(), obs=pdf.kde_sample.get_obs(), name=f'{name}_kde_bkg{ipdf}', **kde_options ) @staticmethod def build_bkg_hist( pdf: F2PDFBase, obs: zfit.Space, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a bkg PDF from a histogram template. Args: pdf: The PDF to build obs: The observable space for the PDF name: Base name for the PDF ipdf: Index of the PDF """ if not pdf.hist_sample: Logger(f'Missing datasample for histogram template of background {ipdf}!', 'FATAL') pdf.pdf = zfit.pdf.SplinePDF( zfit.pdf.HistogramPDF( pdf.hist_sample.get_binned_data(), name=f'{name}_hist_bkg{ipdf}' ), order=3, obs=obs ) @staticmethod def _update_with_defaults( config: Dict[str, Any], pdf: F2PDFBase ) -> None: """Update the parameter dictionaries with default values from config.""" for par_name, par_config in config['parameters'].items(): pdf.set_default_init_par(par_name, par_config['init']) pdf.set_default_limits_par(par_name, par_config['limits']) pdf.set_default_fix_par(par_name, par_config['fix'])Class to build signal and background PDFs using zfit.
Static methods
def build_bkg_hist(pdf: F2PDFBase,
obs: zfit.core.space.Space,
name: str,
ipdf: int) ‑> zfit.core.basepdf.BasePDF-
Expand source code
@staticmethod def build_bkg_hist( pdf: F2PDFBase, obs: zfit.Space, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a bkg PDF from a histogram template. Args: pdf: The PDF to build obs: The observable space for the PDF name: Base name for the PDF ipdf: Index of the PDF """ if not pdf.hist_sample: Logger(f'Missing datasample for histogram template of background {ipdf}!', 'FATAL') pdf.pdf = zfit.pdf.SplinePDF( zfit.pdf.HistogramPDF( pdf.hist_sample.get_binned_data(), name=f'{name}_hist_bkg{ipdf}' ), order=3, obs=obs )Build a bkg PDF from a histogram template.
Args
pdf- The PDF to build
obs- The observable space for the PDF
name- Base name for the PDF
ipdf- Index of the PDF
def build_bkg_kde(pdf: F2PDFBase,
name: str,
ipdf: int) ‑> zfit.core.basepdf.BasePDF-
Expand source code
@staticmethod def build_bkg_kde( pdf: F2PDFBase, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a background KDE PDF. Args: pdf_kind: Kind of KDE ('kde_exact', 'kde_grid', 'kde_fft', 'kde_isj') kde_sample: The sample data for KDE estimation name: Base name for the PDF ipdf: Index of the PDF kde_options: Additional options for the KDE Returns: The constructed KDE PDF """ if not pdf.kde_sample: Logger(f'Missing datasample for Kernel Density Estimation of background {ipdf}!', 'FATAL') kde_options = pdf.kde_option or {} pdf.pdf = get_kde_pdf(pdf.kind)( data=pdf.kde_sample.get_data(), obs=pdf.kde_sample.get_obs(), name=f'{name}_kde_bkg{ipdf}', **kde_options )Build a background KDE PDF.
Args
pdf_kind- Kind of KDE ('kde_exact', 'kde_grid', 'kde_fft', 'kde_isj')
kde_sample- The sample data for KDE estimation
name- Base name for the PDF
ipdf- Index of the PDF
kde_options- Additional options for the KDE
Returns
The constructed KDE PDF
def build_bkg_pdf(pdf: F2PDFBase,
obs: zfit.core.space.Space,
name: str,
ipdf: int) ‑> zfit.core.basepdf.BasePDF-
Expand source code
@staticmethod def build_bkg_pdf( pdf: F2PDFBase, obs: zfit.Space, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a background PDF with configurable parameters. Args: pdf: The PDF to build obs: The observable space for the PDF name: Base name for parameters ipdf: Index of the PDF """ if pdf.is_kde(): pdf = PDFBuilder.build_bkg_kde( pdf, name, ipdf ) return if pdf.is_hist(): pdf = PDFBuilder.build_bkg_hist( pdf, obs, name, ipdf ) return if pdf.kind == PDFType.CHEBPOL: # Handle Chebyshev polynomials specially PDFBuilder._build_chebyshev_pdf( pdf, obs, name, ipdf ) return config = get_bkg_pdf_config(pdf.kind) # Update the input dictionaries with default values PDFBuilder._update_with_defaults(config, pdf) parameters = {} for par_name in config['parameters'].keys(): param_name = f'{name}_{par_name}_bkg{ipdf}' parameters[param_name] = zfit.Parameter( name=param_name, value=pdf.get_init_par(par_name), lower=pdf.get_limits_par(par_name)[0], upper=pdf.get_limits_par(par_name)[1], floating=not pdf.get_fix_par(par_name) ) pdf_args = {'obs': obs} for arg_name in config['pdf_args']: if 'args_mapping' in config: # flarefly -> zfit argument name mapping param_key = f"{name}_{config['args_mapping'][arg_name]}_bkg{ipdf}" else: param_key = f'{name}_{arg_name}_bkg{ipdf}' pdf_args[arg_name] = parameters[param_key] pdf.pdf = config['pdf_class'](**pdf_args) pdf.parameters = parametersBuild a background PDF with configurable parameters.
Args
pdf- The PDF to build
obs- The observable space for the PDF
name- Base name for parameters
ipdf- Index of the PDF
def build_signal_hist(pdf: F2PDFBase,
obs: zfit.core.space.Space,
name: str,
ipdf: int) ‑> zfit.core.basepdf.BasePDF-
Expand source code
@staticmethod def build_signal_hist( pdf: F2PDFBase, obs: zfit.Space, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a signal PDF from a histogram template. Args: pdf: The PDF to build obs: The observable space for the PDF name: Base name for the PDF ipdf: Index of the PDF Returns: The constructed PDF """ if not pdf.hist_sample: Logger(f'Missing datasample for histogram template of signal {ipdf}!', 'FATAL') pdf.pdf = zfit.pdf.SplinePDF( zfit.pdf.HistogramPDF( pdf.hist_sample.get_binned_data(), name=f'{name}_hist_signal{ipdf}' ), order=3, obs=obs )Build a signal PDF from a histogram template.
Args
pdf- The PDF to build
obs- The observable space for the PDF
name- Base name for the PDF
ipdf- Index of the PDF
Returns
The constructed PDF
def build_signal_kde(pdf: F2PDFBase,
name: str,
ipdf: int) ‑> zfit.core.basepdf.BasePDF-
Expand source code
@staticmethod def build_signal_kde( pdf: F2PDFBase, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a signal KDE PDF. Args: pdf: The PDF to build name: Base name for the PDF ipdf: Index of the PDF """ if not pdf.kde_sample: Logger(f'Missing datasample for Kernel Density Estimation of signal {ipdf}!', 'FATAL') kde_options = pdf.kde_option or {} pdf.pdf = get_kde_pdf(pdf.kind)( data=pdf.kde_sample.get_data(), obs=pdf.kde_sample.get_obs(), name=f'{name}_kde_signal{ipdf}', **kde_options )Build a signal KDE PDF.
Args
pdf- The PDF to build
name- Base name for the PDF
ipdf- Index of the PDF
def build_signal_pdf(pdf: F2PDFBase,
obs: zfit.core.space.Space,
name: str,
ipdf: int) ‑> zfit.core.basepdf.BasePDF-
Expand source code
@staticmethod def build_signal_pdf( pdf: F2PDFBase, obs: zfit.Space, name: str, ipdf: int, ) -> zfit.pdf.BasePDF: """Build a signal PDF with configurable parameters. Args: pdf: The PDF to build obs: The observable space for the PDF name: Base name for parameters ipdf: Index of the PDF """ if pdf.is_kde(): pdf = PDFBuilder.build_signal_kde( pdf, name, ipdf ) return if pdf.is_hist(): pdf = PDFBuilder.build_signal_hist( pdf, obs, name, ipdf ) return config = get_signal_pdf_config(pdf.kind) # Update the input dictionaries with default values PDFBuilder._update_with_defaults(config, pdf) parameters = {} for par_name in config['parameters'].keys(): param_name = f'{name}_{par_name}_signal{ipdf}' parameters[param_name] = zfit.Parameter( name=param_name, value=pdf.get_init_par(par_name), lower=pdf.get_limits_par(par_name)[0], upper=pdf.get_limits_par(par_name)[1], floating=not pdf.get_fix_par(par_name) ) pdf_args = {'obs': obs} for arg_name in config['pdf_args']: if 'args_mapping' in config: # flarefly -> zfit argument name mapping param_key = f"{name}_{config['args_mapping'][arg_name]}_signal{ipdf}" else: param_key = f'{name}_{arg_name}_signal{ipdf}' pdf_args[arg_name] = parameters[param_key] pdf.pdf = config['pdf_class'](**pdf_args) pdf.parameters = parameters if pdf.at_threshold: # pion mass as default pdf.set_default_par( 'massthr', init=pdf.pdg_api.get_particle_by_mcid(211).mass, fix=True, limits=[None, None] ) pdf.set_default_par('powerthr', init=1., fix=False, limits=[None, None]) pdf.parameters[f'{name}_massthr_signal{ipdf}'] = zfit.Parameter( f'{name}_massthr_signal{ipdf}', pdf.get_init_par('massthr'), pdf.get_limits_par('massthr')[0], pdf.get_limits_par('massthr')[1], floating=not pdf.get_fix_par('massthr')) pdf.parameters[f'{name}_powerthr_signal{ipdf}'] = zfit.Parameter( f'{name}_powerthr_signal{ipdf}', pdf.get_init_par('powerthr'), pdf.get_limits_par('powerthr')[0], pdf.get_limits_par('powerthr')[1], floating=not pdf.get_fix_par('powerthr')) signalthr_pdf = cpdf.Pow( obs=obs, mass=pdf.parameters[f'{name}_massthr_signal{ipdf}'], power=pdf.parameters[f'{name}_powerthr_signal{ipdf}'] ) pdf.pdf = zfit.pdf.ProductPDF([pdf.pdf, signalthr_pdf], obs=obs)Build a signal PDF with configurable parameters.
Args
pdf- The PDF to build
obs- The observable space for the PDF
name- Base name for parameters
ipdf- Index of the PDF