LSSTApplications  18.1.0
LSSTDataManagementBasePackage
footprints.py
Go to the documentation of this file.
1 # This file is part of {{ cookiecutter.package_name }}.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (https://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 
22 
23 import numpy as np
24 from astropy.io.votable.tree import Info
25 from astropy.io.votable import from_table
26 from astropy.table import Column
27 
28 import lsst.afw.geom as afwGeom
29 import lsst.afw.table as afwTable
30 
31 
32 def recordSelector(record, selection):
33  """Select records from source catalog
34 
35  Parameters:
36  -----------
37  record : `lsst.afw.detect.SourceRecord`
38  record to select
39  selection : `str`
40  'all' to select all records. 'blended parents' to select records with
41  more than zero children. 'deblended children' to select records with
42  non-zero parents. 'isolated' to select records that are not blended,
43  meaning zero parents and zero children.
44  Values to check for sel
45  """
46  nChildren = record.get('deblend_nChild')
47  parentId = record.getParent()
48  if selection == 'all':
49  return True
50  elif selection == 'blended parents':
51  return (nChildren > 0)
52  elif selection == 'deblended children':
53  return (parentId > 0)
54  elif selection == 'isolated':
55  return ((parentId == 0) and (nChildren == 0))
56  else:
57  raise RuntimeError('invalid selection: {}'.format(selection) +
58  '\nMust be one of "all", "blended parents", ' +
59  '"deblended children", "isolated"')
60 
61 
62 def createFootprintsTable(catalog, xy0=None, insertColumn=4):
63  """make a VOTable of SourceData table and footprints
64 
65  Parameters:
66  -----------
67  catalog : `lsst.afw.table.SourceCatalog`
68  Source catalog from which to display footprints.
69  xy0 : tuple or list or None
70  Pixel origin to subtract off from the footprint coordinates.
71  If None, the value used is (0,0)
72  insertColumn : `int`
73  Column at which to insert the "family_id" and "category" columns
74 
75  Returns:
76  --------
77  `astropy.io.votable.voTableFile`
78  VOTable object to upload to Firefly
79  """
80  if xy0 is None:
81  xy0 = afwGeom.Point2I(0, 0)
82 
83  _catalog = afwTable.SourceCatalog(catalog.table.clone())
84  _catalog.extend(catalog, deep=True)
85  sourceTable = _catalog.asAstropy()
86 
87  # Change int64 dtypes so they convert to VOTable
88  for colName in sourceTable.colnames:
89  if sourceTable[colName].dtype.num == 9:
90  sourceTable[colName].dtype = np.dtype('long')
91 
92  inputColumnNames = sourceTable.colnames
93 
94  x0, y0 = xy0
95  spanList = []
96  peakList = []
97  familyList = []
98  categoryList = []
99  fpxll = []
100  fpyll = []
101  fpxur = []
102  fpyur = []
103  for record in catalog:
104  footprint = record.getFootprint()
105  recordId = record.getId()
106  spans = footprint.getSpans()
107  scoords = [(s.getY()-y0, s.getX0()-x0, s.getX1()-x0) for s in spans]
108  scoords = np.array(scoords).flatten()
109  scoords = np.ma.MaskedArray(scoords, mask=np.zeros(len(scoords),
110  dtype=np.bool))
111  fpbbox = footprint.getBBox()
112  corners = [(c.getX()-x0, c.getY()-y0) for c in fpbbox.getCorners()]
113  fpxll.append(corners[0][0])
114  fpyll.append(corners[0][1])
115  fpxur.append(corners[2][0])
116  fpyur.append(corners[2][1])
117  peaks = footprint.getPeaks()
118  pcoords = [(p.getFx()-x0, p.getFy()-y0) for p in peaks]
119  pcoords = np.array(pcoords).flatten()
120  pcoords = np.ma.MaskedArray(pcoords, mask=np.zeros(len(pcoords),
121  dtype=np.bool))
122  fpbbox = footprint.getBBox()
123  parentId = record.getParent()
124  nChild = record.get('deblend_nChild')
125  if parentId == 0:
126  familyList.append(recordId)
127  if nChild > 0:
128  # blended parent
129  categoryList.append('blended parent')
130  else:
131  # isolated
132  categoryList.append('isolated')
133  else:
134  # deblended child
135  familyList.append(parentId)
136  categoryList.append('deblended child')
137  spanList.append(scoords)
138  peakList.append(pcoords)
139 
140  sourceTable.add_column(Column(np.array(familyList)),
141  name='family_id',
142  index=insertColumn)
143  sourceTable.add_column(Column(np.array(categoryList)),
144  name='category',
145  index=insertColumn+1)
146  sourceTable.add_column(Column(np.array(spanList)), name='spans')
147  sourceTable.add_column(Column(np.array(peakList)), name='peaks')
148  sourceTable.add_column(Column(np.array(fpxll)), name='footprint_corner1_x')
149  sourceTable.add_column(Column(np.array(fpyll)), name='footprint_corner1_y')
150  sourceTable.add_column(Column(np.array(fpxur)), name='footprint_corner2_x')
151  sourceTable.add_column(Column(np.array(fpyur)), name='footprint_corner2_y')
152 
153  outputVO = from_table(sourceTable)
154  outTable = outputVO.get_first_table()
155 
156  outTable.infos.append(Info(name='contains_lsst_footprints', value='true'))
157  outTable.infos.append(Info(name='contains_lsst_measurements', value='true'))
158  outTable.infos.append(Info(name='FootPrintColumnNames',
159  value='id;footprint_corner1_x;footprint_corner1_y;' +
160  'footprint_corner2_x;footprint_corner2_y;spans;peaks'))
161  outTable.infos.append(Info(name='pixelsys', value='zero-based'))
162  # Check whether the coordinates are included and are valid
163  if (('slot_Centroid_x' in inputColumnNames) and
164  ('slot_Centroid_y' in inputColumnNames) and
165  np.isfinite(outTable.array['slot_Centroid_x']).any() and
166  np.isfinite(outTable.array['slot_Centroid_y']).any()):
167  coord_column_string = 'slot_Centroid_x;slot_Centroid_y;ZERO_BASED'
168  elif (('coord_ra' in inputColumnNames) and
169  ('coord_dec' in inputColumnNames) and
170  np.isfinite(outTable.array['coord_ra']).any() and
171  np.isfinite(outTable.array['coord_dec']).any()):
172  coord_column_string = 'coord_ra;coord_dec;EQ_J2000'
173  elif (('base_SdssCentroid_x' in inputColumnNames) and
174  ('base_SdssCentroid_y' in inputColumnNames) and
175  np.isfinite(outTable.array['base_SdssCentroid_x']).any() and
176  np.isfinite(outTable.array['base_SdssCentroid_y']).any()):
177  coord_column_string = 'base_SdssCentroid_x;base_SdssCentroid_y;ZERO_BASED'
178  elif (('base_NaiveCentroid_x' in inputColumnNames) and
179  ('base_NaiveCentroid_y' in inputColumnNames) and
180  np.isfinite(outTable.array['base_NaiveCentroid_x']).any() and
181  np.isfinite(outTable.array['base_NaiveCentroid_y']).any()):
182  coord_column_string = 'base_NaiveCentroid_x;base_NaiveCentroid_y;ZERO-BASED'
183  else:
184  raise RuntimeError('No valid coordinate columns in catalog')
185  outTable.infos.append(Info(name='CatalogCoordColumns',
186  value=coord_column_string))
187 
188  for f in outTable.fields:
189  if f.datatype == 'bit':
190  f.datatype = 'boolean'
191 
192  outTable._config['version_1_3_or_later'] = True
193  outputVO.set_all_tables_format('binary2')
194 
195  return(outputVO)
def recordSelector(record, selection)
Definition: footprints.py:32
bool any(CoordinateExpr< N > const &expr) noexcept
Return true if any elements are true.
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:168
def createFootprintsTable(catalog, xy0=None, insertColumn=4)
Definition: footprints.py:62