22"""Code to load multi-Gaussian approximations to profiles from "The Tractor"
23into a lsst.shapelet.MultiShapeletBasis.
25Please see the README file in the data directory of the lsst.shapelet
26package for more information.
36from ._shapeletLib
import RadialProfile, MultiShapeletBasis, ShapeletFunction
38_LOG = logging.getLogger(__name__)
42 """Register the pickled profiles in the data directory with the RadialProfile
45 This should only be called at import time by this module; it
's only a function to
46 avoid polluting the module namespace with all the local variables used here.
48 dataDir = os.path.join(os.environ["SHAPELET_DIR"],
"data")
49 regex = re.compile(
r"([a-z]+\d?)_K(\d+)_MR(\d+)\.pickle")
50 for filename
in os.listdir(dataDir):
51 match = regex.match(filename)
55 nComponents = int(match.group(2))
56 maxRadius = int(match.group(3))
58 profile = RadialProfile.get(name)
60 _LOG.warning(
"No C++ profile for multi-Gaussian pickle file '%s'", filename)
62 with open(os.path.join(dataDir, filename),
'rb')
as stream:
63 array = pickle.load(stream, encoding=
'latin1')
64 amplitudes = array[:nComponents]
65 amplitudes /= amplitudes.sum()
66 variances = array[nComponents:]
67 if amplitudes.shape != (nComponents,)
or variances.shape != (nComponents,):
68 _LOG.warning(
"Unknown format for multi-Gaussian pickle file '%s'", filename)
70 basis = MultiShapeletBasis(1)
71 for amplitude, variance
in zip(amplitudes, variances):
72 radius = variance**0.5
73 matrix = numpy.array([[amplitude / ShapeletFunction.FLUX_FACTOR]], dtype=float)
74 basis.addComponent(radius, 0, matrix)
75 profile.registerBasis(basis, nComponents, maxRadius)
84 """Plot a single-element MultiShapeletBasis as a radial profile.
91 `
True` to evaluate components.
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)
114 """Integrate the profiles to compare relative fluxes between the true profiles
115 and their approximations.
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.
122 maxRadius : `float`, optional
123 Maximum radius to integrate the profile,
in units of r_e.
124 nSteps : `int`, optional
125 Number of concrete points at which to evaluate the profile to
126 do the integration (we just use the trapezoidal rule).
130 fluxes : `dict` of `float` values
131 Dictionary of fluxes (``exp``, ``lux``, ``dev``, ``luv``, ``ser2``, ``ser3``,
132 ``ser5``, ``gexp``, ``glux``, ``gdev``, ``gluv``, ``gser2``, ``gser3``, ``gser5``)
134 radii = numpy.linspace(0.0, maxRadius, nSteps)
135 profiles = {name: RadialProfile.get(name) for name
in (
"exp",
"lux",
"dev",
"luv",
136 "ser2",
"ser3",
"ser5")}
138 for name, profile
in profiles.items():
139 evaluated[name] = profile.evaluate(radii)
140 basis = profile.getBasis(8)
141 evaluated[
"g" + name] =
evaluateRadial(basis, radii, sbNormalize=
True, doComponents=
False)[0, :]
142 fluxes = {name: numpy.trapz(z*radii, radii)
for name, z
in evaluated.items()}
147 """Plot all the profiles defined in this module together.
149 Plot all the profiles defined in this module together: true exp
and dev,
150 the SDSS softened/truncated lux
and luv,
and the multi-Gaussian approximations
155 doComponents : `bool`, optional
156 True, to plot the individual Gaussians that form the multi-Gaussian approximations.
160 figure : `matplotlib.figure.Figure`
161 Figure that contains the plot.
162 axes : `numpy.ndarray` of `matplotlib.axes.Axes`
163 A 2x4 NumPy array of matplotlib axes objects.
165 from matplotlib
import pyplot
166 fig = pyplot.figure(figsize=(9, 4.7))
167 axes = numpy.zeros((2, 4), dtype=object)
168 r1 = numpy.logspace(-3, 0, 1000, base=10)
169 r2 = numpy.linspace(1, 10, 1000)
173 axes[i, j] = fig.add_subplot(2, 4, i*4+j+1)
174 profiles = {name: RadialProfile.get(name)
for name
in (
"exp",
"lux",
"dev",
"luv")}
175 basis = {name: profiles[name].getBasis(8)
for name
in profiles}
176 z = numpy.zeros((2, 4), dtype=object)
177 colors = (
"k",
"g",
"b",
"r")
178 fig.subplots_adjust(wspace=0.025, hspace=0.025, bottom=0.15, left=0.1, right=0.98, top=0.92)
179 centers = [
None,
None]
181 for j
in range(0, 4, 2):
182 bbox0 = axes[i, j].get_position()
183 bbox1 = axes[i, j+1].get_position()
184 bbox1.x0 = bbox0.x1 - 0.06
186 centers[j//2] = 0.5*(bbox0.x0 + bbox1.x1)
187 axes[i, j].set_position(bbox0)
188 axes[i, j+1].set_position(bbox1)
189 for j
in range(0, 2):
190 z[0, j] = [
evaluateRadial(basis[k], r[j], sbNormalize=
True, doComponents=doComponents)
191 for k
in (
"exp",
"lux")]
192 z[0, j][0:0] = [profiles[k].evaluate(r[j])[numpy.newaxis, :]
for k
in (
"exp",
"lux")]
193 z[0, j+2] = [
evaluateRadial(basis[k], r[j], sbNormalize=
True, doComponents=doComponents)
194 for k
in (
"dev",
"luv")]
195 z[0, j+2][0:0] = [profiles[k].evaluate(r[j])[numpy.newaxis, :]
for k
in (
"dev",
"luv")]
196 methodNames = [[
"loglog",
"semilogy"], [
"semilogx",
"plot"]]
197 for j
in range(0, 4):
198 z[1, j] = [(z[0, j][0][0, :] - z[0, j][i][0, :])/z[0, j][0][0, :]
for i
in range(0, 4)]
200 method0 = getattr(axes[0, j], methodNames[0][j%2])
201 method1 = getattr(axes[1, j], methodNames[1][j%2])
204 handles.append(method0(r[j%2], y0[0, :], color=colors[k])[0])
206 for ll
in range(1, y0.shape[0]):
207 method0(r[j%2], y0[ll, :], color=colors[k], alpha=0.25)
208 method1(r[j%2], z[1, j][k], color=colors[k])
209 axes[0, j].set_xticklabels([])
210 axes[0, j].set_ylim(1E-6, 1E3)
211 axes[1, j].set_ylim(-0.2, 1.0)
212 for i, label
in enumerate((
"profile",
"relative error")):
213 axes[i, 0].set_ylabel(label)
214 for t
in axes[i, 0].get_yticklabels():
216 for j
in range(1, 4):
217 axes[0, j].set_yticklabels([])
218 axes[1, j].set_yticklabels([])
219 xticks = [[
'$\\mathdefault{10^{%d}}$' % i
for i
in range(-3, 1)],
220 [str(i)
for i
in range(1, 11)]]
223 for j
in range(0, 4):
224 axes[1, j].set_xticklabels(xticks[j%2])
225 for t
in axes[1, j].get_xticklabels():
227 fig.legend(handles, [
"exp/dev",
"lux/luv",
"approx exp/dev",
"approx lux/luv"],
228 loc=
'lower center', ncol=4)
229 fig.text(centers[0], 0.95,
"exponential", ha=
'center', weight=
'bold')
230 fig.text(centers[1], 0.95,
"de Vaucouleur", ha=
'center', weight=
'bold')
An ellipse core for the semimajor/semiminor axis and position angle parametrization (a,...
An ellipse defined by an arbitrary BaseCore and a center point.
evaluateRadial(basis, r, sbNormalize=False, doComponents=False)
plotSuite(doComponents=False)
integrateNormalizedFluxes(maxRadius=20.0, nSteps=5000)