Combining shells

We now look at tie-ing parameters from different annuli (that is, forcing the temperature or abundance of one shell to be the same as a neighbouring shell), which is a technique used to try and reduce the “ringing” that can be seen in deprojected data (e.g. Russell, Sanders, & Fabian 2008 and seen in the temperature profile of the M87 data). Sherpa supports complicated links between model parameters with the link and unlink functions, and the Deproject class provides helper methods - tie_par() and untie_par() - that allows you to easily tie together annuli.

Starting from where the M87 example left off, we have:

../_images/m87_temperature_abundance.png

The get_shells() method lists the current set of annuli, and show that there are currently no grouped (or tied-together) annuli:

>>> dep.get_shells()
[{'annuli': [19], 'dataids': [19]},
 {'annuli': [18], 'dataids': [18]},
 {'annuli': [17], 'dataids': [17]},
 {'annuli': [16], 'dataids': [16]},
 {'annuli': [15], 'dataids': [15]},
 {'annuli': [14], 'dataids': [14]},
 {'annuli': [13], 'dataids': [13]},
 {'annuli': [12], 'dataids': [12]},
 {'annuli': [11], 'dataids': [11]},
 {'annuli': [10], 'dataids': [10]},
 {'annuli': [9], 'dataids': [9]},
 {'annuli': [8], 'dataids': [8]},
 {'annuli': [7], 'dataids': [7]},
 {'annuli': [6], 'dataids': [6]},
 {'annuli': [5], 'dataids': [5]},
 {'annuli': [4], 'dataids': [4]},
 {'annuli': [3], 'dataids': [3]},
 {'annuli': [2], 'dataids': [2]},
 {'annuli': [1], 'dataids': [1]},
 {'annuli': [0], 'dataids': [0]}]

For this example we are going to see what happens when we tie together the temperature and abundance of annulus 17 and 18 (the inner-most annulus is numbered 0, the outer-most is 19 in this example).

>>> dep.tie_par('xsmekal.kt', 17, 18)
Tying xsmekal_18.kT to xsmekal_17.kT
>>> dep.tie_par('xsmekal.abundanc', 17, 18)
Tying xsmekal_18.Abundanc to xsmekal_17.Abundanc

Looking at the first few elements of the list returned by get_shells shows us that the two annuli have now been grouped together. This means that when a fit is run then these two annuli will be fit simultaneously.

>>> dep.get_shells()[0:5]
[{'annuli': [19], 'dataids': [19]},
 {'annuli': [17, 18], 'dataids': [17, 18]},
 {'annuli': [16], 'dataids': [16]},
 {'annuli': [15], 'dataids': [15]},
 {'annuli': [14], 'dataids': [14]}]

Since the model values for the 18th annulus have been changed, the data needs to be re-fit. The screen output is slightly different, as highlighted below, to reflect this new grouping:

>>> dep.fit()
Note: annuli have been tied together
Fitting annulus 19  dataset: 19
Dataset               = 19
...
Freezing xswabs_19
Freezing xsmekal_19
Fitting annuli [17, 18]  datasets: [17, 18]
Datasets              = 17, 18
Method                = levmar
Statistic             = chi2xspecvar
Initial fit statistic = 469.803
Final fit statistic   = 447.963 at function evaluation 16
Data points           = 439
Degrees of freedom    = 435
Probability [Q-value] = 0.323566
Reduced statistic     = 1.0298
Change in statistic   = 21.8398
   xsmekal_17.kT   2.64505      +/- 0.0986876
   xsmekal_17.Abundanc   0.520943     +/- 0.068338
   xsmekal_17.norm   0.0960039    +/- 0.00370363
   xsmekal_18.norm   0.0516096    +/- 0.00232468
Freezing xswabs_17
Freezing xsmekal_17
Freezing xswabs_18
Freezing xsmekal_18
Fitting annulus 16  dataset: 16
...

The table returned by fit() and get_fit_results() still contains 20 rows, since each annulus has its own row:

>>> tied = dep.get_fit_results()
>>> len(tied)
20

Looking at the outermost annuli, we can see that the temperature and abundance values are the same:

>>> print(tied['xsmekal.kT'][16:])
    xsmekal.kT
------------------
2.5470334673573936
 2.645045455995055
 2.645045455995055
2.7480050952727346
>>> print(tied['xsmekal.Abundanc'][16:])
  xsmekal.Abundanc
-------------------
0.24424232427701525
 0.5209430839965413
 0.5209430839965413
 0.4297577517591726

Note

The field names in the table are case sensitive - that is, you have to say xsmekal.kT and not xsmekal.kt - unlike the Sherpa parameter interface.

The results can be compared to the original, such as in the following plot, which shows that the temperature profile hasn’t changed significantly in the core, but some of the oscillations at large radii have been reduced (the black circles show the temperature values from the original fit):

>>> dep.fit_plot('xsmekal.kt', units='pc')
>>> rmid = (onion['rlo_phys'] + onion['rhi_phys']) / 2
>>> plt.scatter(rmid.to(u.pc), onion['xsmekal.kT', c='k')
../_images/m87_temperature_tied_comparison.png

Note

As the X-axis of the plot created by fit_plot() is in pc, the rmid value is expliclty converted to these units before plotting.

The results parameter of fit_plot could have been set to the variable onion to display the results of the previous fit, but there is no easy way to change the color of the points.

More shells could be tied together to try and further reduce the oscillations, or errors calculated, with either conf() or covar().

The parameter ties can be removed with untie_par():

>>> dep.untie_par('xsmekal.kt', 18)
Untying xsmekal_18.kT
>>> dep.untie_par('xsmekal.abundanc', 18)
Untying xsmekal_18.Abundanc
>>> dep.get_shells()[0:4]
[{'annuli': [19], 'dataids': [19]},
 {'annuli': [18], 'dataids': [18]},
 {'annuli': [17], 'dataids': [17]},
 {'annuli': [16], 'dataids': [16]}]