LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
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 
33 def isPositive(x):
34  return x > 0
35 
36 
37 class GaussianPsfFactory(Config):
38  """Factory for simple Gaussian PSF models
39 
40  Provides a high-level interface to DoubleGaussianPsf and SingleGaussianPsf
41  by specifying Gaussian PSF model width in FWHM instead of sigma,
42  and supporting computing kernel size as a multiple of PSF width.
43  This makes it suitable for tasks where PSF width is not known in advance.
44  """
45  size = Field(
46  doc="Kernel size (width and height) (pixels); if None then sizeFactor is used",
47  dtype=int,
48  optional=True,
49  default=None,
50  check=isPositive,
51  )
52  sizeFactor = Field(
53  doc="Kernel size as a factor of fwhm (dimensionless); "
54  + "size = sizeFactor * fwhm; ignored if size is not None",
55  dtype=float,
56  optional=False,
57  default=3.0,
58  check=isPositive,
59  )
60  minSize = Field(
61  doc="Minimum kernel size if using sizeFactor (pixels); ignored if size is not None",
62  dtype=int,
63  optional=True,
64  default=5,
65  check=isPositive,
66  )
67  maxSize = Field(
68  doc="Maximum kernel size if using sizeFactor (pixels); ignored if size is not None",
69  dtype=int,
70  optional=True,
71  default=None,
72  check=isPositive,
73  )
74  defaultFwhm = Field(
75  doc="Default FWHM of Gaussian model of core of star (pixels)",
76  dtype=float,
77  default=3.0,
78  check=isPositive,
79  )
80  addWing = Field(
81  doc="Add a Gaussian to represent wings?",
82  dtype=bool,
83  optional=False,
84  default=True,
85  )
86  wingFwhmFactor = Field(
87  doc="wing width, as a multiple of core width (dimensionless); ignored if addWing false",
88  dtype=float,
89  optional=False,
90  default=2.5,
91  check=isPositive,
92  )
93  wingAmplitude = Field(
94  doc="wing amplitude, as a multiple of core amplitude (dimensionless); ignored if addWing false",
95  dtype=float,
96  optional=False,
97  default=0.1,
98  check=isPositive,
99  )
100 
101  def computeSizeAndSigma(self, fwhm=None):
102  """Compute kernel size and star width as sigma
103 
104  kernel size will be odd unless minSize or maxSize is used and that value is even.
105 
106  @param[in] fwhm: FWHM of core star (pixels); if None then defaultFwhm is used
107  @return two values:
108  - kernel size (width == height) in pixels
109  - sigma equivalent to supplied fwhm, assuming a Gaussian (pixels)
110 
111  @warning assumes a valid config
112  """
113  if fwhm is None:
114  fwhm = self.defaultFwhm
115 
116  if self.size is not None:
117  size = self.size
118  else:
119  desSize = (int(self.sizeFactor * fwhm) // 2) * 2 + 1 # make result odd
120  if self.minSize and self.minSize > desSize:
121  size = self.minSize
122  elif self.maxSize and self.maxSize < desSize:
123  size = self.maxSize
124  else:
125  size = desSize
126 
127  return size, fwhm * SigmaPerFwhm
128 
129  def validate(self):
130  Config.validate(self)
131  if self.minSize and self.maxSize and self.minSize > self.maxSize:
132  raise RuntimeError("minSize=%s > maxSize=%s" % (self.minSize, self.maxSize))
133 
134  def apply(self, fwhm=None):
135  """Construct a GaussianPsf
136 
137  @param[in] self: an instance of ConfigClass
138  @param[in] fwhm: FWHM of core of star (pixels); if None then self.defaultFwhm is used
139  @return a DoubleGaussianPsf if self.addWing is True, else a SingleGaussianPsf
140  """
141  kernelSize, sigma = self.computeSizeAndSigma(fwhm)
142  if self.addWing:
143  wingsSigma = sigma * self.wingFwhmFactor
144  return DoubleGaussianPsf(kernelSize, kernelSize, sigma, wingsSigma, self.wingAmplitude)
145  else:
146  return SingleGaussianPsf(kernelSize, kernelSize, sigma)
147 
148  @classmethod
149  def makeField(cls, doc):
150  """Make an lsst.pex.config.ConfigurableField
151  """
152  def applyWrapper(config, **kwargs):
153  """Construct a Gaussian PSF
154 
155  @param[in] config: an instance of GaussianPsfFactory
156  """
157  return config.apply(**kwargs)
158  return ConfigurableField(
159  doc=doc,
160  target=applyWrapper,
161  ConfigClass=cls
162  )
Represent a Psf as a circularly symmetrical double Gaussian.