lsst.ip.diffim  16.0-12-g1dc09ba+1
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 
23 __all__ = ["makeKernelBasisList", "generateAlardLuptonBasisList"]
24 
25 from . import diffimLib
26 from lsst.log import Log
27 import numpy as np
28 
29 sigma2fwhm = 2. * np.sqrt(2. * np.log(2.))
30 
31 
32 def makeKernelBasisList(config, targetFwhmPix=None, referenceFwhmPix=None,
33  basisDegGauss=None, metadata=None):
34  """Generate the appropriate Kernel basis based on the Config"""
35  if config.kernelBasisSet == "alard-lupton":
36  return generateAlardLuptonBasisList(config, targetFwhmPix=targetFwhmPix,
37  referenceFwhmPix=referenceFwhmPix,
38  basisDegGauss=basisDegGauss,
39  metadata=metadata)
40  elif config.kernelBasisSet == "delta-function":
41  kernelSize = config.kernelSize
42  return diffimLib.makeDeltaFunctionBasisList(kernelSize, kernelSize)
43  else:
44  raise ValueError("Cannot generate %s basis set" % (config.kernelBasisSet))
45 
46 
47 def generateAlardLuptonBasisList(config, targetFwhmPix=None, referenceFwhmPix=None,
48  basisDegGauss=None, metadata=None):
49  """Generate an Alard-Lupton kernel basis based upon the Config and
50  the input FWHM of the science and template images"""
51 
52  if config.kernelBasisSet != "alard-lupton":
53  raise RuntimeError("Cannot generate %s basis within generateAlardLuptonBasisList" %
54  config.kernelBasisSet)
55 
56  kernelSize = config.kernelSize
57  fwhmScaling = config.kernelSizeFwhmScaling
58  basisNGauss = config.alardNGauss
59  basisSigmaGauss = config.alardSigGauss
60  basisGaussBeta = config.alardGaussBeta
61  basisMinSigma = config.alardMinSig
62  if basisDegGauss is None:
63  basisDegGauss = config.alardDegGauss
64 
65  if len(basisDegGauss) != basisNGauss:
66  raise ValueError("len(basisDegGauss) != basisNGauss : %d vs %d" % (len(basisDegGauss), basisNGauss))
67  if len(basisSigmaGauss) != basisNGauss:
68  raise ValueError("len(basisSigmaGauss) != basisNGauss : %d vs %d" %
69  (len(basisSigmaGauss), basisNGauss))
70  if (kernelSize % 2) != 1:
71  raise ValueError("Only odd-sized Alard-Lupton bases allowed")
72 
73  if (targetFwhmPix is None) or (referenceFwhmPix is None) or (not config.scaleByFwhm):
74  if metadata is not None:
75  metadata.add("ALBasisNGauss", basisNGauss)
76  metadata.add("ALBasisDegGauss", basisDegGauss)
77  metadata.add("ALBasisSigGauss", basisSigmaGauss)
78  metadata.add("ALKernelSize", kernelSize)
79 
80  return diffimLib.makeAlardLuptonBasisList(kernelSize//2, basisNGauss, basisSigmaGauss, basisDegGauss)
81 
82  targetSigma = targetFwhmPix / sigma2fwhm
83  referenceSigma = referenceFwhmPix / sigma2fwhm
84  logger = Log.getLogger("lsst.ip.diffim.generateAlardLuptonBasisList")
85  logger.debug("Generating matching bases for sigma %.2f pix -> %.2f pix", targetSigma, referenceSigma)
86 
87  # Modify the size of Alard Lupton kernels based upon the images FWHM
88  #
89  # Note the operation is : template.x.kernel = science
90  #
91  # Assuming the template and science image Psfs are Gaussians with
92  # the Fwhm above, Fwhm_T **2 + Fwhm_K **2 = Fwhm_S **2
93  #
94  if targetSigma == referenceSigma:
95  # Leave defaults as-is
96  pass
97  elif referenceSigma > targetSigma:
98  # Normal convolution
99 
100  # First Gaussian has the sigma that comes from the convolution
101  # of two Gaussians : Sig_S**2 = Sig_T**2 + Sig_K**2
102  #
103  # If it's larger than basisMinSigma * basisGaussBeta, make it the
104  # second kernel. Else make it the smallest kernel. Unless
105  # only 1 kernel is asked for.
106  kernelSigma = np.sqrt(referenceSigma**2 - targetSigma**2)
107  if kernelSigma < basisMinSigma:
108  kernelSigma = basisMinSigma
109 
110  basisSigmaGauss = []
111  if basisNGauss == 1:
112  basisSigmaGauss.append(kernelSigma)
113  nAppended = 1
114  else:
115  if (kernelSigma/basisGaussBeta) > basisMinSigma:
116  basisSigmaGauss.append(kernelSigma/basisGaussBeta)
117  basisSigmaGauss.append(kernelSigma)
118  nAppended = 2
119  else:
120  basisSigmaGauss.append(kernelSigma)
121  nAppended = 1
122 
123  # Any other Gaussians above basisNGauss=1 come from a scaling
124  # relationship: Sig_i+1 / Sig_i = basisGaussBeta
125  for i in range(nAppended, basisNGauss):
126  basisSigmaGauss.append(basisSigmaGauss[-1]*basisGaussBeta)
127 
128  kernelSize = int(fwhmScaling * basisSigmaGauss[-1])
129  kernelSize += 0 if kernelSize%2 else 1 # Make sure it's odd
130  kernelSize = min(config.kernelSizeMax, max(kernelSize, config.kernelSizeMin))
131 
132  else:
133  # Deconvolution; Define the progression of Gaussians using a
134  # method to derive a deconvolution sum-of-Gaussians from it's
135  # convolution counterpart. Only use 3 since the algorithm
136  # assumes 3 components.
137  #
138  # http://iopscience.iop.org/0266-5611/26/8/085002 Equation 40
139 
140  # Use specializations for deconvolution
141  basisNGauss = config.alardNGaussDeconv
142  basisMinSigma = config.alardMinSigDeconv
143 
144  kernelSigma = np.sqrt(targetSigma**2 - referenceSigma**2)
145  if kernelSigma < basisMinSigma:
146  kernelSigma = basisMinSigma
147 
148  basisSigmaGauss = []
149  if (kernelSigma/basisGaussBeta) > basisMinSigma:
150  basisSigmaGauss.append(kernelSigma/basisGaussBeta)
151  basisSigmaGauss.append(kernelSigma)
152  nAppended = 2
153  else:
154  basisSigmaGauss.append(kernelSigma)
155  nAppended = 1
156 
157  for i in range(nAppended, basisNGauss):
158  basisSigmaGauss.append(basisSigmaGauss[-1]*basisGaussBeta)
159 
160  kernelSize = int(fwhmScaling * basisSigmaGauss[-1])
161  kernelSize += 0 if kernelSize%2 else 1 # Make sure it's odd
162  kernelSize = min(config.kernelSizeMax, max(kernelSize, config.kernelSizeMin))
163 
164  # Now build a deconvolution set from these sigmas
165  sig0 = basisSigmaGauss[0]
166  sig1 = basisSigmaGauss[1]
167  sig2 = basisSigmaGauss[2]
168  basisSigmaGauss = []
169  for n in range(1, 3):
170  for j in range(n):
171  sigma2jn = (n - j)*sig1**2
172  sigma2jn += j * sig2**2
173  sigma2jn -= (n + 1)*sig0**2
174  sigmajn = np.sqrt(sigma2jn)
175  basisSigmaGauss.append(sigmajn)
176 
177  basisSigmaGauss.sort()
178  basisNGauss = len(basisSigmaGauss)
179  basisDegGauss = [config.alardDegGaussDeconv for x in basisSigmaGauss]
180 
181  if metadata is not None:
182  metadata.add("ALBasisNGauss", basisNGauss)
183  metadata.add("ALBasisDegGauss", basisDegGauss)
184  metadata.add("ALBasisSigGauss", basisSigmaGauss)
185  metadata.add("ALKernelSize", kernelSize)
186 
187  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)