def get_direction(self): """Function to calculate the fibre direction based on the fibre position and the determined beam center from the data Returns: dir_x (float) : x coordinate of fibre direction vector dir_y (float) : x coordinate of fibre direction vector dir_z (float) : x coordinate of fibre direction vector dir_error_x (float) : x coordinate uncertainty of fibre direction vector dir_error_x (float) : x coordinate uncertainty of fibre direction vector dir_error_x (float) : x coordinate uncertainty of fibre direction vector """ #get fibre position of the to be measured fibre val = fibre_handling.FibreHandling(self.f) sourcepos, sourcedir = val.get_fibre_position() #fill beam center vector with the x, y, z coordinates determined from the data beam_center = ROOT.TVector3() beam_center.SetXYZ(self.x, self.y, self.z) #determine fibre direction from beam center vector and fibre position direction = beam_center - sourcepos dir_x = direction.X() dir_y = direction.Y() dir_z = direction.Z() #calculate uncertainty on fibre direction from uncertainty on the beam center coordinates dir_error_x = math.sqrt( math.pow((math.sqrt( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2)) - math.pow(dir_x, 2) * math.pow( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2), -0.5)) * self.x_error / (math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2)), 2) + math.pow( dir_x * dir_y * math.pow( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2), -1.5) * self.y_error, 2) + math.pow( dir_x * dir_z * math.pow( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2), -1.5) * self.z_error, 2)) dir_error_y = math.sqrt( math.pow((math.sqrt( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2)) - math.pow(dir_y, 2) * math.pow( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2), -0.5)) * self.y_error / (math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2)), 2) + math.pow( dir_y * dir_x * math.pow( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2), -1.5) * self.x_error, 2) + math.pow( dir_y * dir_z * math.pow( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2), -1.5) * self.z_error, 2)) dir_error_z = math.sqrt( math.pow((math.sqrt( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2)) - math.pow(dir_z, 2) * math.pow( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2), -0.5)) * self.z_error / (math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2)), 2) + math.pow( dir_z * dir_x * math.pow( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2), -1.5) * self.x_error, 2) + math.pow( dir_z * dir_y * math.pow( math.pow(dir_x, 2) + math.pow(dir_y, 2) + math.pow(dir_z, 2), -1.5) * self.y_error, 2)) #normalise direction vector direction.SetMag(1.) dir_x = direction.X() dir_y = direction.Y() dir_z = direction.Z() #return direction coordinates and uncertainties return dir_x, dir_y, dir_z, dir_error_x, dir_error_y, dir_error_z
def generate_data_output(file_name, fibre, wl, ratio): """Function which runs over the EV branch of a RAT root file and applies the SMELLIE cut selection. Writes the number of hitd selection by each cut to an output file and saves histograms for each cut region to a root file. Can be used on MC simulations and SNO+ data. Args: file_name (string) : name of the input rat file fibre (string) : fibre label wl (string) : wavelength ratio (string) : string component to define which scattering length scaling factor the root file was produced with (in case of the simulation) """ reader = ROOT.RAT.DU.DSReader(file_name, True) #get fibre specific variabes val = fibre_handling.FibreHandling(fibre) val.cut_values() sourcepos, sourcedir = val.get_fibre_position() AV1_cross, AV2_cross, PSUP_cross, n_scint, n_water = val.get_crossing_points( float(wl)) #path lengths for direct beam scint_path = (AV2_cross - AV1_cross).Mag() water_path = (AV1_cross - sourcepos).Mag() + (PSUP_cross - AV2_cross).Mag() maxBeam, z_beam_min, z_beam_max, alpha_min, alpha_max, z_avout_min, z_avout_max, alpha_avin = val.spatialcuts[ 0], val.spatialcuts[1], val.spatialcuts[2], val.spatialcuts[ 3], val.spatialcuts[4], val.spatialcuts[5], val.spatialcuts[ 6], val.spatialcuts[7] tbeam, beam_tres, tAV1, t, tAV, tpsup, tmulti = val.timecuts[ 0], val.timecuts[1], val.timecuts[2], val.timecuts[3], val.timecuts[ 4], val.timecuts[5], val.timecuts[6] #define output root file outputroot = ROOT.TFile( "/data/langrock/rat-5.0-SMELLIE_analysis/" + str(fibre) + "/root/" + str(wl) + "_" + str(ratio) + "_data_water_c_mh.root", "recreate") #define output text file outputfile = open( "/data/langrock/rat-5.0-SMELLIE_analysis/" + str(fibre) + "/" + str(wl) + "_" + ratio + "_water.txt", "w") #get tools for data correction corrections = data_corrections.DataCorrections(reader) beam_center = corrections.fit_beam_time(sourcepos, sourcedir) pmtid = corrections.mh_corr() nevents = reader.GetEntryCount() #define histograms hist = define_histograms.DefineHistograms() #speed of light c = 300 #variables used to count photons in cut region beam = 0 double_refl = 0 avin = 0 avout = 0 scatt = 0 psup = 0 multi = 0 total = 0 pmt_prop = rat.utility().GetPMTInfo() LightPath = rat.utility().GetLightPathCalculator() groupVelTime = rat.utility().GetGroupVelocity() #start looping through file for ievent in range(0, nevents): ds, run = reader.GetEntry(ievent), reader.GetRun() #loop through events for iev in range(ds.GetEVCount()): ev = ds.GetEV(iev) hist.h_nhits.Fill(ev.GetNhits()) pmts = ev.GetCalPMTs() #run over pmts for ipmt in range(0, pmts.GetCount()): pmt_cal = pmts.GetPMT(ipmt) pmt_id = pmt_cal.GetID() #calculate multiple hits corrections P_occ = pmtid.GetBinContent(pmt_id) / nevents mu = 0 if P_occ == 1: mu = 0 else: mu = -math.log(1 - P_occ) c_mh = 1 + (mu - (1 - math.exp(-mu))) #get pmt position and direction with respect to fibre position pmtpos = pmt_prop.GetPosition(pmt_id) pmtdir = (pmtpos - sourcepos) #define spatial variables to cut on z = pmtpos.Z() theta = pmtpos.Theta() phi = pmtpos.Phi() alpha_mc_rad = math.acos( (sourcedir * pmtdir) / (sourcedir.Mag() * pmtdir.Mag())) alpha_mc = math.degrees(alpha_mc_rad) pmt_time = pmt_cal.GetTime() #calculate time it takes the photon in respective pmt to get there LightPath.CalcByPosition(sourcepos, pmtpos) PathTime = groupVelTime.CalcByDistance( LightPath.GetDistInScint(), LightPath.GetDistInAV(), LightPath.GetDistInWater()) time = pmt_time - PathTime #time for direct light to cross detector Beam_time = beam_center + (scint_path * n_scint + water_path * n_water) / c #AV1 reflection time off the outside of the AV AV_ref1_time = beam_center + ( (pmtpos - AV1_cross).Mag() + (AV1_cross - sourcepos).Mag()) * n_water / c #AV2 reflection time off the inside of the AV after crossing the detector AV_ref2_time = beam_center + ( ((pmtpos - AV2_cross).Mag() + (AV2_cross - sourcepos).Mag() - water_path) * n_scint + water_path * n_water) / c #PSUP reflection time PSUP_ref_time = beam_center + ( ((pmtpos - PSUP_cross).Mag() + scint_path - water_path) * n_scint + 2 * water_path * n_water) / c #count total number of hits detected and fill histograms, apply multiple hits correction total += 1 * c_mh hist.t_res.Fill(time - beam_center, c_mh) hist.angle_time.Fill(time - beam_center, alpha_mc) hist.z_time.Fill(time - beam_center, z) hist.theta_phi.Fill(phi, theta) hist.h_theta.Fill(theta, c_mh) hist.h_phi.Fill(phi, c_mh) ##### apply cuts, count photons and fill histograms for each each cut, including multiple hits correction #### #apply direct beam cuts if alpha_mc_rad <= ( maxBeam / 180. ) * math.pi and z < z_beam_max and z > z_beam_min and time < Beam_time + tbeam and ( pmt_time - PathTime - beam_center) <= beam_tres: beam += 1 * c_mh hist.t_res_beam.Fill(time - beam_center, c_mh) hist.angle_time_beam.Fill(time - beam_center, alpha_mc) hist.z_time_beam.Fill(time - beam_center, z) hist.theta_phi_beam.Fill(phi, theta) hist.h_theta_beam.Fill(theta, c_mh) hist.h_phi_beam.Fill(phi, c_mh) #apply late pulse cuts elif alpha_mc_rad <= ( maxBeam / 180. ) * math.pi and z < z_beam_max and z > z_beam_min and time < Beam_time + tbeam and ( pmt_time - PathTime - beam_center) > beam_tres and ( pmt_time - PathTime - beam_center) < 50: double_refl += 1 * c_mh hist.t_res_double.Fill(time - beam_center, c_mh) hist.angle_time_double.Fill(time - beam_center, alpha_mc) hist.z_time_double.Fill(time - beam_center, z) hist.theta_phi_double.Fill(phi, theta) hist.h_theta_double.Fill(theta, c_mh) hist.h_phi_double.Fill(phi, c_mh) else: #apply cuts on outer (1st) AV reflections if time < AV_ref1_time + tAV1 and alpha_mc_rad > ( alpha_min / 180.) * math.pi and alpha_mc_rad < ( alpha_max / 180.) * math.pi and ( pmt_time - PathTime - beam_center ) < t and z < z_avout_max and z > z_avout_min: avout += 1 * c_mh hist.t_res_avout.Fill(time - beam_center, c_mh) hist.angle_time_avout.Fill(time - beam_center, alpha_mc) hist.z_time_avout.Fill(time - beam_center, z) hist.theta_phi_avout.Fill(phi, theta) hist.h_theta_avout.Fill(theta, c_mh) hist.h_phi_avout.Fill(phi, c_mh) #apply cuts on scattered events elif time < AV_ref2_time - tAV: scatt += 1 * c_mh hist.t_res_scatt.Fill(time - beam_center, c_mh) hist.angle_time_scatt.Fill(time - beam_center, alpha_mc) hist.z_time_scatt.Fill(time - beam_center, z) hist.theta_phi_scatt.Fill(phi, theta) hist.h_theta_scatt.Fill(theta, c_mh) hist.h_phi_scatt.Fill(phi, c_mh) #apply cuts on inner (2nd) AV reflections elif time > AV_ref2_time - tAV and ( (time < PSUP_ref_time - tpsup and alpha_mc_rad > (alpha_avin / 180.) * math.pi and alpha_mc_rad < ((alpha_avin + 15) / 180.) * math.pi) or (time < PSUP_ref_time - tpsup + 10 and alpha_mc_rad > ((alpha_avin + 15) / 180.) * math.pi and alpha_mc_rad < ((alpha_avin + 20) / 180.) * math.pi) or (time < PSUP_ref_time - tpsup + 20 and alpha_mc_rad > ((alpha_avin + 20) / 180.) * math.pi and alpha_mc_rad < ((alpha_avin + 30) / 180.) * math.pi) or (time < PSUP_ref_time - tpsup + 25 and alpha_mc_rad > ((alpha_avin + 30) / 180.) * math.pi and alpha_mc_rad < ((alpha_avin + 40) / 180.) * math.pi) or (time < PSUP_ref_time - tpsup + 35 and alpha_mc_rad > ((alpha_avin + 40) / 180.) * math.pi and alpha_mc_rad < ((alpha_avin + 50) / 180.) * math.pi) or (time < PSUP_ref_time - tpsup + 40 and alpha_mc_rad > ((alpha_avin + 50) / 180.) * math.pi and alpha_mc_rad < ((alpha_avin + 60) / 180.) * math.pi) or (time < PSUP_ref_time - tpsup + 45 and alpha_mc_rad > ((alpha_avin + 60) / 180.) * math.pi)): avin += 1 * c_mh hist.t_res_avin.Fill(time - beam_center, c_mh) hist.angle_time_avin.Fill(time - beam_center, alpha_mc) hist.z_time_avin.Fill(time - beam_center, z) hist.theta_phi_avin.Fill(phi, theta) hist.h_theta_avin.Fill(theta, c_mh) hist.h_phi_avin.Fill(phi, c_mh) #apply cuts on PSUP reflections elif time > AV_ref2_time - tAV and time < PSUP_ref_time + tmulti: psup += 1 * c_mh hist.t_res_psup.Fill(time - beam_center, c_mh) hist.angle_time_psup.Fill(time - beam_center, alpha_mc) hist.z_time_psup.Fill(time - beam_center, z) hist.theta_phi_psup.Fill(phi, theta) hist.h_theta_psup.Fill(theta, c_mh) hist.h_phi_psup.Fill(phi, c_mh) #apply cuts on multiple effects elif time > PSUP_ref_time + tmulti: multi += 1 * c_mh hist.t_res_multi.Fill(time - beam_center, c_mh) hist.angle_time_multi.Fill(time - beam_center, alpha_mc) hist.z_time_multi.Fill(time - beam_center, z) hist.theta_phi_multi.Fill(phi, theta) hist.h_theta_multi.Fill(theta, c_mh) hist.h_phi_multi.Fill(phi, c_mh) #save histograms to root file outputroot.Write() outputroot.Close() #calculate poissonian uncertainty on all cut region counts total_error = math.sqrt(float(total)) scatt_error = math.sqrt(float(scatt)) beam_error = math.sqrt(float(beam)) double_refl_error = math.sqrt(float(double_refl)) avin_error = math.sqrt(float(avin)) avout_error = math.sqrt(float(avout)) psup_error = math.sqrt(float(psup)) multi_error = math.sqrt(float(multi)) #calculate the ratio of scattered/in-beam events to the total number of events and the uncertainty on the ratio ratio_scatt = float(scatt) / float(total) ratio_scatt_error = math.sqrt( math.pow(scatt_error / float(total), 2) + math.pow(float(scatt) * total_error / math.pow(float(total), 2), 2)) ratio_beam = float(beam) / float(total) ratio_beam_error = math.sqrt( math.pow(beam_error / float(total), 2) + math.pow(float(beam) * total_error / math.pow(float(total), 2), 2)) #save all values to a txt file outputfile.write(wl) outputfile.write('\t') outputfile.write(ratio.replace('p', '.')) outputfile.write('\t scattering ratio: ') outputfile.write(str(ratio_scatt)) outputfile.write('\t +/- ') outputfile.write(str(ratio_scatt_error)) outputfile.write('\t beam ratio: ') outputfile.write(str(ratio_beam)) outputfile.write('\t +/- ') outputfile.write(str(ratio_beam_error)) outputfile.write('\n \n \n \n') outputfile.write("total: " + str(total) + " +/-" + str(total_error) + "\n") outputfile.write("beam: " + str(beam) + " +/-" + str(beam_error) + "\n") outputfile.write("double_refl: " + str(double_refl) + " +/-" + str(double_refl_error) + "\n") outputfile.write("avin: " + str(avin) + " +/-" + str(avin_error) + "\n") outputfile.write("avout: " + str(avout) + " +/-" + str(avout_error) + "\n") outputfile.write("scatt: " + str(scatt) + " +/-" + str(scatt_error) + "\n") outputfile.write("psup: " + str(psup) + " +/-" + str(psup_error) + "\n") outputfile.write("multi: " + str(multi) + " +/-" + str(multi_error) + "\n") outputfile.close()
def find_noise(file_name, fibre, wl, ratio): """Function which runs over the MC branch of a RAT root file and applies the SMELLIE cut selection to all photons which originate from PMT noise. Writes the number of photons selected by each cut to an output file and saves histograms for each cut region to a root file. Can only be used on MC simulations. Args: file_name (string) : name of the input rat file fibre (string) : fibre label wl (string) : wavelength ratio (string) : string component to define which scattering length scaling factor the root file was produced with """ reader = ROOT.RAT.DU.DSReader(file_name,True) #get fibre specific variables val = fibre_handling.FibreHandling(fibre) val.cut_values() sourcepos, sourcedir = val.get_fibre_position() AV1_cross, AV2_cross, PSUP_cross, n_scint, n_water = val.get_crossing_points(float(wl)) #path lengths for direct beam scint_path = (AV2_cross - AV1_cross).Mag() water_path = (AV1_cross - sourcepos).Mag() + (PSUP_cross - AV2_cross).Mag() #get cut values maxBeam, z_beam_min, z_beam_max, alpha_min, alpha_max, z_avout_min, z_avout_max, alpha_avin = val.spatialcuts[0], val.spatialcuts[1], val.spatialcuts[2], val.spatialcuts[3], val.spatialcuts[4], val.spatialcuts[5], val.spatialcuts[6], val.spatialcuts[7] tbeam, beam_tres, tAV1, t, tAV, tpsup, tmulti = val.timecuts[0], val.timecuts[1], val.timecuts[2], val.timecuts[3], val.timecuts[4], val.timecuts[5], val.timecuts[6] #define output root file outputroot = ROOT.TFile("/data/langrock/rat-5.0-SMELLIE_analysis/" + str(fibre) + "/root/" + str(wl) + "_" + ratio + "_noise.root","recreate") #define output text file outputfile = open("/data/langrock/rat-5.0-SMELLIE_analysis/" + str(fibre) + "/" + str(wl) + "_" + ratio + "_noise.txt","w") #define histograms hist = define_histograms.DefineHistograms() #speed of light c = 300 #variables used to count photons in cut region beam = 0 avin = 0 avout = 0 scatt = 0 psup = 0 multi = 0 total = 0 double_refl = 0 pmt_prop = rat.utility().GetPMTInfo() LightPath = rat.utility().GetLightPathCalculator() groupVelTime = rat.utility().GetGroupVelocity() #start looping through file for ievent in range(0,reader.GetEntryCount()): ds, run = reader.GetEntry(ievent), reader.GetRun() mc = ds.GetMC() #run over pmts for ipmt in range(mc.GetMCPMTCount()): pmt_id = mc.GetMCPMT(ipmt).GetID() #get pmt position and direction with respect to fibre position pmtpos = pmt_prop.GetPosition(pmt_id) pmtdir = (pmtpos - sourcepos) #define spatial variables to cut on z = pmtpos.Z() theta = pmtpos.Theta() phi = pmtpos.Phi() alpha_mc_rad = math.acos((sourcedir * pmtdir)/(sourcedir.Mag() * pmtdir.Mag())) alpha_mc = math.degrees(alpha_mc_rad) #calculate time it takes the photon in respective pmt to get there LightPath.CalcByPosition(sourcepos,pmtpos) PathTime = groupVelTime.CalcByDistance(LightPath.GetDistInScint(),LightPath.GetDistInAV(),LightPath.GetDistInWater()) #time for direct light to cross detector Beam_time = (scint_path*n_scint + water_path*n_water)/c #AV1 reflection time off the outside of the AV AV_ref1_time = ((pmtpos - AV1_cross).Mag() + (AV1_cross - sourcepos).Mag()) * n_water /c #AV2 reflection time off the inside of the AV after crossing the detector AV_ref2_time = (((pmtpos - AV2_cross).Mag() + (AV2_cross - sourcepos).Mag() - water_path)*n_scint + water_path*n_water) /c #PSUP reflection time PSUP_ref_time = (((pmtpos - PSUP_cross).Mag() + scint_path - water_path)*n_scint + 2*water_path*n_water) /c #loop through photons in PMT mc_pmt = mc.GetMCPMT(ipmt) for photon in range(mc_pmt.GetMCPECount()): mc_photon = mc_pmt.GetMCPE(photon) pmt_time = mc_photon.GetCreationTime() time = pmt_time - PathTime #if photon is a noise hit, apply cuts, count photons and fill histograms for each each cut if mc_photon.GetNoise(): #count total number of photons detected and fill histograms total += 1 hist.t_res.Fill(time) hist.angle_time.Fill(time,alpha_mc) hist.z_time.Fill(time,z) hist.theta_phi.Fill(phi,theta) hist.h_theta.Fill(theta) hist.h_phi.Fill(phi) #apply direct beam cuts if alpha_mc_rad<=(maxBeam/180.)*math.pi and z < z_beam_max and z > z_beam_min and time < Beam_time+tbeam and (pmt_time - PathTime) < beam_tres: beam += 1 hist.t_res_beam.Fill(time) hist.angle_time_beam.Fill(time,alpha_mc) hist.z_time_beam.Fill(time,z) hist.theta_phi_beam.Fill(phi,theta) hist.h_theta_beam.Fill(theta) hist.h_phi_beam.Fill(phi) #apply late pulse cuts elif alpha_mc_rad<=(maxBeam/180.)*math.pi and z < z_beam_max and z > z_beam_min and time < Beam_time+tbeam and (pmt_time - PathTime) > beam_tres and (pmt_time - PathTime) < 50: double_refl += 1 hist.t_res_double.Fill(time) hist.angle_time_double.Fill(time,alpha_mc) hist.z_time_double.Fill(time,z) hist.theta_phi_double.Fill(phi,theta) hist.h_theta_double.Fill(theta) hist.h_phi_double.Fill(phi) else: #apply cuts on outer (1st) AV reflections if time < AV_ref1_time+tAV1 and alpha_mc_rad > (alpha_min/180.)*math.pi and alpha_mc_rad < (alpha_max/180.)*math.pi and (pmt_time - PathTime) < t and z < z_avout_max and z > z_avout_min: avout += 1 hist.t_res_avout.Fill(time) hist.angle_time_avout.Fill(time,alpha_mc) hist.z_time_avout.Fill(time,z) hist.theta_phi_avout.Fill(phi,theta) hist.h_theta_avout.Fill(theta) hist.h_phi_avout.Fill(phi) #apply cuts on scattered events elif time < AV_ref2_time-tAV: scatt += 1 hist.t_res_scatt.Fill(time) hist.angle_time_scatt.Fill(time,alpha_mc) hist.z_time_scatt.Fill(time,z) hist.theta_phi_scatt.Fill(phi,theta) hist.h_theta_scatt.Fill(theta) hist.h_phi_scatt.Fill(phi) #apply cuts on inner (2nd) AV reflections elif time > AV_ref2_time-tAV and ((time < PSUP_ref_time-tpsup and alpha_mc_rad > (alpha_avin/180.)*math.pi and alpha_mc_rad < ((alpha_avin+15)/180.)*math.pi) or (time < PSUP_ref_time-tpsup+10 and alpha_mc_rad > ((alpha_avin+15)/180.)*math.pi and alpha_mc_rad < ((alpha_avin+20)/180.)*math.pi) or (time < PSUP_ref_time-tpsup+20 and alpha_mc_rad > ((alpha_avin+20)/180.)*math.pi and alpha_mc_rad < ((alpha_avin+30)/180.)*math.pi) or (time < PSUP_ref_time-tpsup+25 and alpha_mc_rad > ((alpha_avin+30)/180.)*math.pi and alpha_mc_rad < ((alpha_avin+40)/180.)*math.pi) or (time < PSUP_ref_time-tpsup+35 and alpha_mc_rad > ((alpha_avin+40)/180.)*math.pi and alpha_mc_rad < ((alpha_avin+50)/180.)*math.pi) or (time < PSUP_ref_time-tpsup+40 and alpha_mc_rad > ((alpha_avin+50)/180.)*math.pi and alpha_mc_rad < ((alpha_avin+60)/180.)*math.pi) or (time < PSUP_ref_time-tpsup+45 and alpha_mc_rad > ((alpha_avin+60)/180.)*math.pi)): avin += 1 hist.t_res_avin.Fill(time) hist.angle_time_avin.Fill(time,alpha_mc) hist.z_time_avin.Fill(time,z) hist.theta_phi_avin.Fill(phi,theta) hist.h_theta_avin.Fill(theta) hist.h_phi_avin.Fill(phi) #apply cuts on PSUP reflections elif time > AV_ref2_time-tAV and time < PSUP_ref_time+tmulti: psup += 1 hist.t_res_psup.Fill(time) hist.angle_time_psup.Fill(time,alpha_mc) hist.z_time_psup.Fill(time,z) hist.theta_phi_psup.Fill(phi,theta) hist.h_theta_psup.Fill(theta) hist.h_phi_psup.Fill(phi) #apply cuts on multiple effects elif time > PSUP_ref_time+tmulti: multi += 1 hist.t_res_multi.Fill(time) hist.angle_time_multi.Fill(time,alpha_mc) hist.z_time_multi.Fill(time,z) hist.theta_phi_multi.Fill(phi,theta) hist.h_theta_multi.Fill(theta) hist.h_phi_multi.Fill(phi) #save histograms to root file outputroot.Write() outputroot.Close() #save all values to a text file outputfile.write("total: " + str(total) + "\n") outputfile.write("beam: " + str(beam) + "\n") outputfile.write("double_refl: " + str(double_refl) + "\n") outputfile.write("avin: " + str(avin) + "\n") outputfile.write("avout: " + str(avout) + "\n") outputfile.write("scatt: " + str(scatt) + "\n") outputfile.write("psup: " + str(psup) + "\n") outputfile.write("multi: " + str(multi) + "\n") outputfile.close()
def get_water_profiles(file_name, fibre, n): """Function which runs over the EV branch of a RAT root file to extract the angular beam profile. It fills angular histograms with variable bin width determined by the number of PMTs n covered by the angular bin. The histogram to be extracted from air-fill data are converted to a water-fill profile for analysis purposes. Args: file_name (string) : name of the input rat file fibre (string) : fibre label n (int) : number of PMTs to be covered by each angular bin Returns: a histogram normalised by the number of working PMTs per bin """ reader = ROOT.RAT.DU.DSReader(file_name, False) #get fibre specific variables val = fibre_handling.FibreHandling(fibre) sourcepos, sourcedir = val.get_fibre_position() pmt_prop = rat.utility().GetPMTInfo() #get bins of the angular histogram to be filled dependent on the number of PMTs n to be covered by each bin angle = angle_measurement.AngleMeasurement() angle.get_number_of_pmts(n) angle.create_pmt_angle_map(sourcepos, sourcedir) angle.get_bin_edges() #get tools for data correction corrections = data_corrections.DataCorrections(reader) pmtid = corrections.mh_corr() nevents = reader.GetEntryCount() #define angular histograms h_angle = ROOT.TH1D("h_angle", "", angle.nbins, angle.bin_edges) h_angle_pmt = ROOT.TH2D("h_angle_pmt", "", 1000, 0, 10000, angle.nbins, angle.bin_edges) #start looping through file for ievent in range(0, nevents): ds = reader.GetEntry(ievent) #loop through events for iev in range(ds.GetEVCount()): ev = ds.GetEV(iev) #run over PMTs pmts = ev.GetCalPMTs() for ipmt in range(0, pmts.GetCount()): pmt_cal = pmts.GetPMT(ipmt) pmt_id = pmt_cal.GetID() #calculate multiple hits corrections P_occ = pmtid.GetBinContent(pmt_id) / nevents mu = 0 if P_occ == 1: mu = 0 else: mu = -math.log(1 - P_occ) c_mh = 1 + (mu - (1 - math.exp(-mu))) #get pmt position and direction with respect to fibre position pmtpos = pmt_prop.GetPosition(pmt_id) pmtdir = (pmtpos - sourcepos) #calculate angle with respect to the fibre direction alpha_mc_rad = math.acos( (sourcedir * pmtdir) / (sourcedir.Mag() * pmtdir.Mag())) alpha_mc = math.degrees(alpha_mc_rad) #refractive indices of all involved materials n_quartz = 1.46 n_air = 1.0003 n_water = 1.34 #snell's law - calculate incident angle alpha_quartz from air-fill angle and then use alpha_quartz to calculate the water-fill angle alpha_water alpha_quartz = math.asin( math.sin(alpha_mc_rad) * n_air / n_quartz) alpha_water = math.degrees( math.asin(math.sin(alpha_quartz) * n_quartz / n_water)) #fill histograms h_angle.Fill(alpha_water, c_mh) h_angle_pmt.Fill(pmt_id, alpha_water) #normalise angular histogram by number of working PMTs per bin and return return angle.normalise_bins(h_angle_pmt, h_angle)