def guess(self, data, x=None, **kwargs): lm = LinearModel() y_slope = lm.eval(x=x, params=lm.guess(np.abs(data), x=x)) center, hwhm, height = guess_peak(np.abs(np.abs(data) - y_slope), x=x) pars = self.make_params(Ms=height, B_res=center, dB=hwhm) return pars
def fitting_math( self, xfile: List[str], yfile: List[str], flag: int = 1, ) -> Any: """PeakLogic.fitting_math() fits the data to a cosh and a gaussian, then subtracts the cosh to find peak current..""" try: center: float = self.app.peak_center_.get() x: "np.ndarray[Any, np.dtype[np.float64]]" = np.array( xfile, dtype=np.float64) y: "np.ndarray[Any, np.dtype[np.float64]]" = np.array( yfile, dtype=np.float64) # cut out outliers passingx: "np.ndarray[Any, np.dtype[np.float64]]" passingy: "np.ndarray[Any, np.dtype[np.float64]]" passingx, passingy = self.trunc_edges(xfile, yfile) rough_peak_positions = [min(passingx), center] min_y = float(min(passingy)) model = LinearModel(prefix="Background") params = model.make_params() # a=0, b=0, c=0 params.add("slope", 0, min=0) # params.add("b", 0, min=0) params.add("intercept", 0, min=min_y) for i, cen in enumerate(rough_peak_positions): peak, pars = self.add_lz_peak(f"Peak_{i+1}", cen) model = model + peak params.update(pars) _ = model.eval(params, x=passingx) result = model.fit(passingy, params, x=passingx) comps = result.eval_components() ip = float(max(comps["Peak_2"])) if flag == 1: return ip if flag == 0: return ( x, y, result.best_fit, comps["Background"], comps["Peak_1"], comps["Peak_2"], ip, passingx, ) except Exception: # pragma: no cover print("Error Fitting") print(sys.exc_info()) return -1
def replaceSpike(x, y, I): """ y = replaceSpike(x, y, I) Replace bad points in y by good ones. I is the index of bad points. Works by doing a linear fit over the data. """ mod = LinearModel() params = mod.guess(data=np.delete(y, I), x=np.delete(x, I)) # print(params) # print(np.delete(y, I)) result = mod.fit(np.delete(y, I), params, x=np.delete(x, I)) # print(result.fit_report()) # print(result.best_values) yy = mod.eval(x=x, slope=result.best_values['slope'], intercept=result.best_values['intercept']) y[I] = yy[I] return y
def guess_peak_lorentzian(data, x=None, **kwargs): y = np.abs(np.squeeze(np.real(data))) x = np.squeeze(x) idx = np.argsort(x) x = x[idx] y = y[idx] # prepare fitting a lorentzian m_lin = LinearModel() m_lorentzian = LorentzianModel() p_lin = m_lin.guess(y, x=x) p_lorentzian = m_lorentzian.guess(y - m_lin.eval(x=x, params=p_lin), x=x) m = m_lin + m_lorentzian p = p_lin + p_lorentzian r = m.fit(y, x=x, params=p) return (r.best_values["center"], r.best_values["sigma"], r.best_values["amplitude"] / (np.pi * r.best_values["sigma"]))
def measure_line_index_recover_spectrum(wave, params, norm=False): """ recover the fitted line profile from params Parameters ---------- wave: array-like the wavelength to which the recovered flux correspond params: 5-element tuple the 1 to 5 elements are: mod_linear_slope mod_linear_intercept mod_gauss_amplitude mod_gauss_center mod_gauss_sigma norm: bool if True, linear model (continuum) is deprecated else linear + Gaussian model is used """ from lmfit.models import LinearModel, GaussianModel mod_linear = LinearModel(prefix='mod_linear_') mod_gauss = GaussianModel(prefix='mod_gauss_') par_linear = mod_linear.make_params() par_gauss = mod_gauss.make_params() par_linear['mod_linear_slope'].value = params[0] par_linear['mod_linear_intercept'].value = params[1] par_gauss['mod_gauss_amplitude'].value = params[2] par_gauss['mod_gauss_center'].value = params[3] par_gauss['mod_gauss_sigma'].value = params[4] if not norm: flux = 1 - mod_gauss.eval(params=par_gauss, x=wave) else: flux = \ (1 - mod_gauss.eval(params=par_gauss, x=wave)) * \ mod_linear.eval(params=par_linear, x=wave) return flux
def measure_line_index(wave, flux, flux_err=None, mask=None, z=None, line_info=None, num_refit=(100, None), filepath=None, return_type='dict', verbose=False): """ Measure line index / EW and have it plotted Parameters ---------- wave: array-like wavelength vector flux: array-like flux vector flux_err: array-like flux error vector (optional) If un-specified, auto-generate an np.ones array mask: array-like andmask or ormask (optional) If un-specified, auto-generate an np.ones array (evenly weighted) line_info: dict information about spectral line, eg: line_info_dib5780 = {'line_center': 5780, 'line_range': (5775, 5785), 'line_shoulder_left': (5755, 5775), 'line_shoulder_right': (5805, 5825)} num_refit: non-negative integer number of refitting. If 0, no refit will be performed If positive, refits will be performed after adding normal random noise z: float redshift (only specify when z is large) filepath: string path of the diagnostic figure if None, do nothing, else print diagnostic figure return_type: string 'dict' or 'array' if 'array', np.array(return dict.values()) verbose: bool if True, print details Returns ------- line_indx: dict A dictionary type result of line index. If any problem encountered, return the default result (filled with nan). """ try: # 0. do some input check # 0.1> check line_info line_info_keys = line_info.keys() assert 'line_range' in line_info_keys assert 'line_shoulder_left' in line_info_keys assert 'line_shoulder_right' in line_info_keys # 0.2> check line range/shoulder in spectral range assert np.min(wave) <= line_info['line_shoulder_left'][0] assert np.max(wave) >= line_info['line_shoulder_right'][0] # 1. get line information # line_center = line_info['line_center'] # not used line_range = line_info['line_range'] line_shoulder_left = line_info['line_shoulder_left'] line_shoulder_right = line_info['line_shoulder_right'] # 2. shift spectra to rest-frame wave = np.array(wave) flux = np.array(flux) if z is not None: wave /= 1. + z # 3. estimate the local continuum # 3.1> shoulder wavelength range ind_shoulder = np.any([ np.all([wave > line_shoulder_left[0], wave < line_shoulder_left[1]], axis=0), np.all([wave > line_shoulder_right[0], wave < line_shoulder_right[1]], axis=0)], axis=0) wave_shoulder = wave[ind_shoulder] flux_shoulder = flux[ind_shoulder] # 3.2> integrated/fitted wavelength range ind_range = np.logical_and(wave > line_range[0], wave < line_range[1]) wave_range = wave[ind_range] flux_range = flux[ind_range] # flux_err_range = flux_err[ind_range] # not used mask_range = mask[ind_range] flux_err_shoulder = flux_err[ind_shoulder] # mask_shoulder = mask[ind_shoulder] # not used # 4. linear model mod_linear = LinearModel(prefix='mod_linear_') par_linear = mod_linear.guess(flux_shoulder, x=wave_shoulder) # ############################################# # # to see the parameter names: # # model_linear.param_names # # {'linear_fun_intercept', 'linear_fun_slope'} # # ############################################# # out_linear = mod_linear.fit(flux_shoulder, par_linear, x=wave_shoulder, method='leastsq') # 5. estimate continuum cont_shoulder = out_linear.best_fit noise_std = np.std(flux_shoulder / cont_shoulder) cont_range = mod_linear.eval(out_linear.params, x=wave_range) resi_range = 1 - flux_range / cont_range # 6.1 Integrated EW ( # estimate EW_int wave_diff = np.diff(wave_range) wave_step = np.mean(np.vstack([np.hstack([wave_diff[0], wave_diff]), np.hstack([wave_diff, wave_diff[-1]])]), axis=0) EW_int = np.dot(resi_range, wave_step) # estimate EW_int_err num_refit_ = num_refit[0] if num_refit_ is not None and num_refit_>0: EW_int_err = np.std(np.dot( (resi_range.reshape(1, -1).repeat(num_refit_, axis=0) + np.random.randn(num_refit_, resi_range.size) * noise_std), wave_step)) # 6.2 Gaussian model # estimate EW_fit mod_gauss = GaussianModel(prefix='mod_gauss_') par_gauss = mod_gauss.guess(resi_range, x=wave_range) out_gauss = mod_gauss.fit(resi_range, par_gauss, x=wave_range) line_indx = collections.OrderedDict([ ('SN_local_flux_err', np.median(flux_shoulder / flux_err_shoulder)), ('SN_local_flux_std', 1. / noise_std), ('num_bad_pixel', np.sum(mask_range != 0)), ('EW_int', EW_int), ('EW_int_err', EW_int_err), ('mod_linear_slope', out_linear.params[mod_linear.prefix + 'slope'].value), ('mod_linear_slope_err', out_linear.params[mod_linear.prefix + 'slope'].stderr), ('mod_linear_intercept', out_linear.params[mod_linear.prefix + 'intercept'].value), ('mod_linear_intercept_err', out_linear.params[mod_linear.prefix + 'intercept'].stderr), ('mod_gauss_amplitude', out_gauss.params[mod_gauss.prefix + 'amplitude'].value), ('mod_gauss_amplitude_err', out_gauss.params[mod_gauss.prefix + 'amplitude'].stderr), ('mod_gauss_center', out_gauss.params[mod_gauss.prefix + 'center'].value), ('mod_gauss_center_err', out_gauss.params[mod_gauss.prefix + 'center'].stderr), ('mod_gauss_sigma', out_gauss.params[mod_gauss.prefix + 'sigma'].value), ('mod_gauss_sigma_err', out_gauss.params[mod_gauss.prefix + 'sigma'].stderr), ('mod_gauss_amplitude_std', np.nan), ('mod_gauss_center_std', np.nan), ('mod_gauss_sigma_std', np.nan)]) # estimate EW_fit_err num_refit_ = num_refit[1] if num_refit_ is not None and num_refit_ > 2: # {'mod_gauss_amplitude', # 'mod_gauss_center', # 'mod_gauss_fwhm', # 'mod_gauss_sigma'} out_gauss_refit_amplitude = np.zeros(num_refit_) out_gauss_refit_center = np.zeros(num_refit_) out_gauss_refit_sigma = np.zeros(num_refit_) # noise_fit = np.random.randn(num_refit,resi_range.size)*noise_std for i in range(int(num_refit_)): # resi_range_with_noise = resi_range + noise_fit[i,:] resi_range_with_noise = resi_range + \ np.random.randn(resi_range.size) * noise_std out_gauss_refit = mod_gauss.fit(resi_range_with_noise, par_gauss, x=wave_range) out_gauss_refit_amplitude[i],\ out_gauss_refit_center[i],\ out_gauss_refit_sigma[i] =\ out_gauss_refit.params[mod_gauss.prefix + 'amplitude'].value,\ out_gauss_refit.params[mod_gauss.prefix + 'center'].value,\ out_gauss_refit.params[mod_gauss.prefix + 'sigma'].value print(out_gauss_refit_amplitude[i], out_gauss_refit_center[i], out_gauss_refit_sigma[i]) line_indx.update({'mod_gauss_amplitude_std': np.nanstd(out_gauss_refit_amplitude), 'mod_gauss_center_std': np.nanstd(out_gauss_refit_center), 'mod_gauss_sigma_std': np.nanstd(out_gauss_refit_sigma)}) # 7. plot and save image if filepath is not None and os.path.exists(os.path.dirname(filepath)): save_image_line_indice(filepath, wave, flux, ind_range, cont_range, ind_shoulder, line_info) # if necessary, convert to array # NOTE: for a non-ordered dict the order of keys and values may change! if return_type == 'array': return np.array(line_indx.values()) return line_indx except Exception: return measure_line_index_null_result(return_type)
plt.legend(loc='lower right') figname = fignamebase + '_viablecellconc.png' plt.savefig(figname, dpi=199) #plot semilog of viable cell concentration fig = plt.figure(3) viable_log = np.log(np.array(viable).astype(float)) mod = LinearModel() pars = mod.guess(viable_log[first_linearpoint:first_linearpoint + linearpoints], x=hours[first_linearpoint:first_linearpoint + linearpoints]) init = mod.eval(pars, x=hours[first_linearpoint:first_linearpoint + linearpoints]) out = mod.fit(viable_log[first_linearpoint:first_linearpoint + linearpoints], pars, x=hours[first_linearpoint:first_linearpoint + linearpoints]) slope = out.params['slope'].value intercept = out.params['intercept'].value y = slope * np.arange(-1, 10) + intercept doubling_time = int(np.log(2) / slope * 24) #doubling time in hours plt.plot(np.arange(-1, 10), y, 'r-', label='linear fit') plt.errorbar(hours, viable_log, yerr=viable_err / viable, label='viable cells', fmt='-o') plt.xlabel('days')
def taucplot(dataset, UV_folder="./AZO_2016_UV/", plot=False): """Fit tauc plot according to highest d_tauc/d_hv and a few points above and below. """ report_folder = UV_folder + "UV_fit/" if not os.path.exists(report_folder): os.makedirs(report_folder) ################ pull out variables from dataset ######################## run_no = dataset["run_no"] sub = dataset["sub"] data = dataset["data"] data = data[(data["hv"] > 3) & (data["hv"] < 4.5)] x = data["hv"] y = data["Tauc"] max_x = np.inf if run_no == "706" and sub == "C": max_x = 4 max_a = max(data["d_Tauc"][x < max_x]) mxi = data[data["d_Tauc"] == max_a].index.values[0] ################ Setup points to fit ##################################### xlim = 5 xliml = 2 if run_no in ["719", "720"]: xlim = 1 xliml = 1 points = data.loc[mxi - xliml:mxi + xlim, ["hv", "Tauc", "d_Tauc"]] px = np.array(points["hv"]) py = np.array(points["Tauc"]) ####Setup model and variables line = LinearModel() pars = line.guess(py, x=px) pars["slope"].set(value=max_a, vary=True) init = line.eval(pars, x=px) out = line.fit(py, pars, x=px) a = out.best_values["slope"] b = out.best_values["intercept"] bandgap = -b / a dataset.update({"t_bandgap": bandgap}) #################### plotting and recording results from fit #################### with open(report_folder + "UV_fit_%s%s.txt" % (run_no, sub), "w") as report_fh: report_fh.write(out.fit_report()) f, ax = plt.subplots(1, figsize=(4, 4)) ax.plot(x, y, label="data") ax.plot(px, init, color="k", ls="--", label="initial guess") ax.plot(x, a * x + b, color="r", label="best fit", lw=0.5) ax.legend(loc="lower right") ax.annotate("Bandgap: \n %1.3f eV" % bandgap, xy=(0.4, 0.4), xycoords='axes fraction', fontsize=16, horizontalalignment='right', verticalalignment='bottom') ax.set_ylim(0, max(data.loc[:, "Tauc"])) ax.set_xlim(3.2, 4.5) ax.set_ylabel(r"($\alpha$h$\nu$)$^2$", fontsize=16) ax.set_xlabel("(eV)", fontsize=16) f.suptitle("Tauc plot %s %s" % (run_no, sub), fontsize=16) f.savefig(report_folder + "Tauc_%s%s.png" % (run_no, sub), dpi=300, bbox_fit="tight") if plot == False: plt.close() else: plt.show()
def measure_line_index(wave, flux, flux_err=None, mask=None, z=None, line_info=None, num_refit=(100, None), filepath=None, return_type='dict', verbose=False): """ Measure line index / EW and have it plotted Parameters ---------- wave: array-like wavelength vector flux: array-like flux vector flux_err: array-like flux error vector (optional) If un-specified, auto-generate an np.ones array mask: array-like andmask or ormask (optional) If un-specified, auto-generate an np.ones array (evenly weighted) line_info: dict information about spectral line, eg: line_info_dib5780 = {'line_center': 5780, 'line_range': (5775, 5785), 'line_shoulder_left': (5755, 5775), 'line_shoulder_right': (5805, 5825)} num_refit: non-negative integer number of refitting. If 0, no refit will be performed If positive, refits will be performed after adding normal random noise z: float redshift (only specify when z is large) filepath: string path of the diagnostic figure if None, do nothing, else print diagnostic figure return_type: string 'dict' or 'array' if 'array', np.array(return dict.values()) verbose: bool if True, print details Returns ------- line_indx: dict A dictionary type result of line index. If any problem encountered, return the default result (filled with nan). """ try: # 0. do some input check # 0.1> check line_info line_info_keys = line_info.keys() assert 'line_range' in line_info_keys assert 'line_shoulder_left' in line_info_keys assert 'line_shoulder_right' in line_info_keys # 0.2> check line range/shoulder in spectral range assert np.min(wave) <= line_info['line_shoulder_left'][0] assert np.max(wave) >= line_info['line_shoulder_right'][0] # 1. get line information # line_center = line_info['line_center'] # not used line_range = line_info['line_range'] line_shoulder_left = line_info['line_shoulder_left'] line_shoulder_right = line_info['line_shoulder_right'] # 2. data preparation # 2.1> shift spectra to rest-frame wave = np.array(wave) flux = np.array(flux) if z is not None: wave /= 1. + z # 2.2> generate flux_err and mask if un-specified if flux_err == None: flux_err = np.ones(wave.shape) if mask == None: mask = np.zeros(wave.shape) mask_ = np.zeros(wave.shape) ind_mask = np.all([mask != 0], axis=0) mask_[ind_mask] = 1 mask = mask_ # 3. estimate the local continuum # 3.1> shoulder wavelength range ind_shoulder = np.any([ np.all( [wave > line_shoulder_left[0], wave < line_shoulder_left[1]], axis=0), np.all( [wave > line_shoulder_right[0], wave < line_shoulder_right[1]], axis=0) ], axis=0) wave_shoulder = wave[ind_shoulder] flux_shoulder = flux[ind_shoulder] # 3.2> integrated/fitted wavelength range ind_range = np.logical_and(wave > line_range[0], wave < line_range[1]) wave_range = wave[ind_range] flux_range = flux[ind_range] # flux_err_range = flux_err[ind_range] # not used mask_range = mask[ind_range] flux_err_shoulder = flux_err[ind_shoulder] # mask_shoulder = mask[ind_shoulder] # not used # 4. linear model mod_linear = LinearModel(prefix='mod_linear_') par_linear = mod_linear.guess(flux_shoulder, x=wave_shoulder) # ############################################# # # to see the parameter names: # # model_linear.param_names # # {'linear_fun_intercept', 'linear_fun_slope'} # # ############################################# # out_linear = mod_linear.fit(flux_shoulder, par_linear, x=wave_shoulder, method='leastsq') # 5. estimate continuum cont_shoulder = out_linear.best_fit noise_std = np.std(flux_shoulder / cont_shoulder) cont_range = mod_linear.eval(out_linear.params, x=wave_range) resi_range = 1 - flux_range / cont_range # 6.1 Integrated EW ( # estimate EW_int wave_diff = np.diff(wave_range) wave_step = np.mean(np.vstack([ np.hstack([wave_diff[0], wave_diff]), np.hstack([wave_diff, wave_diff[-1]]) ]), axis=0) EW_int = np.dot(resi_range, wave_step) # estimate EW_int_err num_refit_ = num_refit[0] if num_refit_ is not None and num_refit_ > 0: EW_int_err = np.std( np.dot( (resi_range.reshape(1, -1).repeat(num_refit_, axis=0) + np.random.randn(num_refit_, resi_range.size) * noise_std), wave_step)) # 6.2 Gaussian model # estimate EW_fit mod_gauss = GaussianModel(prefix='mod_gauss_') par_gauss = mod_gauss.guess(resi_range, x=wave_range) out_gauss = mod_gauss.fit(resi_range, par_gauss, x=wave_range) line_indx = collections.OrderedDict([ ('SN_local_flux_err', np.median(flux_shoulder / flux_err_shoulder)), ('SN_local_flux_std', 1. / noise_std), ('num_bad_pixel', np.sum(mask_range != 0)), ('EW_int', EW_int), ('EW_int_err', EW_int_err), ('mod_linear_slope', out_linear.params[mod_linear.prefix + 'slope'].value), ('mod_linear_slope_err', out_linear.params[mod_linear.prefix + 'slope'].stderr), ('mod_linear_intercept', out_linear.params[mod_linear.prefix + 'intercept'].value), ('mod_linear_intercept_err', out_linear.params[mod_linear.prefix + 'intercept'].stderr), ('mod_gauss_amplitude', out_gauss.params[mod_gauss.prefix + 'amplitude'].value), ('mod_gauss_amplitude_err', out_gauss.params[mod_gauss.prefix + 'amplitude'].stderr), ('mod_gauss_center', out_gauss.params[mod_gauss.prefix + 'center'].value), ('mod_gauss_center_err', out_gauss.params[mod_gauss.prefix + 'center'].stderr), ('mod_gauss_sigma', out_gauss.params[mod_gauss.prefix + 'sigma'].value), ('mod_gauss_sigma_err', out_gauss.params[mod_gauss.prefix + 'sigma'].stderr), ('mod_gauss_amplitude_std', np.nan), ('mod_gauss_center_std', np.nan), ('mod_gauss_sigma_std', np.nan) ]) # estimate EW_fit_err num_refit_ = num_refit[1] if num_refit_ is not None and num_refit_ > 2: # {'mod_gauss_amplitude', # 'mod_gauss_center', # 'mod_gauss_fwhm', # 'mod_gauss_sigma'} out_gauss_refit_amplitude = np.zeros(num_refit_) out_gauss_refit_center = np.zeros(num_refit_) out_gauss_refit_sigma = np.zeros(num_refit_) # noise_fit = np.random.randn(num_refit,resi_range.size)*noise_std for i in range(int(num_refit_)): # resi_range_with_noise = resi_range + noise_fit[i,:] resi_range_with_noise = resi_range + \ np.random.randn(resi_range.size) * noise_std out_gauss_refit = mod_gauss.fit(resi_range_with_noise, par_gauss, x=wave_range) out_gauss_refit_amplitude[i],\ out_gauss_refit_center[i],\ out_gauss_refit_sigma[i] =\ out_gauss_refit.params[mod_gauss.prefix + 'amplitude'].value,\ out_gauss_refit.params[mod_gauss.prefix + 'center'].value,\ out_gauss_refit.params[mod_gauss.prefix + 'sigma'].value print(out_gauss_refit_amplitude[i], out_gauss_refit_center[i], out_gauss_refit_sigma[i]) line_indx.update([ ('mod_gauss_amplitude_std', np.nanstd(out_gauss_refit_amplitude)), ('mod_gauss_center_std', np.nanstd(out_gauss_refit_center)), ('mod_gauss_sigma_std', np.nanstd(out_gauss_refit_sigma)) ]) # 7. plot and save image if filepath is not None and os.path.exists(os.path.dirname(filepath)): save_image_line_indice(filepath, wave, flux, ind_range, cont_range, ind_shoulder, line_info) # if necessary, convert to array # NOTE: for a non-ordered dict the order of keys and values may change! if return_type == 'array': return np.array(line_indx.values()) return line_indx except Exception: return measure_line_index_null_result(return_type)
def analyse_vi_curve( current_bias: np.ndarray, measured_voltage: np.ndarray, ic_voltage_threshold: float, high_bias_threshold: float, debug: bool = False, ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray, np.ndarray]: """Extract the critical and excess current along with the normal resistance. All values are extracted for cold and hot electrons. The cold side is the one on which the bias is ramped from 0 to large value, the hot one the one on which bias is ramped towards 0. Parameters ---------- current_bias : np.ndarray N+1D array of the current bias applied on the junction in A. measured_voltage : np.ndarray N+1D array of the voltage accross the junction in V. ic_voltage_threshold : float Voltage threshold in V above which the junction is not considered to carry a supercurrent anymore. Used in the determination of the critical current. high_bias_threshold : float Positive bias value above which the data can be used to extract the normal resistance. debug : bool, optional Generate summary plots of the fitting. Returns ------- voltage_offset_correction : np.ndarray Offset used to correct the measured voltage. ND array rn_c : np.ndarray Normal resistance evaluated on the cold electron side. ND array rn_h : np.ndarray Normal resistance evaluated on the hot electron side. ND array ic_c : np.ndarray Critical current evaluated on the cold electron side. ND array ic_h : np.ndarray Critical current evaluated on the hot electron side. ND array iexe_c : np.ndarray Excess current evaluated on the cold electron side. ND array iexe_h : np.ndarray Excess current evaluated on the hot electron side. ND array """ ic_c = np.empty(current_bias.shape[:-1]) ic_h = np.empty(current_bias.shape[:-1]) rn_c = np.empty(current_bias.shape[:-1]) rn_h = np.empty(current_bias.shape[:-1]) ie_c = np.empty(current_bias.shape[:-1]) ie_h = np.empty(current_bias.shape[:-1]) # Iterate on additional dimensions it = np.nditer(current_bias[..., 0], ["multi_index"]) for b in it: m_index = it.multi_index # Extract the relevant sweeps. cb = current_bias[m_index] mv = measured_voltage[m_index] # Determine the hot and cold electron side if cb[0] < 0.0: cold_value = lambda p, n: abs(p) hot_value = lambda p, n: abs(n) else: cold_value = lambda p, n: abs(n) hot_value = lambda p, n: abs(p) # Sort the data so that the bias always go from negative to positive sorting_index = np.argsort(cb) cb = cb[sorting_index] mv = mv[sorting_index] # Index at which the bias current is zero index = np.argmin(np.abs(cb)) # Extract the critical current on the positive and negative branch ic_n = cb[np.max( np.where(np.less(mv[:index], -ic_voltage_threshold))[0])] ic_p = cb[ np.min(np.where(np.greater(mv[index:], ic_voltage_threshold))[0]) + index] # Fit the high positive/negative bias to extract the normal resistance # excess current and their product index_pos = np.argmin(np.abs(cb - high_bias_threshold)) index_neg = np.argmin(np.abs(cb + high_bias_threshold)) model = LinearModel() pars = model.guess(mv[index_pos:], x=cb[index_pos:]) pos_results = model.fit(mv[index_pos:], pars, x=cb[index_pos:]) pars = model.guess(mv[index_neg:], x=cb[index_neg:]) neg_results = model.fit(mv[:index_neg], pars, x=cb[:index_neg]) rn_p = pos_results.best_values["slope"] # Iexe p iexe_p = -pos_results.best_values["intercept"] / rn_p rn_n = neg_results.best_values["slope"] # Iexe n iexe_n = neg_results.best_values["intercept"] / rn_n if debug: # Prepare a summary plot: full scale fig = plt.figure(constrained_layout=True) ax = fig.gca() ax.plot(cb * 1e6, mv * 1e3) ax.plot( cb[index:] * 1e6, model.eval(pos_results.params, x=cb[index:]) * 1e3, "--k", ) ax.plot( cb[:index + 1] * 1e6, model.eval(neg_results.params, x=cb[:index + 1]) * 1e3, "--k", ) ax.set_xlabel("Bias current (µA)") ax.set_ylabel("Voltage drop (mV)") # Prepare a summary plot: zoomed in mask = np.logical_and(np.greater(cb, -3 * ic_p), np.less(cb, 3 * ic_p)) if np.any(mask): fig = plt.figure(constrained_layout=True) ax = fig.gca() ax.plot(cb * 1e6, mv * 1e3) aux = model.eval(pos_results.params, x=cb[index:]) * 1e3 ax.plot( cb[index:] * 1e6, model.eval(pos_results.params, x=cb[index:]) * 1e3, "--", ) ax.plot( cb[:index + 1] * 1e6, model.eval(neg_results.params, x=cb[:index + 1]) * 1e3, "--", ) ax.set_xlim(( -3 * cold_value(ic_p, ic_n) * 1e6, 3 * cold_value(ic_p, ic_n) * 1e6, )) aux = mv[mask] ax.set_ylim(( np.min(mv[mask]) * 1e3, np.max(mv[mask]) * 1e3, )) ax.set_xlabel("Bias current (µA)") ax.set_ylabel("Voltage drop (mV)") plt.show() rn_c[m_index] = cold_value(rn_p, rn_n) rn_h[m_index] = hot_value(rn_p, rn_n) ic_c[m_index] = cold_value(ic_p, ic_n) ic_h[m_index] = hot_value(ic_p, ic_n) ie_c[m_index] = cold_value(iexe_p, iexe_n) ie_h[m_index] = hot_value(iexe_p, iexe_n) return (rn_c, rn_h, ic_c, ic_h, ie_c, ie_h)
#x = usefulProtons[sample]/camTime[sample] protonsOnCup[sample] = camCharge[sample]/constants.e x = protonsOnCup[sample]/camTime[sample] y = sampleGausVol[sample]/camTime[sample] p = ax.plot(x,y,linestyle = 'None',marker='o',alpha=0.2) color = p[0].get_color() colors[sample] = color guesses = mod.guess(y, x=x) fitResult = mod.fit(y, guesses, x=x) slope = fitResult.best_values['slope'] slopes[sample] = slope y2 = fitResult.best_fit ax.plot(x,y2,color,label=sample) x_mid = (x.max() + x.min())/2 y_mid = mod.eval(x=x_mid,**fitResult.best_values) xp2 = x.max() yp2 = mod.eval(x=xp2,**fitResult.best_values) pa[sample] = (x_mid,y_mid) pb[sample] = (xp2,yp2) ax.set_xlabel('Proton Flux Into Cup [proton/s]') ax.set_ylabel('Estimated Total Photon Generation [photon/s]') # this is the volume under the gaussian fit ax.set_title('Photons per Proton'+'|'+session) ax.legend() ax.grid() fig.tight_layout() # annotate the plot with text on the lines now
def measure_line_index(wave, flux, flux_err=None, line_info=None, num_refit_=100, plotfig=False): if line_info == None: # He II 4686 line_info = { 'line_range': (4666, 4706), 'line_shoulder_left': (4545, 4620), 'line_shoulder_right': (4726, 4800) } try: # 0. do some input check # 0.1> check line_info line_info_keys = line_info.keys() assert 'line_range' in line_info_keys assert 'line_shoulder_left' in line_info_keys assert 'line_shoulder_right' in line_info_keys # 0.2> check line range/shoulder in spectral range assert np.min(wave) <= line_info['line_shoulder_left'][0] assert np.max(wave) >= line_info['line_shoulder_right'][0] # 1. get line information # line_center = line_info['line_center'] # not used line_range = line_info['line_range'] line_shoulder_left = line_info['line_shoulder_left'] line_shoulder_right = line_info['line_shoulder_right'] # 2. data preparation wave = np.array(wave) flux = np.array(flux) if flux_err == None: flux_err = np.ones(wave.shape) # 3. estimate the local continuum # 3.1> shoulder wavelength range ind_shoulder = np.any([ np.all( [wave > line_shoulder_left[0], wave < line_shoulder_left[1]], axis=0), np.all( [wave > line_shoulder_right[0], wave < line_shoulder_right[1]], axis=0) ], axis=0) wave_shoulder = wave[ind_shoulder] flux_shoulder = flux[ind_shoulder] flux_err_shoulder = flux_err[ind_shoulder] # 3.2> integrated/fitted wavelength range ind_range = np.logical_and(wave > line_range[0], wave < line_range[1]) wave_range = wave[ind_range] flux_range = flux[ind_range] # flux_err_range = flux_err[ind_range] # not used # mask_shoulder = mask[ind_shoulder] # not used # 4. linear model mod_linear = LinearModel(prefix='mod_linear_') par_linear = mod_linear.guess(flux_shoulder, x=wave_shoulder) # ############################################# # # to see the parameter names: # # model_linear.param_names # # {'linear_fun_intercept', 'linear_fun_slope'} # # ############################################# # out_linear = mod_linear.fit(flux_shoulder, par_linear, x=wave_shoulder, method='leastsq') # 5. estimate continuum cont_shoulder = out_linear.best_fit noise_std = np.std(flux_shoulder / cont_shoulder) cont_range = mod_linear.eval(out_linear.params, x=wave_range) resi_range = 1 - flux_range / cont_range if plotfig == True: plt.figure(figsize=(6, 4)) ix = (wave > line_shoulder_left[0]) & ( (wave < line_shoulder_right[1])) plt.plot(wave[ix], flux[ix], color="k", alpha=0.1) plt.plot(wave_shoulder, flux_shoulder, 'b-') plt.plot(wave_range, cont_range, 'g-') plt.plot(wave_range, flux_range, 'r-') # 6.1 Integrated EW ( # estimate EW_int wave_diff = np.diff(wave_range) wave_step = np.mean(np.vstack([ np.hstack([wave_diff[0], wave_diff]), np.hstack([wave_diff, wave_diff[-1]]) ]), axis=0) EW_int = np.dot(resi_range, wave_step) # estimate EW_int_err if num_refit_ is not None and num_refit_ > 0: EW_int_err = np.std( np.dot( (resi_range.reshape(1, -1).repeat(num_refit_, axis=0) + np.random.randn(num_refit_, resi_range.size) * noise_std), wave_step)) # 6.2 Gaussian model # estimate EW_fit line_indx = collections.OrderedDict([ ('SN_local_flux_err', np.median(flux_shoulder / flux_err_shoulder)), ('SN_local_flux_std', 1. / noise_std), ('EW_int', EW_int), ('EW_int_err', EW_int_err), ('mod_linear_slope', out_linear.params[mod_linear.prefix + 'slope'].value), ('mod_linear_slope_err', out_linear.params[mod_linear.prefix + 'slope'].stderr), ('mod_linear_intercept', out_linear.params[mod_linear.prefix + 'intercept'].value), ('mod_linear_intercept_err', out_linear.params[mod_linear.prefix + 'intercept'].stderr) ]) return line_indx except Exception: print("Some error happened...?")
def measure_abs_velocity(wave, flux, line_info=None, sigma_guess=2000, line_center=-6500, line_bound_width=1000, plotfig=False): if line_info == None: # He I 5875 line_info = { 'line_shoulder_left': (-12600, -9800), 'line_shoulder_right': (-1300, 1800), 'line_fit': (-8000, -3500) } line_shoulder_left = line_info['line_shoulder_left'] line_shoulder_right = line_info['line_shoulder_right'] line_range = (line_shoulder_left[1], line_shoulder_right[0]) line_fit = line_info["line_fit"] ind_shoulder = np.any([ np.all([wave > line_shoulder_left[0], wave < line_shoulder_left[1]], axis=0), np.all([wave > line_shoulder_right[0], wave < line_shoulder_right[1]], axis=0) ], axis=0) wave_shoulder = wave[ind_shoulder] flux_shoulder = flux[ind_shoulder] ind_range = np.logical_and(wave > line_range[0], wave < line_range[1]) wave_range = wave[ind_range] flux_range = flux[ind_range] ind_fit = np.logical_and(wave > line_fit[0], wave < line_fit[1]) wave_fit = wave[ind_fit] flux_fit = flux[ind_fit] mod_linear = LinearModel(prefix='mod_linear_') par_linear = mod_linear.guess(flux_shoulder, x=wave_shoulder) out_linear = mod_linear.fit(flux_shoulder, par_linear, x=wave_shoulder, method='leastsq') cont_shoulder = out_linear.best_fit noise_std = np.std(flux_shoulder / cont_shoulder) cont_range = mod_linear.eval(out_linear.params, x=wave_range) cont_fit = mod_linear.eval(out_linear.params, x=wave_fit) norm_fit = (flux_fit / cont_fit - 1.) * (-1) a_fixed = 0. a_width = 0.05 A_guess = max(norm_fit) - a_fixed bounds = ((a_fixed - a_width, 0.2 * A_guess, line_center - line_bound_width * 2, sigma_guess / 5), (a_fixed + a_width, 5 * A_guess, line_center + line_bound_width * 2, sigma_guess * 5)) popt1, pcov1 = curve_fit(gaus, wave_fit, norm_fit, p0=[a_fixed, A_guess, line_center, sigma_guess], bounds=bounds) print("line width = %.2f +- %.2f km/s" % (popt1[-1], np.sqrt(pcov1[-1, -1]))) print("line center = %.2f +- %.2f km/s" % (popt1[2], np.sqrt(pcov1[2, 2]))) line_center = popt1[2] new_width = popt1[-1] * 4 # four times the sigma wvnew = np.linspace(line_center - new_width, line_center + new_width, 300) flnew = gaus(wvnew, *popt1) if plotfig == True: plt.figure(figsize=(6, 6)) ax1 = plt.subplot(211) ax1.plot(wave_shoulder, flux_shoulder, 'b-') ax1.plot(wave_range, cont_range, 'g-') ax1.plot(wave_range, flux_range, 'r-', alpha=0.2) ax1.plot(wave_fit, flux_fit, 'r-') ax2 = plt.subplot(212) ax2.plot(wave_fit, norm_fit, 'k-') ax2.plot(wvnew, flnew) a_fixed = min(flux_fit) A_guess = (max(flux_fit) - min(flux_fit)) / 2000**2 bounds = ((a_fixed - a_width, 0.2 * A_guess, line_center - line_bound_width * 2), (a_fixed + a_width, 5 * A_guess, line_center + line_bound_width * 2)) popt1, pcov1 = curve_fit(parabola, wave_fit, flux_fit, p0=[a_fixed, A_guess, line_center], bounds=bounds) print("line center = %.2f +- %.2f km/s" % (popt1[2], np.sqrt(pcov1[2, 2]))) line_center = popt1[2]