What is the relationship between peak counts in STIX flares and GOES class?
c.f. Lastufka et al 2020b
GOES class is the Richter scale for solar flares; it is determined from the peak flux in the GOES 1-8 Å (long wavelength) channel during a X-ray flare event.
GOES is in geostationary orbit and therefore has a constant, full-disk view of only the earth-facing side of the Sun. Solar Orbiter orbits the Sun, meaning X-ray flares observed by STIX will not always be observed with GOES.
GOES X-ray Sensor (XRS)
Solar Orbiter STIX
def stix_hek_data(start_time=None,end_time=None,lighttime_correct=True,local_copy=False):
'''Get STIX flare list for given time period. Search HEK/AIA database for flares occuring within +- 5 minutes from specified time. Perform coordinate transformation.
To be implemented: Reverse joint visibility calculation (is STIX flare visible from Earth) once CFL locations are returned by stixdcpy'''
if not start_time:
start_time=dt(2020,2,10,5,0,0)
if not end_time:
end_time=dt.now()
load_SOLO_SPICE(dt.now()) #SPICE kernels for Solar Orbiter trajectory
stix_flare_list=get_stix_flares(start_time,end_time,sortedby='time',lighttime_correct=True)
stix_flare_list['peak_utc']=pd.to_datetime(stix_flare_list.peak_UTC)
#stix_flare_list['peak_utc']=[d.replace(microsecond=0) for d in stix_flare_list.peak_utc]
nflares=stix_flare_list.peak_utc.count()
log.info(f"{nflares} STIX flares found")
if nflares == 1000:
log.warning(f"{nflares} STIX flares found, there might be more results in the specified date range!")
#is there a HEK event at same time?
hek_events=[hek.HEKEventHandler(f.peak_utc_corrected).df for _,f in stix_flare_list.iterrows()]
log.info(f"{len(hek_events)} HEK results found")
hdf=pd.concat(hek_events)
hdf['event_peaktime']=pd.to_datetime(hdf.event_peaktime)
#merge STIX results with HEK results
df=stix_flare_list.merge(hdf,left_on='peak_utc_corrected',right_on='date_obs',how='outer')
return df
def get_stix_flares(start_time,end_time,sortedby='time',lighttime_correct=True,local_copy=True):
'''Query STIX data center for flare list. Perform light travel time correction.'''
flares=jreq.fetch_flare_list(start_time,end_time,sortedby=sortedby) #current limit is 1000, results are returned backwards from end time
df=pd.DataFrame(flares)
corrected_times,solo_r=[],[]
if lighttime_correct:
for d in df.peak_UTC:
ctime,solor=spacecraft_to_earth_time(d,solo_r=True)
corrected_times.append(ctime)
solo_r.append(solor)
df['peak_utc_corrected']=corrected_times
df['solo_r']=solo_r
df['peak_counts_corrected']=df.peak_counts*(df.solo_r)**2 #correct to counts @ 1AU
if local_copy:
df.to_json(f"/home/erica/STIX/data/stix_flares_{dt.strftime(dt.now(),'%Y-%m-%dT%H:%M')}.json")
return df
HEKEventHandler gets and formats results from AIA flare catalog. It also gets the Solar Orbiter trajectory information and uses this to transform the AIA coordinates to the Solar Orbiter coordinate system via _rotatecoord
rotate_coord takes a coordinate or list of coordinates and rotates it, providing output in units relevant to different applications
def update_stix_hek_data(current_data_file='/home/erica/STIX/data/stix_hek_full.json'):
'''update the csv file with the latest flares from STIX and AIA'''
df=pd.read_json(current_data_file)
df['peak_utc']=pd.to_datetime(df.peak_utc,unit='ms')
last_date=df.peak_utc.iloc[0] #newest events are added at the beginning
newdf=stix_hek_data(start_time=last_date)
udf=pd.concat([newdf,df])
udf.drop_duplicates(subset=[k for k in udf.keys() if k !='goes'],inplace=True)
udf.reset_index(inplace=True,drop=True)
udf.to_json(current_data_file)
df.describe()
flare_id | total_signal_counts | total_counts | duration | LC0_BKG | _id | GOES_flux | CFL_X_arcsec | CFL_Y_arcsec | peak_counts | ... | rotated_y_arcsec | rotated_lon_deg | rotated_lat_deg | rotated_x_px | rotated_y_px | visible_from_SOLO | start_unix | end_unix | STIX_AIA_timedelta | STIX_AIA_timedelta_abs | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | 3.423000e+03 | 3.423000e+03 | 4.720000e+02 | 3423.000000 | 472.000000 | 3423.000000 | 4.720000e+02 | 0.0 | 0.0 | 3423.000000 | ... | 1988.000000 | 1988.000000 | 1988.000000 | 1988.000000 | 1988.000000 | 2023.000000 | 2.951000e+03 | 2.951000e+03 | 2023 | 2023 |
mean | 2.125082e+09 | 4.735241e+05 | 5.950362e+05 | 857.280748 | 279.135593 | 2305.458662 | 1.362252e-06 | NaN | NaN | 3845.376629 | ... | -93.811257 | 14.986685 | -6.209649 | 2273.108068 | 1953.687093 | 0.867523 | 1.632102e+09 | 1.632102e+09 | 0 days 00:05:20.429510133 | 0 days 00:20:13.049021749 |
std | 3.496230e+07 | 5.462422e+06 | 3.765789e+06 | 1062.892194 | 53.964668 | 991.701731 | 2.980354e-06 | NaN | NaN | 27491.654699 | ... | 462.247365 | 58.579077 | 34.129521 | 772.867709 | 462.252368 | 0.339092 | 6.282455e+06 | 6.282389e+06 | 0 days 01:15:44.329653006 | 0 days 01:13:11.063900368 |
min | 2.104240e+09 | 6.400000e+01 | 7.929000e+03 | 80.000000 | 247.000000 | 589.000000 | 0.000000e+00 | NaN | NaN | 262.466667 | ... | -1093.814195 | -87.407210 | -89.177735 | 836.053013 | 953.675551 | 0.000000 | 1.619226e+09 | 1.619228e+09 | -1 days +08:11:16.071000 | 0 days 00:00:00.286000 |
25% | 2.108201e+09 | 4.384000e+03 | 3.555250e+04 | 348.000000 | 247.000000 | 1444.500000 | 5.519000e-07 | NaN | NaN | 337.133333 | ... | -495.312198 | -40.325495 | -37.766042 | 1570.362438 | 1552.186403 | 1.000000 | 1.627829e+09 | 1.627829e+09 | 0 days 00:00:50.007500 | 0 days 00:02:38.810500 |
50% | 2.110041e+09 | 1.126400e+04 | 6.639950e+04 | 584.000000 | 271.000000 | 2307.000000 | 8.603500e-07 | NaN | NaN | 441.666667 | ... | -293.295623 | 22.147903 | -25.045989 | 2354.270866 | 1754.201461 | 1.000000 | 1.632336e+09 | 1.632337e+09 | 0 days 00:04:18.543000 | 0 days 00:05:43.435000 |
75% | 2.112212e+09 | 4.230800e+04 | 1.402060e+05 | 1030.000000 | 271.000000 | 3162.500000 | 1.220925e-06 | NaN | NaN | 892.866667 | ... | 344.011934 | 73.784082 | 28.810110 | 2930.122439 | 2391.515049 | 1.000000 | 1.636705e+09 | 1.636708e+09 | 0 days 00:07:07.060500 | 0 days 00:08:18.781000 |
max | 2.202022e+09 | 2.089835e+08 | 5.447654e+07 | 35680.000000 | 463.000000 | 4028.000000 | 5.508880e-05 | NaN | NaN | 753663.000000 | ... | 822.923871 | 89.111706 | 54.493623 | 3613.201130 | 2870.438193 | 1.000000 | 1.642118e+09 | 1.642119e+09 | 0 days 14:13:33.318000 | 0 days 15:48:43.929000 |
8 rows × 36 columns
tplus=td(minutes=10)
dfs=df.query("visible_from_SOLO==True and STIX_AIA_timedelta_abs < @tplus").dropna(how='all')
#dfs=df.query("visible_from_SOLO==True and STIX_AIA_timedelta_abs < @tplus and r_less_than_50_arcsec").dropna(how='all')
dfgc=dfs.where(dfs.fl_goescls !='').dropna(how='all')
dfgc['GOES_flux']=[goes_class_to_flux(c) for c in dfgc.fl_goescls]
fit=STIX_GOES_fit(dfgc)
fit.do_fit(dfgc)
fit.bin_residuals(dfgc) #gives statistics-based boundaries on predictions - very important!
fit.__dict__
{'start_date': Timestamp('2021-04-24 14:54:07.893000'), 'end_date': Timestamp('2022-02-02 16:35:08.374000'), 'nflares': 1165, 'timestamp': datetime.datetime(2022, 2, 4, 10, 28, 36, 299416), 'min_counts': 275.8, 'bins': [2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0], 'slope': 0.6474373955427877, 'intercept': -8.017059728369057, 'rvalue': 0.8404334190665731, 'pvalue': 1.0143336224873e-311, 'bin_2.0_sigma': 0.24294403493347283, 'bin_2.5_sigma': 0.28223799401465166, 'bin_3.0_sigma': 0.17811255923183106, 'bin_3.5_sigma': 0.2518162616056952, 'bin_4.0_sigma': 0.14362285052090484, 'bin_4.5_sigma': 0.2454768948923288, 'bin_5.0_sigma': 0.4029749010665078}
Observed GOES class - GOES class calculated using linear relationship
log10 (counts) | 1 $\sigma$ | N flares |
---|---|---|
< 3 | 0.272 | 830 |
[3,4) | 0.205 | 264 |
> 4 | 0.222 | 71 |