Coverage for metadetect / tests / test_masking.py: 8%

293 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-28 09:05 +0000

1import numpy as np 

2import ngmix 

3 

4import pytest 

5 

6from metadetect.masking import ( 

7 _intersects, 

8 _ap_kern_kern, 

9 _do_apodization_mask, 

10 make_foreground_apodization_mask, 

11 _do_mask_foreground, 

12 make_foreground_bmask, 

13 apply_foreground_masking_corrections, 

14 _build_square_apodization_mask, 

15 apply_apodization_corrections, 

16) 

17 

18 

19def test_apply_apodization_corrections(): 

20 nband = 2 

21 seed = 10 

22 dims = (13, 13) 

23 

24 mbobs = ngmix.MultiBandObsList() 

25 rng = np.random.RandomState(seed=seed) 

26 for _ in range(nband): 

27 image = rng.uniform(size=dims) 

28 noise = rng.uniform(size=dims) 

29 obs = ngmix.Observation( 

30 image=image, 

31 noise=noise, 

32 weight=rng.uniform(size=dims), 

33 bmask=np.zeros(dims, dtype=np.int32), 

34 ormask=np.zeros(dims, dtype=np.int32), 

35 ) 

36 obs.mfrac = rng.uniform(size=dims) 

37 obslist = ngmix.ObsList() 

38 obslist.append(obs) 

39 mbobs.append(obslist) 

40 

41 apply_apodization_corrections( 

42 mbobs=mbobs, 

43 mask_bit_val=2**3, 

44 ap_rad=1, 

45 ) 

46 

47 rng = np.random.RandomState(seed=seed) 

48 for obslist in mbobs: 

49 for obs in obslist: 

50 msk = (obs.bmask & 2**3) != 0 

51 image = rng.uniform(size=dims) 

52 noise = rng.uniform(size=dims) 

53 # we need to match these calls to the ones above 

54 rng.uniform(size=dims) 

55 rng.uniform(size=dims) 

56 

57 assert np.all(obs.mfrac[msk] == 1) 

58 assert np.all(obs.weight[msk] == 0) 

59 

60 assert np.all(image[msk] != obs.image[msk]) 

61 assert np.all(image[~msk] == obs.image[~msk]) 

62 assert np.all(noise[msk] != obs.noise[msk]) 

63 assert np.all(noise[~msk] == obs.noise[~msk]) 

64 

65 

66def test_apply_apodization_corrections_all(): 

67 nband = 2 

68 seed = 10 

69 dims = (13, 13) 

70 mbobs = ngmix.MultiBandObsList() 

71 rng = np.random.RandomState(seed=seed) 

72 for _ in range(nband): 

73 image = rng.uniform(size=dims) 

74 noise = rng.uniform(size=dims) 

75 obs = ngmix.Observation( 

76 image=image, 

77 noise=noise, 

78 weight=rng.uniform(size=dims), 

79 bmask=np.zeros(dims, dtype=np.int32), 

80 ormask=np.zeros(dims, dtype=np.int32), 

81 ) 

82 obs.mfrac = rng.uniform(size=dims) 

83 obslist = ngmix.ObsList() 

84 obslist.append(obs) 

85 mbobs.append(obslist) 

86 

87 apply_apodization_corrections( 

88 mbobs=mbobs, 

89 mask_bit_val=2**3, 

90 ap_rad=4, 

91 ) 

92 

93 rng = np.random.RandomState(seed=seed) 

94 for obslist in mbobs: 

95 for obs in obslist: 

96 assert np.all((obs.bmask & 2**3) != 0) 

97 

98 

99@pytest.mark.parametrize("ap_rad", [0.5, 1, 1.2]) 

100def test_build_square_apodization_mask(ap_rad): 

101 dim = 100 

102 ap_mask = np.ones((dim, dim)) 

103 _build_square_apodization_mask(ap_rad, ap_mask) 

104 

105 ap_range = int(6*ap_rad + 0.5) 

106 assert np.all(ap_mask[0:ap_range, :] < 1.0) 

107 assert np.all(ap_mask[-ap_range:, :] < 1.0) 

108 assert np.all(ap_mask[:, 0:ap_range] < 1.0) 

109 assert np.all(ap_mask[:, -ap_range:] < 1.0) 

110 

111 assert np.all(ap_mask[ap_range, ap_range:-ap_range] == 1.0) 

112 assert np.all(ap_mask[-ap_range-1, ap_range:-ap_range] == 1.0) 

113 assert np.all(ap_mask[ap_range:-ap_range, ap_range] == 1.0) 

114 assert np.all(ap_mask[ap_range:-ap_range, -ap_range-1] == 1.0) 

115 

116 if False: 

117 import matplotlib.pyplot as plt 

118 plt.figure() 

119 plt.imshow(ap_mask) 

120 import pdb 

121 pdb.set_trace() 

122 

123 

124def test_build_square_apodization_mask_all(): 

125 dim = 13 

126 ap_mask = np.ones((dim, dim)) 

127 _build_square_apodization_mask(4, ap_mask) 

128 

129 assert np.all(ap_mask < 1.0) 

130 

131 

132@pytest.mark.parametrize('row,col,radius_pixels,nrows,ncols,yes', [ 

133 # basic 

134 (0, 0, 10, 10, 10, True), 

135 (-1000, 0, 10, 10, 10, False), 

136 (1000, 0, 10, 10, 10, False), 

137 (0, -1000, 10, 10, 10, False), 

138 (0, 1000, 10, 10, 10, False), 

139 # edge cases 

140 (-10, 0, 10, 10, 10, False), 

141 (19, 0, 10, 10, 10, False), 

142 (0, -10, 10, 10, 10, False), 

143 (0, 19, 10, 10, 10, False), 

144 # partial 

145 (2, 5, 10, 7, 7, True), 

146]) 

147def test_intersects(row, col, radius_pixels, nrows, ncols, yes): 

148 if yes: 

149 assert _intersects(row, col, radius_pixels, nrows, ncols) 

150 else: 

151 assert not _intersects(row, col, radius_pixels, nrows, ncols) 

152 

153 

154@pytest.mark.parametrize("fac,val", [ 

155 (1, 1), 

156 (0, 1), 

157 (-3, 0.5), 

158 (-6, 0), 

159 (-7, 0), 

160]) 

161def test_ap_kern_kern(fac, val): 

162 h = 2.0 

163 m = 10.0 

164 assert np.allclose(_ap_kern_kern(m + fac*h, m, h), val) 

165 

166 

167def test_do_apodization_mask_all_masked(): 

168 ap_mask = np.ones((10, 13)) 

169 rows = np.array([0, 3]) 

170 cols = rows = np.array([0, 5]) 

171 radius_pixels = np.array([100, 10]) 

172 

173 _do_apodization_mask( 

174 rows=rows, 

175 cols=cols, 

176 radius_pixels=radius_pixels, 

177 ap_mask=ap_mask, 

178 ap_rad=1.5, 

179 ) 

180 

181 assert np.all(ap_mask == 0) 

182 

183 

184def test_do_apodization_mask_half_masked(): 

185 ap_mask = np.ones((10, 13)) 

186 rows = np.array([0]) 

187 cols = np.array([6]) 

188 radius_pixels = np.array([5]) 

189 

190 _do_apodization_mask( 

191 rows=rows, 

192 cols=cols, 

193 radius_pixels=radius_pixels, 

194 ap_mask=ap_mask, 

195 ap_rad=0.1, 

196 ) 

197 

198 assert np.all(ap_mask[6:, :] == 1) 

199 assert not np.all(ap_mask[:6, :] == 1) 

200 assert np.all(ap_mask[0:2, 6:8] == 0) 

201 

202 if False: 

203 import matplotlib.pyplot as plt 

204 plt.figure() 

205 plt.pcolormesh(ap_mask) 

206 import pdb 

207 pdb.set_trace() 

208 

209 

210def test_make_foreground_apodization_mask(): 

211 ap_mask = make_foreground_apodization_mask( 

212 xm=np.array([6], dtype='f8'), 

213 ym=np.array([0], dtype='f8'), 

214 rm=np.array([5], dtype='f8'), 

215 dims=(10, 13), 

216 symmetrize=False, 

217 ap_rad=0.1 

218 ) 

219 

220 assert np.all(ap_mask[6:, :] == 1) 

221 assert not np.all(ap_mask[:6, :] == 1) 

222 assert np.all(ap_mask[0:2, 6:8] == 0) 

223 

224 

225def test_make_foreground_apodization_mask_symmetrize(): 

226 ap_mask = make_foreground_apodization_mask( 

227 xm=np.array([6], dtype='f8'), 

228 ym=np.array([0], dtype='f8'), 

229 rm=np.array([5], dtype='f8'), 

230 dims=(10, 10), 

231 symmetrize=False, 

232 ap_rad=0.1 

233 ) 

234 

235 ap_mask_sym = make_foreground_apodization_mask( 

236 xm=np.array([6], dtype='f8'), 

237 ym=np.array([0], dtype='f8'), 

238 rm=np.array([5], dtype='f8'), 

239 dims=(10, 10), 

240 symmetrize=True, 

241 ap_rad=0.1 

242 ) 

243 

244 msk = ap_mask == 0 

245 assert np.allclose(ap_mask[msk], ap_mask_sym[msk]) 

246 

247 msk = ap_mask_sym == 1 

248 assert np.allclose(ap_mask[msk], ap_mask_sym[msk]) 

249 

250 rot_ap_mask = np.rot90(ap_mask) 

251 msk = rot_ap_mask == 0 

252 assert np.allclose(ap_mask_sym[msk], rot_ap_mask[msk]) 

253 

254 assert np.all(ap_mask[0:2, 6:8] == 0) 

255 

256 if False: 

257 import matplotlib.pyplot as plt 

258 plt.figure() 

259 plt.pcolormesh(ap_mask_sym) 

260 import pdb 

261 pdb.set_trace() 

262 

263 

264def test_do_mask_foreground_all_masked(): 

265 flag = 2**5 

266 bmask = np.zeros((10, 13), dtype=np.int32) 

267 rows = np.array([0, 3]) 

268 cols = rows = np.array([0, 5]) 

269 radius_pixels = np.array([100, 10]) 

270 bmask[4, 5] |= 2**3 

271 

272 _do_mask_foreground( 

273 rows=rows, 

274 cols=cols, 

275 radius_pixels=radius_pixels, 

276 bmask=bmask, 

277 flag=flag, 

278 ) 

279 

280 assert np.all((bmask & flag) != 0) 

281 assert (bmask[4, 5] & 2**3) != 0 

282 assert (bmask[1, 2] & 2**3) == 0 

283 

284 

285def test_do_mask_foreground_half_masked(): 

286 flag = 2**5 

287 bmask = np.zeros((10, 13), dtype=np.int32) 

288 rows = np.array([0]) 

289 cols = np.array([6]) 

290 radius_pixels = np.array([5]) 

291 bmask[4, 5] |= 2**3 

292 

293 _do_mask_foreground( 

294 rows=rows, 

295 cols=cols, 

296 radius_pixels=radius_pixels, 

297 bmask=bmask, 

298 flag=flag, 

299 ) 

300 

301 assert np.all((bmask[6:, 6:] & flag) == 0) 

302 assert np.all((bmask[0:2, 6:8] & flag) != 0) 

303 assert (bmask[4, 5] & 2**3) != 0 

304 assert (bmask[1, 2] & 2**3) == 0 

305 

306 

307def test_make_foreground_bmask(): 

308 flag = 2**7 

309 

310 bmask = make_foreground_bmask( 

311 xm=np.array([6], dtype='f8'), 

312 ym=np.array([0], dtype='f8'), 

313 rm=np.array([5], dtype='f8'), 

314 dims=(10, 13), 

315 symmetrize=False, 

316 mask_bit_val=flag, 

317 ) 

318 

319 assert np.all((bmask[6:, 6:] & flag) == 0) 

320 assert np.all((bmask[0:2, 6:8] & flag) != 0) 

321 

322 

323def test_make_foreground_bmask_symmetrize(): 

324 flag = 2**9 

325 

326 bmask = make_foreground_bmask( 

327 xm=np.array([6], dtype='f8'), 

328 ym=np.array([0], dtype='f8'), 

329 rm=np.array([5], dtype='f8'), 

330 dims=(10, 10), 

331 mask_bit_val=flag, 

332 symmetrize=False, 

333 ) 

334 

335 bmask_sym = make_foreground_bmask( 

336 xm=np.array([6], dtype='f8'), 

337 ym=np.array([0], dtype='f8'), 

338 rm=np.array([5], dtype='f8'), 

339 dims=(10, 10), 

340 mask_bit_val=flag, 

341 symmetrize=True, 

342 ) 

343 

344 msk = bmask > 0 

345 assert np.all((bmask[msk] & bmask_sym[msk]) != 0) 

346 

347 rot_bmask = np.rot90(bmask) 

348 msk = rot_bmask > 0 

349 assert np.all((rot_bmask[msk] & bmask_sym[msk]) != 0) 

350 

351 assert np.all((bmask_sym[0:2, 6:8] & flag) != 0) 

352 

353 

354@pytest.mark.parametrize("msk_exp_rad", [0, 4]) 

355def test_apply_foreground_masking_corrections_interp(msk_exp_rad): 

356 nband = 2 

357 seed = 10 

358 dims = (13, 13) 

359 

360 def _make_mbobs(): 

361 mbobs = ngmix.MultiBandObsList() 

362 rng = np.random.RandomState(seed=seed) 

363 for _ in range(nband): 

364 image = rng.uniform(size=dims) 

365 noise = rng.uniform(size=dims) 

366 obs = ngmix.Observation( 

367 image=image, 

368 noise=noise, 

369 weight=rng.uniform(size=dims), 

370 bmask=np.zeros(dims, dtype=np.int32), 

371 ormask=np.zeros(dims, dtype=np.int32), 

372 ) 

373 obs.mfrac = rng.uniform(size=dims) 

374 obslist = ngmix.ObsList() 

375 obslist.append(obs) 

376 mbobs.append(obslist) 

377 

378 return mbobs 

379 

380 res = {} 

381 for method in ['interp', 'interp-noise']: 

382 mbobs = _make_mbobs() 

383 apply_foreground_masking_corrections( 

384 mbobs=mbobs, 

385 xm=np.array([6]), 

386 ym=np.array([0]), 

387 rm=np.array([5-msk_exp_rad]), 

388 method=method, 

389 mask_expand_rad=msk_exp_rad, 

390 mask_bit_val=2**3, 

391 expand_mask_bit_val=2**4, 

392 interp_bit_val=2**5, 

393 symmetrize=False, 

394 ap_rad=1, 

395 iso_buff=1, 

396 rng=np.random.RandomState(seed=11) 

397 ) 

398 res[method] = mbobs 

399 

400 for method in ['interp', 'interp-noise']: 

401 mbobs = res[method] 

402 rng = np.random.RandomState(seed=seed) 

403 for obslist in mbobs: 

404 for obs in obslist: 

405 msk = (obs.bmask & 2**3) != 0 

406 image = rng.uniform(size=dims) 

407 noise = rng.uniform(size=dims) 

408 # we need to match these calls to the ones above 

409 rng.uniform(size=dims) 

410 rng.uniform(size=dims) 

411 

412 assert np.all(obs.mfrac[msk] == 1) 

413 assert np.all(obs.weight[msk] == 0) 

414 assert np.all((obs.bmask[msk] & 2**5) != 0) 

415 

416 assert np.all(image[msk] != obs.image[msk]) 

417 assert np.all(image[~msk] == obs.image[~msk]) 

418 assert np.all(noise[msk] != obs.noise[msk]) 

419 assert np.all(noise[~msk] == obs.noise[~msk]) 

420 

421 msk = (obs.bmask & 2**4) != 0 

422 if msk_exp_rad > 0: 

423 assert np.sum(msk) > 0 

424 

425 assert not np.all(obs.mfrac[msk] == 1) 

426 assert not np.all(obs.weight[msk] == 0) 

427 assert not np.all((obs.bmask[msk] & 2**5) != 0) 

428 

429 assert not np.all(image[msk] != obs.image[msk]) 

430 assert np.all(image[~msk] == obs.image[~msk]) 

431 assert not np.all(noise[msk] != obs.noise[msk]) 

432 assert np.all(noise[~msk] == obs.noise[~msk]) 

433 else: 

434 assert np.sum(msk) == 0 

435 

436 for i in range(len(res['interp'])): 

437 if msk_exp_rad > 0: 

438 assert np.array_equal( 

439 res['interp'][i][0].image, res['interp-noise'][i][0].image 

440 ) 

441 else: 

442 assert not np.array_equal( 

443 res['interp'][i][0].image, res['interp-noise'][i][0].image 

444 ) 

445 

446 

447@pytest.mark.parametrize('method', ['interp', 'interp-noise']) 

448def test_apply_foreground_masking_corrections_interp_all(method): 

449 nband = 2 

450 seed = 10 

451 dims = (13, 13) 

452 mbobs = ngmix.MultiBandObsList() 

453 rng = np.random.RandomState(seed=seed) 

454 for _ in range(nband): 

455 image = rng.uniform(size=dims) 

456 noise = rng.uniform(size=dims) 

457 obs = ngmix.Observation( 

458 image=image, 

459 noise=noise, 

460 weight=rng.uniform(size=dims), 

461 bmask=np.zeros(dims, dtype=np.int32), 

462 ormask=np.zeros(dims, dtype=np.int32), 

463 ) 

464 obs.mfrac = rng.uniform(size=dims) 

465 obslist = ngmix.ObsList() 

466 obslist.append(obs) 

467 mbobs.append(obslist) 

468 

469 apply_foreground_masking_corrections( 

470 mbobs=mbobs, 

471 xm=np.array([6]), 

472 ym=np.array([0]), 

473 rm=np.array([100]), 

474 method=method, 

475 mask_expand_rad=0, 

476 mask_bit_val=2**3, 

477 expand_mask_bit_val=2**4, 

478 interp_bit_val=2**5, 

479 symmetrize=False, 

480 ap_rad=1, 

481 iso_buff=1, 

482 rng=np.random.RandomState(seed=11) 

483 ) 

484 

485 rng = np.random.RandomState(seed=seed) 

486 for obslist in mbobs: 

487 for obs in obslist: 

488 assert np.all(obs.mfrac == 1) 

489 assert np.all(obs.weight == 0) 

490 assert np.all((obs.bmask & 2**3) != 0) 

491 

492 

493@pytest.mark.parametrize("msk_exp_rad", [0, 4]) 

494def test_apply_foreground_masking_corrections_apodize(msk_exp_rad): 

495 nband = 2 

496 seed = 10 

497 dims = (13, 13) 

498 

499 mbobs = ngmix.MultiBandObsList() 

500 rng = np.random.RandomState(seed=seed) 

501 for _ in range(nband): 

502 image = rng.uniform(size=dims) 

503 noise = rng.uniform(size=dims) 

504 obs = ngmix.Observation( 

505 image=image, 

506 noise=noise, 

507 weight=rng.uniform(size=dims), 

508 bmask=np.zeros(dims, dtype=np.int32), 

509 ormask=np.zeros(dims, dtype=np.int32), 

510 ) 

511 obs.mfrac = rng.uniform(size=dims) 

512 obslist = ngmix.ObsList() 

513 obslist.append(obs) 

514 mbobs.append(obslist) 

515 

516 apply_foreground_masking_corrections( 

517 mbobs=mbobs, 

518 xm=np.array([6]), 

519 ym=np.array([0]), 

520 rm=np.array([5-msk_exp_rad]), 

521 method="apodize", 

522 mask_expand_rad=msk_exp_rad, 

523 mask_bit_val=2**3, 

524 expand_mask_bit_val=2**4, 

525 interp_bit_val=2**5, 

526 symmetrize=False, 

527 ap_rad=1, 

528 iso_buff=1, 

529 rng=np.random.RandomState(seed=11) 

530 ) 

531 

532 rng = np.random.RandomState(seed=seed) 

533 for obslist in mbobs: 

534 for obs in obslist: 

535 msk = (obs.bmask & 2**3) != 0 

536 image = rng.uniform(size=dims) 

537 noise = rng.uniform(size=dims) 

538 # we need to match these calls to the ones above 

539 rng.uniform(size=dims) 

540 rng.uniform(size=dims) 

541 

542 assert np.all(obs.mfrac[msk] == 1) 

543 assert np.all(obs.weight[msk] == 0) 

544 

545 assert np.all(image[msk] != obs.image[msk]) 

546 assert np.all(image[~msk] == obs.image[~msk]) 

547 assert np.all(noise[msk] != obs.noise[msk]) 

548 assert np.all(noise[~msk] == obs.noise[~msk]) 

549 

550 msk = (obs.bmask & 2**4) != 0 

551 if msk_exp_rad > 0: 

552 assert np.sum(msk) > 0 

553 

554 assert not np.all(obs.mfrac[msk] == 1) 

555 assert not np.all(obs.weight[msk] == 0) 

556 

557 assert not np.all(image[msk] != obs.image[msk]) 

558 assert np.all(image[~msk] == obs.image[~msk]) 

559 assert not np.all(noise[msk] != obs.noise[msk]) 

560 assert np.all(noise[~msk] == obs.noise[~msk]) 

561 else: 

562 assert np.sum(msk) == 0 

563 

564 

565def test_apply_foreground_masking_corrections_apodize_all(): 

566 nband = 2 

567 seed = 10 

568 dims = (13, 13) 

569 mbobs = ngmix.MultiBandObsList() 

570 rng = np.random.RandomState(seed=seed) 

571 for _ in range(nband): 

572 image = rng.uniform(size=dims) 

573 noise = rng.uniform(size=dims) 

574 obs = ngmix.Observation( 

575 image=image, 

576 noise=noise, 

577 weight=rng.uniform(size=dims), 

578 bmask=np.zeros(dims, dtype=np.int32), 

579 ormask=np.zeros(dims, dtype=np.int32), 

580 ) 

581 obs.mfrac = rng.uniform(size=dims) 

582 obslist = ngmix.ObsList() 

583 obslist.append(obs) 

584 mbobs.append(obslist) 

585 

586 apply_foreground_masking_corrections( 

587 mbobs=mbobs, 

588 xm=np.array([6]), 

589 ym=np.array([0]), 

590 rm=np.array([100]), 

591 method="apodize", 

592 mask_expand_rad=0, 

593 mask_bit_val=2**3, 

594 expand_mask_bit_val=2**4, 

595 interp_bit_val=2**5, 

596 symmetrize=False, 

597 ap_rad=1, 

598 iso_buff=1, 

599 rng=np.random.RandomState(seed=11) 

600 ) 

601 

602 rng = np.random.RandomState(seed=seed) 

603 for obslist in mbobs: 

604 for obs in obslist: 

605 assert np.all(obs.mfrac == 1) 

606 assert np.all(obs.weight == 0) 

607 assert np.all((obs.bmask & 2**3) != 0) 

608 assert np.all(obs.image == 0) 

609 assert np.all(obs.noise == 0)