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 build_detector(): """Returns a cubic detector made of cubic photodetectors.""" g = Geometry(water) for pos, dir in iter_box(nx,ny,nz,spacing): # convert to arrays pos, dir = np.array(pos), np.array(dir) # we need to figure out what rotation matrix to apply to each # photodetector so that the photosensitive surface will be facing # `dir`. if tuple(dir) == (0,0,1): rotation = None elif tuple(dir) == (0,0,-1): rotation = make_rotation_matrix(np.pi,(1,0,0)) else: rotation = make_rotation_matrix(np.arccos(dir.dot((0,0,1))), np.cross(dir,(0,0,1))) # add the photodetector g.add_solid(build_pd(size,glass_thickness),rotation=rotation, displacement=pos) world = Solid(make.box(spacing*nx,spacing*ny,spacing*nz),water,vacuum, color=0x33ffffff) g.add_solid(world) return g
def build_rotation_matrices(self): rotation_matrices = np.empty((20, 3, 3)) for k in range(20): rotation_matrices[k] = np.dot( make_rotation_matrix(self.spin_angle[k], self.direction[k]), make_rotation_matrix(self.angle[k], self.axis[k])) return rotation_matrices
def build_detector(): """Returns a cubic detector made of cubic photodetectors.""" g = Geometry(water) for pos, dir in iter_box(nx, ny, nz, spacing): # convert to arrays pos, dir = np.array(pos), np.array(dir) # we need to figure out what rotation matrix to apply to each # photodetector so that the photosensitive surface will be facing # `dir`. if tuple(dir) == (0, 0, 1): rotation = None elif tuple(dir) == (0, 0, -1): rotation = make_rotation_matrix(np.pi, (1, 0, 0)) else: rotation = make_rotation_matrix(np.arccos(dir.dot((0, 0, 1))), np.cross(dir, (0, 0, 1))) # add the photodetector g.add_solid(build_pd(size, glass_thickness), rotation=rotation, displacement=pos) world = Solid(make.box(spacing * nx, spacing * ny, spacing * nz), water, vacuum, color=0x33ffffff) g.add_solid(world) return g
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 get_lens_triangle_centers(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 lenses = lenssystem.get_lens_mesh_list(lens_system_name, scale_rad) lens_mesh = None for lns in lenses: # Add all the lenses for the first lens system to solid 'face' if not lens_mesh: lens_mesh = lns else: lens_mesh += lns X, Y, Z = get_assembly_xyz(lens_mesh) lens_centers = np.asarray([np.mean(X), np.mean(Y), np.mean(Z)]) lns_center_arr = [] phi, axs = rot_axis([0, 0, 1], vtx) for vx, ph, ax in zip(vtx, -phi, axs): lns_center_arr.append( np.dot(make_rotation_matrix(ph, ax), lens_centers) - vx) return np.asarray(lns_center_arr)
def render_particle_track(self): x = 10.0 h = x * np.sqrt(3) / 2 pyramid = make.linear_extrude([-x / 2, 0, x / 2], [-h / 2, h / 2, -h / 2], h, [0] * 3, [0] * 3) marker = Solid(pyramid, vacuum, vacuum) if self.photon_display_mode == 'beg': photons = self.ev.photons_beg else: photons = self.ev.photons_end geometry = Geometry() sample_factor = max(1, len(photons.pos) / 10000) for pos in photons.pos[::sample_factor]: geometry.add_solid(marker, displacement=pos, rotation=make_rotation_matrix( np.random.uniform(0, 2 * np.pi), uniform_sphere())) geometry = create_geometry_from_obj(geometry) gpu_geometry = gpu.GPUGeometry(geometry) self.gpu_geometries = [self.gpu_geometry, gpu_geometry]
def build_detector(self, detector=None, volume_classifier=_default_volume_classifier): ''' Add the meshes defined by this GDML to the detector. If detector is not specified, a new detector will be created. The volume_classifier should be a function that returns a classification of the volume ('pmt','solid','omit') and kwargs passed to the Solid constructor for that volume: material1, material2, color, surface The different classifications have different behaviors: 'pmt' should specify channel_type in the kwargs to identify the channel, calls add_pmt 'solid' will add a normal solid to the Chroma geometry, calls add_solid 'omit' will not add the Solid to the Chroma geometry ''' if detector is None: detector = Detector(vacuum) q = deque() q.append([self.world, np.zeros(3), np.identity(3), None]) while len(q): v, pos, rot, parent_material_ref = q.pop() for child, c_pos, c_rot in zip(v.children, v.child_pos, v.child_rot): c_pos = self.get_vals(c_pos) if c_pos is not None else np.zeros(3) c_rot = self.get_vals(c_rot) if c_rot is not None else np.identity(3) c_pos = np.matmul(c_pos,rot)+pos x_rot = make_rotation_matrix(c_rot[0], [1, 0, 0]) y_rot = make_rotation_matrix(c_rot[1], [0, 1, 0]) z_rot = make_rotation_matrix(c_rot[2], [0, 0, 1]) c_rot = np.matmul(rot, np.matmul(x_rot, np.matmul(y_rot, z_rot))) #FIXME verify this order q.append([child, c_pos, c_rot, v.material_ref]) m = self.get_mesh(v.solid_ref) mesh = Mesh(m.vertices, m.faces) # convert PyMesh mesh to Chroma mesh classification, kwargs = volume_classifier(v.name, v.material_ref, parent_material_ref) if classification == 'pmt': channel_type = kwargs.pop('channel_type',None) solid = Solid(mesh, **kwargs) detector.add_pmt(solid, displacement=pos, rotation=rot, channel_type=channel_type) elif classification == 'solid': solid = Solid(mesh, **kwargs) detector.add_solid(solid, displacement=pos, rotation=rot) elif classification == 'omit': pass else: raise Exception('Unknown volume classification: '+classification) return detector
def gen_rot(a, b): '''Construct a matrix to rotate vector a to vector b''' a = a / np.linalg.norm(a) b = b / np.linalg.norm(b) if (a == b).all(): return np.diag([1., 1., 1.]) if (a == -b).all(): return np.diag([-1., -1., -1.]) v = np.cross(a, b) c = np.arccos(-np.dot(a, b)) return make_rotation_matrix(c, v)
def BuildBlocker(radius, height): nsteps = 50 x_value = np.linspace(radius, radius + 200, nsteps) y_value = [1] * nsteps blocker = make.rotate_extrude(x_value, y_value, nsteps) blocker = mh.rotate(blocker, make_rotation_matrix(+np.pi / 2, (1, 0, 0))) blocker = mh.shift(blocker, (0, 0, height)) return blocker
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_pmt_icosahedron(kabamland, vtx, focal_length=1.0): offset = 1.2 * (vtx + focal_length) angles = np.linspace(np.pi / 4, 2 * np.pi + np.pi / 4, 4, endpoint=False) square = make.linear_extrude(offset * np.sqrt(2) * np.cos(angles), offset * np.sqrt(2) * np.sin(angles), 2.0) vrs = np.eye(3) for vr in vrs: if np.array_equal(vr, [0, 0, 1]): kabamland.add_pmt(Solid(square, glass, kabamland.detector_material, lm.fullabsorb, 0xBBFFFFFF), displacement=offset * vr) kabamland.add_pmt(Solid(square, glass, kabamland.detector_material, lm.fullabsorb, 0xBBFFFFFF), displacement=-offset * vr) else: trasl = np.cross(vr, [0, 0, 1]) kabamland.add_pmt(Solid(square, glass, kabamland.detector_material, lm.fullabsorb, 0xBBFFFFFF), rotation=make_rotation_matrix(np.pi / 2, vr), displacement=offset * trasl) kabamland.add_pmt(Solid(square, glass, kabamland.detector_material, lm.fullabsorb, 0xBBFFFFFF), rotation=make_rotation_matrix(np.pi / 2, vr), displacement=-offset * trasl)
def render_vertex( self, geometry, vertex, children=2, sz=5.0, colors={ 'mu+': 0x50E0FF, 'mu-': 0xFFE050, 'e+': 0x0000FF, 'e-': 0xFF0000, 'gamma': 0x00FF00 }): steps = np.vstack((vertex.steps.x, vertex.steps.y, vertex.steps.z)).T for index in range(len(steps) - 1): vec = steps[index + 1] - steps[index] mag = np.linalg.norm(vec) u = vec / mag axis = np.cross(u, [0, 0, 1]) ang = np.arccos(np.dot(u, [0, 0, 1])) rotmat = make_rotation_matrix(ang, axis) x = sz / 2 y = x * np.sqrt(3) / 2 segment = make.linear_extrude([-x, 0, x], [-y, y, -y], mag, [0, 0, 0], [0, 0, 0]) segment.vertices[:, 2] += mag / 2.0 marker = Solid(segment, vacuum, vacuum, color=colors[vertex.particle_name] if vertex.particle_name in colors else 0xAAAAAA) geometry.add_solid(marker, displacement=steps[index], rotation=rotmat) if children and vertex.children: for child in vertex.children: if isinstance(children, bool): self.render_vertex(geometry, child, children) else: self.render_vertex(geometry, child, children - 1)
def PlotBlocker(radius, height): nsteps = 30 x_value = np.linspace(radius, radius + 200, nsteps) y_value = [0] * nsteps blocker = make.rotate_extrude(x_value, y_value, nsteps) blocker = mh.rotate(blocker, make_rotation_matrix(+np.pi / 2, (1, 0, 0))) blocker = mh.shift(blocker, (0, 0, height)) blocker_triangles = blocker.get_triangle_centers() blocker_vertices = blocker.assemble() X = blocker_vertices[:, :, 0].flatten() Y = blocker_vertices[:, :, 1].flatten() Z = blocker_vertices[:, :, 2].flatten() trianglesblocker = [[3 * ii, 3 * ii + 1, 3 * ii + 2] for ii in range(len(X) / 3)] triang = Triangulation(X, Y, trianglesblocker) return triang, Z
def render_particle_track(self): x = 10.0 h = x*np.sqrt(3)/2 pyramid = make.linear_extrude([-x/2,0,x/2], [-h/2,h/2,-h/2], h, [0]*3, [0]*3) marker = Solid(pyramid, vacuum, vacuum) if self.photon_display_mode == 'beg': photons = self.ev.photons_beg else: photons = self.ev.photons_end geometry = Geometry() sample_factor = max(1, len(photons.pos) / 10000) for pos in photons.pos[::sample_factor]: geometry.add_solid(marker, displacement=pos, rotation=make_rotation_matrix(np.random.uniform(0,2*np.pi), uniform_sphere())) geometry = create_geometry_from_obj(geometry) gpu_geometry = gpu.GPUGeometry(geometry) self.gpu_geometries = [self.gpu_geometry, gpu_geometry]
def build_kabamland(kabamland, configname): # focal_length sets dist between lens plane and PMT plane (or back of curved detecting surface); #(need not equal true lens focal length) config = detectorconfig.configdict(configname) _, lens = kb.get_lens_triangle_centers( config.edge_length, config.base, config.diameter_ratio, config.thickness_ratio, config.half_EPD, config.blockers, blocker_thickness_ratio=config.blocker_thickness_ratio, light_confinement=config.light_confinement, focal_length=config.focal_length, lens_system_name=config.lens_system_name) surf = mh.rotate( kb.curved_surface2(config.detector_r, diameter=2 * kb.find_max_radius(config.edge_length, config.base), nsteps=9), make_rotation_matrix(-np.pi / 2, (1, 0, 0))) surf = mh.shift(surf, (0, 0, -config.focal_length)) kabamland.add_solid(Solid(surf, lm.ls, lm.ls, lm.fulldetect, 0x0000FF), rotation=None, displacement=(0, 0, 0)) kabamland.add_solid(Solid(lens, lm.lensmat, lm.ls), rotation=None, displacement=None) blocker = BuildBlocker( np.max(lens.assemble()[:, :, 0].flatten()), lens.assemble()[:, :, 2].flatten()[np.argmax(lens.assemble()[:, :, 0].flatten())]) kabamland.add_solid(Solid(blocker, lm.ls, lm.ls, lm.fullabsorb, 0x0000FF), rotation=None, displacement=(0, 0, 0)) kabamland.channel_index_to_channel_id = [1] return lens, surf
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))