Exemple #1
0
    def __init__(self, settings, thread_count=1):
        import expresso.pycas as pc

        super(Fresnel2D, self).__init__(settings)
        self._thread_count = thread_count

        self._set_initial_field(settings)

        pe = settings.partial_differential_equation
        x, y, z = settings.partial_differential_equation.coordinates

        R, = self._get_evaluators([pc.exp(pe.F * z.step)],
                                  settings,
                                  return_type=pc.Types.Complex)

        D = pc.numpyfy(
            self._evaluate(pc.exp(-pe.A * z.step * (pc.Symbol('kx')**2)),
                           settings))

        if self._F_is_constant_in_z:
            self.__R_step = R(*self._get_indices())
        else:
            self.__R = R

        import numpy as np
        fx = 2 * np.pi / (self._nx * self._get_as(x.step, float, settings))
        kx = fx * (self._nx / 2. - np.abs(np.arange(self._nx) - self._nx / 2.))
        self.__D_step = D(kx=kx, **self._get_indices_dict())
Exemple #2
0
    def __init__(self,settings,thread_count = None):

        super(FresnelPropagator2D,self).__init__(settings)

        if thread_count == None:
            import multiprocessing
            thread_count = multiprocessing.cpu_count()
        self._thread_count = thread_count

        self._set_initial_field(settings)

        pe = settings.partial_differential_equation
        x,y,z = settings.partial_differential_equation.coordinates

        import expresso.pycas as pc
        R, = self._get_evaluators([pc.exp(pe.F*z.step)],settings,return_type=pc.Types.Complex,parallel=not self._F_is_constant_in_z)

        if self._F_is_constant_in_z:
            self.__R_step = R(*self._get_coordinates())
        else:
            self.__R = R

        D = pc.numpyfy( self._evaluate( pc.exp(-z.step*(pe.A * pc.Symbol('kx')**2 + pe.C * pc.Symbol('ky')**2)) ,settings) )

        import numpy as np

        fx = 2*np.pi/(self._nx*self._get_as(x.step,float,settings))
        fy = 2*np.pi/(self._ny*self._get_as(y.step,float,settings))

        ky,kx = np.meshgrid(
            fy*( self._ny/2.-np.abs(np.arange(self._ny)-self._ny/2.) ),
            fx*( self._nx/2.-np.abs(np.arange(self._nx)-self._nx/2.) )
        )

        self.__D_step = D(kx=kx,ky=ky,**self._get_coordinate_dict())
    def __init__(self,settings):        
        super(FiniteDifferencesPropagator2D,self).__init__(settings)
        from _pypropagate import finite_difference_acF,finite_difference_a0F

        pde = settings.partial_differential_equation
        sb = settings.simulation_box

        self._2step = settings.get_numeric( pc.equal(pde.C, 0)  ) != pc.S(True)
        sf = 0.5 if self._2step else 1

        if self._2step:
            ra = settings.get_as(pde.ra*sf,complex)
            rc = settings.get_as(pde.rc*sf,complex)
        else:
            ra = pc.numpyfy(settings.get_unitless(pde.ra))(**{self._y.name + '_i':range(self._ny)})

        z,dz = sb.coordinates[2].symbol,sb.coordinates[2].step

        evaluators = self._get_evaluators([ (pde.rf*sf),
                                            (pde.rf*sf).subs(z,z-dz*sf),
                                            pde.u_boundary,
                                            pde.u_boundary.subs(z,z-dz*sf) ],
                                          settings,return_type=pc.Types.Complex,compile_to_c = True,parallel=True)

        self.__rf = evaluators[:2]
        self.__u_boundary = evaluators[2:]

        self._solver = finite_difference_acF() if self._2step else finite_difference_a0F()
        self._solver.resize(self._nx,self._ny)

        if self._2step:
            self._solver.ra = ra
            self._solver.rc = rc
        else:
            self._solver.ra.as_numpy()[:] = ra
        
        d,u,l,r = [(self._get_x_coordinates(),np.zeros(self._nx,dtype = np.uint)),
                   (self._get_x_coordinates(),np.ones(self._nx,dtype = np.uint)*(self._ny-1)),
                   (np.zeros(self._ny,dtype = np.uint),
                    self._get_y_coordinates()),
                   (np.ones(self._ny,dtype = np.uint)*(self._nx-1),self._get_y_coordinates())]

        self.__boundary_values = [np.concatenate([v[0] for v in d,u,l,r]),
                                  np.concatenate([v[1] for v in d,u,l,r]),
                                  np.zeros(2*self._nx+2*self._ny,dtype=np.uint)]

        self._set_initial_field(settings)
        self._reset()
Exemple #4
0
    def __init__(self, settings, thread_count=None):

        super(Fresnel3D, self).__init__(settings)
        if thread_count == None:
            import multiprocessing
            thread_count = multiprocessing.cpu_count()
        self._thread_count = thread_count
        pe = settings.partial_differential_equation
        x, y, z = settings.partial_differential_equation.coordinates

        import expresso.pycas as pc
        R, = self._get_evaluators([pc.exp(pe.F * z.step)],
                                  settings,
                                  return_type=pc.Types.Complex,
                                  parallel=not self._F_is_constant_in_z)
        if self._F_is_constant_in_z:
            self.__R_step = R(*self._get_indices())
        else:
            self.__R = R

        D = pc.numpyfy(
            self._evaluate(
                pc.exp(
                    -z.step *
                    (pe.A * pc.Symbol('kx')**2 + pe.C * pc.Symbol('ky')**2)),
                settings))

        import numpy as np

        fx = 2 * np.pi / (self._nx * self._get_as(x.step, float, settings))
        fy = 2 * np.pi / (self._ny * self._get_as(y.step, float, settings))

        ky, kx = np.meshgrid(
            fy * (self._ny / 2. - np.abs(np.arange(self._ny) - self._ny / 2.)),
            fx * (self._nx / 2. - np.abs(np.arange(self._nx) - self._nx / 2.)))

        self.__C_is_zero = settings.get_numeric(pe.C) == pc.S(0)

        self.__D_step = D(kx=kx, ky=ky, **self._get_indices_dict())

        self._set_initial_field(settings)
Exemple #5
0
    def __init__(self, settings, thread_count=1):
        import expresso.pycas as pc
        import numpy as np

        pe = settings.partial_differential_equation
        x, y, z = settings.partial_differential_equation.coordinates

        xi = getattr(settings.simulation_box, x.name + 'i')
        self.__ximin = float(settings.get_unitless(xi.subs(x.symbol, 0)))
        self.__ximax = float(settings.get_unitless(xi.subs(x.symbol, x.max)))
        self.__sx = self.__ximax - self.__ximin

        super(FresnelCS, self).__init__(settings)
        self._thread_count = thread_count

        self._set_initial_field(settings)

        R, = self._get_evaluators([pc.exp(pe.F * z.step)],
                                  settings,
                                  return_type=pc.Types.Complex)

        D = pc.numpyfy(
            self._evaluate(pc.exp(-pe.A * z.step * (pc.Symbol('kx')**2)),
                           settings))

        if self._F_is_constant_in_z:
            self.__R_step = R(*self._get_indices())
        else:
            self.__R = R

        kx = hankel_freq(self._nx) * ((self._nx - 1) * 1. / self.__sx)
        self.__D_step = D(kx=kx, **self._get_indices_dict())

        self.__hankel_resample_matrix = hankel_resample_matrix(
            self._nx,
            (np.arange(self._nx) - self.__ximin) * (self._nx * 1. / self.__sx),
            cache_key=(self._nx, self.__ximin, self.__sx),
            xmax=self._nx)
Exemple #6
0
    def __init__(self,settings,thread_count=1):
        import expresso.pycas as pc

        super(FresnelPropagator1D,self).__init__(settings)
        self._thread_count = thread_count

        self._set_initial_field(settings)

        pe = settings.partial_differential_equation
        x,y,z = settings.partial_differential_equation.coordinates

        R, = self._get_evaluators([pc.exp(pe.F*z.step)],settings,return_type=pc.Types.Complex)

        D = pc.numpyfy( self._evaluate( pc.exp(-pe.A*z.step*(pc.Symbol('kx')**2)) , settings) )

        if self._F_is_constant_in_z:
            self.__R_step = R(*self._get_coordinates())
        else:
            self.__R = R

        import numpy as np
        fx = 2*np.pi/(self._nx*self._get_as(x.step,float,settings))
        kx = fx*( self._nx/2.-np.abs(np.arange(self._nx)- self._nx/2.) )
        self.__D_step = D(kx=kx,**self._get_coordinate_dict())
def analytical_circular_waveguide(settings):
    from pypropagate.coordinate_ndarray import CoordinateNDArray
    import expresso.pycas as pc
    import warnings
    import scipy.optimize
    import scipy.integrate
    from scipy.special import j0, j1, k0, k1
    import numpy as np
    from numpy import sqrt, ceil, pi, sign, cos, sin, exp, sum, abs

    s = settings.symbols
    r = settings.waveguide.r
    dx = float(settings.get_numeric(s.dx / r))
    kn = float(settings.get_numeric(s.k * r))
    n1 = settings.get_as(settings.waveguide.n_1, complex)
    n2 = settings.get_as(settings.waveguide.n_2, complex)
    R = 1

    # We will determine um for all guided modes as the roots of the characteristic equation:
    def char(kappa):
        gamma = sqrt(kn**2 * (n1.real**2 - n2.real**2) - kappa**2)
        return gamma * k1(gamma * R) * j0(kappa * R) - kappa * j1(
            kappa * R) * k0(gamma * R)

    kappa_max = kn * sqrt(n1.real**2 - n2.real**2)

    # Dimensionless waveguide paramter
    V = kn * R * sqrt(n1.real**2 - n2.real**2)

    # V determines the number of guided modes
    N = ceil(V / pi)

    # Now find all N roots of the characteristic equation
    kappa_values = []
    segments = N

    with warnings.catch_warnings():
        warnings.simplefilter("ignore")

        while len(kappa_values) < N and segments < 10000:
            segments = segments * 2
            kappa_values = []
            xsegs = np.linspace(0, kappa_max, segments)
            for interval in [(xi, xj)
                             for xi, xj in zip(xsegs[1:], xsegs[:-1])]:
                va, vb = char(np.array(interval))
                # Check if values for interval boundaries are finite and have opposite sign
                if np.isfinite(va) and np.isfinite(
                        vb) and sign(va) != sign(vb):
                    # There might be a root in the interval. Find it using Brent's method!
                    kappa, res = scipy.optimize.brentq(char,
                                                       interval[0],
                                                       interval[1],
                                                       full_output=True)
                    # Check that point converged and value is small (we might have converged to a pole instead)
                    if kappa != 0 and res.converged and abs(char(kappa)) < 1:
                        kappa_values.append(kappa)
        # Reactivate warnings
        warnings.resetwarnings()

    kappa_values = np.array(kappa_values)

    # Define the guided modes
    def psi(kappa, r):
        gamma = sqrt(kn**2 * (n1.real**2 - n2.real**2) - kappa**2)
        return np.piecewise(r, [r < R, r >= R], [
            lambda r: j0(kappa * r),
            lambda r: j0(kappa * R) * k0(gamma * r) / k0(gamma * R)
        ])

    # Normalize the modes by integrating the intensity of the guided modes over R^2
    B_values = [
        (2 * pi *
         scipy.integrate.quad(lambda r: abs(psi(kappa, r))**2 * r, 0, R)[0] +
         (2 * pi * scipy.integrate.quad(lambda r: abs(psi(kappa, r))**2 * r, R,
                                        np.inf)[0]))**(-0.5)
        for kappa in kappa_values
    ]

    #Project the modes onto the symmetrical initial condition
    u0 = pc.numpyfy(settings.get_numeric(s.u0.subs(s.y, 0).subs(s.x, s.x * r)),
                    restype=float)
    c_values = [
        B**2 * 2 * pi *
        (scipy.integrate.quad(lambda r: psi(kappa, r) * u0(x=r) * r, 0, R)[0] +
         scipy.integrate.quad(lambda r: psi(kappa, r) * u0(x=r) * r, R,
                              np.inf)[0])
        for kappa, B in zip(kappa_values, B_values)
    ]

    # Integrate mu
    mu_values = np.array([
        2 * pi * scipy.integrate.quad(
            lambda r: abs(psi(kappa, r) * B)**2 * kn * n1.imag * r, 0, R)[0] +
        2 * pi * scipy.integrate.quad(
            lambda r: abs(psi(kappa, r) * B)**2 * kn * n2.imag * r, R,
            np.inf)[0] for kappa, B in zip(kappa_values, B_values)
    ])
    beta_values = sqrt(n1.real**2 * kn**2 - kappa_values**2)

    # The full solution is the superposition of the guided modes
    def field(x, r):
        solution = None
        for i in range(len(kappa_values)):
            mode = c_values[i] * psi(kappa_values[i], np.abs(r)) * exp(
                (1j * (beta_values[i] - kn) + mu_values[i]) * x)
            if solution is None: solution = mode
            else: solution += mode
        return solution

    linspace = lambda a, b, N: np.linspace(a, b, int(N))
    x_values = linspace(
        *settings.get_as((s.zmin / r, s.zmax / r, s.Nz), float))
    r_values = linspace(
        *settings.get_as((s.xmin / r, s.xmax / r, s.Nx), float))
    data = np.conjugate(field(*np.meshgrid(x_values, r_values)))
    sx = settings.get_numeric(s.sx)
    sz = settings.get_numeric(s.sz)
    res = CoordinateNDArray(data, [(-sx / 2, sx / 2), (0, sz)], (s.x, s.z),
                            settings.get_numeric_transform())
    return res
def analytical_slab_waveguide(settings):
    from pypropagate.coordinate_ndarray import CoordinateNDArray
    import expresso.pycas as pc
    from pypropagate import expression_to_array
    import scipy.optimize
    import scipy.integrate
    from scipy.special import j0, j1, k0, k1
    import numpy as np
    from numpy import sqrt, ceil, pi, sign, cos, sin, exp, tan, sum, abs
    import warnings

    s = settings.symbols
    r = settings.waveguide.r
    k = float(settings.get_numeric(s.k * r))
    n1 = settings.get_as(settings.waveguide.n_1, complex)
    n2 = settings.get_as(settings.waveguide.n_2, complex)
    d = 2
    dx = settings.get_as(s.dx / r, float)

    # We will determine um for all guided modes as the roots of the characteristic equation:
    def Char(kappa):
        gamma = sqrt((n1.real**2 - n2.real**2) * k**2 - kappa**2)
        return kappa * tan(kappa * d / 2) - gamma

    kappa_max = sqrt(n1.real**2 - n2.real**2) * k

    # maximum number of guided modes
    N = ceil(d * kappa_max / (2 * pi))

    # Now find roots of the characteristic equation by searching intervals
    kappa_values = []
    segments = N

    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        while len(kappa_values) < N:
            segments = segments * 2
            if segments > 10000:
                break
            kappa_values = []
            xsegs = np.linspace(0, kappa_max, segments)
            for interval in [(xi, xj)
                             for xi, xj in zip(xsegs[1:], xsegs[:-1])]:
                va, vb = Char(np.array(interval))
                # Check if values for interval boundaries are finite and have opposite sign
                if np.isfinite(va) and np.isfinite(
                        vb) and sign(va) != sign(vb):
                    # There might be a root in the interval. Find it using Brent's method!
                    kappa, res = scipy.optimize.brentq(Char,
                                                       interval[0],
                                                       interval[1],
                                                       full_output=True)
                    # Check that point converged and value is small (we might have converged to a pole instead)
                    if kappa != 0 and res.converged and abs(Char(kappa)) < 1:
                        kappa_values.append(kappa)
    kappa_values = np.array(kappa_values)

    # Define the guided modes
    def psi(kappa, r):
        gamma = sqrt((n1.real**2 - n2.real**2) * k**2 - kappa**2)
        return cos(kappa * r) * (r * 2 <= d) + cos(kappa * d / 2) * exp(
            -gamma * (r - d / 2)) * (r * 2 > d)

    # Normalize the modes by integrating the intensity of the guided modes over R
    B_values = [(2 * scipy.integrate.quad(lambda r: abs(psi(kappa, r))**2, 0,
                                          np.inf)[0])**(-0.5)
                for kappa in kappa_values]

    #Project the modes onto the symmetrical initial condition
    u0 = pc.numpyfy(settings.get_numeric(s.u0.subs(s.y, 0).subs(s.x, s.x * r)),
                    restype=float)
    c_values = [
        2 * B**2 *
        scipy.integrate.quad(lambda r: psi(kappa, r) * u0(x=r), 0, np.inf)[0]
        for kappa, B in zip(kappa_values, B_values)
    ]

    # Determine attenuation coeffcients
    mu_values = np.array([
        2 * B**2 * k *
        (scipy.integrate.quad(lambda r: abs(psi(kappa, r))**2 * n1.imag, 0,
                              d / 2)[0] +
         scipy.integrate.quad(lambda r: abs(psi(kappa, r))**2 * n2.imag, d / 2,
                              np.inf)[0])
        for kappa, B in zip(kappa_values, B_values)
    ])

    # The full solution is the superposition of the guided modes
    def field(x, r):
        solution = None
        for c, b, kappa, mu in zip(c_values, B_values, kappa_values,
                                   mu_values):
            beta = sqrt(k**2 * n1.real**2 - kappa**2)
            mode = c * psi(kappa, r) * exp((mu + 1j * (beta - k)) * x)
            if solution is None: solution = mode
            else: solution += mode
        return solution

    linspace = lambda a, b, N: np.linspace(a, b, int(N))
    x_values = linspace(
        *settings.get_as((s.zmin / r, s.zmax / r, s.Nz), float))
    r_values = abs(
        linspace(*settings.get_as((s.xmin / r, s.xmax / r, s.Nx), float)))
    data = np.conjugate(field(*np.meshgrid(x_values, r_values)))
    sx = settings.get_numeric(s.sx)
    sz = settings.get_numeric(s.sz)
    res = CoordinateNDArray(data, [(-sx / 2, sx / 2), (0, sz)], (s.x, s.z),
                            settings.get_numeric_transform())
    return res