コード例 #1
0
def analyze():
    analyze_status = True
    # read data from error file
    filenames = ['bin/turb_serial.hst',
                 'bin/turb_mpi1.hst',
                 'bin/turb_mpi2.hst',
                 'bin/turb_mpi4.hst']

    hst = athena_read.hst(filenames[0])
    KE0 = hst['1-KE']+hst['2-KE']+hst['3-KE']

    KE_final = [KE0[-1]]
    diff = []
    for hstfile in filenames[1:]:
        hst = athena_read.hst(hstfile)
        KE = hst['1-KE']+hst['2-KE']+hst['3-KE']
        KE_final.append(KE[-1])
        diff.append(np.sum(np.abs(KE-KE0)))

    logger.info("%g %g %g %g", KE0[-1], KE_final[1], KE_final[2], KE_final[3])

    # check errors between runs w/wo MPI and different numbers of cores
    if diff[0] > 1.e-7:
        logger.warning("Turb runs with serial and 1 MPI rank are different %g", diff[0])
        analyze_status = False
    if diff[1] > 1.e-7:
        logger.warning("Turb runs with serial and 2 MPI ranks are different %g", diff[1])
        analyze_status = False
    if diff[2] > 1.e-7:
        logger.warning("Turb runs with serial and 4 MPI ranks are different %g", diff[2])
        analyze_status = False

    return analyze_status
コード例 #2
0
def load_hst(output_dir,
             adot,
             prob=DEFAULT_PROB,
             do_path_format=1,
             method='matt'):
    '''Loads data from .hst files output from Athena++.
    '''
    hstLoc = format_path(output_dir, do_path_format) + prob + '.hst'
    hst_data = hst(hstLoc)

    if 'a' not in hst_data.keys():
        t_hst = hst_data['time']
        hst_data['a'] = 1.0 + adot * t_hst

    a_hst = hst_data['a']
    if method == 'nothing':
        return hst_data
    elif method == 'matt':
        hst_data['mass'] /= a_hst**2
        hst_data['1-mom'] /= a_hst**2
        hst_data['2-mom'] /= a_hst
        hst_data['3-mom'] /= a_hst
        hst_data['1-KE'] /= a_hst**2  # Perp kinetic energies have same scaling
        hst_data['1-ME'] /= a_hst**4
        hst_data['2-ME'] /= a_hst**2
        hst_data['3-ME'] /= a_hst**2
    elif method == 'jono':
        hst_data['2-mom'] *= a_hst  # perp momenta ~ u_perp
        hst_data['3-mom'] *= a_hst
        hst_data['2-KE'] *= a_hst**2  # perp energies ~ u_perp^2 and B_perp^2
        hst_data['3-KE'] *= a_hst**2
        hst_data['2-ME'] *= a_hst**2
        hst_data['3-ME'] *= a_hst**2

    return hst_data
コード例 #3
0
def analyze():

    # omg  = 1.0e-3 # unused
    rho0 = 1.0
    cs = 1.0
    pres = rho0 * cs**2
    vol = 1.0 * np.pi * 1.0
    index = -500

    fname = 'data/mhd_mri_3d.hst'
    a = athena_read.hst(fname)
    me = (a['1-ME'] + a['2-ME'] + a['3-ME'])
    ref_stress = np.average(a['-BxBy'][index:] / vol / pres)
    ref_me = np.average(me[index:] / vol / pres)
    ref_ratio = ref_me / ref_stress

    fname = 'bin/HGB.hst'
    b = athena_read.hst(fname)
    me = (b['1-ME'] + b['2-ME'] + b['3-ME'])
    new_stress = np.average(b['-BxBy'][index:] / vol / pres)
    new_me = np.average(me[index:] / vol / pres)
    new_ratio = new_me / new_stress

    msg = '[MRI-3D]: {}(stress,ME,ratio) = {} {} {}'
    logger.warning(msg.format('Ref', ref_stress, ref_me, ref_ratio))
    logger.warning(msg.format('New', new_stress, new_me, new_ratio))
    flag = True
    error_rel = np.fabs((new_stress / ref_stress) - 1.0)
    if error_rel > 0.5:
        logger.warning('[MRI-3D]: averaged stress is off by a factor > 2')
        flag = False
    error_rel = np.fabs((new_me / ref_me) - 1.0)
    if error_rel > 0.5:
        logger.warning(
            '[MRI-3D]: averaged magnetic energy is off by a factor > 2')
        flag = False
    error_rel = np.fabs(new_ratio - ref_ratio)
    if error_rel > 1.0:
        logger.warning(
            '[MRI-3D]: energy-to-stress ratio is off by an amount > 1.0')
        flag = False

    return flag
コード例 #4
0
def plotmdot(hstname, ax):

    #reading history file
    hstdata = hst(hstname)

    massinflow = hstdata['massfluxix1'] - hstdata['massfluxox1']
    cumsum = np.cumsum(massinflow)
    dt = 0.1
    dv = (0.6 / 128) * (2 * np.pi / 256)
    time = hstdata['time'][1:]
    mass = hstdata['mass'][1:]

    ax.plot(time, -hstdata['massfluxix1'][1:], label=r'$\dot{M}_{\rm inner}$')
    ax.plot(time, -hstdata['massfluxox1'][1:], label=r'$\dot{M}_{\rm outer}$')
    ax.legend(loc='lower right')
    ax.set_ylabel(r'$\dot{M}$')
    ax.set_xlim(np.min(time), np.max(time))

    axx = ax.twinx()
    axx.set_ylabel(r"$M(t)$", color="tab:red")
    axx.plot(time, hstdata['mass'][1:], color='tab:red', ls='--')
    axx.tick_params(axis='y', labelcolor="tab:red")
    axx.set_ylim(0.0, 0.6)
コード例 #5
0
def analyze():
    # set parameters
    nx = -2
    ny = 1
    nz = 1

    Lx = 0.5
    Ly = 0.5
    Lz = 0.5

    Omega0 = 1.0
    qshear = 1.5
    iso_cs = 1.0
    rho0 = 1.0
    epsilon = 1.0e-6
    beta = 20.0

    Bx = 0.1 * iso_cs * math.sqrt(rho0)
    By0 = 0.2 * iso_cs * math.sqrt(rho0)

    kx0 = float(nx) * 2.0 * math.pi / Lx
    ky = float(ny) * 2.0 * math.pi / Ly
    kz = float(nz) * 2.0 * math.pi / Lz

    # read results w/o Orbital Advection
    fname = 'bin/JGG.hst'
    a = athena_read.hst(fname)
    time1 = a['time']
    dByc1 = a['dByc']
    xidBx1 = a['xidBx']
    nf1 = len(time1)

    # initialize parameters
    norm1a = 0.0
    norm1b = 0.0
    for i in range(nf1):
        if (i == 0):
            k = math.sqrt(kx0**2 + ky**2 + kz**2)
            dBya = epsilon * By0
            dBya *= math.sqrt(iso_cs * k / Omega0 * math.sqrt(beta /
                                                              (1.0 + beta)))
            dBy0 = dBya
            dBya = 1.0
        else:
            kx = kx0 + qshear * Omega0 * time1[i] * ky
            k = math.sqrt(kx**2 + ky**2 + kz**2)
            By = By0 - qshear * Omega0 * time1[i] * Bx
            dBya = epsilon * By / dBy0
            dBya *= math.sqrt(iso_cs * k / Omega0 * math.sqrt(beta /
                                                              (1.0 + beta)))
        norm1a += abs(dByc1[i] - abs(dBya))
        norm1b += abs(xidBx1[i])
    norm1a /= nf1
    norm1b /= nf1

    # read results w/  Orbital Advection
    fname = 'bin/JGG_ORB.hst'
    b = athena_read.hst(fname)
    time2 = b['time']
    dByc2 = b['dByc']
    xidBx2 = b['xidBx']
    nf2 = len(time2)

    # initialize parameters
    norm2a = 0.0
    norm2b = 0.0
    for i in range(nf1):
        if (i == 0):
            k = math.sqrt(kx0**2 + ky**2 + kz**2)
            dBya = epsilon * By0
            dBya *= math.sqrt(iso_cs * k / Omega0 * math.sqrt(beta /
                                                              (1.0 + beta)))
            dBy0 = dBya
            dBya = 1.0
        else:
            kx = kx0 + qshear * Omega0 * time1[i] * ky
            k = math.sqrt(kx**2 + ky**2 + kz**2)
            By = By0 - qshear * Omega0 * time1[i] * Bx
            dBya = epsilon * By / dBy0
            dBya *= math.sqrt(iso_cs * k / Omega0 * math.sqrt(beta /
                                                              (1.0 + beta)))
        norm2a += abs(dByc2[i] - abs(dBya))
        norm2b += abs(xidBx2[i])
    norm2a /= nf2
    norm2b /= nf2

    logger.warning('[MHD_SHWAVE]: L1-Norm Errors')
    msg = '[MHD_SHWAVE]: epsilon_c = {}, xi_dBx = {}'
    flag = True
    logger.warning('[MHD_SHWAVE]: w/o Orbital Advection')
    logger.warning(msg.format(norm1a, norm1b))
    if norm1a > 0.01:
        logger.warning('[MHD_SHWAVE]: dByc Error is more than 1%.')
        flag = False
    if norm1b > 0.01:
        logger.warning('[MHD_SHWAVE]: xi_dBx Error is more than 1%.')
        flag = False
    logger.warning('[MHD_SHWAVE]: w/  Orbital Advection')
    logger.warning(msg.format(norm2a, norm2b))
    if norm2a > 0.01:
        logger.warning('[MHD_SHWAVE]: dByc Error is more than 1%.')
        flag = False
    if norm2b > 0.01:
        logger.warning('[MHD_SHWAVE]: xi_dBx Error is more than 1%.')
        flag = False

    return flag
コード例 #6
0
import glob
import numpy as np
import athena_read

#print "make sure to use python2"

names = glob.glob('*.vtk')
nfiles = len(names)

name = str(names[0])
pos_dot = name.index('.')
name = name[:pos_dot]

data = athena_read.hst("%s.hst" % (name))
times = data['time']
np.savetxt('times', times)
コード例 #7
0
def analyze():
    # set parameters
    ky = 0.5*math.pi
    kx0 = -2.0*math.pi
    Omega0 = 0.001
    qshear = 1.5
    kappa2 = 2.0*(2.0-qshear)*Omega0**2.0
    cs = 0.001
    constC = 0.5*(cs**2.0*ky**2.0+kappa2)/(qshear*Omega0*cs*ky)
    c1 = -1.82085106245
    c2 = -0.8208057072217868

    # read results of SSEET_SHWAVE
    fname = 'bin/SSHEET_SHWAVE.hst'
    a = athena_read.hst(fname)
    time1 = a['time']
    dvyc1 = a['dvyc']
    dvys1 = a['dvys']
    nf1 = len(time1)
    norm1c = 0.0
    norm1s = 0.0
    for n in range(nf1):
        tau_ = qshear*Omega0*time1[n]+kx0/ky
        T_ = 1.0j * cmath.sqrt(2.0*cs*ky/(qshear*Omega0))*tau_
        exp_ = cmath.exp(-0.25j*T_*T_)
        fterm_ = exp_*mp.hyp1f1(0.25-0.5j*constC, 0.5, 0.5j*T_*T_)
        first_ = fterm_.real
        exp_ = cmath.exp(0.25j*(math.pi-T_*T_))
        sterm_ = exp_*T_*mp.hyp1f1(0.75-0.5j*constC, 1.5, 0.5j*T_*T_)
        second_ = sterm_.real
        advy = c1*first_+c2*second_
        norm1c += abs(dvyc1[n]-advy)
        norm1s += abs(dvys1[n])
    norm1c /= nf1
    norm1s /= nf1

    # read results of SSEET_SHWAVE_ORB
    fname = 'bin/SSHEET_SHWAVE_ORB.hst'
    b = athena_read.hst(fname)
    time2 = b['time']
    dvyc2 = b['dvyc']
    dvys2 = b['dvys']
    nf2 = len(time2)
    norm2c = 0.0
    norm2s = 0.0
    for n in range(nf2):
        tau_ = qshear*Omega0*time2[n]+kx0/ky
        T_ = 1.0j * cmath.sqrt(2.0*cs*ky/(qshear*Omega0))*tau_
        exp_ = cmath.exp(-0.25j*T_*T_)
        fterm_ = exp_*mp.hyp1f1(0.25-0.5j*constC, 0.5, 0.5j*T_*T_)
        first_ = fterm_.real
        exp_ = cmath.exp(0.25j*(math.pi-T_*T_))
        sterm_ = exp_*T_*mp.hyp1f1(0.75-0.5j*constC, 1.5, 0.5j*T_*T_)
        second_ = sterm_.real
        advy = c1*first_+c2*second_
        norm2c += abs(dvyc2[n]-advy)
        norm2s += abs(dvys2[n])
    norm2c /= nf2
    norm2s /= nf2

    logger.warning('[SSHEET_SHWAVE]: L1-Norm Errors')
    msg = '[SSHEET_SHWAVE]: epsilon_c = {}, epsilon_s = {}'
    flag = True
    logger.warning('[SSHEET_SHWAVE]: w/o Orbital Advection')
    logger.warning(msg.format(norm1c, norm1s))
    if norm1c > 0.2:
        logger.warning('[SSHEET_SHWAVE]: dvyc Error is more than 20%.')
        flag = False
    if norm1s > 0.01:
        logger.warning('[SSHEET_SHWAVE]: dvys Error is more than 1%.')
        flag = False

    logger.warning('[SSHEET_SHWAVE]: w/  Orbital Advection')
    logger.warning(msg.format(norm2c, norm2s))
    if norm1c > 0.2:
        logger.warning('[SSHEET_SHWAVE]: dvyc Error is more than 20%.')
        flag = False
    if norm1s > 0.01:
        logger.warning('[SSHEET_SHWAVE]: dvys Error is more than 1%.')
        flag = False

    return flag
コード例 #8
0
def analyze():
    # Lambda=1 for Athena++'s linear wave setups in 1D, 2D, and 3D:
    L = 1.0
    ksqr = (2.0 * np.pi / L)**2
    # Equation 3.13 from Ryu, et al. (modified to add thermal conduction term)
    # fast mode decay rate = (19\nu/4 + 3\eta + 3(\gamma-1)^2*kappa/gamma/4)*(2/15)*k^2
    # Equation 3.14 from Ryu, et al. (modified to add thermal conduction term)
    # slow mode decay rate = (4\nu + 3\eta/4 + 3(\gamma-1)^2*kappa/gamma)*(2/15)*k^2
    slow_mode_rate = (4.0 * _nu + 3.0 * _eta / 4.0 +
                      _kappa * 4.0 / 5.0) * (2.0 / 15.0) * ksqr

    # Equation 3.16
    re_num = (4.0 * np.pi**2 * _c_s) / (L * slow_mode_rate)
    analyze_status = True
    errors_abs = []

    for (nx, err_tol) in zip(resolution_range, error_rel_tols):
        logging.info('[Decaying 3D Linear Wave {}]: '
                     'Mesh size {} x {} x {}'.format(method, nx, nx / 2,
                                                     nx / 2))
        filename = 'bin/DecayLinWave-{}.hst'.format(nx)
        hst_data = athena_read.hst(filename)
        tt = hst_data['time']
        max_vy = hst_data['max-v2']
        # estimate the decay rate from simulation, using weighted least-squares (WLS)
        yy = np.log(np.abs(max_vy))
        p, [resid, rank, sv, rcond] = Polynomial.fit(tt,
                                                     yy,
                                                     1,
                                                     w=np.sqrt(max_vy),
                                                     full=True)
        resid_normal = np.sum((yy - p(tt))**2)
        r2 = 1 - resid_normal / (yy.size * yy.var())
        pnormal = p.convert(domain=(-1, 1))
        fit_rate = -pnormal.coef[-1]

        error_abs = np.fabs(slow_mode_rate - fit_rate)
        errors_abs += [error_abs]
        error_rel = np.fabs(slow_mode_rate / fit_rate - 1.0)
        err_rel_tol_percent = err_tol * 100.

        logger.info(
            '[Decaying 3D Linear Wave {}]: Reynolds number of slow mode: {}'.
            format(method, re_num))
        logger.info(
            '[Decaying 3D Linear Wave {}]: R-squared of WLS regression = {}'.
            format(method, r2))
        logger.info(
            '[Decaying 3D Linear Wave {}]: Analytic decay rate = {}'.format(
                method, slow_mode_rate))
        logger.info(
            '[Decaying 3D Linear Wave {}]: Measured decay rate = {}'.format(
                method, fit_rate))
        logger.info(
            '[Decaying 3D Linear Wave {}]: Decay rate absolute error = {}'.
            format(method, error_abs))
        logger.info(
            '[Decaying 3D Linear Wave {}]: Decay rate relative error = {}'.
            format(method, error_rel))

        if error_rel > err_tol:
            logger.warning('[Decaying 3D Linear Wave {}]: decay rate disagrees'
                           ' with prediction by >{}%'.format(
                               method, err_rel_tol_percent))
            analyze_status = False
        else:
            logger.info('[Decaying 3D Linear Wave {}]: decay rate is within '
                        '{}% of analytic value'.format(method,
                                                       err_rel_tol_percent))
            logger.info('')

    # Check 2nd order convergence rate of solver (STS should only converge at 1st order)
    # SEE ABOVE NOTE
    rate = np.log(errors_abs[-2] / errors_abs[-1]) / (np.log(
        resolution_range[-1] / resolution_range[-2]))
    logger.info(
        '[Decaying 3D Linear Wave]: convergence rate of decay rate error = {}'.
        format(rate))
    if rate < rate_tols[-1]:
        logger.warning(
            '[Decaying 3D Linear Wave]: convergence of decay rate absolute '
            'error is slower than {}'.format(rate_tols[-1]))
        analyze_status = False
    else:
        logger.info(
            '[Decaying 3D Linear Wave]: convergence of decay rate absolute error '
            'is at least {}'.format(rate_tols[-1]))

    return analyze_status
コード例 #9
0
import matplotlib.colors as colors
from athena_read import athdf
import numpy as np
from time import time
import multiprocessing as mp
import matplotlib.pyplot as plt
from athena_read import hst
import matplotlib.gridspec as gridspec
from matplotlib import animation
from matplotlib import rc

rc('text', usetex=True)
rc('font', family='serif', size=12)

#reading history file
hst = hst('BDstream.hst')

#Plotting
fig = plt.figure(figsize=(10, 7.5))
spec = gridspec.GridSpec(ncols=1, nrows=2)
ax0 = fig.add_subplot(spec[0, :])
ax1 = fig.add_subplot(spec[1, :])

ax0.plot(hst['time'][1:],
         -hst['massfluxix1'][1:],
         label=r'$\dot{M}_{\rm inner}$')
ax0.plot(hst['time'][1:],
         -hst['massfluxox1'][1:],
         label=r'$\dot{M}_{\rm outer}$')
#ax0.set_yscale('log')
ax0.legend(loc='upper right')
コード例 #10
0
def main(**kwargs):

  # Extract inputs
  data_files = kwargs['data_files'].split(',')
  x_names = kwargs['x_names'].split(',')
  y_names = kwargs['y_names'].split(',')
  output_file = kwargs['output_file']
  styles = kwargs['styles'].split(',')
  colors = kwargs['colors']
  labels = kwargs['labels']
  x_log = kwargs['x_log']
  y_log = kwargs['y_log']
  x_min = kwargs['x_min']
  x_max = kwargs['x_max']
  y_min = kwargs['y_min']
  y_max = kwargs['y_max']
  x_label = kwargs['x_label']
  y_label = kwargs['y_label']

  # Verify inputs
  num_lines = max(len(data_files), len(x_names), len(y_names))
  if data_files[0] == '':
    raise RuntimeError('First entry in data_files must be nonempty')
  if x_names[0] == '':
    raise RuntimeError('First entry in x_names must be nonempty')
  if y_names[0] == '':
    raise RuntimeError('First entry in y_names must be nonempty')
  for data_file in data_files:
    if data_file[-4:] != '.hst' and data_file[-4:] != '.tab':
      raise RuntimeError('Files must have .hst or .tab extension')
  if len(data_files) < num_lines:
    data_files += data_files[-1:] * (num_lines - len(data_files))
  if len(x_names) < num_lines:
    x_names += x_names[-1:] * (num_lines - len(x_names))
  if len(y_names) < num_lines:
    y_names += y_names[-1:] * (num_lines - len(y_names))
  for n in range(num_lines):
    if data_files[n] == '':
      data_files[n] = data_files[n-1]
    if x_names[n] == '':
      x_names[n] = x_names[n-1]
    if y_names[n] == '':
      y_names[n] = y_names[n-1]
  if len(styles) < num_lines:
    styles += styles[-1:] * (num_lines - len(styles))
  for n in range(num_lines):
    styles[n] = styles[n].lstrip()
    if styles[n] == '':
      styles[n] = '-'
  if colors is None:
    colors = [None] * num_lines
  else:
    colors = colors.split(',')
    if len(colors) < num_lines:
      colors += colors[-1:] * (num_lines - len(colors))
    for n in range(num_lines):
      if colors[n] == '':
        colors[n] = None
  if num_lines == 1 and colors[0] == None:
    colors[0] = 'k'
  if labels is None:
    labels = [None] * num_lines
  else:
    labels = labels.split(',')
    if len(labels) < num_lines:
      labels += [None] * (num_lines - len(labels))
    for n in range(num_lines):
      if labels[n] == '':
        labels[n] = None
  labels_used = False
  for n in range(num_lines):
    if labels[n] != None:
      labels_used = True
      break

  # Load Python plotting modules
  if output_file != 'show':
    import matplotlib
    matplotlib.use('agg')
  import matplotlib.pyplot as plt

  # Read data
  x_vals = []
  y_vals = []
  for n in range(num_lines):
    if data_files[n][-4:] == '.hst':
      data = athena_read.hst(data_files[n])
    else:
      data = athena_read.tab(data_files[n])
    x_vals.append(data[x_names[n]])
    y_vals.append(data[y_names[n]])

  # Plot data
  plt.figure()
  for n in range(num_lines):
    plt.plot(x_vals[n], y_vals[n], styles[n], color=colors[n], label=labels[n])
  if x_log:
    plt.xscale('log')
  if y_log:
    plt.yscale('log')
  plt.xlim((x_min, x_max))
  plt.ylim((y_min, y_max))
  if x_label is not None:
    plt.xlabel(x_label)
  if y_label is not None:
    plt.ylabel(y_label)
  if labels_used:
    plt.legend(loc='best')
  if output_file == 'show':
    plt.show()
  else:
    plt.savefig(output_file, bbox_inches='tight')
コード例 #11
0
def analyze():
    # Lambda=1 for Athena++'s linear wave setups in 1D, 2D, and 3D:
    L = 1.0
    ksqr = (2.0 * np.pi / L)**2
    # The decay rate for a sound wave with a thermal conduction term is given by
    # decay rate = ((\gamma-1)^2*kappa/gamma/2)*k^2
    decay_rate = 2.0 * _kappa / 15.0 * ksqr
    analyze_status = True
    errors_abs = []

    for (nx, err_tol) in zip(resolution_range, error_rel_tols):
        logger.info('[Decaying 3D Linear Wave {}]: '
                    'Mesh size {} x {} x {}'.format(method, nx, nx / 2,
                                                    nx / 2))
        filename = 'bin/DecayLinWave-{}.hst'.format(nx)
        hst_data = athena_read.hst(filename)
        tt = hst_data['time']
        max_vy = hst_data['max-v2']

        # estimate the decay rate from simulation, using weighted least-squares (WLS)
        yy = np.log(np.abs(max_vy))
        p, [resid, rank, sv, rcond] = Polynomial.fit(tt,
                                                     yy,
                                                     1,
                                                     w=np.sqrt(max_vy),
                                                     full=True)
        resid_normal = np.sum((yy - p(tt))**2)
        r2 = 1 - resid_normal / (yy.size * yy.var())
        pnormal = p.convert(domain=(-1, 1))
        fit_rate = -pnormal.coef[-1]

        error_abs = np.fabs(decay_rate - fit_rate)
        errors_abs += [error_abs]
        error_rel = np.fabs(decay_rate / fit_rate - 1.0)
        err_rel_tol_percent = err_tol * 100.

        logger.info(
            '[Decaying 3D Linear Wave {}]: R-squared of WLS regression = {}'.
            format(method, r2))
        logger.info(
            '[Decaying 3D Linear Wave {}]: Analytic decay rate = {}'.format(
                method, decay_rate))
        logger.info(
            '[Decaying 3D Linear Wave {}]: Measured decay rate = {}'.format(
                method, fit_rate))
        logger.info(
            '[Decaying 3D Linear Wave {}]: Decay rate absolute error = {}'.
            format(method, error_abs))
        logger.info(
            '[Decaying 3D Linear Wave {}]: Decay rate relative error = {}'.
            format(method, error_rel))

        if error_rel > err_tol:
            logger.warning('[Decaying 3D Linear Wave {}]: decay rate disagrees'
                           ' with prediction by >{}%'.format(
                               method, err_rel_tol_percent))
            analyze_status = False
        else:
            logger.info('[Decaying 3D Linear Wave {}]: decay rate is within '
                        '{}% of analytic value'.format(method,
                                                       err_rel_tol_percent))
            logger.info('')

    return analyze_status