Source code for pyamptools.utility.load_parameters

import numpy as np

############################################################
# This file holds scripts to load in amptools information
############################################################


[docs] class LoadParameters: """ Class to extract amplitude parameters from an AmpTools FitResults or ConfigurationInfo object Parameters (like production coefficients) can then be formatted (complex -> real, imag) for input to other minimization algorithms """ def __init__(self, cfg): self.load_cfg(cfg)
[docs] def load_cfg(self, cfg): # cfg: [FitResults, ConfigurationInfo] """ Get a map of unique (parameter: value) pairs excluding redundant constrained ones These include production parameters and amplitude parameters Args: cfg: If cfg is a FitResults object set values to fitted results. For a ConfigurationInfo object set values to initial values """ ######## GET UNIQUE AMPLITUDES' PRODUCTION PARAMETERS ######## results = None if hasattr(cfg, "configInfo"): # input was a FitResults object # print("Input was a FitResults object. Take actions accordingly...") results, cfg = cfg, cfg.configInfo() ftype = "FitResults" elif hasattr(cfg, "constraintMap"): # print("Input was a ConfigurationInfo object. Take actions accordingly...") ftype = "ConfigurationInfo" # input was a ConfigurationInfo object else: raise ValueError("Input must be a FitResults or ConfigurationInfo object") self.results = results self.cfg = cfg constraintMap = cfg.constraintMap() constraintIndex = {} uniqueProdPars = [] allProdPars = set() i = 0 for k, vs in constraintMap: allProdPars.add(k) if k not in constraintIndex and not cfg.amplitude(k).fixed(): uniqueProdPars.append(k) constraintIndex[k] = i # uniqueProdPars[i] for v in vs: if v not in constraintIndex and not cfg.amplitude(v).fixed(): # str(v) needed! appears that inserting v alone will go out of scope constraintIndex[str(v)] = i # uniqueProdPars[i] i += 1 ######## GET VALUES / REALNESS OF UNIQUE AMPLITUDES' PRODUCTION PARAMETERS ######## self.uniqueProdPars = {k: (results.ampProdParMap()[k] if ftype == "FitResults" else cfg.amplitude(k).value()) for k in uniqueProdPars} self.uniqueProdIsReal = {k: cfg.amplitude(k).real() for k in uniqueProdPars} # check if amplitude is set to be real ####### GET AMPLITUDE PARAMETERS ######## # parameters associated with amplitudes (i.e. masses, widths, etc) ampPars = cfg.parameterList() # ParameterInfo* self.ampPars = {} for par in ampPars: if not par.fixed(): self.ampPars[par.parName()] = results.ampParMap()[par.parName()] if ftype == "FitResults" else par.value() self.nAmpPars = len(ampPars) ####### MERGE DICTIONARIES ######## self.params = self.uniqueProdPars | self.ampPars # python 3.9 - merge dictionaries self.paramsIsReal = self.uniqueProdIsReal | {k: True for k in self.ampPars.keys()} # all amp params are real ####### ADDITIONAL TRACKING ####### self.allProdPars = list(allProdPars)
[docs] def flatten_parameters(self, params={}): """ Flatten amplitude parameters (complex-> real, imag) skipping imaginary parts of amplitudes fixed to be real. If no arguments are passed, use the uniqueProdPars and uniqueProdIsReal from the last call to load_cfg(). Can also format any dictionary pair into flat format. Dictionary to List Args: params (dict): dictionary of parameters to flatten Returns: parameters (list): list of flattened parameters keys (list): list of keys (parameter names) corresponding to parameters names (list): list of parameter names expanding complex parameters into Re[par] and Im[par] """ parameters = [] keys = [] # lose information on flatten, use key to keep track of provenance names = [] # track parameters in a prettier format if len(params) == 0: params = self.params for k, v in params.items(): assert k in self.paramsIsReal.keys(), f"Parameter {k} not found in parameter list! Is parameter fixed?" pk = k.split("::")[-1] # Production amplitudes take form "Reaction::Sum::Amp" grab Amp, pretty_k = pk real_value = v.real if k in self.uniqueProdPars else v names.append(f"Re[{pk}]" if k in self.uniqueProdPars else pk) parameters.append(real_value) # Production coefficients will have :: in their name. Normal parameters will not if "::" in k: keys.append(k + "_re") # MUST match notation in AmpTools' parameterManager else: keys.append(k) # If parameters are complex, we will include their imaginary components if not self.paramsIsReal[k]: parameters.append(v.imag) keys.append(k + "_im") names.append(f"Im[{pk}]") self.keys = keys self.names = names self.parmameters = parameters return parameters, keys, names
[docs] def unflatten_parameters(self, parameters, keys=[]): """ Unflatten parameters forming complex values (for production parameters) when requested. List to Dictionary Args: parameters (list): list of flattened parameters. Arrays work also, ensure you loop over parameters (columns of the mcmc samples) keys (list): list of keys (parameter names) corresponding to parameters. When empty will load from last flatten_parameters call Returns: paramDict (dict): dictionary of parameters """ if len(keys) == 0 and len(parameters) != 0 and len(parameters) == len(self.parmameters): print(f"Bool 1 {len(keys)==0 and len(parameters)!=0}") print(f"Bool 2 {len(parameters) == len(self.parmameters)} {len(parameters)} {len(self.parmameters)}") keys = self.keys paramDict = {} for k, param in zip(keys, parameters): amp = k[:-3] part = 1 if k[-3:] == "_re" else 1j if amp not in paramDict: paramDict[amp] = np.complex64(part * param) else: paramDict[amp] += np.complex64(part * param) for k in paramDict.keys(): paramDict[k] = np.round(paramDict[k], 10) return paramDict
def createMovesMixtureFromDict(moves_dict): """ Creates a mixture of moves for the emcee sampler Args: moves_dict { move: {kwargs: {}, probability} }: Dictionary of moves and their kwargs and probability Returns: moves_mixture [ (emcee.moves.{move}(kwargs), probability) ]: List of tuples of moves (with kwargs pluggin in) and their probability """ moves_mixture = [] for move, moveDict in moves_dict.items(): move = eval(f"emcee.moves.{move}") # convert string to class kwargs = moveDict["kwargs"] prob = moveDict["prob"] moves_mixture.append((move(**kwargs), prob)) return moves_mixture