2__all__ = [
"SkyObjectsConfig",
"SkyObjectsTask",
"generateSkyObjects"]
4from scipy.stats
import qmc
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.
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.
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)))
101 """Generate a list of Footprints of sky objects.
103 ConfigClass = SkyObjectsConfig
105 def run(self, mask, seed):
106 """Generate a list of Footprints of sky objects
108 Sky objects don't overlap with other objects. This is determined
109 through the provided `mask` (in which objects are typically flagged
112 Sky objects are positioned using a quasi-random Halton sequence
113 number generator. This
is a deterministic sequence that mimics a random
114 trial
and error approach whilst acting to minimize clustering of points
115 for a given field of view. Up to `nTrialSources` points are generated,
116 returning the first `nSources` that do
not overlap
with the mask.
121 Input mask plane, which identifies pixels to avoid
for the sky
124 Random number generator seed.
129 Footprints of sky objects. Each will have a peak at the center
133 self.log.info("Added %d of %d requested sky sources (%.0f%%)", len(skyFootprints),
134 self.config.nSources, 100*len(skyFootprints)/self.config.nSources)
static std::shared_ptr< geom::SpanSet > fromMask(image::Mask< T > const &mask, UnaryPredicate comparator=details::AnyBitSetFunctor< T >())
Create a SpanSet from a mask.
static std::shared_ptr< geom::SpanSet > fromShape(int r, Stencil s=Stencil::CIRCLE, lsst::geom::Point2I offset=lsst::geom::Point2I())
Factory function for creating SpanSets from a Stencil.
Represent a 2-dimensional array of bitmask pixels.
generateSkyObjects(mask, seed, config)