def from_basisgrid(cls, bg, element_type=sensors.Mtrx): """ Convert a BasisGrid object to a CompoundCamera. Parameters ---------- bg : basisgrid.BasisGrid The basisgrid object to convert. element_type : sensors.PixelArraySensor The SensorElement type to populate the camera with. Returns ------- cd : CompoundCamera The compound camera instance. """ if not isinstance(bg, basisgrid.BasisGrid): raise TypeError('`bg` argument must be instance of BasisGrid,' ' got: %s' % type(bg)) cd = cls(type_name='root_frame', id_num=0, parent=None) for g in range(bg.num_grids): p, s, f, shape = bg.get_grid(g) pixel_shape = (np.linalg.norm(s), np.linalg.norm(f)) # to compute the rotation, find the us = s / pixel_shape[0] # unit vector uf = f / pixel_shape[1] # unit vector n = np.cross(us, uf) # tested for orthog. in next fxn # remember: in the matrix convention (Mikhail uses), +x is slow # and +y is fast ra = moveable._angles_from_rotated_frame(us, uf, n) # translation is just p tr = p pas = element_type(shape, pixel_shape, id_num=g, parent=cd, rotation_angles=ra, translation=tr) return cd
def test_angle_retrieval(): for i in range(100): alpha = np.random.rand() * 180.0 beta = np.random.rand() * 180.0 gamma = np.random.rand() * 180.0 R = moveable._rotation_matrix_from_angles(gamma, beta, alpha) I = np.eye(3) Ip = np.dot(R, I) gp, bp, ap = moveable._angles_from_rotated_frame(Ip[:,0], Ip[:,1], Ip[:,2]) #print np.array([gamma, beta, alpha]), np.array([gp, bp, ap]) # test to make sure they rotate to the same thing R2 = moveable._rotation_matrix_from_angles(gp, bp, ap) assert np.sum( np.abs( R - R2 ) ) < 1e-12
def test_angle_retrieval(): for i in range(100): alpha = np.random.rand() * 180.0 beta = np.random.rand() * 180.0 gamma = np.random.rand() * 180.0 R = moveable._rotation_matrix_from_angles(gamma, beta, alpha) I = np.eye(3) Ip = np.dot(R, I) gp, bp, ap = moveable._angles_from_rotated_frame( Ip[:, 0], Ip[:, 1], Ip[:, 2]) #print np.array([gamma, beta, alpha]), np.array([gp, bp, ap]) # test to make sure they rotate to the same thing R2 = moveable._rotation_matrix_from_angles(gp, bp, ap) assert np.sum(np.abs(R - R2)) < 1e-12
def from_basisgrid(cls, bg): """ Convert a BasisGrid object to a Cspad. The BasisGrid must have 64 grids/ panels, one for each CSPAD ASIC. Parameters ---------- bg : basisgrid.BasisGrid The basisgrid object to convert. Returns ------- cspad : Cspad The Cspad instance. """ cspad = cls(type_name='CSPAD:V1') if not isinstance(bg, basisgrid.BasisGrid): raise TypeError('`bg` argument must be instance of BasisGrid,' ' got: %s' % type(bg)) # if the grids are asics, we can strip out every other one and then # treat them like 2x1s if bg.num_pixels / bg.num_grids == 185 * 388: # two-by-one grids stride = 1 elif bg.num_pixels / bg.num_grids == 185 * 194: # asic grids stride = 2 else: raise RuntimeError('Could not tell if BasisGrid grid elements are ' 'CSPAD 2x1s or ASICs. Pixels per element:' '%d' % (bg.num_pixels / bg.num_grids,)) for g in range(0, bg.num_grids, stride): asic_id = (g/stride) # index from 0 to 7 # find the quad geometry quad_index = asic_id / 8 # we just put the quads in a zero'd frame, no knowledge of absolute # orientations quad_rot = np.array([0.0, 0.0, 0.0]) quad_trs = np.array([0.0, 0.0, 0.0]) # add a new quad if necessary if asic_id % 8 == 0: quad = CompoundCamera(type_name='QUAD:V1', id_num=quad_index, parent=cspad, rotation_angles=quad_rot, translation=quad_trs) p, s, f, shape = bg.get_grid(g) pixel_shape = (np.linalg.norm(s), np.linalg.norm(f)) # compute the rotation based on s/f vectors us = s / pixel_shape[0] # unit vector uf = f / pixel_shape[1] # unit vector # BIG WARNING: There is a minus sign on `us` below, which is needed # to account for the fact that the slow scan is swapped in the # sensors.Cspad2x1 class n = np.cross(uf, -us) # tested for orthog. in next fxn ra = moveable._angles_from_rotated_frame(uf, -us, n) # translation is center of 2x1, less the quad center # dont forget the big pixels! # dont forget p/s/f here is only an ASIC! # dont forget p points to the middle of a pixel! tr = p + 184.0/2.0 * 109.92 * us + (192.5 * 109.92 + 274.8) * uf # construct the 2x1 pas = sensors.Cspad2x1(type_name='SENS2X1:V1', id_num=int(asic_id % 8), parent=quad, rotation_angles=ra, translation=tr) # if we skipped a grid (ASIC), we'll check to make sure that # the p-vector from that grid points to the correct pixel on # our newly oriented 2x1 -- allow 10 um error in x/y, 200 um in z if stride == 2: p_skipped, _, _, _ = bg.get_grid(g + 1) # be more lenient in z, since some programs are not general # enough to handle it if (np.linalg.norm(p_skipped[:2] - pas.xyz[0,194,:2]) > 10.0) or \ (np.abs(p_skipped[2] - pas.xyz[0,194,2]) > 200.0): print('quad %d / 2x1 %d' % (quad_index, asic_id % 8)) print('grid p-vector: ', p_skipped) print('pixel (0, 194): ', pas.xyz[0,194,:]) print('') warnings.warn('The two ASICs making up the %d-th 2x1 on ' 'the %d-th quad (grids %d, %d) do not conform' ' to the geometric requirements of a 2x1 ' 'unit. Check your geometry! Do not ignore this' ' warning unless you were expecting it!!' '' % (asic_id % 8, quad_index, g, g+1)) if _STRICT: raise RuntimeError('_STRICT set, no warnings allowed') return cspad
def from_basisgrid(cls, bg): """ Convert a BasisGrid object to a Cspad. The BasisGrid must have 64 grids/ panels, one for each CSPAD ASIC. Parameters ---------- bg : basisgrid.BasisGrid The basisgrid object to convert. Returns ------- cspad : Cspad The Cspad instance. """ cspad = cls(type_name='CSPAD:V1') if not isinstance(bg, basisgrid.BasisGrid): raise TypeError('`bg` argument must be instance of BasisGrid,' ' got: %s' % type(bg)) # if the grids are asics, we can strip out every other one and then # treat them like 2x1s if bg.num_pixels / bg.num_grids == 185 * 388: # two-by-one grids stride = 1 elif bg.num_pixels / bg.num_grids == 185 * 194: # asic grids stride = 2 else: raise RuntimeError('Could not tell if BasisGrid grid elements are ' 'CSPAD 2x1s or ASICs. Pixels per element:' '%d' % (bg.num_pixels / bg.num_grids, )) for g in range(0, bg.num_grids, stride): asic_id = (g / stride) # index from 0 to 7 # find the quad geometry quad_index = asic_id / 8 # we just put the quads in a zero'd frame, no knowledge of absolute # orientations quad_rot = np.array([0.0, 0.0, 0.0]) quad_trs = np.array([0.0, 0.0, 0.0]) # add a new quad if necessary if asic_id % 8 == 0: quad = CompoundCamera(type_name='QUAD:V1', id_num=quad_index, parent=cspad, rotation_angles=quad_rot, translation=quad_trs) p, s, f, shape = bg.get_grid(g) pixel_shape = (np.linalg.norm(s), np.linalg.norm(f)) # compute the rotation based on s/f vectors us = s / pixel_shape[0] # unit vector uf = f / pixel_shape[1] # unit vector # BIG WARNING: There is a minus sign on `us` below, which is needed # to account for the fact that the slow scan is swapped in the # sensors.Cspad2x1 class n = np.cross(uf, -us) # tested for orthog. in next fxn ra = moveable._angles_from_rotated_frame(uf, -us, n) # translation is center of 2x1, less the quad center # dont forget the big pixels! # dont forget p/s/f here is only an ASIC! # dont forget p points to the middle of a pixel! tr = p + 184.0 / 2.0 * 109.92 * us + (192.5 * 109.92 + 274.8) * uf # construct the 2x1 pas = sensors.Cspad2x1(type_name='SENS2X1:V1', id_num=int(asic_id % 8), parent=quad, rotation_angles=ra, translation=tr) # if we skipped a grid (ASIC), we'll check to make sure that # the p-vector from that grid points to the correct pixel on # our newly oriented 2x1 -- allow 10 um error in x/y, 200 um in z if stride == 2: p_skipped, _, _, _ = bg.get_grid(g + 1) # be more lenient in z, since some programs are not general # enough to handle it if (np.linalg.norm(p_skipped[:2] - pas.xyz[0,194,:2]) > 10.0) or \ (np.abs(p_skipped[2] - pas.xyz[0,194,2]) > 200.0): print('quad %d / 2x1 %d' % (quad_index, asic_id % 8)) print('grid p-vector: ', p_skipped) print('pixel (0, 194): ', pas.xyz[0, 194, :]) print('') warnings.warn( 'The two ASICs making up the %d-th 2x1 on ' 'the %d-th quad (grids %d, %d) do not conform' ' to the geometric requirements of a 2x1 ' 'unit. Check your geometry! Do not ignore this' ' warning unless you were expecting it!!' '' % (asic_id % 8, quad_index, g, g + 1)) if _STRICT: raise RuntimeError('_STRICT set, no warnings allowed') return cspad