15 """Configuration for generating sky objects"""
16 avoidMask = ListField(dtype=str, default=[
"DETECTED",
"DETECTED_NEGATIVE",
"BAD",
"NO_DATA"],
17 doc=
"Avoid pixels masked with these mask planes")
18 growMask = Field(dtype=int, default=0,
19 doc=
"Number of pixels to grow the masked pixels when adding sky objects")
20 sourceRadius = Field(dtype=float, default=8, doc=
"Radius, in pixels, of sky objects")
21 nSources = Field(dtype=int, default=100, doc=
"Try to add this many sky objects")
22 nTrialSources = Field(dtype=int, default=
None, optional=
True,
23 doc=
"Maximum number of trial sky object positions "
24 "(default: nSkySources*nTrialSkySourcesMultiplier)")
25 nTrialSourcesMultiplier = Field(dtype=int, default=5,
26 doc=
"Set nTrialSkySources to "
27 "nSkySources*nTrialSkySourcesMultiplier "
28 "if nTrialSkySources is None")
32 """Generate a list of Footprints of sky objects
34 Sky objects don't overlap with other objects. This is determined
35 through the provided `mask` (in which objects are typically flagged
38 Sky objects are positioned using a quasi-random Halton sequence number
39 generator. This is a deterministic sequence that mimics a random trial and
40 error approach whilst acting to minimize clustering of points for a given
41 field of view. Up to `nTrialSources` points are generated, returning the
42 first `nSources` that do not overlap with the mask.
46 mask : `lsst.afw.image.Mask`
47 Input mask plane, which identifies pixels to avoid for the sky
50 Random number generator seed.
51 config : `SkyObjectsConfig`
52 Configuration for finding sky objects.
56 skyFootprints : `list` of `lsst.afw.detection.Footprint`
57 Footprints of sky objects. Each will have a peak at the center
60 if config.nSources <= 0:
63 skySourceRadius = config.sourceRadius
64 nSkySources = config.nSources
65 nTrialSkySources = config.nTrialSources
66 if nTrialSkySources
is None:
67 nTrialSkySources = config.nTrialSourcesMultiplier*nSkySources
70 box.grow(-(int(skySourceRadius) + 1))
71 xMin, yMin = box.getMin()
72 xMax, yMax = box.getMax()
75 if config.growMask > 0:
76 avoid = avoid.dilated(config.growMask)
78 sampler = qmc.Halton(d=2, seed=seed).random(nTrialSkySources)
79 sample = qmc.scale(sampler, [xMin, yMin], [xMax, yMax])
82 for x, y
in zip(sample[:, 0].astype(int), sample[:, 1].astype(int)):
83 if len(skyFootprints) == nSkySources:
87 if spans.overlaps(avoid):
92 skyFootprints.append(fp)
95 avoid = avoid.union(spans.dilated(int(skySourceRadius)))