Beispiel #1
0
def _downsample(b_xyz, dt):
    delta_t = (b_xyz.time.data[-1] - b_xyz.time.data[0]).view("i8") * 1e-9
    n_t = int(delta_t / dt)
    timeline = b_xyz.time.data[0].copy()
    timeline += (np.linspace(0, delta_t, n_t) * 1e9).astype(int)
    timeline = ts_scalar(timeline, np.zeros(len(timeline)))
    return resample(b_xyz, timeline)
Beispiel #2
0
def pressure_balance_b0(b_xyz=None, moments_i=None, moments_e=None):
    """Compute lobe magnetic field using pressure balance condition

    Parameters
    ----------
    b_xyz : xarray.DataArray
        Time series of the magnetic field.

    moments_i : list of xarray.DataArray
        Time series of the moments of the ion VDF.

    moments_e : list of xarray.DataArray
        Time series of the moments of the electron VDF.

    Returns
    -------
    b0 : xarray.DataArray
        Time series of the lobe field.

    """
    # Unpack pressure tensors
    p_xyz_i, p_xyz_e = [moments_i[-1], moments_e[-1]]

    # Compute total pressure tensor
    p_xyz = p_xyz_i + resample(p_xyz_e, p_xyz_i)

    # Transform to field aligned coordinates
    p_xyzfac = rotate_tensor(p_xyz, "fac", b_xyz, "pp")

    # Estimate magnetic field in the lobe using pressure balance
    mu0 = constants.mu0.value  # magnetic permittivity

    p_th, p_b = [1e-9 * trace(p_xyzfac), 1e-18 * norm(b_xyz)**2 / (2 * mu0)]

    # Compute plasma parameter
    beta = resample(p_th, p_b) / p_b

    # Compute lobe field using pressure balance
    b0 = b_xyz * np.sqrt(1 + beta)

    return b0
Beispiel #3
0
def st_derivative(r, b, mva, crossing_times):
    """
    Computes velocity of the structure using spatio-temporal derivative method
    """

    b_xyz = avg_4sc(b)

    # Gradient of the magnetic field
    grad_b = c_4_grad(r, b)
    db_dt = gradient(b_xyz)

    # Transform gradient to LMN frame
    l_grad_b = np.matmul(grad_b.data, mva[:, 0])
    m_grad_b = np.matmul(grad_b.data, mva[:, 1])
    n_grad_b = np.matmul(grad_b.data, mva[:, 2])

    # Compute velocity of the structure using MDD
    v_str = np.zeros(db_dt.shape)
    v_str[:, 0] = np.sum(db_dt * l_grad_b, axis=1) / np.linalg.norm(l_grad_b,
                                                                    axis=1)**2
    v_str[:, 1] = np.sum(db_dt * m_grad_b, axis=1) / np.linalg.norm(m_grad_b,
                                                                    axis=1)**2
    v_str[:, 2] = np.sum(db_dt * n_grad_b, axis=1) / np.linalg.norm(n_grad_b,
                                                                    axis=1)**2

    dt = calc_dt(b_xyz)
    y_m = np.abs(np.cumsum(-v_str[:, 1]) * dt)
    z_n = np.cumsum(-v_str[:, 2]) * dt

    v_str = ts_vec_xyz(b_xyz.time.data, -v_str)
    y_m = ts_scalar(b_xyz.time.data, y_m)
    z_n = ts_scalar(b_xyz.time.data, z_n)

    z_off = resample(t_eval(z_n, crossing_times), y_m)
    z_n -= z_off

    return v_str, y_m, z_n
Beispiel #4
0
def main(args):
    """main function
    """

    with open(args.config) as f:
        cfg = yaml.load(f, Loader=yaml.FullLoader)

    tint = cfg["tint"]

    # Spacecraft indices
    mms_ids = np.arange(1, 5)

    # Load spacecraft position and background magnetic field
    r_mms = [
        get_data("R_gse", tint, i, args.verbose, data_path=cfg["data_path"])
        for i in mms_ids
    ]

    # Load background magnetic field
    suf_b = "fgm_{}_{}".format(cfg["fgm"]["data_rate"], cfg["fgm"]["level"])
    b_mms = [
        get_data("B_gse_{}".format(suf_b),
                 tint,
                 i,
                 args.verbose,
                 data_path=cfg["data_path"]) for i in mms_ids
    ]

    # Remove offset on z component of the background magnetic field
    b_mms = remove_bz_offset(b_mms)

    # Compute current density
    j_xyz, div_b, b_xyz, _, _, _ = c_4_j(r_mms, b_mms)

    # j A.m^{-2}->nA.m^{-2}
    j_xyz *= 1e9

    # Load moments
    moments_i, moments_e = load_moments(tint, cfg["fpi"], args,
                                        cfg["data_path"])

    # Resample moments to magnetic field sampling
    moments_i = [resample(mom, b_xyz) for mom in moments_i]
    moments_e = [resample(mom, b_xyz) for mom in moments_e]

    lmn = lmn_cs(b_xyz, moments_i[1])

    # Transform fields to MVA frame
    b_lmn, j_lmn = [new_xyz(field, lmn) for field in [b_xyz, j_xyz]]

    # Compute dispersion relation using either Jn of the timing
    # Estimate phase velocity using normal current density
    disprel_jn = calc_vph_current(b_lmn, j_lmn)

    # Load timing data
    timing_lr = load_timing(args.timing)
    timing_ts = load_timing(args.table_wei2019)

    # Unpack slowness vector
    m_xyz, _ = [timing_lr.m, timing_lr.dm]
    m_lmn = new_xyz(m_xyz, lmn)

    n_lmn = new_xyz(timing_lr.n, lmn)
    delta = np.arccos(n_lmn[:, 1] / np.linalg.norm(n_lmn.data[:, 1:], axis=1))
    v_lmn = timing_lr.v.data[:, None] * n_lmn
    v_n = np.linalg.norm(v_lmn[:, 1:], axis=1)
    v_ph = v_n / np.cos(delta)
    v_ph[delta > np.pi / 2 - .01] = np.nan
    dv_ph = timing_lr.dv / np.cos(delta)
    dv_ph[delta > np.pi / 2 - .01] = np.nan

    # Crossing times
    crossing_times = m_xyz.time.data

    # Dispersion relation from timing
    disprel_lr = calc_disprel_tm(v_ph,
                                 dv_ph,
                                 2 * timing_lr.tau,
                                 timing_lr.dtau,
                                 ci=95)

    disprel_ts = calc_disprel_tm(timing_ts.v, timing_ts.dv, 2 * timing_ts.tau,
                                 timing_ts.dtau)

    # d_i = 527.0
    # Compute thickness of the CS using the lobe field corresponding to the
    # Harris like CS
    # Compute lobe field using Harris current sheet fit
    harris_fit = fit_harris_cs(b_lmn, j_lmn)

    # Compute thickness as h = B0/curl(B) = B0/(m0*J) and the error
    mu0 = constants.mu_0
    # continuous thickness
    h_c = norm(harris_fit.B0) / (1e3 * mu0 * norm(j_lmn))
    # discrete thickness
    h_d = t_eval(h_c, crossing_times)

    # curl of the magnetic field
    curl_b = c_4_grad(r_mms, b_mms, "curl")

    # Errors
    # relative error on curlometer technique
    dj_j = np.abs(div_b / norm(curl_b))
    # relative error on the thickness
    dh_d = h_d * t_eval(dj_j / (1 + dj_j), crossing_times)

    # Thickness from Wei 2019 table
    h_ts, dh_ts = [timing_ts.h, timing_ts.dh]

    # Compute ion inertial length to normalize the thickness
    # unpack number densities
    n_i, n_e = moments_i[0], moments_e[0]

    # Unpack ion/electron temperature
    _, _, t_i = dec_temperature(b_xyz, moments_i)
    _, _, t_e = dec_temperature(b_xyz, moments_i)

    # Compute plasma parameters
    plasma_params = plasma_calc(harris_fit.B0, t_i, t_e, n_i, n_e)

    # Averaged ion inertial length
    d_i = np.mean(plasma_params.l_i).data
    r_p = np.mean(plasma_params.rho_p).data
    r_e = np.mean(plasma_params.rho_e).data

    # Outliers indices
    ols = cfg["outliers"]

    # Fit scaling wavelength CS thickness
    scaling_lr = scaling_h_lambda(h_d[~np.isnan(v_ph)], dh_d[~np.isnan(v_ph)],
                                  disprel_lr, ols["Richard2021"])
    scaling_ts = scaling_h_lambda(h_ts, dh_ts, disprel_ts, ols["Wei2019"])

    fig6 = plt.figure(**cfg["figure"]["main"])

    gs6 = fig6.add_gridspec(2, 2, **cfg["figure"]["gridspec"])

    gs60 = gs6[:, 0].subgridspec(2, 1)
    gs61 = gs6[:, 1].subgridspec(2, 1)

    axs0 = [fig6.add_subplot(gs60[i]) for i in range(2)]
    axs1 = [fig6.add_subplot(gs61[i]) for i in range(2)]

    axs0[0], caxs00 = plot_spectr(axs0[0],
                                  disprel_jn.hist,
                                  cscale="log",
                                  cmap="viridis")
    axs0[0].plot(disprel_jn.hires_dBdt, disprel_jn.pred_Jn, "k")
    axs0[0].fill_between(disprel_jn.hires_dBdt,
                         disprel_jn.bound_upper,
                         disprel_jn.bound_lower,
                         color="lightgrey")

    labels = [
        "$J_N=${:3.2f}*d$_t B_L$".format(disprel_jn.fit_db_dt_jn.data),
        "95% CI"
    ]
    axs0[0].legend(labels, frameon=True, loc="upper right")
    axs0[0].set_xlabel("d$_t B_L$ [nT s$^{-1}$]")
    axs0[0].set_ylabel("$J_N$ [nA m$^{-2}$]")
    caxs00.set_ylabel("Counts")
    axs0[0].grid(True, which="both")
    axs0[0].set_title("$\\rho = {:3.2f}$".format(disprel_jn.rho.data))

    h_lambda = scaling_lr.h.data * scaling_lr.k.data / (2 * np.pi)
    dh_lambda = scaling_lr.h.data * scaling_lr.dk.data / (2 * np.pi)

    n_bins = optimize_nbins_1d(h_lambda)
    """
    y, edges_ = np.histogram(h_lambda, bins=n_bins)
    axs0[1].bar(0.5 * (edges_[1:] + edges_[:-1]), y,
                width=edges_[1:] - edges_[:-1], facecolor='tab:blue',
                edgecolor="k", yerr=np.sqrt(y))
    """
    #axs0[1].axvspan(0.8 / (2 * np.pi), 1.8 / (2 * np.pi), color="tab:orange")
    _, _, _ = axs0[1].hist(h_lambda, bins=n_bins, **cfg["figure"]["hist"])
    #axs0[1].errorbar(scaling_lr.scaling.data / (2 * np.pi), 16.5,
    #                 xerr=scaling_lr.sigma_scaling.data / (2 * np.pi),)
    axs0[1].axvline(scaling_lr.scaling.data / (2 * np.pi),
                    color="k",
                    linestyle="-")
    axs0[1].set_ylim([0, 17])
    axs0[1].set_yticks(np.arange(0, 17, 2))

    left_bound = (scaling_lr.scaling.data -
                  1.96 * scaling_lr.sigma_scaling.data) / (2 * np.pi)
    right_bound = (scaling_lr.scaling.data +
                   1.96 * scaling_lr.sigma_scaling.data) / (2 * np.pi)
    width = right_bound - left_bound
    _, ymax = axs0[1].get_ylim()
    height = .5
    rect_drift = plt.Rectangle((0.8 / (2 * np.pi), ymax - .5),
                               1. / (2 * np.pi),
                               .5,
                               color='tab:orange')
    rect_sigma = plt.Rectangle((left_bound, ymax - 2.1 * height),
                               width,
                               height,
                               color='lightgrey')
    axs0[1].add_patch(rect_drift)
    axs0[1].add_patch(rect_sigma)

    axs0[1].set_xlabel("$h/\\lambda$")
    axs0[1].set_ylabel("Counts")
    axs0[1].grid(True, which="both")

    axs1[0].errorbar(disprel_lr.k.data,
                     disprel_lr.omega.data,
                     disprel_lr.omega_err.data,
                     disprel_lr.k_err.data,
                     color="tab:blue",
                     **cfg["figure"]["errorbar"])

    axs1[0].errorbar(disprel_ts.k.data,
                     disprel_ts.omega.data,
                     disprel_ts.omega_err.data,
                     disprel_ts.k_err.data,
                     color="tab:red",
                     **cfg["figure"]["errorbar"])

    axs1[0].errorbar(disprel_lr.k.data[ols["Richard2021"]],
                     disprel_lr.omega.data[ols["Richard2021"]],
                     disprel_lr.omega_err.data[ols["Richard2021"]],
                     disprel_lr.k_err.data[ols["Richard2021"]],
                     color="k",
                     **cfg["figure"]["errorbar"])

    axs1[0].plot(disprel_lr.hires_k.data, disprel_lr.pred_omega.data, 'k-')
    axs1[0].fill_between(disprel_lr.hires_k.data,
                         disprel_lr.bound_lower.data,
                         disprel_lr.bound_upper.data,
                         color="lightgrey")
    axs1[0].set_xlim([0, 2.6e-3])
    axs1[0].set_ylim([0, 1])
    axs1[0].set_xlabel("$k$ [km$^{-1}$]")
    axs1[0].set_ylabel("$\\omega$ [rad s$^{-1}$]")
    labels = [
        "$\\omega$ = {:4.2f}*$k$".format(disprel_lr.vph.data[0]), "95% CI",
        "2019-09-14", "Table Wei2019"
    ]
    axs1[0].legend(labels, frameon=True, loc="upper right")

    axs1[0].yaxis.set_label_position("right")
    axs1[0].yaxis.tick_right()
    axs1[0].grid(True, which="both")

    axs1[1].errorbar(scaling_lr.k,
                     scaling_lr.h,
                     scaling_lr.dh,
                     scaling_lr.dk,
                     color="tab:blue",
                     **cfg["figure"]["errorbar"])

    axs1[1].errorbar(scaling_ts.k,
                     scaling_ts.h,
                     scaling_ts.dh,
                     scaling_ts.dk,
                     color="tab:red",
                     **cfg["figure"]["errorbar"])

    axs1[1].errorbar(scaling_lr.k_ols,
                     scaling_lr.h_ols,
                     scaling_lr.dh_ols,
                     scaling_lr.dk_ols,
                     color="k",
                     **cfg["figure"]["errorbar"])

    axs1[1].plot(scaling_lr.hires_k, scaling_lr.pred_h, "k")
    axs1[1].fill_between(scaling_lr.hires_k,
                         scaling_lr.bound_lower,
                         scaling_lr.bound_upper,
                         color="lightgrey")

    axs1[1].set_xlabel("$k$ [km$^{-1}$]")
    axs1[1].set_ylabel("$h$ [km]")
    labels = [
        f"$h=${scaling_lr.scaling.data / (2 * np.pi):3.2f}$*\\lambda$",
        "95% CI", "2019-09-14", "Table Wei2019"
    ]
    axs1[1].legend(labels, frameon=True, loc="upper right")

    axs1[1].plot(scaling_lr.hires_k,
                 0.8 / scaling_lr.hires_k,
                 color="tab:orange")
    axs1[1].plot(scaling_lr.hires_k,
                 1.8 / scaling_lr.hires_k,
                 color="tab:orange")

    axs1[1].yaxis.set_label_position("right")
    axs1[1].yaxis.tick_right()
    axs1[1].set_xlim([0, 2.6e-3])
    axs1[1].set_ylim([0, 9000])
    axs1[1].grid(True, which="both")

    # Add panels labels
    labels_pos = [0.032, 0.95]
    _ = make_labels(axs0 + axs1, labels_pos)

    if args.figname:
        fig6.savefig(args.figname, **cfg["figure"]["save"])
    else:
        plt.show()

    if args.verbose:
        b_lobe = harris_fit.b_lobe.data
        sigma_b_lobe = harris_fit.sigma_b_lobe.data

        h_h = harris_fit.scale.data / d_i
        sigma_h_h = harris_fit.sigma_scale.data / d_i

        a_j = disprel_jn.fit_db_dt_jn.data
        sigma_a_j = disprel_jn.sigma.data

        v_ph_j = 1e-3 / (constants.mu_0 * a_j)
        sigma_v_ph_j = v_ph_j * (sigma_a_j / a_j) / (1 + (sigma_a_j / a_j))

        v_ph = disprel_lr.vph.data[0]
        sigma_v_ph = disprel_lr.sigma_k_w.data[0]

        kh_ = scaling_lr.scaling.data
        sigma_kh = scaling_lr.sigma_scaling.data

        h_l = kh_ / (2 * np.pi)
        sigma_h_l = sigma_kh / (2 * np.pi)

        h_min = 1e3 * np.min(h_d.data)
        l_min = 1e3 * np.min(disprel_lr.lamb.data)

        l_lh = 2 * np.pi * np.sqrt(r_p * r_e)

        print(f"B_0 = {b_lobe:3.2f} \pm {sigma_b_lobe:3.2f} nT")
        print(f"h_H = {h_h:3.2f} \pm {sigma_h_h:3.2f} d_i")
        print(f"a = {a_j:3.2f} \pm {sigma_a_j:3.2f} s/H")
        print(f"v_ph = {v_ph_j:3.2f} \pm {sigma_v_ph_j:3.2f} km/s")
        print(f"v_ph = {v_ph:3.2f} \pm {sigma_v_ph:3.2f} km/s")
        print(f"kh = {kh_:3.2f} \pm {sigma_kh:3.2f}")
        print(f"h/\lambda = {h_l:3.2f} \pm {sigma_h_l:3.2f}")
        print(f"\lambda_min = {(l_min / d_i):3.2f} d_i")
        print(f"\lambda_min = {(l_min / r_p):3.2f} r_i")
        print(f"\lambda_LH = {(l_lh / d_i):3.2f}")
        print(f"h_min = {(h_min / d_i):3.2f} d_i")
        print(f"h_min = {(h_min / r_p):3.2f} r_i")
Beispiel #5
0
def main(args):
    """main function
    """
    
    with open(args.config) as f:
        cfg = yaml.load(f, Loader=yaml.FullLoader)

    tint = cfg["tints"]["flapping"]

    # Spacecraft indices
    mms_ids = np.arange(1, 5)

    # Load spacecraft position and background magnetic field
    r_mms = [get_data("R_gse", tint, i,
                      data_path=cfg["data_path"]) for i in mms_ids]
    
    # Load background magnetic field
    suf_b = "fgm_{}_{}".format(cfg["fgm"]["data_rate"], cfg["fgm"]["level"])
    b_mms = [get_data("B_gse_{}".format(suf_b), tint, i, args.verbose,
                      data_path=cfg["data_path"]) for i in mms_ids]

    # Remove offset on z component of the background magnetic field
    b_mms = remove_bz_offset(b_mms)

    # Load moments
    moments_i, moments_e = load_moments(tint, cfg["fpi"], args,
                                        cfg["data_path"])

    # Compute current density
    j_xyz, div_b, b_xyz, _, _, _ = c_4_j(r_mms, b_mms)
    j_xyz *= 1e9

    # Compute MVA frame
    _, _, lmn = mva(b_xyz)

    # Resample moments to magnetic field sampling
    moments_i = [resample(mom, b_xyz) for mom in moments_i]
    moments_e = [resample(mom, b_xyz) for mom in moments_e]

    # lmn = np.vstack([lmn[:, 0], -lmn[:, 2], lmn[:, 1]]).T
    l = lmn[:, 0]
    m = np.mean(moments_i[1].data, axis=0)
    m /= np.linalg.norm(m, axis=0)
    n = np.cross(l, m) / np.linalg.norm(np.cross(l, m))
    m = np.cross(n, l)
    lmn = np.transpose(np.vstack([l, m, n]))

    # transform magnetic field and current density to LMN coordinates system
    b_lmn, j_lmn = [new_xyz(field, lmn) for field in [b_xyz, j_xyz]]

    # Load data from timing
    timing_lr = load_timing(args.timing)

    # Transform slowness vector to LMN frame
    m_lmn, dm_lmn = [new_xyz(vec, lmn) for vec in [timing_lr.m, timing_lr.dm]]

    # Transform normal from timing to LMN coordinates system
    n_lmn = new_xyz(timing_lr.n, lmn)

    slowness = xr.Dataset({"m": m_lmn, "dm": dm_lmn})

    # Get crossing times
    crossing_times = m_lmn.time.data

    # Unpack ion/electron temperature
    _, _, t_i = dec_temperature(b_xyz, moments_i)
    _, _, t_e = dec_temperature(b_xyz, moments_i)

    v_xyz_i = moments_i[1]
    v_xyz_e = moments_e[1]

    v_lmn_i, v_lmn_e = [new_xyz(v_xyz, lmn) for v_xyz in [v_xyz_i, v_xyz_e]]

    # Compute velocity and geometry of the CS using spatio-temporal derivative
    b_mms_ds = [_downsample(b_xyz, 2.5) for b_xyz in b_mms]
    #v_str_lmn, y_m, z_n = st_derivative(r_mms, b_mms, lmn, crossing_times)
    v_str_lmn, y_m, z_n = st_derivative(r_mms, b_mms_ds, lmn, crossing_times)


    # filter velocity of the CS
    # change 257 to physical value
    #v_str_lmn_filtered = medfilt(v_str_lmn, 100)
    grad_b = c_4_grad(r_mms, b_mms_ds)
    grad_b_dete = ts_scalar(grad_b.time.data,
                            np.abs(np.linalg.det(grad_b.data)))
    res_dete = grad_b_dete.data - medfilt(grad_b_dete, 5).data
    idx_ = np.abs(res_dete) > np.std(res_dete)

    v_str_lmn_filtered = v_str_lmn.copy()
    v_str_lmn_filtered.data[idx_, 1] = np.nan
    v_str_lmn_filtered.data[idx_, 2] = np.nan

    # Plot
    fig, axs = plt.subplots(4, **cfg["figure"]["main"])
    fig.subplots_adjust(**cfg["figure"]["subplots"])

    plot_line(axs[0], b_lmn)
    axs[0].legend(["$B_L$", "$B_M$", "$B_N$"], **cfg["figure"]["legend"])
    axs[0].set_ylabel("$B$ [nT]")
    axs[0].grid(True, which="both")

    axs[1].quiver(timing_lr.tau.time.data, np.zeros(len(n_lmn)),
                  n_lmn[:, 1], n_lmn[:, 2],
                  color="tab:green", angles="uv")
    axs[1].set_ylabel("$n_{timing}^{MN}$")
    axs[1].grid(True, which="both")

    plot_line(axs[2], v_lmn_i[:, 1], color="tab:blue", label="Ions")
    plot_line(axs[2], v_str_lmn_filtered[:, 1], color="k", label="STD")
    axs[2].errorbar(slowness.time.data, slowness.m.data[:, 1],
                    slowness.dm.data[:, 1],
                    color="tab:green", label="Timing")
    axs[2].legend(**cfg["figure"]["legend"])
    axs[2].set_ylim([-650, 650])
    axs[2].set_ylabel("$V_M$ [km s$^{-1}$]")
    axs[2].grid(True, which="both")

    plot_line(axs[3], v_lmn_e[:, 2], color="tab:red", label="Electrons")
    plot_line(axs[3], v_str_lmn_filtered[:, 2], color="k", label="STD")
    axs[3].errorbar(slowness.time.data, slowness.m.data[:, 2],
                    slowness.dm.data[:, 2],
                    color="tab:green", label="Tining")
    axs[3].legend(**cfg["figure"]["legend"])
    axs[3].set_ylim([-650, 650])
    axs[3].set_ylabel("$V_N$ [km s$^{-1}$]")
    axs[3].grid(True, which="both")
    axs[-1].set_xlim(mdates.date2num(tint))
    fig.align_ylabels(axs)

    labels_pos = [0.02, 0.92]
    _ = make_labels(axs, labels_pos)

    if args.figname:
        fig.savefig(args.figname, **cfg["figure"]["save"])
    else:
        plt.show()
Beispiel #6
0
def main(args):
    """main function
    """
    with open(args.config) as f:
        cfg = yaml.load(f, Loader=yaml.FullLoader)

    # Spacecraft indices
    mms_ids = np.arange(1, 5)

    # Load spacecraft position and background magnetic field
    r_mms = [get_data("R_gse", cfg["tint"], i,
                      data_path=cfg["data_path"]) for i in mms_ids]

    # Load background magnetic field
    suf_b = "fgm_{}_{}".format(cfg["fgm"]["data_rate"], cfg["fgm"]["level"])
    b_mms = [get_data("B_gse_{}".format(suf_b), cfg["tint"], i, args.verbose,
                      data_path=cfg["data_path"]) for i in mms_ids]

    # Remove offset on z component of the background magnetic field
    b_mms = remove_bz_offset(b_mms)

    # Load moments
    moments_i, moments_e = load_moments(cfg["tint"], cfg["fpi"], args,
                                        cfg["data_path"])

    # Compute current density
    j_xyz, div_b, b_xyz, _, _, _ = c_4_j(r_mms, b_mms)
    j_xyz *= 1e9  														# j A.m^{-2}->nA.m^{-2}

    # Resample moments to magnetic field sampling
    moments_i = [resample(mom, b_xyz) for mom in moments_i]
    moments_e = [resample(mom, b_xyz) for mom in moments_e]

    # Compute new coordinates system
    lmn = lmn_cs(b_xyz, moments_i[1])

    # transform magnetic field and current density to LMN coordinates system
    b_lmn, j_lmn = [new_xyz(field, lmn) for field in [b_xyz, j_xyz]]

    # Fit J perp vs B as Harris like CS
    harris_fit = fit_harris_cs(b_lmn, j_lmn)

    # Load data from timing
    timing_lr = load_timing(args.timing)

    # Transform slowness vector to LMN frame
    m_lmn = new_xyz(timing_lr.m, lmn)

    # Get crossing times
    crossing_times = m_lmn.time.data

    # Use Harris like CS lobe field to estimate the thickness
    # Compute thickness as h = B0/curl(B) = B0/(m0*J) and the error
    mu0 = constants.mu_0
    # continuous thickness
    h_c = norm(harris_fit.B0) / (1e3 * mu0 * norm(j_lmn))
    # discrete thickness
    h_d = t_eval(h_c, crossing_times)

    # Errors
    # relative error on curlometer technique
    dj_j = np.abs(div_b / (mu0 * norm(1e-9 * j_xyz)))
    # relative error on the thickness
    dh_d = h_d * t_eval(dj_j / (1 + dj_j), crossing_times)

    # Compute ion inertial length to normalize the thickness
    # unpack number densities
    n_i, n_e = moments_i[0], moments_e[0]

    # Unpack ion/electron temperature
    _, _, t_i = dec_temperature(b_xyz, moments_i)
    _, _, t_e = dec_temperature(b_xyz, moments_i)

    # Compute plasma parameters
    plasma_params = plasma_calc(harris_fit.B0, t_i, t_e, n_i, n_e)

    # Averaged ion inertial length
    d_i = 1e-3 * np.mean(plasma_params.l_i).data
    r_p = 1e-3 * np.mean(plasma_params.rho_p).data
    r_e = 1e-3 * np.mean(plasma_params.rho_e).data

    # Normalize thickness by ion inertial length
    h_d, dh_d = [h_d / d_i, dh_d / d_i]

    # Compute velocity and geometry of the CS using spatio-temporal derivative
    v_str_lmn, y_m, z_n = st_derivative(r_mms, b_mms, lmn, crossing_times)

    geometry = xr.Dataset({"y_m": y_m / d_i, "z_n": z_n / d_i})

    # Compute ym and zn at the crossings
    crossing_times = h_d.time.data

    yc_m, zc_n = [t_eval(x, crossing_times) for x in [geometry.y_m, geometry.z_n]]

    fig = plt.figure(**cfg["figure"]["main"])
    gs0 = fig.add_gridspec(4, 2, **cfg["figure"]["gridspec"])
    gs10 = gs0[:2, 0].subgridspec(1, 1)
    gs20 = gs0[:2, 1].subgridspec(2, 1, hspace=.4)
    gs30 = gs0[2:, :].subgridspec(1, 1)

    axs0 = [fig.add_subplot(gs10[i]) for i in range(1)]
    axs1 = [fig.add_subplot(gs20[i]) for i in range(2)]
    axs2 = [fig.add_subplot(gs30[i]) for i in range(1)]

    axs0[0], caxs0 = plot_spectr(axs0[0], harris_fit.hist,
                                 cscale="log", cmap="viridis")
    axs0[0].errorbar(harris_fit.bbins, harris_fit.medbin,
                     harris_fit.medstd, marker="s", color="tab:red")
    axs0[0].plot(harris_fit.hires_b, harris_fit.pred_j_perp,
                 color="tab:red", linestyle="--", linewidth=2)
    axs0[0].set_ylim([0, 18])
    axs0[0].set_xlabel("$B_L$ [nT]")
    axs0[0].set_ylabel("$J_{MN}$ [nA m$^{-2}$]")
    caxs0.set_ylabel("Counts")
    labels0 = ["Harris fit $B_0$={:2.0f} nT".format(harris_fit.B0.data[0, 0]),
               "median"]
    axs0[0].legend(labels0, **cfg["figure"]["legend"])

    for ax in axs1:
        ax.errorbar(yc_m.data, zc_n.data, h_d.data / 2, **cfg["figure"][
            "errorbar"])
        ax.plot(geometry.y_m.data, geometry.z_n.data, "tab:blue")
        ax.set_ylim([-6, 6])
        ax.set_xlabel("$M/d_i$")
        ax.set_ylabel("$N/d_i$")

    axs1[0].legend(["CS", "h"], **cfg["figure"]["legend"])
    axs1[1].set_xticks(yc_m.data)
    axs1[0].set_xlim([0, np.max(geometry.y_m.data)])
    axs1[1].set_xlim([70, 105])
    axs1[0].grid(True, which="both")
    axs1[1].grid(True, which="both")

    zoom(axs1[1], axs1[0], ec="k")

    # Label the panels
    axs0[0].text(0.02, 0.95, "({})".format("a"), transform=axs0[0].transAxes)
    axs1 = make_labels(axs1, [0.02, 0.86], 1)

    axs2[0].text(0.01, 0.95, "({})".format(string.ascii_lowercase[len(axs1) + 1]),
                 transform=axs2[0].transAxes)
    axs2[0].axis("off")

    if args.figname:
        fig.savefig(args.figname, **cfg["figure"]["save"])
    else:
        plt.show()
Beispiel #7
0
def main(args):
    """main function
    """
    # Read time intervals
    with open(args.config) as f:
        cfg = yaml.load(f, Loader=yaml.FullLoader)

    tint_flap = cfg["tints"]["flapping"]
    tint_zoom = cfg["tints"]["close-up"]

    mms_ids = np.arange(1, 5)

    # Load spacecraft position and background magnetic field
    r_mms = [
        get_data("R_gse",
                 tint_flap,
                 i,
                 args.verbose,
                 data_path=cfg["data_path"]) for i in mms_ids
    ]

    suf_b = "fgm_{}_{}".format(cfg["fgm"]["data_rate"], cfg["fgm"]["level"])
    b_mms = [
        get_data("B_gse_{}".format(suf_b),
                 tint_flap,
                 i,
                 args.verbose,
                 data_path=cfg["data_path"]) for i in mms_ids
    ]

    # Remove offset on z component of the background magnetic field
    b_mms = remove_bz_offset(b_mms)

    # Compute magnetic field at the center of mass of the tetrahedron
    j_xyz, _, b_xyz, _, _, _ = c_4_j(r_mms, b_mms)
    j_xyz *= 1e9  # j A.m^{-2}->nA.m^{-2}

    # Compute magnetic field at the center of mass of the tetrahedron
    b_xyz = avg_4sc(b_mms)

    # Compute MVA frame
    b_lmn, _, lmn = mva(b_xyz)

    # Correct minimum variance frame
    # lmn = np.vstack([lmn[:, 0], -lmn[:, 2], lmn[:, 1]]).T
    l = lmn[:, 0]
    m = np.mean(j_xyz.data, axis=0) / np.linalg.norm(np.mean(j_xyz, axis=0))
    n = np.cross(l, m) / np.linalg.norm(np.cross(l, m))
    m = np.cross(n, l)
    lmn = np.transpose(np.vstack([l, m, n]))

    b_xyz = time_clip(b_mms[args.mms_id - 1], tint_zoom)
    b_lmn = new_xyz(b_xyz, lmn)

    # Load electric field and magnetic field fluctuation
    # Load electric field
    suf_e = "edp_{}_{}".format(cfg["edp"]["data_rate"], cfg["edp"]["level"])
    e_xyz = get_data("e_gse_{}".format(suf_e),
                     tint_zoom,
                     args.mms_id,
                     args.verbose,
                     data_path=cfg["data_path"])

    # Load electric field
    suf_db = "scm_{}_{}".format(cfg["scm"]["data_rate"], cfg["scm"]["level"])
    b_scm = get_data("b_gse_{}".format(suf_db),
                     tint_zoom,
                     args.mms_id,
                     args.verbose,
                     data_path=cfg["data_path"])

    # Load density and pressure tensor
    moments_i, moments_e = load_moments(tint_flap,
                                        cfg["fpi"],
                                        args,
                                        data_path=cfg["data_path"])

    # Unpack moments
    _, _, _, p_xyz_i = moments_i
    n_e, _, _, p_xyz_e = moments_e

    # Total pressure tensor
    p_xyz = p_xyz_i + resample(p_xyz_e, p_xyz_i)

    # Convert to field-aligned coordinates
    p_xyzfac = rotate_tensor(p_xyz, "fac", b_xyz, "pp")

    # Permittivity
    mu0 = constants.mu_0

    # Thermal pressure (scalar)
    pth = 1e-9 * trace(p_xyzfac) / 3.

    # Magnetic pressure
    p_mag = 1e-18 * norm(b_xyz)**2 / (2 * mu0)

    # Plasma beta
    beta = resample(pth, b_xyz) / p_mag

    # Plasma parameters
    plasma_params = plasma_calc(b_xyz, n_e, n_e, n_e, n_e)

    # Convert electric field and magnetic field fluctuation to field aligned
    # coordinates
    e_xyzfac = convert_fac(e_xyz, b_xyz, [1, 0, 0])

    # bandpass filter electric field and magnetic field fluctuation
    f_min = 4
    e_xyzfac_hf = filt(e_xyzfac, f_min, 0, 3)

    cwt_options = dict(nf=100, f=[0.5, 1e3], plot=False)

    # Compute continuous wavelet transform of the electric field
    e_xyzfac_cwt = wavelet(e_xyzfac, **cwt_options)

    # Construct compressed spectrogram of E
    e_cwt_times, e_cwt_x, e_cwt_y, e_cwt_z = compress_cwt(e_xyzfac_cwt, nc=100)

    e_cwt = xr.DataArray(e_cwt_x + e_cwt_y + e_cwt_z,
                         coords=[e_cwt_times, e_xyzfac_cwt.frequency],
                         dims=["time", "frequency"])

    # Compute continuous wavelet transform of the magnetic field fluctuations
    b_scm_cwt = wavelet(b_scm, **cwt_options)

    # Construct compressed spectrogram of E
    b_cwt_times, b_cwt_x, b_cwt_y, b_cwt_z = compress_cwt(b_scm_cwt, nc=100)

    b_cwt = xr.DataArray(b_cwt_x + b_cwt_y + b_cwt_z,
                         coords=[b_cwt_times, b_scm_cwt.frequency],
                         dims=["time", "frequency"])

    # Plot
    fig, axs = plt.subplots(4, sharex="all", figsize=(6.5, 9))
    fig.subplots_adjust(bottom=.05, top=.95, left=.15, right=.85, hspace=0.)

    kwargs_legend = dict(ncol=3, loc="upper right", frameon=True)
    kwargs_spectr = dict(cscale="log",
                         yscale="log",
                         cmap="Spectral_r",
                         clim=[1e-7, 1e0])

    plot_line(axs[0], b_lmn)
    axs[0].legend(["$B_L$", "$B_M$", "$B_N$"], **cfg["figure"]["legend"])
    axs[0].set_ylabel("$B$ [nT]")
    axs[0].grid(True, which="both")

    plot_line(axs[1], e_xyzfac_hf)
    labels = ["$E_{\\perp 1}$", "$E_{\\perp 2}$", "$E_{\\parallel}$"]
    axs[1].legend(labels, **cfg["figure"]["legend"])
    axs[1].set_ylabel("$E$ [mV m$^{-1}$]")
    axs[1].set_ylim([-9, 9])
    axs[1].set_yticks([-6, 0, 6])
    axs1b = axs[1].twinx()
    plot_line(axs1b, beta, color="k")
    axs1b.set_yscale("log")
    axs1b.set_ylabel("$\\beta$")
    axs1b.set_ylim([10**(.5) * 1e0, 10**(.5) * 1e3])
    axs[1].grid(True, which="both")

    axs[2], caxs2 = plot_spectr(axs[2], e_cwt, **cfg["figure"]["spectrum"])
    plot_line(axs[2], plasma_params.f_lh, color="k", label="$f_{lh}$")
    plot_line(axs[2], plasma_params.f_ce, color="w", label="$f_{ce}$")
    plot_line(axs[2], plasma_params.f_pp, color="red", label="$f_{pi}$")
    axs[2].set_ylim([0.5, 1e3])
    axs[2].set_ylabel("$f$ [Hz]")
    caxs2.set_ylabel("$E^2$ " + "\n" + "[mV$^2$ m$^{-2}$ Hz$^{-1}$]")
    axs[2].legend(**cfg["figure"]["legend"])

    axs[3], caxs3 = plot_spectr(axs[3], b_cwt, **cfg["figure"]["spectrum"])
    plot_line(axs[3], plasma_params.f_lh, color="k", label="$f_{lh}$")
    plot_line(axs[3], plasma_params.f_ce, color="w", label="$f_{ce}$")
    plot_line(axs[3], plasma_params.f_pp, color="red", label="$f_{pi}$")
    axs[3].set_ylim([0.5, 1e3])
    axs[3].set_ylabel("$f$ [Hz]")
    caxs3.set_ylabel("$B^2$ " + "\n" + "[nT$^2$ Hz$^{-1}$]")
    axs[3].legend(**cfg["figure"]["legend"])

    fig.align_ylabels(axs)

    axs[1].text(.85,
                .15,
                "$f > ${:2.1f} Hz".format(f_min),
                transform=axs[1].transAxes)

    # Time interval of the flapping
    axs[-1].set_xlim(mdates.date2num(tint_zoom))

    # Add panels labels
    labels_pos = [0.02, 0.90]
    _ = make_labels(axs, labels_pos)

    if args.figname:
        fig.savefig(args.figname, **cfg["figure"]["save"])
    else:
        plt.show()
Beispiel #8
0
def main(args):
    """main function
    """
    # Read time intervals
    with open(args.config) as f:
        cfg = yaml.load(f, Loader=yaml.FullLoader)

    tint_flap = cfg["tints"]["flapping"]
    tint_zoom = cfg["tints"]["close-up"]

    mms_ids = np.arange(1, 5)

    # Load spacecraft position
    r_mms = [
        get_data("R_gse", tint_flap, i, data_path=cfg["data_path"])
        for i in mms_ids
    ]

    # Load background magnetic field
    suf_b = "fgm_{}_{}".format(cfg["fgm"]["data_rate"], cfg["fgm"]["level"])
    b_mms = [
        get_data("B_gse_{}".format(suf_b),
                 tint_flap,
                 i,
                 args.verbose,
                 data_path=cfg["data_path"]) for i in mms_ids
    ]

    # Load electric field
    suf_e = "edp_{}_{}".format(cfg["edp"]["data_rate"], cfg["edp"]["level"])
    e_mms = [
        get_data("e_gse_{}".format(suf_e),
                 tint_flap,
                 i,
                 args.verbose,
                 data_path=cfg["data_path"]) for i in mms_ids
    ]

    # Load moments from FPI
    moments_i, moments_e = load_moments(tint_flap,
                                        cfg["fpi"],
                                        args,
                                        data_path=cfg["data_path"])

    # Remove offset on z component of the background magnetic field
    b_mms = remove_bz_offset(b_mms)

    # Compute current density
    j_xyz, _, b_xyz, _, _, _ = c_4_j(r_mms, b_mms)
    j_xyz *= 1e9  # j A.m^{-2}->nA.m^{-2}

    # Compute electric field at the center of mass of the tetrahedron
    e_xyz = avg_4sc(e_mms)

    # Compute new coordinates system
    lmn = lmn_cs(b_xyz, moments_i[1])

    # Resample magnetic field and current density to electric field sampling
    b_xyz, j_xyz = [resample(field, e_xyz) for field in [b_xyz, j_xyz]]

    # Transform fields to MVA frame
    b_lmn, e_lmn, j_lmn = [new_xyz(x_, lmn) for x_ in [b_xyz, e_xyz, j_xyz]]

    # Resample ion/electron moments to electric field sampling
    moments_i = [resample(mom, e_xyz) for mom in moments_i]
    moments_e = [resample(mom, e_xyz) for mom in moments_e]

    # Transform moments
    moments_lmn_i = [moments_i[0], None, None, None]
    moments_lmn_e = [moments_e[0], None, None, None]

    moments_lmn_i[1:] = [new_xyz(mom, lmn) for mom in moments_i[1:]]
    moments_lmn_e[1:] = [new_xyz(mom, lmn) for mom in moments_e[1:]]

    # Compute terms of the Ohm's law
    vxb_lmn_i, vxb_lmn_e, jxb_lmn = calc_ol_terms(b_lmn, j_lmn, moments_lmn_i,
                                                  moments_lmn_e)

    # Compute ion scale total contribution
    s_lmn = -vxb_lmn_i + jxb_lmn

    # Plot
    fig = plt.figure(**cfg["figure"]["main"])
    gs0 = fig.add_gridspec(2, 1, **cfg["figure"]["gridspec"])

    gs00 = gs0[:1].subgridspec(4, 1, hspace=0)
    gs10 = gs0[1:].subgridspec(4, 1, hspace=0)

    axs0 = [fig.add_subplot(gs00[i]) for i in range(4)]
    axs1 = [fig.add_subplot(gs10[i]) for i in range(4)]

    for axs in [axs0, axs1]:
        plot_line(axs[0], b_lmn)
        axs[0].legend(["$B_L$", "$B_M$", "$B_N$"], **cfg["figure"]["legend"])
        axs[0].set_ylabel("$B$" + "\n" + "[nT]")
        axs[0].grid(True, which="both")

        plot_line(axs[1], jxb_lmn[:, 1], label="$J\\times B / ne$")
        plot_line(axs[1], -vxb_lmn_i[:, 1], label="$-V_i\\times B$")
        plot_line(axs[1], s_lmn[:, 1], label="$J\\times B / ne -V_i\\times B$")
        plot_line(axs[1], e_lmn[:, 1], label="$E_{EDP}$")
        axs[1].set_ylim([-12, 12])
        axs[1].set_ylabel("$E_M$" + "\n" + "[mV m$^{-1}$]")
        axs[1].grid(True, which="both")

        plot_line(axs[2], jxb_lmn[:, 2], label="$J\\times B / ne$")
        plot_line(axs[2], -vxb_lmn_i[:, 2], label="$-V_i\\times B$")
        plot_line(axs[2], s_lmn[:, 2], label="$J\\times B / ne -V_i\\times B$")
        plot_line(axs[2], e_lmn[:, 2], label="$E_{EDP}$")
        axs[2].legend(frameon=True,
                      ncol=2,
                      bbox_to_anchor=(1, 1.3),
                      loc="upper right")
        axs[2].set_ylim([-12, 12])
        axs[2].set_ylabel("$E_N$" + "\n" + "[mV m$^{-1}$]")
        axs[2].grid(True, which="both")

        plot_line(axs[3],
                  norm(e_xyz + vxb_lmn_i),
                  color="deeppink",
                  label="$| E+V_{i}\\times B |$")
        plot_line(axs[3],
                  norm(jxb_lmn),
                  color="tab:blue",
                  label="$|J\\times B / ne|$")
        axs[3].legend(**cfg["figure"]["legend"])
        axs[3].set_ylim([0, 12])
        axs[3].set_ylabel("$|E|$" + "\n" + "[mV m$^{-1}$]")
        axs[3].grid(True, which="both")

        axs[-1].get_shared_x_axes().join(*axs)

        fig.align_ylabels(axs)

        for ax in axs[:-1]:
            ax.xaxis.set_ticklabels([])

    axs0[-1].set_xlim(mdates.date2num(tint_flap))
    axs1[-1].set_xlim(mdates.date2num(tint_zoom))

    # zoom
    zoom(axs1[0], axs0[-1], ec="k")
    span_options = dict(linestyle="--",
                        linewidth=0.8,
                        facecolor="none",
                        edgecolor="k")
    span_tint(axs0, tint_zoom, **span_options)
    # number subplots
    labels_pos = [0.02, 0.83]
    _ = make_labels(axs0 + axs1, labels_pos)

    if args.figname:
        fig.savefig(args.figname, **cfg["figure"]["save"])
    else:
        plt.show()