def skew_gaussian(peak, sig_minus, sig_plus): """ Creates a skewed gaussian """ x = np.arange(-100, 100, .01) g1 = Gaussian1D(amplitude=peak, stddev=sig_minus)(x) g2 = Gaussian1D(amplitude=peak, stddev=sig_plus)(x) ind = np.argmin(abs(x)) g3 = np.copy(g1) g3[ind:] = g2[ind:] gauss = np.array([x, g3]) return gauss
def test_subpixel_gauss_1D(): """ Test subpixel accuracy of the integrate mode with gaussian 1D model. """ gauss_1D = Gaussian1D(1, 0, 0.1) values = discretize_model(gauss_1D, (-1, 2), mode='integrate', factor=100) assert_allclose(values.sum(), np.sqrt(2 * np.pi) * 0.1, atol=0.00001)
def add_emission_line(self, line_center, line_width, line_amp, line_type="gaussian"): """ Add an emission line to this spectrum. Parameters ---------- line_center : float, (value, unit) tuple, or :class:`~astropy.units.Quantity` The line center position in units of keV, in the observer frame. line_width : one or more float, (value, unit) tuple, or :class:`~astropy.units.Quantity` The line width (FWHM) in units of keV, in the observer frame. Can also input the line width in units of velocity in the rest frame. For the Voigt profile, a list, tuple, or array of two values should be provided since there are two line widths, the Lorentzian and the Gaussian (in that order). line_amp : float, (value, unit) tuple, or :class:`~astropy.units.Quantity` The integrated line amplitude in the units of the flux line_type : string, optional The line profile type. Default: "gaussian" """ line_center = parse_value(line_center, "keV") line_width = parse_value(line_width, "keV", equivalence=line_width_equiv(line_center)) line_amp = parse_value(line_amp, self._units) if line_type == "gaussian": sigma = line_width / sigma_to_fwhm line_amp /= sqrt2pi * sigma f = Gaussian1D(line_amp, line_center, sigma) else: raise NotImplementedError("Line profile type '%s' " % line_type + "not implemented!") self.flux += u.Quantity(f(self.emid.value), self._units) self._compute_total_flux()
def add_absorption_line(self, line_center, line_width, equiv_width, line_type='gaussian'): """ Add an absorption line to this spectrum. Parameters ---------- line_center : float, (value, unit) tuple, or :class:`~astropy.units.Quantity` The line center position in units of keV, in the observer frame. line_width : one or more float, (value, unit) tuple, or :class:`~astropy.units.Quantity` The line width (FWHM) in units of keV, in the observer frame. Can also input the line width in units of velocity in the rest frame. For the Voigt profile, a list, tuple, or array of two values should be provided since there are two line widths, the Lorentzian and the Gaussian (in that order). equiv_width : float, (value, unit) tuple, or :class:`~astropy.units.Quantity` The equivalent width of the line, in units of milli-Angstrom line_type : string, optional The line profile type. Default: "gaussian" """ line_center = parse_value(line_center, "keV") line_width = parse_value(line_width, "keV", equivalence=line_width_equiv(line_center)) equiv_width = parse_value(equiv_width, "1.0e-3*angstrom") # in milliangstroms equiv_width *= 1.0e-3 # convert to angstroms if line_type == "gaussian": sigma = line_width / sigma_to_fwhm B = equiv_width*line_center*line_center B /= hc * sqrt2pi * sigma f = Gaussian1D(B, line_center, sigma) else: raise NotImplementedError("Line profile type '%s' " % line_type + "not implemented!") self.flux *= np.exp(-f(self.emid.value)) self._compute_total_flux()
def Gfit2hist(data): ''' Gaussian fit to the frequency distribution of the nddata. ''' freq = itemfreq(data.flatten()) fitter = LevMarLSQFitter() mode = freq[freq[:, 1] == freq[:, 1].max(), 0][0] init = Gaussian1D(mean=mode) fitG = fitter(init, freq[:, 0], freq[:, 1]) return fitG
def add_slices(self, xcen, xshift, xspan, psf_xlength, wmin, wmax, wmin_d, wmax_d): xcens = range(xcen - xshift, xcen + xshift, xspan) for c, t in zip(xcens[1:], self.psf.traces): _, _, sl_msignal = self.add_slice(t, c, wmin, wmax, wmin_d, wmax_d) self.mod_init.append( Gaussian1D(amplitude=sl_msignal, mean=c, stddev=psf_xlength)) self.sl_cen.append(c)
def test_gaussian_eval_1D(mode): """ Discretize Gaussian with different modes and check if result is at least similar to Gaussian1D.eval(). """ model = Gaussian1D(1, 0, 20) x = np.arange(-100, 101) values = model(x) disc_values = discretize_model(model, (-100, 101), mode=mode) assert_allclose(values, disc_values, atol=0.001)
def get_mask(self, flt_name, kernel_fwhm=1.25, background_box=20, thr=0.05, npixels=100): """ Function to create a mask (set to 0 for no detection and 1 for detection) appropriate to mask WFC3 slitless data. Attributes ---------- flt_name string containing the name of the FLT name to create a mask for kernel_fwhm Float The size of the detection kernel (default = 1.25 pixel) background_box Int The saie fo the background box when estimating the background (default = 20 pixels) thr Float Threshold above noise to detect signal (default = 0.25) npixels Int number of pixels for a spectrum to be detected (default = 15) Output ------ A numpy array containing the mask """ h = fits.open(flt_name)[0].header filt = h["FILTER"] fin = fits.open(flt_name) image = fin["SCI"].data err = fin["ERR"].data dq = fin["DQ"].data dq = np.bitwise_and(dq, np.zeros(np.shape(dq), np.int16) + self.bit_mask) g = Gaussian1D(mean=0., stddev=kernel_fwhm / 2.35) x = np.arange(16.) - 8 a = g(x) kernel = np.tile(a, (16 * int(kernel_fwhm + 1), 1)).T kernel = kernel / np.sum(kernel) b = Background2D(image, background_box) image = image - b.background threshold = thr * err image[dq > 0] = 0. #np.nan mask = detect_sources(image, threshold, npixels=npixels, filter_kernel=kernel).data ok = (mask == 0.) & (dq == 0) mask[~ok] = 1. return mask
def lnprob(p, n, N): x = np.linspace(0, 170, 10000) G = Gaussian1D(1, 0, p)(x) use = x < 15.9 #sb radius theta = simps(abs(x[use]) * G[use], x[use]) / simps(abs(x) * G, x) bounds = (0, 100) lp = lnprior(p, bounds) if not np.isfinite(lp): return -np.inf ll = lnlike(theta, n, N) if np.isnan(ll): return -np.inf return ll + lp
def test3(): from astropy.modeling.functional_models import Gaussian1D def norm_gauss(sigma): return 1 / np.sqrt(2 * np.pi * sigma**2) x = np.arange(-8, 8, 0.1) ax1 = plt.subplot(1, 1, 1) for s in range(1, 5): gauss = Gaussian1D(amplitude=1, mean=0, stddev=s) ax1.plot(x, norm_gauss(s) * gauss(x), ls=":", label="sigma={0:.0f}, HWHM={1:.1f}".format(s, 2.355 * s / 2)) ax1.plot(x, gauss(x), label="sigma={0:.0f}, HWHM={1:.1f}".format(s, 2.355 * s / 2))
# %% def fisher(pdf_grid, dx): normed = pdf_grid / np.trapz(pdf_grid, dx=dx) grad = np.gradient(normed, dx) return np.trapz(grad ** 2 / normed, dx=dx) # %% mi, ma, s = -30, 30, 1001 xs = np.linspace(mi, ma, s) dx = (ma - mi) / s pdf = Gaussian1D(stddev=1)(xs) pdf /= np.trapz(pdf, dx=dx) print(np.trapz(pdf, dx=dx)) print(np.sum(pdf)) # %% mi, ma, s = -30, 30, 1001 xs = np.linspace(mi, ma, s) dx = (ma - mi) / s pdf = Gaussian1D(stddev=1)(xs) pdf /= np.trapz(pdf, dx=dx) plt.figure() plt.plot(xs, pdf)
def __init__( self, obs_x, obs_y, estimate_start=False, param_info=None, filename=None, tformat=None, ): """ Setup a variant based on inputs. Generates an astropy.modeling compound model. """ # check that param_info or filename is set if filename is None and param_info is None: raise ValueError("Either param_info or filename need to be set \ when initializing a PAHFITBase object") # read in the parameter info from a file if filename is not None: param_info = self.read(filename, tformat=tformat) if estimate_start: # guess values and update starting point (if not set fixed) based on the input spectrum param_info = self.estimate_init(obs_x, obs_y, param_info) if not param_info: raise ValueError("No parameter information set.") self.param_info = param_info bb_info = param_info[0] dust_features = param_info[1] h2_features = param_info[2] ion_features = param_info[3] att_info = param_info[4] # setup the model self.model = None self.bb_info = bb_info if bb_info is not None: bbs = [] for k in range(len(bb_info["names"])): BBClass = ModifiedBlackBody1D if bb_info["modified"][ k] else BlackBody1D bbs.append( BBClass( name=bb_info["names"][k], temperature=bb_info["temps"][k], amplitude=bb_info["amps"][k], bounds={ "temperature": bb_info["temps_limits"][k], "amplitude": bb_info["amps_limits"][k], }, fixed={ "temperature": bb_info["temps_fixed"][k], "amplitude": bb_info["amps_fixed"][k], }, )) self.model = sum(bbs[1:], bbs[0]) self.dust_features = dust_features if dust_features is not None: df = [] for k in range(len(dust_features["names"])): df.append( Drude1D( name=dust_features["names"][k], amplitude=dust_features["amps"][k], x_0=dust_features["x_0"][k], fwhm=dust_features["fwhms"][k], bounds={ "amplitude": dust_features["amps_limits"][k], "x_0": dust_features["x_0_limits"][k], "fwhm": dust_features["fwhms_limits"][k], }, fixed={ "amplitude": dust_features["amps_fixed"][k], "x_0": dust_features["x_0_fixed"][k], "fwhm": dust_features["fwhms_fixed"][k], }, )) df = sum(df[1:], df[0]) if self.model: self.model += df else: self.model = df self.h2_features = h2_features if h2_features is not None: h2 = [] for k in range(len(h2_features["names"])): h2.append( Gaussian1D( name=h2_features["names"][k], amplitude=h2_features["amps"][k], mean=h2_features["x_0"][k], stddev=h2_features["fwhms"][k] / 2.355, bounds={ "amplitude": h2_features["amps_limits"][k], "mean": h2_features["x_0_limits"][k], "stddev": ( h2_features["fwhms"][k] * 0.9 / 2.355, h2_features["fwhms"][k] * 1.1 / 2.355, ), }, fixed={ "amplitude": h2_features["amps_fixed"][k], "mean": h2_features["x_0_fixed"][k], "stddev": h2_features["fwhms_fixed"][k], }, )) h2 = sum(h2[1:], h2[0]) if self.model: self.model += h2 else: self.model = h2 self.ion_features = ion_features if ion_features is not None: ions = [] for k in range(len(ion_features["names"])): ions.append( Gaussian1D( name=ion_features["names"][k], amplitude=ion_features["amps"][k], mean=ion_features["x_0"][k], stddev=ion_features["fwhms"][k] / 2.355, bounds={ "amplitude": ion_features["amps_limits"][k], "mean": ion_features["x_0_limits"][k], "stddev": ( ion_features["fwhms"][k] * 0.9 / 2.355, ion_features["fwhms"][k] * 1.1 / 2.355, ), }, fixed={ "amplitude": ion_features["amps_fixed"][k], "mean": ion_features["x_0_fixed"][k], "stddev": ion_features["fwhms_fixed"][k], }, )) ions = sum(ions[1:], ions[0]) if self.model: self.model += ions else: self.model = ions # add additional att components to the model if necessary if not self.model: raise ValueError("No model components found") self.att_info = att_info if att_info is not None: for k in range(len(att_info["names"])): if ( att_info["names"][k] == "S07_att" ): # Only loop through att components that can be parameterized self.model *= S07_attenuation( name=att_info["names"][k], tau_sil=att_info["amps"][k], bounds={"tau_sil": att_info["amps_limits"][k]}, fixed={"tau_sil": att_info["amps_fixed"][k]}, ) else: self.model *= att_Drude1D( name=att_info["names"][k], tau=att_info["amps"][k], x_0=att_info["x_0"][k], fwhm=att_info["fwhms"][k], bounds={ "tau": att_info["amps_limits"][k], "fwhm": att_info["fwhms_limits"][k], }, fixed={"x_0": att_info["x_0_fixed"][k]}, )
return G(power) / (width * np.sqrt(np.pi) * G(power - 1 / 2)) def HWHM_moffat(width, power): return width * np.sqrt(2**(1 / power) - 1) x = np.arange(0, 10, 0.1) sigma = np.array([1, 2]) width = np.array([2, 5]) power = np.array([1.5, 2.5]) ax1 = plt.subplot(1, 2, 1) ax2 = plt.subplot(1, 2, 2) for s in sigma: gauss = Gaussian1D(amplitude=1, mean=0, stddev=s) ax1.plot(x, norm_gauss(s) * gauss(x), ls=":", label="sigma={0:.0f}, HWHM={1:.1f}".format(s, 2.355 * s / 2)) ax2.plot(x, -2.5 * np.log10(norm_gauss(s) * gauss(x)), ls=":", label="sigma={0:.0f}, HWHM={1:.1f}".format(s, 2.355 * s / 2)) for w in width: for p in power: moffat = Moffat1D(amplitude=1, x_0=0, gamma=w, alpha=p) HWHM = HWHM_moffat(w, p) ax1.plot(x, norm_moffat(w, p) * moffat(x),
def eqws(comp_type, x_0, amp, fwhm_stddev, obs_fit): """ Calculate the emission features equivalent width (integral[(I_nu-I_cont)/I_cont d_lam]) in microns. Parameters ---------- comp_type : string type of emission component (Drude1D/Gaussian) x_0 : float central wavelength of the feature. amp : float central intensity of the feature. fwhm_stddev : float fwhm or stddev of the feature depending on comp_type. Returns ------- eqw : float the equivalent width of the feature """ # Check if the emission component is Gaussian and calculate fwhm. if comp_type == 'Gaussian1D': fwhm = 2 * fwhm_stddev * np.sqrt(2 * np.log(2)) else: fwhm = fwhm_stddev # Get range and wavelength region for integration. low = x_0 - (fwhm * 6) lmin = low if low > 0 else 0. lmax = x_0 + (fwhm * 6) # lam = np.arange(100) / 99 * (lmax - lmin) + lmin lam = np.linspace(lmin, lmax, num=100) # Calculate the continuum and feature components in the integration range. cont_components = [] for cmodel in obs_fit: if isinstance(cmodel, BlackBody1D): cont_components.append(cmodel) cont_model = cont_components[0] for cmodel in cont_components[1:]: cont_model += cmodel continuum = np.nan_to_num(cont_model(lam)) if comp_type == 'Drude1D': drude = Drude1D(amplitude=amp, x_0=x_0, fwhm=fwhm) lnu = drude(lam) elif comp_type == 'Gaussian1D': gauss = Gaussian1D(amplitude=amp, mean=x_0, stddev=fwhm_stddev) lnu = gauss(lam) # Following the EQW calculation in IDL PAHFIT, we define a default broad limit (bl). # Set bl to replace the continuum in the EQW calculation # by its profile-averaged value for fractional FWHM greater than that limit. # Useful when the EQW requires extrapolation to regions where the continuum # can vanish, such that f_line/f_continuum diverges. # Default value bl = 0.05. bl = 0.05 # Calculate EQW. if fwhm / x_0 > bl: ilam = integrate.simpson(lnu, lam) weighted_cont = integrate.simpson(lnu * continuum, lam) / ilam eqw = ilam / weighted_cont else: eqw = integrate.simpson(lnu / continuum, lam) return eqw
def __init__(self, param_info=None, filename=None, tformat=None): """ Setup a variant based on inputs. Generates an astropy.modeling compound model. """ # check that param_info or filename is set if filename is None and param_info is None: raise ValueError('Either param_info or filename need to be set \ when initializing a PAHFITBase object') # read in the parameter info from a file if filename is not None: param_info = self.read(filename, tformat=tformat) bb_info = param_info[0] dust_features = param_info[1] h2_features = param_info[2] ion_features = param_info[3] att_info = param_info[4] # setup the model self.bb_info = bb_info if bb_info is not None: # 1st component defines the overall model variable self.model = BlackBody1D(name=bb_info['names'][0], temperature=bb_info['temps'][0], amplitude=bb_info['amps'][0], bounds={ 'temperature': bb_info['temps_limits'][0], 'amplitude': bb_info['amps_limits'][0] }, fixed={ 'temperature': bb_info['temps_fixed'][0], 'amplitude': bb_info['amps_fixed'][0] }) for k in range(1, len(bb_info['names'])): self.model += BlackBody1D(name=bb_info['names'][k], temperature=bb_info['temps'][k], amplitude=bb_info['amps'][k], bounds={ 'temperature': bb_info['temps_limits'][k], 'amplitude': bb_info['amps_limits'][k] }, fixed={ 'temperature': bb_info['temps_fixed'][k], 'amplitude': bb_info['amps_fixed'][k] }) self.dust_features = dust_features if dust_features is not None: for k in range(len(dust_features['names'])): self.model += Drude1D(name=dust_features['names'][k], amplitude=dust_features['amps'][k], x_0=dust_features['x_0'][k], fwhm=dust_features['fwhms'][k], bounds={ 'amplitude': dust_features['amps_limits'][k], 'x_0': dust_features['x_0_limits'][k], 'fwhm': dust_features['fwhms_limits'][k] }, fixed={ 'amplitude': dust_features['amps_fixed'][k], 'x_0': dust_features['x_0_fixed'][k], 'stddev': dust_features['fwhms_fixed'][k] }) self.h2_features = h2_features if h2_features is not None: for k in range(len(h2_features['names'])): self.model += Gaussian1D( name=h2_features['names'][k], amplitude=h2_features['amps'][k], mean=h2_features['x_0'][k], stddev=h2_features['fwhms'][k] / 2.355, bounds={ 'amplitude': h2_features['amps_limits'][k], 'mean': h2_features['x_0_limits'][k], 'stddev': (h2_features['fwhms_limits'][k][0] / 2.355, h2_features['fwhms_limits'][k][1] / 2.355) }, fixed={ 'amplitude': h2_features['amps_fixed'][k], 'mean': h2_features['x_0_fixed'][k], 'stddev': h2_features['fwhms_fixed'][k] }) self.ion_features = ion_features if ion_features is not None: for k in range(len(ion_features['names'])): self.model += Gaussian1D( name=ion_features['names'][k], amplitude=ion_features['amps'][k], mean=ion_features['x_0'][k], stddev=ion_features['fwhms'][k] / 2.355, bounds={ 'amplitude': ion_features['amps_limits'][k], 'mean': ion_features['x_0_limits'][k], 'stddev': (ion_features['fwhms_limits'][k][0] / 2.355, ion_features['fwhms_limits'][k][1] / 2.355) }, fixed={ 'amplitude': ion_features['amps_fixed'][k], 'mean': ion_features['x_0_fixed'][k], 'stddev': ion_features['fwhms_fixed'][k] }) # apply the attenuation to *all* the components self.model *= S07_attenuation( name=att_info['names'][0], tau_sil=att_info['amps'][0], bounds={'tau_sil': att_info['amps_limits'][0]}, fixed={'tau_sil': att_info['amps_fixed'][0]})
def __init__(self, obs_x, obs_y, estimate_start=False, param_info=None, filename=None, tformat=None): """ Setup a variant based on inputs. Generates an astropy.modeling compound model. """ # check that param_info or filename is set if filename is None and param_info is None: raise ValueError("Either param_info or filename need to be set \ when initializing a PAHFITBase object") # read in the parameter info from a file if filename is not None: param_info = self.read(filename, tformat=tformat) if estimate_start: # guess values and update starting point (if not set fixed) based on the input spectrum param_info = self.estimate_init(obs_x, obs_y, param_info) bb_info = param_info[0] dust_features = param_info[1] h2_features = param_info[2] ion_features = param_info[3] att_info = param_info[4] # setup the model self.bb_info = bb_info if bb_info is not None: # 1st component defines the overall model variable self.model = BlackBody1D( name=bb_info["names"][0], temperature=bb_info["temps"][0], amplitude=bb_info["amps"][0], bounds={ "temperature": bb_info["temps_limits"][0], "amplitude": bb_info["amps_limits"][0], }, fixed={ "temperature": bb_info["temps_fixed"][0], "amplitude": bb_info["amps_fixed"][0], }, ) for k in range(1, len(bb_info["names"])): self.model += BlackBody1D( name=bb_info["names"][k], temperature=bb_info["temps"][k], amplitude=bb_info["amps"][k], bounds={ "temperature": bb_info["temps_limits"][k], "amplitude": bb_info["amps_limits"][k], }, fixed={ "temperature": bb_info["temps_fixed"][k], "amplitude": bb_info["amps_fixed"][k], }, ) self.dust_features = dust_features if dust_features is not None: for k in range(len(dust_features["names"])): self.model += Drude1D( name=dust_features["names"][k], amplitude=dust_features["amps"][k], x_0=dust_features["x_0"][k], fwhm=dust_features["fwhms"][k], bounds={ "amplitude": dust_features["amps_limits"][k], "x_0": dust_features["x_0_limits"][k], "fwhm": dust_features["fwhms_limits"][k], }, fixed={ "amplitude": dust_features["amps_fixed"][k], "x_0": dust_features["x_0_fixed"][k], "fwhm": dust_features["fwhms_fixed"][k], }, ) self.h2_features = h2_features if h2_features is not None: for k in range(len(h2_features["names"])): self.model += Gaussian1D( name=h2_features["names"][k], amplitude=h2_features["amps"][k], mean=h2_features["x_0"][k], stddev=h2_features["fwhms"][k] / 2.355, bounds={ "amplitude": h2_features["amps_limits"][k], "mean": h2_features["x_0_limits"][k], "stddev": ( h2_features["fwhms_limits"][k][0] / 2.355, h2_features["fwhms_limits"][k][1] / 2.355, ), }, fixed={ "amplitude": h2_features["amps_fixed"][k], "mean": h2_features["x_0_fixed"][k], "stddev": h2_features["fwhms_fixed"][k], }, ) self.ion_features = ion_features if ion_features is not None: for k in range(len(ion_features["names"])): self.model += Gaussian1D( name=ion_features["names"][k], amplitude=ion_features["amps"][k], mean=ion_features["x_0"][k], stddev=ion_features["fwhms"][k] / 2.355, bounds={ "amplitude": ion_features["amps_limits"][k], "mean": ion_features["x_0_limits"][k], "stddev": ( ion_features["fwhms_limits"][k][0] / 2.355, ion_features["fwhms_limits"][k][1] / 2.355, ), }, fixed={ "amplitude": ion_features["amps_fixed"][k], "mean": ion_features["x_0_fixed"][k], "stddev": ion_features["fwhms_fixed"][k], }, ) # apply the attenuation to *all* the components self.model *= S07_attenuation( name=att_info["names"][0], tau_sil=att_info["amps"][0], bounds={"tau_sil": att_info["amps_limits"][0]}, fixed={"tau_sil": att_info["amps_fixed"][0]}, )
def norm_gauss(sigma): return 1 / np.sqrt(2 * np.pi * sigma**2) def norm_moffat(width, power): return G(power) / (width * np.sqrt(np.pi) * G(power - 1 / 2)) # 2 = 2*np.sqrt(2np.ln(2*sigma)) # 1 = np.ln(2*sigma) # np.e**1 = 2*sigma sigma = np.e / 2 x = np.arange(0, 8, 0.1) moffat = Moffat1D(amplitude=1, x_0=0, gamma=2, alpha=2.5) gauss = Gaussian1D(amplitude=sigma) sb.set_context('paper', font_scale=1.5) sb.lineplot(x=x, y=moffat(x) * norm_moffat(2, 2.5), label='Moffat, FWHM=2.2', linewidth=3, color='#870734') sb.lineplot(x=x, y=gauss(x) * norm_gauss(sigma), label='Gaussian, FWHM=2.2', linewidth=3, color='#ef473a') plt.xlabel('r') plt.ylabel('Probability') plt.savefig('gauss_vs_moffat.png', dpi=200)
def __init__(self, bb_info, dust_features, h2_features, ion_features): """ Setup a variant based on inputs. Generates an astropy.modeling compound model. Notes ----- Would be great to rename the parameters such that they uniquely identify the component (dust, gas, specific line, etc.). This is possible - say a discussion on the stsci slack channel - James Davies? """ model_comps = [] self.bb_info = bb_info if bb_info is not None: amps = bb_info['amps'] temps = bb_info['temps'] amps_limits = bb_info['amps_limits'] n_bb = len(amps) cont_model = BlackBody1D(temperature=temps[0], amplitude=amps[0], fixed={'temperature': True}) cont_model.amplitude.bounds = amps_limits[0] for k in range(1, n_bb): new_model = BlackBody1D(temperature=temps[k], amplitude=amps[k], fixed={'temperature': True}) new_model.amplitude.bounds = amps_limits[k] cont_model = cont_model + new_model self.cont_model = cont_model model_comps.append(cont_model) # dust features should be a Drude profile self.dust_features = dust_features if dust_features is not None: amps = dust_features['amps'] x_0 = dust_features['x_0'] fwhms = dust_features['fwhms'] amps_limits = dust_features['amps_limits'] x_0_limits = dust_features['x_0_limits'] fwhms_limits = dust_features['fwhms_limits'] n_df = len(amps) df_model = Drude1D(amplitude=amps[0], x_0=x_0[0], fwhm=fwhms[0], bounds={ 'amplitude': amps_limits[0], 'x_0': x_0_limits[0], 'fwhm': fwhms_limits[0] }) for k in range(1, n_df): df_model = df_model + Drude1D(amplitude=amps[k], x_0=x_0[k], fwhm=fwhms[k], bounds={ 'amplitude': amps_limits[k], 'x_0': x_0_limits[k], 'fwhm': fwhms_limits[k] }) self.df_model = df_model model_comps.append(df_model) self.h2_features = h2_features if h2_features is not None: amps = h2_features['amps'] x_0 = h2_features['x_0'] fwhms = h2_features['fwhms'] amps_limits = h2_features['amps_limits'] x_0_limits = h2_features['x_0_limits'] fwhms_limits = h2_features['fwhms_limits'] names = h2_features['names'] n_h2 = len(amps) h2_model = Gaussian1D(name=names[0], amplitude=amps[0], mean=x_0[0], stddev=fwhms[0] / 2.355, bounds={ 'amplitude': amps_limits[0], 'x_0': x_0_limits[0], 'stddev': (fwhms_limits[0][0] / 2.355, fwhms_limits[0][1] / 2.355) }) for k in range(1, n_h2): h2_model = h2_model + Gaussian1D( name=names[k], amplitude=amps[k], mean=x_0[k], stddev=fwhms[k] / 2.355, bounds={ 'amplitude': amps_limits[k], 'x_0': x_0_limits[k], 'stddev': (fwhms_limits[k][0] / 2.355, fwhms_limits[k][1] / 2.355) }) self.h2_model = h2_model model_comps.append(h2_model) self.ion_features = ion_features if ion_features is not None: amps = ion_features['amps'] x_0 = ion_features['x_0'] fwhms = ion_features['fwhms'] amps_limits = ion_features['amps_limits'] x_0_limits = ion_features['x_0_limits'] fwhms_limits = ion_features['fwhms_limits'] names = ion_features['names'] n_ion = len(amps) ion_model = Gaussian1D(name=names[0], amplitude=amps[0], mean=x_0[0], stddev=fwhms[0] / 2.355, bounds={ 'amplitude': amps_limits[0], 'x_0': x_0_limits[0], 'stddev': (fwhms_limits[0][0] / 2.355, fwhms_limits[0][1] / 2.355) }) for k in range(1, n_ion): ion_model = ion_model + Gaussian1D( name=names[k], amplitude=amps[k], mean=x_0[k], stddev=fwhms[k] / 2.355, bounds={ 'amplitude': amps_limits[k], 'x_0': x_0_limits[k], 'stddev': (fwhms_limits[k][0] / 2.355, fwhms_limits[k][1] / 2.355) }) self.ion_model = ion_model model_comps.append(ion_model) self.model = model_comps[0] for cmodel in model_comps[1:]: self.model += cmodel # need to make the type of attenuation model a passed variable self.model *= S07_attenuation()
def elo_explain_experiments(): # Coin toss steps = 100 np.random.seed(42) random_eval = np.random.choice([0, 1], steps) random_eval = [ sum(random_eval[:i+1] == 0)/len(random_eval[:i+1]) for i in range(len(random_eval)) ] # Run against itself saved = evaluate(['alpha-beta', 'alpha-beta'], 4, [3, 3], steps) std = np.array([saved[i].sigma for i in range(len(saved))]) mean = np.array([saved[i].mu for i in range(len(saved))]) x = np.arange(0, 50, 0.01) plt.figure() plt.plot(x, Gaussian1D(mean=25, stddev=8.333)(x), label='Initial value') plt.plot(x, Gaussian1D(mean=15, stddev=6)(x), label='Player 2, loss') plt.plot(x, Gaussian1D(mean=35, stddev=6)(x), label='Player 1, win') plt.xlabel('Rating Scale') plt.yticks([]) plt.axvline(15, c='gray', ls='dashed') plt.axvline(25, c='gray', ls='dashed') plt.axvline(35, c='gray', ls='dashed') plt.text(13.1, 0.8, '$\mu = 15$', rotation='vertical', c='k', alpha=0.4) plt.text(23.1, 0.8, '$\mu = 25$', rotation='vertical', c='k', alpha=0.4) plt.text(33.1, 0.8, '$\mu = 35$', rotation='vertical', c='k', alpha=0.4) plt.legend(loc=6) plt.tight_layout() plt.savefig('./output/ELO_explain1.pdf') plt.close() x = np.arange(-20, 50, 0.01) fig, ax1 = plt.subplots() ax1.plot(x, Gaussian1D(mean=10, stddev=10)(x), label='Diff. Gaussian') ax1.fill_between( np.arange(-20, 0, 0.01), Gaussian1D( mean=10, stddev=10 )(np.arange(-20, 0, 0.01)), color='blue', alpha=0.3 ) ax1.axvline(10, c='gray', ls='dashed') ax1.legend(loc=6) cum_gaus = np.cumsum(Gaussian1D(mean=10, stddev=10)(x)) ax2 = ax1.twinx() ax2.plot(x, cum_gaus/cum_gaus[-1], color='red', label='Cum. diff. Gaussian') ax2.legend(loc=5) ax2.set_ylabel("P(x)") ax1.set_ylabel('p(x) [unnormalized]') ax1.set_xlabel('x') fig.tight_layout() plt.savefig('./output/ELO_explain2.pdf') plt.close() indexing = np.arange(0, len(saved), 2) x = np.arange(steps) fig, ax1 = plt.subplots() fig.set_figwidth(10) fig.set_figheight(5) ax1.plot(random_eval, label='# of Heads in a Coin Flip') ax1.set_ylim(ymin=0, ymax=1) ax1.axhline(0.5, ls='dashed', c='gray') ax1.axvline(12, c='k', alpha=0.4) ax1.set_ylabel('p (Heads)') ax1.set_xlabel('Amount of Games') ax1.text(12.5, 0.02, 'Recommaned Cut-off', rotation='vertical', c='k', alpha=0.4) ax1.text(14.5, 0.02, 'by TrueSkill', rotation='vertical', c='k', alpha=0.4) ax1.legend(loc=1) ax2 = ax1.twinx() ax2.fill_between(x, y1=mean[indexing]-2 * std[indexing], y2=mean[indexing]+2 * std[indexing], color='orange', alpha=0.3, label='$2\sigma$ rating uncertainty') ax2.plot(mean[indexing], label='Alpha-Beta, depth = 3', c='orange', alpha=0.7) ax2.fill_between(x, y1=mean[indexing+1]-2 * std[indexing+1], y2=mean[indexing+1] + 2*std[indexing+1], color='red', alpha=0.3, label='$2\sigma$ rating uncertainty') ax2.plot(mean[indexing+1], label='Alpha-Beta, depth = 3', c='red', alpha=0.7) ax2.legend(loc=4) ax2.axvline(24, c='k', alpha=0.4) ax1.text(24.5, 0.02, 'Chosen Cut-off', rotation='vertical', c='k', alpha=0.4) fig.tight_layout() plt.savefig('./output/ELO_convergience.pdf') plt.close()