示例#1
0
def compare_moments(sc,
                    mode,
                    species,
                    start_date,
                    end_date,
                    scpot_correction=False,
                    ephoto_correction=False):
    '''
    Compare moments derived from the 3D velocity distribution functions
    from three sources: official FPI moments, derived herein, and those
    of an equivalent Maxwellian distribution derived herein.
    
    Parameters
    ----------
    sc : str
        Spacecraft identifier. Choices are ('mms1', 'mms2', 'mms3', 'mms4')
    mode : str
        Data rate mode. Choices are ('fast', 'brst')
    species : str
        Particle species. Choices are ('i', 'e') for ions and electrons,
        respectively
    start_date, end_date : `datetime.datetime`
        Start and end dates and times of the time interval
    scpot_correction : bool
        Apply spacecraft potential correction to the distribution functions.
    ephoto : bool
        Subtract photo-electrons. Applicable to DES data only.
    
    Returns
    -------
    fig : `matplotlib.figure`
        Figure in which graphics are displayed
    ax : list
        List of `matplotlib.pyplot.axes` objects
    '''
    # Read the data
    moms_xr = fpi.load_moms(sc=sc,
                            mode=mode,
                            optdesc='d' + species + 's-moms',
                            start_date=start_date,
                            end_date=end_date)
    dist_xr = fpi.load_dist(sc=sc,
                            mode=mode,
                            optdesc='d' + species + 's-dist',
                            start_date=start_date,
                            end_date=end_date,
                            ephoto=ephoto_correction)

    # Spacecraft potential correction
    scpot = None
    if scpot_correction:
        edp_mode = mode if mode == 'brst' else 'fast'
        scpot = edp.load_scpot(sc=sc,
                               mode=edp_mode,
                               start_date=start_date,
                               end_date=end_date)
        scpot = scpot.interp_like(moms_xr, method='nearest')

    # Create an equivalent Maxwellian distribution
    max_xr = fpi.maxwellian_distribution(dist_xr['dist'], moms_xr['density'],
                                         moms_xr['velocity'], moms_xr['t'])

    # Density
    ni_xr = fpi.density(dist_xr['dist'], scpot=scpot)
    ni_max_dist = fpi.density(max_xr, scpot=scpot)

    # Entropy
    s_xr = fpi.entropy(dist_xr['dist'], scpot=scpot)
    s_max_dist = fpi.entropy(max_xr, scpot=scpot)
    s_max = fpi.maxwellian_entropy(moms_xr['density'], moms_xr['p'])

    # Velocity
    v_xr = fpi.velocity(dist_xr['dist'], N=ni_xr, scpot=scpot)
    v_max_dist = fpi.velocity(max_xr, N=ni_max_dist, scpot=scpot)

    # Temperature
    T_xr = fpi.temperature(dist_xr['dist'], N=ni_xr, V=v_xr, scpot=scpot)
    T_max_dist = fpi.temperature(max_xr,
                                 N=ni_max_dist,
                                 V=v_max_dist,
                                 scpot=scpot)

    # Pressure
    P_xr = fpi.pressure(dist_xr['dist'], N=ni_xr, T=T_xr)
    P_max_dist = fpi.pressure(max_xr, N=ni_max_dist, T=T_max_dist)

    # Scalar pressure
    p_scalar_xr = (P_xr[:, 0, 0] + P_xr[:, 1, 1] + P_xr[:, 2, 2]) / 3.0
    p_scalar_max_dist = (P_max_dist[:, 0, 0] + P_max_dist[:, 1, 1] +
                         P_max_dist[:, 2, 2]) / 3.0

    p_scalar_xr = p_scalar_xr.drop(['t_index_dim1', 't_index_dim2'])
    p_scalar_max_dist = p_scalar_max_dist.drop(
        ['t_index_dim1', 't_index_dim2'])

    # Epsilon
    e_xr = fpi.epsilon(dist_xr['dist'], dist_max=max_xr, N=ni_xr)

    nrows = 6
    ncols = 3
    figsize = (10.0, 5.5)
    fig, axes = plt.subplots(nrows=nrows,
                             ncols=ncols,
                             figsize=figsize,
                             squeeze=False)

    # Density
    ax = axes[0, 0]
    moms_xr['density'].attrs['label'] = 'moms'
    ni_xr.attrs['label'] = 'dist'
    ni_max_dist.attrs['label'] = 'max'
    ax = util.plot([moms_xr['density'], ni_xr, ni_max_dist],
                   ax=ax,
                   labels=['moms', 'dist', 'max'],
                   xaxis='off',
                   ylabel='N\n($cm^{-3}$)')

    # Entropy
    ax = axes[1, 0]
    ax = util.plot([s_max, s_xr, s_max_dist],
                   ax=ax,
                   labels=['moms', 'dist', 'max dist'],
                   xaxis='off',
                   ylabel='S\n[J/K/$m^{3}$ ln($s^{3}/m^{6}$)]')

    # Epsilon
    ax = axes[1, 0].twinx()
    e_xr.plot(ax=ax, color='r')
    ax.spines['right'].set_color('red')
    ax.yaxis.label.set_color('red')
    ax.tick_params(axis='y', colors='red')
    ax.set_title('')
    ax.set_xticks([])
    ax.set_xlabel('')
    ax.set_ylabel('$\epsilon$\n$(s/m)^{3/2}$')

    # Vx
    ax = axes[2, 0]
    ax = util.plot([moms_xr['velocity'][:, 0], v_xr[:, 0], v_max_dist[:, 0]],
                   ax=ax,
                   labels=['moms', 'dist', 'max'],
                   xaxis='off',
                   ylabel='Vx\n(km/s)')

    # Vy
    ax = axes[3, 0]
    ax = util.plot([moms_xr['velocity'][:, 1], v_xr[:, 1], v_max_dist[:, 1]],
                   ax=ax,
                   labels=['moms', 'dist', 'max'],
                   xaxis='off',
                   ylabel='Vy\n(km/s)')

    # Vz
    ax = axes[4, 0]
    ax = util.plot([moms_xr['velocity'][:, 2], v_xr[:, 2], v_max_dist[:, 2]],
                   ax=ax,
                   labels=['moms', 'dist', 'max'],
                   xaxis='off',
                   ylabel='Vz\n(km/s)')

    # Scalar Pressure
    ax = axes[5, 0]
    ax = util.plot([moms_xr['p'], p_scalar_xr, p_scalar_max_dist],
                   ax=ax,
                   labels=['moms', 'dist', 'max'],
                   xlabel='',
                   ylabel='p\n(nPa)')

    # T_xx
    ax = axes[0, 1]
    ax = util.plot(
        [moms_xr['temptensor'][:, 0, 0], T_xr[:, 0, 0], T_max_dist[:, 0, 0]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xaxis='off',
        ylabel='Txx\n(eV)')

    # T_yy
    ax = axes[1, 1]
    ax = util.plot(
        [moms_xr['temptensor'][:, 1, 1], T_xr[:, 1, 1], T_max_dist[:, 1, 1]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xaxis='off',
        ylabel='Tyy\n(eV)')

    # T_zz
    ax = axes[2, 1]
    ax = util.plot(
        [moms_xr['temptensor'][:, 2, 2], T_xr[:, 2, 2], T_max_dist[:, 2, 2]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xaxis='off',
        ylabel='Tzz\n(eV)')

    # T_xy
    ax = axes[3, 1]
    ax = util.plot(
        [moms_xr['temptensor'][:, 0, 1], T_xr[:, 0, 1], T_max_dist[:, 0, 1]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xaxis='off',
        ylabel='Txy\n(eV)')

    # T_xz
    ax = axes[4, 1]
    ax = util.plot(
        [moms_xr['temptensor'][:, 0, 2], T_xr[:, 0, 2], T_max_dist[:, 0, 2]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xaxis='off',
        ylabel='Txz\n(eV)')

    # T_yz
    ax = axes[5, 1]
    ax = util.plot(
        [moms_xr['temptensor'][:, 1, 2], T_xr[:, 1, 2], T_max_dist[:, 1, 2]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xlabel='',
        ylabel='Txz\n(eV)')

    # P_xx
    ax = axes[0, 2]
    ax = util.plot(
        [moms_xr['prestensor'][:, 0, 0], P_xr[:, 0, 0], P_max_dist[:, 0, 0]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xaxis='off',
        ylabel='Pxx\n(nPa)')

    # P_yy
    ax = axes[1, 2]
    ax = util.plot(
        [moms_xr['prestensor'][:, 1, 1], P_xr[:, 1, 1], P_max_dist[:, 1, 1]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xaxis='off',
        ylabel='Pyy\n(nPa)')

    # P_zz
    ax = axes[2, 2]
    ax = util.plot(
        [moms_xr['prestensor'][:, 2, 2], P_xr[:, 2, 2], P_max_dist[:, 2, 2]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xaxis='off',
        ylabel='Pzz\n(nPa)')

    # P_xy
    ax = axes[3, 2]
    ax = util.plot(
        [moms_xr['prestensor'][:, 0, 1], P_xr[:, 0, 1], P_max_dist[:, 0, 1]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xaxis='off',
        ylabel='Pxy\n(nPa)')

    # P_xz
    ax = axes[4, 2]
    ax = util.plot(
        [moms_xr['prestensor'][:, 0, 2], P_xr[:, 0, 2], P_max_dist[:, 0, 2]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xaxis='off',
        ylabel='Pxz\n(nPa)')

    # P_yz
    ax = axes[5, 2]
    ax = util.plot(
        [moms_xr['prestensor'][:, 1, 2], P_xr[:, 1, 2], P_max_dist[:, 1, 2]],
        ax=ax,
        labels=['moms', 'dist', 'max'],
        xlabel='',
        ylabel='Pyz\n(nPa)')

    fig.suptitle(
        'Comparing FPI Moments, Integrated Distribution, Equivalent Maxwellian'
    )
    plt.subplots_adjust(left=0.1,
                        right=0.90,
                        top=0.95,
                        bottom=0.12,
                        hspace=0.3,
                        wspace=0.8)
    return fig, axes
示例#2
0
def kinetic_entropy(sc, mode, start_date, end_date):
    
    # Read the data
    b = fgm.load_data(sc, mode, start_date, end_date)
    dis_moms = fpi.load_moms(sc, mode, 'i', start_date, end_date)
    des_moms = fpi.load_moms(sc, mode, 'e', start_date, end_date)
    dis_dist = fpi.load_dist(sc, mode, 'i', start_date, end_date)
    des_dist = fpi.load_dist(sc, mode, 'e', start_date, end_date)
    
    # Philosopy
    #   - For the Maxwellian distributions, use the FPI moments data
    #     whenever possible
    #   - For the integrated moments, do not mix them with FPI moments
    
    # Equivalent Maxwellian distribution
    dis_max_dist = fpi.maxwellian_distribution(dis_dist,
                                               N=dis_moms['density'],
                                               bulkv=dis_moms['velocity'],
                                               T=dis_moms['t'])
    des_max_dist = fpi.maxwellian_distribution(des_dist,
                                               N=des_moms['density'],
                                               bulkv=des_moms['velocity'],
                                               T=des_moms['t'])
    
    # Spacecraft potential correction
    edp_mode = mode if mode == 'brst' else 'fast'
    scpot = edp.load_scpot(sc, edp_mode, start_date, end_date)
    scpot_dis = scpot.interp_like(dis_moms, method='nearest')
    scpot_des = scpot.interp_like(des_moms, method='nearest')
    
    # Maxwellian entropy density
    #   - Calculated from FPI moments to stick with philosophy
#    si_dist = fpi.entropy(dis_dist, scpot=scpot_dis)
#    se_dist = fpi.entropy(des_dist, scpot=scpot_des)
    
    si_max = fpi.maxwellian_entropy(dis_moms['density'], dis_moms['p'])
    se_max = fpi.maxwellian_entropy(des_moms['density'], des_moms['p'])
    
    # Velocity space entropy density
    siv_dist = fpi.vspace_entropy(dis_dist,
#                                  N=dis_moms['density'],
#                                  s=si_dist,
                                  scpot=scpot_dis)
    sev_dist = fpi.vspace_entropy(des_dist,
#                                  N=des_moms['density'],
#                                  s=se_dist,
                                  scpot=scpot_des)
    
    siv_max = fpi.vspace_entropy(dis_max_dist,
                                 N=dis_moms['density'],
                                 s=si_max,
                                 scpot=scpot_dis)
    sev_max = fpi.vspace_entropy(des_max_dist,
                                 N=des_moms['density'],
                                 s=se_max,
                                 scpot=scpot_des)
    
    # M-bar
    miv_bar = np.abs(siv_max - siv_dist) / siv_max
    mev_bar = np.abs(sev_max - sev_dist) / sev_max
    
    # Anisotropy
    Ai = dis_moms['temppara'] / dis_moms['tempperp'] - 1
    Ae = des_moms['temppara'] / des_moms['tempperp'] - 1
    
    nrows = 8
    ncols = 1
    figsize = (5.5, 7.0)
    fig, axes = plt.subplots(nrows=nrows, ncols=ncols,
                             figsize=figsize, squeeze=False)
    
    # B
    ax = axes[0,0]
    ax = util.plot([b['B'][:,3], b['B'][:,0], b['B'][:,1], b['B'][:,2]],
                   ax=ax, labels=['|B|', 'Bx', 'By', 'Bz'],
                   xaxis='off', ylabel='B\n(nT)'
                   )
    
    # N
    ax = axes[1,0]
    ax = util.plot([dis_moms['density'], des_moms['density']],
                   ax=ax, labels=['Ni', 'Ne'],
                   xaxis='off', ylabel='N\n($cm^{-3}$)'
                   )
    
    # Velocity space ion entropy density
    ax = axes[2,0]
    ax = util.plot([siv_max, siv_dist],
                   ax=ax, labels=['$s_{i,V,max}$', '$s_{i,V}$'],
                   xaxis='off', ylabel='$s_{V}$\n$J/K/m^{3}$ $ln()$'
                   )
    
    # Velocity space electron entropy density
    ax = axes[3,0]
    ax = util.plot([sev_max, sev_dist],
                   ax=ax, labels=['$s_{e,V,max}$', '$s_{e,V}$'],
                   xaxis='off', ylabel='$s_{V}$'
                   )
    
    # Velocity space M-bar
    ax = axes[4,0]
    ax = util.plot([miv_bar, mev_bar],
                   ax=ax, labels=['$\overline{M}_{i,V}$', '$\overline{M}_{e,V}$'],
                   xaxis='off', ylabel='$\overline{M}_{V}$'
                   )
    
    # Ion temperature
    ax = axes[5,0]
    ax = util.plot([dis_moms['temppara'], dis_moms['tempperp'], dis_moms['t']],
                   ax=ax, labels=['$T_{\parallel}$', '$T_{\perp}$, $T$'],
                   xaxis='off', ylabel='$T_{i}$\n(eV)'
                   )
    
    # Electron temperature
    ax = axes[6,0]
    ax = util.plot([des_moms['temppara'], des_moms['tempperp'], des_moms['t']],
                   ax=ax, labels=['$T_{\parallel}$', '$T_{\perp}$, $T$'],
                   xaxis='off', ylabel='$T_{e}$\n(eV)'
                   )
    
    # Anisotropy
    ax = axes[7,0]
    ax = util.plot([Ai, Ae],
                   ax=ax, labels=['$A_{i}$', '$A_{e}$'],
                   ylabel='A'
                   )
    
    fig.suptitle('Plasma Parameters for Kinetic and Boltzmann Entropy')
    plt.subplots_adjust(left=0.2, right=0.85, top=0.95, hspace=0.4)
#    plt.setp(axes, xlim=xlim)
    return fig, axes
示例#3
0
def plot_photocurrent():

    # Download the data
    scpot = edp.load_scpot(sc=sc,
                           mode=mode,
                           start_date=orbit_t0,
                           end_date=orbit_t1)
    dis_moms = fpi.load_moms(sc=sc,
                             mode=mode,
                             optdesc='dis-moms',
                             start_date=orbit_t0,
                             end_date=orbit_t1)
    des_moms = fpi.load_moms(sc=sc,
                             mode=mode,
                             optdesc='des-moms',
                             start_date=orbit_t0,
                             end_date=orbit_t1)
    aspoc = mms_util.load_data(sc=sc,
                               instr='aspoc',
                               mode='srvy',
                               level='l2',
                               start_date=orbit_t0,
                               end_date=orbit_t1)

    # Bin data into FPI time stamps
    t_bins = np.append(
        dis_moms['time'].data - dis_moms['Epoch_minus_var'].data,
        dis_moms['time'].data[-1] + dis_moms['Epoch_plus_var'].data)
    Vsc, edges, binnum = binned_statistic(scpot['time'].astype('i8'),
                                          scpot['Vsc'],
                                          statistic='mean',
                                          bins=t_bins.astype('i8'))

    asp1, edges, binnum = binned_statistic(aspoc['Epoch'].astype('i8'),
                                           aspoc[sc + '_asp1_ionc'],
                                           statistic='mean',
                                           bins=t_bins.astype('i8'))

    idx = 0
    data_bin = []
    asp2 = np.empty_like(asp1)
    asp_on = np.zeros(asp1.shape, dtype='?')
    ref_idx = binnum[0]

    for aspoc_idx, bin_idx in enumerate(binnum):
        if (bin_idx == 0) | (bin_idx == len(aspoc[sc + '_asp1_ionc'])):
            continue
        elif ref_idx == 0:
            ref_idx = bin_idx

        if bin_idx == ref_idx:
            data_bin.append(aspoc_idx)
        else:
            asp2[idx] = aspoc[sc + '_asp2_ionc'][data_bin].mean()
            asp_on[idx] = aspoc[sc + '_aspoc_status'][data_bin, 3].max() > 0
            idx += 1
            ref_idx = bin_idx
            data_bin = [aspoc_idx]

    Vsc = xr.DataArray(Vsc, dims='time', coords={'time': dis_moms['time']})
    asp = xr.Dataset(
        {
            'asp1': (['time'], asp1),
            'asp2': (['time'], asp2),
            'asp': (['time'], asp1 + asp2)
        },
        coords={'time': dis_moms['time']})

    # Electron current
    Ie = electron_current(des_moms['density'], des_moms['t'], Vsc)

    # Flag the data
    flag = xr.DataArray(asp_on.astype('int'),
                        dims='time',
                        coords={'time': dis_moms['time']})
    flag += (((Ie < 1e-11) & (Vsc > 8) & (Vsc < 11)) * 2**1)
    flag += (((Vsc > 14.75) & (Ie > 7.9e-12) & (Ie < 2e-11)) * 2**2)
    flag += (((Vsc > 12.6) & (Vsc <= 14.75) & (Ie > 9.2e-12) & (Ie < 2e-11)) *
             2**2)

    #
    # Fit the data
    #

    # Ie = Iph0 exp(-Vsc/Vph0)
    # y = a exp(b * x)
    # log(y) = log(a) + b*x
    b, a = np.polyfit(Vsc[flag == 0],
                      np.log(Ie[flag == 0]),
                      1,
                      w=np.sqrt(Ie[flag == 0]))
    Ie_fit = np.exp(a) * np.exp(b * Vsc[flag == 0])
    str_fit = ('Ie = {0:0.3e} exp(-Vsc/{1:0.3e})'.format(
        np.exp(a), 1 / np.exp(b)))

    # Fit density to the spacecraft potential
    c, b, a = np.polyfit(Vsc[flag == 0], des_moms['density'][flag == 0], 2)
    Ne_fit2 = c * Vsc[flag == 0]**2 + b * Vsc[flag == 0] + a
    str_Ne_fit2 = ('Ne = {0:0.3e}Vsc^2 + {1:0.3e}Vsc^1 + {2:0.3e})'.format(
        c, b, a))

    e, d, c, b, a = np.polyfit(Vsc[flag == 0], des_moms['density'][flag == 0],
                               4)
    Ne_fit4 = e * Vsc[flag == 0]**4 + d * Vsc[flag == 0]**3 + c * Vsc[
        flag == 0]**2 + b * Vsc[flag == 0] + a
    str_Ne_fit4 = (
        'Ne = {0:0.3e}Vsc^4 + {1:0.3e}Vsc^3 + {2:0.3e}Vsc^2 + {3:0.3e}Vsc + {4:0.3e})'
        .format(e, d, c, b, a))

    # Fit density to the inverse of the spacecraft potential
    c, b, a = np.polyfit(1 / Vsc[flag == 0], des_moms['density'][flag == 0], 2)
    invV_fit2 = c / Vsc[flag == 0]**2 + b / Vsc[flag == 0] + a
    str_invV_fit2 = ('Ne = {0:0.3e}/Vsc^2 + {1:0.3e}/Vsc + {2:0.3e})'.format(
        c, b, a))

    e, d, c, b, a = np.polyfit(1 / Vsc[flag == 0],
                               des_moms['density'][flag == 0], 4)
    invV_fit4 = e / Vsc[flag == 0]**4 + d / Vsc[flag == 0]**3 + c / Vsc[
        flag == 0]**2 + b / Vsc[flag == 0] + a
    str_invV_fit4 = (
        'Ne = {0:0.3e}/Vsc^4 + {1:0.3e}/Vsc^3 + {2:0.3e}/Vsc^2 + {3:0.3e}/Vsc + {4:0.3e})'
        .format(e, d, c, b, a))

    #
    # Plot: Time Series
    #

    # Plot current-related data
    fig1, axes1 = plt.subplots(nrows=8,
                               ncols=1,
                               sharex=True,
                               figsize=(5, 6.5),
                               squeeze=False)
    plt.subplots_adjust(left=0.17, right=0.85, bottom=0.14, top=0.95)

    # Ion energy spectrogram
    nt = dis_moms['omnispectr'].shape[0]
    nE = dis_moms['omnispectr'].shape[1]
    x0 = mdates.date2num(dis_moms['time'])[:, np.newaxis].repeat(nE, axis=1)
    x1 = dis_moms['energy']

    y = np.where(dis_moms['omnispectr'] == 0, 1, dis_moms['omnispectr'])
    y = np.log(y[0:-1, 0:-1])

    ax = axes1[0, 0]
    im = ax.pcolorfast(x0, x1, y, cmap='nipy_spectral')
    ax.images.append(im)
    ax.set_title(sc.upper())
    ax.set_yscale('log')
    ax.set_ylabel('E (ion)\n(eV)')
    util.format_axes(ax, xaxis='off')
    cb = util.add_colorbar(ax, im)
    cb.set_label('$log_{10}$DEF\nkeV/($cm^{2}$ s sr keV)')

    # Electron energy spectrogram
    nt = des_moms['omnispectr'].shape[0]
    nE = des_moms['omnispectr'].shape[1]
    x0 = mdates.date2num(des_moms['time'])[:, np.newaxis].repeat(nE, axis=1)
    x1 = des_moms['energy']

    y = np.where(des_moms['omnispectr'] == 0, 1, des_moms['omnispectr'])
    y = np.log(y[0:-1, 0:-1])

    ax = axes1[1, 0]
    im = ax.pcolorfast(x0, x1, y, cmap='nipy_spectral')
    ax.images.append(im)
    ax.set_yscale('log')
    ax.set_ylabel('E (e-)\n(eV)')
    util.format_axes(ax, xaxis='off')
    cb = util.add_colorbar(ax, im)
    cb.set_label('$log_{10}$DEF\nkeV/($cm^{2}$ s sr keV)')

    # Density
    ax = axes1[2, 0]
    l1 = dis_moms['density'].plot(ax=ax, label='$N_{i}$')
    l2 = des_moms['density'].plot(ax=ax, label='$N_{e}$')
    ax.set_title('')
    ax.set_ylabel('N\n($cm^{3}$)')
    ax.set_yscale('log')
    util.format_axes(ax, xaxis='off')
    util.add_legend(ax, [l1[0], l2[0]])

    # Temperature
    ax = axes1[3, 0]
    l1 = dis_moms['t'].plot(ax=ax, label='$T_{i}$')
    l2 = des_moms['t'].plot(ax=ax, label='$T_{e}$')
    util.format_axes(ax, xaxis='off')
    util.add_legend(ax, [l1[0], l2[0]])
    ax.set_title('')
    ax.set_ylabel('T\n(eV)')
    ax.set_yscale('log')

    # Spacecraft potential
    ax = axes1[4, 0]
    Vsc[~asp_on].plot(ax=ax)
    Vsc[asp_on].plot(ax=ax, color='red')
    util.format_axes(ax, xaxis='off')
    ax.set_title('')
    ax.set_ylabel('$V_{S/C}$\n(V)')

    # Electron current
    ax = axes1[5, 0]
    Ie.plot(ax=ax)
    ax.set_title('')
    ax.set_ylabel('$I_{e}$\n($\mu A$)')
    ax.set_yscale('log')
    ax.set_ylim([1e-12, 1e-10])
    util.format_axes(ax, xaxis='off')

    # Aspoc Status
    ax = axes1[6, 0]
    l1 = asp['asp1'].plot(ax=ax, label='$ASP_{1}$')
    l2 = asp['asp2'].plot(ax=ax, label='$ASP_{2}$')
    l3 = asp['asp'].plot(ax=ax, label='$ASP_{tot}$')
    util.format_axes(ax, xaxis='off')
    util.add_legend(ax, [l1[0], l2[0], l3[0]])
    ax.set_title('')
    ax.set_xlabel('')
    ax.set_ylabel('$I_{ASPOC}$\n($\mu A$)')

    # Flag
    ax = axes1[7, 0]
    flag.plot(ax=ax)
    util.format_axes(ax)
    ax.set_title('')
    ax.set_xlabel('')
    ax.set_ylabel('Flag')

    #
    # Plot: Photocurrent Fit
    #

    # Plot the data
    fig2, axes = plt.subplots(nrows=3,
                              ncols=1,
                              figsize=[5, 5.5],
                              squeeze=False)
    plt.subplots_adjust(left=0.15, right=0.95, top=0.94)

    # I_ph = I_ph0 exp(Vsc/Vph0)
    ax = axes[0, 0]
    ax.scatter(Vsc[flag == 0], Ie[flag == 0], marker='o')
    ax.scatter(Vsc[np.bitwise_and(flag, 2**0) > 0],
               Ie[np.bitwise_and(flag, 2**0) > 0],
               marker='o',
               color='red')
    ax.scatter(Vsc[np.bitwise_and(flag, 2**1) > 0],
               Ie[np.bitwise_and(flag, 2**1) > 0],
               marker='o',
               color='purple')
    ax.scatter(Vsc[np.bitwise_and(flag, 2**2) > 0],
               Ie[np.bitwise_and(flag, 2**2) > 0],
               marker='o',
               color='green')
    ax.plot(Vsc[flag == 0], Ie_fit, color='black')
    ax.set_title(
        'Photocurrent Parameters $I_{e} = -I_{ph0} \exp(V_{S/C}/V_{ph0})$')
    ax.set_xlabel('$V_{S/C}$ (V)')
    ax.set_ylabel('$I_{e}$\n($\mu A$)')
    ax.set_yscale('log')
    ax.set_ylim([
        10**np.floor(np.log10(Ie.min().values)),
        10**np.ceil(np.log10(Ie.max().values))
    ])
    ax.text(0.9 * ax.get_xlim()[1],
            0.7 * ax.get_ylim()[1],
            str_fit,
            horizontalalignment='right',
            verticalalignment='bottom',
            color='black')

    # Ne = \Sum a_i * V^i
    ax = axes[1, 0]
    ax.scatter(Vsc[flag == 0], des_moms['density'][flag == 0], marker='o')
    ax.scatter(Vsc[np.bitwise_and(flag, 2**0) > 0],
               des_moms['density'][np.bitwise_and(flag, 2**0) > 0],
               marker='o',
               color='red')
    ax.scatter(Vsc[np.bitwise_and(flag, 2**1) > 0],
               des_moms['density'][np.bitwise_and(flag, 2**1) > 0],
               marker='o',
               color='purple')
    ax.scatter(Vsc[np.bitwise_and(flag, 2**2) > 0],
               des_moms['density'][np.bitwise_and(flag, 2**2) > 0],
               marker='o',
               color='green')
    ax.plot(Vsc[flag == 0], Ne_fit2, color='black')
    ax.plot(Vsc[flag == 0], Ne_fit4, color='grey')
    ax.set_title('')
    ax.set_xlabel('$V_{S/C}$ (V)')
    ax.set_ylabel('$N_{e}$\n($cm^{-3}$)')
    ax.text(0.98 * ax.get_xlim()[1],
            0.85 * ax.get_ylim()[1],
            str_Ne_fit2,
            horizontalalignment='right',
            verticalalignment='bottom',
            color='black')
    ax.text(0.98 * ax.get_xlim()[1],
            0.75 * ax.get_ylim()[1],
            str_Ne_fit4,
            horizontalalignment='right',
            verticalalignment='bottom',
            color='grey')

    # Ne = \Sum a_i * V^-i
    ax = axes[2, 0]
    ax.scatter(1 / Vsc[flag == 0], des_moms['density'][flag == 0], marker='o')
    ax.scatter(1 / Vsc[np.bitwise_and(flag, 2**0) > 0],
               des_moms['density'][np.bitwise_and(flag, 2**0) > 0],
               marker='o',
               color='red')
    ax.scatter(1 / Vsc[np.bitwise_and(flag, 2**1) > 0],
               des_moms['density'][np.bitwise_and(flag, 2**1) > 0],
               marker='o',
               color='purple')
    ax.scatter(1 / Vsc[np.bitwise_and(flag, 2**2) > 0],
               des_moms['density'][np.bitwise_and(flag, 2**2) > 0],
               marker='o',
               color='green')
    ax.plot(Vsc[flag == 0], invV_fit2, color='black')
    ax.plot(Vsc[flag == 0], invV_fit4, color='grey')
    ax.set_title('')
    ax.set_xlabel('1/$V_{S/C}$ ($V^{-1}$)')
    ax.set_ylabel('$N_{e}$\n($cm^{-3}$)')
    ax.text(0.98 * ax.get_xlim()[1],
            0.85 * ax.get_ylim()[1],
            str_invV_fit2,
            horizontalalignment='right',
            verticalalignment='bottom',
            color='black')
    ax.text(0.98 * ax.get_xlim()[1],
            0.75 * ax.get_ylim()[1],
            str_invV_fit4,
            horizontalalignment='right',
            verticalalignment='bottom',
            color='grey')

    return [fig1, fig2], ax