TCDSolar/stixpy

`create_meta_pixels` should check the time bins edges (rather than just center) to return time mask

Closed this issue · 3 comments

Currently, in create_meta_pixels to find the data that is contained within the times and energies, only the center of the time bins are checked.

For example here:
https://github.com/TCDSolar/stixpy/blob/main/stixpy/calibration/visibility.py#L119

the time-range passed is only checked against the center time of the data bins. However, if the bins are large (e.g. 20s or something), then the time-range passed could be within the bin, however it isn't satisfied by the center value.

For example:
In this extreme example, this data only have one time bin, which is quite large (890s). Following the logic from L119 from the visibility.py, this isn't satisfied

>>> time_range = ["2023-04-01T07:32:17.850", "2023-04-01T07:35:37.850"]
>>> pixel_data = Product("https://pub099.cs.technik.fhnw.ch/data/fits/L1/2023/04/01/SCI/solo_L1_stix-sci-xray-cpd_20230401T073020-20230401T074511_V02_2304011277-50312.fits")

>>> t_mask = (pixel_data.times >= Time(time_range[0])) & (pixel_data.times <= Time(time_range[1]))
>>> t_mask
array([False])

however, its just because the center of the time bin is:

>>> pixel_data.times
<Time object: scale='utc' format='isot' value=['2023-04-01T07:37:45.999']>

however the passed time_range is within the bin of the data (here as its only one time point):

>>> pixel_data.time_range
   <sunpy.time.timerange.TimeRange object at 0x1180da180>
    Start: 2023-04-01 07:30:20
    End:   2023-04-01 07:45:11
    Center:2023-04-01 07:37:45
    Duration:0.010309027777777757 days or
           0.24741666666666617 hours or
           14.84499999999997 minutes or
           890.6999999999982 seconds

so it really should be checking that the passed time range is withing the edge of the bins, something like pixel.start_times and pixel.end_times? This could be inferred from the duration.

For context, this is what the IDL software does as far as I know.

like a simple solution would be something like:

pixel_starts = pixel_data.times - pixel_data.durtaion/2
pixel_ends = pixel_data.times + pixel_data.durtaion/2

t_mask = (pixel_starts >= Time(time_range[0])) & (pixel_ends <= Time(time_range[1]))

what do you think @samaloney ?

We also need to consider bins where the time range is inside the bin edges so I think the following three cases should work

t_mask_1 = (pixel_starts >= Time(time_range[0])) & (pixel_ends <= Time(time_range[1]))
t_mask_2 = (Time(time_range[0]) - pixel_starts < pixel_data.durtaion) & (Time(time_range[0]) - pixel_starts > 0 * u.s)
t_mask_3 = (pixel_ends - Time(time_range[1]) < pixel_data.durtaion) & (pixel_ends - Time(time_range[0]) > 0 * u.s) 
    
t_mask = np.logical_or(t_mask_1, t_mask_2, t_mask_3)

Yes I think this is similar to what we currently do in the client but for file start/end

stixpy/stixpy/net/client.py

Lines 107 to 115 in ba0ef1c

# 4 cases file time full in, fully our start in or end in
if file_tr.start >= tr.start and file_tr.end <= tr.end:
metalist.append(rowdict)
elif tr.start <= file_tr.start and tr.end >= file_tr.end:
metalist.append(rowdict)
elif file_tr.start <= tr.start <= file_tr.end:
metalist.append(rowdict)
elif file_tr.start <= tr.end <= file_tr.end:
metalist.append(rowdict)

I'm down to one hand for a while, broken finger, so things are a bit slow myside.