def Read(self, firstVis=None): err_msg = "Error reading UV file '%s'" % self.name # NOTE(bcotton) # There is a quirk in the order things are done it # that causes what you are trying to misbehave. # If you want purely sequential access # (probably all you will ever want), simply leave off # the firstVis=firstVis. Alternatively, in your script # uv.Read(err, firstVis=firstVis-(nvispio-1)) will do # what you want. The problem is that internally, # the low level I/O routine is expecting that the value # it gets for firstVis is from the last call and it # updates it assuming sequential access before reading # the file. If you want to use this option to specify # where in the file to read, I'll need to find a safe way # to make it more obvious without breaking something else. if firstVis: nvispio = self.uv.List.Dict['nVisPIO'][2][0] firstVis = firstVis - (nvispio - 1) try: self.uv.Read(self._err, firstVis=firstVis) except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err)
def write(self): """ Writes the appropriate row of the AIPS Table """ if self._row is None: return self._table.WriteRow(self._rownr, self._row, self._err) handle_obit_err("Error writing row '%s'" % self._rownr, self._err)
def FitMF(self, out_path, **kwargs): """ Fit spectrum to each pixel of an ImageMF. Uses ImageMF.PFitSpec2 and passes kwargs (from ImageMF.PFitSpec2 docstring). Parameters ---------- out_path : :class:`AIPSPath` AIPS catalog entry to write output antSize : float If > 0 make primary beam corrections assuming antenna diameter (m) antSize (default: 0.0) nterm : int Order of fit, 1=intensity, 2=spectral index, 3=also curvature (default: 2) corAlpha : float Spectral index correction to apply before fitting (default: 0.0) """ err_msg = "Unable to fit pixel spectra to image '%s'." % self.name # Check we have the right type of image if self.isObitImageMF(): with img_factory(aips_path=out_path, mode='rw') as out_img: try: # Copy the structure of self.img to out_img self.img.Clone(out_img.img, self._err) # Use an imgMF pointer for PFitSpec2 ImageMF.PFitSpec2(self.imgMF, out_img.imgMF, self._err, **kwargs) except Exception: raise Exception(err_msg) handle_obit_err(err_msg)
def _open_logic(self, uv, err, **kwargs): """ Peforms logic for opening a UV file * Opening the UV File if given an AIPS path. * Setting up the AIPS Path if given a UV file. * Open any Tables attached to the UV file. Parameters ---------- uv: :class:`UV` or :class:`AIPSPath` Either a Obit UV object or an AIPSPath describing it """ # Given an AIPSPath. open it. if isinstance(uv, AIPSPath): self._aips_path = uv mode = kwargs.pop('mode', 'r') self._uv = uv = open_uv(uv, mode=mode) # Given an Obit UV file. # Construct an AIPSPath elif isinstance(uv, UV.UV): # FITS and AIPS files have different properties if uv.FileType == "FITS": name = uv.FileName aclass = None seq = None elif uv.FileType == "AIPS": name = uv.Aname aclass = uv.Aclass seq = uv.Aseq else: raise ValueError("Invalid FileType '%s'" % uv.FileType) self._aips_path = AIPSPath(name, uv.Disk, aclass, seq, dtype=uv.FileType) self._uv = uv else: raise TypeError("Invalid type '%s'. " "Must be Obit UV object " "or an AIPSPath." % type(uv)) # Open tables attached to this UV file. tables = TableList.PGetList(uv.TableList, err) handle_obit_err("Error getting '%s' table list" % self.name) # History tables don't work like the other tables ignored_tables = ["AIPS HI"] self._tables = { name: AIPSTable(uv, name, version, 'r', err) for version, name in tables if name not in ignored_tables } self._tables["AIPS HI"] = AIPSHistory(uv, err)
def __getitem__(self, index): record = self._table.ReadRec(index + 1, self._err) if not record: raise IndexError("No history record at index %d" % index + 1) handle_obit_err("Error reading history table record at index %d" % index + 1) return record
def Write(self, firstVis=None): err_msg = "Error writing UV file '%s'" % self.name try: self.uv.Write(self._err, firstVis=firstVis) except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err)
def Open(self, mode): err_msg = "Error opening Image file '%s'" % self.name try: self.img.Open(mode, self._err) except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err)
def Open(self, mode): err_msg = "Error opening UV file '%s'" % self.name try: self.uv.Open(mode, self._err) except Exception: raise Exception handle_obit_err(err_msg, self._err)
def Zap(self): err_msg = "Error zapping UV file '%s'" % self.name try: self.uv.Zap(self._err) except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err) self._clear_uv()
def _open_logic(self, img, err, **kwargs): """ Peforms logic for opening a Image file * Opening the Image File if given an AIPS path. * Setting up the AIPS Path if given a Image file. * Open any Tables attached to the Image file. """ self.mode = kwargs.pop('mode', 'r') # Given an AIPSPath. open it. if isinstance(img, AIPSPath): self._aips_path = img self._img = img = open_img(img, mode=self.mode) # Given an Obit Image file. # Construct an AIPSPath elif isinstance(img, Image.Image): # FITS and AIPS files have different properties if img.FileType == "FITS": name = img.FileName aclass = None seq = None elif img.FileType == "AIPS": name = img.Aname aclass = img.Aclass seq = img.Aseq else: raise ValueError("Invalid FileType '%s'" % img.FileType) self._aips_path = AIPSPath(name, img.Disk, aclass, seq, atype='MA', label=img.GetName(), dtype=img.FileType) self._img = img else: raise TypeError("Invalid type '%s'. " "Must be Obit Image object " "or an AIPSPath." % type(img)) # Open tables attached to this UV file. tables = TableList.PGetList(img.TableList, err) handle_obit_err("Error getting '%s' table list" % self.name) # History tables don't work like the other tables ignored_tables = ["AIPS HI"] self._tables = { name: AIPSTable(img, name, version, 'r', err) for version, name in tables if name not in ignored_tables } self._tables["AIPS HI"] = AIPSHistory(img, err)
def Zap(self): err_msg = "Exception zapping image file '%s'" % self.name try: self.img.Zap(self._err) except Exception: raise Exception(err_msg) handle_obit_err("Error deleting Image file '%s'" % self.name, self._err) self._clear_img()
def writefits(self, disk, output, tables_to_copy=['AIPS CC', 'AIPS SN']): """ Write the image to a FITS file """ err_msg = "Unable to write image to %s" % output outImage = Image.newPFImage("FITS Image DATA", output, disk, False, self._err) Image.PCopy(self._img, outImage, self._err) Image.PCopyTables(self._img, outImage, ['AIPS HI'], tables_to_copy, self._err) handle_obit_err(err_msg, self._err)
def Copy(self, to_path): """ Copy this image to a new file in to_path. """ err_msg = "Error copying Image file '%s' to '%s'" % (self.name, to_path) to_img = img_factory(aips_path=to_path, mode='rw') try: self.img.Copy(to_img.img, self._err) except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err)
def PutPlane(self, array, plane=[1, 1, 1, 1, 1]): """ Put the FArray in array in specified image plane. """ err_msg = ("Error putting plane '%s' " "into image '%s'" % (plane, self.name)) try: self.img.PutPlane(array, plane, self._err) except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err)
def close(self): """ Close the AIPS table """ # Flush Table.PDirty(self._table) self._table.Open(Table.READWRITE, self._err) handle_obit_err("Error opening table '%s' for flush" % self._name, self._err) # Close self._table.Close(self._err) handle_obit_err("Error closing '%s' table" % self._name, self._err)
def __init__(self, uv, name, version, mode, err, **kwargs): """ Creates an AIPS Table object Parameters ---------- uv: :class:`UV` Obit UV object associated with this table. name: string Table name. e.g. "AIPS AN" version: integer Table version mode: string "r" to read, "w" to write. err: :class:`OErr` Obit error stack **kwargs (optional): integer, usually Additional keyword arguments to pass in to the table constructor. For example, the "AIPS FQ" frequency table takes a `numIF` keyword argument specified the number of spectral windows. """ self._err = err if 'w' in mode: self._clobber_old_tables(uv, name, err) self._table = table = uv.NewTable(Table.READWRITE, name, version, err, **kwargs) handle_obit_err("Error creating table '%s'" % name, err) self._table.Open(Table.READWRITE, err) handle_obit_err("Error opening table '%s'" % name, err) desc = table.Desc.Dict nrow = desc['nrow'] self._name = name = desc['Table name'] self._version = desc['version'] self._keywords = AIPSTableKeywords(self._table, name) self._fields = fields = self._get_field_defs(desc) self._default_row = self._get_row_definitions(self._name, fields) self._rows = AIPSTableRows(table, nrow, self._default_row, err)
def close(self): """ Closes the wrapped UV file """ # Close all attached tables for table in self._tables.values(): table.close() self._tables = {} try: self._uv.Close(self._err) except AttributeError: # Closed return except Exception: raise Exception("Exception closing uv file '%s'" % self.name) handle_obit_err("Error closing uv file '%s'" % self.name, self._err) self._clear_uv()
def _clobber_old_tables(self, uv, name, err): """ Removes all previously existing versions of table. Parameters ---------- uv: :class:`UV` Obit UV object name: string AIPS Table name, "AIPS AN" for instance. err: :class:`OErr` Obit error stack object """ prev_ver = uv.GetHighVer(name) while prev_ver > 0: uv.ZapTable(name, prev_ver, err) handle_obit_err("Error removing old '%s' table" % name, err) prev_ver = uv.GetHighVer(name)
def attach_CL_from_NX_table(self, max_ant_nr): """ Creates a CL table associated with this UV file from an NX table. Parameters ---------- max_ant_nr : integer Maximum antenna number written to the AIPS AN table. """ err_msg = ("Error creating CL table " "from NX table on UV file '%s'" % self.name) try: UV.PTableCLfromNX(self.uv, max_ant_nr, self._err) except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err)
def close(self): """ Closes the wrapped Image file """ # Close all attached tables for table in self._tables.values(): table.close() self._tables = {} err_msg = "Exception closing image file '%s'" % self.name try: self._img.Close(self._err) except AttributeError: # Already closed return except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err) self._clear_img()
def GetPlane(self, array=None, plane=[1, 1, 1, 1, 1]): """ Get an image plane and store it in array. Use self.FArray if array is None. Default to first image plane. Return the opened plane. """ err_msg = ("Error getting plane '%s' " "from image '%s'" % (plane, self.name)) try: self.img.GetPlane(array, plane, self._err) if array is None: # Plane is retrieved to self.img.FArray # Return a deep copy. array = FArray.PCopy(self.img.FArray, self._err) except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err) return array
def parse_aips_config(aips_cfg_file): """ Parses an AIPS config file into a dictionary with schema :code:`{ option: [type, dimensions, value]}` :code:`type_` is an enum. Look at ObitTypes.h to figure it out. :code:`dims` indicate dimensionality of input For scalar types :code:`[64,1,1,1,1]` indicates a 1D array of length 64 floats. String dims need to be handled slightly differently First dimension indicates string length so for e.g. :code:`["obit", " ", "abcd"]` has dims :code:`[4,3,1,1,1]` So a :code:`[4,1,1,1,1]` implies one string of length 4 :code:`value` will always be a list and is probably nested if :code:`dims is setup appropriately. Parameters ---------- aips_cfg_file : str AIPS configuration file Returns ------- dict A dictionary of AIPS configuration options """ err = obit_err() info_list = InfoList.InfoList() ParserUtil.PParse(aips_cfg_file, info_list, err) handle_obit_err( "Error parsing Obit configuration file '{}'".format(aips_cfg_file), err) return InfoList.PGetDict(info_list)
def next_seq_nr(aips_path): """ Returns the highest available sequence number for which a catalogue entry does not exist Parameters ---------- aips_path : :class:`AIPSPath` An AIPS path Returns ------- integer Highest sequence number """ from AIPSDir import PHiSeq, PTestCNO from OSystem import PGetAIPSuser err = obit_err() aips_user = PGetAIPSuser() hi_seq = PHiSeq(Aname=aips_path.name, user=aips_user, disk=aips_path.disk, Aclass=aips_path.aclass, Atype=aips_path.atype, err=err) handle_obit_err("Error finding highest sequence number", err) while True: cno = PTestCNO(disk=aips_path.disk, user=aips_user, Aname=aips_path.name, Aclass=aips_path.aclass, Atype=aips_path.atype, seq=hi_seq, err=err) handle_obit_err("Error finding catalogue entry", err) if cno == -1: return hi_seq hi_seq += 1
def MergeCC(self): """ Merge the positionally coincidental clean components in the attached CC table and attach the merged table. """ err_msg = "Exception merging CC Table in '%s'" % self.name cctab = self.tables["AIPS CC"] init_nrow = cctab.nrow # Create an empty table to hold the merged table merged_cctab = self.img.NewTable(Table.READWRITE, "AIPS CC", cctab.version + 1, self._err) try: TableUtil.PCCMerge(cctab._table, merged_cctab, self._err) except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err) # Attach merged version of CC Table self.attach_table("AIPS CC", cctab.version + 1) merged_cctab = self.tables["AIPS CC"] log.info("Merged %d CCs to %d for %s", init_nrow, merged_cctab.nrow, self.name) return merged_cctab
def update_descriptor(self, descriptor): """ Update the UV descriptor. Parameters ---------- descriptor: dict Dictionary containing updates applicable to :code:`uv.Desc.Dict`. """ uv = self.uv desc = uv.Desc.Dict desc.update(descriptor) uv.Desc.Dict = desc err_msg = "Error updating descriptor on UV file '%s'" % self.name try: uv.UpdateDesc(self._err) except Exception: raise Exception(err_msg) handle_obit_err(err_msg, self._err)
def __init__(self, uv, err): self._err = err self._table = History.History('AIPS HI', uv.List, self._err) handle_obit_err("Error accessing history table", err) self._table.Open(Table.READWRITE, err) handle_obit_err("Error opening history table", err)
def close(self): self._table.Close(self._err) handle_obit_err("Error closing history table", self._err)
def append(self, record): self._table.WriteRec(0, record, self._err) handle_obit_err("Error appending history table record")
def tablelist(self): tables = TableList.PGetList(self.img.TableList, self._err) handle_obit_err("Error getting '%s' table list" % self.name) return tables
def open_img(aips_path, mode=None, MF=False): """ Opens an AIPS/FITS Image file and returns a wrapped :class:`ImageFacade` object. Parameters ---------- aips_path: :class:`AIPSPath` Obit file object. mode(optional): str "r" to read, "w" to write, "rw" to read and write. Defaults to "r" MF(optional): boolean Open as an ImageMF? Returns ------- :class:`Image` An Obit Image object """ err = obit_err() if mode is None: mode = "r" img_mode = img_file_mode(mode) exists = False # Test if the file exists if aips_path.dtype == "AIPS": if MF: img_open = ImageMF.newPAImage else: img_open = Image.newPAImage try: img = img_open(aips_path.label, aips_path.name, aips_path.aclass, aips_path.disk, aips_path.seq, exists, err) except Exception: raise ValueError("Error calling newPAImage on '%s'" % aips_path) elif aips_path.dtype == "FITS": raise NotImplementedError("newPFImage calls do not currently work") try: img = Image.newPFImage(aips_path.label, aips_path.name, aips_path.disk, exists, err) except Exception: raise ValueError("Error calling newPFImage on '%s'" % aips_path) else: raise ValueError("Invalid dtype '{}'".format(aips_path.dtype)) handle_obit_err("Error opening '%s'" % aips_path, err) err_msg = "Error opening '%s'" % aips_path try: img.Open(img_mode, err) except Exception: raise ValueError(err_msg) handle_obit_err(err_msg, err) return img