def check_write_pha_fits_basic_roundtrip_crates(path): import pycrates ds = pycrates.CrateDataset(str(path), mode="r") assert ds.get_ncrates() == 2 cr = ds.get_crate(2) assert cr.name == "SPECTRUM" assert cr.get_colnames() == ["CHANNEL", "COUNTS"] # undortunately crates auto-converts int32 to int64 # (this is actually the underlying cxcdm module). # c0 = cr.get_column(0) assert c0.name == "CHANNEL" assert c0.values.dtype == np.int64 assert c0.get_tlmin() == 1 assert c0.get_tlmax() == 4 c1 = cr.get_column(1) assert c1.name == "COUNTS" assert c1.values.dtype == np.int64 # crates circa CIAO 4.14 doesn't return the correct values here; # it's returning int32 values and has got the negative value # wrong by 1 assert c1.get_tlmin() <= -2147483647 assert c1.get_tlmax() == 2147483647 assert cr.get_key_value("HDUCLASS") == "OGIP" assert cr.get_key_value("HDUCLAS1") == "SPECTRUM" assert cr.get_key_value("HDUCLAS2") == "TOTAL" assert cr.get_key_value("HDUCLAS3") == "TYPE:I" assert cr.get_key_value("HDUCLAS4") == "COUNT" assert cr.get_key_value("HDUVERS") == "1.2.1" assert cr.get_key_value("TELESCOP") == "none" assert cr.get_key_value("INSTRUME") == "none" assert cr.get_key_value("FILTER") == "none" assert cr.get_key_value("POISSERR") assert cr.get_key_value("CHANTYPE") == "PI" assert cr.get_key_value("DETCHANS") == 4 assert cr.get_key_value("SYS_ERR") == 0 assert cr.get_key_value("QUALITY") == 0 assert cr.get_key_value("GROUPING") == 0 assert cr.get_key_value("AREASCAL") == pytest.approx(1.0) assert cr.get_key_value("BACKSCAL") == pytest.approx(1.0) assert cr.get_key_value("CORRSCAL") == 0 for key in ["BACKFILE", "CORRFILE", "RESPFILE", "ANCRFILE"]: assert cr.get_key_value(key) == "none" # keywords we should have but currently don't for key in ["EXPOSURE"]: assert cr.get_key_value(key) is None
def apply_binning_to_image(binmap_file, image_file, root=None, clobber=False): """ Applies the binning scheme from the binmap to an image of the same shape. Inputs: binmap_file - fits file of map of bins (pixel values = bin numbers) image_file - fits file of image (must have the same shape as the binmap) root - root name of ouput map; defaults to image_file_root + "_binned" clobber - if True, overwrite any existing files Outputs: Binned version of the input image with each bin set to the mean value inside that bin, named "root.fits". """ if root is None: root = os.path.splitext(image_file)[0] + '_binned' # Check if min bin is negative or starts or ends on the image boundary. # If so, assume it is not wanted (e.g., for wvt bin maps). # # Use a CrateDataset to read in the file to ensure any "extra" # blocks are retained. If this is not needed then # pycrates.read_file could be used here. # ds = pycrates.CrateDataset(binmap_file, mode='r') cr = ds.get_crate(0) assert isinstance(cr, pycrates.IMAGECrate) binimage = cr.get_image().values minbin = int(binimage.min()) maxbin = int(binimage.max()) if minbin < 0: minbin = 0 inbin = numpy.where(binimage == minbin) if 0 in inbin[0] or numpy.size(binimage, 0) - 1 in inbin[0]: minbin += 1 nbins = maxbin - minbin + 1 icr = pycrates.read_file(image_file) assert isinstance(icr, pycrates.IMAGECrate) im = icr.get_image().values # Check that the binmap and image have the same shape if binimage.shape != im.shape: sys.exit('ERROR: Input binmap and image must have the same shape.') # make copy of the binmap binimage_out = binimage.astype(float) for i in range(nbins): inbin = numpy.where(binimage == i + minbin) binimage_out[inbin] = numpy.mean(im[inbin]) cr.get_image().values = binimage_out ds.write(root + '.fits', clobber=clobber)
def check_csc_pha_roundtrip_crates(path): import pycrates ds = pycrates.CrateDataset(str(path), mode="r") assert ds.get_ncrates() == 2 cr = ds.get_crate(2) assert cr.name == "SPECTRUM" assert cr.get_colnames() == ["CHANNEL", "COUNTS"] c0 = cr.get_column(0) assert c0.name == "CHANNEL" assert c0.values.dtype == np.int64 assert c0.get_tlmin() == 1 assert c0.get_tlmax() == 1024 c1 = cr.get_column(1) assert c1.name == "COUNTS" assert c1.values.dtype == np.float32 assert c1.get_tlmin() == pytest.approx(-3.4028235e+38) assert c1.get_tlmax() == pytest.approx(3.4028235e+38) assert cr.get_key_value("HDUCLASS") == "OGIP" assert cr.get_key_value("HDUCLAS1") == "SPECTRUM" assert cr.get_key_value("HDUCLAS2") == "TOTAL" assert cr.get_key_value("HDUCLAS3") == "COUNT" assert cr.get_key_value("HDUCLAS4") == "TYPE:I" assert cr.get_key_value("HDUVERS") == "1.1.0" assert cr.get_key_value("HDUVERS1") == "1.1.0" assert cr.get_key_value("POISSERR") assert cr.get_key_value("TELESCOP") == "CHANDRA" assert cr.get_key_value("INSTRUME") == "ACIS" assert cr.get_key_value("FILTER") == "none" assert cr.get_key_value("EXPOSURE") == pytest.approx(37664.157219191) assert cr.get_key_value("BACKSCAL") == pytest.approx(2.2426552620567e-06) assert cr.get_key_value("CORRFILE") == "none" assert cr.get_key_value("ANCRFILE") == "acisf01575_001N001_r0085_arf3.fits" assert cr.get_key_value("BACKFILE") == "acisf01575_001N001_r0085_pha3.fits" assert cr.get_key_value("RESPFILE") == "acisf01575_001N001_r0085_rmf3.fits" assert cr.get_key_value("CHANTYPE") == "PI" assert cr.get_key_value("DETCHANS") == 1024 assert cr.get_key_value("CORRSCAL") == 0 assert cr.get_key_value("SYS_ERR") == 0 assert cr.get_key_value("AREASCAL") == pytest.approx(1.0) assert cr.get_key_value("QUALITY") == 0 assert cr.get_key_value("GROUPING") == 0
def read_ensemble(infile): """Read in the ensemble file. Parameters ---------- infile : str The master-hull file for this ensemble. It must have HULLMATCH and HULLLIST blocks. Notes ----- At present only HULLLIST is looked for and used. """ ds = pycrates.CrateDataset(infile, mode='r') # We are primarily interested in the HULLLIST block, but may # need to look at HULLMATCH for QA cases. # cr = ds.get_crate('HULLLIST') nhulls = cr.get_nrows() if nhulls == 0: raise IOError("No rows in HULLLIST block of {}".format(infile)) ver = cr.get_key_value('CHSVER') ensemble = cr.get_key_value('ENSEMBLE') stacks = [] for i in range(cr.get_key_value('STKIDNUM')): stacks.append(cr.get_key_value('STKID{:03d}'.format(i))) if stacks == []: raise IOError("No stacks stored in {}".format(infile)) coords = [] for nv, eqpos in zip(cr.NVERTEX.values, cr.EQPOS.values): if nv == 0: cs = None else: cs = eqpos[:, :nv].copy() coords.append(cs) return {'infile': infile, 'version': ver, 'ensemble': ensemble, 'stacks': stacks, 'hulls': coords}
def transform_region_fits(infile, outfile, wcs_in, wcs_out): """Transform coordinates in FITS input file. This routine is called assuming the output file is to be clobbered if it already exists. """ # Read in the whole file in case there are any other interesting # blocks in the file that should be retained. # ds = pycrates.CrateDataset(infile, mode='r') cr = ds.get_crate(2) assert isinstance(cr, pycrates.TABLECrate) # NOTE: the EQPOS column could be read directly, which would # avoid the need to convert the input file from physical to # celestial coordinates. # shapes = cr.get_column('SHAPE').values pos = cr.get_column('POS').values # Since the shapes are being processed on a row-by-row bases, # do not try and convert all the coordinates in one go (which # is supported by the apply and invert methods). # for i in xrange(0, cr.get_nrows()): shape = shapes[i].upper() if shape == 'POLYGON': coords_cel = wcs_in.apply(pos[i].T) coords_out = wcs_out.invert(coords_cel).T # Overwrite this row pos[i] = coords_out elif shape == 'ROTBOX': # It should be possible to encode ROTBOX in CXC FITS # region files. # sys.exit('ERROR: Sorry, only polygons are currently supported for FITS regions.') cr.get_column('POS').values = pos ds.write(outfile, clobber=True)
def read_table_blocks(arg, make_copy=False): filename = '' dataset = None close_dataset = False if isinstance(arg, pycrates.TABLECrate): filename = arg.get_filename() dataset = arg.get_dataset() elif isinstance(arg, pycrates.CrateDataset): filename = arg.get_filename() dataset = arg elif type(arg) in (str, unicode, numpy.str_): filename = arg dataset = pycrates.CrateDataset(arg) close_dataset = True else: raise IOErr('badfile', arg, "CrateDataset obj") # index of block number starts at 1 blockidx = numpy.arange(dataset.get_ncrates()) + 1 cols = {} hdr = {} for ii in blockidx: crate = dataset.get_crate(ii) hdr[ii] = {} names = crate.get_keynames() for name in names: hdr[ii][name] = crate.get_key_value(name) cols[ii] = {} # skip over primary if crate.name == 'PRIMARY': continue names = crate.get_colnames() for name in names: cols[ii][name] = crate.get_column(name).values if close_dataset: close_crate_dataset(dataset) return filename, cols, hdr
def create_mhull(outfile, ensemble, revision, hullmd, cpts, mhulls, polys, mstzero=9000, compzero=0, creator=None): """Create the final master hull file. Parameters ---------- outfile : str The name of the file to create. This must not exist. ensemble : str The ensemble name (e.g. 'ens0000100_001'). revision : int The revision number of the finalized mhull file. hullmd : dict The mhull metadata read from the last revision (from chs_utils.read_master_hulls). cpts : list The component information. mhulls : dict The master hulls (the keys are the master id). polys : dict The master hull outlines (the keys are the master id) mstzero : int, optional The offset to apply to the Master_Id values for both the HULLMATCH and HULLLIST blocks. It must be 0 or greater. This value is written out as the MSTZERO keyword in the header. compzero : int, optional The component offset to apply to the component values when writing out the HULLMATCH block. It is expected to be 0. This value is written out as the COMPZERO keyword in the header. creator : str or None The value for the CREATOR keyword, if set. Notes ----- Deleted components are re-numbered to have unique master ids: -1, -2, ... """ """DBG: print("***"); print(hullmd) print("***"); print(cpts) print("***"); print(mhulls) print("***"); print(polys) print(polys[1]['eqpos'].shape[1]) """ assert mstzero >= 0 header = { 'compzero': compzero, 'mstzero': mstzero, 'stacks': hullmd['stacks'], 'svdqafile': hullmd['svdqafile'], 'centroidfile': hullmd['centroidfile'] } # track the deleted components ndel = 0 hullmatch = defaultdict(list) for cpt in cpts: # A component can have multiple rows in this table mids = utils.get_user_setting(cpt, 'master_id') incl_in_centroid = utils.get_user_setting(cpt, 'include_in_centroid') # TODO: check that this hasn't already been done, # because it should have # if len(mids) == 1: assert cpt['match_type'] in ['unambiguous', 'deleted'], cpt else: assert cpt['match_type'] == 'ambiguous', cpt for mid in mids: assert mid != 0, mids if mid < 0: ndel += 1 mid = -1 * ndel nhulls = -1 else: nhulls = mhulls[mid]['ncpts'] hullmatch['master_id'].append(mid) hullmatch['nhulls'].append(nhulls) hullmatch['stackid'].append(cpt['stack']) hullmatch['component'].append(cpt['component']) hullmatch['match_type'].append(cpt['match_type']) # Do not really care about the area any longer (and am not # carrying the value around), so just use a terminal value. # try: hullmatch['area'].append(cpt['area']) except KeyError: hullmatch['area'].append(np.nan) hullmatch['eband'].append(cpt['eband']) hullmatch['likelihood'].append(cpt['likelihood']) hullmatch['man_code'].append(cpt['man_code']) hullmatch['mrg3rev'].append(cpt['mrg3rev']) hullmatch['include_in_centroid'].append(incl_in_centroid) hullmatch['stksvdqa'].append(cpt['stksvdqa']) # Be explicit in the ordering here # hulllist = defaultdict(list) nmasters = 0 for mid in sorted(list(mhulls.keys())): mhull = mhulls[mid] status = utils.get_user_setting(mhull, 'useraction') if status == chs_status.DELETE: continue nmasters += 1 poly = polys[mid] eqpos = poly['eqpos'] nvertex = eqpos.shape[1] status = utils.get_user_setting(mhull, 'useraction') # This will have to be updated, but at present, when only # supporting deletion or acceptance of the proposed hull, # neither flag is set. # # TODO: fix this man_match = False man_reg = False hulllist['master_id'].append(mid) hulllist['status'].append(status) hulllist['base_stk'].append(poly['base_stk']) hulllist['manmatch'].append(man_match) hulllist['manreg'].append(man_reg) hulllist['nvertex'].append(nvertex) hulllist['nstkhull'].append(mhull['ncpts']) hulllist['eqpos'].append(eqpos) utils.create_mhull_file(ensemble, revision, outfile, hullmatch, hulllist, header, creator=creator) # Check we can read in both blocks, but no real validation # beyond that. # chk = pycrates.CrateDataset(outfile, mode='r') assert chk.get_ncrates() == 3 assert chk.get_current_crate() == 2 # Note: hack for nrows=None to mean empty table def valid(idx, name, nrows=None): bl = chk.get_crate(idx) assert bl.name == name if nrows is None: assert bl.get_shape() == (0, ), bl.get_shape() else: assert bl.get_nrows() == nrows, (bl.get_nrows(), nrows) # TODO: is len(cpts) actually correct when we have ambiguous # matches? valid(1, 'PRIMARY') valid(2, 'HULLMATCH', len(cpts)) valid(3, 'HULLLIST', nmasters) chk = None
def check_write_pha_fits_with_extras_roundtrip_crates(path, etime, bscal): import pycrates ds = pycrates.CrateDataset(str(path), mode="r") assert ds.get_ncrates() == 2 cr = ds.get_crate(2) assert cr.name == "SPECTRUM" assert cr.get_colnames() == ["CHANNEL", "COUNTS", "GROUPING", "QUALITY", "AREASCAL"] c0 = cr.get_column(0) assert c0.name == "CHANNEL" assert c0.values.dtype == np.int64 assert c0.get_tlmin() == 1 assert c0.get_tlmax() == 10 c1 = cr.get_column(1) assert c1.name == "COUNTS" assert c1.values.dtype == np.float32 assert c1.get_tlmin() == pytest.approx(-3.4028235e+38) assert c1.get_tlmax() == pytest.approx(3.4028235e+38) c2 = cr.get_column(2) assert c2.name == "GROUPING" assert c2.values.dtype == np.int16 assert c2.get_tlmin() == -32768 assert c2.get_tlmax() == 32767 c3 = cr.get_column(3) assert c3.name == "QUALITY" assert c3.values.dtype == np.int16 assert c3.get_tlmin() == -32768 assert c3.get_tlmax() == 32767 c4 = cr.get_column(4) assert c4.name == "AREASCAL" assert c4.values.dtype == np.float64 assert c4.get_tlmin() < 1e308 assert c4.get_tlmax() > 1e308 assert cr.get_key_value("HDUCLASS") == "OGIP" assert cr.get_key_value("HDUCLAS1") == "SPECTRUM" assert cr.get_key_value("HDUCLAS2") == "TOTAL" assert cr.get_key_value("HDUCLAS3") == "COUNT" assert cr.get_key_value("HDUCLAS4") == "TYPE:I" assert cr.get_key_value("HDUVERS") == "1.2.1" assert cr.get_key_value("HDUVERS1") is None assert cr.get_key_value("POISSERR") assert cr.get_key_value("TELESCOP") == "CHANDRA" assert cr.get_key_value("INSTRUME") == "ACIS" assert cr.get_key_value("FILTER") == "NONE" assert cr.get_key_value("EXPOSURE") == pytest.approx(etime) assert cr.get_key_value("BACKSCAL") == pytest.approx(bscal) assert cr.get_key_value("CORRFILE") == "None" assert cr.get_key_value("ANCRFILE") == "made-up-ancrfile.fits" assert cr.get_key_value("CHANTYPE") == "PI" assert cr.get_key_value("DETCHANS") == 10 assert cr.get_key_value("CORRSCAL") == 0 for key in ["BACKFILE", "RESPFILE"]: assert cr.get_key_value(key) == "none" assert cr.get_key_value("SYS_ERR") == 0 # We do not have these keywords as they are stored as columns for key in ["AREASCAL", "QUALITY", "GROUPING"]: assert cr.get_key_value(key) is None
def paint_map(binmap_file, fit_file, vars_to_map, root=None, fit2_file=None, second_comp=None, best_fit=None, Fprob=None, clobber=False): """ Paints the binmap with the values from spectral fitting. Inputs: binmap_file - fits file of map of bins (pixel values = bin numbers) fit_file - output of fit_spectra.py with fit results vars_to_map - variables to map. A map is created for each variable root - root name of ouput map(s); defaults to "output" fit2_file - output of fit_spectra.py with fit results for 2-comp model second_comp - name of component added to single-temperature model to make the 2-comp model whose results are given in fit2_file best_fit - index (1 or 2) of "best" fit; used only when fit2_file and second_comp are specified Fprob - F-test probability; used only when fit2_file and second_comp are specified clobber - if True, overwrite any existing files Outputs: Writes maps using the output of "fit_spectra.py". The maps are called: root_kT_map.fits, root_Z_map.fits, etc. """ # Check if min bin is negative or starts or ends on the image boundary. # If so, assume it is not wanted (e.g., for wvt bin maps). # # Using the pycrates.read_file routine returns a single block in # the file. This means when it is written out, any other blocks # are lost (other than associated GTI blocks). As it is not clear # whether this is an issue here, I use pycrates.CrateDataset to # read in the whole file. # ds = pycrates.CrateDataset(binmap_file, mode='r') # Assume the image data is in the first block cr = ds.get_crate(0) assert isinstance(cr, pycrates.IMAGECrate) binimage = cr.get_image().values minbin = int(binimage.min()) maxbin = int(binimage.max()) if minbin < 0: minbin = 0 inbin = numpy.where(binimage == minbin) if 0 in inbin[0] or numpy.size(binimage, 0) - 1 in inbin[0]: minbin += 1 nbins = maxbin - minbin + 1 # Read in the fit results file and # calculate errors and check for upper limits data1 = read_fit_results(fit_file) if 'kT' in data1.dtype.names: kT_err = numpy.sqrt(data1['kT_lo']**2 + data1['kT_hi']**2) upper_limits = numpy.where(kT_err / data1['kT'] >= 1.0) kT_err[upper_limits] = data1['kT'][upper_limits] if 'Z' in data1.dtype.names: Z_err = numpy.sqrt(data1['Z_lo']**2 + data1['Z_hi']**2) upper_limits = numpy.where(Z_err / data1['Z'] >= 1.0) Z_err[upper_limits] = data1['Z'][upper_limits] if 'nH' in data1.dtype.names: nH_err = numpy.sqrt(data1['nH_lo']**2 + data1['nH_hi']**2) upper_limits = numpy.where(nH_err / data1['nH'] >= 1.0) nH_err[upper_limits] = data1['nH'][upper_limits] if 'norm' in data1.dtype.names: norm_err = numpy.sqrt(data1['norm_lo']**2 + data1['norm_hi']**2) upper_limits = numpy.where(norm_err / data1['norm'] >= 1.0) norm_err[upper_limits] = data1['norm'][upper_limits] if fit2_file is not None: data2 = read_fit_results(fit2_file, second_comp=second_comp) if 'kT' in data2.dtype.names: kT2_err = numpy.sqrt(data2['kT_lo']**2 + data2['kT_hi']**2) upper_limits = numpy.where(kT2_err / data2['kT'] >= 1.0) kT2_err[upper_limits] = data2['kT'][upper_limits] if 'kT1' in data2.dtype.names: kT1_err = numpy.sqrt(data2['kT1_lo']**2 + data2['kT1_hi']**2) upper_limits = numpy.where(kT1_err / data2['kT1'] >= 1.0) kT1_err[upper_limits] = data2['kT1'][upper_limits] if 'kT2' in data2.dtype.names: kT2_err = numpy.sqrt(data2['kT2_lo']**2 + data2['kT2_hi']**2) upper_limits = numpy.where(kT2_err / data2['kT2'] >= 1.0) kT2_err[upper_limits] = data2['kT2'][upper_limits] if 'Z' in data2.dtype.names: Z2_err = numpy.sqrt(data2['Z_lo']**2 + data2['Z_hi']**2) upper_limits = numpy.where(Z2_err / data2['Z'] >= 1.0) Z2_err[upper_limits] = data2['Z'][upper_limits] if 'Z1' in data2.dtype.names: Z1_err = numpy.sqrt(data2['Z1_lo']**2 + data2['Z1_hi']**2) upper_limits = numpy.where(Z1_err / data2['Z1'] >= 1.0) Z1_err[upper_limits] = data2['Z1'][upper_limits] if 'Z2' in data2.dtype.names: Z2_err = numpy.sqrt(data2['Z2_lo']**2 + data2['Z2_hi']**2) upper_limits = numpy.where(Z2_err / data2['Z2'] >= 1.0) Z2_err[upper_limits] = data2['Z2'][upper_limits] if 'nH' in data2.dtype.names: nH2_err = numpy.sqrt(data2['nH_lo']**2 + data2['nH_hi']**2) upper_limits = numpy.where(nH2_err / data2['nH'] >= 1.0) nH2_err[upper_limits] = data2['nH'][upper_limits] if 'norm' in data2.dtype.names: norm2_err = numpy.sqrt(data2['norm_lo']**2 + data2['norm_hi']**2) upper_limits = numpy.where(norm2_err / data2['norm'] >= 1.0) norm2_err[upper_limits] = data2['norm'][upper_limits] if 'norm1' in data2.dtype.names: norm1_err = numpy.sqrt(data2['norm1_lo']**2 + data2['norm1_hi']**2) upper_limits = numpy.where(norm1_err / data2['norm1'] >= 1.0) norm1_err[upper_limits] = data2['norm1'][upper_limits] if 'norm2' in data2.dtype.names: norm2_err = numpy.sqrt(data2['norm2_lo']**2 + data2['norm2_hi']**2) upper_limits = numpy.where(norm2_err / data2['norm2'] >= 1.0) norm2_err[upper_limits] = data2['norm2'][upper_limits] if 'plindx' in data2.dtype.names: plindx_err = numpy.sqrt(data2['plindx_lo']**2 + data2['plindx_hi']**2) if 'mdot' in data2.dtype.names: mkcnorm_err = numpy.sqrt(data2['mkcnorm_lo']**2 + data2['mkcnorm_hi']**2) upper_limits = numpy.where(mkcnorm_err / data2['mkcnorm'] >= 1.0) mkcnorm_err[upper_limits] = data2['mkcnorm'][upper_limits] nreg1 = len(data1) if fit2_file is not None: nreg2 = len(data2) else: nreg2 = nreg1 # Make sure both have the same length, and they match the number of bins in the binmap if nreg1 != nreg2: sys.exit('ERROR: The two fits have a different number of regions. Please check the fitting results') if nreg1 != nbins or nreg2 != nbins: sys.exit('ERROR: Number of regions does not match the number of bins. Please check the fitting results') if best_fit is None: best_fit = numpy.ones(nreg1, dtype=int) # import pdb; pdb.set_trace() # make copies of the binmap as needed if 'kT' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': binimage_kT1 = numpy.zeros(binimage.shape, dtype=float) binimage_kT2 = numpy.zeros(binimage.shape, dtype=float) else: binimage_kT = numpy.zeros(binimage.shape, dtype=float) if 'Z' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': binimage_Z1 = numpy.zeros(binimage.shape, dtype=float) binimage_Z2 = numpy.zeros(binimage.shape, dtype=float) else: binimage_Z = numpy.zeros(binimage.shape, dtype=float) if 'plindx' in vars_to_map: binimage_plindx = numpy.zeros(binimage.shape, dtype=float) if 'mdot' in vars_to_map: binimage_mkcnorm = numpy.zeros(binimage.shape, dtype=float) if 'nH' in vars_to_map: binimage_nH = numpy.zeros(binimage.shape, dtype=float) if 'norm' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': binimage_norm1 = numpy.zeros(binimage.shape, dtype=float) binimage_norm2 = numpy.zeros(binimage.shape, dtype=float) else: binimage_norm = numpy.zeros(binimage.shape, dtype=float) if 'fkT' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': binimage_fkT1 = numpy.zeros(binimage.shape, dtype=float) binimage_fkT2 = numpy.zeros(binimage.shape, dtype=float) else: binimage_fkT = numpy.zeros(binimage.shape, dtype=float) if 'fZ' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': binimage_fZ1 = numpy.zeros(binimage.shape, dtype=float) binimage_fZ2 = numpy.zeros(binimage.shape, dtype=float) else: binimage_fZ = numpy.zeros(binimage.shape, dtype=float) if 'fplindx' in vars_to_map: binimage_fplindx = numpy.zeros(binimage.shape, dtype=float) if 'fmdot' in vars_to_map: binimage_fmkcnorm = numpy.zeros(binimage.shape, dtype=float) if 'fnH' in vars_to_map: binimage_fnH = numpy.zeros(binimage.shape, dtype=float) if 'fnorm' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': binimage_fnorm1 = numpy.zeros(binimage.shape, dtype=float) binimage_fnorm2 = numpy.zeros(binimage.shape, dtype=float) else: binimage_fnorm = numpy.zeros(binimage.shape, dtype=float) if 'chi2' in vars_to_map: binimage_chi2 = numpy.zeros(binimage.shape, dtype=float) if Fprob is not None: binimage_Fprob = numpy.zeros(binimage.shape, dtype=float) for k in range(nreg1): # First, make sure the loop index matches the reg_id of the region of interest (i.e. to catch entries that are out order or missing) if k + minbin == data1['reg_id'][k]: i = k else: i = data1['reg_id'][k] # find all pixels in region of interest inbin = numpy.where(binimage == i + minbin) if 'kT' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': if data2['kT1'][i] <= data2['kT2'][i]: binimage_kT1[inbin] = data2['kT1'][i] binimage_kT2[inbin] = data2['kT2'][i] else: binimage_kT1[inbin] = data2['kT2'][i] binimage_kT2[inbin] = data2['kT1'][i] if best_fit[i] == 1: # single-temp model preferred binimage_kT1[inbin] = data1['kT'][i] binimage_kT2[inbin] = data1['kT'][i] else: if best_fit[i] == 1: binimage_kT[inbin] = data1['kT'][i] else: binimage_kT[inbin] = data2['kT'][i] if 'Z' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': if data2['kT1'][i] <= data2['kT2'][i]: binimage_Z1[inbin] = data2['Z1'][i] binimage_Z2[inbin] = data2['Z2'][i] else: binimage_Z1[inbin] = data2['Z2'][i] binimage_Z2[inbin] = data2['Z1'][i] if best_fit[i] == 1: binimage_Z1[inbin] = data1['Z'][i] binimage_Z2[inbin] = data1['Z'][i] else: if best_fit[i] == 1: binimage_Z[inbin] = data1['Z'][i] else: binimage_Z[inbin] = data2['Z'][i] if 'plindx' in vars_to_map: if best_fit[i] == 1: binimage_plindx[inbin] = 0.0 else: binimage_plindx[inbin] = data2['plindx'][i] if 'mdot' in vars_to_map: if best_fit[i] == 1: binimage_mkcnorm[inbin] = 0.0 else: binimage_mkcnorm[inbin] = data2['mkcnorm'][i] if 'nH' in vars_to_map: if best_fit[i] == 1: binimage_nH[inbin] = data1['nH'][i] else: binimage_nH[inbin] = data2['nH'][i] if 'norm' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': if data2['kT1'][i] <= data2['kT2'][i]: binimage_norm1[inbin] = data2['norm1'][i] binimage_norm2[inbin] = data2['norm2'][i] else: binimage_norm1[inbin] = data2['norm2'][i] binimage_norm2[inbin] = data2['norm1'][i] if best_fit[i] == 1: # single-temp model preferred binimage_norm1[inbin] = data1['norm'][i] binimage_norm2[inbin] = data1['norm'][i] else: if best_fit[i] == 1: binimage_norm[inbin] = data1['norm'][i] else: binimage_norm[inbin] = data2['norm'][i] if 'fkT' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': if data2['kT1'][i] <= data2['kT2'][i]: binimage_fkT1[inbin] = kT1_err[i] binimage_fkT2[inbin] = kT2_err[i] else: binimage_fkT1[inbin] = kT2_err[i] binimage_fkT2[inbin] = kT1_err[i] if best_fit[i] == 1: # single-temp model preferred binimage_fkT1[inbin] = kT_err[i] binimage_fkT2[inbin] = kT_err[i] else: if best_fit[i] == 1: binimage_fkT[inbin] = kT_err[i] else: binimage_fkT[inbin] = kT2_err[i] if 'fZ' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': if data2['kT1'][i] <= data2['kT2'][i]: binimage_fZ1[inbin] = Z1_err[i] binimage_fZ2[inbin] = Z2_err[i] else: binimage_fZ1[inbin] = Z2_err[i] binimage_fZ2[inbin] = Z1_err[i] if best_fit[i] == 1: # single-temp model preferred binimage_fZ1[inbin] = Z_err[i] binimage_fZ2[inbin] = Z_err[i] else: if best_fit[i] == 1: binimage_fZ[inbin] = Z_err[i] else: binimage_fZ[inbin] = Z2_err[i] if 'fplindx' in vars_to_map: if best_fit[i] == 1: binimage_fplindx[inbin] = 0.0 else: binimage_fplindx[inbin] = plindx_err[i] if 'fmdot' in vars_to_map: if best_fit[i] == 1: binimage_fmkcnorm[inbin] = 0.0 else: binimage_fmkcnorm[inbin] = mkcnorm_err[i] if 'fnH' in vars_to_map: if best_fit[i] == 1: binimage_fnH[inbin] = nH_err[i] else: binimage_fnH[inbin] = nH2_err[i] if 'fnorm' in vars_to_map: if second_comp == 'mekal' or second_comp == 'apec': if data2['norm1'][i] <= data2['norm2'][i]: binimage_fnorm1[inbin] = norm1_err[i] binimage_fnorm2[inbin] = norm2_err[i] else: binimage_fnorm1[inbin] = norm2_err[i] binimage_fnorm2[inbin] = norm1_err[i] if best_fit[i] == 1: # single-temp model preferred binimage_fnorm1[inbin] = norm_err[i] binimage_fnorm2[inbin] = norm_err[i] else: if best_fit[i] == 1: binimage_fnorm[inbin] = norm_err[i] else: binimage_fnorm[inbin] = norm2_err[i] if 'chi2' in vars_to_map: if best_fit[i] == 1: binimage_chi2[inbin] = data1['chi2'][i] else: binimage_chi2[inbin] = data2['chi2'][i] if Fprob is not None: binimage_Fprob[inbin] = Fprob[i] if root is None: root = 'output' def saveimg(idata, suffix): """Write out the data using the given suffix.""" cr.get_image().values = idata ds.write(root + suffix, clobber=clobber) has_2cpt = second_comp == 'mekal' or second_comp == 'apec' if 'kT' in vars_to_map: if has_2cpt: saveimg(binimage_kT1, '_kT1_map.fits') saveimg(binimage_kT2, '_kT2_map.fits') else: saveimg(binimage_kT, '_kT_map.fits') if 'Z' in vars_to_map: if has_2cpt: saveimg(binimage_Z1, '_Z1_map.fits') saveimg(binimage_Z2, '_Z2_map.fits') else: saveimg(binimage_Z, '_Z_map.fits') if 'plindx' in vars_to_map: saveimg(binimage_plindx, '_plindx_map.fits') if 'mdot' in vars_to_map: saveimg(binimage_mkcnorm, '_mdot_map.fits') if 'nH' in vars_to_map: saveimg(binimage_nH, '_nH_map.fits') if 'norm' in vars_to_map: if has_2cpt: saveimg(binimage_norm1, '_norm1_map.fits') saveimg(binimage_norm2, '_norm2_map.fits') else: saveimg(binimage_norm, '_norm_map.fits') if 'fkT' in vars_to_map: if has_2cpt: saveimg(binimage_fkT1, '_fkT1_map.fits') saveimg(binimage_fkT2, '_fkT2_map.fits') else: saveimg(binimage_fkT, '_fkT_map.fits') if 'fZ' in vars_to_map: if has_2cpt: saveimg(binimage_fZ1, '_fZ1_map.fits') saveimg(binimage_fZ2, '_fZ2_map.fits') else: saveimg(binimage_fZ, '_fZ_map.fits') if 'fnorm' in vars_to_map: if has_2cpt: saveimg(binimage_fnorm1, '_fnorm1_map.fits') saveimg(binimage_fnorm2, '_fnorm2_map.fits') else: saveimg(binimage_fnorm, '_fnorm_map.fits') if 'fplindx' in vars_to_map: saveimg(binimage_fplindx, '_fplindx_map.fits') if 'fmdot' in vars_to_map: saveimg(binimage_fmkcnorm, '_fmdot_map.fits') if 'fnH' in vars_to_map: saveimg(binimage_fnH, '_fnH_map.fits') if 'chi2' in vars_to_map: saveimg(binimage_chi2, '_chi2_map.fits') if Fprob is not None: saveimg(binimage_Fprob, '_Ftest_map.fits')
def read_wcs_transform(infile, blocknum): """Read in the physical to celestial transform from the file. Return a WCSTransform object that represents the physical to celestial - e.g. SKY (Chandra)/POS (XMM) to Ra,Dec - from the given block. Parameters ---------- infile : str The name of the file to read in. blocknum : int The block number to use: this follows CFITSIO convention, rather than the CXC DM, and numbers the first block 0. If the block is a table then the column "EQPOS" and then "EQSRC" is searched for. If it is an image then the first axis that returns a WCSTransform is used. If no transform is found an IOError is raised (and then hopefully the logic here tweaked to support the "problem" file structure). Returns ------- tr A pytransform.WCSTransform object. Notes ----- It attempts to be somewhat general, and support images or tables, but it does rely on the FITS header information being "Chandra like". """ # The get_crate routine uses 0 to indicate the "interesting" # (or default) block to open, so need to add 1 to blocknum. # ds = pycrates.CrateDataset(infile, mode='r') cr = ds.get_crate(blocknum + 1) if isinstance(cr, pycrates.TABLECrate): for name in ['EQPOS', 'EQSRC']: try: tr = cr.get_transform(name) except ValueError: continue # In older CIAO's this could be WCSTanTransform if isinstance(tr, pytransform.WCSTransform): return tr raise IOError("No transform found from table {}".format(infile)) elif isinstance(cr, pycrates.IMAGECrate): # loop through all the axes; can probably guarantee # that the first one is not relevant, but just in case. # for axis in cr.get_axisnames(): try: tr = cr.get_transform(axis) except KeyError: continue # In older CIAO's this could be WCSTanTransform if isinstance(tr, pytransform.WCSTransform): return tr raise IOError("No transform found from image {}".format(infile)) else: raise IOError("Unexpected crate: {}".format(type(cr)))