Esempio n. 1
0
def overdensity(Pos, Mass, Nmesh, BoxSize, smoothing):
    """ Pos and smoothing is given in the same unit as BoxSize """
    Ndim = Pos.shape[1]

    assert Ndim == 3

    # first convert to Nmesh units:

    smoothing = smoothing * (1.0 * Nmesh / BoxSize)

    pm = ParticleMesh(BoxSize, Nmesh, verbose=False)

    layout = pm.decompose(Pos)
    tpos = layout.exchange(Pos)

    if numpy.isscalar(P.Mass):
        tmass = P.Mass
    else:
        tmass = layout.exchange(P.Mass)

    pm.r2c(tpos, tmass)

    D = numpy.empty(len(Pos), dtype='f8')

    tmp = pm.c2r(
        tpos, 
        TransferFunction.Inspect('K0', (0, 0, 0)),
#        TransferFunction.NormalizeDC,
        TransferFunction.RemoveDC,
        TransferFunction.Trilinear,
        TransferFunction.Gaussian(smoothing), 
        TransferFunction.Trilinear,
        )
    D[:] = layout.gather(tmp, mode='sum')
    return D
Esempio n. 2
0
def strain_tensor(Pos, Mass, Nmesh, BoxSize, smoothing):
    """ Pos and smoothing is given in the same unit as BoxSize """
    Ndim = Pos.shape[1]

    assert Ndim == 3

    # first convert to Nmesh units:

    smoothing = smoothing * (1.0 * Nmesh / BoxSize)

    pm = ParticleMesh(BoxSize, Nmesh, verbose=False)

    layout = pm.decompose(Pos)
    tpos = layout.exchange(Pos)

    if numpy.isscalar(P.Mass):
        tmass = P.Mass
    else:
        tmass = layout.exchange(P.Mass)

    pm.r2c(tpos, tmass)

    S = numpy.empty((len(Pos), 
                Ndim, Ndim), dtype='f8')

    for i, j in numpy.ndindex(Ndim, Ndim):
        if i > j: continue
        tmp = pm.c2r(
            tpos, 
            TransferFunction.RemoveDC,
            TransferFunction.Trilinear,
            TransferFunction.Gaussian(smoothing), 
            TransferFunction.Poisson, 
            TransferFunction.Constant(4 * numpy.pi * G),
            TransferFunction.Constant(Nmesh ** -2 * BoxSize ** 2),
            TransferFunction.Trilinear,
            TransferFunction.SuperLanzcos(i), 
            TransferFunction.SuperLanzcos(j), 
            TransferFunction.Constant(Nmesh ** 1 * BoxSize ** -1),
            TransferFunction.Constant(Nmesh ** 1 * BoxSize ** -1),
            )

        tmp = layout.gather(tmp, mode='sum')
        # symmetric!
        S[..., i, j] = tmp
        S[..., j, i] = tmp
    return S
Esempio n. 3
0
def GridIC(PowerSpectrum, BoxSize, Ngrid, order=3, preshift=False,
        shift=0.5, ZAonly=False, dtype='f8'):
    """ 2LPT IC from PowerSpectrum for particle grid of Ngrid
    
        CPARAM is a Cosmology object. We also need CPARAM.PowerSpectrum object.

        order is the force differentialtion kernel order. 0 or 3.
        This rather long code does 

        (http://arxiv.org/pdf/astro-ph/9711187v1.pdf)

        A few strange things to notice. 
        The real space gaussian field has an amplitude of 1.0. 
        In gaussian field it is 0.707 in amplitude. (grid **3 to adjust that)

        (Also see http://www.design.caltech.edu/erik/Misc/Gaussian.html)
        (And what FFTW really computes)

        After applying the phase each component is further reduced to 0.5.
        (thus FFT back from delta_k with unity power doesn't give us 
        The PowerSpectrum we use is Pk/(2pi)**3. This is the convention used in
        Gadget.

        The sign of terms.  We agree with the paper but shall pull out the - sign in D2
        in Formula D2; 
        The final result agrees with Martin's code(ic_2lpt_big). 
        The final result differ with 2LPTic by -1.

        Factor 3/7 is multiplied to 2LPT field, abs(D2) and abs(D1) shall be
        applied the ZA and 2LPT before shifting the particles and adding the
        velocity.

        Position of initial points. If set to the center of cells the small
        scale power is smoothed. 
        COLA does a global shift after the readout. This matters if one wants to
        evolve the position by 2LPT. We follow COLA, but give an option to do
        the preshift shift.
    """
    # convert to the internal vel units of Gadget a**2 xdot

    D1 = 1.0
    D2 = D1 ** 2 

    pm = ParticleMesh(BoxSize, Ngrid, verbose=False, dtype='f4')

    x0 = pm.partition.local_i_start
    ni = pm.partition.local_ni
    Nlocal = numpy.prod(ni)

    pos = numpy.empty((Nlocal, 3), dtype=dtype)
    ID = numpy.empty(Nlocal, dtype=('i8'))

    view = pos.reshape(list(ni) + [3])
    view[:, :, :, 0] = numpy.arange(ni[0])[:, None, None] + x0[0]
    view[:, :, :, 1] = numpy.arange(ni[1])[None, :, None] + x0[1]
    view[:, :, :, 2] = numpy.arange(ni[2])[None, None, :] + x0[2]

    view *= 1.0 * BoxSize / Ngrid
    if preshift:
        pos += shift * BoxSize / Ngrid

    # now set up the ranks
    Nlist = numpy.array(pm.comm.allgather(Nlocal), dtype='i8')
    offset = numpy.cumsum(Nlist)
    ID = numpy.arange(Nlocal)
    if pm.comm.rank > 0:
        ID += offset[pm.comm.rank - 1]
    P = dict()
    P['Position'] = pos
    P['ID'] = ID

    layout = pm.decompose(P['Position'])
    tpos = layout.exchange(P['Position'])

    GlobalRNG = numpy.random.RandomState(299995)
    seed = GlobalRNG.randint(999999999, size=pm.comm.size*11)[::11][pm.comm.rank]
    RNG = numpy.random.RandomState(seed)

    pm.real[:] = RNG.normal(scale=1.0, size=pm.real.shape)
#    realstd = pm.comm.allreduce((pm.real ** 2).sum(), MPI.SUM)
#    if pm.comm.rank == 0:
#        print 'realstd', (realstd / pm.Nmesh ** 3) ** 0.5

    pm.real *= Ngrid ** -1.5

    pm.r2c()
#    realstd = pm.comm.allreduce((pm.complex.real ** 2).sum(), MPI.SUM)
#    if pm.comm.rank == 0:
#        print 'complex std', (realstd / (1. + pm.Nmesh//2 +1) / pm.Nmesh ** 2) ** 0.5

    def Transfer(comm, complex, w):
        w2 = 0
        for wi in w:
            w2 = w2 + wi ** 2
        w2 **= 0.5
        w2 *= 1.0 * Ngrid / BoxSize
        wt = PowerSpectrum.PofK(w2)
        wt *= (2 * numpy.pi) ** 3 * (BoxSize) ** -3 * D1 ** 2
        wt **= 0.5 
        wt[w2 == 0] = 0
        # cut at nyquist
        wt[w2 >= numpy.pi / (BoxSize) * Ngrid] =0 
        complex[:] *= wt

    pm.transfer( [
            TransferFunction.RemoveDC,
            Transfer,
            TransferFunction.Poisson,
            TransferFunction.Constant((1.0 * Ngrid / BoxSize) ** -2),
            ])

    # now we have the 'potential' field in K-space

    # ZA displacements
    P['ZA'] = numpy.empty_like(pos)

    for dir in range(3):
        pm.c2r( [
                TransferFunction.SuperLanzcos(dir, order=order),
                TransferFunction.Constant(-1.0 * Ngrid / BoxSize),
                ])
        tmp = pm.readout(tpos)
        tmp = layout.gather(tmp, mode='sum')
        P['ZA'][:, dir] = tmp

    # additional source term for 2 lpt correction

    # diag terms
    diag = []
    for i, dir in enumerate([(0, 0), (1, 1), (2, 2)]):
        pm.c2r([
                TransferFunction.SuperLanzcos(dir[0], order=order),
                TransferFunction.SuperLanzcos(dir[1], order=order),
                TransferFunction.Constant((1.0 * Ngrid / BoxSize) ** 2),
               ])
        diag.append(pm.real.copy())

    field = diag[0] * diag[1]
    field += diag[1] * diag[2] 
    field += diag[2] * diag[0]
    diag = []

    # off terms
    for i, dir in enumerate([(0, 1), (0, 2), (1, 2)]):
        pm.c2r([
                TransferFunction.SuperLanzcos(dir[0], order=order),
                TransferFunction.SuperLanzcos(dir[1], order=order),
                TransferFunction.Constant((1.0 * Ngrid / BoxSize) ** 2),
               ])
        field -= pm.real ** 2
        
    field *= Ngrid ** -3.0
    pm.real[:] = field
    field = []

    pm.r2c()

    P['2LPT'] = numpy.empty_like(pos)

    tmp = pm.readout(tpos)
    P['digrad'] = layout.gather(tmp, mode='sum')

    for dir in range(3):
        pm.c2r([
                TransferFunction.Poisson,
                TransferFunction.SuperLanzcos(dir, order=0),
                TransferFunction.Constant((1.0 * Ngrid / BoxSize) ** -2),
                TransferFunction.Constant(-1.0 * Ngrid / BoxSize),
                ])
        tmp = pm.readout(tpos)
        tmp = layout.gather(tmp, mode='sum')
        P['2LPT'][:, dir] = tmp

    P['2LPT'] *= 3.0 / 7
    # std of displacements
    ZA2 = pm.comm.allreduce(numpy.einsum('ij,ij->', P['ZA'], P['ZA'],
        dtype='f8'), MPI.SUM)
    LPT2 = pm.comm.allreduce(numpy.einsum('ij,ij->', P['2LPT'], P['2LPT'],
        dtype='f8'), MPI.SUM)
    ZAM = pm.comm.allreduce(numpy.max(P['ZA']), MPI.MAX)
    LPTM = pm.comm.allreduce(numpy.max(P['2LPT']), MPI.MAX)

    # norm of the 3-vector!
    ZA2 /= Ngrid ** 3
    LPT2 /= Ngrid ** 3

    stats = dict(
            BoxSize=BoxSize,
            Ngrid=Ngrid,
            stdZA=ZA2 ** 0.5 / BoxSize * Ngrid,
            std2LPT= LPT2 ** 0.5 / BoxSize * Ngrid,
            maxZA= ZAM ** 0.5 / BoxSize * Ngrid,
            max2LPT= LPTM ** 0.5 / BoxSize * Ngrid,
            T=str(pm.T))
    if not preshift:
        P['Position'] += shift * BoxSize / Ngrid
    return P, stats