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

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

 

__all__ = ["SkyObjectsConfig", "SkyObjectsTask", "generateSkyObjects"] 

 

from lsst.pex.config import Config, Field, ListField 

from lsst.pipe.base import Task 

 

import lsst.afw.detection 

import lsst.afw.geom 

import lsst.afw.math 

 

 

class SkyObjectsConfig(Config): 

"""Configuration for generating sky objects""" 

avoidMask = ListField(dtype=str, default=["DETECTED", "DETECTED_NEGATIVE", "BAD", "NO_DATA"], 

doc="Avoid pixels masked with these mask planes") 

growMask = Field(dtype=int, default=0, 

doc="Number of pixels to grow the masked pixels when adding sky objects") 

sourceRadius = Field(dtype=float, default=8, doc="Radius, in pixels, of sky objects") 

nSources = Field(dtype=int, default=100, doc="Try to add this many sky objects") 

nTrialSources = Field(dtype=int, default=None, optional=True, 

doc="Maximum number of trial sky object positions\n" 

"(default: nSkySources*nTrialSkySourcesMultiplier)") 

nTrialSourcesMultiplier = Field(dtype=int, default=5, 

doc="Set nTrialSkySources to\n" 

" nSkySources*nTrialSkySourcesMultiplier\n" 

"if nTrialSkySources is None") 

 

 

def generateSkyObjects(mask, seed, config): 

"""Generate a list of Footprints of sky objects 

 

Sky objects don't overlap with other objects. This is determined 

through the provided `mask` (in which objects are typically flagged 

as `DETECTED`). 

 

The algorithm for determining sky objects is random trial and error: 

we try up to `nTrialSkySources` random positions to find `nSources` 

sky objects. 

 

Parameters 

---------- 

mask : `lsst.afw.image.Mask` 

Input mask plane, which identifies pixels to avoid for the sky 

objects. 

seed : `int` 

Random number generator seed. 

config : `SkyObjectsConfig` 

Configuration for finding sky objects. 

 

Returns 

------- 

skyFootprints : `list` of `lsst.afw.detection.Footprint` 

Footprints of sky objects. Each will have a peak at the center 

of the sky object. 

""" 

if config.nSources <= 0: 

return [] 

 

skySourceRadius = config.sourceRadius 

nSkySources = config.nSources 

nTrialSkySources = config.nTrialSources 

if nTrialSkySources is None: 

nTrialSkySources = config.nTrialSourcesMultiplier*nSkySources 

 

box = mask.getBBox() 

box.grow(-(int(skySourceRadius) + 1)) # Avoid objects partially off the image 

xMin, yMin = box.getMin() 

xMax, yMax = box.getMax() 

 

avoid = lsst.afw.geom.SpanSet.fromMask(mask, mask.getPlaneBitMask(config.avoidMask)) 

if config.growMask > 0: 

avoid = avoid.dilated(config.growMask) 

 

rng = lsst.afw.math.Random(seed=seed) 

 

skyFootprints = [] 

for _ in range(nTrialSkySources): 

if len(skyFootprints) == nSkySources: 

break 

 

x = int(rng.flat(xMin, xMax)) 

y = int(rng.flat(yMin, yMax)) 

spans = lsst.afw.geom.SpanSet.fromShape(int(skySourceRadius), offset=(x, y)) 

if spans.overlaps(avoid): 

continue 

 

fp = lsst.afw.detection.Footprint(spans, mask.getBBox()) 

fp.addPeak(x, y, 0) 

skyFootprints.append(fp) 

 

return skyFootprints 

 

 

class SkyObjectsTask(Task): 

ConfigClass = SkyObjectsConfig 

 

def run(self, mask, seed): 

"""Generate a list of Footprints of sky objects 

 

Sky objects don't overlap with other objects. This is determined 

through the provided `mask` (in which objects are typically flagged 

as `DETECTED`). 

 

The algorithm for determining sky objects is random trial and error: 

we try up to `nTrialSkySources` random positions to find `nSources` 

sky objects. 

 

Parameters 

---------- 

mask : `lsst.afw.image.Mask` 

Input mask plane, which identifies pixels to avoid for the sky 

objects. 

seed : `int` 

Random number generator seed. 

 

Returns 

------- 

skyFootprints : `list` of `lsst.afw.detection.Footprint` 

Footprints of sky objects. Each will have a peak at the center 

of the sky object. 

""" 

skyFootprints = generateSkyObjects(mask, seed, self.config) 

self.log.info("Added %d of %d requested sky sources (%.0f%%)", len(skyFootprints), 

self.config.nSources, 100*len(skyFootprints)/self.config.nSources) 

return skyFootprints