28 from .cachingSkyMap
import CachingSkyMap
29 from .tractInfo
import ExplicitTractInfo
31 __all__ = [
"RingsSkyMapConfig",
"RingsSkyMap"]
35 """Configuration for the RingsSkyMap""" 36 numRings = Field(dtype=int, doc=
"Number of rings", check=
lambda x: x > 0)
37 raStart = Field(dtype=float, default=0.0, doc=
"Starting center RA for each ring (degrees)",
38 check=
lambda x: x >= 0.0
and x < 360.0)
42 """Rings sky map pixelization. 44 We divide the sphere into N rings of Declination, plus the two polar 45 caps, which sets the size of the individual tracts. The rings are 46 divided in RA into an integral number of tracts of this size; this 47 division is made at the Declination closest to zero so as to ensure 50 Rings are numbered in the rings from south to north. The south pole cap is 51 ``tract=0``, then the tract at ``raStart`` in the southernmost ring is 52 ``tract=1``. Numbering continues (in the positive RA direction) around that 53 ring and then continues in the same fashion with the next ring north, and 54 so on until all reaching the north pole cap, which is 55 ``tract=len(skymap) - 1``. 57 However, ``version=0`` had a bug in the numbering of the tracts: the first 58 and last tracts in the first (southernmost) ring were identical, and the 59 first tract in the last (northernmost) ring was missing. When using 60 ``version=0``, these tracts remain missing in order to preserve the 65 config : `lsst.skymap.RingsSkyMapConfig` 66 Configuration for this skymap. 67 version : `int`, optional 68 Software version of this class, to retain compatibility with old 69 verisons. ``version=0`` covers the period from first implementation 70 until DM-14809, at which point bugs were identified in the numbering 71 of tracts (affecting only tracts at RA=0). ``version=1`` uses the 72 post-DM-14809 tract numbering. 74 ConfigClass = RingsSkyMapConfig
79 assert version
in (0, 1),
"Unrecognised version: %s" % (version,)
82 self.
_ringSize = math.pi / (config.numRings + 1)
84 for i
in range(config.numRings):
85 startDec = self.
_ringSize*(i + 0.5) - 0.5*math.pi
87 dec = min(math.fabs(startDec), math.fabs(stopDec))
90 super(RingsSkyMap, self).
__init__(numTracts, config, version)
94 """Calculate ring indices given a numerical index of a tract 96 The ring indices are the ring number and the tract number within 99 The ring number is -1 for the south polar cap and increases to the 100 north. The north polar cap has ring number = numRings. The tract 101 number is zero for either of the polar caps. 106 return self.
config.numRings, 0
108 raise IndexError(
"Tract index %d is out of range [0, %d]" % (index, len(self) - 1))
119 while ring < self.
config.numRings
and tractNum >= self.
_ringNums[ring]:
122 return ring, tractNum
125 """Generate the TractInfo for this index""" 128 ra, dec = 0, -0.5*math.pi
129 elif ringNum == self.
config.numRings:
130 ra, dec = 0, 0.5*math.pi
132 dec = self.
_ringSize*(ringNum + 1) - 0.5*math.pi
133 ra = ((2*math.pi*tractNum/self.
_ringNums[ringNum])*afwGeom.radians +
136 center = afwGeom.SpherePoint(ra, dec, afwGeom.radians)
137 wcs = self.
_wcsFactory.makeWcs(crPixPos=afwGeom.Point2D(0, 0), crValCoord=center)
139 0.5*self.
_ringSize*afwGeom.radians, self.
config.tractOverlap*afwGeom.degrees,
142 def _decToRingNum(self, dec):
143 """Calculate ring number from Declination 147 dec : `lsst.afw.geom.Angle` 153 Ring number: -1 for the south polar cap, and increasing to the 154 north, ending with ``numRings`` for the north polar cap. 156 firstRingStart = self.
_ringSize*0.5 - 0.5*math.pi
157 if dec < firstRingStart:
160 elif dec > firstRingStart*-1:
162 return self.
config.numRings
163 return int((dec.asRadians() - firstRingStart)/self.
_ringSize)
165 def _raToTractNum(self, ra, ringNum):
166 """Calculate tract number from the Right Ascension 170 ra : `lsst.afw.geom.Angle` 173 Ring number (from ``_decToRingNum``). 178 Tract number within the ring (starts at 0 for the tract at raStart). 180 if ringNum
in (-1, self.
config.numRings):
182 assert ringNum
in range(self.
config.numRings)
183 tractNum = int((ra - self.
_raStart).wrap().asRadians() /
184 (2*math.pi/self.
_ringNums[ringNum]) + 0.5)
185 return 0
if tractNum == self.
_ringNums[ringNum]
else tractNum
188 """Find the tract whose center is nearest the specified coord. 190 @param[in] coord: sky coordinate (afwCoord.Coord) 191 @return TractInfo of tract whose center is nearest the specified coord 194 - if tracts do not cover the whole sky then the returned tract may not include the coord 197 - If coord is equidistant between multiple sky tract centers then one is arbitrarily chosen. 203 if ringNum == self.
config.numRings:
208 if self.
_version == 0
and tractNum == 0
and ringNum != 0:
213 index = sum(self.
_ringNums[:ringNum], tractNum + 1)
217 """Find all tracts which include the specified coord. 219 @param[in] coord: sky coordinate (afwCoord.Coord) 220 @return List of TractInfo of tracts which include the specified coord 223 - This routine will be more efficient if coord is ICRS. 230 for r
in [ringNum - 1, ringNum, ringNum + 1]:
231 if r < 0
or r >= self.
config.numRings:
236 for t
in [tractNum - 1, tractNum, tractNum + 1]:
244 if self.
_version == 0
and t == 0
and r != 0:
249 index = sum(self.
_ringNums[:r + extra], t + 1)
251 if tract.contains(coord):
252 tractList.append(tract)
256 for entry
in [0, len(self)-1]:
258 if tract.contains(coord):
259 tractList.append(tract)
264 """Find tracts and patches that overlap a region 266 @param[in] coordList: list of sky coordinates (afwCoord.Coord) 267 @return list of (TractInfo, list of PatchInfo) for tracts and patches that contain, 268 or may contain, the specified region. The list will be empty if there is no overlap. 270 @warning this uses a naive algorithm that may find some tracts and patches that do not overlap 271 the region (especially if the region is not a rectangle aligned along patch x,y). 274 for coord
in coordList:
276 patchList = tractInfo.findPatchList(coordList)
277 if patchList
and not (tractInfo, patchList)
in retList:
278 retList.append((tractInfo, patchList))
282 """Add subclass-specific state or configuration options to the SHA1.""" 283 sha1.update(struct.pack(
"<id", self.
config.numRings, self.
config.raStart))
def _raToTractNum(self, ra, ringNum)
def generateTract(self, index)
def findTractPatchList(self, coordList)
def updateSha1(self, sha1)
def __init__(self, config, version=1)
def findTract(self, coord)
def _decToRingNum(self, dec)
def getRingIndices(self, index)
def findAllTracts(self, coord)