コード例 #1
0
ファイル: tools.py プロジェクト: BenLand100/chroma
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)
コード例 #2
0
ファイル: kabamland2.py プロジェクト: multilenssim/simulation
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
コード例 #3
0
ファイル: benchmark.py プロジェクト: wcgillis01/chroma
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)))
コード例 #4
0
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)
コード例 #5
0
ファイル: kabamland2.py プロジェクト: multilenssim/simulation
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
コード例 #6
0
ファイル: __init__.py プロジェクト: wcgillis01/chroma
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
コード例 #7
0
ファイル: tools.py プロジェクト: NuTufts/ChromaUBooNE
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)
コード例 #8
0
    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
コード例 #9
0
ファイル: benchmark.py プロジェクト: wcgillis01/chroma
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)))
コード例 #10
0
ファイル: kabamland2.py プロジェクト: multilenssim/simulation
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))
コード例 #11
0
ファイル: kabamland2.py プロジェクト: multilenssim/simulation
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))
コード例 #12
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
コード例 #13
0
    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
コード例 #14
0
 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
コード例 #15
0
    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)))
コード例 #16
0
    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))