def build_lnl_fn(self, normv, nllv): """ Build a function to return the likelihood value arrays of normalization and likelihood values. Parameters ---------- normv : `numpy.array` Set of test normalization values nllv : `numpy.array` Corresponding set of negative log-likelihood values Returns ------- output : `fermipy.castro.LnLFn` or `LnLFn_norm_prior` Object that can compute the negative log-likelihood with the prior included (if requested) """ lnlfn = castro.LnLFn(normv, nllv, self._norm_type) if self._astro_prior is None: return lnlfn if self._prior_applied: return lnlfn return LnLFn_norm_prior(lnlfn, self._astro_prior)
def build_lnl_fn(self, normv, nllv): """ Build a function to return the likelihood value arrays of normalization and likelihood values """ lnlfn = castro.LnLFn(normv, nllv, self._norm_type) if self._astro_prior is None: return lnlfn if self._prior_applied: return lnlfn return stats_utils.LnLFn_norm_prior(lnlfn, self._astro_prior)
def compute_castro_data(castro_data, spec_vals, xscan_vals, **kwargs): """ Convert CastroData object, i.e., Likelihood as a function of flux and energy flux, to a StackCastroData object, i.e., Likelihood as a function of stacking normalization and index Parameters ---------- castro_data : `CastroData` Input data spec_vals : `numpy.array` Input spectra xscan_vals : `numpy.array` Values for scan variables Returns ------- output : `StackCastroData` The stacking-space likelihood curves """ ref_stack = kwargs.get('ref_stack', 1.) norm_factor = kwargs.pop('norm_factor', 1.) spec_name = kwargs.pop('spec_name') astro_prior = kwargs.pop('astro_prior') n_xval = len(xscan_vals) n_yval = kwargs.get('nystep', 200) norm_limits = castro_data.getLimits(1e-5) # This puts the spectrum in units of the reference spectrum # This means that the scan values will be expressed # In units of the reference spectra as well spec_vals /= norm_factor norm_vals = np.ndarray((n_xval, n_yval)) dll_vals = np.ndarray((n_xval, n_yval)) mle_vals = np.ndarray((n_xval)) nll_offsets = np.ndarray((n_xval)) scan_mask = np.ones((n_xval), bool) # for i, index in enumerate(xscan_vals): for i in range(n_xval): max_ratio = 1. / ((spec_vals[i] / norm_limits).max()) log_max_ratio = np.log10(max_ratio) norm_vals[i][0] = 10**(log_max_ratio - 5) norm_vals[i][1:] = np.logspace(log_max_ratio - 4, log_max_ratio + 4, n_yval - 1) test_vals = (np.expand_dims(spec_vals[i], 1) * (np.expand_dims(norm_vals[i], 1).T)) dll_vals[i, 0:] = castro_data(test_vals) mle_vals[i] = norm_vals[i][dll_vals[i].argmin()] nll_offsets[i] = dll_vals[i].min() dll_vals[i] -= nll_offsets[i] msk = np.isfinite(dll_vals[i]) if not msk.any(): print("Skipping scan value %0.2e for spec %s" % (xscan_vals[i], spec_name)) scan_mask[i] = False continue if is_not_null(astro_prior): try: lnlfn = castro.LnLFn(norm_vals[i], dll_vals[i], 'dummy') lnlfn_prior = LnLFn_norm_prior(lnlfn, astro_prior) dll_vals[i, 0:] = lnlfn_prior(norm_vals[i]) nll_offsets[i] = dll_vals[i].min() except ValueError: print("Skipping index %0.2e for spec %s" % (xscan_vals[i], spec_name)) scan_mask[i] = False dll_vals[i, 0:] = np.nan * np.ones((n_yval)) nll_offsets[i] = np.nan kwcopy = kwargs.copy() kwcopy['xscan_vals'] = xscan_vals[scan_mask] kwcopy['astro_prior'] = astro_prior # Here we convert the normalization values to standard units norm_vals *= ref_stack stack_castro = StackCastroData(norm_vals[scan_mask], dll_vals[scan_mask], nll_offsets[scan_mask], **kwcopy) return stack_castro
def convert_castro_data(self, castro_data, channel, norm_type, jfactor=None): """ Convert CastroData object, i.e., Likelihood as a function of flux and energy flux, to a DMCastroData object, i.e., Likelihood as a function of DM mass and sigmav """ if not self.check_energy_bins(castro_data.refSpec): raise ValueError("CastroData energy binning does not match") mask = self._s_table['ref_chan'] == channel masses = self._s_table[mask]['ref_mass'].data spec_vals = self._s_table[mask]['ref_%s' % norm_type].data nmass = len(masses) # Get the reference values ref_sigmav = self._ref_vals["ref_sigv"] ref_norm = self._ref_vals["ref_J"] j_prior = None if jfactor is None: # Just use the reference values j_ref = ref_norm norm_factor = 1. elif isinstance(jfactor, float): # Rescale the normalization values j_ref = jfactor norm_factor = jfactor / ref_norm elif isinstance(jfactor, dict): j_ref = jfactor.get('j_value') norm_factor = j_ref / ref_norm j_prior = stats_utils.create_prior_functor(jfactor) norm_limits = castro_data.getLimits(1e-5) spec_vals *= norm_factor n_scan_pt = 100 norm_vals = np.ndarray((nmass, n_scan_pt)) dll_vals = np.ndarray((nmass, n_scan_pt)) mle_vals = np.ndarray((nmass)) # for i, mass in enumerate(masses): for i in range(nmass): max_ratio = 1. / ((spec_vals[i] / norm_limits).max()) log_max_ratio = np.log10(max_ratio) norm_vals[i][0] = 0. norm_vals[i][1:] = np.logspace(log_max_ratio - 2, log_max_ratio + 2, n_scan_pt - 1) test_vals = (np.expand_dims(spec_vals[i], 1) * (np.expand_dims(norm_vals[i], 1).T)) dll_vals[i, 0:] = castro_data(test_vals) mle_vals[i] = norm_vals[i][dll_vals[i].argmin()] mle_ll = dll_vals[i].min() dll_vals[i] -= mle_ll if j_prior is not None: lnlfn = castro.LnLFn(norm_vals[i], dll_vals[i], 'dummy') lnlfn_prior = stats_utils.LnLFn_norm_prior(lnlfn, j_prior) dll_vals[i, 0:] = lnlfn_prior(norm_vals[i]) norm_vals *= (ref_sigmav) dm_castro = DMCastroData(norm_vals, dll_vals, norm_factor, channel, masses, j_ref, j_prior) return dm_castro
def convert_castro_data(self, castro_data, channel, norm_type, astro_factor=None): """ Convert CastroData object, i.e., Likelihood as a function of flux and energy flux, to a DMCastroData object, i.e., Likelihood as a function of DM mass and sigmav Parameters ---------- castro_data : `CastroData` Input data channel : int Index for the DM interaction channel norm_type : str Type of spectral normalization to use for the conversion astro_factor : dict or float or None Nuisance factor used to make the conversion. If astro_factor is None, it will use the reference value If astro_factor is a float, it will use that If astro_factor is a dict, it will use that to create a prior Returns ------- output : `DMCastroData` The DM-space likelihood curves """ if not self.check_energy_bins(castro_data.refSpec): raise ValueError("CastroData energy binning does not match") mask = self._s_table['ref_chan'] == channel masses = self._s_table[mask]['ref_mass'].data spec_vals = self._s_table[mask]['ref_%s' % norm_type].data nmass = len(masses) is_decay = channel >= 100 # Get the reference values if is_decay: ref_inter = self._ref_vals["REF_TAU"] ref_norm = self._ref_vals["REF_D"] astro_str = 'd_value' else: ref_inter = self._ref_vals["REF_SIGV"] ref_norm = self._ref_vals["REF_J"] astro_str = 'j_value' astro_prior = None if is_null(astro_factor): # Just use the reference values astro_value = ref_norm norm_factor = 1. elif isinstance(astro_factor, float): # Rescale the normalization values astro_value = astro_factor norm_factor = ref_norm / astro_factor elif isinstance(astro_factor, dict): astro_value = astro_factor.get(astro_str) norm_factor = ref_norm / astro_value astro_factor['scale'] = astro_value astro_functype = astro_factor.get('functype', None) if is_null(astro_functype): astro_prior = None else: astro_prior = create_prior_functor(astro_factor) else: sys.stderr.write( "Did not recoginize Astro factor %s %s\n" % (astro_factor, type(astro_factor))) norm_limits = castro_data.getLimits(1e-5) # This puts the spectrum in units of the reference spectrum # This means that the scan values will be expressed # In units of the reference spectra as well spec_vals /= norm_factor n_scan_pt = 200 norm_vals = np.ndarray((nmass, n_scan_pt)) dll_vals = np.ndarray((nmass, n_scan_pt)) mle_vals = np.ndarray((nmass)) nll_offsets = np.ndarray((nmass)) mass_mask = np.ones((nmass), bool) # for i, mass in enumerate(masses): for i in range(nmass): max_ratio = 1. / ((spec_vals[i] / norm_limits).max()) log_max_ratio = np.log10(max_ratio) norm_vals[i][0] = 10**(log_max_ratio - 5) norm_vals[i][1:] = np.logspace(log_max_ratio - 4, log_max_ratio + 4, n_scan_pt - 1) test_vals = (np.expand_dims( spec_vals[i], 1) * (np.expand_dims(norm_vals[i], 1).T)) dll_vals[i, 0:] = castro_data(test_vals) mle_vals[i] = norm_vals[i][dll_vals[i].argmin()] nll_offsets[i] = dll_vals[i].min() dll_vals[i] -= nll_offsets[i] msk = np.isfinite(dll_vals[i]) if not msk.any(): print ( "Skipping mass %0.2e for channel %s" % (masses[i], channel)) mass_mask[i] = False continue if is_not_null(astro_prior): try: lnlfn = castro.LnLFn(norm_vals[i], dll_vals[i], 'dummy') lnlfn_prior = LnLFn_norm_prior(lnlfn, astro_prior) dll_vals[i, 0:] = lnlfn_prior(norm_vals[i]) nll_offsets[i] = dll_vals[i].min() except ValueError: print ( "Skipping mass %0.2e for channel %s" % (masses[i], channel)) mass_mask[i] = False dll_vals[i, 0:] = np.nan * np.ones((n_scan_pt)) nll_offsets[i] = np.nan # Here we convert the normalization values to standard units norm_vals *= (ref_inter) dm_castro = DMCastroData(norm_vals[mass_mask], dll_vals[mass_mask], nll_offsets[mass_mask], channel, masses[mass_mask], astro_value, astro_prior=astro_prior, ref_astro=ref_norm, ref_inter=ref_inter, decay=is_decay) return dm_castro