def spectral_norm_meas_inv2(x,a,b): m1,m2 = x aM = measurement(a,0.0) bM = measurement(b,0.0) arrS = [] wSum = 0 for i,m in enumerate(m1): #arrS.append(m1[i]*aM.val + (m2[i]*m2[i]/m1[i])*bM.val) arrS.append(m1[i]*aM.val + (m1[i]*m1[i]/m2[i])*bM.val) return arrS
def extract_paired_runs(runPair, redRun, cfg): # If we already have a paired list of runs, this produces lifetimes # and peak values if cfg.vb: print("Combining pre-paired runs") runNum = [] # Get a list of runs for indexing for r in redRun: runNum.append(r.run) # This is for scattering lifetime vs. rate and bkg rate. lts = [] rates = [] bkgs = [] hlds = [] norms = [] for pair in runPair: ind1 = np.where(runNum == pair[0])[0] ind2 = np.where(runNum == pair[1])[0] if not (np.size(ind1) > 0 and np.size(ind2) > 0): # Didn't get this pair! continue else: #int(ind1,ind2) # Convert to indices if redRun[int(ind1)].hold < redRun[int( ind2)].hold: # Run 1 is short, run 2 is long sInd = int(ind1) lInd = int(ind2) else: sInd = int(ind2) lInd = int(ind1) normS = redRun[sInd].pct_cts(cfg) / redRun[sInd].norm_unl(cfg) normL = redRun[lInd].pct_cts(cfg) / redRun[lInd].norm_unl(cfg) if cfg.useMeanArr: matS = redRun[sInd].mat matL = redRun[lInd].mat else: matS = measurement(redRun[sInd].hold, 0.0) matL = measurement(redRun[lInd].hold, 0.0) lifetime = ltMeas_corr(normS, normL, matS, matL) lts.append(lifetime) rateS = redRun[sInd].pct_raw_cts(cfg) / redRun[sInd].len rateL = redRun[lInd].pct_raw_cts(cfg) / redRun[lInd].len rates.append([rateS, rateL]) bkgRS = redRun[sInd].bkgSum / redRun[sInd].len bkgRL = redRun[lInd].bkgSum / redRun[lInd].len bkgs.append([bkgRS, bkgRL]) norms.append([redRun[sInd].norm_unl(cfg) / redRun[lInd].norm_unl(cfg)]) hlds.append([ measurement(redRun[sInd].hold, 0.0), measurement(redRun[lInd].hold, 0.0) ]) return lts, rates, bkgs, hlds, norms
def calc_lifetime_paired_sections(ltVec, runPair): # Calculate the paired, weighted lifetime. # Here I've divided this into majorSections, which are the separation places ltval = [] # Generate list of lifetimes lterr = [] for lt in ltVec: ltval.append(float(lt.val) + totally_sick_blinding_factor) # Blind here lterr.append(1.0 / float(lt.err**2)) # Value of weighting is 1/err^2 majorSections = [4200, 4711, 7326, 9600, 11669, 13209, 14517] years = [4200, 9600, 14517] ltSections = [] for s in range(len(majorSections) - 1): # Dividing the lifetime into chunks ltAvg = 0.0 ltWts = 0.0 for i, lt in enumerate(ltval): # Weighted sum of lifetimes if majorSections[s] <= runPair[i][0] < majorSections[s + 1]: ltAvg += lt * lterr[i] ltWts += lterr[i] if ltWts > 0: ltFin = ltAvg / ltWts # Lifetime is weighted sum over sum of weights ltErr = np.sqrt(1 / ltWts) # Uncertainty is sqrt of sum of weights else: ltFin = ltAvg ltErr = np.inf print(" For runs", majorSections[s], "to", majorSections[s + 1], ":") print(" Lifetime is:", ltFin, "+/-", ltErr) ltSections.append(measurement(ltFin, ltErr)) ltYears = [] print(" ---------------------------------------------------") for s in range(len(years) - 1): # Dividing the lifetime into chunks ltAvg = 0.0 ltWts = 0.0 for i, lt in enumerate(ltval): # Weighted sum of lifetimes if years[s] <= runPair[i][0] < years[s + 1]: ltAvg += lt * lterr[i] ltWts += lterr[i] if ltWts > 0: ltFin = ltAvg / ltWts # Lifetime is weighted sum over sum of weights ltErr = np.sqrt(1 / ltWts) # Uncertainty is sqrt of sum of weights else: ltFin = ltAvg ltErr = np.inf print(" For runs", years[s], "to", years[s + 1], ":") print(" Lifetime is:", ltFin, "+/-", ltErr) ltYears.append(measurement(ltFin, ltErr)) return ltSections, ltYears
def bkgFunc(r_m, hDep, run, pmt, hi=10.0, hf=10.0, ti_f=np.inf, tf_f=np.inf): # This is the generic background function. # Need to fit to alpha, beta, t1, t2. # # For a given time, have R = f(h)*(a0 + a1*e^(-t/t1) + a2*e^(-t/t2)) # # End of run thus gives a0 = R_end / f(h_end) - a1*e^(-tf/t1) + a2*e^(-tf/t2) # # So R(h,t) = f(h)*(R_end / f(h_end)) # + a1*(f(h)*e^(-t/t1) - f(h_end)*e^(-t/t1)) # + a2*(f(h)*e^(-t/t2) - f(h_end)*e^(-t/t2)) # # Requires measured bkg (r_m), run number, and pmt. # # ti_f is the time we want to calculate the background at # tf_f is the time we measured the background. #A_i = height_factor_run(run, hi, pmt) #A_f = height_factor_run(run, hf, pmt) A_i = hDep.hF(hi, pmt) A_f = hDep.hF(hf, pmt) a, t1, b, t2 = time_dependence_run(run, pmt, hDep) ti = measurement(ti_f, 0.0) tf = measurement(tf_f, 0.0) if r_m > 0: rate_h = (measurement(r_m, np.sqrt(r_m)) / A_f) else: rate_h = (measurement(0.0, 0.0) / A_f) #print(measurement(r_m,np.sqrt(r_m)),rate_h) #print(r_m,r_m-(A_i*rate_h).val) try: rate_t = a * ((-ti / t1).exp() - A_f * (-tf / t1).exp() / A_i) + b * ((-ti / t2).exp() - A_f * (-tf / t2).exp() / A_i) #rate_t = a*(np.exp(-ti/t1) - A_f*np.exp(-tf/t1)/A_i) + b*(np.exp(-ti/t2) - A_f*np.exp(-tf/t2)/A_i) #print(run) #print(" ",(-ti/t1).exp(),ti,t1,ti/t1) #print(" ",np.exp(-tf/t1),np.exp(-tf/t2)) #print(" ",a, b) except RuntimeWarning: print( str(ti) + " " + str(t1) + " " + str(tf) + " " + str(t2) + " " + str(run)) rate_t = a * ((-ti / t1).exp() - A_f * (-tf / t1).exp() / A_i) + b * ((-ti / t2).exp() - A_f * (-tf / t2).exp() / A_i) #rate_t = a*(np.exp(-ti/t1) - A_f*np.exp(-tf/t1)/A_i) + b*(np.exp(-ti/t2) - A_f*np.exp(-tf/t2)/A_i) #rate_t = measurement(0.0,0.0) #print(A_i*(rate_h+rate_t)) return A_i * (rate_h + rate_t)
def hF(self, hgt, pmt): # This is our height_factor_run() but in object form. f = measurement(1.0, 0.0) # Default is 1 for i, h in enumerate(self.hgts): # Loop through heights if h - 1 < hgt < h + 1: if pmt == 0: # Coinc f = measurement(self.coinc[i], self.coincE[i]) elif pmt == 1: # PMT 1 f = measurement(self.pmt1[i], self.pmt1E[i]) elif pmt == 2: # PMT 2 f = measurement(self.pmt2[i], self.pmt2E[i]) break # If we got the right hgt don't need to loop. return f
def lt(sCts, lCts, sDD, lDD): # Lifetime, no mean arr error # Lifetime pair measurement calculation -- need short/long counts and short/long times tau = measurement(0.0, np.inf) if sCts.val <= 0 or lCts.val <= 0: return tau tau.val = (lDD-sDD)/(log(sCts.val/lCts.val)) tau.err = sqrt(pow(sCts.err/sCts.val,2)+pow(lCts.err/lCts.val,2))*(lDD-sDD)/pow((log(sCts.val/lCts.val)),2) return tau
def spectral_norm_meas_inv(x,a,b): #Change this later m1,m2 = x aM = measurement(a,0.0) bM = measurement(b,0.0) arrS = [] wSum = 0 for i,m in enumerate(m1): # Find "main detector" #if m1[i] > m2[i]: arrS.append(m1[i]*aM.val+ (m2[i]/m1[i])*bM.val) #else: # arrS.append(m2[i]*aM.val+(m1[i]/m2[i])*bM.val) return arrS
def tF(self, hgt, pmt): # This is our time_dependence_factor() but in object form. # Technically this is hardcoded towards 2 as an output fac = [] t = [] for i in range(self.consts): # Initialization loop fac.append(measurement(0.0, 0.0)) # Default is 0 t.append(measurement(np.inf, 0.0)) # Default is inf for i in range(self.consts): # Forced to scale to 490 if pmt == 0: fac[i] = self.coinc[i] * hgt.hF(490., 0) t[i] = self.coincT[i] if pmt == 1: fac[i] = self.pmt1[i] * hgt.hF(490., 1) t[i] = self.pmt1T[i] if pmt == 2: fac[i] = self.pmt2[i] * hgt.hF(490., 2) t[i] = self.pmt2T[i] # Here's the hardcode to do least work return fac[0], t[0], fac[1], t[1]
def ltMeas(sCts, lCts, sDD, lDD): # Lifetime, propagate mean arr. error # Lifetime pair measurement calculation including uncertainty in MAT # Error lifetime is -1 with infinite uncertainty tau = measurement(-1.0, np.inf) if (sCts.val <= 0.0) or (lCts.val <= 0.0) or (sDD.val <=0) or (lDD.val <= 0): # Check that we got data into all four values return tau if (sCts.val <= lCts.val) or (sDD.val >= lDD.val): # Check that short/long counts are actually short/long return tau dt = lDD - sDD # Difference in lifetime try: sCts = measurement(float(sCts.val),float(sCts.err)) lCts = measurement(float(lCts.val),float(lCts.err)) except AttributeError: sCts = measurement(float(sCts),0.0) lCts = measurement(float(lCts),0.0) ctsR = sCts/lCts # Ratio of counts tau = dt / ctsR.log() #print tau return tau
def spectral_norm_meas(x,a,b): m1,m2 = x aM = measurement(a,0.0) bM = measurement(b,0.0) #arr = aM*m1+bM*m2 arrS = [] wSum = 0 for i,m in enumerate(m1): #arrS.append(arr.val) # if isinstance(m1[i],measurement): #arrS.append(float(m1[i]*aM + m2[i]*aM)) # weight = 1.0 / ((m1[i].err/m1[i].val)**2 + (m2[i].err/m2[i].val)**2) # else: arrS.append(m1[i]*aM.val+m2[i]*bM.val) # weight = 1.0 #arrS.append(aM.val*(float(m1[i])+bM.val*float(m2[i]))) #wSum += weight #val = a*m1+b*m2 #print val return arrS
def ltMeas_corr(sCts, lCts, sDD, lDD): # Lifetime, propagate mean arr. error # Lifetime pair measurement calculation including uncertainty in MAT # Error lifetime is -1 with infinite uncertainty tau = measurement(-1.0, np.inf) if (sCts.val <= 0.0) or (lCts.val <= 0.0) or (sDD.val <=0) or (lDD.val <= 0): # Check that we got data into all four values return tau if (sCts.val <= lCts.val) or (sDD.val >= lDD.val): # Check that short/long counts are actually short/long return tau dt = lDD - sDD # Difference in lifetime try: sCts = measurement(float(sCts.val),float(sCts.err)) lCts = measurement(float(lCts.val),float(lCts.err)) except AttributeError: sCts = measurement(float(sCts),0.0) lCts = measurement(float(lCts),0.0) ctsR = (sCts/lCts) corr1 = measurement((sCts/lCts).val * (lCts.err/lCts.val)*(lCts.err/lCts.val),0.) #corr3 = (lCts.err/(lCts.val*lCts.val))*((sCts.val/lCts.val)*lCts.err + sCts.err) ctsR -= corr1 #ctsR.err = np.sqrt(( (sCts.err/lCts.err)*(1 - (lCts.err/lCts.val)**2))**2 \ #+ ((sCts.val*lCts.err)/(lCts.val*lCts.val)*(1 - 3*(lCts.err/lCts.val)**2))**2) #print(corr1, corr3) #ctsR = sCts/lCts + (lCts.err/(lCts.val*lCts.val))*((sCts.val/lCts.val)*lCts.err + sCts.err) #ctsR = sCts/lCts # Ratio of counts tau = dt / ctsR.log()# * (1 - (1 - 0.5*ctsR.log().val)*((ctsR.err)/(ctsR.val*ctsR.log().val))**2) #corr = 0 #corr = -0.5 * (dt *(ctsR.log() + 2) / (ctsR.log()*ctsR.log()*ctsR.log()) ).val * (ctsR.err*ctsR.err)/(ctsR.val*ctsR.val) #tau.err = dt.val/((ctsR.val**3)*((ctsR.log()).val**4))*((ctsR.val**2 - ctsR.err**2)*(ctsR.log().val**2) \ # - 3*ctsR.err*ctsR.err*(1 + ctsR.log().val) )*ctsR.err corr = -0.5 * (dt *(ctsR.log() + 2) / (ctsR.log()*ctsR.log()*ctsR.log()) ).val * \ ((sCts.err/sCts.val)*(sCts.err/sCts.val) \ -(lCts.err/lCts.val)*(lCts.err/lCts.val) \ - 2*(sCts.err*lCts.err)/(sCts.val*lCts.val*(ctsR.log().val+2))) tau = measurement(float(tau.val+corr),float(tau.err)) #print(tau) return tau
def calc_lifetime_ODR(nCtsVec, holdVec, useMeanArr=True): # TEST of Orthogonal Distance Regression (allows errors in X and Y) #print len(timeV), len(timeE), len(rawCts), len(rawErr) rawCts = [] rawErr = [] for x in nCtsVec: #separate out counts rawCts.append(float(x.val)) rawErr.append(float(x.err)) expModel = Model(lnlt) if useMeanArr: odrData = RealData(timeV, rawCts, sx=timeE, sy=rawErr) testODR = ODR(odrData, expModel, beta0=[1, 880.0]) output = testODR.run() print("ODR lifetime is: " + str(output.beta[1]) + " +/- " + str(output.sd_beta[1])) return measurement(output.beta[1], output.sd_beta[1])
def calc_lifetime_paired(ltVec, runPair=[], vb=True): # Calculate the paired, weighted lifetime. # This should track well with an exponential, but is subject to # statistical bias (it'll undershoot lifetime for low statistics) if vb: print("Calculating Lifetime (Paired)...") ltval = [] # Generate list of lifetimes lterr = [] for lt in ltVec: ltval.append(float(lt.val) + totally_sick_blinding_factor) # Blind here lterr.append(1.0 / float(lt.err**2)) # Value of weighting is 1/err^2 ltAvg = 0.0 ltWts = 0.0 for i, lt in enumerate(ltval): # Weighted sum of lifetimes ltAvg += lt * lterr[i] ltWts += lterr[i] if ltWts > 0: ltFin = ltAvg / ltWts # Lifetime is weighted sum over sum of weights ltErr = np.sqrt(1 / ltWts) # Uncertainty is sqrt of sum of weights else: print("Error! Unable to predict uncertainty on lifetime!") ltFin = ltAvg ltErr = np.inf ltval = np.array(ltval) unc = 1. / np.sqrt(np.array(lterr)) chi2 = np.sum(np.power((ltval - ltFin) / unc, 2)) chi2NDF = chi2 / (len(ltval) - 1) ltErr2 = ltErr * np.sqrt(chi2NDF) if vb: print("Paired (weighted) lifetime is:", ltFin, "+/-", ltErr) print("Chi2 is:", chi2, "(NDF):", chi2NDF) print("Scale Err = ", ltErr2) return measurement(ltFin, ltErr2)
def calc_lifetime_unw_paired(ltVec, runPair): # Calculate the paired, weighted lifetime. # This should be less statistically biased than weighted. # However it might still overshoot the lifetime a bit. # # Additionally it's not a great use of statistics and will give # inflated error bars print("Calculating Lifetime (Paired but Unweighted)...") ltval = [] # Generate list of lifetimes for lt in ltVec: # Just look at the value of lifetimes -- ignore errors ltval.append(float(lt) + totally_sick_blinding_factor ) # float fcn auto-casts .val for measurement class ltAvg = np.mean(ltval) ltStd = np.std(ltval) print("Paired (unweighted) lifetime is: " + str(ltAvg) + " +/- " + str(ltStd / np.sqrt(len(ltVec)))) return measurement(ltAvg, ltStd / np.sqrt(len(ltVec))) #, runPair,ltVec
def calc_lifetime_exp(rRed, cfg): # Single normalization exponential lifetime if cfg.vb: print("Calculating Lifetime (Exponential Fit)...") rawCts = [] rawErr = [] timeV = [] for x in rRed: if x.normalize_cts().err > 0: # Avoid divide by zero errors rawCts.append(x.normalize_cts().val) rawErr.append(x.normalize_cts().err) if cfg.useMeanArr: timeV.append(x.mat) # Assume perfect knowledge of time else: timeV.append(x.hold) pFitE, pVarE = curve_fit(explt, timeV, rawCts, p0=(1, 880.0), sigma=rawErr, absolute_sigma=False) print("Exponential lifetime (floating) is: " + str(pFitE[1]) + " +/- " + str(np.sqrt(np.diag(pVarE))[1])) print(str(pVarE)) varT = np.sqrt( pFitE[1] * pFitE[1] * pVarE[1][1] * pVarE[1][1] + 2 * pFitE[0] * pFitE[1] * pVarE[0][1]) # Attempt to correct for cov. print("Uncertainty of t given fixed a is " + str(varT / len(rawCts))) #return measurement(pFitE[1], np.sqrt(np.diag(pVarE))[1]), measurement(pFitE[0], np.sqrt(np.diag(pVarE))[0]) #pFitE, pVarE = curve_fit(explt_fix, timeV, rawCts, p0=(880.0), sigma=rawErr,absolute_sigma=True) #print("Exponential lifetime (fixed) is: "+str(pFitE[0]+totally_sick_blinding_factor)+" +/- "+str(np.sqrt(np.diag(pVarE))[0])) return measurement(pFitE[0], np.sqrt(np.diag(pVarE))[0])
def __init__(self, r_min, r_max): self.rMin = r_min self.rMax = r_max # How many time dependent curves we want to load # That would also require modifying dataIO. self.consts = 2 # Time constants as "measurement" values self.pmt1 = [] self.pmt1T = [] self.pmt2 = [] self.pmt2T = [] self.coinc = [] self.coincT = [] for i in range(self.consts): # Load factors as 0 self.pmt1.append(measurement(0.0, 0.0)) self.pmt2.append(measurement(0.0, 0.0)) self.coinc.append(measurement(0.0, 0.0)) # and time constants infinite self.pmt1T.append(measurement(np.inf, 0.0)) self.pmt2T.append(measurement(np.inf, 0.0)) self.coincT.append(measurement(np.inf, 0.0))
def calc_lifetime_ODR_meanFit(ctsVec, holdVec, mArrVec=[]): # TEST of Orthogonal Distance Regression (allows errors in X and Y) # meanFit averages all the points before doing a fit. # If we're not doing mean arrival time, assume mean arrival is just hold if len(mArrVec) == 0: mArrVec = holdVec fixTimes = [] # Generate the total number of time bins for t in holdVec: if round(t.val) not in fixTimes: fixTimes.append(round(t.val)) # Count our buffers tBuff = np.zeros(len(fixTimes)) tEBuff = np.zeros(len(fixTimes)) ctsBuff = np.zeros(len(fixTimes)) ctsEBuff = np.zeros(len(fixTimes)) #tBuff = np.array([measurement(0.0,0.0) for y in range(len(fixTimes))]) #ctsBuff = np.array([measurement(0.0,0.0) for y in range(len(fixTimes))]) num = np.zeros(len(fixTimes)) for i, t in enumerate(holdVec): ind = int(np.argwhere(np.array(fixTimes) == round(t.val))) ctsBuff[ind] += ctsVec[i].val / (ctsVec[i].err * ctsVec[i].err) ctsEBuff[ind] += 1 / (ctsVec[i].err * ctsVec[i].err) if t.err > 0: tBuff[ind] += t.val / (t.err * t.err) tEBuff[ind] += 1 / (t.err * t.err) else: tBuff[ind] += t.val tEBuff[ind] += 1 #tBuff[ind] += t num[ind] += 1 meanCts = [] meanCtsE = [] meanT = [] meanTE = [] for i, x in enumerate(fixTimes): #separate out counts meanCts.append(float(ctsBuff[i] / ctsEBuff[i])) meanCtsE.append(1 / np.sqrt(ctsEBuff[i])) meanT.append(float(tBuff[i] / tEBuff[i])) meanTE.append(1 / np.sqrt(tEBuff[i])) expModel = Model(lnlt) if len(meanTE) > 0: odrData = RealData(meanT, meanCts, sx=meanTE, sy=meanCtsE) else: odrData = RealData(meanT, meanCts, sy=meanCtsE) testODR = ODR(odrData, expModel, beta0=[1, 880.0]) output = testODR.run() print("ODR (mean fit) lifetime is: " + str(output.beta[1]) + " +/- " + str(output.sd_beta[1])) linetxt = np.linspace(0, 5000, 5000) ltTest = output.beta[0] * np.exp(-linetxt / output.beta[1]) #plt.figure(9001) #if len(meanTE) > 0: # plt.errorbar(meanT,meanCts,xerr=meanTE,yerr=meanCtsE,fmt='b.') #else: # plt.errorbar(meanT,meanCts,yerr=meanCtsE,fmt='b.') #plt.plot(linetxt,ltTest) #plt.yscale('log') #plt.show() return measurement(output.beta[1], output.sd_beta[1]), meanT, meanCts
def pair_runs_summed(runBreaks, rN, unld, time, normFac=[], corr=0.9): # Redoing the pairing algorithm but with summed ext. counts # If we sum up the counts before taking lifetimes, we should still get # the right lifetime. There's a little bit of weirdness required here. # # Namely, we have to be careful with the long runs since they're paired # with multiple short lengths (and vice versa) #print runBreaks runsS = [] # Separate run list into short and long nCtsS = [] hldTS = [] runsL = [] nCtsL = [] hldTL = [] hldTVecS = [] # This is the list of short run times hldTVecL = [] # This is the list of long run times if len(normFac) != len(rN): normFac = [] for r in rN: normFac.append(1.0) nFS = [] nFL = [] for i, run in enumerate(rN): if unld[i].err == np.inf or unld[ i].err == 0.0: # Weird error state catch continue t = time[i].val if (t < 500.0): runsS.append(run) nCtsS.append(unld[i]) hldTS.append(time[i]) nFS.append(normFac[i]) if round(t) not in hldTVecS: hldTVecS.append(round(t)) else: runsL.append(run) nCtsL.append(unld[i]) hldTL.append(time[i]) nFL.append(normFac[i]) if round(t) not in hldTVecL: hldTVecL.append(round(t)) hldTVecS.sort() hldTVecL.sort() nRunsMat = np.zeros( (len(hldTVecS), len(hldTVecL))) # Create matrices for runs (number of runs) sCtsMat = np.array([[measurement(0.0, 0.0) for y in range(len(hldTVecL))] for x in range(len(hldTVecS)) ]) # Create matrices for runs (short cts) lCtsMat = np.array([[measurement(0.0, 0.0) for y in range(len(hldTVecL))] for x in range(len(hldTVecS)) ]) # Create matrices for runs (long cts) #lCtsMat = np.empty((len(hldTVecS),len(hldTVecL)),dtype=measurement) # Create matrices for runs (long cts) #lCtsMat = np.empty((len(hldTVecS),len(hldTVecL)),dtype=measurement) # Create matrices for runs (long cts) #print sCtsMat, hldTVecS, hldTVecL # Pairing scMax = 16 # Max separation lInd = 0 bCount = 0 runPair = [] #print hldTVecS #print hldTVecL for gap in range( 1, scMax ): # Pairing algorithm looks to "minimize" spacing between short/long pairs bCount = 0 for sInd, sr in enumerate(runsS): # Loop through short paired = False # For breaking this loop while runBreaks[bCount + 1] < sr: # Find runBreaks region bCount += 1 for lInd, lr in enumerate(runsL): # and through long #print sr,lr, gap, runBreaks[bCount],runBreaks[bCount+1] if abs( sr - lr ) < gap: # We're in possible range, let's now check other things # First, check if this is really the "best" pair if lInd != len(runsL) - 1: if runBreaks[bCount] <= runsL[lInd + 1] < runBreaks[ bCount + 1]: # Make sure we don't cross a break if abs(sr - runsL[lInd + 1]) < abs( sr - lr ): # We have another pair that's closer in range! continue elif abs(sr - runsL[lInd + 1]) == abs( sr - lr): # tiebreaker should be normalization. if abs(1.0 - float(nFS[sInd] / nFL[lInd])) > abs( 1.0 - float(nFS[sInd] / nFL[lInd + 1])): continue # I'll let this continue -- you could beat this if you auto-paired this here. if ( (runBreaks[bCount] <= sr < runBreaks[bCount + 1] and runBreaks[bCount] <= lr < runBreaks[bCount + 1] ) # check break regions and (corr < float(nFS[sInd] / nFL[lInd]) < 1.0 / corr) ): # Check that the normalization is roughly the same too tvIndS = int( np.argwhere( np.array(hldTVecS) == round(hldTS[sInd].val)) ) # figure out the short index tvIndL = int( np.argwhere( np.array(hldTVecL) == round(hldTL[lInd].val)) ) # figure out the long index # We're good! Now just calculate the lifetime nRunsMat[tvIndS][tvIndL] += 1 sCtsMat[tvIndS][tvIndL] += measurement( float(nCtsS[sInd].val), float(nCtsS[sInd].err)) lCtsMat[tvIndS][tvIndL] += measurement( float(nCtsL[lInd].val), float(nCtsL[lInd].err)) # runPair.append([sr,lr]) # lts.append(lifetime) # output vector runPair.append([sr, lr]) # And remove these runs, since we've successfully paired them runsL.pop(lInd) nCtsL.pop(lInd) hldTL.pop(lInd) nFL.pop(lInd) paired = True #For breaking out of the other loop break elif lr - sr > scMax: # If lr is scMax more than sr, we can assume lr is sorted and break break if paired: # If we found a long run for this short run, take this run out for the future! runsS.pop(sInd) nCtsS.pop(sInd) hldTS.pop(sInd) nFS.pop(sInd) # for sInd, sr in enumerate(runsS): # if nCtsS[sInd].err == np.inf: # If we have an infinite errorbar, continue. # #print sr # continue # tvIndS = int(np.argwhere(np.array(hldTVecS) == round(hldTS[sInd].val))) # figure out the short index # while runBreaks[bCount+1] < sr: # If the short index is in the right "break" region it's OK # bCount += 1 # if runBreaks[bCount] <= sr < runBreaks[bCount+1]: # for lInd, lr in enumerate(runsL): # Loop through long to see if we're in the right "break" region # if runBreaks[bCount] <= lr < runBreaks[bCount+1]: # if abs(sr - lr) < scMax: # #print np.argwhere(np.array(hldTVecL)) == hldTL[lInd] # tvIndL = int(np.argwhere(np.array(hldTVecL) == round(hldTL[lInd].val))) # figure out the long index # #try: # if not nCtsL[lInd].err == np.inf: # If we have an infinite errorbar, continue. # # add counts to the proper position our summing matrices # nRunsMat[tvIndS][tvIndL] += 1 # sCtsMat[tvIndS][tvIndL] += measurement(float(nCtsS[sInd].val),float(nCtsS[sInd].err)) # lCtsMat[tvIndS][tvIndL] += measurement(float(nCtsL[lInd].val),float(nCtsL[lInd].err)) # runPair.append([sr,lr]) # #except: # # continue # runsL.pop(lInd) # nCtsL.pop(lInd) # hldTL.pop(lInd) # break lts = [] wts = [] for tvIndS, tS in enumerate(hldTVecS): for tvIndL, tL in enumerate(hldTVecL): #lifetime = ltMeas(sCtsMat[tvIndS][tvIndL]/nRunsMat[tvIndS][tvIndL],lCtsMat[tvIndS][tvIndL]/nRunsMat[tvIndS][tvIndL],measurement(tS,0.0),measurement(tL,0.0)) lifetime = ltMeas(sCtsMat[tvIndS][tvIndL], lCtsMat[tvIndS][tvIndL], measurement(tS, 0.0), measurement(tL, 0.0)) # lifetime = measurement(0.0,np.inf) #print sCtsMat[tvIndS][tvIndL] #print lCtsMat[tvIndS][tvIndL] #print lifetime, tS, tL, nRunsMat[tvIndS][tvIndL] lifetime.err = lifetime.err / np.sqrt( nRunsMat[tvIndS][tvIndL]) # This is a sqrt then another sqrt. lts.append(lifetime) wts.append(nRunsMat[tvIndS][tvIndL]) if len(lts) == 0: print("Something went wrong, no pairs created!") else: print("Summing " + str(len(runPair)) + " short-long pairs!") lt_meas = measurement(0.0, 0.0) for i, x in enumerate(lts): if x.val > 0.0: lt_meas += x * measurement(wts[i], 0.0) else: wts[i] = 0.0 print("Summed Lifetime is: " + str(lt_meas / measurement(np.sum(wts), 0.0))) #print lts return lts, runPair
def pair_runs_from_file(rRed, cfg, inFName='/home/frank/run_pairs.csv'): #------------------------------------------------------------------- # This script loads pairs of runs from a file #------------------------------------------------------------------- print("Loading list of pairs from " + inFName) datatype = [('r1', 'i4'), ('r2', 'i4')] pairs = np.loadtxt(inFName, delimiter=",", dtype=datatype) runsS = [] # Separate run list into short and long nCtsS = [] hldTS = [] matTS = [] runsL = [] nCtsL = [] matTL = [] hldTL = [] #if len(normFac) != len(rN): normFac = [] for r in rRed: # This doesn't mean anything now normFac.append(1.0) nFS = [] nFL = [] rUse = [] for r in rRed: if r.run in pairs['r1'] or r.run in pairs['r2']: rUse.append(r) if (r.hold > 2000.0) and not (cfg.useLong): continue #unld = (r.ctsSum-r.bkgSum)/r.norm_unl(cfg) unld = r.pct_cts(cfg) / r.norm_unl(cfg) #unld /= (r.eff[0] + r.eff[1]) if (not np.isfinite( unld.err)) or unld.err == 0.0: # Weird error state catch if cfg.vb: print("%d has infinite unload error" % r.run) continue if (r.hold < 500.0): runsS.append(r.run) nCtsS.append(unld) hldTS.append(measurement(r.hold, 0.0)) if cfg.useMeanArr: matTS.append(r.mat) else: matTS.append(measurement(r.hold, 0.0)) #nFS.append(normFac[i]) nFS.append(r.norm_unl(cfg)) else: runsL.append(r.run) nCtsL.append(unld) hldTL.append(measurement(r.hold, 0.0)) if cfg.useMeanArr: matTL.append(r.mat) else: matTL.append(measurement(r.hold, 0.0)) nFL.append(r.norm_unl(cfg)) runsS = np.array(runsS) runsL = np.array(runsL) lts = [] runPair = [] for pair in pairs: runS = pair['r1'] runL = pair['r2'] sInd = np.where(runsS == runS)[0] lInd = np.where(runsL == runL)[0] if not (np.size(sInd) > 0 and np.size(lInd) > 0): continue else: sInd = int(sInd) lInd = int(lInd) if (float(matTS[sInd]) < float( matTL[lInd])): # Run 1 is short, run 2 is long lifetime = ltMeas_corr(nCtsS[sInd], nCtsL[lInd], matTS[sInd], matTL[lInd]) lts.append(lifetime) runPair.append([runS, runL]) else: # Run 2 is short, run 1 is long lifetime = ltMeas_corr(nCtsS[lInd], nCtsL[sInd], matTS[lInd], matTL[sInd]) lts.append(lifetime) runPair.append([runS, runL]) #print (str(lifetime)) return lts, runPair, rUse
tdPmt1_raw = tCts['pmt1'][21:] * 0. global bkgExp bkgExp = muCts[r].pmt1 #s* hDCts[r].pmt1 #tdPmt1 -= muCts[r].pmt1 * hDCts[r].pmt1 # Background Subtraction if tCts['pmt2'][0] > 0: tdPmt2_raw = tCts['pmt2'][21:] / tCts['pmt2'][0] else: tdPmt2_raw = tCts['pmt1'][21:] * 0. #tdPmt2 -= muCts[r].pmt2 * hDCts[r].pmt2 if tCts['coinc'][0] > 0: tdPmtC_raw = tCts['coinc'][21:] / tCts['coinc'][0] else: tdPmtC_raw = tCts['coinc'][21:] * 0. # Extract the expected background rates pmt1_avg = measurement(muCts[r].pmt1/hDCts[r].pmt1,\ muCts[r].pmt1/hDCts[r].pmt1*np.sqrt((muStd[r].pmt1/muCts[r].pmt1)**2+(hDStd[r].pmt1/hDCts[r].pmt1)**2)) pmt2_avg = measurement(muCts[r].pmt2/hDCts[r].pmt2,\ muCts[r].pmt2/hDCts[r].pmt2*np.sqrt((muStd[r].pmt2/muCts[r].pmt2)**2+(hDStd[r].pmt2/hDCts[r].pmt2)**2)) pmtC_avg = measurement(muCts[r].coinc/hDCts[r].coinc,\ muCts[r].coinc/hDCts[r].coinc*np.sqrt((muStd[r].coinc/muCts[r].coinc)**2+(hDStd[r].coinc/hDCts[r].coinc)**2)) avg_bin = 10 bins = np.zeros(int(len(bins_raw) / avg_bin)) tdPmt1 = np.zeros(int(len(bins_raw) / avg_bin)) tdPmt2 = np.zeros(int(len(bins_raw) / avg_bin)) tdPmtC = np.zeros(int(len(bins_raw) / avg_bin)) for i in range(int(len(bins_raw) / avg_bin)): bins[i] = np.mean(bins_raw[10 * i:10 * (i + 1) - 1]) tdPmt1[i] = np.mean(tdPmt1_raw[10 * i:10 * (i + 1) - 1]) tdPmt2[i] = np.mean(tdPmt2_raw[10 * i:10 * (i + 1) - 1]) tdPmtC[i] = np.mean(tdPmtC_raw[10 * i:10 * (i + 1) - 1])
def time_dependence_run(run, pmt, hDep): # Again this is a lookup table for time dependence runs # There are now 4 factors to look up here for each run/PMT. # # These numbers are "raw" meaning un-height-corrected for the time dep. # We height-correct the scaling factor at the end. # # I'm also assuming there's no time dependence in coincidences (for now.) # To turn on coincidences I'd just add an else for PMTs. # # I should probably re-do the math on these a = measurement(0.0, 0.0) t1 = measurement(np.inf, 0.0) b = measurement(0.0, 0.0) t2 = measurement(np.inf, 0.0) if 4200 <= run < 7327: if pmt == 1: a = measurement(0.0009514, 0.0002624) t1 = measurement(35.58, 8.35) b = measurement(0.002028, 0.000052) t2 = measurement(491.2, 14.0) elif pmt == 2: a = measurement(0.000304, 0.000019) t1 = measurement(136.0, 18.2) b = measurement(0.0007963, 0.0000155) t2 = measurement(2306.0, 101.0) elif 7327 <= run < 9545: if pmt == 1: a = measurement(0.0001638, 0.0000042) t1 = measurement(110.2, 6.8) b = measurement(0.0006133, 0.0000026) t2 = measurement(5490, 123.7) elif pmt == 2: a = measurement(0.0003004, 0.000079) t1 = measurement(70.54, 3.58) b = measurement(0.0007014, 0.000031) t2 = measurement(3107, 46.5) elif 9545 <= run < 13309: if pmt == 1: a = measurement(0.000611, 0.0000035) t1 = measurement(31.36, 2.54) b = measurement(0.001348, 0.000010) t2 = measurement(851.8, 9.4) elif pmt == 2: a = measurement(0.001744, 0.000105) t1 = measurement(33.23, 2.36) b = measurement(0.0027538, 0.000046) t2 = measurement(364.3, 6.4) * 3 elif 13309 <= run < 15000: # These numbers should be re-calculated if pmt == 1: a = measurement(0.0006849, 0.00000428) t1 = measurement(98.27, 7.91) b = measurement(0.001191, 0.000027) t2 = measurement(940.1, 26.6) elif pmt == 2: a = measurement(0.0006847, 0.0000428) t1 = measurement(98.26, 7.91) b = measurement(0.001191, 0.000027) t2 = measurement(939.2, 26.6) # Need to correct for height factor here and scale to Hz #a = a * height_factor_run(run,490.0,pmt) * measurement(1550.0,0.0) #b = b * height_factor_run(run,490.0,pmt) * measurement(1550.0,0.0) a = a * hDep.hF(490.0, pmt) * measurement(1550.0, 0.0) b = b * hDep.hF(490.0, pmt) * measurement(1550.0, 0.0) return a, t1, b, t2
def pair_runs_from_list(rRed, pairsList, cfg): # Pairing algorithm. I wrote this with a bunch of individual lists # so it could be optimized better. runsS = [] # Separate run list into short and long nCtsS = [] hldTS = [] matTS = [] runsL = [] nCtsL = [] matTL = [] hldTL = [] #if len(normFac) != len(rN): normFac = [] for r in rRed: # This doesn't mean anything now normFac.append(1.0) pairs = np.zeros(len(pairsList), dtype=[('r1', 'f8'), ('r2', 'f8')]) for i in range(len(pairsList)): try: pairs[i]['r1'] = pairsList[i][0] pairs[i]['r2'] = pairsList[i][1] except ValueError: continue nFS = [] nFL = [] rUse = [] for r in rRed: if r.run in pairs['r1'] or r.run in pairs['r2']: rUse.append(r) else: continue unld = r.cts / r.norm if (not np.isfinite( unld.err)) or unld.err == 0.0: # Weird error state catch if cfg.vb: print("%d has infinite unload error" % r.run) continue if (r.hold < 500.0): runsS.append(r.run) nCtsS.append(unld) hldTS.append(measurement(r.hold, 0.0)) if cfg.useMeanArr: matTS.append(r.mat) else: matTS.append(measurement(r.hold, 0.0)) nFS.append(r.norm) else: runsL.append(r.run) nCtsL.append(unld) hldTL.append(measurement(r.hold, 0.0)) if cfg.useMeanArr: matTL.append(r.mat) else: matTL.append(measurement(r.hold, 0.0)) nFL.append(r.norm) runsS = np.array(runsS) runsL = np.array(runsL) lts = [] ltsC = [] hTPair = [] runPair = [] for pair in pairs: runS = pair['r1'] runL = pair['r2'] sInd = np.where(runsS == runS)[0] lInd = np.where(runsL == runL)[0] if not (np.size(sInd) > 0 and np.size(lInd) > 0): continue else: sInd = int(sInd) lInd = int(lInd) #if (float(matTS[sInd]) < float(matTL[lInd])): # Run 1 is short, run 2 is long # At one point I was concerned about short/long, but I don't think(?) that's an issue lifetime = ltMeas(nCtsS[sInd], nCtsL[lInd], matTS[sInd], matTL[lInd]) lifetime_C = ltMeas_corr(nCtsS[sInd], nCtsL[lInd], matTS[sInd], matTL[lInd]) lts.append(lifetime) ltsC.append(lifetime_C) hTPair.append([hldTS[sInd], hldTL[lInd]]) runPair.append([runS, runL]) #else: # Run 2 is short, run 1 is long # lifetime = ltMeas(nCtsS[lInd], nCtsL[sInd], matTS[lInd], matTL[sInd]) # lifetime_C = ltMeas_corr(nCtsS[lInd], nCtsL[sInd], matTS[sInd], matTL[lInd]) # lts.append(lifetime) # ltsC.append(lifetime_C) # hTPair.append([hldTS[sInd],hldTL[lInd]]) # runPair.append([runS,runL]) #print (str(lifetime)) return lts, runPair, hTPair, ltsC
def bkgFunc_obj(bkg, pmt=0, h_i=10.0, ti_f=np.inf): # This is the generic background function. # Need to fit to alpha, beta, t1, t2. # # For a given time, have R = f(h)*(a0 + a1*e^(-t/t1) + a2*e^(-t/t2)) # # End of run thus gives a0 = R_end / f(h_end) - a1*e^(-tf/t1) + a2*e^(-tf/t2) # # So R(h,t) = f(h)*(R_end / f(h_end)) # + a1*(f(h)*e^(-t/t1) - f(h_end)*e^(-t/t1)) # + a2*(f(h)*e^(-t/t2) - f(h_end)*e^(-t/t2)) # # Requires measured bkg (r_m), run number, and pmt. # # ti_f is the time we want to calculate the background at # tf_f is the time we measured the background. # Extract factors for measured point a, t1, b, t2 = bkg.tDep.tF(bkg.hDep, pmt) #a, t1, b, t2 = time_dependence_run(bkg.run, pmt,bkg.hDep) A_i = bkg.hDep.hF(h_i, pmt) # height dependence stored in object # A_i = height_factor_run(bkg.run, h_i, pmt) ti = measurement(ti_f, 0.0) # Convert time to meas. # Scale background to point A_f = bkg.hDep.hF(bkg.hgt, pmt) #A_f = height_factor_run(bkg.run, bkg.hgt, pmt) tf = measurement(bkg.time, 0.0) if pmt == 1: r_m = bkg.pmt1 elif pmt == 2: r_m = bkg.pmt2 elif pmt == 0: r_m = bkg.coinc else: sys.exit("ERROR! You're scaling backgrounds for a non-existent PMT!") rate_h = (measurement(r_m, np.sqrt(r_m)) / A_f) #try: if np.isfinite(t1.val) and ( t1.val > 0): # numpy doesn't like infinite time constants a_val = a * ((-ti / t1).exp() - A_f * (-tf / t1).exp() / A_i) else: a_val = a * (measurement(1., 0.) - A_f / A_i) if np.isfinite( t2.val) and (t2.val > 0): # Again, avoid infinite time constants. b_val = b * ((-ti / t2).exp() - A_f * (-tf / t2).exp() / A_i) else: b_val = b * (measurement(1., 0.) - A_f / A_i) rate_t = a_val + b_val # Time dependence is function of these two #else: # rate_t = measurement(0.0,0.0) #except RuntimeWarning: # print("Warning! Possible Overflow Error!",str(run)) # Error here is probably an overflow error # rate_t = measurement(0.0,np.inf)\ bkgTot = A_i * (rate_h + rate_t) bkgPos = A_i / A_f * measurement(r_m, np.sqrt(r_m)) - measurement( r_m, np.sqrt(r_m)) bkgPos.err = bkgPos.val * np.sqrt(r_m + (A_i / A_f).err * (A_i / A_f).err) bkgTime = A_i * rate_t bkgTime.err = np.sqrt(bkgTime.err * bkgTime.val) # Fractional time dependence return bkgTot, bkgPos, bkgTime
def height_factor_run(run, height=10.0, pmt=0): # This is just a lookup table of height dependence factors. # Calculated for PMT1/2. Coinc is "unknown" case [0 = coinc] # # If in doubt there's no height dependence. #if height == 250.0: # height = 490.0 #elif height == 490.0: # height = 250.0 if 9.0 < height < 11.0: return measurement(1.0, 0.0) factor = [] if 4200 <= run < 7327: if 489.0 < height < 491.0: factor.append(measurement(0.923, 0.017)) # Coinc factor.append(measurement(1.0221, 0.0013)) # PMT 1 factor.append(measurement(1.0594, 0.0020)) # PMT 2 elif 379.0 < height < 381.0: factor.append(measurement(1.007, 0.018)) # Coinc factor.append(measurement(1.005, 0.0012)) # PMT 1 factor.append(measurement(1.0406, 0.0021)) # PMT 2 elif 249.0 < height < 251.0: factor.append(measurement(1.013, 0.0021)) # Coinc factor.append(measurement(0.9935, 0.0014)) # PMT 1 factor.append(measurement(1.0196, 0.0018)) # PMT 2 elif 7327 <= run < 9545: if 489.0 < height < 491.0: factor.append(measurement(0.940, 0.016)) # Coinc factor.append(measurement(1.1536, 0.0042)) # PMT 1 factor.append(measurement(1.1220, 0.0028)) # PMT2 elif 379.0 < height < 381.0: factor.append(measurement(0.997, 0.016)) # Coinc factor.append(measurement(1.0210, 0.0019)) # PMT 1 factor.append(measurement(1.0691, 0.0025)) # PMT 2 elif 249.0 < height < 251.0: factor.append(measurement(0.985, 0.017)) # Coinc factor.append(measurement(1.0172, 0.0016)) # PMT 1 factor.append(measurement(1.0428, 0.0022)) # PMT 2 elif 9545 <= run < 13309: if 489.0 < height < 491.0: factor.append(measurement(0.9353, 0.0075)) # Coinc factor.append(measurement(1.0180, 0.0023)) # PMT 1 factor.append(measurement(1.0098, 0.0011)) # PMT 2 elif 379.0 < height < 381.0: factor.append(measurement(0.9525, 0.0081)) # Coinc factor.append(measurement(1.0150, 0.0024)) # PMT 1 factor.append(measurement(1.0051, 0.0013)) # PMT 2 elif 249.0 < height < 251.0: factor.append(measurement(0.9435, 0.0074)) # Coinc factor.append(measurement(1.0043, 0.0019)) # PMT 1 factor.append(measurement(0.9833, 0.0011)) # PMT 2 elif 13309 <= run < 15000: if 489.0 < height < 491.0: factor.append(measurement(0.9862, 0.0148)) # Coinc factor.append(measurement(1.0251, 0.0019)) # PMT 1 factor.append(measurement(1.0259, 0.0016)) # PMT 2 elif 379.0 < height < 381.0: factor.append(measurement(0.9983, 0.0148)) # Coinc factor.append(measurement(1.0203, 0.0017)) # PMT 1 factor.append(measurement(1.0284, 0.0016)) # PMT 2 elif 249.0 < height < 251.0: factor.append(measurement(1.0005, 0.0133)) # Coinc factor.append(measurement(0.9988, 0.0017)) # PMT 1 factor.append(measurement(1.0002, 0.0014)) # PMT 2 if pmt >= len( factor): # Unknown case assumes at bottom, which is always 1.0. return measurement(1.0, 0.0) else: #print (run,height,pmt,factor[pmt]) #f_test = measurement(1.0,0.0) + (measurement(1.0,0.0) - factor[pmt])*measurement(249.0,0.0) #return measurement(1.0,0.0)/factor[pmt] return factor[pmt]
def pair_runs(runBreaks, rRed, cfg): # Pairing algorithm. I wrote this with a bunch of individual lists # so it could be optimized better. if cfg.vb: print("Pairing runs...") runsS = [] # Separate run list into short and long nCtsS = [] hldTS = [] matTS = [] runsL = [] nCtsL = [] matTL = [] hldTL = [] #if len(normFac) != len(rN): normFac = [] for r in rRed: # This doesn't mean anything now normFac.append(1.0) nFS = [] nFL = [] for r in rRed: if (r.hold > 2000.0) and not (cfg.useLong): continue #unld = (r.ctsSum-r.bkgSum)/r.norm_unl(cfg) #unld = r.pct_cts(cfg)/r.norm_unl(cfg) #print((r.ctsSum-r.bkgSum)-r.cts,((r.ctsSum-r.ctsSum)-(r.bkgSum-r.bkgSum))) unld = r.cts / r.norm #unld /= (r.eff[0] + r.eff[1]) if (not np.isfinite( unld.err)) or unld.err == 0.0: # Weird error state catch if cfg.vb: print("%d has infinite unload error" % r.run) continue if (r.hold < 500.0): runsS.append(r.run) nCtsS.append(unld) hldTS.append(measurement(r.hold, 0.0)) if cfg.useMeanArr: matTS.append(r.mat) else: matTS.append(measurement(r.hold, 0.0)) #nFS.append(normFac[i]) nFS.append(r.norm) #nFS.append(r.norm_unl(cfg)) else: runsL.append(r.run) nCtsL.append(unld) hldTL.append(measurement(r.hold, 0.0)) if cfg.useMeanArr: matTL.append(r.mat) else: matTL.append(measurement(r.hold, 0.0)) #nFL.append(r.norm_unl(cfg)) nFL.append(r.norm) # Pairing scMax = 16 # +/- 2 octets lInd = 0 bCount = 0 corr = 0.9 # No crazy norm drop-offs lts = [] ltsC = [] runPair = [] hTPair = [] for gap in range( 1, scMax ): # Pairing algorithm looks to "minimize" spacing between short/long pairs bCount = 0 for sInd, sr in enumerate(runsS): # Loop through short paired = False # For breaking this loop while runBreaks[bCount + 1] < sr: # Find runBreaks region bCount += 1 if bCount == len(runBreaks) - 2: break for lInd, lr in enumerate(runsL): # and through long #print sr,lr, gap, runBreaks[bCount],runBreaks[bCount+1] if abs( sr - lr ) < gap: # We're in possible range, let's now check other things # First, check if this is really the "best" pair if lInd != len(runsL) - 1: if runBreaks[bCount] <= runsL[lInd + 1] < runBreaks[ bCount + 1]: # Make sure we don't cross a break if abs(sr - runsL[lInd + 1]) < abs( sr - lr ): # We have another pair that's closer in range! continue elif abs(sr - runsL[lInd + 1]) == abs( sr - lr): # tiebreaker should be normalization. if abs(1.0 - float(nFS[sInd] / nFL[lInd])) > abs( 1.0 - float(nFS[sInd] / nFL[lInd + 1])): continue # I'll let this continue -- you could beat this if you auto-paired this here. if ( (runBreaks[bCount] <= sr < runBreaks[bCount + 1] and runBreaks[bCount] <= lr < runBreaks[bCount + 1] ) # check break regions and (corr < float(nFS[sInd] / nFL[lInd]) < 1.0 / corr) ): # Check that the normalization is roughly the same too # We're good! Now just calculate the lifetime lifetime = ltMeas(nCtsS[sInd], nCtsL[lInd], matTS[sInd], matTL[lInd]) lifetimeC = ltMeas_corr(nCtsS[sInd], nCtsL[lInd], matTS[sInd], matTL[lInd]) if lifetime.err < lifetime.val: # ignore giant errorbars (for plotting) lts.append(lifetime) # output vector ltsC.append(lifetimeC) runPair.append([sr, lr]) hTPair.append([hldTS[sInd], hldTL[lInd]]) # And remove these runs, since we've successfully paired them runsL.pop(lInd) nCtsL.pop(lInd) hldTL.pop(lInd) matTL.pop(lInd) nFL.pop(lInd) paired = True #For breaking out of the other loop break elif lr - sr > scMax: # If lr is scMax more than sr, we can assume lr is sorted and break break if paired: # If we found a long run for this short run, take this run out for the future! runsS.pop(sInd) nCtsS.pop(sInd) hldTS.pop(sInd) matTS.pop(sInd) nFS.pop(sInd) if len(lts) == 0: print("Something went wrong, no pairs created!") else: print("Using " + str(len(lts)) + " short-long pairs!") print(" First lifetime in list: " + str(lts[0].val) + " +/- " + str(lts[0].err)) return lts, runPair, hTPair, ltsC