23 __all__ = [
"RingsSkyMapConfig",
"RingsSkyMap"]
28 from lsst.pex.config
import Field
30 from .cachingSkyMap
import CachingSkyMap
31 from .tractInfo
import ExplicitTractInfo
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 The 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
78 assert version
in (0, 1),
"Unrecognised version: %s" % (version,)
81 self.
_ringSize = math.pi / (config.numRings + 1)
83 for i
in range(config.numRings):
84 startDec = self.
_ringSize*(i + 0.5) - 0.5*math.pi
86 dec =
min(math.fabs(startDec), math.fabs(stopDec))
89 super(RingsSkyMap, self).
__init__(numTracts, config, version)
93 """Calculate ring indices given a numerical index of a tract. 95 The ring indices are the ring number and the tract number within 98 The ring number is -1 for the south polar cap and increases to the 99 north. The north polar cap has ring number = numRings. The tract 100 number is zero for either of the polar caps. 105 return self.
config.numRings, 0
107 raise IndexError(
"Tract index %d is out of range [0, %d]" % (index, len(self) - 1))
118 while ring < self.
config.numRings
and tractNum >= self.
_ringNums[ring]:
121 return ring, tractNum
124 """Generate TractInfo for the specified tract index.""" 127 ra, dec = 0, -0.5*math.pi
128 elif ringNum == self.
config.numRings:
129 ra, dec = 0, 0.5*math.pi
131 dec = self.
_ringSize*(ringNum + 1) - 0.5*math.pi
132 ra = ((2*math.pi*tractNum/self.
_ringNums[ringNum])*geom.radians +
138 0.5*self.
_ringSize*geom.radians, self.
config.tractOverlap*geom.degrees,
141 def _decToRingNum(self, dec):
142 """Calculate ring number from Declination. 146 dec : `lsst.geom.Angle` 152 Ring number: -1 for the south polar cap, and increasing to the 153 north, ending with ``numRings`` for the north polar cap. 155 firstRingStart = self.
_ringSize*0.5 - 0.5*math.pi
156 if dec < firstRingStart:
159 elif dec > firstRingStart*-1:
161 return self.
config.numRings
162 return int((dec.asRadians() - firstRingStart)/self.
_ringSize)
164 def _raToTractNum(self, ra, ringNum):
165 """Calculate tract number from the Right Ascension. 169 ra : `lsst.geom.Angle` 172 Ring number (from ``_decToRingNum``). 177 Tract number within the ring (starts at 0 for the tract at raStart). 179 if ringNum
in (-1, self.
config.numRings):
181 assert ringNum
in range(self.
config.numRings)
182 tractNum = int((ra - self.
_raStart).
wrap().asRadians() /
183 (2*math.pi/self.
_ringNums[ringNum]) + 0.5)
184 return 0
if tractNum == self.
_ringNums[ringNum]
else tractNum
191 if ringNum == self.
config.numRings:
196 if self.
_version == 0
and tractNum == 0
and ringNum != 0:
201 index = sum(self.
_ringNums[:ringNum], tractNum + 1)
205 """Find all tracts which include the specified coord. 209 coord : `lsst.geom.SpherePoint` 210 ICRS sky coordinate to search for. 214 tractList : `list` of `TractInfo` 215 The tracts which include the specified coord. 222 for r
in [ringNum - 1, ringNum, ringNum + 1]:
223 if r < 0
or r >= self.
config.numRings:
228 for t
in [tractNum - 1, tractNum, tractNum + 1]:
236 if self.
_version == 0
and t == 0
and r != 0:
241 index = sum(self.
_ringNums[:r + extra], t + 1)
243 if tract.contains(coord):
244 tractList.append(tract)
248 for entry
in [0, len(self)-1]:
250 if tract.contains(coord):
251 tractList.append(tract)
257 for coord
in coordList:
259 patchList = tractInfo.findPatchList(coordList)
260 if patchList
and not (tractInfo, patchList)
in retList:
261 retList.append((tractInfo, patchList))
265 """Add subclass-specific state or configuration options to the SHA1.""" 266 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)
std::shared_ptr< FrameSet > append(FrameSet const &first, FrameSet const &second)
Construct a FrameSet that performs two transformations in series.
def findTract(self, coord)
def _decToRingNum(self, dec)
std::shared_ptr< afw::geom::SkyWcs > makeWcs(SipForwardTransform const &sipForward, SipReverseTransform const &sipReverse, geom::SpherePoint const &skyOrigin)
Create a new TAN SIP Wcs from a pair of SIP transforms and the sky origin.
Point in an unspecified spherical coordinate system.
def getRingIndices(self, index)
def findAllTracts(self, coord)
daf::base::PropertyList * list