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'] 

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) 

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 max_coverage = np.max(norm_coverage) 

137 if max_coverage != 0: 

138 norm_coverage = norm_coverage/max_coverage 

139 self.current_footprints = self.footprints * norm_coverage 

140 c_sum = np.sum(self.current_footprints) 

141 if norm: 

142 if c_sum != 0: 

143 self.current_footprints = self.current_footprints/c_sum 

144 

145 def arr2struc(self, inarr): 

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

147 """ 

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

149 for key in self.filters: 

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

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

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

153 return result 

154 

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

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

157 """ 

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

159 pix_per_visit = fov_area/pix_area 

160 self._update_mjd(mjd, norm=True) 

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

162 return self.arr2struc(self.estimate) 

163 

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

165 """ 

166 Returns 

167 ------- 

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

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

170 desired. 

171 """ 

172 self._update_mjd(mjd) 

173 #if array: 

174 # return self.current_footprints 

175 #else: 

176 return self.arr2struc(self.current_footprints) 

177 

178 

179class Constant_footprint(Footprint): 

180 def __init__(self, nside=32, 

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

182 self.nside = nside 

183 self.filters = filters 

184 self.npix = hp.nside2npix(nside) 

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

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

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

188 

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

190 return self.to_return 

191 

192 

193 

194class Footprints(Footprint): 

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

196 """ 

197 def __init__(self, footprint_list): 

198 self.footprint_list = footprint_list 

199 self.mjd_current = None 

200 self.current_footprints = 0 

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

202 self.npix = footprint_list[0].npix 

203 self.out_dtype = footprint_list[0].out_dtype 

204 self.filters = footprint_list[0].filters 

205 self.nside = footprint_list[0].nside 

206 

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

208 for Fp in self.footprint_list: 

209 self.footprints += Fp.footprints 

210 

211 def set_footprint(self, filtername, values): 

212 pass 

213 

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

215 if mjd != self.mjd_current: 

216 self.mjd_current = mjd 

217 self.current_footprints = 0. 

218 for fp in self.footprint_list: 

219 fp._update_mjd(mjd, norm=False) 

220 self.current_footprints += fp.current_footprints 

221 c_sum = np.sum(self.current_footprints) 

222 if norm: 

223 if c_sum != 0: 

224 self.current_footprints = self.current_footprints/c_sum 

225 

226 

227def ra_dec_hp_map(nside=None): 

228 """ 

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

230 """ 

231 if nside is None: 

232 nside = set_default_nside() 

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

234 return ra, dec 

235 

236 

237def get_dustmap(nside=None): 

238 if nside is None: 

239 nside = set_default_nside() 

240 ebvDataDir = getPackageDir('sims_maps') 

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

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

243 return dustmap 

244 

245 

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

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

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

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

250 

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

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

253 

254 Parameters 

255 ---------- 

256 nside : int, opt 

257 Resolution for the healpix maps. 

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

259 elevation_limit : float, opt 

260 Elevation limit for map. 

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

262 mask : float, opt 

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

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

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

266 

267 Returns 

268 ------- 

269 dict of np.ndarray 

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

271 """ 

272 if nside is None: 

273 nside = set_default_nside() 

274 

275 # Calculate coordinates of everything. 

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

277 ra, dec = ra_dec_hp_map(nside=nside) 

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

279 eclip_lat = coord.barycentrictrueecliptic.lat.deg 

280 eclip_lon = coord.barycentrictrueecliptic.lon.deg 

281 gal_lon = coord.galactic.l.deg 

282 gal_lat = coord.galactic.b.deg 

283 

284 # Calculate max altitude (when on meridian). 

285 lsst_site = Site('LSST') 

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

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

288 

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

290 'eclip_lat': eclip_lat, 'eclip_lon': eclip_lon, 

291 'gal_lat': gal_lat, 'gal_lon': gal_lon} 

292 

293 

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

295 """ 

296 Define a region based on declination limits only. 

297 

298 Parameters 

299 ---------- 

300 nside : int, opt 

301 Resolution for the healpix maps. 

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

303 dec_min : float, opt 

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

305 dec_max : float, opt 

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

307 

308 Returns 

309 ------- 

310 np.ndarray 

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

312 """ 

313 if nside is None: 

314 nside = set_default_nside() 

315 

316 ra, dec = ra_dec_hp_map(nside=nside) 

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

318 dec = int_rounded(dec) 

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

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

321 result[good] = 1 

322 return result 

323 

324 

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

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

327 """ 

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

329 

330 Parameters 

331 ---------- 

332 nside : int, opt 

333 Resolution for the healpix maps. 

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

335 dec_min : float, opt 

336 Minimum declination of the region (deg). 

337 dec_max : float, opt 

338 Maximum declination of the region (deg). 

339 center_width : float, opt 

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

341 end_width : float, opt 

342 Width across the remainder of the galactic plane region. 

343 gal_long1 : float, opt 

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

345 gal_long2 : float, opt 

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

347 

348 Returns 

349 ------- 

350 np.ndarray 

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

352 """ 

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

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

355 gal_long1=gal_long1, gal_long2=gal_long2) 

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

357 return sky 

358 

359 

360def WFD_bigsky_healpixels(nside): 

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

362 gal_long1=0, gal_long2=360) 

363 return sky 

364 

365 

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

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

368 

369 Parameters 

370 ---------- 

371 nside : int, opt 

372 Resolution for the healpix maps. 

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

374 dec_min : float, opt 

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

376 dec_max : float, opt. 

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

378 1.75 is the FOV radius in deg. 

379 dust_limit : float, None 

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

381 

382 Returns 

383 ------- 

384 result : numpy array 

385 """ 

386 if nside is None: 

387 nside = set_default_nside() 

388 

389 ra, dec = ra_dec_hp_map(nside=nside) 

390 dustmap = get_dustmap(nside) 

391 

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

393 # First set based on dec range. 

394 dec = int_rounded(dec) 

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

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

397 result[good] = 1 

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

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

400 return result 

401 

402 

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

404 """ 

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

406 """ 

407 if nside is None: 

408 nside = set_default_nside() 

409 

410 ra, dec = ra_dec_hp_map(nside=nside) 

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

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

413 result[good] = 1 

414 return result 

415 

416 

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

418 """ 

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

420 

421 Parameters 

422 ---------- 

423 nside : int 

424 A valid healpix nside 

425 min_EB : float (-30.) 

426 Minimum barycentric true ecliptic latitude (deg) 

427 max_EB : float (10.) 

428 Maximum barycentric true ecliptic latitude (deg) 

429 dec_min : float (2.8) 

430 Minimum dec in degrees 

431 

432 Returns 

433 ------- 

434 result : numpy array 

435 """ 

436 if nside is None: 

437 nside = set_default_nside() 

438 

439 ra, dec = ra_dec_hp_map(nside=nside) 

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

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

442 eclip_lat = coord.barycentrictrueecliptic.lat.radian 

443 eclip_lat = int_rounded(eclip_lat) 

444 dec = int_rounded(dec) 

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

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

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

448 result[good] = 1 

449 

450 return result 

451 

452 

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

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

455 """ 

456 Define a Galactic Plane region. 

457 

458 Parameters 

459 ---------- 

460 nside : int, opt 

461 Resolution for the healpix maps. 

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

463 center_width : float, opt 

464 Width at the center of the galactic plane region. 

465 end_width : float, opt 

466 Width at the remainder of the galactic plane region. 

467 gal_long1 : float, opt 

468 Longitude at which to start the GP region. 

469 gal_long2 : float, opt 

470 Longitude at which to stop the GP region. 

471 Order matters for gal_long1 / gal_long2! 

472 

473 Returns 

474 ------- 

475 np.ndarray 

476 Healpix map with galactic plane regions set to 1. 

477 """ 

478 if nside is None: 

479 nside = set_default_nside() 

480 ra, dec = ra_dec_hp_map(nside=nside) 

481 

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

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

484 # Reject anything beyond the central width. 

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

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

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

488 gp_length = (gal_long2 - gal_long1) % 360 

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

490 if gp_length > 0: 

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

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

493 # Add the tapers. 

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

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

496 half_width = gp_length / 2. 

497 slope = (center_width - end_width) / half_width 

498 gp_center = (gal_long1 + half_width) % 360 

499 gp_dist = gal_lon - gp_center 

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

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

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

503 return sky 

504 

505 

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

507 """ 

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

509 """ 

510 if nside is None: 

511 nside = set_default_nside() 

512 ra, dec = ra_dec_hp_map(nside=nside) 

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

514 

515 lmc_ra = np.radians(80.893860) 

516 lmc_dec = np.radians(-69.756126) 

517 lmc_radius = np.radians(lmc_radius) 

518 

519 smc_ra = np.radians(13.186588) 

520 smc_dec = np.radians(-72.828599) 

521 smc_radius = np.radians(smc_radius) 

522 

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

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

525 result[lmc_pix] = 1 

526 

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

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

529 result[smc_pix] = 1 

530 return result 

531 

532 

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

534 SCP_fraction=0.4, GP_fraction = 0.2, 

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

536 SCP_dec_max=-62.5, gp_center_width=10., 

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

538 wfd_dec_min=-62.5, wfd_dec_max=3.6, 

539 generate_id_map=False): 

540 """ 

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

542 """ 

543 if nside is None: 

544 nside = set_default_nside() 

545 

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

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

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

549 pid = 1 

550 prop_name_dict = dict() 

551 

552 if NES_fraction > 0.: 

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

554 dec_min=NES_dec_min) 

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

556 result += NES_fraction*nes 

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

558 pid += 1 

559 prop_name_dict[1] = 'NorthEclipticSpur' 

560 

561 if WFD_fraction > 0.: 

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

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

564 result += WFD_fraction*wfd 

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

566 pid += 1 

567 prop_name_dict[3] = 'WideFastDeep' 

568 

569 if SCP_fraction > 0.: 

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

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

572 result += SCP_fraction*scp 

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

574 pid += 1 

575 prop_name_dict[2] = 'SouthCelestialPole' 

576 

577 if GP_fraction > 0.: 

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

579 end_width=gp_end_width, gal_long1=gp_long1, 

580 gal_long2=gp_long2) 

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

582 result += GP_fraction*gp 

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

584 pid += 1 

585 prop_name_dict[4] = 'GalacticPlane' 

586 

587 if generate_id_map: 

588 return result, id_map, prop_name_dict 

589 else: 

590 return result 

591 

592 

593def standard_goals(nside=None): 

594 """ 

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

596 """ 

597 if nside is None: 

598 nside = set_default_nside() 

599 

600 result = {} 

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

602 WFD_fraction=0.31, SCP_fraction=0.15, 

603 GP_fraction=0.15, 

604 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

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

606 WFD_fraction=0.44, SCP_fraction=0.15, 

607 GP_fraction=0.15, 

608 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

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

610 WFD_fraction=1.0, SCP_fraction=0.15, 

611 GP_fraction=0.15, 

612 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

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

614 WFD_fraction=1.0, SCP_fraction=0.15, 

615 GP_fraction=0.15, 

616 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

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

618 WFD_fraction=0.9, SCP_fraction=0.15, 

619 GP_fraction=0.15, 

620 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

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

622 WFD_fraction=0.9, SCP_fraction=0.15, 

623 GP_fraction=0.15, 

624 wfd_dec_min=-62.5, wfd_dec_max=3.6) 

625 return result 

626 

627 

628def calc_norm_factor(goal_dict, radius=1.75): 

629 """Calculate how to normalize a Target_map_basis_function. 

630 This is basically: 

631 the area of the fov / area of a healpixel / 

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

633 

634 Parameters 

635 ----------- 

636 goal_dict : dict of healpy maps 

637 The target goal map(s) being used 

638 radius : float (1.75) 

639 Radius of the FoV (degrees) 

640 

641 Returns 

642 ------- 

643 Value to use as Target_map_basis_function norm_factor kwarg 

644 """ 

645 all_maps_sum = 0 

646 for key in goal_dict: 

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

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

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

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

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

652 return norm_val 

653 

654 

655def filter_count_ratios(target_maps): 

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

657 This is basically: 

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

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

660 """ 

661 results = {} 

662 all_norm = 0. 

663 for key in target_maps: 

664 good = target_maps[key] > 0 

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

666 all_norm += results[key] 

667 for key in results: 

668 results[key] /= all_norm 

669 return results