예제 #1
0
    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
예제 #2
0
    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
예제 #3
0
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
예제 #4
0
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"]))
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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)
예제 #8
0
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')
예제 #9
0
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()
예제 #10
0
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)
예제 #11
0
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)
예제 #12
0
   #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
예제 #13
0
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...?")
예제 #14
0
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]