Reference Flare Spectra#

Generate reference spectra using some work from Amir Caspi’s previous papers (see IDL script). These are then converted from irradiance values to radiance values so that we can use them to simulate MOXSI spectra.

[1]:
import asdf
import hissw
import astropy.units as u
import numpy as np
from scipy.interpolate import interp1d
from astropy.visualization import quantity_support
import matplotlib.pyplot as plt
import ndcube
from ndcube.extra_coords import QuantityTableCoordinate

I got this script from Amir.

[2]:
idl_script = """
energy_bin_edges = {{ energy_bin_edges | to_unit('keV') | list }}
tmp = get_edges(energy_bin_edges, edges_2=eee, mean=eee_mean, wid=eee_wid)
area = 1
eee_wid = 1
; Calculate various incident photon flux spectra
 ; spec = (phot / cm^2 / s / keV) * keV * cm^2 = phot / s
 ; For 2002 Jul 23, interval 9 (peak HXR) based on Caspi & Lin (2010)
 spec_x5 = (f_vth(eee, [1.27277, 3.63241, 1.0]) + f_vth(eee, [5.40545, 2.02360, 1.0]) + f_vth(eee, [58, 0.52, 1.0]) + f_3pow(eee, [19.9396, 1.50000, 48.1353, 2.65948, 400.000, 2.00000])) * eee_wid * area
; if not keyword_set(filter) then spec_x5[where(eee_mean ge 27.)] = interpol(spec_x5[where(eee_mean ge 20. and eee_mean lt 27.)], eee_mean[where(eee_mean ge 20. and eee_mean lt 27.)], eee_mean[where(eee_mean ge 27.)])
 ; With temps based on Caspi, Krucker, & Lin 2014, EMs adjusted to match GOES flux, and PL adjusted arbitrarily
 spec_m5 = (f_vth(eee, [0.175, 2.75755, 1.0]) + f_vth(eee, [0.6, 1.55112, 1.0]) + f_vth(eee, [5.8, 0.52, 1.0]) + f_3pow(eee, [1.99396, 1.50000, 35, 3.5, 400.000, 2.00000])) * eee_wid * area
 spec_m1 = (f_vth(eee, [0.044, 1.80964, 1.0]) + f_vth(eee, [0.135, 1.29260, 1.0]) + f_vth(eee, [1.2, 0.52, 1.0]) + f_3pow(eee, [0.39879, 1.50000, 20, 4, 400.000, 2.00000])) * eee_wid * area
 ; With temps based on Caspi, Krucker, & Lin 2014 for GOES, guesstimate for RHESSI, EMs adjusted to match GOES flux, and PL adjusted arbitrarily
 spec_c1 = (f_vth(eee, [0.01, 1.2, 1.0]) + f_vth(eee, [0.015, 0.896204, 1.0]) + f_vth(eee, [.08, 0.52, 1.0]) + f_vth(eee, [3.5, 0.2, 0.41]) + f_3pow(eee, [0.04, 1.50000, 15, 6, 400.000, 2.00000])) * eee_wid * area
 ; For strong and weak ARs, based on X123 rocket results of Caspi et al. (2015) -- B7 and B1.6 levels
 spec_b7 = (f_vth(eee, [0.031242997, 0.74194414, 0.41]) + f_vth(eee, [3.5, 0.23129428, 0.41])) * eee_wid * area
 spec_b1 = (f_vth(eee, [0.0014166682, 0.75919482, 1.0]) + f_vth(eee, [0.4, 0.25346233, 1.0])) * eee_wid * area
 spec_a1 = (f_vth(eee, [0.0003, 0.6, 1.0]) + f_vth(eee, [0.07, 0.22, 1.0])) * eee_wid * area
 ; For deep minimum, based on Sylwester et al. (2012)
 spec_min = (f_vth(eee, [0.0978000, 0.147357, 1.0])) * eee_wid * area
 ; Add B7 active-region background to the BIG flares, B1 to the small flare
 spec_x5 += spec_b7 & spec_m5 += spec_b7 & spec_m1 += spec_b7 & spec_c1 += spec_b1
 spec_b1 += spec_min & spec_a1 += spec_min
"""

Run IDL script to generate spectra using f_vth and f_3pow for an energy range that covers the MOXSI bandpass.

[3]:
env = hissw.Environment(ssw_paths=['xray'], ssw_packages=['xray'],)
res = env.run(
    idl_script,
    args={
        'energy_bin_edges': np.logspace(-1, np.log10(125), 10000)*u.keV,
    },
    verbose=False,
)
energy_bin_edges = res['energy_bin_edges'] * u.keV
wavelength_bin_edges = energy_bin_edges.to('AA', equivalencies=u.equivalencies.spectral())
for k in res:
    if 'spec' in k:
        res[k] = u.Quantity(res[k], 'ph / (cm2 s keV)')

Look at these spectra in energy space per keV

[4]:
plt.figure(figsize=(8,8))
with quantity_support():
    for goes_class in ['a1', 'b1', 'b7', 'c1', 'm1', 'm5', 'x5']:
        plt.stairs(res[f'spec_{goes_class}'], edges=energy_bin_edges, label=goes_class.upper())
plt.yscale('log')
plt.xscale('log')
plt.legend(loc=1,ncol=3)
plt.xlim(energy_bin_edges.min(), energy_bin_edges.max())
plt.ylim(1,1e12)
[4]:
(1, 1000000000000.0)
../_images/reports_caspi_flare_spectra_7_1.png

We need to assume some angular size in order to convert our irradiance to a radiance. We assume a 10”-by-10” size for our flare here.

[5]:
flare_angular_size = (10*u.arcsec)**2
[6]:
spectra_collection = []
wavelength_wcs = QuantityTableCoordinate((energy_bin_edges[:-1]+energy_bin_edges[1:])/2, names='energy', physical_types='em.energy').wcs
delta_e_over_delta_wave = np.fabs(np.diff(energy_bin_edges))/np.fabs(np.diff(wavelength_bin_edges))
for goes_class in ['a1', 'b1', 'b7', 'c1', 'm1', 'm5', 'x5']:
    data = res[f'spec_{goes_class}'] * delta_e_over_delta_wave / flare_angular_size.to('sr')
    spectra_collection.append(
        (goes_class, ndcube.NDCube(data.to('ph cm-2 s-1 AA-1 sr-1'), wcs=wavelength_wcs,))
    )
spectra_collection = ndcube.NDCollection(spectra_collection, aligned_axes=(0,),)

Now that we have the radiance values per Angstrom, do a quick sanity check to make sure the values are about what we expect.

[7]:
plt.figure(figsize=(8,8))
with quantity_support():
    for k in spectra_collection:
        plt.stairs((spectra_collection[k].data*spectra_collection[k].unit).to('ph AA-1 cm-2 sr-1 s-1'), edges=wavelength_bin_edges, label=k.upper())
plt.yscale('log')
#plt.xscale('log')
plt.legend(loc=1,ncol=3)
plt.xlim(wavelength_bin_edges.min(), wavelength_bin_edges.max())
plt.ylim(1e9,1e19)
[7]:
(1000000000.0, 1e+19)
../_images/reports_caspi_flare_spectra_12_1.png

Now, save these all out to an ASDF file so we can easily reconstruct the NDCollection later.

[8]:
tree = {}
for k in spectra_collection:
    tree[k] = {
        'data': spectra_collection[k].data*spectra_collection[k].unit,
        'wcs': spectra_collection[k].wcs,
    }
tree['flare_angular_size'] = flare_angular_size
with asdf.AsdfFile(tree) as af:
    af.write_to('../data/reference_spectra/caspi_flare_spectra.asdf')
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
[ ]: