Esempio n. 1
0
def multifit_std_err_scale_analysis(folder, file):
    # fig, axes = plt.subplots(2, 1, sharex='all', sharey='all')
    magopter = Magopter(folder, file, ts_filename=ts_file)
    magopter.prepare(down_sampling_rate=1, roi_b_plasma=True, crit_freq=4000, crit_ampl=None)

    index = int(0.5 * len(magopter.iv_arrs[0]))
    scales = np.arange(0.5, 1.2, 0.05)
    chis = np.zeros_like(scales)

    plt.figure()

    for i, fitter in enumerate([f.SimpleIVFitter(), f.FullIVFitter()]):
        raw_iv_data = magopter.iv_arrs[0][index].copy()
        sigma = raw_iv_data[c.SIGMA]

        for j, scaler in enumerate(scales):
            raw_iv_data[c.SIGMA] = sigma * scaler
            fitdata = raw_iv_data.multi_fit(iv_fitter=fitter)
            print('Sigma * {}'.format(scaler))
            fitdata.print_fit_params()
            chis[j] = fitdata.reduced_chi2

        plt.plot(scales, chis, label=fitter.name)
    plt.axhline(y=1.0, color='black', linewidth=1)
    plt.xlabel('$\delta I$ ($\sigma$)')
    plt.ylabel(r'Reduced $\chi^2$')
    plt.legend()
Esempio n. 2
0
def analyse_small_probe(ds_full, probe_designation, output_tag, sweep_range):
    # Select the small probe
    ds_full = ds_full.sel(probe=probe_designation)

    manual_start = sweep_range[0]
    manual_end = sweep_range[1]
    plt.figure()
    ds_full.max(dim='time').mean('direction')['current'].plot.line(x='sweep')
    ds_full.max(dim='time').mean('direction').isel(sweep=slice(manual_start, manual_end))['current'].plot.line(
        x='sweep')
    plt.savefig(f'{output_tag}_shot.png', bbox_inches='tight')

    # Choose only the IVs in the static section
    ds_full = ds_full.isel(sweep=slice(manual_start, manual_end))

    # Average across each sweep direction
    sweep_avg_up = ds_full.sel(direction='up').mean('sweep')
    sweep_avg_dn = ds_full.sel(direction='down').mean('sweep')

    # Add in standard deviation of each bin as a new data variable
    sweep_avg_up = sweep_avg_up.assign({'d_current': ds_full.sel(direction='up').std('sweep')['current']})
    sweep_avg_dn = sweep_avg_dn.assign({'d_current': ds_full.sel(direction='down').std('sweep')['current']})

    print(ds_full)

    sweep_avg_updn = ds_full.mean('direction').mean('sweep').assign(
        {'d_current': ds_full.std('direction').std('sweep')['current']})
    sweep_avg_updn = sweep_avg_updn.where(sweep_avg_updn.current <= 0, drop=True)
    print(sweep_avg_updn)

    # sweep_avg_updn['current'].plot.line()

    # concatenate the up and down sweeps together to cancel the (small) capacitance effect
    iv_data = ivd.IVData(sweep_avg_updn['voltage'].data,
                         -sweep_avg_updn['current'].data,
                         sweep_avg_updn['time'].data,
                         sigma=sweep_avg_updn['d_current'].data, estimate_error_fl=False)

    starting_params = [0.69, 0.009, 1.12, 1]

    full_iv_fitter = fts.FullIVFitter()
    fit_data = full_iv_fitter.fit_iv_data(iv_data, initial_vals=starting_params)

    fig = plt.figure()
    fit_data.plot(fig=fig, show_fl=False)
    # plt.errorbar(fit_data.raw_x, fit_data.raw_y, yerr=iv_data['sigma'], ecolor='silver')
    # plt.plot(fit_data.raw_x, fit_data.fit_y, color='orange', label=r'')
    plt.plot(iv_data['V'], full_iv_fitter.fit_function(iv_data['V'], *starting_params), label='Start-param IV')
    plt.legend()
    plt.ylim([-.25, 2.0])

    plt.tight_layout()
    plt.savefig(f'{output_tag}_fit.png', bbox_inches='tight')

    del sweep_avg_up, sweep_avg_dn, sweep_avg_updn
    import gc
    gc.collect()
Esempio n. 3
0
def fit_by_upper_index(iv_data_ds, upper_index, ax=None, multi_fit_fl=False, plot_fl=True):
    """
    This has been superceded by the IVData method fit_to_minimum()
    """
    import flopter.core.fitters as f

    # Determine which way round the sweep goes
    if iv_data_ds['voltage'].values[0] < iv_data_ds['voltage'].values[-1]:
        iv_data_trimmed_ds = iv_data_ds.isel(time=slice(0, upper_index))
    else:
        iv_data_trimmed_ds = iv_data_ds.isel(time=slice(iv_data_ds.time.size - upper_index, -1))

    if plot_fl:
        if ax is None:
            fig, ax = plt.subplots()
        else:
            fig = ax.figure
        fig.suptitle(f'upper_index = {upper_index}')
        ax.errorbar(iv_data_trimmed_ds['voltage'].values, -iv_data_trimmed_ds['current'].values,
                    yerr=iv_data_trimmed_ds['d_current'].values,
                    linestyle='none', color='k', ecolor='k', label='Sweep-averaged IV', zorder=2)

        # Plot the whole IV in an inset axis
        inner_ax = plt.axes([0.2, 0.35, .2, .2])
        (-iv_data_ds.set_coords('voltage')['current']).plot(x='voltage', ax=inner_ax)
        inner_ax.axvline(x=iv_data_trimmed_ds.max('time')['voltage'].values, **c.AX_LINE_DEFAULTS)
        inner_ax.set_title('Whole IV')
        inner_ax.set_xlabel('V')
        inner_ax.set_ylabel('I')
        inner_ax.set_xticks([])
        inner_ax.set_yticks([])

    shot_iv = iv.IVData(iv_data_trimmed_ds['voltage'].values,
                        -iv_data_trimmed_ds['current'].values,
                        iv_data_trimmed_ds['shot_time'].values,
                        sigma=iv_data_trimmed_ds['stderr_current'].values)
    # shot_iv = iv.IVData(iv_data_ds['voltage'].values,
    #                     -iv_data_ds['current'].values,
    #                     iv_data_ds['shot_time'].values,
    #                     sigma=iv_data_ds['stderr_current'].values)

    if multi_fit_fl:
        shot_fit = shot_iv.multi_fit(sat_region=-52)
    else:
        fitter = f.FullIVFitter()
        shot_fit = fitter.fit_iv_data(shot_iv, sigma=shot_iv['sigma'])

    if plot_fl:
        chi_2_str = r"$\chi^2_{red}$"
        ax.plot(*shot_fit.get_fit_plottables(),
                label=f'Fit - T_e={shot_fit.get_temp():.3g}, {chi_2_str} = {shot_fit.reduced_chi2:.3g}')

        ax.legend()

    return shot_fit
Esempio n. 4
0
def straight_iv_fit(iv_data, cutoff=-2, all_initial_values=None):
    if all_initial_values is None:
        all_initial_values = DEFAULT_INITIAL_PARAMS

    fitter = fts.FullIVFitter()
    if cutoff is None:
        cutoff = fts.IVFitter.find_floating_pot(iv_data['V'][:-1], iv_data['I'][:-1])

    iv_region = np.where(iv_data['V'] <= cutoff)
    fit_iv_data = iv.IVData.non_contiguous_trim(iv_data, iv_region)

    initial_vals = fitter.generate_guess(**all_initial_values)

    try:
        fit_data = fitter.fit_iv_data(fit_iv_data, sigma=fit_iv_data['sigma'], initial_vals=initial_vals)
    except ValueError:
        print('CAUGHT: straight fit error')
        fit_data = get_dummy_fit(fit_iv_data, fitter)

    return fit_data
Esempio n. 5
0
def multi_iv_fit(iv_data, sat_region=-6, show_err_fl=True, all_initial_values=None, **kwargs):
    if all_initial_values is None:
        all_initial_values = DEFAULT_INITIAL_PARAMS

    if 'iv_fitter' in kwargs:
        fitter = kwargs['iv_fitter']
    else:
        fitter = fts.FullIVFitter()

    if 'stage_2_guess' not in kwargs:
        initial_vals = fitter.generate_guess(**all_initial_values)
    else:
        initial_vals = kwargs.pop('stage_2_guess')

    try:
        fit_data = iv_data.multi_fit(sat_region=sat_region, stage_2_guess=initial_vals, **kwargs)
    except ValueError as e:
        print('CAUGHT: multi fit error')
        if show_err_fl:
            print(e)
        fit_data = get_dummy_fit(iv_data, fitter)

    return fit_data
def averaged_iv_analysis(filename=None,
                         ts_temp=None,
                         ts_dens=None,
                         shunt_resistance=10.0,
                         theta_perp=10.0,
                         probe_designations=PROBE_DESIGNATIONS,
                         sweep_range=SWEEP_RANGE,
                         downsamplnig_factor=1):
    if filename is None:
        # folders = ['2019-05-28_Leland/', '2019-05-29_Leland/']
        mg.Magoptoffline._FOLDER_STRUCTURE = '/Data/external/magnum/'
        files = []
        file_folders = []
        for folder1 in FOLDERS:
            os.chdir(mg.Magoptoffline.get_data_path() + folder1)
            files.extend(glob.glob('*.adc'))
            file_folders.extend([folder1] * len(glob.glob('*.adc')))
        files.sort()

        # for i, f in enumerate(files):
        #     print(i, f)

        # file = files[286]
        # adc_file = files[285]
        # ts_file = files[284]
        adc_file = files[-1]
        folder = FOLDERS[-1]
    else:
        # If using the tkinter file chooser
        adc_file = filename.split('/')[-1]
        folder = filename.split('/')[-2] + '/'
        mg.Magoptoffline._FOLDER_STRUCTURE = '/Data/external/magnum/'

    print('"{}" \t\t "{}"'.format(folder, adc_file))

    mp = lp.MagnumProbes()
    probe_S = mp.probe_s
    probe_B = mp.probe_b

    dsr = downsamplnig_factor

    # Create magopter object
    print('Creating magopter object')
    magopter = mg.Magoptoffline(folder,
                                adc_file,
                                shunt_resistor=shunt_resistance,
                                cabling_resistance=2)
    magopter._VOLTAGE_CHANNEL = 3
    magopter._PROBE_CHANNEL_3 = 4
    magopter._PROBE_CHANNEL_4 = 5
    magopter.prepare(down_sampling_rate=dsr,
                     roi_b_plasma=True,
                     filter_arcs_fl=False,
                     crit_freq=None,
                     crit_ampl=None)

    print('0: {}, 1: {}'.format(len(magopter.iv_arrs[0]),
                                len(magopter.iv_arrs[1])))

    if ts_dens is not None and ts_temp is not None:
        T_e_ts = ts_temp
        d_T_e_ts = ts_temp * 0.01
        n_e_ts = ts_dens
        d_n_e_ts = ts_dens * 0.01
    else:
        T_e_ts = 1.12
        d_T_e_ts = 0.01
        n_e_ts = 4.44e20
        d_n_e_ts = 0.01e20

    # print length of the 0th probes (probe S) number of sweeps
    print(len(magopter.iv_arrs[1]))

    # Create relative t array by subtracting the first timestep value from the first time array
    first_time_arr = magopter.iv_arrs[1][0]['t']
    relative_t = np.zeros(len(first_time_arr))

    sweep_length = np.shape(relative_t)[0] // 2
    print('Sweep length is {}'.format(sweep_length))

    relative_t = first_time_arr - first_time_arr[0]

    # create a list of datasets for each sweep
    ds_probes = []

    for i in range(len(magopter.iv_arrs)):
        ds_list = []
        for j, iv in enumerate(magopter.iv_arrs[i]):
            if j % 2 == 0:
                ds = xr.Dataset(
                    {
                        'voltage': (['time'], iv['V'][:sweep_length]),
                        'current': (['time'], iv['I'][:sweep_length]),
                        'shot_time': (['time'], iv['t'][:sweep_length]),
                        'start_time': iv['t'][0]
                    },
                    coords={
                        'time': relative_t[:sweep_length],
                        'direction': 'up',
                        'probe': probe_designations[i]
                    })
            else:
                ds = xr.Dataset(
                    {
                        'voltage': (['time'], np.flip(iv['V'][:sweep_length])),
                        'current': (['time'], np.flip(iv['I'][:sweep_length])),
                        'shot_time':
                        (['time'], np.flip(iv['t'][:sweep_length])),
                        'start_time': iv['t'][0]
                    },
                    coords={
                        'time': relative_t[:sweep_length],
                        'direction': 'down',
                        'probe': probe_designations[i]
                    })
            ds_list.append(ds)

        # # Separate into up and down sweeps then concat along sweep direction as an axis
        print('Before equalisation: ', len(ds_list), len(ds_list[::2]),
              len(ds_list[1::2]))
        if len(ds_list[::2]) == len(ds_list[1::2]) + 1:
            ds_ups = xr.concat(ds_list[:-2:2], 'sweep')
        else:
            ds_ups = xr.concat(ds_list[::2], 'sweep')
        ds_downs = xr.concat(ds_list[1::2], 'sweep')
        print('After equalisation: ', len(ds_ups['sweep']),
              len(ds_downs['sweep']))

        direction = xr.DataArray(np.array(['up', 'down']),
                                 dims=['direction'],
                                 name='direction')
        ds_probes.append(xr.concat([ds_ups, ds_downs], dim=direction))

    probe = xr.DataArray(np.array(probe_designations),
                         dims=['probe'],
                         name='probe')
    ds_full = xr.concat(ds_probes, dim=probe)

    # Select the small probe
    ds_full = ds_full.sel(probe=probe_designations[0])

    manual_start = sweep_range[0]
    manual_end = sweep_range[1]
    plt.figure()
    ds_full.max(dim='time').mean('direction')['current'].plot.line(x='sweep')
    ds_full.max(dim='time').mean('direction').isel(
        sweep=slice(manual_start, manual_end))['current'].plot.line(x='sweep')

    # Choose only the IVs in the static section
    ds_full = ds_full.isel(sweep=slice(manual_start, manual_end))

    # Average across each sweep direction
    sweep_avg_up = ds_full.sel(direction='up').mean('sweep')
    sweep_avg_dn = ds_full.sel(direction='down').mean('sweep')

    # Add in standard deviation of each bin as a new data variable
    sweep_avg_up = sweep_avg_up.assign(
        {'d_current': ds_full.sel(direction='up').std('sweep')['current']})
    sweep_avg_dn = sweep_avg_dn.assign(
        {'d_current': ds_full.sel(direction='down').std('sweep')['current']})

    print(ds_full)

    sweep_avg_updn = ds_full.mean('direction').mean('sweep').assign(
        {'d_current': ds_full.std('direction').std('sweep')['current']})
    sweep_avg_updn = sweep_avg_updn.where(sweep_avg_updn.current <= 0,
                                          drop=True)
    print(sweep_avg_updn)

    # sweep_avg_updn['current'].plot.line()

    # concatenate the up and down sweeps together to cancel the (small) capacitance effect
    iv_data = ivd.IVData(sweep_avg_updn['voltage'].data,
                         -sweep_avg_updn['current'].data,
                         sweep_avg_updn['time'].data,
                         sigma=sweep_avg_updn['d_current'].data,
                         estimate_error_fl=False)

    starting_params = [0.69, 0.009, 1.12, +1]

    full_iv_fitter = fts.FullIVFitter()
    fit_data = full_iv_fitter.fit_iv_data(iv_data,
                                          initial_vals=starting_params)
    fig = plt.figure()
    fit_data.plot(fig=fig, show_fl=False)
    # plt.errorbar(fit_data.raw_x, fit_data.raw_y, yerr=iv_data['sigma'], ecolor='silver')
    # plt.plot(fit_data.raw_x, fit_data.fit_y, color='orange', label=r'')
    plt.plot(iv_data['V'],
             full_iv_fitter.fit_function(iv_data['V'], *starting_params),
             label='Start-param IV')
    plt.legend()
    plt.ylim([-.25, 1])

    # Create new averaged iv figure
    theta_perp = np.radians(theta_perp)

    # probe_selected = probe_L

    A_coll_0 = probe_S.get_collection_area(theta_perp)
    d_A_coll = np.abs(
        probe_S.get_collection_area(theta_perp + np.radians(0.8)) - A_coll_0)

    v_f_fitted = fit_data.get_param('V_f')
    d_v_f_fitted = fit_data.get_param('V_f', errors_fl=True).error

    v_f_approx = -3 * fit_data.get_temp()
    d_v_f_approx = 0.05 * v_f_approx

    v_f_approx_ts = -3 * T_e_ts
    d_v_f_approx_ts = 0.05 * v_f_approx_ts

    c_s_fitted = lp.sound_speed(fit_data.get_temp(), gamma_i=1)
    d_c_s_fitted = lp.d_sound_speed(c_s_fitted, fit_data.get_temp(),
                                    fit_data.get_temp(errors_fl=True).error)
    n_e_fitted = lp.electron_density(fit_data.get_isat(), c_s_fitted, A_coll_0)
    d_n_e_fitted = lp.d_electron_density(
        n_e_fitted, c_s_fitted, d_c_s_fitted, A_coll_0, d_A_coll,
        fit_data.get_isat(),
        fit_data.get_isat(errors_fl=True).error)

    print("iv = averaged: \n"
          "\t v_f = {:.3g} +- {:.1g} \n"
          "\t T_e = {:.3g} +- {:.1g} \n"
          "\t I_sat = {:.3g} +- {:.1g} \n"
          "\t n_e = {:.3g} +- {:.1g} \n"
          "\t a = {:.3g} +- {:.1g} \n"
          "\t c_s = {:.3g} +- {:.1g} \n"
          "\t A_coll = {:.3g} +- {:.1g} \n".format(
              v_f_fitted, d_v_f_fitted, fit_data.get_temp(),
              fit_data.get_temp(errors_fl=True).error, fit_data.get_isat(),
              fit_data.get_isat(errors_fl=True).error, n_e_fitted,
              d_n_e_fitted, fit_data.get_sheath_exp(),
              fit_data.get_sheath_exp(errors_fl=True).error, c_s_fitted,
              d_c_s_fitted, A_coll_0, d_A_coll))

    I_f = probe_S.get_analytical_iv(fit_data.raw_x,
                                    v_f_fitted,
                                    theta_perp,
                                    fit_data.get_temp(),
                                    n_e_fitted,
                                    print_fl=True)
    I_ts = probe_S.get_analytical_iv(fit_data.raw_x,
                                     v_f_approx_ts,
                                     theta_perp,
                                     T_e_ts,
                                     n_e_ts,
                                     print_fl=True)

    plt.figure()
    plt.errorbar(fit_data.raw_x,
                 fit_data.raw_y,
                 yerr=fit_data.sigma,
                 label='Raw IV',
                 ecolor='silver',
                 color='gray',
                 zorder=-1)
    # plt.plot(iv_data[c.RAW_X].tolist()[0], I_f, label='Analytical - measured', linestyle='dashed', linewidth=1, color='r')
    plt.plot(fit_data.raw_x,
             fit_data.fit_y,
             color='blue',
             linewidth=1.2,
             label='Fit - ({:.2g}eV, {:.2g}m'.format(fit_data.get_temp(),
                                                     n_e_fitted) + r'$^{-3}$)')
    plt.plot(fit_data.raw_x,
             I_ts,
             linestyle='dashed',
             color='red',
             label='Analytical from TS - ({:.2g}eV, {:.2g}m'.format(
                 T_e_ts, n_e_ts) + '$^{-3}$)')

    plt.legend()
    # plt.title('Comparison of analytical to measured IV curves for the small area probe')
    plt.xlabel(r'$V_p$ / V')
    plt.ylabel(r'$I$ / A')
    # plt.ylim([-0.01, 3.2])
    plt.show()
Esempio n. 7
0
def fit_magnum_ds(magnum_subset_ds, probes=('L', 'S', 'B', 'R'), ax=True, scan_param='tilt', scan_selection=None,
                  threshold='auto', fitter=None, print_fl=False, temp_from_phi_fl=True, multi_fit_fl=True, mass=1, Z=1,
                  **kwargs):
    if fitter is None:
        fitter = fts.FullIVFitter()

    if scan_selection is not None:
        magnum_subset_ds = magnum_subset_ds.sel(scan_selection)

    metadata_labels = [
        scan_param,
        'probe',
        'B',
        'ts_temp',
        'ts_dens',
        'fit_success_fl',
    ]
    fit_param_labels = [
        'temp',
        'd_temp',
        'isat',
        'd_isat',
        'a',
        'd_a',
        'v_f',
        'd_v_f',
        'dens',
        'd_dens',
        'chi2',
        'reduced_chi2'
    ]
    phi_labels = [
        'phi',
        'temp_phi',
        'temp_fit_phi'
    ]
    if temp_from_phi_fl:
        fit_param_labels += phi_labels

    all_labels = metadata_labels + fit_param_labels

    fit_df = pd.DataFrame(columns=all_labels)

    for scan_param_value in magnum_subset_ds[scan_param].values:
        scan_param_ds = magnum_subset_ds.sel(**{scan_param: scan_param_value})
        if print_fl:
            print(f'\n\n -- ({scan_param_ds.shot_number.values}) Running fit on {scan_param} with {scan_param_value} -- \n')
        for probe in probes:
            probe_paramscan_ds = scan_param_ds.sel(probe=probe)
            probe_paramscan_ds = probe_paramscan_ds.where(np.isfinite(probe_paramscan_ds['voltage']), drop=True)
            probe_paramscan_ds = probe_paramscan_ds.where(np.isfinite(probe_paramscan_ds['current']), drop=True)

            if threshold == 'auto':
                # Auto option finds the first point the other side of the floating potential and then selects up to that
                threshold = 1

            if isinstance(threshold, int):
                iv_indices = np.where(probe_paramscan_ds.current < 0)[0]
                if iv_indices[0] == 0:
                    extreme_index = max(iv_indices)
                    extension = [extreme_index + (i + 1) for i in range(threshold)]
                    ext_iv_indices = np.concatenate((iv_indices, extension))
                else:
                    extreme_index = min(iv_indices)
                    extension = [extreme_index - (threshold - i) for i in range(threshold)]
                    ext_iv_indices = np.concatenate((extension, iv_indices))
                probe_paramscan_ds = probe_paramscan_ds.isel(time=ext_iv_indices)
            elif isinstance(threshold, float):
                probe_paramscan_ds = probe_paramscan_ds.where(probe_paramscan_ds.current < threshold, drop=True)
            elif print_fl:
                print('No threshold set, continuing with full sweep.')

            if scan_param == 'tilt':
                tilt = scan_param_value
            else:
                tilt = np.array(probe_paramscan_ds['tilt'].values, ndmin=1)[0]
            alpha = np.radians(tilt)

            if len(probe_paramscan_ds.time) == 0:
                if print_fl:
                    print('Time has no length, continuing...')
                continue

            shot_iv = iv.IVData(probe_paramscan_ds['voltage'].values,
                                -probe_paramscan_ds['current'].values,
                                probe_paramscan_ds['shot_time'].values,
                                sigma=probe_paramscan_ds['d_current'].values)

            # Generate a guess for a 4-parameter IV characteristic
            temp_guess = probe_paramscan_ds['ts_temperature'].mean().values
            dens_guess = probe_paramscan_ds['ts_density'].mean().values
            a_guess = magnum_probes[probe].get_sheath_exp_param(temp_guess, dens_guess, alpha)
            isat_guess = probe_paramscan_ds['current'].min('time').values
            v_f_guess = fitter.find_floating_pot_iv_data(shot_iv)

            initial_params = fitter.generate_guess(
                temperature=temp_guess,
                floating_potential=v_f_guess,
                isat=isat_guess,
                sheath_exp_param=a_guess
            )
            if print_fl:
                print(f"First guess initial_params: {[temp_guess, dens_guess, isat_guess, v_f_guess]}")
                print(f"Generated initial_params: {initial_params}")

            try:
                if multi_fit_fl:
                    shot_fit = shot_iv.multi_fit(print_fl=print_fl, stage_2_guess=initial_params, iv_fitter=fitter,
                                                 **kwargs)
                else:
                    shot_fit = fitter.fit_iv_data(shot_iv, sigma=shot_iv['sigma'], initial_vals=initial_params)

                dens = magnum_probes[probe].get_density(shot_fit.get_isat(), shot_fit.get_temp(), alpha=alpha,
                                                        mass=mass, Z=Z)
                d_dens = magnum_probes[probe].get_d_density(
                    shot_fit.get_isat(),
                    shot_fit.get_isat_err(),
                    shot_fit.get_temp(),
                    shot_fit.get_temp_err(),
                    alpha=alpha,
                    mass=mass,
                    Z=Z,
                )
                if isinstance(dens, collections.Iterable):
                    dens = dens[0]
                    d_dens = d_dens[0]

                fit_params = {
                    'fit_success_fl': True,
                    'temp': shot_fit.get_temp(),
                    'd_temp': shot_fit.get_temp_err(),
                    'isat': shot_fit.get_isat(),
                    'd_isat': shot_fit.get_isat_err(),
                    'a': shot_fit.get_sheath_exp(),
                    'd_a': shot_fit.get_sheath_exp_err(),
                    'v_f': shot_fit.get_floating_pot(),
                    'd_v_f': shot_fit.get_floating_pot_err(),
                    'dens': dens,
                    'd_dens': d_dens,
                    'chi2': shot_fit.chi2,
                    'reduced_chi2': shot_fit.reduced_chi2,
                }

                if temp_from_phi_fl:
                    phi = shot_iv.estimate_phi()
                    temp_phi = lpu.estimate_temperature(shot_iv.get_vf(), phi)
                    temp_fit_phi = lpu.estimate_temperature(shot_fit.get_floating_pot(), phi)
                    fit_params.update({
                        'phi': phi,
                        'temp_phi': temp_phi,
                        'temp_fit_phi': temp_fit_phi
                    })

                if ax is not None:
                    if ax is True:
                        fig, ax = plt.subplots()
                    ax.errorbar(shot_iv['V'], shot_iv['I'], yerr=shot_iv['sigma'],
                                ecolor='silver', color='silver', marker='+', zorder=1)
                    ax.plot(*shot_fit.get_fit_plottables())
            except RuntimeError as e:
                print(f'WARNING: Failed on {scan_param}={scan_param_value} with probe {probe}')
                print(e)
                fit_params = {label: np.NaN for label in fit_param_labels}
                fit_params['fit_success_fl'] = False

            fit_df = fit_df.append({
                scan_param: scan_param_value,
                'probe': probe,
                'B': np.around(probe_paramscan_ds['shot_b_field'].mean().values, decimals=1),
                'ts_temp': probe_paramscan_ds['ts_temperature'].max().values,
                'ts_dens': probe_paramscan_ds['ts_density'].max().values,
                **fit_params,
            }, ignore_index=True)

    return fit_df
Esempio n. 8
0
    def fit(self,
            fitter=None,
            initial_vals=None,
            bounds=None,
            load_fl=False,
            save_fl=False,
            print_fl=False):
        if load_fl and save_fl:
            print(
                'WARNING: Unnecessary to save and load at the same time - loading will be prioritised if successful.'
            )

        # Looks for csv files containing previously fitted data if asked for by the load_fl boolean flag.
        fit_files = [
            self._FIT_FILE_STRING.format(i, self.timestamp)
            for i in range(self.coaxes)
        ]
        if load_fl:
            start_dir = os.getcwd()
            os.chdir('{}{}{}'.format(pth.Path.home(), self._FOLDER_STRUCTURE,
                                     self.directory))
            directory_fit_files = glob.glob(self._FIT_FILE_GLOBSTR)
            if set(fit_files).issubset(directory_fit_files):
                return [pd.read_csv(filepath_or_buffer=ff) for ff in fit_files]
            else:
                print(
                    'Could not find fit files - they should be in {} with names of the format {}'
                    .format(self.directory, fit_files[0]))
                print('Continuing with regular fit...')
            os.chdir(start_dir)

        # Fitting routine
        if not fitter:
            fitter = f.FullIVFitter()
        if all(iv_arr is None or len(iv_arr) == 0 for iv_arr in self.iv_arrs):
            raise ValueError('No iv_data found to fit in self.iv_arrs')
        # pool = mp.Pool()
        fit_arrs = [[] for dummy in range(self.coaxes)]
        fit_time = [[] for dummy in range(self.coaxes)]
        for i in range(self.coaxes):
            for iv_data in self.iv_arrs[i]:
                try:
                    # Parallelised using multiprocessing.pool
                    # TODO: Not currently working according to system monitor.
                    fit_data = iv_data.multi_fit(plot_fl=False)
                    # result = pool.apply_async(iv_data.multi_fit)
                    # fit_data = result.get(timeout=10)
                except RuntimeError:
                    if print_fl:
                        print('Error encountered in fit, skipping timestep {}'.
                              format(np.mean(iv_data.time)))
                    continue
                if all(param.error >= (param.value * 0.5)
                       for param in fit_data.fit_params):
                    if print_fl:
                        print(
                            'All fit parameters exceeded good fit voltage_threshold, skipping time step {}'
                            .format(np.mean(iv_data[c.TIME])))
                    continue
                fit_arrs[i].append(fit_data)
                fit_time[i].append(np.mean(iv_data[c.TIME]))
        fit_dfs = [
            pd.DataFrame([fit_data.to_dict() for fit_data in fit_arrs[i]],
                         index=fit_time[i]) for i in range(self.coaxes)
        ]
        if save_fl:
            for i in range(self.coaxes):
                fit_dfs[i].to_csv(
                    path_or_buf='{}{}{}{}'.format(pth.Path.home(
                    ), self._FOLDER_STRUCTURE, self.directory, fit_files[i]))
        return fit_dfs
Esempio n. 9
0
def multifit_trim_filter_analysis(probe_0, folder, file):
    # noinspection PyTypeChecker
    fig, ax = plt.subplots(2, 1, sharex=True, sharey=True)
    fitter = f.FullIVFitter()
    for i, freq in enumerate([None, 4000]):
        magopter = Magopter(folder, file, ts_filename=ts_file)
        magopter.prepare(down_sampling_rate=1, roi_b_plasma=True, crit_freq=freq, crit_ampl=None)

        index = int(0.5 * len(magopter.iv_arrs[0]))
        iv_data = magopter.iv_arrs[0][index]

        fitdata = iv_data.multi_fit(iv_fitter=fitter)

        iv_data.trim_beg = 0.01
        iv_data.trim_end = 0.45
        fitdata_1 = iv_data.multi_fit(iv_fitter=fitter)
        print('{}:{}'.format(iv_data.trim_beg, iv_data.trim_end))
        fitdata_1.print_fit_params()
        # fitdata_1_fvf = iv_data.multi_fit(plot_fl=False, fix_vf_fl=True)

        untrimmed_x = iv_data[c.POTENTIAL]
        untrimmed_y = iv_data[c.CURRENT]

        custom_params = [1.08, 0.006, 4.30, -15.1]

        # Plot the raw signal and the untrimmed fit
        plt.sca(ax[i])
        plt.title('Critical Frequency is {}'.format('{}Hz'.format(freq) if freq is not None else 'not set'))
        plt.errorbar(untrimmed_x, untrimmed_y, fmt='.', yerr=iv_data[c.SIGMA], label='Raw', color='silver', zorder=-1)
        plt.plot(untrimmed_x, fitdata.fit_function(untrimmed_x), label='Fit - No Trim', color='green', zorder=10)

        # Plot the comparion between fixed vf and free vf
        plt.plot(untrimmed_x, fitdata_1.fit_function(untrimmed_x), color='red', linewidth=1,
                 label=r'T_e = {:.3g},  $\chi^2$ = {:.3g}'.format(fitdata_1.get_temp().value, fitdata_1.reduced_chi2))
        plt.axvline(x=np.max(fitdata_1.raw_x), label='Trim Min/Max', color='red', linestyle='dashed', linewidth=1)
        plt.axvline(x=np.min(fitdata_1.raw_x), color='red', linestyle='dashed', linewidth=1)
        # plt.plot(untrimmed_x, fitdata_1_fvf.fit_function(untrimmed_x), label=r'Fixed $V_f$ Fit - {}:{}'
        #          .format(iv_data.trim_end, iv_data.trim_beg), color='red', linestyle='-.')

        # # Plot the raw signal and the untrimmed fit
        # plt.figure()
        # plt.errorbar(untrimmed_x, untrimmed_y, fmt='.', yerr=iv_data[c.SIGMA], label='Raw', color='silver', zorder=-1)
        # plt.plot(untrimmed_x, fitdata.fit_function(untrimmed_x), label='Fit - No Trim', color='green')

        # Trim and plot again
        iv_data.trim_beg = -0.05
        iv_data.trim_end = 0.45
        fitdata_2 = iv_data.multi_fit(iv_fitter=fitter)
        print('{}:{}'.format(iv_data.trim_beg, iv_data.trim_end))
        fitdata_2.print_fit_params()
        # fitdata_2_fvf = iv_data.multi_fit(fix_vf_fl=True)

        plt.plot(untrimmed_x, fitdata_2.fit_function(untrimmed_x), color='blue', linewidth=1,
                 label=r'T_e = {:.3g},  $\chi^2$ = {:.3g}'.format(fitdata_2.get_temp().value, fitdata_2.reduced_chi2))
        plt.axvline(x=np.max(fitdata_2.raw_x), label='Trim Min/Max', color='blue', linestyle='dashed', linewidth=1)
        plt.axvline(x=np.min(fitdata_2.raw_x), color='blue', linestyle='dashed', linewidth=1)
        # plt.plot(untrimmed_x, fitdata_0160_fvf.fit_function(untrimmed_x), label=r'Fixed $V_f$ Fit - {}:{}'
        #          .format(iv_data.trim_end, iv_data.trim_beg), color='blue', linestyle='-.')

        # Trim and plot again
        iv_data.trim_beg = -0.1
        iv_data.trim_end = 0.45
        fitdata_3 = iv_data.multi_fit(iv_fitter=fitter)
        print('{}:{}'.format(iv_data.trim_beg, iv_data.trim_end))
        fitdata_3.print_fit_params()
        # fitdata_3_fvf = iv_data.multi_fit(fix_vf_fl=True)

        plt.plot(untrimmed_x, fitdata_3.fit_function(untrimmed_x), color='orange', linewidth=1,
                 label=r'T_e = {:.3g},  $\chi^2$ = {:.3g}'.format(fitdata_3.get_temp().value, fitdata_3.reduced_chi2))
        plt.axvline(x=np.max(fitdata_3.raw_x), label='Trim Min/Max', color='orange', linestyle='dashed', linewidth=1)
        plt.axvline(x=np.min(fitdata_3.raw_x), color='orange', linestyle='dashed', linewidth=1)

        # Plot the custom fit and an axis line through 0
        # plt.plot(untrimmed_x, f.FullIVFitter().fit_function(untrimmed_x, *custom_params), label='Custom Fit {}'
        #          .format(', '.join([str(i) for i in custom_params])))
        plt.axhline(color='black', linewidth=1)
        plt.ylim(-1.1, 1.6)
        plt.xlabel('Voltage (V)')
        plt.ylabel('Current (A)')
        plt.legend()
Esempio n. 10
0
    def fit_to_minimum(self,
                       initial_vals=None,
                       fitter=None,
                       trimming_vals=None,
                       mode=0,
                       plot_fl=False,
                       print_fl=False):
        """
        A fitting function which minimises the fitted temperature of the IV
        characteristic by varying how many values around the floating potential
        are included in the fit. The default values for distance around the
        floating potential are 0.2 and 0.1 towards the plasma potential and ion
        saturation region respectively. As of now these are hard coded, but will
        be configurable in future updates.

        :param fitter:          (IVFitter) Fitter object used to perform the
                                fit. The default is FullIVFitter
        :param initial_vals:    (tuple) The initial parameters for the fit.
                                Default's to the fitter's preset starting params
                                if left as None.
        :param trimming_vals:   (tuple) The trimming fractions used to control
                                the range of values minimised over. Each value
                                should be the distance from the floating
                                potential as a fraction of the total IV
                                characteristic.The first value determines the
                                upper limit (>V_f), the second value determines
                                the lower limit (<V_f) and the third value
                                determines how big the steps should be. Default
                                values are (0.3, 0.3, 0.02), which for an IV
                                of length 50 would give ~31 total points (15
                                above V_f, 15 points below V_f, and V_f itself).
        :param mode:            (int) Choice of minimisation parameter. Choices
                                currently implemented:
                                > 0 = T_e · dT_e · (|chi² - 1| + 1)
                                > 1 = T_e · dT_e · |chi² - 1|
                                > 2 = |chi² - 1| + 1
                                > 3 = T_e · dT_e
                                > 4 = T_e
                                > 5 = |T_e - 1|
                                Prototyping for these parameters was created in
                                a jupyter notebook, see that for more details.
        :param plot_fl:         (Boolean) Flag to control whether the process is
                                plotted while running. Current configuration is
                                to plot the full IV, overlaid with each of the
                                trimmed IVs, and below that a separate plot of
                                temperature as a function of upper trim voltage.
        :param print_fl:        (Boolean) Flag to control whether information is
                                printed to terminal during the fitting process.
        :return:                (IVFitData) FitData object for lowest
                                temperature fit performed.

        """
        import flopter.core.fitters as f

        if fitter is None or not isinstance(fitter, f.IVFitter):
            fitter = f.FullIVFitter()

        vf_index = self.get_vf_index()
        v_f = self['V'][vf_index]

        # Select how far from the floating potential we want to iterate
        if trimming_vals is None:
            trimming_vals = self.MINFIT_TRIM_VALS

        upper_dist_frac, lower_dist_frac, step_frac = trimming_vals

        trim_range_updist = int(upper_dist_frac * len(self['t']))
        trim_range_dndist = int(lower_dist_frac * len(self['t']))
        trim_range_step = max(int(step_frac * len(self['t'])), 1)

        # Set trim range depending on what direction our data is in.
        if self['V'][0] < self['V'][-1]:
            trim_range = np.arange(
                max(vf_index - trim_range_dndist, 0),
                min(vf_index + trim_range_updist, len(self['t'])),
                trim_range_step)
        else:
            trim_range = np.arange(
                max(vf_index - trim_range_updist, 0),
                min(vf_index + trim_range_dndist, len(self['t'])),
                trim_range_step)

        ax_big = None
        if plot_fl:
            height_ratios = [2.5, 1, 1, 1, 1, 1]
            fig = plt.figure(constrained_layout=True)
            gs = fig.add_gridspec(ncols=2,
                                  nrows=6,
                                  height_ratios=height_ratios)

            ax = []

            ax_big = fig.add_subplot(gs[0, :])
            # ax_big.errorbar('voltage', 'current', yerr='stderr_current', data=sweep_avg_ds)
            self.plot(ax=ax_big)

            ax_big.axvline(x=v_f, **c.AX_LINE_DEFAULTS, label=r'$V_f$')
            ax_big.axvline(x=self['V'][max(trim_range)],
                           linewidth=0.7,
                           color='black',
                           label='trim min/max')
            ax_big.axvline(x=self['V'][min(trim_range)],
                           linewidth=0.7,
                           color='black')
            ax_big.legend()

            for row in range(1, 6):
                ax_left = fig.add_subplot(gs[row, 0])
                ax_right = fig.add_subplot(gs[row, 1])
                ax.append([ax_left, ax_right])

        # Fit for each value of trim around the floating potential
        trimmed_fits = []
        temps = np.array([])
        d_temps = np.array([])
        isats = np.array([])
        d_isats = np.array([])
        sheathexps = np.array([])
        d_sheathexps = np.array([])
        chis = np.array([])
        volts = np.array([])
        for i in trim_range:
            # Trim is defined as: from the 0th element to the ith element, or from the ith element to the last element
            # depending on the direction of sweep.
            if self['V'][0] < self['V'][-1]:
                trim_iv = self.upper_trim(i)
            else:
                trim_iv = self.lower_trim(i)

            if plot_fl:
                trim_iv.plot(ax=ax_big, zorder=i)

            try:
                trim_fit = fitter.fit_iv_data(trim_iv,
                                              sigma=trim_iv['sigma'],
                                              initial_vals=initial_vals)
                for fp in trim_fit.fit_params:
                    error_ratio = fp.error / fp.value
                    if error_ratio > self.MINFIT_ERR_RATIO:
                        raise RuntimeError(
                            f'Fit produced a parameter with an unacceptable error ratio ({error_ratio})'
                        )

                trimmed_fits.append(trim_fit)

                # Append values relevant to minimisation param to their respective arrays
                volts = np.append(volts, np.max(trim_fit.raw_x))
                temps = np.append(temps, trim_fit.get_temp())
                d_temps = np.append(d_temps, trim_fit.get_temp_err())
                isats = np.append(isats, trim_fit.get_isat())
                d_isats = np.append(d_isats, trim_fit.get_isat_err())
                chis = np.append(chis, trim_fit.reduced_chi2)

                # Check if sheath expansion parameter is present and append zeros if not. This would happen if using a
                # 3-parameter fit.
                if c.SHEATH_EXP in trim_fit:
                    sheathexps = np.append(sheathexps,
                                           trim_fit.get_sheath_exp())
                    d_sheathexps = np.append(d_sheathexps,
                                             trim_fit.get_sheath_exp_err())
                else:
                    sheathexps = np.append(sheathexps, 0.0)
                    d_sheathexps = np.append(d_sheathexps, 0.0)

            except RuntimeError as e:
                if print_fl:
                    print(f'Temp-minimisation fit failed on index {i}\n:'
                          f'{e}')

        if len(temps) == 0:
            raise RuntimeError(
                'All temperature minimisation fits failed. Try using different trimming_vals.'
            )

        temp_param = temps * d_temps
        chi_param = np.abs(chis - 1) + 1
        alt_chi_param = np.abs(chis - 1)
        goodness_param = temp_param * chi_param
        alt_goodness_param = temp_param * alt_chi_param
        alt_temp_param = np.abs(temps - 1)

        # Get the indices for the minimum values for each of the parameters
        minimisable_params = [
            goodness_param,
            alt_goodness_param,
            chi_param,
            temp_param,
            temps,
            alt_temp_param,
        ]

        if plot_fl:
            t_minv = volts[np.argmin(temps)]
            t_dt_minv = volts[np.argmin(temp_param)]
            chi_param_minv = volts[np.argmin(chi_param)]
            alt_chi_param_minv = volts[np.argmin(alt_chi_param)]
            alt_goodness_minv = volts[np.argmin(alt_goodness_param)]
            goodness_minv = volts[np.argmin(goodness_param)]
            t_param_minv = volts[np.argmin(alt_temp_param)]

            chi2_str = r'$\chi^{2}_{\nu}$'
            temp_str = r'$T_e$'
            d_temp_str = r'$\Delta T_e$'
            isat_str = r'$I_{sat}$'
            a_str = r'$a$'
            chi_param_str = r'$|\chi^{2}_{\nu} - 1| + 1$'
            alt_chi_param_str = r'$|\chi^{2}_{\nu} - 1|$'
            d_temps_ratio_str = r'$\frac{\Delta T_e}{T_e}$'
            alt_temp_param_str = r'$|T_e - 1|$'

            ax[0][0].errorbar(volts, temps, yerr=d_temps)
            ax[0][0].plot(volts, alt_temp_param, label=alt_temp_param_str)
            ax[0][0].set_ylabel(temp_str)
            ax[0][0].axvline(x=t_minv,
                             color='blue',
                             linestyle='--',
                             label='T min')
            ax[0][0].axvline(
                x=t_dt_minv,
                color='purple',
                linestyle='--',
            )
            ax[0][0].axvline(
                x=chi_param_minv,
                color='green',
                linestyle='--',
            )
            ax[0][0].axvline(
                x=goodness_minv,
                color='red',
                linestyle='--',
            )
            ax[0][0].axvline(x=t_param_minv,
                             color='pink',
                             linestyle=':',
                             label=alt_temp_param_str)

            ax[0][1].plot(volts, chis, label=chi2_str)
            ax[0][1].axhline(y=1, **c.AX_LINE_DEFAULTS)
            ax[0][1].set_yscale('log')
            ax[0][1].set_ylabel(chi2_str)
            ax[0][1].axvline(
                x=t_minv,
                color='blue',
                linestyle='--',
            )
            ax[0][1].axvline(
                x=t_dt_minv,
                color='purple',
                linestyle='--',
            )
            ax[0][1].axvline(
                x=chi_param_minv,
                color='green',
                linestyle='--',
            )
            ax[0][1].axvline(
                x=goodness_minv,
                color='red',
                linestyle='--',
            )

            ax[1][0].errorbar(volts, isats, yerr=d_isats, label=isat_str)
            ax[1][0].set_ylabel(isat_str)

            ax[1][1].errorbar(volts, sheathexps, yerr=d_sheathexps, label='a')
            ax[1][1].set_ylabel(a_str)

            ax[2][0].plot(volts, temp_param)
            ax[2][0].set_ylabel(temp_str + r'$\cdot$' + d_temp_str)
            ax[2][0].set_yscale('log')
            ax[2][0].axvline(x=t_dt_minv,
                             color='purple',
                             linestyle='--',
                             label=r'$T \cdot \Delta T$')

            ax[2][1].plot(volts, d_temps / temps)
            ax[2][1].set_ylabel(d_temps_ratio_str)
            ax[2][1].set_yscale('log')
            ax[2][1].axhline(y=self.MINFIT_ERR_RATIO,
                             color='black',
                             linewidth=0.75,
                             label='Threshold')

            ax[3][0].plot(volts, chi_param)
            ax[3][0].set_yscale('log')
            ax[3][0].set_ylabel(chi_param_str)
            ax[3][0].axvline(x=chi_param_minv,
                             color='green',
                             linestyle='--',
                             label=chi_param_str)

            ax[3][1].plot(volts, alt_chi_param)
            ax[3][1].set_yscale('log')
            ax[3][1].set_ylabel(alt_chi_param_str)
            ax[3][1].axvline(x=alt_chi_param_minv,
                             color='green',
                             linestyle='--',
                             label=alt_chi_param_str)

            ax[4][0].plot(volts, goodness_param)
            ax[4][0].set_yscale('log')
            ax[4][0].set_ylabel(
                r'$T_e \cdot \Delta T_e \cdot (|\chi^{2}_{\nu} - 1| + 1)$')
            ax[4][0].axvline(x=goodness_minv,
                             color='red',
                             linestyle='--',
                             label='goodness')

            ax[4][1].plot(volts, alt_goodness_param)
            ax[4][1].set_yscale('log')
            ax[4][1].set_ylabel(
                r'$T_e \cdot \Delta T_e \cdot |\chi^{2}_{\nu} - 1|$')
            ax[4][1].axvline(x=alt_goodness_minv,
                             color='gold',
                             linestyle='--',
                             label='alt_goodness')

            for col in ax:
                for axis in col:
                    axis.axvline(x=v_f, **c.AX_LINE_DEFAULTS)
                    axis.legend()

        minimised_param_index = int(
            np.argmin(minimisable_params[mode], axis=None))
        if plot_fl:
            ax_big.axvline(x=volts[np.argmin(minimisable_params[mode])],
                           linewidth=0.7,
                           color='red',
                           linestyle=':',
                           label='Chosen')

        return trimmed_fits[minimised_param_index]
Esempio n. 11
0
    def multi_fit(self,
                  sat_region=_DEFAULT_STRAIGHT_CUTOFF,
                  stage_2_guess=None,
                  iv_fitter=None,
                  sat_fitter=None,
                  fix_vf_fl=False,
                  plot_fl=False,
                  print_fl=False,
                  minimise_temp_fl=True,
                  trim_to_floating_fl=True,
                  **kwargs):
        """
        Multi-stage fitting method using an initial straight line fit to the
        saturation region of the IV curve (decided by the sat_region kwarg). The
        fitted I_sat is then left fixed while T_e and a are found with a
        2-parameter fit, which gives the guess parameters for an unconstrained
        full IV fit.

        :param sat_region:  (Integer) Threshold voltage value below which the
                            'Straight section' is defined. The straight section
                            is fitted to get an initial value of saturation
                            current for subsequent fits.
        :param sat_fitter:  Fitter object to be used for the initial saturation
                            region fit
        :param stage_2_guess:
                            Tuple-like containing starting values for all
                            parameters in iv_fitter, to be used as initial
                            parameters in the second stage fit. Note that only
                            the temperature (and optionally sheath expansion
                            parameter) will be used, as the isat will
                            already have a value (by design) and the floating
                            potential is set at the interpolated value. These
                            will be overwritten if present. Default behaviour
                            (stage_2_guess=None) is to use the defaults on the
                            iv_fitter object.
        :param iv_fitter:   Fitter object to be used for the fixed-I_sat fit and
                            the final, full, free fit.
        :param plot_fl:     (Boolean) If true, plots the output of all 3 stages
                            of fitting. Default is False.
        :param fix_vf_fl:   (Boolean) If true, fixes the floating potential for
                            all 3 stages of fitting. The value used is the
                            interpolated value of Voltage where Current = 0.
                            Default is False.
        :param print_fl:    (Boolean) If true, prints fitter information to
                            console.
        :param minimise_temp_fl:
                            (Boolean) Flag to control whether multiple final
                            fits are performed at a range of upper indices past
                            the floating potential, with the fit producing the
                            lowest temperature returned.
        :param trim_to_floating_fl:
                            (Boolean) Flag to control whether to truncate the IV
                            characteristic to values strictly below the floating
                            potential before fitting. This is ignored by the
                            minimisation routine, so the full IV will be used in
                            that case.
        :return:            (IVFitData) Full 4-parameter IVFitData object

        """
        import flopter.core.fitters as f

        if iv_fitter is None or not isinstance(iv_fitter, f.IVFitter):
            iv_fitter = f.FullIVFitter()
        if not isinstance(sat_fitter, f.GenericCurveFitter):
            if sat_fitter is not None and print_fl:
                print(
                    'Provided sat_fitter is not a valid child of GenericCurveFitter, continuing with the default \n'
                    'straight line fitter.')
            sat_fitter = f.StraightLineFitter()

        if print_fl:
            print(f'Running saturation region fit with {sat_fitter.name}, \n'
                  f'running subsequent IV fits with {iv_fitter.name}')

        # find floating potential and max potential
        v_f = f.IVFitter.find_floating_pot_iv_data(self)

        if trim_to_floating_fl:
            iv_data_trim = self.get_below_floating(v_f=v_f, print_fl=print_fl)
        else:
            iv_data_trim = self.copy()

        # Find and fit straight section
        str_sec = np.where(iv_data_trim[c.POTENTIAL] <= sat_region)
        iv_data_ss = IVData.non_contiguous_trim(iv_data_trim, str_sec)
        if fix_vf_fl and c.FLOAT_POT in sat_fitter:
            sat_fitter.set_fixed_values({c.FLOAT_POT: v_f})

        # Attempt first stage fit
        try:
            stage1_f_data = sat_fitter.fit(iv_data_ss[c.POTENTIAL],
                                           iv_data_ss[c.CURRENT],
                                           sigma=iv_data_ss[c.SIGMA])
        except RuntimeError as e:
            raise MultiFitError(f'RuntimeError occured in stage 1. \n'
                                f'Original error: {e}')

        # Use I_sat value to fit a fixed_value 4-parameter IV fit
        if c.ION_SAT in sat_fitter:
            isat_guess = stage1_f_data.get_isat()
        else:
            isat_guess = stage1_f_data.fit_function(sat_region)

        if fix_vf_fl:
            iv_fitter.set_fixed_values({
                c.FLOAT_POT: v_f,
                c.ION_SAT: isat_guess
            })
        else:
            iv_fitter.set_fixed_values({c.ION_SAT: isat_guess})

        if stage_2_guess is None:
            stage_2_guess = list(iv_fitter.default_values)
        elif len(stage_2_guess) != len(iv_fitter.default_values):
            raise ValueError(
                f'stage_2_guess is not of the appropriate length ({len(stage_2_guess)}) for use as initial '
                f'parameters in the given iv_fitter (should be length {len(iv_fitter.default_values)}).'
            )
        stage_2_guess[iv_fitter.get_isat_index()] = isat_guess
        stage_2_guess[iv_fitter.get_vf_index()] = v_f

        # Attempt second stage fit
        try:
            stage2_f_data = iv_fitter.fit_iv_data(iv_data_trim,
                                                  sigma=iv_data_trim[c.SIGMA],
                                                  initial_vals=stage_2_guess)
        except RuntimeError as e:
            raise MultiFitError(f'RuntimeError occured in stage 2. \n'
                                f'Original error: {e}')

        # Do a full 4 parameter fit with initial guess params taken from previous fit
        params = stage2_f_data.fit_params.get_values()
        iv_fitter.unset_fixed_values()
        if fix_vf_fl:
            iv_fitter.set_fixed_values({c.FLOAT_POT: v_f})

        # Attempt third stage fit. Option to fit to multiple values past the floating potential to minimise the
        # temperature of the fit or just to the floating potential.
        try:
            if minimise_temp_fl:
                stage3_f_data = self.fit_to_minimum(initial_vals=params,
                                                    fitter=iv_fitter,
                                                    plot_fl=plot_fl,
                                                    **kwargs)
            else:
                stage3_f_data = iv_fitter.fit_iv_data(
                    iv_data_trim,
                    initial_vals=params,
                    sigma=iv_data_trim[c.SIGMA])
        except RuntimeError as e:
            raise MultiFitError(f'RuntimeError occured in stage 3. \n'
                                f'Original error: {e}')

        if plot_fl:
            fig, ax = plt.subplots(3, sharex=True, sharey=True)
            stage1_f_data.plot(ax=ax[0])
            ax[0].set_xlabel('')
            ax[0].set_ylabel('Current (A)')

            stage2_f_data.plot(ax=ax[1])
            ax[1].set_xlabel('')
            ax[1].set_ylabel('Current (A)')

            stage3_f_data.plot(ax=ax[2])
            ax[2].set_xlabel('Voltage (V)')
            ax[2].set_ylabel('Current (A)')

            fig.suptitle('lower_offset = {}, upper_offset = {}'.format(
                self.trim_beg, self.trim_end))

        return stage3_f_data
Esempio n. 12
0
                           (flopter.core.constants.ELEM_CHARGE * n_e))
        c_s = np.sqrt(
            (flopter.core.constants.ELEM_CHARGE * (T_e + gamma_i * T_i)) / m_i)
        a = ((c_1 + (c_2 / np.tan(np.radians(alpha)))) /
             np.sqrt(np.sin(np.radians(alpha)))) * (lambda_D / (L + g))
        I_0 = n_e * flopter.core.constants.ELEM_CHARGE * c_s * A_coll
        J_0 = I_0 / A_coll
        q_par = 8 * T_e * J_0
        print('Heat flux: {}'.format(q_par))
        # I_0 = n_e * nrm.ELEM_CHARGE * c_s * np.sin(np.radians(alpha)) * A_probe
        isats_def.append(I_0)

        I = I_0 * (1 + (a * np.float_power(np.abs(V), .75)) - np.exp(-V))
        currents[alpha] = I

        fitter = f.FullIVFitter()
        temps_t = []
        temps_err_t = []
        isats_t = []
        isats_err_t = []
        count = 0
        for i in range(num_samples):
            noisey = (0.09 * (np.random.rand(len(I)) - 0.5)) + I
            try:
                fit_data = fitter.fit(V_range, noisey)
            except RuntimeError:
                count += 1
                continue
            if i == 0 and alpha == 10.5 and v_max == 100 and plot_fl:
                # plt.figure()
                # plt.plot(V_range, I, label='Analytical')