Binned data products¶
ixpeobssim comes with its own set of facilities for binning event lists in several different flavors. Rather than just for the fun of reinventing the wheel, this was intentionally done with the precise purpose of making easy for people to develop Analysis pipelines.
From an architectural standpoint, each binning flavor comes with its own interface classes for output (i.e., creating binned files from event lists) and input (i.e., reading, visualizing and manipulating binned FITS files). This is documented for developers in the APIs.
All the binned data products implemented in ixpeobssim provide an overloaded __iadd__() dunder that allows to sum multiple files transparently—which is customarily done, e.g., over the three detector units.
When manipulating binned files programmatically you can call the class
constructor directly or, more commonly, use the
from ixpeobssim.binning.polarization import xBinnedCountSpectrum # Load a count spectrum for a single DU spec = xBinnedCountSpectrum('du1.fits') # Load the combined count spectrum for three DUs spec = xBinnedCountSpectrum.from_file_list(['du1.fits', 'du2.fits', 'du3.fits'])
We emphasize that all the polarization analysis takes place in Stokes parameter space, starting from the event-by-event Stokes parameters corrected for the spurious modulation
Additionally, the polarization analysis tools are aware of the event weights
After the spurious modulation subtraction the event-by-event Stokes parameters are not properly normalized, i.e., can lie outside (and even very much outside) the physical [-2, 2] interval. This is generally not an issue, as the the spurious modulation subtractions provides the right answer on average for any reasonably large event sample.
The basic strategy for the spurious modulation subtraction in the SOC pipeline is described in this paper.
Binned Stokes spectra are the main interface to spectro-polarimetric fitting in XSPEC, and one of the most relevant data structures in ixpeobssim.
Stokes spectra are a simple generalization of the standard pha spectra, and the corresponding FITS files designed to store them are closely modeled on the PHA1 file definition in the OGIP spectral file format (in fact the spectrum corresponding to the I Stokes parameter is a standard PHA1 file).
Not surprisingly—at least in the IXPE context, where we neglect circular polarization—Stokes spectra come in three flavors:
I, mapped to
*pha1.fitsfiles via the
Q, mapped to
*pha1q.fitsfiles via the
U, mapped to
*pha1u.fitsfiles via the
Accordingly, binned files in the three flavors are created by invoking xpbin
PHA1U values for the
ixpeobssim.binning.polarization.xBinnedCountSpectrum is the read interface
to all of the three flavors.
Binary table definition¶
The definition of the FITS binary tables for storing Stokes spectra is the same for the three different incarnations
class xBinTableHDUPHA1(xBinTableHDUBase): """Binary table for binned PHA1 data. """ NAME = 'SPECTRUM' HEADER_KEYWORDS = [ ('HDUCLASS', 'OGIP'), ('HDUCLAS1', 'SPECTRUM'), ('HDUCLAS2', 'TOTAL'), ('HDUCLAS3', 'RATE'), ('CHANTYPE', 'PI'), ('HDUVERS' , '1.2.1', 'OGIP version number'), ('TLMIN1' , TLMIN, 'first channel number'), ('TLMAX1' , TLMAX, 'last channel number'), ('CORRSCAL', 1., 'scaling for correction file'), ('POISSERR', False, 'use statistical errors'), ('BACKFILE', ''), ('CORRFILE', ''), ('SYS_ERR' , 0.), ('AREASCAL', 1.), ('BACKSCAL', 1.) ] DATA_SPECS = [ ('CHANNEL' , 'J'), ('RATE' , 'E', 'counts/s'), ('STAT_ERR', 'E', 'counts/s'), ]
the only difference being the value of the
XFLT0001 keyword of the
SPECTRUM extension, which needs to be properly set in order to instruct
XSPEC to apply the polarization correction—and particularly:
Stokes:0for I spectra;
Stokes:1for Q spectra;
Stokes:2for U spectra.
Analytically, Stokes spectra are (possibly weighted) histograms in pulse-invariant space where, given the definition
the content of the k-th bin is given by
It is worth mentioning that for an un-weighted analysis (i.e., when the weights are unitary for all the events) the above expressions reduce to the more familiar ones
The reader is referred to the section about the XSPEC support for more details about one would use binned Stokes spectra in a spectro-polarimetric fit using XSPEC.
Normalized Stokes spectra¶
xpbin provides facilities to produce normalized Stokes spectra
(i.e., spectra where the Q and U channels are divided by the corresponding I
channels) with the
PHA1UN binning algorithms:
Q/I, mapped to
*pha1qn.fitsfiles via the
U/I, mapped to
*pha1un.fitsfiles via the
This can be used in purely polarimetric fits, e.g., in XSPEC, with the spectral part of the problem completely factored out—more about this in the section about XSPEC support.
Binned Stokes cubes are not the only binned data product that is relevant to polarization measurement. ixpeobssim provides a series of data structures designed to hold broadband polarization information—possibly in multiple energy layers and sky-coordinate bins.
One important point to emphasize up-front is that the formalism described in this section neglects by construction the effect of the energy dispersion (which is instead properly handled when fitting with XSPEC). The focus, here, is to provide model-independent quantities that are easy to calculate and visualize, rather than guaranteeing full accuracy.
Whether that is actually important or not depends critically on the
application. Comparing the relevant data products binned in true and
reconstructed energy (you can toggle the
--mc command-line switch to do
just that) is a way to gauge the effect of the energy dispersion in a given,
All the polarization analysis in ixpeobssim is based on the
paper by Kislat et al. (2015), whose
formalism is (partially) implemented verbatim (well, almost—you will notice
that IXPE adopts a slightly different convention for the event-by-event Stokes
parameters, resulting in a factor of 2 popping out here and there) in the
ixpeobssim.evt.kislat2015 Python module.
More specifically, for each event we define the three additive reconstructed quantities
A few remarks on these basic definitions:
the inverse of the effective area in the definition of the weights acts as an acceptance correction guaranteeing that the relevant quantities are summed (or averaged) over the input source spectrum—as opposed to the measured count spectrum;
any additional (multiplicative) event-by-event weight can be easily incorporated into the first term (and gets automatically propagated to the other two);
the effective area and modulation factor are calculated at the measured energy—see the warning above about the effect of the energy dispersion.
(Note the lack of treatment for the energy dispersion is a consequence of our, largely simplistic, implementation of the full formalism described in Kislat et al. (2015), rather than a fundamental limitation of the paper.)
That all said, the measured Stokes parameters over a generic subset S of the events (be that a specific energy range, or a spatial bin in sky coordinates), is obtained by simply summing the event-by-event quantities:
This formalism has been thoroughly tested with Monte Carlo simulation, and provides the right answer in the limit of large statistics (i.e., for any sensible polarization analysis). When the statistics is low, though, due to the very nature of the quantities defined above, the recovered Q and U Stokes parameters can lie outside the physical bounds.
Counter-intuitive as it is, this is the same as saying that, with low statistics, you can have an upward fluctuation of the measured modulation and, when you divide by the modulation factor to recover the polarization, there is nothing preventing the latter from exceeding 1.
You should be aware of the limitation of this method when dealing with small samples. The uncertainties on Q and U will tell you right away whether that is the case.
The polarization degree and angle can be recovered with the usual formulae, and Kislat et al. (2015) provides all the facilities to propagate the statistical uncertainties. Note that, in a weighted scheme, the error propagation requires keeping track of the sum of the weights squared
and the minimum detectable polarization reads
Two related, interesting quantities are the effective number of events and the fractional weight
which reduce to the actual number of counts (and to 1, respectrively), in the un-weighted case. Incidentally, these quantities are used to build the effective area in the weighted case.
The polarization cubes, maps and map cubes are not equipped (yet) to treat the background, or any estimate of the background, in any specific way.
New in version 25.0.0.
All the binned data structures have been largely reworked to add the necessary infrastructure to keep track of the errors on the Stokes parameters and the significance of a detection.
The simplest possible data structure holding polarization information is
a polarization cube. A polarization cube is generated by xpbin
run with the
--algorithm PCUBE command-line switch, and is stored as a
FITS binary table where the relevant metrics are calculated in energy bins.
ixpeobssim.binning.polarization.xBinnedPolarizationCube is the basic
read interface to polarization cubes.
The following snippet from the source code should be self-explaining.
class xBinTableHDUPCUBE(xBinTableHDUBase): """Binary table for binned PCUBE data. """ NAME = 'POLARIZATION' HEADER_KEYWORDS =  # Be careful: if you change any of these, make sure you update the # MDP_COLUMNS and POL_COLUMNS class members below, as this all need to be # in synch with the MDP and polarization maps and map cubes. DATA_SPECS = [ ('ENERG_LO', 'E', 'keV', 'low energy bound'), ('ENERG_HI', 'E', 'keV', 'high energy bound'), ('E_MEAN' , 'E', 'keV', 'average energy within the bin'), ('COUNTS' , 'J', '' , 'number of counts'), ('MU' , 'E', '' , 'effective modulation factor'), ('W2' , 'E', '' , 'sum of weights squared'), ('N_EFF' , 'E', '' , 'effective number of events w/o acceptance correction'), ('FRAC_W' , 'E', '' , 'N_EFF / COUNTS'), ('MDP_99' , 'E', '' , 'minimum detectable polarization at the 99% CL'), ('I' , 'E', '' , 'I Stokes parameter'), ('I_ERR' , 'E', '' , '1-sigma uncertainty on I'), ('Q' , 'E', '' , 'Q Stokes parameter'), ('Q_ERR' , 'E', '' , '1-sigma uncertainty on Q'), ('U' , 'E', '' , 'U Stokes parameter'), ('U_ERR' , 'E', '' , '1-sigma uncertainty on U'), ('QN' , 'E', '' , 'normalized Q Stokes parameter Q/I'), ('QN_ERR' , 'E', '' , '1-sigma uncertainty on Q/I'), ('UN' , 'E', '' , 'normalized U Stokes parameter Q/I'), ('UN_ERR' , 'E', '' , '1-sigma uncertainty on U/I'), ('QUN_COV' , 'E', '' , 'covariance between QN and UN'), ('PD' , 'E', '' , 'measured polarization degree'), ('PD_ERR' , 'E', '' , '1-sigma uncertainty on the polarization degree'), ('PA' , 'E', 'deg', 'measured polarization angle'), ('PA_ERR' , 'E', 'deg', '1-sigma uncertainty on the polarization angle'), ('P_VALUE' , 'E', '' , 'p-value for the null hypothesis (no polarization)'), ('CONFID' , 'E', '' , 'confidence of the polarization detection'), ('SIGNIF' , 'E', '' , 'detection significance in equivalent gaussian sigma') ] COL_NAMES = [col_name for col_name, *_ in DATA_SPECS] # Be careful: these need to be in synch with the DATA_SPECS above. # MDP_COL_NAMES defines the extensions of the MDP maps and map cubes. # POL_COL_NAMES defines the extensions of the polarization maps and map cubes. MDP_COL_NAMES = COL_NAMES[2:10] POL_COL_NAMES = COL_NAMES[2:]
It is worth mentioning that, while some of the columns (i.e., polarization degree and angle, associated uncertainties and MDP) can be calculated from the others (and, are, in fact, recalculated when polarization cubes are summed over the three detector units) we include this redundant information in the FITS file as a convenience.
Polarization-map cubes hold the exact same information as polarization cubes,
but binned in sky-coordinates. Each column in a polarization cube maps directly
into an image extension in the corresponding polarization-map cube file.
Each image extension has three dimensions (two for the spatial binning and one
for the energy binning), and the
EBOUNDS binary table holds the physical
bounds for the energy layers.
Polarization-map cubes are generated by xpbin run with the
--algorithm PMAPCUBE command-line switch, and the main read-interface is
xpbin provides a
PMAP binning a mode that is simply
an alias for a polarization-map cube with a single energy layer—which we
refer to as a polarization map.
MDP-map cubes are stripped-down versions of polarization cubes where only the necessary information for the calculation of the minimum detectable polarization is retained.
No. Name Ver Type Cards Dimensions Format 0 PRIMARY 1 xPrimaryHDU 50 () 1 E_MEAN 1 ImageHDU 24 (1, 1, 1) float64 2 COUNTS 1 ImageHDU 24 (1, 1, 1) float64 3 MU_MDP 1 ImageHDU 24 (1, 1, 1) float64 4 I_MDP 1 ImageHDU 24 (1, 1, 1) float64 5 W2_MDP 1 ImageHDU 24 (1, 1, 1) float64 6 MDP_99 1 ImageHDU 24 (1, 1, 1) float64 7 N_EFF 1 ImageHDU 24 (1, 1, 1) float64 8 FRAC_W 1 ImageHDU 24 (1, 1, 1) float64 9 EBOUNDS 1 xBinTableHDUEBOUNDS 34 1R x 2C ['E', 'E']
xpbin provides a
MDPMAP binning a mode that is simply an alias for a
MDP-map cube with a single energy layer—which we refer to as a MDP map.
xpbin provides livetime map cubes in sky coordinates and off axis angle bins;
livetime-cubes are generated by xpbin run with the
command-line switch, and the main read-interface is
xpbin provides additional facilities not strictly related to polarizations—namely:
binned count maps in sky coordinates (use the
--algorithm CMAPcommand-line switch for generation, read interface is
binned pulse profiles (use the
--algorithm PPcommand-line switch for generation, read interface is
binned area-rate maps in detector coordinates (use the
--algorithm ARMAPcommand-line switch for generation, read interface is
binned energy-flux maps in detector coordinates (use the
--algorithm EFLUXcommand-line switch for generation, read interface is
binned light curves (use the
--algorithm LCcommand-line switch for generation, read interface is