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

1import numpy as np 

2from lsst.sims.featureScheduler.detailers import Base_detailer 

3from lsst.sims.utils import _approx_RaDec2AltAz 

4from lsst.sims.featureScheduler.utils import approx_altaz2pa 

5 

6 

7__all__ = ["Dither_detailer", "Camera_rot_detailer"] 

8 

9 

10def gnomonic_project_toxy(ra, dec, raCen, decCen): 

11 """Calculate x/y projection of RA1/Dec1 in system with center at RAcen, Deccenp. 

12 Input radians. Returns x/y.""" 

13 # also used in Global Telescope Network website 

14 if (len(ra) != len(dec)): 

15 raise Exception("Expect RA and Dec arrays input to gnomonic projection to be same length.") 

16 cosc = np.sin(decCen) * np.sin(dec) + np.cos(decCen) * np.cos(dec) * np.cos(ra-raCen) 

17 x = np.cos(dec) * np.sin(ra-raCen) / cosc 

18 y = (np.cos(decCen)*np.sin(dec) - np.sin(decCen)*np.cos(dec)*np.cos(ra-raCen)) / cosc 

19 return x, y 

20 

21 

22def gnomonic_project_tosky(x, y, raCen, decCen): 

23 """Calculate RA/Dec on sky of object with x/y and RA/Cen of field of view. 

24 Returns Ra/Dec in radians.""" 

25 denom = np.cos(decCen) - y * np.sin(decCen) 

26 ra = raCen + np.arctan2(x, denom) 

27 dec = np.arctan2(np.sin(decCen) + y * np.cos(decCen), np.sqrt(x*x + denom*denom)) 

28 return ra, dec 

29 

30 

31class Dither_detailer(Base_detailer): 

32 """ 

33 make a uniform dither pattern. Offset by a maximum radius in a random direction. 

34 Mostly intended for DDF pointings, the BaseMarkovDF_survey class includes dithering 

35 for large areas. 

36 

37 Parameters 

38 ---------- 

39 max_dither : float (0.7) 

40 The maximum dither size to use (degrees). 

41 per_night : bool (True) 

42 If true, us the same dither offset for an entire night 

43 

44 

45 """ 

46 def __init__(self, max_dither=0.7, seed=42, per_night=True): 

47 self.survey_features = {} 

48 

49 self.current_night = -1 

50 self.max_dither = np.radians(max_dither) 

51 self.per_night = per_night 

52 np.random.seed(seed=seed) 

53 self.offset = None 

54 

55 def _generate_offsets(self, n_offsets, night): 

56 if self.per_night: 

57 if night != self.current_night: 

58 self.current_night = night 

59 self.offset = (np.random.random((1, 2))-0.5) * 2.*self.max_dither 

60 angle = np.random.random(1)*2*np.pi 

61 radius = self.max_dither * np.sqrt(np.random.random(1)) 

62 self.offset = np.array([radius*np.cos(angle), radius*np.sin(angle)]) 

63 offsets = np.tile(self.offset, (n_offsets, 1)) 

64 else: 

65 angle = np.random.random(n_offsets)*2*np.pi 

66 radius = self.max_dither * np.sqrt(np.random.random(n_offsets)) 

67 offsets = np.array([radius*np.cos(angle), radius*np.sin(angle)]) 

68 

69 return offsets 

70 

71 def __call__(self, observation_list, conditions): 

72 

73 # Generate offsets in RA and Dec 

74 offsets = self._generate_offsets(len(observation_list), conditions.night) 

75 

76 obs_array = np.concatenate(observation_list) 

77 newRA, newDec = gnomonic_project_tosky(offsets[0, :], offsets[1, :], obs_array['RA'], obs_array['dec']) 

78 for i, obs in enumerate(observation_list): 

79 observation_list[i]['RA'] = newRA[i] 

80 observation_list[i]['dec'] = newDec[i] 

81 return observation_list 

82 

83 

84class Camera_rot_detailer(Base_detailer): 

85 """ 

86 Randomly set the camera rotation, either for each exposure, or per night. 

87 

88 Parameters 

89 ---------- 

90 max_rot : float (90.) 

91 The maximum amount to offset the camera (degrees) 

92 min_rot : float (90) 

93 The minimum to offset the camera (degrees) 

94 per_night : bool (True) 

95 If True, only set a new offset per night. If False, randomly rotates every observation. 

96 """ 

97 def __init__(self, max_rot=90., min_rot=-90., per_night=True, seed=42): 

98 self.survey_features = {} 

99 

100 self.current_night = -1 

101 self.max_rot = np.radians(max_rot) 

102 self.min_rot = np.radians(min_rot) 

103 self.range = self.max_rot - self.min_rot 

104 self.per_night = per_night 

105 np.random.seed(seed=seed) 

106 self.offset = None 

107 

108 def _generate_offsets(self, n_offsets, night): 

109 if self.per_night: 

110 if night != self.current_night: 

111 self.current_night = night 

112 self.offset = np.random.random(1) * self.range + self.min_rot 

113 offsets = np.ones(n_offsets) * self.offset 

114 else: 

115 offsets = np.random.random(n_offsets) * self.range + self.min_rot 

116 

117 offsets = offsets % (2.*np.pi) 

118 

119 return offsets 

120 

121 def __call__(self, observation_list, conditions): 

122 

123 # Generate offsets in RA and Dec 

124 offsets = self._generate_offsets(len(observation_list), conditions.night) 

125 

126 for i, obs in enumerate(observation_list): 

127 alt, az = _approx_RaDec2AltAz(obs['RA'], obs['dec'], conditions.site.latitude_rad, 

128 conditions.site.longitude_rad, conditions.mjd) 

129 obs_pa = approx_altaz2pa(alt, az, conditions.site.latitude_rad) 

130 obs['rotSkyPos'] = (obs_pa + offsets[i]) % (2.*np.pi) 

131 

132 return observation_list