Beispiel #1
0
def _transfer_ray_4x4_1_windows(windows, field, wavenumbers, layer, dmat1, dmat2, betas, phis,
                    nsteps = 1, out = None,
                    betamax = BETAMAX):
        
    d, epsv, epsa = layer

    kd = wavenumbers*d 
    
    if out is None:
        out = np.zeros_like(field)

    for j in range(nsteps):
        field = dotmf(dmat1,field)
        for window, beta, phi in zip(windows, betas, phis):
            alpha, f = alphaf(beta,phi,epsv,epsa)
            p = phasem(alpha,kd[...,None,None])
            
            e = E_mat(f, mode = None)
            ei = inv(e)
            
            f = field * window
            
            
            f = ifft2(f, out = f)
            f = dotmdmf(e,p,ei,f, out = f)  
            f = fft2(field, out = f)
            out += f
            
        out = dotmf(dmat2,out, out = out)
                  
    return out
Beispiel #2
0
def _transfer_ray_4x4_1(field,
                        wavenumbers,
                        layer,
                        dmat1,
                        dmat2,
                        beta=0,
                        phi=0,
                        nsteps=1,
                        betamax=BETAMAX,
                        out=None):

    d, epsv, epsa = layer

    kd = wavenumbers * d

    alpha, f = alphaf(beta, phi, epsv, epsa)
    p = phasem(alpha, kd[..., None, None])

    e = E_mat(f, mode=None)
    ei = inv(e)

    for j in range(nsteps):
        field = dotmf(dmat1, field, out=out)
        field = ifft2(field, out=field)
        field = dotmdmf(e, p, ei, field, out=field)
        field = fft2(field, out=field)
        field = dotmf(dmat2, field, out=out)

    return field
Beispiel #3
0
def transmitted_field_direct(field, beta, phi, n=1.):
    ev = refind2eps([n] * 3)
    ea = np.zeros_like(ev)
    alpha, fmat = alphaf(beta, phi, ev, ea)
    pmat = projection_mat(fmat)
    field0 = np.empty_like(field)
    dotmv(pmat, transpose(field), out=transpose(field0))
    return field0
Beispiel #4
0
def Epn_correction_matrix(beta,
                          phi,
                          ks,
                          d=1.,
                          epsv=(1, 1, 1),
                          epsa=(0, 0, 0.),
                          out=None):
    alpha, f = alphaf(beta, phi, epsv, epsa)
    kd = -np.asarray(ks) * d
    pmat = phase_mat(alpha, kd[..., None, None])
    e = E_mat(f, mode=None)
    ei = inv(e)
    return dotmdm(e, pmat, ei, out=out)
Beispiel #5
0
def ray_jonesmat4x4(
        jmat,
        beta=0,
        phi=0,
        epsv=(1., 1., 1.),
        epsa=(0., 0., 0.),
):
    """Returns a ray polarizer for field data in the laboratory frame.
    
    Numpy broadcasting rules apply.
    
    Parameters
    ----------
    jmat : (...,2,2) array
        A 2x2 jones matrix that needs to be converted to 4x4 mode matrices.
    beta : float
        The beta parameter of the beam.
    phi : float
        The phi parameter of the beam.
    epsv : (...,3) array
        Medium epsilon eigenvalues
    epsa : (...,3) array
        Medium epsilon euler angles
    betamax : float
        The betamax parameter
        
    Returns
    -------
    pmat : (...,4,4) array
        Output matrix.
        
    See Also
    --------
    mode_jonesmat4x4 : for applying the jones matrix in the fft space.
    jonesmat4x4 : for applying the jones matrix in the eigenframe.
    """
    epsv = np.asarray(epsv, CDTYPE)
    epsa = np.asarray(epsa, FDTYPE)
    beta = np.asarray(beta, FDTYPE)
    phi = np.asarray(phi, FDTYPE)

    alpha, f = alphaf(beta, phi, epsv, epsa)

    jmat = rotated_matrix(jmat, phi)
    pmat = jonesmat4x4(jmat, f)

    return pmat
Beispiel #6
0
def _layer_mat3d(k0, d, epsv, epsa, mask, betas, phis, indices, method):
    n = len(betas)
    kd = k0 * d  #/2.
    shape = epsv.shape[-3], epsv.shape[-2]
    if method.startswith("2x2"):
        out = np.empty(shape=(n, n, 2, 2), dtype=CDTYPE)
    else:
        out = np.empty(shape=(n, n, 4, 4), dtype=CDTYPE)

    for j, (beta, phi) in enumerate(zip(betas, phis)):
        if method.startswith("2x2"):
            alpha, fmat = alphaf(beta, phi, epsv, epsa)
            f = tmm.E_mat(fmat, mode=+1, copy=False)
            fi = inv(f)
            pmat = phase_mat(alpha[..., ::2], kd)
        else:
            alpha, f, fi = alphaffi(beta, phi, epsv, epsa)
            pmat = phase_mat(alpha, -kd)
            if method == "4x4_1":
                pmat[..., 1::2] = 0.
            if method != "4x4":
                raise ValueError("Unsupported method.")

        wave = eigenwave(shape, indices[j, 0], indices[j, 1], amplitude=1.)

        m = dotmdm(f, pmat, fi)
        mw = m * wave[..., None, None]

        mf = mfft2(mw, overwrite_x=True)

        #dd = np.linspace(0,1.,10)*d

        # dmat = 0.

        # for dm in dd:

        #     dmat = dmat + second_field_diffraction_matrix(shape, -k0, beta, phi,dm,
        #                                   epsv = (1.5,1.5,1.5),
        #                             epsa = (0.,0.,0.), betamax = 1.4) /len(dd)

        # mf = dotmm(dmat,mf)

        mf = mf[mask, ...]

        out[:, j, :, :] = mf

    return out
Beispiel #7
0
def ray_polarizer(
        jones=(1, 0),
        beta=0,
        phi=0,
        epsv=(1., 1., 1.),
        epsa=(0., 0., 0.),
):
    """Returns a ray polarizer that should be applied in real space. Good for
    beams that can be approximated with a single wave vector and with a direction of 
    ray propagation beta and phi parameters.
    
    See also mode_polarizer, which is for non-planewave field data."""
    epsv = np.asarray(epsv, CDTYPE)
    epsa = np.asarray(epsa, FDTYPE)
    beta = np.asarray(beta, FDTYPE)
    phi = np.asarray(phi, FDTYPE)

    alpha, f = alphaf(beta, phi, epsv, epsa)
    jones = jonesvec(jones, phi)
    pmat = polarizer4x4(jones, f)
    return pmat
Beispiel #8
0
def diffraction_alphaf(shape,
                       ks,
                       epsv=(1., 1., 1.),
                       epsa=(0., 0., 0.),
                       betamax=BETAMAX,
                       out=None):

    ks = np.asarray(ks)
    ks = abs(ks)
    beta, phi = betaphi(shape, ks)
    epsv = np.asarray(epsv, CDTYPE)
    epsa = np.asarray(epsa, FDTYPE)

    alpha, f = alphaf(beta, phi, epsv, epsa, out=out)

    out = (alpha, f)

    mask0 = (beta >= betamax)

    f[mask0] = 0.
    alpha[mask0] = 0.

    return out
Beispiel #9
0
    def test_alphaf(self):
        for e in (1, 2):
            alpha0, f0 = alphaf(0, 0, (e, e, e), (0, 0, 0))

            alpha, f = alphaf(0.00001, 0.0001, (e, e, e), (0, 0, 0))

            self.allclose(np.round(f, 3), np.round(f0, 3))

            alpha, f = alphaf(0., 0, (e, e, e + 0.0001), (0, 0, 0))
            self.allclose(np.round(normalize_f(f), 3),
                          np.round(normalize_f(f0), 3))

            alpha, f = alphaf(0.0001, 0, (e, e, e + 0.0001), (0, 0, 0))
            self.allclose(np.round(normalize_f(f), 3),
                          np.round(normalize_f(f0), 3))

            alpha0, f0 = alphaf(0, np.pi / 4, (e, e, e), (0, 0, 0))

            alpha, f = alphaf(0.0001, np.pi / 4, (e, e, e + 0.0001), (0, 0, 0))
            self.allclose(np.round(normalize_f(f), 3),
                          np.round(normalize_f(f0), 3))
Beispiel #10
0
def illumination_data(shape,
                      wavelengths,
                      pixelsize=1.,
                      beta=0.,
                      phi=0.,
                      intensity=1.,
                      n=1.,
                      focus=0.,
                      window=None,
                      backdir=False,
                      jones=None,
                      diffraction=True,
                      betamax=BETAMAX):
    """Constructs forward (or backward) propagating input illumination field data.
    
    Parameters
    ----------
    shape : (int,int)
        Shape of the illumination
    wavelengths : array_like
        A list of wavelengths.
    pixelsize : float, optional
        Size of the pixel in nm.
    beta : float or array_like of floats, optional
        Beta parameter(s) of the illumination. (Default 0. - normal incidence) 
    phi : float or array_like of floats, optional
        Azimuthal angle(s) of the illumination. 
    n : float, optional
        Refractive index of the media that this illumination field is assumed to
        be propagating in (default 1.)
    focus : float, optional
        Focal plane of the field. By default it is set at z=0. 
    window : array or None, optional
        If None, no window function is applied. This window function
        is multiplied with the constructed plane waves to define field diafragm
        of the input light. See :func:`.window.aperture`.
    backdir : bool, optional
        Whether field is bacward propagating, instead of being forward
        propagating (default)
    jones : jones vector or None, optional
        If specified it has to be a valid jones vector that defines polarization
        of the light. If not given (default), the resulting field will have two
        polarization components. See documentation for details and examples.
    diffraction : bool, optional
        Specifies whether field is diffraction limited or not. By default, the 
        field is filtered so that it has only propagating waves. You can disable
        this by specifying diffraction = False.    
    betamax : float, optional
        The betamax parameter of the propagating field.
    """

    verbose_level = DTMMConfig.verbose
    if verbose_level > 0:
        print("Building illumination data.")
    wavelengths = np.asarray(wavelengths)
    wavenumbers = 2 * np.pi / wavelengths * pixelsize
    if wavenumbers.ndim not in (1, ):
        raise ValueError("Wavelengths should be 1D array")

    if jones is None:
        intensity = intensity / 2.

    waves = illumination_waves(shape,
                               wavenumbers,
                               beta=beta,
                               phi=phi,
                               window=window)
    #intensity = ((np.abs(waves)**2).sum((-2,-1)))* np.asarray(intensity)[...,None]#sum over pixels
    #intensity = intensity * intensity
    mode = -1 if backdir else +1
    _beta = np.asarray(beta, FDTYPE)
    _phi = np.asarray(phi, FDTYPE)
    _intensity = np.asarray(intensity, FDTYPE)

    nrays = len(_beta) if _beta.ndim > 0 else 1

    beta = _beta[..., None, None, None]
    phi = _phi[..., None, None, None]
    intensity = _intensity[..., None, None, None, None]

    epsa = np.asarray((0., 0., 0.), FDTYPE)
    alpha, fmat = alphaf(beta, phi, refind2eps([n] * 3), epsa)
    field = waves2field2(waves, fmat, jones=jones, phi=phi, mode=mode)
    intensity1 = field2intensity(field)
    norm = np.ones_like(intensity1)
    norm[:, ...] = (intensity / nrays)**0.5
    if diffraction == True:
        diffracted_field(field,
                         wavenumbers,
                         d=-focus,
                         n=n,
                         mode=mode,
                         betamax=betamax,
                         out=field)
        intensity2 = field2intensity(field)
        ratio = (intensity1.sum((-2, -1)) / intensity2.sum((-2, -1)))**0.5
        norm[...] = norm * ratio[..., None, None]

    np.multiply(norm[..., None, :, :], field, field)

    return (field, wavelengths, pixelsize)
Beispiel #11
0
def propagate_2x2_full(field,
                       wavenumbers,
                       layer,
                       input_layer=None,
                       nsteps=1,
                       mode=+1,
                       reflection=True,
                       betamax=BETAMAX,
                       refl=None,
                       bulk=None,
                       out=None):

    shape = field.shape[-2:]

    d, epsv, epsa = layer
    if input_layer is not None:
        d_in, epsv_in, epsa_in = input_layer

    kd = wavenumbers * d / nsteps

    if out is None:
        out = np.empty_like(field)

    ii, jj = np.meshgrid(range(shape[0]),
                         range(shape[1]),
                         copy=False,
                         indexing="ij")

    for step in range(nsteps):
        for i in range(len(wavenumbers)):
            ffield = fft2(field[..., i, :, :, :])
            ofield = np.zeros_like(out[..., i, :, :, :])

            b, p = betaphi(shape, wavenumbers[i])
            mask = b < betamax

            amplitude = ffield[..., mask]

            betas = b[mask]
            phis = p[mask]
            iind = ii[mask]
            jind = jj[mask]

            if bulk is not None:
                obulk = bulk[..., i, :, :, :]

            if refl is not None:
                tampl = fft2(refl[..., i, :, :, :])[..., mask]
                orefl = refl[..., i, :, :, :]
                orefl[...] = 0.

            for bp in sorted(zip(range(len(betas)), betas, phis, iind, jind),
                             key=lambda el: el[1],
                             reverse=False):
                #for j,bp in enumerate(zip(betas,phis,iind,jind)):

                j, beta, phi, ieig, jeig = bp

                out_af = alphaf(beta, phi, epsv, epsa)
                alpha, fmat_out = out_af
                e = E_mat(fmat_out, mode=mode)
                ei0 = inv(e)
                ei = ei0
                pm = phase_mat(alpha, kd[i, None, None], mode=mode)
                w = eigenwave(amplitude.shape[:-1] + shape,
                              ieig,
                              jeig,
                              amplitude=amplitude[..., j])
                if step == 0 and reflection != False:
                    alphain, fmat_in = alphaf(beta, phi, epsv_in, epsa_in)
                    if refl is not None:
                        ei, eri = Etri_mat(fmat_in, fmat_out, mode=mode)
                        ein = E_mat(fmat_in, mode=-1 * mode)
                        t = eigenwave(amplitude.shape[:-1] + shape,
                                      ieig,
                                      jeig,
                                      amplitude=tampl[..., j])
                        r = dotmf(eri, w)
                        r = dotmf(ein, r, out=r)
                        np.add(orefl, r, orefl)

                        w = dotmf(ei, w, out=w)
                        t = dotmf(ei0, t, out=t)
                        w = np.add(t, w, out=w)

                    else:
                        ei = Eti_mat(fmat_in, fmat_out, mode=mode)
                        w = dotmf(ei, w, out=w)
                    w = dotmf(dotmd(e, pm), w, out=w)
                    np.add(ofield, w, ofield)

                else:
                    w = dotmdmf(e, pm, ei, w, out=w)
                    np.add(ofield, w, ofield)

                if bulk is not None:
                    e2h = E2H_mat(fmat_out, mode=mode)
                    obulk[..., 1::2, :, :] += dotmf(e2h, w)
                    obulk[..., ::2, :, :] += w

            out[..., i, :, :, :] = ofield

        field = out
    return out, refl
Beispiel #12
0
def _transfer_ray_2x2_1(fft_field,
                        wavenumbers,
                        layer,
                        effective_layer_in,
                        effective_layer_out,
                        dmat1,
                        dmat2,
                        beta=0,
                        phi=0,
                        nsteps=1,
                        mode=+1,
                        reflection=True,
                        betamax=BETAMAX,
                        refl=None,
                        bulk=None,
                        out=None,
                        tmpdata=None):
    _out = {} if tmpdata is None else tmpdata
    #fft_field = fft2(fft_field, out = out)
    shape = fft_field.shape[-2:]
    d_in, epsv_in, epsa_in = effective_layer_in

    d_out, epsv_out, epsa_out = effective_layer_out

    if reflection:
        tmat, rmat = E_tr_matrix(shape,
                                 wavenumbers,
                                 epsv_in=epsv_in,
                                 epsa_in=epsa_in,
                                 epsv_out=epsv_out,
                                 epsa_out=epsa_out,
                                 mode=mode,
                                 betamax=betamax)

    d, epsv, epsa = layer
    alpha, fmat = alphaf(beta, phi, epsv, epsa, out=_out.get("alphaf"))

    e = E_mat(fmat, mode=mode, copy=False)  #2x2 E-only view of fmat
    ei = inv(e, out=_out.get("ei"))
    #
    kd = wavenumbers * d
    p = phase_mat(alpha, kd[..., None, None], mode=mode, out=_out.get("p"))

    if tmpdata is not None:
        _out["alphaf"] = alpha, fmat
        _out["ei"] = ei
        _out["p"] = p

    for j in range(nsteps):
        if j == 0 and reflection:
            #reflect only at the beginning
            if refl is not None:
                trans = refl.copy()
                refl = dotmf(rmat, fft_field, out=refl)
                fft_field = dotmf(tmat, fft_field, out=out)
                fft_field = np.add(fft_field, trans, out=fft_field)

                if mode == -1 and bulk is not None:
                    field = ifft2(fft_field)
                    e2h = E2H_mat(fmat, mode=mode)
                    bulk[..., ::2, :, :] += field
                    bulk[..., 1::2, :, :] += dotmf(e2h, field, out=field)

                fft_field = dotmf(dmat1, fft_field, out=fft_field)
                out = fft_field
            else:
                fft_field = dotmf(tmat, fft_field, out=out)
                fft_field = dotmf(dmat1, fft_field, out=fft_field)
                out = fft_field
        else:
            if dmat1 is not None:
                fft_field = dotmf(dmat1, fft_field, out=out)
            out = fft_field
        field = ifft2(fft_field, out=out)
        field = dotmdmf(e, p, ei, field, out=field)
        fft_field = fft2(field, out=field)
        if dmat2 is not None:
            fft_field = dotmf(dmat2, fft_field, out=fft_field)
    #return fft_field, refl

    #out = ifft2(fft_field, out = out)

    if mode == +1 and bulk is not None:
        field = ifft2(fft_field)
        e2h = E2H_mat(fmat, mode=mode)
        bulk[..., 1::2, :, :] += dotmf(e2h, field)
        bulk[..., ::2, :, :] += field

    return fft_field, refl
Beispiel #13
0
def _transfer_ray_2x2_2(field,
                        wavenumbers,
                        in_layer,
                        out_layer,
                        dmat=None,
                        beta=0,
                        phi=0,
                        nsteps=1,
                        mode=+1,
                        reflection=True,
                        betamax=BETAMAX,
                        refl=None,
                        bulk=None,
                        out=None,
                        tmpdata=None):
    _out = {} if tmpdata is None else tmpdata
    if in_layer is not None:
        d, epsv, epsa = in_layer
        alpha, fmat_in = alphaf(beta, phi, epsv, epsa, out=_out.get("afin"))
        if tmpdata is not None:
            _out["afin"] = alpha, fmat_in
    d, epsv, epsa = out_layer
    alpha, fmat = alphaf(beta, phi, epsv, epsa, out=_out.get("afout"))
    e = E_mat(fmat, mode=mode, copy=False)  #2x2 E-only view of fmat
    #    if refl is not None:
    #        ein = E_mat(fmat_in, mode = mode * (-1)) #reverse direction
    #
    #    if reflection == 0:
    #        kd = wavenumbers * d
    #    else:
    kd = wavenumbers * d / 2
    p = phase_mat(alpha, kd[..., None, None], mode=mode, out=_out.get("p"))

    ei0 = inv(e, out=_out.get("ei0"))
    ei = ei0

    if tmpdata is not None:
        _out["afout"] = alpha, fmat
        _out["ei0"] = ei
        _out["p"] = p

    for j in range(nsteps):
        #reflect only at the beginning
        if j == 0 and reflection != 0:
            #if we need to track reflections (multipass)
            if refl is not None:
                #ei,eri = Etri_mat(fmat_in, fmat, mode = mode, out = _out.get("eieri"))
                tmat, rmat = tr_mat(fmat_in,
                                    fmat,
                                    mode=mode,
                                    out=_out.get("eieri"))
                if tmpdata is not None:
                    #_out["eieri"] = ei,eri
                    _out["eieri"] = tmat, rmat
                trans = refl.copy()
                #refl = dotmf(eri, field, out = refl)
                refl = dotmf(rmat, field, out=refl)
                #field = dotmf(ei,field, out = out)
                field = dotmf(tmat, field, out=out)
                field = np.add(field, trans, out=field)

                if mode == -1 and bulk is not None:
                    #tmp_field = dotmf(e,field)
                    tmp_field = field
                    e2h = E2H_mat(fmat, mode=mode)
                    bulk[..., ::2, :, :] += tmp_field
                    bulk[..., 1::2, :, :] += dotmf(e2h, tmp_field)

                field = dotmf(ei, field, out=field)

                if d != 0.:
                    field = dotmf(dotmd(e, p), field, out=field)

                else:
                    field = dotmf(e, field, out=field)
                out = field

                #                rmat = dotmm(ein, eri, out = eri)
                #                trans = refl.copy()
                #                refl = dotmf(rmat, field, out = refl)
                #                ei0 = inv(e)
                #                field = dotmf(ei,field, out = out)
                #                field = dotmf(e,field) + trans
                #                if d != 0.:
                #                    field = dotmdmf(e,p,ei0,field, out = out)

                ei = ei0
            else:
                ei = Eti_mat(fmat_in, fmat, mode=mode, out=_out.get("eti"))
                field = dotmdmf(e, p, ei, field, out=out)
                out = field
                if tmpdata is not None:
                    _out["eti"] = ei
                ei = ei0
        else:
            #no need to compute if d == 0!.. identity
            if d != 0.:
                field = dotmdmf(e, p, ei, field, out=out)
                out = field
        if dmat is not None:
            field = diffract(field, dmat, out=out)
            out = field
        #no need to compute if d == 0!.. identity
        if d != 0.:
            field = dotmdmf(e, p, ei, field, out=out)

    if mode == +1 and bulk is not None:
        e2h = E2H_mat(fmat, mode=mode)
        bulk[..., 1::2, :, :] += dotmf(e2h, field)
        bulk[..., ::2, :, :] += field

    return field, refl
Beispiel #14
0
def field2jones(field,
                ks=None,
                beta=None,
                phi=None,
                epsv=(1., 1., 1.),
                epsa=(0., 0., 0.),
                mode=+1,
                input_fft=False,
                output_fft=False,
                betamax=BETAMAX):
    """Converts (..., 4,n,m) field array to (..., 2,n,m) jones array
    
    The conversion is done either in reciprocal space (default) or in real space,
    if you provide the beta or phi parameter.
    
    Parameters
    ----------
    field : ndarray
        Input field array data of shape (..., 4,n,m).
    ks : array
        A list of k-values (wave numbers). Required if beta and phi are not provided.
    beta : float, optional
        If set, it defines the field beta parameter, conversion is then done
        in real space.
    phi : float, optional
        If set, it defines the field phi parameter, conversion is then done
        in real space.
    epsv : array
        The epsilon eigenvalues of the medium
    epsv : array
        The Euler rotation angles.
    mode : [+1 | -1]
        Propagation mode, +1 (forward) by default 
    input_fft : bool
        Specifies whether input array is fft data or not.
    output_fft : bool
        Specifies whether output array is fft data or not.
    betamax : float
        Defines the betamax parameter if transformation is done in Fourier space.
        
    Returns
    -------
    jones : ndarray
        Output jones array of shape (..., 2,n,m).
    """
    modal = beta is None and phi is None
    if modal and ks is None:
        raise ValueError(
            "For modal fields, you need to define the wave number(s).")
    elif not modal and ks is not None:
        import warnings
        warnings.warn(
            "`ks`, was set, although it is not required - field is not modal",
            UserWarning)

    field = np.asarray(field)
    out = np.empty(field.shape[:-3] + (2, ) + field.shape[-2:], field.dtype)
    if input_fft == False and modal:
        field = fft2(field)
    elif input_fft == True and not modal:
        field = ifft2(field)
    shape = field.shape[-3:]
    if modal:
        a, fmat = diffraction_alphaf(shape, ks, epsv, epsa, betamax=betamax)
    else:
        a, fmat, = alphaf(beta, phi, epsv, epsa)
    fvec = field2fvec(field)
    evec = field2fvec(out)
    evec[...] = fvec2E(fvec, fmat=fmat, mode=mode)
    if output_fft == False and modal:
        ifft2(out, out=out)
    elif output_fft == True and not modal:
        fft2(out, out=out)
    return out
Beispiel #15
0
def jones2field(jones,
                ks,
                beta=None,
                phi=None,
                epsv=(1., 1., 1.),
                epsa=(0., 0., 0.),
                mode=+1,
                input_fft=False,
                output_fft=False,
                betamax=BETAMAX):
    """Converts (..., 2,n,m) jones array to (..., 4,n,m) field array
    
    The conversion is done either in reciprocal space (default) or in real space,
    if you provide the beta or phi parameter.
    
    Parameters
    ----------
    jones : ndarray
        Input jones array data of shape (..., 2,n,m).
    ks : array
        A list of k-values (wave numbers).
    beta : float, optional
        If set, it defines the field beta parameter, conversion is then done
        in real space.
    phi : float, optional
        If set, it defines the field phi parameter, conversion is then done
        in real space.
    epsv : array
        The epsilon eigenvalues of the medium
    epsv : array
        The Euler rotation angles.
    mode : [+1 | -1]
        Propagation mode, +1 (forward) by default 
    input_fft : bool
        Specifies whether input array is fft data or not.
    output_fft : bool
        Specifies whether output array is fft data or not.
    betamax : float
        Defines the betamax parameter if transformation is done in Fourier space.
        
    Returns
    -------
    field : ndarray
        Output field array of shape (..., 4,n,m).
    """

    jones = np.asarray(jones)
    modal = beta is None and phi is None

    out = np.empty(jones.shape[:-3] + (4, ) + jones.shape[-2:], jones.dtype)
    if input_fft == False and modal:
        jones = fft2(jones)
    elif input_fft == True and not modal:
        jones = ifft2(jones)

    shape = jones.shape[-3:]
    if modal:
        a, fmat = diffraction_alphaf(shape, ks, epsv, epsa, betamax=betamax)
    else:
        a, fmat, = alphaf(beta, phi, epsv, epsa)
    fvec = field2fvec(out)
    jvec = field2fvec(jones)
    E2fvec(jvec, fmat=fmat, mode=mode, out=fvec)
    if output_fft == False and modal:
        ifft2(out, out=out)
    elif output_fft == True and not modal:
        fft2(out, out=out)
    return out