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
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)
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)
93 """Plot a single-element MultiShapeletBasis as a radial profile. 96 coefficients = numpy.ones(1, dtype=float)
97 msf = basis.makeFunction(ellipse, coefficients)
101 n += len(msf.getComponents())
102 z = numpy.zeros((n,) + r.shape, dtype=float)
103 for j, x
in enumerate(r):
106 for i, sf
in enumerate(msf.getComponents()):
108 for j, x
in enumerate(r):
109 z[i+1, j] = evc(x, 0.0)
117 After normalizing by surface brightness at r=1 r_e, integrate the profiles to compare 118 relative fluxes between the true profiles and their approximations. 120 @param[in] maxRadius Maximum radius to integrate the profile, in units of r_e. 121 @param[in] nSteps Number of concrete points at which to evaluate the profile to 122 do the integration (we just use the trapezoidal rule). 124 radii = numpy.linspace(0.0, maxRadius, nSteps)
125 profiles = {name: RadialProfile.get(name)
for name
in (
"exp",
"lux",
"dev",
"luv",
126 "ser2",
"ser3",
"ser5")}
128 for name, profile
in profiles.items():
129 evaluated[name] = profile.evaluate(radii)
130 basis = profile.getBasis(8)
131 evaluated[
"g" + name] =
evaluateRadial(basis, radii, sbNormalize=
True, doComponents=
False)[0, :]
132 fluxes = {name: numpy.trapz(z*radii, radii)
for name, z
in evaluated.items()}
137 """Plot all the profiles defined in this module together: true exp and dev, the SDSS softended/truncated 138 lux and luv, and the multi-Gaussian approximations to all of these. 140 To plot the individual Gaussians that form the multi-Gaussian approximations, pass doComponents=True. 142 Returns a tuple of (figure, axes), where 'figure' is the matplotlib figure that contains the plot, 143 and axes is a 2x4 NumPy array of matplotlib axes objects 145 from matplotlib
import pyplot
146 fig = pyplot.figure(figsize=(9, 4.7))
147 axes = numpy.zeros((2, 4), dtype=object)
148 r1 = numpy.logspace(-3, 0, 1000, base=10)
149 r2 = numpy.linspace(1, 10, 1000)
153 axes[i, j] = fig.add_subplot(2, 4, i*4+j+1)
154 profiles = {name: RadialProfile.get(name)
for name
in (
"exp",
"lux",
"dev",
"luv")}
155 basis = {name: profiles[name].getBasis(8)
for name
in profiles}
156 z = numpy.zeros((2, 4), dtype=object)
157 colors = (
"k",
"g",
"b",
"r") 158 fig.subplots_adjust(wspace=0.025, hspace=0.025, bottom=0.15, left=0.1, right=0.98, top=0.92) 159 centers = [None,
None]
161 for j
in range(0, 4, 2):
162 bbox0 = axes[i, j].get_position()
163 bbox1 = axes[i, j+1].get_position()
164 bbox1.x0 = bbox0.x1 - 0.06
166 centers[j/2] = 0.5*(bbox0.x0 + bbox1.x1)
167 axes[i, j].set_position(bbox0)
168 axes[i, j+1].set_position(bbox1)
169 for j
in range(0, 2):
170 z[0, j] = [
evaluateRadial(basis[k], r[j], sbNormalize=
True, doComponents=doComponents)
171 for k
in (
"exp",
"lux")]
172 z[0, j][0:0] = [profiles[k].evaluate(r[j])[numpy.newaxis, :]
for k
in (
"exp",
"lux")]
173 z[0, j+2] = [
evaluateRadial(basis[k], r[j], sbNormalize=
True, doComponents=doComponents)
174 for k
in (
"dev",
"luv")]
175 z[0, j+2][0:0] = [profiles[k].evaluate(r[j])[numpy.newaxis, :]
for k
in (
"dev",
"luv")]
176 methodNames = [[
"loglog",
"semilogy"], [
"semilogx",
"plot"]]
177 for j
in range(0, 4):
178 z[1, j] = [(z[0, j][0][0, :] - z[0, j][i][0, :])/z[0, j][0][0, :]
for i
in range(0, 4)]
180 method0 = getattr(axes[0, j], methodNames[0][j%2])
181 method1 = getattr(axes[1, j], methodNames[1][j%2])
184 handles.append(method0(r[j%2], y0[0, :], color=colors[k])[0])
186 for l
in range(1, y0.shape[0]):
187 method0(r[j%2], y0[l, :], color=colors[k], alpha=0.25)
188 method1(r[j%2], z[1, j][k], color=colors[k])
189 axes[0, j].set_xticklabels([])
190 axes[0, j].set_ylim(1E-6, 1E3)
191 axes[1, j].set_ylim(-0.2, 1.0)
192 for i, label
in enumerate((
"profile",
"relative error")):
193 axes[i, 0].set_ylabel(label)
194 for t
in axes[i, 0].get_yticklabels():
196 for j
in range(1, 4):
197 axes[0, j].set_yticklabels([])
198 axes[1, j].set_yticklabels([])
199 xticks = [[
'$\\mathdefault{10^{%d}}$' % i
for i
in range(-3, 1)],
200 [str(i)
for i
in range(1, 11)]]
203 for j
in range(0, 4):
204 axes[1, j].set_xticklabels(xticks[j%2])
205 for t
in axes[1, j].get_xticklabels():
207 fig.legend(handles, [
"exp/dev",
"lux/luv",
"approx exp/dev",
"approx lux/luv"],
208 loc=
'lower center', ncol=4)
209 fig.text(centers[0], 0.95,
"exponential", ha=
'center', weight=
'bold')
210 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...