def test_cam_to_tel(): from ctapipe.coordinates import CameraFrame, TelescopeFrame # Coordinates in any fram can be given as a numpy array of the xyz positions # e.g. in this case the position on pixels in the camera pix_x = [1] * u.m pix_y = [1] * u.m focal_length = 15 * u.m # first define the camera frame camera_coord = CameraFrame(pix_x, pix_y, focal_length=focal_length) # then use transform to function to convert to a new system # making sure to give the required values for the conversion # (these are not checked yet) telescope_coord = camera_coord.transform_to(TelescopeFrame()) assert telescope_coord.x[0] == (1 / 15) * u.rad # check rotation camera_coord = CameraFrame(pix_x, pix_y, focal_length=focal_length) telescope_coord_rot = camera_coord.transform_to(TelescopeFrame()) assert telescope_coord_rot.y[0] - (1 / 15) * u.rad < 1e-6 * u.rad # The Transform back camera_coord2 = telescope_coord.transform_to( CameraFrame(focal_length=focal_length) ) # Check separation assert camera_coord.separation_3d(camera_coord2)[0] == 0 * u.m
def test_cam_to_tel(): from ctapipe.coordinates import CameraFrame, TelescopeFrame # Coordinates in any fram can be given as a numpy array of the xyz positions # e.g. in this case the position on pixels in the camera pix_x = [1] * u.m pix_y = [1] * u.m focal_length = 15 * u.m # first define the camera frame camera_coord = CameraFrame(pix_x, pix_y, focal_length=focal_length) # then use transform to function to convert to a new system # making sure to give the required values for the conversion # (these are not checked yet) telescope_coord = camera_coord.transform_to(TelescopeFrame()) assert telescope_coord.x[0] == (1 / 15) * u.rad # check rotation camera_coord = CameraFrame(pix_x, pix_y, focal_length=focal_length) telescope_coord_rot = camera_coord.transform_to(TelescopeFrame()) assert telescope_coord_rot.y[0] - (1 / 15) * u.rad < 1e-6 * u.rad # The Transform back camera_coord2 = telescope_coord.transform_to( CameraFrame(focal_length=focal_length)) # Check separation assert camera_coord.separation_3d(camera_coord2)[0] == 0 * u.m
def cam_to_nom(): pix = [np.ones(2048),np.ones(2048),np.zeros(2048)] * u.m camera_coord = CameraFrame(pix,focal_length = 15*u.m) # In this case we bypass the telescope system nom_coord = camera_coord.transform_to(NominalFrame(pointing_direction=[70*u.deg,180*u.deg],array_direction=[75*u.deg,180*u.deg])) alt_az = camera_coord.transform_to(HorizonFrame(pointing_direction=[70*u.deg,180*u.deg],array_direction=[75*u.deg,180*u.deg])) print("Nominal Coordinate",nom_coord)
def cam_to_nom(): pix = [np.ones(2048), np.ones(2048), np.zeros(2048)] * u.m camera_coord = CameraFrame(pix, focal_length=15 * u.m) # In this case we bypass the telescope system nom_coord = camera_coord.transform_to( NominalFrame(pointing_direction=[70 * u.deg, 180 * u.deg], array_direction=[75 * u.deg, 180 * u.deg])) alt_az = camera_coord.transform_to( HorizonFrame(pointing_direction=[70 * u.deg, 180 * u.deg], array_direction=[75 * u.deg, 180 * u.deg])) print("Nominal Coordinate", nom_coord)
def test_array_draw(): filename = get_dataset("gamma_test.simtel.gz") cam_geom = {} source = hessio_event_source(filename, max_events=2) r1 = HESSIOR1Calibrator() dl0 = CameraDL0Reducer() calibrator = CameraDL1Calibrator() for event in source: array_pointing = SkyCoord( event.mcheader.run_array_direction[1] * u.rad, event.mcheader.run_array_direction[0] * u.rad, frame=AltAz) # array_view = ArrayPlotter(instrument=event.inst, # system=TiltedGroundFrame( # pointing_direction=array_pointing)) hillas_dict = {} r1.calibrate(event) dl0.reduce(event) calibrator.calibrate(event) # calibrate the events # store MC pointing direction for the array for tel_id in event.dl0.tels_with_data: pmt_signal = event.dl1.tel[tel_id].image[0] geom = deepcopy(event.inst.subarray.tel[tel_id].camera) fl = event.inst.subarray.tel[tel_id].optics.equivalent_focal_length # Transform the pixels positions into nominal coordinates camera_coord = CameraFrame(x=geom.pix_x, y=geom.pix_y, z=np.zeros(geom.pix_x.shape) * u.m, focal_length=fl, rotation=90 * u.deg - geom.cam_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=array_pointing, pointing_direction=array_pointing)) geom.pix_x = nom_coord.x geom.pix_y = nom_coord.y mask = tailcuts_clean(geom, pmt_signal, picture_thresh=10., boundary_thresh=5.) try: moments = hillas_parameters(geom, pmt_signal * mask) hillas_dict[tel_id] = moments nom_coord = NominalPlotter(hillas_parameters=hillas_dict, draw_axes=True) nom_coord.draw_array() except HillasParameterizationError as e: print(e) continue
def test_camera_telescope_transform(): camera_coord = CameraFrame(x=1*u.m, y=2*u.m, z=0*u.m) print(camera_coord) telescope_coord = camera_coord.transform_to(TelescopeFrame) print(telescope_coord) camera_coord2 = telescope_coord.transform_to(CameraFrame) print(camera_coord2)
def test_camera_telescope_transform(): camera_coord = CameraFrame(x=1 * u.m, y=2 * u.m, z=0 * u.m) print(camera_coord) telescope_coord = camera_coord.transform_to(TelescopeFrame) print(telescope_coord) camera_coord2 = telescope_coord.transform_to(CameraFrame) print(camera_coord2)
def test_array_draw(): filename = get_dataset("gamma_test.simtel.gz") cam_geom = {} source = hessio_event_source(filename, max_events=2) r1 = HessioR1Calibrator(None, None) dl0 = CameraDL0Reducer(None, None) calibrator = CameraDL1Calibrator(None, None) for event in source: array_pointing = SkyCoord(event.mcheader.run_array_direction[1] * u.rad, event.mcheader.run_array_direction[0] * u.rad, frame=AltAz) # array_view = ArrayPlotter(instrument=event.inst, # system=TiltedGroundFrame( # pointing_direction=array_pointing)) hillas_dict = {} r1.calibrate(event) dl0.reduce(event) calibrator.calibrate(event) # calibrate the events # store MC pointing direction for the array for tel_id in event.dl0.tels_with_data: pmt_signal = event.dl1.tel[tel_id].image[0] geom = event.inst.subarray.tel[tel_id].camera fl = event.inst.subarray.tel[tel_id].optics.effective_focal_length # Transform the pixels positions into nominal coordinates camera_coord = CameraFrame(x=geom.pix_x, y=geom.pix_y, z=np.zeros(geom.pix_x.shape) * u.m, focal_length=fl, rotation=90 * u.deg - geom.cam_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=array_pointing, pointing_direction=array_pointing)) mask = tailcuts_clean(geom, pmt_signal, picture_thresh=10., boundary_thresh=5.) try: moments = hillas_parameters(nom_coord.x, nom_coord.y, pmt_signal * mask) hillas_dict[tel_id] = moments nom_coord = NominalPlotter(hillas_parameters=hillas_dict, draw_axes=True) nom_coord.draw_array() except HillasParameterizationError as e: print(e) continue
def get_nominal(self, tel_id): if not tel_id in self.nominal_geom_dict: camera_geom = self.get_camera(tel_id) pix_x, pix_y = self.inst.pixel_pos[tel_id] foclen = self.inst.optical_foclen[tel_id] camera_coord = CameraFrame(x=pix_x, y=pix_y, focal_length=foclen, rotation=-1 * camera_geom.cam_rotation) nom_coord = camera_coord.transform_to(self.nom_system) geom = CameraGeometry(camera_geom.cam_id, camera_geom.pix_id, nom_coord.x, nom_coord.y, None, camera_geom.pix_type, camera_geom.pix_rotation, camera_geom.cam_rotation, camera_geom.neighbors, False) self.nominal_geom_dict[tel_id] = geom return self.nominal_geom_dict[tel_id]
def camera_to_horizontal(x, y, alt_pointing, az_pointing, focal_length): with warnings.catch_warnings(): warnings.simplefilter("ignore", MissingFrameAttributeWarning) altaz = AltAz() tel_pointing = SkyCoord( alt=u.Quantity(alt_pointing, u.deg, copy=False), az=u.Quantity(az_pointing, u.deg, copy=False), frame=altaz, ) camera_coordinates = CameraFrame( x=u.Quantity(x, u.m, copy=False), y=u.Quantity(y, u.m, copy=False), focal_length=u.Quantity(focal_length, u.m, copy=False), telescope_pointing=tel_pointing, ) horizontal_coordinates = camera_coordinates.transform_to(altaz) return horizontal_coordinates.alt.to_value(u.deg), horizontal_coordinates.az.to_value(u.deg)
def cam_to_tel(): # Coordinates in any fram can be given as a numpy array of the xyz positions # e.g. in this case the position on pixels in the camera pix = [np.ones(2048),np.ones(2048),np.zeros(2048)] * u.m # first define the camera frame camera_coord = CameraFrame(pix,focal_length=15*u.m,rotation=0*u.deg) # then use transform to function to convert to a new system # making sure to give the required values for the conversion (these are not checked yet) telescope_coord = camera_coord.transform_to(TelescopeFrame()) # Print coordinates in the new frame print("Telescope Coordinate",telescope_coord) # Transforming back is then easy camera_coord2 = telescope_coord.transform_to(CameraFrame(focal_length=15*u.m,rotation=0*u.deg)) # We can easily check the distance between 2 coordinates in the same frame # In this case they should be the same print("Separation",np.sum(camera_coord.separation_3d(camera_coord2)))
def cam_to_tel(): # Coordinates in any fram can be given as a numpy array of the xyz positions # e.g. in this case the position on pixels in the camera pix = [np.ones(2048), np.ones(2048), np.zeros(2048)] * u.m # first define the camera frame camera_coord = CameraFrame(pix) # then use transform to function to convert to a new system # making sure to give the required values for the conversion (these are not checked yet) telescope_coord = camera_coord.transform_to( TelescopeFrame(focal_length=15 * u.m, rotation=0 * u.deg)) # Print cordinates in the new frame print("Telescope Coordinate", telescope_coord) # Transforming back is then easy camera_coord2 = telescope_coord.transform_to(CameraFrame()) # We can easily check the distance between 2 coordinates in the same frame # In this case they should be the same print("Separation", np.sum(camera_coord.separation_3d(camera_coord2)))
def analyze_muon_event(event, params=None, geom_dict=None): """ Generic muon event analyzer. Parameters ---------- event : ctapipe dl1 event container Returns ------- muonringparam, muonintensityparam : MuonRingParameter and MuonIntensityParameter container event """ # Declare a dict to define the muon cuts (ASTRI and SCT missing) muon_cuts = {} names = ['LST:LSTCam','MST:NectarCam','MST:FlashCam','MST-SCT:SCTCam','SST-1M:DigiCam','SST-GCT:CHEC','SST-ASTRI:ASTRICam'] TailCuts = [(5,7),(5,7),(10,12),(5,7),(5,7),(5,7),(5,7)] #10,12? impact = [(0.2,0.9),(0.1,0.95),(0.2,0.9),(0.2,0.9),(0.1,0.95),(0.1,0.95),(0.1,0.95)] ringwidth = [(0.04,0.08),(0.02,0.1),(0.01,0.1),(0.02,0.1),(0.01,0.5),(0.02,0.2),(0.02,0.2)] TotalPix = [1855.,1855.,1764.,11328.,1296.,2048.,2368.]#8% (or 6%) as limit MinPix = [148.,148.,141.,680.,104.,164.,142.] #Need to either convert from the pixel area in m^2 or check the camera specs AngPixelWidth = [0.1,0.2,0.18,0.067,0.24,0.2,0.17] #Found from TDRs (or the pixel area) hole_rad = []#Need to check and implement cam_rad = [2.26,3.96,3.87,4.,4.45,2.86,5.25]#Found from the field of view calculation sec_rad = [0.*u.m,0.*u.m,0.*u.m,2.7*u.m,0.*u.m,1.*u.m,1.8*u.m] sct = [False,False,False,True,False,True,True] muon_cuts = {'Name':names,'TailCuts':TailCuts,'Impact':impact,'RingWidth':ringwidth,'TotalPix':TotalPix,'MinPix':MinPix,'CamRad':cam_rad,'SecRad':sec_rad,'SCT':sct,'AngPixW':AngPixelWidth} #print(muon_cuts) muonringlist = []#[None] * len(event.dl0.tels_with_data) muonintensitylist = []#[None] * len(event.dl0.tels_with_data) tellist = [] #for tid in event.dl0.tels_with_data: # tellist.append(tid) muon_event_param = {'TelIds':tellist,'MuonRingParams':muonringlist,'MuonIntensityParams':muonintensitylist} #muonringparam = None #muonintensityparam = None for telid in event.dl0.tels_with_data: #print("Analysing muon event for tel",telid) muonringparam = None muonintensityparam = None #idx = muon_event_param['TelIds'].index(telid) x, y = event.inst.pixel_pos[telid] #image = event.dl1.tel[telid].calibrated_image image = event.dl1.tel[telid].image[0] # Get geometry geom = None if geom_dict is not None and telid in geom_dict: geom = geom_dict[telid] else: log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) log.debug("[calib] Camera geometry found") if geom_dict is not None: geom_dict[telid] = geom teldes = event.inst.subarray.tel[telid] dict_index = muon_cuts['Name'].index(str(teldes)) #print('found an index of',dict_index,'for camera',geom.cam_id) #tailcuts = (5.,7.) tailcuts = muon_cuts['TailCuts'][dict_index] #print("Tailcuts are",tailcuts[0],tailcuts[1]) #rot_angle = 0.*u.deg #if event.inst.optical_foclen[telid] > 10.*u.m and event.dl0.tel[telid].num_pixels != 1764: #rot_angle = -100.14*u.deg clean_mask = tailcuts_clean(geom,image,picture_thresh=tailcuts[0],boundary_thresh=tailcuts[1]) camera_coord = CameraFrame(x=x,y=y,z=np.zeros(x.shape)*u.m, focal_length = event.inst.optical_foclen[telid], rotation=geom.pix_rotation) #print("Camera",geom.cam_id,"focal length",event.inst.optical_foclen[telid],"rotation",geom.pix_rotation) #TODO: correct this hack for values over 90 altval = event.mcheader.run_array_direction[1] if (altval > np.pi/2.): altval = np.pi/2. altaz = HorizonFrame(alt=altval*u.rad,az=event.mcheader.run_array_direction[0]*u.rad) nom_coord = camera_coord.transform_to(NominalFrame(array_direction=altaz,pointing_direction=altaz)) x = nom_coord.x.to(u.deg) y = nom_coord.y.to(u.deg) img = image*clean_mask noise = 5. weight = img / (img+noise) muonring = ChaudhuriKunduRingFitter(None) #print("img:",np.sum(image),"mask:",np.sum(clean_mask), "x=",x,"y=",y) if not sum(img):#Nothing left after tail cuts continue muonringparam = muonring.fit(x,y,image*clean_mask) #muonringparam = muonring.fit(x,y,weight) dist = np.sqrt(np.power(x-muonringparam.ring_center_x,2) + np.power(y-muonringparam.ring_center_y,2)) ring_dist = np.abs(dist-muonringparam.ring_radius) muonringparam = muonring.fit(x,y,img*(ring_dist<muonringparam.ring_radius*0.4)) dist = np.sqrt(np.power(x-muonringparam.ring_center_x,2) + np.power(y-muonringparam.ring_center_y,2)) ring_dist = np.abs(dist-muonringparam.ring_radius) #print("1: x",muonringparam.ring_center_x,"y",muonringparam.ring_center_y,"radius",muonringparam.ring_radius) muonringparam = muonring.fit(x,y,img*(ring_dist<muonringparam.ring_radius*0.4)) #print("2: x",muonringparam.ring_center_x,"y",muonringparam.ring_center_y,"radius",muonringparam.ring_radius) muonringparam.tel_id = telid muonringparam.run_id = event.dl0.run_id muonringparam.event_id = event.dl0.event_id dist_mask = np.abs(dist-muonringparam.ring_radius)<muonringparam.ring_radius*0.4 rad = list() cx = list() cy = list() mc_x = event.mc.core_x mc_y = event.mc.core_y pix_im = image*dist_mask nom_dist = np.sqrt(np.power(muonringparam.ring_center_x,2)+np.power(muonringparam.ring_center_y,2)) #numpix = event.dl0.tel[telid].num_pixels minpix = muon_cuts['MinPix'][dict_index]#0.06*numpix #or 8% mir_rad = np.sqrt(event.inst.mirror_dish_area[telid]/(np.pi))#need to consider units? (what about hole? Area is then less...) #Camera containment radius - better than nothing - guess pixel diameter of 0.11, all cameras are perfectly circular cam_rad = np.sqrt(numpix*0.11/(2.*np.pi)) if(np.sum(pix_im>tailcuts[0])>0.1*minpix and np.sum(pix_im)>minpix and nom_dist < muon_cuts['CamRad'][dict_index]*u.deg and muonringparam.ring_radius<1.5*u.deg and muonringparam.ring_radius>1.*u.deg): #Guess HESS is 0.16 #sec_rad = 0.*u.m #sct = False #if numpix == 2048 and mir_rad > 2.*u.m and mir_rad < 2.1*u.m: # sec_rad = 1.*u.m # sct = True #Store muon ring parameters (passing cuts stage 1) #muonringlist[idx] = muonringparam tellist.append(telid) muonringlist.append(muonringparam) muonintensitylist.append(None) #embed() ctel = MuonLineIntegrate(mir_rad,0.2*u.m,pixel_width=muon_cuts['AngPixW'][dict_index]*u.deg,sct_flag=muon_cuts['SCT'][dict_index], secondary_radius=muon_cuts['SecRad'][dict_index]) if (image.shape[0] == muon_cuts['TotalPix'][dict_index]): muonintensityoutput = ctel.fit_muon(muonringparam.ring_center_x,muonringparam.ring_center_y,muonringparam.ring_radius,x[dist_mask],y[dist_mask],image[dist_mask]) muonintensityoutput.tel_id = telid muonintensityoutput.run_id = event.dl0.run_id muonintensityoutput.event_id = event.dl0.event_id muonintensityoutput.mask = dist_mask print("Tel",telid,"Impact parameter = ",muonintensityoutput.impact_parameter,"mir_rad",mir_rad,"ring_width=",muonintensityoutput.ring_width) #if(muonintensityoutput.impact_parameter > muon_cuts['Impact'][dict_index][1]*mir_rad or muonintensityoutput.impact_parameter < muon_cuts['Impact'][dict_index][0]*mir_rad): # print("Failed on impact parameter low cut",muon_cuts['Impact'][dict_index][0]*mir_rad,"high cut",muon_cuts['Impact'][dict_index][1]*mir_rad,"for",geom.cam_id) #if(muonintensityoutput.ring_width > muon_cuts['RingWidth'][dict_index][1]*u.deg or muonintensityoutput.ring_width < muon_cuts['RingWidth'][dict_index][0]*u.deg): # print("Failed on ring width low cut",muon_cuts['RingWidth'][dict_index][0]*u.deg,"high cut",muon_cuts['RingWidth'][dict_index][1]*u.deg,"for ",geom.cam_id) #print("Cuts <",muon_cuts["Impact"][dict_index][1]*mir_rad,"cuts >",muon_cuts['Impact'][dict_index][0]*u.m,'ring_width < ',muon_cuts['RingWidth'][dict_index][1]*u.deg,'ring_width >',muon_cuts['RingWidth'][dict_index][0]*u.deg) if( muonintensityoutput.impact_parameter < muon_cuts['Impact'][dict_index][1]*mir_rad and muonintensityoutput.impact_parameter > muon_cuts['Impact'][dict_index][0]*u.m and muonintensityoutput.ring_width < muon_cuts['RingWidth'][dict_index][1]*u.deg and muonintensityoutput.ring_width > muon_cuts['RingWidth'][dict_index][0]*u.deg ): muonintensityparam = muonintensityoutput idx = tellist.index(telid) muonintensitylist[idx] = muonintensityparam print("Muon in tel",telid,"# tels in event=",len(event.dl0.tels_with_data)) else: continue #print("Fitted ring centre (2):",muonringparam.ring_center_x,muonringparam.ring_center_y) #return muonringparam, muonintensityparam return muon_event_param
table = "CameraTable_VersionFeb2016_TelID" for tel_id in container.dl0.tels_with_data: x, y = event.meta.pixel_pos[tel_id] if geom == 0: geom = io.CameraGeometry.guess(x, y,event.meta.optical_foclen[tel_id]) image = apply_mc_calibration(event.dl0.tel[tel_id].adc_sums[0], tel_id) if image.shape[0] >1000: continue clean_mask = tailcuts_clean(geom,image,1,picture_thresh=5,boundary_thresh=7) camera_coord = CameraFrame(x=x,y=y,z=np.zeros(x.shape)*u.m) nom_coord = camera_coord.transform_to(NominalFrame(array_direction=[container.mc.alt,container.mc.az], pointing_direction=[container.mc.alt,container.mc.az], focal_length=tel['TelescopeTable_VersionFeb2016'][tel['TelescopeTable_VersionFeb2016']['TelID']==tel_id]['FL'][0]*u.m)) x = nom_coord.x.to(u.deg) y = nom_coord.y.to(u.deg) img = image*clean_mask noise = 5 weight = img / (img+noise) centre_x,centre_y,radius = chaudhuri_kundu_circle_fit(x,y,image*clean_mask) dist = np.sqrt(np.power(x-centre_x,2) + np.power(y-centre_y,2)) ring_dist = np.abs(dist-radius) centre_x,centre_y,radius = chaudhuri_kundu_circle_fit(x,y,image*(ring_dist<radius*0.3)) dist = np.sqrt(np.power(x-centre_x,2) + np.power(y-centre_y,2))
def analyze_muon_event(event, params=None, geom_dict=None): """ Generic muon event analyzer. Parameters ---------- event : ctapipe dl1 event container Returns ------- muonringparam, muonintensityparam : MuonRingParameter and MuonIntensityParameter container event """ # Declare a dict to define the muon cuts (ASTRI and SCT missing) muon_cuts = {} names = [ 'LST:LSTCam', 'MST:NectarCam', 'MST:FlashCam', 'MST-SCT:SCTCam', 'SST-1M:DigiCam', 'SST-GCT:CHEC', 'SST-ASTRI:ASTRICam' ] TailCuts = [(5, 7), (5, 7), (10, 12), (5, 7), (5, 7), (5, 7), (5, 7)] #10,12? impact = [(0.2, 0.9), (0.1, 0.95), (0.2, 0.9), (0.2, 0.9), (0.1, 0.95), (0.1, 0.95), (0.1, 0.95)] ringwidth = [(0.04, 0.08), (0.02, 0.1), (0.01, 0.1), (0.02, 0.1), (0.01, 0.5), (0.02, 0.2), (0.02, 0.2)] TotalPix = [1855., 1855., 1764., 11328., 1296., 2048., 2368.] #8% (or 6%) as limit MinPix = [148., 148., 141., 680., 104., 164., 142.] #Need to either convert from the pixel area in m^2 or check the camera specs AngPixelWidth = [0.1, 0.2, 0.18, 0.067, 0.24, 0.2, 0.17] #Found from TDRs (or the pixel area) hole_rad = [] #Need to check and implement cam_rad = [2.26, 3.96, 3.87, 4., 4.45, 2.86, 5.25] #Found from the field of view calculation sec_rad = [ 0. * u.m, 0. * u.m, 0. * u.m, 2.7 * u.m, 0. * u.m, 1. * u.m, 1.8 * u.m ] sct = [False, False, False, True, False, True, True] muon_cuts = { 'Name': names, 'TailCuts': TailCuts, 'Impact': impact, 'RingWidth': ringwidth, 'TotalPix': TotalPix, 'MinPix': MinPix, 'CamRad': cam_rad, 'SecRad': sec_rad, 'SCT': sct, 'AngPixW': AngPixelWidth } #print(muon_cuts) muonringlist = [] #[None] * len(event.dl0.tels_with_data) muonintensitylist = [] #[None] * len(event.dl0.tels_with_data) tellist = [] #for tid in event.dl0.tels_with_data: # tellist.append(tid) muon_event_param = { 'TelIds': tellist, 'MuonRingParams': muonringlist, 'MuonIntensityParams': muonintensitylist } #muonringparam = None #muonintensityparam = None for telid in event.dl0.tels_with_data: #print("Analysing muon event for tel",telid) muonringparam = None muonintensityparam = None #idx = muon_event_param['TelIds'].index(telid) x, y = event.inst.pixel_pos[telid] #image = event.dl1.tel[telid].calibrated_image image = event.dl1.tel[telid].image[0] # Get geometry geom = None if geom_dict is not None and telid in geom_dict: geom = geom_dict[telid] else: log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.inst.pixel_pos[telid], event.inst.optical_foclen[telid]) log.debug("[calib] Camera geometry found") if geom_dict is not None: geom_dict[telid] = geom teldes = event.inst.subarray.tel[telid] dict_index = muon_cuts['Name'].index(str(teldes)) #print('found an index of',dict_index,'for camera',geom.cam_id) #tailcuts = (5.,7.) tailcuts = muon_cuts['TailCuts'][dict_index] #print("Tailcuts are",tailcuts[0],tailcuts[1]) #rot_angle = 0.*u.deg #if event.inst.optical_foclen[telid] > 10.*u.m and event.dl0.tel[telid].num_pixels != 1764: #rot_angle = -100.14*u.deg clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) camera_coord = CameraFrame( x=x, y=y, z=np.zeros(x.shape) * u.m, focal_length=event.inst.optical_foclen[telid], rotation=geom.pix_rotation) #print("Camera",geom.cam_id,"focal length",event.inst.optical_foclen[telid],"rotation",geom.pix_rotation) #TODO: correct this hack for values over 90 altval = event.mcheader.run_array_direction[1] if (altval > np.pi / 2.): altval = np.pi / 2. altaz = HorizonFrame(alt=altval * u.rad, az=event.mcheader.run_array_direction[0] * u.rad) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=altaz, pointing_direction=altaz)) x = nom_coord.x.to(u.deg) y = nom_coord.y.to(u.deg) img = image * clean_mask noise = 5. weight = img / (img + noise) muonring = ChaudhuriKunduRingFitter(None) #print("img:",np.sum(image),"mask:",np.sum(clean_mask), "x=",x,"y=",y) if not sum(img): #Nothing left after tail cuts continue muonringparam = muonring.fit(x, y, image * clean_mask) #muonringparam = muonring.fit(x,y,weight) dist = np.sqrt( np.power(x - muonringparam.ring_center_x, 2) + np.power(y - muonringparam.ring_center_y, 2)) ring_dist = np.abs(dist - muonringparam.ring_radius) muonringparam = muonring.fit( x, y, img * (ring_dist < muonringparam.ring_radius * 0.4)) dist = np.sqrt( np.power(x - muonringparam.ring_center_x, 2) + np.power(y - muonringparam.ring_center_y, 2)) ring_dist = np.abs(dist - muonringparam.ring_radius) #print("1: x",muonringparam.ring_center_x,"y",muonringparam.ring_center_y,"radius",muonringparam.ring_radius) muonringparam = muonring.fit( x, y, img * (ring_dist < muonringparam.ring_radius * 0.4)) #print("2: x",muonringparam.ring_center_x,"y",muonringparam.ring_center_y,"radius",muonringparam.ring_radius) muonringparam.tel_id = telid muonringparam.run_id = event.dl0.run_id muonringparam.event_id = event.dl0.event_id dist_mask = np.abs( dist - muonringparam.ring_radius) < muonringparam.ring_radius * 0.4 rad = list() cx = list() cy = list() mc_x = event.mc.core_x mc_y = event.mc.core_y pix_im = image * dist_mask nom_dist = np.sqrt( np.power(muonringparam.ring_center_x, 2) + np.power(muonringparam.ring_center_y, 2)) #numpix = event.dl0.tel[telid].num_pixels minpix = muon_cuts['MinPix'][dict_index] #0.06*numpix #or 8% mir_rad = np.sqrt( event.inst.mirror_dish_area[telid] / (np.pi) ) #need to consider units? (what about hole? Area is then less...) #Camera containment radius - better than nothing - guess pixel diameter of 0.11, all cameras are perfectly circular cam_rad = np.sqrt(numpix*0.11/(2.*np.pi)) if (np.sum(pix_im > tailcuts[0]) > 0.1 * minpix and np.sum(pix_im) > minpix and nom_dist < muon_cuts['CamRad'][dict_index] * u.deg and muonringparam.ring_radius < 1.5 * u.deg and muonringparam.ring_radius > 1. * u.deg): #Guess HESS is 0.16 #sec_rad = 0.*u.m #sct = False #if numpix == 2048 and mir_rad > 2.*u.m and mir_rad < 2.1*u.m: # sec_rad = 1.*u.m # sct = True #Store muon ring parameters (passing cuts stage 1) #muonringlist[idx] = muonringparam tellist.append(telid) muonringlist.append(muonringparam) muonintensitylist.append(None) #embed() ctel = MuonLineIntegrate( mir_rad, 0.2 * u.m, pixel_width=muon_cuts['AngPixW'][dict_index] * u.deg, sct_flag=muon_cuts['SCT'][dict_index], secondary_radius=muon_cuts['SecRad'][dict_index]) if (image.shape[0] == muon_cuts['TotalPix'][dict_index]): muonintensityoutput = ctel.fit_muon( muonringparam.ring_center_x, muonringparam.ring_center_y, muonringparam.ring_radius, x[dist_mask], y[dist_mask], image[dist_mask]) muonintensityoutput.tel_id = telid muonintensityoutput.run_id = event.dl0.run_id muonintensityoutput.event_id = event.dl0.event_id muonintensityoutput.mask = dist_mask print("Tel", telid, "Impact parameter = ", muonintensityoutput.impact_parameter, "mir_rad", mir_rad, "ring_width=", muonintensityoutput.ring_width) #if(muonintensityoutput.impact_parameter > muon_cuts['Impact'][dict_index][1]*mir_rad or muonintensityoutput.impact_parameter < muon_cuts['Impact'][dict_index][0]*mir_rad): # print("Failed on impact parameter low cut",muon_cuts['Impact'][dict_index][0]*mir_rad,"high cut",muon_cuts['Impact'][dict_index][1]*mir_rad,"for",geom.cam_id) #if(muonintensityoutput.ring_width > muon_cuts['RingWidth'][dict_index][1]*u.deg or muonintensityoutput.ring_width < muon_cuts['RingWidth'][dict_index][0]*u.deg): # print("Failed on ring width low cut",muon_cuts['RingWidth'][dict_index][0]*u.deg,"high cut",muon_cuts['RingWidth'][dict_index][1]*u.deg,"for ",geom.cam_id) #print("Cuts <",muon_cuts["Impact"][dict_index][1]*mir_rad,"cuts >",muon_cuts['Impact'][dict_index][0]*u.m,'ring_width < ',muon_cuts['RingWidth'][dict_index][1]*u.deg,'ring_width >',muon_cuts['RingWidth'][dict_index][0]*u.deg) if (muonintensityoutput.impact_parameter < muon_cuts['Impact'][dict_index][1] * mir_rad and muonintensityoutput.impact_parameter > muon_cuts['Impact'][dict_index][0] * u.m and muonintensityoutput.ring_width < muon_cuts['RingWidth'][dict_index][1] * u.deg and muonintensityoutput.ring_width > muon_cuts['RingWidth'][dict_index][0] * u.deg): muonintensityparam = muonintensityoutput idx = tellist.index(telid) muonintensitylist[idx] = muonintensityparam print("Muon in tel", telid, "# tels in event=", len(event.dl0.tels_with_data)) else: continue #print("Fitted ring centre (2):",muonringparam.ring_center_x,muonringparam.ring_center_y) #return muonringparam, muonintensityparam return muon_event_param
angpixwidth = pixwidth / ( teloptconfigdict['focallengths'][dictindex]) * ( 180. / np.pi) * (u.deg / u.m) # This is not correct... # print('Area of the pixel is:',geom.pix_area,'approx width as', # pixwidth,angpixwidth) # 1/0 camera_coord = CameraFrame(x=x, y=y, z=np.zeros(x.shape) * u.m) optics = event.inst.subarray.tel[tel_id].optics foclen = optics.equivalent_focal_length frame = NominalFrame( array_direction=[container.mc.alt, container.mc.az], pointing_direction=[container.mc.alt, container.mc.az], focal_length=foclen) nom_coord = camera_coord.transform_to(frame) x = nom_coord.x.to(u.deg) y = nom_coord.y.to(u.deg) img = image * clean_mask noise = 5 weight = img / (img + noise) circlefitter = ChaudhuriKunduRingFitter() ringoutparams = circlefitter.fit(x, y, image * clean_mask) # print('RingOutParams',ringoutparams) centre_x = ringoutparams.ring_center_x centre_y = ringoutparams.ring_center_y radius = ringoutparams.ring_radius
dictindex]) * (180. / np.pi) * ( u.deg / u.m) # This is not correct... # print('Area of the pixel is:',geom.pix_area,'approx width as', # pixwidth,angpixwidth) # 1/0 camera_coord = CameraFrame(x=x, y=y, z=np.zeros(x.shape) * u.m) optics = event.inst.subarray.tel[tel_id].optics foclen = optics.effective_focal_length frame = NominalFrame(array_direction=[container.mc.alt, container.mc.az], pointing_direction=[container.mc.alt, container.mc.az], focal_length=foclen) nom_coord = camera_coord.transform_to(frame) x = nom_coord.x.to(u.deg) y = nom_coord.y.to(u.deg) img = image * clean_mask noise = 5 weight = img / (img + noise) circlefitter = ChaudhuriKunduRingFitter() ringoutparams = circlefitter.fit(x, y, image * clean_mask) # print('RingOutParams',ringoutparams) centre_x = ringoutparams.ring_center_x centre_y = ringoutparams.ring_center_y radius = ringoutparams.ring_radius
plt.pause(0.01) if args.write: plt.savefig('CT{:03d}_EV{:010d}_S{:02d}.png' .format(args.tel, event.dl0.event_id, ii)) else: # display integrated event: im = event.dl0.tel[args.tel].adc_sums[args.channel] im = apply_mc_calibration(im, args.tel) disp.image = im if args.hillas: clean_mask = reco.cleaning.tailcuts_clean(geom,im,1,picture_thresh=10,boundary_thresh=5) camera_coord = CameraFrame(x=x,y=y,z=np.zeros(x.shape)*u.m) nom_coord = camera_coord.transform_to(NominalFrame(array_direction=[70*u.deg,0*u.deg], pointing_direction=[70*u.deg,0*u.deg], focal_length=tel['TelescopeTable_VersionFeb2016'][tel['TelescopeTable_VersionFeb2016']['TelID']==args.tel]['FL'][0]*u.m)) image = np.asanyarray(im * clean_mask, dtype=np.float64) nom_x = nom_coord.x nom_y = nom_coord.y hillas = reco.hillas_parameters(x,y,im * clean_mask) hillas_nom = reco.hillas_parameters(nom_x,nom_y,im * clean_mask) print (hillas) print (hillas_nom) disp.image = im * clean_mask disp.overlay_moments(hillas, color='seagreen', linewidth=3)
def plot_muon_event(event, muonparams, args=None): if muonparams['MuonRingParams'] is not None: # Plot the muon event and overlay muon parameters fig = plt.figure(figsize=(16, 7)) colorbar = None colorbar2 = None #for tel_id in event.dl0.tels_with_data: for tel_id in muonparams['TelIds']: idx = muonparams['TelIds'].index(tel_id) if not muonparams['MuonRingParams'][idx]: continue #otherwise... npads = 2 # Only create two pads if there is timing information extracted # from the calibration ax1 = fig.add_subplot(1, npads, 1) plotter = CameraPlotter(event) image = event.dl1.tel[tel_id].image[0] geom = event.inst.subarray.tel[tel_id].camera tailcuts = (5., 7.) # Try a higher threshold for if geom.cam_id == 'FlashCam': tailcuts = (10., 12.) clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) signals = image * clean_mask #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y) muon_incl = np.sqrt(muonparams['MuonRingParams'][idx].ring_center_x**2. + muonparams['MuonRingParams'][idx].ring_center_y**2.) muon_phi = np.arctan(muonparams['MuonRingParams'][idx].ring_center_y / muonparams['MuonRingParams'][idx].ring_center_x) rotr_angle = geom.pix_rotation # if event.inst.optical_foclen[tel_id] > 10.*u.m and # event.dl0.tel[tel_id].num_pixels != 1764: if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam': #print("Resetting the rotation angle") rotr_angle = 0. * u.deg # Convert to camera frame (centre & radius) altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az) ring_nominal = NominalFrame(x=muonparams['MuonRingParams'][idx].ring_center_x, y=muonparams['MuonRingParams'][idx].ring_center_y, array_direction=altaz, pointing_direction=altaz) # embed() ring_camcoord = ring_nominal.transform_to(CameraFrame( pointing_direction=altaz, focal_length=event.inst.optical_foclen[tel_id], rotation=rotr_angle)) centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2) centroid = (ring_camcoord.x.value, ring_camcoord.y.value) ringrad_camcoord = muonparams['MuonRingParams'][idx].ring_radius.to(u.rad) \ * event.inst.optical_foclen[tel_id] * 2. # But not FC? px, py = event.inst.pixel_pos[tel_id] flen = event.inst.optical_foclen[tel_id] camera_coord = CameraFrame(x=px, y=py, z=np.zeros(px.shape) * u.m, focal_length=flen, rotation=geom.pix_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=altaz, pointing_direction=altaz) ) px = nom_coord.x.to(u.deg) py = nom_coord.y.to(u.deg) dist = np.sqrt(np.power( px - muonparams['MuonRingParams'][idx].ring_center_x, 2) + np.power(py - muonparams['MuonRingParams'][idx].ring_center_y, 2)) ring_dist = np.abs(dist - muonparams['MuonRingParams'][idx].ring_radius) pixRmask = ring_dist < muonparams['MuonRingParams'][idx].ring_radius * 0.4 #if muonparams[1] is not None: if muonparams['MuonIntensityParams'][idx] is not None: signals *= muonparams['MuonIntensityParams'][idx].mask camera1 = plotter.draw_camera(tel_id, signals, ax1) cmaxmin = (max(signals) - min(signals)) cmin = min(signals) if not cmin: cmin = 1. if not cmaxmin: cmaxmin = 1. cmap_charge = colors.LinearSegmentedColormap.from_list( 'cmap_c', [(0 / cmaxmin, 'darkblue'), (np.abs(cmin) / cmaxmin, 'black'), (2.0 * np.abs(cmin) / cmaxmin, 'blue'), (2.5 * np.abs(cmin) / cmaxmin, 'green'), (1, 'yellow')] ) camera1.pixels.set_cmap(cmap_charge) if not colorbar: camera1.add_colorbar(ax=ax1, label=" [photo-electrons]") colorbar = camera1.colorbar else: camera1.colorbar = colorbar camera1.update(True) camera1.add_ellipse(centroid, ringrad_camcoord.value, ringrad_camcoord.value, 0., 0., color="red") if muonparams['MuonIntensityParams'][idx] is not None: # continue #Comment this...(should ringwidthfrac also be *0.5?) ringwidthfrac = muonparams['MuonIntensityParams'][idx].ring_width / muonparams['MuonRingParams'][idx].ring_radius ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac) ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac) camera1.add_ellipse(centroid, ringrad_inner.value, ringrad_inner.value, 0., 0., color="magenta") camera1.add_ellipse(centroid, ringrad_outer.value, ringrad_outer.value, 0., 0., color="magenta") npads = 2 ax2 = fig.add_subplot(1, npads, npads) pred = muonparams['MuonIntensityParams'][idx].prediction if len(pred) != np.sum(muonparams['MuonIntensityParams'][idx].mask): print("Warning! Lengths do not match...len(pred)=", len(pred), "len(mask)=", np.sum(muonparams['MuonIntensityParams'][idx].mask)) # Numpy broadcasting - fill in the shape plotpred = np.zeros(image.shape) plotpred[muonparams['MuonIntensityParams'][idx].mask == True] = pred camera2 = plotter.draw_camera(tel_id, plotpred, ax2) if np.isnan(max(plotpred)) or np.isnan(min(plotpred)): print("nan prediction, skipping...") continue c2maxmin = (max(plotpred) - min(plotpred)) if not c2maxmin: c2maxmin = 1. c2map_charge = colors.LinearSegmentedColormap.from_list( 'c2map_c', [(0 / c2maxmin, 'darkblue'), (np.abs(min(plotpred)) / c2maxmin, 'black'), (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'), (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'), (1, 'yellow')] ) camera2.pixels.set_cmap(c2map_charge) if not colorbar2: camera2.add_colorbar(ax=ax2, label=" [photo-electrons]") colorbar2 = camera2.colorbar else: camera2.colorbar = colorbar2 camera2.update(True) plt.pause(1.) # make shorter # plt.pause(0.1) # if pp is not None: # pp.savefig(fig) #fig.savefig(str(args.output_path) + "_" + # str(event.dl0.event_id) + '.png') plt.close()
def plot_muon_event(event, muonparams, geom_dict=None, args=None): if muonparams[0] is not None: # Plot the muon event and overlay muon parameters fig = plt.figure(figsize=(16, 7)) # if args.display: # plt.show(block=False) #pp = PdfPages(args.output_path) if args.output_path is not None else None # pp = None #For now, need to correct this colorbar = None colorbar2 = None for tel_id in event.dl0.tels_with_data: npads = 2 # Only create two pads if there is timing information extracted # from the calibration ax1 = fig.add_subplot(1, npads, 1) plotter = CameraPlotter(event, geom_dict) #image = event.dl1.tel[tel_id].calibrated_image image = event.dl1.tel[tel_id].image[0] # Get geometry geom = None if geom_dict is not None and tel_id in geom_dict: geom = geom_dict[tel_id] else: #log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.inst.pixel_pos[tel_id], event.inst.optical_foclen[tel_id]) #log.debug("[calib] Camera geometry found") if geom_dict is not None: geom_dict[tel_id] = geom tailcuts = (5., 7.) # Try a higher threshold for if geom.cam_id == 'FlashCam': tailcuts = (10., 12.) #print("Using Tail Cuts:",tailcuts) clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) signals = image * clean_mask #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y) muon_incl = np.sqrt(muonparams[0].ring_center_x**2. + muonparams[0].ring_center_y**2.) muon_phi = np.arctan(muonparams[0].ring_center_y / muonparams[0].ring_center_x) rotr_angle = geom.pix_rotation # if event.inst.optical_foclen[tel_id] > 10.*u.m and # event.dl0.tel[tel_id].num_pixels != 1764: if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam': #print("Resetting the rotation angle") rotr_angle = 0. * u.deg # Convert to camera frame (centre & radius) altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az) ring_nominal = NominalFrame(x=muonparams[0].ring_center_x, y=muonparams[0].ring_center_y, array_direction=altaz, pointing_direction=altaz) # embed() ring_camcoord = ring_nominal.transform_to(CameraFrame( pointing_direction=altaz, focal_length=event.inst.optical_foclen[tel_id], rotation=rotr_angle)) centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2) centroid = (ring_camcoord.x.value, ring_camcoord.y.value) ringrad_camcoord = muonparams[0].ring_radius.to(u.rad) \ * event.inst.optical_foclen[tel_id] * 2. # But not FC? #rot_angle = 0.*u.deg # if event.inst.optical_foclen[tel_id] > 10.*u.m and event.dl0.tel[tel_id].num_pixels != 1764: #rot_angle = -100.14*u.deg px, py = event.inst.pixel_pos[tel_id] flen = event.inst.optical_foclen[tel_id] camera_coord = CameraFrame(x=px, y=py, z=np.zeros(px.shape) * u.m, focal_length=flen, rotation=geom.pix_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=altaz, pointing_direction=altaz) ) #,focal_length = event.inst.optical_foclen[tel_id])) # tel['TelescopeTable_VersionFeb2016'][tel['TelescopeTable_VersionFeb2016']['TelID']==telid]['FL'][0]*u.m)) px = nom_coord.x.to(u.deg) py = nom_coord.y.to(u.deg) dist = np.sqrt(np.power( px - muonparams[0].ring_center_x, 2) + np.power(py - muonparams[0].ring_center_y, 2)) ring_dist = np.abs(dist - muonparams[0].ring_radius) pixRmask = ring_dist < muonparams[0].ring_radius * 0.4 if muonparams[1] is not None: signals *= muonparams[1].mask camera1 = plotter.draw_camera(tel_id, signals, ax1) cmaxmin = (max(signals) - min(signals)) if not cmaxmin: cmaxmin = 1. cmap_charge = colors.LinearSegmentedColormap.from_list( 'cmap_c', [(0 / cmaxmin, 'darkblue'), (np.abs(min(signals)) / cmaxmin, 'black'), (2.0 * np.abs(min(signals)) / cmaxmin, 'blue'), (2.5 * np.abs(min(signals)) / cmaxmin, 'green'), (1, 'yellow')] ) camera1.pixels.set_cmap(cmap_charge) if not colorbar: camera1.add_colorbar(ax=ax1, label=" [photo-electrons]") colorbar = camera1.colorbar else: camera1.colorbar = colorbar camera1.update(True) camera1.add_ellipse(centroid, ringrad_camcoord.value, ringrad_camcoord.value, 0., 0., color="red") # ax1.set_title("CT {} ({}) - Mean pixel charge" # .format(tel_id, geom_dict[tel_id].cam_id)) if muonparams[1] is not None: # continue #Comment this...(should ringwidthfrac also be *0.5?) ringwidthfrac = muonparams[ 1].ring_width / muonparams[0].ring_radius ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac) ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac) camera1.add_ellipse(centroid, ringrad_inner.value, ringrad_inner.value, 0., 0., color="magenta") camera1.add_ellipse(centroid, ringrad_outer.value, ringrad_outer.value, 0., 0., color="magenta") npads = 2 ax2 = fig.add_subplot(1, npads, npads) pred = muonparams[1].prediction if len(pred) != np.sum(muonparams[1].mask): print("Warning! Lengths do not match...len(pred)=", len(pred), "len(mask)=", np.sum(muonparams[1].mask)) # Numpy broadcasting - fill in the shape plotpred = np.zeros(image.shape) plotpred[muonparams[1].mask == True] = pred camera2 = plotter.draw_camera(tel_id, plotpred, ax2) c2maxmin = (max(plotpred) - min(plotpred)) if not c2maxmin: c2maxmin = 1. c2map_charge = colors.LinearSegmentedColormap.from_list( 'c2map_c', [(0 / c2maxmin, 'darkblue'), (np.abs(min(plotpred)) / c2maxmin, 'black'), (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'), (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'), (1, 'yellow')] ) camera2.pixels.set_cmap(c2map_charge) if not colorbar2: camera2.add_colorbar(ax=ax2, label=" [photo-electrons]") colorbar2 = camera2.colorbar else: camera2.colorbar = colorbar2 camera2.update(True) plt.pause(1.) # make shorter # plt.pause(0.1) # if pp is not None: # pp.savefig(fig) fig.savefig(str(args.output_path) + "_" + str(event.dl0.event_id) + '.png') plt.close()
def analyze_muon_event(event): """ Generic muon event analyzer. Parameters ---------- event : ctapipe dl1 event container Returns ------- muonringparam, muonintensityparam : MuonRingParameter and MuonIntensityParameter container event """ names = [ 'LST:LSTCam', 'MST:NectarCam', 'MST:FlashCam', 'MST-SCT:SCTCam', 'SST-1M:DigiCam', 'SST-GCT:CHEC', 'SST-ASTRI:ASTRICam', 'SST-ASTRI:CHEC' ] tail_cuts = [(5, 7), (5, 7), (10, 12), (5, 7), (5, 7), (5, 7), (5, 7), (5, 7)] # 10, 12? impact = [(0.2, 0.9), (0.1, 0.95), (0.2, 0.9), (0.2, 0.9), (0.1, 0.95), (0.1, 0.95), (0.1, 0.95), (0.1, 0.95)] * u.m ringwidth = [(0.04, 0.08), (0.02, 0.1), (0.01, 0.1), (0.02, 0.1), (0.01, 0.5), (0.02, 0.2), (0.02, 0.2), (0.02, 0.2)] * u.deg total_pix = [1855., 1855., 1764., 11328., 1296., 2048., 2368., 2048] # 8% (or 6%) as limit min_pix = [148., 148., 141., 680., 104., 164., 142., 164] # Need to either convert from the pixel area in m^2 or check the camera specs ang_pixel_width = [0.1, 0.2, 0.18, 0.067, 0.24, 0.2, 0.17, 0.2, 0.163 ] * u.deg # Found from TDRs (or the pixel area) hole_rad = [ 0.308 * u.m, 0.244 * u.m, 0.244 * u.m, 4.3866 * u.m, 0.160 * u.m, 0.130 * u.m, 0.171 * u.m, 0.171 * u.m ] # Assuming approximately spherical hole cam_rad = [2.26, 3.96, 3.87, 4., 4.45, 2.86, 5.25, 2.86] * u.deg # Above found from the field of view calculation sec_rad = [ 0. * u.m, 0. * u.m, 0. * u.m, 2.7 * u.m, 0. * u.m, 1. * u.m, 1.8 * u.m, 1.8 * u.m ] sct = [False, False, False, True, False, True, True, True] muon_cuts = { 'Name': names, 'tail_cuts': tail_cuts, 'Impact': impact, 'RingWidth': ringwidth, 'total_pix': total_pix, 'min_pix': min_pix, 'CamRad': cam_rad, 'SecRad': sec_rad, 'SCT': sct, 'AngPixW': ang_pixel_width, 'HoleRad': hole_rad } logger.debug(muon_cuts) muonringlist = [] # [None] * len(event.dl0.tels_with_data) muonintensitylist = [] # [None] * len(event.dl0.tels_with_data) tellist = [] muon_event_param = { 'TelIds': tellist, 'MuonRingParams': muonringlist, 'MuonIntensityParams': muonintensitylist } for telid in event.dl0.tels_with_data: logger.debug("Analysing muon event for tel %d", telid) image = event.dl1.tel[telid].image[0] # Get geometry teldes = event.inst.subarray.tel[telid] geom = teldes.camera x, y = geom.pix_x, geom.pix_y dict_index = muon_cuts['Name'].index(str(teldes)) logger.debug('found an index of %d for camera %d', dict_index, geom.cam_id) tailcuts = muon_cuts['tail_cuts'][dict_index] logger.debug("Tailcuts are %s", tailcuts) clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) camera_coord = CameraFrame( x=x, y=y, focal_length=teldes.optics.equivalent_focal_length, rotation=geom.pix_rotation) # TODO: correct this hack for values over 90 altval = event.mcheader.run_array_direction[1] if altval > np.pi / 2.: altval = np.pi / 2. altaz = HorizonFrame(alt=altval * u.rad, az=event.mcheader.run_array_direction[0] * u.rad) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=altaz, pointing_direction=altaz)) x = nom_coord.x.to(u.deg) y = nom_coord.y.to(u.deg) img = image * clean_mask muonring = ChaudhuriKunduRingFitter(None) logger.debug("img: %s mask: %s, x=%s y= %s", np.sum(image), np.sum(clean_mask), x, y) if not sum(img): # Nothing left after tail cuts continue muonringparam = muonring.fit(x, y, image * clean_mask) dist = np.sqrt( np.power(x - muonringparam.ring_center_x, 2) + np.power(y - muonringparam.ring_center_y, 2)) ring_dist = np.abs(dist - muonringparam.ring_radius) muonringparam = muonring.fit( x, y, img * (ring_dist < muonringparam.ring_radius * 0.4)) dist = np.sqrt( np.power(x - muonringparam.ring_center_x, 2) + np.power(y - muonringparam.ring_center_y, 2)) ring_dist = np.abs(dist - muonringparam.ring_radius) muonringparam = muonring.fit( x, y, img * (ring_dist < muonringparam.ring_radius * 0.4)) muonringparam.tel_id = telid muonringparam.obs_id = event.dl0.obs_id muonringparam.event_id = event.dl0.event_id dist_mask = np.abs( dist - muonringparam.ring_radius) < muonringparam.ring_radius * 0.4 pix_im = image * dist_mask nom_dist = np.sqrt( np.power(muonringparam.ring_center_x, 2) + np.power(muonringparam.ring_center_y, 2)) minpix = muon_cuts['min_pix'][dict_index] # 0.06*numpix #or 8% mir_rad = np.sqrt(teldes.optics.mirror_area.to("m2") / np.pi) # Camera containment radius - better than nothing - guess pixel # diameter of 0.11, all cameras are perfectly circular cam_rad = # np.sqrt(numpix*0.11/(2.*np.pi)) if (npix_above_threshold(pix_im, tailcuts[0]) > 0.1 * minpix and npix_composing_ring(pix_im) > minpix and nom_dist < muon_cuts['CamRad'][dict_index] and muonringparam.ring_radius < 1.5 * u.deg and muonringparam.ring_radius > 1. * u.deg): muonringparam.ring_containment = ring_containment( muonringparam.ring_radius, muon_cuts['CamRad'][dict_index], muonringparam.ring_center_x, muonringparam.ring_center_y) # Guess HESS is 0.16 # sec_rad = 0.*u.m # sct = False # if numpix == 2048 and mir_rad > 2.*u.m and mir_rad < 2.1*u.m: # sec_rad = 1.*u.m # sct = True # # Store muon ring parameters (passing cuts stage 1) # muonringlist[idx] = muonringparam tellist.append(telid) muonringlist.append(muonringparam) muonintensitylist.append(None) ctel = MuonLineIntegrate( mir_rad, hole_radius=muon_cuts['HoleRad'][dict_index], pixel_width=muon_cuts['AngPixW'][dict_index], sct_flag=muon_cuts['SCT'][dict_index], secondary_radius=muon_cuts['SecRad'][dict_index]) if image.shape[0] == muon_cuts['total_pix'][dict_index]: muonintensityoutput = ctel.fit_muon( muonringparam.ring_center_x, muonringparam.ring_center_y, muonringparam.ring_radius, x[dist_mask], y[dist_mask], image[dist_mask]) muonintensityoutput.tel_id = telid muonintensityoutput.obs_id = event.dl0.obs_id muonintensityoutput.event_id = event.dl0.event_id muonintensityoutput.mask = dist_mask idx_ring = np.nonzero(pix_im) muonintensityoutput.ring_completeness = ring_completeness( x[idx_ring], y[idx_ring], pix_im[idx_ring], muonringparam.ring_radius, muonringparam.ring_center_x, muonringparam.ring_center_y, threshold=30, bins=30) dist_ringwidth_mask = np.abs( dist - muonringparam.ring_radius) < ( muonintensityoutput.ring_width) pix_ringwidth_im = image * dist_ringwidth_mask idx_ringwidth = np.nonzero(pix_ringwidth_im) muonintensityoutput.ring_pix_completeness = npix_above_threshold( pix_ringwidth_im[idx_ringwidth], tailcuts[0]) / len( pix_im[idx_ringwidth]) logger.debug( "Tel %d Impact parameter = %s mir_rad=%s " "ring_width=%s", telid, muonintensityoutput.impact_parameter, mir_rad, muonintensityoutput.ring_width) conditions = [ muonintensityoutput.impact_parameter * u.m < muon_cuts['Impact'][dict_index][1] * mir_rad, muonintensityoutput.impact_parameter > muon_cuts['Impact'][dict_index][0], muonintensityoutput.ring_width < muon_cuts['RingWidth'][dict_index][1], muonintensityoutput.ring_width > muon_cuts['RingWidth'][dict_index][0] ] if all(conditions): muonintensityparam = muonintensityoutput idx = tellist.index(telid) muonintensitylist[idx] = muonintensityparam logger.debug("Muon found in tel %d, tels in event=%d", telid, len(event.dl0.tels_with_data)) else: continue return muon_event_param
def plot_muon_event(event, muonparams, args=None): if muonparams['MuonRingParams'] is not None: # Plot the muon event and overlay muon parameters fig = plt.figure(figsize=(16, 7)) colorbar = None colorbar2 = None #for tel_id in event.dl0.tels_with_data: for tel_id in muonparams['TelIds']: idx = muonparams['TelIds'].index(tel_id) if not muonparams['MuonRingParams'][idx]: continue #otherwise... npads = 2 # Only create two pads if there is timing information extracted # from the calibration ax1 = fig.add_subplot(1, npads, 1) plotter = CameraPlotter(event) image = event.dl1.tel[tel_id].image[0] geom = event.inst.subarray.tel[tel_id].camera tailcuts = (5., 7.) # Try a higher threshold for if geom.cam_id == 'FlashCam': tailcuts = (10., 12.) clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) signals = image * clean_mask #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y) muon_incl = np.sqrt( muonparams['MuonRingParams'][idx].ring_center_x**2. + muonparams['MuonRingParams'][idx].ring_center_y**2.) muon_phi = np.arctan( muonparams['MuonRingParams'][idx].ring_center_y / muonparams['MuonRingParams'][idx].ring_center_x) rotr_angle = geom.pix_rotation # if event.inst.optical_foclen[tel_id] > 10.*u.m and # event.dl0.tel[tel_id].num_pixels != 1764: if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam': #print("Resetting the rotation angle") rotr_angle = 0. * u.deg # Convert to camera frame (centre & radius) altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az) ring_nominal = NominalFrame( x=muonparams['MuonRingParams'][idx].ring_center_x, y=muonparams['MuonRingParams'][idx].ring_center_y, array_direction=altaz, pointing_direction=altaz) # embed() ring_camcoord = ring_nominal.transform_to( CameraFrame(pointing_direction=altaz, focal_length=event.inst.optical_foclen[tel_id], rotation=rotr_angle)) centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2) centroid = (ring_camcoord.x.value, ring_camcoord.y.value) ringrad_camcoord = muonparams['MuonRingParams'][idx].ring_radius.to(u.rad) \ * event.inst.optical_foclen[tel_id] * 2. # But not FC? px, py = event.inst.pixel_pos[tel_id] flen = event.inst.optical_foclen[tel_id] camera_coord = CameraFrame(x=px, y=py, focal_length=flen, rotation=geom.pix_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=altaz, pointing_direction=altaz)) px = nom_coord.x.to(u.deg) py = nom_coord.y.to(u.deg) dist = np.sqrt( np.power(px - muonparams['MuonRingParams'][idx].ring_center_x, 2) + np.power(py - muonparams['MuonRingParams'][idx].ring_center_y, 2)) ring_dist = np.abs(dist - muonparams['MuonRingParams'][idx].ring_radius) pixRmask = ring_dist < muonparams['MuonRingParams'][ idx].ring_radius * 0.4 #if muonparams[1] is not None: if muonparams['MuonIntensityParams'][idx] is not None: signals *= muonparams['MuonIntensityParams'][idx].mask camera1 = plotter.draw_camera(tel_id, signals, ax1) cmaxmin = (max(signals) - min(signals)) cmin = min(signals) if not cmin: cmin = 1. if not cmaxmin: cmaxmin = 1. cmap_charge = colors.LinearSegmentedColormap.from_list( 'cmap_c', [(0 / cmaxmin, 'darkblue'), (np.abs(cmin) / cmaxmin, 'black'), (2.0 * np.abs(cmin) / cmaxmin, 'blue'), (2.5 * np.abs(cmin) / cmaxmin, 'green'), (1, 'yellow')]) camera1.pixels.set_cmap(cmap_charge) if not colorbar: camera1.add_colorbar(ax=ax1, label=" [photo-electrons]") colorbar = camera1.colorbar else: camera1.colorbar = colorbar camera1.update(True) camera1.add_ellipse(centroid, ringrad_camcoord.value, ringrad_camcoord.value, 0., 0., color="red") if muonparams['MuonIntensityParams'][idx] is not None: # continue #Comment this...(should ringwidthfrac also be *0.5?) ringwidthfrac = muonparams['MuonIntensityParams'][ idx].ring_width / muonparams['MuonRingParams'][ idx].ring_radius ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac) ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac) camera1.add_ellipse(centroid, ringrad_inner.value, ringrad_inner.value, 0., 0., color="magenta") camera1.add_ellipse(centroid, ringrad_outer.value, ringrad_outer.value, 0., 0., color="magenta") npads = 2 ax2 = fig.add_subplot(1, npads, npads) pred = muonparams['MuonIntensityParams'][idx].prediction if len(pred) != np.sum( muonparams['MuonIntensityParams'][idx].mask): print("Warning! Lengths do not match...len(pred)=", len(pred), "len(mask)=", np.sum(muonparams['MuonIntensityParams'][idx].mask)) # Numpy broadcasting - fill in the shape plotpred = np.zeros(image.shape) plotpred[muonparams['MuonIntensityParams'][idx].mask == True] = pred camera2 = plotter.draw_camera(tel_id, plotpred, ax2) if np.isnan(max(plotpred)) or np.isnan(min(plotpred)): print("nan prediction, skipping...") continue c2maxmin = (max(plotpred) - min(plotpred)) if not c2maxmin: c2maxmin = 1. c2map_charge = colors.LinearSegmentedColormap.from_list( 'c2map_c', [(0 / c2maxmin, 'darkblue'), (np.abs(min(plotpred)) / c2maxmin, 'black'), (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'), (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'), (1, 'yellow')]) camera2.pixels.set_cmap(c2map_charge) if not colorbar2: camera2.add_colorbar(ax=ax2, label=" [photo-electrons]") colorbar2 = camera2.colorbar else: camera2.colorbar = colorbar2 camera2.update(True) plt.pause(1.) # make shorter # plt.pause(0.1) # if pp is not None: # pp.savefig(fig) #fig.savefig(str(args.output_path) + "_" + # str(event.dl0.event_id) + '.png') plt.close()
def plot_muon_event(event, muonparams, geom_dict=None, args=None): if muonparams[0] is not None: # Plot the muon event and overlay muon parameters fig = plt.figure(figsize=(16, 7)) # if args.display: # plt.show(block=False) #pp = PdfPages(args.output_path) if args.output_path is not None else None # pp = None #For now, need to correct this colorbar = None colorbar2 = None for tel_id in event.dl0.tels_with_data: npads = 2 # Only create two pads if there is timing information extracted # from the calibration ax1 = fig.add_subplot(1, npads, 1) plotter = CameraPlotter(event, geom_dict) #image = event.dl1.tel[tel_id].calibrated_image image = event.dl1.tel[tel_id].image[0] # Get geometry geom = None if geom_dict is not None and tel_id in geom_dict: geom = geom_dict[tel_id] else: #log.debug("[calib] Guessing camera geometry") geom = CameraGeometry.guess(*event.inst.pixel_pos[tel_id], event.inst.optical_foclen[tel_id]) #log.debug("[calib] Camera geometry found") if geom_dict is not None: geom_dict[tel_id] = geom tailcuts = (5., 7.) # Try a higher threshold for if geom.cam_id == 'FlashCam': tailcuts = (10., 12.) #print("Using Tail Cuts:",tailcuts) clean_mask = tailcuts_clean(geom, image, picture_thresh=tailcuts[0], boundary_thresh=tailcuts[1]) signals = image * clean_mask #print("Ring Centre in Nominal Coords:",muonparams[0].ring_center_x,muonparams[0].ring_center_y) muon_incl = np.sqrt(muonparams[0].ring_center_x**2. + muonparams[0].ring_center_y**2.) muon_phi = np.arctan(muonparams[0].ring_center_y / muonparams[0].ring_center_x) rotr_angle = geom.pix_rotation # if event.inst.optical_foclen[tel_id] > 10.*u.m and # event.dl0.tel[tel_id].num_pixels != 1764: if geom.cam_id == 'LSTCam' or geom.cam_id == 'NectarCam': #print("Resetting the rotation angle") rotr_angle = 0. * u.deg # Convert to camera frame (centre & radius) altaz = HorizonFrame(alt=event.mc.alt, az=event.mc.az) ring_nominal = NominalFrame(x=muonparams[0].ring_center_x, y=muonparams[0].ring_center_y, array_direction=altaz, pointing_direction=altaz) # embed() ring_camcoord = ring_nominal.transform_to( CameraFrame(pointing_direction=altaz, focal_length=event.inst.optical_foclen[tel_id], rotation=rotr_angle)) centroid_rad = np.sqrt(ring_camcoord.y**2 + ring_camcoord.x**2) centroid = (ring_camcoord.x.value, ring_camcoord.y.value) ringrad_camcoord = muonparams[0].ring_radius.to(u.rad) \ * event.inst.optical_foclen[tel_id] * 2. # But not FC? #rot_angle = 0.*u.deg # if event.inst.optical_foclen[tel_id] > 10.*u.m and event.dl0.tel[tel_id].num_pixels != 1764: #rot_angle = -100.14*u.deg px, py = event.inst.pixel_pos[tel_id] flen = event.inst.optical_foclen[tel_id] camera_coord = CameraFrame(x=px, y=py, z=np.zeros(px.shape) * u.m, focal_length=flen, rotation=geom.pix_rotation) nom_coord = camera_coord.transform_to( NominalFrame(array_direction=altaz, pointing_direction=altaz)) #,focal_length = event.inst.optical_foclen[tel_id])) # tel['TelescopeTable_VersionFeb2016'][tel['TelescopeTable_VersionFeb2016']['TelID']==telid]['FL'][0]*u.m)) px = nom_coord.x.to(u.deg) py = nom_coord.y.to(u.deg) dist = np.sqrt( np.power(px - muonparams[0].ring_center_x, 2) + np.power(py - muonparams[0].ring_center_y, 2)) ring_dist = np.abs(dist - muonparams[0].ring_radius) pixRmask = ring_dist < muonparams[0].ring_radius * 0.4 if muonparams[1] is not None: signals *= muonparams[1].mask camera1 = plotter.draw_camera(tel_id, signals, ax1) cmaxmin = (max(signals) - min(signals)) if not cmaxmin: cmaxmin = 1. cmap_charge = colors.LinearSegmentedColormap.from_list( 'cmap_c', [(0 / cmaxmin, 'darkblue'), (np.abs(min(signals)) / cmaxmin, 'black'), (2.0 * np.abs(min(signals)) / cmaxmin, 'blue'), (2.5 * np.abs(min(signals)) / cmaxmin, 'green'), (1, 'yellow')]) camera1.pixels.set_cmap(cmap_charge) if not colorbar: camera1.add_colorbar(ax=ax1, label=" [photo-electrons]") colorbar = camera1.colorbar else: camera1.colorbar = colorbar camera1.update(True) camera1.add_ellipse(centroid, ringrad_camcoord.value, ringrad_camcoord.value, 0., 0., color="red") # ax1.set_title("CT {} ({}) - Mean pixel charge" # .format(tel_id, geom_dict[tel_id].cam_id)) if muonparams[1] is not None: # continue #Comment this...(should ringwidthfrac also be *0.5?) ringwidthfrac = muonparams[1].ring_width / muonparams[ 0].ring_radius ringrad_inner = ringrad_camcoord * (1. - ringwidthfrac) ringrad_outer = ringrad_camcoord * (1. + ringwidthfrac) camera1.add_ellipse(centroid, ringrad_inner.value, ringrad_inner.value, 0., 0., color="magenta") camera1.add_ellipse(centroid, ringrad_outer.value, ringrad_outer.value, 0., 0., color="magenta") npads = 2 ax2 = fig.add_subplot(1, npads, npads) pred = muonparams[1].prediction if len(pred) != np.sum(muonparams[1].mask): print("Warning! Lengths do not match...len(pred)=", len(pred), "len(mask)=", np.sum(muonparams[1].mask)) # Numpy broadcasting - fill in the shape plotpred = np.zeros(image.shape) plotpred[muonparams[1].mask == True] = pred camera2 = plotter.draw_camera(tel_id, plotpred, ax2) c2maxmin = (max(plotpred) - min(plotpred)) if not c2maxmin: c2maxmin = 1. c2map_charge = colors.LinearSegmentedColormap.from_list( 'c2map_c', [(0 / c2maxmin, 'darkblue'), (np.abs(min(plotpred)) / c2maxmin, 'black'), (2.0 * np.abs(min(plotpred)) / c2maxmin, 'blue'), (2.5 * np.abs(min(plotpred)) / c2maxmin, 'green'), (1, 'yellow')]) camera2.pixels.set_cmap(c2map_charge) if not colorbar2: camera2.add_colorbar(ax=ax2, label=" [photo-electrons]") colorbar2 = camera2.colorbar else: camera2.colorbar = colorbar2 camera2.update(True) plt.pause(1.) # make shorter # plt.pause(0.1) # if pp is not None: # pp.savefig(fig) fig.savefig( str(args.output_path) + "_" + str(event.dl0.event_id) + '.png') plt.close()