Example #1
0
    def powerspectrum_1D(self, k_vec, z1, z2, numz):
        r"""A vectorized routine for calculating the redshift space powerspectrum.

        Parameters
        ----------
        k_vec: array_like
            The magnitude of the k-vector
        redshift: scalar
            Redshift at which to evaluate other parameters

        Returns
        -------
        ps: array_like
            The redshift space power spectrum at the given k-vector and redshift.

        Note that this uses the same ps_vv as the realisation generator until
        the full dd, dv, vv calculation is ready.

        TODO: evaluate this using the same weight function in z as the data.
        """
        c1 = self.cosmology.comoving_distance(z1)
        c2 = self.cosmology.comoving_distance(z2)
        # Construct an array of the redshifts on each slice of the cube.
        comoving_inv = cosmo.inverse_approx(self.cosmology.comoving_distance,
                                            z1, z2)
        da = np.linspace(c1, c2, numz + 1, endpoint=True)
        za = comoving_inv(da)

        # Calculate the bias and growth factors for each slice of the cube.
        mz = self.mean(za)
        bz = self.bias_z(za)
        fz = self.growth_rate(za)
        Dz = self.growth_factor(za) / self.growth_factor(self.ps_redshift)
        pz = self.prefactor(za)

        dfactor = np.mean(Dz * pz * bz)
        vfactor = np.mean(Dz * pz * fz)

        return self.ps_vv(k_vec) * dfactor * dfactor
Example #2
0
    def powerspectrum_1D(self, k_vec, z1, z2, numz):
        r"""A vectorized routine for calculating the redshift space powerspectrum.

        Parameters
        ----------
        k_vec: array_like
            The magnitude of the k-vector
        redshift: scalar
            Redshift at which to evaluate other parameters

        Returns
        -------
        ps: array_like
            The redshift space power spectrum at the given k-vector and redshift.

        Note that this uses the same ps_vv as the realisation generator until
        the full dd, dv, vv calculation is ready.

        TODO: evaluate this using the same weight function in z as the data.
        """
        c1 = self.cosmology.comoving_distance(z1)
        c2 = self.cosmology.comoving_distance(z2)
        # Construct an array of the redshifts on each slice of the cube.
        comoving_inv = cosmo.inverse_approx(self.cosmology.comoving_distance, z1, z2)
        da = np.linspace(c1, c2, numz + 1, endpoint=True)
        za = comoving_inv(da)

        # Calculate the bias and growth factors for each slice of the cube.
        mz = self.mean(za)
        bz = self.bias_z(za)
        fz = self.growth_rate(za)
        Dz = self.growth_factor(za) / self.growth_factor(self.ps_redshift)
        pz = self.prefactor(za)

        dfactor = np.mean(Dz * pz * bz)
        vfactor = np.mean(Dz * pz * fz)

        return self.ps_vv(k_vec) * dfactor * dfactor
def physical_grid(input_array, refinement=2, pad=5, order=2):
    r"""Project from freq, ra, dec into physical coordinates

    Parameters
    ----------
    input_array: np.ndarray
        The freq, ra, dec map

    Returns
    -------
    cube: np.ndarray
        The cube projected back into physical coordinates

    """
    freq_axis = input_array.get_axis('freq') / 1.e6
    ra_axis = input_array.get_axis('ra')
    dec_axis = input_array.get_axis('dec')

    nu_lower, nu_upper = freq_axis.min(), freq_axis.max()
    ra_fact = sp.cos(sp.pi * input_array.info['dec_centre'] / 180.0)
    thetax, thetay = np.ptp(ra_axis), np.ptp(dec_axis)
    thetax *= ra_fact
    (numz, numx, numy) = input_array.shape

    cosmology = cosmo.Cosmology()
    z1 = units.nu21 / nu_upper - 1.0
    z2 = units.nu21 / nu_lower - 1.0
    d1 = cosmology.proper_distance(z1)
    d2 = cosmology.proper_distance(z2)
    c1 = cosmology.comoving_distance(z1)
    c2 = cosmology.comoving_distance(z2)
    c_center = (c1 + c2) / 2.

    # Make cube pixelisation finer, such that angular cube will
    # have sufficient resolution on the closest face.
    phys_dim = np.array([c2 - c1,
                         thetax * d2 * units.degree,
                         thetay * d2 * units.degree])

    # Note that the ratio of deltas in Ra, Dec in degrees may
    # be different than the Ra, Dec in physical coordinates due to
    # rounding onto this grid
    n = np.array([numz, int(d2 / d1 * numx), int(d2 / d1 * numy)])

    # Enlarge cube size by `pad` in each dimension, so raytraced cube
    # sits exactly within the gridded points.
    phys_dim = phys_dim * (n + pad).astype(float) / n.astype(float)
    c1 = c_center - (c_center - c1) * (n[0] + pad) / float(n[0])
    c2 = c_center + (c2 - c_center) * (n[0] + pad) / float(n[0])
    n = n + pad
    # now multiply by scaling for a finer sub-grid
    n = refinement * n

    print "converting from obs. to physical coord refinement=%s, pad=%s" % \
                      (refinement, pad)

    print "(%d, %d, %d)->(%f to %f) x %f x %f (%d, %d, %d) (h^-1 cMpc)^3" % \
                      (numz, numx, numy, c1, c2, \
                       phys_dim[1], phys_dim[2], \
                       n[0], n[1], n[2])

    # this is wasteful in memory, but numpy can be pickled
    phys_map_npy = np.zeros(n)
    phys_map = algebra.make_vect(phys_map_npy, axis_names=('freq', 'ra', 'dec'))
    #mask = np.ones_like(phys_map)
    mask = np.ones_like(phys_map_npy)

    # TODO: should this be more sophisticated? N-1 or N?
    info = {}
    info['axes'] = ('freq', 'ra', 'dec')
    info['type'] = 'vect'

    #info = {'freq_delta': abs(phys_dim[0])/float(n[0]),
    #        'freq_centre': abs(c2+c1)/2.,
    info['freq_delta'] = abs(c2 - c1) / float(n[0] - 1)
    info['freq_centre'] = c1 + info['freq_delta'] * float(n[0] // 2)

    info['ra_delta'] = abs(phys_dim[1]) / float(n[1] - 1)
    #info['ra_centre'] = info['ra_delta'] * float(n[1] // 2)
    info['ra_centre'] = 0.

    info['dec_delta'] = abs(phys_dim[2]) / float(n[2] - 1)
    #info['dec_centre'] = info['dec_delta'] * float(n[2] // 2)
    info['dec_centre'] = 0.

    phys_map.info = info
    print info

    # same as np.linspace(c1, c2, n[0], endpoint=True)
    radius_axis = phys_map.get_axis("freq")
    x_axis = phys_map.get_axis("ra")
    y_axis = phys_map.get_axis("dec")

    # Construct an array of the redshifts on each slice of the cube.
    comoving_inv = cosmo.inverse_approx(cosmology.comoving_distance, z1, z2)
    za = comoving_inv(radius_axis)  # redshifts on the constant-D spacing
    nua = units.nu21 / (1. + za)

    gridy, gridx = np.meshgrid(y_axis, x_axis)
    interpol_grid = np.zeros((3, n[1], n[2]))

    for i in range(n[0]):
        # nua[0] = nu_upper, nua[1] = nu_lower
        #print nua[i], freq_axis[0], freq_axis[-1], (nua[i] - freq_axis[0]) / \
        #                                (freq_axis[-1] - freq_axis[0]) * numz

        interpol_grid[0, :, :] = (nua[i] - freq_axis[0]) / \
                               (freq_axis[-1] - freq_axis[0]) * numz
        proper_z = cosmology.proper_distance(za[i])

        angscale = proper_z * units.degree
        interpol_grid[1, :, :] = gridx / angscale / thetax * numx + numx / 2
        interpol_grid[2, :, :] = gridy / angscale / thetay * numy + numy / 2

        phys_map_npy[i, :, :] = sp.ndimage.map_coordinates(input_array,
                                                           interpol_grid,
                                                           order=order)

        interpol_grid[1, :, :] = np.logical_or(interpol_grid[1, :, :] > numx,
                                             interpol_grid[1, :, :] < 0)
        interpol_grid[2, :, :] = np.logical_or(interpol_grid[1, :, :] > numy,
                                             interpol_grid[1, :, :] < 0)
        mask = np.logical_not(np.logical_or(interpol_grid[1, :, :],
                                            interpol_grid[2, :, :]))
        phys_map_npy *= mask

    return phys_map_npy, info
Example #4
0
    def realisation(
        self,
        z1,
        z2,
        thetax,
        thetay,
        numz,
        numx,
        numy,
        zspace=True,
        refinement=1,
        report_physical=False,
        density_only=False,
        no_mean=False,
        no_evolution=False,
        pad=5,
    ):
        r"""Simulate a redshift-space volume.

        Generates a 3D (angle-angle-redshift) volume from the given
        power spectrum. Currently only works with simply biased power
        spectra (i.e. vv_only). This routine uses a flat sky
        approximation, and so becomes inaccurate when a large volume
        of the sky is simulated.

        Parameters
        ----------
        z1, z2 : scalar
            Lower and upper redshifts of the box.
        thetax, thetay : scalar
            The angular size (in degrees) of the box.
        numz : integer
            The number of bins in redshift.
        numx, numy : integer
            The number of angular pixels along each side.
        zspace : boolean, optional
            If True (default) redshift bins are equally spaced in
            redshift. Otherwise space equally in the scale factor
            (useful for generating an equal range in frequency).
        density_only: boolean
            no velocity contribution
        no_mean: boolean
            do not add the mean temperature
        no_evolution: boolean
            do not let b(z), D(z) etc. evolve: take their mean
        pad: integer
            number of pixels over which to pad the physical region for
            interpolation onto freq, ra, dec; match spline order?

        Returns
        -------
        cube : np.ndarray
            The volume cube.

        """
        d1 = self.cosmology.proper_distance(z1)
        d2 = self.cosmology.proper_distance(z2)
        c1 = self.cosmology.comoving_distance(z1)
        c2 = self.cosmology.comoving_distance(z2)
        c_center = (c1 + c2) / 2.0

        # Make cube pixelisation finer, such that angular cube will
        # have sufficient resolution on the closest face.
        d = np.array([c2 - c1, thetax * d2 * units.degree, thetay * d2 * units.degree])
        # Note that the ratio of deltas in Ra, Dec in degrees may
        # be different than the Ra, Dec in physical coordinates due to
        # rounding onto this grid
        n = np.array([numz, int(d2 / d1 * numx), int(d2 / d1 * numy)])

        # Enlarge cube size by 1 in each dimension, so raytraced cube
        # sits exactly within the gridded points.
        d = d * (n + pad).astype(float) / n.astype(float)
        c1 = c_center - (c_center - c1) * (n[0] + pad) / float(n[0])
        c2 = c_center + (c2 - c_center) * (n[0] + pad) / float(n[0])
        n = n + pad
        # now multiply by scaling for a finer sub-grid
        n = refinement * n

        print "Generating cube: (%f to %f) x %f x %f (%d, %d, %d) (h^-1 cMpc)^3" % (
            c1,
            c2,
            d[1],
            d[2],
            n[0],
            n[1],
            n[2],
        )

        cube = self._realisation_dv(d, n)
        # TODO: this is probably unnecessary now (realisation used to change
        # shape through irfftn)
        n = cube[0].shape

        # Construct an array of the redshifts on each slice of the cube.
        comoving_inv = cosmo.inverse_approx(self.cosmology.comoving_distance, z1, z2)
        da = np.linspace(c1, c2, n[0], endpoint=True)
        za = comoving_inv(da)

        # Calculate the bias and growth factors for each slice of the cube.
        mz = self.mean(za)
        bz = self.bias_z(za)
        fz = self.growth_rate(za)
        Dz = self.growth_factor(za) / self.growth_factor(self.ps_redshift)
        pz = self.prefactor(za)

        # Construct the observable and velocity fields.
        if not no_evolution:
            df = cube[0] * (Dz * pz * bz)[:, np.newaxis, np.newaxis]
            vf = cube[1] * (Dz * pz * fz)[:, np.newaxis, np.newaxis]
        else:
            df = cube[0] * np.mean(Dz * pz * bz)
            vf = cube[1] * np.mean(Dz * pz * fz)

        # Construct the redshift space cube.
        rsf = df
        if not density_only:
            rsf += vf

        if not no_mean:
            rsf += mz[:, np.newaxis, np.newaxis]

        # Find the distances that correspond to a regular redshift
        # spacing (or regular spacing in a).
        if zspace:
            za = np.linspace(z1, z2, numz, endpoint=False)
        else:
            za = 1.0 / np.linspace(1.0 / (1 + z2), 1.0 / (1 + z1), numz, endpoint=False)[::-1] - 1.0

        da = self.cosmology.proper_distance(za)
        xa = self.cosmology.comoving_distance(za)

        # Construct the angular offsets into cube
        tx = np.linspace(-thetax / 2.0, thetax / 2.0, numx) * units.degree
        ty = np.linspace(-thetay / 2.0, thetay / 2.0, numy) * units.degree

        # tgridx, tgridy = np.meshgrid(tx, ty)
        tgridy, tgridx = np.meshgrid(ty, tx)
        tgrid2 = np.zeros((3, numx, numy))
        acube = np.zeros((numz, numx, numy))

        # Iterate over redshift slices, constructing the coordinates
        # and interpolating into the 3d cube. Note that the multipliers scale
        # from 0 to 1, or from i=0 to i=N-1
        for i in range(numz):
            tgrid2[0, :, :] = (xa[i] - c1) / (c2 - c1) * (n[0] - 1.0)
            tgrid2[1, :, :] = (tgridx * da[i]) / d[1] * (n[1] - 1.0) + 0.5 * (n[1] - 1.0)
            tgrid2[2, :, :] = (tgridy * da[i]) / d[2] * (n[2] - 1.0) + 0.5 * (n[2] - 1.0)

            # if(zi > numz - 2):
            # TODO: what order here?; do end-to-end P(k) study
            # acube[i,:,:] = scipy.ndimage.map_coordinates(rsf, tgrid2, order=2)
            acube[i, :, :] = scipy.ndimage.map_coordinates(rsf, tgrid2, order=1)

        if report_physical:
            return acube, rsf, (c1, c2, d[1], d[2])
        else:
            return acube
Example #5
0
from utils import cosmology
from simulations import corr
from utils.cosmology import Cosmology

redshift = 1.

cosmo = Cosmology()
proper = cosmo.proper_distance(redshift)
comoving = cosmo.comoving_distance(redshift)
comoving_inv = cosmology.inverse_approx(cosmo.comoving_distance, 0.6, 1.)

print proper, comoving, comoving_inv(2355.35909781)

Example #6
0
def physical_grid(input_array, refinement=2, pad=5, order=2):
    r"""Project from freq, ra, dec into physical coordinates

    Parameters
    ----------
    input_array: np.ndarray
        The freq, ra, dec map

    Returns
    -------
    cube: np.ndarray
        The cube projected back into physical coordinates

    """
    freq_axis = input_array.get_axis('freq') / 1.e6
    ra_axis = input_array.get_axis('ra')
    dec_axis = input_array.get_axis('dec')

    nu_lower, nu_upper = freq_axis.min(), freq_axis.max()
    ra_fact = sp.cos(sp.pi * input_array.info['dec_centre'] / 180.0)
    thetax, thetay = np.ptp(ra_axis), np.ptp(dec_axis)
    thetax *= ra_fact
    (numz, numx, numy) = input_array.shape

    cosmology = cosmo.Cosmology()
    z1 = units.nu21 / nu_upper - 1.0
    z2 = units.nu21 / nu_lower - 1.0
    d1 = cosmology.proper_distance(z1)
    d2 = cosmology.proper_distance(z2)
    c1 = cosmology.comoving_distance(z1)
    c2 = cosmology.comoving_distance(z2)
    c_center = (c1 + c2) / 2.

    # Make cube pixelisation finer, such that angular cube will
    # have sufficient resolution on the closest face.
    phys_dim = np.array(
        [c2 - c1, thetax * d2 * units.degree, thetay * d2 * units.degree])

    # Note that the ratio of deltas in Ra, Dec in degrees may
    # be different than the Ra, Dec in physical coordinates due to
    # rounding onto this grid
    n = np.array([numz, int(d2 / d1 * numx), int(d2 / d1 * numy)])

    # Enlarge cube size by `pad` in each dimension, so raytraced cube
    # sits exactly within the gridded points.
    phys_dim = phys_dim * (n + pad).astype(float) / n.astype(float)
    c1 = c_center - (c_center - c1) * (n[0] + pad) / float(n[0])
    c2 = c_center + (c2 - c_center) * (n[0] + pad) / float(n[0])
    n = n + pad
    # now multiply by scaling for a finer sub-grid
    n = refinement * n

    print "converting from obs. to physical coord refinement=%s, pad=%s" % \
                      (refinement, pad)

    print "(%d, %d, %d)->(%f to %f) x %f x %f (%d, %d, %d) (h^-1 cMpc)^3" % \
                      (numz, numx, numy, c1, c2, \
                       phys_dim[1], phys_dim[2], \
                       n[0], n[1], n[2])

    # this is wasteful in memory, but numpy can be pickled
    phys_map_npy = np.zeros(n)
    phys_map = algebra.make_vect(phys_map_npy,
                                 axis_names=('freq', 'ra', 'dec'))
    #mask = np.ones_like(phys_map)
    mask = np.ones_like(phys_map_npy)

    # TODO: should this be more sophisticated? N-1 or N?
    info = {}
    info['axes'] = ('freq', 'ra', 'dec')
    info['type'] = 'vect'

    #info = {'freq_delta': abs(phys_dim[0])/float(n[0]),
    #        'freq_centre': abs(c2+c1)/2.,
    info['freq_delta'] = abs(c2 - c1) / float(n[0] - 1)
    info['freq_centre'] = c1 + info['freq_delta'] * float(n[0] // 2)

    info['ra_delta'] = abs(phys_dim[1]) / float(n[1] - 1)
    #info['ra_centre'] = info['ra_delta'] * float(n[1] // 2)
    info['ra_centre'] = 0.

    info['dec_delta'] = abs(phys_dim[2]) / float(n[2] - 1)
    #info['dec_centre'] = info['dec_delta'] * float(n[2] // 2)
    info['dec_centre'] = 0.

    phys_map.info = info
    print info

    # same as np.linspace(c1, c2, n[0], endpoint=True)
    radius_axis = phys_map.get_axis("freq")
    x_axis = phys_map.get_axis("ra")
    y_axis = phys_map.get_axis("dec")

    # Construct an array of the redshifts on each slice of the cube.
    comoving_inv = cosmo.inverse_approx(cosmology.comoving_distance, z1, z2)
    za = comoving_inv(radius_axis)  # redshifts on the constant-D spacing
    nua = units.nu21 / (1. + za)

    gridy, gridx = np.meshgrid(y_axis, x_axis)
    interpol_grid = np.zeros((3, n[1], n[2]))

    for i in range(n[0]):
        # nua[0] = nu_upper, nua[1] = nu_lower
        #print nua[i], freq_axis[0], freq_axis[-1], (nua[i] - freq_axis[0]) / \
        #                                (freq_axis[-1] - freq_axis[0]) * numz

        interpol_grid[0, :, :] = (nua[i] - freq_axis[0]) / \
                               (freq_axis[-1] - freq_axis[0]) * numz
        proper_z = cosmology.proper_distance(za[i])

        angscale = proper_z * units.degree
        interpol_grid[1, :, :] = gridx / angscale / thetax * numx + numx / 2
        interpol_grid[2, :, :] = gridy / angscale / thetay * numy + numy / 2

        phys_map_npy[i, :, :] = sp.ndimage.map_coordinates(input_array,
                                                           interpol_grid,
                                                           order=order)

        interpol_grid[1, :, :] = np.logical_or(interpol_grid[1, :, :] > numx,
                                               interpol_grid[1, :, :] < 0)
        interpol_grid[2, :, :] = np.logical_or(interpol_grid[1, :, :] > numy,
                                               interpol_grid[1, :, :] < 0)
        mask = np.logical_not(
            np.logical_or(interpol_grid[1, :, :], interpol_grid[2, :, :]))
        phys_map_npy *= mask

    return phys_map_npy, info
Example #7
0
    def realisation(self,
                    z1,
                    z2,
                    thetax,
                    thetay,
                    numz,
                    numx,
                    numy,
                    zspace=True,
                    refinement=1,
                    report_physical=False,
                    density_only=False,
                    no_mean=False,
                    no_evolution=False,
                    pad=5):
        r"""Simulate a redshift-space volume.

        Generates a 3D (angle-angle-redshift) volume from the given
        power spectrum. Currently only works with simply biased power
        spectra (i.e. vv_only). This routine uses a flat sky
        approximation, and so becomes inaccurate when a large volume
        of the sky is simulated.

        Parameters
        ----------
        z1, z2 : scalar
            Lower and upper redshifts of the box.
        thetax, thetay : scalar
            The angular size (in degrees) of the box.
        numz : integer
            The number of bins in redshift.
        numx, numy : integer
            The number of angular pixels along each side.
        zspace : boolean, optional
            If True (default) redshift bins are equally spaced in
            redshift. Otherwise space equally in the scale factor
            (useful for generating an equal range in frequency).
        density_only: boolean
            no velocity contribution
        no_mean: boolean
            do not add the mean temperature
        no_evolution: boolean
            do not let b(z), D(z) etc. evolve: take their mean
        pad: integer
            number of pixels over which to pad the physical region for
            interpolation onto freq, ra, dec; match spline order?

        Returns
        -------
        cube : np.ndarray
            The volume cube.

        """
        d1 = self.cosmology.proper_distance(z1)
        d2 = self.cosmology.proper_distance(z2)
        c1 = self.cosmology.comoving_distance(z1)
        c2 = self.cosmology.comoving_distance(z2)
        c_center = (c1 + c2) / 2.

        # Make cube pixelisation finer, such that angular cube will
        # have sufficient resolution on the closest face.
        d = np.array(
            [c2 - c1, thetax * d2 * units.degree, thetay * d2 * units.degree])
        # Note that the ratio of deltas in Ra, Dec in degrees may
        # be different than the Ra, Dec in physical coordinates due to
        # rounding onto this grid
        n = np.array([numz, int(d2 / d1 * numx), int(d2 / d1 * numy)])

        # Enlarge cube size by 1 in each dimension, so raytraced cube
        # sits exactly within the gridded points.
        d = d * (n + pad).astype(float) / n.astype(float)
        c1 = c_center - (c_center - c1) * (n[0] + pad) / float(n[0])
        c2 = c_center + (c2 - c_center) * (n[0] + pad) / float(n[0])
        n = n + pad
        # now multiply by scaling for a finer sub-grid
        n = refinement * n

        print "Generating cube: (%f to %f) x %f x %f (%d, %d, %d) (h^-1 cMpc)^3" % \
              (c1, c2, d[1], d[2], n[0], n[1], n[2])

        cube = self._realisation_dv(d, n)
        # TODO: this is probably unnecessary now (realisation used to change
        # shape through irfftn)
        n = cube[0].shape

        # Construct an array of the redshifts on each slice of the cube.
        comoving_inv = cosmo.inverse_approx(self.cosmology.comoving_distance,
                                            z1, z2)
        da = np.linspace(c1, c2, n[0], endpoint=True)
        za = comoving_inv(da)

        # Calculate the bias and growth factors for each slice of the cube.
        mz = self.mean(za)
        bz = self.bias_z(za)
        fz = self.growth_rate(za)
        Dz = self.growth_factor(za) / self.growth_factor(self.ps_redshift)
        pz = self.prefactor(za)

        # Construct the observable and velocity fields.
        if not no_evolution:
            df = cube[0] * (Dz * pz * bz)[:, np.newaxis, np.newaxis]
            vf = cube[1] * (Dz * pz * fz)[:, np.newaxis, np.newaxis]
        else:
            df = cube[0] * np.mean(Dz * pz * bz)
            vf = cube[1] * np.mean(Dz * pz * fz)

        # Construct the redshift space cube.
        rsf = df
        if not density_only:
            rsf += vf

        if not no_mean:
            rsf += mz[:, np.newaxis, np.newaxis]

        # Find the distances that correspond to a regular redshift
        # spacing (or regular spacing in a).
        if zspace:
            za = np.linspace(z1, z2, numz, endpoint=False)
        else:
            za = 1.0 / np.linspace(
                1.0 / (1 + z2), 1.0 /
                (1 + z1), numz, endpoint=False)[::-1] - 1.0

        da = self.cosmology.proper_distance(za)
        xa = self.cosmology.comoving_distance(za)

        # Construct the angular offsets into cube
        tx = np.linspace(-thetax / 2., thetax / 2., numx) * units.degree
        ty = np.linspace(-thetay / 2., thetay / 2., numy) * units.degree

        #tgridx, tgridy = np.meshgrid(tx, ty)
        tgridy, tgridx = np.meshgrid(ty, tx)
        tgrid2 = np.zeros((3, numx, numy))
        acube = np.zeros((numz, numx, numy))

        # Iterate over redshift slices, constructing the coordinates
        # and interpolating into the 3d cube. Note that the multipliers scale
        # from 0 to 1, or from i=0 to i=N-1
        for i in range(numz):
            tgrid2[0, :, :] = (xa[i] - c1) / (c2 - c1) * (n[0] - 1.)
            tgrid2[1,:,:] = (tgridx * da[i]) / d[1] * (n[1] - 1.) + \
                            0.5*(n[1] - 1.)
            tgrid2[2,:,:] = (tgridy * da[i]) / d[2] * (n[2] - 1.) + \
                            0.5*(n[2] - 1.)

            #if(zi > numz - 2):
            # TODO: what order here?; do end-to-end P(k) study
            #acube[i,:,:] = scipy.ndimage.map_coordinates(rsf, tgrid2, order=2)
            acube[i, :, :] = scipy.ndimage.map_coordinates(rsf,
                                                           tgrid2,
                                                           order=1)

        if report_physical:
            return acube, rsf, (c1, c2, d[1], d[2])
        else:
            return acube