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

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
7__all__ = ["Dither_detailer", "Camera_rot_detailer"]
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
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
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.
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
45 """
46 def __init__(self, max_dither=0.7, seed=42, per_night=True):
47 self.survey_features = {}
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
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)])
69 return offsets
71 def __call__(self, observation_list, conditions):
73 # Generate offsets in RA and Dec
74 offsets = self._generate_offsets(len(observation_list), conditions.night)
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
84class Camera_rot_detailer(Base_detailer):
85 """
86 Randomly set the camera rotation, either for each exposure, or per night.
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 = {}
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
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
117 offsets = offsets % (2.*np.pi)
119 return offsets
121 def __call__(self, observation_list, conditions):
123 # Generate offsets in RA and Dec
124 offsets = self._generate_offsets(len(observation_list), conditions.night)
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)
132 return observation_list