Thermal Emission

The first example we’ll look at is that of thermal emission from a galaxy cluster. In this case, the gas in the core of the cluster is “sloshing” in the center, producing spiral-shaped cold fronts. The dataset we want to use for this example is available for download from the yt Project at this link.

First, import our necessary modules:

[1]:
%matplotlib inline
import yt
import pyxsim
import soxs
/Users/jzuhone/Source/yt/yt/utilities/logger.py:4: VisibleDeprecationWarning: The configuration file /Users/jzuhone/.config/yt/ytrc is deprecated in favor of /Users/jzuhone/.config/yt/yt.toml. Currently, both are present. Please manually remove the deprecated one to silence this warning.
Deprecated since v4.0.0. This feature will be removed in v4.1.0
  from yt.config import ytcfg

Next, we load the dataset with yt. Note that this dataset does not have species fields in it, so we’ll set default_species_fields="ionized" to assume full ionization (as appropriate for galaxy clusters):

[2]:
ds = yt.load("GasSloshing/sloshing_nomag2_hdf5_plt_cnt_0150",
             default_species_fields="ionized")
yt : [INFO     ] 2021-09-09 08:27:27,841 Parameters: current_time              = 1.1835090993823291e+17
yt : [INFO     ] 2021-09-09 08:27:27,842 Parameters: domain_dimensions         = [16 16 16]
yt : [INFO     ] 2021-09-09 08:27:27,843 Parameters: domain_left_edge          = [-3.70272e+24 -3.70272e+24 -3.70272e+24]
yt : [INFO     ] 2021-09-09 08:27:27,843 Parameters: domain_right_edge         = [3.70272e+24 3.70272e+24 3.70272e+24]
yt : [INFO     ] 2021-09-09 08:27:27,844 Parameters: cosmological_simulation   = 0

Let’s use yt to take a slice of density and temperature through the center of the dataset so we can see what we’re looking at:

[3]:
slc = yt.SlicePlot(ds, "z", ["density", "temperature"], width=(1.0,"Mpc"))
slc.show()
yt : [INFO     ] 2021-09-09 08:27:30,489 xlim = -1542838790481162406985728.000000 1542838790481162406985728.000000
yt : [INFO     ] 2021-09-09 08:27:30,490 ylim = -1542838790481162406985728.000000 1542838790481162406985728.000000
yt : [INFO     ] 2021-09-09 08:27:30,491 xlim = -1542838790481162406985728.000000 1542838790481162406985728.000000
yt : [INFO     ] 2021-09-09 08:27:30,492 ylim = -1542838790481162406985728.000000 1542838790481162406985728.000000
yt : [INFO     ] 2021-09-09 08:27:30,493 Making a fixed resolution buffer of (('gas', 'density')) 800 by 800
yt : [INFO     ] 2021-09-09 08:27:30,563 Making a fixed resolution buffer of (('gas', 'temperature')) 800 by 800


Ok, sloshing gas as advertised. Next, we’ll create a sphere object to serve as a source for the photons. Place it at the center of the domain with "c", and use a radius of 500 kpc:

[4]:
sp = ds.sphere("c", (500.,"kpc"))

Now, we need to set up a source model. We said we were going to look at the thermal emission from the hot plasma, so to do that we can set up a ThermalSourceModel. The first argument specifies which model we want to use. Currently the only option available in pyXSIM is "apec". The next three arguments are the maximum and minimum energies, and the number of bins in the spectrum. We’ve chosen these numbers so that the spectrum has an energy resolution of about 1 eV.

ThermalSourceModel takes a lot of optional arguments, which you can investigate in the docs, but here we’ll do something simple and say that the metallicity is a constant \(Z = 0.3~Z_\odot\):

[5]:
source_model = pyxsim.ThermalSourceModel("apec", 0.05, 11.0, 1000, Zmet=0.3)
soxs : [INFO     ] 2021-09-09 08:27:32,202 Using APEC version 3.0.9.
soxs : [INFO     ] 2021-09-09 08:27:32,204 Using apec_v3.0.9_coco.fits for generating spectral lines.
soxs : [INFO     ] 2021-09-09 08:27:32,204 Using apec_v3.0.9_line.fits for generating the continuum.

We’re almost ready to go to generate the photons from this source, but first we should decide what our redshift, collecting area, and exposure time should be. Let’s pick big numbers, because remember the point of this first step is to create a Monte-Carlo sample from which to draw smaller sub-samples for mock observations. Note these are all (value, unit) tuples:

[6]:
exp_time = (300., "ks") # exposure time
area = (1000.0, "cm**2") # collecting area
redshift = 0.05

So, that’s everything–let’s create the photons! We use the make_photons function for this:

[7]:
n_photons, n_cells = pyxsim.make_photons("sloshing_photons", sp, redshift, area, exp_time, source_model)
pyxsim : [INFO     ] 2021-09-09 08:27:32,338 Cosmology: h = 0.71 100*km/(Mpc*s), omega_matter = 0.27, omega_lambda = 0.73
pyxsim : [INFO     ] 2021-09-09 08:27:32,339 Using emission measure field '('gas', 'emission_measure')'.
pyxsim : [INFO     ] 2021-09-09 08:27:32,340 Using temperature field '('gas', 'temperature')'.
pyxsim : [INFO     ] 2021-09-09 08:29:22,267 Finished generating photons.
pyxsim : [INFO     ] 2021-09-09 08:29:22,268 Number of photons generated: 41523050
pyxsim : [INFO     ] 2021-09-09 08:29:22,268 Number of cells with photons: 4375667

Ok, that was easy. Now we have a photon list that we can use to create events using the project_photons function. Here, we’ll just do a simple projection along the z-axis, and center the photons at RA, Dec = (45, 30) degrees. Since we want to be realistic, we’ll want to apply foreground galactic absorption using the "tbabs" model, assuming a neutral hydrogen column of \(N_H = 4 \times 10^{20}~{\rm cm}^{-2}\):

[8]:
n_events = pyxsim.project_photons("sloshing_photons", "sloshing_events", "z", (45.,30.), absorb_model="tbabs", nH=0.04)
pyxsim : [INFO     ] 2021-09-09 08:29:22,296 Foreground galactic absorption: using the tbabs model and nH = 0.04.
Projecting photons from cells/particles: 100%|██████████| 4375667/4375667 [02:41<00:00, 27024.83it/s]
pyxsim : [INFO     ] 2021-09-09 08:32:04,456 Detected 15412059 events.

Now that we have a set of “events” on the sky, we can read them in and write them to a SIMPUT file:

[9]:
events = pyxsim.EventList("sloshing_events.h5")
events.write_to_simput("sloshing", overwrite=True)
soxs : [WARNING  ] 2021-09-09 08:32:05,961 Overwriting sloshing_phlist.fits.
soxs : [INFO     ] 2021-09-09 08:32:06,385 Writing source to sloshing_phlist.fits.

We can then use this SIMPUT file as an input to the instrument simulator in SOXS. We’ll use a small exposure time (100 ks instead of 300 ks), and observe it with the as-launched ACIS-I model:

[10]:
soxs.instrument_simulator("sloshing_simput.fits", "evt.fits", (100.0, "ks"), "chandra_acisi_cy0",
                          [45., 30.], overwrite=True)
soxs : [INFO     ] 2021-09-09 08:32:08,064 Making observation of source in evt.fits.
soxs : [INFO     ] 2021-09-09 08:32:08,487 Detecting events from source sloshing
soxs : [INFO     ] 2021-09-09 08:32:08,488 Applying energy-dependent effective area from acisi_aimpt_cy0.arf.
soxs : [INFO     ] 2021-09-09 08:32:09,933 1377078 events detected.
soxs : [INFO     ] 2021-09-09 08:32:10,046 Pixeling events.
soxs : [INFO     ] 2021-09-09 08:32:10,432 Scattering events with a multi_image-based PSF.
soxs : [INFO     ] 2021-09-09 08:32:11,501 97337 events were rejected because they do not fall on any CCD.
soxs : [INFO     ] 2021-09-09 08:32:11,619 Scattering energies with RMF acisi_aimpt_cy0.rmf.
soxs : [INFO     ] 2021-09-09 08:32:12,869 Adding background events.
soxs : [INFO     ] 2021-09-09 08:32:12,942 Adding in point-source background.
soxs : [INFO     ] 2021-09-09 08:32:13,623 Detecting events from source ptsrc_bkgnd
soxs : [INFO     ] 2021-09-09 08:32:13,624 Applying energy-dependent effective area from acisi_aimpt_cy0.arf.
soxs : [INFO     ] 2021-09-09 08:32:13,629 12514 events detected.
soxs : [INFO     ] 2021-09-09 08:32:13,633 Pixeling events.
soxs : [INFO     ] 2021-09-09 08:32:13,638 Scattering events with a multi_image-based PSF.
soxs : [INFO     ] 2021-09-09 08:32:13,731 3849 events were rejected because they do not fall on any CCD.
soxs : [INFO     ] 2021-09-09 08:32:13,733 Scattering energies with RMF acisi_aimpt_cy0.rmf.
soxs : [INFO     ] 2021-09-09 08:32:13,996 Generated 8665 photons from the point-source background.
soxs : [INFO     ] 2021-09-09 08:32:13,997 Adding in astrophysical foreground.
soxs : [INFO     ] 2021-09-09 08:32:14,004 Making 4165 events from the astrophysical foreground.
soxs : [INFO     ] 2021-09-09 08:32:14,006 Scattering energies with RMF acisi_aimpt_cy0.rmf.
soxs : [INFO     ] 2021-09-09 08:32:14,110 Adding in instrumental background.
soxs : [INFO     ] 2021-09-09 08:32:14,164 Making 121870 events from the instrumental background.
soxs : [INFO     ] 2021-09-09 08:32:14,232 Writing events to file evt.fits.
soxs : [INFO     ] 2021-09-09 08:32:14,809 Observation complete.

We can use the write_image() function in SOXS to bin the events into an image and write them to a file, restricting the energies between 0.5 and 2.0 keV:

[11]:
soxs.write_image("evt.fits", "img.fits", emin=0.5, emax=2.0, overwrite=True)

Now we can take a quick look at the image:

[12]:
soxs.plot_image("img.fits", stretch='sqrt', cmap='arbre', vmin=0.0, vmax=10.0, width=0.2)
[12]:
(<Figure size 720x720 with 2 Axes>,
 <astropy.visualization.wcsaxes.core.WCSAxes at 0x17e5cfb80>)
../_images/cookbook_Thermal_Emission_24_1.png