예제 #1
0
    def _test_pickeling(self):
        """
        Test csbkgmodel pickeling
        """
        # Perform pickeling tests of empty class
        self._pickeling(cscripts.csbkgmodel())

        # Set-up csbkgmodel
        bkgmodel = cscripts.csbkgmodel()
        bkgmodel['inobs'] = self._events
        bkgmodel['caldb'] = self._caldb
        bkgmodel['irf'] = self._irf
        bkgmodel['instrument'] = 'CTA'
        bkgmodel['spatial'] = 'GAUSS'
        bkgmodel['gradient'] = True
        bkgmodel['spectral'] = 'NODES'
        bkgmodel['ebinalg'] = 'LOG'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['runwise'] = True
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 2
        bkgmodel['outmodel'] = 'csbkgmodel_py1_pickle.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py1_pickle.log'

        # Perform pickeling tests of filled class
        obj = self._pickeling(bkgmodel)

        # Run csbkgmodel script and save background model
        obj.logFileOpen()  # Make sure we get a log file
        obj.run()
        obj.save()

        # Check background model
        self._check_bkg_model('csbkgmodel_py1_pickle.xml')

        # Return
        return
def get_bkg_model(obs, rad=2.0, suffix=''):
    """
    Get background model

    Parameters
    ----------
    obs : `~gammalib.GObservations`
        Observation container
    rad : float, optional
        RoI radius (deg)
    suffix : str, optional
        Background lookup file suffix

    Returns
    -------
    models : `~gammalib.GModels`
        Model container
    """
    # Get energy range for observation
    emin = obs[0].ebounds().emin().TeV()
    emax = obs[0].ebounds().emax().TeV()

    # Setup task parameters
    bkg = cscripts.csbkgmodel(obs)
    bkg['instrument'] = 'HESS'
    bkg['spatial'] = 'LOOKUP'
    bkg['slufile'] = 'bkg_lookup%s.fits' % (suffix)
    bkg['snumbins'] = 3
    bkg['smin'] = emin
    bkg['smax'] = 5.0
    bkg['gradient'] = True
    bkg['spectral'] = 'NODES'
    bkg['ebinalg'] = 'LOG'
    bkg['emin'] = emin
    bkg['emax'] = emax
    bkg['enumbins'] = 8
    bkg['runwise'] = True
    bkg['rad'] = rad
    bkg['debug'] = True

    # Generate background model
    bkg.run()

    # Extract models
    models = bkg.models().copy()

    # Return models
    return models
예제 #3
0
def prepare(obsname, bkgname, rad=2.0, emin=0.3, emax=50.0, ebins=20):
    """
    Prepare events for analysis

    Parameters
    ----------
    obsname : str
        Observation definition XML file
    bkgname : str
        Background model definition XML file
    rad : float, optional
        Selection radius (degrees)
    emin : float, optional
        Minimum energy for analysis (TeV)
    emax : float, optional
        Maximum energy for analysis (TeV)
    ebins : int, optional
        Number of energy bins
    """
    # Set filenames
    cntcube = 'rx_stacked%2.2d_cntcube.fits' % ebins
    expcube = 'rx_stacked%2.2d_expcube.fits' % ebins
    psfcube = 'rx_stacked%2.2d_psfcube.fits' % ebins
    edispcube = 'rx_stacked%2.2d_edispcube.fits' % ebins
    bkgcube = 'rx_stacked%2.2d_bkgcube.fits' % ebins
    obsname_binned = add_attribute(obsname, '_binned%2.2d' % ebins)
    bkgname_stacked = add_attribute(bkgname, '_stacked')
    obsname_stacked = add_attribute(obsname, '_stacked%2.2d' % ebins)
    obsname_stacked_edisp = add_attribute(obsname_stacked, '_edisp')

    # Generate background lookup
    generate_background_lookup()

    # Continue only if selected events do not exist
    if not os.path.isfile(obsname):

        # Setup task parameters
        select = ctools.ctselect()
        select['inobs'] = '$HESSDATA/obs/obs_rx.xml'
        select['outobs'] = obsname
        select['ra'] = 'UNDEF'
        select['dec'] = 'UNDEF'
        select['rad'] = rad
        select['tmin'] = 'UNDEF'
        select['tmax'] = 'UNDEF'
        select['emin'] = emin
        select['emax'] = emax
        select['usethres'] = 'DEFAULT'
        select['logfile'] = 'rx_hess_select_events.log'
        select.logFileOpen()

        # Select events
        select.execute()

    # Continue only if background model does not exist
    if not os.path.isfile(bkgname):

        # Setup task parameters
        bkg = cscripts.csbkgmodel()
        bkg['inobs'] = '$HESSDATA/obs/obs_rx.xml'
        bkg['outmodel'] = bkgname
        bkg['instrument'] = 'HESS'
        bkg['spatial'] = 'LOOKUP'
        bkg['slufile'] = 'off_lookup.fits'
        bkg['gradient'] = True
        bkg['spectral'] = 'NODES'
        bkg['ebinalg'] = 'LOG'
        bkg['emin'] = emin
        bkg['emax'] = 30.0
        bkg['enumbins'] = 8
        bkg['runwise'] = True
        bkg['rad'] = rad
        bkg['logfile'] = 'rx_hess_create_background.log'
        bkg.logFileOpen()

        # Generate background model
        bkg.execute()

    # Continue only if counts cube does not exist
    if not os.path.isfile(cntcube):

        # Setup task parameters
        ctbin = ctools.ctbin()
        ctbin['inobs'] = obsname
        ctbin['outobs'] = cntcube
        ctbin['ebinalg'] = 'LOG'
        ctbin['emin'] = emin
        ctbin['emax'] = emax
        ctbin['enumbins'] = ebins
        ctbin['coordsys'] = 'CEL'
        ctbin['proj'] = 'TAN'
        ctbin['xref'] = 258.1125
        ctbin['yref'] = -39.6867
        ctbin['nxpix'] = 300
        ctbin['nypix'] = 300
        ctbin['binsz'] = 0.02
        ctbin['logfile'] = 'rx_hess_create_cntcube.log'
        ctbin.logFileOpen()

        # Generate counts cube
        ctbin.execute()

    # Continue only if counts cubes for binned analysis do not exist
    if not os.path.isfile(obsname_binned):

        # Setup task parameters
        ctbin = ctools.ctbin()
        ctbin['inobs'] = obsname
        ctbin['outobs'] = obsname_binned
        ctbin['stack'] = False
        ctbin['usepnt'] = True
        ctbin['ebinalg'] = 'LOG'
        ctbin['emin'] = emin
        ctbin['emax'] = emax
        ctbin['enumbins'] = ebins
        ctbin['coordsys'] = 'CEL'
        ctbin['proj'] = 'TAN'
        ctbin['nxpix'] = 200
        ctbin['nypix'] = 200
        ctbin['binsz'] = 0.02
        ctbin['logfile'] = 'rx_hess_create_cntcube_binned.log'
        ctbin.logFileOpen()

        # Generate counts cubes
        ctbin.execute()

    # Continue only if exposure cube does not exist
    if not os.path.isfile(expcube):

        # Setup task parameters
        ctexpcube = ctools.ctexpcube()
        ctexpcube['inobs'] = obsname
        ctexpcube['incube'] = 'NONE'
        ctexpcube['ebinalg'] = 'LOG'
        ctexpcube['emin'] = 0.1  # Full energy range
        ctexpcube['emax'] = 100.0  # Full energy range
        ctexpcube['enumbins'] = 300  # Factor ~3 oversampling of IRF
        ctexpcube['coordsys'] = 'CEL'
        ctexpcube['proj'] = 'TAN'
        ctexpcube['xref'] = 258.1125
        ctexpcube['yref'] = -39.6867
        ctexpcube['nxpix'] = 300
        ctexpcube['nypix'] = 300
        ctexpcube['binsz'] = 0.02
        ctexpcube['outcube'] = expcube
        ctexpcube['logfile'] = 'rx_hess_create_expcube.log'
        ctexpcube.logFileOpen()

        # Generate exposure cube
        ctexpcube.execute()

    # Continue only if PSF cube does not exist
    if not os.path.isfile(psfcube):

        # Setup task parameters
        ctpsfcube = ctools.ctpsfcube()
        ctpsfcube['inobs'] = obsname
        ctpsfcube['incube'] = 'NONE'
        ctpsfcube['ebinalg'] = 'LOG'
        ctpsfcube['emin'] = 0.1  # Full energy range
        ctpsfcube['emax'] = 100.0  # Full energy range
        ctpsfcube['enumbins'] = 300  # Factor ~3 oversampling of IRF
        ctpsfcube['coordsys'] = 'CEL'
        ctpsfcube['proj'] = 'TAN'
        ctpsfcube['xref'] = 258.1125
        ctpsfcube['yref'] = -39.6867
        ctpsfcube['nxpix'] = 30
        ctpsfcube['nypix'] = 30
        ctpsfcube['binsz'] = 0.2
        ctpsfcube['amax'] = 0.7  # Full H.E.S.S. PSF range
        ctpsfcube['anumbins'] = 300  # Factor ~2 oversampling of IRF
        ctpsfcube['outcube'] = psfcube
        ctpsfcube['logfile'] = 'rx_hess_create_psfcube.log'
        ctpsfcube.logFileOpen()

        # Generate PSF cube
        ctpsfcube.execute()

    # Continue only if energy dispersion cube does not exist
    if not os.path.isfile(edispcube):

        # Setup task parameters
        ctedispcube = ctools.ctedispcube()
        ctedispcube['inobs'] = obsname
        ctedispcube['incube'] = 'NONE'
        ctedispcube['ebinalg'] = 'LOG'
        ctedispcube['emin'] = 0.1  # Full energy range
        ctedispcube['emax'] = 100.0  # Full energy range
        ctedispcube['enumbins'] = 300  # Factor ~3 oversampling of IRF
        ctedispcube['coordsys'] = 'CEL'
        ctedispcube['proj'] = 'TAN'
        ctedispcube['xref'] = 258.1125
        ctedispcube['yref'] = -39.6867
        ctedispcube['nxpix'] = 30
        ctedispcube['nypix'] = 30
        ctedispcube['binsz'] = 0.2
        ctedispcube['migramax'] = 5.0
        ctedispcube['migrabins'] = 300
        ctedispcube['outcube'] = edispcube
        ctedispcube['logfile'] = 'rx_hess_create_edispcube.log'
        ctedispcube.logFileOpen()

        # Generate energy dispersion cube
        ctedispcube.execute()

    # Continue only if background cube does not exist
    if not os.path.isfile(bkgcube):

        # Setup task parameters
        ctbkgcube = ctools.ctbkgcube()
        ctbkgcube['inobs'] = obsname
        ctbkgcube['incube'] = cntcube
        ctbkgcube['inmodel'] = bkgname
        ctbkgcube['outcube'] = bkgcube
        ctbkgcube['outmodel'] = bkgname_stacked
        ctbkgcube['logfile'] = 'rx_hess_create_bkgcube.log'
        ctbkgcube.logFileOpen()

        # Generate background cube
        ctbkgcube.execute()

    # Continue only if stacked observation definition XML file does not
    # exist
    if not os.path.isfile(obsname_stacked):

        # Build stacked observation
        run = gammalib.GCTAObservation(cntcube, expcube, psfcube, bkgcube)
        run.name('RX J1713.7-3946')
        run.instrument('HESS')

        # Append to observation container
        obs = gammalib.GObservations()
        obs.append(run)

        # Save observation container
        obs.save(obsname_stacked)

    # Continue only if stacked observation definition XML file with energy
    # energy dispersion enabled does not exist
    if not os.path.isfile(obsname_stacked_edisp):

        # Build stacked observation
        run = gammalib.GCTAObservation(cntcube, expcube, psfcube, edispcube,
                                       bkgcube)
        run.name('RX J1713.7-3946')
        run.instrument('HESS')

        # Append to observation container
        obs = gammalib.GObservations()
        obs.append(run)

        # Save observation container
        obs.save(obsname_stacked_edisp)

    # Continue only if stacked model definition XML file does exist
    if os.path.isfile(bkgname_stacked):

        # Load model definition XML files
        joint = gammalib.GModels(bkgname)
        stacked = gammalib.GModels(bkgname_stacked)

        # Get spectral component of joint file and remplace it as spectral
        # component of stacked file
        spectrum = joint[0].spectral()
        for i in range(spectrum.nodes()):
            spectrum.intensity(i, 1.0)
        spectrum.autoscale()
        stacked[0].spectral(spectrum)

        # Save stacked model
        stacked.save(bkgname_stacked)

    # Return
    return
예제 #4
0
def spectrum(obsname, bkgname, srcmodel, pars, emin=0.3, emax=20.0, alpha=1.0):
    """
    Generate spectrum

    Parameters
    ----------
    obsname : str
        Observation definition XML file
    bkgname : str
        Background model definition XML file
    srcmodel : str
        Source model
    pars : dict
        Dictionary of analysis parameters
    emin : float, optional
        Minimum energy (TeV)
    emax : float, optional
        Maximum energy (TeV)
    alpha : float, optional
        Template map scaling factor
    """
    # Set observation name
    _obsname = set_observation(obsname, srcmodel, bkgname, pars)

    # Set analysis
    analysis = set_analysis(srcmodel, bkgname, 'plaw', pars, alpha=alpha)

    # Set file names
    outfile = 'rx_spectrum_%s.fits' % (analysis)
    logfile = 'rx_spectrum_%s.log' % (analysis)

    # Continue only if result file does not exist
    if not os.path.isfile(outfile):

        # Load observations
        obs = gammalib.GObservations(_obsname)

        # Set background model for stacked analysis
        if pars['stacked']:
            bname = add_attribute(bkgname, '_stacked')
            models = set_model(srcmodel, 'plaw', bname, alpha=alpha)
            for model in models:
                if model.type() == 'CTACubeBackground':
                    model.spectral()['Index'].fix()

        # ... otherwise create H.E.S.S. background model with power law
        # spectral component
        else:

            # Setup plaw background model
            bkg = cscripts.csbkgmodel()
            bkg['inobs'] = '$HESSDATA/obs/obs_rx.xml'
            bkg['instrument'] = 'HESS'
            bkg['spatial'] = 'LOOKUP'
            bkg['slufile'] = 'off_lookup.fits'
            bkg['gradient'] = True
            bkg['spectral'] = 'PLAW'
            bkg['runwise'] = True
            bkg['emin'] = emin
            bkg['emax'] = emax
            bkg['rad'] = 2.0
            bkg.run()

            # Initialise model container
            models = gammalib.GModels()

            # Set source model
            source = set_source_model(srcmodel, spec='plaw', alpha=alpha)
            models.append(source)

            # Set background model
            bkg_models = bkg.models()
            for model in bkg_models:
                if model.type() == 'CTABackground':
                    model.spectral()['Index'].fix()
                    model.spatial()[0].fix()  # Normalization
                    model.spatial()[1].free()  # DETX
                    model.spatial()[2].free()  # DETY

            # Append background models
            models.extend(bkg_models)

        # Append models
        obs.models(models)

        # Generate spectrum
        spec = cscripts.csspec(obs)
        spec['srcname'] = 'RX J1713.7-3946'
        spec['edisp'] = pars['edisp']
        spec['outfile'] = outfile
        spec['method'] = 'SLICE'
        spec['ebinalg'] = 'LOG'
        spec['emin'] = emin
        spec['emax'] = emax
        spec['enumbins'] = 15
        spec['logfile'] = logfile
        spec['debug'] = True
        spec['chatter'] = 4
        spec.logFileOpen()
        spec.execute()

    # Return
    return
예제 #5
0
    def _test_python(self):
        """
        Test csbkgmodel from Python
        """
        # Set-up csbkgmodel
        bkgmodel = cscripts.csbkgmodel()
        bkgmodel['inobs'] = self._events
        bkgmodel['caldb'] = self._caldb
        bkgmodel['irf'] = self._irf
        bkgmodel['instrument'] = 'CTA'
        bkgmodel['spatial'] = 'GAUSS'
        bkgmodel['gradient'] = True
        bkgmodel['spectral'] = 'NODES'
        bkgmodel['ebinalg'] = 'LOG'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['runwise'] = True
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 2
        bkgmodel['outmodel'] = 'csbkgmodel_py1.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py1.log'

        # Run csbkgmodel script and save background model
        bkgmodel.logFileOpen()  # Make sure we get a log file
        bkgmodel.run()
        bkgmodel.save()

        # Check background model
        self._check_bkg_model('csbkgmodel_py1.xml')

        # Now test without gradient, power law and not runwise
        bkgmodel = cscripts.csbkgmodel()
        bkgmodel['inobs'] = self._events
        bkgmodel['caldb'] = self._caldb
        bkgmodel['irf'] = self._irf
        bkgmodel['instrument'] = 'CTA'
        bkgmodel['spatial'] = 'GAUSS'
        bkgmodel['gradient'] = False
        bkgmodel['spectral'] = 'PLAW'
        bkgmodel['ebinalg'] = 'LOG'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['runwise'] = False
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 3
        bkgmodel['outmodel'] = 'csbkgmodel_py2.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py2.log'

        # Execute csbkgmodel script
        bkgmodel.logFileOpen()  # Make sure we get a log file
        bkgmodel.execute()

        # Check background model
        self._check_bkg_model('csbkgmodel_py2.xml')

        # Now test AEFF model
        bkgmodel = cscripts.csbkgmodel()
        bkgmodel['inobs'] = self._events
        bkgmodel['caldb'] = self._caldb
        bkgmodel['irf'] = self._irf
        bkgmodel['instrument'] = 'CTA'
        bkgmodel['spatial'] = 'AEFF'
        bkgmodel['gradient'] = False
        bkgmodel['spectral'] = 'PLAW'
        bkgmodel['ebinalg'] = 'LOG'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['runwise'] = False
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 4
        bkgmodel['outmodel'] = 'csbkgmodel_py3.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py3.log'

        # Execute csbkgmodel script
        bkgmodel.logFileOpen()  # Make sure we get a log file
        bkgmodel.execute()

        # Check background model
        self._check_bkg_model('csbkgmodel_py3.xml')

        # Now test IRF model
        bkgmodel = cscripts.csbkgmodel()
        bkgmodel['inobs'] = self._events
        bkgmodel['caldb'] = self._caldb
        bkgmodel['irf'] = self._irf
        bkgmodel['instrument'] = 'CTA'
        bkgmodel['spatial'] = 'IRF'
        bkgmodel['gradient'] = False
        bkgmodel['spectral'] = 'PLAW'
        bkgmodel['ebinalg'] = 'LOG'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['runwise'] = False
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 4
        bkgmodel['outmodel'] = 'csbkgmodel_py4.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py4.log'

        # Execute csbkgmodel script
        bkgmodel.logFileOpen()  # Make sure we get a log file
        bkgmodel.execute()

        # Check background model
        self._check_bkg_model('csbkgmodel_py4.xml')

        # Test with multiple input observations
        obs = gammalib.GObservations()
        for s, events in enumerate([self._myevents1, self._myevents2]):
            run = gammalib.GCTAObservation(events)
            run.id(str(s + 1))
            run.response(self._irf, gammalib.GCaldb('cta', self._caldb))
            obs.append(run)

        # Set-up csbkgmodel
        bkgmodel = cscripts.csbkgmodel(obs)
        bkgmodel['instrument'] = 'CTA'
        bkgmodel['spatial'] = 'GAUSS'
        bkgmodel['gradient'] = True
        bkgmodel['spectral'] = 'NODES'
        bkgmodel['ebinalg'] = 'POW'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['ebingamma'] = 1.1
        bkgmodel['runwise'] = True
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 2
        bkgmodel['outmodel'] = 'csbkgmodel_py5.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py5.log'

        # Execute csbkgmodel script
        bkgmodel.logFileOpen()  # Make sure we get a log file
        bkgmodel.execute()

        # Check background model
        self._check_bkg_model('csbkgmodel_py5.xml', nmodels=2)

        # Test GAUSS(E) spatial model
        bkgmodel = cscripts.csbkgmodel()
        bkgmodel['inobs'] = self._events
        bkgmodel['caldb'] = self._caldb
        bkgmodel['irf'] = self._irf
        bkgmodel['instrument'] = 'CTA'
        bkgmodel['spatial'] = 'GAUSS(E)'
        bkgmodel['snumbins'] = 2
        bkgmodel['smin'] = 1.0
        bkgmodel['smax'] = 10.0
        bkgmodel['gradient'] = True
        bkgmodel['spectral'] = 'NODES'
        bkgmodel['ebinalg'] = 'LOG'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['runwise'] = True
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 2
        bkgmodel['outmodel'] = 'csbkgmodel_py6.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py6.log'

        # Run csbkgmodel script and save background model
        bkgmodel.logFileOpen()  # Make sure we get a log file
        bkgmodel.execute()

        # Check background model
        self._check_bkg_model('csbkgmodel_py6.xml')

        # Test LOOKUP spatial model
        bkgmodel = cscripts.csbkgmodel()
        bkgmodel['inobs'] = self._events
        bkgmodel['caldb'] = self._caldb
        bkgmodel['irf'] = self._irf
        bkgmodel['instrument'] = 'CTA'
        bkgmodel['spatial'] = 'LOOKUP'
        bkgmodel['slufile'] = self._lookup
        bkgmodel['gradient'] = True
        bkgmodel['spectral'] = 'NODES'
        bkgmodel['ebinalg'] = 'LOG'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['runwise'] = True
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 2
        bkgmodel['outmodel'] = 'csbkgmodel_py7.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py7.log'

        # Run csbkgmodel script and save background model
        bkgmodel.logFileOpen()  # Make sure we get a log file
        bkgmodel.execute()

        # Check background model
        self._check_bkg_model('csbkgmodel_py7.xml')

        # Test PROFILE spatial model
        bkgmodel = cscripts.csbkgmodel()
        bkgmodel['inobs'] = self._events
        bkgmodel['caldb'] = self._caldb
        bkgmodel['irf'] = self._irf
        bkgmodel['instrument'] = 'CTA'
        bkgmodel['spatial'] = 'PROFILE'
        bkgmodel['gradient'] = True
        bkgmodel['spectral'] = 'NODES'
        bkgmodel['ebinalg'] = 'LOG'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['runwise'] = True
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 2
        bkgmodel['outmodel'] = 'csbkgmodel_py8.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py8.log'

        # Run csbkgmodel script and save background model
        bkgmodel.logFileOpen()  # Make sure we get a log file
        bkgmodel.execute()

        # Check background model
        self._check_bkg_model('csbkgmodel_py8.xml')

        # Test POLYNOM spatial model
        bkgmodel = cscripts.csbkgmodel()
        bkgmodel['inobs'] = self._events
        bkgmodel['caldb'] = self._caldb
        bkgmodel['irf'] = self._irf
        bkgmodel['instrument'] = 'CTA'
        bkgmodel['spatial'] = 'POLYNOM'
        bkgmodel['gradient'] = True
        bkgmodel['spectral'] = 'NODES'
        bkgmodel['ebinalg'] = 'LOG'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['runwise'] = True
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 2
        bkgmodel['outmodel'] = 'csbkgmodel_py9.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py9.log'

        # Run csbkgmodel script and save background model
        bkgmodel.logFileOpen()  # Make sure we get a log file
        bkgmodel.execute()

        # Check background model
        self._check_bkg_model('csbkgmodel_py9.xml')

        # Check with data from multiple instruments
        new_inst = 'INST2'
        obs_multi_inst = gammalib.GObservations(obs)
        for run in obs_multi_inst:
            run.instrument(new_inst)
        obs_multi_inst.extend(obs)

        # Set-up csbkgmodel
        bkgmodel = cscripts.csbkgmodel(obs_multi_inst)
        bkgmodel['instrument'] = new_inst
        bkgmodel['spatial'] = 'GAUSS'
        bkgmodel['gradient'] = True
        bkgmodel['spectral'] = 'NODES'
        bkgmodel['ebinalg'] = 'POW'
        bkgmodel['emin'] = 1.0
        bkgmodel['emax'] = 100.0
        bkgmodel['enumbins'] = 8
        bkgmodel['ebingamma'] = 1.1
        bkgmodel['runwise'] = True
        bkgmodel['rad'] = 2.0
        bkgmodel['chatter'] = 2
        bkgmodel['outmodel'] = 'csbkgmodel_py10.xml'
        bkgmodel['logfile'] = 'csbkgmodel_py10.log'

        # Execute csbkgmodel script
        bkgmodel.logFileOpen()  # Make sure we get a log file
        bkgmodel.execute()

        # Check background model
        self._check_bkg_model('csbkgmodel_py10.xml', nmodels=obs.size())

        # Return
        return