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

1"""Footprints: Some relevant LSST footprints, including utilities to build them. 

2 

3The goal here is to make it easy to build typical target maps and then their associated combined 

4survey inputs (maps in each filter, including scaling between filters; the associated cloud and 

5sky brightness maps that would have limits for WFD, etc.). 

6 

7For generic use for defining footprints from scratch, there is also a utility that simply generates 

8the healpix points across the sky, along with their corresponding RA/Dec/Galactic l,b/Ecliptic l,b values. 

9""" 

10 

11import os 

12import numpy as np 

13import healpy as hp 

14from astropy.coordinates import SkyCoord 

15from astropy import units as u 

16from .utils import set_default_nside, int_rounded 

17from lsst.sims.utils import _hpid2RaDec, _angularSeparation 

18from lsst.sims.utils import Site 

19from lsst.utils import getPackageDir 

20 

21__all__ = ['ra_dec_hp_map', 'generate_all_sky', 'get_dustmap', 

22 'WFD_healpixels', 'WFD_no_gp_healpixels', 'WFD_bigsky_healpixels', 'WFD_no_dust_healpixels', 

23 'SCP_healpixels', 'NES_healpixels', 

24 'galactic_plane_healpixels', #'low_lat_plane_healpixels', 'bulge_healpixels', 

25 'magellanic_clouds_healpixels', 'Constant_footprint', 

26 'generate_goal_map', 'standard_goals', 

27 'calc_norm_factor', 'filter_count_ratios', 'Step_line', 'Footprints', 'Footprint', 

28 'Step_slopes', 'Base_pixel_evolution'] 

29 

30 

31class Base_pixel_evolution(object): 

32 """Helper class that can be used to describe the time evolution of a HEALpix in a footprint 

33 """ 

34 

35 def __init__(self, period=365.25, rise=1., t_start=0.): 

36 self.period = period 

37 self.rise = rise 

38 self.t_start = t_start 

39 

40 def __call__(self, mjd_in, phase): 

41 pass 

42 

43 

44class Step_line(Base_pixel_evolution): 

45 """ 

46 Parameters 

47 ---------- 

48 period : float (365.25) 

49 The period to use 

50 rise : float (1.) 

51 How much the curve should rise every period 

52 """ 

53 def __call__(self, mjd_in, phase): 

54 t = mjd_in+phase - self.t_start 

55 n_periods = np.floor(t/(self.period)) 

56 result = n_periods*self.rise 

57 tphased = t % self.period 

58 step_area = np.where(tphased > self.period/2.)[0] 

59 result[step_area] += (tphased[step_area] - self.period/2)*self.rise/(0.5*self.period) 

60 result[np.where(t < 0)] = 0 

61 return result 

62 

63 

64class Step_slopes(Base_pixel_evolution): 

65 """ 

66 Parameters 

67 ---------- 

68 period : float (365.25) 

69 The period to use 

70 rise : np.array-like 

71 How much the curve should rise each period. 

72 """ 

73 def __call__(self, mjd_in, phase): 

74 steps = np.array(self.rise) 

75 t = mjd_in+phase - self.t_start 

76 season = np.floor(t/(self.period)) 

77 season = season.astype(int) 

78 plateus = np.cumsum(steps)-steps[0] 

79 result = plateus[season] 

80 tphased = t % self.period 

81 step_area = np.where(tphased > self.period/2.)[0] 

82 result[step_area] += (tphased[step_area] - self.period/2)*steps[season+1][step_area]/(0.5*self.period) 

83 result[np.where(t < 0)] = 0 

84 

85 return result 

86 

87 

88class Footprint(object): 

89 """An object to compute the desired survey footprint at a given time 

90 

91 Parameters 

92 ---------- 

93 mjd_start : float 

94 The MJD the survey starts on 

95 sun_RA_start : float 

96 The RA of the sun at the start of the survey (radians) 

97 

98 """ 

99 def __init__(self, mjd_start, sun_RA_start=0, nside=32, 

100 filters={'u': 0, 'g': 1, 'r': 2, 'i': 3, 'z': 4, 'y': 5}, 

101 period=365.25, step_func=None): 

102 self.period = period 

103 self.nside = nside 

104 if step_func is None: 

105 step_func = Step_line() 

106 self.step_func = step_func 

107 self.mjd_start = mjd_start 

108 self.sun_RA_start = sun_RA_start 

109 self.npix = hp.nside2npix(nside) 

110 self.filters = filters 

111 self.ra, self.dec = _hpid2RaDec(self.nside, np.arange(self.npix)) 

112 # Set the phase of each healpixel. If RA to sun is zero, we are at phase np.pi/2. 

113 self.phase = (-self.ra + self.sun_RA_start + np.pi/2) % (2.*np.pi) 

114 self.phase = self.phase * (self.period/2./np.pi) 

115 # Empty footprints to start 

116 self.out_dtype = list(zip(filters, [float]*len(filters))) 

117 self.footprints = np.zeros((len(filters), self.npix), dtype=float) 

118 self.estimate = np.zeros((len(filters), self.npix), dtype=float) 

119 self.current_footprints = np.zeros((len(filters), self.npix), dtype=float) 

120 self.zero = self.step_func(0., self.phase) 

121 self.mjd_current = None 

122 

123 def set_footprint(self, filtername, values): 

124 self.footprints[self.filters[filtername], :] = values 

125 

126 def get_footprint(self, filtername): 

127 return self.footprints[self.filters[filtername], :] 

128 

129 def _update_mjd(self, mjd, norm=True): 

130 if mjd != self.mjd_current: 

131 self.mjd_current = mjd 

132 t_elapsed = mjd - self.mjd_start 

133 

134 norm_coverage = self.step_func(t_elapsed, self.phase) 

135 norm_coverage -= self.zero 

136 self.current_footprints = self.footprints * norm_coverage 

137 c_sum = np.sum(self.current_footprints) 

138 if norm: 

139 if c_sum != 0: 

140 self.current_footprints = self.current_footprints/c_sum 

141 

142 def arr2struc(self, inarr): 

143 """take an array and convert it to labled struc array 

144 """ 

145 result = np.empty(self.npix, dtype=self.out_dtype) 

146 for key in self.filters: 

147 result[key] = inarr[self.filters[key]] 

148 # Argle bargel, why doesn't this view work? 

149 # struc = inarr.view(dtype=self.out_dtype).squeeze() 

150 return result 

151 

152 def estimate_counts(self, mjd, nvisits=2.2e6, fov_area=9.6): 

153 """Estimate the counts we'll get after some time and visits 

154 """ 

155 pix_area = hp.nside2pixarea(self.nside, degrees=True) 

156 pix_per_visit = fov_area/pix_area 

157 self._update_mjd(mjd, norm=True) 

158 self.estimate = self.current_footprints * pix_per_visit * nvisits 

159 return self.arr2struc(self.estimate) 

160 

161 def __call__(self, mjd, array=False, norm=True): 

162 """ 

163 Returns 

164 ------- 

165 a numpy array with the normalized number of observations that should be at each HEALpix. 

166 Multiply by the number of HEALpix observations (all filters), to convert to the number of observations 

167 desired. 

168 """ 

169 self._update_mjd(mjd, norm=norm) 

170 #if array: 

171 # return self.current_footprints 

172 #else: 

173 return self.arr2struc(self.current_footprints) 

174 

175 

176class Constant_footprint(Footprint): 

177 def __init__(self, nside=32, 

178 filters={'u': 0, 'g': 1, 'r': 2, 'i': 3, 'z': 4, 'y': 5}): 

179 self.nside = nside 

180 self.filters = filters 

181 self.npix = hp.nside2npix(nside) 

182 self.footprints = np.zeros((len(filters), self.npix), dtype=float) 

183 self.out_dtype = list(zip(filters, [float]*len(filters))) 

184 self.to_return = self.arr2struc(self.footprints) 

185 

186 def __call__(self, mjd, array=False): 

187 return self.to_return 

188 

189 

190 

191class Footprints(Footprint): 

192 """An object to combine multiple Footprint objects. 

193 """ 

194 def __init__(self, footprint_list): 

195 self.footprint_list = footprint_list 

196 self.mjd_current = None 

197 self.current_footprints = 0 

198 # Should probably run a check that all the footprints are compatible (same nside, etc) 

199 self.npix = footprint_list[0].npix 

200 self.out_dtype = footprint_list[0].out_dtype 

201 self.filters = footprint_list[0].filters 

202 self.nside = footprint_list[0].nside 

203 

204 self.footprints = np.zeros((len(self.filters), self.npix), dtype=float) 

205 for Fp in self.footprint_list: 

206 self.footprints += Fp.footprints 

207 

208 def set_footprint(self, filtername, values): 

209 pass 

210 

211 def _update_mjd(self, mjd, norm=True): 

212 if mjd != self.mjd_current: 

213 self.mjd_current = mjd 

214 self.current_footprints = 0. 

215 for fp in self.footprint_list: 

216 fp._update_mjd(mjd, norm=False) 

217 self.current_footprints += fp.current_footprints 

218 c_sum = np.sum(self.current_footprints) 

219 if norm: 

220 if c_sum != 0: 

221 self.current_footprints = self.current_footprints/c_sum 

222 

223 

224def ra_dec_hp_map(nside=None): 

225 """ 

226 Return all the RA,dec points for the centers of a healpix map, in radians. 

227 """ 

228 if nside is None: 

229 nside = set_default_nside() 

230 ra, dec = _hpid2RaDec(nside, np.arange(hp.nside2npix(nside))) 

231 return ra, dec 

232 

233 

234def get_dustmap(nside=None): 

235 if nside is None: 

236 nside = set_default_nside() 

237 ebvDataDir = getPackageDir('sims_maps') 

238 filename = 'DustMaps/dust_nside_%i.npz' % nside 

239 dustmap = np.load(os.path.join(ebvDataDir, filename))['ebvMap'] 

240 return dustmap 

241 

242 

243def generate_all_sky(nside=None, elevation_limit=20, mask=hp.UNSEEN): 

244 """Set up a healpix map over the entire sky. 

245 Calculate RA & Dec, Galactic l & b, Ecliptic l & b, for all healpixels. 

246 Calculate max altitude, to set to areas which LSST cannot reach (set these to hp.unseen). 

247 

248 This is intended to be a useful tool to use to set up target maps, beyond the standard maps 

249 provided in these utilities. Masking based on RA, Dec, Galactic or Ecliptic lat and lon is easier. 

250 

251 Parameters 

252 ---------- 

253 nside : int, opt 

254 Resolution for the healpix maps. 

255 Default None uses lsst.sims.featureScheduler.utils.set_default_nside to set default (often 32). 

256 elevation_limit : float, opt 

257 Elevation limit for map. 

258 Parts of the sky which do not reach this elevation limit will be set to mask. 

259 mask : float, opt 

260 Mask value for 'unreachable' parts of the sky, defined as elevation < 20. 

261 Note that the actual limits will be set elsewhere, using the observatory model. 

262 This limit is for use when understanding what the maps could look like. 

263 

264 Returns 

265 ------- 

266 dict of np.ndarray 

267 Returns map, RA/Dec, Gal l/b, Ecl l/b (each an np.ndarray IN RADIANS) in a dictionary. 

268 """ 

269 if nside is None: 

270 nside = set_default_nside() 

271 

272 # Calculate coordinates of everything. 

273 skymap = np.zeros(hp.nside2npix(nside), float) 

274 ra, dec = ra_dec_hp_map(nside=nside) 

275 coord = SkyCoord(ra=ra * u.rad, dec=dec * u.rad, frame='icrs') 

276 eclip_lat = coord.barycentrictrueecliptic.lat.deg 

277 eclip_lon = coord.barycentrictrueecliptic.lon.deg 

278 gal_lon = coord.galactic.l.deg 

279 gal_lat = coord.galactic.b.deg 

280 

281 # Calculate max altitude (when on meridian). 

282 lsst_site = Site('LSST') 

283 elev_max = np.pi / 2. - np.abs(dec - lsst_site.latitude_rad) 

284 skymap = np.where(int_rounded(elev_max) >= int_rounded(np.radians(elevation_limit), skymap, mask)) 

285 

286 return {'map': skymap, 'ra': np.degrees(ra), 'dec': np.degrees(dec), 

287 'eclip_lat': eclip_lat, 'eclip_lon': eclip_lon, 

288 'gal_lat': gal_lat, 'gal_lon': gal_lon} 

289 

290 

291def WFD_healpixels(nside=None, dec_min=-62.5, dec_max=3.6): 

292 """ 

293 Define a region based on declination limits only. 

294 

295 Parameters 

296 ---------- 

297 nside : int, opt 

298 Resolution for the healpix maps. 

299 Default None uses lsst.sims.featureScheduler.utils.set_default_nside to set default (often 32). 

300 dec_min : float, opt 

301 Minimum declination of the region (deg). Default -62.5. 

302 dec_max : float, opt 

303 Maximum declination of the region (deg). Default 3.6. 

304 

305 Returns 

306 ------- 

307 np.ndarray 

308 Healpix map with regions in declination-limited 'wfd' region as 1. 

309 """ 

310 if nside is None: 

311 nside = set_default_nside() 

312 

313 ra, dec = ra_dec_hp_map(nside=nside) 

314 result = np.zeros(ra.size, float) 

315 dec = int_rounded(dec) 

316 good = np.where((dec >= int_rounded(np.radians(dec_min))) & 

317 (dec <= int_rounded(np.radians(dec_max)))) 

318 result[good] = 1 

319 return result 

320 

321 

322def WFD_no_gp_healpixels(nside, dec_min=-62.5, dec_max=3.6, 

323 center_width=10., end_width=4., gal_long1=290., gal_long2=70.): 

324 """ 

325 Define a wide fast deep region with a galactic plane limit. 

326 

327 Parameters 

328 ---------- 

329 nside : int, opt 

330 Resolution for the healpix maps. 

331 Default None uses lsst.sims.featureScheduler.utils.set_default_nside to set default (often 32). 

332 dec_min : float, opt 

333 Minimum declination of the region (deg). 

334 dec_max : float, opt 

335 Maximum declination of the region (deg). 

336 center_width : float, opt 

337 Width across the central part of the galactic plane region. 

338 end_width : float, opt 

339 Width across the remainder of the galactic plane region. 

340 gal_long1 : float, opt 

341 Longitude at which to start tapering from center_width to end_width. 

342 gal_long2 : float, opt 

343 Longitude at which to stop tapering from center_width to end_width. 

344 

345 Returns 

346 ------- 

347 np.ndarray 

348 Healpix map with regions in declination-limited 'wfd' region as 1. 

349 """ 

350 wfd_dec = WFD_healpixels(nside, dec_min=dec_min, dec_max=dec_max) 

351 gp = galactic_plane_healpixels(nside=nside, center_width=center_width, end_width=end_width, 

352 gal_long1=gal_long1, gal_long2=gal_long2) 

353 sky = np.where(wfd_dec - gp > 0, wfd_dec - gp, 0) 

354 return sky 

355 

356 

357def WFD_bigsky_healpixels(nside): 

358 sky = WFD_no_gp_healpixels(nside, dec_min=-72.25, dec_max=12.4, center_width=14.9, 

359 gal_long1=0, gal_long2=360) 

360 return sky 

361 

362 

363def WFD_no_dust_healpixels(nside, dec_min=-72.25, dec_max=12.4, dust_limit=0.19): 

364 """Define a WFD region with a dust extinction limit. 

365 

366 Parameters 

367 ---------- 

368 nside : int, opt 

369 Resolution for the healpix maps. 

370 Default None uses lsst.sims.featureScheduler.utils.set_default_nside to set default (often 32). 

371 dec_min : float, opt 

372 Minimum dec of the region (deg). Default -72.5 deg. 

373 dec_max : float, opt. 

374 Maximum dec of the region (deg). Default 12.5 deg. 

375 1.75 is the FOV radius in deg. 

376 dust_limit : float, None 

377 Remove pixels with E(B-V) values greater than dust_limit from the footprint. 

378 

379 Returns 

380 ------- 

381 result : numpy array 

382 """ 

383 if nside is None: 

384 nside = set_default_nside() 

385 

386 ra, dec = ra_dec_hp_map(nside=nside) 

387 dustmap = get_dustmap(nside) 

388 

389 result = np.zeros(ra.size, float) 

390 # First set based on dec range. 

391 dec = int_rounded(dec) 

392 good = np.where((dec >= int_rounded(np.radians(dec_min))) & 

393 (dec <= int_rounded(np.radians(dec_max)))) 

394 result[good] = 1 

395 # Now remove areas with dust extinction beyond the limit. 

396 result = np.where(dustmap >= dust_limit, 0, result) 

397 return result 

398 

399 

400def SCP_healpixels(nside=None, dec_max=-60.): 

401 """ 

402 Define the South Celestial Pole region. Return a healpix map with SCP pixels as 1. 

403 """ 

404 if nside is None: 

405 nside = set_default_nside() 

406 

407 ra, dec = ra_dec_hp_map(nside=nside) 

408 result = np.zeros(ra.size, float) 

409 good = np.where(int_rounded(dec) < int_rounded(np.radians(dec_max))) 

410 result[good] = 1 

411 return result 

412 

413 

414def NES_healpixels(nside=None, min_EB=-30.0, max_EB = 10.0, dec_min=2.8): 

415 """ 

416 Define the North Ecliptic Spur region. Return a healpix map with NES pixels as 1. 

417 

418 Parameters 

419 ---------- 

420 nside : int 

421 A valid healpix nside 

422 min_EB : float (-30.) 

423 Minimum barycentric true ecliptic latitude (deg) 

424 max_EB : float (10.) 

425 Maximum barycentric true ecliptic latitude (deg) 

426 dec_min : float (2.8) 

427 Minimum dec in degrees 

428 

429 Returns 

430 ------- 

431 result : numpy array 

432 """ 

433 if nside is None: 

434 nside = set_default_nside() 

435 

436 ra, dec = ra_dec_hp_map(nside=nside) 

437 result = np.zeros(ra.size, float) 

438 coord = SkyCoord(ra=ra*u.rad, dec=dec*u.rad) 

439 eclip_lat = coord.barycentrictrueecliptic.lat.radian 

440 eclip_lat = int_rounded(eclip_lat) 

441 dec = int_rounded(dec) 

442 good = np.where((eclip_lat > int_rounded(np.radians(min_EB))) & 

443 (eclip_lat < int_rounded(np.radians(max_EB))) & 

444 (dec > int_rounded(np.radians(dec_min)))) 

445 result[good] = 1 

446 

447 return result 

448 

449 

450def galactic_plane_healpixels(nside=None, center_width=10., end_width=4., 

451 gal_long1=290., gal_long2=70.): 

452 """ 

453 Define a Galactic Plane region. 

454 

455 Parameters 

456 ---------- 

457 nside : int, opt 

458 Resolution for the healpix maps. 

459 Default None uses lsst.sims.featureScheduler.utils.set_default_nside to set default (often 32). 

460 center_width : float, opt 

461 Width at the center of the galactic plane region. 

462 end_width : float, opt 

463 Width at the remainder of the galactic plane region. 

464 gal_long1 : float, opt 

465 Longitude at which to start the GP region. 

466 gal_long2 : float, opt 

467 Longitude at which to stop the GP region. 

468 Order matters for gal_long1 / gal_long2! 

469 

470 Returns 

471 ------- 

472 np.ndarray 

473 Healpix map with galactic plane regions set to 1. 

474 """ 

475 if nside is None: 

476 nside = set_default_nside() 

477 ra, dec = ra_dec_hp_map(nside=nside) 

478 

479 coord = SkyCoord(ra=ra*u.rad, dec=dec*u.rad) 

480 gal_lon, gal_lat = coord.galactic.l.deg, coord.galactic.b.deg 

481 # Reject anything beyond the central width. 

482 sky = np.where(np.abs(gal_lat) < center_width, 1, 0) 

483 # Apply the galactic longitude cuts, so that plane goes between gal_long1 to gal_long2. 

484 # This is NOT the shortest distance between the angles. 

485 gp_length = (gal_long2 - gal_long1) % 360 

486 # If the length is greater than 0 then we can add additional cuts. 

487 if gp_length > 0: 

488 # First, remove anything outside the gal_long1/gal_long2 region. 

489 sky = np.where(int_rounded((gal_lon - gal_long1) % 360) < int_rounded(gp_length), sky, 0) 

490 # Add the tapers. 

491 # These slope from the center (gp_center @ center_width) 

492 # to the edge (gp_center + gp_length/2 @ end_width). 

493 half_width = gp_length / 2. 

494 slope = (center_width - end_width) / half_width 

495 gp_center = (gal_long1 + half_width) % 360 

496 gp_dist = gal_lon - gp_center 

497 gp_dist = np.abs(np.where(int_rounded(gp_dist) > int_rounded(180), (180 - gp_dist) % 180, gp_dist)) 

498 lat_limit = np.abs(center_width - slope * gp_dist) 

499 sky = np.where(int_rounded(np.abs(gal_lat)) < int_rounded(lat_limit), sky, 0) 

500 return sky 

501 

502 

503def magellanic_clouds_healpixels(nside=None, lmc_radius=10, smc_radius=5): 

504 """ 

505 Define the Galactic Plane region. Return a healpix map with GP pixels as 1. 

506 """ 

507 if nside is None: 

508 nside = set_default_nside() 

509 ra, dec = ra_dec_hp_map(nside=nside) 

510 result = np.zeros(hp.nside2npix(nside)) 

511 

512 lmc_ra = np.radians(80.893860) 

513 lmc_dec = np.radians(-69.756126) 

514 lmc_radius = np.radians(lmc_radius) 

515 

516 smc_ra = np.radians(13.186588) 

517 smc_dec = np.radians(-72.828599) 

518 smc_radius = np.radians(smc_radius) 

519 

520 dist_to_lmc = _angularSeparation(lmc_ra, lmc_dec, ra, dec) 

521 lmc_pix = np.where(int_rounded(dist_to_lmc) < int_rounded(lmc_radius)) 

522 result[lmc_pix] = 1 

523 

524 dist_to_smc = _angularSeparation(smc_ra, smc_dec, ra, dec) 

525 smc_pix = np.where(int_rounded(dist_to_smc) < int_rounded(smc_radius)) 

526 result[smc_pix] = 1 

527 return result 

528 

529 

530def generate_goal_map(nside=None, NES_fraction = .3, WFD_fraction = 1., 

531 SCP_fraction=0.4, GP_fraction = 0.2, 

532 NES_min_EB = -30., NES_max_EB = 10, NES_dec_min = 3.6, 

533 SCP_dec_max=-62.5, gp_center_width=10., 

534 gp_end_width=4., gp_long1=290., gp_long2=70., 

535 wfd_dec_min=-62.5, wfd_dec_max=3.6, 

536 generate_id_map=False): 

537 """ 

538 Handy function that will put together a target map in the proper order. 

539 """ 

540 if nside is None: 

541 nside = set_default_nside() 

542 

543 # Note, some regions overlap, thus order regions are added is important. 

544 result = np.zeros(hp.nside2npix(nside), dtype=float) 

545 id_map = np.zeros(hp.nside2npix(nside), dtype=int) 

546 pid = 1 

547 prop_name_dict = dict() 

548 

549 if NES_fraction > 0.: 

550 nes = NES_healpixels(nside=nside, min_EB = NES_min_EB, max_EB = NES_max_EB, 

551 dec_min=NES_dec_min) 

552 result[np.where(nes != 0)] = 0 

553 result += NES_fraction*nes 

554 id_map[np.where(nes != 0)] = 1 

555 pid += 1 

556 prop_name_dict[1] = 'NorthEclipticSpur' 

557 

558 if WFD_fraction > 0.: 

559 wfd = WFD_healpixels(nside=nside, dec_min=wfd_dec_min, dec_max=wfd_dec_max) 

560 result[np.where(wfd != 0)] = 0 

561 result += WFD_fraction*wfd 

562 id_map[np.where(wfd != 0)] = 3 

563 pid += 1 

564 prop_name_dict[3] = 'WideFastDeep' 

565 

566 if SCP_fraction > 0.: 

567 scp = SCP_healpixels(nside=nside, dec_max=SCP_dec_max) 

568 result[np.where(scp != 0)] = 0 

569 result += SCP_fraction*scp 

570 id_map[np.where(scp != 0)] = 2 

571 pid += 1 

572 prop_name_dict[2] = 'SouthCelestialPole' 

573 

574 if GP_fraction > 0.: 

575 gp = galactic_plane_healpixels(nside=nside, center_width=gp_center_width, 

576 end_width=gp_end_width, gal_long1=gp_long1, 

577 gal_long2=gp_long2) 

578 result[np.where(gp != 0)] = 0 

579 result += GP_fraction*gp 

580 id_map[np.where(gp != 0)] = 4 

581 pid += 1 

582 prop_name_dict[4] = 'GalacticPlane' 

583 

584 if generate_id_map: 

585 return result, id_map, prop_name_dict 

586 else: 

587 return result 

588 

589 

590def standard_goals(nside=None): 

591 """ 

592 A quick function to generate the "standard" goal maps. This is the traditional WFD/mini survey footprint. 

593 """ 

594 if nside is None: 

595 nside = set_default_nside() 

596 

597 result = {} 

598 result['u'] = generate_goal_map(nside=nside, NES_fraction=0., 

599 WFD_fraction=0.31, SCP_fraction=0.15, 

600 GP_fraction=0.15, 

601 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

602 result['g'] = generate_goal_map(nside=nside, NES_fraction=0.2, 

603 WFD_fraction=0.44, SCP_fraction=0.15, 

604 GP_fraction=0.15, 

605 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

606 result['r'] = generate_goal_map(nside=nside, NES_fraction=0.46, 

607 WFD_fraction=1.0, SCP_fraction=0.15, 

608 GP_fraction=0.15, 

609 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

610 result['i'] = generate_goal_map(nside=nside, NES_fraction=0.46, 

611 WFD_fraction=1.0, SCP_fraction=0.15, 

612 GP_fraction=0.15, 

613 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

614 result['z'] = generate_goal_map(nside=nside, NES_fraction=0.4, 

615 WFD_fraction=0.9, SCP_fraction=0.15, 

616 GP_fraction=0.15, 

617 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

618 result['y'] = generate_goal_map(nside=nside, NES_fraction=0., 

619 WFD_fraction=0.9, SCP_fraction=0.15, 

620 GP_fraction=0.15, 

621 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

622 return result 

623 

624 

625def calc_norm_factor(goal_dict, radius=1.75): 

626 """Calculate how to normalize a Target_map_basis_function. 

627 This is basically: 

628 the area of the fov / area of a healpixel / 

629 the sum of all of the weighted-healpix values in the footprint. 

630 

631 Parameters 

632 ----------- 

633 goal_dict : dict of healpy maps 

634 The target goal map(s) being used 

635 radius : float (1.75) 

636 Radius of the FoV (degrees) 

637 

638 Returns 

639 ------- 

640 Value to use as Target_map_basis_function norm_factor kwarg 

641 """ 

642 all_maps_sum = 0 

643 for key in goal_dict: 

644 good = np.where(goal_dict[key] > 0) 

645 all_maps_sum += goal_dict[key][good].sum() 

646 nside = hp.npix2nside(goal_dict[key].size) 

647 hp_area = hp.nside2pixarea(nside, degrees=True) 

648 norm_val = radius**2*np.pi/hp_area/all_maps_sum 

649 return norm_val 

650 

651 

652def filter_count_ratios(target_maps): 

653 """Given the goal maps, compute the ratio of observations we want in each filter. 

654 This is basically: 

655 per filter, sum the number of pixels in each map and return this per filter value, normalized 

656 so that the total sum across all filters is 1. 

657 """ 

658 results = {} 

659 all_norm = 0. 

660 for key in target_maps: 

661 good = target_maps[key] > 0 

662 results[key] = np.sum(target_maps[key][good]) 

663 all_norm += results[key] 

664 for key in results: 

665 results[key] /= all_norm 

666 return results