Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Sometimes it is more efficient to write a getter which calculates the values of many columns at once.  An obvious example of this is in the case of simulated photometry.  It would be wasteful to load a source's SED, then integrate it over the u-band, then exit, then load the SED again, then integrate it over the g-band, then exit, then load the SED again.... It makes much more sense to load the SED once and integrate it over all of the desired bands before moving on to the next source SED.  The catalog simulations framework enables this functionality with compound getters.  The following is an example of a compound getter taken from sims_photUtils'glon' and 'glat' are, themselves, examples of this case.  Since both the galactic longitude and the galactic latitude require knowledge of the RA and Dec of an object, it makes much more sense to calculate them together than separately.  Here is an example of a compound getter taken from /sims_coordUtils/python/lsst/sims/photUtilscoordUtils/PhotometryAstrometry.py

Code Block
    @compound('lsst_uglon','lsst_g','lsst_r','lsst_i','lsst_z','lsst_y')
    def get_magnitudes(self):
        """
        Getter for stellar magnitudes
        """
        
        idNames = self.column_by_name('id')
        bandPassList = ['u','g','r','i','z','y']
        
        magDict = self.calculate_magnitudes(bandPassList,idNames)
        
        uu = numpy.zeros(len(idNames),dtype=float)
        gg = numpy.zeros(len(idNames),dtype=float)
        rr = numpy.zeros(len(idNames),dtype=float)
        ii = numpy.zeros(len(idNames),dtype=float)
        zz = numpy.zeros(len(idNames),dtype=floatglat')
        yy = numpy.zeros(len(idNames),dtype=float)def get_galactic_coords(self):
        """
        Getter for galactic icoordinates, in range(len(idNames)):
            uu[i] = magDict[idNames[i]]["u"]case the catalog class does not provide that
        Reads in the ra and dec gg[i] = magDict[idNames[i]]["g"]
      from the data base and returns columns with galactic
      rr[i] = magDict[idNames[i]]["r"] longitude and latitude.
        All angles are  ii[i] = magDict[idNames[i]]["i"]
in radians
        """
       zz[i] = magDict[idNames[i]]["z"]ra=self.column_by_name('raJ2000')
            yy[i] = magDict[idNames[i]]["y"]
dec=self.column_by_name('decJ2000')
        glon, glat = galacticFromEquatorial(ra,dec)
        return numpy.array([uu,gg,rr,ii,zz,yy([glon,glat])

In this case, the name of the method is only contained to be get_something ('something' should be descriptive of what the getter does, but should not correspond to the name of any of the returned columns).  The getter is flagged for use by column_by_name with the decorator @compound.  The arguments of @compound are the names the columns calculated by the getter (in this case, the magnitudes 'lsst_uglon' , 'lsst_g', 'lsst_r', etc.and 'glat').  It is important that the compound getter return its results as a two dimensional numpy array with the rows set in the same order as the arguments of @compound.  The decorator @compound is defined in /sims_catalogs_measures/python/lsst/sims/catalogs/measures/instance/decorators.py.  It modified the getter method so that the rows of the output emerge in an Ordered Dict keyed to the arguments of @compound.  This is how column_by_name knows how to process the results of a compound getter.

...

As can be seen, column_by_name first determines if it knows how to calculate the requested column.  If not, it determines whether or not the column exists natively in the database.  If not, it determines whether or not it knows a default value for the column (if all of these fail, column_by_name will throw an exception).  Note that, if the column is defined natively in the database, it is returned as self._current_chunk[column_name].  Before calling column_by_name, write_catalog defined the member variable self._current_chunk to be the chunk of the database it was currently iterating over.  This means that, when column_by_name returns self._current_chunk[column_name], it will return a numpy array containing the values of the column for all of the rows in self._current_chunk.  This is important, because it illustrates how getters know to return results on the entire chunk.

Here is an example of a getter taken from /sims_coordUtils/phython/lsst/sims/coordUtils/Astrometry.py (it reads in RA and Dec and returns galactic longitude and galactic latitudeLet us return to our 'glon', 'glat' example from above.

Code Block
    @compound('glon','glat')
    def get_galactic_coords(self):
        """
        Getter for galactic coordinates, in case the catalog class does not provide that
        
        Reads in the ra and dec from the data base and returns columns with galactic
        longitude and latitude.
        All angles are in radians
        """
        ra=self.column_by_name('raJ2000')
        dec=self.column_by_name('decJ2000')
        
        glon, glat = self.equatorialToGalacticgalacticFromEquatorial(ra,dec)
        return numpy.array([glon,glat])

If the user asked for the column 'glon' (galactic longitude), column_by_name would call this method the getter (more on how it would know to make that choice later).  Nothing about this method the getter refers explicitly to the size of self._current_chunk, except that this getter requires the columns 'raJ2000' and 'decJ2000' (the RA and Dec in the J2000 coordinate system), which exist natively in the database.  Thus, the calls to column_by_name made in get_galactic_coords will return numpy arrays of all of the raJ2000 and decJ2000 values associated with the rows in self._current_chunk.  These arrays will be passed to self.equatorialToGalacticgalacticFromEquatorial, which knows to return arrays of the same length as the arrays it is passed.  Finally, get_galactic_coords combines glon and glat into a single, two row numpy array containing the galactic coordinates associated with all of the rows in self._current_chunk. 

...