Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2This module provides wrappers for afwCameraGeom camera objects. 

3This is necessary because of a 90-degree rotation between how 

4the LSST Data Management software team defines coordinate 

5axes on the focal plane and how the LSST Camera team defines 

6coorindate axes on the focal plane. Specifically 

7 

8Camera +y = DM +x 

9Camera +x = DM -y 

10 

11Because we want ImSim images to have the same WCS conventions 

12as PhoSim e-images, we need to apply this rotation to the 

13mappings between RA, Dec and pixel coordinates. We may not 

14wish to do that for arbitrary cameras, so we will give 

15users the ability to apply a no-op wrapper to their cameras. 

16 

17The class LSSTCameraWrapper applies this transformation. 

18In cases where users do not wish to apply any transformation 

19to their pixel coordinate system, the class GalSimCameraWrapper 

20provides the same API as LSSTCamerWrapper, but treats the 

21software-based pixel coordinates as truth. 

22 

23In order to implement your own camera wrapper, create a python 

24class that inherits from GalSimCameraWrapper. This class will 

25need: 

26 

27- a property self.camera that is an afwCamerGeom camera object 

28 

29- a method getBBox() that returns the bounding box in pixel space 

30 of a detector, given that detector's name 

31 

32- a method getCenterPixel() that returns the central pixel of a 

33 detector, given that detector's name 

34 

35- a method getCenterPupil() that returns the pupil coordinates 

36 (or field angle) in radians of the center of a detector given 

37 that detector's name 

38 

39- a method getCornerPupilList that returns the pupil coordinates 

40 (or field angles) in radians of the corners of a detector given 

41 that detector's name 

42 

43- a method getTanPixelBounds() that returns the minimum and maximum 

44 x and y pixel values of a detector, ignoring radial distortions, 

45 given that detector's name 

46 

47- wrappers to the corresponding methods in lsst.sims.coordUtils that 

48 use the self.camera property and apply the necessary transformations 

49 to pixel space coordinates: 

50 pixelCoordsFromPupilCoords() 

51 pupilCoordsFromPixelCoords() 

52 pixelCoordsFromRaDec() 

53 _pixelCoordsFromRaDec() 

54 raDecFromPixelCoords() 

55 _raDecFromPixelCoords() 

56""" 

57 

58import numpy as np 

59from lsst.afw.cameraGeom import FOCAL_PLANE, PIXELS, TAN_PIXELS 

60from lsst.afw.cameraGeom import FIELD_ANGLE 

61import lsst.geom as LsstGeom 

62import lsst.sims.coordUtils as coordUtils 

63import lsst.sims.utils as simsUtils 

64 

65__all__ = ["GalSimCameraWrapper", "LSSTCameraWrapper"] 

66 

67class GalSimCameraWrapper(object): 

68 """ 

69 This is a no-op camera wrapper. 

70 """ 

71 

72 def __init__(self, camera): 

73 """ 

74 Parameters 

75 ---------- 

76 camera is an instantiation of an afwCameraGeom camera 

77 """ 

78 self._camera = camera 

79 

80 @property 

81 def camera(self): 

82 return self._camera 

83 

84 @property 

85 def focal_to_field(self): 

86 """ 

87 Transformation to go from FOCAL_PLANE to FIELD_ANGLE 

88 """ 

89 if not hasattr(self, '_focal_to_field'): 

90 self._focal_to_field = self.camera.getTransformMap().getTransform(FOCAL_PLANE, FIELD_ANGLE) 

91 return self._focal_to_field 

92 

93 def getBBox(self, detector_name): 

94 """ 

95 Return the bounding box for the detector named by detector_name 

96 """ 

97 return self._camera[detector_name].getBBox() 

98 

99 def getCenterPixel(self, detector_name): 

100 """ 

101 Return the central pixel for the detector named by detector_name 

102 """ 

103 if not hasattr(self, '_center_pixel_cache'): 

104 self._center_pixel_cache = {} 

105 

106 if detector_name not in self._center_pixel_cache: 

107 centerPoint = self._camera[detector_name].getCenter(FOCAL_PLANE) 

108 centerPixel = self._camera[detector_name].getTransform(FOCAL_PLANE, PIXELS).applyForward(centerPoint) 

109 self._center_pixel_cache[detector_name] = centerPixel 

110 

111 return self._center_pixel_cache[detector_name] 

112 

113 def getCenterPupil(self, detector_name): 

114 """ 

115 Return the pupil coordinates of the center of the named detector 

116 as an LsstGeom.Point2D 

117 """ 

118 if not hasattr(self, '_center_pupil_cache'): 

119 self._center_pupil_cache = {} 

120 

121 if detector_name not in self._center_pupil_cache: 

122 dd = self._camera[detector_name] 

123 centerPoint = dd.getCenter(FOCAL_PLANE) 

124 pupilPoint = self.focal_to_field.applyForward(centerPoint) 

125 self._center_pupil_cache[detector_name] = pupilPoint 

126 

127 return self._center_pupil_cache[detector_name] 

128 

129 def getCornerPupilList(self, detector_name): 

130 """ 

131 Return a list of the pupil coordinates of the corners of the named 

132 detector as a list of LsstGeom.Point2D objects 

133 """ 

134 if not hasattr(self, '_corner_pupil_cache'): 

135 self._corner_pupil_cache = {} 

136 

137 if detector_name not in self._corner_pupil_cache: 

138 dd = self._camera[detector_name] 

139 cornerPointList = dd.getCorners(FOCAL_PLANE) 

140 pupil_point_list = self.focal_to_field.applyForward(cornerPointList) 

141 self._corner_pupil_cache[detector_name] = pupil_point_list 

142 

143 return self._corner_pupil_cache[detector_name] 

144 

145 def getTanPixelBounds(self, detector_name): 

146 """ 

147 Return the min and max pixel values of a detector, assuming 

148 all radial distortions are set to zero (i.e. using the afwCameraGeom 

149 TAN_PIXELS coordinate system) 

150 

151 Parameters 

152 ---------- 

153 detector_name is a string denoting the name of the detector 

154 

155 Returns 

156 ------- 

157 xmin, xmax, ymin, ymax pixel values 

158 """ 

159 if not hasattr(self, '_tan_pixel_bounds_cache'): 

160 self._tan_pixel_bounds_cache = {} 

161 

162 if detector_name not in self._tan_pixel_bounds_cache: 

163 afwDetector = self._camera[detector_name] 

164 focal_to_tan_pix = afwDetector.getTransform(FOCAL_PLANE, TAN_PIXELS) 

165 xPixMin = None 

166 xPixMax = None 

167 yPixMin = None 

168 yPixMax = None 

169 cornerPointList = focal_to_tan_pix.applyForward(afwDetector.getCorners(FOCAL_PLANE)) 

170 for cornerPoint in cornerPointList: 

171 xx = cornerPoint.getX() 

172 yy = cornerPoint.getY() 

173 if xPixMin is None or xx < xPixMin: 

174 xPixMin = xx 

175 if xPixMax is None or xx > xPixMax: 

176 xPixMax = xx 

177 if yPixMin is None or yy < yPixMin: 

178 yPixMin = yy 

179 if yPixMax is None or yy > yPixMax: 

180 yPixMax = yy 

181 

182 self._tan_pixel_bounds_cache[detector_name] = (xPixMin, xPixMax, yPixMin, yPixMax) 

183 

184 return self._tan_pixel_bounds_cache[detector_name] 

185 

186 def pixelCoordsFromPupilCoords(self, xPupil, yPupil, chipName, obs_metadata, 

187 includeDistortion=True): 

188 """ 

189 Get the pixel positions (or nan if not on a chip) for objects based 

190 on their pupil coordinates. 

191 

192 Parameters 

193 --------- 

194 xPupil is the x pupil coordinates in radians. Can be either a float 

195 or a numpy array. 

196 

197 yPupil is the y pupil coordinates in radians. Can be either a float 

198 or a numpy array. 

199 

200 chipName designates the names of the chips on which the pixel 

201 coordinates will be reckoned. Can be either single value, an array, or None. 

202 If an array, there must be as many chipNames as there are (RA, Dec) pairs. 

203 If a single value, all of the pixel coordinates will be reckoned on the same 

204 chip. If None, this method will calculate which chip each(RA, Dec) pair actually 

205 falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate 

206 chip. 

207 

208 obs_metadata is an ObservationMetaData characterizing the telescope 

209 pointing. 

210 

211 includeDistortion is a boolean. If True (default), then this method will 

212 return the true pixel coordinates with optical distortion included. If False, this 

213 method will return TAN_PIXEL coordinates, which are the pixel coordinates with 

214 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

215 details. 

216 

217 Returns 

218 ------- 

219 a 2-D numpy array in which the first row is the x pixel coordinate 

220 and the second row is the y pixel coordinate 

221 """ 

222 if obs_metadata is None: 

223 raise RuntimeError("Must pass obs_metdata to " 

224 "cameraWrapper.pixelCoordsFromPupilCoords") 

225 

226 return coordUtils.pixelCoordsFromPupilCoords(xPupil, yPupil, chipName=chipName, 

227 camera=self._camera, 

228 includeDistortion=includeDistortion) 

229 

230 def pupilCoordsFromPixelCoords(self, xPix, yPix, chipName, obs_metadata, 

231 includeDistortion=True): 

232 

233 """ 

234 Convert pixel coordinates into pupil coordinates 

235 

236 Parameters 

237 ---------- 

238 xPix is the x pixel coordinate of the point. 

239 Can be either a float or a numpy array. 

240 

241 yPix is the y pixel coordinate of the point. 

242 Can be either a float or a numpy array. 

243 

244 chipName is the name of the chip(s) on which the pixel coordinates 

245 are defined. This can be a list (in which case there should be one chip name 

246 for each (xPix, yPix) coordinate pair), or a single value (in which case, all 

247 of the (xPix, yPix) points will be reckoned on that chip). 

248 

249 obs_metadata is an ObservationMetaData characterizing the telescope 

250 pointing. 

251 

252 includeDistortion is a boolean. If True (default), then this method will 

253 expect the true pixel coordinates with optical distortion included. If False, this 

254 method will expect TAN_PIXEL coordinates, which are the pixel coordinates with 

255 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

256 details. 

257 

258 Returns 

259 ------- 

260 a 2-D numpy array in which the first row is the x pupil coordinate 

261 and the second row is the y pupil coordinate (both in radians) 

262 """ 

263 

264 return coordUtils.pupilCoordsFromPixelCoords(xPix, yPix, chipName, 

265 camera=self._camera, 

266 includeDistortion=includeDistortion) 

267 

268 def _raDecFromPixelCoords(self, xPix, yPix, chipName, obs_metadata, 

269 epoch=2000.0, includeDistortion=True): 

270 """ 

271 Convert pixel coordinates into RA, Dec 

272 

273 Parameters 

274 ---------- 

275 xPix is the x pixel coordinate. It can be either 

276 a float or a numpy array. 

277 

278 yPix is the y pixel coordinate. It can be either 

279 a float or a numpy array. 

280 

281 chipName is the name of the chip(s) on which the pixel coordinates 

282 are defined. This can be a list (in which case there should be one chip name 

283 for each (xPix, yPix) coordinate pair), or a single value (in which case, all 

284 of the (xPix, yPix) points will be reckoned on that chip). 

285 

286 obs_metadata is an ObservationMetaData defining the pointing 

287 

288 epoch is the mean epoch in years of the celestial coordinate system. 

289 Default is 2000. 

290 

291 includeDistortion is a boolean. If True (default), then this method will 

292 expect the true pixel coordinates with optical distortion included. If False, this 

293 method will expect TAN_PIXEL coordinates, which are the pixel coordinates with 

294 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

295 details. 

296 

297 Returns 

298 ------- 

299 a 2-D numpy array in which the first row is the RA coordinate 

300 and the second row is the Dec coordinate (both in radians; in the 

301 International Celestial Reference System) 

302 

303 WARNING: This method does not account for apparent motion due to parallax. 

304 This method is only useful for mapping positions on a theoretical focal plane 

305 to positions on the celestial sphere. 

306 """ 

307 

308 return coordUtils._raDecFromPixelCoords(xPix, yPix, chipName, 

309 camera=self._camera, 

310 obs_metadata=obs_metadata, 

311 epoch=epoch, 

312 includeDistortion=includeDistortion) 

313 

314 def raDecFromPixelCoords(self, xPix, yPix, chipName, obs_metadata, 

315 epoch=2000.0, includeDistortion=True): 

316 

317 """ 

318 Convert pixel coordinates into RA, Dec 

319 

320 Parameters 

321 ---------- 

322 xPix is the x pixel coordinate. It can be either 

323 a float or a numpy array. 

324 

325 yPix is the y pixel coordinate. It can be either 

326 a float or a numpy array. 

327 

328 chipName is the name of the chip(s) on which the pixel coordinates 

329 are defined. This can be a list (in which case there should be one chip name 

330 for each (xPix, yPix) coordinate pair), or a single value (in which case, all 

331 of the (xPix, yPix) points will be reckoned on that chip). 

332 

333 obs_metadata is an ObservationMetaData defining the pointing 

334 

335 epoch is the mean epoch in years of the celestial coordinate system. 

336 Default is 2000. 

337 

338 includeDistortion is a boolean. If True (default), then this method will 

339 expect the true pixel coordinates with optical distortion included. If False, this 

340 method will expect TAN_PIXEL coordinates, which are the pixel coordinates with 

341 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

342 details. 

343 

344 Returns 

345 ------- 

346 a 2-D numpy array in which the first row is the RA coordinate 

347 and the second row is the Dec coordinate (both in degrees; in the 

348 International Celestial Reference System) 

349 

350 WARNING: This method does not account for apparent motion due to parallax. 

351 This method is only useful for mapping positions on a theoretical focal plane 

352 to positions on the celestial sphere. 

353 """ 

354 

355 return coordUtils.raDecFromPixelCoords(xPix, yPix, chipName, 

356 camera=self._camera, 

357 obs_metadata=obs_metadata, 

358 epoch=2000.0, includeDistortion=True) 

359 

360 def _pixelCoordsFromRaDec(self, ra, dec, pm_ra=None, pm_dec=None, 

361 parallax=None, v_rad=None, 

362 obs_metadata=None, 

363 chipName=None, 

364 epoch=2000.0, includeDistortion=True): 

365 """ 

366 Get the pixel positions (or nan if not on a chip) for objects based 

367 on their RA, and Dec (in radians) 

368 

369 Parameters 

370 ---------- 

371 ra is in radians in the International Celestial Reference System. 

372 Can be either a float or a numpy array. 

373 

374 dec is in radians in the International Celestial Reference System. 

375 Can be either a float or a numpy array. 

376 

377 pm_ra is proper motion in RA multiplied by cos(Dec) (radians/yr) 

378 Can be a numpy array or a number or None (default=None). 

379 

380 pm_dec is proper motion in dec (radians/yr) 

381 Can be a numpy array or a number or None (default=None). 

382 

383 parallax is parallax in radians 

384 Can be a numpy array or a number or None (default=None). 

385 

386 v_rad is radial velocity (km/s) 

387 Can be a numpy array or a number or None (default=None). 

388 

389 obs_metadata is an ObservationMetaData characterizing the telescope 

390 pointing. 

391 

392 epoch is the epoch in Julian years of the equinox against which 

393 RA is measured. Default is 2000. 

394 

395 chipName designates the names of the chips on which the pixel 

396 coordinates will be reckoned. Can be either single value, an array, or None. 

397 If an array, there must be as many chipNames as there are (RA, Dec) pairs. 

398 If a single value, all of the pixel coordinates will be reckoned on the same 

399 chip. If None, this method will calculate which chip each(RA, Dec) pair actually 

400 falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate 

401 chip. Default is None. 

402 

403 includeDistortion is a boolean. If True (default), then this method will 

404 return the true pixel coordinates with optical distortion included. If False, this 

405 method will return TAN_PIXEL coordinates, which are the pixel coordinates with 

406 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

407 details. 

408 

409 Returns 

410 ------- 

411 a 2-D numpy array in which the first row is the x pixel coordinate 

412 and the second row is the y pixel coordinate 

413 """ 

414 

415 return coordUtils._pixelCoordsFromRaDec(ra, dec, pm_ra=pm_ra, pm_dec=pm_dec, 

416 parallax=parallax, v_rad=v_rad, 

417 obs_metadata=obs_metadata, 

418 chipName=chipName, camera=self._camera, 

419 epoch=epoch, includeDistortion=includeDistortion) 

420 

421 def pixelCoordsFromRaDec(self, ra, dec, pm_ra=None, pm_dec=None, parallax=None, v_rad=None, 

422 obs_metadata=None, 

423 chipName=None, camera=None, 

424 epoch=2000.0, includeDistortion=True): 

425 """ 

426 Get the pixel positions (or nan if not on a chip) for objects based 

427 on their RA, and Dec (in degrees) 

428 

429 Parameters 

430 ---------- 

431 ra is in degrees in the International Celestial Reference System. 

432 Can be either a float or a numpy array. 

433 

434 dec is in degrees in the International Celestial Reference System. 

435 Can be either a float or a numpy array. 

436 

437 pm_ra is proper motion in RA multiplied by cos(Dec) (arcsec/yr) 

438 Can be a numpy array or a number or None (default=None). 

439 

440 pm_dec is proper motion in dec (arcsec/yr) 

441 Can be a numpy array or a number or None (default=None). 

442 

443 parallax is parallax in arcsec 

444 Can be a numpy array or a number or None (default=None). 

445 

446 v_rad is radial velocity (km/s) 

447 Can be a numpy array or a number or None (default=None). 

448 

449 obs_metadata is an ObservationMetaData characterizing the telescope 

450 pointing. 

451 

452 epoch is the epoch in Julian years of the equinox against which 

453 RA is measured. Default is 2000. 

454 

455 chipName designates the names of the chips on which the pixel 

456 coordinates will be reckoned. Can be either single value, an array, or None. 

457 If an array, there must be as many chipNames as there are (RA, Dec) pairs. 

458 If a single value, all of the pixel coordinates will be reckoned on the same 

459 chip. If None, this method will calculate which chip each(RA, Dec) pair actually 

460 falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate 

461 chip. Default is None. 

462 

463 includeDistortion is a boolean. If True (default), then this method will 

464 return the true pixel coordinates with optical distortion included. If False, this 

465 method will return TAN_PIXEL coordinates, which are the pixel coordinates with 

466 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

467 details. 

468 

469 Returns 

470 ------- 

471 a 2-D numpy array in which the first row is the x pixel coordinate 

472 and the second row is the y pixel coordinate 

473 """ 

474 

475 return coordUtils.pixelCoordsFromRaDec(ra, dec, pm_ra=pm_ra, pm_dec=pm_dec, 

476 parallax=parallax, v_rad=v_rad, 

477 obs_metadata=obs_metadata, 

478 chipName=chipName, camera=self._camera, 

479 epoch=epoch, includeDistortion=includeDistortion) 

480 

481 

482 

483class LSSTCameraWrapper(coordUtils.DMtoCameraPixelTransformer, 

484 GalSimCameraWrapper): 

485 

486 def getTanPixelBounds(self, detector_name): 

487 """ 

488 Return the min and max pixel values of a detector, assuming 

489 all radial distortions are set to zero (i.e. using the afwCameraGeom 

490 TAN_PIXELS coordinate system) 

491 

492 Parameters 

493 ---------- 

494 detector_name is a string denoting the name of the detector 

495 

496 Returns 

497 ------- 

498 xmin, xmax, ymin, ymax pixel values 

499 """ 

500 if not hasattr(self, '_tan_pixel_bounds_cache'): 

501 self._tan_pixel_bounds_cache = {} 

502 

503 if detector_name not in self._tan_pixel_bounds_cache: 

504 dm_xmin, dm_xmax, dm_ymin, dm_ymax = GalSimCameraWrapper.getTanPixelBounds(self, detector_name) 

505 self._tan_pixel_bounds_cache[detector_name] = (dm_ymin, dm_ymax, dm_xmin, dm_xmax) 

506 

507 return self._tan_pixel_bounds_cache[detector_name] 

508 

509 def pixelCoordsFromPupilCoords(self, xPupil, yPupil, chipName, obs_metadata, 

510 includeDistortion=True): 

511 """ 

512 Get the pixel positions (or nan if not on a chip) for objects based 

513 on their pupil coordinates. 

514 

515 Paramters 

516 --------- 

517 xPupil is the x pupil coordinates in radians. Can be either a float 

518 or a numpy array. 

519 

520 yPupil is the y pupil coordinates in radians. Can be either a float 

521 or a numpy array. 

522 

523 chipName designates the names of the chips on which the pixel 

524 coordinates will be reckoned. Can be either single value, an array, or None. 

525 If an array, there must be as many chipNames as there are (RA, Dec) pairs. 

526 If a single value, all of the pixel coordinates will be reckoned on the same 

527 chip. If None, this method will calculate which chip each(RA, Dec) pair actually 

528 falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate 

529 chip. 

530 

531 obs_metadata is an ObservationMetaData characterizing the telescope 

532 pointing. 

533 

534 includeDistortion is a boolean. If True (default), then this method will 

535 return the true pixel coordinates with optical distortion included. If False, this 

536 method will return TAN_PIXEL coordinates, which are the pixel coordinates with 

537 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

538 details. 

539 

540 Returns 

541 ------- 

542 a 2-D numpy array in which the first row is the x pixel coordinate 

543 and the second row is the y pixel coordinate. These pixel coordinates 

544 are defined in the Camera team system, rather than the DM system. 

545 """ 

546 (dm_x_pix, 

547 dm_y_pix) = coordUtils.pixelCoordsFromPupilCoordsLSST(xPupil, yPupil, 

548 chipName=chipName, 

549 band=obs_metadata.bandpass, 

550 includeDistortion=includeDistortion) 

551 

552 cam_y_pix = dm_x_pix 

553 if isinstance(chipName, list) or isinstance(chipName, np.ndarray): 

554 center_pix_dict = {} 

555 cam_x_pix = np.zeros(len(dm_y_pix)) 

556 for ix, (det_name, yy) in enumerate(zip(chipName, dm_y_pix)): 

557 if det_name not in center_pix_dict: 

558 center_pix = self.getCenterPixel(det_name) 

559 center_pix_dict[det_name] = center_pix 

560 else: 

561 center_pix = center_pix_dict[det_name] 

562 cam_x_pix[ix] = 2.0*center_pix[0]-yy 

563 else: 

564 center_pix = self.getCenterPixel(chipName) 

565 cam_x_pix = 2.0*center_pix[0] - dm_y_pix 

566 

567 return cam_x_pix, cam_y_pix 

568 

569 def pupilCoordsFromPixelCoords(self, xPix, yPix, chipName, obs_metadata, 

570 includeDistortion=True): 

571 """ 

572 Convert pixel coordinates into pupil coordinates 

573 

574 Parameters 

575 ---------- 

576 xPix is the x pixel coordinate of the point. 

577 Can be either a float or a numpy array. 

578 Defined in the Camera team system (not the DM system). 

579 

580 yPix is the y pixel coordinate of the point. 

581 Can be either a float or a numpy array. 

582 Defined in the Camera team system (not the DM system). 

583 

584 chipName is the name of the chip(s) on which the pixel coordinates 

585 are defined. This can be a list (in which case there should be one chip name 

586 for each (xPix, yPix) coordinate pair), or a single value (in which case, all 

587 of the (xPix, yPix) points will be reckoned on that chip). 

588 

589 obs_metadata is an ObservationMetaData characterizing the telescope 

590 pointing. 

591 

592 includeDistortion is a boolean. If True (default), then this method will 

593 expect the true pixel coordinates with optical distortion included. If False, this 

594 method will expect TAN_PIXEL coordinates, which are the pixel coordinates with 

595 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

596 details. 

597 

598 Returns 

599 ------- 

600 a 2-D numpy array in which the first row is the x pupil coordinate 

601 and the second row is the y pupil coordinate (both in radians) 

602 """ 

603 dm_xPix = yPix 

604 if isinstance(chipName, list) or isinstance(chipName, np.ndarray): 

605 dm_yPix = np.zeros(len(xPix)) 

606 for ix, (det_name, xx) in enumerate(zip(chipName, xPix)): 

607 came_center_pix = self.getCenterPixel(det_name) 

608 dm_yPix[ix] = 2.0*cam_center_pix.getX()-xPix[ix] 

609 else: 

610 cam_center_pix = self.getCenterPixel(chipName) 

611 dm_yPix = 2.0*cam_center_pix.getX()-xPix 

612 return coordUtils.pupilCoordsFromPixelCoordsLSST(dm_xPix, dm_yPix, chipName, 

613 band=obs_metadata.bandpass, 

614 includeDistortion=includeDistortion) 

615 

616 def _raDecFromPixelCoords(self, xPix, yPix, chipName, obs_metadata, 

617 epoch=2000.0, includeDistortion=True): 

618 """ 

619 Convert pixel coordinates into RA, Dec 

620 

621 Parameters 

622 ---------- 

623 xPix is the x pixel coordinate. It can be either 

624 a float or a numpy array. Defined in the Camera 

625 team system (not the DM system). 

626 

627 yPix is the y pixel coordinate. It can be either 

628 a float or a numpy array. Defined in the Camera 

629 team system (not the DM system). 

630 

631 chipName is the name of the chip(s) on which the pixel coordinates 

632 are defined. This can be a list (in which case there should be one chip name 

633 for each (xPix, yPix) coordinate pair), or a single value (in which case, all 

634 of the (xPix, yPix) points will be reckoned on that chip). 

635 

636 obs_metadata is an ObservationMetaData defining the pointing 

637 

638 epoch is the mean epoch in years of the celestial coordinate system. 

639 Default is 2000. 

640 

641 includeDistortion is a boolean. If True (default), then this method will 

642 expect the true pixel coordinates with optical distortion included. If False, this 

643 method will expect TAN_PIXEL coordinates, which are the pixel coordinates with 

644 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

645 details. 

646 

647 Returns 

648 ------- 

649 a 2-D numpy array in which the first row is the RA coordinate 

650 and the second row is the Dec coordinate (both in radians; in the 

651 International Celestial Reference System) 

652 

653 WARNING: This method does not account for apparent motion due to parallax. 

654 This method is only useful for mapping positions on a theoretical focal plane 

655 to positions on the celestial sphere. 

656 """ 

657 

658 if isinstance(chipName, list) or isinstance(chipName, np.ndarray): 

659 dm_xPix = yPix 

660 dm_yPix = np.zeros(len(xPix)) 

661 for ix, (det_name, xx) in enumerate(zip(chipName, xPix)): 

662 cam_center_pix = self.getCenterPixel(det_name) 

663 dm_yPix[ix] = 2.0*cam_center_pix.getX() - xx 

664 else: 

665 dm_xPix = yPix 

666 cam_center_pix = self.getCenterPixel(chipName) 

667 dm_yPix = 2.0*cam_center_pix.getX() - xPix 

668 

669 return coordUtils._raDecFromPixelCoordsLSST(dm_xPix, dm_yPix, chipName, 

670 obs_metadata=obs_metadata, 

671 band=obs_metadata.bandpass, 

672 epoch=epoch, 

673 includeDistortion=includeDistortion) 

674 

675 def raDecFromPixelCoords(self, xPix, yPix, chipName, obs_metadata, 

676 epoch=2000.0, includeDistortion=True): 

677 """ 

678 Convert pixel coordinates into RA, Dec 

679 

680 Parameters 

681 ---------- 

682 xPix is the x pixel coordinate. It can be either 

683 a float or a numpy array. Defined in the Camera 

684 team system (not the DM system). 

685 

686 yPix is the y pixel coordinate. It can be either 

687 a float or a numpy array. Defined in the Camera 

688 team system (not the DM system). 

689 

690 chipName is the name of the chip(s) on which the pixel coordinates 

691 are defined. This can be a list (in which case there should be one chip name 

692 for each (xPix, yPix) coordinate pair), or a single value (in which case, all 

693 of the (xPix, yPix) points will be reckoned on that chip). 

694 

695 obs_metadata is an ObservationMetaData defining the pointing 

696 

697 epoch is the mean epoch in years of the celestial coordinate system. 

698 Default is 2000. 

699 

700 includeDistortion is a boolean. If True (default), then this method will 

701 expect the true pixel coordinates with optical distortion included. If False, this 

702 method will expect TAN_PIXEL coordinates, which are the pixel coordinates with 

703 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

704 details. 

705 

706 Returns 

707 ------- 

708 a 2-D numpy array in which the first row is the RA coordinate 

709 and the second row is the Dec coordinate (both in degrees; in the 

710 International Celestial Reference System) 

711 

712 WARNING: This method does not account for apparent motion due to parallax. 

713 This method is only useful for mapping positions on a theoretical focal plane 

714 to positions on the celestial sphere. 

715 """ 

716 

717 _ra, _dec = self._raDecFromPixelCoords(xPix, yPix, chipName, 

718 obs_metadata=obs_metadata, 

719 epoch=2000.0, includeDistortion=True) 

720 

721 return np.degrees(_ra), np.degrees(_dec) 

722 

723 def _pixelCoordsFromRaDec(self, ra, dec, pm_ra=None, pm_dec=None, parallax=None, v_rad=None, 

724 obs_metadata=None, 

725 chipName=None, 

726 epoch=2000.0, includeDistortion=True): 

727 """ 

728 Get the pixel positions (or nan if not on a chip) for objects based 

729 on their RA, and Dec (in radians) 

730 

731 Parameters 

732 ---------- 

733 ra is in radians in the International Celestial Reference System. 

734 Can be either a float or a numpy array. 

735 

736 dec is in radians in the International Celestial Reference System. 

737 Can be either a float or a numpy array. 

738 

739 pm_ra is proper motion in RA multiplied by cos(Dec) (radians/yr) 

740 Can be a numpy array or a number or None (default=None). 

741 

742 pm_dec is proper motion in dec (radians/yr) 

743 Can be a numpy array or a number or None (default=None). 

744 

745 parallax is parallax in radians 

746 Can be a numpy array or a number or None (default=None). 

747 

748 v_rad is radial velocity (km/s) 

749 Can be a numpy array or a number or None (default=None). 

750 

751 obs_metadata is an ObservationMetaData characterizing the telescope 

752 pointing. 

753 

754 epoch is the epoch in Julian years of the equinox against which 

755 RA is measured. Default is 2000. 

756 

757 chipName designates the names of the chips on which the pixel 

758 coordinates will be reckoned. Can be either single value, an array, or None. 

759 If an array, there must be as many chipNames as there are (RA, Dec) pairs. 

760 If a single value, all of the pixel coordinates will be reckoned on the same 

761 chip. If None, this method will calculate which chip each(RA, Dec) pair actually 

762 falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate 

763 chip. Default is None. 

764 

765 includeDistortion is a boolean. If True (default), then this method will 

766 return the true pixel coordinates with optical distortion included. If False, this 

767 method will return TAN_PIXEL coordinates, which are the pixel coordinates with 

768 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

769 details. 

770 

771 Returns 

772 ------- 

773 a 2-D numpy array in which the first row is the x pixel coordinate 

774 and the second row is the y pixel coordinate. These pixel coordinates 

775 are defined in the Camera team system, rather than the DM system. 

776 """ 

777 

778 dm_xPix, dm_yPix = coordUtils._pixelCoordsFromRaDecLSST(ra, dec, 

779 pm_ra=pm_ra, pm_dec=pm_dec, 

780 parallax=parallax, v_rad=v_rad, 

781 obs_metadata=obs_metadata, 

782 chipName=chipName, 

783 band=obs_metadata.bandpass, 

784 epoch=epoch, 

785 includeDistortion=includeDistortion) 

786 

787 return self.cameraPixFromDMPix(dm_xPix, dm_yPix, chipName) 

788 

789 def pixelCoordsFromRaDec(self, ra, dec, pm_ra=None, pm_dec=None, parallax=None, v_rad=None, 

790 obs_metadata=None, chipName=None, 

791 epoch=2000.0, includeDistortion=True): 

792 """ 

793 Get the pixel positions (or nan if not on a chip) for objects based 

794 on their RA, and Dec (in degrees) 

795 

796 Parameters 

797 ---------- 

798 ra is in degrees in the International Celestial Reference System. 

799 Can be either a float or a numpy array. 

800 

801 dec is in degrees in the International Celestial Reference System. 

802 Can be either a float or a numpy array. 

803 

804 pm_ra is proper motion in RA multiplied by cos(Dec) (arcsec/yr) 

805 Can be a numpy array or a number or None (default=None). 

806 

807 pm_dec is proper motion in dec (arcsec/yr) 

808 Can be a numpy array or a number or None (default=None). 

809 

810 parallax is parallax in arcsec 

811 Can be a numpy array or a number or None (default=None). 

812 

813 v_rad is radial velocity (km/s) 

814 Can be a numpy array or a number or None (default=None). 

815 

816 obs_metadata is an ObservationMetaData characterizing the telescope 

817 pointing. 

818 

819 epoch is the epoch in Julian years of the equinox against which 

820 RA is measured. Default is 2000. 

821 

822 chipName designates the names of the chips on which the pixel 

823 coordinates will be reckoned. Can be either single value, an array, or None. 

824 If an array, there must be as many chipNames as there are (RA, Dec) pairs. 

825 If a single value, all of the pixel coordinates will be reckoned on the same 

826 chip. If None, this method will calculate which chip each(RA, Dec) pair actually 

827 falls on, and return pixel coordinates for each (RA, Dec) pair on the appropriate 

828 chip. Default is None. 

829 

830 includeDistortion is a boolean. If True (default), then this method will 

831 return the true pixel coordinates with optical distortion included. If False, this 

832 method will return TAN_PIXEL coordinates, which are the pixel coordinates with 

833 estimated optical distortion removed. See the documentation in afw.cameraGeom for more 

834 details. 

835 

836 Returns 

837 ------- 

838 a 2-D numpy array in which the first row is the x pixel coordinate 

839 and the second row is the y pixel coordinate. These pixel coordinates 

840 are defined in the Camera team system, rather than the DM system. 

841 """ 

842 

843 if pm_ra is not None: 

844 pm_ra_out = simsUtils.radiansFromArcsec(pm_ra) 

845 else: 

846 pm_ra_out = None 

847 

848 if pm_dec is not None: 

849 pm_dec_out = simsUtils.radiansFromArcsec(pm_dec) 

850 else: 

851 pm_dec_out = None 

852 

853 if parallax is not None: 

854 parallax_out = simsUtils.radiansFromArcsec(parallax) 

855 else: 

856 parallax_out = None 

857 

858 return self._pixelCoordsFromRaDec(np.radians(ra), np.radians(dec), 

859 pm_ra=pm_ra_out, pm_dec=pm_dec_out, 

860 parallax=parallax_out, v_rad=v_rad, 

861 chipName=chipName, obs_metadata=obs_metadata, 

862 epoch=2000.0, includeDistortion=includeDistortion)