LSSTApplications  10.0-2-g4f67435,11.0.rc2+1,11.0.rc2+12,11.0.rc2+3,11.0.rc2+4,11.0.rc2+5,11.0.rc2+6,11.0.rc2+7,11.0.rc2+8
LSSTDataManagementBasePackage
gaussianPsfFactory.py
Go to the documentation of this file.
1 from __future__ import absolute_import, division
2 #
3 # LSST Data Management System
4 # Copyright 2008, 2009, 2010 LSST Corporation.
5 #
6 # This product includes software developed by the
7 # LSST Project (http://www.lsst.org/).
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the LSST License Statement and
20 # the GNU General Public License along with this program. If not,
21 # see <http://www.lsstcorp.org/LegalNotices/>.
22 #
23 import math
24 
25 from lsst.pex.config import Config, Field, ConfigurableField
26 from .algorithmsLib import SingleGaussianPsf, DoubleGaussianPsf
27 
28 __all__ = ["GaussianPsfFactory", "SigmaPerFwhm"]
29 
30 SigmaPerFwhm = 1.0 / (2.0 * math.sqrt(2.0 * math.log(2.0)))
31 
32 def isPositive(x):
33  return x > 0
34 
35 class GaussianPsfFactory(Config):
36  """Factory for simple Gaussian PSF models
37 
38  Provides a high-level interface to DoubleGaussianPsf and SingleGaussianPsf
39  by specifying Gaussian PSF model width in FWHM instead of sigma,
40  and supporting computing kernel size as a multiple of PSF width.
41  This makes it suitable for tasks where PSF width is not known in advance.
42  """
43  size = Field(
44  doc = "Kernel size (width and height) (pixels); if None then sizeFactor is used",
45  dtype = int,
46  optional = True,
47  default = None,
48  check = isPositive,
49  )
50  sizeFactor = Field(
51  doc = "Kernel size as a factor of fwhm (dimensionless); " \
52  + "size = sizeFactor * fwhm; ignored if size is not None",
53  dtype = float,
54  optional = False,
55  default = 3.0,
56  check = isPositive,
57  )
58  minSize = Field(
59  doc = "Minimum kernel size if using sizeFactor (pixels); ignored if size is not None",
60  dtype = int,
61  optional = True,
62  default = 5,
63  check = isPositive,
64  )
65  maxSize = Field(
66  doc = "Maximum kernel size if using sizeFactor (pixels); ignored if size is not None",
67  dtype = int,
68  optional = True,
69  default = None,
70  check = isPositive,
71  )
72  defaultFwhm = Field(
73  doc = "Default FWHM of Gaussian model of core of star (pixels)",
74  dtype = float,
75  default = 3.0,
76  check = isPositive,
77  )
78  addWing = Field(
79  doc = "Add a Gaussian to represent wings?",
80  dtype = bool,
81  optional = False,
82  default = True,
83  )
84  wingFwhmFactor = Field(
85  doc = "wing width, as a multiple of core width (dimensionless); ignored if addWing false",
86  dtype = float,
87  optional = False,
88  default = 2.5,
89  check = isPositive,
90  )
91  wingAmplitude = Field(
92  doc = "wing amplitude, as a multiple of core amplitude (dimensionless); ignored if addWing false",
93  dtype = float,
94  optional = False,
95  default = 0.1,
96  check = isPositive,
97  )
98 
99  def computeSizeAndSigma(self, fwhm=None):
100  """Compute kernel size and star width as sigma
101 
102  kernel size will be odd unless minSize or maxSize is used and that value is even.
103 
104  @param[in] fwhm: FWHM of core star (pixels); if None then defaultFwhm is used
105  @return two values:
106  - kernel size (width == height) in pixels
107  - sigma equivalent to supplied fwhm, assuming a Gaussian (pixels)
108 
109  @warning assumes a valid config
110  """
111  if fwhm is None:
112  fwhm = self.defaultFwhm
113 
114  if self.size is not None:
115  size = self.size
116  else:
117  desSize = (int(self.sizeFactor * fwhm) // 2) * 2 + 1 # make result odd
118  if self.minSize and self.minSize > desSize:
119  size = self.minSize
120  elif self.maxSize and self.maxSize < desSize:
121  size = self.maxSize
122  else:
123  size = desSize
124 
125  return size, fwhm * SigmaPerFwhm
126 
127  def validate(self):
128  Config.validate(self)
129  if self.minSize and self.maxSize and self.minSize > self.maxSize:
130  raise RuntimeError("minSize=%s > maxSize=%s" % (self.minSize, self.maxSize))
131 
132  def apply(self, fwhm=None):
133  """Construct a GaussianPsf
134 
135  @param[in] self: an instance of ConfigClass
136  @param[in] fwhm: FWHM of core of star (pixels); if None then self.defaultFwhm is used
137  @return a DoubleGaussianPsf if self.addWing is True, else a SingleGaussianPsf
138  """
139  kernelSize, sigma = self.computeSizeAndSigma(fwhm)
140  if self.addWing:
141  wingsSigma = sigma * self.wingFwhmFactor
142  return DoubleGaussianPsf(kernelSize, kernelSize, sigma, wingsSigma, self.wingAmplitude)
143  else:
144  return SingleGaussianPsf(kernelSize, kernelSize, sigma)
145 
146  @classmethod
147  def makeField(cls, doc):
148  """Make an lsst.pex.config.ConfigurableField
149  """
150  def applyWrapper(config, **kwargs):
151  """Construct a Gaussian PSF
152 
153  @param[in] config: an instance of GaussianPsfFactory
154  """
155  return config.apply(**kwargs)
156  return ConfigurableField(
157  doc = doc,
158  target = applyWrapper,
159  ConfigClass=cls
160  )
161 
Represent a Psf as a circularly symmetrical double Gaussian.