1 from __future__
import absolute_import, division, print_function
3 __all__ = [
"getIndexPath",
"getConfigFromEnvironment",
"AstrometryNetCatalog",
"generateCache"]
5 from builtins
import zip
6 from builtins
import range
7 from builtins
import object
11 from astropy.io
import fits
15 from .astrometry_net
import MultiIndex, healpixDistance
16 from .astrometryNetDataConfig
import AstrometryNetDataConfig
20 """!Get the path to the specified astrometry.net index file 22 No effort is made to confirm that the file exists, so it may be used to 23 locate the path to a non-existent file (e.g., to write). 25 @param[in] fn path to index file; if relative, then relative to 26 astrometry_net_data if that product is setup, else relative to the 27 current working directory 28 @return the absolute path to the index file 36 return os.path.abspath(fn)
37 return os.path.join(andir, fn)
41 """Find the config file from the environment 43 The andConfig.py file is in the astrometry_net_data directory. 49 andConfigPath =
"andConfig.py" 50 if not os.path.exists(andConfigPath):
51 raise RuntimeError(
"Unable to find andConfig.py in the current directory. " 52 "Did you forget to setup astrometry_net_data?")
54 andConfigPath = os.path.join(anDir,
"andConfig.py")
55 if not os.path.exists(andConfigPath):
56 raise RuntimeError(
"Unable to find andConfig.py in astrometry_net_data directory %s" % (anDir,))
59 andConfig.load(andConfigPath)
64 """A wrapper for the multiindex_t, which only reads the data when it 67 The MultiIndexCache may be instantiated directly, or via the 68 'fromFilenameList' class method, which loads it from a list of filenames. 71 def __init__(self, filenameList, healpix, nside):
74 @param filenameList List of filenames; first is the multiindex, then 75 follows the individual index files 76 @param healpix Healpix number 77 @param nside Healpix nside 79 if len(filenameList) < 2:
80 raise RuntimeError(
"Insufficient filenames provided for multiindex (%s): expected >= 2" %
87 self.
log = Log.getDefaultLogger()
91 """Construct from a list of filenames 93 The list of filenames should contain the multiindex filename first, 94 then the individual index filenames. The healpix and nside are 95 determined by reading the indices, so this is not very efficient. 97 self =
cls(filenameList, 0, 0)
99 healpixes =
set(self[i].healpix
for i
in range(len(self)))
100 nsides =
set(self[i].hpnside
for i
in range(len(self)))
101 assert len(healpixes) == 1
102 assert len(nsides) == 1
104 self.
_nside = nsides.pop()
108 """Read the indices""" 109 if self.
_mi is not None:
112 if not os.path.exists(fn):
114 "Unable to get filename for astrometry star file %s" % (self.
_filenameList[0],))
118 raise RuntimeError(
'Failed to read stars from astrometry multiindex filename "%s"' % fn)
121 self.
log.
debug(
'Unable to find index part of multiindex %s', fn)
124 if not os.path.exists(fn):
125 self.
log.
warn(
"Unable to get filename for astrometry index %s", fn)
127 self.
log.
debug(
'Reading index from multiindex file "%s"', fn)
128 self.
_mi.addIndex(fn,
False)
130 self.
log.
debug(
' index %i, hp %i (nside %i), nstars %i, nquads %i',
131 ind.indexid, ind.healpix, ind.hpnside, ind.nstars, ind.nquads)
134 """Reload the indices.""" 144 """Unload the indices""" 151 """!Is the index within range of the provided coordinates? 153 @param coord ICRS coordinate to check (lsst.afw.geom.SpherPoint) 154 @param distance Angular distance (lsst.afw.geom.Angle) 167 return iter(self.
_mi)
171 """An interface to an astrometry.net catalog 173 Behaves like a list of MultiIndexCache (or multiindex_t). 175 These should usually be constructed using the 'fromEnvironment' 176 class method, which wraps the 'fromIndexFiles' and 'fromCache' 177 alternative class methods. 179 _cacheFilename =
"andCache.fits" 184 @param andConfig Configuration (an AstrometryNetDataConfig) 188 if self.
config.allowCache
and os.path.exists(cacheName):
193 def _initFromIndexFiles(self, andConfig):
194 """Initialise from the index files in an AstrometryNetDataConfig""" 195 indexFiles =
list(zip(andConfig.indexFiles, andConfig.indexFiles)) + andConfig.multiIndexFiles
196 self.
_multiInds = [MultiIndexCache.fromFilenameList(fnList)
for fnList
in indexFiles]
199 """Write a cache file 201 The cache file is a FITS file with all the required information to 202 build the AstrometryNetCatalog quickly. The first table extension 203 contains a row for each multiindex, storing the healpix and nside 204 values. The second table extension contains a row for each filename 205 in all the multiindexes. The two may be JOINed through the 'id' 209 numFilenames = sum(len(ind._filenameList)
for ind
in self.
_multiInds)
210 maxLength =
max(len(fn)
for ind
in self.
_multiInds for fn
in ind._filenameList) + 1
213 first = fits.BinTableHDU.from_columns([fits.Column(name=
"id", format=
"K"),
214 fits.Column(name=
"healpix", format=
"K"),
215 fits.Column(name=
"nside", format=
"K"),
217 first.data.field(
"id")[:] = np.arange(len(self.
_multiInds), dtype=int)
218 first.data.field(
"healpix")[:] = np.array([ind._healpix
for ind
in self.
_multiInds])
219 first.data.field(
"nside")[:] = np.array([ind._nside
for ind
in self.
_multiInds])
222 second = fits.BinTableHDU.from_columns([fits.Column(name=
"id", format=
"K"),
223 fits.Column(name=
"filename", format=
"%dA" % (maxLength)),
224 ], nrows=numFilenames)
225 ident = second.data.field(
"id")
226 filenames = second.data.field(
"filename")
229 for fn
in ind._filenameList:
234 fits.HDUList([fits.PrimaryHDU(), first, second]).writeto(outName, overwrite=
True)
236 def _initFromCache(self, filename):
237 """Initialise from a cache file 239 Ingest the cache file written by the 'writeCache' method and 240 use that to quickly instantiate the AstrometryNetCatalog. 242 with fits.open(filename)
as hduList:
243 first = hduList[1].data
244 second = hduList[2].data
247 filenames = {i: []
for i
in first.field(
"id")}
248 for id2, fn
in zip(second.field(
"id"), second.field(
"filename")):
251 zip(first.field(
"id"), first.field(
"healpix"), first.field(
"nside"))]
254 cacheFiles =
set(second.field(
"filename"))
255 configFiles =
set(sum(self.
config.multiIndexFiles, []) + self.
config.indexFiles)
256 assert(cacheFiles == configFiles)
269 """Generate a cache file""" 270 if andConfig
is None:
274 for index
in catalog:
278 for index
in catalog:
def _initFromIndexFiles(self, andConfig)
def _initFromCache(self, filename)
std::shared_ptr< FrameSet > append(FrameSet const &first, FrameSet const &second)
Construct a FrameSet that performs two transformations in series.
daf::base::PropertySet * set
def isWithinRange(self, coord, distance)
Is the index within range of the provided coordinates?
std::string getPackageDir(std::string const &packageName)
return the root directory of a setup package
lsst::afw::geom::Angle healpixDistance(int hp, int nside, lsst::afw::geom::SpherePoint const &coord)
Calculate the distance from coordinates to a healpix.
def getIndexPath(fn)
Get the path to the specified astrometry.net index file.
def generateCache(andConfig=None)
def __init__(self, filenameList, healpix, nside)
Constructor.
def getConfigFromEnvironment()
def __init__(self, andConfig)
Constructor.
def __getitem__(self, ii)
daf::base::PropertyList * list
def fromFilenameList(cls, filenameList)