def tigger_src(src, idx): name = "SRC%d" % idx flux = ModelClasses.Polarization(float(src["int_flux"]), 0, 0, 0, I_err=float(src["err_int_flux"])) ra, ra_err = map(numpy.deg2rad, (float(src["ra"]), float(src["err_ra"]))) dec, dec_err = map(numpy.deg2rad, (float(src["dec"]), float(src["err_dec"]))) pos = ModelClasses.Position(ra, dec, ra_err=ra_err, dec_err=dec_err) ex, ex_err = map(numpy.deg2rad, (float(src["a"]), float(src["err_a"]))) ey, ey_err = map(numpy.deg2rad, (float(src["b"]), float(src["err_b"]))) pa, pa_err = map(numpy.deg2rad, (float(src["pa"]), float(src["err_pa"]))) if ex and ey: shape = ModelClasses.Gaussian( ex, ey, pa, ex_err=ex_err, ey_err=ey_err, pa_err=pa_err) else: shape = None source = SkyModel.Source(name, pos, flux, shape=shape) # Adding source peak flux (error) as extra flux attributes for sources, # and to avoid null values for point sources I_peak = src["Total_flux"] if shape: source.setAttribute("I_peak", float(src["peak_flux"])) source.setAttribute("I_peak_err", float(src["err_peak_flux"])) else: source.setAttribute("I_peak", float(src["int_flux"])) source.setAttribute("I_peak_err", float(src["err_int_flux"])) return source
def tigger_src(src, idx): name = "SRC%d" % idx flux = ModelClasses.Polarization(src["Total_flux"], 0, 0, 0, I_err=src["E_Total_flux"]) ra, ra_err = map(numpy.deg2rad, (src["RA"], src["E_RA"])) dec, dec_err = map(numpy.deg2rad, (src["DEC"], src["E_DEC"])) pos = ModelClasses.Position(ra, dec, ra_err=ra_err, dec_err=dec_err) ex, ex_err = map(numpy.deg2rad, (src["DC_Maj"], src["E_DC_Maj"])) ey, ey_err = map(numpy.deg2rad, (src["DC_Min"], src["E_DC_Min"])) pa, pa_err = map(numpy.deg2rad, (src["PA"], src["E_PA"])) if ex and ey: shape = ModelClasses.Gaussian(ex, ey, pa, ex_err=ex_err, ey_err=ey_err, pa_err=pa_err) else: shape = None source = SkyModel.Source(name, pos, flux, shape=shape) # Adding source peak flux (error) as extra flux attributes for sources, # and to avoid null values for point sources I_peak = src["Total_flux"] if shape: source.setAttribute("I_peak", src["Peak_flux"]) source.setAttribute("I_peak_err", src["E_peak_flux"]) else: source.setAttribute("I_peak", src["Total_flux"]) source.setAttribute("I_peak_err", src["E_Total_flux"]) if spi_do: # Check if start frequency is provided if not provided raise error. # It is used to define tigger source spectrum index frequency if freq0: spi, spi_err = (src['Spec_Indx'], src['E_Spec_Indx']) source.spectrum = ModelClasses.SpectralIndex(spi, freq0) source.setAttribute('spi_error', spi_err) else: raise RuntimeError("No start frequency (freq0) provided.") return source
def tigger_src(src, idx): name = "SRC%d" % idx flux = ModelClasses.Polarization(src["f_int"], 0, 0, 0) ra = numpy.deg2rad(src["ra"]) dec = numpy.deg2rad(src["dec"]) pos = ModelClasses.Position(ra, dec) ex = numpy.deg2rad(src["ell_maj"]) ey = numpy.deg2rad(src["ell_min"]) pa = numpy.deg2rad(src["ell_pa"]) if ex and ey: shape = ModelClasses.Gaussian(ex, ey, pa) else: shape = None source = SkyModel.Source(name, pos, flux, shape=shape) # Adding source peak flux (error) as extra flux attributes for sources, # and to avoid null values for point sources I_peak = src["Total_flux"] if shape: source.setAttribute("I_peak", float(src["f_peak"])) else: source.setAttribute("I_peak", float(src["f_int"])) return source
def load(filename, import_src=True, import_cc=True, min_extent=0, **kw): """Imports a NEWSTAR MDL file. min_extent is minimal source extent (in radians), above which a source will be treated as a Gaussian rather than a point component. import_src=False causes source components to be omitted import_cc=False causes clean components to be omitted """ srclist = [] dprint(1, "importing NEWSTAR file", filename) # build the LSM from a NewStar .MDL model file # if only_cleancomp=True, only clean components are used to build the LSM # if no_cleancomp=True, no clean components are used to build the LSM ff = open(filename, mode="rb") ### read GFH and MDH headers -- 512 bytes try: gfh = numpy.fromfile(ff, dtype=numpy.uint8, count=512) mdh = numpy.fromfile(ff, dtype=numpy.uint8, count=64) # parse headers ftype, fhlen, fver, crdate, crtime, rrdate, rrtime, rcount, nname = parseGFH( gfh) if ftype != ".MDL": raise TypeError maxlin, modptr, nsources, mtype, mepoch, ra0, dec0, freq0 = parseMDH( mdh) beam_const = 65 * 1e-9 * freq0 ## temp dict to hold unique nodenames unamedict = {} ### Models -- 56 bytes for ii in range(0, nsources): mdl = numpy.fromfile(ff, dtype=numpy.uint8, count=56) ### source parameters sI, ll, mm, id, sQ, sU, sV, eX, eY, eP, SI, RM = struct.unpack( 'fffiffffffff', mdl[0:48]) ### type bits bit1, bit2 = struct.unpack('BB', mdl[52:54]) # convert fluxes sI *= 0.005 # convert from WU to Jy (1WU=5mJy) sQ *= sI sU *= sI sV *= sI # Interpret bitflags 1: bit 0= extended; bit 1= Q|U|V <>0 and no longer used according to Wim fl_ext = bit1 & 1 # Interpret bitflags 2: bit 0= clean component; bit 3= beamed fl_cc = bit2 & 1 fl_beamed = bit2 & 8 ### extended source params: in arcsec, so multiply by ??? if fl_ext: ## the procedure is NMOEXT in nscan/nmoext.for if eP == 0 and eX == eY: r0 = 0 else: r0 = .5 * math.atan2(-eP, eY - eX) r1 = math.sqrt(eP * eP + (eX - eY) * (eX - eY)) r2 = eX + eY eX = 2 * math.sqrt(abs(0.5 * (r2 + r1))) eY = 2 * math.sqrt(abs(0.5 * (r2 - r1))) eP = r0 # NEWSTAR MDL lists might have same source twice if they are # clean components, so make a unique name for them bname = 'N' + str(id) if bname in unamedict: uniqname = bname + '_' + str(unamedict[bname]) unamedict[bname] += 1 else: uniqname = bname unamedict[bname] = 1 # compose source information pos = ModelClasses.Position(*lm_ncp_to_radec(ra0, dec0, ll, mm)) flux = ModelClasses.PolarizationWithRM(sI, sQ, sU, sV, RM, freq0) spectrum = ModelClasses.SpectralIndex(SI, freq0) tags = {} # work out beam gain and apparent flux tags['_lm_ncp'] = (ll, mm) tags['_newstar_r'] = tags['r'] = r = math.sqrt(ll * ll + mm * mm) tags['newstar_beamgain'] = bg = max( math.cos(beam_const * r)**6, .01) tags['newstar_id'] = id if fl_beamed: tags['Iapp'] = sI * bg tags['newstar_beamed'] = True tags['flux_intrinsic'] = True else: tags['flux_apparent'] = True # make some tags based on model flags if fl_cc: tags['newstar_cc'] = True # make shape if extended if fl_ext and max(eX, eY) >= min_extent: shape = ModelClasses.Gaussian(eX, eY, eP) else: shape = None # compute apparent flux src = SkyModel.Source(uniqname, pos, flux, shape=shape, spectrum=spectrum, **tags) srclist.append(src) except: traceback.print_exc() raise TypeError("%s does not appear to be a valid NEWSTAR MDL file" % filename) dprintf(2, "imported %d sources from file %s\n", len(srclist), filename) return ModelClasses.SkyModel(ra0=ra0, dec0=dec0, freq0=freq0, pbexp='max(cos(65*1e-9*fq*r)**6,.01)', *srclist)
def load(filename, format=None, freq0=None, center_on_brightest=False, min_extent=0, verbose=0, **kw): """Imports an ASCII table The 'format' argument can be either a dict (such as the DefaultDMSFormat dict above), or a string such as DefaultDMSFormatString. (Other possible field names are "ra_d", "ra_rad", "dec_rad", "dec_sign".) If None is specified, DefaultDMSFormat is used. The 'freq0' argument supplies a default reference frequency (if one is not contained in the file.) If 'center_on_brightest' is True, the mpodel field center will be set to the brightest source. 'min_extent' is minimal source extent (in radians), above which a source will be treated as a Gaussian rather than a point component. """ srclist = [] dprint(1, "importing ASCII DMS file", filename) # brightest source and its coordinates maxbright = 0 brightest_name = radec0 = None # Get column number associated with field from format dict, as well as the error # column number. Returns tuple of indices, with None index indicating no such column def get_field(name): return format.get(name, None), format.get(name + "_err", None) # Get column number associated with field from format dict, as well as the error # column number. Field is an angle thus will be suffixed with _{rad,d,h,m,s}. # Returns tuple of # column,scale,err_column,err_scale # with None index indicating no such column. Scale is scaling factor to convert # quantity in column to radians def get_ang_field(name, units=ANGULAR_UNITS): column = err_column = colunit = errunit = None units = units or ANGULAR_UNITS for unit, scale in units.items(): if column is None: column = format.get("%s_%s" % (name, unit)) if column is not None: colunit = scale if err_column is None: err_column = format.get("%s_err_%s" % (name, unit)) if err_column is not None: errunit = scale return column, colunit, err_column, errunit # helper function: returns element #num from the fields list, multiplied by scale, or None if no such field def getval(num, scale=1): return None if (num is None or len(fields) <= num) else float(fields[num]) * scale # now process file line-by-line linenum = 0 format_str = '' for line in open(filename): # for the first line, figure out the file format if not linenum: if not format and line.startswith("#format:"): format = line[len("#format:"):].strip() dprint(1, "file contains format header:", format) # set default format if format is None: format = DefaultDMSFormatString # is the format a string rather than a dict? Turn it into a dict then if isinstance(format, str): format_str = format # make list of fieldname,fieldnumber tuples fields = [(field, i) for i, field in enumerate(format.split())] if not fields: raise ValueError("illegal format string in file: '%s'" % format) # last fieldname can end with ... to indicate that it absorbs the rest of the line if fields[-1][0].endswith('...'): fields[-1] = (fields[-1][0][:-3], slice(fields[-1][1], None)) # make format dict format = dict(fields) elif not isinstance(format, dict): raise TypeError("invalid 'format' argument of type %s" % (type(format))) # nf = max(format.itervalues())+1 # fields = ['---']*nf # for field,number in format.iteritems(): # fields[number] = field # format_str = " ".join(fields) # get list of custom attributes from format custom_attrs = [] for name, col in format.items(): if name.startswith(":"): m = re.match("^:(bool|int|float|complex|str):([\w]+)$", name) if not m: raise TypeError("invalid field specification '%s' in format string" % name) custom_attrs.append((eval(m.group(1)), m.group(2), col)) # get minimum necessary fields from format name_field = format.get('name', None) # flux i_field, i_err_field = get_field("i") if i_field is None: raise ValueError("ASCII format specification lacks mandatory flux field ('i')") # main RA field ra_field, ra_scale, ra_err_field, ra_err_scale = get_ang_field('ra', ANGULAR_UNITS_RA) if ra_field is None: raise ValueError("ASCII format specification lacks mandatory Right Ascension field ('ra_h', 'ra_d' or 'ra_rad')") # main Dec field dec_field, dec_scale, dec_err_field, dec_err_scale = get_ang_field('dec', ANGULAR_UNITS_DEC) if dec_field is None: raise ValueError("ASCII format specification lacks mandatory Declination field ('dec_d' or 'dec_rad')") # polarization as QUV quv_fields = [get_field(x) for x in ['q', 'u', 'v']] # linear polarization as fraction and angle polfrac_field = format.get('pol_frac', None) if polfrac_field is not None: polpa_field, polpa_scale = format.get('pol_pa_d', None), (math.pi / 180) if not polpa_field is not None: polpa_field, polpa_scale = format.get('pol_pa_rad', None), 1 # fields for extent parameters extent_fields = [get_ang_field(x, ANGULAR_UNITS) for x in ('emaj', 'emin', 'pa')] # all three must be present, else ignore if any([x[0] is None for x in extent_fields]): extent_fields = None # fields for reference freq and RM and SpI freq0_field = format.get('freq0', None) rm_field, rm_err_field = get_field('rm') spi_fields = [get_field('spi')] + [get_field('spi%d' % i) for i in range(2, 10)] tags_slice = format.get('tags', None) # now go on to process the line linenum += 1 try: # strip whitespace line = line.strip() dprintf(4, "%s:%d: read line '%s'\n", filename, linenum, line) # skip empty or commented lines if not line or line[0] == '#': continue # split (at whitespace) into fields fields = line.split() # get name name = fields[name_field] if name_field is not None else str(len(srclist) + 1) i = getval(i_field) i_err = getval(i_err_field) # get position: RA ra = getval(ra_field) ra_err = getval(ra_err_field, ra_scale) if 'ra_m' in format: ra += float(fields[format['ra_m']]) / 60. if 'ra_s' in format: ra += float(fields[format['ra_s']]) / 3600. ra *= ra_scale # position: Dec. Separate treatment of sign dec = abs(getval(dec_field)) dec_err = getval(dec_err_field, dec_scale) if 'dec_m' in format: dec += float(fields[format['dec_m']]) / 60. if 'dec_s' in format: dec += float(fields[format['dec_s']]) / 3600. if fields[format.get('dec_sign', dec_field)][0] == '-': dec = -dec dec *= dec_scale # for up position object pos = ModelClasses.Position(ra, dec, ra_err=ra_err, dec_err=dec_err) # see if we have freq0 # Use explicitly provided reference frequency for this source if available f0 = None if freq0_field is not None: try: f0 = float(fields[freq0_field]) # If no default reference frequency for the model was supplied, # initialise from first source with a reference frequency if freq0 is None: freq0 = f0 dprint(0, "Set default freq0 to %s " "from source on line %s." % (f0, linenum)) except IndexError: f0 = None # Otherwise use default reference frequency (derived from args # or first reference frequency found in source) if f0 is None and freq0 is not None: f0 = freq0 # see if we have Q/U/V (q, q_err), (u, u_err), (v, v_err) = [(getval(x), getval(x_err)) for x, x_err in quv_fields] if polfrac_field is not None: pf = fields[polfrac_field] pf = float(pf[:-1]) / 100 if pf.endswith("%") else float(pf) ppa = float(fields[polpa_field]) * polpa_scale if polpa_field is not None else 0 q = i * pf * math.cos(2 * ppa) u = i * pf * math.sin(2 * ppa) v = 0 # see if we have RM as well. Create flux object (unpolarized, polarized, polarized w/RM) rm, rm_err = getval(rm_field), getval(rm_err_field) if q is None: flux = ModelClasses.Polarization(i, 0, 0, 0, I_err=i_err) elif f0 is None or rm is None: flux = ModelClasses.Polarization(i, q, u, v, I_err=i_err, Q_err=q_err, U_err=u_err, V_err=v_err) else: flux = ModelClasses.PolarizationWithRM(i, q, u, v, rm, f0, I_err=i_err, Q_err=q_err, U_err=u_err, V_err=v_err, rm_err=rm_err) # see if we have a spectral index if f0 is None: spectrum = None else: spi = [getval(x) for x, xerr in spi_fields] spi_err = [getval(xerr) for x, xerr in spi_fields] dprint(4, name, "spi is", spi, "err is", spi_err) # if any higher-order spectral terms are specified, include them here but trim off all trailing zeroes while spi and not spi[-1]: del spi[-1] del spi_err[-1] if not spi: spectrum = None elif len(spi) == 1: spectrum = ModelClasses.SpectralIndex(spi[0], f0) if spi_err[0] is not None: spectrum.spi_err = spi_err[0] else: spectrum = ModelClasses.SpectralIndex(spi, f0) if any([x is not None for x in spi_err]): spectrum.spi_err = spi_err # see if we have extent parameters ex = ey = pa = 0 if extent_fields: ex, ey, pa = [(getval(x[0], x[1]) or 0) for x in extent_fields] extent_errors = [getval(x[2], x[3]) for x in extent_fields] # form up shape object if (ex or ey) and max(ex, ey) >= min_extent: shape = ModelClasses.Gaussian(ex, ey, pa) for ifield, field in enumerate(['ex', 'ey', 'pa']): if extent_errors[ifield] is not None: shape.setAttribute(field + "_err", extent_errors[ifield]) else: shape = None # get tags tagdict = {} if tags_slice: try: tags = fields[tags_slice] except IndexError: pass for tagstr1 in tags: for tagstr in tagstr1.split(","): if tagstr[0] == "+": tagname, value = tagstr[1:], True elif tagstr[0] == "-": tagname, value = tagstr[1:], False elif "=" in tagstr: tagname, value = tagstr.split("=", 1) if value[0] in "'\"" and value[-1] in "'\"": value = value[1:-1] else: try: value = float(value) except: continue else: tagname, value = tagstr, True tagdict[tagname] = value # OK, now form up the source object # now create a source object dprint(3, name, ra, dec, i, q, u, v) src = SkyModel.Source(name, pos, flux, shape=shape, spectrum=spectrum, **tagdict) # get custom attributes for type_, attr, column in custom_attrs: if column is not None and len(fields) > column: src.setAttribute(attr, type_(fields[column])) # add to source list srclist.append(src) # check if it's the brightest brightness = src.brightness() if brightness > maxbright: maxbright = brightness brightest_name = src.name radec0 = ra, dec except: dprintf(0, "%s:%d: %s, skipping\n", filename, linenum, str(sys.exc_info()[1])) if verbose: raise dprintf(2, "imported %d sources from file %s\n", len(srclist), filename) # create model model = ModelClasses.SkyModel(*srclist) if freq0 is not None: model.setRefFreq(freq0) # set model format model.setAttribute("ASCII_Format", format_str) # setup model center if center_on_brightest and radec0: dprintf(2, "brightest source is %s (%g Jy) at %f,%f\n", brightest_name, maxbright, *radec0) model.setFieldCenter(*radec0) # setup radial distances projection = Coordinates.Projection.SinWCS(*model.fieldCenter()) for src in model.sources: l, m = projection.lm(src.pos.ra, src.pos.dec) src.setAttribute('r', math.sqrt(l * l + m * m)) return model
def params(self, modelfits): # reads in source finder output with pyfits.open(modelfits) as hdu: data = hdu[1].data tfile = tempfile.NamedTemporaryFile(suffix=".txt") tfile.flush() # writes a catalogue in a temporaty txt file with open(tfile.name, "w") as std: std.write("#format:name ra_rad dec_rad i emaj_r emin_r pa_r\n") model = Tigger.load(tfile.name) # open a tmp. file peak, total, area, loc, corr = [], [], [], [], [] for i in range(len(data)): flux = data["Total_flux"][i] dc_emaj, dc_emin = data["DC_Maj"][i], data["DC_Min"][i] ra, dec = data["RA"][i], data["DEC"][i] pa = data["DC_PA"][i] name = "SRC%d" % i peak_flux = data["Peak_flux"][i] posrd = ModelClasses.Position(numpy.deg2rad(ra), numpy.deg2rad(dec)) flux_I = ModelClasses.Polarization(flux, 0, 0, 0) if dc_emaj == 0 and dc_emin == 0: shape = None else: shape = ModelClasses.Gaussian(numpy.deg2rad(dc_emaj), numpy.deg2rad(dc_emin), numpy.deg2rad(pa)) srs = SkyModel.Source(name, posrd, flux_I, shape=shape) # using convolved maj and min for reliability estimate emaj, emin = data["Maj"][i], data["Min"][i] # area: find ex and ey if are 0 assign beam size if emaj or emin == 0: srcarea = math.pi * (numpy.rad2deg(self.bmaj)) * pow(3600.0, 2) *\ (numpy.rad2deg(self.bmin)) if emaj and emin > 0: srcarea = emaj * emin * math.pi * pow(3600.0, 2) # arcsecond # only accepts sources with flux > 0 and not nan RA and DEC # and local variance pos = [self.wcs.wcs2pix(*(ra, dec)) ][0] #positions from deg to pixel with pyfits.open(self.negimage) as hdu: negdata = utils.image_data(hdu[0].data) if flux > 0 and peak_flux > 0 and not math.isnan(float(ra))\ and not math.isnan(float(dec)): local = utils.compute_local_variance(negdata, pos, self.locstep) srs.setAttribute("local_variance", local) if not math.isnan(float(local)) or local > 0: if self.psfname: pdata, psf = utils.compute_psf_correlation( self.imagename, self.psfname, pos, self.cfstep) if len(pdata) == len(psf): c_region = numpy.corrcoef((pdata, psf)) cf = (numpy.diag((numpy.rot90(c_region))** 2).sum())**0.5 / 2**0.5 srs.setAttribute("correlation_factor", cf) corr.append(cf) model.sources.append(srs) peak.append(peak_flux) total.append(flux) area.append(srcarea) loc.append(local) else: model.sources.append(srs) peak.append(peak_flux) total.append(flux) area.append(srcarea) loc.append(local) labels = dict(size=(0, "Log$_{10}$(Source area)"), peak=(1, "Log$_{10}$( Peak flux [Jy] )"), tot=(2, "Log$_{10}$( Total flux [Jy] )")) if self.do_psf_corr: labels.update({"coeff": (len(labels), "Log$_{10}$ (CF)")}) if self.do_local_var: labels.update( {"local": (len(labels), "Log$_{10}$(Local Variance)")}) if self.nearsources: labels.update({"near": (len(labels), "Log$_{10}$(Near Sources)")}) nsrc = len(model.sources) out = numpy.zeros([nsrc, len(labels)]) # returning parameters for i, src in enumerate(model.sources): ra, dec = src.pos.ra, src.pos.dec near = model.getSourcesNear(ra, dec, 5 * self.bmaj) nonear = len(near) if self.nearsources: src.setAttribute("neibours", nonear) if self.do_psf_corr and self.do_local_var and self.nearsources: out[i, ...] = area[i], peak[i], total[i], corr[i], loc[i], nonear elif self.do_psf_corr and self.do_local_var and not self.nearsources: out[i, ...] = area[i], peak[i], total[i], corr[i], loc[i] elif self.do_psf_corr and self.nearsources and not self.do_local_var: out[i, ...] = area[i], peak[i], total[i], corr[i], nonear elif not self.do_psf_corr and self.do_local_var and self.nearsources: out[i, ...] = area[i], peak[i], total[i], loc[i], nonear elif self.do_psf_corr and not self.do_local_var and not self.nearsources: out[i, ...] = area[i], peak[i], total[i], corr[i] elif not self.do_psf_corr and self.do_local_var and not self.nearsources: out[i, ...] = area[i], peak[i], total[i], loc[i] elif not self.do_psf_corr and not self.do_local_var and self.nearsources: out[i, ...] = area[i], peak[i], total[i], nonear else: out[i, ...] = area[i], peak[i], total[i] # removes the rows with 0s removezeros = (out == 0).sum(1) output = out[removezeros <= 0, :] return model, numpy.log10(output), labels
def load(filename, freq0=None, center_on_brightest=False, **kw): """Imports an BBS catalog file The 'format' argument can be either a dict (such as the DefaultDMSFormat dict above), or a string such as DefaultDMSFormatString. (Other possible field names are "ra_d", "ra_rad", "dec_rad", "dec_sign".) If None is specified, DefaultDMSFormat is used. The 'freq0' argument supplies a default reference frequency (if one is not contained in the file.) If 'center_on_brightest' is True, the mpodel field center will be set to the brightest source, else to the center of the first patch. """ srclist = [] dprint(1, "importing BBS source table", filename) # read file ff = open(filename) # first line must be a format string: extract it line0 = ff.readline().strip() match = re.match("#\s*\((.+)\)\s*=\s*format", line0) if not match: raise ValueError("line 1 is not a valid format specification") format_str = match.group(1) # create format parser from this string parser = CatalogParser(format_str) # check for mandatory fields for field in "Name", "Type": if not parser.defines(field): raise ValueError("Table lacks mandatory field '%s'" % field) maxbright = 0 patches = [] ref_freq = freq0 # now process file line-by-line linenum = 1 for line in ff: linenum += 1 try: # parse one line dprint(4, "read line:", line) catline = parser.parse(line, linenum) if not catline: continue dprint(5, "line %d: " % linenum, catline.__dict__) # is it a patch record? patchname = getattr(catline, 'Patch', '') if not catline.Name: dprintf(2, "%s:%d: patch %s\n", filename, linenum, patchname) patches.append((patchname, catline.ra_rad, catline.dec_rad)) continue # form up name name = "%s:%s" % (patchname, catline.Name) if patchname else catline.Name # check source type stype = catline.Type.upper() if stype not in ("POINT", "GAUSSIAN"): raise ValueError("unsupported source type %s" % stype) # see if we have freq0 if freq0: f0 = freq0 elif hasattr(catline, 'ReferenceFrequency'): f0 = float(catline.ReferenceFrequency or '0') else: f0 = None # set model refrence frequency if f0 is not None and ref_freq is None: ref_freq = f0 # see if we have Q/U/V i, q, u, v = [float(getattr(catline, stokes, '0') or '0') for stokes in "IQUV"] # see if we have RM as well. Create flux object (unpolarized, polarized, polarized w/RM) if f0 is not None and hasattr(catline, 'RotationMeasure'): flux = ModelClasses.PolarizationWithRM(i, q, u, v, float(catline.RotationMeasure or '0'), f0) else: flux = ModelClasses.Polarization(i, q, u, v) # see if we have a spectral index if f0 is not None and hasattr(catline, 'SpectralIndex:0'): spectrum = ModelClasses.SpectralIndex(float(getattr(catline, 'SpectralIndex:0') or '0'), f0) else: spectrum = None # see if we have extent parameters if stype == "GAUSSIAN": ex = float(getattr(catline, "MajorAxis", "0") or "0") ey = float(getattr(catline, "MinorAxis", "0") or "0") pa = float(getattr(catline, "Orientation", "0") or "0") shape = ModelClasses.Gaussian(ex, ey, pa) else: shape = None # create tags tags = {} for field in "Patch", "Category": if hasattr(catline, field): tags['BBS_%s' % field] = getattr(catline, field) # OK, now form up the source object # position pos = ModelClasses.Position(catline.ra_rad, catline.dec_rad) # now create a source object src = SkyModel.Source(name, pos, flux, shape=shape, spectrum=spectrum, **tags) srclist.append(src) # check if it's the brightest brightness = src.brightness() if brightness > maxbright: maxbright = brightness brightest_name = src.name radec0 = catline.ra_rad, catline.dec_rad except: dprintf(0, "%s:%d: %s, skipping\n", filename, linenum, str(sys.exc_info()[1])) dprintf(2, "imported %d sources from file %s\n", len(srclist), filename) # create model model = ModelClasses.SkyModel(*srclist) if ref_freq is not None: model.setRefFreq(ref_freq) # setup model center if center_on_brightest and radec0: dprintf(2, "setting model centre to brightest source %s (%g Jy) at %f,%f\n", brightest_name, maxbright, *radec0) model.setFieldCenter(*radec0) elif patches: name, ra, dec = patches[0] dprintf(2, "setting model centre to first patch %s at %f,%f\n", name, ra, dec) model.setFieldCenter(ra, dec) # map patches to model tags model.setAttribute("BBS_Patches", patches) model.setAttribute("BBS_Format", format_str) # setup radial distances projection = Coordinates.Projection.SinWCS(*model.fieldCenter()) for src in model.sources: l, m = projection.lm(src.pos.ra, src.pos.dec) src.setAttribute('r', math.sqrt(l * l + m * m)) return model
def load(filename, format=None, freq0=None, center_on_brightest=False, min_extent=0, **kw): """Imports an ASCII table The 'format' argument can be either a dict (such as the DefaultDMSFormat dict above), or a string such as DefaultDMSFormatString. (Other possible field names are "ra_d", "ra_rad", "dec_rad", "dec_sign".) If None is specified, DefaultDMSFormat is used. The 'freq0' argument supplies a default reference frequency (if one is not contained in the file.) If 'center_on_brightest' is True, the mpodel field center will be set to the brightest source. 'min_extent' is minimal source extent (in radians), above which a source will be treated as a Gaussian rather than a point component. """ srclist = [] dprint(1, "importing ASCII DMS file", filename) # brightest source and its coordinates maxbright = 0 brightest_name = radec0 = None # now process file line-by-line linenum = 0 format_str = '' for line in file(filename): # for the first line, firgure out the file format if not linenum: if not format and line.startswith("#format:"): format = line[len("#format:"):].strip() dprint(1, "file contains format header:", format) # set default format if format is None: format = DefaultDMSFormatString # is the format a string rather than a dict? Turn it into a dict then if isinstance(format, str): format_str = format # make list of fieldname,fieldnumber tuples fields = [(field, i) for i, field in enumerate(format.split())] if not fields: raise ValueError, "illegal format string in file: '%s'" % format # last fieldname can end with ... to indicate that it absorbs the rest of the line if fields[-1][0].endswith('...'): fields[-1] = (fields[-1][0][:-3], slice(fields[-1][1], None)) # make format dict format = dict(fields) elif not isinstance(format, dict): raise TypeError, "invalid 'format' argument of type %s" % ( type(format)) nf = max(format.itervalues()) + 1 fields = ['---'] * nf for field, number in format.iteritems(): fields[number] = field format_str = " ".join(fields) # get minimum necessary fields from format name_field = format.get('name', None) # flux try: i_field = format['i'] except KeyError: raise ValueError, "ASCII format specification lacks mandatory flux field ('i')" # main RA field if 'ra_h' in format: ra_field, ra_scale = format['ra_h'], (math.pi / 12) elif 'ra_d' in format: ra_field, ra_scale = format['ra_d'], (math.pi / 180) elif 'ra_rad' in format: ra_field, ra_scale = format['ra_rad'], 1. else: raise ValueError, "ASCII format specification lacks mandatory Right Ascension field ('ra_h', 'ra_d' or 'ra_rad')" # main Dec field if 'dec_d' in format: dec_field, dec_scale = format['dec_d'], (math.pi / 180) elif 'dec_rad' in format: dec_field, dec_scale = format['dec_rad'], 1. else: raise ValueError, "ASCII format specification lacks mandatory Declination field ('dec_d' or 'dec_rad')" # polarization as QUV try: quv_fields = [format[x] for x in ['q', 'u', 'v']] except KeyError: quv_fields = None # linear polarization as fraction and angle polfrac_field = format.get('pol_frac', None) if polfrac_field is not None: polpa_field, polpa_scale = format.get('pol_pa_d', None), (math.pi / 180) if not polpa_field is not None: polpa_field, polpa_scale = format.get('pol_pa_rad', None), 1 # fields for extent parameters ext_fields = [] for ext in 'emaj', 'emin', 'pa': for field, scale in (ext, 1.), (ext + "_rad", 1.), (ext + '_d', DEG), (ext + '_m', DEG / 60), (ext + '_s', DEG / 3600): if field in format: ext_fields.append((format[field], scale)) break # if not all three accumulated, ignore if len(ext_fields) != 3: ext_fields = None # fields for reference freq and RM and SpI freq0_field = format.get('freq0', None) rm_field = format.get('rm', None) spi_field = format.get('spi', None) spi2_field = [format.get('spi%d' % i, None) for i in range(2, 10)] tags_slice = format.get('tags', None) # now go on to process the line linenum += 1 try: # strip whitespace line = line.strip() dprintf(4, "%s:%d: read line '%s'\n", filename, linenum, line) # skip empty or commented lines if not line or line[0] == '#': continue # split (at whitespace) into fields fields = line.split() # get name name = fields[name_field] if name_field is not None else str( len(srclist) + 1) i = float(fields[i_field]) # get position: RA ra = float(fields[ra_field]) if 'ra_m' in format: ra += float(fields[format['ra_m']]) / 60. if 'ra_s' in format: ra += float(fields[format['ra_s']]) / 3600. ra *= ra_scale # position: Dec. Separate treatment of sign dec = abs(float(fields[dec_field])) if 'dec_m' in format: dec += float(fields[format['dec_m']]) / 60. if 'dec_s' in format: dec += float(fields[format['dec_s']]) / 3600. if fields[format.get('dec_sign', dec_field)][0] == '-': dec = -dec dec *= dec_scale # see if we have freq0 try: f0 = freq0 or (freq0_field and float(fields[freq0_field])) except IndexError: f0 = None # set model refrence frequency if f0 is not None and freq0 is None: freq0 = f0 # see if we have Q/U/V q = u = v = None if quv_fields: try: q, u, v = map(float, [fields[x] for x in quv_fields]) except IndexError: pass if polfrac_field is not None: pf = fields[polfrac_field] pf = float(pf[:-1]) / 100 if pf.endswith("%") else float(pf) ppa = float(fields[polpa_field] ) * polpa_scale if polpa_field is not None else 0 q = i * pf * math.cos(2 * ppa) u = i * pf * math.sin(2 * ppa) v = 0 # see if we have RM as well. Create flux object (unpolarized, polarized, polarized w/RM) if q is None: flux = ModelClasses.Polarization(i, 0, 0, 0) elif f0 is None or rm_field is None or rm_field >= len(fields): flux = ModelClasses.Polarization(i, q, u, v) else: flux = ModelClasses.PolarizationWithRM(i, q, u, v, float(fields[rm_field]), f0) # see if we have a spectral index if f0 is None or spi_field is None or spi_field >= len(fields): spectrum = None else: spi = [ float(fields[spi_field]) ] + \ [ (float(fields[x]) if x is not None else 0) for x in spi2_field ] # if any higher-order spectral terms are specified, include them here # but trim off all trailing zeroes while len(spi) > 1 and not spi[-1]: del spi[-1] if len(spi) == 1: spi = spi[0] spectrum = ModelClasses.SpectralIndex(spi, f0) # see if we have extent parameters ex = ey = pa = 0 if ext_fields: try: ex, ey, pa = [ float(fields[num]) * scale for num, scale in ext_fields ] except IndexError: pass # form up shape object if (ex or ey) and max(ex, ey) >= min_extent: shape = ModelClasses.Gaussian(ex, ey, pa) else: shape = None # get tags tagdict = {} if tags_slice: try: tags = fields[tags_slice] except IndexError: pass for tagstr1 in tags: for tagstr in tagstr1.split(","): if tagstr[0] == "+": tagname, value = tagstr[1:], True elif tagstr[0] == "-": tagname, value = tagstr[1:], False elif "=" in tagstr: tagname, value = tagstr.split("=", 1) if value[0] in "'\"" and value[-1] in "'\"": value = value[1:-1] else: try: value = float(value) except: continue else: tagname, value = tagstr, True tagdict[tagname] = value # OK, now form up the source object # position pos = ModelClasses.Position(ra, dec) # now create a source object dprint(3, name, ra, dec, i, q, u, v) src = SkyModel.Source(name, pos, flux, shape=shape, spectrum=spectrum, **tagdict) srclist.append(src) # check if it's the brightest brightness = src.brightness() if brightness > maxbright: maxbright = brightness brightest_name = src.name radec0 = ra, dec except: dprintf(0, "%s:%d: %s, skipping\n", filename, linenum, str(sys.exc_info()[1])) dprintf(2, "imported %d sources from file %s\n", len(srclist), filename) # create model model = ModelClasses.SkyModel(*srclist) if freq0 is not None: model.setRefFreq(freq0) # set model format model.setAttribute("ASCII_Format", format_str) # setup model center if center_on_brightest and radec0: dprintf(2, "brightest source is %s (%g Jy) at %f,%f\n", brightest_name, maxbright, *radec0) model.setFieldCenter(*radec0) # setup radial distances projection = Coordinates.Projection.SinWCS(*model.fieldCenter()) for src in model.sources: l, m = projection.lm(src.pos.ra, src.pos.dec) src.setAttribute('r', math.sqrt(l * l + m * m)) return model