@@ -28,16 +28,15 @@ class RhessiLoader(instruments.InstrumentBlueprint):
28
28
[1] https://heasarc.gsfc.nasa.gov/xanadu/xspec/manual/XSappendixStatistics.html
29
29
"""
30
30
31
- def __init__ (self , spectrum_fn , srm_fn , ** kwargs ):
31
+ def __init__ (self , spectrum_fn , srm_fn ):
32
32
"""
33
33
Spectrum and SRM files are both required: attenuator state change times
34
34
are in the spectrum file,
35
35
and the state determines which SRM will be used.
36
36
"""
37
- self ._construction_string = f"RhessiLoader(spectrum_fn={ spectrum_fn } , " f"srm_fn={ srm_fn } ," f"** { kwargs } )"
37
+ self ._construction_string = f"RhessiLoader(spectrum_fn={ spectrum_fn } , " f"srm_fn={ srm_fn } )"
38
38
self ._systematic_error = 0
39
39
self .load_prepare_spectrum_srm (spectrum_fn , srm_fn )
40
- self ._start_background_time , self ._end_background_time = None , None
41
40
42
41
@property
43
42
def systematic_error (self ):
@@ -96,9 +95,11 @@ def load_prepare_spectrum_srm(self, spectrum_fn, srm_fn):
96
95
}
97
96
self ._update_event_data_with_times ()
98
97
self ._original_data = copy .deepcopy (self ._loaded_spec_data )
98
+ # Set these times to sensible defaults
99
+ self .update_background_times (self ._start_event_time , self ._end_event_time )
99
100
100
101
@property
101
- def subtract_background (self ):
102
+ def subtract_background (self ) -> bool :
102
103
"""
103
104
States whether the the data is event minus background or not.
104
105
"""
@@ -411,10 +412,7 @@ def _rebin_ts(self, times, clump_bins):
411
412
def lightcurve (self , energy_ranges = None , axes = None , rebin_time = 1 ):
412
413
"""Creates a RHESSI lightcurve.
413
414
414
- Helps the user see the RHESSI time profile. The defined event time (defined either through `start_event_time`,
415
- `end_event_time` setters, or `select_time(...)` method) is shown with a purple shaded region and if a background
416
- time (defined either through `start_background_time`, `end_background_time` setters, or
417
- `select_time(...,background=True)` method) is defined then it is shown with an orange shaded region.
415
+ The background and event times are highlighted based on what the user has set.
418
416
419
417
Parameters
420
418
----------
@@ -445,10 +443,9 @@ def lightcurve(self, energy_ranges=None, axes=None, rebin_time=1):
445
443
elif len (np .shape (energy_ranges )) == 1 :
446
444
energy_ranges = [energy_ranges ]
447
445
elif len (np .shape (energy_ranges )) == 0 :
448
- print (
446
+ raise ValueError (
449
447
"The `energy_ranges` input should be a range of two energy values (e.g., [4,8] meaning 4-8 keV inclusive) or a list of these ranges."
450
448
)
451
- return
452
449
453
450
ax = axes or plt .gca ()
454
451
font_size = plt .rcParams ["font.size" ]
@@ -462,11 +459,11 @@ def lightcurve(self, energy_ranges=None, axes=None, rebin_time=1):
462
459
463
460
# plot each energy range
464
461
time_binning = (flat_times [1 :] - flat_times [:- 1 ]).to_value ("s" )
462
+ left_edges , right_edges = self ._loaded_spec_data ["count_channel_bins" ].T
465
463
for er in energy_ranges :
466
- i = np .where (
467
- (self ._loaded_spec_data ["count_channel_bins" ][:, 0 ] >= er [0 ])
468
- & (self ._loaded_spec_data ["count_channel_bins" ][:, - 1 ] <= er [- 1 ])
469
- )
464
+ # Restrict the energy range to the data energy bins
465
+ ea , eb = max (er [0 ], left_edges [0 ]), min (er [1 ], right_edges [- 1 ])
466
+ i = np .where ((left_edges >= ea ) & (right_edges <= eb ))
470
467
e_range_cts = np .sum (self ._spectrum ["counts" ][:, i ].reshape ((len (time_binning ), - 1 )), axis = 1 )
471
468
472
469
if rebin_time > 1 :
@@ -475,7 +472,7 @@ def lightcurve(self, energy_ranges=None, axes=None, rebin_time=1):
475
472
476
473
e_range_ctr , e_range_ctr_err = e_range_cts / time_binning , np .sqrt (e_range_cts ) / time_binning
477
474
lc = e_range_ctr
478
- p = ax .stairs (lc , flat_times .datetime , label = f"{ er [ 0 ] } $-${ er [ - 1 ] } keV" )
475
+ p = ax .stairs (lc , flat_times .datetime , label = f"{ ea } $-${ eb } keV" )
479
476
ax .errorbar (
480
477
x = time_mids .datetime , y = e_range_ctr , yerr = e_range_ctr_err , c = p .get_edgecolor (), ls = ""
481
478
) # error bar in middle of the bin
@@ -515,10 +512,7 @@ def lightcurve(self, energy_ranges=None, axes=None, rebin_time=1):
515
512
def spectrogram (self , axes = None , rebin_time = 1 , rebin_energy = 1 , ** kwargs ):
516
513
"""Creates a RHESSI spectrogram.
517
514
518
- Helps the user see the RHESSI time and energy evolution. The defined event time (defined either through
519
- `start_event_time`, `end_event_time` setters, or `select_time(...)` method) is shown with a violet line
520
- and if a background time (defined either through `start_background_time`, `end_background_time` setters,
521
- or `select_time(...,background=True)` method) is defined then it is shown with an orange line.
515
+ The background and event times are highlighted based on what the user has set.
522
516
523
517
Parameters
524
518
----------
@@ -604,32 +598,65 @@ def spectrogram(self, axes=None, rebin_time=1, rebin_energy=1, **kwargs):
604
598
605
599
return ax
606
600
607
- def select_time (self , start = None , end = None , background = False ):
608
- """Provides method to set start and end time of the event or background in one line.
601
+ # "retroactive" properties for setting the times like in older versions,
602
+ # for legacy compatibility.
603
+ @property
604
+ def start_event_time (self ):
605
+ time_depr_warn ('event' )
606
+ return self ._start_event_time
609
607
610
- Parameters
611
- ----------
612
- start, end : str, `astropy.Time`, None
613
- String to be given to astropy's Time, `astropy.Time` is used directly, None sets the
614
- start/end event time to be the first time of the data. None doesn't add, or will remove,
615
- any background data in `_loaded_spec_data["extras"]` if background is set to True.
616
- Default: None
608
+ @start_event_time .setter
609
+ def start_event_time (self , new_time : atime .Time ):
610
+ time_depr_warn ('event' )
611
+ self .update_event_times (new_time , self ._end_event_time )
617
612
618
- background : bool
619
- Determines whether the start and end times are for the event (False) or background
620
- time (True).
621
- Default: False
613
+ @ property
614
+ def end_event_time ( self ):
615
+ time_depr_warn ( 'event' )
616
+ return self . _end_event_time
622
617
623
- Returns
624
- -------
625
- None.
626
- """
627
- self .__warn = False if (start is not None ) and (end is not None ) else True
618
+ @end_event_time .setter
619
+ def end_event_time (self , new_time : atime .Time ):
620
+ time_depr_warn ('event' )
621
+ self .update_event_times (self ._start_event_time , new_time )
628
622
629
- if background :
630
- self .start_background_time , self .end_background_time = start , end
631
- else :
632
- self .start_event_time , self .end_event_time = start , end
623
+ @property
624
+ def start_background_time (self ):
625
+ time_depr_warn ('background' )
626
+ return self ._start_background_time
627
+
628
+ @start_background_time .setter
629
+ def start_background_time (self , new_time : atime .Time ):
630
+ time_depr_warn ('background' )
631
+ self .update_background_times (new_time , self ._end_background_time )
632
+
633
+ @property
634
+ def end_background_time (self ):
635
+ time_depr_warn ('background' )
636
+ return self ._end_background_time
637
+
638
+ @end_background_time .setter
639
+ def end_background_time (self , new_time : atime .Time ):
640
+ time_depr_warn ('background' )
641
+ self .update_background_times (self ._start_background_time , new_time )
642
+
643
+ # "retroactive" properties for specifying background subtraction,
644
+ # like in older versions.
645
+ @property
646
+ def data2data_minus_background (self ) -> bool :
647
+ warnings .warn (
648
+ "Please use the `subtract_background` property instead." ,
649
+ stacklevel = 2
650
+ )
651
+ return self .subtract_background
652
+
653
+ @data2data_minus_background .setter
654
+ def data2data_minus_background (self , do_subtract : bool ):
655
+ warnings .warn (
656
+ "Please use the `subtract_background` property instead." ,
657
+ stacklevel = 2
658
+ )
659
+ self .subtract_background = do_subtract
633
660
634
661
635
662
def load_spectrum (spec_fn : str ):
@@ -801,3 +828,18 @@ def load_srm(srm_file: str):
801
828
}
802
829
803
830
return dict (channel_bins = channel_bins , photon_bins = photon_bins , srm_options = ret_srms )
831
+
832
+
833
+ class LegacyRhessiLoader (RhessiLoader ):
834
+ '''Allow legacy `Fitter` to load in RHESSI data with the expected args format'''
835
+ def __init__ (self , spec_fn , ** kw ):
836
+ srm_fn = kw .pop ('srm_file' )
837
+ super ().__init__ (spec_fn , srm_fn )
838
+
839
+
840
+ def time_depr_warn (partial_name : str ):
841
+ warnings .warn (
842
+ "This time-related property is deprecated. "
843
+ f"In the future, please use `RhessiLoader.update_{ partial_name } _times`" ,
844
+ stacklevel = 2
845
+ )
0 commit comments