23 Code to load multi-Gaussian approximations to profiles from "The Tractor" 24 into a lsst.shapelet.MultiShapeletBasis. 26 Please see the README file in the data directory of the lsst.shapelet 27 package for more information. 29 from future
import standard_library
30 standard_library.install_aliases()
31 from builtins
import zip
32 from builtins
import str
33 from builtins
import range
42 import lsst.pex.exceptions
43 from .radialProfile
import RadialProfile
44 from .multiShapeletBasis
import MultiShapeletBasis
45 from .shapeletFunction
import ShapeletFunction
49 """Register the pickled profiles in the data directory with the RadialProfile singleton registry. 51 This should only be called at import time by this module; it's only a function to avoid polluting 52 the module namespace with all the local variables used here. 54 dataDir = os.path.join(os.environ[
"SHAPELET_DIR"],
"data")
55 regex = re.compile(
r"([a-z]+\d?)_K(\d+)_MR(\d+)\.pickle")
56 for filename
in os.listdir(dataDir):
57 match = regex.match(filename)
61 nComponents = int(match.group(2))
62 maxRadius = int(match.group(3))
64 profile = RadialProfile.get(name)
65 except lsst.pex.exceptions.Exception:
66 warnings.warn(
"No C++ profile for multi-Gaussian pickle file '%s'" % filename)
68 with open(os.path.join(dataDir, filename),
'rb')
as stream:
69 if sys.version_info[0] >= 3:
70 array = pickle.load(stream, encoding=
'latin1')
72 array = pickle.load(stream)
73 amplitudes = array[:nComponents]
74 amplitudes /= amplitudes.sum()
75 variances = array[nComponents:]
76 if amplitudes.shape != (nComponents,)
or variances.shape != (nComponents,):
77 warnings.warn(
"Unknown format for multi-Gaussian pickle file '%s'" % filename)
79 basis = MultiShapeletBasis(1)
80 for amplitude, variance
in zip(amplitudes, variances):
81 radius = variance**0.5
82 matrix = numpy.array([[amplitude / ShapeletFunction.FLUX_FACTOR]], dtype=float)
83 basis.addComponent(radius, 0, matrix)
84 profile.registerBasis(basis, nComponents, maxRadius)
91 """Plot a single-element MultiShapeletBasis as a radial profile. 93 ellipse = lsst.afw.geom.ellipses.Ellipse(lsst.afw.geom.ellipses.Axes())
94 coefficients = numpy.ones(1, dtype=float)
95 msf = basis.makeFunction(ellipse, coefficients)
99 n += len(msf.getComponents())
100 z = numpy.zeros((n,) + r.shape, dtype=float)
101 for j, x
in enumerate(r):
104 for i, sf
in enumerate(msf.getComponents()):
106 for j, x
in enumerate(r):
107 z[i+1, j] = evc(x, 0.0)
115 After normalizing by surface brightness at r=1 r_e, integrate the profiles to compare 116 relative fluxes between the true profiles and their approximations. 118 @param[in] maxRadius Maximum radius to integrate the profile, in units of r_e. 119 @param[in] nSteps Number of concrete points at which to evaluate the profile to 120 do the integration (we just use the trapezoidal rule). 122 radii = numpy.linspace(0.0, maxRadius, nSteps)
123 profiles = {name: RadialProfile.get(name)
for name
in (
"exp",
"lux",
"dev",
"luv",
124 "ser2",
"ser3",
"ser5")}
126 for name, profile
in profiles.items():
127 evaluated[name] = profile.evaluate(radii)
128 basis = profile.getBasis(8)
129 evaluated[
"g" + name] =
evaluateRadial(basis, radii, sbNormalize=
True, doComponents=
False)[0, :]
130 fluxes = {name: numpy.trapz(z*radii, radii)
for name, z
in evaluated.items()}
135 """Plot all the profiles defined in this module together: true exp and dev, the SDSS softended/truncated 136 lux and luv, and the multi-Gaussian approximations to all of these. 138 To plot the individual Gaussians that form the multi-Gaussian approximations, pass doComponents=True. 140 Returns a tuple of (figure, axes), where 'figure' is the matplotlib figure that contains the plot, 141 and axes is a 2x4 NumPy array of matplotlib axes objects 143 from matplotlib
import pyplot
144 fig = pyplot.figure(figsize=(9, 4.7))
145 axes = numpy.zeros((2, 4), dtype=object)
146 r1 = numpy.logspace(-3, 0, 1000, base=10)
147 r2 = numpy.linspace(1, 10, 1000)
151 axes[i, j] = fig.add_subplot(2, 4, i*4+j+1)
152 profiles = {name: RadialProfile.get(name)
for name
in (
"exp",
"lux",
"dev",
"luv")}
153 basis = {name: profiles[name].getBasis(8)
for name
in profiles}
154 z = numpy.zeros((2, 4), dtype=object)
155 colors = (
"k",
"g",
"b",
"r") 156 fig.subplots_adjust(wspace=0.025, hspace=0.025, bottom=0.15, left=0.1, right=0.98, top=0.92) 157 centers = [None,
None]
159 for j
in range(0, 4, 2):
160 bbox0 = axes[i, j].get_position()
161 bbox1 = axes[i, j+1].get_position()
162 bbox1.x0 = bbox0.x1 - 0.06
164 centers[j/2] = 0.5*(bbox0.x0 + bbox1.x1)
165 axes[i, j].set_position(bbox0)
166 axes[i, j+1].set_position(bbox1)
167 for j
in range(0, 2):
168 z[0, j] = [
evaluateRadial(basis[k], r[j], sbNormalize=
True, doComponents=doComponents)
169 for k
in (
"exp",
"lux")]
170 z[0, j][0:0] = [profiles[k].evaluate(r[j])[numpy.newaxis, :]
for k
in (
"exp",
"lux")]
171 z[0, j+2] = [
evaluateRadial(basis[k], r[j], sbNormalize=
True, doComponents=doComponents)
172 for k
in (
"dev",
"luv")]
173 z[0, j+2][0:0] = [profiles[k].evaluate(r[j])[numpy.newaxis, :]
for k
in (
"dev",
"luv")]
174 methodNames = [[
"loglog",
"semilogy"], [
"semilogx",
"plot"]]
175 for j
in range(0, 4):
176 z[1, j] = [(z[0, j][0][0, :] - z[0, j][i][0, :])/z[0, j][0][0, :]
for i
in range(0, 4)]
178 method0 = getattr(axes[0, j], methodNames[0][j%2])
179 method1 = getattr(axes[1, j], methodNames[1][j%2])
182 handles.append(method0(r[j%2], y0[0, :], color=colors[k])[0])
184 for l
in range(1, y0.shape[0]):
185 method0(r[j%2], y0[l, :], color=colors[k], alpha=0.25)
186 method1(r[j%2], z[1, j][k], color=colors[k])
187 axes[0, j].set_xticklabels([])
188 axes[0, j].set_ylim(1E-6, 1E3)
189 axes[1, j].set_ylim(-0.2, 1.0)
190 for i, label
in enumerate((
"profile",
"relative error")):
191 axes[i, 0].set_ylabel(label)
192 for t
in axes[i, 0].get_yticklabels():
194 for j
in range(1, 4):
195 axes[0, j].set_yticklabels([])
196 axes[1, j].set_yticklabels([])
197 xticks = [[
'$\\mathdefault{10^{%d}}$' % i
for i
in range(-3, 1)],
198 [str(i)
for i
in range(1, 11)]]
201 for j
in range(0, 4):
202 axes[1, j].set_xticklabels(xticks[j%2])
203 for t
in axes[1, j].get_xticklabels():
205 fig.legend(handles, [
"exp/dev",
"lux/luv",
"approx exp/dev",
"approx lux/luv"],
206 loc=
'lower center', ncol=4)
207 fig.text(centers[0], 0.95,
"exponential", ha=
'center', weight=
'bold')
208 fig.text(centers[1], 0.95,
"de Vaucouleur", ha=
'center', weight=
'bold')
def evaluateRadial(basis, r, sbNormalize=False, doComponents=False)
def plotSuite(doComponents=False)
def registerRadialProfiles()
def integrateNormalizedFluxes(maxRadius=20.0, nSteps=5000)
After normalizing by surface brightness at r=1 r_e, integrate the profiles to compare relative fluxes...