예제 #1
0
def _check_transform(coords):
    # Coords is a shape.Subinterval
    wcsprm = Wcsprm()
    coord_array = np.array([[coords.lower, coords.upper]])
    sky_transform = wcsprm.p2s(coord_array, ORIGIN)
    pix_transform = wcsprm.s2p(sky_transform['world'], ORIGIN)
    transformed_coords = pix_transform['pixcrd']

    if not (transformed_coords[0][0] == coords.lower
            and transformed_coords[0][1] == coords.upper):
        raise ValueError(
            "Could not transform coordinates pixel to sky, sky to pixel")
예제 #2
0
def _check_transform(coords):
    # Coords is a shape.Subinterval
    wcsprm = Wcsprm()
    coord_array = np.array([[coords.lower, coords.upper]])
    sky_transform = wcsprm.p2s(coord_array, ORIGIN)
    wcsprm.s2p(sky_transform['world'], ORIGIN)
예제 #3
0
def _check_transform(lower, upper):
    wcsprm = Wcsprm()
    coord_array = np.array([[lower, upper]])
    sky_transform = wcsprm.p2s(coord_array, ORIGIN)
    wcsprm.s2p(sky_transform['world'], ORIGIN)
예제 #4
0
def add_wcs_coordinates(objects, catParNames, catParFormt, catParUnits, Parameters):
	try:
		hdulist = fits.open(Parameters["import"]["inFile"])
		header = hdulist[0].header
		hdulist.close()
		
		# Fix headers where "per second" is written "/S" instead of "/s"
		# (assuming they mean "per second" and not "per Siemens").
		if "cunit3" in header and "/S" in header["cunit3"]:
			err.warning("Converting '/S' to '/s' in CUNIT3.")
			header["cunit3"] = header["cunit3"].replace("/S","/s")
		
		# Check if there is a Nmap/GIPSY FITS header keyword value present
		gipsyKey = [k for k in ["FREQ-OHEL", "FREQ-OLSR", "FREQ-RHEL", "FREQ-RLSR"] if (k in [header[key] for key in header if ("CTYPE" in key)])]
		if gipsyKey:
			err.message("GIPSY header found. Trying to convert to FITS standard.")
			from astropy.wcs import Wcsprm
			header = fix_gipsy_header(header)
			wcsin = Wcsprm(str(header))
			wcsin.sptr("VOPT-F2W")
			#if header["naxis"] == 4:
			#	objects = np.concatenate((objects, wcsin.p2s(np.concatenate((objects[:, catParNames.index("x"):catParNames. index("x") + 3], np.zeros((objects.shape[0], 1))), axis=1), 0)["world"][:,:-1]), axis=1)
			#else:
			#	objects = np.concatenate((objects, wcsin.p2s(objects[:, catParNames.index("x"):catParNames.index("x") + 3], 0)["world"]), axis=1)
			objects = np.concatenate((objects, wcsin.p2s(objects[:, catParNames.index("x"):catParNames.index("x") + 3], 0)["world"]), axis=1)
			catParUnits = tuple(list(catParUnits) + [str(cc).replace(" ", "") for cc in wcsin.cunit])
			catParNames = tuple(list(catParNames) + [(cc.split("--")[0]).lower() for cc in wcsin.ctype])
			catParFormt = tuple(list(catParFormt) + ["%15.7e", "%15.7e", "%15.7e"])
		
		else:
			# Constrain the RA axis reference value CRVAL_ to be between 0 and 360 deg
			rafound = 0
			for kk in range(header["naxis"]):
				if header["ctype1"][:2] == "RA":
					rafound = 1
					break
			if rafound:
				if header["crval%i" % (kk + 1)] < 0:
					err.warning("Adding 360 deg to RA reference value.")
					header["crval%i" % (kk + 1)] += 360
				elif header["crval%i" % (kk + 1)] > 360:
					err.warning("Subtracting 360 deg from RA reference value.")
					header["crval%i" % (kk + 1)] -= 360
			
			#if header["naxis"] == 4: wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL, wcs.WCSSUB_STOKES])
			#else: wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL])
			wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL])
			xyz = objects[:, catParNames.index("x"):catParNames.index("x") + 3].astype(float)
			if "cellscal" in header and header["cellscal"] == "1/F":
				err.warning(
					"CELLSCAL keyword with value of 1/F found.\n"
					"Will account for varying pixel scale in WCS coordinate calculation.")
				x0, y0 = header["crpix1"] - 1, header["crpix2"] - 1
				# Will calculate the pixscale factor of each channel as:
				# pixscale = ref_frequency / frequency
				if header["ctype3"] == "VELO-HEL":
					pixscale = (1 - header["crval3"] / scipy.constants.c) / (1 - (((xyz[:, 2] + 1) - header["crpix3"]) * header["cdelt3"] + header["crval3"]) / scipy.constants.c)
				else:
					err.warning("Cannot convert 3rd axis coordinates to frequency. Ignoring the effect of CELLSCAL = 1/F.")
					pixscale = 1.0
				xyz[:, 0] = (xyz[:, 0] - x0) * pixscale + x0
				xyz[:, 1] = (xyz[:, 1] - y0) * pixscale + y0
			#if header["naxis"] == 4: objects = np.concatenate((objects, wcsin.wcs_pix2world(np.concatenate((xyz, np.zeros((objects.shape[0], 1))), axis=1), 0)[:, :-1]), axis=1)
			#else: objects = np.concatenate((objects, wcsin.wcs_pix2world(xyz, 0)), axis=1)
			objects = np.concatenate((objects, wcsin.wcs_pix2world(xyz, 0)), axis=1)
			catParUnits = tuple(list(catParUnits) + [str(cc).replace(" ", "") for cc in wcsin.wcs.cunit])
			catParNames = tuple(list(catParNames) + [(cc.split("--")[0]).lower() for cc in wcsin.wcs.ctype])
			catParFormt = tuple(list(catParFormt) + ["%15.7e", "%15.7e", "%15.7e"])
		#if header["naxis"] == 4:
		#	catParUnits = catParUnits[:-1]
		#	catParNames= catParNames[:-1]
		err.message("WCS coordinates added to catalogue.")
		
		# Create IAU-compliant source name:
		# WARNING: This currently assumes a regular, ≥ 2-dim. data cube where the first two axes are longitude and latitude.
		n_src = objects.shape[0]
		n_par = objects.shape[1]
		
		iau_names = np.empty([n_src, 1], dtype=object)
		
		if header["ctype1"][:4] == "RA--":
			# Equatorial coordinates; try to figure out equinox:
			iau_coord = "equ"
			if "equinox" in header:
				if int(header["equinox"]) >= 2000: iau_equinox = "J"
				else: iau_equinox = "B"
			elif "epoch" in header:
				# Assume that EPOCH has been abused to record the equinox:
				if int(header["epoch"]) >= 2000: iau_equinox = "J"
				else: iau_equinox = "B"
			else:
				# Equinox undefined:
				iau_equinox = "X"
		elif header["ctype1"][:4] == "GLON":
			# Galactic coordinates:
			iau_coord = "gal"
			iau_equinox = "G"
		else:
			# Unsupported coordinate system:
			iau_coord = ""
			iau_equinox = ""
		
		for src in xrange(n_src):
			lon = objects[src][n_par - 3]
			lat = objects[src][n_par - 2]
			
			if iau_coord == "equ":
				ra = Longitude(lon, unit=u.deg)
				dec = Latitude(lat, unit=u.deg)
				iau_pos = ra.to_string(unit=u.h, decimal=False, sep="", precision=2, alwayssign=False, pad=True, fields=3)
				iau_pos += dec.to_string(unit=u.deg, decimal=False, sep="", precision=1, alwayssign=True, pad=True, fields=3)
			else:
				iau_pos = "{0:08.4f}".format(lon)
				if lat < 0.0: iau_pos += "-"
				else: iau_pos += "+"
				iau_pos += "{0:07.4f}".format(abs(lat))
			
			iau_names[src][0] = "SoFiA " + iau_equinox + iau_pos
		
		objects = np.concatenate((objects, iau_names), axis = 1)
		catParUnits = tuple(list(catParUnits) + ["-"])
		catParNames = tuple(list(catParNames) + ["name"])
		catParFormt = tuple(list(catParFormt) + ["%30s"])
	except:
		err.warning("WCS conversion of parameters failed.")
	
	return (objects, catParNames, catParFormt, catParUnits)
예제 #5
0
def add_wcs_coordinates(objects, catParNames, catParFormt, catParUnits,
                        Parameters):
    try:
        hdulist = fits.open(Parameters["import"]["inFile"])
        header = hdulist[0].header
        hdulist.close()

        # Fix headers where "per second" is written "/S" instead of "/s"
        # (assuming they mean "per second" and not "per Siemens").
        if "cunit3" in header and "/S" in header["cunit3"]:
            err.warning("Converting '/S' to '/s' in CUNIT3.")
            header["cunit3"] = header["cunit3"].replace("/S", "/s")

        # Check if there is a Nmap/GIPSY FITS header keyword value present
        gipsyKey = [
            k for k in ["FREQ-OHEL", "FREQ-OLSR", "FREQ-RHEL", "FREQ-RLSR"]
            if (k in [header[key] for key in header if ("CTYPE" in key)])
        ]
        if gipsyKey:
            err.message(
                "GIPSY header found. Trying to convert to FITS standard.")
            from astropy.wcs import Wcsprm
            header = fix_gipsy_header(header)
            wcsin = Wcsprm(str(header))
            wcsin.sptr("VOPT-F2W")
            #if header["naxis"] == 4:
            #	objects = np.concatenate((objects, wcsin.p2s(np.concatenate((objects[:, catParNames.index("x"):catParNames. index("x") + 3], np.zeros((objects.shape[0], 1))), axis=1), 0)["world"][:,:-1]), axis=1)
            #else:
            #	objects = np.concatenate((objects, wcsin.p2s(objects[:, catParNames.index("x"):catParNames.index("x") + 3], 0)["world"]), axis=1)
            objects = np.concatenate(
                (objects,
                 wcsin.p2s(
                     objects[:,
                             catParNames.index("x"):catParNames.index("x") +
                             3], 0)["world"]),
                axis=1)
            catParUnits = tuple(
                list(catParUnits) +
                [str(cc).replace(" ", "") for cc in wcsin.cunit])
            catParNames = tuple(
                list(catParNames) + [(cc.split("--")[0]).lower()
                                     for cc in wcsin.ctype])
            catParFormt = tuple(
                list(catParFormt) + ["%15.7e", "%15.7e", "%15.7e"])

        else:
            # Constrain the RA axis reference value CRVAL_ to be between 0 and 360 deg
            rafound = 0
            for kk in range(header["naxis"]):
                if header["ctype1"][:2] == "RA":
                    rafound = 1
                    break
            if rafound:
                if header["crval%i" % (kk + 1)] < 0:
                    err.warning("Adding 360 deg to RA reference value.")
                    header["crval%i" % (kk + 1)] += 360
                elif header["crval%i" % (kk + 1)] > 360:
                    err.warning("Subtracting 360 deg from RA reference value.")
                    header["crval%i" % (kk + 1)] -= 360

            #if header["naxis"] == 4: wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL, wcs.WCSSUB_STOKES])
            #else: wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL])
            wcsin = wcs.WCS(header,
                            naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL])
            xyz = objects[:,
                          catParNames.index("x"):catParNames.index("x") +
                          3].astype(float)
            if "cellscal" in header and header["cellscal"] == "1/F":
                err.warning(
                    "CELLSCAL keyword with value of 1/F found.\n"
                    "Will account for varying pixel scale in WCS coordinate calculation."
                )
                x0, y0 = header["crpix1"] - 1, header["crpix2"] - 1
                # Will calculate the pixscale factor of each channel as:
                # pixscale = ref_frequency / frequency
                if header["ctype3"] == "VELO-HEL":
                    pixscale = (1 - header["crval3"] / scipy.constants.c) / (
                        1 - (((xyz[:, 2] + 1) - header["crpix3"]) *
                             header["cdelt3"] + header["crval3"]) /
                        scipy.constants.c)
                else:
                    err.warning(
                        "Cannot convert 3rd axis coordinates to frequency. Ignoring the effect of CELLSCAL = 1/F."
                    )
                    pixscale = 1.0
                xyz[:, 0] = (xyz[:, 0] - x0) * pixscale + x0
                xyz[:, 1] = (xyz[:, 1] - y0) * pixscale + y0
            #if header["naxis"] == 4: objects = np.concatenate((objects, wcsin.wcs_pix2world(np.concatenate((xyz, np.zeros((objects.shape[0], 1))), axis=1), 0)[:, :-1]), axis=1)
            #else: objects = np.concatenate((objects, wcsin.wcs_pix2world(xyz, 0)), axis=1)
            objects = np.concatenate((objects, wcsin.wcs_pix2world(xyz, 0)),
                                     axis=1)
            catParUnits = tuple(
                list(catParUnits) +
                [str(cc).replace(" ", "") for cc in wcsin.wcs.cunit])
            catParNames = tuple(
                list(catParNames) + [(cc.split("--")[0]).lower()
                                     for cc in wcsin.wcs.ctype])
            catParFormt = tuple(
                list(catParFormt) + ["%15.7e", "%15.7e", "%15.7e"])
        #if header["naxis"] == 4:
        #	catParUnits = catParUnits[:-1]
        #	catParNames= catParNames[:-1]
        err.message("WCS coordinates added to catalogue.")

        # Create IAU-compliant source name:
        # WARNING: This currently assumes a regular, ≥ 2-dim. data cube where the first two axes are longitude and latitude.
        n_src = objects.shape[0]
        n_par = objects.shape[1]

        iau_names = np.empty([n_src, 1], dtype=object)

        if header["ctype1"][:4] == "RA--":
            # Equatorial coordinates; try to figure out equinox:
            iau_coord = "equ"
            if "equinox" in header:
                if int(header["equinox"]) >= 2000: iau_equinox = "J"
                else: iau_equinox = "B"
            elif "epoch" in header:
                # Assume that EPOCH has been abused to record the equinox:
                if int(header["epoch"]) >= 2000: iau_equinox = "J"
                else: iau_equinox = "B"
            else:
                # Equinox undefined:
                iau_equinox = "X"
        elif header["ctype1"][:4] == "GLON":
            # Galactic coordinates:
            iau_coord = "gal"
            iau_equinox = "G"
        else:
            # Unsupported coordinate system:
            iau_coord = ""
            iau_equinox = ""

        for src in xrange(n_src):
            lon = objects[src][n_par - 3]
            lat = objects[src][n_par - 2]

            if iau_coord == "equ":
                ra = Longitude(lon, unit=u.deg)
                dec = Latitude(lat, unit=u.deg)
                iau_pos = ra.to_string(unit=u.h,
                                       decimal=False,
                                       sep="",
                                       precision=2,
                                       alwayssign=False,
                                       pad=True,
                                       fields=3)
                iau_pos += dec.to_string(unit=u.deg,
                                         decimal=False,
                                         sep="",
                                         precision=1,
                                         alwayssign=True,
                                         pad=True,
                                         fields=3)
            else:
                iau_pos = "{0:08.4f}".format(lon)
                if lat < 0.0: iau_pos += "-"
                else: iau_pos += "+"
                iau_pos += "{0:07.4f}".format(abs(lat))

            iau_names[src][0] = "SoFiA " + iau_equinox + iau_pos

        objects = np.concatenate((objects, iau_names), axis=1)
        catParUnits = tuple(list(catParUnits) + ["-"])
        catParNames = tuple(list(catParNames) + ["name"])
        catParFormt = tuple(list(catParFormt) + ["%30s"])
    except:
        err.warning("WCS conversion of parameters failed.")

    return (objects, catParNames, catParFormt, catParUnits)
예제 #6
0
def addpv(header, order=5, radial=False, ndata=64):
    logger = logging.getLogger(__name__)

    if isinstance(ndata, (tuple, list)):
        ndata = dict(x=ndata[0], y=ndata[1])
    elif not isinstance(ndata, dict):
        ndata = dict(x=ndata, y=ndata)

    header = header.copy()
    crpix = dict(x=header['crpix1'], y=header['crpix2'])
    shape = dict(x=header['naxis1'], y=header['naxis2'])
    crval = dict(x=header['crval1'], y=header['crval2'])

    with warnings.catch_warnings():
        warnings.filterwarnings(
            'ignore',
            category=FITSFixedWarning,
            message="Removed redundant "
            "SCAMP distortion parameters because SIP parameters "
            "are also present")
        wcs = WCS(header)

    start, step = {}, {}
    if shape['x'] >= ndata['x']:
        step['x'] = shape['x'] // ndata['x']
        start['x'] = (shape['x'] % ndata['x']) // 2
    else:
        step['x'] = 1
        start['x'] = 0
    if shape['y'] >= ndata['y']:
        step['y'] = shape['y'] // ndata['y']
        start['y'] = (shape['y'] % ndata['y']) // 2
    else:
        step['y'] = 1
        start['y'] = 0

    xpix, ypix = np.mgrid[start['x']:shape['x']:step['x'],
                          start['y']:shape['y']:step['y']]

    px = xpix.ravel()
    py = ypix.ravel()
    ra, dec = wcs.all_pix2world(px, py, 1)

    mask = slice(55, 60)
    ra, dec = wcs.wcs_pix2world(px, py, 1)

    cd = wcs.pixel_scale_matrix
    dpx = px - crpix['x']
    dpy = py - crpix['y']
    x = cd[0, 0] * dpx + cd[0, 1] * dpy
    y = cd[1, 0] * dpx + cd[1, 1] * dpy

    r = np.sqrt(x * x + y * y)
    phi = np.arctan2(x, -y)
    theta = np.arctan(180 / np.pi / r)

    raref = np.radians(crval['x'])
    decref = np.radians(crval['y'])

    arg = np.sin(theta) * np.sin(decref) - np.cos(theta) * np.cos(
        phi) * np.cos(decref)
    dec = np.arcsin(arg)
    arg = np.cos(theta) * np.sin(phi) / np.cos(dec)
    ra = np.arcsin(arg)
    ra += raref

    dec = np.degrees(dec)
    ra = np.degrees(ra)

    # Set up the args for minimization
    tra, tdec = wcs.all_pix2world(px, py, 1)
    tra, tdec = np.radians(tra), np.radians(tdec)
    p = np.zeros(2 * 40)
    p[1] = 1
    p[41] = 1
    pv = p.reshape(2, -1)
    pixels = np.asarray([px, py])
    wcspv = WCSParam()
    wcspv.cd = wcs.wcs.cd.copy()
    wcspv.crpix = wcs.wcs.crpix.copy()
    wcspv.crval = np.radians(wcs.wcs.crval)

    ra, dec = wcs2pv(pv, pixels, wcspv)
    args = tra, tdec, pixels, wcspv, order, radial

    before = error(p, *args)

    results = minimize(error, p, args)

    pv = results['x'].reshape(2, -1)
    after = error(results['x'], *args)

    pv[np.abs(pv) < np.finfo(pv.dtype).tiny] = 0.0

    logger.debug("New PV keywords:")
    for i in range(pv.shape[-1]):
        if pv[0, i] != 0.0:
            key = "PV1_{i:d}".format(i=i)
            header[key] = pv[0, i]
            logger.debug("%s = %f", key, pv[0, i])
        if pv[1, i] != 0.0:
            key = "PV2_{i:d}".format(i=i)
            header[key] = pv[1, i]
            logger.debug("%s = %f", key, pv[0, i])

    fraction = before / after
    logger.info("Difference improvement = %.5e / %.5e = %.2f%%", before, after,
                100 * fraction)

    return header
예제 #7
0
def _check_transform(lower, upper):
    wcsprm = Wcsprm()
    coord_array = np.array([[lower, upper]])
    sky_transform = wcsprm.p2s(coord_array, ORIGIN)
    wcsprm.s2p(sky_transform['world'], ORIGIN)
예제 #8
0
def add_wcs_coordinates(objects,catParNames,catParFormt,catParUnits,Parameters):
	import imp
	import sys
	import numpy as np
	
	c = 299792458.0  # speed of light in m/s
	
	try:
		imp.find_module('astropy')
		found = True
	except ImportError: found = False
	
	if found:
		try:
			from astropy import wcs
			from astropy.io import fits
			
			hdulist = fits.open(Parameters['import']['inFile'])
			header = hdulist[0].header
			hdulist.close()
			
			# Fix headers where "per second" is written "/S" instead of "/s"
			# (assuming they mean "per second" and not "per Siemens").
			if 'cunit3' in header and '/S' in header['cunit3']:
				sys.stderr.write('WARNING: Converting "/S" to "/s" in CUNIT3.\n')
				header['cunit3']=header['cunit3'].replace('/S','/s')
			
			## check if there is a Nmap/GIPSY FITS header keyword value present
			gipsyKey = [k for k in ['FREQ-OHEL','FREQ-OLSR','FREQ-RHEL','FREQ-RLSR'] if (k in [header[key] for key in header if ('CTYPE' in key)])]
			if gipsyKey:
				print ('GIPSY header found. Trying to convert it.')
				from astropy.wcs import Wcsprm
				header = fix_gipsy_header(header)
				wcsin = Wcsprm(str(header))
				wcsin.sptr('VOPT-F2W')
				#if header['naxis'] == 4:
				#	objects = np.concatenate((objects, wcsin.p2s(np.concatenate((objects[:, catParNames.index('x'):catParNames.index('x')+3], np.zeros((objects.shape[0], 1))), axis=1),0)['world'][:,:-1]), axis=1)
				#else:
				#	objects = np.concatenate((objects, wcsin.p2s(objects[:, catParNames.index('x'):catParNames.index('x')+3], 0)['world']), axis=1)
				objects = np.concatenate((objects, wcsin.p2s(objects[:, catParNames.index('x'):catParNames.index('x')+3], 0)['world']), axis=1)
				catParUnits = tuple(list(catParUnits) + [str(cc).replace(' ','') for cc in wcsin.cunit])
				catParNames = tuple(list(catParNames) + [(cc.split('--')[0]).lower() for cc in wcsin.ctype])
				catParFormt = tuple(list(catParFormt) + ['%15.7e', '%15.7e', '%15.7e'])
			
			else:
				# constrain the RA axis reference value CRVAL_ to be between 0 and 360 deg
				rafound = 0
				for kk in range(header['naxis']):
					if header['ctype1'][:2] == 'RA':
						rafound = 1
						break
				if rafound:
					if header['crval%i'%(kk + 1)] < 0:
						sys.stderr.write("WARNING: adding 360 deg to RA reference value.\n")
						header['crval%i'%(kk + 1)] += 360
					elif header['crval%i'%(kk + 1)] > 360:
						sys.stderr.write("WARNING: subtracting 360 deg from RA reference value.\n")
						header['crval%i'%(kk + 1)] -= 360
				
				#if header['naxis'] == 4: wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL,wcs.WCSSUB_STOKES])
				#else: wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL])
				wcsin = wcs.WCS(header, naxis=[wcs.WCSSUB_CELESTIAL, wcs.WCSSUB_SPECTRAL])
				xyz = objects[:,catParNames.index('x'):catParNames.index('x')+3].astype(float)
				if 'cellscal' in header and header['cellscal'] == '1/F':
					sys.stderr.write('WARNING: CELLSCAL keyword with value 1/F found.\n')
					sys.stderr.write('         Will account for varying pixel scale in WCS coordinate calculation.\n')
					x0, y0 = header['crpix1'] - 1, header['crpix2'] - 1
					# Will calculate the pixscale factor of each channel as:
					# pixscale = ref_frequency / frequency
					if header['ctype3'] == 'VELO-HEL':
						pixscale = (1 - header['crval3'] / c) / (1 - (((xyz[:,2] + 1) - header['crpix3']) * header['cdelt3'] + header['crval3']) / c)
					else:
						sys.stderr.write("WARNING: Cannot convert 3rd axis coordinates to frequency. Will ignore the effect of CELLSCAL = 1/F.\n")
						pixscale = 1.
					xyz[:,0] = (xyz[:,0] - x0) * pixscale + x0
					xyz[:,1] = (xyz[:,1] - y0) * pixscale + y0
				#if header['naxis'] == 4: objects = np.concatenate((objects, wcsin.wcs_pix2world(np.concatenate((xyz, np.zeros((objects.shape[0], 1))), axis=1), 0)[:,:-1]), axis=1)
				#else: objects = np.concatenate((objects, wcsin.wcs_pix2world(xyz, 0)), axis=1)
				objects = np.concatenate((objects, wcsin.wcs_pix2world(xyz, 0)), axis=1)
				catParUnits = tuple(list(catParUnits) + [str(cc).replace(' ','') for cc in wcsin.wcs.cunit])
				catParNames = tuple(list(catParNames) + [(cc.split('--')[0]).lower() for cc in wcsin.wcs.ctype])
				catParFormt = tuple(list(catParFormt) + ['%15.7e', '%15.7e', '%15.7e'])
			#if header['naxis'] == 4:
			#	catParUnits = catParUnits[:-1]
			#	catParNames= catParNames[:-1]
			print ('WCS coordinates added to catalogue.')
			
			# Create IAU-compliant source name:
			# WARNING: This currently assumes a regular, ≥ 2-dim. data cube where the first two axes are longitude and latitude.
			n_src = objects.shape[0]
			n_par = objects.shape[1]
			
			iau_names = np.empty([n_src, 1], dtype=object)
			
			if header["ctype1"][:4] == "RA--":
				# Equatorial coordinates try to figure out equinox:
				iau_coord = "equ"
				if "equinox" in header:
					if int(header["equinox"]) >= 2000: iau_equinox = "J"
					else: iau_equinox = "B"
				elif "epoch" in header:
					# Assume that EPOCH has been abused to record the equinox:
					if int(header["epoch"]) >= 2000: iau_equinox = "J"
					else: iau_equinox = "B"
				else:
					# Equinox undefined:
					iau_equinox = "X"
			elif header["ctype1"][:4] == "GLON":
				# Galactic coordinates:
				iau_coord = "gal"
				iau_equinox = "G"
			else:
				# Unsupported coordinate system:
				iau_coord = ""
				iau_equinox = ""
			
			for src in xrange(n_src):
				lon = objects[src][n_par - 3]
				lat = objects[src][n_par - 2]
				
				if iau_coord == "equ":
					ra = lon / 15.0    # convert assumed degrees to hours
					ra_h = int(ra)
					ra_m = int((ra - ra_h) * 60.0)
					ra_s = (ra - ra_h - (ra_m / 60.0)) * 3600.0
					
					dec_sgn = np.sign(lat)
					dec = abs(lat)
					dec_d = int(dec)
					dec_m = int((dec - dec_d) * 60.0)
					dec_s = (dec - dec_d - (dec_m / 60.0)) * 3600.0
					
					iau_pos = "{0:02d}{1:02d}{2:05.2f}".format(ra_h, ra_m, ra_s)
					if dec_sgn < 0: iau_pos += "-"
					else: iau_pos += "+"
					iau_pos += "{0:02d}{1:02d}{2:04.1f}".format(dec_d, dec_m, dec_s)
				else:
					iau_pos = "{0:08.4f}".format(lon)
					if lat < 0.0: iau_pos += "-"
					else: iau_pos += "+"
					iau_pos += "{0:07.4f}".format(abs(lat))
				
				iau_names[src][0] = "SoFiA " + iau_equinox + iau_pos
			
			objects = np.concatenate((objects, iau_names), axis = 1)
			catParUnits = tuple(list(catParUnits) + ["-"])
			catParNames = tuple(list(catParNames) + ["name"])
			catParFormt = tuple(list(catParFormt) + ["%30s"])
		
		except:
			sys.stderr.write("WARNING: WCS conversion of parameters failed.\n")
	
	return(objects, catParNames, catParFormt, catParUnits)
예제 #9
0
def add_wcs_coordinates(objects,catParNames,catParFormt,catParUnits,Parameters):
	import imp
	import sys
	import numpy as np
	try:
	    imp.find_module('astropy')
	    found = True
	except ImportError: found = False
	
	if found:
		try:	
			from astropy import wcs
			from astropy.io import fits
			
			hdulist = fits.open(Parameters['import']['inFile'])
			header = hdulist[0].header
			hdulist.close()
			
			## check if there is a Nmap/GIPSY FITS header keyword value present
			gipsyKey = [k for k in ['FREQ-OHEL','FREQ-OLSR','FREQ-RHEL','FREQ-RLSR'] if (k in [header[key] for key in header if ('CTYPE' in key)])]
			if gipsyKey:
				print 'GIPSY header found. Trying to convert it.'
				from astropy.wcs import Wcsprm
				header = fix_gipsy_header(header)
				wcsin = Wcsprm(str(header))
				wcsin.sptr('VOPT-F2W')
				if header['naxis']==4:
					objects = np.concatenate((objects,wcsin.p2s(np.concatenate((objects[:,catParNames.index('Xm'):catParNames.index('Xm')+3],np.zeros((objects.shape[0],1))),axis=1),0)['world'][:,:-1]),axis=1)
				else:
					objects = np.concatenate((objects,wcsin.p2s(objects[:,catParNames.index('Xm'):catParNames.index('Xm')+3],0)['world']),axis=1)
				catParUnits = tuple(list(catParUnits) + [str(cc).replace(' ','') for cc in wcsin.cunit])
				catParNames = tuple(list(catParNames) + [cc.split('--')[0]+'m' for cc in wcsin.ctype])
				catParFormt = tuple(list(catParFormt) + ['%15.7e', '%15.7e', '%15.7e'])

			else:
				# constrain the RA axis reference value CRVAL_ to be between 0 and 360 deg
				rafound=0
				for kk in range(header['naxis']):
					if header['ctype1'][:2]=='RA':
						rafound=1
						break
				if rafound:
					if header['crval%i'%(kk+1)]<0:
						print 'WARNING: adding 360 deg to RA reference value'
						header['crval%i'%(kk+1)]+=360
					elif header['crval%i'%(kk+1)]>360:
						print 'WARNING: subtracting 360 deg from RA reference value'
						header['crval%i'%(kk+1)]-=360

				wcsin = wcs.WCS(header)
				if header['naxis']==4:
					objects=np.concatenate((objects,wcsin.wcs_pix2world(np.concatenate((objects[:,catParNames.index('Xm'):catParNames.index('Xm')+3],np.zeros((objects.shape[0],1))),axis=1),0)[:,:-1]),axis=1)
				else:
					objects=np.concatenate((objects,wcsin.wcs_pix2world(objects[:,catParNames.index('Xm'):catParNames.index('Xm')+3],0)),axis=1)
				catParUnits = tuple(list(catParUnits) + [str(cc).replace(' ','') for cc in wcsin.wcs.cunit])
				catParNames = tuple(list(catParNames) + [cc.split('--')[0]+'m' for cc in wcsin.wcs.ctype])
				catParFormt = tuple(list(catParFormt) + ['%15.7e', '%15.7e', '%15.7e'])
			if header['naxis']==4:
				catParUnits = catParUnits[:-1]
				catParNames= catParNames[:-1]
			print "WCS coordinates added to the catalog."
				
		except:
			print "WARNING: WCS conversion of parameters could not be executed!\n"
			
	return(objects, catParNames, catParFormt, catParUnits)
예제 #10
0
def main():
    """Perform photometry for the given file."""
    print("Program version: 0.2")
    StartTime = datetime.now()
    args = parseArguments()

    if (args.ignore_warnings):
        warnings.simplefilter('ignore', UserWarning)

    fits_image_filenames = args.input
    #print(fits_image_filenames)

    #for directories search for appropriate fits files
    if (os.path.isdir(fits_image_filenames[0])):
        print(
            "detected a directory. Will search for fits files in it that already have astrometry calibration and therefor contain _astro"
        )
        path = fits_image_filenames[0]
        fits_image_filenames = []
        for file in os.listdir(path):
            if file.endswith(".fits") and "_astro" in file:
                fits_image_filenames.append(path + "/" + file)
        print(fits_image_filenames)

    for fits_image_filename in fits_image_filenames:
        print("")
        print(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
        print("> Photometry for {} ".format(fits_image_filename))

        with fits.open(fits_image_filename) as hdul:
            #print(hdul.info())
            if (args.verbose):
                print(
                    "if image is not at first position in the fits file the program will break later on"
                )
            #print(hdul[0].header)

            hdu = hdul[0]
            hdr = hdu.header

            image_or = hdul[0].data.astype(float)
            image = image_or - np.median(image_or)

        wcsprm = Wcsprm(hdr.tostring().encode(
            'utf-8'))  #everything else gave me errors with python 3

        #tranlating aperture into pixel:
        on_sky = wcsprm.p2s([[0, 0], [1, 1]], 0)["world"]
        px_scale = np.sqrt((on_sky[0, 0] - on_sky[1, 0])**2 +
                           (on_sky[0, 1] - on_sky[1, 1])**2)
        px_scale = px_scale * 60 * 60  #in arcsec
        aperture = args.aperture / px_scale  #aperture n pixel
        print("aperture")
        observation = find_sources(image, aperture)
        #print(observation)

        positions = (observation['xcenter'], observation['ycenter'])
        apertures = CircularAperture(positions, r=4.)

        #get rough coordinates
        coord = SkyCoord(wcsprm.crval[0],
                         wcsprm.crval[1],
                         unit=(u.deg, u.deg),
                         frame="icrs")

        #put in nice wrapper! with repeated tries and maybe try synchron!
        print(">Dowloading catalog data")
        #WCS.calc_footprint(header=None, undistort=True, axes=None, center=True)
        radius = u.Quantity(5, u.arcmin)  #should be enough for all images
        catalog_data, band_name, catalog_name, mag_sys = query.get_photometry_data(
            coord, radius, args.band, args.catalog)

        #throwing out blended sources (should be improved, TODO)

        apertures_catalog = CircularAperture(wcsprm.s2p(
            catalog_data[["ra", "dec"]], 1)['pixcrd'],
                                             r=5.)

        obs_matched, cat_matched, distances = register.find_matches_keep_catalog_info(
            observation, catalog_data, wcsprm, threshold=3)
        print("Found {} matches".format(obs_matched.shape[0]))
        MAG_CALC = True
        if (obs_matched.shape[0] == 0):
            MAG_CALC = False

        obs_matched["aperture_sum"]
        cat_matched[band_name]

        #mag = -2.5 log10(cts) + ZP
        ZP = -1 * (-2.5 * np.log10(obs_matched["aperture_sum"].values) -
                   cat_matched[band_name].values)

        #FIGURE OUT LINEAR RANGE TOTO
        ZP_median = np.median(ZP[~np.isnan(ZP)])
        new_magnitudes = -2.5 * np.log10(
            observation["aperture_sum"].values) + ZP_median

        ra = args.ra
        dec = args.dec
        if (args.name):
            targets = pd.read_csv("targets.csv")

            if ((targets["NAME"] == args.name).sum()):
                ra = targets.loc[targets["NAME"] == args.name, "RA"].values[0]
                dec = targets.loc[targets["NAME"] == args.name,
                                  "DEC"].values[0]
                print("For {} the following coordinates where found".format(
                    args.name))
                print("ra: {} dec: {}".format(ra, dec))
            else:
                print("{} not found".format(args.name))
        if (ra and dec):
            c_unknown = SkyCoord(ra, dec, unit=(u.deg, u.deg), frame="icrs")
            #print(observation[["xcenter", "ycenter"]].values)
            coordinats_obs = wcsprm.p2s(
                observation[["xcenter", "ycenter"]].values, 1)["world"]
            #print(coordinats_obs[17])
            c_obs = SkyCoord(coordinats_obs[:, 0],
                             coordinats_obs[:, 1],
                             unit=(u.deg, u.deg),
                             frame="icrs")
            #print(coordinats_obs)
            from astropy.coordinates import match_coordinates_sky
            idx, d2d, d3d = match_coordinates_sky(c_unknown, c_obs)
            cand_dups = d2d < 5 * u.arcsec

            mean, median, std = sigma_clipped_stats(image, sigma=3.0)
            ap_area = CircularAperture((2, 2), r=aperture)
            sig3_limiting_mag = -2.5 * np.log10(
                3 * std * np.sqrt(ap_area.area())) + ZP_median
            sig5_limiting_mag = -2.5 * np.log10(
                5 * std * np.sqrt(ap_area.area())) + ZP_median

            #######################
            #estimating the error via random apertures
            # print(std*np.sqrt(aperture_obj.area()))
            ran_x = 2 * aperture + np.random.random(1000) * (image.shape[0] -
                                                             4 * aperture)
            ran_y = 2 * aperture + np.random.random(1000) * (image.shape[0] -
                                                             4 * aperture)
            apertures_error = CircularAperture((ran_x, ran_y), r=aperture)
            phot_table = aperture_photometry(image, apertures_error)
            phot_table[
                'aperture_sum'].info.format = '%.8g'  # for consistent table output
            random_extractions = Table(phot_table).to_pandas()
            #print(np.mean(np.abs(random_extractions["aperture_sum"])))
            # print(np.median(np.abs(random_extractions["aperture_sum"])))
            # sig5_limiting_mag_apertures = -2.5*np.log10(5*np.median(np.abs(random_extractions["aperture_sum"]))) + ZP_median
            # print(sig5_limiting_mag_apertures)
            m, _, std_apertures = sigma_clipped_stats(
                random_extractions["aperture_sum"], sigma=3)
            print(std_apertures)
            sig5_limiting_mag_apertures = -2.5 * np.log10(
                5 * std_apertures) + ZP_median
            # print(sig5_limiting_mag_apertures)
            # print(np.mean(random_extractions.loc[random_extractions["aperture_sum"]<0,"aperture_sum"]))
            ###########################
            mag = 0
            if (cand_dups.sum() > 0):
                print(
                    "Position was given. Found {} sources in a 5 arcsec radius. Here is the magnitude:"
                    .format(cand_dups.sum()))
                print(new_magnitudes[idx])
                print("----")

                aperture_obj = CircularAperture(
                    ((observation["xcenter"].values)[idx],
                     (observation["ycenter"].values)[idx]),
                    r=aperture)
                #noise = (observation["aperture_sum"].values)[idx] /(std*np.sqrt(aperture_obj.area()))
                #https://en.wikipedia.org/wiki/Sum_of_normally_distributed_random_variables
                #the std**2 is added, so we get a square root for the area!
                noise = (
                    observation["aperture_sum"].values)[idx] / std_apertures

                #print(noise_prob_wrong)
                #print(noise_prob_wrong2)

                print("We get a signal to noise of {} for the fixed aperture".
                      format(noise))

                mag = new_magnitudes[idx]
                mag_err = 2.5 * np.log10(1 + 1 / noise)
                text = "found detection in {} band,\n {:.4g} +- {:.2g} {}mag, {:.3g} S/N \n 5 sig limiting mag is {:.4g}".format(
                    args.band, mag, mag_err, mag_sys, noise,
                    sig5_limiting_mag_apertures)

            else:
                print(
                    "Position was given. No object was found at that position."
                )
                pix_unknown = wcsprm.s2p([[ra, dec]], 1)
                pix_unknown = pix_unknown['pixcrd']

                aperture_obj = CircularAperture(pix_unknown, r=aperture)
                phot_table = aperture_photometry(image, aperture_obj)
                phot_table[
                    'aperture_sum'].info.format = '%.8g'  # for consistent table output
                #print(phot_table)
                forced_phot = Table(phot_table).to_pandas()

                forced_mag = -2.5 * np.log10(
                    forced_phot["aperture_sum"].values) + ZP_median
                forced_mag = forced_mag[0]

                #noise = (forced_phot["aperture_sum"].values)[0] /(std*np.sqrt(aperture_obj.area()))
                noise = (forced_phot["aperture_sum"].values)[0] / std_apertures

                print("Forced photometry gives a magnitude of {}".format(
                    forced_mag))

                #local error
                # pix_unknown = pix_unknown[0]
                # mean_loc, median_loc, std_loc = sigma_clipped_stats(image[int(pix_unknown[0])-50:int(pix_unknown[0])+50,int(pix_unknown[1])-50:int(pix_unknown[1])+50], sigma=3.0)
                # ap_area= CircularAperture((2,2), r=aperture)
                # sig5_limiting_mag_local = -2.5*np.log10(5*std_loc*np.sqrt(ap_area.area())) + ZP_median
                # print((std_loc*np.sqrt(aperture_obj.area())))
                # print(sig5_limiting_mag_local)

                print("We get a signal to noise of {} for the fixed aperture".
                      format(noise))
                mag = forced_mag
                mag_err = 2.5 * np.log10(1 + 1 / noise)
                text = "forced photometry in {} band,\n {:.4g} +- {:.2g} {}mag, {:.3g} S/N \n 5 sig limiting mag is {:.4g} ".format(
                    args.band, mag, mag_err, mag_sys, noise,
                    sig5_limiting_mag_apertures)

        else:
            print(new_magnitudes)
            mag = 0

        obs_with_photometry = observation.copy()
        obs_with_photometry["mag"] = new_magnitudes

        #search for targeted object and print out its magnitude TODO

        if (ra and dec):
            plt.figure(figsize=(15, 8))
            plt.subplot(1, 2, 1)
            pix_unknown = wcsprm.s2p([[ra, dec]], 1)
            pix_unknown = pix_unknown['pixcrd']
            pix_unknown = pix_unknown[0]

            plt.xlabel("pixel x direction")
            plt.ylabel("pixel y direction")
            plt.title(text, size=20)
            #plt.imshow(image[int( pix_unknown[0])-30: int(pix_unknown[0])+30, int(pix_unknown[1])-30:int(pix_unknown[1])+30],cmap='Greys', origin='lower', norm=LogNorm())
            #plt.plot(30, 30, "+", color="red", markersize=20)
            plt.imshow(image, cmap='Greys', origin='lower', norm=LogNorm())
            plt.xlim(int(pix_unknown[0]) - 20, int(pix_unknown[0]) + 20)
            plt.ylim(int(pix_unknown[1]) - 20, int(pix_unknown[1]) + 20)
            aperture_obj.plot(color='blue',
                              lw=1.5,
                              alpha=0.5,
                              label=str(args.aperture) + " arcsec aperture")
            plt.plot(pix_unknown[0],
                     pix_unknown[1],
                     "+",
                     color="red",
                     markersize=20,
                     linewidth=10,
                     label="predicted target position")
            plt.legend(bbox_to_anchor=(1.1, -0.1), ncol=2)

            plt.subplot(1, 2, 2)
            plt.title("Photometric calibration with {} sources from {}".format(
                obs_matched.shape[0], catalog_name))
            plt.plot(cat_matched[band_name].values,
                     ZP,
                     "o",
                     markersize=20,
                     label="catalog objects")
            if (MAG_CALC):
                plt.ylim(np.nanmin(ZP) - 1, np.nanmax(ZP) + 1)
            else:
                plt.ylim(10, 30)
            if (mag):
                plt.axvline(x=mag, linewidth=4, color="green", label="target")
            plt.xlabel("catalog " + band_name + " magnitude")
            plt.ylabel(
                "Zeropoint (should be constant in linear part of the detector)"
            )
            plt.legend()
            outputname = fits_image_filename.replace('.fits', '')
            plt.savefig(outputname + "_ra{}dec{}.pdf".format(ra, dec))
            plt.show()

        else:

            plt.figure()
            plt.plot(cat_matched[band_name].values,
                     ZP,
                     "o",
                     markersize=20,
                     label="catalog objects")
            plt.ylim(np.nanmin(ZP) - 1, np.nanmax(ZP) + 1)
            if (mag):
                plt.axvline(x=mag, linewidth=4, color="green", label="target")
            plt.xlabel("catalog " + band_name + " magnitude")
            plt.ylabel(
                "Zeropoint (should be constant in linear part of the detector)"
            )
            plt.legend()
            plt.show()

        print("overall time taken")
        print(datetime.now() - StartTime)
        # if(args.show_images):
        #     plt.show()
    print("-- finished --")
예제 #11
0
def galaxy_mask(header,leda):

    ra, dec, theta, diam, ba = leda

    sz = (header["NAXIS1"], header["NAXIS2"])
    outmsk = np.zeros((sz[0],sz[1]),dtype=bool)
    w = WCS(header)

    ##CCD corners (these are actually in the header for DECam)
    xc = [0,0,sz[0]-1,sz[0]-1]
    yc = [0,sz[1]-1,0,sz[1]-1]
    xcen = (sz[0]-1)/2
    ycen = (sz[1]-1)/2

    c = w.pixel_to_world(xcen,ycen)
    sep = c.separation(w.pixel_to_world(xc, yc))

    racen = c.ra.degree
    deccen = c.dec.degree

    dac = np.max(sep.degree)
    coordleda = SkyCoord(ra,dec,frame='icrs',unit='deg')
    dangle = c.separation(coordleda).degree

    keep = dangle < dac + diam
    #filter out galaxies with too large angle displace to consider
    if sum(keep) == 0:
        return outmsk

    relevant = w.world_to_pixel(coordleda[keep])

    with warnings.catch_warnings():
        warnings.simplefilter('ignore', category=(AstropyWarning,RuntimeWarning))
        wperm = Wcsprm(header=header.tostring().encode('utf-8'))
        cd = wperm.cd #* wperm.cdelt[np.mod(np.linspace(0,3,4,dtype=int),2).reshape(2,2)]
    pscl = np.mean(np.sqrt(np.sum(cd**2,axis=1)))*3600 #convert back to arcsec from deg for interp
    msz = np.ceil(3600*diam[keep]/pscl).astype(int) #this is the mask size in the pixel scale
    msz += np.mod(msz,2) == 0 #adjust even size to be odd so that the center means something
    mh = (msz-1)//2 #I think this -1 is necessary becase we are all odd by construction

    ix = np.round(relevant[0]).astype(int)
    iy = np.round(relevant[1]).astype(int)

    #largest circle approx must fall in ccd
    insideim = ((ix+mh) >= 0) & ((ix-mh) < sz[0]) & ((iy+mh) >= 0) & (iy-mh < sz[1])
    nim = sum(insideim)

    #filter out galaxy with no overlap
    if nim == 0:
        return outmsk

    rainl = coordleda[keep][insideim].ra.degree
    decinl = coordleda[keep][insideim].dec.degree
    thetal = np.deg2rad(theta[keep][insideim])

    print("Masked Galaxies: %d" % nim)
    for i in range(0,nim):
        un, ue = tan_unit_vectors(rainl[i],decinl[i],racen,deccen)

        ueofn = un*np.cos(thetal[i])+ue*np.sin(thetal[i])
        angle = np.rad2deg(np.arctan2(ueofn[1],ueofn[0]))

        ixn = ix[insideim][i]
        iyn = iy[insideim][i]
        mhn = mh[insideim][i]
        mszn = msz[insideim][i]

        e = Ellipse2D(x_0=mhn, y_0=mhn, a=mhn, b=ba[keep][insideim][i]*mhn,
                      theta=np.deg2rad(angle))
        y, x = np.mgrid[0:mszn, 0:mszn]
        smsk = (e(x, y) == 1)

        outmsk[np.clip(ixn-mhn,a_min=0,a_max=None):np.clip(ixn+mhn+1,a_min=None,a_max=sz[0]),
           np.clip(iyn-mhn,a_min=0,a_max=None):np.clip(iyn+mhn+1,a_min=None,a_max=sz[1])] |= smsk[
        np.clip(mhn-ixn,a_min=0,a_max=None):np.clip(sz[0]-ixn+mhn,a_min=None,a_max=mszn),
             np.clip(mhn-iyn,a_min=0,a_max=None):np.clip(sz[1]-iyn+mhn,a_min=None,a_max=mszn)]
    return outmsk.T #revist need for transpose
예제 #12
0
def add_wcs_coordinates(objects,catParNames,catParFormt,catParUnits,Parameters):
	import imp
	import sys
	import numpy as np
	try:
	    imp.find_module('astropy')
	    found = True
	except ImportError: found = False
	
	if found:
		try:	
			from astropy import wcs
			from astropy.io import fits
			
			hdulist = fits.open(Parameters['import']['inFile'])
			header = hdulist[0].header
			hdulist.close()

			# Fix headers where "per second" is written "/S" instead of "/s"
			# (assuming they mean "per second" and not "per Siemens").
			if 'cunit3' in header and '/S' in header['cunit3']:
				print 'WARNING: Converting "/S" to "/s" in CUNIT3.'
				header['cunit3']=header['cunit3'].replace('/S','/s')
			
			## check if there is a Nmap/GIPSY FITS header keyword value present
			gipsyKey = [k for k in ['FREQ-OHEL','FREQ-OLSR','FREQ-RHEL','FREQ-RLSR'] if (k in [header[key] for key in header if ('CTYPE' in key)])]
			if gipsyKey:
				print 'GIPSY header found. Trying to convert it.'
				from astropy.wcs import Wcsprm
				header = fix_gipsy_header(header)
				wcsin = Wcsprm(str(header))
				wcsin.sptr('VOPT-F2W')
				if header['naxis']==4:
					objects = np.concatenate((objects,wcsin.p2s(np.concatenate((objects[:,catParNames.index('x'):catParNames.index('x')+3],np.zeros((objects.shape[0],1))),axis=1),0)['world'][:,:-1]),axis=1)
				else:
					objects = np.concatenate((objects,wcsin.p2s(objects[:,catParNames.index('x'):catParNames.index('x')+3],0)['world']),axis=1)
				catParUnits = tuple(list(catParUnits) + [str(cc).replace(' ','') for cc in wcsin.cunit])
				catParNames = tuple(list(catParNames) + [(cc.split('--')[0]).lower() for cc in wcsin.ctype])
				catParFormt = tuple(list(catParFormt) + ['%15.7e', '%15.7e', '%15.7e'])

			else:
				# constrain the RA axis reference value CRVAL_ to be between 0 and 360 deg
				rafound=0
				for kk in range(header['naxis']):
					if header['ctype1'][:2]=='RA':
						rafound=1
						break
				if rafound:
					if header['crval%i'%(kk+1)]<0:
						sys.stderr.write("WARNING: adding 360 deg to RA reference value.\n")
						header['crval%i'%(kk+1)]+=360
					elif header['crval%i'%(kk+1)]>360:
						sys.stderr.write("WARNING: subtracting 360 deg from RA reference value.\n")
						header['crval%i'%(kk+1)]-=360

				wcsin = wcs.WCS(header)
				xyz=objects[:,catParNames.index('x'):catParNames.index('x')+3].astype(float)
				if 'cellscal' in header and header['cellscal'] == '1/F':
					print 'WARNING: CELLSCAL keyword with value 1/F found.'
					print 'Will take into account varying pixel scale when calculating wcs coordinates.'
					x0,y0=header['crpix1']-1,header['crpix2']-1
					# Will calculate the pixscale factor of each channel as:
					# pixscale = ref_frequency / frequency
					if header['ctype3']=='VELO-HEL':
						pixscale=(1-header['crval3']/2.99792458e+8)/(1-(((xyz[:,2]+1)-header['crpix3'])*header['cdelt3']+header['crval3'])/2.99792458e+8)
					else:
						sys.stderr.write("WARNING: Cannot convert axis3 coordinates to frequency. Will ignore the effect of CELLSCAL = 1/F.\n")
						pixscale=1.
					xyz[:,0]=(xyz[:,0]-x0)*pixscale+x0
					xyz[:,1]=(xyz[:,1]-y0)*pixscale+y0
				if header['naxis']==4: objects=np.concatenate((objects,wcsin.wcs_pix2world(np.concatenate((xyz,np.zeros((objects.shape[0],1))),axis=1),0)[:,:-1]),axis=1)
				else: objects=np.concatenate((objects,wcsin.wcs_pix2world(xyz,0)),axis=1)
				catParUnits = tuple(list(catParUnits) + [str(cc).replace(' ','') for cc in wcsin.wcs.cunit])
				catParNames = tuple(list(catParNames) + [(cc.split('--')[0]).lower() for cc in wcsin.wcs.ctype])
				catParFormt = tuple(list(catParFormt) + ['%15.7e', '%15.7e', '%15.7e'])
			if header['naxis']==4:
				catParUnits = catParUnits[:-1]
				catParNames= catParNames[:-1]
			print "WCS coordinates added to the catalogue."
				
		except:
			sys.stderr.write("WARNING: WCS conversion of parameters failed.\n")
			
	return(objects, catParNames, catParFormt, catParUnits)