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
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 locate the 23 path to a non-existent file (e.g., to write). 25 @param[in] fn path to index file; if relative, then relative to astrometry_net_data 26 if that product is setup, else relative to the current working directory 27 @return the absolute path to the index file 35 return os.path.abspath(fn)
36 return os.path.join(andir, fn)
40 """Find the config file from the environment 42 The andConfig.py file is in the astrometry_net_data directory. 48 andConfigPath =
"andConfig.py" 49 if not os.path.exists(andConfigPath):
50 raise RuntimeError(
"Unable to find andConfig.py in the current directory. " 51 "Did you forget to setup astrometry_net_data?")
53 andConfigPath = os.path.join(anDir,
"andConfig.py")
54 if not os.path.exists(andConfigPath):
55 raise RuntimeError(
"Unable to find andConfig.py in astrometry_net_data directory %s" % (anDir,))
58 andConfig.load(andConfigPath)
63 """A wrapper for the multiindex_t, which only reads the data when it needs to 65 The MultiIndexCache may be instantiated directly, or via the 'fromFilenameList' 66 class method, which loads it from a list of filenames. 69 def __init__(self, filenameList, healpix, nside):
72 @param filenameList List of filenames; first is the multiindex, then 73 follows the individual index files 74 @param healpix Healpix number 75 @param nside Healpix nside 77 if len(filenameList) < 2:
78 raise RuntimeError(
"Insufficient filenames provided for multiindex (%s): expected >= 2" %
85 self.
log = Log.getDefaultLogger()
89 """Construct from a list of filenames 91 The list of filenames should contain the multiindex filename first, 92 then the individual index filenames. The healpix and nside are 93 determined by reading the indices, so this is not very efficient. 95 self = cls(filenameList, 0, 0)
97 healpixes = set(self[i].healpix
for i
in range(len(self)))
98 nsides = set(self[i].hpnside
for i
in range(len(self)))
99 assert len(healpixes) == 1
100 assert len(nsides) == 1
102 self.
_nside = nsides.pop()
106 """Read the indices""" 107 if self.
_mi is not None:
110 if not os.path.exists(fn):
112 "Unable to get filename for astrometry star file %s" % (self.
_filenameList[0],))
116 raise RuntimeError(
'Failed to read stars from astrometry multiindex filename "%s"' % fn)
119 self.
log.debug(
'Unable to find index part of multiindex %s', fn)
122 if not os.path.exists(fn):
123 self.
log.warn(
"Unable to get filename for astrometry index %s", fn)
125 self.
log.debug(
'Reading index from multiindex file "%s"', fn)
126 self.
_mi.addIndex(fn,
False)
128 self.
log.debug(
' index %i, hp %i (nside %i), nstars %i, nquads %i',
129 ind.indexid, ind.healpix, ind.hpnside, ind.nstars, ind.nquads)
132 """Reload the indices.""" 142 """Unload the indices""" 149 """!Is the index within range of the provided coordinates? 151 @param coord ICRS coordinate to check (lsst.afw.geom.SpherPoint) 152 @param distance Angular distance (lsst.afw.geom.Angle) 165 return iter(self.
_mi)
169 """An interface to an astrometry.net catalog 171 Behaves like a list of MultiIndexCache (or multiindex_t). 173 These should usually be constructed using the 'fromEnvironment' 174 class method, which wraps the 'fromIndexFiles' and 'fromCache' 175 alternative class methods. 177 _cacheFilename =
"andCache.fits" 182 @param andConfig Configuration (an AstrometryNetDataConfig) 186 if self.
config.allowCache
and os.path.exists(cacheName):
191 def _initFromIndexFiles(self, andConfig):
192 """Initialise from the index files in an AstrometryNetDataConfig""" 193 indexFiles = list(zip(andConfig.indexFiles, andConfig.indexFiles)) + andConfig.multiIndexFiles
194 self.
_multiInds = [MultiIndexCache.fromFilenameList(fnList)
for fnList
in indexFiles]
197 """Write a cache file 199 The cache file is a FITS file with all the required information to build the 200 AstrometryNetCatalog quickly. The first table extension contains a row for each multiindex, 201 storing the healpix and nside values. The second table extension contains a row 202 for each filename in all the multiindexes. The two may be JOINed through the 206 numFilenames = sum(len(ind._filenameList)
for ind
in self.
_multiInds)
207 maxLength = max(len(fn)
for ind
in self.
_multiInds for fn
in ind._filenameList) + 1
210 first = pyfits.new_table([pyfits.Column(name=
"id", format=
"K"),
211 pyfits.Column(name=
"healpix", format=
"K"),
212 pyfits.Column(name=
"nside", format=
"K"),
214 first.data.field(
"id")[:] = np.arange(len(self.
_multiInds), dtype=int)
215 first.data.field(
"healpix")[:] = np.array([ind._healpix
for ind
in self.
_multiInds])
216 first.data.field(
"nside")[:] = np.array([ind._nside
for ind
in self.
_multiInds])
219 second = pyfits.new_table([pyfits.Column(name=
"id", format=
"K"),
220 pyfits.Column(name=
"filename", format=
"%dA" % (maxLength)),
221 ], nrows=numFilenames)
222 ident = second.data.field(
"id")
223 filenames = second.data.field(
"filename")
226 for fn
in ind._filenameList:
231 pyfits.HDUList([pyfits.PrimaryHDU(), first, second]).writeto(outName, clobber=
True)
233 def _initFromCache(self, filename):
234 """Initialise from a cache file 236 Ingest the cache file written by the 'writeCache' method and 237 use that to quickly instantiate the AstrometryNetCatalog. 239 with pyfits.open(filename)
as hduList:
240 first = hduList[1].data
241 second = hduList[2].data
244 filenames = {i: []
for i
in first.field(
"id")}
245 for id2, fn
in zip(second.field(
"id"), second.field(
"filename")):
246 filenames[id2].append(fn)
248 zip(first.field(
"id"), first.field(
"healpix"), first.field(
"nside"))]
251 cacheFiles = set(second.field(
"filename"))
252 configFiles = set(sum(self.
config.multiIndexFiles, []) + self.
config.indexFiles)
253 assert(cacheFiles == configFiles)
266 """Generate a cache file""" 267 if andConfig
is None:
271 for index
in catalog:
275 for index
in catalog:
def _initFromIndexFiles(self, andConfig)
def _initFromCache(self, filename)
def isWithinRange(self, coord, distance)
Is the index within range of the provided coordinates?
std::string getPackageDir(std::string const &packageName)
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)
def fromFilenameList(cls, filenameList)