def from_film(position=(0,0,0), axis1=(0,0,1), axis2=(1,0,0), size=(800,600), width=35.0, focal_length=18.0): """Project rays from a piece of film whose focal point is located at `position`. `axis1` and `axis2` specify the vectors pointing along the length and height of the film respectively. """ height = width*(size[1]/float(size[0])) axis1 = normalize(axis1) axis2 = normalize(axis2) dx0 = width/size[0] dx1 = height/size[1] # for i in range(size[0]): # for j in range(size[1]): # grid[i*size[1]+j] = axis1*dx1*j - axis2*dx0*i x = np.arange(size[0]) y = np.arange(size[1]) yy, xx = np.meshgrid(y,x) n = size[0]*size[1] grid = -np.tile(axis2, (n,1))*xx.ravel()[:,np.newaxis]*dx0 + \ np.tile(axis1, (n,1))*yy.ravel()[:,np.newaxis]*dx1 grid += axis2*width/2 - axis1*height/2 grid -= np.cross(axis1,axis2)*focal_length return np.tile(position,(n,1)), normalize(-grid)
def rot_axis(norm, r_norm): if not np.array_equal(norm, r_norm): norm = np.broadcast_to(norm, r_norm.shape) norm = normalize(norm) r_norm = normalize(r_norm) axis = normalize(np.cross(norm, r_norm)) phi = np.arccos(np.einsum('ij,ij->i', norm, r_norm)) return phi, axis
def propagate(gpu_detector, number=10, nphotons=500000, nthreads_per_block=64, max_blocks=1024): "Returns the average number of photons propagated on the GPU per second." rng_states = gpu.get_rng_states(nthreads_per_block * max_blocks) run_times = [] for i in tools.progress(list(range(number))): pos = np.zeros((nphotons, 3)) dir = sample.uniform_sphere(nphotons) reorder = tools.argsort_direction(dir) dir = dir[reorder] pol = normalize(np.cross(sample.uniform_sphere(nphotons), dir)) wavelengths = np.random.uniform(400, 800, size=nphotons) photons = event.Photons(pos, dir, pol, wavelengths) gpu_photons = gpu.GPUPhotons(photons) t0 = time.time() gpu_photons.propagate(gpu_detector, rng_states, nthreads_per_block, max_blocks) cuda.Context.get_current().synchronize() elapsed = time.time() - t0 if i > 0: # first kernel call incurs some driver overhead run_times.append(elapsed) return nphotons / ufloat((np.mean(run_times), np.std(run_times)))
def test_rotate(): n = nthreads_per_block * blocks a = np.random.rand(n, 3).astype(np.float32) t = np.random.rand(n).astype(np.float32) * 2 * np.pi w = normalize(np.random.rand(3)) a_gpu = ga.to_gpu(to_float3(a)) t_gpu = ga.to_gpu(t) dest_gpu = ga.empty(n, dtype=ga.vec.float3) t0 = time.time() rotate_gpu(a_gpu, t_gpu, ga.vec.make_float3(*w), dest_gpu, block=(nthreads_per_block, 1, 1), grid=(blocks, 1)) autoinit.context.synchronize() elapsed = time.time() - t0 print('elapsed %f sec' % elapsed) r = rotate(a, t, w) assert np.allclose(r, dest_gpu.get().view(np.float32).reshape((-1, 3)), atol=1e-5)
def get_curved_surf_triangle_centers(vtx, rad, detector_r=1.0, focal_length=1.0, nsteps=10, b_pxl=4): #Changed the rotation matrix to try and keep the curved surface towards the interior #Make sure diameter, etc. are set properly curved_surf_triangle_centers = [] mesh_surf, ring = curved_surface2(detector_r, diameter=2 * rad, nsteps=nsteps, base_pxl=b_pxl, ret_arr=True) initial_curved_surf = mh.rotate( mesh_surf, make_rotation_matrix(-np.pi / 2, (1, 0, 0))) #-np.pi with curved_surface2 triangles_per_surface = initial_curved_surf.triangles.shape[0] phi, axs = rot_axis([0, 0, 1], vtx) for vx, ph, ax in zip(vtx, -phi, axs): curved_surf_triangle_centers.extend( mh.shift( mh.rotate(initial_curved_surf, make_rotation_matrix(ph, ax)), -normalize(vx) * (np.linalg.norm(vx) + focal_length)).get_triangle_centers()) return np.asarray( curved_surf_triangle_centers), triangles_per_surface, ring
def detector(pmt_radius=14000.0, sphere_radius=14500.0, spiral_step=350.0): pmt = build_8inch_pmt_with_lc() geo = Detector(water) geo.add_solid(Solid(sphere(sphere_radius,nsteps=200), water, water, surface=black_surface, color=0xBBFFFFFF)) for position in spherical_spiral(pmt_radius, spiral_step): direction = -normalize(position) # Orient PMT that starts facing Y axis y_axis = np.array((0.0,1.0,0.0)) axis = np.cross(direction, y_axis) angle = np.arccos(np.dot(y_axis, direction)) rotation = make_rotation_matrix(angle, axis) # Place PMT (note that position is front face of PMT) geo.add_pmt(pmt, rotation, position) time_rms = 1.5 # ns charge_mean = 1.0 charge_rms = 0.1 # Don't I wish! geo.set_time_dist_gaussian(time_rms, -5 * time_rms, 5*time_rms) geo.set_charge_dist_gaussian(charge_mean, charge_rms, 0.0, charge_mean + 5*charge_rms) logger.info('Demo detector: %d PMTs' % geo.num_channels()) logger.info(' %1.1f ns time RMS' % time_rms) logger.info(' %1.1f%% charge RMS' % (100.0*charge_rms/charge_mean)) return geo
def from_film(position=(0, 0, 0), axis1=(0, 0, 1), axis2=(1, 0, 0), size=(800, 600), width=35.0, focal_length=18.0): """Project rays from a piece of film whose focal point is located at `position`. `axis1` and `axis2` specify the vectors pointing along the length and height of the film respectively. """ height = width * (size[1] / float(size[0])) axis1 = normalize(axis1) axis2 = normalize(axis2) dx0 = width / size[0] dx1 = height / size[1] # for i in range(size[0]): # for j in range(size[1]): # grid[i*size[1]+j] = axis1*dx1*j - axis2*dx0*i x = np.arange(size[0]) y = np.arange(size[1]) yy, xx = np.meshgrid(y, x) n = size[0] * size[1] grid = -np.tile(axis2, (n,1))*xx.ravel()[:,np.newaxis]*dx0 + \ np.tile(axis1, (n,1))*yy.ravel()[:,np.newaxis]*dx1 grid += axis2 * width / 2 - axis1 * height / 2 grid -= np.cross(axis1, axis2) * focal_length return np.tile(position, (n, 1)), normalize(-grid)
def _find_photons_for_pmt(self, photons_beg_pos, photons_end_pos, detected, end_direction_array, n_det, max_storage): beginning_photons = photons_beg_pos[ detected] # Include reflected photons ending_photons = photons_end_pos[detected] length = len(ending_photons) pmt_b = self.find_pmt_bin_array( ending_photons) # This line is now duplicative end_point = self.lens_centers[pmt_b / self.n_pmts_per_surf] end_dir = normalize(end_point - beginning_photons) if n_det + length > max_storage: logger.critical( "Too many photons to store in memory; not reading any further events." ) return None end_direction_array[n_det:(n_det + length), :] = end_dir return ending_photons, length
def load_photons(number=100, nphotons=500000): """Returns the average number of photons moved to the GPU device memory per second.""" pos = np.zeros((nphotons, 3)) dir = sample.uniform_sphere(nphotons) pol = normalize(np.cross(sample.uniform_sphere(nphotons), dir)) wavelengths = np.random.uniform(400, 800, size=nphotons) photons = event.Photons(pos, dir, pol, wavelengths) run_times = [] for i in tools.progress(list(range(number))): t0 = time.time() gpu_photons = gpu.GPUPhotons(photons) cuda.Context.get_current().synchronize() elapsed = time.time() - t0 if i > 0: # first kernel call incurs some driver overhead run_times.append(elapsed) return nphotons / ufloat((np.mean(run_times), np.std(run_times)))
def build_curvedsurface_icosahedron(kabamland, vtx, rad, diameter_ratio, focal_length=1.0, detector_r=1.0, nsteps=10, b_pxl=4): initial_curved_surf = mh.rotate( curved_surface2(detector_r, diameter=rad * 2, nsteps=nsteps, base_pxl=b_pxl), make_rotation_matrix(-np.pi / 2, (1, 0, 0))) face = Solid(initial_curved_surf, kabamland.detector_material, kabamland.detector_material, lm.fulldetect, 0x0000FF) phi, axs = rot_axis([0, 0, 1], vtx) for vx, ph, ax in zip(vtx, -phi, axs): kabamland.add_solid(face, rotation=make_rotation_matrix(ph, ax), displacement=-normalize(vx) * (np.linalg.norm(vx) + focal_length))
def build_lens_icosahedron(kabamland, vtx, rad, diameter_ratio, thickness_ratio, half_EPD, blockers=True, blocker_thickness_ratio=1.0 / 1000, light_confinement=False, focal_length=1.0, lens_system_name=None): """input edge length of icosahedron 'edge_length', the number of small triangles in the base of each face 'base', the ratio of the diameter of each lens to the maximum diameter possible 'diameter_ratio' (or the fraction of the default such ratio, if a curved detector lens system), the ratio of the thickness of the lens to the chosen (not maximum) diameter 'thickness_ratio', the radius of the blocking entrance pupil 'half_EPD', and the ratio of the thickness of the blockers to that of the lenses 'blocker_thickness_ratio' to return the icosahedron of lenses in kabamland. Light_confinment=True adds cylindrical shells behind each lens that absorb all the light that touches them, so that light doesn't overlap between lenses. If lens_system_name is a string that matches one of the lens systems in lenssystem.py, the corresponding lenses and detectors will be built. Otherwise, a default simple lens will be built, with parameters hard-coded below. """ # Get the list of lens meshes from the appropriate lens system as well as the lens material''' scale_rad = rad * diameter_ratio #max_radius->rad of the lens assembly lenses = lenssystem.get_lens_mesh_list(lens_system_name, scale_rad) lensmat = lenssystem.get_lens_material(lens_system_name) face = None for lns in lenses: #lns = mh.rotate(lns,make_rotation_matrix(ph,ax)) if not face: face = Solid(lns, lensmat, kabamland.detector_material) else: face += Solid(lns, lensmat, kabamland.detector_material) if light_confinement: shield = mh.rotate( cylindrical_shell(rad * (1 - 0.001), rad, focal_length, 32), make_rotation_matrix(np.pi / 2.0, (1, 0, 0))) baffle = Solid(shield, lensmat, kabamland.detector_material, black_surface, 0xff0000) if blockers: blocker_thickness = 2 * rad * blocker_thickness_ratio if half_EPD < rad: c1 = lenssystem.get_lens_sys( lens_system_name).c1 * lenssystem.get_scale_factor( lens_system_name, scale_rad) offset = [0, 0, c1 - np.sqrt(c1 * c1 - rad * rad)] anulus_blocker = mh.shift( mh.rotate( cylindrical_shell(half_EPD, rad, blocker_thickness, 32), make_rotation_matrix(np.pi / 2.0, (1, 0, 0))), offset) face += Solid(anulus_blocker, lensmat, kabamland.detector_material, black_surface, 0xff0000) phi, axs = rot_axis([0, 0, 1], vtx) for vx, ph, ax in zip(vtx, -phi, axs): kabamland.add_solid(face, rotation=make_rotation_matrix(ph, ax), displacement=-vx) if light_confinement: kabamland.add_solid(baffle, rotation=make_rotation_matrix(ph, ax), displacement=-normalize(vx) * (np.linalg.norm(vx) + focal_length / 2.0))
def build_perfect_resolution_direction_list(self, simname, filename): # creates a list of average ending direction per detectorbin per pmtbin. Each pmtbin will have an array of detectorbins with an average ending direction of photons eminating from each one for each one. Simulation must just be the pmticosohedron. Make sure that the focal length is the same for the simulation as it is in this file at the top. reader = ShortRootReader(simname) detectorbins = self.detectorxbins * self.detectorybins * self.detectorzbins calc6x = self.detectorxbins / (2 * self.inscribed_radius) calc6y = self.detectorybins / (2 * self.inscribed_radius) calc6z = self.detectorzbins / (2 * self.inscribed_radius) calc7x = self.detectorxbins / 2.0 calc7y = self.detectorybins / 2.0 calc7z = self.detectorzbins / 2.0 culprit_count = 0 loops = 0 full_length = 0 for ev in reader: detected = (ev.photons_end.flags & (0x1 << 2)).astype(bool) beginning_photons = ev.photons_beg.pos[detected] ending_photons = ev.photons_end.pos[detected] end_direction_array = normalize(ending_photons - beginning_photons) length = np.shape(ending_photons)[0] full_length += length #creating an array of pmt bins for the ending_photons pmt_bin_array = self.find_pmt_bin_array(ending_photons) # creating arrays for the detector bins of each photon. xinitbin_array = np.floor(calc6x * beginning_photons[:, 0] + calc7x).astype(int) yinitbin_array = np.floor(calc6y * beginning_photons[:, 1] + calc7y).astype(int) zinitbin_array = np.floor(calc6z * beginning_photons[:, 2] + calc7z).astype(int) # creating a single bin for each detectorbin. detector_bin_array = xinitbin_array + yinitbin_array * self.detectorxbins + zinitbin_array * self.detectorxbins * self.detectorybins if loops == 0: full_end_direction_array = end_direction_array full_pmt_bin_array = pmt_bin_array full_detector_bin_array = detector_bin_array else: full_end_direction_array = np.append(full_end_direction_array, end_direction_array) full_pmt_bin_array = np.append(full_pmt_bin_array, pmt_bin_array) full_detector_bin_array = np.append(full_detector_bin_array, detector_bin_array) loops += 1 if loops == 50: break print loops full_end_direction_array = np.reshape(full_end_direction_array, (full_length, 3)) print 'number of hits: ' + str(full_length) detector_dir_list = [[] for i in range(self.npmt_bins)] #for each of the entries in detector_dir_list we want an array of length detectorbins where in each slot of each array we have the average ending direction corresponding to that detector (for photons from that detector going to the pmt cooresponding to the entry index of the whole list.) This makes an array of shape: (detxbins*detybins*detzbins, 3). for i in range(self.npmt_bins): if i % 10000 == 0: print str(i) + ' out of ' + str(self.npmt_bins) pmt_indices = np.where(full_pmt_bin_array == i)[0] if np.shape(pmt_indices)[0] == 0: culprit_count += 1 continue detectorbins_for_pmt = full_detector_bin_array[pmt_indices] average_direction_array = -5 * np.ones( (detectorbins, 3)).astype(np.float32) for j in range(detectorbins): detector_indices = np.where(detectorbins_for_pmt == j)[0] if np.shape(detector_indices)[0] == 0: continue direction_indices = pmt_indices[detector_indices] ending_directions = full_end_direction_array[direction_indices] average_direction_array[j] = np.mean(ending_directions, axis=0) detector_dir_list[i] = average_direction_array print 'culprit_count: ' + str(culprit_count) writer = AngleRootWriter(filename) for i in range(self.npmt_bins): writer.write_PMT(detector_dir_list[i], i, self.detectorxbins, self.detectorybins, self.detectorzbins) #print writer.T.GetEntries() writer.close() return detector_dir_list
def angles_response(self, config, simname, nolens=False, rmax_frac=1.0): # takes a simulation file and creates an array of angles that photons hit the pmts at. # (replace lenses with disk pmts for the simulation to see what angles light hits the lenses at. # Light needs to land on an icosahedron face plane so use disks instead of just changing the surface of the lens to detecting.) # ev.photons_end.dir[detected] is always 0s as of now because we aren't saving directions in event or simulation files. #If nolens is True, assumes a "perfectres" type detector, with no lenses instead of lenses replaced with PMTs. #Restricts starting photons to be w/in rmax_frac*inscribed_radius of the center. reader = ShortRootReader(simname) total_angles = np.zeros(0) loops = 0 for ev in reader: detected = (ev.photons_end.flags & (0x1 << 2)).astype(bool) # Check which photons start w/in r_max of center r_max = rmax_frac * self.inscribed_radius r0 = np.linalg.norm(ev.photons_beg.pos, axis=1) #print r0 start_in_bounds = r0 < r_max #print start_in_bounds use_photon = np.logical_and(detected, start_in_bounds) beginning_photons = ev.photons_beg.pos[use_photon] ending_photons = ev.photons_end.pos[use_photon] transpose_pos_array = np.transpose(ending_photons) length = np.shape(ending_photons)[0] facebin_array = -np.ones(length).astype(int) # finding which LENS face each position belongs to by seeing which inverse rotation and displacement brings the position closest to z = 0. Note this is different than finding the PMT face as in find_pmt_bin_array. # Will find the PMT face if nolens is True for k in range(20): if nolens: initial_position_array = np.transpose( np.dot(self.inverse_rotation_matrices[k], transpose_pos_array) ) - self.inverse_rotated_displacement_matrix[k] else: initial_position_array = np.transpose( np.dot(self.inverse_rotation_matrices[k], transpose_pos_array) ) - self.lens_inverse_rotated_displacement_matrix[k] wherezeros = (initial_position_array[:, 2] < 1e-5) & (initial_position_array[:, 2] > -1e-5) np.place(facebin_array, wherezeros, k) #print facebin_array #finding the angles between each direction and facecoord (facecoords[k] representing the optical axis of every lens on the kth face.) directions = normalize(ending_photons - beginning_photons) face_directions = normalize(self.facecoords) angles = -np.ones(length) for i in range(length): face = facebin_array[i] if face == -1: continue angles[i] = np.arccos( np.dot(directions[i], face_directions[face])) if total_angles == []: total_angles = angles else: total_angles = np.append(total_angles, angles) loops += 1 if np.mod(loops, 10) == 0: print 'loop: ' + str(loops) if loops == 100: break #sorting from lowest to highest and removing any -1s. total_angles = np.sort(total_angles) first_good = 0 for i in range(np.shape(total_angles)[0]): if total_angles[i] == -1: continue else: first_good = i break total_angles = total_angles[first_good:] def choose_values(values, num): #choose num amount of points chosen evenly through the array values- not including endpoints. In essence the particular method used here creates num bins and then chooses the value at the center of each bin, rounding down if it lands between two values. length = np.shape(values)[0] half_bin_size = (length - 1.0) / (2.0 * num) odd_numbers = np.linspace(1, 2 * num - 1, num) indices = (odd_numbers * half_bin_size).astype(int) chosen_values = np.take(values, indices) return chosen_values my_values = choose_values(total_angles, 6) print 'length: ' + str(np.shape(total_angles)[0]) print 'first_good: ' + str(first_good) print 'total_angles: ' + str(total_angles) print 'chosen_values: ' + str(my_values) print 'chosen_values in degrees: ' + str(np.degrees(my_values)) fig = plt.figure(figsize=(7.8, 6)) plt.hist(total_angles, bins=100) plt.xlabel('Angles') plt.ylabel('Amount') plt.title('Angles Response Histogram for ' + config.config_name) plt.show() return total_angles
def build_displacement_matrix(self): displacement_matrix = np.empty((20, 3)) for k in range(20): displacement_matrix[k] = self.facecoords[ k] + self.focal_length * normalize(self.facecoords[k]) return displacement_matrix
def calibrate_old(self, simname, nevents=-1): # Use with a simulation file 'simname' to calibrate the detector # Creates a list of mean angles and their uncertainties (sigma for # a cone of unit length), one for each PMT # There are 1000 events in a typical simulation. # Older method - estimates variance for each PMT one event at a time from ShortIO.root_short import ShortRootReader self.is_calibrated = True reader = ShortRootReader(simname) culprit_count = 0 loops = 0 full_length = 0 if nevents < 1: nevents = len(reader) total_means = np.zeros((nevents, self.npmt_bins, 3), dtype=np.float32) total_variances = np.zeros((nevents, self.npmt_bins), dtype=np.float32) amount_of_hits = np.zeros((nevents, self.npmt_bins), dtype=np.float32) #looping through each event in the simulation, in order to save a mean_angle and a variance for each pmt. for ev in reader: print "Event " + str(loops + 1) + " of " + str(nevents) detected = (ev.photons_end.flags & (0x1 << 2)).astype(bool) beginning_photons = ev.photons_beg.pos[detected] ending_photons = ev.photons_end.pos[detected] length = np.shape(ending_photons)[0] end_direction_array = normalize(ending_photons - beginning_photons) pmt_bins = self.find_pmt_bin_array(ending_photons) for i in range(self.npmt_bins): if i % 10000 == 0: print str(i) + ' out of ' + str(self.npmt_bins) + ' PMTs' pmt_indices = np.where(pmt_bins == i)[0] if np.shape(pmt_indices)[0] == 0: continue angles_for_pmt = end_direction_array[pmt_indices] n_angles = np.shape(angles_for_pmt)[0] #skipping pmts with no photon hits, and only 1 photon hit (in which case the variance will be undefined with ddof=1) if n_angles < 2: continue norms = np.repeat(1.0, n_angles) mean_angle = normalize(np.mean(angles_for_pmt, axis=0)) projection_norms = np.dot(angles_for_pmt, mean_angle) orthogonal_complements = np.sqrt( np.maximum(norms**2 - projection_norms**2, 0.)) variance = np.var(orthogonal_complements, ddof=1) total_means[loops, i] = mean_angle total_variances[loops, i] = variance amount_of_hits[loops, i] = n_angles loops += 1 if loops == nevents: break #combining all of the variances and mean_angles with the weightings for each event in order to create a single value for each pmt for the entire simulation. # Masking the amount_of_hits first so that we don't divide by 0 when averaging for pmts that recieve no hits: # CURRENTLY WE ARE SKIPPING EVERY PMT THAT ONLY HAS UP TO NEVENTS HITS: I.E. THE TOTAL DEGREE OF FREEDOM IN THE DIVISION FOR THE VARIANCE AVERAGING. bad_pmts = np.where(np.sum(amount_of_hits, axis=0) <= nevents)[0] # temporary, for debugging: n_hits = np.sum(amount_of_hits, axis=0) print n_hits print "PMTs w/ 0 hits: " + str( len(np.where(n_hits < 1)[0]) * 1.0 / self.npmt_bins) print "PMTs w/ < nevents hits: " + str( len(np.where(n_hits < nevents)[0]) * 1.0 / self.npmt_bins) print "PMTs w/ < 100 hits: " + str( len(np.where(n_hits < 100)[0]) * 1.0 / self.npmt_bins) m_means = np.zeros_like(total_means) m_means[:, bad_pmts] = 1 m_variances = np.zeros_like(total_variances) m_variances[:, bad_pmts] = 1 masked_total_means = np.ma.masked_array(total_means, m_means) masked_total_variances = np.ma.masked_array(total_variances, m_variances) reshaped_weightings = np.reshape(np.repeat(amount_of_hits, 3), (nevents, self.npmt_bins, 3)) averaged_means = np.ma.average(masked_total_means, axis=0, weights=reshaped_weightings) averaged_variances = np.ma.average(masked_total_variances, axis=0, weights=amount_of_hits - 1) #unmasking masked entries to turn them into 0.0s averaged_means.mask = np.ma.nomask averaged_variances.mask = np.ma.nomask #turning type: MaskedArray into type: npArray so that it can be written. self.means = -np.array(averaged_means.astype(np.float32)).T self.sigmas = np.sqrt(np.array(averaged_variances.astype(np.float32)))
def calibrate(self, simname, directory=".", nevents=-1, fast_calibration=False): # Use with a simulation file 'simname' to calibrate the detector # Creates a list of mean angles and their uncertainties (sigma for # a cone of unit length), one for each PMT # There are 1000 events in a typical simulation. # Uses all photons hitting a given PMT at once (better estimate of sigma, # but may run out of memory in some cases). # Will not calibrate PMTs with <n_min hits logger.info('Fast calibration: %s' % str(fast_calibration)) self.is_calibrated = True start_time = time.time() base_hits_file_name = self.configname + '-hits' pickle_name = base_hits_file_name + '.pickle' hit_file_exists = False n_min = 10 # Do not calibrate a PMT if <n_min photons hit it try: logger.info('Attempting to load pickle hits file: %s%s' % (directory, pickle_name)) # TODO: This generally won't do anything because we no longer write this file with open(directory + pickle_name, 'rb') as inf: pmt_hits = pickle.load(inf) logger.info('Hit map pickle file loaded: ' + pickle_name) pmt_bins = pmt_hits['pmt_bins'] end_direction_array = pmt_hits['end_direction_array'] n_det = len(pmt_bins) hit_file_exists = True except IOError as error: # Assume file not found logger.info('Hit map pickle file not found. Creating: ' + base_hits_file_name) using_h5 = False if simname.endswith('.h5'): using_h5 = True ev_file = dd.io.load(simname) # TODO: Check the UUID!! events_in_file = len(ev_file['photons_start']) else: from ShortIO.root_short import GaussAngleRootWriter, GaussAngleRootReader, ShortRootReader reader = ShortRootReader(simname) events_in_file = len(reader) logger.info('Loaded simulation file: %s' % simname) logger.info('Simulation event count: %d' % events_in_file) if nevents < 1: nevents = events_in_file max_storage = min( nevents * 1000000, 120000000 ) #600M is too much, 400M is OK (for np.float32; using 300M) end_direction_array = np.empty((max_storage, 3), dtype=np.float32) pmt_bins = np.empty(max_storage, dtype=np.int) n_det = 0 # Loop through events, store for each photon the index of the PMT it hit (pmt_bins) # and the direction pointing back to its origin (end_direction_array) loops = 0 event_source = ev_file['photons_start'] if using_h5 else reader for index, ev_proxy in enumerate( event_source): # Not sure if we can enumerate a reader???? # TODO: This needs to be cleaned up if (using_h5): photons_beg = Photons(ev_proxy, [], [], []) photons_end = Photons(ev_file['photons_stop'][index], [], [], [], flags=ev_file['photon_flags'][index]) else: photons_beg = ev_proxy.photons_beg photons_end = ev_proxy.photons_end loops += 1 if loops > nevents: break if loops % 100 == 0: logger.info("Event " + str(loops) + " of " + str(nevents)) logger.handlers[0].flush() detected = (photons_end.flags & (0x1 << 2)).astype(bool) ''' reflected_diffuse = (ev.photons_end.flags & (0x1 << 5)).astype(bool) reflected_specular = (ev.photons_end.flags & (0x1 << 6)).astype(bool) logger.info("Total detected: " + str(sum(detected * 1))) logger.info("Total reflected: " + str(sum(reflected_diffuse * 1) + sum(reflected_specular * 1))) good_photons = detected & np.logical_not(reflected_diffuse) & np.logical_not(reflected_specular) logger.info("Total detected and not reflected: " + str(sum(good_photons * 1))) ''' if fast_calibration: ending_photons, length = self._find_photons_for_pmt( photons_beg.pos, photons_end.pos, detected, end_direction_array, n_det, max_storage) pmt_b = self.find_pmt_bin_array(ending_photons) if length is None: break else: beginning_photons = photons_beg.pos[ detected] # Include reflected photons ending_photons = photons_end.pos[detected] length = np.shape(ending_photons)[0] pmt_b = self.find_pmt_bin_array(ending_photons) end_point = self.lens_centers[pmt_b / self.n_pmts_per_surf] end_dir = normalize(end_point - beginning_photons) # if end_direction_array is None: # end_direction_array = end_dir # else: # end_direction_array = np.vstack((end_direction_array, end_dir)) #end_direction_array.append(end_dir) if n_det + length > max_storage: logger.info( 'Too many photons to store in memory; not reading any further events.' ) break end_direction_array[n_det:(n_det + length), :] = end_dir # if pmt_bins is None: # pmt_bins = pmt_b # else: # pmt_bins = np.hstack((pmt_bins, pmt_b)) #pmt_bins.append(pmt_b) pmt_bins[n_det:(n_det + length)] = pmt_b n_det += length if loops % 100 == 0: logger.info('Photons detected so far: ' + str(n_det + length)) # logger.info('Sample pmt bins: ' + str(pmt_bins[n_det:(n_det+length)])) logger.info("Time: " + str(time.time() - start_time)) total_means = np.zeros((self.npmt_bins, 3)) total_variances = np.zeros((self.npmt_bins)) total_u_minus_v = np.zeros((self.npmt_bins)) amount_of_hits = np.zeros((self.npmt_bins)) end_direction_array.resize((n_det, 3)) logger.info("Time: " + str(time.time() - start_time)) pmt_bins.resize(n_det) if not hit_file_exists: # TODO: No longer writing the pickle file # Write the pickle hits file regardless of whether using fast_calibration or not #pmt_hits = {'pmt_bins': pmt_bins, 'end_direction_array': end_direction_array} #with open(directory+pickle_name, 'wb') as outf: # pickle.dump(pmt_hits, outf) with h5py.File(directory + base_hits_file_name + '.h5', 'w') as h5file: _ = h5file.create_dataset( 'pmt_bins', data=pmt_bins, chunks=True) # TODO: Should we assign max shape? _ = h5file.create_dataset( 'end_direction_array', data=end_direction_array, chunks=True) # TODO: Should we assign max shape? logger.info('Hit map file created: ' + pickle_name) logger.info( "Finished collecting photons (or loading photon hit list). Time: " + str(time.time() - start_time)) if fast_calibration: bins_base_file_name = self.configname + '-pmt-bins' bins_pickle_file = bins_base_file_name + '.pickle' try: with open( directory + bins_pickle_file, 'rb' ) as inf: # TODO: This generally won't do anything because we no longer write this file pmt_photons = pickle.load(inf) logger.info('PMT photon list pickle file loaded: ' + bins_pickle_file) except IOError as error: start_assign = time.time() pmt_photons = assign_photons(self.npmt_bins, n_det, pmt_bins) logger.info("assign_photons took: " + str(time.time() - start_assign)) # TODO: No longer writing the pickle file #with open(directory + bins_pickle_file, 'wb') as outf: # pickle.dump(pmt_photons, outf) # TODO: Pure H5 does not work. (Because?) #with h5py.File(directory + bins_file + '.h5', 'w') as h5file: # _ = h5file.create_dataset('photon_pmts', data=pmt_photons, chunks=True) # Should we assign max shape? #logger.info('Type: ' + str(type(pmt_photons)) + ' ' + str(type(pmt_photons[0]))) dd.io.save(directory + bins_base_file_name + '.h5', pmt_photons) logger.info('PMT photon list file created: ' + bins_base_file_name + '.h5') logger.info("Finished listing photons by pmt. Time: " + str(time.time() - start_time)) draw_pmt_ind = -1 # looping through each pmt in order to save a mean_angle and a variance for i in range(self.npmt_bins): if i % 10000 == 0: logger.info( str(i) + ' out of ' + str(self.npmt_bins) + ' PMTs') logger.handlers[0].flush() logger.info("Time: " + str(time.time() - start_time)) if fast_calibration: photon_list = pmt_photons[i] angles_for_pmt = end_direction_array[photon_list] n_angles = len(angles_for_pmt) # np.shape(angles_for_pmt)[0] # skipping pmts with <2 photon hits (in which case the variance will be undefined with ddof=1) # also skipping if <n_min photon hits if n_angles < 2 or n_angles < n_min: logger.warning('Not enough angles for PMT: %d, %d' % (i, n_angles)) continue mean_angle, variance, uvvar = compute_pmt_calibration( angles_for_pmt, n_min) else: pmt_indices = np.where(pmt_bins == i)[0] if np.shape(pmt_indices)[0] == 0: continue angles_for_pmt = end_direction_array[pmt_indices] n_angles = np.shape(angles_for_pmt)[0] #skipping pmts with <2 photon hits (in which case the variance will be undefined with ddof=1) #also skipping if <n_min photon hits if n_angles < 2 or n_angles < n_min: continue mean_angle = normalize(np.mean(angles_for_pmt, axis=0)) # For each PMT, get a pair of axes which form an # orthonormal coordinate system with the PMT mean direction u_dir = np.cross(mean_angle, np.array([0, 0, 1])) if not (np.dot(u_dir, u_dir) > 0): # In case mean_angle = [0,0,1] u_dir = np.cross(mean_angle, np.array([0, 1, 0])) u_dir = normalize(u_dir) v_dir = np.cross(mean_angle, u_dir) u_proj = np.dot(angles_for_pmt, u_dir) u_var = np.var(u_proj, ddof=1) v_proj = np.dot(angles_for_pmt, v_dir) v_var = np.var(v_proj, ddof=1) variance = (u_var + v_var) / 2. # Old method, which calculated variance of projected norma, even though # the mean of the projections wasn't 0 due to the solid angle factor norms = np.repeat(1.0, n_angles) projection_norms = np.dot(angles_for_pmt, mean_angle) orthogonal_complements = np.sqrt( np.maximum(norms**2 - projection_norms**2, 0.)) #variance = np.var(orthogonal_complements, ddof=1) uvvar = u_var - v_var try: #draw_pmt_ind = None draw_pmt_ind = int(draw_pmt_ind) ''' if i == draw_pmt_ind or draw_pmt_ind<0: # Temporary, to visualize histogram of angles, distances #angles = np.arccos(projection_norms) #ang_variance = np.var(angles, ddof=1) #fig1 = plt.figure(figsize=(7.8, 6)) #plt.hist(angles, bins=20) #plt.xlabel('Angular Separation to Mean Angle') #plt.ylabel('Counts per bin') #plt.title('Angles Histogram for PMT ' + str(i)) ##plt.show() # #fig2 = plt.figure(figsize=(7.8, 6)) #plt.hist(angles, bins=20, weights=1./np.sin(angles)) #plt.xlabel('Angular Separation to Mean Angle') #plt.ylabel('Counts per solid angle') #plt.title('Angles Histogram for PMT ' + str(i)) fig3 = plt.figure(figsize=(7.8, 6)) plt.hist(orthogonal_complements, bins=20) plt.xlabel('Normalized Distance to Mean Angle') plt.ylabel('Counts per bin') plt.title('Distances Histogram for PMT ' + str(i)) fig4 = plt.figure(figsize=(7.8, 6)) plt.hist(u_proj, bins=20) plt.xlabel('U Distance to Mean Angle') plt.ylabel('Counts per bin') plt.title('U Distances Histogram for PMT ' + str(i)) fig5 = plt.figure(figsize=(7.8, 6)) plt.hist(v_proj, bins=20) plt.xlabel('V Distance to Mean Angle') plt.ylabel('Counts per bin') plt.title('V Distances Histogram for PMT ' + str(i)) plt.show() #print "Average projected variance: ", variance #print "Variance of projected 2D norms: ", np.var(orthogonal_complements, ddof=1) draw_pmt_ind = raw_input("Enter index of next PMT to draw; will stop drawing if not a valid PMT index.\n") ''' except ValueError: pass except TypeError: pass total_means[i] = mean_angle total_variances[i] = variance total_u_minus_v[i] = np.abs(uvvar) amount_of_hits[i] = n_angles if np.isnan(variance): print "Nan for PMT " + str(i) # nan_ind = np.where(np.isnan(orthogonal_complements)) # print nan_ind # print projection_norms # print orthogonal_complements # print angles_for_pmt # print variance # print mean_angle # temporary, for debugging: n_hits = np.sum(amount_of_hits, axis=0) print "Total hits for calibrated PMTs: " + str(n_hits) print "PMTs w/ < n_events hits: " + str( len(np.where(amount_of_hits < nevents)[0]) * 1.0 / self.npmt_bins) print "PMTs w/ < n_min hits: " + str( len(np.where(amount_of_hits < n_min)[0]) * 1.0 / self.npmt_bins) print "PMTs w/ < 100 hits: " + str( len(np.where(amount_of_hits < 100)[0]) * 1.0 / self.npmt_bins) print "Mean U-V variance (abs): " + str(np.mean(total_u_minus_v)) # Store final calibrated values self.means = -total_means.astype(np.float32).T self.sigmas = np.sqrt(total_variances.astype(np.float32))