Skip to content

Commit

Permalink
transpose the template matrices so that individual templates are cont…
Browse files Browse the repository at this point in the history
…iguous in memory,

which speeds up a couple of things including the dot product in build_stellar_continuum.
We may want to do the transposition in the input template file instead.
  • Loading branch information
Jeremy Buhler committed Nov 7, 2024
1 parent 699c9dc commit 99f2f44
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 39 deletions.
36 changes: 18 additions & 18 deletions py/fastspecfit/continuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ def build_stellar_continuum(self, templateflux, templatecoeff,
Parameters
----------
templateflux : :class:`numpy.ndarray` [npix, ntemplates]
templateflux : :class:`numpy.ndarray` [ntemplates, npix]
Rest-frame, native-resolution template spectra corresponding to
`templatewave`.
templatecoeff : :class:`numpy.ndarray` [ntemplates]
Expand All @@ -566,7 +566,7 @@ def build_stellar_continuum(self, templateflux, templatecoeff,
"""
if conv_pre is None or vdisp > Templates.MAX_PRE_VDISP:
# Compute the weighted sum of the templates.
contmodel = templateflux.dot(templatecoeff)
contmodel = templatecoeff.dot(templateflux)

# Optionally convolve to the desired velocity dispersion.
if vdisp is not None:
Expand All @@ -578,13 +578,13 @@ def build_stellar_continuum(self, templateflux, templatecoeff,
flux_lohi, ft_flux_mid, fft_len = conv_pre

# Compute the weighted sum of the templates.
cont_lohi = flux_lohi.dot(templatecoeff)
ft_cont_mid = ft_flux_mid.dot(templatecoeff)
cont_lohi = templatecoeff.dot(flux_lohi)
ft_cont_mid = templatecoeff.dot(ft_flux_mid)

# Convolve to the desired velocity dispersion. Use the vdisp
# convolution that takes precomputed FT of flux for convolved
# region.
flux_len = templateflux.shape[0]
flux_len = templateflux.shape[1]
contmodel = self.templates.convolve_vdisp_from_pre(
cont_lohi, ft_cont_mid, flux_len, fft_len, vdisp)

Expand Down Expand Up @@ -759,7 +759,7 @@ def fit_stellar_continuum(self, templateflux, fit_vdisp=False, conv_pre=None,
Parameters
----------
templateflux : :class:`numpy.ndarray` [npix, ntemplate]
templateflux : :class:`numpy.ndarray` [ntemplate, npix]
Grid of input (model) spectra.
fit_vdisp : :class:`bool`
If `True`, solve for the velocity dispersion;
Expand Down Expand Up @@ -830,7 +830,7 @@ def fit_stellar_continuum(self, templateflux, fit_vdisp=False, conv_pre=None,
if vdisp_bounds is None:
vdisp_bounds = self.vdisp_bounds

ntemplates = templateflux.shape[1]
ntemplates = templateflux.shape[0]

# Unpack the input data to infer the fitting "mode" and the objective
# function.
Expand Down Expand Up @@ -995,7 +995,7 @@ def continuum_fastphot(redshift, objflam, objflamivar, CTools,

t0 = time.time()
tauv, _, coeff, resid = CTools.fit_stellar_continuum(
templates.flux_nomvdisp[:, agekeep], fit_vdisp=False,
templates.flux_nomvdisp[agekeep, :], fit_vdisp=False,
objflam=objflam, objflamistd=objflamistd,
synthphot=True, synthspec=False)
dt = time.time()-t0
Expand All @@ -1017,7 +1017,7 @@ def continuum_fastphot(redshift, objflam, objflamivar, CTools,
# Get the best-fitting model with and without line-emission.
sedmodel = CTools.optimizer_saved_contmodel
sedmodel_nolines = CTools.build_stellar_continuum(
templates.flux_nolines_nomvdisp[:, agekeep], coeff,
templates.flux_nolines_nomvdisp[agekeep, :], coeff,
tauv=tauv, vdisp=None, dust_emission=False)

# Measure Dn(4000) from the line-free model.
Expand All @@ -1042,7 +1042,7 @@ def continuum_fastphot(redshift, objflam, objflamivar, CTools,

for imonte in range(nmonte):
tauv1, _, coeff1, _ = CTools.fit_stellar_continuum(
templates.flux_nomvdisp[:, agekeep], fit_vdisp=False,
templates.flux_nomvdisp[agekeep, :], fit_vdisp=False,
tauv_guess=tauv_guess[imonte], objflam=objflam_monte[:, imonte],
objflamistd=objflamistd, synthphot=True, synthspec=False)

Expand All @@ -1051,7 +1051,7 @@ def continuum_fastphot(redshift, objflam, objflamivar, CTools,

sedmodel_monte[:, imonte] = CTools.optimizer_saved_contmodel
sedmodel_nolines_monte[:, imonte] = CTools.build_stellar_continuum(
templates.flux_nolines_nomvdisp[:, agekeep], coeff1,
templates.flux_nolines_nomvdisp[agekeep, :], coeff1,
tauv=tauv1, vdisp=None, dust_emission=False)

dn4000_model1, _ = Photometry.get_dn4000(
Expand Down Expand Up @@ -1158,7 +1158,7 @@ def continuum_fastspec(redshift, objflam, objflamivar, CTools,
# the IR fluxes put an additional constraint on the dust content.
init_tauv_bounds = (0., 1.)
tauv_nomvdisp, _, coeff_nomvdisp, resid_nomvdisp = CTools.fit_stellar_continuum(
templates.flux_nolines_nomvdisp[:, agekeep], fit_vdisp=False, conv_pre=None,
templates.flux_nolines_nomvdisp[agekeep, :], fit_vdisp=False, conv_pre=None,
tauv_bounds=init_tauv_bounds, specflux=specflux, specistd=specistd,
dust_emission=False, synthspec=True)

Expand All @@ -1178,7 +1178,7 @@ def continuum_fastspec(redshift, objflam, objflamivar, CTools,
input_conv_pre_nolines = templates.conv_pre_select(templates.conv_pre_nolines, agekeep)

tauv_withvdisp, vdisp, coeff_withvdisp, resid_withvdisp = CTools.fit_stellar_continuum(
templates.flux_nolines[:, agekeep], fit_vdisp=True,
templates.flux_nolines[agekeep, :], fit_vdisp=True,
conv_pre=input_conv_pre_nolines,
vdisp_guess=templates.vdisp_nominal,
tauv_bounds=init_tauv_bounds, specflux=specflux,
Expand All @@ -1198,8 +1198,8 @@ def continuum_fastspec(redshift, objflam, objflamivar, CTools,
contmodel = contmodel_withvdisp

# convolve the templates at the derived vdisp
input_templateflux = templates.convolve_vdisp(templates.flux[:, agekeep], vdisp)
input_templateflux_nolines = templates.convolve_vdisp(templates.flux_nolines[:, agekeep], vdisp)
input_templateflux = templates.convolve_vdisp(templates.flux[agekeep, :], vdisp)
input_templateflux_nolines = templates.convolve_vdisp(templates.flux_nolines[agekeep, :], vdisp)
else:
tauv = tauv_nomvdisp
coeff = coeff_nomvdisp
Expand All @@ -1219,7 +1219,7 @@ def continuum_fastspec(redshift, objflam, objflamivar, CTools,

for imonte in range(nmonte):
tauv1, vdisp1, coeff1, _ = CTools.fit_stellar_continuum(
templates.flux_nolines[:, agekeep], fit_vdisp=True,
templates.flux_nolines[agekeep, :], fit_vdisp=True,
conv_pre=input_conv_pre_nolines,
vdisp_guess=vdisp_guess[imonte],
tauv_guess=tauv_guess[imonte],
Expand Down Expand Up @@ -1302,8 +1302,8 @@ def continuum_fastspec(redshift, objflam, objflamivar, CTools,
tauv = tauv_nomvdisp
coeff = coeff_nomvdisp
vdisp = templates.vdisp_nominal
input_templateflux = templates.flux_nomvdisp[:, agekeep]
input_templateflux_nolines = templates.flux_nolines_nomvdisp[:, agekeep]
input_templateflux = templates.flux_nomvdisp[agekeep, :]
input_templateflux_nolines = templates.flux_nolines_nomvdisp[agekeep, :]
contmodel = CTools.optimizer_saved_contmodel.copy()

# Next, estimate the aperture correction.
Expand Down
45 changes: 24 additions & 21 deletions py/fastspecfit/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ def __init__(self, template_file=None, template_version=None, imf=None,
templateinfo = T['METADATA'].read()
templatehdr = T['METADATA'].read_header()

templateflux = np.transpose(templateflux).copy()
templatelineflux = np.transpose(templatelineflux).copy()

self.version = T[0].read_header()['VERSION']

self.imf = templatehdr['IMF']
Expand All @@ -87,8 +90,8 @@ def __init__(self, template_file=None, template_version=None, imf=None,
keeplo = np.searchsorted(templatewave, mintemplatewave, 'left')
keephi = np.searchsorted(templatewave, maxtemplatewave, 'right')
self.wave = templatewave[keeplo:keephi]
self.flux = templateflux[keeplo:keephi, :]
self.flux_nolines = self.flux - templatelineflux[keeplo:keephi, :]
self.flux = templateflux[:, keeplo:keephi]
self.flux_nolines = self.flux - templatelineflux[:, keeplo:keephi]
self.npix = len(self.wave)

# dust attenuation curve
Expand Down Expand Up @@ -196,7 +199,7 @@ def convolve_vdisp_pre(self, templateflux):
Parameters
----------
templateflux: :class:`np.ndarray`
[nwavelengths x ntemplates] array of templates
[ntemplates x nwavelengths] array of templates
Returns
-------
Expand All @@ -215,43 +218,43 @@ def convolve_vdisp_pre(self, templateflux):
lo, hi = self.pixkms_bounds

# extract the un-convolved ranges of templateflux
flux_lo = templateflux[:lo, :]
flux_hi = templateflux[hi:, :]
flux_mid = templateflux[lo:hi, :]
flux_lo = templateflux[:, :lo]
flux_hi = templateflux[:, hi:]
flux_mid = templateflux[:, lo:hi]

mid_len = flux_mid.shape[0]
mid_len = flux_mid.shape[1]

fft_len = sc_fft.next_fast_len(mid_len + kernel_size - 1,
real=True)
ft_flux_mid = sc_fft.rfft(flux_mid, n=fft_len, axis=0)
ft_flux_mid = sc_fft.rfft(flux_mid, n=fft_len)

return (np.vstack((flux_lo, flux_hi)), ft_flux_mid, fft_len)
return (np.hstack((flux_lo, flux_hi)), ft_flux_mid, fft_len)


@staticmethod
def conv_pre_select(conv_pre, cols):
def conv_pre_select(conv_pre, rows):
"""
Filter a set of preprocessing data for vdisp convolution
to use only the specified columns (templates)
to use only the specified rows (templates)
Parameters
----------
conv_pre: :class:`tuple` or None
Preprocessing structure for vdisp convolution (may be None)
cols: :class:`int`
Which columns (templates) from the preprocessing
rows: :class:`int`
Which rows (templates) from the preprocessing
data should we keep?
Returns
-------
Revised preprocessing data with only the selected columns
Revised preprocessing data with only the selected rows
"""
if conv_pre is None:
return None
else:
flux_lohi, ft_flux_mid, fft_len = conv_pre
return (flux_lohi[:, cols], ft_flux_mid[:, cols], fft_len)
return (flux_lohi[rows, :], ft_flux_mid[rows, :], fft_len)


def convolve_vdisp_from_pre(self, flux_lohi, ft_flux_mid, flux_len, fft_len, vdisp):
Expand Down Expand Up @@ -322,7 +325,7 @@ def convolve_vdisp(self, templateflux, vdisp):
----------
templateflux: :class:`np.ndarray`
Either a 1D template array of fluxes, or a 2D array of size
[nfluxes x ntemplates] representing ntemplates fluxes
[ntemplates x nfluxes] representing ntemplates fluxes
vdisp: :class:`float64`
Velocity dispersion to convolve with fluxes
Expand Down Expand Up @@ -354,12 +357,12 @@ def convolve_vdisp(self, templateflux, vdisp):
output[:lo] = templateflux[:lo]
output[hi:] = templateflux[hi:]
else:
ntemplates = templateflux.shape[1]
ntemplates = templateflux.shape[0]
for ii in range(ntemplates):
output[lo:hi, ii] = self.convolve(
templateflux[lo:hi, ii], kernel, mode='same')
output[:lo, :] = templateflux[:lo, :]
output[hi:, :] = templateflux[hi:, :]
output[ii, lo:hi] = self.convolve(
templateflux[ii, lo:hi], kernel, mode='same')
output[:, :lo] = templateflux[:, :lo]
output[:, hi:] = templateflux[:, hi:]

return output

Expand Down

0 comments on commit 99f2f44

Please sign in to comment.