Commit 74c93801ddd5758252381446308f64eb9040df15

Authored by Josh Cardenzana
1 parent 8c7309c7

(#2938) Adjust column name formatting in csspec fits files

This ensures the SED fits files are consistent with the current suggested data format
cscripts/csspec.py
... ... @@ -645,6 +645,7 @@ class csspec(ctools.csobservation):
645 645 emin = self._ebounds.emin(i)
646 646 emax = self._ebounds.emax(i)
647 647 elogmean = self._ebounds.elogmean(i)
  648 + e_scale = elogmean.MeV() * elogmean.MeV() * gammalib.MeV2erg
648 649  
649 650 # Select observations for energy bin
650 651 obs = self._select_obs(emin, emax)
... ... @@ -654,6 +655,7 @@ class csspec(ctools.csobservation):
654 655 'energy_low': (elogmean - emin).TeV(),
655 656 'energy_high': (emax - elogmean).TeV(),
656 657 'flux': 0.0,
  658 + 'e2dnde': 0.0,
657 659 'flux_err': 0.0,
658 660 'TS': 0.0,
659 661 'ulimit': 0.0,
... ... @@ -736,8 +738,7 @@ class csspec(ctools.csobservation):
736 738  
737 739 # Compute upper limit
738 740 if ulimit_value > 0.0:
739   - result['ulimit'] = ulimit_value * elogmean.MeV() * \
740   - elogmean.MeV() * gammalib.MeV2erg
  741 + result['ulimit'] = ulimit_value
741 742  
742 743 # Compute differential flux and flux error
743 744 fitted_flux = source.spectral().eval(elogmean)
... ... @@ -758,14 +759,14 @@ class csspec(ctools.csobservation):
758 759 e_flux *= norm
759 760  
760 761 # Convert differential flux and flux error to nuFnu
761   - elogmean2 = elogmean.MeV() * elogmean.MeV()
762   - result['flux'] = fitted_flux * elogmean2 * gammalib.MeV2erg
763   - result['flux_err'] = e_flux * elogmean2 * gammalib.MeV2erg
  762 + result['flux'] = fitted_flux
  763 + result['e2dnde'] = fitted_flux * e_scale
  764 + result['flux_err'] = e_flux
764 765  
765 766 # Log information
766   - value = '%e +/- %e' % (result['flux'], result['flux_err'])
  767 + value = '%e +/- %e' % (result['e2dnde'], result['flux_err']*e_scale)
767 768 if self['calc_ulim'].boolean() and result['ulimit'] > 0.0:
768   - value += ' [< %e]' % (result['ulimit'])
  769 + value += ' [< %e]' % (result['ulimit']*e_scale)
769 770 value += ' erg/cm2/s'
770 771 if self['calc_ts'].boolean() and result['TS'] > 0.0:
771 772 value += ' (TS = %.3f)' % (result['TS'])
... ... @@ -866,6 +867,7 @@ class csspec(ctools.csobservation):
866 867 'energy_low': (elogmean - emin).TeV(),
867 868 'energy_high': (emax - elogmean).TeV(),
868 869 'flux': 0.0,
  870 + 'e2dnde': 0.0,
869 871 'flux_err': 0.0,
870 872 'TS': 0.0,
871 873 'ulimit': 0.0,
... ... @@ -876,8 +878,9 @@ class csspec(ctools.csobservation):
876 878  
877 879 # Convert differential flux and flux error to nuFnu
878 880 norm = elogmean.MeV() * elogmean.MeV() * gammalib.MeV2erg
879   - result['flux'] = spectrum[i*2+1].value() * norm
880   - result['flux_err'] = spectrum[i*2+1].error() * norm
  881 + result['flux'] = spectrum[i*2+1].value()
  882 + result['e2dnde'] = spectrum[i*2+1].value() * norm
  883 + result['flux_err'] = spectrum[i*2+1].error()
881 884  
882 885 # Compute upper flux limit
883 886 ulimit_value = -1.0
... ... @@ -925,8 +928,7 @@ class csspec(ctools.csobservation):
925 928  
926 929 # Compute upper limit
927 930 if ulimit_value > 0.0:
928   - result['ulimit'] = ulimit_value * elogmean.MeV() * \
929   - elogmean.MeV() * gammalib.MeV2erg
  931 + result['ulimit'] = ulimit_value
930 932  
931 933 # Compute TS
932 934 if self['calc_ts'].boolean():
... ... @@ -954,9 +956,9 @@ class csspec(ctools.csobservation):
954 956 result['TS'] = 2.0 * (logL1 - logL0)
955 957  
956 958 # Log information
957   - value = '%e +/- %e' % (result['flux'], result['flux_err'])
  959 + value = '%e +/- %e' % (result['e2dnde'], result['flux_err']*norm)
958 960 if self['calc_ulim'].boolean() and result['ulimit'] > 0.0:
959   - value += ' [< %e]' % (result['ulimit'])
  961 + value += ' [< %e]' % (result['ulimit']*norm)
960 962 value += ' erg/cm2/s'
961 963 if self['calc_ts'].boolean() and result['TS'] > 0.0:
962 964 value += ' (TS = %.3f)' % (result['TS'])
... ... @@ -994,7 +996,6 @@ class csspec(ctools.csobservation):
994 996 dll_sigmax = self['dll_sigmax'].real()
995 997 dll_sigstep = self['dll_sigstep'].real()
996 998 sigsteps = int(2 * (dll_sigmax/dll_sigstep) + 1)
997   - scale = elogmean.MeV() * elogmean.MeV() * gammalib.MeV2erg
998 999  
999 1000 # Setup the source model for fitting
1000 1001 source = like.obs().models()[self['srcname'].string()]
... ... @@ -1016,6 +1017,9 @@ class csspec(ctools.csobservation):
1016 1017 # Store the resulting log-likelihood
1017 1018 norm_scan = []
1018 1019 dloglike = []
  1020 + ref_norm = norm
  1021 + if self._method == 'SLICE':
  1022 + ref_norm = spectral.eval(elogmean)
1019 1023  
1020 1024 # Compute the flux values to evaluate loglike at
1021 1025 log_norm = math.log10(norm)
... ... @@ -1042,9 +1046,9 @@ class csspec(ctools.csobservation):
1042 1046 # Store dlikelihood & norm
1043 1047 dloglike.append(loglike - like.obs().logL())
1044 1048 if self._method == 'SLICE':
1045   - norm_scan.append(spectral.eval(elogmean) * scale)
  1049 + norm_scan.append(spectral.eval(elogmean))
1046 1050 else:
1047   - norm_scan.append(new_norm * scale)
  1051 + norm_scan.append(new_norm)
1048 1052  
1049 1053 return (norm_scan, dloglike, -loglike)
1050 1054  
... ... @@ -1063,22 +1067,27 @@ class csspec(ctools.csobservation):
1063 1067 energy = gammalib.GFitsTableDoubleCol('e_ref', nrows)
1064 1068 energy_low = gammalib.GFitsTableDoubleCol('e_min', nrows)
1065 1069 energy_high = gammalib.GFitsTableDoubleCol('e_max', nrows)
1066   - flux = gammalib.GFitsTableDoubleCol('e2dnde', nrows)
1067   - flux_err = gammalib.GFitsTableDoubleCol('e2dnde_err', nrows)
  1070 + norm = gammalib.GFitsTableDoubleCol('norm', nrows)
  1071 + norm_err = gammalib.GFitsTableDoubleCol('norm_err', nrows)
  1072 + ulim_values = gammalib.GFitsTableDoubleCol('norm_ul', nrows)
  1073 + e2dnde = gammalib.GFitsTableDoubleCol('ref_e2dnde', nrows)
  1074 + flux = gammalib.GFitsTableDoubleCol('ref_flux', nrows)
  1075 + Npred_values = gammalib.GFitsTableDoubleCol('ref_npred', nrows)
1068 1076 TSvalues = gammalib.GFitsTableDoubleCol('ts', nrows)
1069   - ulim_values = gammalib.GFitsTableDoubleCol('e2dnde_ul', nrows)
1070   - Npred_values = gammalib.GFitsTableDoubleCol('npred', nrows)
1071 1077 loglike = gammalib.GFitsTableDoubleCol('loglike', nrows)
1072 1078 norm_scan = gammalib.GFitsTableDoubleCol('norm_scan', nrows, ncols)
1073 1079 dloglike_scan= gammalib.GFitsTableDoubleCol('dloglike_scan', nrows, ncols)
1074 1080 energy.unit('TeV')
1075 1081 energy_low.unit('TeV')
1076 1082 energy_high.unit('TeV')
1077   - flux.unit('erg/cm2/s')
1078   - flux_err.unit('erg/cm2/s')
1079   - ulim_values.unit('erg/cm2/s')
  1083 + norm.unit('')
  1084 + norm_err.unit('')
  1085 + ulim_values.unit('')
  1086 + e2dnde.unit('erg/cm2/s')
  1087 + flux.unit('counts/MeV/cm2/s')
  1088 + Npred_values.unit('counts')
1080 1089 loglike.unit('')
1081   - norm_scan.unit('erg/cm2/s')
  1090 + norm_scan.unit('')
1082 1091 dloglike_scan.unit('')
1083 1092  
1084 1093 # File FITS table columns
... ... @@ -1086,17 +1095,19 @@ class csspec(ctools.csobservation):
1086 1095 energy[i] = result['energy']
1087 1096 energy_low[i] = result['energy_low']
1088 1097 energy_high[i] = result['energy_high']
  1098 + norm[i] = 1.0
  1099 + norm_err[i] = result['flux_err'] / result['flux']
  1100 + ulim_values[i] = result['ulimit'] / result['flux']
  1101 + e2dnde[i] = result['e2dnde']
1089 1102 flux[i] = result['flux']
1090   - flux_err[i] = result['flux_err']
1091   - TSvalues[i] = result['TS']
1092   - ulim_values[i] = result['ulimit']
1093 1103 Npred_values[i] = result['Npred']
  1104 + TSvalues[i] = result['TS']
1094 1105 loglike[i] = result['logL']
1095 1106  
1096 1107 # Add likelihood scan values
1097 1108 for fbin in range(ncols):
1098 1109 dloglike_scan[i,fbin] = result['dloglike'][fbin]
1099   - norm_scan[i,fbin] = result['norm_scan'][fbin]
  1110 + norm_scan[i,fbin] = result['norm_scan'][fbin] / result['flux']
1100 1111  
1101 1112 # Initialise FITS Table with extension "SPECTRUM"
1102 1113 table = gammalib.GFitsBinTable(nrows)
... ... @@ -1110,26 +1121,29 @@ class csspec(ctools.csobservation):
1110 1121 table.append(energy)
1111 1122 table.append(energy_low)
1112 1123 table.append(energy_high)
  1124 + table.append(norm)
  1125 + table.append(norm_err)
  1126 + table.append(ulim_values)
  1127 + table.append(e2dnde)
1113 1128 table.append(flux)
1114   - table.append(flux_err)
1115 1129 table.append(TSvalues)
1116   - table.append(ulim_values)
1117 1130 table.append(Npred_values)
1118   -
  1131 +
1119 1132 # Define the SED type
1120   - sed_type = 'e2dnde'
1121   - if ncols > 0:
1122   - sed_type = 'likelihood'
1123   - table.append(loglike)
1124   - table.append(norm_scan)
1125   - table.append(dloglike_scan)
1126   - table.card('SED_TYPE', sed_type, 'SED type')
  1133 + table.card('SED_TYPE', 'norm,e2dnde,flux,npred', 'SED type')
1127 1134  
1128 1135 # Define the upper limit confidence level
1129 1136 ulimit = ctools.ctulimit()
1130 1137 table.card('UL_CONF', ulimit['confidence'].real(),
1131 1138 'Confidence level of upper limits')
1132 1139  
  1140 + # Add the likelihood data
  1141 + if ncols > 0:
  1142 + table.card('SED_TYPE', 'likelihood,e2dnde,flux,npred', 'Likelihood scan data')
  1143 + table.append(loglike)
  1144 + table.append(norm_scan)
  1145 + table.append(dloglike_scan)
  1146 +
1133 1147 # Create the FITS file now
1134 1148 self._fits = gammalib.GFits()
1135 1149 self._fits.append(table)
... ...
examples/show_spectrum.py
... ... @@ -82,10 +82,11 @@ def get_spectrum_fits(fits):
82 82 c_energy = table['e_ref']
83 83 c_ed = table['e_min']
84 84 c_eu = table['e_max']
85   - c_flux = table['e2dnde']
86   - c_eflux = table['e2dnde_err']
  85 + c_flux = table['ref_e2dnde']
  86 + c_norm = table['norm']
  87 + c_eflux = table['norm_err']
  88 + c_upper = table['norm_ul']
87 89 c_ts = table['ts']
88   - c_upper = table['e2dnde_ul']
89 90  
90 91 # Initialise arrays to be filled
91 92 spec = {
... ... @@ -101,18 +102,22 @@ def get_spectrum_fits(fits):
101 102 'yerr' : [],
102 103 'loglike' : [],
103 104 'engs_scan' : [],
104   - 'norm_scan' : [],
  105 + 'e2dnde_scan' : [],
105 106 'dll_scan' : []
106 107 }
107 108  
108 109 # Determine if we can load the delta-log-likelihood profiles
  110 + has_sedtype = table.has_card('SED_TYPE')
109 111 load_dll = False
110   - if (fits.table(1).has_card('SED_TYPE') and
111   - fits.table(1).card('SED_TYPE').string() == 'likelihood'):
112   - c_loglike = table['loglike']
113   - c_norm_scan = table['norm_scan']
114   - c_dll_scan = table['dloglike_scan']
115   - load_dll = True
  112 + if has_sedtype:
  113 + seds = table.card('SED_TYPE').string().split(',')
  114 +
  115 + # Load likelhood columns if present
  116 + if seds[0] == 'likelihood':
  117 + load_dll = True
  118 + c_loglike = table['loglike']
  119 + c_norm_scan = table['norm_scan']
  120 + c_dll_scan = table['dloglike_scan']
116 121  
117 122 # Loop over rows of the file
118 123 nrows = table.nrows()
... ... @@ -120,36 +125,37 @@ def get_spectrum_fits(fits):
120 125  
121 126 # Get Test Statistic, flux and flux error
122 127 ts = c_ts.real(row)
123   - flx = c_flux.real(row)
124   - e_flx = c_eflux.real(row)
  128 + norm = c_norm.real(row)
  129 + flx = norm * c_flux.real(row)
  130 + e_flx = flx * c_eflux.real(row)
125 131  
126 132 # If Test Statistic is larger than 9 and flux error is smaller than
127 133 # flux then append flux plots ...
128 134 if ts > 9.0 and e_flx < flx:
129 135 spec['energies'].append(c_energy.real(row))
130   - spec['flux'].append(c_flux.real(row))
  136 + spec['flux'].append(flx)
131 137 spec['ed_engs'].append(c_ed.real(row))
132 138 spec['eu_engs'].append(c_eu.real(row))
133   - spec['e_flux'].append(c_eflux.real(row))
  139 + spec['e_flux'].append(e_flx)
134 140  
135 141 # ... otherwise append upper limit
136 142 else:
137 143 spec['ul_energies'].append(c_energy.real(row))
138   - spec['ul_flux'].append(c_upper.real(row))
  144 + spec['ul_flux'].append(flx*c_upper.real(row))
139 145 spec['ul_ed_engs'].append(c_ed.real(row))
140 146 spec['ul_eu_engs'].append(c_eu.real(row))
141 147  
142 148 # Load the delta log-likelihood values
143 149 if load_dll:
144   - spec['norm_scan'] = np.zeros((nrows, c_norm_scan.elements(0)))
145   - spec['dll_scan'] = np.zeros((nrows, c_norm_scan.elements(0)))
  150 + spec['e2dnde_scan'] = np.zeros((nrows, c_norm_scan.elements(0)))
  151 + spec['dll_scan'] = np.zeros((nrows, c_norm_scan.elements(0)))
146 152  
147 153 for row in range(nrows):
148 154 loglike = c_loglike.real(row)
149 155 spec['loglike'].append(loglike)
150 156 spec['engs_scan'].append(c_energy.real(row) - c_ed.real(row))
151 157 for col in range(c_norm_scan.elements(row)):
152   - spec['norm_scan'][row,col] = c_norm_scan.real(row,col)
  158 + spec['e2dnde_scan'][row,col] = c_norm_scan.real(row,col) * c_flux.real(row)
153 159 spec['dll_scan'][row,col] = c_dll_scan.real(row,col)
154 160 spec['engs_scan'].append(c_energy.real(nrows-1)+c_eu.real(nrows-1))
155 161  
... ... @@ -183,10 +189,10 @@ def plot_dloglike(spec):
183 189 y_bounds = 10 ** y_bounds
184 190  
185 191 dll_hist = []
186   - for ebin in range(len(spec['norm_scan'])):
  192 + for ebin in range(len(spec['e2dnde_scan'])):
187 193  
188 194 # Interpolate the dlogLike values
189   - dll_interp = np.interp(fluxpnts, spec['norm_scan'][ebin],
  195 + dll_interp = np.interp(fluxpnts, spec['e2dnde_scan'][ebin],
190 196 spec['dll_scan'][ebin])
191 197 dll_hist.append(dll_interp)
192 198  
... ...