Assessing line diagnostics for different tube lengths#

Need to understand what we’re losing by shortening the tube and losing wavelengths

[145]:
import copy

import astropy.table
import astropy.units as u
import matplotlib.pyplot as plt
from adjustText import adjust_text
import numpy as np
import fiasco
from scipy.interpolate import interp1d
from aiapy.response import Channel

from astropy.visualization import quantity_support

from mocksipipeline.detector.response import SpectrogramChannel
[3]:
line_list = astropy.table.QTable.read('../data/line_lists/curated_line_list.asdf')
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
[8]:
plt.plot(line_list['wavelength'], line_list['T_max (Maxwellian)'].to('MK'),
         marker='.', ls='')
plt.yscale('log')
../_images/reports_temperature-wave-space_3_0.png
[257]:
full_line_list = astropy.table.QTable.read('../data/line_lists/full-line-list.asdf')
WARNING: UnitsWarning: The unit 'Angstrom' has been deprecated in the VOUnit standard. Suggested: 0.1nm. [astropy.units.format.utils]
[258]:
channel_o1 = SpectrogramChannel(1)
[259]:
response_unit = u.Unit('cm2 sr / ( pix)')
intensity_unit = response_unit * u.Unit('ph cm-2 s-1 sr-1')
f_interp_ea = interp1d(channel_o1.wavelength.to_value('AA'),
                       (channel_o1.effective_area* channel_o1.plate_scale).to_value(response_unit),
                       bounds_error=True,
                       assume_sorted=False)
plt.plot(full_line_list['wavelength'], f_interp_ea(full_line_list['wavelength'].to_value('AA')), marker='.', ls='')
plt.plot(channel_o1.wavelength, channel_o1.effective_area*channel_o1.plate_scale)
plt.yscale('log')
/Users/wtbarnes/mambaforge/envs/mocksipipeline/lib/python3.9/site-packages/astropy/units/quantity.py:673: RuntimeWarning: divide by zero encountered in divide
  result = super().__array_ufunc__(function, method, *arrays, **kwargs)
../_images/reports_temperature-wave-space_6_1.png
[260]:
# Add a T_max column based on the ionization fraction (existing ones depend on the DEM used)
temperature_grid = 10**np.arange(4,8,0.001)*u.K
all_chianti_ions = [fiasco.Ion(i, temperature_grid) for i in fiasco.list_ions(fiasco.defaults['hdf5_dbase_root'])]
ioneq_tmax = {i.ion_name_roman: i.formation_temperature for i in all_chianti_ions}
#full_line_list['T_max (Maxwellian)'] = list(map(lambda x: ioneq_tmax[x], full_line_list['ion name']))
# Add a FIP column
all_chianti_elements = [fiasco.Element(el, 1*u.MK) for el in fiasco.list_elements(fiasco.defaults['hdf5_dbase_root'])]
element_is_low_fip = {el.atomic_symbol: el[0].ip<=10*u.eV for el in all_chianti_elements}
full_line_list['is low FIP'] = list(map(lambda x: element_is_low_fip[x], full_line_list['element']))
# Add a column that expresses the intensity in MOXSI detector units
full_line_list['intensity_moxsi (coronal)_active_region'] = (full_line_list['intensity (coronal)_active_region']
                                                             * f_interp_ea(full_line_list['wavelength'].to_value('AA'))
                                                             * u.Unit(response_unit)).to(intensity_unit)
full_line_list['intensity_moxsi_scaled (coronal)_active_region'] = full_line_list['intensity_moxsi (coronal)_active_region'] / full_line_list['intensity_moxsi (coronal)_active_region'].max()
full_line_list['intensity_moxsi (coronal)_flare_ext'] = (full_line_list['intensity (coronal)_flare_ext']
                                                         * f_interp_ea(full_line_list['wavelength'].to_value('AA'))
                                                         * u.Unit(response_unit)).to(intensity_unit)
full_line_list['intensity_moxsi_scaled (coronal)_flare_ext'] = full_line_list['intensity_moxsi (coronal)_flare_ext'] / full_line_list['intensity_moxsi (coronal)_flare_ext'].max()
[263]:
full_line_list.colnames
[263]:
['atomic number',
 'ionization stage',
 'transition',
 'transition (latex)',
 'ion name',
 'lower level',
 'upper level',
 'max temperature_flare_ext',
 'wavelength',
 'only theoretical_flare_ext',
 'element',
 'ion id',
 'energy',
 'abundance (coronal)',
 'abundance (photospheric)',
 'intensity (coronal)_flare_ext',
 'intensity_scaled (coronal)_flare_ext',
 'intensity (photospheric)_flare_ext',
 'intensity_scaled (photospheric)_flare_ext',
 'max temperature_active_region',
 'only theoretical_active_region',
 'intensity (coronal)_active_region',
 'intensity_scaled (coronal)_active_region',
 'intensity (photospheric)_active_region',
 'intensity_scaled (photospheric)_active_region',
 'is low FIP',
 'intensity_moxsi (coronal)_active_region',
 'intensity_moxsi_scaled (coronal)_active_region',
 'intensity_moxsi (coronal)_flare_ext',
 'intensity_moxsi_scaled (coronal)_flare_ext']
[315]:
fig = plt.figure(figsize=(18,10))
ax = fig.add_subplot(111)
low_fip_color = 'C5'
high_fip_color = 'C6'
with quantity_support():
    ax.scatter(full_line_list['wavelength'],
               full_line_list['max temperature_active_region'].to('MK'),
               s=full_line_list['intensity_scaled (coronal)_active_region']*3e3,
               marker='.', alpha=0.3, color=[low_fip_color if r['is low FIP'] else high_fip_color for r in full_line_list])
    for ls,spec_res in zip(['--', ':'], [55, 71.8] * u.milliAA / u.pix):
        max_wave = 1000 * u.pix * spec_res
        for i,order in enumerate([1,2,3,4]):
            ax.axvline(x=max_wave/order, ls=ls, color=f'C{i}')
    ax.axhline(y=1*u.MK, ls='-.', color='k', lw=1)
    ax.axhline(y=10*u.MK, ls='-.', color='k', lw=1)

    line_labels = []
    line_label_tol = 0.05
    for row in full_line_list:
        if row['intensity_scaled (coronal)_active_region'] >= line_label_tol:
            line_labels.append(ax.text(row['wavelength'], row['max temperature_active_region'], row['ion name'],
                                       color=low_fip_color if row['is low FIP'] else high_fip_color))
    adjust_text(
        line_labels,
        x=copy.deepcopy(full_line_list['wavelength'].to_value('AA')),
        y=copy.deepcopy(full_line_list['max temperature_active_region'].to_value('MK')),
        avoid_points=False,
        arrowprops=dict(arrowstyle='->', color='k', alpha=0.75),
    )
    #ax.set_yscale('log')
    ax.set_ylim(0,10.1)
    ax.set_title('AR Intensities')
    ax.legend(handles=[plt.Line2D([0], [0], marker='.', color=low_fip_color, label='Low FIP', ls='', alpha=0.3, markersize=15),
                       plt.Line2D([0], [0], marker='.', color=high_fip_color, label='High FIP', ls='', alpha=0.3, markersize=15)],
              loc=1, frameon=False)
ax.set_xlabel(r'Transition Wavelength [Å]')
ax.set_ylabel(r'Effective Formation Temperature ($\argmax_T G(T)\mathrm{DEM}(T)$) [MK]')
[315]:
Text(192.09722222222223, 0.5, 'Effective Formation Temperature ($\\argmax_T G(T)\\mathrm{DEM}(T)$) [MK]')
../_images/reports_temperature-wave-space_9_1.png
[319]:
fig = plt.figure(figsize=(18,10))
ax = fig.add_subplot(111)
low_fip_color = 'C5'
high_fip_color = 'C6'
with quantity_support():
    ax.scatter(full_line_list['wavelength'],
               full_line_list['max temperature_active_region'].to('MK'),
               s=full_line_list['intensity_moxsi_scaled (coronal)_active_region']*3e3,
               marker='.', alpha=0.3, color=[low_fip_color if r['is low FIP'] else high_fip_color for r in full_line_list])
    for ls,spec_res in zip(['--', ':'], [55, 71.8] * u.milliAA / u.pix):
        max_wave = 1000 * u.pix * spec_res
        for i,order in enumerate([1,2,3,4]):
            ax.axvline(x=max_wave/order, ls=ls, color=f'C{i}')
    ax.axhline(y=1*u.MK, ls='-.', color='k', lw=1)
    ax.axhline(y=10*u.MK, ls='-.', color='k', lw=1)

    line_labels = []
    line_label_tol = 0.01
    for row in full_line_list:
        if row['intensity_moxsi_scaled (coronal)_active_region'] >= line_label_tol:
            line_labels.append(ax.text(row['wavelength'], row['max temperature_active_region'], row['ion name'],
                                       color=low_fip_color if row['is low FIP'] else high_fip_color))
    adjust_text(
        line_labels,
        x=copy.deepcopy(full_line_list['wavelength'].to_value('AA')),
        y=copy.deepcopy(full_line_list['max temperature_active_region'].to_value('MK')),
        avoid_points=False,
        arrowprops=dict(arrowstyle='->', color='k', alpha=0.75),
    )
    #ax.set_yscale('log')
    ax.set_ylim(0,10.1)
    ax.set_title('AR Intensities')
    ax.legend(handles=[plt.Line2D([0], [0], marker='.', color=low_fip_color, label='Low FIP', ls='', alpha=0.3, markersize=15),
                       plt.Line2D([0], [0], marker='.', color=high_fip_color, label='High FIP', ls='', alpha=0.3, markersize=15)],
              loc=1, frameon=False)
ax.set_xlabel(r'Transition Wavelength [Å]')
ax.set_ylabel(r'Effective Formation Temperature ($\argmax_T G(T)\mathrm{DEM}(T)$) [MK]')
[319]:
Text(192.09722222222223, 0.5, 'Effective Formation Temperature ($\\argmax_T G(T)\\mathrm{DEM}(T)$) [MK]')
../_images/reports_temperature-wave-space_10_1.png
[321]:
fig = plt.figure(figsize=(18,10))
ax = fig.add_subplot(111)
with quantity_support():
    ax.scatter(full_line_list['wavelength'],
               full_line_list['max temperature_flare_ext'].to('MK'),
               s=full_line_list['intensity_scaled (coronal)_flare_ext']*3e3,
               marker='.', alpha=0.3, color=[low_fip_color if r['is low FIP'] else high_fip_color for r in full_line_list])
    for ls,spec_res in zip(['--', ':'], [55, 71.8] * u.milliAA / u.pix):
        max_wave = 1000 * u.pix * spec_res
        for i,order in enumerate([1,2,3,4]):
            ax.axvline(x=max_wave/order, ls=ls, color=f'C{i}')
    ax.axhline(y=1*u.MK, ls='-.', color='k', lw=1)
    ax.axhline(y=10*u.MK, ls='-.', color='k', lw=1)

    line_labels = []
    line_label_tol = 0.03
    for row in full_line_list:
        if row['intensity_scaled (coronal)_flare_ext'] >= line_label_tol:
            line_labels.append(ax.text(row['wavelength'], row['max temperature_flare_ext'], row['ion name'],
                                       color=low_fip_color if row['is low FIP'] else high_fip_color,clip_on=True))
    adjust_text(
        line_labels,
        x=copy.deepcopy(full_line_list['wavelength'].to_value('AA')),
        y=copy.deepcopy(full_line_list['max temperature_flare_ext'].to_value('MK')),
        avoid_points=False,
        arrowprops=dict(arrowstyle='->', color='k', alpha=0.75),
        clip_on=True,
    )
    #ax.set_yscale('log')
    ax.set_ylim(0,40)
    ax.set_title('Flare Intensities')
    ax.legend(handles=[plt.Line2D([0], [0], marker='.', color=low_fip_color, label='Low FIP', ls='', alpha=0.3, markersize=15),
                   plt.Line2D([0], [0], marker='.', color=high_fip_color, label='High FIP', ls='', alpha=0.3, markersize=15)],
          loc=1, frameon=False)
ax.set_xlabel(r'Transition Wavelength [Å]')
ax.set_ylabel(r'Effective Formation Temperature ($\argmax_T G(T)\mathrm{DEM}(T)$) [MK]')
[321]:
Text(192.09722222222223, 0.5, 'Effective Formation Temperature ($\\argmax_T G(T)\\mathrm{DEM}(T)$) [MK]')
../_images/reports_temperature-wave-space_11_1.png
[320]:
fig = plt.figure(figsize=(18,10))
ax = fig.add_subplot(111)
with quantity_support():
    ax.scatter(full_line_list['wavelength'],
               full_line_list['max temperature_flare_ext'].to('MK'),
               s=full_line_list['intensity_moxsi_scaled (coronal)_flare_ext']*3e3,
               marker='.', alpha=0.3, color=[low_fip_color if r['is low FIP'] else high_fip_color for r in full_line_list])
    for ls,spec_res in zip(['--', ':'], [55, 71.8] * u.milliAA / u.pix):
        max_wave = 1000 * u.pix * spec_res
        for i,order in enumerate([1,2,3,4]):
            ax.axvline(x=max_wave/order, ls=ls, color=f'C{i}')
    ax.axhline(y=1*u.MK, ls='-.', color='k', lw=1)
    ax.axhline(y=10*u.MK, ls='-.', color='k', lw=1)

    line_labels = []
    line_label_tol = 0.03
    for row in full_line_list:
        if row['intensity_moxsi_scaled (coronal)_flare_ext'] >= line_label_tol:
            line_labels.append(ax.text(row['wavelength'], row['max temperature_flare_ext'], row['ion name'],
                                       color=low_fip_color if row['is low FIP'] else high_fip_color,
                                       clip_on=True))
    adjust_text(
        line_labels,
        x=copy.deepcopy(full_line_list['wavelength'].to_value('AA')),
        y=copy.deepcopy(full_line_list['max temperature_flare_ext'].to_value('MK')),
        avoid_points=False,
        arrowprops=dict(arrowstyle='->', color='k', alpha=0.75),
        clip_on=True,
    )
    #ax.set_yscale('log')
    ax.set_ylim(0,40)
    ax.set_title('Flare Intensities')
    ax.legend(handles=[plt.Line2D([0], [0], marker='.', color=low_fip_color, label='Low FIP', ls='', alpha=0.3, markersize=15),
                   plt.Line2D([0], [0], marker='.', color=high_fip_color, label='High FIP', ls='', alpha=0.3, markersize=15)],
          loc=1, frameon=False)
ax.set_xlabel(r'Transition Wavelength [Å]')
ax.set_ylabel(r'Effective Formation Temperature ($\argmax_T G(T)\mathrm{DEM}(T)$) [MK]')
[320]:
Text(192.09722222222223, 0.5, 'Effective Formation Temperature ($\\argmax_T G(T)\\mathrm{DEM}(T)$) [MK]')
../_images/reports_temperature-wave-space_12_1.png
[211]:
full_line_list[full_line_list['ion name']=='Ca XIX']
[211]:
QTable length=1
atomic numberionization stagetransitiontransition (latex)ion namelower levelupper levelmax temperature_flare_extwavelengthonly theoretical_flare_extelemention idenergyabundance (coronal)abundance (photospheric)intensity (coronal)_flare_extintensity_scaled (coronal)_flare_extintensity (photospheric)_flare_extintensity_scaled (photospheric)_flare_extmax temperature_active_regiononly theoretical_active_regionintensity (coronal)_active_regionintensity_scaled (coronal)_active_regionintensity (photospheric)_active_regionintensity_scaled (photospheric)_active_regionT_max (Maxwellian)is low FIPintensity_moxsi (coronal)_active_regionintensity_moxsi (coronal)_flare_extintensity_moxsi_scaled (coronal)_active_regionintensity_moxsi_scaled (coronal)_flare_ext
MKAngstromkeVph / (cm2 s sr)ph / (cm2 s sr)MKph / (cm2 s sr)ph / (cm2 s sr)Kph / (pix s)ph / (pix s)
int16int16str48str93str9int16int16float32float64boolstr2str5float64float64float64float64float64float64float64float32boolfloat64float64float64float64float64boolfloat64float64float64float64
20191s2 1S0 - 1s.2p 1P11s$^{2}$ $^1$S$_{0}$ - 1s 2p $^1$P$_{1}$Ca XIX1728.1838150024414063.177299976348877FalseCaca_193.90218737154538038.51138038202376e-062.0892961308540407e-0653168349084686.8750.01418511890545701113051282053043.5040.0133866299675612946.309576034545898False2745900.3198598611.2336774759948343e-06674038.59967423866.803072194777514e-0714125375.446261758True4.302436112725481e-090.083307257551004684.346543031098956e-060.03003118618894085
[212]:
ca19 = fiasco.Ion('Ca XIX', np.logspace(5,8,1000)*u.K)
[213]:
goft_ca19 = ca19.contribution_function(1e15*u.Unit('cm-3 K')/ca19.temperature, couple_density_to_temperature=True,)
WARNING: No proton data available for Ca 19. Not including proton excitation and de-excitation in level populations calculation. [fiasco.ions]
[218]:
transitions_ca19 = ca19.transitions.wavelength[~ca19.transitions.is_twophoton]
idx = np.argmin(np.fabs(transitions_ca19-3.177299976348877*u.AA))
transitions_ca19[idx]
goft_ca19_ = goft_ca19.squeeze()[:,idx]
[306]:
plt.plot(ca19.temperature, goft_ca19_, color='C0', ls='-', label=f'$G(T)$, {ca19.temperature[np.argmax(goft_ca19_)].to("MK"):latex}')
plt.xscale('log')
plt.ylim(1e-28, 1e-25)
plt.legend(loc=1)
plt.twinx().plot(ca19.temperature, ca19.ioneq, color='C0', ls='--', label=f'ioneq, {ca19.temperature[np.argmax(ca19.ioneq)].to("MK"):latex}')
plt.legend(loc=2)
[306]:
<matplotlib.legend.Legend at 0x2c6e3e880>
../_images/reports_temperature-wave-space_17_1.png
[274]:
oxygen = fiasco.Element('oxygen', 10**np.arange(5,8,0.05)*u.K)
[280]:
def find_goft(goft, ion, transition):
    transitions_ion = ion.transitions.wavelength[~ion.transitions.is_twophoton]
    idx = np.argmin(np.fabs(transitions_ion-transition))
    print(transitions_ion[idx])
    return goft[..., idx].squeeze()
[302]:
o7_goft = oxygen[6].contribution_function(1e15*u.Unit('cm-3 K')/oxygen.temperature, couple_density_to_temperature=True)
o8_goft = oxygen[7].contribution_function(1e15*u.Unit('cm-3 K')/oxygen.temperature, couple_density_to_temperature=True)
WARNING: No proton data available for O 7. Not including proton excitation and de-excitation in level populations calculation. [fiasco.ions]
WARNING: No proton data available for O 8. Not including proton excitation and de-excitation in level populations calculation. [fiasco.ions]
[289]:
full_line_list[full_line_list['ion name']=='O VIII']
[289]:
QTable length=6
atomic numberionization stagetransitiontransition (latex)ion namelower levelupper levelmax temperature_flare_extwavelengthonly theoretical_flare_extelemention idenergyabundance (coronal)abundance (photospheric)intensity (coronal)_flare_extintensity_scaled (coronal)_flare_extintensity (photospheric)_flare_extintensity_scaled (photospheric)_flare_extmax temperature_active_regiononly theoretical_active_regionintensity (coronal)_active_regionintensity_scaled (coronal)_active_regionintensity (photospheric)_active_regionintensity_scaled (photospheric)_active_regionis low FIPintensity_moxsi (coronal)_active_regionintensity_moxsi_scaled (coronal)_active_regionintensity_moxsi (coronal)_flare_extintensity_moxsi_scaled (coronal)_flare_ext
MKAngstromkeVph / (cm2 s sr)ph / (cm2 s sr)MKph / (cm2 s sr)ph / (cm2 s sr)ph / (pix s)ph / (pix s)
int16int16str48str93str9int16int16float32float64boolstr2str5float64float64float64float64float64float64float64float32boolfloat64float64float64float64boolfloat64float64float64float64
881s 2S1/2 - 2p 2P1/21s $^2$S$_{1/2}$ - 2p $^2$P$_{1/2}$O VIII1311.22018909454345718.97249984741211FalseOo_80.6534942650170160.00077624711662869280.0004897788193684457772339483192452.50.20605731780412825487313269352313.50.499834605411864532.8183817863464355False683780940424.3230.30720894659391895431436606376.2990.4354490057492695False0.000140969958810620460.142415128547826230.15922740558678350.05739941517857621
881s 2S1/2 - 2p 2P3/21s $^2$S$_{1/2}$ - 2p $^2$P$_{3/2}$O VIII1411.22018909454345718.967100143432617FalseOo_80.65368030692941710.00077624711662869280.00048977881936844571545190098544784.80.4122510037782132974949041294903.11.02.8183817863464355False1367396974302.1840.6143438040118606862769163755.9550.8707929948368375False0.000282282671147858770.28517652439944790.318985924823358970.11499028994150647
881s 2S1/2 - 3p 2P1/21s $^2$S$_{1/2}$ - 3p $^2$P$_{1/2}$O VIII1611.22018909454345716.00670051574707FalseOo_80.77457686117902370.00077624711662869280.0004897788193684457113454244281620.10.03026917279113078371584788691937.980.073424133631498163.1622776985168457False78278500171.292910.03516894689058136549390394597.971210.04984972972481674False2.880854027016425e-050.0291038743322777630.041754136296121120.015051824752477452
881s 2S1/2 - 3p 2P3/21s $^2$S$_{1/2}$ - 3p $^2$P$_{3/2}$O VIII1711.22018909454345716.00550079345703FalseOo_80.77463492103842420.00077624711662869280.0004897788193684457227110775978951.750.060592315116662104143297212114515.10.146979181521314483.1622776985168457False156698404883.33190.0704014239813160998870009429.469010.09978950943938328False5.7680372436712774e-050.0582716894050909760.08359902675850540.030136365205178293
881s 2S1/2 - 4p 2P1/21s $^2$S$_{1/2}$ - 4p $^2$P$_{1/2}$O VIII11111.22018909454345715.17650032043457FalseOo_80.81694854423229790.00077624711662869280.000489778819368445737664510565143.8360.01004875212565674623764699567329.2770.024375324822890843.1622776985168457False23792132596.0868450.01068932396321394315011820802.3475670.01515143209050504False1.0242225696430012e-050.0103472250504980430.0162141168470633120.005844978891848404
881s 2S1/2 - 4p 2P3/21s $^2$S$_{1/2}$ - 4p $^2$P$_{3/2}$O VIII11211.22018909454345715.175999641418457FalseOo_80.81697549659148370.00077624711662869280.000489778819368445775380739473064.50.0201113025138985147562031202877.940.048784120183047953.1622776985168457False47607003729.869920.02138886389151227530037988652.0573040.030317344657207427False2.0496133877963747e-050.020706252350438750.0324534964818727550.011699064691123105
[303]:
fig = plt.figure()
ax = fig.add_subplot()
ax2 = ax.twinx()
ax.plot(oxygen.temperature, find_goft(o7_goft, oxygen[6], 21.601499557495117*u.AA), color='C0', ls='-', label=oxygen[6].ion_name_roman)
ax2.plot(oxygen.temperature, oxygen[6].ioneq, color='C0', ls='--')
ax.plot(oxygen.temperature, find_goft(o8_goft, oxygen[7], 18.967100143432617*u.AA), color='C1', ls='-', label=oxygen[7].ion_name_roman)
ax2.plot(oxygen.temperature, oxygen[7].ioneq, color='C1', ls='--')
ax.set_xscale('log')
ax.legend()
21.602 Angstrom
18.9671 Angstrom
[303]:
<matplotlib.legend.Legend at 0x2e6b88550>
../_images/reports_temperature-wave-space_22_2.png
[309]:
np.unique(full_line_list['ion name']).shape
[309]:
(83,)
[312]:
len(fiasco.list_ions(fiasco.defaults['hdf5_dbase_root']))
[312]:
495
[ ]: