Coverage for python/lsst/sims/featureScheduler/detailers/dither_detailer.py : 16%

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
6__all__ = ["Dither_detailer", "Camera_rot_detailer"]
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
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
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.
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
44 """
45 def __init__(self, max_dither=0.7, seed=42, per_night=True):
46 self.survey_features = {}
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
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)])
68 return offsets
70 def __call__(self, observation_list, conditions):
72 # Generate offsets in RA and Dec
73 offsets = self._generate_offsets(len(observation_list), conditions.night)
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
83class Camera_rot_detailer(Base_detailer):
84 """
85 Randomly set the camera rotation, either for each exposure, or per night.
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 = {}
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
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
116 offsets = offsets % (2.*np.pi)
118 return offsets
120 def __call__(self, observation_list, conditions):
122 # Generate offsets in camamera rotator
123 offsets = self._generate_offsets(len(observation_list), conditions.night)
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]
132 return observation_list