11"""
2- Author: O. Limousin, CEA
3- Date: Oct 23, 2024
4- This script to:
5-
6- #%%%%%%%%%%%%%% FOR fit of ECC_ULTRA_FINE %%%%%%%%%%%%%%
7- ../00_CALIBRATION_MONITORING_ULTRA_FINE/02_MONITOR_ECC_SPECTRA ==> XX_erg.fits
8-
9- ../00_CALIBRATION_MONITORING_ULTRA_FINE/01_MONITOR_ECC_PARA/ ==> ECC_para_XXXX.fits
10-
11- + read the log (.xlsx file)
12- + open the ECC calibrated spectra XX_erg.fits
13- + fit 31 and 81 keV lines (Fit_Ba_robust) (fit right hand side, and baseline)
14- + register the results in a Pandas Dataframe
15- + date, Run Number, Fit Goodness flags,DET, PIX,
16- P31, err_P31, dE31, err_dE31, H31
17- P81, err_P81, dE81, err_dE81, H81
18- + compute gain/offset corrections
19- + fill the dataframe with new values
20- + include errors
21- + include a Flag (Flag31 and Flag81) which is True if fit was OK
22- if was not OK, the ECC value in NOT corrected
23- + store the results in pkl
24- + generate update ECC_para files to recalibrate uncalibrated files
2+ Author: O. Limousin, CEA
3+ Date: Oct 23, 2024
4+ This script to:
5+
6+ #%%%%%%%%%%%%%% FOR fit of ECC_ULTRA_FINE %%%%%%%%%%%%%%
7+ ../00_CALIBRATION_MONITORING_ULTRA_FINE/02_MONITOR_ECC_SPECTRA ==> XX_erg.fits
8+
9+ ../00_CALIBRATION_MONITORING_ULTRA_FINE/01_MONITOR_ECC_PARA/ ==> ECC_para_XXXX.fits
10+
11+ + read the log (.xlsx file)
12+ + open the ECC calibrated spectra XX_erg.fits
13+ + fit 31 and 81 keV lines (Fit_Ba_robust) (fit right hand side, and baseline)
14+ + register the results in a Pandas Dataframe
15+ + date, Run Number, Fit Goodness flags,DET, PIX,
16+ P31, err_P31, dE31, err_dE31, H31
17+ P81, err_P81, dE81, err_dE81, H81
18+ + compute gain/offset corrections
19+ + fill the dataframe with new values
20+ + include errors
21+ + include a Flag (Flag31 and Flag81) which is True if fit was OK
22+ if was not OK, the ECC value in NOT corrected
23+ + store the results in pkl
24+ + generate update ECC_para files to recalibrate uncalibrated files
2525
2626"""
2727
@@ -49,43 +49,42 @@ def open_fits_tables(fits_path):
4949 data_names = [data_i .columns .names for data_i in data ]
5050 data_format = [data_i .columns .formats for data_i in data ]
5151 data_unit = [data_i .columns .units for data_i in data ]
52- data_list = [[list (data [i ][data_names [i ][j ]]) for j in range (len (data_names [i ]))] for i in
53- range (len (data ))]
52+ data_list = [[list (data [i ][data_names [i ][j ]]) for j in range (len (data_names [i ]))] for i in range (len (data ))]
5453 return header , data , data_list , data_names , data_format , data_unit
5554
5655
5756def Read_fits_STIX_One_Pixel (data , PIX = 0 , DETECTOR_ID = 1 , Nbin = 2024 , NRebin = 1 , NSigma = 1 ):
5857 data = data [0 ]
5958 Pix = PIX
60- Pix = Pix + (DETECTOR_ID - 1 ) * 12
59+ Pix = Pix + (DETECTOR_ID - 1 ) * 12
6160 obs = [0 ] * Nbin
6261 erg_c = data .ERG_center # data.field(0)
63- obs = data .field (3 + Pix )
62+ obs = data .field (3 + Pix )
6463 nbin = Nbin
65- Nbin = [Nbin / NRebin ]
64+ Nbin = [Nbin / NRebin ]
6665 # TODO: check if we really need to rebin with congrid here
6766 # erg_c = congrid(erg_c[:nbin], Nbin)
6867 # obs = congrid(obs[:nbin], Nbin)
6968 erg_c = erg_c [:nbin ]
7069 obs = obs [:nbin ]
7170
72- yerr = NSigma * np .sqrt (obs )
71+ yerr = NSigma * np .sqrt (obs )
7372 return erg_c , obs , yerr
7473
7574
7675def line (x , slope , intercept ):
7776 """a line"""
78- return ( slope * x + intercept )
77+ return slope * x + intercept
7978
8079
8180def poly (x , degree , slope , intercept ):
8281 """a line"""
83- return ( degree * x * x + slope * x + intercept )
82+ return degree * x * x + slope * x + intercept
8483
8584
8685def gaussian (x , amp , cen , wid ):
8786 # """1-d gaussian: gaussian(x, amp, cen, wid)"""
88- return ( amp * np .exp (- (x - cen )** 2 / (2 * wid ** 2 ) ))
87+ return amp * np .exp (- (( x - cen ) ** 2 ) / (2 * wid ** 2 ))
8988
9089
9190def Fit_Ba_Lines_Robust (erg_c , obs , PLOT_VERBOSE = 1 , LogScale = 1 ):
@@ -97,66 +96,68 @@ def Fit_Ba_Lines_Robust(erg_c, obs, PLOT_VERBOSE=1, LogScale=1):
9796 + flag to say if the fit was successful or not
9897 """
9998 # Select Energy range for 81 keV Ba-133 line
100- pipo = ((erg_c > 80.5 ) & (erg_c < 90. )).nonzero ()
101- y = ( obs [pipo ])
102- x = ( erg_c [pipo ])
103- x = np .array (x , dtype = ' float64' )
104- y = np .array (y , dtype = ' float64' )
99+ pipo = ((erg_c > 80.5 ) & (erg_c < 90.0 )).nonzero ()
100+ y = obs [pipo ]
101+ x = erg_c [pipo ]
102+ x = np .array (x , dtype = " float64" )
103+ y = np .array (y , dtype = " float64" )
105104 mod = Model (gaussian ) + Model (line )
106105 pars = mod .make_params (amp = 10 , cen = 81 , wid = 0.5 , slope = 0 , intercept = 0 )
107106 result = mod .fit (y , pars , x = x )
108107
109- if ((result .params ['wid' ].stderr is not None ) &
110- (result .params ['cen' ].stderr is not None ) &
111- (np .abs (result .best_values ['cen' ] - 81. ) < 1. )):
112- dE81 = result .best_values ['wid' ]* 2.35
113- err_dE81 = result .params ['wid' ].stderr * 2.35
114- P81 = result .best_values ['cen' ]
115- err_P81 = result .params ['cen' ].stderr
116- H81 = result .best_values ['amp' ]
108+ if (
109+ (result .params ["wid" ].stderr is not None )
110+ & (result .params ["cen" ].stderr is not None )
111+ & (np .abs (result .best_values ["cen" ] - 81.0 ) < 1.0 )
112+ ):
113+ dE81 = result .best_values ["wid" ] * 2.35
114+ err_dE81 = result .params ["wid" ].stderr * 2.35
115+ P81 = result .best_values ["cen" ]
116+ err_P81 = result .params ["cen" ].stderr
117+ H81 = result .best_values ["amp" ]
117118 Goodness_Flag_81 = True
118119 else :
119120 dE81 , err_dE81 , P81 , err_P81 , H81 = 0 , 0 , 0 , 0 , 0
120121 Goodness_Flag_81 = False
121122
122123 # Select Energy range for 81 keV Ba-133 line
123- # THE FOLLWING SECTION IS QUIET ROBUST BUT MIGHT OVERESTIMATE THE ENERGY RESOLUTION AT 32 keV
124- # THIS ALLOWS TO FORCE THE BASE LINE TO ADJSUT in 40-45 keV range while a simple Gaussian
124+ # THE FOLLOWING SECTION IS QUIET ROBUST BUT MIGHT OVERESTIMATE THE ENERGY RESOLUTION AT 32 keV
125+ # THIS ALLOWS TO FORCE THE BASE LINE TO ADJUST in 40-45 keV range while a simple Gaussian
125126 # is used to fit the right hand side of the 32 keV Line
126127 pipo = (((erg_c > 30.2 ) & (erg_c < 33.0 )) | ((erg_c > 40 ) & (erg_c < 45 ))).nonzero ()
127128 y = obs [pipo ]
128129 x = erg_c [pipo ]
129- x = np .array (x , dtype = ' float64' )
130- y = np .array (y , dtype = ' float64' )
130+ x = np .array (x , dtype = " float64" )
131+ y = np .array (y , dtype = " float64" )
131132
132- mod = Model (gaussian , prefix = ' g1_' ) + Model (poly )
133- pars = mod .make_params (g1_amp = 10 , g1_cen = 30.6 , g1_wid = 0.4 , degree = 0. , slope = 0 , intercept = 0. )
133+ mod = Model (gaussian , prefix = " g1_" ) + Model (poly )
134+ pars = mod .make_params (g1_amp = 10 , g1_cen = 30.6 , g1_wid = 0.4 , degree = 0.0 , slope = 0 , intercept = 0.0 )
134135
135136 result = mod .fit (y , pars , x = x )
136137
137- if ((result .params ['g1_wid' ].stderr is not None ) &
138- (result .params ['g1_cen' ].stderr is not None ) &
139- ((np .abs (result .best_values ['g1_cen' ] - 31. ) < 1. ) & (Goodness_Flag_81 ))):
140- dE31 = result .best_values ['g1_wid' ]* 2.35
141- err_dE31 = result .params ['g1_wid' ].stderr * 2.35
142- P31 = result .best_values ['g1_cen' ]
143- err_P31 = result .params ['g1_cen' ].stderr
144- H31 = result .best_values ['g1_amp' ]
138+ if (
139+ (result .params ["g1_wid" ].stderr is not None )
140+ & (result .params ["g1_cen" ].stderr is not None )
141+ & ((np .abs (result .best_values ["g1_cen" ] - 31.0 ) < 1.0 ) & (Goodness_Flag_81 ))
142+ ):
143+ dE31 = result .best_values ["g1_wid" ] * 2.35
144+ err_dE31 = result .params ["g1_wid" ].stderr * 2.35
145+ P31 = result .best_values ["g1_cen" ]
146+ err_P31 = result .params ["g1_cen" ].stderr
147+ H31 = result .best_values ["g1_amp" ]
145148 Goodness_Flag_31 = True
146149 else :
147150 dE31 , err_dE31 , P31 , err_P31 , H31 = 0 , 0 , 0 , 0 , 0
148151 Goodness_Flag_31 = False
149152
150- return P31 , P81 , dE31 , dE81 , err_P31 , err_P81 , err_dE31 , err_dE81 , \
151- H31 , H81 , Goodness_Flag_31 , Goodness_Flag_81
153+ return P31 , P81 , dE31 , dE81 , err_P31 , err_P81 , err_dE31 , err_dE81 , H31 , H81 , Goodness_Flag_31 , Goodness_Flag_81
152154
153155
154156def ecc_post_fit (erg_file , para_file , livetime ):
155-
156- DETs = np .arange (32 )+ 1
157+ DETs = np .arange (32 ) + 1
157158 LARGEs = [0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ]
158159 SMALLs = [8 , 9 , 10 , 11 ]
159- PIXELs = LARGEs + SMALLs
160+ PIXELs = LARGEs + SMALLs
160161
161162 # Prep Pandas DataFrame
162163 df = pd .DataFrame () # dict will be define later during concactenation with appropriated keys
@@ -166,63 +167,63 @@ def ecc_post_fit(erg_file, para_file, livetime):
166167 data = open_fits_tables (erg_file )[1 ] # only need data
167168 for DET in DETs :
168169 for PIX in PIXELs : # or in LARGEs, SMALLs
169- erg_c , obs , yerr = Read_fits_STIX_One_Pixel (data , PIX = PIX , DETECTOR_ID = DET ,
170- Nbin = 2024 , NRebin = 1 , NSigma = 1 )
171-
172- P31 , P81 , dE31 , dE81 , err_P31 , err_P81 , err_dE31 , err_dE81 , H31 , H81 , Goodness_Flag31 , \
173- Goodness_Flag81 = Fit_Ba_Lines_Robust (erg_c , obs / livetime ,
174- PLOT_VERBOSE = 0 , LogScale = 0 )
175-
176- dict = {'DET' : [DET ],
177- 'PIX' : [PIX ],
178- 'P31' : [P31 ],
179- 'err_P31' : [err_P31 ],
180- 'dE31' : [dE31 ],
181- 'err_dE31' : [err_dE31 ],
182- 'Flag31' : [Goodness_Flag31 ],
183- 'P81' : [P81 ],
184- 'err_P81' : [err_P81 ],
185- 'dE81' : [dE81 ],
186- 'err_dE81' : [err_dE81 ],
187- 'Flag81' : [Goodness_Flag81 ]}
170+ erg_c , obs , yerr = Read_fits_STIX_One_Pixel (data , PIX = PIX , DETECTOR_ID = DET , Nbin = 2024 , NRebin = 1 , NSigma = 1 )
171+
172+ P31 , P81 , dE31 , dE81 , err_P31 , err_P81 , err_dE31 , err_dE81 , H31 , H81 , Goodness_Flag31 , Goodness_Flag81 = (
173+ Fit_Ba_Lines_Robust (erg_c , obs / livetime , PLOT_VERBOSE = 0 , LogScale = 0 )
174+ )
175+
176+ dict = {
177+ "DET" : [DET ],
178+ "PIX" : [PIX ],
179+ "P31" : [P31 ],
180+ "err_P31" : [err_P31 ],
181+ "dE31" : [dE31 ],
182+ "err_dE31" : [err_dE31 ],
183+ "Flag31" : [Goodness_Flag31 ],
184+ "P81" : [P81 ],
185+ "err_P81" : [err_P81 ],
186+ "dE81" : [dE81 ],
187+ "err_dE81" : [err_dE81 ],
188+ "Flag81" : [Goodness_Flag81 ],
189+ }
188190 logger .debug (dict )
189191
190192 # NB: this is faster to append a list of dict and create DataFrame at the end
191- # than concatening the DataFrame row by row, this slows down dramatically progressively
193+ # than concatenating the DataFrame row by row, this slows down dramatically progressively
192194 accumulator .append (pd .DataFrame (dict ))
193195
194196 df = pd .concat (accumulator )
195197 df = df .reset_index (drop = True )
196198
197199 # 3- gain and offset correction factors of ECC pre-calibrated data
198- G_prime = (df [' P81' ] - df [' P31' ]) / (80.9979 - (30.6254 * 33.8 + 30.9731 * 62.4 )/ (62.4 + 33.8 ))
199- O_prime = df [' P31' ] - G_prime * (30.6254 * 33.8 + 30.9731 * 62.4 )/ (62.4 + 33.8 )
200+ G_prime = (df [" P81" ] - df [" P31" ]) / (80.9979 - (30.6254 * 33.8 + 30.9731 * 62.4 ) / (62.4 + 33.8 ))
201+ O_prime = df [" P31" ] - G_prime * (30.6254 * 33.8 + 30.9731 * 62.4 ) / (62.4 + 33.8 )
200202
201203 # 4- add correction factors to the DataFrame
202- df [' Gain_Prime' ] = G_prime
203- df [' Offset_Prime' ] = O_prime
204+ df [" Gain_Prime" ] = G_prime
205+ df [" Offset_Prime" ] = O_prime
204206
205207 # check, Run number and pixel number prior to assign Gain and Offset for further correction
206208 data_para = open_fits_tables (para_file )[1 ] # only need data
207209
208- df [' Gain_ECC' ] = np .float32 (data_para [0 ].gain )
209- df [' Offset_ECC' ] = np .float32 (data_para [0 ].off )
210- df [' goc' ] = np .float32 (data_para [0 ].goc )
210+ df [" Gain_ECC" ] = np .float32 (data_para [0 ].gain )
211+ df [" Offset_ECC" ] = np .float32 (data_para [0 ].off )
212+ df [" goc" ] = np .float32 (data_para [0 ].goc )
211213
212214 # 7 - Compute corrected Gain and Offset and fill df
213215 # 7.2 - Now assign the corrected Gain and Offset values
214216 # except when ECC works better
215- df [' Gain_Cor' ] = 0.0
216- df [' Offset_Cor' ] = 0.0
217+ df [" Gain_Cor" ] = 0.0
218+ df [" Offset_Cor" ] = 0.0
217219
218220 # apply correction to gain and offset when fit is ok
219- idx = df ['Flag31' ] & df ['Flag81' ]
220- df .loc [idx , 'Gain_Cor' ] = df ['Gain_ECC' ][idx ] * df ['Gain_Prime' ][idx ]
221- df .loc [idx , 'Offset_Cor' ] = df ['Gain_ECC' ][idx ] * df ['Offset_Prime' ][idx ] + \
222- df ['Offset_ECC' ][idx ]
221+ idx = df ["Flag31" ] & df ["Flag81" ]
222+ df .loc [idx , "Gain_Cor" ] = df ["Gain_ECC" ][idx ] * df ["Gain_Prime" ][idx ]
223+ df .loc [idx , "Offset_Cor" ] = df ["Gain_ECC" ][idx ] * df ["Offset_Prime" ][idx ] + df ["Offset_ECC" ][idx ]
223224 # otherwise keep uncorrected ECC Values
224225 idx = ~ idx
225- df .loc [idx , ' Gain_Cor' ] = df [' Gain_ECC' ][idx ]
226- df .loc [idx , ' Offset_Cor' ] = df [' Offset_ECC' ][idx ]
226+ df .loc [idx , " Gain_Cor" ] = df [" Gain_ECC" ][idx ]
227+ df .loc [idx , " Offset_Cor" ] = df [" Offset_ECC" ][idx ]
227228
228229 return df , idx
0 commit comments