コード例 #1
0
def ASM_crop(Fin, z, factor=5):
    wavelength = Fin.lam
    # N = Fin.N*factor
    size = Fin.siz
    k = 2 * _np.pi / wavelength
    a1 = Fin.field
    A1 = _fftshift(_fft2(_fftshift(a1)))
    r1 = _np.linspace(-a1.shape[0] / 2, a1.shape[1] / 2 - 1, a1.shape[0])
    s1 = _np.linspace(-a1.shape[0] / 2, a1.shape[1] / 2 - 1, a1.shape[0])

    deltaFX = 1 / size * r1
    deltaFY = 1 / size * s1
    meshgrid = _np.meshgrid(deltaFX, deltaFY)
    H = _np.exp(1.0j * k * z *
                _np.sqrt(1 - _np.power(wavelength * meshgrid[0], 2) -
                         _np.power(wavelength * meshgrid[1], 2)))
    U = _np.multiply(A1, H)
    u = _ifftshift(_ifft2(_ifftshift(U)))
    Fout = Fin
    Fout.field = crop_intensity(u, N)
    return Fout
コード例 #2
0
def ASM_Ext_fail(Fin, z, factor=5):
    wavelength = Fin.lam
    N = Fin.N
    size = Fin.siz
    deltax = size / N
    deltay = size / N
    F_ext = Interpol(Fin, size, N * factor)
    k = 2 * _np.pi / wavelength
    a1 = F_ext.field
    A1 = _fftshift(_fft2(_fftshift(a1)))
    r1 = _np.linspace(-a1.shape[0] / 2, a1.shape[1] / 2 - 1, a1.shape[0])
    s1 = _np.linspace(-a1.shape[0] / 2, a1.shape[1] / 2 - 1, a1.shape[0])
    deltaFX = 1 / (N * deltax) * r1
    deltaFY = 1 / (N * deltay) * s1
    meshgrid = _np.meshgrid(deltaFX, deltaFY)
    H = _np.exp(1.0j * k * z *
                _np.sqrt(1 - _np.power(wavelength * meshgrid[0], 2) -
                         _np.power(wavelength * meshgrid[1], 2)))
    U = _np.multiply(A1, H)
    u = _ifftshift(_ifft2(_ifftshift(U)))
    Fout = Fin
    Fout.field = crop_intensity(u, N)
    return Fout
コード例 #3
0
def ASM(Fin, z):
    # Fout = Field.shallowcopy(Fin)
    Fout = Fin
    wavelength = Fout.lam
    N = Fout.N
    size = Fout.siz
    # deltaX = size/N
    # deltaY = size/N
    k = 2 * _np.pi / wavelength
    a1 = Fout.field
    A1 = _fftshift(_fft2(_fftshift(a1)))
    r1 = _np.linspace(-a1.shape[0] / 2, a1.shape[1] / 2 - 1, a1.shape[0])
    s1 = _np.linspace(-a1.shape[0] / 2, a1.shape[1] / 2 - 1, a1.shape[0])
    deltaFX = 1 / size * r1
    deltaFY = 1 / size * s1
    meshgrid = _np.meshgrid(deltaFX, deltaFY)
    H = _np.exp(1.0j * k * z *
                _np.sqrt(1 - _np.power(wavelength * meshgrid[0], 2) -
                         _np.power(wavelength * meshgrid[1], 2)))
    U = _np.multiply(A1, H)
    u = _ifftshift(_ifft2(_ifftshift(U)))
    Fout.field = u
    return Fout
コード例 #4
0
ファイル: propagators.py プロジェクト: ldoyle/lightpipes
def _field_Fresnel(z, field, dx, lam):
    """
    Separated the "math" logic out so that only standard and numpy types
    are used.
    
    Parameters
    ----------
    z : float
        Propagation distance.
    field : ndarray
        2d complex numpy array (NxN) of the field.
    dx : float
        In units of sim (usually [m]), spacing of grid points in field.
    lam : float
        Wavelength lambda in sim units (usually [m]).

    Returns
    -------
    ndarray (2d, NxN, complex)
        The propagated field.

    """
    """ *************************************************************
    Major differences to Cpp based LP version:
        - dx =siz/N instead of dx=siz/(N-1), more consistent with physics 
            and rest of LP package
        - fftw DLL uses no normalization, numpy uses 1/N on ifft -> omitted
            factor of 1/(2*N)**2 in final calc before return
        - bug in Cpp version: did not touch top row/col, now we extract one
            more row/col to fill entire field. No errors noticed with the new
            method so far
    ************************************************************* """
    tictoc.tic()
    N = field.shape[0]  #assert square

    legacy = True  #switch on to numerically compare oldLP/new results
    if legacy:
        kz = 2. * 3.141592654 / lam * z
        siz = N * dx
        dx = siz / (N - 1)  #like old Cpp code, even though unlogical
    else:
        kz = 2 * _np.pi / lam * z

    cokz = _np.cos(kz)
    sikz = _np.sin(kz)

    No2 = int(N / 2)  #"N over 2"
    """The following section contains a lot of uses which boil down to
    2*No2. For even N, this is N. For odd N, this is NOT redundant:
        2*No2 is N-1 for odd N, therefore sampling an even subset of the
        field instead of the whole field. Necessary for symmetry of first
        step involving Fresnel integral calc.
    """
    if _using_pyfftw:
        in_outF = _pyfftw.zeros_aligned((2 * N, 2 * N), dtype=complex)
        in_outK = _pyfftw.zeros_aligned((2 * N, 2 * N), dtype=complex)
    else:
        in_outF = _np.zeros((2 * N, 2 * N), dtype=complex)
        in_outK = _np.zeros((2 * N, 2 * N), dtype=complex)
    """Our grid is zero-centered, i.e. the 0 coordiante (beam axis) is
    not at field[0,0], but field[No2, No2]. The FFT however is implemented
    such that the frequency 0 will be the first element of the output array,
    and it also expects the input to have the 0 in the corner.
    For the correct handling, an fftshift is necessary before *and* after
    the FFT/IFFT:
        X = fftshift(fft(ifftshift(x)))  # correct magnitude and phase
        x = fftshift(ifft(ifftshift(X)))  # correct magnitude and phase
        X = fftshift(fft(x))  # correct magnitude but wrong phase !
        x = fftshift(ifft(X))  # correct magnitude but wrong phase !
    A numerically faster way to achieve the same result is by multiplying
    with an alternating phase factor as done below.
    Speed for N=2000 was ~0.4s for a double fftshift and ~0.1s for a double
    phase multiplication -> use the phase factor approach (iiij).
    """
    # Create the sign-flip pattern for largest use case and
    # reference smaller grids with a view to the same data for
    # memory saving.
    ii2N = _np.ones((2 * N), dtype=float)
    ii2N[1::2] = -1  #alternating pattern +,-,+,-,+,-,...
    iiij2N = _np.outer(ii2N, ii2N)
    iiij2No2 = iiij2N[:2 * No2, :2 * No2]  #slice to size used below
    iiijN = iiij2N[:N, :N]

    RR = _np.sqrt(1 / (2 * lam * z)) * dx * 2
    io = _np.arange(0,
                    (2 * No2) + 1)  #add one extra to stride fresnel integrals
    R1 = RR * (io - No2)
    fs, fc = _fresnel(R1)
    fss = _np.outer(fs, fs)  #    out[i, j] = a[i] * b[j]
    fsc = _np.outer(fs, fc)
    fcs = _np.outer(fc, fs)
    fcc = _np.outer(fc, fc)
    """Old notation (0.26-0.33s):
        temp_re = (a + b + c - d + ...)
        # numpy func add takes 2 operands A, B only
        # -> each operation needs to create a new temporary array, i.e.
        # ((((a+b)+c)+d)+...)
        # since python does not optimize to += here (at least is seems)
    New notation (0.14-0.16s):
        temp_re = (a + b) #operation with 2 operands
        temp_re += c
        temp_re -= d
        ...
    Wrong notation:
        temp_re = a #copy reference to array a
        temp_re += b
        ...
        # changing `a` in-place, re-using `a` will give corrupted
        # result
    """
    temp_re = (
        fsc[1:, 1:]  #s[i+1]c[j+1]
        + fcs[1:, 1:])  #c[+1]s[+1]
    temp_re -= fsc[:-1, 1:]  #-scp [p=+1, without letter =+0]
    temp_re -= fcs[:-1, 1:]  #-csp
    temp_re -= fsc[1:, :-1]  #-spc
    temp_re -= fcs[1:, :-1]  #-cps
    temp_re += fsc[:-1, :-1]  #sc
    temp_re += fcs[:-1, :-1]  #cs

    temp_im = (
        -fcc[1:, 1:]  #-cpcp
        + fss[1:, 1:])  # +spsp
    temp_im += fcc[:-1, 1:]  # +ccp
    temp_im -= fss[:-1, 1:]  # -ssp
    temp_im += fcc[1:, :-1]  # +cpc
    temp_im -= fss[1:, :-1]  # -sps
    temp_im -= fcc[:-1, :-1]  # -cc
    temp_im += fss[:-1, :-1]  # +ss

    temp_K = 1j * temp_im  # a * b creates copy and casts to complex
    temp_K += temp_re
    temp_K *= iiij2No2
    temp_K *= 0.5
    in_outK[(N - No2):(N + No2), (N - No2):(N + No2)] = temp_K

    in_outF[(N-No2):(N+No2), (N-No2):(N+No2)] \
        = field[(N-2*No2):N,(N-2*No2):N] #cutting off field if N odd (!)
    in_outF[(N - No2):(N + No2), (N - No2):(N + No2)] *= iiij2No2

    tictoc.tic()
    in_outK = _fft2(in_outK, **_fftargs)
    in_outF = _fft2(in_outF, **_fftargs)
    t_fft1 = tictoc.toc()

    in_outF *= in_outK

    in_outF *= iiij2N
    tictoc.tic()
    in_outF = _ifft2(in_outF, **_fftargs)
    t_fft2 = tictoc.toc()
    #TODO check normalization if USE_PYFFTW

    Ftemp = (in_outF[No2:N + No2, No2:N + No2] -
             in_outF[No2 - 1:N + No2 - 1, No2:N + No2])
    Ftemp += in_outF[No2 - 1:N + No2 - 1, No2 - 1:N + No2 - 1]
    Ftemp -= in_outF[No2:N + No2, No2 - 1:N + No2 - 1]
    comp = complex(cokz, sikz)
    Ftemp *= 0.25 * comp
    Ftemp *= iiijN
    field = Ftemp  #reassign without data copy
    ttotal = tictoc.toc()
    t_fft = t_fft1 + t_fft2
    t_outside = ttotal - t_fft
    debug_time = False
    if debug_time:
        print('Time total = fft + rest: {:.2f}={:.2f}+{:.2f}'.format(
            ttotal, t_fft, t_outside))
    return field
コード例 #5
0
ファイル: propagators.py プロジェクト: ldoyle/lightpipes
def Forvard(z, Fin):
    """
    Fout = Forvard(z, Fin)

    :ref:`Propagates the field using a FFT algorithm. <Forvard>`

    Args::
    
        z: propagation distance
        Fin: input field
        
    Returns::
     
        Fout: output field (N x N square array of complex numbers).
            
    Example:
    
    :ref:`Diffraction from a circular aperture <Diffraction>`
    
    """
    if z == 0:
        Fout = Field.copy(Fin)
        return Fout  #return copy to avoid hidden reference
    Fout = Field.shallowcopy(Fin)
    N = Fout.N
    size = Fout.siz
    lam = Fout.lam

    if _using_pyfftw:
        in_out = _pyfftw.zeros_aligned((N, N), dtype=complex)
    else:
        in_out = _np.zeros((N, N), dtype=complex)
    in_out[:, :] = Fin.field

    _2pi = 2 * _np.pi
    legacy = True
    if legacy:
        _2pi = 2. * 3.141592654  #make comparable to Cpp version by using exact same val
    if (z == 0):  #check if z==0, return Fin
        return Fin
    zz = z
    z = abs(z)
    kz = _2pi / lam * z
    cokz = _np.cos(kz)
    sikz = _np.sin(kz)

    # Sign pattern effectively equals an fftshift(), see Fresnel code
    iiN = _np.ones((N, ), dtype=float)
    iiN[1::2] = -1  #alternating pattern +,-,+,-,+,-,...
    iiij = _np.outer(iiN, iiN)
    in_out *= iiij

    z1 = z * lam / 2
    No2 = int(N / 2)

    SW = _np.arange(-No2, N - No2) / size
    SW *= SW
    SSW = SW.reshape((-1, 1)) + SW  #fill NxN shape like np.outer()
    Bus = z1 * SSW
    Ir = Bus.astype(int)  #truncate, not round
    Abus = _2pi * (Ir - Bus)  #clip to interval [-2pi, 0]
    Cab = _np.cos(Abus)
    Sab = _np.sin(Abus)
    CC = Cab + 1j * Sab  #noticably faster than writing exp(1j*Abus)

    if zz >= 0.0:
        in_out = _fft2(in_out, **_fftargs)
        in_out *= CC
        in_out = _ifft2(in_out, **_fftargs)
    else:
        in_out = _ifft2(in_out, **_fftargs)
        CCB = CC.conjugate()
        in_out *= CCB
        in_out = _fft2(in_out, **_fftargs)

    in_out *= (cokz + 1j * sikz)
    in_out *= iiij  #/N**2 omitted since pyfftw already normalizes (numpy too)
    Fout.field = in_out
    return Fout