Coverage for python/lsst/sims/maf/stackers/NEODistStacker.py : 38%

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 .baseStacker import BaseStacker
3from .generalStackers import FiveSigmaStacker
5__all__ = ['NEODistStacker']
8class NEODistStacker(BaseStacker):
9 """
10 For each observation, find the max distance to a ~144 km NEO,
11 also stack on the x,y position of the object.
12 """
13 colsAdded = ['MaxGeoDist', 'NEOHelioX', 'NEOHelioY']
15 def __init__(self,
16 stepsize=.001, maxDist=3., minDist=.3, H=22, elongCol='solarElong',
17 filterCol='filter', sunAzCol='sunAz', azCol='azimuth', m5Col='fiveSigmaDepth'):
18 """
19 stepsize: The stepsize to use when solving (in AU)
20 maxDist: How far out to try and measure (in AU)
21 H: Asteroid magnitude
23 Adds columns:
24 MaxGeoDist: Geocentric distance to the NEO
25 NEOHelioX: Heliocentric X (with Earth at x,y,z (0,1,0))
26 NEOHelioY: Heliocentric Y (with Earth at (0,1,0))
28 Note that both opsim v3 and v4 report solarElongation in degrees.
29 """
30 self.units = ['AU', 'AU', 'AU']
31 # Also grab things needed for the HA stacker
32 self.colsReq = [elongCol, filterCol, sunAzCol, azCol, m5Col]
34 self.sunAzCol = sunAzCol
35 self.elongCol = elongCol
36 self.filterCol = filterCol
37 self.azCol = azCol
38 self.m5Col = m5Col
40 self.H = H
41 # Magic numbers (Ivezic '15, private comm.)that convert an asteroid
42 # V-band magnitude to LSST filters:
43 # V_5 = m_5 + (adjust value)
44 self.limitingAdjust = {'u': -2.1, 'g': -0.5, 'r': 0.2, 'i': 0.4, 'z': 0.6, 'y': 0.6}
45 self.deltas = np.arange(minDist, maxDist+stepsize, stepsize)
46 self.G = 0.15
48 # Magic numbers from http://adsabs.harvard.edu/abs/2002AJ....124.1776J
49 self.a1 = 3.33
50 self.b1 = 0.63
51 self.a2 = 1.87
52 self.b2 = 1.22
54 def _run(self, simData, cols_present=False):
55 if cols_present:
56 # This is a pretty rare stacker. Assume we need to rerun
57 pass
58 elongRad = np.radians(simData[self.elongCol])
59 v5 = np.zeros(simData.size, dtype=float) + simData[self.m5Col]
60 for filterName in self.limitingAdjust:
61 fmatch = np.where(simData[self.filterCol] == filterName)
62 v5[fmatch] += self.limitingAdjust[filterName]
63 for i, elong in enumerate(elongRad):
64 # Law of cosines:
65 # Heliocentric Radius of the object
66 R = np.sqrt(1.+self.deltas**2-2.*self.deltas*np.cos(elong))
67 # Angle between sun and earth as seen by NEO
68 alphas = np.arccos((1.-R**2-self.deltas**2)/(-2.*self.deltas*R))
69 ta2 = np.tan(alphas/2.)
70 phi1 = np.exp(-self.a1*ta2**self.b1)
71 phi2 = np.exp(-self.a2*ta2**self.b2)
73 alpha_term = 2.5*np.log10((1. - self.G)*phi1+self.G*phi2)
74 appmag = self.H+5.*np.log10(R*self.deltas)-alpha_term
75 # There can be some local minima/maxima when solving, so
76 # need to find the *1st* spot where it is too faint, not the
77 # last spot it is bright enough.
78 tooFaint = np.where(appmag > v5[i])
80 # Check that there is a minimum
81 if np.size(tooFaint[0]) == 0:
82 simData['MaxGeoDist'][i] = 0
83 else:
84 simData['MaxGeoDist'][i] = np.min(self.deltas[tooFaint])
86 # Make coords in heliocentric
87 interior = np.where(elongRad <= np.pi/2.)
88 outer = np.where(elongRad > np.pi/2.)
89 simData['NEOHelioX'][interior] = simData['MaxGeoDist'][interior]*np.sin(elongRad[interior])
90 simData['NEOHelioY'][interior] = -simData['MaxGeoDist'][interior]*np.cos(elongRad[interior]) + 1.
92 simData['NEOHelioX'][outer] = simData['MaxGeoDist'][outer]*np.sin(np.pi-elongRad[outer])
93 simData['NEOHelioY'][outer] = simData['MaxGeoDist'][outer]*np.cos(np.pi-elongRad[outer]) + 1.
95 # Flip the X coord if sun az is negative?
96 if simData[self.azCol].min() < - np.pi/2.0:
97 halfval = 180.
98 else:
99 halfval = np.pi
100 flip = np.where(((simData[self.sunAzCol] > halfval) & (simData[self.azCol] > halfval)) |
101 ((simData[self.sunAzCol] < halfval) & (simData[self.azCol] > halfval)))
103 simData['NEOHelioX'][flip] *= -1.
105 return simData