def _check_result_file(self, filename, events=126): """ Check result file """ # Load counts cube cube = gammalib.GCTAEventCube(filename) # Check counts cube self.test_value(cube.size(), 2000, 'Check for number of cube bins') self.test_value(cube.number(), events, 'Check for number of events') # Return return
def _check_result_file(self, filename): """ Check result file """ # Load counts cube cube = gammalib.GCTAEventCube(filename) # Check counts cube self.test_value(cube.size(), 800000, 'Check for 800000 cube bins') self.test_value(cube.number(), 4921, 'Check for 4921 events') # Return return
def _test_cmd(self): """ Test ctbin on the command line """ # Set tool name ctbin = self._tool('ctbin') # Setup ctbin command cmd = ctbin+' inobs="'+self._events+'"'+ \ ' outcube="cntmap_cmd1.fits"'+\ ' emin=0.1 emax=100.0 enumbins=20 ebinalg="LOG"'+ \ ' nxpix=200 nypix=200 binsz=0.02 coordsys="CEL"'+ \ ' xref=83.63 yref=22.01 proj="CAR"'+ \ ' logfile="ctbin_cmd1.log" chatter=1' # Check if execution of wrong command fails self.test_assert( self._execute('command_that_does_not_exist') != 0, 'Self test of test script') # Check if execution was successful self.test_assert( self._execute(cmd) == 0, 'Check successful execution from command line') # Load counts cube and check content. evt = gammalib.GCTAEventCube('cntmap_cmd1.fits') self._check_cube(evt, 5542) # Setup ctbin command cmd = ctbin+' inobs="events_that_do_not_exist.fits"'+ \ ' outcube="cntmap_cmd2.fits"'+\ ' emin=0.1 emax=100.0 enumbins=20 ebinalg="LOG"'+ \ ' nxpix=200 nypix=200 binsz=0.02 coordsys="CEL"'+ \ ' xref=83.63 yref=22.01 proj="CAR"'+ \ ' logfile="ctbin_cmd1.log" chatter=1' # Check if execution failed self.test_assert( self._execute(cmd) != 0, 'Check invalid input file when executed from command line') # Return return
def _check_result_file(self, filename, nx=40, ny=40, nebins=5): """ Check result file Parameters ---------- filename : str Model cube file name nx : int, optional Number of pixels in X direction ny : int, optional Number of pixels in Y direction nebins : int, optional Number of energy bins """ # Open result file cube = gammalib.GCTAEventCube(filename) # Check cube self._check_cube(cube, nx=nx, ny=ny, nebins=nebins) # Return return
def show_residuals(obslist=None, emin=0.2, emax=20.0, ebins=20, npix=200, binsz=0.02, suffix=''): """ Show residuals for all OFF observations Parameters ---------- obslist : list of ints, optional Index of observations to stack emin : float, optional Minimum energy (TeV) emax : float, optional Maximum energy (TeV) ebins : int, optional Number of energy bins npix : int, optional Number of spatial pixels binsz : float, optional Spatial bin size suffix : str, optional Plot filename suffix """ # Set XML filename obsname = '$HESSDATA/obs/obs_off.xml' # Generate background lookup generate_background_lookup(obslist=obslist, suffix=suffix) # If observation list is specified and suffix is empty then build suffix if obslist != None and suffix == '': for obs in obslist: suffix += '_%2.2d' % obs # Set stacked cube filenames cntfile = 'off_stacked_counts%s.fits' % (suffix) modfile = 'off_stacked_model%s.fits' % (suffix) # If stacked cubes exist then load them if os.path.isfile(cntfile) and os.path.isfile(modfile): cntcube_stacked = gammalib.GCTAEventCube(cntfile) modcube_stacked = gammalib.GCTAEventCube(modfile) # ... otherwise generate them else: # Define counts and model cubes for stacking map = gammalib.GSkyMap('TAN', 'CEL', 0.0, 0.0, -binsz, binsz, npix, npix, ebins) ebds = gammalib.GEbounds(ebins, gammalib.GEnergy(emin, 'TeV'), gammalib.GEnergy(emax, 'TeV')) gti = gammalib.GGti(gammalib.GTime(0.0, 's'), gammalib.GTime(1.0, 's')) cntcube_stacked = gammalib.GCTAEventCube(map, ebds, gti) modcube_stacked = gammalib.GCTAEventCube(map, ebds, gti) # Load observations inobs = gammalib.GObservations(obsname) # Loop over runs in observations for i, run in enumerate(inobs): # If an observation list is defined then skip observation if it # is not in list if obslist != None: if i not in obslist: continue # Build observation container with single run obs = gammalib.GObservations() obs.append(run) # Select events obs = select_events(obs, emin=emin, emax=emax) # Generate background model models = get_bkg_model(obs, suffix=suffix) # Attach models to observation container obs.models(models) # Create counts cube cntcube = create_cntcube(obs, emin=emin, emax=emax, ebins=ebins, npix=npix, binsz=binsz) # Create model cube modcube = create_modcube(obs, cntcube) # Stack cubes cntcube_stacked = stack_cube(cntcube_stacked, cntcube) modcube_stacked = stack_cube(modcube_stacked, modcube) # Stop after first run #break # Save cubes cntcube_stacked.save(cntfile, True) modcube_stacked.save(modfile, True) # Plot stacked cubes plot(cntcube_stacked, modcube_stacked, suffix=suffix) plot_sectors(cntcube_stacked, modcube_stacked, suffix=suffix) plot_radial_profiles(cntcube_stacked, modcube_stacked, suffix=suffix) # Return return
def _test_python(self): """ Test ctbin from Python """ # Set-up ctbin bin = ctools.ctbin() bin['inobs'] = self._events bin['outcube'] = 'cntmap.fits' bin['ebinalg'] = 'LOG' bin['emin'] = 0.1 bin['emax'] = 100.0 bin['enumbins'] = 20 bin['nxpix'] = 200 bin['nypix'] = 200 bin['binsz'] = 0.02 bin['coordsys'] = 'CEL' bin['proj'] = 'CAR' bin['xref'] = 83.63 bin['yref'] = 22.01 bin['logfile'] = 'ctbin_py1.log' bin['chatter'] = 2 # Run ctbin tool #bin.logFileOpen() # Make sure we get a log file, but this leads # to a segmentation fault on Linux, e.g. CentOS 6. # see issue #1823 (need to fix that) bin.run() # Check content of observation and cube self._check_observation(bin, 5542) self._check_cube(bin.cube(), 5542) # Test copy constructor cpy_bin = bin.copy() # Check content of observation and cube self._check_observation(cpy_bin, 5542) self._check_cube(cpy_bin.cube(), 5542) # Run copy of ctbin tool again cpy_bin['logfile'] = 'ctbin_py2.log' cpy_bin['chatter'] = 3 cpy_bin.run() # Check content of observation and cube. We expect now an empty # event cube as on input the observation is binned, and any binned # observation will be skipped, hence the counts cube should be # empty. self._check_observation(cpy_bin, 0) self._check_cube(cpy_bin.cube(), 0) # Save counts cube bin.save() # Load counts cube and check content. evt = gammalib.GCTAEventCube('cntmap.fits') self._check_cube(evt, 5542) # Prepare observation container for stacked analysis cta = gammalib.GCTAObservation(self._events) obs = gammalib.GObservations() cta.id('0001') obs.append(cta) cta.id('0002') obs.append(cta) cta.id('0003') obs.append(cta) # Set-up ctbin using an observation container bin = ctools.ctbin(obs) bin['outcube'] = 'cntmap.fits' bin['ebinalg'] = 'LOG' bin['emin'] = 0.1 bin['emax'] = 100.0 bin['enumbins'] = 20 bin['nxpix'] = 200 bin['nypix'] = 200 bin['binsz'] = 0.02 bin['coordsys'] = 'CEL' bin['proj'] = 'CAR' bin['xref'] = 83.63 bin['yref'] = 22.01 bin['logfile'] = 'ctbin_py3.log' bin['chatter'] = 4 # Run ctbin tool bin.logFileOpen() # Make sure we get a log file bin.run() # Check content of observation and cube (need multiplier=3 since # three identical observations have been appended) self._check_observation(bin, 5542, multiplier=3) self._check_cube(bin.cube(), 5542, multiplier=3) # Set-up ctbin using an observation container bin = ctools.ctbin(obs) bin['outcube'] = 'cntmap2.fits' bin['ebinalg'] = 'LOG' bin['emin'] = 0.1 bin['emax'] = 100.0 bin['enumbins'] = 20 bin['nxpix'] = 200 bin['nypix'] = 200 bin['binsz'] = 0.02 bin['coordsys'] = 'CEL' bin['proj'] = 'CAR' bin['xref'] = 83.63 bin['yref'] = 22.01 bin['logfile'] = 'ctbin_py4.log' bin['chatter'] = 4 # Execute ctbin tool bin.execute() # Load counts cube and check content. evt = gammalib.GCTAEventCube('cntmap2.fits') self._check_cube(evt, 5542, multiplier=3) # Return return
def run(self): """ Run the script. """ # Switch screen logging on in debug mode if self._logDebug(): self._log.cout(True) # Get parameters self._get_parameters() # Write observation into logger if self._logTerse(): self._log("\n") self._log.header1("Observation") self._log(str(self._obs)) self._log("\n") # Use input file directly if given if self._use_maps: countmap = gammalib.GSkyMap(self["inobs"].filename()) modelmap = gammalib.GSkyMap(self._modcube) else: # ... if self._skip_binning: cta_counts_cube = gammalib.GCTAEventCube(self._obs[0].events().clone()) # ... else: # Write header if self._logTerse(): self._log("\n") self._log.header1("Generate binned map (ctbin)") # Create countsmap bin = ctools.ctbin(self._obs) bin["nxpix"].integer(self._nxpix) bin["nypix"].integer(self._nypix) bin["proj"].string(self._proj) bin["coordsys"].string(self._coordsys) bin["xref"].real(self._xref) bin["yref"].real(self._yref) bin["enumbins"].integer(self._enumbins) bin["ebinalg"].string(self._ebinalg) bin["emin"].real(self._emin) bin["emax"].real(self._emax) bin["binsz"].real(self._binsz) bin["chatter"].integer(self._chatter) bin["clobber"].boolean(self._clobber) bin["debug"].boolean(self._debug) bin.run() # Retrieve counts cube cta_counts_cube = bin.cube() # Assign GCTAEventCube to skymap countmap = cta_counts_cube.counts() # Write header if self._logTerse(): self._log("\n") self._log.header1("Generate model map (ctmodel)") # Create model map model = ctools.ctmodel(self._obs) model.cube(cta_counts_cube) model["chatter"].integer(self._chatter) model["clobber"].boolean(self._clobber) model["debug"].boolean(self._debug) model["edisp"].boolean(self._edisp) model.run() # Get model map into GSkyMap object modelmap = model.cube().counts().copy() # Store counts map as residual map. Note that we need a # special construct here to avoid memory leaks. This seems # to be a SWIG feature as SWIG creates a new object when # calling bin.cube() #residualmap = bin.cube().counts() self._resmap = countmap.copy() self._resmap.stack_maps() modelmap.stack_maps() # Continue calculations depending on given algorithm if self._algorithm == "SUB": # Subtract maps self._resmap -= modelmap elif self._algorithm == "SUBDIV": # Subtract and divide by model map self._resmap -= modelmap self._resmap /= modelmap #for pixel in modelmap: # if pixel != 0.0: # pixel = 1.0/pixel #self._resmap *= modelmap elif self._algorithm == "SUBDIVSQRT": # subtract and divide by sqrt of model map self._resmap -= modelmap self._resmap /= modelmap.sqrt() #for pixel in modelmap: # if pixel != 0.0: # pixel = 1.0/math.sqrt(pixel) #self._resmap *= modelmap else: # Raise error if algorithm is unkown raise TypeError("Algorithm \""+self._algorithm+"\" not known") # Optionally publish map if self._publish: self.publish() # Return return
def _test_get_stacked_response(self): """ Test get_stacked_response() function """ # Set-up observation container obs = self._setup_sim() # Set-up counts cube map = gammalib.GSkyMap('CAR','CEL',83.6331,22.0145,0.1,0.1,10,10,5) emin = gammalib.GEnergy(0.1, 'TeV') emax = gammalib.GEnergy(100.0, 'TeV') ebds = gammalib.GEbounds(5, emin, emax) tmin = gammalib.GTime(0.0) tmax = gammalib.GTime(1000.0) gti = gammalib.GGti(tmin, tmax) cntcube = gammalib.GCTAEventCube(map, ebds, gti) # Get stacked response res = obsutils.get_stacked_response(obs, cntcube, edisp=False) # Check result self.test_value(res['expcube'].cube().npix(), 100, 'Check number of exposure cube pixels') self.test_value(res['expcube'].cube().nmaps(), 91, 'Check number of exposure cube maps') self.test_value(res['psfcube'].cube().npix(), 4, 'Check number of PSF cube pixels') self.test_value(res['psfcube'].cube().nmaps(), 18200, 'Check number of PSF cube maps') self.test_value(res['bkgcube'].cube().npix(), 100, 'Check number of background cube pixels') self.test_value(res['bkgcube'].cube().nmaps(), 5, 'Check number of background cube maps') # Get stacked response with energy dispersion res = obsutils.get_stacked_response(obs, cntcube, edisp=True) # Check result self.test_value(res['expcube'].cube().npix(), 100, 'Check number of exposure cube pixels') self.test_value(res['expcube'].cube().nmaps(), 105, 'Check number of exposure cube maps') self.test_value(res['psfcube'].cube().npix(), 4, 'Check number of PSF cube pixels') self.test_value(res['psfcube'].cube().nmaps(), 21000, 'Check number of PSF cube maps') self.test_value(res['bkgcube'].cube().npix(), 100, 'Check number of background cube pixels') self.test_value(res['bkgcube'].cube().nmaps(), 5, 'Check number of background cube maps') self.test_value(res['edispcube'].cube().npix(), 4, 'Check number of energy dispersion cube pixels') self.test_value(res['edispcube'].cube().nmaps(), 10500, 'Check number of energy dispersion cube maps') # Set-up counts cube with large number of energy bins ebds = gammalib.GEbounds(100, emin, emax) cntcube = gammalib.GCTAEventCube(map, ebds, gti) # Get stacked response with xref/yref set and large number of energy bins res = obsutils.get_stacked_response(obs, cntcube, edisp=False) # Check result self.test_value(res['expcube'].cube().npix(), 100, 'Check number of exposure cube pixels') self.test_value(res['expcube'].cube().nmaps(), 91, 'Check number of exposure cube maps') self.test_value(res['psfcube'].cube().npix(), 4, 'Check number of PSF cube pixels') self.test_value(res['psfcube'].cube().nmaps(), 18200, 'Check number of PSF cube maps') self.test_value(res['bkgcube'].cube().npix(), 100, 'Check number of background cube pixels') self.test_value(res['bkgcube'].cube().nmaps(), 100, 'Check number of background cube maps') # Return return
def _test_cmd(self): """ Test ctbin on the command line """ # Set tool name ctbin = self._tool('ctbin') # Setup ctbin command cmd = ctbin+' inobs="'+self._events+'"'+ \ ' outobs="cntmap_cmd1.fits"'+\ ' emin=1.0 emax=100.0 enumbins=10 ebinalg="LOG"'+ \ ' nxpix=40 nypix=40 binsz=0.1 coordsys="CEL"'+ \ ' xref=83.63 yref=22.01 proj="CAR"'+ \ ' logfile="ctbin_cmd1.log" chatter=1' # Check if execution was successful self.test_value(self._execute(cmd), 0, 'Check successful execution from command line') # Load counts cube and check content. evt = gammalib.GCTAEventCube('cntmap_cmd1.fits') self._check_cube(evt, 245) # Setup ctbin command cmd = ctbin+' inobs="events_that_do_not_exist.fits"'+ \ ' outobs="cntmap_cmd2.fits"'+\ ' emin=1.0 emax=100.0 enumbins=10 ebinalg="LOG"'+ \ ' nxpix=40 nypix=40 binsz=0.1 coordsys="CEL"'+ \ ' xref=83.63 yref=22.01 proj="CAR"'+ \ ' logfile="ctbin_cmd2.log" debug=yes chatter=1' # Check if execution failed self.test_assert( self._execute(cmd, success=False) != 0, 'Check invalid input file when executed from command line') # Setup ctbin command with different ebounds than input cmd = ctbin+' inobs="'+self._events+'"'+ \ ' outobs="cntmap_cmd3.fits"'+\ ' emin=2.0 emax=20.0 enumbins=10 ebinalg="LOG"'+ \ ' nxpix=40 nypix=40 binsz=0.1 coordsys="CEL"'+ \ ' xref=83.63 yref=22.01 proj="CAR"'+ \ ' logfile="ctbin_cmd3.log" chatter=3' # Check if execution was successful self.test_value(self._execute(cmd), 0, 'Check successful execution from command line') # Load counts cube and check content. evt = gammalib.GCTAEventCube('cntmap_cmd3.fits') self._check_cube(evt, 115) # Check joint (unstacked) binning # Setup ctbin command cmd = ctbin+' inobs="'+self._inobs_two+'"'+ \ ' outobs="obs_unbinned_two_binned.xml"'+\ ' emin=1.0 emax=100.0 enumbins=10 ebinalg="LOG"'+ \ ' nxpix=40 nypix=40 binsz=0.1 coordsys="CEL"'+ \ ' xref=83.63 yref=22.01 proj="CAR"'+ \ ' logfile="ctbin_cmd4.log" chatter=1 stack=no'+ \ ' prefix="cntmap_cmd4_"' # Check if execution was successful self.test_value( self._execute(cmd), 0, 'Check successful execution from command line with stack=no') # Load counts cubes and check content. evt = gammalib.GCTAEventCube('cntmap_cmd4_cta_00001.fits') self._check_cube(evt, 245) # Load counts cubes and check content. evt = gammalib.GCTAEventCube('cntmap_cmd4_cta_00002.fits') self._check_cube(evt, 245) # Check observation definition XML output file obs = gammalib.GObservations('obs_unbinned_two_binned.xml') self.test_value(obs.size(), 2, 'Check for 2 observations in XML file') # Check for content of observations file self.test_value(obs[0].eventfile().file(), 'cntmap_cmd4_cta_00001.fits', 'Check first counts cube file name') self.test_value(obs[1].eventfile().file(), 'cntmap_cmd4_cta_00002.fits', 'Check second counts cube file name') # Check ctbin --help self._check_help(ctbin) # Return return
def _test_python(self): """ Test ctbin from Python """ # Allocate ctbin binning = ctools.ctbin() # Check that empty ctbin has an empty observation container and counts # cube self.test_value( binning.obs().size(), 0, 'Check that empty ctbin has an empty observation container') self.test_value(binning.cubes(), 0, 'Check that empty ctbin has an empty counts cube') # Check that saving does not nothing binning['logfile'] = 'ctbin_py0.log' binning['outobs'] = 'ctbin_py0.fits' binning.logFileOpen() binning.save() self.test_assert(not os.path.isfile('ctbin_py0.fits'), 'Check that no counts cube has been created') # Check that publishing does not lead to an exception or segfault binning.publish() # Check that clearing does not lead to an exception or segfault binning.clear() # Now set ctbin parameters binning['inobs'] = self._events binning['outobs'] = 'ctbin_py1.fits' binning['ebinalg'] = 'LOG' binning['emin'] = 1.0 binning['emax'] = 100.0 binning['enumbins'] = 10 binning['nxpix'] = 40 binning['nypix'] = 40 binning['binsz'] = 0.1 binning['coordsys'] = 'CEL' binning['proj'] = 'CAR' binning['xref'] = 83.63 binning['yref'] = 22.01 binning['logfile'] = 'ctbin_py1.log' binning['chatter'] = 2 # Run ctbin tool binning.logFileOpen() binning.run() # Check content of observation container and counts cube self._check_observation(binning, 245) self._check_cube(binning.cube(), 245) # Copy ctbin tool cpy_bin = binning.copy() # Check content of observation container and counts cube self._check_observation(cpy_bin, 245) self._check_cube(cpy_bin.cube(), 245) # Run copy of ctbin tool again cpy_bin['logfile'] = 'ctbin_py2.log' cpy_bin['chatter'] = 3 cpy_bin.logFileOpen() cpy_bin.run() # Check content of observation container and number of counts cubes. # There should be a single binned observation in the observation # container, which is the one that was produced in the run before. # Since ctbin finds no unbinned observation in the container, the # number of cubes should be zero. self._check_observation(cpy_bin, 245) self.test_value(cpy_bin.cubes(), 0, 'Check that there are no counts cubes') # Save counts cube binning.save() # Load counts cube and check content evt = gammalib.GCTAEventCube('ctbin_py1.fits') self._check_cube(evt, 245) # Now clear ctbin tool binning.clear() # Check that cleared ctbin has an empty observation container and # counts cube self.test_value( binning.obs().size(), 0, 'Check that empty ctbin has an empty observation container') self.test_value(binning.cubes(), 0, 'Check that empty ctbin has an empty counts cube') # Prepare observation container for stacking of events into a # single counts cube obs = self._obs_events() # Set-up ctbin using an observation container binning = ctools.ctbin(obs) binning['outobs'] = 'ctbin_py3.fits' binning['ebinalg'] = 'LOG' binning['emin'] = 1.0 binning['emax'] = 100.0 binning['enumbins'] = 10 binning['nxpix'] = 40 binning['nypix'] = 40 binning['binsz'] = 0.1 binning['coordsys'] = 'CEL' binning['proj'] = 'CAR' binning['xref'] = 83.63 binning['yref'] = 22.01 binning['publish'] = True binning['logfile'] = 'ctbin_py3.log' binning['chatter'] = 3 # Execute ctbin tool binning.logFileOpen() binning.execute() # Check content of observation and cube (need multiplier=3 since # three identical observations have been appended) self._check_observation(binning, 245, multiplier=3) self._check_cube(binning.cube(), 245, multiplier=3) # Load counts cube and check content. evt = gammalib.GCTAEventCube('ctbin_py3.fits') self._check_cube(evt, 245, multiplier=3) # Now go for a fully Pythonic version with all parameters being # specified in a dictionary pars = { 'inobs': self._events, 'ebinalg': 'LIN', 'emin': 1.0, 'emax': 100.0, 'enumbins': 10, 'nxpix': 40, 'nypix': 40, 'binsz': 0.1, 'coordsys': 'CEL', 'proj': 'CAR', 'xref': 83.63, 'yref': 22.01, 'outobs': 'ctbin_py4.fits', 'logfile': 'ctbin_py4.log', 'chatter': 2 } binning = ctools.ctbin() binning.pardict(pars) binning.logFileOpen() binning.execute() # Load counts cube and check content evt = gammalib.GCTAEventCube('ctbin_py4.fits') self._check_cube(evt, 245) # Test unstacked version binning = ctools.ctbin() binning['inobs'] = self._inobs_two binning['stack'] = False binning['prefix'] = 'cntcube_py5_' binning['ebinalg'] = 'LOG' binning['emin'] = 1.0 binning['emax'] = 100.0 binning['enumbins'] = 10 binning['nxpix'] = 40 binning['nypix'] = 40 binning['binsz'] = 0.1 binning['coordsys'] = 'CEL' binning['proj'] = 'CAR' binning['xref'] = 83.63 binning['yref'] = 22.01 binning['outobs'] = 'ctbin_py5.xml' binning['logfile'] = 'ctbin_py5.log' binning['chatter'] = 2 binning.logFileOpen() binning.run() # Check individual cubes self._check_cube(binning.cube(0), 245) self._check_cube(binning.cube(1), 245) # Save counts cube binning.save() # Load observations obs = gammalib.GObservations('ctbin_py5.xml') self.test_value(obs.size(), 2, 'Check number of output observations') # Check counts cubes evt = obs[0].events() self._check_cube(evt, 245) evt = obs[1].events() self._check_cube(evt, 245) # Load counts cubes and check content evt = gammalib.GCTAEventCube('cntcube_py5_cta_00001.fits') self._check_cube(evt, 245) evt = gammalib.GCTAEventCube('cntcube_py5_cta_00002.fits') self._check_cube(evt, 245) # Return return
def _residuals_3D(self, obs, models, obs_id, ccube=None): """ Calculate residuals for 3D observation Parameters ---------- obs : `~gammalib.GCTAObservation` CTA observation models : `~gammalib.GModels` Models obs_id : str Observation ID ccube : `~gammalib.GCTAEventCube', optional Count cube with stacked events lists Returns ------- result : dict Residual result dictionary """ # Create observation container with observation obs_container = gammalib.GObservations() obs_container.append(obs) obs_container.models(models) # If binned data already exist set the evlist_info dictionary to have # attribute was_list False if obs.eventtype() == 'CountsCube' or ccube is not None: evlist_info = {'was_list': False} # ... otherwise bin now else: # we remember if we binned an event list so that we can # mask only the ROI for residual calculation msg = 'Setting up binned observation' self._log_string(gammalib.NORMAL, msg) obs_container, evlist_info = self._bin_evlist(obs_container) # Calculate Model and residuals. If model cube is provided load # it if self._use_maps: modcube = gammalib.GCTAEventCube(self['modcube'].filename()) # ... otherwise calculate it now else: msg = 'Computing model cube' self._log_string(gammalib.NORMAL, msg) modelcube = ctools.ctmodel(obs_container) if ccube is not None: modelcube.cube(ccube) modelcube['edisp'] = self['edisp'].boolean() modelcube.run() modcube = modelcube.cube().copy() # Extract cntcube for residual computation if ccube is not None: cntcube = ccube else: cntcube = obs_container[0].events().copy() # Derive count spectra from cubes msg = 'Computing counts, model, and residual spectra' self._log_string(gammalib.NORMAL, msg) counts = self._cube_to_spectrum(cntcube, evlist_info) model = self._cube_to_spectrum(modcube, evlist_info) # Calculate residuals residuals = obsutils.residuals(self, counts, model) # Extract energy bounds ebounds = cntcube.ebounds().copy() # Set result dictionary result = { 'obs_id': obs_id, 'ebounds': ebounds, 'counts_on': counts, 'model': model, 'residuals_on': residuals } # Calculate models of individual components if requested if self['components'].boolean(): # Loop over components for component in models: # Log action self._log_value(gammalib.NORMAL, 'Computing model component', component.name()) # Set model cube models to individual component model_cont = gammalib.GModels() model_cont.append(component) modelcube.obs().models(model_cont) # Reset base cube that was modified internally by ctmodel if ccube is not None: modelcube.cube(ccube) # Run model cube modelcube['edisp'] = self['edisp'].boolean() modelcube.run() # Extract spectrum of individual component modcube = modelcube.cube().copy() model = self._cube_to_spectrum(modcube, evlist_info) # Append to results result['component_%s' % component.name()] = model # Return result return result