def test_xspec_tablemodel(self): # Just test one table model; use the same scheme as # test_xspec_models_noncontiguous(). # # The table model is from # https://heasarc.gsfc.nasa.gov/xanadu/xspec/models/rcs.html # retrieved July 9 2015. The exact model is irrelevant for this # test, so this was chosen as it's relatively small. ui.load_table_model('tmod', self.make_path('xspec/tablemodel/RCS.mod')) # when used in the test suite it appears that the tmod # global symbol is not created, so need to access the component tmod = ui.get_model_component('tmod') self.assertEqual(tmod.name, 'xstablemodel.tmod') egrid, elo, ehi, wgrid, wlo, whi = make_grid() evals1 = tmod(egrid) evals2 = tmod(elo, ehi) wvals1 = tmod(wgrid) wvals2 = tmod(wlo, whi) emsg = "table model evaluation failed: " assert_array_equal(evals1[:-1], evals2, err_msg=emsg + "energy comparison") assert_allclose(evals1, wvals1, err_msg=emsg + "single arg") assert_allclose(evals2, wvals2, err_msg=emsg + "two args")
def test_xspec_tablemodel(self): # Just test one table model; use the same scheme as # test_xspec_models_noncontiguous(). # # The table model is from # https://heasarc.gsfc.nasa.gov/xanadu/xspec/models/rcs.html # retrieved July 9 2015. The exact model is irrelevant for this # test, so this was chosen as it's relatively small. ui.load_table_model('tmod', self.make_path('xspec-tablemodel-RCS.mod')) # when used in the test suite it appears that the tmod # global symbol is not created, so need to access the component tmod = ui.get_model_component('tmod') self.assertEqual(tmod.name, 'xstablemodel.tmod') egrid, elo, ehi, wgrid, wlo, whi = make_grid() evals1 = tmod(egrid) evals2 = tmod(elo, ehi) wvals1 = tmod(wgrid) wvals2 = tmod(wlo, whi) self.assertFinite(evals1, tmod, "energy") self.assertFinite(wvals1, tmod, "wavelength") emsg = "table model evaluation failed: " assert_array_equal(evals1[:-1], evals2, err_msg=emsg + "energy comparison") assert_allclose(evals1, wvals1, err_msg=emsg + "single arg") assert_allclose(evals2, wvals2, err_msg=emsg + "two args")
def setup(imgfile, emapfile): shp.load_data(imgfile) shp.load_table_model('emap', emapfile) shp.freeze(emap.ampl) # we're using an on axis psf provided in # /packages/CALDB/data/nustar/fpm/bcf/psf/ shp.load_psf('psf', 'nuA2dpsf20100101v003_onaxis.fits') shp.set_psf(psf) psf.center = (500.0, 500.0) psf.size = (200, 200)
def test_load_table_model_fails_with_dir(): """Check that the function fails with invalid input: directory The temporary directory is used for this (the test is skipped if it does not exist). """ ui.clean() assert ui.list_model_components() == [] with pytest.raises(IOError): ui.load_table_model('tmpdir', tmpdir) assert ui.list_model_components() == []
def test_xspec_tablemodel_noncontiguous2(self): ui.load_table_model('tmod', self.make_path('xspec/tablemodel/RCS.mod')) tmod = ui.get_model_component('tmod') elo, ehi, wlo, whi = make_grid_noncontig2() evals2 = tmod(elo, ehi) wvals2 = tmod(wlo, whi) emsg = "table model non-contiguous evaluation failed: " rtol = 1e-3 assert_allclose(evals2, wvals2, rtol=rtol, err_msg=emsg + "energy to wavelength")
def test_load_table_model_fails_with_dev_null(): """Check that load_table_model fails with invalid input: /dev/null This simulates an empty file (and relies on the system containing a /dev/null file that reads in 0 bytes). """ ui.clean() assert ui.list_model_components() == [] # The error depends on the load function with pytest.raises(ValueError): ui.load_table_model('devnull', '/dev/null') assert ui.list_model_components() == []
def test_tablemodel_checks_input_length(self): # see test_table_model for more information on the table # model being used. # ui.load_table_model('mdl', self.make_path('xspec-tablemodel-RCS.mod')) mdl = ui.get_model_component('mdl') # Check when input array is too small (< 2 elements) self.assertRaises(TypeError, mdl, [0.1]) # Check when input arrays are not the same size (when the # low and high bin edges are given) self.assertRaises(TypeError, mdl, [0.1, 0.2, 0.3], [0.2, 0.3]) self.assertRaises(TypeError, mdl, [0.1, 0.2], [0.2, 0.3, 0.4])
def test_load_table_model_fails_with_dir(tmp_path): """Check that the function fails with invalid input: directory The temporary directory is used for this. """ tmpdir = tmp_path / 'load_table_model' tmpdir.mkdir() ui.clean() assert ui.list_model_components() == [] with pytest.raises(IOError): ui.load_table_model('tmpdir', str(tmpdir)) assert ui.list_model_components() == []
def image_model_sherpa(exposure, psf, sources, model_image, overwrite): """Compute source model image with Sherpa. Inputs: * Source list (JSON file) * PSF (JSON file) * Exposure image (FITS file) Outputs: * Source model flux image (FITS file) * Source model excess image (FITS file) """ import sherpa.astro.ui as sau from ..image.models.psf import Sherpa from ..image.models.utils import read_json log.info('Reading exposure: {0}'.format(exposure)) # Note: We don't really need the exposure as data, # but this is a simple way to init the dataspace to the correct shape sau.load_data(exposure) sau.load_table_model('exposure', exposure) log.info('Reading PSF: {0}'.format(psf)) Sherpa(psf).set() log.info('Reading sources: {0}'.format(sources)) read_json(sources, sau.set_source) name = sau.get_source().name full_model = 'exposure * psf({})'.format(name) sau.set_full_model(full_model) log.info('Computing and writing model_image: {0}'.format(model_image)) sau.save_model(model_image, clobber=overwrite) sau.clean() sau.delete_psf()
def test_load_table_model_fails_with_text_column(make_data_path): """Check that load_table_model fails with invalid input: text column The first column is text (and an ASCII file) so it is expected to fail. """ # Check that this file hasn't been changed (as I am re-using it for # this test) infile = make_data_path('table.txt') assert os.path.isfile(infile) ui.clean() assert ui.list_model_components() == [] # The error depends on the load function. with pytest.raises(Exception): ui.load_table_model('stringcol', infile) assert ui.list_model_components() == []
def sherpa_model_image(exposure, psf, sources, model_image, overwrite): """Compute source model image with Sherpa. Inputs: * Source list (JSON file) * PSF (JSON file) * Exposure image (FITS file) Outputs: * Source model flux image (FITS file) * Source model excess image (FITS file) """ import logging logging.basicConfig(level=logging.DEBUG, format='%(levelname)s - %(message)s') import sherpa.astro.ui as sau # @UnresolvedImport from ..morphology.psf import Sherpa from ..morphology.utils import read_json logging.info('Reading exposure: {0}'.format(exposure)) # Note: We don't really need the exposure as data, # but this is a simple way to init the dataspace to the correct shape sau.load_data(exposure) sau.load_table_model('exposure', exposure) logging.info('Reading PSF: {0}'.format(psf)) Sherpa(psf).set() logging.info('Reading sources: {0}'.format(sources)) read_json(sources, sau.set_source) name = sau.get_source().name full_model = 'exposure * psf({})'.format(name) sau.set_full_model(full_model) logging.info('Computing and writing model_image: {0}'.format(model_image)) sau.save_model(model_image, clobber=overwrite)
def test_table_model_fits_table(self): ui.load_table_model('tbl', self.singletbl) ui.load_table_model('tbl', self.doubletbl)
def test_table_model_ascii_table(self): ui.load_table_model('tbl', self.singledat) ui.load_table_model('tbl', self.doubledat)
def assign_model(model_name, i): """Dedicated set up for the most common models.""" if model_name == 'powlaw1d': from sherpa.models import PowLaw1D p1 = PowLaw1D('PowLaw' + str(i)) p1.gamma = 2.6 p1.ampl = 1e-20 p1.ref = 1e9 sau.freeze(p1.ref) elif model_name == 'logparabola': p1 = logparabola('LogPar' + str(i)) p1.ampl = 1e-20 p1.c1 = 2. p1.c2 = 1. p1.ref = 1e9 sau.freeze(p1.ref) elif model_name == 'plexpcutoff': # all parameters in TeV here from .models.plexpcutoff import MyPLExpCutoff p1 = MyPLExpCutoff('PLexpCutoff' + str(i)) p1.gamma = 2. p1.No = 1e-11 p1.beta = 1e-1 # 1/Ecutoff p1.Eo = 1 sau.freeze(p1.Eo) elif model_name == 'Finke': # EBL model from Finke et al. 2010 # enable_table_model() from ..datasets import gammapy_extra filename = gammapy_extra.filename('datasets/ebl/frd_abs.fits.gz') sau.load_table_model('p1', filename) elif model_name == 'Franceschini': # EBL model from Franceschini et al. 2012 # enable_table_model() from ..datasets import gammapy_extra filename = gammapy_extra.filename('datasets/ebl/ebl_franceschini.fits.gz') sau.load_table_model('p1', filename) elif model_name == 'synchro': # print('Synchrotron model not available yet, sorry.') # quit() # Stops with an error: ValueError: slice step cannot be zero from naima.sherpamod import Synchrotron p1 = Synchrotron('Synchro' + str(i)) p1.index = 2. p1.ampl = 1. elif model_name == 'ic': # Inverse Compton peak # Weird, it returns the fit results twice (actually, it seems to do everything twice) # Returns error except if --noplot: TypeError: calc() takes exactly 4 arguments (3 given) from naima.sherpamod import InverseCompton p1 = InverseCompton('IC' + str(i)) p1.index = 2. p1.ampl = 1e-7 # Not sure if the units are OK elif model_name == 'pion': # Pion-decay gamma-ray spectrum # Veeery slow convergence # also doubled operations and problems for plotting, like in ic. from naima.sherpamod import PionDecay p1 = PionDecay('Pion' + str(i)) p1.index = 2. p1.ampl = 10. else: # set initial parameter values manually # (user-defined models and models that need some extra import will not work) p1 = globals()[model_name](model_name + str(i)) set_manual_model(p1) return p1
**opts) spec_true.plot(ax=ax_sed, label='True', color='magenta', **opts) ax_sed.legend() # # Sherpa Morphological fit # In[53]: import sherpa.astro.ui as sh sh.set_stat("cash") sh.set_method("simplex") sh.load_image('../datasets/images/MSH15-52_counts.fits.gz') sh.set_coord("logical") sh.load_table_model("expo", "../datasets/images/MSH15-52_exposure.fits.gz") sh.load_table_model("bkg", "../datasets/images/MSH15-52_background.fits.gz") sh.load_psf("psf", "../datasets/images/MSH15-52_psf.fits.gz") # In[54]: sh.set_full_model(bkg) bkg.ampl = 1 sh.freeze(bkg) data = sh.get_data_image().y - sh.get_model_image().y resid = SkyImage(data=data, wcs=ref_image.wcs) resid_table = [] #Keep residual images in a list to show them later resid_smo6 = resid.smooth(radius=6) resid_smo6.plot(vmax=5, add_cbar=True)
def test_mod_fits(make_data_path): tablemodelfile = make_data_path("xspec-tablemodel-RCS.mod") ui.load_table_model("tmod", tablemodelfile) tmod = ui.get_model_component("tmod") assert tmod.name == "xstablemodel.tmod"
def test_ui_table_model_ascii_table(setup_files): ui.load_table_model('tbl', setup_files.singledat) ui.load_table_model('tbl', setup_files.doubledat)
def test_table_model_fits_image(self): ui.load_table_model('tbl', self.img)
def test_ui_table_model_fits_image(setup_files): ui.load_table_model('tbl', setup_files.img)
def test_mod_fits(self): tablemodelfile = self.make_path("xspec-tablemodel-RCS.mod") ui.load_table_model("tmod", tablemodelfile) tmod = ui.get_model_component("tmod") self.assertEqual("xstablemodel.tmod", tmod.name)
# # We now have the prepared files which sherpa can read. # This part of the notebook shows how to do image analysis using sherpa # In[ ]: import sherpa.astro.ui as sh sh.set_stat("cash") sh.set_method("simplex") sh.load_image("analysis_3d/counts_2D.fits") sh.set_coord("logical") sh.load_table_model("expo", "analysis_3d/exposure_2D.fits") sh.load_table_model("bkg", "analysis_3d/background_2D.fits") sh.load_psf("psf", "analysis_3d/psf_2D.fits") # In principle one might first want to fit the background amplitude. However the background estimation method already yields the correct normalization, so we freeze the background amplitude to unity instead of adjusting it. The (smoothed) residuals from this background model are then computed and shown. # In[ ]: sh.set_full_model(bkg) bkg.ampl = 1 sh.freeze(bkg) # In[ ]:
import sherpa.astro.ui as sh # In[2]: # Read the fits file to load them in a sherpa model hdr = fits.getheader("G300-0_test_counts.fits") wcs = WCS(hdr) sh.set_stat("cash") sh.set_method("simplex") sh.load_image("G300-0_test_counts.fits") sh.set_coord("logical") sh.load_table_model("expo", "G300-0_test_exposure.fits") sh.load_table_model("bkg", "G300-0_test_background.fits") sh.load_psf("psf", "G300-0_test_psf.fits") # In principle one might first want to fit the background amplitude. However the background estimation method already yields the correct normalization, so we freeze the background amplitude to unity instead of adjusting it. The (smoothed) residuals from this background model are then computed and shown. # In[3]: sh.set_full_model(bkg) bkg.ampl = 1 sh.freeze(bkg) data = sh.get_data_image().y - sh.get_model_image().y resid = SkyImage(data=data, wcs=wcs)
def test_ui_table_model_fits_table(setup_files): ui.load_table_model('tbl', setup_files.singletbl) ui.load_table_model('tbl', setup_files.doubletbl)
#galnh_value = float(open(filename + '.nh').read()) galabso = auto_galactic_absorption() galabso.nH.freeze() if args.backgroundmodel == 'chandra': print('calling singlefitter...') fitter = SingleFitter(id, filename, ChandraBackground) try: fitter.tryload() except IOError: fitter.fit(plot=False) # Models available at https://doi.org/10.5281/zenodo.602282 #torus, scat = None, None load_table_model("torus", '/home/user/Downloads/specmodels/uxclumpy-cutoff.fits') load_table_model("scat", '/home/user/Downloads/specmodels/uxclumpy-cutoff-omni.fits') # the limits correspond to fluxes between Sco X-1 and CDFS7Ms faintest fluxes srclevel = Parameter('src', 'level', 0, -8, 3, -20, 20) print('combining components') model = torus + scat print('linking parameters') torus.norm = 10**srclevel srcnh = Parameter('src', 'nH', 22, 20, 26, 20, 26) torus.nh = 10**(srcnh - 22) scat.nh = torus.nh scat.nh = torus.nh print('setting redshift') redshift = Parameter('src', 'z', 1, 0, 10, 0, 10) torus.redshift = redshift
def assign_model(model_name, i): """Dedicated set up for the most common models.""" if model_name == 'powlaw1d': from sherpa.models import PowLaw1D p1 = PowLaw1D('PowLaw' + str(i)) p1.gamma = 2.6 p1.ampl = 1e-20 p1.ref = 1e9 sau.freeze(p1.ref) elif model_name == 'logparabola': p1 = logparabola('LogPar' + str(i)) p1.ampl = 1e-20 p1.c1 = 2. p1.c2 = 1. p1.ref = 1e9 sau.freeze(p1.ref) elif model_name == 'plexpcutoff': # all parameters in TeV here from .models.plexpcutoff import MyPLExpCutoff p1 = MyPLExpCutoff('PLexpCutoff' + str(i)) p1.gamma = 2. p1.No = 1e-11 p1.beta = 1e-1 # 1/Ecutoff p1.Eo = 1 sau.freeze(p1.Eo) elif model_name == 'Finke': # EBL model from Finke et al. 2010 # enable_table_model() from ..datasets import gammapy_extra filename = gammapy_extra.filename('datasets/ebl/frd_abs.fits.gz') sau.load_table_model('p1', filename) elif model_name == 'Franceschini': # EBL model from Franceschini et al. 2012 # enable_table_model() from ..datasets import gammapy_extra filename = gammapy_extra.filename( 'datasets/ebl/ebl_franceschini.fits.gz') sau.load_table_model('p1', filename) elif model_name == 'synchro': # print('Synchrotron model not available yet, sorry.') # quit() # Stops with an error: ValueError: slice step cannot be zero from naima.sherpamod import Synchrotron p1 = Synchrotron('Synchro' + str(i)) p1.index = 2. p1.ampl = 1. elif model_name == 'ic': # Inverse Compton peak # Weird, it returns the fit results twice (actually, it seems to do everything twice) # Returns error except if --noplot: TypeError: calc() takes exactly 4 arguments (3 given) from naima.sherpamod import InverseCompton p1 = InverseCompton('IC' + str(i)) p1.index = 2. p1.ampl = 1e-7 # Not sure if the units are OK elif model_name == 'pion': # Pion-decay gamma-ray spectrum # Veeery slow convergence # also doubled operations and problems for plotting, like in ic. from naima.sherpamod import PionDecay p1 = PionDecay('Pion' + str(i)) p1.index = 2. p1.ampl = 10. else: # set initial parameter values manually # (user-defined models and models that need some extra import will not work) p1 = globals()[model_name](model_name + str(i)) set_manual_model(p1) return p1
# In[ ]: # Read the fits file to load them in a sherpa model filecounts = os.environ["GAMMAPY_DATA"] + "/sherpaCTA/G300-0_test_counts.fits" hdr = fits.getheader(filecounts) wcs = WCS(hdr) sh.set_stat("cash") sh.set_method("simplex") sh.load_image(filecounts) sh.set_coord("logical") fileexp = os.environ["GAMMAPY_DATA"] + "/sherpaCTA/G300-0_test_exposure.fits" filebkg = os.environ["GAMMAPY_DATA"] + "/sherpaCTA/G300-0_test_background.fits" filepsf = os.environ["GAMMAPY_DATA"] + "/sherpaCTA/G300-0_test_psf.fits" sh.load_table_model("expo", fileexp) sh.load_table_model("bkg", filebkg) sh.load_psf("psf", filepsf) # In principle one might first want to fit the background amplitude. However the background estimation method already yields the correct normalization, so we freeze the background amplitude to unity instead of adjusting it. The (smoothed) residuals from this background model are then computed and shown. # In[ ]: sh.set_full_model(bkg) bkg.ampl = 1 sh.freeze(bkg) resid = Map.read(filecounts) resid.data = sh.get_data_image().y - sh.get_model_image().y resid_smooth = resid.smooth(width=6) resid_smooth.plot()