def test_2d_pml_and_absorber(self):
     blayers = [mp.PML(1, mp.Y, mp.High), mp.PML(2, mp.Y, mp.Low),
                mp.Absorber(1, mp.X, mp.High), mp.Absorber(3, mp.X, mp.Low)]
     fs = self.get_fragment_stats(mp.Vector3(), mp.Vector3(30, 30), 2, pml=blayers, geom=[])
     self.assertEqual(fs.num_nonzero_conductivity_pixels, 12000)
     self.assertEqual(fs.num_1d_pml_pixels, 9000)
     self.assertEqual(fs.num_2d_pml_pixels, 0)
     self.assertEqual(fs.num_3d_pml_pixels, 0)
Beispiel #2
0
def main(args):

    resolution = 40
    cell_size = mp.Vector3(z=10)

    boundary_layers = [
        mp.PML(1, direction=mp.Z) if args.pml else mp.Absorber(1,
                                                               direction=mp.Z)
    ]

    sources = [
        mp.Source(src=mp.GaussianSource(1 / 0.803, fwidth=0.1),
                  center=mp.Vector3(),
                  component=mp.Ex)
    ]

    def print_stuff(sim):
        p = sim.get_field_point(mp.Ex, mp.Vector3())
        print("ex:, {}, {}".format(sim.meep_time(), p.real))

    sim = mp.Simulation(cell_size=cell_size,
                        resolution=resolution,
                        dimensions=1,
                        default_material=Al,
                        boundary_layers=boundary_layers,
                        sources=sources)

    sim.run(mp.at_every(10, print_stuff),
            until_after_sources=mp.stop_when_fields_decayed(
                50, mp.Ex, mp.Vector3(), 1e-6))
 def test_3d_with_absorbers(self):
     fs = self.get_fragment_stats(mp.Vector3(), mp.Vector3(30, 30, 30), 3,
                                  geom=[], pml=[mp.Absorber(1)])
     self.assertEqual(fs.num_1d_pml_pixels, 0)
     self.assertEqual(fs.num_2d_pml_pixels, 0)
     self.assertEqual(fs.num_3d_pml_pixels, 0)
     self.assertEqual(fs.num_nonzero_conductivity_pixels, 5048000)
Beispiel #4
0
def main(args):

    resolution = 20
    cell_size = mp.Vector3(z=10)
    dimensions = 1

    # conversion factor fro eV to 1/um
    eV_um_scale = 1 / 1.23984193

    # Al, from Rakic et al., Applied Optics, vol. 32, p. 5274 (1998)
    Al_eps_inf = 1
    Al_plasma_frq = 14.98 * eV_um_scale

    Al_f0 = 0.523
    Al_frq0 = 1e-10
    Al_gam0 = 0.047 * eV_um_scale
    Al_sig0 = (Al_f0 * math.sqrt(Al_plasma_frq)) / (math.sqrt(Al_frq0))

    Al_f1 = 0.050
    Al_frq1 = 1.544 * eV_um_scale  # 803 nm
    Al_gam1 = 0.312 * eV_um_scale
    Al_sig1 = (Al_f1 * math.sqrt(Al_plasma_frq)) / (math.sqrt(Al_frq1))

    E_susceptibilities = [
        mp.DrudeSusceptibility(frequency=Al_frq0, gamma=Al_gam0,
                               sigma=Al_sig0),
        mp.LorentzianSusceptibility(frequency=Al_frq1,
                                    gamma=Al_gam1,
                                    sigma=Al_sig1)
    ]

    Al = mp.Medium(epsilon=Al_eps_inf, E_susceptibilities=E_susceptibilities)

    pml_layers = [
        mp.PML(1, direction=mp.Z) if args.pml else mp.Absorber(1,
                                                               direction=mp.Z)
    ]

    sources = [
        mp.Source(src=mp.GaussianSource(1 / 0.803, fwidth=0.1),
                  center=mp.Vector3(),
                  component=mp.Ex)
    ]

    def print_stuff(sim):
        print("ex:, {}, {}".format(sim.meep_time(),
                                   sim.get_field_point(mp.Ex, mp.Vector3())))

    sim = mp.Simulation(cell_size=cell_size,
                        resolution=resolution,
                        dimensions=dimensions,
                        default_material=Al,
                        boundary_layers=pml_layers,
                        sources=sources)

    sim.run(mp.at_every(10, print_stuff),
            until_after_sources=mp.stop_when_fields_decayed(
                50, mp.Ex, mp.Vector3(), 1e-6))
Beispiel #5
0
    def test_2d_pml_and_absorber(self):
        blayers = [mp.PML(1, mp.Y, mp.High), mp.PML(2, mp.Y, mp.Low),
                   mp.Absorber(1, mp.X, mp.High), mp.Absorber(3, mp.X, mp.Low)]
        fragments = self.get_fragment_stats(mp.Vector3(), mp.Vector3(30, 30), 2, pml=blayers, geom=[])

        num_nonzero_cond = 0
        num_pml_1d = 0
        num_pml_2d = 0
        num_pml_3d = 0

        for f in fragments:
            num_nonzero_cond += f.num_nonzero_conductivity_pixels
            num_pml_1d += f.num_1d_pml_pixels
            num_pml_2d += f.num_2d_pml_pixels
            num_pml_3d += f.num_3d_pml_pixels

        self.assertEqual(num_nonzero_cond, 12000)
        self.assertEqual(num_pml_1d, 9000)
        self.assertEqual(num_pml_2d, 0)
        self.assertEqual(num_pml_3d, 0)
Beispiel #6
0
    def test_3d_with_absorbers(self):
        fs = self.get_fragment_stats(mp.Vector3(), mp.Vector3(30, 30, 30), 3,
                                     geom=[], pml=[mp.Absorber(1)])

        total_nonzero_cond_pixels = 0
        for i in range(len(fs)):
            self.assertEqual(fs[i].num_1d_pml_pixels, 0)
            self.assertEqual(fs[i].num_2d_pml_pixels, 0)
            self.assertEqual(fs[i].num_3d_pml_pixels, 0)
            total_nonzero_cond_pixels += fs[i].num_nonzero_conductivity_pixels

        self.assertEqual(total_nonzero_cond_pixels, 5048000)
Beispiel #7
0
    def setUp(self):

        resolution = 20
        cell_size = mp.Vector3(z=10)
        dimensions = 1

        # conversion factor from eV to 1/um
        eV_um_scale = 1 / 1.23984193

        # Al, from Rakic et al., Applied Optics, vol. 32, p. 5274 (1998)
        Al_eps_inf = 1
        Al_plasma_frq = 14.98 * eV_um_scale

        Al_f0 = 0.523
        Al_frq0 = 1e-10
        Al_gam0 = 0.047 * eV_um_scale
        Al_sig0 = (Al_f0 * math.sqrt(Al_plasma_frq)) / (math.sqrt(Al_frq0))

        Al_f1 = 0.050
        Al_frq1 = 1.544 * eV_um_scale  # 803 nm
        Al_gam1 = 0.312 * eV_um_scale
        Al_sig1 = (Al_f1 * math.sqrt(Al_plasma_frq)) / (math.sqrt(Al_frq1))

        E_susceptibilities = [
            mp.DrudeSusceptibility(frequency=Al_frq0,
                                   gamma=Al_gam0,
                                   sigma=Al_sig0),
            mp.LorentzianSusceptibility(frequency=Al_frq1,
                                        gamma=Al_gam1,
                                        sigma=Al_sig1)
        ]

        Al = mp.Medium(epsilon=Al_eps_inf,
                       E_susceptibilities=E_susceptibilities)

        absorber_layers = [mp.Absorber(1, direction=mp.Z)]

        sources = [
            mp.Source(src=mp.GaussianSource(1 / 0.803, fwidth=0.1),
                      center=mp.Vector3(),
                      component=mp.Ex)
        ]

        self.sim = mp.Simulation(cell_size=cell_size,
                                 resolution=resolution,
                                 dimensions=dimensions,
                                 default_material=Al,
                                 boundary_layers=absorber_layers,
                                 sources=sources)
Beispiel #8
0
    def test_absorber_2d(self):
        source = mp.Source(src=mp.GaussianSource(frequency=0.1, fwidth=0.1),
                           component=mp.Hz,
                           center=mp.Vector3())

        sim = mp.Simulation(cell_size=mp.Vector3(20, 20, 0),
                            resolution=10,
                            sources=[source],
                            boundary_layers=[mp.Absorber(5)])

        sim.run(until_after_sources=1000)
        v = mp.Vector3(4.13, 3.75, 0)
        p = sim.get_field_point(mp.Hz, v)

        self.assertAlmostEqual(-4.058476603571745e-11, p.real)
Beispiel #9
0
    def setUp(self):

        resolution = 40
        cell_size = mp.Vector3(z=10)

        absorber_layers = [mp.Absorber(1, direction=mp.Z)]

        sources = [mp.Source(src=mp.GaussianSource(1 / 0.803, fwidth=0.1), center=mp.Vector3(),
                             component=mp.Ex)]

        self.sim = mp.Simulation(cell_size=cell_size,
                                 resolution=resolution,
                                 dimensions=1,
                                 default_material=Al,
                                 boundary_layers=absorber_layers,
                                 sources=sources)
Beispiel #10
0
    def setUpClass(cls):
        cls.resolution = 30  # pixels/μm

        cls.dpml = 1.0  # PML thickness
        cls.dsub = 1.0  # substrate thickness
        cls.dpad = 1.0  # padding thickness between grating and PML
        cls.gp = 6.0  # grating period
        cls.gh = 0.5  # grating height
        cls.gdc = 0.5  # grating duty cycle

        cls.sx = cls.dpml + cls.dsub + cls.gh + cls.dpad + cls.dpml
        cls.sy = cls.gp

        cls.cell_size = mp.Vector3(cls.sx, cls.sy, 0)

        # replace anisotropic PML with isotropic Absorber to
        # attenuate parallel-directed fields of oblique source
        cls.abs_layers = [mp.Absorber(thickness=cls.dpml, direction=mp.X)]

        wvl = 0.5  # center wavelength
        cls.fcen = 1 / wvl  # center frequency
        cls.df = 0.05 * cls.fcen  # frequency width

        cls.ng = 1.5
        cls.glass = mp.Medium(index=cls.ng)

        cls.geometry = [
            mp.Block(material=cls.glass,
                     size=mp.Vector3(cls.dpml + cls.dsub, mp.inf, mp.inf),
                     center=mp.Vector3(
                         -0.5 * cls.sx + 0.5 * (cls.dpml + cls.dsub), 0, 0)),
            mp.Block(material=cls.glass,
                     size=mp.Vector3(cls.gh, cls.gdc * cls.gp, mp.inf),
                     center=mp.Vector3(
                         -0.5 * cls.sx + cls.dpml + cls.dsub + 0.5 * cls.gh, 0,
                         0))
        ]
Beispiel #11
0
resolution = 50  # pixels/μm

dpml = 2.0  # PML thickness
dsub = 3.0  # substrate thickness
dpad = 3.0  # length of padding between grating and pml
gp = 10.0  # grating period
gh = 0.5  # grating height
gdc = 0.5  # grating duty cycle

sx = dpml + dsub + gh + dpad + dpml
sy = gp

cell_size = mp.Vector3(sx, sy, 0)

# replace anisotropic PML with isotropic Absorber to attenuate parallel-directed fields of oblique source
abs_layers = [mp.Absorber(thickness=dpml, direction=mp.X)]

wvl = 0.5  # center wavelength
fcen = 1 / wvl  # center frequency
df = 0.05 * fcen  # frequency width

ng = 1.5
glass = mp.Medium(index=ng)

# rotation angle of incident planewave; CCW about Y axis, 0 degrees along +X axis
theta_in = math.radians(10.7)

# k (in source medium) with correct length (plane of incidence: XY)
k = mp.Vector3(math.cos(theta_in), math.sin(theta_in), 0).scale(fcen * ng)

symmetries = []
Beispiel #12
0
pos_y = 0
pos_z = height + 0.005

pt = mp.Vector3(pos_x, pos_y, pos_z)

resolution = 150
numx = int(width_cal * resolution)
numy = int(height_cal * resolution)
x_list = np.linspace(-width_cal / 2, width_cal / 2, numx)
y_list = np.linspace(-height_cal / 2, height_cal / 2, numy)
x_grid, y_grid = np.meshgrid(x_list, y_list)
# %%
cell_size = mp.Vector3(length_cal, width_cal, height_cal)

pml_layers = [
    mp.Absorber(thickness=t_pml, direction=mp.Y),
    mp.PML(thickness=t_pml, direction=mp.Z),
    mp.PML(thickness=t_pml, direction=mp.X)
]

# Y dipole
source = [
    mp.Source(mp.ContinuousSource(frequency=omega), component=mp.Ey, center=pt)
]

# We first calculate the normalized power
sim0 = mp.Simulation(resolution=resolution,
                     cell_size=cell_size,
                     boundary_layers=pml_layers,
                     default_material=mp.Medium(index=index_SiN),
                     sources=source,
Beispiel #13
0
####################

cfreq = 1.5
fwidth = 1.5
comp = mp.Hz
sources = [
    mp.Source(mp.GaussianSource(frequency=cfreq, fwidth=fwidth),
              size=mp.Vector3(0, fully, 0),
              component=comp,
              center=mp.Vector3(-sizex / 2, 0))
]

# Absorber on grating side because of field divergence at metal/pml interface
pml_layers = [
    mp.PML(pml_th, direction=mp.X),
    mp.Absorber(pml_th, direction=mp.Y)
]

# empty cell for reference run
geometry = []
sim = mp.Simulation(cell_size=cell,
                    boundary_layers=pml_layers,
                    geometry=geometry,
                    sources=sources,
                    resolution=resolution,
                    filename_prefix="data",
                    split_chunks_evenly=False)

# define monitors for further spectra calculation
mon_height = sizey
nfreq = 200
Beispiel #14
0
  def run_binary_grating_oblique(self, theta):
  
    resolution = 30        # pixels/um

    dpml = 1.0             # PML thickness
    dsub = 1.0             # substrate thickness
    dpad = 1.0             # length of padding between grating and pml
    gp = 6.0               # grating period
    gh = 0.5               # grating height
    gdc = 0.5              # grating duty cycle

    sx = dpml+dsub+gh+dpad+dpml
    sy = gp

    cell_size = mp.Vector3(sx,sy,0)

    # replace anisotropic PML with isotropic Absorber to attenuate parallel-directed fields of oblique source
    abs_layers = [mp.Absorber(thickness=dpml,direction=mp.X)] 

    wvl = 0.5              # center wavelength
    fcen = 1/wvl           # center frequency
    df = 0.05*fcen         # frequency width

    ng = 1.5
    glass = mp.Medium(index=ng)

    # rotation angle of incident planewave; CCW about Y axis, 0 degrees along +X axis
    theta_in = math.radians(theta)

    # k (in source medium) with correct length (plane of incidence: XY)
    k = mp.Vector3(math.cos(theta_in),math.sin(theta_in),0).scale(fcen*ng)

    symmetries = []
    eig_parity = mp.ODD_Z
    if theta_in == 0:
      k = mp.Vector3(0,0,0)
      symmetries = [mp.Mirror(mp.Y)]
      eig_parity += mp.EVEN_Y
  
    def pw_amp(k,x0):
      def _pw_amp(x):
        return cmath.exp(1j*2*math.pi*k.dot(x+x0))
      return _pw_amp

    src_pt = mp.Vector3(-0.5*sx+dpml+0.3*dsub,0,0)
    sources = [mp.Source(mp.GaussianSource(fcen,fwidth=df),
                         component=mp.Ez,
                         center=src_pt,
                         size=mp.Vector3(0,sy,0),
                         amp_func=pw_amp(k,src_pt))]

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=abs_layers,
                        k_point=k,
                        default_material=glass,
                        sources=sources,
                        symmetries=symmetries)

    refl_pt = mp.Vector3(-0.5*sx+dpml+0.5*dsub,0,0)
    refl_flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=refl_pt, size=mp.Vector3(0,sy,0)))

    sim.run(until_after_sources=100)
  
    input_flux = mp.get_fluxes(refl_flux)
    input_flux_data = sim.get_flux_data(refl_flux)

    sim.reset_meep()

    geometry = [mp.Block(material=glass, size=mp.Vector3(dpml+dsub,mp.inf,mp.inf), center=mp.Vector3(-0.5*sx+0.5*(dpml+dsub),0,0)),
                mp.Block(material=glass, size=mp.Vector3(gh,gdc*gp,mp.inf), center=mp.Vector3(-0.5*sx+dpml+dsub+0.5*gh,0,0))]

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=abs_layers,
                        geometry=geometry,
                        k_point=k,
                        sources=sources,
                        symmetries=symmetries)

    refl_flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=refl_pt, size=mp.Vector3(0,sy,0)))
    sim.load_minus_flux_data(refl_flux,input_flux_data)

    tran_pt = mp.Vector3(0.5*sx-dpml-0.5*dpad,0,0)
    tran_flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=tran_pt, size=mp.Vector3(0,sy,0)))

    sim.run(until_after_sources=100)

    nm_r = np.floor((fcen*ng-k.y)*gp)-np.ceil((-fcen*ng-k.y)*gp) # number of reflected orders
    if theta_in == 0:
      nm_r = nm_r/2 # since eig_parity removes degeneracy in y-direction
    nm_r = int(nm_r)

    res = sim.get_eigenmode_coefficients(refl_flux, range(1,nm_r+1), eig_parity=eig_parity)
    r_coeffs = res.alpha

    Rsum = 0
    for nm in range(nm_r):
      Rsum += abs(r_coeffs[nm,0,1])**2/input_flux[0]

    nm_t = np.floor((fcen-k.y)*gp)-np.ceil((-fcen-k.y)*gp)       # number of transmitted orders
    if theta_in == 0:
      nm_t = nm_t/2 # since eig_parity removes degeneracy in y-direction
    nm_t = int(nm_t)

    res = sim.get_eigenmode_coefficients(tran_flux, range(1,nm_t+1), eig_parity=eig_parity)
    t_coeffs = res.alpha

    Tsum = 0
    for nm in range(nm_t):
      Tsum += abs(t_coeffs[nm,0,0])**2/input_flux[0]

    r_flux = mp.get_fluxes(refl_flux)
    t_flux = mp.get_fluxes(tran_flux)
    Rflux = -r_flux[0]/input_flux[0]
    Tflux =  t_flux[0]/input_flux[0]

    self.assertAlmostEqual(Rsum,Rflux,places=2)
    self.assertAlmostEqual(Tsum,Tflux,places=2)
Beispiel #15
0
def simulation_fun():
    resolution = 50
    geom = common.geom
    sig = common.sig

    # source parameters
    fcen = common.fcen
    df = common.df
    df2 = df * 1.4  # source frequency width
    nfreq = 31  # number of frequency bins

    k = False  # ensure PEC boundary condition

    mat_env = mp.Medium(epsilon=1)
    mat_wg = mp.Medium(epsilon=14.44)
    mat_metal = mat.Al  # mp.Medium(epsilon=20)

    nDBR = common.nDBR
    mat_high = mp.Medium(epsilon=14.44)
    mat_low = mp.Medium(epsilon=10.24)
    d_high = 0.25
    d_low = 0.30

    pol = common.pol
    src_cmpt = eval('mp.{}'.format(pol))

    ############################################
    # begin empty and actual simulation
    if geom == 'Empty':
        dpml = 1.0
        sx = 1
        sy = 1
        sz = 1
        sxx = sx + 2 * dpml
        syy = sy + 2 * dpml
        szz = sz + 2 * dpml
        cell_size = mp.Vector3(sxx, syy, szz)
        boundary_layers = [mp.PML(thickness=dpml)]

        # geometry
        geometry = [mp.Block(size=mp.Vector3(sxx, syy, szz), material=mat_wg)]

        # define point
        pt_src = mp.Vector3(0, 0, 0)
        pt_field = mp.Vector3(sx / 4, sy / 4, 0)
        pt_flux = mp.Vector3(0, 0, 0)
        l_flux = 0.1
        frs_src = my.FluxRegions_Cube_Center(l_flux, pt_flux)

        # sources
        sources = [
            mp.Source(mp.GaussianSource(fcen, fwidth=df2),
                      component=src_cmpt,
                      center=pt_src,
                      size=mp.Vector3(0, 0, 0))
        ]

        # symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)]
        if src_cmpt == mp.Ex:
            symmetries = [
                mp.Mirror(mp.X, -1),
                mp.Mirror(mp.Y, +1),
                mp.Mirror(mp.Z, +1)
            ]
        elif src_cmpt == mp.Ey:
            symmetries = [
                mp.Mirror(mp.X, +1),
                mp.Mirror(mp.Y, -1),
                mp.Mirror(mp.Z, +1)
            ]
        elif src_cmpt == mp.Ez:
            symmetries = [
                mp.Mirror(mp.X, +1),
                mp.Mirror(mp.Y, +1),
                mp.Mirror(mp.Z, -1)
            ]
        else:
            return None

    else:
        ### actually simulations
        # from bottom up
        t_front = 0.1
        t_metal = 0.2
        t_wg = common.t
        t_DBR = nDBR * (d_high + d_low)
        t_back = 0.2

        a = common.a
        dx = common.dx
        dy = common.dy
        dz = common.dz

        dpmlxy = a  # PML thickness
        dpmlz = 1
        sx = 4
        sy = 12
        sz = t_front + t_metal + t_wg + t_DBR + t_back
        sxx = sx + 2 * dpmlxy
        syy = sy + 2 * dpmlxy
        szz = sz + dpmlz
        cell_size = mp.Vector3(sxx, syy, szz)

        # pml
        boundary_layers = [
            mp.Absorber(thickness=dpmlxy, direction=mp.X),
            mp.Absorber(thickness=dpmlxy, direction=mp.Y),
            mp.PML(thickness=dpmlz, direction=mp.Z, side=mp.High)
        ]

        # geometry
        tts = [t_front, t_metal, t_wg]
        ccs = my.center_from_thickness(tts, -szz / 2)

        geometry = [
            mp.Block(size=mp.Vector3(2 * sxx, 2 * syy, 2 * szz),
                     center=mp.Vector3(0, 0, 0),
                     material=mat_wg),
            mp.Block(size=mp.Vector3(sxx, syy, tts[1]),
                     center=mp.Vector3(0, 0, ccs[1]),
                     material=mat_metal),
            mp.Block(size=mp.Vector3(sxx, syy, tts[2]),
                     center=mp.Vector3(0, 0, ccs[2]),
                     material=mat_wg),
        ]

        z0 = -szz / 2 + t_front + t_metal + t_wg  # waveguide/DBR interface
        for i in range(nDBR):
            # add low
            geometry.append(
                mp.Block(size=mp.Vector3(sxx, syy, d_low),
                         center=mp.Vector3(0, 0, z0 + d_low / 2),
                         material=mat_low))
            z0 += d_low
            # add high
            geometry.append(
                mp.Block(size=mp.Vector3(sxx, syy, d_high),
                         center=mp.Vector3(0, 0, z0 + d_high / 2),
                         material=mat_high))
            z0 += d_high

        # sources and flux box
        z0 = -szz / 2 + t_front + t_metal  # metal surface
        z1 = z0 + t_wg + t_DBR  # DBR surface

        pt_src = mp.Vector3(dx, dy, z0 + dz)
        pt_field = mp.Vector3(0.08 * sx / 2, 0.07 * sy / 2, z0 + 0.77 * t_wg)
        l_flux, pt_flux = my.FluxBox3D(size=0.1,
                                       src=pt_src,
                                       zmin=z0,
                                       zmax=z0 + t_wg)
        frs_src = my.FluxRegions_Cube_Center(l_flux, pt_flux)
        assert dz < t_wg, "The source is inside the waveguide."

        # big box, the box include the whole GaSb area
        frs_big = my.FluxRegions_Box_Corner(-sx / 2, sx / 2, -sy / 2, sy / 2,
                                            z0, z1)
        # near2far region
        near_sizes = np.arange(sy, sy - 6.05, -1.0)
        near_z = z1 + 0.1  # above DBR
        near_fluxes = [
            mp.FluxRegion(center=mp.Vector3(0, 0, near_z),
                          size=mp.Vector3(sx, nsize, 0))
            for nsize in near_sizes
        ]
        near_regions = [
            mp.Near2FarRegion(center=mp.Vector3(0, 0, near_z),
                              size=mp.Vector3(sx, nsize, 0))
            for nsize in near_sizes
        ]

        sources = [
            mp.Source(mp.GaussianSource(fcen, fwidth=df2),
                      component=src_cmpt,
                      center=pt_src,
                      size=mp.Vector3(0, 0, 0))
        ]

        # symmetries
        if src_cmpt == mp.Ex:
            symmetries = [mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, +1)]
        elif src_cmpt == mp.Ey:
            symmetries = [mp.Mirror(mp.X, +1), mp.Mirror(mp.Y, -1)]
        elif src_cmpt == mp.Ez:
            symmetries = [mp.Mirror(mp.X, +1), mp.Mirror(mp.Y, +1)]

    # end of big if between emtpy and geom
    ####################################
    print('Real simulation area ' + str(mp.Vector3(sx, sy, sz)))
    print('Total simulation area ' + str(mp.Vector3(sxx, syy, szz)))
    print('Source at ' + str(pt_src))
    print('Field is monitored at ' + str(pt_field))
    print('Flux center at ' + str(pt_flux))
    print('Flux region size is ' + str(l_flux))

    # set up simulation
    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        geometry=geometry,
                        boundary_layers=boundary_layers,
                        dimensions=3,
                        sources=sources,
                        k_point=k,
                        force_complex_fields=True,
                        symmetries=symmetries,
                        default_material=mat_wg,
                        filename_prefix=sig)

    # calculate flux
    if geom == 'Empty':
        trans_src = [sim.add_flux(fcen, df, nfreq, fr) for fr in frs_src]
    else:
        trans_src = [sim.add_flux(fcen, df, nfreq, fr) for fr in frs_src]
        trans_big = [sim.add_flux(fcen, df, nfreq, fr) for fr in frs_big]

        near_trans = [sim.add_flux(fcen, df, nfreq, fr) for fr in near_fluxes]
        near_fields = [
            sim.add_near2far(fcen, df, nfreq, rgn) for rgn in near_regions
        ]
        # nearfield=sim.add_near2far(fcen, df, nfreq, *frs)

    #### define two functions to organize output
    def get_flux_data_from_many(trans):
        # simulation data are saved in trans
        freqs = mp.get_flux_freqs(trans[0])
        fluxes = [mp.get_fluxes(tran) for tran in trans]
        data = np.column_stack((
            freqs,
            *fluxes,
        ))
        return data

    def get_flux_data_from_one(ntran, nsize):
        # simulation data are saved in trans
        freqs = mp.get_flux_freqs(ntran)
        fluxes = mp.get_fluxes(ntran)
        data = np.column_stack((
            freqs,
            fluxes,
        ))
        data = np.insert(data, 1, nsize, axis=1)
        return data

    def get_far_data_from_one(nearfield, nsize):
        # simulation data are saved in nearfield
        freqs = mp.get_near2far_freqs(nearfield)
        r = 1000 * 3.8  # 1000 wavelengths out from the source

        thetas = np.concatenate(
            [np.arange(0.5, 20, 1),
             np.arange(22.5, 89, 3)])  # polar angle
        phis = [
            45,
        ]  # azimuthal angle
        data = np.empty(shape=[0, 16])
        for phi in phis:
            for theta in thetas:
                phi0 = np.radians(phi)
                theta0 = np.radians(theta)
                pt = r * mp.Vector3(
                    math.sin(theta0) * math.cos(phi0),
                    math.sin(theta0) * math.sin(phi0), math.cos(theta0))
                fields = sim.get_farfield(nearfield, pt)
                mat = np.vstack((np.real(fields), np.imag(fields)))
                fields = mat.T.reshape((1, -1)).reshape((-1, 12))

                infos = np.vstack(
                    (freqs, nsize * np.ones(len(freqs)),
                     theta * np.ones(len(freqs)), phi * np.ones(len(freqs))))

                data = np.vstack((data, np.hstack((infos.T, fields))))
        return data

    ####
    # define step function to display fluxes
    my_display_count = 0
    step_time_flush = 10
    step_time_print = 100
    step_time_terminate = 20

    def my_display_fluxes(sim):
        nonlocal my_display_count
        nonlocal step_time_print
        print('=' * 40)
        print('=' * 40)
        # power flow around the source
        data = get_flux_data_from_many(trans_src)
        my.matrix_output(None, data, "{:10.3e}", "flux_src")

        if geom != "Empty":
            print('<' * 40)
            data = get_flux_data_from_many(trans_big)
            my.matrix_output(None, data, "{:10.3e}", "flux_big")
            print('<' * 40)

            # power flow through near region
            for idx, ntran in enumerate(near_trans):
                nsize = near_sizes[idx]
                data = get_flux_data_from_one(ntran, nsize)
                my.matrix_output(None, data, "{:10.3e}",
                                 "flux{:0.2f}".format(nsize))
                print('<' * 40)
                print('=' * 40)
            # far fields
            for idx, nfield in enumerate(near_fields):
                nsize = near_sizes[idx]
                data = get_far_data_from_one(nfield, nsize)
                my.matrix_output(None, data, "{:10.3e}",
                                 "farfield{:4.2f}".format(nsize))
                print('>' * 40)

        my_display_count += 1
        print('=' * 40)
        print('No. {} display at t={}'.format(my_display_count,
                                              step_time_print))
        my.my_flush_step(sim)

    # run simulations
    sim.run(  # mp.at_beginning(mp.output_epsilon),
        mp.at_every(step_time_flush, my.my_flush_step),
        mp.at_every(step_time_print, my_display_fluxes),
        until_after_sources=mp.stop_when_fields_decayed(
            step_time_terminate, src_cmpt, pt_field, 1e-9))
    sys.stdout.flush()

    # power flow around the source
    data = get_flux_data_from_many(trans_src)
    fname = sig + "_T0.dat"
    my.matrix_output(fname, data, "{:10.6e}", "flux_src")
    if geom != "Empty":
        data = get_flux_data_from_many(trans_big)
        fname = sig + "_T1.dat"
        my.matrix_output(fname, data, "{:10.6e}", "flux_big")

        # power flow through near region
        for idx, ntran in enumerate(near_trans):
            nsize = near_sizes[idx]
            data = get_flux_data_from_one(ntran, nsize)
            fname = sig + "_S{:0.2f}_T.dat".format(nsize)
            my.matrix_output(fname, data, "{:10.6e}",
                             "flux{:0.2f}".format(nsize))
            # far field
            for idx, nfield in enumerate(near_fields):
                nsize = near_sizes[idx]
                data = get_far_data_from_one(nfield, nsize)
                fname = sig + "_S{:0.2f}_FF.dat".format(nsize)
                my.matrix_output(fname, data, "{:10.3e}",
                                 "farfield{:4.2f}".format(nsize))
Beispiel #16
0
while iscontinue:
    wvl_min = 0.350
    wvl_max = 0.750
    frq_min = 1 / wvl_max
    frq_max = 1 / wvl_min
    frq_cen = 0.5 * (frq_min + frq_max)
    dfrq = frq_max - frq_min
    nfrq = 100
    Material = Au
    #here the resulation can be effect according to wavelength and simulation size
    resolution = 100
    dpml = dpml + 0.02  #0.05
    pml_layers = [
        mp.PML(dpml, direction=mp.X, side=mp.High),
        mp.Absorber(dpml, direction=mp.X, side=mp.Low)
    ]
    symmetries = [mp.Mirror(mp.Y)]
    offsetx = 0.01
    block_thicknessy = 0.5
    block_thicknessx = 0.02
    spacing_thickness = block_thicknessy * 2  # this varible is our main purpose of doing this experiment
    celly = (spacing_thickness + block_thicknessy)
    cellx = block_thicknessx + 2 * dpml + 2 * offsetx

    geometry = []

    sources = [
        mp.Source(mp.GaussianSource(frq_cen, fwidth=dfrq),
                  center=mp.Vector3(-0.5 * cellx + dpml),
                  size=mp.Vector3(0, celly),
Beispiel #17
0
    Ls = -2 * x  # Position of source
    Lr1 = -2 * x - 1.25  # Position of reflection monitor 1
    Lr2 = -2 * x + 1.25  # Position of reflection monitor 2
    Lt = -Lr2  # Position of transmission monitor
    scatter_monitor_size = 2 * Lt

    assert (Lr1 > -a / 2 + dpml
            )  # Make sure that nothing we care about is sitting inside the PML

    sources = [
        mp.EigenModeSource(mp.ContinuousSource(frequency=fcen),
                           size=mp.Vector3(0, H),
                           center=mp.Vector3(Ls, 0))
    ]

    pml_layers = [mp.Absorber(thickness=dpml)]

    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        geometry=geometry,
                        sources=sources,
                        resolution=resolution)

    sim.reset_meep()

    nfreq = 1

    refl_fr1 = mp.FluxRegion(center=mp.Vector3(Lr1, 0),
                             size=mp.Vector3(0, monitorheight))
    refl_fr2 = mp.FluxRegion(center=mp.Vector3(Lr2, 0),
                             size=mp.Vector3(0, monitorheight))
def simulation(f_cen, df, fmin, fmax, sy, dpml, air, sx, resolution, nfreq,
               geometry, init_refl_data, init_tran_flux, n, THICKNESS):
    #----------------------Simulation------------------------------
    cell = mp.Vector3(sx, sy)
    thick = np.sum(THICKNESS)
    #define Gaussian plane wave
    sources = [
        mp.Source(mp.GaussianSource(f_cen, fwidth=df),
                  component=mp.Ez,
                  center=mp.Vector3(0, 0.5 * sy - dpml - 0.02 * air, 0),
                  size=mp.Vector3(x=sx))
    ]
    #define pml layers
    pml_layers = [
        mp.PML(thickness=dpml, direction=mp.Y, side=mp.High),
        mp.Absorber(thickness=dpml, direction=mp.Y, side=mp.Low)
    ]
    tran_fr = mp.FluxRegion(center=mp.Vector3(0, -0.5 * sy + dpml + 0.05),
                            size=mp.Vector3(x=sx))
    refl_fr = mp.FluxRegion(center=mp.Vector3(0, 0.5 * sy - dpml - 0.1 * air),
                            size=mp.Vector3(x=sx))
    mp.quiet(quietval=True)
    if n == 0:
        #if os.path.exists('dft_Z_empty.h5'):
        #os.remove('dft_Z_empty.h5')
        sim = mp.Simulation(cell_size=cell,
                            boundary_layers=pml_layers,
                            sources=sources,
                            symmetries=[mp.Mirror(mp.X)],
                            dimensions=2,
                            resolution=resolution,
                            k_point=mp.Vector3())

        #----------------------Monitors------------------------------
        refl = sim.add_flux(f_cen, df, nfreq, refl_fr)
        tran = sim.add_flux(f_cen, df, nfreq, tran_fr)
        dfts_Z = sim.add_dft_fields([mp.Ez],
                                    fmin,
                                    fmax,
                                    nfreq,
                                    where=mp.Volume(center=mp.Vector3(
                                        0, -sy * 0.5 + dpml + THICKNESS * 0.5,
                                        0),
                                                    size=mp.Vector3(
                                                        sx, THICKNESS)))
        #----------------------Run------------------------------
        sim.run(until_after_sources=mp.stop_when_fields_decayed(
            5, mp.Ez, mp.Vector3(), 1e-3))

        #----------------------Genetic------------------------------
        sim.output_dft(dfts_Z, "dft_Z_empty")
        init_refl_data = sim.get_flux_data(refl)
        init_tran_flux = mp.get_fluxes(tran)
        sim.reset_meep()
        get = init_refl_data, init_tran_flux

    elif n == 1:
        #if os.path.exists('dft_Z_fields.h5'):
        #os.remove('dft_Z_fields.h5')
        sim = mp.Simulation(cell_size=cell,
                            boundary_layers=pml_layers,
                            sources=sources,
                            geometry=geometry,
                            symmetries=[mp.Mirror(mp.X)],
                            dimensions=2,
                            resolution=resolution,
                            k_point=mp.Vector3())

        refl = sim.add_flux(f_cen, df, nfreq, refl_fr)
        tran = sim.add_flux(f_cen, df, nfreq, tran_fr)
        sim.load_minus_flux_data(refl, init_refl_data)
        dfts_Z = sim.add_dft_fields([mp.Ez],
                                    fmin,
                                    fmax,
                                    nfreq,
                                    where=mp.Volume(center=mp.Vector3(
                                        0, -sy * 0.5 + dpml + thick * 0.5, 0),
                                                    size=mp.Vector3(sx,
                                                                    thick)))
        sim.run(until_after_sources=mp.stop_when_fields_decayed(
            5, mp.Ez, mp.Vector3(),
            1e-3))  #mp.at_beginning(mp.output_epsilon),
        sim.output_dft(dfts_Z, "dft_Z_fields")
        flux_freqs = mp.get_flux_freqs(refl)
        final_refl_flux = mp.get_fluxes(refl)
        wl = []
        Rs = []
        for i in range(nfreq):
            wl = np.append(wl, 1 / flux_freqs[i])
            Rs = np.append(Rs, -final_refl_flux[i] / init_tran_flux[i])
        sim.reset_meep()
        #get = np.min(Rs)
        en = enhance(Rs, 0)
        get = en, Rs, wl
    elif n == 2:
        #if os.path.exists('dft_Z_fields.h5'):
        #os.remove('dft_Z_fields.h5')
        sim = mp.Simulation(cell_size=cell,
                            boundary_layers=pml_layers,
                            sources=sources,
                            geometry=geometry,
                            symmetries=[mp.Mirror(mp.X)],
                            dimensions=2,
                            resolution=resolution,
                            k_point=mp.Vector3())

        refl = sim.add_flux(f_cen, df, nfreq, refl_fr)
        tran = sim.add_flux(f_cen, df, nfreq, tran_fr)
        sim.load_minus_flux_data(refl, init_refl_data)
        dfts_Z = sim.add_dft_fields([mp.Ez],
                                    fmin,
                                    fmax,
                                    nfreq,
                                    where=mp.Volume(center=mp.Vector3(
                                        0, -sy * 0.5 + dpml + thick * 0.5, 0),
                                                    size=mp.Vector3(sx,
                                                                    thick)))
        sim.run(mp.at_beginning(mp.output_epsilon),
                until_after_sources=mp.stop_when_fields_decayed(
                    5, mp.Ez, mp.Vector3(),
                    1e-3))  #mp.at_beginning(mp.output_epsilon),
        sim.output_dft(dfts_Z, "dft_Z_fields")
        flux_freqs = mp.get_flux_freqs(refl)
        final_refl_flux = mp.get_fluxes(refl)
        final_tran_flux = mp.get_fluxes(tran)
        wl = []
        Rs = []
        Ts = []
        for i in range(nfreq):
            wl = np.append(wl, 1 / flux_freqs[i])
            Rs = np.append(Rs, -final_refl_flux[i] / init_tran_flux[i])
            Ts = np.append(Ts, final_tran_flux[i] / init_tran_flux[i])
        As = 1 - Rs - Ts
        plt.clf()
        plt.figure()
        plt.plot(wl, Rs, 'bo-', label='reflectance')
        plt.plot(wl, Ts, 'ro-', label='transmittance')
        plt.plot(wl, As, 'go-', label='absorption')
        plt.xlabel("wavelength (μm)")
        plt.legend(loc="upper right")
        plt.savefig('Extinction.png')
        #get = np.min(Rs)
        en = enhance(Rs, 1)
        get = en, Rs, wl

        #plt.figure()
        #plt.plot(wl,Rs,'bo-',label='reflectance')
        eps = h5py.File('_last-eps-000000000.h5', 'r')
        eps = eps.get('eps').value
        Enhance = np.rot90(eps)
        plt.clf()
        plt.figure()
        heat_map = sb.heatmap(Enhance,
                              cmap='plasma',
                              xticklabels=False,
                              yticklabels=False)
        plt.xlabel("x-axis")
        plt.ylabel("y-axis")
        plt.savefig('Epsilon.png')

    return (get)
Beispiel #19
0
    def run_binary_grating_diffraction(self, gp, gh, gdc, theta, bands,
                                       orders):

        resolution = 50  # pixels/um

        dpml = 1.0  # PML thickness
        dsub = 3.0  # substrate thickness
        dpad = 3.0  # length of padding between grating and PML

        sx = dpml + dsub + gh + dpad + dpml
        sy = gp

        cell_size = mp.Vector3(sx, sy, 0)
        absorber_layers = [mp.Absorber(thickness=dpml, direction=mp.X)]

        wvl = 0.5  # center wavelength
        fcen = 1 / wvl  # center frequency
        df = 0.05 * fcen  # frequency width

        ng = 1.5
        glass = mp.Medium(index=ng)

        # rotation angle of incident planewave; counter clockwise (CCW) about Z axis, 0 degrees along +X axis
        theta_in = math.radians(theta)

        eig_parity = mp.ODD_Z

        # k (in source medium) with correct length (plane of incidence: XY)
        k = mp.Vector3(fcen * ng).rotate(mp.Vector3(z=1), theta_in)

        symmetries = []
        if theta_in == 0:
            k = mp.Vector3()
            eig_parity += mp.EVEN_Y
            symmetries = [mp.Mirror(direction=mp.Y)]

        def pw_amp(k, x0):
            def _pw_amp(x):
                return cmath.exp(1j * 2 * math.pi * k.dot(x + x0))

            return _pw_amp

        src_pt = mp.Vector3(-0.5 * sx + dpml, 0, 0)
        sources = [
            mp.Source(mp.GaussianSource(fcen, fwidth=df),
                      component=mp.Ez,
                      center=src_pt,
                      size=mp.Vector3(0, sy, 0),
                      amp_func=pw_amp(k, src_pt))
        ]

        sim = mp.Simulation(resolution=resolution,
                            cell_size=cell_size,
                            boundary_layers=absorber_layers,
                            k_point=k,
                            default_material=glass,
                            sources=sources,
                            symmetries=symmetries)

        tran_pt = mp.Vector3(0.5 * sx - dpml, 0, 0)
        tran_flux = sim.add_flux(
            fcen, 0, 1, mp.FluxRegion(center=tran_pt,
                                      size=mp.Vector3(0, sy, 0)))

        sim.run(until_after_sources=50)

        input_flux = mp.get_fluxes(tran_flux)

        sim.reset_meep()

        geometry = [
            mp.Block(material=glass,
                     size=mp.Vector3(dpml + dsub, mp.inf, mp.inf),
                     center=mp.Vector3(-0.5 * sx + 0.5 * (dpml + dsub), 0, 0)),
            mp.Block(material=glass,
                     size=mp.Vector3(gh, gdc * gp, mp.inf),
                     center=mp.Vector3(-0.5 * sx + dpml + dsub + 0.5 * gh, 0,
                                       0))
        ]

        sim = mp.Simulation(resolution=resolution,
                            cell_size=cell_size,
                            boundary_layers=absorber_layers,
                            geometry=geometry,
                            k_point=k,
                            sources=sources,
                            symmetries=symmetries)

        tran_flux = sim.add_mode_monitor(
            fcen, 0, 1, mp.FluxRegion(center=tran_pt,
                                      size=mp.Vector3(0, sy, 0)))

        sim.run(until_after_sources=100)

        for band, order in zip(bands, orders):
            res = sim.get_eigenmode_coefficients(tran_flux, [band],
                                                 eig_parity=eig_parity)
            tran_ref = abs(res.alpha[0, 0, 0])**2 / input_flux[0]
            if (theta_in == 0):
                tran_ref = 0.5 * tran_ref
            vg_ref = res.vgrp[0]

            res = sim.get_eigenmode_coefficients(
                tran_flux,
                mp.DiffractedPlanewave((0, order, 0), mp.Vector3(0, 1, 0), 1,
                                       0))
            if res is not None:
                tran_dp = abs(res.alpha[0, 0, 0])**2 / input_flux[0]
                if ((theta_in == 0) and (order == 0)):
                    tran_dp = 0.5 * tran_dp
            else:
                tran_dp = 0
            vg_dp = res.vgrp[0]

            err = abs(tran_ref - tran_dp) / tran_ref
            print(
                "tran:, {} (band), {} (order), {:.8f} (eigensolver), {:.8f} (planewave), {:.8f} (error)"
                .format(band, order, tran_ref, tran_dp, err))

            self.assertAlmostEqual(vg_ref, vg_dp, places=5)
            self.assertAlmostEqual(tran_ref, tran_dp, places=5)
def simulation(square, THICKNESS, cx, cy, cz):
    #----------------------------Variables------------------------------
    period = square  #um
    PADDING = 0.70  #um
    fmin = 1 / .800  #maximum wavelength
    fmax = 1 / .300  #minimum wavelength
    fcen = (fmax + fmin) / 2  #set centre of gaussian source
    df = fmax - fmin  #set width of gaussian source
    nfreq = 50  #number of frequencies between min and max
    dpml = 0.4  #thickness of PML (top and bottom) um
    resolution = 100  #pixels/um
    BASE = PADDING - THICKNESS  #metal thin film is set on a PDMS base
    sz = THICKNESS + 2 * PADDING + 2 * dpml  #size of simulation
    sx = period  #size of simulation
    sy = period  #size of simulation
    box = 0.010  #optimised size of radiation monitoring box set around dipole
    cell = mp.Vector3(sx, sy, sz)
    runtime = 1600

    #define geometry
    slab = mp.Block(size=mp.Vector3(1e20, 1e20, THICKNESS),
                    center=mp.Vector3(0, 0, -THICKNESS / 2),
                    material=Au)  #Gold thin film
    hole = mp.Block(size=mp.Vector3(0.145, 0.145, THICKNESS),
                    center=mp.Vector3(0, 0, 0))  #nanohole
    slab3 = mp.Block(mp.Vector3(1e20, 1e20, BASE),
                     center=mp.Vector3(0, 0, -0.5 * sz + dpml + 0.5 * BASE),
                     material=mp.Medium(index=1.53))  #pdms base
    geometry = [slab, hole, slab3]

    #--------------------------Simulation Parameters----------------------------------------

    #define Gaussian plane wave Ez polarised
    sources = [
        mp.Source(mp.GaussianSource(fcen, fwidth=df),
                  component=mp.Ex,
                  center=mp.Vector3(cx, cy, cz))
    ]

    #define pml layers (Absorber is a type of PML that helps when there are Bloch Wave SPP modes. Placed in substrate)
    pml_layers = [
        mp.Absorber(thickness=dpml, direction=mp.Z, side=mp.Low),
        mp.PML(thickness=dpml, direction=mp.Z, side=mp.High)
    ]

    #sets the simulation without the substrate so that it is a homogeneous environment
    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        sources=sources,
                        resolution=resolution,
                        k_point=mp.Vector3(0, 0, 0))

    #power monitors around the simulation
    #power monitor around the dipole
    dipole_box = sim.add_flux(
        fcen, df, nfreq,
        mp.FluxRegion(center=mp.Vector3(cx + 0.5 * box, cy, cz),
                      size=mp.Vector3(0, box, box),
                      direction=mp.X,
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(cx - 0.5 * box, cy, cz),
                      size=mp.Vector3(0, box, box),
                      direction=mp.X,
                      weight=-1),
        mp.FluxRegion(center=mp.Vector3(cx, cy, cz + 0.5 * box),
                      size=mp.Vector3(box, box, 0),
                      direction=mp.Z,
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(cx, cy, cz - 0.5 * box),
                      size=mp.Vector3(box, box, 0),
                      direction=mp.Z,
                      weight=-1),
        mp.FluxRegion(center=mp.Vector3(cx, cy + 0.5 * box, cz),
                      size=mp.Vector3(box, 0, box),
                      direction=mp.Y,
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(cx, cy - 0.5 * box, cz),
                      size=mp.Vector3(box, 0, box),
                      direction=mp.Y,
                      weight=-1))

    #power monitor on the surface of the thin film
    rad_box = sim.add_flux(
        fcen, df, nfreq,
        mp.FluxRegion(center=mp.Vector3(0, 0, 0),
                      size=mp.Vector3(sx, sy, 0),
                      weight=-1))

    #power monitors surrounding 'free space'
    top_box = sim.add_flux(
        fcen, df, nfreq,
        mp.FluxRegion(center=mp.Vector3(0, 0, 0.5 * sz - dpml),
                      size=mp.Vector3(sx, sy, 0)),
        mp.FluxRegion(center=mp.Vector3(0, 0.5 * sy, 0.25 * sz),
                      size=mp.Vector3(sx, 0, 0.5 * sz - dpml),
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(0, -0.5 * sy, 0.25 * sz),
                      size=mp.Vector3(sx, 0, 0.5 * sz - dpml),
                      weight=-1),
        mp.FluxRegion(center=mp.Vector3(0.5 * sx, 0, 0.25 * sz),
                      size=mp.Vector3(0, sy, 0.5 * sz - dpml),
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(-0.5 * sx, 0, 0.25 * sz),
                      size=mp.Vector3(0, sy, 0.5 * sz - dpml),
                      weight=-1))

    #run simulation until the source has decayed "fully"
    sim.run(until_after_sources=runtime)

    #collect radiation information
    init_rad = np.asarray(mp.get_fluxes(rad_box))
    init_dipole = np.asarray(mp.get_fluxes(dipole_box))
    init_top = np.asarray(mp.get_fluxes(top_box))

    sim.reset_meep()

    #run simulation again with the substrate (inhomogeneous environment)
    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        sources=sources,
                        geometry=geometry,
                        resolution=resolution,
                        k_point=mp.Vector3(0, 0, 0))

    #power monitors around the dipole
    dipole_box2 = sim.add_flux(
        fcen, df, nfreq,
        mp.FluxRegion(center=mp.Vector3(cx + 0.5 * box, cy, cz),
                      size=mp.Vector3(0, box, box),
                      direction=mp.X,
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(cx - 0.5 * box, cy, cz),
                      size=mp.Vector3(0, box, box),
                      direction=mp.X,
                      weight=-1),
        mp.FluxRegion(center=mp.Vector3(cx, cy, cz + 0.5 * box),
                      size=mp.Vector3(box, box, 0),
                      direction=mp.Z,
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(cx, cy, cz - 0.5 * box),
                      size=mp.Vector3(box, box, 0),
                      direction=mp.Z,
                      weight=-1),
        mp.FluxRegion(center=mp.Vector3(cx, cy + 0.5 * box, cz),
                      size=mp.Vector3(box, 0, box),
                      direction=mp.Y,
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(cx, cy - 0.5 * box, cz),
                      size=mp.Vector3(box, 0, box),
                      direction=mp.Y,
                      weight=-1))

    rad_box2 = sim.add_flux(
        fcen, df, nfreq,
        mp.FluxRegion(center=mp.Vector3(0, 0, 0),
                      size=mp.Vector3(sx, sy, 0),
                      weight=-1))

    top_box2 = sim.add_flux(
        fcen, df, nfreq,
        mp.FluxRegion(center=mp.Vector3(0, 0, 0.5 * sz - dpml),
                      size=mp.Vector3(sx, sy, 0),
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(0, 0.5 * sy, 0.25 * sz),
                      size=mp.Vector3(sx, 0, 0.5 * sz - dpml),
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(0, -0.5 * sy, 0.25 * sz),
                      size=mp.Vector3(sx, 0, 0.5 * sz - dpml),
                      weight=-1),
        mp.FluxRegion(center=mp.Vector3(0.5 * sx, 0, 0.25 * sz),
                      size=mp.Vector3(0, sy, 0.5 * sz - dpml),
                      weight=+1),
        mp.FluxRegion(center=mp.Vector3(-0.5 * sx, 0, 0.25 * sz),
                      size=mp.Vector3(0, sy, 0.5 * sz - dpml),
                      weight=-1))

    sim.run(until_after_sources=runtime)

    rad = np.asarray(mp.get_fluxes(rad_box2))
    dipole = np.asarray(mp.get_fluxes(dipole_box2))
    top = np.asarray(mp.get_fluxes(top_box2))

    #Output data
    data = np.zeros((6, len(rad)))
    data[0, :] = init_rad
    data[1, :] = rad
    data[2, :] = init_dipole
    data[3, :] = dipole
    data[4, :] = init_top
    data[5, :] = top

    np.savetxt('REPLACE.txt', data)

    return ()
def sim(queryrow, src_angle, nm_val, src_pol):
    global resolution
    result_df = pd.DataFrame(columns=result.columns)

    dpml = 1.0  # PML length
    dair = 4.0  # padding length between PML and grating
    dsub = 3.0  # substrate thickness
    d = queryrow["period"]  # grating period
    h = queryrow["height"]  # grating height
    g = queryrow["gap"]  # grating gap
    theta_1 = math.radians(queryrow["theta_1"])  # grating sidewall angle #1
    theta_2 = math.radians(queryrow["theta_2"])  # grating sidewall angle #2
    transmittance = 0

    sx = dpml + dair + h + dsub + dpml
    sy = d

    cell_size = mp.Vector3(sx, sy, 0)
    pml_layers = [mp.Absorber(thickness=dpml, direction=mp.X)]

    wvl = 0.5  # center wavelength
    fcen = 1 / wvl  # center frequency
    df = 0.05 * fcen  # frequency width

    ng = 1.716  # episulfide refractive index @ 0.532 um
    glass = mp.Medium(index=ng)

    if src_pol == 1:
        src_cmpt = mp.Ez
        eig_parity = mp.ODD_Z
    elif src_pol == 2:
        src_cmpt = mp.Hz
        eig_parity = mp.EVEN_Z
    else:
        sys.exit("error: src_pol={} is invalid".format(args.src_pol))

    # rotation angle of incident planewave source; CCW about Z axis, 0 degrees along +X axis
    theta_src = math.radians(src_angle)

    # k (in source medium) with correct length (plane of incidence: XY)
    k = mp.Vector3(math.cos(theta_src), math.sin(theta_src), 0).scale(fcen)
    if theta_src == 0:
        k = mp.Vector3(0, 0, 0)

    def pw_amp(k, x0):
        def _pw_amp(x):
            return cmath.exp(1j * 2 * math.pi * k.dot(x + x0))

        return _pw_amp

    src_pt = mp.Vector3(-0.5 * sx + dpml + 0.2 * dair, 0, 0)
    sources = [
        mp.Source(mp.GaussianSource(fcen, fwidth=df),
                  component=src_cmpt,
                  center=src_pt,
                  size=mp.Vector3(0, sy, 0),
                  amp_func=pw_amp(k, src_pt))
    ]

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=pml_layers,
                        k_point=k,
                        sources=sources)

    refl_pt = mp.Vector3(-0.5 * sx + dpml + 0.7 * dair, 0, 0)
    refl_flux = sim.add_flux(
        fcen, 0, 1, mp.FluxRegion(center=refl_pt, size=mp.Vector3(0, sy, 0)))

    sim.run(until_after_sources=100)

    input_flux = mp.get_fluxes(refl_flux)
    input_flux_data = sim.get_flux_data(refl_flux)

    sim.reset_meep()

    geometry = [
        mp.Block(material=glass,
                 size=mp.Vector3(dpml + dsub, mp.inf, mp.inf),
                 center=mp.Vector3(0.5 * sx - 0.5 * (dpml + dsub), 0, 0)),
        mp.Prism(material=glass,
                 height=mp.inf,
                 vertices=[
                     mp.Vector3(0.5 * sx - dpml - dsub, 0.5 * sy, 0),
                     mp.Vector3(0.5 * sx - dpml - dsub - h,
                                0.5 * sy - h * math.tan(theta_2), 0),
                     mp.Vector3(0.5 * sx - dpml - dsub - h,
                                -0.5 * sy + g - h * math.tan(theta_1), 0),
                     mp.Vector3(0.5 * sx - dpml - dsub, -0.5 * sy + g, 0)
                 ])
    ]

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=pml_layers,
                        k_point=k,
                        sources=sources,
                        geometry=geometry)

    refl_flux = sim.add_flux(
        fcen, 0, 1, mp.FluxRegion(center=refl_pt, size=mp.Vector3(0, sy, 0)))
    sim.load_minus_flux_data(refl_flux, input_flux_data)

    tran_pt = mp.Vector3(0.5 * sx - dpml - 0.5 * dsub, 0, 0)
    tran_flux = sim.add_flux(
        fcen, 0, 1, mp.FluxRegion(center=tran_pt, size=mp.Vector3(0, sy, 0)))

    sim.run(until_after_sources=500)

    kdom_tol = 1e-2
    angle_tol = 1e-6

    Rsum = 0
    Tsum = 0
    if theta_src == 0:
        nm_r = int(0.5 * (np.floor((fcen - k.y) * d) - np.ceil(
            (-fcen - k.y) * d)))  # number of reflected orders

        res = sim.get_eigenmode_coefficients(refl_flux,
                                             range(1, nm_r + 1),
                                             eig_parity=eig_parity + mp.EVEN_Y)
        r_coeffs = res.alpha
        r_kdom = res.kdom
        for nm in range(nm_r):
            if nm != nm_val:
                continue
            if r_kdom[nm].x > kdom_tol:
                r_angle = np.sign(r_kdom[nm].y) * math.acos(
                    r_kdom[nm].x / fcen) if (
                        r_kdom[nm].x % fcen > angle_tol) else 0
                Rmode = abs(r_coeffs[nm, 0, 1])**2 / input_flux[0]
                print("refl: (even_y), {}, {:.2f}, {:.8f}".format(
                    nm, math.degrees(r_angle), Rmode))
                Rsum += Rmode

        res = sim.get_eigenmode_coefficients(refl_flux,
                                             range(1, nm_r + 1),
                                             eig_parity=eig_parity + mp.ODD_Y)
        r_coeffs = res.alpha
        r_kdom = res.kdom
        for nm in range(nm_r):
            if nm != nm_val:
                continue
            if r_kdom[nm].x > kdom_tol:
                r_angle = np.sign(r_kdom[nm].y) * math.acos(
                    r_kdom[nm].x / fcen) if (
                        r_kdom[nm].x % fcen > angle_tol) else 0
                Rmode = abs(r_coeffs[nm, 0, 1])**2 / input_flux[0]
                print("refl: (odd_y), {}, {:.2f}, {:.8f}".format(
                    nm, math.degrees(r_angle), Rmode))
                Rsum += Rmode

        nm_t = int(0.5 * (np.floor((fcen * ng - k.y) * d) - np.ceil(
            (-fcen * ng - k.y) * d)))  # number of transmitted orders

        res = sim.get_eigenmode_coefficients(tran_flux,
                                             range(1, nm_t + 1),
                                             eig_parity=eig_parity + mp.EVEN_Y)
        t_coeffs = res.alpha
        t_kdom = res.kdom
        for nm in range(nm_t):
            if nm != nm_val:
                continue
            if t_kdom[nm].x > kdom_tol:
                t_angle = np.sign(t_kdom[nm].y) * math.acos(
                    t_kdom[nm].x / (ng * fcen)) if (
                        t_kdom[nm].x % ng * fcen > angle_tol) else 0
                Tmode = abs(t_coeffs[nm, 0, 0])**2 / input_flux[0]
                transmittance = transmittance + Tmode

                Tsum += Tmode

        res = sim.get_eigenmode_coefficients(tran_flux,
                                             range(1, nm_t + 1),
                                             eig_parity=eig_parity + mp.ODD_Y)
        t_coeffs = res.alpha
        t_kdom = res.kdom
        for nm in range(nm_t):
            if nm != nm_val:
                continue
            if t_kdom[nm].x > kdom_tol:
                t_angle = np.sign(t_kdom[nm].y) * math.acos(
                    t_kdom[nm].x / (ng * fcen)) if (
                        t_kdom[nm].x % ng * fcen > angle_tol) else 0
                Tmode = abs(t_coeffs[nm, 0, 0])**2 / input_flux[0]
                transmittance = transmittance + Tmode

                Tsum += Tmode
    else:
        nm_r = int(np.floor((fcen - k.y) * d) - np.ceil(
            (-fcen - k.y) * d))  # number of reflected orders
        res = sim.get_eigenmode_coefficients(refl_flux,
                                             range(1, nm_r + 1),
                                             eig_parity=eig_parity)
        r_coeffs = res.alpha
        r_kdom = res.kdom
        for nm in range(nm_r):
            if nm != nm_val:
                continue
            if r_kdom[nm].x > kdom_tol:
                r_angle = np.sign(r_kdom[nm].y) * math.acos(
                    r_kdom[nm].x / fcen) if (
                        r_kdom[nm].x % fcen > angle_tol) else 0
                Rmode = abs(r_coeffs[nm, 0, 1])**2 / input_flux[0]
                Rsum += Rmode

        nm_t = int(
            np.floor((fcen * ng - k.y) * d) - np.ceil(
                (-fcen * ng - k.y) * d))  # number of transmitted orders
        res = sim.get_eigenmode_coefficients(tran_flux,
                                             range(1, nm_t + 1),
                                             eig_parity=eig_parity)
        t_coeffs = res.alpha
        t_kdom = res.kdom
        for nm in range(nm_t):
            if nm != nm_val:
                continue
            if t_kdom[nm].x > kdom_tol:
                t_angle = np.sign(t_kdom[nm].y) * math.acos(
                    t_kdom[nm].x / (ng * fcen)) if (
                        t_kdom[nm].x % ng * fcen > angle_tol) else 0
                Tmode = abs(t_coeffs[nm, 0, 0])**2 / input_flux[0]
                transmittance = transmittance + Tmode

    return transmittance
import meep as mp
import numpy as np

results = []
for fi in range(1):
    for fj in range(10):

        fingersize = 0.05 * (fj + 1)
        cell = mp.Vector3(7, fingersize * 10, fingersize * 10)
        pml_layers = [mp.Absorber(1, mp.X, mp.Low), mp.PML(1, mp.X, mp.High)]
        CdSe = mp.Medium(index=2.52)
        ZnO = mp.Medium(index=2.21)
        resolution = 80 - fj * 4

        sources = [
            mp.Source(mp.ContinuousSource(wavelength=0.550, end_time=10),
                      component=mp.Ez,
                      center=mp.Vector3(-1, 0, 0))
        ]

        firstfr = mp.FluxRegion(center=mp.Vector3(-2, 0, 0),
                                size=mp.Vector3(0, cell.y, cell.z))

        secfr = mp.FluxRegion(center=mp.Vector3(2.5, 0, 0),
                              size=mp.Vector3(0, cell.y, cell.z))

        sim = mp.Simulation(cell_size=cell,
                            k_point=mp.Vector3(),
                            default_material=CdSe,
                            boundary_layers=pml_layers,
                            eps_averaging=False,
def Simulation(period, grating_t, grating_w, sep, mthick, mat):

    #----------------------Variables------------------------------
    sub = 1.4  #thickness of the substrate (where the grating is embedded)
    d1 = 1.52  #dielectric constant of medium
    dpml = 0.2  #um
    air = 1.5  #um
    matty = [Au, Ag]
    #-------------------------Clear-------------------------------
    #if os.path.exists("dft_X_empty.h5"):
    #    os.remove("dft_X_empty.h5")
    #if os.path.exists("dft_X_fields.h5"):
    #    os.remove("dft_X_fields.h5")
    #if os.path.exists("dft_Y_empty.h5"):
    #    os.remove("dft_Y_empty.h5")
    #if os.path.exists("dft_Y_fields.h5"):
    #    os.remove("dft_Y_fields.h5")

    #----------------------Simulation------------------------------
    ideal = np.loadtxt('ideal_peak.txt')  # maximum source waveWIDTH
    lambda_ideal = ideal
    nfreq = 1
    f_cen = 1 / lambda_ideal  # source frequency center
    df = 0.05 * f_cen  # source frequency width
    sy = period
    sx = dpml + sub + sep + mthick + air + dpml
    resolution = 1000  #pixels/um
    diel1 = mp.Medium(index=d1)
    cell = mp.Vector3(sx, sy, 0)
    #define Gaussian plane wave
    sources = [
        mp.Source(mp.GaussianSource(f_cen, fwidth=df),
                  component=mp.Hz,
                  center=mp.Vector3(-0.5 * sx + dpml + 0.1, 0, 0),
                  size=mp.Vector3(0, sy, 0))
    ]
    #define pml layers
    pml_layers = [mp.Absorber(thickness=dpml, direction=mp.X)]
    supers = mp.Block(mp.Vector3(sub + sep, mp.inf, mp.inf),
                      center=mp.Vector3(-0.5 * sx + 0.5 * (sub + sep), 0, 0),
                      material=diel1)
    geometry = [supers]
    #mp.quiet(quietval=True)
    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        sources=sources,
                        symmetries=[mp.Mirror(mp.Y, phase=-1)],
                        dimensions=2,
                        resolution=resolution,
                        k_point=mp.Vector3(0, 0, 0))

    #----------------------Monitors------------------------------
    dfts_Y1 = sim.add_dft_fields([mp.Ey],
                                 f_cen,
                                 f_cen,
                                 1,
                                 where=mp.Volume(center=mp.Vector3(
                                     0.5 * sx - dpml - 0.5 * (mthick + air),
                                     0),
                                                 size=mp.Vector3(
                                                     air + mthick, sy)))
    dfts_X1 = sim.add_dft_fields([mp.Ex],
                                 f_cen,
                                 f_cen,
                                 1,
                                 where=mp.Volume(center=mp.Vector3(
                                     0.5 * sx - dpml - 0.5 * (mthick + air),
                                     0),
                                                 size=mp.Vector3(
                                                     air + mthick, sy)))
    #----------------------Run------------------------------
    sim.run(until_after_sources=100)

    #----------------------Reset------------------------------
    sim.output_dft(dfts_Y1, "dft_Y_empty")
    sim.output_dft(dfts_X1, "dft_X_empty")
    sim.reset_meep()
    grating = mp.Block(mp.Vector3(grating_t, grating_w, mp.inf),
                       center=mp.Vector3(-0.5 * sx + sub - 0.5 * grating_t, 0,
                                         0),
                       material=matty[int(mat)])
    metal = mp.Block(mp.Vector3(mthick, mp.inf, mp.inf),
                     center=mp.Vector3(-0.5 * sx + sub + sep + 0.5 * mthick, 0,
                                       0),
                     material=matty[int(mat)])
    geometry = [supers, grating, metal]

    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        sources=sources,
                        geometry=geometry,
                        symmetries=[mp.Mirror(mp.Y, phase=-1)],
                        dimensions=2,
                        resolution=resolution,
                        k_point=mp.Vector3(0, 0, 0))

    dfts_Y2 = sim.add_dft_fields([mp.Ey],
                                 f_cen,
                                 f_cen,
                                 1,
                                 where=mp.Volume(center=mp.Vector3(
                                     0.5 * sx - dpml - 0.5 * (mthick + air),
                                     0),
                                                 size=mp.Vector3(
                                                     air + mthick, sy)))
    dfts_X2 = sim.add_dft_fields([mp.Ex],
                                 f_cen,
                                 f_cen,
                                 1,
                                 where=mp.Volume(center=mp.Vector3(
                                     0.5 * sx - dpml - 0.5 * (mthick + air),
                                     0),
                                                 size=mp.Vector3(
                                                     air + mthick, sy)))
    sim.run(until_after_sources=400)  #mp.at_beginning(mp.output_epsilon),
    sim.output_dft(dfts_Y2, "dft_Y_fields")
    sim.output_dft(dfts_X2, "dft_X_fields")

    #----------------------------Graph the Outputs----------------------------
    with h5py.File('dft_Y_fields.h5', 'r') as Esy:
        with h5py.File('dft_Y_empty.h5', 'r') as Eoy:
            with h5py.File('dft_X_fields.h5', 'r') as Esx:
                with h5py.File('dft_X_empty.h5', 'r') as Eox:
                    eix2 = np.array(Esx[('ex_0.i')])
                    erx2 = np.array(Esx[('ex_0.r')])
                    eiy2 = np.array(Esy[('ey_0.i')])
                    ery2 = np.array(Esy[('ey_0.r')])
                    E2 = (eix2**2 + erx2**2) + (eiy2**2 + ery2**2)
                    eix2 = np.array(Eox[('ex_0.i')])
                    erx2 = np.array(Eox[('ex_0.r')])
                    eiy2 = np.array(Eoy[('ey_0.i')])
                    ery2 = np.array(Eoy[('ey_0.r')])
                    E1 = (eix2**2 + erx2**2) + (eiy2**2 + ery2**2)
                    Enhance = E2 / E1
                    Enhance = np.rot90(Enhance)
                    heat_map = sb.heatmap(Enhance,
                                          cmap='plasma',
                                          xticklabels=False,
                                          yticklabels=False)
                    plt.ylabel("y-axis")
                    plt.xlabel("x-axis")
                    plt.savefig('Enhance_Z.png')
                    en = np.zeros(len(Enhance[0]))
                    pos = np.linspace(0, 3.82, len(en))
                    for i in range(len(Enhance[0])):
                        en[i] = np.max(Enhance[:, i])
                    plt.clf()
                    plt.figure()
                    plt.plot(pos, en)
                    plt.xlabel('position along substrate (um)')
                    plt.ylabel('enhancement')
                    plt.savefig('Profile.png')

    return ()
Beispiel #24
0
def main(args):

    resolution = 30

    nSiO2 = 1.4
    SiO2 = mp.Medium(index=nSiO2)

    # conversion factor for eV to 1/um
    eV_um_scale = 1 / 1.23984193

    # W, from Rakic et al., Applied Optics, vol. 32, p. 5274 (1998)
    W_eps_inf = 1
    W_plasma_frq = 13.22 * eV_um_scale
    W_f0 = 0.206
    W_frq0 = 1e-10
    W_gam0 = 0.064 * eV_um_scale
    W_sig0 = W_f0 * W_plasma_frq**2 / W_frq0**2
    W_f1 = 0.054
    W_frq1 = 1.004 * eV_um_scale  # 1.235 um
    W_gam1 = 0.530 * eV_um_scale
    W_sig1 = W_f1 * W_plasma_frq**2 / W_frq1**2
    W_f2 = 0.166
    W_frq2 = 1.917 * eV_um_scale  # 0.647
    W_gam2 = 1.281 * eV_um_scale
    W_sig2 = W_f2 * W_plasma_frq**2 / W_frq2**2

    W_susc = [
        mp.DrudeSusceptibility(frequency=W_frq0, gamma=W_gam0, sigma=W_sig0),
        mp.LorentzianSusceptibility(frequency=W_frq1,
                                    gamma=W_gam1,
                                    sigma=W_sig1),
        mp.LorentzianSusceptibility(frequency=W_frq2,
                                    gamma=W_gam2,
                                    sigma=W_sig2)
    ]

    W = mp.Medium(epsilon=W_eps_inf, E_susceptibilities=W_susc)

    # crystalline Si, from M.A. Green, Solar Energy Materials and Solar Cells, vol. 92, pp. 1305-1310 (2008)
    # fitted Lorentzian parameters, only for 600nm-1100nm
    Si_eps_inf = 9.14
    Si_eps_imag = -0.0334
    Si_eps_imag_frq = 1 / 1.55
    Si_frq = 2.2384
    Si_gam = 4.3645e-02
    Si_sig = 14.797 / Si_frq**2

    Si = mp.Medium(epsilon=Si_eps_inf,
                   D_conductivity=2 * math.pi * Si_eps_imag_frq * Si_eps_imag /
                   Si_eps_inf,
                   E_susceptibilities=[
                       mp.LorentzianSusceptibility(frequency=Si_frq,
                                                   gamma=Si_gam,
                                                   sigma=Si_sig)
                   ])

    a = args.a  # lattice periodicity
    cone_r = args.cone_r  # cone radius
    cone_h = args.cone_h  # cone height
    wire_w = args.wire_w  # metal-grid wire width
    wire_h = args.wire_h  # metal-grid wire height
    trench_w = args.trench_w  # trench width
    trench_h = args.trench_h  # trench height
    Np = args.Np  # number of periods in supercell

    dair = 1.0  # air gap thickness
    dmcl = 1.7  # micro lens thickness
    dsub = 3000.0  # substrate thickness
    dpml = 1.0  # PML thickness

    sxy = Np * a
    sz = dpml + dair + dmcl + dsub + dpml
    cell_size = mp.Vector3(sxy, sxy, sz)

    boundary_layers = [
        mp.PML(dpml, direction=mp.Z, side=mp.High),
        mp.Absorber(dpml, direction=mp.Z, side=mp.Low)
    ]

    geometry = []

    if args.substrate:
        geometry = [
            mp.Sphere(material=SiO2,
                      radius=dmcl,
                      center=mp.Vector3(0, 0, 0.5 * sz - dpml - dair - dmcl)),
            mp.Block(material=Si,
                     size=mp.Vector3(mp.inf, mp.inf, dsub + dpml),
                     center=mp.Vector3(0, 0, -0.5 * sz + 0.5 * (dsub + dpml))),
            mp.Block(
                material=W,
                size=mp.Vector3(mp.inf, wire_w, wire_h),
                center=mp.Vector3(0, -0.5 * sxy + 0.5 * wire_w,
                                  -0.5 * sz + dpml + dsub + 0.5 * wire_h)),
            mp.Block(
                material=W,
                size=mp.Vector3(mp.inf, wire_w, wire_h),
                center=mp.Vector3(0, +0.5 * sxy - 0.5 * wire_w,
                                  -0.5 * sz + dpml + dsub + 0.5 * wire_h)),
            mp.Block(
                material=W,
                size=mp.Vector3(wire_w, mp.inf, wire_h),
                center=mp.Vector3(-0.5 * sxy + 0.5 * wire_w, 0,
                                  -0.5 * sz + dpml + dsub + 0.5 * wire_h)),
            mp.Block(material=W,
                     size=mp.Vector3(wire_w, mp.inf, wire_h),
                     center=mp.Vector3(+0.5 * sxy - 0.5 * wire_w, 0,
                                       -0.5 * sz + dpml + dsub + 0.5 * wire_h))
        ]

    if args.substrate and args.texture:
        for nx in range(Np):
            for ny in range(Np):
                cx = -0.5 * sxy + (nx + 0.5) * a
                cy = -0.5 * sxy + (ny + 0.5) * a
                geometry.append(
                    mp.Cone(material=SiO2,
                            radius=0,
                            radius2=cone_r,
                            height=cone_h,
                            center=mp.Vector3(
                                cx, cy,
                                0.5 * sz - dpml - dair - dmcl - 0.5 * cone_h)))

    if args.substrate:
        geometry.append(
            mp.Block(material=SiO2,
                     size=mp.Vector3(mp.inf, trench_w, trench_h),
                     center=mp.Vector3(
                         0, -0.5 * sxy + 0.5 * trench_w,
                         0.5 * sz - dpml - dair - dmcl - 0.5 * trench_h)))
        geometry.append(
            mp.Block(material=SiO2,
                     size=mp.Vector3(mp.inf, trench_w, trench_h),
                     center=mp.Vector3(
                         0, +0.5 * sxy - 0.5 * trench_w,
                         0.5 * sz - dpml - dair - dmcl - 0.5 * trench_h)))
        geometry.append(
            mp.Block(material=SiO2,
                     size=mp.Vector3(trench_w, mp.inf, trench_h),
                     center=mp.Vector3(
                         -0.5 * sxy + 0.5 * trench_w, 0,
                         0.5 * sz - dpml - dair - dmcl - 0.5 * trench_h)))
        geometry.append(
            mp.Block(material=SiO2,
                     size=mp.Vector3(trench_w, mp.inf, trench_h),
                     center=mp.Vector3(
                         +0.5 * sxy - 0.5 * trench_w, 0,
                         0.5 * sz - dpml - dair - dmcl - 0.5 * trench_h)))

    k_point = mp.Vector3(0, 0, 0)

    lambda_min = 0.7  # minimum source wavelength
    lambda_max = 1.0  # maximum source wavelength
    fmin = 1 / lambda_max
    fmax = 1 / lambda_min
    fcen = 0.5 * (fmin + fmax)
    df = fmax - fmin

    sources = [
        mp.Source(mp.GaussianSource(fcen, fwidth=df),
                  component=mp.Ex,
                  center=mp.Vector3(0, 0, 0.5 * sz - dpml - 0.5 * dair),
                  size=mp.Vector3(sxy, sxy, 0))
    ]

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=boundary_layers,
                        geometry=geometry,
                        dimensions=3,
                        k_point=k_point,
                        sources=sources)

    nfreq = 50
    refl = sim.add_flux(
        fcen, df, nfreq,
        mp.FluxRegion(center=mp.Vector3(0, 0, 0.5 * sz - dpml),
                      size=mp.Vector3(sxy, sxy, 0)))
    trans_grid = sim.add_flux(
        fcen, df, nfreq,
        mp.FluxRegion(center=mp.Vector3(0, 0,
                                        -0.5 * sz + dpml + dsub + wire_h),
                      size=mp.Vector3(sxy, sxy, 0)))
    trans_sub_top = sim.add_flux(
        fcen, df, nfreq,
        mp.FluxRegion(center=mp.Vector3(0, 0, -0.5 * sz + dpml + dsub),
                      size=mp.Vector3(sxy, sxy, 0)))
    trans_sub_bot = sim.add_flux(
        fcen, df, nfreq,
        mp.FluxRegion(center=mp.Vector3(0, 0, -0.5 * sz + dpml),
                      size=mp.Vector3(sxy, sxy, 0)))

    sim.run(mp.at_beginning(mp.output_epsilon), until=0)

    if args.substrate:
        sim.load_minus_flux('refl-flux', refl)

    sim.run(until_after_sources=mp.stop_when_fields_decayed(
        50, mp.Ex, mp.Vector3(0, 0, -0.5 * sz + dpml + 0.5 * dsub), 1e-9))

    if not args.substrate:
        sim.save_flux('refl-flux', refl)

    sim.display_fluxes(refl, trans_grid, trans_sub_top, trans_sub_bot)
Beispiel #25
0
def notch(w):

    print("#----------------------------------------")
    print("NOTCH WIDTH: %s nanometers" % (w * 1000))
    print("#----------------------------------------")

    # w is the width of the notch in the waveguide

    angrad = ang * pi / 180
    bottomoffset = e * h / tan(angrad)

    vertices = [
        mp.Vector3(w / 2 + bottomoffset, (.5 + e) * h),
        mp.Vector3(-w / 2 - bottomoffset, (.5 + e) * h),
        mp.Vector3(-w / 2 + bottomoffset, (.5 - e) * h),
        mp.Vector3(w / 2 - bottomoffset, (.5 - e) * h)
    ]

    if bottomoffset > w / 2:
        ratio = (w / 2) / bottomoffset
        vertices = [
            mp.Vector3(w / 2, h / 2),
            mp.Vector3(-w / 2, h / 2),
            mp.Vector3(0, (.5 - e * ratio) * h)
        ]

    print(vertices)

    #Waveguide Geometry
    cell = mp.Vector3(a, H)

    geometry = [
        mp.Block(cell, center=mp.Vector3(0, 0), material=default_material),
        mp.Block(mp.Vector3(a, hu + h / 2),
                 center=mp.Vector3(0, (hu + h / 2) / 2),
                 material=upper_material),
        mp.Block(mp.Vector3(a, hl + h / 2),
                 center=mp.Vector3(0, -(hl + h / 2) / 2),
                 material=lower_material),
        mp.Block(mp.Vector3(a, h),
                 center=mp.Vector3(0, 0),
                 material=core_material)
    ]

    if w > 0:
        geometry.append(mp.Prism(vertices, height=1, material=upper_material))

    pml_layers = [mp.Absorber(thickness=dpml)]

    r00 = None
    r01 = None
    r10 = None
    r11 = None

    t00 = None
    t01 = None
    t10 = None
    t11 = None

    su0 = None
    sd0 = None
    su1 = None
    sd1 = None

    modes = [0, 1]

    if only_fund:
        modes = [0]

    # eig_parity_fund = 	mp.EVEN_Z+mp.EVEN_Y;
    # eig_parity_first = 	mp.EVEN_Z+mp.ODD_Y;

    eig_parity_fund = mp.EVEN_Y
    eig_parity_first = mp.ODD_Y

    # for mode in [0, 1]:
    for mode in modes:

        if mode == 0:
            eig_parity = eig_parity_fund  # Fundamental
            print("-----------")
            print("MODE TYPE: FUNDAMENTAL")

        else:
            eig_parity = eig_parity_first  # First Order
            print("-----------")
            print("MODE TYPE: FIRST ORDER")

        sources = [
            mp.EigenModeSource(mp.ContinuousSource(frequency=fcen),
                               size=mp.Vector3(0, H),
                               center=mp.Vector3(Ls, 0),
                               eig_parity=eig_parity)
        ]

        sim = mp.Simulation(cell_size=cell,
                            boundary_layers=pml_layers,
                            geometry=geometry,
                            sources=sources,
                            resolution=resolution,
                            force_complex_fields=True)
        '''
		#--------------------------------------------------
		#FOR DISPLAYING THE GEOMETRY

		sim.run(until = 200)

		eps_data = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Dielectric)
		plt.figure(dpi=100)
		plt.imshow(eps_data.transpose(), interpolation='spline36', cmap='binary')
		#plt.axis('off')
		plt.show()

		quit()
		#----------------------------------------------------
		'''
        '''
		#------------------------------------------------------
		#FOR GENERATING THE ELECTRIC FIELD GIF
		#Note: After running this program, write the following commands in Terminal:
		    # $ source deactivate mp
		    # $ cd notch-out/
		    # $ python ../NotchIP.py

		sim.use_output_directory()
		sim.run(mp.at_beginning(mp.output_epsilon),
		        mp.to_appended("ez", mp.at_every(0.6, mp.output_efield_z)),
		        until = 200)
		#sim.run(mp.at_every(0.6 , mp.output_png(mp.Ez, "-Zc dkbluered")), until=200)

		#---------------------------------------------------------
		'''

        #---------------------------------------------------------
        # FOR GENERATING THE TRANSMITTANCE SPECTRUM

        nfreq = 1  # number of frequencies at which to compute flux

        refl_fr1 = mp.FluxRegion(center=mp.Vector3(Lr1, 0),
                                 size=mp.Vector3(
                                     0, monitorheight))  # Reflected flux 1
        refl_fr2 = mp.FluxRegion(center=mp.Vector3(Lr2, 0),
                                 size=mp.Vector3(
                                     0, monitorheight))  # Reflected flux 2
        tran_fr = mp.FluxRegion(center=mp.Vector3(Lt, 0),
                                size=mp.Vector3(
                                    0, monitorheight))  # Transmitted flux
        su_fr = mp.FluxRegion(center=mp.Vector3(0, monitorheight / 2),
                              size=mp.Vector3(
                                  a, 0))  # Flux loss above the waveguide
        sd_fr = mp.FluxRegion(center=mp.Vector3(0, -monitorheight / 2),
                              size=mp.Vector3(
                                  a, 0))  # Flux loss below the waveguide

        # refl1 = sim.add_flux(fcen, df, nfreq, refl_fr1)
        # refl2 = sim.add_flux(fcen, df, nfreq, refl_fr2)
        # tran = 	sim.add_flux(fcen, df, nfreq, tran_fr)
        # su = 	sim.add_flux(fcen, df, nfreq, su_fr)
        # sd = 	sim.add_flux(fcen, df, nfreq, sd_fr)

        # ------------------------ CODE FOR SEPARATING FUND AND FIRST ORDER MODE STARTS HERE ------------------------

        refl_vals = []
        tran_vals = []

        def get_refl_slice(sim):
            # print(sim.get_array(center=mp.Vector3(Lr1,0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True))
            # refl_val = sim.get_array(center=mp.Vector3(Lr1,0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True)
            refl_vals.append(
                sim.get_array(center=mp.Vector3(Lr1, 0),
                              size=mp.Vector3(0,
                                              monitorheight - 2 / resolution),
                              component=mp.Ez,
                              cmplx=True))

        def get_tran_slice(sim):
            # print(sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True))
            # tran_val = sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True)
            tran_vals.append(
                sim.get_array(center=mp.Vector3(Lt, 0),
                              size=mp.Vector3(0,
                                              monitorheight - 2 / resolution),
                              component=mp.Ez,
                              cmplx=True))

        gif = True

        if gif:  # and w == 0.1:
            sim.use_output_directory()
            sim.run(mp.at_beginning(mp.output_epsilon),
                    mp.at_end(get_refl_slice),
                    mp.at_end(get_tran_slice),
                    until=100)

            refl1 = sim.add_flux(fcen, df, nfreq, refl_fr1)
            refl2 = sim.add_flux(fcen, df, nfreq, refl_fr2)
            tran = sim.add_flux(fcen, df, nfreq, tran_fr)
            su = sim.add_flux(fcen, df, nfreq, su_fr)
            sd = sim.add_flux(fcen, df, nfreq, sd_fr)

            # sim.run(mp.at_every(wavelength / 20, mp.output_efield_z), until=wavelength)
            # sim.run(mp.at_every(wavelength/20 , mp.output_png(mp.Ez, "-RZc bluered -A notch-out/notch-eps-000000000.h5 -a gray:.2")), until=19*wavelength/20)
            sim.run(mp.at_every(
                wavelength / 20,
                mp.output_png(
                    mp.Ez,
                    "-RZc bluered -A notch-out/notch-eps-000000.00.h5 -a gray:.2"
                )),
                    until=19 * wavelength / 20)
            sim.run(until=50)
        else:
            sim.run(mp.at_end(get_refl_slice),
                    mp.at_end(get_tran_slice),
                    until=100)

            sim.run(until_after_sources=mp.stop_when_fields_decayed(
                50, mp.Ez, mp.Vector3(), 1e-5))

        os.system(
            "h5topng notch-out/notch-eps-000000.00.h5; mv notch-out/notch-eps-000000.00.png "
            + case + "-" + str(int(w * 1000)) + "-" + str(mode) + "-eps.png")
        os.system("cp notch-out/notch-ez-000100.00.png " + case + "-" +
                  str(int(w * 1000)) + "-" + str(mode) + ".png")
        os.system("convert notch-out/notch-ez-*.png    " + case + "-" +
                  str(int(w * 1000)) + "-" + str(mode) + ".gif")

        # get_eigenmode(fcen, mp., refl_fr1, 1, kpoint)
        # v = mp.volume(mp.vec(Lr1, -monitorheight/2), mp.vec(Lr1, monitorheight/2))
        # mode = get_eigenmode(fcen, mp.X, v, v, 1, mp.vec(0, 0, 0), True, 0, 0, 1e-7, True)
        # print(mode.amplitude)

        # coef_refl_fund = 	mp.get_eigenmode_coefficients_and_kpoints(refl_fr1, 1, eig_parity=eig_parity_fund, 	eig_resolution=resolution, eig_tolerance=1e-7)
        # coef_refl_first = 	mp.get_eigenmode_coefficients_and_kpoints(refl_fr1, 1, eig_parity=eig_parity_first, eig_resolution=resolution, eig_tolerance=1e-7)
        #
        # coef_tran_fund = 	mp.get_eigenmode_coefficients_and_kpoints(tran_fr, 	1, eig_parity=eig_parity_fund, 	eig_resolution=resolution, eig_tolerance=1e-7)
        # coef_tran_first = 	mp.get_eigenmode_coefficients_and_kpoints(tran_fr, 	1, eig_parity=eig_parity_first, eig_resolution=resolution, eig_tolerance=1e-7)

        ep = mp.ODD_Z

        #coef_refl_fund, 	vgrp, kpoints_fund 	= 	sim.get_eigenmode_coefficients(refl1, [1], eig_parity=ep, 	eig_resolution=resolution, eig_tolerance=1e-7)
        #coef_refl_first, 	vgrp, kpoints_first =	sim.get_eigenmode_coefficients(refl1, [2], eig_parity=ep,	eig_resolution=resolution, eig_tolerance=1e-7)

        #coef_tran_fund, 	vgrp, kpoints_fund 	=	sim.get_eigenmode_coefficients(tran,  [1], eig_parity=ep, 	eig_resolution=resolution, eig_tolerance=1e-7)
        #coef_tran_first,	vgrp, kpoints_first = 	sim.get_eigenmode_coefficients(tran,  [2], eig_parity=ep, 	eig_resolution=resolution, eig_tolerance=1e-7)

        # print(kpoints_fund)
        # print(kpoints_first)
        # print(kpoints_fund[0])
        # print(type(kpoints_fund[0]))
        # print(dir(kpoints_fund[0]))

        # n_eff_fund = 	wavelength*kpoints_fund[0].x
        # n_eff_first = 	wavelength*kpoints_first[0].x

        n_eff_fund = neff
        n_eff_first = 1

        print(n_eff_fund)
        print(n_eff_first)

        # print(coef_refl_fund)
        # print(type(coef_refl_fund))
        # print(dir(coef_refl_fund))

        # print(coef_refl_fund[0])
        # print(coef_refl_fund[0][0,0,:])
        #
        # fund_refl_amp = 		coef_refl_fund[0][0,0,1];
        # first_order_refl_amp =	coef_refl_first[0][0,0,1];
        # fund_tran_amp =			coef_tran_fund[0][0,0,0];
        # first_order_tran_amp =	coef_tran_first[0][0,0,0];

        print("get_eigenmode_coefficients:\n")

        #print(coef_refl_fund)
        #print(coef_refl_first)
        #print(coef_tran_fund)
        #print(coef_tran_first)

        print("\n")
        # print(coef_refl_fund[0,0,:])

        #fund_refl_amp = 		coef_refl_fund[0,0,1];
        #first_order_refl_amp =	coef_refl_first[0,0,1];
        #fund_tran_amp =			coef_tran_fund[0,0,0];
        #first_order_tran_amp =	coef_tran_first[0,0,0];

        refl_val = refl_vals[0]
        tran_val = tran_vals[0]

        # n_eff must satisfy n_e <= n_eff <= n_c for the mode to be bound.

        def fund_func(n_eff):
            if n_eff >= n_c and n_eff <= n_e:
                return sqrt(n_eff**2 - n_c**2) - sqrt(n_e**2 - n_eff**2) * tan(
                    pi * h / wavelength * sqrt(n_e**2 - n_eff**2))

        def first_order_func(n_eff):
            if n_eff >= n_c and n_eff <= n_e:
                return sqrt(n_eff**2 - n_c**2) - sqrt(n_e**2 - n_eff**2) * tan(
                    pi * h / wavelength * sqrt(n_e**2 - n_eff**2) - pi / 2)

        initial_guess = (n_c + n_e) / 2

        # n_eff_fund = 	fsolve(fund_func, initial_guess)
        # n_eff_first = 	fsolve(first_order_func, n_c)

        print(n_eff_fund, n_eff_first)

        assert (n_eff_fund > n_eff_first)

        if len(n_eff_funds) == 0:
            n_eff_funds.append(n_eff_fund)

        if len(n_eff_firsts) == 0:
            n_eff_firsts.append(n_eff_first)

        ky0_fund = np.abs(2 * pi / wavelength * sqrt(n_e**2 - n_eff_fund**2))
        ky0_first = np.abs(2 * pi / wavelength * sqrt(n_e**2 - n_eff_first**2))

        ky1_fund = ky0_fund  # np.abs(2 * pi / wavelength * sqrt(n_eff_fund **2 - n_c**2))
        ky1_first = ky0_first  # np.abs(2 * pi / wavelength * sqrt(n_eff_first**2 - n_c**2))

        E_fund = lambda y: cos(ky0_fund * y) if np.abs(y) < h / 2 else cos(
            ky0_fund * h / 2) * np.exp(-ky1_fund * (np.abs(y) - h / 2))
        E_first_order = lambda y: sin(ky0_first * y) if np.abs(
            y) < h / 2 else sin(ky0_first * h / 2) * np.exp(-ky1_first * (
                np.abs(y) - h / 2)) * np.sign(y)
        # y_list = np.arange(-H/2+.5/resolution, H/2-.5/resolution, 1/resolution)

        #print("Y LIST: ", y_list)
        #print("SIZE OF Y LIST: ", y_list.size)

        E_fund_vec = np.zeros(y_list.size)
        E_first_order_vec = np.zeros(y_list.size)

        for index in range(y_list.size):
            y = y_list[index]
            E_fund_vec[index] = E_fund(y)
            E_first_order_vec[index] = E_first_order(y)

        # print(dir(sim))
        # print(type(sim.get_eigenmode_coefficients))
        # print(dir(sim.get_eigenmode_coefficients))
        # print(type(sim.get_eigenmode))
        # print(dir(sim.get_eigenmode))
        # print(sim.get_eigenmode.__code__.co_varnames)
        # print(sim.get_eigenmode.__defaults__)

        # E1 = sim.get_eigenmode(fcen, mp.X, refl1.where, 1, None)
        # E2 = sim.get_eigenmode(fcen, mp.X, refl1.where, 2, None)
        # E3 = sim.get_eigenmode(fcen, mp.X, refl1.where, 3, None)
        # E4 = sim.get_eigenmode(fcen, mp.X, refl1.where, 4, None)

        # E1 = sim.get_eigenmode(fcen, mp.X, refl1.where, 1, mp.Vector3(0, 0, 0))
        # E2 = sim.get_eigenmode(fcen, mp.X, refl1.where, 2, mp.Vector3(0, 0, 0))
        # E3 = sim.get_eigenmode(fcen, mp.X, refl1.where, 3, mp.Vector3(0, 0, 0))
        # E4 = sim.get_eigenmode(fcen, mp.X, refl1.where, 4, mp.Vector3(0, 0, 0))

        # print(refl1.where)
        # numEA = 0
        # E1 = sim.fields.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 1, mp.vec(0,0,0), True, 0, numEA, 1e-7, True)

        # print(type(E1))
        # print(dir(E1))
        #
        # print(refl1.where)
        # # print(E1, E2, E3, E4)
        # print(E1.amplitude, E1.band_num, E1.group_velocity, E1.k)
        # print(type(E1.amplitude))
        # print(dir(E1.amplitude))
        # print(doc(E1.amplitude))
        # print(self(E1.amplitude))
        # print(E1.amplitude(y_list))
        # print(type(E1.amplitude(y_list)))
        # print(dir(E1.amplitude(y_list)))
        # print(E1.amplitude, E2.amplitude, E3.amplitude, E4.amplitude)

        # E1 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 1, mp.vec(0, 0, 0))
        # E2 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 2, mp.vec(0, 0, 0))
        # E3 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 3, mp.vec(0, 0, 0))
        # E4 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 4, mp.vec(0, 0, 0))

        # print(y_list)
        #
        # E1a = np.zeros(y_list.size, dtype='Complex128');
        # E2a = np.zeros(y_list.size, dtype='Complex128');
        # E3a = np.zeros(y_list.size, dtype='Complex128');
        # E4a = np.zeros(y_list.size, dtype='Complex128');
        #
        # # print(mp.eigenmode_amplitude.__code__.co_varnames)
        # # print(mp.eigenmode_amplitude.__defaults__)
        #
        # for i in range(y_list.size):
        # 	# print(E1)
        # 	# print(E1.swigobj)
        # 	# print(E1.amplitude)
        # 	# print(mp.vec(Lr1, y_list[i], 0))
        # 	# print(mp.Vector3(Lr1, y_list[i], 0))
        # 	# print(mp.Ez)
        # 	# E1a[i] = mp.eigenmode_amplitude(E1.swigobj, mp.vec(Lr1, y_list[i], 0), mp.Ez);
        # 	eval_point = mp.vec(Lr1, y_list[i], 0)
        # 	# print(eval_point)
        # 	E1a[i] = mp.eigenmode_amplitude(E1.swigobj, eval_point, mp.Ex)
        # 	E2a[i] = mp.eigenmode_amplitude(E2.swigobj, eval_point, mp.Ex)
        # 	E3a[i] = mp.eigenmode_amplitude(E3.swigobj, eval_point, mp.Ex)
        # 	E4a[i] = mp.eigenmode_amplitude(E4.swigobj, eval_point, mp.Ex)
        # 	# E1a[i] = mp.eigenmode_amplitude(E1.amplitude, mp.Vector3(Lr1, y_list[i], 0), mp.Ez);
        #
        # plt.plot(y_list, np.abs(E1a)**2, 'bo-', label='E1')
        # plt.plot(y_list, np.abs(E2a)**2, 'ro-', label='E2')
        # plt.plot(y_list, np.abs(E3a)**2, 'go-', label='E3')
        # plt.plot(y_list, np.abs(E4a)**2, 'co-', label='E4')
        # # plt.axis([40.0, 300.0, 0.0, 100.0])
        # plt.xlabel("y (um)")
        # plt.ylabel("Field (a.u.)")
        # plt.legend(loc="center right")
        # plt.show()

        # print("r VECTOR: ", 	refl_val)
        # print("t VECTOR: ", 	tran_val)
        # print("E0 VECTOR: ", 	E_fund_vec)
        # print("E1 VECTOR: ", 	E_first_order_vec)

        # fund_refl_amp_2 = 			np.conj(np.dot(refl_val, E_fund_vec) 		/ np.dot(E_fund_vec, E_fund_vec))					# Conjugate becasue MEEP uses physics exp(kz-wt) rather than engineering exp(wt-kz)
        # first_order_refl_amp_2 = 	np.conj(np.dot(refl_val, E_first_order_vec) / np.dot(E_first_order_vec, E_first_order_vec))
        # fund_tran_amp_2 = 			np.conj(np.dot(tran_val, E_fund_vec) 		/ np.dot(E_fund_vec, E_fund_vec))
        # first_order_tran_amp_2 = 	np.conj(np.dot(tran_val, E_first_order_vec) / np.dot(E_first_order_vec, E_first_order_vec))

        fund_refl_amp = np.conj(
            np.dot(refl_val, E0) / np.dot(E0, E0)
        )  # Conjugate becasue MEEP uses physics exp(kz-wt) rather than engineering exp(wt-kz)
        first_order_refl_amp = 0  # np.conj(np.dot(refl_val, E1[:,2]) / np.dot(E1[:,2], E1[:,2]))
        fund_tran_amp = np.conj(np.dot(tran_val, E0) / np.dot(E0, E0))
        first_order_tran_amp = 0  # np.conj(np.dot(tran_val, E1[:,2]) / np.dot(E1[:,2], E1[:,2]))

        fund_refl = np.conj(fund_refl_amp) * E0
        not_fund_refl = refl_val - fund_refl
        fund_tran = np.conj(fund_tran_amp) * E0
        not_fund_tran = tran_val - fund_tran

        fund_refl_power = np.dot(np.conj(fund_refl), fund_refl)
        not_fund_refl_power = np.dot(np.conj(not_fund_refl), not_fund_refl)
        fund_tran_power = np.dot(np.conj(fund_tran), fund_tran)
        not_fund_tran_power = np.dot(np.conj(not_fund_tran), not_fund_tran)

        fund_refl_ratio = np.abs(fund_refl_power /
                                 (fund_refl_power + not_fund_refl_power))
        first_order_refl_ratio = 0
        fund_tran_ratio = np.abs(fund_tran_power /
                                 (fund_tran_power + not_fund_tran_power))
        first_order_tran_ratio = 0

        # plt.plot(y_list, np.abs(refl_val),	'bo-',label='reflectance')
        # plt.plot(y_list, np.abs(tran_val),	'ro-',label='transmittance')
        # plt.plot(y_list, E0,	'go-',label='E0')
        # plt.plot(y_list, fund_refl_amp*E0,	'co-',label='over')
        # # plt.axis([40.0, 300.0, 0.0, 100.0])
        # plt.xlabel("y (um)")
        # plt.ylabel("Field")
        # plt.legend(loc="center right")
        # plt.show()
        #
        # print("\n")
        #
        # print(tran_val.size, refl_val.size)
        #
        # print("\n")
        #
        # print(tran_val, refl_val, E0)
        #
        # print("\n")
        # # print(np.conj(tran_val), tran_val, E1[:,2])
        # #
        # # print(np.conj(refl_val), refl_val, E1[:,2])
        #
        # refl_tot_power = np.abs(np.dot(np.conj(refl_val), refl_val))
        # tran_tot_power = np.abs(np.dot(np.conj(tran_val), tran_val))
        #
        # print(fund_refl_amp, refl_tot_power, fund_tran_amp, tran_tot_power)

        # print(fund_refl_amp 		, fund_refl_amp_2 		)
        # print(first_order_refl_amp 	, first_order_refl_amp_2)
        # print(fund_tran_amp 		, fund_tran_amp_2 		)
        # print(first_order_tran_amp 	, first_order_tran_amp_2)
        #
        # print(np.angle(fund_refl_amp), 			np.angle(fund_refl_amp_2))
        # print(np.angle(first_order_refl_amp), 	np.angle(first_order_refl_amp_2))
        # print(np.angle(fund_tran_amp), 			np.angle(fund_tran_amp_2))
        # print(np.angle(first_order_tran_amp), 	np.angle(first_order_tran_amp_2))

        # fund_refl_power = 			np.abs(fund_tran_amp)			** 2
        # fund_refl_power = 			np.abs(fund_refl_amp)			** 2
        # first_order_refl_power = 	np.abs(first_order_refl_amp) 	** 2
        # fund_tran_power = 			np.abs(fund_tran_amp) 			** 2
        # first_order_tran_power = 	np.abs(first_order_tran_amp) 	** 2

        # print(fund_refl_power, first_order_refl_power, fund_tran_power, first_order_tran_power)

        # fund_refl_ratio = 			fund_refl_power 		/ (fund_refl_power + first_order_refl_power)
        # first_order_refl_ratio = 	first_order_refl_power 	/ (fund_refl_power + first_order_refl_power)
        # fund_tran_ratio = 			fund_tran_power 		/ (fund_tran_power + first_order_tran_power)
        # first_order_tran_ratio = 	first_order_tran_power 	/ (fund_tran_power + first_order_tran_power)

        # fund_refl_power = 			np.abs(fund_refl_amp)			** 2
        # first_order_refl_power = 	np.abs(first_order_refl_amp)	** 2
        # fund_tran_power = 			np.abs(fund_tran_amp)			** 2
        # first_order_tran_power = 	np.abs(first_order_tran_amp)	** 2
        #
        # fund_refl_ratio = 			fund_refl_power 		/ refl_tot_power
        # first_order_refl_ratio = 	first_order_refl_power 	/ refl_tot_power
        # fund_tran_ratio = 			fund_tran_power 		/ tran_tot_power
        # first_order_tran_ratio = 	first_order_tran_power 	/ tran_tot_power
        #
        # fund_refl_ratio = 			1
        # first_order_refl_ratio = 	0
        # fund_tran_ratio = 			1
        # first_order_tran_ratio = 	0

        print("Percentage of reflected light in fundamental mode: ",
              fund_refl_ratio * 100)
        print("Percentage of reflected light in first order mode: ",
              first_order_refl_ratio * 100)
        print("Percentage of transmitted light in fundamental mode: ",
              fund_tran_ratio * 100)
        print("Percentage of transmitted light in first order mode: ",
              first_order_tran_ratio * 100)

        # ------------------------ CODE FOR SEPARATING FUND AND FIRST ORDER MODE ENDS HERE ------------------------

        wl = []  #list of wavelengths

        refl1_flux = mp.get_fluxes(refl1)
        refl2_flux = mp.get_fluxes(refl2)
        tran_flux = mp.get_fluxes(tran)
        su_flux = mp.get_fluxes(su)
        sd_flux = mp.get_fluxes(sd)

        flux_freqs = mp.get_flux_freqs(refl1)

        for i in range(nfreq):
            wl = np.append(wl, 1 / flux_freqs[i])
            print(1 / flux_freqs[i])

        # for ind, elt in enumerate(wl):
        #     #print(round(elt, 4))
        #     if round(elt, 3) == 0.637:
        #         #print("ALERT: MATCH FOUND")
        #         index = ind

        index = 0

        rp = refl1_flux[index]
        tp = tran_flux[index]

        # print("rp/tp:\n")
        # print(rp)
        # print(tp)
        # print("\n")

        R = -refl1_flux[index] / (refl2_flux[index] - refl1_flux[index])
        T = tran_flux[index] / (refl2_flux[index] - refl1_flux[index])
        S = (refl2_flux[index] - tran_flux[index]) / (refl2_flux[index] -
                                                      refl1_flux[index])
        Su = su_flux[index] / (refl2_flux[index] - refl1_flux[index])
        Sd = -sd_flux[index] / (refl2_flux[index] - refl1_flux[index])

        S_correction = (1 - R - T) / (Su + Sd)

        # print(R, T, S, Su, Sd)

        r = sqrt(R)
        t = sqrt(T)

        # The amplitude ... times the phase ... accounting for the distance to the detector (Reverse exp(-kz) of phase).
        # r_fund = 	(r * fund_refl_ratio) 			* (fund_refl_amp 		/ np.abs(fund_refl_amp)) 		* (np.exp( 2j*pi * (-Lr1 - w/2) * n_eff_fund  / wavelength))	# Lr1 is negative because it is the (negative) position of the monitor, not the distace from the monitor to the center.
        # r_first = 	(r * first_order_refl_ratio) 	* (first_order_refl_amp / np.abs(first_order_refl_amp)) * (np.exp( 2j*pi * (-Lr1 - w/2) * n_eff_first / wavelength))
        # t_fund =    (t * fund_tran_ratio) 			* (fund_tran_amp 		/ np.abs(fund_tran_amp))		* (np.exp( 2j*pi * ( Lt  - w/2) * n_eff_fund  / wavelength))
        # t_first =   (t * first_order_tran_ratio) 	* (first_order_tran_amp / np.abs(first_order_tran_amp)) * (np.exp( 2j*pi * ( Lt  - w/2) * n_eff_first / wavelength))

        r_fund = (r * fund_refl_ratio) * np.exp(
            1j * np.angle(fund_refl_amp) + 2j * pi *
            (-Lr1 - w / 2) * n_eff_fund / wavelength
        )  # Lr1 is negative because it is the (negative) position of the monitor, not the distace from the monitor to the center.
        r_first = (r * first_order_refl_ratio
                   ) * np.exp(1j * np.angle(first_order_refl_amp) + 2j * pi *
                              (-Lr1 - w / 2) * n_eff_first / wavelength)
        t_fund = (t * fund_tran_ratio
                  ) * np.exp(1j * np.angle(fund_tran_amp) + 2j * pi *
                             (Lt - w / 2) * n_eff_fund / wavelength)
        t_first = (t * first_order_tran_ratio
                   ) * np.exp(1j * np.angle(first_order_tran_amp) + 2j * pi *
                              (Lt - w / 2) * n_eff_first / wavelength)

        if mode == 0:
            r00 = r_fund
            r01 = r_first

            t00 = t_fund
            t01 = t_first

            su0 = sqrt(np.abs(Su * S_correction))
            sd0 = sqrt(np.abs(Sd * S_correction))
            # su0 = sqrt(Su)
            # sd0 = sqrt(Sd)

            r00s.append(r00)
            r01s.append(r01)
            t00s.append(t00)
            t01s.append(t01)
            su0s.append(su0)
            sd0s.append(sd0)

            if only_fund:
                r10s.append(0)
                r11s.append(0)
                t10s.append(0)
                t11s.append(1)
                su1s.append(0)
                sd1s.append(0)
        else:
            r10 = r_fund
            r11 = r_first

            t10 = t_fund
            t11 = t_first

            su1 = sqrt(np.abs(Su * S_correction))
            sd1 = sqrt(np.abs(Sd * S_correction))
            # su1 = sqrt(Su)
            # sd1 = sqrt(Sd)

            r10s.append(r10)
            r11s.append(r11)
            t10s.append(t10)
            t11s.append(t11)
            su1s.append(su1)
            sd1s.append(sd1)

        norm_Su = S * Su / (Su + Sd)

        NET = round((R + T + S) * 100, 0)
        if NET > 100.0:
            NET = 100.0

        NET_LOSS = round((Su + Sd) / S * 100, 0)
        if NET_LOSS > 100.0:
            NET_LOSS = 100.0
        '''
		np.append(ws, [w * 1000])
		np.append(Rs, [R * 100])
		np.append(Ts, [T * 100])
		np.append(Ss, [S * 100])
		np.append(NET_LIST, [NET])
		np.append(Sus, [Su * 100])
		np.append(Sds, [Sd * 100])
		np.append(NET_LOSS_LIST, [NET_LOSS])
		np.append(norm_Sus, [norm_Su * 100])
		'''

        if mode == 0:
            ws.append(w * 1000)
            Rs.append(R * 100)
            Ts.append(T * 100)
            Ss.append(S * 100)
            NET_LIST.append(NET)
            Sus.append(Su * 100)
            Sds.append(Sd * 100)
            NET_LOSS_LIST.append(NET_LOSS)
            norm_Sus.append(norm_Su * 100)

        if mode == 0:

            f1.write("--------------------------------------------------- \n")

            f1.write("Notch Width: %s nanometers \n" % (w * 1000))
            f1.write("Reflection Percentage: %s\n" % (R * 100))
            f1.write("Transmission Percentage: %s\n" % (T * 100))
            f1.write("Total Loss Percentage: %s\n" % (S * 100))
            f1.write("Percentage of Light Accounted For: %s\n" % (NET))
            f1.write("Upper Loss Percentage: %s\n" % (Su * 100))
            f1.write("Lower Loss Percentage: %s\n" % (Sd * 100))
            f1.write("Percentage of Total Loss Accounted For: %s\n" %
                     (NET_LOSS))
            f1.write("Normalized Upper Loss Percentage: %s\n" %
                     (norm_Su * 100))
            f1.write("\n \n")

            f1.write("FUNDAMENTAL MODE \n")
            f1.write("n_eff:   %s\n" % (n_eff_fund))
            f1.write("Re(r00): %s\n" % (np.real(r00)))
            f1.write("Im(r00): %s\n" % (np.imag(r00)))
            f1.write("Re(r01): %s\n" % (np.real(r01)))
            f1.write("Im(r01): %s\n" % (np.imag(r01)))
            f1.write("Re(t00): %s\n" % (np.real(t00)))
            f1.write("Im(t00): %s\n" % (np.imag(t00)))
            f1.write("Re(t01): %s\n" % (np.real(t01)))
            f1.write("Im(t01): %s\n" % (np.imag(t01)))
            f1.write("Re(su0): %s\n" % (np.real(su0)))
            f1.write("Im(su0): %s\n" % (np.imag(su0)))
            f1.write("Re(sd0): %s\n" % (np.real(sd0)))
            f1.write("Im(sd0): %s\n" % (np.imag(sd0)))
            f1.write("\n")

        else:

            f1.write("FIRST ORDER MODE \n")
            f1.write("n_eff:   %s\n" % (n_eff_first))
            f1.write("Re(r10): %s\n" % (np.real(r10)))
            f1.write("Im(r10): %s\n" % (np.imag(r10)))
            f1.write("Re(r11): %s\n" % (np.real(r11)))
            f1.write("Im(r11): %s\n" % (np.imag(r11)))
            f1.write("Re(t10): %s\n" % (np.real(t10)))
            f1.write("Im(t10): %s\n" % (np.imag(t10)))
            f1.write("Re(t11): %s\n" % (np.real(t11)))
            f1.write("Im(t11): %s\n" % (np.imag(t11)))
            f1.write("Re(su1): %s\n" % (np.real(su1)))
            f1.write("Im(su1): %s\n" % (np.imag(su1)))
            f1.write("Re(sd1): %s\n" % (np.real(sd1)))
            f1.write("Im(sd1): %s\n" % (np.imag(sd1)))

            f1.write("--------------------------------------------------- \n")

        sim.reset_meep()
Beispiel #26
0
    def _load_dump_structure_3d(self,
                                chunk_file=False,
                                chunk_sim=False,
                                single_parallel_file=True):
        from meep.materials import aSi
        resolution = 15
        cell = mp.Vector3(2.3, 2.1, 2.7)
        sources = mp.Source(src=mp.GaussianSource(2.5, fwidth=0.1),
                            center=mp.Vector3(),
                            component=mp.Hy)
        one_by_one_by_one = mp.Vector3(1, 1, 1)
        geometry = [
            mp.Block(material=mp.Medium(index=2.3),
                     center=mp.Vector3(),
                     size=one_by_one_by_one),
            mp.Block(material=aSi,
                     center=mp.Vector3(1),
                     size=one_by_one_by_one)
        ]
        default_material = mp.Medium(index=1.4)
        boundary_layers = [mp.Absorber(0.2)]
        k_point = mp.Vector3(0.4, -1.3, 0.7)

        sim1 = mp.Simulation(resolution=resolution,
                             cell_size=cell,
                             k_point=k_point,
                             geometry=geometry,
                             boundary_layers=boundary_layers,
                             default_material=default_material,
                             sources=[sources])

        sample_point = mp.Vector3(0.73, -0.33, 0.61)
        ref_field_points = []

        def get_ref_field_point(sim):
            p = sim.get_field_point(mp.Hy, sample_point)
            ref_field_points.append(p.real)

        sim1.run(mp.at_every(5, get_ref_field_point), until=50)

        dump_dirname = os.path.join(self.temp_dir, 'test_load_dump_structure')
        sim1.dump(dump_dirname,
                  dump_structure=True,
                  dump_fields=False,
                  single_parallel_file=single_parallel_file)

        dump_chunk_fname = None
        chunk_layout = None
        if chunk_file:
            dump_chunk_fname = os.path.join(dump_dirname, 'chunk_layout.h5')
            sim1.dump_chunk_layout(dump_chunk_fname)
            chunk_layout = dump_chunk_fname
        if chunk_sim:
            chunk_layout = sim1

        sim = mp.Simulation(resolution=resolution,
                            cell_size=cell,
                            sources=[sources],
                            k_point=k_point,
                            boundary_layers=boundary_layers,
                            chunk_layout=chunk_layout)
        sim.load(dump_dirname,
                 load_structure=True,
                 load_fields=False,
                 single_parallel_file=single_parallel_file)
        field_points = []

        def get_field_point(sim):
            p = sim.get_field_point(mp.Hy, sample_point)
            field_points.append(p.real)

        sim.run(mp.at_every(5, get_field_point), until=50)

        for ref_pt, pt in zip(ref_field_points, field_points):
            self.assertAlmostEqual(ref_pt, pt)
Beispiel #27
0
def notch(w):

    print("#----------------------------------------")
    print("NOTCH WIDTH: %s nanometers" % (w * 1000))
    print("#----------------------------------------")

    # w is the width of the notch in the waveguide

    #Waveguide Math
    e = 0.4  # etch fraction [0 -> 1]

    h2 = h * (1 - e)  #height of the etched region
    d = 1  #spacing of the waveguides
    posd = d / 2  #pos half d
    negd = -d / 2  #neg half d

    ang = 80  #angle of the sidewall
    angrad = ang * pi / 180
    bottomoffset = h / tan(angrad)
    c = bottomoffset / 2
    r = sqrt(bottomoffset**2 + h**2)
    fcen = 1 / wavelength
    df = 0.05

    n_e = 2.2012  # refractive index inside waveguide (at wavelength 0.6372)
    n_c = 1.4569  # refractive index outside waveguide (at wavelength 0.6372)

    #Waveguide Geometry
    cell = mp.Vector3(a, H)

    default_material = mp.Medium(epsilon=n_c**2)
    core_material = mp.Medium(epsilon=n_e**2)

    geometry = [
        mp.Block(cell, center=mp.Vector3(0, 0), material=default_material),
        mp.Block(mp.Vector3(a + 2 * h, h),
                 center=mp.Vector3(0, 0),
                 material=core_material),
        # mp.Block(mp.Vector3(w, e * h),
        mp.Block(mp.Vector3(w, e * h),
                 center=mp.Vector3(0, h2 / 2),
                 material=default_material)
    ]

    # pml_layers = [mp.PML(0.2)]
    pml_layers = [mp.Absorber(thickness=pmlthickness)]
    # resolution = 50

    r00 = None
    r01 = None
    r10 = None
    r11 = None

    t00 = None
    t01 = None
    t10 = None
    t11 = None

    su0 = None
    sd0 = None
    su1 = None
    sd1 = None

    only_fund = True

    modes = [0, 1]

    if only_fund:
        modes = [0]

    # for mode in [0, 1]:
    for mode in modes:

        if mode == 0:
            eig_parity = mp.EVEN_Y  # Fundamental
            print("-----------")
            print("MODE TYPE: FUNDAMENTAL")

        else:
            eig_parity = mp.ODD_Y  # First Order
            print("-----------")
            print("MODE TYPE: FIRST ORDER")

        sources = [
            mp.EigenModeSource(mp.GaussianSource(frequency=fcen, fwidth=df),
                               size=mp.Vector3(0, H),
                               center=mp.Vector3(Ls, 0),
                               eig_parity=eig_parity)
        ]

        sim = mp.Simulation(cell_size=cell,
                            boundary_layers=pml_layers,
                            geometry=geometry,
                            sources=sources,
                            resolution=resolution,
                            force_complex_fields=True)
        '''
		#--------------------------------------------------
		#FOR DISPLAYING THE GEOMETRY

		sim.run(until = 200)

		eps_data = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Dielectric)
		plt.figure(dpi=100)
		plt.imshow(eps_data.transpose(), interpolation='spline36', cmap='binary')
		#plt.axis('off')
		plt.show()

		quit()
		#----------------------------------------------------
		'''
        '''
		#------------------------------------------------------
		#FOR GENERATING THE ELECTRIC FIELD GIF
		#Note: After running this program, write the following commands in Terminal:
		    # $ source deactivate mp
		    # $ cd notch-out/
		    # $ python ../NotchIP.py

		sim.use_output_directory()
		sim.run(mp.at_beginning(mp.output_epsilon),
		        mp.to_appended("ez", mp.at_every(0.6, mp.output_efield_z)),
		        until = 200)
		#sim.run(mp.at_every(0.6 , mp.output_png(mp.Ez, "-Zc dkbluered")), until=200)

		#---------------------------------------------------------
		'''

        #---------------------------------------------------------
        # FOR GENERATING THE TRANSMITTANCE SPECTRUM

        nfreq = 20  # number of frequencies at which to compute flux

        refl_fr1 = mp.FluxRegion(center=mp.Vector3(Lr1, 0),
                                 size=mp.Vector3(
                                     0, monitorheight))  # Reflected flux 1
        refl_fr2 = mp.FluxRegion(center=mp.Vector3(Lr2, 0),
                                 size=mp.Vector3(
                                     0, monitorheight))  # Reflected flux 2
        tran_fr = mp.FluxRegion(center=mp.Vector3(Lt, 0),
                                size=mp.Vector3(
                                    0, monitorheight))  # Transmitted flux
        su_fr = mp.FluxRegion(center=mp.Vector3(0, monitorheight / 2),
                              size=mp.Vector3(
                                  a, 0))  # Flux loss above the waveguide
        sd_fr = mp.FluxRegion(center=mp.Vector3(0, -monitorheight / 2),
                              size=mp.Vector3(
                                  a, 0))  # Flux loss below the waveguide

        refl1 = sim.add_flux(fcen, df, nfreq, refl_fr1)
        refl2 = sim.add_flux(fcen, df, nfreq, refl_fr2)
        tran = sim.add_flux(fcen, df, nfreq, tran_fr)
        su = sim.add_flux(fcen, df, nfreq, su_fr)
        sd = sim.add_flux(fcen, df, nfreq, sd_fr)

        # ------------------------ CODE FOR SEPARATING FUND AND FIRST ORDER MODE STARTS HERE ------------------------

        y_list = np.arange(-H / 2, H / 2, 1 / resolution)

        refl_vals = []
        tran_vals = []

        def get_refl_slice(sim):
            # print(sim.get_array(center=mp.Vector3(Lr1,0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True))
            # refl_val = sim.get_array(center=mp.Vector3(Lr1,0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True)
            refl_vals.append(
                sim.get_array(center=mp.Vector3(Lr1, 0),
                              size=mp.Vector3(0, H),
                              component=mp.Ez,
                              cmplx=True))

        def get_tran_slice(sim):
            # print(sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True))
            # tran_val = sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True)
            tran_vals.append(
                sim.get_array(center=mp.Vector3(Lt, 0),
                              size=mp.Vector3(0, H),
                              component=mp.Ez,
                              cmplx=True))

        pt = mp.Vector3(9.75, 0)  # Hardcoded?

        gif = True

        if gif:  # and w == 0.1:
            sim.use_output_directory()
            sim.run(mp.at_beginning(mp.output_epsilon),
                    mp.at_end(get_refl_slice),
                    mp.at_end(get_tran_slice),
                    until=100)
            # sim.run(mp.at_every(wavelength / 20, mp.output_efield_z), until=wavelength)
            sim.run(mp.at_every(
                wavelength / 20,
                mp.output_png(
                    mp.Ez,
                    "-RZc bluered -A notch-out/notch-eps-000000.00.h5 -a gray:.2"
                )),
                    until=19 * wavelength / 20)
            sim.run(until_after_sources=mp.stop_when_fields_decayed(
                50, mp.Ez, pt, 1e-3))
        else:
            sim.run(mp.at_beginning(mp.output_epsilon),
                    mp.at_time(100, get_refl_slice),
                    mp.at_time(100, get_tran_slice),
                    until_after_sources=mp.stop_when_fields_decayed(
                        50, mp.Ez, pt, 1e-3))

        os.system("cp notch-out/notch-ez-000100.00.png " + str(int(w * 1000)) +
                  "-" + str(mode) + ".png")
        os.system("convert notch-out/notch-ez-*.png " + str(int(w * 1000)) +
                  "-" + str(mode) + ".gif")

        refl_val = refl_vals[0]
        tran_val = tran_vals[0]

        # n_eff must satisfy n_e <= n_eff <= n_c for the mode to be bound.

        def fund_func(n_eff):
            if n_eff >= n_c and n_eff <= n_e:
                return sqrt(n_eff**2 - n_c**2) - sqrt(n_e**2 - n_eff**2) * tan(
                    pi * h / wavelength * sqrt(n_e**2 - n_eff**2))

        def first_order_func(n_eff):
            if n_eff >= n_c and n_eff <= n_e:
                return sqrt(n_eff**2 - n_c**2) - sqrt(n_e**2 - n_eff**2) * tan(
                    pi * h / wavelength * sqrt(n_e**2 - n_eff**2) - pi / 2)

        initial_guess = (n_c + n_e) / 2

        n_eff_fund = fsolve(fund_func, initial_guess)
        n_eff_first = fsolve(first_order_func, n_c)

        print(n_eff_fund, n_eff_first)

        assert (n_eff_fund > n_eff_first)

        if len(n_eff_funds) == 0:
            n_eff_funds.append(n_eff_fund[0])

        if len(n_eff_firsts) == 0:
            n_eff_firsts.append(n_eff_first[0])

        ky0_fund = np.absolute(2 * pi / wavelength *
                               sqrt(n_e**2 - n_eff_fund**2))
        ky0_first = np.absolute(2 * pi / wavelength *
                                sqrt(n_e**2 - n_eff_first**2))

        ky1_fund = np.absolute(2 * pi / wavelength *
                               sqrt(n_eff_fund**2 - n_c**2))
        ky1_first = np.absolute(2 * pi / wavelength *
                                sqrt(n_eff_first**2 - n_c**2))

        E_fund = lambda y: cos(ky0_fund * y) if np.absolute(
            y) < h / 2 else cos(ky0_fund * h / 2) * np.exp(-ky1_fund * (
                np.absolute(y) - h / 2))
        E_first_order = lambda y: sin(ky0_first * y) if np.absolute(
            y) < h / 2 else sin(ky0_first * h / 2) * np.exp(-ky1_first * (
                np.absolute(y) - h / 2)) * np.sign(y)
        # y_list = np.arange(-H/2+.5/resolution, H/2-.5/resolution, 1/resolution)

        #print("Y LIST: ", y_list)
        #print("SIZE OF Y LIST: ", y_list.size)

        E_fund_vec = np.zeros(y_list.size)
        E_first_order_vec = np.zeros(y_list.size)

        for index in range(y_list.size):
            y = y_list[index]
            E_fund_vec[index] = E_fund(y)
            E_first_order_vec[index] = E_first_order(y)

        # print("r VECTOR: ", 	refl_val)
        # print("t VECTOR: ", 	tran_val)
        # print("E0 VECTOR: ", 	E_fund_vec)
        # print("E1 VECTOR: ", 	E_first_order_vec)

        # plt.plot(y_list, refl_val*100,'bo-',label='reflectance')
        # plt.plot(y_list, tran_val*1,'ro-',label='transmittance')
        # plt.plot(y_list, E_fund_vec,'go-',label='E0')
        # plt.plot(y_list, E_first_order_vec, 'co-', label='E1')
        # # plt.axis([40.0, 300.0, 0.0, 100.0])
        # plt.xlabel("y (um)")
        # plt.ylabel("Field")
        # plt.legend(loc="center right")
        # plt.show()

        fund_refl_amp = np.conj(
            np.dot(refl_val, E_fund_vec) / np.dot(E_fund_vec, E_fund_vec)
        )  # Conjugate becasue MEEP uses physics exp(kz-wt) rather than engineering exp(wt-kz)
        first_order_refl_amp = np.conj(
            np.dot(refl_val, E_first_order_vec) /
            np.dot(E_first_order_vec, E_first_order_vec))
        fund_tran_amp = np.conj(
            np.dot(tran_val, E_fund_vec) / np.dot(E_fund_vec, E_fund_vec))
        first_order_tran_amp = np.conj(
            np.dot(tran_val, E_first_order_vec) /
            np.dot(E_first_order_vec, E_first_order_vec))

        # fund_refl_power = 			np.abs(fund_tran_amp)			** 2
        fund_refl_power = np.abs(fund_refl_amp)**2
        first_order_refl_power = np.abs(first_order_refl_amp)**2
        fund_tran_power = np.abs(fund_tran_amp)**2
        first_order_tran_power = np.abs(first_order_tran_amp)**2

        print(fund_refl_power, first_order_refl_power, fund_tran_power,
              first_order_tran_power)

        fund_refl_ratio = fund_refl_power / (fund_refl_power +
                                             first_order_refl_power)
        first_order_refl_ratio = first_order_refl_power / (
            fund_refl_power + first_order_refl_power)
        fund_tran_ratio = fund_tran_power / (fund_tran_power +
                                             first_order_tran_power)
        first_order_tran_ratio = first_order_tran_power / (
            fund_tran_power + first_order_tran_power)

        print("Percentage of reflected light in fundamental mode: ",
              fund_refl_ratio * 100)
        print("Percentage of reflected light in first order mode: ",
              first_order_refl_ratio * 100)
        print("Percentage of transmitted light in fundamental mode: ",
              fund_tran_ratio * 100)
        print("Percentage of transmitted light in first order mode: ",
              first_order_tran_ratio * 100)

        # ------------------------ CODE FOR SEPARATING FUND AND FIRST ORDER MODE ENDS HERE ------------------------

        wl = []  #list of wavelengths

        refl1_flux = mp.get_fluxes(refl1)
        refl2_flux = mp.get_fluxes(refl2)
        tran_flux = mp.get_fluxes(tran)
        su_flux = mp.get_fluxes(su)
        sd_flux = mp.get_fluxes(sd)

        flux_freqs = mp.get_flux_freqs(refl1)

        for i in range(nfreq):
            wl = np.append(wl, 1 / flux_freqs[i])
            print(1 / flux_freqs[i])

        for ind, elt in enumerate(wl):
            #print(round(elt, 4))
            if round(elt, 3) == 0.637:
                #print("ALERT: MATCH FOUND")
                index = ind

        R = -refl1_flux[index] / (refl2_flux[index] - refl1_flux[index])
        T = tran_flux[index] / (refl2_flux[index] - refl1_flux[index])
        S = (refl2_flux[index] - tran_flux[index]) / (refl2_flux[index] -
                                                      refl1_flux[index])
        Su = su_flux[index] / (refl2_flux[index] - refl1_flux[index])
        Sd = -sd_flux[index] / (refl2_flux[index] - refl1_flux[index])

        S_correction = (1 - R - T) / (Su + Sd)

        print(R, T, S, Su, Sd)

        r = sqrt(R)
        t = sqrt(T)

        # The amplitude ... times the phase ... accounting for the distance to the detector (Reverse exp(-kz) of phase).
        r_fund = (r * fund_refl_ratio) * (
            fund_refl_amp / np.abs(fund_refl_amp)
        ) * (
            np.exp(2j * pi * (-Lr1 - w / 2) * n_eff_fund / wavelength)
        )  # Lr1 is negative because it is the (negative) position of the monitor, not the distace from the monitor to the center.
        r_first = (r * first_order_refl_ratio) * (
            first_order_refl_amp / np.abs(first_order_refl_amp)) * (np.exp(
                2j * pi * (-Lr1 - w / 2) * n_eff_first / wavelength))
        t_fund = (t * fund_tran_ratio) * (
            fund_tran_amp / np.abs(fund_tran_amp)) * (np.exp(
                2j * pi * (Lt - w / 2) * n_eff_fund / wavelength))
        t_first = (t * first_order_tran_ratio) * (
            first_order_tran_amp / np.abs(first_order_tran_amp)) * (np.exp(
                2j * pi * (Lt - w / 2) * n_eff_first / wavelength))

        if mode == 0:
            r00 = r_fund
            r01 = r_first

            t00 = t_fund
            t01 = t_first

            su0 = sqrt(np.abs(Su * S_correction))
            sd0 = sqrt(np.abs(Sd * S_correction))

            r00s.append(r00[0])
            r01s.append(r01[0])
            t00s.append(t00[0])
            t01s.append(t01[0])
            su0s.append(su0)
            sd0s.append(sd0)

            if only_fund:
                r10s.append(0)
                r11s.append(0)
                t10s.append(0)
                t11s.append(1)
                su1s.append(0)
                sd1s.append(0)
        else:
            r10 = r_fund
            r11 = r_first

            t10 = t_fund
            t11 = t_first

            su1 = sqrt(np.abs(Su * S_correction))
            sd1 = sqrt(np.abs(Sd * S_correction))

            r10s.append(r10[0])
            r11s.append(r11[0])
            t10s.append(t10[0])
            t11s.append(t11[0])
            su1s.append(su1)
            sd1s.append(sd1)

        norm_Su = S * Su / (Su + Sd)

        NET = round((R + T + S) * 100, 0)
        if NET > 100.0:
            NET = 100.0

        NET_LOSS = round((Su + Sd) / S * 100, 0)
        if NET_LOSS > 100.0:
            NET_LOSS = 100.0
        '''
		np.append(ws, [w * 1000])
		np.append(Rs, [R * 100])
		np.append(Ts, [T * 100])
		np.append(Ss, [S * 100])
		np.append(NET_LIST, [NET])
		np.append(Sus, [Su * 100])
		np.append(Sds, [Sd * 100])
		np.append(NET_LOSS_LIST, [NET_LOSS])
		np.append(norm_Sus, [norm_Su * 100])
		'''

        if mode == 0:
            ws.append(w * 1000)
            Rs.append(R * 100)
            Ts.append(T * 100)
            Ss.append(S * 100)
            NET_LIST.append(NET)
            Sus.append(Su * 100)
            Sds.append(Sd * 100)
            NET_LOSS_LIST.append(NET_LOSS)
            norm_Sus.append(norm_Su * 100)

        if mode == 0:

            f1.write("--------------------------------------------------- \n")

            f1.write("Notch Width: %s nanometers \n" % (w * 1000))
            f1.write("Reflection Percentage: %s\n" % (R * 100))
            f1.write("Transmission Percentage: %s\n" % (T * 100))
            f1.write("Total Loss Percentage: %s\n" % (S * 100))
            f1.write("Percentage of Light Accounted For: %s\n" % (NET))
            f1.write("Upper Loss Percentage: %s\n" % (Su * 100))
            f1.write("Lower Loss Percentage: %s\n" % (Sd * 100))
            f1.write("Percentage of Total Loss Accounted For: %s\n" %
                     (NET_LOSS))
            f1.write("Normalized Upper Loss Percentage: %s\n" %
                     (norm_Su * 100))
            f1.write("\n \n")

            f1.write("FUNDAMENTAL MODE \n")
            f1.write("n_eff:   %s\n" % (n_eff_fund[0]))
            f1.write("Re(r00): %s\n" % (np.real(r00))[0])
            f1.write("Im(r00): %s\n" % (np.imag(r00))[0])
            f1.write("Re(r01): %s\n" % (np.real(r01))[0])
            f1.write("Im(r01): %s\n" % (np.imag(r01))[0])
            f1.write("Re(t00): %s\n" % (np.real(t00))[0])
            f1.write("Im(t00): %s\n" % (np.imag(t00))[0])
            f1.write("Re(t01): %s\n" % (np.real(t01))[0])
            f1.write("Im(t01): %s\n" % (np.imag(t01))[0])
            f1.write("Re(su0): %s\n" % (np.real(su0)))
            f1.write("Im(su0): %s\n" % (np.imag(su0)))
            f1.write("Re(sd0): %s\n" % (np.real(sd0)))
            f1.write("Im(sd0): %s\n" % (np.imag(sd0)))
            f1.write("\n")

        else:

            f1.write("FIRST ORDER MODE \n")
            f1.write("n_eff:   %s\n" % (n_eff_first[0]))
            f1.write("Re(r10): %s\n" % (np.real(r10))[0])
            f1.write("Im(r10): %s\n" % (np.imag(r10))[0])
            f1.write("Re(r11): %s\n" % (np.real(r11))[0])
            f1.write("Im(r11): %s\n" % (np.imag(r11))[0])
            f1.write("Re(t10): %s\n" % (np.real(t10))[0])
            f1.write("Im(t10): %s\n" % (np.imag(t10))[0])
            f1.write("Re(t11): %s\n" % (np.real(t11))[0])
            f1.write("Im(t11): %s\n" % (np.imag(t11))[0])
            f1.write("Re(su1): %s\n" % (np.real(su1)))
            f1.write("Im(su1): %s\n" % (np.imag(su1)))
            f1.write("Re(sd1): %s\n" % (np.real(sd1)))
            f1.write("Im(sd1): %s\n" % (np.imag(sd1)))

            f1.write("--------------------------------------------------- \n")

        sim.reset_meep()
Beispiel #28
0
def energy_flux():
    """Source frequency interval"""

    f_inf = 0.20
    f_sup = 0.35

    f = 0.5 * (f_inf + f_sup)
    df = f_sup - f_inf

    wvl = 1 / f
    n_freq = 100
    source_component = mp.Ex
    """Materials"""
    n_ej232 = 1.58
    n_bgo = 2.15
    n_lyso = 1.82
    n_cdse = 2.61
    eps1_cdse = n_cdse**2
    eps2_cdse = 0
    # eps2_cdse = 0.5
    # fixme: here the sigma_d is different from MEEP's doc in function of freqeuency!
    cdse = mp.Medium(epsilon=eps1_cdse,
                     D_conductivity=f * eps2_cdse / eps1_cdse)
    """Dimension"""
    a = 1.
    thickness = 1. * a
    radius = 0.1 * a
    dpml = 0.5 * wvl
    """Computational domain in Meep"""
    r1 = np.array([0.5, -np.sqrt(3) / 2]) * a
    r2 = np.array([0.5, np.sqrt(3) / 2]) * a

    vec1 = mp.Vector3(*r1)
    vec2 = mp.Vector3(*r2)

    height = thickness + 2 * (wvl + dpml)
    width = 2 * wvl + 2 * dpml

    cell_size = mp.Vector3(width, width, height)

    # resolution = np.ceil((1 / (wvl / 50)))
    resolution = 20

    # geometry
    geom = [
        mp.Block(center=mp.Vector3(z=0.25 * cell_size.z),
                 size=mp.Vector3(mp.inf, mp.inf, 0.5 * cell_size.z),
                 material=mp.Medium(index=n_ej232)),
        mp.Block(center=mp.Vector3(z=-0.25 * cell_size.z),
                 size=mp.Vector3(mp.inf, mp.inf, 0.5 * cell_size.z),
                 material=mp.Medium(index=n_lyso))
    ]
    # periodic patterns
    diagonal = np.sqrt(cell_size.x**2 + cell_size.y**2)
    n1 = int(0.7 * diagonal / vec1.norm())
    n2 = int(0.7 * diagonal / vec2.norm())

    geom.append(
        mp.Block(center=mp.Vector3(),
                 size=mp.Vector3(mp.inf, mp.inf, thickness),
                 material=cdse))

    for i in range(-n1, n1 + 1):
        for j in range(-n2, n2 + 1):
            hole_center = i * vec1 + j * vec2
            if -0.5 * cell_size.x < hole_center.x < 0.5 * cell_size.x \
                    and -0.5 * cell_size.y < hole_center.y < 0.5 * cell_size.y:
                geom.append(
                    mp.Cylinder(radius=radius,
                                center=hole_center,
                                height=thickness,
                                material=mp.Medium(index=n_ej232)))

    source = mp.Source(src=mp.GaussianSource(f, fwidth=df),
                       center=mp.Vector3(),
                       component=mp.Ex)
    """Boundary conditions"""
    pml_layers = [
        mp.Absorber(dpml, direction=mp.X),
        mp.Absorber(dpml, direction=mp.Y),
        mp.PML(dpml, direction=mp.Z)
    ]
    sim = mp.Simulation(sources=[source],
                        boundary_layers=pml_layers,
                        cell_size=cell_size,
                        geometry=geom,
                        resolution=resolution)
    """Energy flux region"""
    # source surrounding box
    srcbox_width = wvl / 4
    srcbox_top = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(0, 0, 0.5 * srcbox_width),
                      size=mp.Vector3(srcbox_width, srcbox_width, 0),
                      direction=mp.Z,
                      weight=1))

    srcbox_bot = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(0, 0, -0.5 * srcbox_width),
                      size=mp.Vector3(srcbox_width, srcbox_width, 0),
                      direction=mp.Z,
                      weight=-1))

    srcbox_yf = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(0, 0.5 * srcbox_width, 0),
                      size=mp.Vector3(srcbox_width, 0, srcbox_width),
                      direction=mp.Y,
                      weight=1))

    srcbox_yb = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(0, -0.5 * srcbox_width, 0),
                      size=mp.Vector3(srcbox_width, 0, srcbox_width),
                      direction=mp.Y,
                      weight=-1))

    srcbox_xf = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(0.5 * srcbox_width, 0, 0),
                      size=mp.Vector3(0, srcbox_width, srcbox_width),
                      direction=mp.X,
                      weight=1))

    srcbox_xb = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(-0.5 * srcbox_width, 0, 0),
                      size=mp.Vector3(0, srcbox_width, srcbox_width),
                      direction=mp.X,
                      weight=-1))

    srcbox_flux = [
        srcbox_top, srcbox_bot, srcbox_xf, srcbox_xb, srcbox_yf, srcbox_yb
    ]

    # axial energy flux

    upper_axial = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(0, 0, 0.5 * height - dpml),
                      size=mp.Vector3(cell_size[0] - 2 * dpml,
                                      cell_size[1] - 2 * dpml, 0),
                      direction=mp.Z,
                      weight=1))

    lower_axial = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(0, 0, -0.5 * height + dpml),
                      size=mp.Vector3(cell_size[0] - 2 * dpml,
                                      cell_size[1] - 2 * dpml, 0),
                      direction=mp.Z,
                      weight=-1))

    # lateral energy flux
    lat_xz1_flux = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(0, 0.5 * cell_size[1] - dpml, 0),
                      size=mp.Vector3(cell_size[0] - 2 * dpml, 0,
                                      cell_size[2] - 2 * dpml),
                      direction=mp.Y))

    lat_xz2_flux = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(0, -0.5 * cell_size[1] + dpml, 0),
                      size=mp.Vector3(cell_size[0] - 2 * dpml, 0,
                                      cell_size[2] - 2 * dpml),
                      direction=mp.Y,
                      weight=-1))

    lat_yz1_flux = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(0.5 * cell_size[0] - dpml, 0, 0),
                      size=mp.Vector3(0, cell_size[1] - 2 * dpml,
                                      cell_size[2] - 2 * dpml),
                      direction=mp.X))

    lat_yz2_flux = sim.add_flux(
        f, df, n_freq,
        mp.FluxRegion(center=mp.Vector3(-0.5 * cell_size[0] + dpml, 0, 0),
                      size=mp.Vector3(0, cell_size[1] - 2 * dpml,
                                      cell_size[2] - 2 * dpml),
                      direction=mp.X,
                      weight=-1))

    lateral_flux = [lat_xz1_flux, lat_xz2_flux, lat_yz1_flux, lat_yz2_flux]
    """Decay point for the stop criteria"""
    decay_point = mp.Vector3(0.5 * cell_size.x - 1.1 * dpml,
                             0.5 * cell_size.y - 1.1 * dpml, 0)

    # sim.run(until=2)
    sim.run(until_after_sources=mp.stop_when_fields_decayed(
        1, source_component, decay_point, 1e-6))
    """Visualization"""
    # eps_data = sim.get_array(center=mp.Vector3(), size=cell_size, component=mp.Dielectric)
    # plot_slice(np.sqrt(eps_data))
    # plt.show()
    """Post-processing"""

    freq = np.array(mp.get_flux_freqs(lower_axial))

    lateral_energy = np.zeros(freq.shape)

    for flux in lateral_flux:
        if np.min(mp.get_fluxes(flux)) < 0:
            raise ValueError("Energy flux negative for LATERAL")
        lateral_energy += np.array(mp.get_fluxes(flux))
        # print(np.min(np.array(mp.get_fluxes(flux))))

    source_energy = np.zeros(freq.shape)
    for flux in srcbox_flux:
        # if np.min(mp.get_fluxes(flux)) < 0:
        #     raise ValueError("Energy flux negative for SOURCE")
        source_energy += np.array(mp.get_fluxes(flux))

    lower_axial = np.array(mp.get_fluxes(lower_axial))

    upper_axial = np.array(mp.get_fluxes(upper_axial))
    """Post-processing"""
    eps_data = sim.get_array(center=mp.Vector3(),
                             size=cell_size,
                             component=mp.Dielectric)
    index_data = np.sqrt(eps_data)

    return index_data, freq, source_energy, lateral_energy, lower_axial, upper_axial