lsst.ip.diffim  15.0-4-gd76abed
makeKernelBasisList.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008-2016 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 from __future__ import absolute_import, division, print_function
23 
24 __all__ = ["makeKernelBasisList", "generateAlardLuptonBasisList"]
25 
26 from builtins import range
27 
28 from . import diffimLib
29 from lsst.log import Log
30 import numpy as np
31 
32 sigma2fwhm = 2. * np.sqrt(2. * np.log(2.))
33 
34 
35 def makeKernelBasisList(config, targetFwhmPix=None, referenceFwhmPix=None,
36  basisDegGauss=None, metadata=None):
37  """Generate the appropriate Kernel basis based on the Config"""
38  if config.kernelBasisSet == "alard-lupton":
39  return generateAlardLuptonBasisList(config, targetFwhmPix=targetFwhmPix,
40  referenceFwhmPix=referenceFwhmPix,
41  basisDegGauss=basisDegGauss,
42  metadata=metadata)
43  elif config.kernelBasisSet == "delta-function":
44  kernelSize = config.kernelSize
45  return diffimLib.makeDeltaFunctionBasisList(kernelSize, kernelSize)
46  else:
47  raise ValueError("Cannot generate %s basis set" % (config.kernelBasisSet))
48 
49 
50 def generateAlardLuptonBasisList(config, targetFwhmPix=None, referenceFwhmPix=None,
51  basisDegGauss=None, metadata=None):
52  """Generate an Alard-Lupton kernel basis based upon the Config and
53  the input FWHM of the science and template images"""
54 
55  if config.kernelBasisSet != "alard-lupton":
56  raise RuntimeError("Cannot generate %s basis within generateAlardLuptonBasisList" %
57  config.kernelBasisSet)
58 
59  kernelSize = config.kernelSize
60  fwhmScaling = config.kernelSizeFwhmScaling
61  basisNGauss = config.alardNGauss
62  basisSigmaGauss = config.alardSigGauss
63  basisGaussBeta = config.alardGaussBeta
64  basisMinSigma = config.alardMinSig
65  if basisDegGauss is None:
66  basisDegGauss = config.alardDegGauss
67 
68  if len(basisDegGauss) != basisNGauss:
69  raise ValueError("len(basisDegGauss) != basisNGauss : %d vs %d" % (len(basisDegGauss), basisNGauss))
70  if len(basisSigmaGauss) != basisNGauss:
71  raise ValueError("len(basisSigmaGauss) != basisNGauss : %d vs %d" %
72  (len(basisSigmaGauss), basisNGauss))
73  if (kernelSize % 2) != 1:
74  raise ValueError("Only odd-sized Alard-Lupton bases allowed")
75 
76  if (targetFwhmPix is None) or (referenceFwhmPix is None) or (not config.scaleByFwhm):
77  if metadata is not None:
78  metadata.add("ALBasisNGauss", basisNGauss)
79  metadata.add("ALBasisDegGauss", basisDegGauss)
80  metadata.add("ALBasisSigGauss", basisSigmaGauss)
81  metadata.add("ALKernelSize", kernelSize)
82 
83  return diffimLib.makeAlardLuptonBasisList(kernelSize//2, basisNGauss, basisSigmaGauss, basisDegGauss)
84 
85  targetSigma = targetFwhmPix / sigma2fwhm
86  referenceSigma = referenceFwhmPix / sigma2fwhm
87  logger = Log.getLogger("lsst.ip.diffim.generateAlardLuptonBasisList")
88  logger.debug("Generating matching bases for sigma %.2f pix -> %.2f pix", targetSigma, referenceSigma)
89 
90  # Modify the size of Alard Lupton kernels based upon the images FWHM
91  #
92  # Note the operation is : template.x.kernel = science
93  #
94  # Assuming the template and science image Psfs are Gaussians with
95  # the Fwhm above, Fwhm_T **2 + Fwhm_K **2 = Fwhm_S **2
96  #
97  if targetSigma == referenceSigma:
98  # Leave defaults as-is
99  pass
100  elif referenceSigma > targetSigma:
101  # Normal convolution
102 
103  # First Gaussian has the sigma that comes from the convolution
104  # of two Gaussians : Sig_S**2 = Sig_T**2 + Sig_K**2
105  #
106  # If it's larger than basisMinSigma * basisGaussBeta, make it the
107  # second kernel. Else make it the smallest kernel. Unless
108  # only 1 kernel is asked for.
109  kernelSigma = np.sqrt(referenceSigma**2 - targetSigma**2)
110  if kernelSigma < basisMinSigma:
111  kernelSigma = basisMinSigma
112 
113  basisSigmaGauss = []
114  if basisNGauss == 1:
115  basisSigmaGauss.append(kernelSigma)
116  nAppended = 1
117  else:
118  if (kernelSigma/basisGaussBeta) > basisMinSigma:
119  basisSigmaGauss.append(kernelSigma/basisGaussBeta)
120  basisSigmaGauss.append(kernelSigma)
121  nAppended = 2
122  else:
123  basisSigmaGauss.append(kernelSigma)
124  nAppended = 1
125 
126  # Any other Gaussians above basisNGauss=1 come from a scaling
127  # relationship: Sig_i+1 / Sig_i = basisGaussBeta
128  for i in range(nAppended, basisNGauss):
129  basisSigmaGauss.append(basisSigmaGauss[-1]*basisGaussBeta)
130 
131  kernelSize = int(fwhmScaling * basisSigmaGauss[-1])
132  kernelSize += 0 if kernelSize%2 else 1 # Make sure it's odd
133  kernelSize = min(config.kernelSizeMax, max(kernelSize, config.kernelSizeMin))
134 
135  else:
136  # Deconvolution; Define the progression of Gaussians using a
137  # method to derive a deconvolution sum-of-Gaussians from it's
138  # convolution counterpart. Only use 3 since the algorithm
139  # assumes 3 components.
140  #
141  # http://iopscience.iop.org/0266-5611/26/8/085002 Equation 40
142 
143  # Use specializations for deconvolution
144  basisNGauss = config.alardNGaussDeconv
145  basisMinSigma = config.alardMinSigDeconv
146 
147  kernelSigma = np.sqrt(targetSigma**2 - referenceSigma**2)
148  if kernelSigma < basisMinSigma:
149  kernelSigma = basisMinSigma
150 
151  basisSigmaGauss = []
152  if (kernelSigma/basisGaussBeta) > basisMinSigma:
153  basisSigmaGauss.append(kernelSigma/basisGaussBeta)
154  basisSigmaGauss.append(kernelSigma)
155  nAppended = 2
156  else:
157  basisSigmaGauss.append(kernelSigma)
158  nAppended = 1
159 
160  for i in range(nAppended, basisNGauss):
161  basisSigmaGauss.append(basisSigmaGauss[-1]*basisGaussBeta)
162 
163  kernelSize = int(fwhmScaling * basisSigmaGauss[-1])
164  kernelSize += 0 if kernelSize%2 else 1 # Make sure it's odd
165  kernelSize = min(config.kernelSizeMax, max(kernelSize, config.kernelSizeMin))
166 
167  # Now build a deconvolution set from these sigmas
168  sig0 = basisSigmaGauss[0]
169  sig1 = basisSigmaGauss[1]
170  sig2 = basisSigmaGauss[2]
171  basisSigmaGauss = []
172  for n in range(1, 3):
173  for j in range(n):
174  sigma2jn = (n - j)*sig1**2
175  sigma2jn += j * sig2**2
176  sigma2jn -= (n + 1)*sig0**2
177  sigmajn = np.sqrt(sigma2jn)
178  basisSigmaGauss.append(sigmajn)
179 
180  basisSigmaGauss.sort()
181  basisNGauss = len(basisSigmaGauss)
182  basisDegGauss = [config.alardDegGaussDeconv for x in basisSigmaGauss]
183 
184  if metadata is not None:
185  metadata.add("ALBasisNGauss", basisNGauss)
186  metadata.add("ALBasisDegGauss", basisDegGauss)
187  metadata.add("ALBasisSigGauss", basisSigmaGauss)
188  metadata.add("ALKernelSize", kernelSize)
189 
190  return diffimLib.makeAlardLuptonBasisList(kernelSize//2, basisNGauss, basisSigmaGauss, basisDegGauss)
def makeKernelBasisList(config, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, metadata=None)
def generateAlardLuptonBasisList(config, targetFwhmPix=None, referenceFwhmPix=None, basisDegGauss=None, metadata=None)