def find_bad_holes(res_c, n_holes, bl2h_ix, bmax=6, verbose=False, display=False): """ Find bad apertures using a linear fit of the v2 vs. spatial frequencies. Parameters ---------- `res_c` : {class} Class containing NRM data of the calibrator (bispect.py),\n `n_holes` : {int} Number of apertures,\n `bl2h_ix` : {array} Baselines to apertures (holes) indices,\n `bmax` : {int}, optional Maximum baseline used to plot the fit, by default 6,\n `verbose` : {bool}, optional If True, print useful informations , by default False,\n `display` : {bool}, optional If True, display figures, by default False. Returns ------- `bad_holes`: {array} List of determined bad holes, """ u = res_c.u/res_c.wl v = res_c.v/res_c.wl X = np.sqrt(u**2+v**2) Y = np.log(res_c.v2) param = {'a': 1, 'b': 0} fit = leastsqFit(linear, X, param, Y, verbose=verbose) xm = np.linspace(0, bmax, 100)/res_c.wl ym = linear(xm, fit['best']) pfit = list(fit['best'].values()) if display: plt.figure() plt.plot(X/1e6, Y, '.', label='data') plt.plot(xm/1e6, ym, '--', label='fit (a=%2.1e, b=%2.2f)' % (pfit[0], pfit[1])) plt.grid(alpha=.1) plt.legend() plt.xlim(0, xm.max()/1e6) plt.ylabel(r'$\log(V^2)$ (calibrator)') plt.xlabel(r'Sp. Freq. [M$\lambda$]') plt.tight_layout() bad_holes = [] for j in range(n_holes): pass w = np.where((bl2h_ix[0, :] == j) | (bl2h_ix[1, :] == j)) if (np.mean(res_c.v2[w]/np.exp(fit['model'][w]))) <= 0.3: bad_holes.append(j) bad_holes = np.unique(bad_holes) return bad_holes
def find_bad_holes(bs, bmax=6, verbose=False, display=False): """Find bad apertures using a linear fit of the v2 vs. spatial frequencies. Parameters ---------- `bs` : {class} Class containing NRM data (bispect.py),\n `bmax` : {int}, optional Maximum baseline used to plot the fit, by default 6,\n `verbose` : {bool}, optional If True, print useful informations , by default False,\n `display` : {bool}, optional If True, display figures, by default False. Returns ------- `bad_holes`: {array} List of determined bad holes, """ u = bs.u / bs.wl v = bs.v / bs.wl X = np.sqrt(u**2 + v**2) Y = np.log(bs.vis2) n_holes = bs.mask.n_holes bl2h_ix = bs.mask.bl2h_ix param = {"a": 1, "b": 0} fit = leastsqFit(linear, X, param, Y, verbose=verbose) xm = np.linspace(0, bmax, 100) / bs.wl ym = linear(xm, fit["best"]) pfit = list(fit["best"].values()) if display: plt.figure() plt.plot(X / 1e6, Y, ".", label="data") plt.plot(xm / 1e6, ym, "--", label=f"fit (a={pfit[0]:2.1e}, b={pfit[1]:2.2f})") plt.grid(alpha=0.1) plt.legend() plt.xlim(0, xm.max() / 1e6) plt.ylabel(r"$\log(V^2)$ (calibrator)") plt.xlabel(r"Sp. Freq. [M$\lambda$]") plt.tight_layout() bad_holes = [] for j in range(n_holes): w = np.where((bl2h_ix[0, :] == j) | (bl2h_ix[1, :] == j)) if (np.mean(bs.vis2[w] / np.exp(fit["model"][w]))) <= 0.3: bad_holes.append(j) bad_holes = np.unique(bad_holes) return bad_holes
def _calc_correction_atm_vis2(data, corr_const=1, nf=100, display=False, verbose=False, normalizedUncer=False): """ This function corrects V^2 for seeing and windshake. Use this on source and cal before division. Returns a multiplicative correction to the V^2. Parameters: ----------- `data` {class}: class like containting results from extract_bs function, `corr_const` {float}: Correction constant (0.4 is good for V for NIRC experiment). Returns: -------- `correction` {array}: Correction factor to apply. """ vis = data.vis2 avar = data.matrix.avar u = data.u v = data.v err_avar = data.matrix.err_avar err_vis = data.e_vis2 w = np.where((vis == 0) | (avar == 0)) if len(w) == 0: print('Cannot continue - divide by zero imminent...') correction = None normvar = avar / vis**2 w0 = np.where(u**2 + v**2 >= 0) param = {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0} if (len(err_avar) == 0): err_avar = normvar * 2.0 / np.sqrt(nf) if (len(err_vis) != 0): err_avar = abs(normvar) * np.sqrt(err_avar**2 / avar**2 + 2.0 * err_vis**2 / vis**2) X = [u[w0], v[w0]] fit = leastsqFit(_v2varfunc, X, param, normvar[w0], err_avar[w0], verbose=verbose, normalizedUncer=normalizedUncer) correction = np.ones(vis.shape) correction[w0] = np.exp(fit['model'] * corr_const) if display: plt.figure() plt.errorbar((X[0]**2 + X[1]**2)**0.5, normvar[w0], yerr=err_avar[w0], ls='None', ecolor='lightgray', marker='.', label='data') plt.plot((X[0]**2 + X[1]**2)**0.5, fit['model'], 'rs') plt.show(block=False) return correction
def smartfit( obs, first_guess, doNotFit=None, fitOnly=None, follow=None, multiproc=False, ftol=1e-4, epsfcn=1e-7, normalizeErrors=False, scale_err=1, fitCP=True, onlyCP=False, verbose=True, ): """ Perform the fit of V2 and CP data contained in the obs tuple. Parameters: ----------- obs: {tuple} Tuple containing all the selected data fromOiClass2Obs function.\n first_guess: {dict} Parameters of the model.\n fitOnly: {list} fitOnly is a LIST of keywords to fit. By default, it fits all parameters in 'first_guess'.\n follow: {list} List of parameters to "follow" in the fit, i.e. to print in verbose mode.\n multiproc: {boolean} If True, use ModelM to compute the model with pool (12 cores by default).\n normalizeErrors: {boolean} If True, give the same weight for the V2 and CP data (even if only few CP compare to V2).\n fitCP: {boolean} If True, fit the CP data. If not fit only the V2 data.\n """ save_obs = obs.copy() if onlyCP: cond = save_obs[:, 1] == "CP" obs = save_obs[cond] if not fitCP and not onlyCP: cond = save_obs[:, 1] == "V2" obs = save_obs[cond] errs = [o[-1] for o in obs] if normalizeErrors: errs = _normalize_err_obs(obs, verbose=False) # -- avoid fitting string parameters tmp = list(filter(lambda x: isinstance(first_guess[x], str), first_guess.keys())) if len(tmp) > 0: if doNotFit is None: doNotFit = tmp else: doNotFit.extend(tmp) try: fitOnly = list( filter(lambda x: not isinstance(first_guess[x], str), fitOnly) ) except Exception: pass if multiproc: M = model_parallelized else: M = model_standard lfit = leastsqFit( M, obs, first_guess, [o[2] for o in obs], err=np.array(errs) * scale_err, doNotFit=doNotFit, fitOnly=fitOnly, follow=follow, normalizedUncer=False, verbose=verbose, ftol=ftol, epsfcn=epsfcn, ) return lfit