22 """Code to load multi-Gaussian approximations to profiles from "The Tractor" 23 into a lsst.shapelet.MultiShapeletBasis. 25 Please see the README file in the data directory of the lsst.shapelet 26 package for more information. 28 from future
import standard_library
29 standard_library.install_aliases()
30 from builtins
import zip
31 from builtins
import str
32 from builtins
import range
42 from .radialProfile
import RadialProfile
43 from .multiShapeletBasis
import MultiShapeletBasis
44 from .shapeletFunction
import ShapeletFunction
48 """Register the pickled profiles in the data directory with the RadialProfile 51 This should only be called at import time by this module; it's only a function to 52 avoid polluting 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. 100 `True` to evaluate components. 103 coefficients = numpy.ones(1, dtype=float)
104 msf = basis.makeFunction(ellipse, coefficients)
108 n += len(msf.getComponents())
109 z = numpy.zeros((n,) + r.shape, dtype=float)
110 for j, x
in enumerate(r):
113 for i, sf
in enumerate(msf.getComponents()):
115 for j, x
in enumerate(r):
116 z[i+1, j] = evc(x, 0.0)
123 """Integrate the profiles to compare relative fluxes between the true profiles 124 and their approximations. 126 After normalizing by surface brightness at r=1 r_e, integrate the profiles to compare 127 relative fluxes between the true profiles and their approximations. 131 maxRadius : `float`, optional 132 Maximum radius to integrate the profile, in units of r_e. 133 nSteps : `int`, optional 134 Number of concrete points at which to evaluate the profile to 135 do the integration (we just use the trapezoidal rule). 139 fluxes : `dict` of `float` values 140 Dictionary of fluxes (``exp``, ``lux``, ``dev``, ``luv``, ``ser2``, ``ser3``, 141 ``ser5``, ``gexp``, ``glux``, ``gdev``, ``gluv``, ``gser2``, ``gser3``, ``gser5``) 143 radii = numpy.linspace(0.0, maxRadius, nSteps)
144 profiles = {name: RadialProfile.get(name)
for name
in (
"exp",
"lux",
"dev",
"luv",
145 "ser2",
"ser3",
"ser5")}
147 for name, profile
in profiles.items():
148 evaluated[name] = profile.evaluate(radii)
149 basis = profile.getBasis(8)
150 evaluated[
"g" + name] =
evaluateRadial(basis, radii, sbNormalize=
True, doComponents=
False)[0, :]
151 fluxes = {name: numpy.trapz(z*radii, radii)
for name, z
in evaluated.items()}
156 """Plot all the profiles defined in this module together. 158 Plot all the profiles defined in this module together: true exp and dev, 159 the SDSS softened/truncated lux and luv, and the multi-Gaussian approximations 164 doComponents : `bool`, optional 165 True, to plot the individual Gaussians that form the multi-Gaussian approximations. 169 figure : `matplotlib.figure.Figure` 170 Figure that contains the plot. 171 axes : `numpy.ndarray` of `matplotlib.axes.Axes` 172 A 2x4 NumPy array of matplotlib axes objects. 174 from matplotlib
import pyplot
175 fig = pyplot.figure(figsize=(9, 4.7))
176 axes = numpy.zeros((2, 4), dtype=object)
177 r1 = numpy.logspace(-3, 0, 1000, base=10)
178 r2 = numpy.linspace(1, 10, 1000)
182 axes[i, j] = fig.add_subplot(2, 4, i*4+j+1)
183 profiles = {name: RadialProfile.get(name)
for name
in (
"exp",
"lux",
"dev",
"luv")}
184 basis = {name: profiles[name].getBasis(8)
for name
in profiles}
185 z = numpy.zeros((2, 4), dtype=object)
186 colors = (
"k",
"g",
"b",
"r") 187 fig.subplots_adjust(wspace=0.025, hspace=0.025, bottom=0.15, left=0.1, right=0.98, top=0.92) 188 centers = [None,
None]
190 for j
in range(0, 4, 2):
191 bbox0 = axes[i, j].get_position()
192 bbox1 = axes[i, j+1].get_position()
193 bbox1.x0 = bbox0.x1 - 0.06
195 centers[j/2] = 0.5*(bbox0.x0 + bbox1.x1)
196 axes[i, j].set_position(bbox0)
197 axes[i, j+1].set_position(bbox1)
198 for j
in range(0, 2):
199 z[0, j] = [
evaluateRadial(basis[k], r[j], sbNormalize=
True, doComponents=doComponents)
200 for k
in (
"exp",
"lux")]
201 z[0, j][0:0] = [profiles[k].evaluate(r[j])[numpy.newaxis, :]
for k
in (
"exp",
"lux")]
202 z[0, j+2] = [
evaluateRadial(basis[k], r[j], sbNormalize=
True, doComponents=doComponents)
203 for k
in (
"dev",
"luv")]
204 z[0, j+2][0:0] = [profiles[k].evaluate(r[j])[numpy.newaxis, :]
for k
in (
"dev",
"luv")]
205 methodNames = [[
"loglog",
"semilogy"], [
"semilogx",
"plot"]]
206 for j
in range(0, 4):
207 z[1, j] = [(z[0, j][0][0, :] - z[0, j][i][0, :])/z[0, j][0][0, :]
for i
in range(0, 4)]
209 method0 = getattr(axes[0, j], methodNames[0][j%2])
210 method1 = getattr(axes[1, j], methodNames[1][j%2])
213 handles.append(method0(r[j%2], y0[0, :], color=colors[k])[0])
215 for l
in range(1, y0.shape[0]):
216 method0(r[j%2], y0[l, :], color=colors[k], alpha=0.25)
217 method1(r[j%2], z[1, j][k], color=colors[k])
218 axes[0, j].set_xticklabels([])
219 axes[0, j].set_ylim(1E-6, 1E3)
220 axes[1, j].set_ylim(-0.2, 1.0)
221 for i, label
in enumerate((
"profile",
"relative error")):
222 axes[i, 0].set_ylabel(label)
223 for t
in axes[i, 0].get_yticklabels():
225 for j
in range(1, 4):
226 axes[0, j].set_yticklabels([])
227 axes[1, j].set_yticklabels([])
228 xticks = [[
'$\\mathdefault{10^{%d}}$' % i
for i
in range(-3, 1)],
229 [
str(i)
for i
in range(1, 11)]]
232 for j
in range(0, 4):
233 axes[1, j].set_xticklabels(xticks[j%2])
234 for t
in axes[1, j].get_xticklabels():
236 fig.legend(handles, [
"exp/dev",
"lux/luv",
"approx exp/dev",
"approx lux/luv"],
237 loc=
'lower center', ncol=4)
238 fig.text(centers[0], 0.95,
"exponential", ha=
'center', weight=
'bold')
239 fig.text(centers[1], 0.95,
"de Vaucouleur", ha=
'center', weight=
'bold')
def evaluateRadial(basis, r, sbNormalize=False, doComponents=False)
def plotSuite(doComponents=False)
Provides consistent interface for LSST exceptions.
def registerRadialProfiles()
An ellipse defined by an arbitrary BaseCore and a center point.
An ellipse core for the semimajor/semiminor axis and position angle parametrization (a...
def integrateNormalizedFluxes(maxRadius=20.0, nSteps=5000)