def build_fisher_matrix(gradient_maps, fiducial_map, template_settings): # fix the ordering of parameters params = gradient_maps.keys() fisher = {} for chan in gradient_maps[params[0]]: # Find non-empty bins in flattened map nonempty = np.nonzero(fiducial_map[chan]['map'].flatten()) logging.info( "Using %u non-empty bins of %u" % (len(nonempty[0]), len(fiducial_map[chan]['map'].flatten()))) # get gradients as calculated above for non-zero bins gradients = np.array([ gradient_maps[par][chan]['map'].flatten()[nonempty] for par in params ]) # get error estimate from best-fit bin count for non-zero bins sigmas = np.sqrt(fiducial_map[chan]['map'].flatten()[nonempty]) # Loop over all parameter per bin (simple transpose) and calculate Fisher # matrix by getting the outer product of all gradients in a bin. Result is # sum of matrix for all bins fmatrix = np.zeros((len(params), len(params))) for bin_gradients, bin_sigma in zip(gradients.T, sigmas.flatten()): fmatrix += np.outer(bin_gradients, bin_gradients) / bin_sigma**2 # Construct the fisher matrix object fisher[chan] = FisherMatrix( matrix=fmatrix, parameters=params, #order is important here! best_fits=[template_settings[par]['value'] for par in params], priors=[ Prior.from_param(template_settings[par]) for par in params ], ) # Return all fisher matrices return fisher
def build_fisher_matrix(gradient_maps, fiducial_map, template_settings): # fix the ordering of parameters params = gradient_maps.keys() fisher = {} for chan in gradient_maps[params[0]]: # Find non-empty bins in flattened map nonempty = np.nonzero(fiducial_map[chan]['map'].flatten()) logging.info("Using %u non-empty bins of %u" % (len(nonempty[0]), len(fiducial_map[chan]['map'].flatten()))) # get gradients as calculated above for non-zero bins gradients = np.array( [ gradient_maps[par][chan]['map'].flatten()[nonempty] for par in params ] ) # get error estimate from best-fit bin count for non-zero bins sigmas = np.sqrt(fiducial_map[chan]['map'].flatten()[nonempty]) # Loop over all parameter per bin (simple transpose) and calculate Fisher # matrix by getting the outer product of all gradients in a bin. Result is # sum of matrix for all bins fmatrix = np.zeros((len(params), len(params))) for bin_gradients, bin_sigma in zip(gradients.T,sigmas.flatten()): fmatrix += np.outer(bin_gradients, bin_gradients)/bin_sigma**2 # Construct the fisher matrix object fisher[chan] = FisherMatrix( matrix=fmatrix, parameters=params, #order is important here! best_fits=[template_settings[par]['value'] for par in params], priors=[Prior.from_param(template_settings[par]) for par in params], ) # Return all fisher matrices return fisher
def get_fisher_matrices(template_settings, grid_settings, IMH=True, NMH=False, dump_all_stages=False, save_templates=False, outdir=None): ''' Main function that runs the Fisher analysis for the chosen hierarchy(ies) (inverted by default). Returns a dictionary of Fisher matrices, in the format: {'IMH': {'cscd': [...], 'trck': [...], 'comb': [...], }, 'NMH': {'cscd': [...], 'trck': [...], 'comb': [...], } } If save_templates=True and no hierarchy is given, only fiducial templates will be written out; if one is given, then the templates used to obtain the gradients will be written out in addition. ''' if outdir is None and (save_templates or dump_all_stages): logging.info( "No output directory specified. Will save templates to current working directory." ) outdir = os.getcwd() tprofile.info("start initializing") # Get the parameters params = template_settings['params'] bins = template_settings['binning'] # Artifically add the hierarchy parameter to the list of parameters # The method get_hierarchy_gradients below will know how to deal with it params['hierarchy_nh'] = { "value": 1., "range": [0., 1.], "fixed": False, "prior": None } params['hierarchy_ih'] = { "value": 0., "range": [0., 1.], "fixed": False, "prior": None } chosen_data = [] if IMH: chosen_data.append(('IMH', False)) logging.info("Fisher matrix will be built for IMH.") if NMH: chosen_data.append(('NMH', True)) logging.info("Fisher matrix will be built for NMH.") if chosen_data == []: # In this case, only the fiducial maps (for both hierarchies) will be written logging.info("No Fisher matrices will be built.") # There is no sense in performing any of the following steps if no Fisher matrices are to be built # and no templates are to be saved. if chosen_data != [] or dump_all_stages or save_templates: # Initialise return dict to hold Fisher matrices fisher = { data_tag: { 'cscd': [], 'trck': [], 'comb': [] } for data_tag, data_normal in chosen_data } # Get a template maker with the settings used to initialize template_maker = TemplateMaker(get_values(params), **bins) tprofile.info("stop initializing\n") # Generate fiducial templates for both hierarchies (needed for partial derivatives # w.r.t. hierarchy parameter) fiducial_maps = {} for hierarchy in ['NMH', 'IMH']: logging.info("Generating fiducial templates for %s." % hierarchy) # Get the fiducial parameter values corresponding to this hierarchy fiducial_params = select_hierarchy( params, normal_hierarchy=(hierarchy == 'NMH')) # Generate fiducial maps, either all of them or only the ultimate one tprofile.info("start template calculation") with Timer() as t: fid_maps = template_maker.get_template( get_values(fiducial_params), return_stages=dump_all_stages) tprofile.info("==> elapsed time for template: %s sec" % t.secs) fiducial_maps[ hierarchy] = fid_maps[4] if dump_all_stages else fid_maps # save fiducial map(s) # all stages if dump_all_stages: stage_names = ("0_unoscillated_flux", "1_oscillated_flux", "2_oscillated_counts", "3_reco", "4_pid") stage_maps = {} for stage in xrange(0, len(fid_maps)): stage_maps[stage_names[stage]] = fid_maps[stage] logging.info( "Writing fiducial maps (all stages) for %s to %s." % (hierarchy, outdir)) to_json(stage_maps, os.path.join(outdir, "fid_map_" + hierarchy + ".json")) # only the final stage elif save_templates: logging.info( "Writing fiducial map (final stage) for %s to %s." % (hierarchy, outdir)) to_json(fiducial_maps[hierarchy], os.path.join(outdir, "fid_map_" + hierarchy + ".json")) # Get_gradients and get_hierarchy_gradients will both (temporarily) # store the templates used to generate the gradient maps store_dir = outdir if save_templates else tempfile.gettempdir() # Calculate Fisher matrices for the user-defined cases (NHM true and/or IMH true) for data_tag, data_normal in chosen_data: logging.info("Running Fisher analysis for %s." % (data_tag)) # The fiducial params are selected from the hierarchy case that does NOT match # the data, as we are varying from this model to find the 'best fit' fiducial_params = select_hierarchy(params, not data_normal) # Get the free parameters (i.e. those for which the gradients should be calculated) free_params = select_hierarchy(get_free_params(params), not data_normal) gradient_maps = {} for param in free_params.keys(): # Special treatment for the hierarchy parameter if param == 'hierarchy': gradient_maps[param] = get_hierarchy_gradients( data_tag=data_tag, fiducial_maps=fiducial_maps, fiducial_params=fiducial_params, grid_settings=grid_settings, store_dir=store_dir) else: gradient_maps[param] = get_gradients( data_tag=data_tag, param=param, template_maker=template_maker, fiducial_params=fiducial_params, grid_settings=grid_settings, store_dir=store_dir) logging.info("Building Fisher matrix for %s." % (data_tag)) # Build Fisher matrices for the given hierarchy fisher[data_tag] = build_fisher_matrix( gradient_maps=gradient_maps, fiducial_map=fiducial_maps['IMH'] if data_normal else fiducial_maps['NMH'], template_settings=fiducial_params) # If Fisher matrices exist for both channels, add the matrices to obtain # the combined one. if len(fisher[data_tag].keys()) > 1: fisher[data_tag]['comb'] = FisherMatrix( matrix=np.array([ f.matrix for f in fisher[data_tag].itervalues() ]).sum(axis=0), parameters=gradient_maps.keys(), #order is important here! best_fits=[ fiducial_params[par]['value'] for par in gradient_maps.keys() ], priors=[ Prior.from_param(fiducial_params[par]) for par in gradient_maps.keys() ], ) return fisher else: logging.info("Nothing to be done.") return {}
def get_fisher_matrices(template_settings, grid_settings, IMH=True, NMH=False, dump_all_stages=False, save_templates=False, outdir=None): ''' Main function that runs the Fisher analysis for the chosen hierarchy(ies) (inverted by default). Returns a dictionary of Fisher matrices, in the format: {'IMH': {'cscd': [...], 'trck': [...], 'comb': [...], }, 'NMH': {'cscd': [...], 'trck': [...], 'comb': [...], } } If save_templates=True and no hierarchy is given, only fiducial templates will be written out; if one is given, then the templates used to obtain the gradients will be written out in addition. ''' if outdir is None and (save_templates or dump_all_stages): logging.info("No output directory specified. Will save templates to current working directory.") outdir = os.getcwd() tprofile.info("start initializing") # Get the parameters params = template_settings['params'] bins = template_settings['binning'] # Artifically add the hierarchy parameter to the list of parameters # The method get_hierarchy_gradients below will know how to deal with it params['hierarchy_nh'] = { "value": 1., "range": [0.,1.], "fixed": False, "prior": None} params['hierarchy_ih'] = { "value": 0., "range": [0.,1.], "fixed": False, "prior": None} chosen_data = [] if IMH: chosen_data.append(('IMH',False)) logging.info("Fisher matrix will be built for IMH.") if NMH: chosen_data.append(('NMH',True)) logging.info("Fisher matrix will be built for NMH.") if chosen_data == []: # In this case, only the fiducial maps (for both hierarchies) will be written logging.info("No Fisher matrices will be built.") # There is no sense in performing any of the following steps if no Fisher matrices are to be built # and no templates are to be saved. if chosen_data!=[] or dump_all_stages or save_templates: # Initialise return dict to hold Fisher matrices fisher = { data_tag:{'cscd':[],'trck':[],'comb':[]} for data_tag, data_normal in chosen_data } # Get a template maker with the settings used to initialize template_maker = TemplateMaker(get_values(params),**bins) tprofile.info("stop initializing\n") # Generate fiducial templates for both hierarchies (needed for partial derivatives # w.r.t. hierarchy parameter) fiducial_maps = {} for hierarchy in ['NMH','IMH']: logging.info("Generating fiducial templates for %s."%hierarchy) # Get the fiducial parameter values corresponding to this hierarchy fiducial_params = select_hierarchy(params,normal_hierarchy=(hierarchy=='NMH')) # Generate fiducial maps, either all of them or only the ultimate one tprofile.info("start template calculation") with Timer() as t: fid_maps = template_maker.get_template(get_values(fiducial_params), return_stages=dump_all_stages) tprofile.info("==> elapsed time for template: %s sec"%t.secs) fiducial_maps[hierarchy] = fid_maps[4] if dump_all_stages else fid_maps # save fiducial map(s) # all stages if dump_all_stages: stage_names = ("0_unoscillated_flux","1_oscillated_flux","2_oscillated_counts","3_reco","4_pid") stage_maps = {} for stage in xrange(0,len(fid_maps)): stage_maps[stage_names[stage]] = fid_maps[stage] logging.info("Writing fiducial maps (all stages) for %s to %s."%(hierarchy,outdir)) to_json(stage_maps,os.path.join(outdir,"fid_map_"+hierarchy+".json")) # only the final stage elif save_templates: logging.info("Writing fiducial map (final stage) for %s to %s."%(hierarchy,outdir)) to_json(fiducial_maps[hierarchy],os.path.join(outdir,"fid_map_"+hierarchy+".json")) # Get_gradients and get_hierarchy_gradients will both (temporarily) # store the templates used to generate the gradient maps store_dir = outdir if save_templates else tempfile.gettempdir() # Calculate Fisher matrices for the user-defined cases (NHM true and/or IMH true) for data_tag, data_normal in chosen_data: logging.info("Running Fisher analysis for %s."%(data_tag)) # The fiducial params are selected from the hierarchy case that does NOT match # the data, as we are varying from this model to find the 'best fit' fiducial_params = select_hierarchy(params,not data_normal) # Get the free parameters (i.e. those for which the gradients should be calculated) free_params = select_hierarchy(get_free_params(params),not data_normal) gradient_maps = {} for param in free_params.keys(): # Special treatment for the hierarchy parameter if param=='hierarchy': gradient_maps[param] = get_hierarchy_gradients( data_tag=data_tag, fiducial_maps=fiducial_maps, fiducial_params=fiducial_params, grid_settings=grid_settings, store_dir=store_dir ) else: gradient_maps[param] = get_gradients( data_tag=data_tag, param=param, template_maker=template_maker, fiducial_params=fiducial_params, grid_settings=grid_settings, store_dir=store_dir ) logging.info("Building Fisher matrix for %s."%(data_tag)) # Build Fisher matrices for the given hierarchy fisher[data_tag] = build_fisher_matrix( gradient_maps=gradient_maps, fiducial_map=fiducial_maps['IMH'] if data_normal else fiducial_maps['NMH'], template_settings=fiducial_params ) # If Fisher matrices exist for both channels, add the matrices to obtain # the combined one. if len(fisher[data_tag].keys()) > 1: fisher[data_tag]['comb'] = FisherMatrix( matrix=np.array([f.matrix for f in fisher[data_tag].itervalues()]).sum(axis=0), parameters=gradient_maps.keys(), #order is important here! best_fits=[fiducial_params[par]['value'] for par in gradient_maps.keys()], priors=[Prior.from_param(fiducial_params[par]) for par in gradient_maps.keys()], ) return fisher else: logging.info("Nothing to be done.") return {}