Example #1
0
def burning_limiter_e(eps_filename, results_base):
    """Plot the effect of the burning timestep factor castro.dtnuc_e."""

    if (os.path.isfile(eps_filename)):
        return

    results_dir = results_base + 'burning_limiter_e/'

    # Get the list of parameter values we have tried

    dtnuc_list = wdmerger.get_parameter_list(results_dir)

    ni56_arr = get_ni56(results_dir)

    dtnuc_list = [dtnuc[len('dt'):] for dtnuc in dtnuc_list]

    plt.plot(np.array(dtnuc_list),
             np.array(ni56_arr),
             linestyle=linestyles[0],
             lw=4.0)

    plt.xscale('log')
    plt.xlabel(r"Nuclear burning timestep factor $\Delta t_{be}$", fontsize=20)
    plt.ylabel(r"$^{56}$Ni generated (M$_{\odot}$)", fontsize=20)
    plt.tick_params(labelsize=16)
    plt.tight_layout()
    plt.savefig(eps_filename)
    wdmerger.insert_commits_into_eps(eps_filename, get_diagfile(results_dir),
                                     'diag')

    plt.close()
def plot_energy_error(diag_filename, output_filename):

    diag_file = open(diag_filename, 'r')
    lines = diag_file.readlines()

    time = get_column("TIME", diag_filename)
    energy = get_column("TOTAL ENERGY", diag_filename)

    rot_period = 0.0

    dir = os.path.dirname(diag_filename)

    inputs_filename = dir + '/' + wdmerger.get_inputs_filename(dir)
    rot_period = wdmerger.get_inputs_var(inputs_filename,
                                         "castro.rotational_period")

    if (rot_period > 0.0):
        time = time / rot_period
        xlabel = "Time / Rotational Period"
    else:
        xlabel = "Time (s)"
    ylabel = "Relative Change in Energy"

    plt.plot(time, abs((energy - energy[0]) / energy[0]), lw=4.0)
    plt.yscale('log')
    plt.xlabel(xlabel, fontsize=20)
    plt.ylabel(ylabel, fontsize=20)
    plt.ylim([1.0e-8, 1.0e0])
    plt.tick_params(labelsize=16)
    plt.tight_layout()

    plt.savefig(output_filename)
    wdmerger.insert_commits_into_eps(output_filename, diag_filename, 'diag')

    plt.close()
Example #3
0
def burning_limiter_X(eps_filename, results_base, do_ni56=True):
    """Plot the effect of the burning timestep limiter castro.dtnuc_X."""

    if (os.path.isfile(eps_filename)):
        return
    else:
        print("Generating file %s" % eps_filename)

    results_dir = results_base + 'burning_limiter_X/'

    if not os.path.isdir(results_dir):
        return

    # Get the list of parameter values we have tried

    dtnuc_list = wdmerger.get_parameter_list(results_dir)

    if (dtnuc_list == []):
        return

    if (do_ni56):
        result_arr = np.array(get_ni56(results_dir))
    else:
        result_arr = np.array(get_abar(results_dir))

    # Don't make the plot if we have fewer than two data points.

    if len(result_arr) < 2:
        return

    dtnuc_list = np.array([float(dtnuc[len('dt'):]) for dtnuc in dtnuc_list])

    # Sort the lists

    result_arr = np.array([x for _, x in sorted(zip(dtnuc_list, result_arr))])
    dtnuc_list = sorted(dtnuc_list)

    plt.plot(dtnuc_list,
             result_arr,
             linestyle=linestyles[0],
             lw=4.0,
             color=colors[0])

    plt.xscale('log')
    plt.xlabel(r"Nuclear burning timestep factor $f_{bX}$", fontsize=20)
    if (do_ni56):
        plt.ylabel(r"$^{56}$Ni generated (M$_{\odot}$)", fontsize=20)
    else:
        plt.ylabel(r"$\overline{A}$", fontsize=20)
    plt.tick_params(labelsize=16)
    plt.tight_layout()
    plt.savefig(eps_filename)
    wdmerger.insert_commits_into_eps(eps_filename, get_diagfile(results_dir),
                                     'diag')
    png_filename = eps_filename[0:-3] + "png"
    plt.savefig(png_filename)

    plt.close()
Example #4
0
def impact_parameter(eps_filename, results_dir):
    """Plot the effect of the impact parameter."""

    import os

    if os.path.isfile(eps_filename):
        return

    import numpy as np
    from matplotlib import pyplot as plt

    # Get the list of parameter values we have tried

    dtnuc_list = wdmerger.get_parameter_list(results_dir)

    ni56_arr = get_ni56(results_dir)

    b_list = [dtnuc[len('b'):] for dtnuc in dtnuc_list]

    b_list = sorted(b_list)

    plt.plot(np.array(b_list), np.array(ni56_arr), markers[0], markersize=12.0)

    xaxis_buffer = 0.025

    plt.xlim(
        [float(b_list[0]) - xaxis_buffer,
         float(b_list[-1]) + xaxis_buffer])
    plt.xlabel(r"Impact parameter $b$", fontsize=24)
    plt.ylabel(r"$^{56}$Ni generated (M$_{\odot}$)", fontsize=24)
    plt.tick_params(labelsize=20)
    plt.tight_layout()
    plt.savefig(eps_filename)
    wdmerger.insert_commits_into_eps(eps_filename, get_diagfile(results_dir),
                                     'diag')

    plt.close()
Example #5
0
    file.write(outString)
    file.write('\n')

file.close()

# Set up an analytical curve that represents perfect second-order convergence.
# We'll place it a bit below the lowest curve on the grid, and give it a grayscale
# color by using the color = 'float' command where float is some number between 0 and 1.

minerr = min(l2[:, 0])
second_order = (minerr / 3.0) * (np.array(ncell_arr) / ncell_arr[0])**(-2.0)

plt.plot(ncell_arr,
         second_order,
         label='Second order convergence',
         linestyle='-',
         lw=3.0,
         color='0.75')

eps_filename = 'plots/phi_comparison.eps'

plt.xlim([ncell_arr[0], ncell_arr[len(ncell_arr) - 1]])
plt.xlabel("Number of cells per dimension", fontsize=20)
plt.ylabel(r"Relative L$^2$ error", fontsize=20)
plt.xscale('log', basex=2)
plt.yscale('log')
plt.legend(loc='upper right', fontsize=12, handlelength=5)
plt.tick_params(labelsize=16)
plt.savefig(eps_filename)
wdmerger.insert_commits_into_eps(eps_filename, pf_name, 'plot')
Example #6
0
# Divide distance by initial distance

dist = dist / dist[0]

# Generate the analytical result

d_exact = np.arange(0.0, 1.0, 0.001)

t_exact = np.arccos(np.sqrt(d_exact)) + np.sqrt(d_exact * (1.0 - d_exact))
t_exact *= 2.0 / np.pi

# Let's plot with reversed axes for aesthetic purposes

eps_filename = 'plots/freefall.eps'

# Stride for our arrays; the markers will be too dense if we plot every data point

stride = 25

plt.plot(dist[::stride], time[::stride], 'o', ms=12.0)
plt.plot(d_exact, t_exact, '-', lw=4.0)
plt.axis([0.0, 1.0, 0.0, 1.0])
plt.gca().invert_xaxis()
plt.gca().invert_yaxis()
plt.xlabel("Distance / Initial Distance", fontsize=20)
plt.ylabel("Time / Free Fall Timescale", fontsize=20)
plt.tick_params(labelsize=16)
plt.savefig(eps_filename)
wdmerger.insert_commits_into_eps(eps_filename, diag_filename, 'diag')
Example #7
0
         color='0.25',
         linestyle='-',
         lw=3.0)
plt.plot(two_level_nproc_arr,
         two_level_speedup_arr,
         'bD',
         ms=12.0,
         label="Two levels")
plt.plot(three_level_nproc_arr,
         three_level_perfect_arr,
         color='0.25',
         linestyle='-',
         lw=3.0)
plt.plot(three_level_nproc_arr,
         three_level_speedup_arr,
         'rs',
         ms=12.0,
         label="Three levels")
plt.xlabel("Number of processors", fontsize=20.0)
plt.ylabel("Relative speedup", fontsize=20.0)
plt.xscale("log", basex=2)
plt.yscale("log")
plt.tick_params(labelsize=16, pad=10)
plt.axis([
    0.8 * one_level_nproc_arr[0], 1.2 * three_level_nproc_arr[-1],
    0.8 * one_level_perfect_arr[0], 2.0 * two_level_perfect_arr[-1]
])
plt.legend(loc="upper right", numpoints=1)
plt.savefig(eps_filename)
wdmerger.insert_commits_into_eps(eps_filename, output_filename, 'info')
def plot_gw_signal(diag_filename,
                   output_filename,
                   n_orbits=-1,
                   do_analytical=0):

    diag_file = open(diag_filename, 'r')

    time = get_column("TIME", diag_filename)
    hplus = get_column("h_+ (axis 3)", diag_filename)
    hcross = get_column("h_x (axis 3)", diag_filename)

    # Normalize time by rotational period.

    rot_period = 0.0

    dir = os.path.dirname(diag_filename)

    inputs_filename = dir + '/' + wdmerger.get_inputs_filename(dir)
    probin_filename = dir + '/probin'

    rot_period = wdmerger.get_inputs_var(inputs_filename,
                                         "castro.rotational_period")

    if (rot_period > 0.0):
        time = time / rot_period
        xlabel = "Time / Rotational Period"
        if (n_orbits > 0):
            idx = np.where(time < n_orbits)
            time = time[idx]
            hplus = hplus[idx]
            hcross = hcross[idx]
    else:
        xlabel = "Time (s)"

    ylabel = "Gravitational Wave Strain"

    markers = ['o', '+', '.', ',', '*']

    # Now work out the analytical result for a circular binary orbit, if desired.

    if (do_analytical == 1):

        # Get relevant CGS constants.

        G_const = wdmerger.get_castro_const('Gconst')
        M_solar = wdmerger.get_castro_const('M_solar')
        c_light = wdmerger.get_castro_const('c_light')
        parsec = wdmerger.get_castro_const('parsec')

        # Relevant variables from the probin file.

        mass_P = wdmerger.get_probin_var(probin_filename, 'mass_P') * M_solar
        mass_S = wdmerger.get_probin_var(probin_filename, 'mass_S') * M_solar

        gw_dist = wdmerger.get_probin_var(probin_filename, 'gw_dist')  # In kpc

        mu = mass_P * mass_S / (mass_P + mass_S)
        M_tot = mass_P + mass_S
        dist = gw_dist * 1.e3 * parsec
        omega = 2.0 * np.pi / rot_period
        coeff = -4 * G_const * mu / (c_light**4 * dist) * (G_const * M_tot *
                                                           omega)**(2.0 / 3.0)
        hplus_true = coeff * np.cos(2.0 * omega * rot_period * time)
        hcross_true = coeff * np.sin(2.0 * omega * rot_period * time)

        plt.plot(time, hplus_true, lw=4.0, ls='-')
        plt.plot(time, hcross_true, lw=4.0, ls='--')

        plt.plot(time,
                 hplus,
                 marker=markers[0],
                 ms=12.0,
                 markevery=200,
                 label=r"$\plus$" + " polarization")
        plt.plot(time,
                 hcross,
                 marker=markers[4],
                 ms=12.0,
                 markevery=200,
                 label=r"$\times$" + " polarization")

    else:

        plt.plot(time,
                 hplus,
                 lw=4.0,
                 ls='-',
                 label=r"$\plus$" + " polarization")
        plt.plot(time,
                 hcross,
                 lw=4.0,
                 ls='--',
                 label=r"$\times$" + " polarization")

    plt.xlabel(xlabel, fontsize=20)
    plt.ylabel(ylabel, fontsize=20)

    # Use the 'best' location for the legend, since for a generic function like this
    # it is hard to know ahead of time where the legend ought to go.
    # The alpha value controls the transparency, since we may end up covering some data.

    plt.legend(loc='best', fancybox=True)

    # The padding ensures that the lower-left ticks on the x- and y-axes don't overlap.

    plt.tick_params(labelsize=16, pad=10)

    # We have now increased the size of both the ticks and the axis labels,
    # which may have caused the latter to fall off the plot. Use tight_layout
    # to automatically adjust the plot to fix this.

    plt.tight_layout()

    # Save it into our designated file, which is usually EPS format.

    plt.savefig(output_filename)

    # Insert git commit hashes into this file from the various code sources.

    wdmerger.insert_commits_into_eps(output_filename, diag_filename, 'diag')

    plt.close()
Example #9
0
def gravitational_wave_signal(eps_filename, results_dir):
    """Plot the gravitational radiation waveform."""

    import os

    if os.path.isfile(eps_filename):
        return

    if not os.path.exists(results_dir):
        return

    from matplotlib import pyplot as plt

    print "Generating plot with filename " + eps_filename

    diag_file = results_dir + '/output/grid_diag.out'

    time = wdmerger.get_column('TIME', diag_file)

    strain_p_1 = wdmerger.get_column('h_+ (axis 1)', diag_file)
    strain_x_1 = wdmerger.get_column('h_x (axis 1)', diag_file)

    strain_p_2 = wdmerger.get_column('h_+ (axis 2)', diag_file)
    strain_x_2 = wdmerger.get_column('h_x (axis 2)', diag_file)

    strain_p_3 = wdmerger.get_column('h_+ (axis 3)', diag_file)
    strain_x_3 = wdmerger.get_column('h_x (axis 3)', diag_file)

    plt.plot(time,
             strain_p_1 / 1.e-22,
             lw=4.0,
             color=colors[0],
             linestyle=linestyles[0],
             marker=markers[0],
             markersize=12,
             markevery=250,
             label=r'$h^x_+$')
    plt.plot(time,
             strain_x_1 / 1.e-22,
             lw=4.0,
             color=colors[1],
             linestyle=linestyles[1],
             marker=markers[1],
             markersize=12,
             markevery=250,
             label=r'$h^x_\times$')

    plt.plot(time,
             strain_p_2 / 1.e-22,
             lw=4.0,
             color=colors[2],
             linestyle=linestyles[2],
             marker=markers[2],
             markersize=12,
             markevery=250,
             label=r'$h^y_+$')
    plt.plot(time,
             strain_x_2 / 1.e-22,
             lw=4.0,
             color=colors[3],
             linestyle=linestyles[3],
             marker=markers[3],
             markersize=12,
             markevery=250,
             label=r'$h^y_\times$')

    plt.plot(time,
             strain_p_3 / 1.e-22,
             lw=4.0,
             color=colors[4],
             linestyle=linestyles[4],
             marker=markers[4],
             markersize=12,
             markevery=250,
             label=r'$h^z_+$')
    plt.plot(time,
             strain_x_3 / 1.e-22,
             lw=4.0,
             color=colors[5],
             linestyle=linestyles[5],
             marker=markers[5],
             markersize=12,
             markevery=250,
             label=r'$h^z_\times$')

    plt.tick_params(labelsize=20)

    plt.xlabel(r'$t\ \mathrm{(s)}$', fontsize=24)
    plt.ylabel(r'$h\, /\, 10^{-22}$', fontsize=24)
    plt.legend(loc='best', prop={'size': 20})
    plt.tight_layout()

    plt.savefig(eps_filename)

    wdmerger.insert_commits_into_eps(eps_filename, diag_file, 'diag')

    plt.close()
Example #10
0
def amr_nickel(eps_filename, results_base):
    """Plot the effect of the refinement based on the nuclear burning rate on the nickel generation."""

    import os

    if os.path.isfile(eps_filename):
        return
    else:
        print("Generating file %s" % eps_filename)

    import math
    import numpy as np
    from matplotlib import pyplot as plt

    if not os.path.isdir(results_base):
        return

    diag_file = None

    # First, generate a plot of nickel production.

    ncell_list = sorted([int(n[1:]) for n in os.listdir(results_base)])

    i = 0

    for ncell in ncell_list:

        results_dir = results_base + 'n' + str(ncell) + '/self-heat/dxnuc/'

        if not os.path.isdir(results_dir):
            continue

        # Get the list of parameter values we have tried

        r_list = wdmerger.get_parameter_list(results_dir)

        # Strip out the non-refinement directories

        r_list = [r for r in r_list if r[0] == 'r']

        if (r_list == []):
            continue

        r_list = [float(r[1:]) for r in r_list]

        ni56_arr = get_ni56(results_dir, 'r')

        if ni56_arr == []:
            continue

        if diag_file == None and get_diagfile(results_dir) != None:
            diag_file = get_diagfile(results_dir)

        # Sort the lists

        ni56_arr = np.array([x for _, x in sorted(zip(r_list, ni56_arr))])
        r_list = np.array(sorted(r_list))

        zonesPerDim = [ncell * int(r) for r in r_list]

        plt.plot(zonesPerDim,
                 ni56_arr,
                 markers[i],
                 markersize=12,
                 linestyle=linestyles[i],
                 lw=4.0,
                 label='n = ' + str(ncell))

        i += 1

    plt.tick_params(axis='both', which='major', pad=10)
    plt.xscale('log', basex=2)
    plt.ylim([0.0, 0.6])
    plt.xlabel(r"Effective zones/dimension", fontsize=24)
    plt.ylabel(r"$^{56}$Ni generated (M$_{\odot}$)", fontsize=24)
    plt.tick_params(labelsize=16)
    plt.legend(loc='best', prop={'size': 20})
    plt.tight_layout()
    plt.savefig(eps_filename)
    wdmerger.insert_commits_into_eps(eps_filename, diag_file, 'diag')
    png_filename = eps_filename[0:-3] + "png"
    plt.savefig(png_filename)

    plt.close()
Example #11
0
def ode_tolerances(eps_filename, results_base):
    """Plot the effects of all ODE tolerance options."""

    if (os.path.isfile(eps_filename)):
        return
    else:
        print("Generating file %s" % eps_filename)

    results_dir = results_base + 'spec_tol/'

    if not os.path.isdir(results_dir):
        return

    # Get the list of parameter values we have tried

    s_tol_list = wdmerger.get_parameter_list(results_dir)

    if (s_tol_list == []):
        return

    ni56_s_arr = np.array(get_ni56(results_dir))

    tol_s_list = [tol[len('tol'):] for tol in tol_s_list]
    tol_s_list = np.array([float(tol.replace('d', 'e')) for tol in tol_s_list])

    # Sort the lists

    ni56_s_arr = np.array([x for _, x in sorted(zip(tol_s_list, ni56_s_arr))])
    tol_s_list = sorted(tol_s_list)

    results_dir = results_base + 'temp_tol/'

    if not os.path.isdir(results_dir):
        return

    # Get the list of parameter values we have tried

    tol_t_list = wdmerger.get_parameter_list(results_dir)

    if (tol_t_list == []):
        return

    ni56_t_arr = np.array(get_ni56(results_dir))

    tol_t_list = [tol[len('tol'):] for tol in tol_t_list]
    tol_t_list = np.array([float(tol.replace('d', 'e')) for tol in tol_t_list])

    # Sort the lists

    ni56_t_arr = np.array([x for _, x in sorted(zip(tol_t_list, ni56_t_arr))])
    tol_t_list = sorted(tol_t_list)

    results_dir = results_base + 'enuc_tol/'

    if not os.path.isdir(results_dir):
        return

    # Get the list of parameter values we have tried

    tol_e_list = wdmerger.get_parameter_list(results_dir)

    if (tol_e_list == []):
        return

    ni56_e_arr = np.array(get_ni56(results_dir))

    tol_e_list = [tol[len('tol'):] for tol in tol_e_list]
    tol_e_list = np.array([float(tol.replace('d', 'e')) for tol in tol_e_list])

    # Sort the lists

    ni56_e_arr = np.array([x for _, x in sorted(zip(tol_e_list, ni56_e_arr))])
    tol_e_list = sorted(tol_e_list)

    plt.plot(tol_s_list,
             ni56_s_arr,
             linestyle=linestyles[0],
             lw=4.0,
             label=r'Species Tolerance')
    plt.plot(tol_t_list,
             ni56_t_arr,
             linestyle=linestyles[1],
             lw=4.0,
             label=r'Temperature Tolerance')
    plt.plot(tol_e_list,
             ni56_e_arr,
             linestyle=linestyles[2],
             lw=4.0,
             label=r'Energy Tolerance')
    plt.xscale('log')
    plt.xlabel(r"ODE Error Tolerance", fontsize=20)
    plt.ylabel(r"$^{56}$Ni generated (M$_{\odot}$)", fontsize=20)
    plt.tick_params(labelsize=16)
    plt.legend(loc='best')
    plt.tight_layout()
    plt.savefig(eps_filename)
    wdmerger.insert_commits_into_eps(eps_filename, get_diagfile(results_dir),
                                     'diag')
    png_filename = eps_filename[0:-3] + "png"
    plt.savefig(png_filename)

    plt.close()
Example #12
0
def gravitational_wave_signal(eps_filename, results_dir, max_time = 1.e20, markevery = None,
                              scale_exp = -22, vary_lines = False):
    """Plot the gravitational radiation waveform."""

    import os

    if os.path.isfile(eps_filename):
        return

    if not os.path.exists(results_dir):
        return

    from matplotlib import pyplot as plt
    import numpy as np

    print "Generating plot with filename " + eps_filename

    scale = 10.0**scale_exp

    if vary_lines:
        linestyles = ['-', '--', ':', '-', '--', ':']
        markers = ['', '', '', 'o', 's', 'D']
        colors = ['b', 'g', 'r', 'c', 'm', 'k']
    else:
        linestyles = ['-', '--', '-', '--', '-', '--']
        markers = ['', '', '', '', '', '']
        colors = ['b', 'g', 'b', 'g', 'b', 'g']

    diag_file = results_dir + '/output/grid_diag.out'

    time       = np.array(wdmerger.get_column('TIME', diag_file))

    strain_p_1 = np.array(wdmerger.get_column('h_+ (axis 1)', diag_file)) / scale
    strain_p_2 = np.array(wdmerger.get_column('h_+ (axis 2)', diag_file)) / scale
    strain_p_3 = np.array(wdmerger.get_column('h_+ (axis 3)', diag_file)) / scale

    strain_x_1 = np.array(wdmerger.get_column('h_x (axis 1)', diag_file)) / scale
    strain_x_2 = np.array(wdmerger.get_column('h_x (axis 2)', diag_file)) / scale
    strain_x_3 = np.array(wdmerger.get_column('h_x (axis 3)', diag_file)) / scale

    # Generate an offset for the x- and y- strains. Then round this to the nearest
    # integer for the convenience of the plot legend.

    offset = max( int(round(2.5 * (max(np.max(strain_p_3), np.max(strain_x_3)) - min(np.min(strain_p_2), np.min(strain_x_2))))),
                  int(round(2.5 * (max(np.max(strain_p_2), np.max(strain_x_2)) - min(np.min(strain_p_1), np.min(strain_x_1))))) )
    z_offset = 0
    y_offset = offset
    x_offset = 2 * offset

    strain_p_1 += x_offset
    strain_p_2 += y_offset
    strain_p_3 += z_offset

    strain_x_1 += x_offset
    strain_x_2 += y_offset
    strain_x_3 += z_offset

    z_label_offset = ''
    y_label_offset = '+ {:d}'.format(y_offset)
    x_label_offset = '+ {:d}'.format(x_offset)

    label_p_1 = r'$h^x_+{}$'.format(x_label_offset)
    label_p_2 = r'$h^y_+{}$'.format(y_label_offset)
    label_p_3 = r'$h^z_+{}$'.format(z_label_offset)

    label_x_1 = r'$h^x_\times{}$'.format(x_label_offset)
    label_x_2 = r'$h^y_\times{}$'.format(y_label_offset)
    label_x_3 = r'$h^z_\times{}$'.format(z_label_offset)

    markersize = 12

    mask = np.where(time <= max_time)

    plot_p_1, = plt.plot(time[mask], strain_p_1[mask], lw = 4.0, color = colors[0], linestyle = linestyles[0],
                         marker = markers[0], markersize = markersize, markevery = markevery, label = label_p_1)
    plot_p_2, = plt.plot(time[mask], strain_p_2[mask], lw = 4.0, color = colors[2], linestyle = linestyles[2],
                         marker = markers[2], markersize = markersize, markevery = markevery, label = label_p_2)
    plot_p_3, = plt.plot(time[mask], strain_p_3[mask], lw = 4.0, color = colors[4], linestyle = linestyles[4],
                         marker = markers[4], markersize = markersize, markevery = markevery, label = label_p_3)

    plot_x_1, = plt.plot(time[mask], strain_x_1[mask], lw = 4.0, color = colors[1], linestyle = linestyles[1],
                         marker = markers[1], markersize = markersize, markevery = markevery, label = label_x_1)
    plot_x_2, = plt.plot(time[mask], strain_x_2[mask], lw = 4.0, color = colors[3], linestyle = linestyles[3],
                         marker = markers[3], markersize = markersize, markevery = markevery, label = label_x_2)
    plot_x_3, = plt.plot(time[mask], strain_x_3[mask], lw = 4.0, color = colors[5], linestyle = linestyles[5],
                         marker = markers[5], markersize = markersize, markevery = markevery, label = label_x_3)

    plt.tick_params(labelsize=20)

    plt.xlabel(r'$t\ \mathrm{(s)}$', fontsize = 24)
    plt.ylabel(r'$h\, /\, 10^{}$'.format('{' + str(scale_exp) + '}'), fontsize = 24)

    xlim = [time[mask][0], time[mask][-1]]
    plt.xlim(xlim)
    ylim = [min(np.min(strain_p_3), np.min(strain_x_3)) - 0.05 * offset, max(np.max(strain_p_1), np.max(strain_x_1)) + 0.5 * offset]
    plt.ylim(ylim)

    # Taking a trick from http://matplotlib.org/users/legend_guide.html#multiple-legends-on-the-same-axes
    # to split the legend into three parts.

    legend_1 = plt.legend(handles = [plot_p_1, plot_x_1], loc = [0.1, 0.85], prop = {'size':20}, ncol = 2, fancybox = True)
    legend_2 = plt.legend(handles = [plot_p_2, plot_x_2], loc = [0.1, 0.55], prop = {'size':20}, ncol = 2, fancybox = True)
    legend_3 = plt.legend(handles = [plot_p_3, plot_x_3], loc = [0.1, 0.25], prop = {'size':20}, ncol = 2, fancybox = True)

    plt.gca().add_artist(legend_1)
    plt.gca().add_artist(legend_2)
    plt.gca().add_artist(legend_3)

    plt.tight_layout()

    plt.savefig(eps_filename)

    wdmerger.insert_commits_into_eps(eps_filename, diag_file, 'diag')

    plt.close()
def plot_wd_distance(diag_filenames, output_filename, n_orbits=-1, labels=''):

    # If we got only a single diagnostic file,
    # create a list out of it for the coming loop.

    if (type(diag_filenames) not in [list, tuple]):
        diag_filenames = [ diag_filenames ]
        labels = [ labels ]

    # Cycle through markers for multiple curves on the same plot.

    markers = ['o', '+', '.', ',', '*']

    j = 0

    for diag_filename, label in zip(diag_filenames, labels):

        diag_file = open(diag_filename, 'r')

        time = get_column("TIME", diag_filename)
        dist = get_column("WD DISTANCE",diag_filename)

        # Normalize distance by initial distance.

        dist = dist / dist[0]

        # Normalize time by rotational period.

        rot_period = 0.0

        dir = os.path.dirname(diag_filename)

        inputs_filename = dir + '/' + wdmerger.get_inputs_filename(dir)
        rot_period = wdmerger.get_inputs_var(inputs_filename, "castro.rotational_period")

        if (rot_period > 0.0):
            time = time / rot_period
            xlabel = "Time / Rotational Period"
            if (n_orbits > 0):
                idx = np.where(time < n_orbits)
                time = time[idx]
                dist = dist[idx]
        else:
            xlabel = "Time (s)"
        ylabel = "WD Distance / Initial Distance"

        if (label is not ''):
            plot_label = label

        if (len(diag_filenames) > 1):
            marker = markers[j]
        else:
            marker = ''

        # Use a markevery stride because of how densely packed the star_diag.out data usually is.

        plt.plot(time, dist, marker = marker, ms = 12.0, markevery = 500, lw = 4.0, label=plot_label)

        j += 1

    plt.xlabel(xlabel, fontsize=20)
    plt.ylabel(ylabel, fontsize=20)

    plt.gca().get_yaxis().get_major_formatter().set_useOffset(False)

    # Use the 'best' location for the legend, since for a generic function like this
    # it is hard to know ahead of time where the legend ought to go.
    # The alpha value controls the transparency, since we may end up covering some data.

    if (label is not ''):
        plt.legend(loc='best', fancybox=True, framealpha=0.5)

    # The padding ensures that the lower-left ticks on the x- and y-axes don't overlap.

    plt.tick_params(labelsize=16, pad=10)

    # We have now increased the size of both the ticks and the axis labels,
    # which may have caused the latter to fall off the plot. Use tight_layout
    # to automatically adjust the plot to fix this.

    plt.tight_layout()

    # Save it into our designated file, which is usually EPS format.

    plt.savefig(output_filename)

    # Insert git commit hashes into this file from the various code sources.

    wdmerger.insert_commits_into_eps(output_filename, diag_filename, 'diag')

    plt.close()
def plot_wd_location(diag_filenames, output_filename):

    # If we got only a single diagnostic file,
    # create a list out of it for the coming loop.

    if (type(diag_filenames) not in [list, tuple]):
        diag_filenames = [ diag_filenames ]

    # Cycle through markers for multiple curves on the same plot.

    N = len(diag_filenames)

    # Determine the number of subplots and their layout.

    nRows = 1
    nCols = 1

    if (N == 2):
        nCols = 2
    elif (N == 3):
        nCols = 3
    elif (N == 4):
        nRows = 2
        nCols = 2

    if (N > 1):  
        fig, ax = plt.subplots(nRows, nCols)
    else:
        fig = plt.gcf()
        ax  = plt.gca()

    row = 0
    col = 0
    j   = 0

    labels = ['(a)', '(b)', '(c)', '(d)']

    for diag_filename in diag_filenames:

        diag_file = open(diag_filename, 'r')

        # x and y locations of each star

        xp   = get_column("PRIMARY X COM",diag_filename)
        yp   = get_column("PRIMARY Y COM",diag_filename)
        xs   = get_column("SECONDARY X COM",diag_filename)
        ys   = get_column("SECONDARY Y COM",diag_filename)

        # Width of domain, from inputs file.

        dir = os.path.dirname(diag_filename)

        inputs_filename = dir + '/' + wdmerger.get_inputs_filename(dir)

        problo = wdmerger.get_inputs_var(inputs_filename, "geometry.prob_lo")
        probhi = wdmerger.get_inputs_var(inputs_filename, "geometry.prob_hi")

        half_width = (probhi - problo) / 2.0

        # If we are in the rotating frame, we want to transform back to the inertial frame.

        do_rotation = wdmerger.get_inputs_var(inputs_filename, "castro.do_rotation")

        if (do_rotation == 1):
            time = get_column("TIME",diag_filename)
            rot_period = wdmerger.get_inputs_var(inputs_filename, "castro.rotational_period")

            theta = (2.0 * np.pi / rot_period) * time        

            # Rotate from rotating frame to inertial frame using rotation matrix

            xp_old = xp
            yp_old = yp

            xp = xp_old * np.cos(theta) - yp_old * np.sin(theta)
            yp = xp_old * np.sin(theta) + yp_old * np.cos(theta)

            xs_old = xs
            ys_old = ys

            xs = xs_old * np.cos(theta) - ys_old * np.sin(theta)
            ys = xs_old * np.sin(theta) + ys_old * np.cos(theta)

        # Normalize the locations by this domain size, so that they are in the range [-0.5, 0.5]

        xp = xp / half_width[0]
        yp = yp / half_width[1]
        xs = xs / half_width[0]
        ys = ys / half_width[1]

        xlabel = "x"
        ylabel = "y"

        if (N > 1):
            curr_ax = ax[row,col]
        else:
            curr_ax = ax

        # Determine the label and position of this subplot based on the number of inputs.

        curr_ax.plot(xp, yp, 'b--')
        curr_ax.plot(xs, ys, 'r')

        curr_ax.set_xlabel(xlabel, fontsize=20)
        curr_ax.set_ylabel(ylabel, fontsize=20)

        curr_ax.set_xlim([-0.55, 0.55])
        curr_ax.set_ylim([-0.55, 0.55])

        curr_ax.xaxis.set_ticks([-0.50, 0.0, 0.50])
        curr_ax.yaxis.set_ticks([-0.50, 0.0, 0.50])

        curr_ax.set_aspect('equal')

        # The padding ensures that the lower-left ticks on the x- and y-axes don't overlap.

        curr_ax.tick_params(labelsize=16, pad=10)

        # Give it a letter label, for multipanel figures.

        if (N > 1):

            curr_ax.annotate(labels[j], xy=(0.15, 0.85), xycoords='axes fraction', fontsize=16,
                             horizontalalignment='right', verticalalignment='bottom')

        col += 1
        
        if (col > nCols-1):
            col = 0
            row += 1

        j += 1

    # Tighten up figure layout.

    fig.tight_layout()

    # Save it into our designated file, which is usually EPS format.

    plt.savefig(output_filename)

    # Insert git commit hashes into this file from the various code sources.

    wdmerger.insert_commits_into_eps(output_filename, diag_filename, 'diag')

    plt.close()