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, _approx_altaz2pa 

4 

5 

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

7 

8 

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

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

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

12 # also used in Global Telescope Network website 

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

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

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

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

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

18 return x, y 

19 

20 

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

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

23 Returns Ra/Dec in radians.""" 

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

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

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

27 return ra, dec 

28 

29 

30class Dither_detailer(Base_detailer): 

31 """ 

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

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

34 for large areas. 

35 

36 Parameters 

37 ---------- 

38 max_dither : float (0.7) 

39 The maximum dither size to use (degrees). 

40 per_night : bool (True) 

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

42 

43 

44 """ 

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

46 self.survey_features = {} 

47 

48 self.current_night = -1 

49 self.max_dither = np.radians(max_dither) 

50 self.per_night = per_night 

51 np.random.seed(seed=seed) 

52 self.offset = None 

53 

54 def _generate_offsets(self, n_offsets, night): 

55 if self.per_night: 

56 if night != self.current_night: 

57 self.current_night = night 

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

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

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

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

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

63 else: 

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

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

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

67 

68 return offsets 

69 

70 def __call__(self, observation_list, conditions): 

71 

72 # Generate offsets in RA and Dec 

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

74 

75 obs_array = np.concatenate(observation_list) 

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

77 for i, obs in enumerate(observation_list): 

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

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

80 return observation_list 

81 

82 

83class Camera_rot_detailer(Base_detailer): 

84 """ 

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

86 

87 Parameters 

88 ---------- 

89 max_rot : float (90.) 

90 The maximum amount to offset the camera (degrees) 

91 min_rot : float (90) 

92 The minimum to offset the camera (degrees) 

93 per_night : bool (True) 

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

95 """ 

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

97 self.survey_features = {} 

98 

99 self.current_night = -1 

100 self.max_rot = np.radians(max_rot) 

101 self.min_rot = np.radians(min_rot) 

102 self.range = self.max_rot - self.min_rot 

103 self.per_night = per_night 

104 np.random.seed(seed=seed) 

105 self.offset = None 

106 

107 def _generate_offsets(self, n_offsets, night): 

108 if self.per_night: 

109 if night != self.current_night: 

110 self.current_night = night 

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

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

113 else: 

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

115 

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

117 

118 return offsets 

119 

120 def __call__(self, observation_list, conditions): 

121 

122 # Generate offsets in camamera rotator 

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

124 

125 for i, obs in enumerate(observation_list): 

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

127 conditions.site.longitude_rad, conditions.mjd) 

128 obs_pa = _approx_altaz2pa(alt, az, conditions.site.latitude_rad) 

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

130 obs['rotTelPos'] = offsets[i] 

131 

132 return observation_list