Пример #1
0
def main():

    c = mp.Cylinder(radius=3, material=mp.Medium(index=3.5))
    e = mp.Ellipsoid(size=mp.Vector3(1, 2, 1e20))

    src_cmpt = mp.Hz
    sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.1),
                        component=src_cmpt,
                        center=mp.Vector3())

    if src_cmpt == mp.Ez:
        symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)]

    if src_cmpt == mp.Hz:
        symmetries = [mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, -1)]

    sim = mp.Simulation(cell_size=mp.Vector3(10, 10),
                        geometry=[c, e],
                        boundary_layers=[mp.PML(1.0)],
                        sources=[sources],
                        symmetries=symmetries,
                        resolution=100)

    def print_stuff(sim_obj):
        v = mp.Vector3(4.13, 3.75, 0)
        p = sim.get_field_point(src_cmpt, v)
        print("t, Ez: {} {}+{}i".format(sim.round_time(), p.real, p.imag))

    sim.run(mp.at_beginning(mp.output_epsilon),
            mp.at_every(0.25, print_stuff),
            mp.at_end(print_stuff),
            mp.at_end(mp.output_efield_z),
            until=23)

    print("stopped at meep time = {}".format(sim.round_time()))
Пример #2
0
def main():

    c = mp.Cylinder(radius=3, material=mp.Medium(index=3.5))
    e = mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf))

    src_cmpt = mp.Hz
    sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.1), component=src_cmpt, center=mp.Vector3())

    if src_cmpt == mp.Ez:
        symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)]

    if src_cmpt == mp.Hz:
        symmetries = [mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, -1)]

    sim = mp.Simulation(cell_size=mp.Vector3(10, 10),
                        geometry=[c, e],
                        boundary_layers=[mp.PML(1.0)],
                        sources=[sources],
                        symmetries=symmetries,
                        resolution=100)

    def print_stuff(sim_obj):
        v = mp.Vector3(4.13, 3.75, 0)
        p = sim.get_field_point(src_cmpt, v)
        print("t, Ez: {} {}+{}i".format(sim.round_time(), p.real, p.imag))

    sim.run(mp.at_beginning(mp.output_epsilon),
            mp.at_every(0.25, print_stuff),
            mp.at_end(print_stuff),
            mp.at_end(mp.output_efield_z),
            until=23)

    print("stopped at meep time = {}".format(sim.round_time()))
Пример #3
0
    def run_simulation(self):

        self.sim.run(mp.at_beginning(mp.output_epsilon),
                     mp.at_every(0.25, self.print_stuff),
                     mp.at_end(self.print_stuff),
                     mp.at_end(mp.output_efield_z),
                     until=23)

        ref_out_field = self.ref_Ez if self.src_cmpt == mp.Ez else self.ref_Hz
        out_field = self.sim.fields.get_field(self.src_cmpt, mp.vec(4.13, 3.75)).real
        diff = abs(out_field - ref_out_field)

        self.assertTrue(abs(diff) <= 0.05 * abs(ref_out_field), "Field output differs")
Пример #4
0
    def run_simulation(self):

        self.sim.run(mp.at_beginning(mp.output_epsilon),
                     mp.at_every(0.25, self.print_stuff),
                     mp.at_end(self.print_stuff),
                     mp.at_end(mp.output_efield_z),
                     until=23)

        ref_out_field = self.ref_Ez if self.src_cmpt == mp.Ez else self.ref_Hz
        out_field = self.sim.fields.get_field(self.src_cmpt,
                                              mp.vec(4.13, 3.75)).real
        diff = abs(out_field - ref_out_field)

        self.assertTrue(
            abs(diff) <= 0.05 * abs(ref_out_field), "Field output differs")
Пример #5
0
    def test_with_prefix(self):
        sim = self.init_simple_simulation()
        sim.use_output_directory(self.temp_dir)
        sim.run(mp.with_prefix('test_prefix-', mp.at_end(mp.output_efield_z)), until=200)

        fname = os.path.join(self.temp_dir, 'test_prefix-simulation-ez-000200.00.h5')
        self.assertTrue(os.path.exists(fname))
Пример #6
0
    def test_geometry_center(self):
        resolution = 20
        cell_size = mp.Vector3(10, 10)
        pml = [mp.PML(1)]
        center = mp.Vector3(2, -1)
        result = []
        fcen = 0.15
        df = 0.1

        sources = [
            mp.Source(src=mp.GaussianSource(fcen, fwidth=df),
                      component=mp.Ez,
                      center=mp.Vector3())
        ]
        geometry = [
            mp.Block(center=mp.Vector3(),
                     size=mp.Vector3(mp.inf, 3, mp.inf),
                     material=mp.Medium(epsilon=12))
        ]

        def print_field(sim):
            result.append(sim.get_field_point(mp.Ez, mp.Vector3(2, -1)))

        sim = mp.Simulation(resolution=resolution,
                            cell_size=cell_size,
                            boundary_layers=pml,
                            sources=sources,
                            geometry=geometry,
                            geometry_center=center)
        sim.run(mp.at_end(print_field), until=50)

        self.assertAlmostEqual(result[0], -0.0599602798684155)
Пример #7
0
    def test_set_materials(self):

        def change_geom(sim):
            t = sim.meep_time()
            fn = t * 0.02
            geom = [mp.Cylinder(radius=3, material=mp.Medium(index=3.5), center=mp.Vector3(fn, fn)),
                    mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf), center=mp.Vector3(fn, fn))]

            sim.set_materials(geometry=geom)

        c = mp.Cylinder(radius=3, material=mp.Medium(index=3.5))
        e = mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf))

        sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.1), component=mp.Hz, center=mp.Vector3())
        symmetries = [mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, -1)]

        sim = mp.Simulation(cell_size=mp.Vector3(10, 10),
                            geometry=[c, e],
                            boundary_layers=[mp.PML(1.0)],
                            sources=[sources],
                            symmetries=symmetries,
                            resolution=16)

        eps = {'arr1': None, 'arr2': None}

        def get_arr1(sim):
            eps['arr1'] = sim.get_array(mp.Dielectric, mp.Volume(mp.Vector3(), mp.Vector3(10, 10)))

        def get_arr2(sim):
            eps['arr2'] = sim.get_array(mp.Dielectric, mp.Volume(mp.Vector3(), mp.Vector3(10, 10)))

        sim.run(mp.at_time(50, get_arr1), mp.at_time(100, change_geom),
                mp.at_end(get_arr2), until=200)

        self.assertFalse(np.array_equal(eps['arr1'], eps['arr2']))
Пример #8
0
    def test_use_output_directory_default(self):
        sim = self.init_simple_simulation()
        output_dir = os.path.join(self.temp_dir, 'simulation-out')
        sim.use_output_directory(output_dir)
        sim.run(mp.at_end(mp.output_efield_z), until=200)

        self.assertTrue(os.path.exists(os.path.join(output_dir, self.fname)))
Пример #9
0
    def test_multilevel_atom(self):
        resolution = 20
        ncav = 1.5
        Lcav = 1
        dpad = 1
        dpml = 1
        sz = Lcav + dpad + dpml

        cell_size = mp.Vector3(z=sz)
        dimensions = 1
        pml_layers = [mp.PML(dpml, side=mp.High)]

        omega_a = 40
        freq_21 = omega_a / (2 * math.pi)

        gamma_perp = 4
        gamma_21 = (2 * gamma_perp) / (2 * math.pi)

        theta = 1
        sigma_21 = 2 * theta * theta * omega_a

        rate_21 = 0.005
        N0 = 28
        Rp = 0.0051

        t1 = mp.Transition(1,
                           2,
                           pumping_rate=Rp,
                           frequency=freq_21,
                           gamma=gamma_21,
                           sigma_diag=mp.Vector3(sigma_21, sigma_21, sigma_21))
        t2 = mp.Transition(2, 1, transition_rate=rate_21)
        ml_atom = mp.MultilevelAtom(sigma=1,
                                    transitions=[t1, t2],
                                    initial_populations=[N0])
        two_level = mp.Medium(index=ncav, E_susceptibilities=[ml_atom])

        geometry = [
            mp.Block(center=mp.Vector3(z=(-0.5 * sz) + (0.5 * Lcav)),
                     size=mp.Vector3(mp.inf, mp.inf, Lcav),
                     material=two_level)
        ]

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

        def field_func(p):
            return 1 if p.z == (-0.5 * sz) + (0.5 * Lcav) else 0

        def check_field(sim):
            fp = sim.get_field_point(
                mp.Ex, mp.Vector3(z=(-0.5 * sz) + Lcav + (0.5 * dpad))).real
            self.assertAlmostEqual(fp, 1.8040684243391956)

        sim.init_sim()
        sim.fields.initialize_field(mp.Ex, field_func)
        sim.run(mp.at_end(check_field), until=7000)
Пример #10
0
    def test_set_materials(self):

        def change_geom(sim):
            t = sim.meep_time()
            fn = t * 0.02
            geom = [mp.Cylinder(radius=3, material=mp.Medium(index=3.5), center=mp.Vector3(fn, fn)),
                    mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf), center=mp.Vector3(fn, fn))]

            sim.set_materials(geometry=geom)

        c = mp.Cylinder(radius=3, material=mp.Medium(index=3.5))
        e = mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf))

        sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.1), component=mp.Hz, center=mp.Vector3())
        symmetries = [mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, -1)]

        sim = mp.Simulation(cell_size=mp.Vector3(10, 10),
                            geometry=[c, e],
                            boundary_layers=[mp.PML(1.0)],
                            sources=[sources],
                            symmetries=symmetries,
                            resolution=16)

        eps = {'arr1': None, 'arr2': None}

        def get_arr1(sim):
            eps['arr1'] = sim.get_array(mp.Dielectric, mp.Volume(mp.Vector3(), mp.Vector3(10, 10)))

        def get_arr2(sim):
            eps['arr2'] = sim.get_array(mp.Dielectric, mp.Volume(mp.Vector3(), mp.Vector3(10, 10)))

        sim.run(mp.at_time(50, get_arr1), mp.at_time(100, change_geom),
                mp.at_end(get_arr2), until=200)

        self.assertFalse(np.array_equal(eps['arr1'], eps['arr2']))
Пример #11
0
 def test_in_point(self):
     sim = self.init_simple_simulation()
     sim.use_output_directory(self.temp_dir)
     sim.filename_prefix = 'test_in_point'
     pt = mp.Vector3()
     sim.run(mp.at_end(mp.in_point(pt, mp.output_efield_z)), until=200)
     fn = os.path.join(self.temp_dir, 'test_in_point-ez-000200.00.h5')
     self.assertTrue(os.path.exists(fn))
Пример #12
0
 def test_in_volume(self):
     sim = self.init_simple_simulation()
     sim.use_output_directory(self.temp_dir)
     sim.filename_prefix = 'test_in_volume'
     vol = mp.Volume(mp.Vector3(), size=mp.Vector3(x=2))
     sim.run(mp.at_end(mp.in_volume(vol, mp.output_efield_z)), until=200)
     fn = os.path.join(self.temp_dir, 'test_in_volume-ez-000200.00.h5')
     self.assertTrue(os.path.exists(fn))
Пример #13
0
    def test_multilevel_atom(self):
        resolution = 40
        ncav = 1.5
        Lcav = 1
        dpad = 1
        dpml = 1
        sz = Lcav + dpad + dpml

        cell_size = mp.Vector3(z=sz)
        dimensions = 1
        pml_layers = [mp.PML(dpml, side=mp.High)]

        omega_a = 40
        freq_21 = omega_a / (2 * math.pi)

        gamma_perp = 4
        gamma_21 = (2 * gamma_perp) / (2 * math.pi)

        theta = 1
        sigma_21 = 2 * theta * theta * omega_a

        rate_21 = 0.005
        N0 = 28
        Rp = 0.0051

        t1 = mp.Transition(
            1,
            2,
            pumping_rate=Rp,
            frequency=freq_21,
            gamma=gamma_21,
            sigma_diag=mp.Vector3(sigma_21, sigma_21, sigma_21)
        )
        t2 = mp.Transition(2, 1, transition_rate=rate_21)
        ml_atom = mp.MultilevelAtom(sigma=1, transitions=[t1, t2], initial_populations=[N0])
        two_level = mp.Medium(index=ncav, E_susceptibilities=[ml_atom])

        geometry = [mp.Block(center=mp.Vector3(z=(-0.5 * sz) + (0.5 * Lcav)),
                             size=mp.Vector3(mp.inf, mp.inf, Lcav), material=two_level)]

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

        def field_func(p):
            return 1 if p.z == (-0.5 * sz) + (0.5 * Lcav) else 0

        def check_field(sim):
            fp = sim.get_field_point(mp.Ex, mp.Vector3(z=(-0.5 * sz) + Lcav + (0.5 * dpad))).real
            self.assertAlmostEqual(fp, -2.7110969214986387)

        sim.init_sim()
        sim.initialize_field(mp.Ex, field_func)
        sim.run(mp.at_end(check_field), until=7000)
Пример #14
0
    def test_in_point(self):
        sim = self.init_simple_simulation(filename_prefix='test_in_point')
        fn = sim.filename_prefix + '-ez-000200.00.h5'
        pt = mp.Vector3()
        sim.run(mp.at_end(mp.in_point(pt, mp.output_efield_z)), until=200)
        self.assertTrue(os.path.exists(fn))

        mp.all_wait()
        if mp.am_master():
            os.remove(fn)
Пример #15
0
    def test_with_prefix(self):
        sim = self.init_simple_simulation()
        sim.run(mp.with_prefix('test_prefix-', mp.at_end(mp.output_efield_z)), until=200)

        fname = 'test_prefix-simulation-ez-000200.00.h5'
        self.assertTrue(os.path.exists(fname))

        mp.all_wait()
        if mp.am_master():
            os.remove(fname)
Пример #16
0
    def test_in_point(self):
        sim = self.init_simple_simulation(filename_prefix='test_in_point')
        fn = sim.filename_prefix + '-ez-000200.00.h5'
        pt = mp.Vector3()
        sim.run(mp.at_end(mp.in_point(pt, mp.output_efield_z)), until=200)
        self.assertTrue(os.path.exists(fn))

        mp.all_wait()
        if mp.am_master():
            os.remove(fn)
Пример #17
0
    def test_with_prefix(self):
        sim = self.init_simple_simulation()
        sim.run(mp.with_prefix('test_prefix-', mp.at_end(mp.output_efield_z)), until=200)

        fname = 'test_prefix-simulation-ez-000200.00.h5'
        self.assertTrue(os.path.exists(fname))

        mp.all_wait()
        if mp.am_master():
            os.remove(fname)
Пример #18
0
    def test_use_output_directory_custom(self):
        sim = self.init_simple_simulation()
        sim.use_output_directory('custom_dir')
        sim.run(mp.at_end(mp.output_efield_z), until=200)

        output_dir = 'custom_dir'
        self.assertTrue(os.path.exists(os.path.join(output_dir, self.fname)))

        mp.all_wait()
        if mp.am_master():
            shutil.rmtree(output_dir)
Пример #19
0
    def test_pw_source(self):
        self.sim.run(mp.at_end(mp.output_efield_z), until=400)

        v1 = mp.Vector3(0.5 * self.s, 0)
        v2 = mp.Vector3(0.5 * self.s, 0.5 * self.s)

        pt1 = self.sim.get_field_point(mp.Ez, v1)
        pt2 = self.sim.get_field_point(mp.Ez, v2)

        self.assertAlmostEqual(pt1 / pt2, 27.557668029008262)
        self.assertAlmostEqual(cmath.exp(1j * self.k.dot(v1 - v2)), 0.7654030066070924 - 0.6435512702783076j)
Пример #20
0
    def test_use_output_directory_custom(self):
        sim = self.init_simple_simulation()
        sim.use_output_directory('custom_dir')
        sim.run(mp.at_end(mp.output_efield_z), until=200)

        output_dir = 'custom_dir'
        self.assertTrue(os.path.exists(os.path.join(output_dir, self.fname)))

        mp.all_wait()
        if mp.am_master():
            shutil.rmtree(output_dir)
Пример #21
0
    def test_pw_source(self):
        self.sim.run(mp.at_end(mp.output_efield_z), until=400)

        v1 = mp.Vector3(0.5 * self.s, 0)
        v2 = mp.Vector3(0.5 * self.s, 0.5 * self.s)

        pt1 = self.sim.get_field_point(mp.Ez, v1)
        pt2 = self.sim.get_field_point(mp.Ez, v2)

        tol = 1e-4 if mp.is_single_precision() else 1e-9
        self.assertClose(pt1 / pt2, 27.557668029008262, epsilon=tol)

        self.assertAlmostEqual(cmath.exp(1j * self.k.dot(v1 - v2)),
                               0.7654030066070924 - 0.6435512702783076j)
Пример #22
0
def main(args):
    resolution = 20 # 20 pixels per unit 1 um
    eps = 80 # epsilon of cylinder medium
    Mat1 = mp.Medium(epsilon=eps) # definition of the material
    dimensions = mp.CYLINDRICAL

    r = args.r # the value of cylinder radius
    rl = args.rl # the r/l ration is given, to obtain the l value l=r/rl
    x = args.x
    dpml = args.dpml
    dair = args.dair
    m=args.m

    w=1*x  
    h = r/rl # the height of the cylinder
    sr = r + dair + dpml
    sz = h + 2*dair + 2*dpml
    w_max=1.8
    w_min=0.2
    dw=w_max-w_min

    boundary_layers = [mp.PML(dpml)]
    Cyl = mp.Cylinder(material=Mat1, radius=r, height=h, center=mp.Vector3(0,0,0)) # make a cylinder with given parameters
    geometry = [Cyl]
    cell_size = mp.Vector3(sr,0,sz)

    #sources = [ mp.Source(mp.ContinuousSource(frequency = w), component=mp.Hz, center=mp.Vector3(r+dair,0,0)) ]
    sources = [mp.Source(mp.GaussianSource(w, fwidth=dw), component=mp.Hz, center=mp.Vector3(r+dair,0,0))]
    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=boundary_layers,
                        geometry=geometry,
                        sources=sources,
                        dimensions=dimensions,
                        m=m)
    sim.run(mp.in_volume(mp.Volume(center=mp.Vector3(), size=mp.Vector3(sr,0,sz)),
            mp.at_end(mp.output_epsilon, mp.output_efield_z)),
            mp.after_sources(mp.Harminv(mp.Hz, mp.Vector3(), w, dw)),
            until_after_sources=100)
Пример #23
0
    def test_geometry_center(self):
        resolution = 20
        cell_size = mp.Vector3(10, 10)
        pml = [mp.PML(1)]
        center = mp.Vector3(2, -1)
        result = []
        fcen = 0.15
        df = 0.1

        sources = [mp.Source(src=mp.GaussianSource(fcen, fwidth=df), component=mp.Ez,
                             center=mp.Vector3())]
        geometry = [mp.Block(center=mp.Vector3(), size=mp.Vector3(mp.inf, 3, mp.inf),
                             material=mp.Medium(epsilon=12))]

        def print_field(sim):
            result.append(sim.get_field_point(mp.Ez, mp.Vector3(2, -1)))

        sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml,
                            sources=sources, geometry=geometry, geometry_center=center)
        sim.run(mp.at_end(print_field), until=50)

        self.assertAlmostEqual(result[0], -0.0599602798684155)
Пример #24
0
def main(from_um_factor, resolution, courant, r, material, paper, reference,
         submerged_index, displacement, surface_index, wlen_range, nfreq,
         air_r_factor, pml_wlen_factor, flux_r_factor, time_factor_cell,
         second_time_factor, series, folder, parallel, n_processes, n_cores,
         n_nodes, split_chunks_evenly, load_flux, load_chunks, near2far):

    #%% CLASSIC INPUT PARAMETERS
    """
    # Simulation size
    from_um_factor = 10e-3 # Conversion of 1 μm to my length unit (=10nm/1μm)
    resolution = 2 # >=8 pixels per smallest wavelength, i.e. np.floor(8/wvl_min)
    courant = 0.5
    
    # Nanoparticle specifications: Sphere in Vacuum :)
    r = 51.5  # Radius of sphere in nm
    paper = "R"
    reference = "Meep"
    displacement = 0 # Displacement of the surface from the bottom of the sphere in nm
    submerged_index = 1 # 1.33 for water
    surface_index = 1 # 1.54 for glass
    
    # Frequency and wavelength
    wlen_range = np.array([350,500]) # Wavelength range in nm
    nfreq = 100
    
    # Box dimensions
    pml_wlen_factor = 0.38
    air_r_factor = 0.5
    flux_r_factor = 0 #0.1
    
    # Simulation time
    time_factor_cell = 1.2
    second_time_factor = 10
    
    # Saving directories
    series = "SilverRes4"
    folder = "Test/TestSilver"
    
    # Configuration
    parallel = False
    n_processes = 1
    n_cores = 1
    n_nodes = 1
    split_chunks_evenly = True
    load_flux = False
    load_chunks = True    
    near2far = False
    """

    #%% MORE INPUT PARAMETERS

    # Frequency and wavelength
    cutoff = 3.2  # Gaussian planewave source's parameter of shape
    nazimuthal = 16
    npolar = 20

    ### TREATED INPUT PARAMETERS

    # Nanoparticle specifications: Sphere in Vacuum :)
    r = r / (from_um_factor * 1e3)  # Now in Meep units
    if reference == "Meep":
        medium = vmt.import_medium(material,
                                   from_um_factor=from_um_factor,
                                   paper=paper)
        # Importing material constants dependant on frequency from Meep Library
    elif reference == "RIinfo":
        medium = vmt.MediumFromFile(material,
                                    paper=paper,
                                    reference=reference,
                                    from_um_factor=from_um_factor)
        # Importing material constants dependant on frequency from external file
    else:
        raise ValueError("Reference for medium not recognized. Sorry :/")
    displacement = displacement / (from_um_factor * 1e3)  # Now in Meep units

    # Frequency and wavelength
    wlen_range = np.array(wlen_range)
    wlen_range = wlen_range / (from_um_factor * 1e3)  # Now in Meep units
    freq_range = 1 / wlen_range  # Hz range in Meep units from highest to lowest
    freq_center = np.mean(freq_range)
    freq_width = max(freq_range) - min(freq_range)

    # Space configuration
    pml_width = pml_wlen_factor * max(wlen_range)  # 0.5 * max(wlen_range)
    air_width = air_r_factor * r  # 0.5 * max(wlen_range)
    flux_box_size = 2 * (1 + flux_r_factor) * r

    # Saving directories
    if series is None:
        series = "Test"
    if folder is None:
        folder = "Test"
    params_list = [
        "from_um_factor", "resolution", "courant", "material", "r", "paper",
        "reference", "submerged_index", "displacement", "surface_index",
        "wlen_range", "nfreq", "nazimuthal", "npolar", "cutoff",
        "flux_box_size", "cell_width", "pml_width", "air_width",
        "source_center", "until_after_sources", "time_factor_cell",
        "second_time_factor", "enlapsed", "parallel", "n_processes", "n_cores",
        "n_nodes", "split_chunks_evenly", "near2far", "script", "sysname",
        "path"
    ]

    #%% GENERAL GEOMETRY SETUP

    air_width = air_width - air_width % (1 / resolution)

    pml_width = pml_width - pml_width % (1 / resolution)
    pml_layers = [mp.PML(thickness=pml_width)]

    # symmetries = [mp.Mirror(mp.Y),
    #               mp.Mirror(mp.Z, phase=-1)]
    # Two mirror planes reduce cell size to 1/4
    # Issue related that lead me to comment this lines:
    # https://github.com/NanoComp/meep/issues/1484

    cell_width = 2 * (pml_width + air_width + r)
    cell_width = cell_width - cell_width % (1 / resolution)
    cell_size = mp.Vector3(cell_width, cell_width, cell_width)

    # surface_center = r/4 - displacement/2 + cell_width/4
    # surface_center = surface_center - surface_center%(1/resolution)
    # displacement = r/2 + cell_width/2 - 2*surface_center

    displacement = displacement - displacement % (1 / resolution)

    flux_box_size = flux_box_size - flux_box_size % (1 / resolution)

    source_center = -0.5 * cell_width + pml_width
    sources = [
        mp.Source(mp.GaussianSource(freq_center,
                                    fwidth=freq_width,
                                    is_integrated=True,
                                    cutoff=cutoff),
                  center=mp.Vector3(source_center),
                  size=mp.Vector3(0, cell_width, cell_width),
                  component=mp.Ez)
    ]
    # Ez-polarized planewave pulse
    # (its size parameter fills the entire cell in 2d)
    # >> The planewave source extends into the PML
    # ==> is_integrated=True must be specified

    until_after_sources = time_factor_cell * cell_width * submerged_index
    # Enough time for the pulse to pass through all the cell
    # Originally: Aprox 3 periods of lowest frequency, using T=λ/c=λ in Meep units
    # Now: Aprox 3 periods of highest frequency, using T=λ/c=λ in Meep units

    geometry = [mp.Sphere(material=medium, center=mp.Vector3(), radius=r)]
    # Au sphere with frequency-dependant characteristics imported from Meep.

    if surface_index != 1:
        geometry = [
            mp.Block(material=mp.Medium(index=surface_index),
                     center=mp.Vector3(
                         r / 2 - displacement / 2 + cell_width / 4, 0, 0),
                     size=mp.Vector3(cell_width / 2 - r + displacement,
                                     cell_width, cell_width)), *geometry
        ]
    # A certain material surface underneath it

    home = vs.get_home()
    sysname = vs.get_sys_name()
    path = os.path.join(home, folder, series)
    if not os.path.isdir(path) and vm.parallel_assign(0, n_processes,
                                                      parallel):
        os.makedirs(path)
    file = lambda f: os.path.join(path, f)

    # Computation
    enlapsed = []

    parallel_specs = np.array([n_processes, n_cores, n_nodes], dtype=int)
    max_index = np.argmax(parallel_specs)
    for index, item in enumerate(parallel_specs):
        if item == 0: parallel_specs[index] = 1
    parallel_specs[0:max_index] = np.full(parallel_specs[0:max_index].shape,
                                          max(parallel_specs))
    n_processes, n_cores, n_nodes = parallel_specs
    parallel = max(parallel_specs) > 1
    del parallel_specs, max_index, index, item

    if parallel:
        np_process = mp.count_processors()
    else:
        np_process = 1

    #%% FIRST RUN

    measure_ram()

    params = {}
    for p in params_list:
        params[p] = eval(p)

    stable, max_courant = vm.check_stability(params)
    if stable:
        print("As a whole, the simulation should be stable")
    else:
        print("As a whole, the simulation could not be stable")
        print(f"Recommended maximum courant factor is {max_courant}")

    if load_flux:
        try:
            flux_path = vm.check_midflux(params)[0]
            flux_needed = False
        except:
            flux_needed = True
    else:
        flux_needed = True

    if load_chunks and not split_chunks_evenly:
        try:
            chunks_path = vm.check_chunks(params)[0]
            chunk_layout = os.path.join(chunks_path, "Layout.h5")
            chunks_needed = False
        except:
            chunks_needed = True
            flux_needed = True
    else:
        if not split_chunks_evenly:
            chunks_needed = True
            flux_needed = True
        else:
            chunk_layout = None
            chunks_needed = False

    if chunks_needed:

        sim = mp.Simulation(
            resolution=resolution,
            cell_size=cell_size,
            boundary_layers=pml_layers,
            sources=sources,
            k_point=mp.Vector3(),
            Courant=courant,
            default_material=mp.Medium(index=submerged_index),
            output_single_precision=True,
            split_chunks_evenly=split_chunks_evenly,
            # symmetries=symmetries,
            geometry=geometry)

        sim.init_sim()

        chunks_path = vm.save_chunks(sim, params, path)
        chunk_layout = os.path.join(chunks_path, "Layout.h5")

        del sim

    if flux_needed:

        #% FIRST RUN: SET UP

        measure_ram()

        sim = mp.Simulation(resolution=resolution,
                            cell_size=cell_size,
                            boundary_layers=pml_layers,
                            sources=sources,
                            k_point=mp.Vector3(),
                            Courant=courant,
                            default_material=mp.Medium(index=submerged_index),
                            split_chunks_evenly=split_chunks_evenly,
                            chunk_layout=chunk_layout,
                            output_single_precision=True)  #,
        # symmetries=symmetries)
        # >> k_point zero specifies boundary conditions needed
        # for the source to be infinitely extended

        measure_ram()

        # Scattered power --> Computed by surrounding it with closed DFT flux box
        # (its size and orientation are irrelevant because of Poynting's theorem)
        box_x1 = sim.add_flux(
            freq_center, freq_width, nfreq,
            mp.FluxRegion(center=mp.Vector3(x=-flux_box_size / 2),
                          size=mp.Vector3(0, flux_box_size, flux_box_size)))
        box_x2 = sim.add_flux(
            freq_center, freq_width, nfreq,
            mp.FluxRegion(center=mp.Vector3(x=+flux_box_size / 2),
                          size=mp.Vector3(0, flux_box_size, flux_box_size)))
        box_y1 = sim.add_flux(
            freq_center, freq_width, nfreq,
            mp.FluxRegion(center=mp.Vector3(y=-flux_box_size / 2),
                          size=mp.Vector3(flux_box_size, 0, flux_box_size)))
        box_y2 = sim.add_flux(
            freq_center, freq_width, nfreq,
            mp.FluxRegion(center=mp.Vector3(y=+flux_box_size / 2),
                          size=mp.Vector3(flux_box_size, 0, flux_box_size)))
        box_z1 = sim.add_flux(
            freq_center, freq_width, nfreq,
            mp.FluxRegion(center=mp.Vector3(z=-flux_box_size / 2),
                          size=mp.Vector3(flux_box_size, flux_box_size, 0)))
        box_z2 = sim.add_flux(
            freq_center, freq_width, nfreq,
            mp.FluxRegion(center=mp.Vector3(z=+flux_box_size / 2),
                          size=mp.Vector3(flux_box_size, flux_box_size, 0)))
        # Funny you can encase the sphere (r radius) so closely (2r-sided box)

        measure_ram()

        if near2far:
            near2far_box = sim.add_near2far(
                freq_center, freq_width, nfreq,
                mp.Near2FarRegion(center=mp.Vector3(x=-flux_box_size / 2),
                                  size=mp.Vector3(0, flux_box_size,
                                                  flux_box_size),
                                  weight=-1),
                mp.Near2FarRegion(center=mp.Vector3(x=+flux_box_size / 2),
                                  size=mp.Vector3(0, flux_box_size,
                                                  flux_box_size),
                                  weight=+1),
                mp.Near2FarRegion(center=mp.Vector3(y=-flux_box_size / 2),
                                  size=mp.Vector3(flux_box_size, 0,
                                                  flux_box_size),
                                  weight=-1),
                mp.Near2FarRegion(center=mp.Vector3(y=+flux_box_size / 2),
                                  size=mp.Vector3(flux_box_size, 0,
                                                  flux_box_size),
                                  weight=+1),
                mp.Near2FarRegion(center=mp.Vector3(z=-flux_box_size / 2),
                                  size=mp.Vector3(flux_box_size, flux_box_size,
                                                  0),
                                  weight=-1),
                mp.Near2FarRegion(center=mp.Vector3(z=+flux_box_size / 2),
                                  size=mp.Vector3(flux_box_size, flux_box_size,
                                                  0),
                                  weight=+1))
            measure_ram()
        else:
            near2far_box = None
            # used_ram.append(used_ram[-1])

        #% FIRST RUN: INITIALIZE

        temp = time()
        sim.init_sim()
        enlapsed.append(time() - temp)
        measure_ram()

        step_ram_function = lambda sim: measure_ram()

        #% FIRST RUN: SIMULATION NEEDED TO NORMALIZE

        temp = time()
        sim.run(mp.at_beginning(step_ram_function),
                mp.at_time(int(until_after_sources / 2), step_ram_function),
                mp.at_end(step_ram_function),
                until_after_sources=until_after_sources)
        #     mp.stop_when_fields_decayed(
        # np.mean(wlen_range), # dT = mean period of source
        # mp.Ez, # Component of field to check
        # mp.Vector3(0.5*cell_width - pml_width, 0, 0), # Where to check
        # 1e-3)) # Factor to decay
        enlapsed.append(time() - temp)

        #% SAVE MID DATA

        for p in params_list:
            params[p] = eval(p)

        flux_path = vm.save_midflux(sim, box_x1, box_x2, box_y1, box_y2,
                                    box_z1, box_z2, near2far_box, params, path)

        freqs = np.asarray(mp.get_flux_freqs(box_x1))
        box_x1_flux0 = np.asarray(mp.get_fluxes(box_x1))
        box_x2_flux0 = np.asarray(mp.get_fluxes(box_x2))
        box_y1_flux0 = np.asarray(mp.get_fluxes(box_y1))
        box_y2_flux0 = np.asarray(mp.get_fluxes(box_y2))
        box_z1_flux0 = np.asarray(mp.get_fluxes(box_z1))
        box_z2_flux0 = np.asarray(mp.get_fluxes(box_z2))

        data_mid = np.array([
            1e3 * from_um_factor / freqs, box_x1_flux0, box_x2_flux0,
            box_y1_flux0, box_y2_flux0, box_z1_flux0, box_z2_flux0
        ]).T

        header_mid = [
            "Longitud de onda [nm]", "Flujo X10 [u.a.]", "Flujo X20 [u.a]",
            "Flujo Y10 [u.a]", "Flujo Y20 [u.a]", "Flujo Z10 [u.a]",
            "Flujo Z20 [u.a]"
        ]

        if vm.parallel_assign(0, n_processes, parallel):
            vs.savetxt(file("MidFlux.txt"),
                       data_mid,
                       header=header_mid,
                       footer=params)

        if not split_chunks_evenly:
            vm.save_chunks(sim, params, path)

        if parallel:
            f = h5.File(file("MidRAM.h5"),
                        "w",
                        driver='mpio',
                        comm=MPI.COMM_WORLD)
            current_process = mp.my_rank()
            f.create_dataset("RAM", (len(used_ram), np_process), dtype="float")
            f["RAM"][:, current_process] = used_ram
            for a in params:
                f["RAM"].attrs[a] = params[a]
            f.create_dataset("SWAP", (len(used_ram), np_process), dtype="int")
            f["SWAP"][:, current_process] = swapped_ram
            for a in params:
                f["SWAP"].attrs[a] = params[a]
        else:
            f = h5.File(file("MidRAM.h5"), "w")
            f.create_dataset("RAM", data=used_ram)
            for a in params:
                f["RAM"].attrs[a] = params[a]
            f.create_dataset("SWAP", data=swapped_ram)
            for a in params:
                f["SWAP"].attrs[a] = params[a]
        f.close()
        del f

        #% PLOT FLUX FOURIER MID DATA

        if vm.parallel_assign(1, np_process, parallel):
            ylims = (np.min(data_mid[:, 1:]), np.max(data_mid[:, 1:]))
            ylims = (ylims[0] - .1 * (ylims[1] - ylims[0]),
                     ylims[1] + .1 * (ylims[1] - ylims[0]))

            fig, ax = plt.subplots(3, 2, sharex=True)
            fig.subplots_adjust(hspace=0, wspace=.05)
            for a in ax[:, 1]:
                a.yaxis.tick_right()
                a.yaxis.set_label_position("right")
            for a, h in zip(np.reshape(ax, 6), header_mid[1:]):
                a.set_ylabel(h)

            for d, a in zip(data_mid[:, 1:].T, np.reshape(ax, 6)):
                a.plot(1e3 * from_um_factor / freqs, d)
                a.set_ylim(*ylims)
            ax[-1, 0].set_xlabel("Wavelength [nm]")
            ax[-1, 1].set_xlabel("Wavelength [nm]")

            plt.savefig(file("MidFlux.png"))
            del fig, ax, ylims, a, h

        sim.reset_meep()

    #%% SECOND RUN: SETUP

    measure_ram()

    sim = mp.Simulation(
        resolution=resolution,
        cell_size=cell_size,
        boundary_layers=pml_layers,
        sources=sources,
        k_point=mp.Vector3(),
        Courant=courant,
        default_material=mp.Medium(index=submerged_index),
        output_single_precision=True,
        split_chunks_evenly=split_chunks_evenly,
        chunk_layout=chunk_layout,
        # symmetries=symmetries,
        geometry=geometry)

    measure_ram()

    box_x1 = sim.add_flux(
        freq_center, freq_width, nfreq,
        mp.FluxRegion(center=mp.Vector3(x=-flux_box_size / 2),
                      size=mp.Vector3(0, flux_box_size, flux_box_size)))
    box_x2 = sim.add_flux(
        freq_center, freq_width, nfreq,
        mp.FluxRegion(center=mp.Vector3(x=+flux_box_size / 2),
                      size=mp.Vector3(0, flux_box_size, flux_box_size)))
    box_y1 = sim.add_flux(
        freq_center, freq_width, nfreq,
        mp.FluxRegion(center=mp.Vector3(y=-flux_box_size / 2),
                      size=mp.Vector3(flux_box_size, 0, flux_box_size)))
    box_y2 = sim.add_flux(
        freq_center, freq_width, nfreq,
        mp.FluxRegion(center=mp.Vector3(y=+flux_box_size / 2),
                      size=mp.Vector3(flux_box_size, 0, flux_box_size)))
    box_z1 = sim.add_flux(
        freq_center, freq_width, nfreq,
        mp.FluxRegion(center=mp.Vector3(z=-flux_box_size / 2),
                      size=mp.Vector3(flux_box_size, flux_box_size, 0)))
    box_z2 = sim.add_flux(
        freq_center, freq_width, nfreq,
        mp.FluxRegion(center=mp.Vector3(z=+flux_box_size / 2),
                      size=mp.Vector3(flux_box_size, flux_box_size, 0)))

    measure_ram()

    if near2far:
        near2far_box = sim.add_near2far(
            freq_center, freq_width, nfreq,
            mp.Near2FarRegion(center=mp.Vector3(x=-flux_box_size / 2),
                              size=mp.Vector3(0, flux_box_size, flux_box_size),
                              weight=-1),
            mp.Near2FarRegion(center=mp.Vector3(x=+flux_box_size / 2),
                              size=mp.Vector3(0, flux_box_size, flux_box_size),
                              weight=+1),
            mp.Near2FarRegion(center=mp.Vector3(y=-flux_box_size / 2),
                              size=mp.Vector3(flux_box_size, 0, flux_box_size),
                              weight=-1),
            mp.Near2FarRegion(center=mp.Vector3(y=+flux_box_size / 2),
                              size=mp.Vector3(flux_box_size, 0, flux_box_size),
                              weight=+1),
            mp.Near2FarRegion(center=mp.Vector3(z=-flux_box_size / 2),
                              size=mp.Vector3(flux_box_size, flux_box_size, 0),
                              weight=-1),
            mp.Near2FarRegion(center=mp.Vector3(z=+flux_box_size / 2),
                              size=mp.Vector3(flux_box_size, flux_box_size, 0),
                              weight=+1))
        measure_ram()
    else:
        near2far_box = None
        # used_ram.append(used_ram[-1])

    #%% SECOND RUN: INITIALIZE

    temp = time()
    sim.init_sim()
    enlapsed.append(time() - temp)
    measure_ram()

    #%% LOAD FLUX FROM FILE

    vm.load_midflux(sim, box_x1, box_x2, box_y1, box_y2, box_z1, box_z2,
                    near2far_box, flux_path)

    measure_ram()

    freqs = np.asarray(mp.get_flux_freqs(box_x1))
    box_x1_flux0 = np.asarray(mp.get_fluxes(box_x1))
    box_x1_data = sim.get_flux_data(box_x1)
    box_x2_data = sim.get_flux_data(box_x2)
    box_y1_data = sim.get_flux_data(box_y1)
    box_y2_data = sim.get_flux_data(box_y2)
    box_z1_data = sim.get_flux_data(box_z1)
    box_z2_data = sim.get_flux_data(box_z2)
    if near2far: near2far_data = sim.get_near2far_data(near2far_box)

    temp = time()
    sim.load_minus_flux_data(box_x1, box_x1_data)
    sim.load_minus_flux_data(box_x2, box_x2_data)
    sim.load_minus_flux_data(box_y1, box_y1_data)
    sim.load_minus_flux_data(box_y2, box_y2_data)
    sim.load_minus_flux_data(box_z1, box_z1_data)
    sim.load_minus_flux_data(box_z2, box_z2_data)
    if near2far: sim.load_minus_near2far_data(near2far_box, near2far_data)
    enlapsed.append(time() - temp)
    del box_x1_data, box_x2_data, box_y1_data, box_y2_data
    del box_z1_data, box_z2_data
    if near2far: del near2far_data

    measure_ram()

    #%% SECOND RUN: SIMULATION :D

    step_ram_function = lambda sim: measure_ram()

    temp = time()
    sim.run(mp.at_beginning(step_ram_function),
            mp.at_time(int(second_time_factor * until_after_sources / 2),
                       step_ram_function),
            mp.at_end(step_ram_function),
            until_after_sources=second_time_factor * until_after_sources)
    #     mp.stop_when_fields_decayed(
    # np.mean(wlen_range), # dT = mean period of source
    # mp.Ez, # Component of field to check
    # mp.Vector3(0.5*cell_width - pml_width, 0, 0), # Where to check
    # 1e-3)) # Factor to decay
    enlapsed.append(time() - temp)
    del temp
    # Aprox 30 periods of lowest frequency, using T=λ/c=λ in Meep units

    box_x1_flux = np.asarray(mp.get_fluxes(box_x1))
    box_x2_flux = np.asarray(mp.get_fluxes(box_x2))
    box_y1_flux = np.asarray(mp.get_fluxes(box_y1))
    box_y2_flux = np.asarray(mp.get_fluxes(box_y2))
    box_z1_flux = np.asarray(mp.get_fluxes(box_z1))
    box_z2_flux = np.asarray(mp.get_fluxes(box_z2))

    #%% SCATTERING ANALYSIS

    scatt_flux = box_x1_flux - box_x2_flux
    scatt_flux = scatt_flux + box_y1_flux - box_y2_flux
    scatt_flux = scatt_flux + box_z1_flux - box_z2_flux

    intensity = box_x1_flux0 / (flux_box_size)**2
    # Flux of one of the six monitor planes / Área
    # (the closest one, facing the planewave source)
    # This is why the six sides of the flux box are separated
    # (Otherwise, the box could've been one flux object with weights ±1 per side)

    scatt_cross_section = np.divide(scatt_flux, intensity)
    # Scattering cross section σ =
    # = scattered power in all directions / incident intensity.

    scatt_eff_meep = -1 * scatt_cross_section / (np.pi * r**2)
    # Scattering efficiency =
    # = scattering cross section / cross sectional area of the sphere

    freqs = np.array(freqs)
    scatt_eff_theory = [
        ps.MieQ(np.sqrt(medium.epsilon(f)[0, 0] * medium.mu(f)[0, 0]),
                1e3 * from_um_factor / f,
                2 * r * 1e3 * from_um_factor,
                nMedium=submerged_index,
                asDict=True)['Qsca'] for f in freqs
    ]
    # The simulation results are validated by comparing with
    # analytic theory of PyMieScatt module

    #%% ANGULAR PATTERN ANALYSIS

    if near2far:

        fraunhofer_distance = 8 * (r**2) / min(wlen_range)
        radial_distance = max(10 * fraunhofer_distance, 1.5 * cell_width / 2)
        # radius of far-field circle must be at least Fraunhofer distance

        azimuthal_angle = np.arange(0, 2 + 2 / nazimuthal,
                                    2 / nazimuthal)  # in multiples of pi
        polar_angle = np.arange(0, 1 + 1 / npolar, 1 / npolar)

        poynting_x = []
        poynting_y = []
        poynting_z = []
        poynting_r = []

        for phi in azimuthal_angle:

            poynting_x.append([])
            poynting_y.append([])
            poynting_z.append([])
            poynting_r.append([])

            for theta in polar_angle:

                farfield_dict = sim.get_farfields(
                    near2far_box,
                    1,
                    where=mp.Volume(center=mp.Vector3(
                        radial_distance * np.cos(np.pi * phi) *
                        np.sin(np.pi * theta),
                        radial_distance * np.sin(np.pi * phi) *
                        np.sin(np.pi *
                               theta), radial_distance *
                        np.cos(np.pi * theta))))

                Px = farfield_dict["Ey"] * np.conjugate(farfield_dict["Hz"])
                Px -= farfield_dict["Ez"] * np.conjugate(farfield_dict["Hy"])
                Py = farfield_dict["Ez"] * np.conjugate(farfield_dict["Hx"])
                Py -= farfield_dict["Ex"] * np.conjugate(farfield_dict["Hz"])
                Pz = farfield_dict["Ex"] * np.conjugate(farfield_dict["Hy"])
                Pz -= farfield_dict["Ey"] * np.conjugate(farfield_dict["Hx"])

                Px = np.real(Px)
                Py = np.real(Py)
                Pz = np.real(Pz)

                poynting_x[-1].append(Px)
                poynting_y[-1].append(Py)
                poynting_z[-1].append(Pz)
                poynting_r[-1].append(
                    np.sqrt(np.square(Px) + np.square(Py) + np.square(Pz)))

        poynting_x = np.array(poynting_x)
        poynting_y = np.array(poynting_y)
        poynting_z = np.array(poynting_z)
        poynting_r = np.array(poynting_r)

    #%% SAVE FINAL DATA

    for p in params_list:
        params[p] = eval(p)

    data = np.array(
        [1e3 * from_um_factor / freqs, scatt_eff_meep, scatt_eff_theory]).T

    header = [
        "Longitud de onda [nm]", "Sección eficaz efectiva (Meep) [u.a.]",
        "Sección eficaz efectiva (Theory) [u.a.]"
    ]

    data_base = np.array([
        1e3 * from_um_factor / freqs, box_x1_flux0, box_x1_flux, box_x2_flux,
        box_y1_flux, box_y2_flux, box_z1_flux, box_z2_flux, intensity,
        scatt_flux, scatt_cross_section
    ]).T

    header_base = [
        "Longitud de onda [nm]", "Flujo X10 [u.a.]", "Flujo X1 [u.a]",
        "Flujo X2 [u.a]", "Flujo Y1 [u.a]", "Flujo Y2 [u.a]", "Flujo Z1 [u.a]",
        "Flujo Z2 [u.a]", "Intensidad incidente [u.a.]",
        "Flujo scattereado [u.a.]", "Sección eficaz de scattering [u.a.]"
    ]

    if vm.parallel_assign(0, np_process, parallel):
        vs.savetxt(file("Results.txt"), data, header=header, footer=params)
        vs.savetxt(file("BaseResults.txt"),
                   data_base,
                   header=header_base,
                   footer=params)

    if near2far:

        header_near2far = [
            "Poynting medio Px [u.a.]", "Poynting medio Py [u.a.]",
            "Poynting medio Pz [u.a.]", "Poynting medio Pr [u.a.]"
        ]

        data_near2far = [
            poynting_x.reshape(poynting_x.size),
            poynting_y.reshape(poynting_y.size),
            poynting_z.reshape(poynting_z.size),
            poynting_r.reshape(poynting_r.size)
        ]

        if vm.parallel_assign(1, np_process, parallel):
            vs.savetxt(file("Near2FarResults.txt"),
                       data_near2far,
                       header=header_near2far,
                       footer=params)

    if not split_chunks_evenly:
        vm.save_chunks(sim, params, path)

    if parallel:
        f = h5.File(file("RAM.h5"), "w", driver='mpio', comm=MPI.COMM_WORLD)
        current_process = mp.my_rank()
        f.create_dataset("RAM", (len(used_ram), np_process), dtype="float")
        f["RAM"][:, current_process] = used_ram
        for a in params:
            f["RAM"].attrs[a] = params[a]
        f.create_dataset("SWAP", (len(used_ram), np_process), dtype="int")
        f["SWAP"][:, current_process] = swapped_ram
        for a in params:
            f["SWAP"].attrs[a] = params[a]
    else:
        f = h5.File(file("RAM.h5"), "w")
        f.create_dataset("RAM", data=used_ram)
        for a in params:
            f["RAM"].attrs[a] = params[a]
        f.create_dataset("SWAP", data=swapped_ram)
        for a in params:
            f["SWAP"].attrs[a] = params[a]
    f.close()
    del f

    if flux_needed and vm.parallel_assign(0, np_process, parallel):
        os.remove(file("MidRAM.h5"))

    #%% PLOT ALL TOGETHER

    if vm.parallel_assign(0, np_process, parallel) and surface_index == 1:
        plt.figure()
        plt.plot(1e3 * from_um_factor / freqs,
                 scatt_eff_meep,
                 'bo-',
                 label='Meep')
        plt.plot(1e3 * from_um_factor / freqs,
                 scatt_eff_theory,
                 'ro-',
                 label='Theory')
        plt.xlabel('Wavelength [nm]')
        plt.ylabel('Scattering efficiency [σ/πr$^{2}$]')
        plt.legend()
        plt.title('Scattering of Au Sphere With {:.1f} nm Radius'.format(
            r * from_um_factor * 1e3))
        plt.tight_layout()
        plt.savefig(file("Comparison.png"))

    #%% PLOT SEPARATE

    if vm.parallel_assign(1, np_process, parallel):
        plt.figure()
        plt.plot(1e3 * from_um_factor / freqs,
                 scatt_eff_meep,
                 'bo-',
                 label='Meep')
        plt.xlabel('Wavelength [nm]')
        plt.ylabel('Scattering efficiency [σ/πr$^{2}$]')
        plt.legend()
        plt.title('Scattering of Au Sphere With {:.1f} nm Radius'.format(
            r * from_um_factor * 1e3))
        plt.tight_layout()
        plt.savefig(file("Meep.png"))

    if vm.parallel_assign(0, np_process, parallel) and surface_index == 1:
        plt.figure()
        plt.plot(1e3 * from_um_factor / freqs,
                 scatt_eff_theory,
                 'ro-',
                 label='Theory')
        plt.xlabel('Wavelength [nm]')
        plt.ylabel('Scattering efficiency [σ/πr$^{2}$]')
        plt.legend()
        plt.title('Scattering of Au Sphere With {:.1f} nm Radius'.format(r *
                                                                         10))
        plt.tight_layout()
        plt.savefig(file("Theory.png"))

    #%% PLOT ONE ABOVE THE OTHER

    if vm.parallel_assign(1, np_process, parallel) and surface_index == 1:
        fig, axes = plt.subplots(nrows=2, sharex=True)
        fig.subplots_adjust(hspace=0)
        plt.suptitle('Scattering of Au Sphere With {:.1f} nm Radius'.format(
            r * from_um_factor * 1e3))

        axes[0].plot(1e3 * from_um_factor / freqs,
                     scatt_eff_meep,
                     'bo-',
                     label='Meep')
        axes[0].yaxis.tick_right()
        axes[0].set_ylabel('Scattering efficiency [σ/πr$^{2}$]')
        axes[0].legend()

        axes[1].plot(1e3 * from_um_factor / freqs,
                     scatt_eff_theory,
                     'ro-',
                     label='Theory')
        axes[1].set_xlabel('Wavelength [nm]')
        axes[1].set_ylabel('Scattering efficiency [σ/πr$^{2}$]')
        axes[1].legend()

        plt.savefig(file("SeparatedComparison.png"))

    #%% PLOT FLUX FOURIER FINAL DATA

    if vm.parallel_assign(0, np_process, parallel):

        ylims = (np.min(data_base[:, 2:8]), np.max(data_base[:, 2:8]))
        ylims = (ylims[0] - .1 * (ylims[1] - ylims[0]),
                 ylims[1] + .1 * (ylims[1] - ylims[0]))

        fig, ax = plt.subplots(3, 2, sharex=True)
        fig.subplots_adjust(hspace=0, wspace=.05)
        plt.suptitle('Final flux of Au Sphere With {:.1f} nm Radius'.format(
            r * from_um_factor * 1e3))
        for a in ax[:, 1]:
            a.yaxis.tick_right()
            a.yaxis.set_label_position("right")
        for a, h in zip(np.reshape(ax, 6), header_base[1:7]):
            a.set_ylabel(h)

        for d, a in zip(data_base[:, 3:9].T, np.reshape(ax, 6)):
            a.plot(1e3 * from_um_factor / freqs, d)
            a.set_ylim(*ylims)
        ax[-1, 0].set_xlabel("Wavelength [nm]")
        ax[-1, 1].set_xlabel("Wavelength [nm]")

        plt.savefig(file("FinalFlux.png"))

    #%% PLOT ANGULAR PATTERN IN 3D

    if near2far and vm.parallel_assign(1, np_process, parallel):

        freq_index = np.argmin(np.abs(freqs - freq_center))

        fig = plt.figure()
        plt.suptitle(
            'Angular Pattern of Au Sphere With {:.1f} nm Radius at {:.1f} nm'.
            format(r * from_um_factor * 1e3,
                   from_um_factor * 1e3 / freqs[freq_index]))
        ax = fig.add_subplot(1, 1, 1, projection='3d')
        ax.plot_surface(poynting_x[:, :, freq_index],
                        poynting_y[:, :, freq_index],
                        poynting_z[:, :, freq_index],
                        cmap=plt.get_cmap('jet'),
                        linewidth=1,
                        antialiased=False,
                        alpha=0.5)
        ax.set_xlabel(r"$P_x$")
        ax.set_ylabel(r"$P_y$")
        ax.set_zlabel(r"$P_z$")

        plt.savefig(file("AngularPattern.png"))

    #%% PLOT ANGULAR PATTERN PROFILE FOR DIFFERENT POLAR ANGLES

    if near2far and vm.parallel_assign(0, np_process, parallel):

        freq_index = np.argmin(np.abs(freqs - freq_center))
        index = [
            list(polar_angle).index(alpha) for alpha in [0, .25, .5, .75, 1]
        ]

        plt.figure()
        plt.suptitle(
            'Angular Pattern of Au Sphere With {:.1f} nm Radius at {:.1f} nm'.
            format(r * from_um_factor * 1e3,
                   from_um_factor * 1e3 / freqs[freq_index]))
        ax_plain = plt.axes()
        for i in index:
            ax_plain.plot(poynting_x[:, i, freq_index],
                          poynting_y[:, i, freq_index],
                          ".-",
                          label=rf"$\theta$ = {polar_angle[i]:.2f} $\pi$")
        plt.legend()
        ax_plain.set_xlabel(r"$P_x$")
        ax_plain.set_ylabel(r"$P_y$")
        ax_plain.set_aspect("equal")

        plt.savefig(file("AngularPolar.png"))

    #%% PLOT ANGULAR PATTERN PROFILE FOR DIFFERENT AZIMUTHAL ANGLES

    if near2far and vm.parallel_assign(1, np_process, parallel):

        freq_index = np.argmin(np.abs(freqs - freq_center))
        index = [
            list(azimuthal_angle).index(alpha)
            for alpha in [0, .25, .5, .75, 1, 1.25, 1.5, 1.75, 2]
        ]

        plt.figure()
        plt.suptitle(
            'Angular Pattern of Au Sphere With {:.1f} nm Radius at {:.1f} nm'.
            format(r * from_um_factor * 1e3,
                   from_um_factor * 1e3 / freqs[freq_index]))
        ax_plain = plt.axes()
        for i in index:
            ax_plain.plot(poynting_x[i, :, freq_index],
                          poynting_z[i, :, freq_index],
                          ".-",
                          label=rf"$\phi$ = {azimuthal_angle[i]:.2f} $\pi$")
        plt.legend()
        ax_plain.set_xlabel(r"$P_x$")
        ax_plain.set_ylabel(r"$P_z$")

        plt.savefig(file("AngularAzimuthal.png"))

    if near2far and vm.parallel_assign(0, np_process, parallel):

        freq_index = np.argmin(np.abs(freqs - freq_center))
        index = [
            list(azimuthal_angle).index(alpha)
            for alpha in [0, .25, .5, .75, 1, 1.25, 1.5, 1.75, 2]
        ]

        plt.figure()
        plt.suptitle(
            'Angular Pattern of Au Sphere With {:.1f} nm Radius at {:.1f} nm'.
            format(r * from_um_factor * 1e3,
                   from_um_factor * 1e3 / freqs[freq_index]))
        ax_plain = plt.axes()
        for i in index:
            ax_plain.plot(np.sqrt(
                np.square(poynting_x[i, :, freq_index]) +
                np.square(poynting_y[i, :, freq_index])),
                          poynting_z[i, :, freq_index],
                          ".-",
                          label=rf"$\phi$ = {azimuthal_angle[i]:.2f} $\pi$")
        plt.legend()
        ax_plain.set_xlabel(r"$P_\rho$")
        ax_plain.set_ylabel(r"$P_z$")

        plt.savefig(file("AngularAzimuthalAbs.png"))
Пример #25
0
 def test_in_volume(self):
     sim = self.init_simple_simulation()
     sim.filename_prefix = 'test_in_volume'
     vol = mp.Volume(mp.Vector3(), size=mp.Vector3(x=2))
     sim.run(mp.at_end(mp.in_volume(vol, mp.output_efield_z)), until=200)
def main(args):
    print("\nstart time:", datetime.now())

    # --------------------------------------------------------------------------
    # physical parameters characterizing light source and interface characteris-
    # tics (must be adjusted - eihter here or via command line interface (CLI))
    # --------------------------------------------------------------------------
    e_z = args.e_z
    e_y = args.e_y

    m_charge = args.m_charge
    ref_medium = args.ref_medium

    n1 = args.n1
    n2 = args.n2

    kw_0 = args.kw_0
    kr_w = args.kr_w

    # angle of incidence
    chi_deg = args.chi_deg
    #chi_deg = 1.0*Critical(n1, n2)
    #chi_deg = 0.95*Brewster(n1, n2)

    test_output = args.test_output

    # --------------------------------------------------------------------------
    # specific Meep parameters (may need to be adjusted)
    # --------------------------------------------------------------------------
    sx = 5  # size of cell including PML in x-direction
    sy = 5  # size of cell including PML in y-direction
    sz = 4  # size of cell including PML in z-direction
    pml_thickness = 0.25  # thickness of PML layer
    freq = 5  # vacuum frequency of source (default 5)
    runtime = 10  # runs simulation for 10 times freq periods

    # number of pixels per wavelength in the denser medium (at least 10,
    # 20 to 30 is a good choice)
    pixel = 10

    # source position with respect to the center (point of impact) in Meep
    # units (-2.15 good); if equal -r_w, then source position coincides with
    # waist position
    source_shift = -2.15

    # --------------------------------------------------------------------------
    # derived (Meep) parameters (do not change)
    # --------------------------------------------------------------------------
    k_vac = 2 * math.pi * freq
    k1 = n1 * k_vac
    n_ref = (1 if ref_medium == 0 else
             n1 if ref_medium == 1 else n2 if ref_medium == 2 else math.nan)
    r_w = kr_w / (n_ref * k_vac)
    w_0 = kw_0 / (n_ref * k_vac)
    shift = source_shift + r_w
    chi_rad = math.radians(chi_deg)
    s_pol = True if (e_z == 1 and e_y == 0) else False
    p_pol = True if (e_z == 0 and e_y == 1) else False

    params = dict(W_y=w_0, m=m_charge, k=k1)

    # --------------------------------------------------------------------------
    # placement of the dielectric interface within the computational cell
    # --------------------------------------------------------------------------
    # helper functions
    def alpha(chi_rad):
        """Angle of inclined plane with y-axis in radians."""
        return math.pi / 2 - chi_rad

    def Delta_x(alpha):
        """Inclined plane offset to the center of the cell."""
        sin_alpha = math.sin(alpha)
        cos_alpha = math.cos(alpha)
        return (sx / 2) * ((
            (math.sqrt(2) - cos_alpha) - sin_alpha) / sin_alpha)

    cell = mp.Vector3(sx, sy, sz)  # geometry-lattice

    default_material = mp.Medium(index=n1)
    # located at lower right edge for 45 degree tilt
    geometry = [
        mp.Block(size=mp.Vector3(mp.inf, sx * math.sqrt(2), mp.inf),
                 center=mp.Vector3(+sx / 2 + Delta_x(alpha(chi_rad)), -sy / 2),
                 e1=mp.Vector3(1 / math.tan(alpha(chi_rad)), 1, 0),
                 e2=mp.Vector3(-1, 1 / math.tan(alpha(chi_rad)), 0),
                 e3=mp.Vector3(0, 0, 1),
                 material=mp.Medium(index=n2))
    ]

    # --------------------------------------------------------------------------
    # add absorbing boundary conditions and discretize structure
    # --------------------------------------------------------------------------
    pml_layers = [mp.PML(pml_thickness)]
    resolution = pixel * (n1 if n1 > n2 else n2) * freq
    # set Courant factor (mandatory if either n1 or n2 is smaller than 1)
    Courant = (n1 if n1 < n2 else n2) / 3

    # --------------------------------------------------------------------------
    # 2d-beam profile distribution (field amplitude) at the waist of the beam
    # --------------------------------------------------------------------------
    def Gauss(r, params):
        """Gauss profile."""
        W_y = params['W_y']

        return math.exp(-((r.y**2 + r.z**2) / W_y**2))

    # --------------------------------------------------------------------------
    # some test outputs
    # --------------------------------------------------------------------------
    if test_output:
        print("Gauss 2d beam profile:", Gauss(mp.Vector3(0, 0.5, 0.2), params))
        print()

    # --------------------------------------------------------------------------
    # spectrum amplitude distribution(s)
    # --------------------------------------------------------------------------

    # cartesian coordinates (not recommmended) -------------------------
    def phi(k_y, k_z):
        """Azimuthal angle.

        Part of coordinate transformation from k-space to (theta, phi)-space.
        """
        return math.atan2(k_y, -k_z)

    def theta(k_y, k_z, k):
        """Polar angle.

        Part of coordinate transformation from k-space to (theta, phi)-space.
        """
        return math.acos(cmath.sqrt(k**2 - k_y**2 - k_z**2).real / k)

    def f_Gauss_cartesian(k_y, k_z, params):
        """2d-Gaussian spectrum amplitude.

        Impementation for Cartesian coordinates.
        """
        W_y = params['W_y']

        return math.exp(-W_y**2 * (k_y**2 + k_z**2) / 4)

    def f_Laguerre_Gauss_cartesian(k_y, k_z, params):
        """Laguerre-Gaussian spectrum amplitude.

        Impementation for Cartesian coordinates.
        """
        m, k = params['m'], params['k']

        return f_Gauss_cartesian(k_y, k_z, params) * \
            cmath.exp(1j*m*phi(k_y, k_z)) * theta(k_y, k_z, k)**abs(m)

    # spherical coordinates --------------------------------------------
    def f_Gauss_spherical(sin_theta, theta, phi, params):
        """2d-Gaussian spectrum amplitude.

        Impementation for spherical coordinates.
        """
        W_y, k = params['W_y'], params['k']

        return math.exp(-(k * W_y * sin_theta / 2)**2)

    def f_Laguerre_Gauss_spherical(sin_theta, theta, phi, params):
        """Laguerre-Gaussian spectrum amplitude.

        Impementation for spherical coordinates.
        """
        m = params['m']

        return f_Gauss_spherical(sin_theta, theta, phi, params) * theta**abs(m) * \
            cmath.exp(1j*m*phi)

    # --------------------------------------------------------------------------
    # some test outputs
    # --------------------------------------------------------------------------
    if test_output:
        k_y, k_z = 1.0, 5.2
        theta_ = theta(k_y, k_z, k1)
        phi_ = phi(k_y, k_z)

        print("Gauss spectrum (cartesian):",
              f_Gauss_cartesian(k_y, k_z, params))
        print("Gauss spectrum (spherical):",
              f_Gauss_spherical(math.sin(theta_), theta_, phi_, params))
        print()
        print("L-G spectrum   (cartesian):",
              f_Laguerre_Gauss_cartesian(k_y, k_z, params))
        print(
            "L-G spectrum   (spherical):",
            f_Laguerre_Gauss_spherical(math.sin(theta_), theta_, phi_, params))
        print()

    # --------------------------------------------------------------------------
    # plane wave decomposition
    # (purpose: calculate field amplitude at light source position if not
    #           coinciding with beam waist)
    # --------------------------------------------------------------------------
    def psi_cartesian(r, x, params):
        """Field amplitude function.

        Integration in Cartesian coordinates.
        """
        k, m = params['k'], params['m']

        try:
            getattr(psi_cartesian, "called")
        except AttributeError:
            psi_cartesian.called = True
            print("Calculating inital field configuration. "
                  "This will take some time...")

        def phase(k_y, k_z, x, y, z):
            """Phase function."""
            return x * cmath.sqrt(k**2 - k_y**2 -
                                  k_z**2).real + y * k_y + z * k_z

        f = (f_Gauss_cartesian if m == 0 else f_Laguerre_Gauss_cartesian)

        try:
            (result, real_tol, imag_tol) = complex_dblquad(
                lambda k_y, k_z: f(k_y, k_z, params) * cmath.exp(1j * phase(
                    k_y, k_z, x, r.y, r.z)), -k, k, -k, k)
        except Exception as e:
            print(type(e).__name__ + ":", e)
            sys.exit()

        return result

    def psi_spherical(r, x, params):
        """Field amplitude function.

        Integration in spherical coordinates.
        """
        k, m = params['k'], params['m']

        try:
            getattr(psi_spherical, "called")
        except AttributeError:
            psi_spherical.called = True
            print("Calculating inital field configuration. "
                  "This will take some time...")

        def phase(theta, phi, x, y, z):
            """Phase function."""
            sin_theta, sin_phi = math.sin(theta), math.sin(phi)
            cos_theta, cos_phi = math.cos(theta), math.cos(phi)

            return k * (sin_theta *
                        (y * sin_phi - z * cos_phi) + cos_theta * x)

        f = (f_Gauss_spherical if m == 0 else f_Laguerre_Gauss_spherical)

        try:
            (result, real_tol, imag_tol) = complex_dblquad(
                lambda theta, phi: math.sin(theta) * math.cos(theta) *
                f(math.sin(theta), theta, phi, params) * cmath.exp(1j * phase(
                    theta, phi, x, r.y, r.z)), 0, 2 * math.pi, 0, math.pi / 2)
        except Exception as e:
            print(type(e).__name__ + ":", e)
            sys.exit()

        return k**2 * result

    # --------------------------------------------------------------------------
    # some test outputs (uncomment if needed)
    # --------------------------------------------------------------------------
    if test_output:
        k_y, k_z = 1.0, 5.2
        x, y, z = -2.15, 0.3, 0.5
        r = mp.Vector3(0, y, z)

        print("phi:", phi(k_y, k_z))
        print()
        print("psi            (cartesian):",
              psi_cartesian(r, f_Laguerre_Gauss_cartesian, x, params))
        print("psi            (spherical):",
              psi_spherical(r, f_Laguerre_Gauss_spherical, x, params))
        print("psi       (origin, simple):", Gauss(r, params))
        sys.exit()

    # --------------------------------------------------------------------------
    # display values of physical variables
    # --------------------------------------------------------------------------
    print()
    print("Expected output file size:",
          round(8 * (sx * sy * sz * resolution**3) / (1024**2)), "MiB")
    print()
    print("Specified variables and derived values:")
    print("n1:", n1)
    print("n2:", n2)
    print("chi:  ", chi_deg, " [degree]")
    # interface inclination with respect to the x-axis
    print("incl.:", 90 - chi_deg, " [degree]")
    print("kw_0: ", kw_0)
    print("kr_w: ", kr_w)
    print("k_vac:", k_vac)
    print("vortex charge:", m_charge)
    print("Jones vector components: "
          "(e_z=",
          e_z,
          ", e_y=",
          e_y,
          ")",
          sep="",
          end="")
    print(" --->",
          ("s-" if s_pol else "p-" if p_pol else "mixed-") + "polarisation")
    print("degree of linear   polarisation at pi/4:",
          2 * (-e_z.conjugate() * e_y).real)
    print("degree of circular polarisation:",
          2 * (-e_z.conjugate() * e_y).imag)

    # --------------------------------------------------------------------------
    # exploiting symmetries to reduce computational effort
    # (only possible for beams without intrinsic orbital angular momentum, i.e.
    #  no vortex charge)
    # --------------------------------------------------------------------------

    # The plane of incidence (x-y-plane) is a mirror plane which is characterised
    # to be orthogonal to the z-axis (symmetry of the geometric structure).
    # Symmetry of the sources must be ensured simultaneously, which is only
    # possible for certain cases. If I am not mistaken this can only be achieved
    # for vortex free beams with pure s- or p-polarisation, i.e. where either
    # the Ez or Ey component is specified.
    symmetries = []
    if m_charge == 0:
        if s_pol:
            symmetries.append(mp.Mirror(mp.Z, phase=-1))
        if p_pol:
            symmetries.append(mp.Mirror(mp.Y, phase=+1))

    # --------------------------------------------------------------------------
    # specify current source, output functions and run simulation
    # --------------------------------------------------------------------------
    force_complex_fields = True  # default: True
    eps_averaging = True  # default: True

    sources = []

    if e_z != 0:
        source_Ez = mp.Source(
            src=mp.ContinuousSource(frequency=freq, width=0.5),
            component=mp.Ez,
            amplitude=e_z,
            size=mp.Vector3(0, 3, 3),
            center=mp.Vector3(source_shift, 0, 0),
            #amp_func=lambda r: Gauss(r, params)
            #amp_func=lambda r: psi_cartesian(r, shift, params)
            amp_func=lambda r: psi_spherical(r, shift, params))
        sources.append(source_Ez)

    if e_y != 0:
        source_Ey = mp.Source(
            src=mp.ContinuousSource(frequency=freq, width=0.5),
            component=mp.Ey,
            amplitude=e_y,
            size=mp.Vector3(0, 3, 3),
            center=mp.Vector3(source_shift, 0, 0),
            #amp_func=lambda r: Gauss(r, params)
            #amp_func=lambda r: psi_cartesian(r, shift, params)
            amp_func=lambda r: psi_spherical(r, shift, params))
        sources.append(source_Ey)

    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        symmetries=symmetries,
                        default_material=default_material,
                        Courant=Courant,
                        geometry=geometry,
                        sources=sources,
                        resolution=resolution,
                        force_complex_fields=force_complex_fields,
                        eps_averaging=eps_averaging)

    sim.use_output_directory()  # put output files in a separate folder

    def efield_real_squared(r, ex, ey, ez):
        """Calculate |Re E|^2.

        With |.| denoting the complex modulus if 'force_complex_fields?'
        is set to true, otherwise |.| gives the Euclidean norm.
        """
        return ex.real**2 + ey.real**2 + ez.real**2

    def efield_imag_squared(r, ex, ey, ez):
        """Calculate |Im E|^2.

        With |.| denoting the complex modulus if 'force_complex_fields?'
        is set to true, otherwise |.| gives the Euclidean norm.
        """
        return ex.imag**2 + ey.imag**2 + ez.imag**2

    def output_efield_real_squared(sim):
        """Output E-field (real part) intensity."""
        name = "e_real2_s" if s_pol else "e_real2_p" if p_pol else "e_real2_mixed"
        func = efield_real_squared
        cs = [mp.Ex, mp.Ey, mp.Ez]
        return sim.output_field_function(name, cs, func, real_only=True)

    def output_efield_imag_squared(sim):
        """Output E-field (imag part) intensity."""
        name = "e_imag2_s" if s_pol else "e_imag2_p" if p_pol else "e_imag2_mixed"
        func = efield_imag_squared
        cs = [mp.Ex, mp.Ey, mp.Ez]
        return sim.output_field_function(name, cs, func, real_only=True)

    run_args = [  #mp.at_beginning(mp.output_epsilon),    # output of dielectric function
        #mp.at_end(mp.output_efield_x),         # output of E_x component
        #mp.at_end(mp.output_efield_z),         # output of E_y component
        #mp.at_end(mp.output_efield_y),         # output of E_z component
        mp.at_end(output_efield_real_squared
                  )  # output of electric field intensity
    ]

    if force_complex_fields:
        run_args.append(mp.at_end(output_efield_imag_squared))

    sim.run(*run_args, until=runtime)

    print("\nend time:", datetime.now())
Пример #27
0
 def test_in_volume(self):
     sim = self.init_simple_simulation()
     sim.filename_prefix = 'test_in_volume'
     vol = mp.Volume(mp.Vector3(), size=mp.Vector3(x=2))
     sim.run(mp.at_end(mp.in_volume(vol, mp.output_efield_z)), until=200)
Пример #28
0
def main(args):

    resolution = 30  # pixels/um

    a_start = args.a_start  # starting periodicity
    a_end = args.a_end  # ending periodicity
    s_cav = args.s_cav  # cavity length
    r = args.r  # hole radius  (units of a)
    h = args.hh  # waveguide height
    w = args.w  # waveguide width

    dair = 1.00  # air padding
    dpml = 1.00  # PML thickness

    Ndef = args.Ndef  # number of defect periods
    a_taper = mp.interpolate(Ndef, [a_start, a_end])
    dgap = a_end - 2 * r * a_end

    Nwvg = args.Nwvg  # number of waveguide periods
    sx = 2 * (Nwvg * a_start + sum(a_taper)) - dgap + s_cav
    sy = dpml + dair + w + dair + dpml
    sz = dpml + dair + h + dair + dpml

    cell_size = mp.Vector3(sx, sy, sz)
    boundary_layers = [mp.PML(dpml)]

    nSi = 3.45
    Si = mp.Medium(index=nSi)

    geometry = [
        mp.Block(material=Si,
                 center=mp.Vector3(),
                 size=mp.Vector3(mp.inf, w, h))
    ]

    for mm in range(Nwvg):
        geometry.append(
            mp.Cylinder(material=mp.air,
                        radius=r * a_start,
                        height=mp.inf,
                        center=mp.Vector3(
                            -0.5 * sx + 0.5 * a_start + mm * a_start, 0, 0)))
        geometry.append(
            mp.Cylinder(material=mp.air,
                        radius=r * a_start,
                        height=mp.inf,
                        center=mp.Vector3(
                            +0.5 * sx - 0.5 * a_start - mm * a_start, 0, 0)))

    for mm in range(Ndef + 2):
        geometry.append(
            mp.Cylinder(material=mp.air,
                        radius=r * a_taper[mm],
                        height=mp.inf,
                        center=mp.Vector3(
                            -0.5 * sx + Nwvg * a_start +
                            (sum(a_taper[:mm]) if mm > 0 else 0) +
                            0.5 * a_taper[mm], 0, 0)))
        geometry.append(
            mp.Cylinder(material=mp.air,
                        radius=r * a_taper[mm],
                        height=mp.inf,
                        center=mp.Vector3(
                            +0.5 * sx - Nwvg * a_start -
                            (sum(a_taper[:mm]) if mm > 0 else 0) -
                            0.5 * a_taper[mm], 0, 0)))

    lambda_min = 1.46  # minimum source wavelength
    lambda_max = 1.66  # 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.Ey,
                  center=mp.Vector3())
    ]

    symmetries = [
        mp.Mirror(mp.X, +1),
        mp.Mirror(mp.Y, -1),
        mp.Mirror(mp.Z, +1)
    ]

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

    sim.run(mp.in_volume(
        mp.Volume(center=mp.Vector3(), size=mp.Vector3(sx, sy, 0)),
        mp.at_end(mp.output_epsilon, mp.output_efield_y)),
            mp.after_sources(mp.Harminv(mp.Ey, mp.Vector3(), fcen, df)),
            until_after_sources=500)
Пример #29
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()
Пример #30
0
def main(args):
    print("\nstart time:", datetime.now())

    # --------------------------------------------------------------------------
    # physical parameters characterizing light source and interface characteris-
    # tics (must be adjusted - eihter here or via command line interface (CLI))
    # --------------------------------------------------------------------------
    e_z = args.e_z
    e_y = args.e_y

    m_charge = args.m_charge
    ref_medium = args.ref_medium

    n1 = args.n1
    n2 = args.n2

    kw_0 = args.kw_0
    kr_w = args.kr_w

    # angle of incidence
    chi_deg = args.chi_deg
    #chi_deg = 1.0*op.critical(n1, n2)
    #chi_deg = 0.95*op.brewster(n1, n2)

    # --------------------------------------------------------------------------
    # specific Meep parameters (may need to be adjusted)
    # --------------------------------------------------------------------------
    sx = 5   # size of cell including PML in x-direction
    sy = 5   # size of cell including PML in y-direction
    sz = 4   # size of cell including PML in z-direction
    pml_thickness = 0.25   # thickness of PML layer
    freq = 5       # vacuum frequency of source (default 5)
    runtime = 10   # runs simulation for 10 times freq periods

    # number of pixels per wavelength in the denser medium (at least 10,
    # 20 to 30 is a good choice)
    pixel = 10

    # source position with respect to the center (point of impact) in Meep
    # units (-2.15 good); if equal -r_w, then source position coincides with
    # waist position
    source_shift = -2.15

    # --------------------------------------------------------------------------
    # derived (Meep) parameters (do not change)
    # --------------------------------------------------------------------------
    k_vac = 2 * math.pi * freq
    k1 = n1 * k_vac
    n_ref = (1  if ref_medium == 0 else
             n1 if ref_medium == 1 else
             n2 if ref_medium == 2 else math.nan)
    r_w = kr_w / (n_ref * k_vac)
    w_0 = kw_0 / (n_ref * k_vac)
    shift = source_shift + r_w
    chi_rad = math.radians(chi_deg)
    s_pol = True if (e_z == 1 and e_y == 0) else False
    p_pol = True if (e_z == 0 and e_y == 1) else False

    params = dict(W_y=w_0, m=m_charge, k=k1)

    # --------------------------------------------------------------------------
    # placement of the dielectric interface within the computational cell
    # --------------------------------------------------------------------------
    # helper functions
    def alpha(chi_rad):
        """Angle of inclined plane with y-axis in radians."""
        return math.pi/2 - chi_rad

    def Delta_x(alpha):
        """Inclined plane offset to the center of the cell."""
        sin_alpha = math.sin(alpha)
        cos_alpha = math.cos(alpha)
        return (sx/2) * (((math.sqrt(2) - cos_alpha) - sin_alpha) / sin_alpha)

    cell = mp.Vector3(sx, sy, sz)  # geometry-lattice

    default_material = mp.Medium(index=n1)
    # located at lower right edge for 45 degree tilt
    geometry = [mp.Block(size=mp.Vector3(mp.inf, sx*math.sqrt(2), mp.inf),
                         center=mp.Vector3(+sx/2 + Delta_x(alpha(chi_rad)),
                                           -sy/2),
                         e1=mp.Vector3(1/math.tan(alpha(chi_rad)), 1, 0),
                         e2=mp.Vector3(-1, 1/math.tan(alpha(chi_rad)), 0),
                         e3=mp.Vector3(0, 0, 1),
                         material=mp.Medium(index=n2))]

    # --------------------------------------------------------------------------
    # add absorbing boundary conditions and discretize structure
    # --------------------------------------------------------------------------
    pml_layers = [mp.PML(pml_thickness)]
    resolution = pixel * (n1 if n1 > n2 else n2) * freq
    # set Courant factor (mandatory if either n1 or n2 is smaller than 1)
    Courant = (n1 if n1 < n2 else n2) / 3

    # --------------------------------------------------------------------------
    # display values of physical variables
    # --------------------------------------------------------------------------
    print()
    print("Expected output file size:",
          round(8*(sx*sy*sz*resolution**3)/(1024**2)), "MiB")
    print()
    print("Specified variables and derived values:")
    print("n1:", n1)
    print("n2:", n2)
    print("chi:  ", chi_deg, " [degree]")
    # interface inclination with respect to the x-axis
    print("incl.:", 90 - chi_deg, " [degree]")
    print("kw_0: ", kw_0)
    print("kr_w: ", kr_w)
    print("k_vac:", k_vac)
    print("vortex charge:", m_charge)
    print("Jones vector components: "
          "(e_z=", e_z, ", e_y=", e_y, ")", sep="", end="")
    print(" --->", ("s-" if s_pol else
                    "p-" if p_pol else
                    "mixed-") + "polarisation")
    print("degree of linear   polarisation at pi/4:",
          2*(-e_z.conjugate()*e_y).real)
    print("degree of circular polarisation:", 2*(-e_z.conjugate()*e_y).imag)

    # --------------------------------------------------------------------------
    # exploiting symmetries to reduce computational effort
    # (only possible for beams without intrinsic orbital angular momentum, i.e.
    #  no vortex charge)
    # --------------------------------------------------------------------------

    # The plane of incidence (x-y-plane) is a mirror plane which is characterised
    # to be orthogonal to the z-axis (symmetry of the geometric structure).
    # Symmetry of the sources must be ensured simultaneously, which is only
    # possible for certain cases. If I am not mistaken this can only be achieved
    # for vortex free beams with pure s- or p-polarisation, i.e. where either
    # the Ez or Ey component is specified.
    symmetries = []
    if m_charge == 0:
        if s_pol:
            symmetries.append(mp.Mirror(mp.Z, phase=-1))
        if p_pol:
            symmetries.append(mp.Mirror(mp.Y, phase=+1))

    # --------------------------------------------------------------------------
    # specify current source, output functions and run simulation
    # --------------------------------------------------------------------------
    force_complex_fields = True           # default: True
    eps_averaging = True                  # default: True

    sources = []

    # specify optical beam
    LGbeam = op.LaguerreGauss3d(x=shift, params=params)

    if e_z != 0:
        source_Ez = mp.Source(src=mp.ContinuousSource(frequency=freq, width=0.5),
                              component=mp.Ez,
                              amplitude=e_z,
                              size=mp.Vector3(0, 3, 3),
                              center=mp.Vector3(source_shift, 0, 0),
                              amp_func=LGbeam.profile
                              )
        sources.append(source_Ez)

    if e_y != 0:
        source_Ey = mp.Source(src=mp.ContinuousSource(frequency=freq, width=0.5),
                              component=mp.Ey,
                              amplitude=e_y,
                              size=mp.Vector3(0, 3, 3),
                              center=mp.Vector3(source_shift, 0, 0),
                              amp_func=LGbeam.profile
                              )
        sources.append(source_Ey)

    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        symmetries=symmetries,
                        default_material=default_material,
                        Courant=Courant,
                        geometry=geometry,
                        sources=sources,
                        resolution=resolution,
                        force_complex_fields=force_complex_fields,
                        eps_averaging=eps_averaging
                        )

    sim.use_output_directory()   # put output files in a separate folder

    def efield_real_squared(r, ex, ey, ez):
        """Calculate |Re E|^2.

        With |.| denoting the complex modulus if 'force_complex_fields?'
        is set to true, otherwise |.| gives the Euclidean norm.
        """
        return ex.real**2 + ey.real**2 + ez.real**2

    def efield_imag_squared(r, ex, ey, ez):
        """Calculate |Im E|^2.

        With |.| denoting the complex modulus if 'force_complex_fields?'
        is set to true, otherwise |.| gives the Euclidean norm.
        """
        return ex.imag**2 + ey.imag**2 + ez.imag**2

    def output_efield_real_squared(sim):
        """Output E-field (real part) intensity."""
        name = "e_real2_s" if s_pol else "e_real2_p" if p_pol else "e_real2_mixed"
        func = efield_real_squared
        cs = [mp.Ex, mp.Ey, mp.Ez]
        return sim.output_field_function(name, cs, func, real_only=True)

    def output_efield_imag_squared(sim):
        """Output E-field (imag part) intensity."""
        name = "e_imag2_s" if s_pol else "e_imag2_p" if p_pol else "e_imag2_mixed"
        func = efield_imag_squared
        cs = [mp.Ex, mp.Ey, mp.Ez]
        return sim.output_field_function(name, cs, func, real_only=True)

    run_args = [#mp.at_beginning(mp.output_epsilon),    # output of dielectric function
                #mp.at_end(mp.output_efield_x),         # output of E_x component
                #mp.at_end(mp.output_efield_z),         # output of E_y component
                #mp.at_end(mp.output_efield_y),         # output of E_z component
                mp.at_end(output_efield_real_squared)  # output of electric field intensity
                ]

    if force_complex_fields:
        run_args.append(mp.at_end(output_efield_imag_squared))

    sim.run(*run_args, until=runtime)

    print("\nend time:", datetime.now())
Пример #31
0
sources = [mp.Source(mp.ContinuousSource(frequency=0.15),
                     component=mp.Ez,
                     center=mp.Vector3(-7,0))]
pml_layers = [mp.PML(1.0)]

resolution = 10

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

sim.run(mp.at_beginning(mp.output_epsilon),
        mp.at_end(mp.output_efield_z),
        until=200)

import h5py
import numpy as np
import matplotlib.pyplot as plt


eps_h5file = h5py.File('straight_waveguide-eps-000000.00.h5','r')
eps_data = np.array(eps_h5file['eps'])
plt.figure(dpi=100)
plt.imshow(eps_data.transpose(), interpolation='spline36', cmap='binary')
plt.axis('off')
plt.show()

ez_h5file = h5py.File('straight_waveguide-ez-000200.00.h5','r')
Пример #32
0
def main(from_um_factor, resolution_wlen, courant, submerged_index,
         displacement, surface_index, wlen_center, wlen_width, nfreq,
         air_wlen_factor, pml_wlen_factor, flux_wlen_factor, time_factor_cell,
         second_time_factor, series, folder, parallel, n_processes,
         split_chunks_evenly):

    #%% CLASSIC INPUT PARAMETERS
    """
    # Simulation size
    from_um_factor = 100e-3 # Conversion of 1 μm to my length unit (=100nm/1μm)
    resolution_wlen = 20 # >=8 pixels per smallest wavelength, i.e. np.floor(8/wvl_min)
    courant = 0.5
    
    # Nanoparticle specifications: Sphere in Vacuum :)
    paper = "R"
    reference = "Meep"
    displacement = 0 # Displacement of the surface from the bottom of the sphere in nm
    submerged_index = 1.33 # 1.33 for water
    surface_index = 1.54 # 1.54 for glass
    
    # Frequency and wavelength
    wlen_center = 650 # Main wavelength range in nm
    wlen_width = 200 # Wavelength band in nm
    nfreq = 100
    
    # Box dimensions
    pml_wlen_factor = 0.38
    air_wlen_factor = 0.15
    flux_wlen_factor = 0.1
    
    # Simulation time
    time_factor_cell = 1.2
    second_time_factor = 10
    
    # Saving directories
    series = "1stTest"
    folder = "Test/TestDipole/DipoleGlass"
    
    # Configuration
    parallel = False
    n_processes = 1
    split_chunks_evenly = True
    """

    #%% MORE INPUT PARAMETERS

    # Simulation size
    resolution = (from_um_factor * 1e3) * resolution_wlen / (wlen_center +
                                                             wlen_width / 2)
    resolution = int(np.ceil(resolution / 2)) * 2

    # Frequency and wavelength
    cutoff = 3.2  # Gaussian planewave source's parameter of shape
    nazimuthal = 16
    npolar = 20

    ### TREATED INPUT PARAMETERS

    # Nanoparticle specifications: Sphere in Vacuum :)
    displacement = displacement / (from_um_factor * 1e3)  # Now in Meep units

    # Frequency and wavelength
    wlen_center = wlen_center / (from_um_factor * 1e3)  # Now in Meep units
    wlen_width = wlen_width / (from_um_factor * 1e3)  # Now in Meep units
    freq_center = 1 / wlen_center  # Hz center frequency in Meep units
    freq_width = 1 / wlen_width  # Hz range in Meep units from highest to lowest

    # Space configuration
    pml_width = pml_wlen_factor * (wlen_center + wlen_width / 2
                                   )  # 0.5 * max(wlen_range)
    air_width = air_wlen_factor * (wlen_center + wlen_width / 2)
    flux_box_size = flux_wlen_factor * (wlen_center + wlen_width / 2)

    # Computation
    enlapsed = []
    if parallel:
        np_process = mp.count_processors()
    else:
        np_process = 1

    # Saving directories
    if series is None:
        series = "Test"
    if folder is None:
        folder = "Test"
    params_list = [
        "from_um_factor", "resolution_wlen", "resolution", "courant",
        "submerged_index", "displacement", "surface_index", "wlen_center",
        "wlen_width", "cutoff", "nfreq", "nazimuthal", "npolar",
        "flux_box_size", "cell_width", "pml_width", "air_width",
        "until_after_sources", "time_factor_cell", "second_time_factor",
        "enlapsed", "parallel", "n_processes", "split_chunks_evenly", "script",
        "sysname", "path"
    ]

    #%% GENERAL GEOMETRY SETUP

    air_width = air_width - air_width % (1 / resolution)

    pml_width = pml_width - pml_width % (1 / resolution)
    pml_layers = [mp.PML(thickness=pml_width)]

    # symmetries = [mp.Mirror(mp.Y),
    #               mp.Mirror(mp.Z, phase=-1)]
    # Two mirror planes reduce cell size to 1/4
    # Issue related that lead me to comment this lines:
    # https://github.com/NanoComp/meep/issues/1484

    cell_width = 2 * (pml_width + air_width)
    cell_width = cell_width - cell_width % (1 / resolution)
    cell_size = mp.Vector3(cell_width, cell_width, cell_width)

    # surface_center = r/4 - displacement/2 + cell_width/4
    # surface_center = surface_center - surface_center%(1/resolution)
    # displacement = r/2 + cell_width/2 - 2*surface_center

    displacement = displacement - displacement % (1 / resolution)

    flux_box_size = flux_box_size - flux_box_size % (1 / resolution)

    sources = [
        mp.Source(mp.GaussianSource(freq_center,
                                    fwidth=freq_width,
                                    is_integrated=True,
                                    cutoff=cutoff),
                  center=mp.Vector3(),
                  component=mp.Ez)
    ]
    # Ez-polarized point pulse
    # (its size parameter is null and it is centered at zero)
    # >> The planewave source extends into the PML
    # ==> is_integrated=True must be specified

    until_after_sources = time_factor_cell * cell_width * submerged_index
    # Enough time for the pulse to pass through all the cell
    # Originally: Aprox 3 periods of lowest frequency, using T=λ/c=λ in Meep units
    # Now: Aprox 3 periods of highest frequency, using T=λ/c=λ in Meep units

    # if surface_index != 1:
    #     geometry = [mp.Block(material=mp.Medium(index=surface_index),
    #                          center=mp.Vector3(
    #                              - displacement/2 + cell_width/4,
    #                              0, 0),
    #                          size=mp.Vector3(
    #                              cell_width/2 + displacement,
    #                              cell_width, cell_width))]
    # else:
    #     geometry = []
    # A certain material surface underneath it

    home = vs.get_home()
    sysname = vs.get_sys_name()
    path = os.path.join(home, folder, series)
    if not os.path.isdir(path) and vm.parallel_assign(0, n_processes,
                                                      parallel):
        os.makedirs(path)
    file = lambda f: os.path.join(path, f)

    #%% BASE SIMULATION: SETUP

    measure_ram()

    params = {}
    for p in params_list:
        params[p] = eval(p)

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=pml_layers,
                        sources=sources,
                        k_point=mp.Vector3(),
                        Courant=courant,
                        default_material=mp.Medium(index=submerged_index),
                        output_single_precision=True,
                        split_chunks_evenly=split_chunks_evenly)

    measure_ram()

    near2far_box = sim.add_near2far(
        freq_center, freq_width, nfreq,
        mp.Near2FarRegion(center=mp.Vector3(x=-flux_box_size / 2),
                          size=mp.Vector3(0, flux_box_size, flux_box_size),
                          weight=-1),
        mp.Near2FarRegion(center=mp.Vector3(x=+flux_box_size / 2),
                          size=mp.Vector3(0, flux_box_size, flux_box_size),
                          weight=+1),
        mp.Near2FarRegion(center=mp.Vector3(y=-flux_box_size / 2),
                          size=mp.Vector3(flux_box_size, 0, flux_box_size),
                          weight=-1),
        mp.Near2FarRegion(center=mp.Vector3(y=+flux_box_size / 2),
                          size=mp.Vector3(flux_box_size, 0, flux_box_size),
                          weight=+1),
        mp.Near2FarRegion(center=mp.Vector3(z=-flux_box_size / 2),
                          size=mp.Vector3(flux_box_size, flux_box_size, 0),
                          weight=-1),
        mp.Near2FarRegion(center=mp.Vector3(z=+flux_box_size / 2),
                          size=mp.Vector3(flux_box_size, flux_box_size, 0),
                          weight=+1))
    measure_ram()
    # used_ram.append(used_ram[-1])

    #%% BASE SIMULATION: INITIALIZE

    temp = time()
    sim.init_sim()
    enlapsed.append(time() - temp)
    measure_ram()

    #%% BASE SIMULATION: SIMULATION :D

    step_ram_function = lambda sim: measure_ram()

    temp = time()
    sim.run(mp.at_beginning(step_ram_function),
            mp.at_time(int(second_time_factor * until_after_sources / 2),
                       step_ram_function),
            mp.at_end(step_ram_function),
            until_after_sources=second_time_factor * until_after_sources)
    #     mp.stop_when_fields_decayed(
    # np.mean(wlen_range), # dT = mean period of source
    # mp.Ez, # Component of field to check
    # mp.Vector3(0.5*cell_width - pml_width, 0, 0), # Where to check
    # 1e-3)) # Factor to decay
    enlapsed.append(time() - temp)
    del temp
    # Aprox 30 periods of lowest frequency, using T=λ/c=λ in Meep units

    #%% BASE SIMULATION: ANGULAR PATTERN ANALYSIS

    freqs = np.linspace(freq_center - freq_center / 2,
                        freq_center + freq_width / 2, nfreq)
    wlens = 1 / freqs

    # fraunhofer_distance = 8 * (r**2) / min(wlen_range)
    # radial_distance = max( 10 * fraunhofer_distance , 1.5 * cell_width/2 )
    # radius of far-field circle must be at least Fraunhofer distance

    radial_distance = cell_width
    azimuthal_angle = np.arange(0, 2 + 2 / nazimuthal,
                                2 / nazimuthal)  # in multiples of pi
    polar_angle = np.arange(0, 1 + 1 / npolar, 1 / npolar)

    poynting_x = []
    poynting_y = []
    poynting_z = []
    poynting_r = []

    for phi in azimuthal_angle:

        poynting_x.append([])
        poynting_y.append([])
        poynting_z.append([])
        poynting_r.append([])

        for theta in polar_angle:

            farfield_dict = sim.get_farfields(
                near2far_box,
                1,
                where=mp.Volume(center=mp.Vector3(
                    radial_distance * np.cos(np.pi * phi) *
                    np.sin(np.pi * theta),
                    radial_distance * np.sin(np.pi * phi) *
                    np.sin(np.pi *
                           theta), radial_distance * np.cos(np.pi * theta))))

            Px = farfield_dict["Ey"] * np.conjugate(farfield_dict["Hz"])
            Px -= farfield_dict["Ez"] * np.conjugate(farfield_dict["Hy"])
            Py = farfield_dict["Ez"] * np.conjugate(farfield_dict["Hx"])
            Py -= farfield_dict["Ex"] * np.conjugate(farfield_dict["Hz"])
            Pz = farfield_dict["Ex"] * np.conjugate(farfield_dict["Hy"])
            Pz -= farfield_dict["Ey"] * np.conjugate(farfield_dict["Hx"])

            Px = np.real(Px)
            Py = np.real(Py)
            Pz = np.real(Pz)

            poynting_x[-1].append(Px)
            poynting_y[-1].append(Py)
            poynting_z[-1].append(Pz)
            poynting_r[-1].append(
                np.sqrt(np.square(Px) + np.square(Py) + np.square(Pz)))

    del phi, theta, farfield_dict, Px, Py, Pz

    poynting_x = np.array(poynting_x)
    poynting_y = np.array(poynting_y)
    poynting_z = np.array(poynting_z)
    poynting_r = np.array(poynting_r)

    #%% BASE SIMULATION: SAVE DATA

    for p in params_list:
        params[p] = eval(p)

    os.chdir(path)
    sim.save_near2far("BaseNear2Far", near2far_box)
    if vm.parallel_assign(0, np_process, parallel):
        f = h5.File("BaseNear2Far.h5", "r+")
        for key, par in params.items():
            f[list(f.keys())[0]].attrs[key] = par
        f.close()
        del f
    os.chdir(syshome)

    if vm.parallel_assign(1, np_process, parallel):
        f = h5.File(file("BaseResults.h5"), "w")
        f["Px"] = poynting_x
        f["Py"] = poynting_y
        f["Pz"] = poynting_z
        f["Pr"] = poynting_r
        for dset in f.values():
            for key, par in params.items():
                dset.attrs[key] = par
        f.close()
        del f

    # if not split_chunks_evenly:
    #     vm.save_chunks(sim, params, path)

    if parallel:
        f = h5.File(file("BaseRAM.h5"),
                    "w",
                    driver='mpio',
                    comm=MPI.COMM_WORLD)
        current_process = mp.my_rank()
        f.create_dataset("RAM", (len(used_ram), np_process), dtype="float")
        f["RAM"][:, current_process] = used_ram
        for a in params:
            f["RAM"].attrs[a] = params[a]
        f.create_dataset("SWAP", (len(used_ram), np_process), dtype="int")
        f["SWAP"][:, current_process] = swapped_ram
        for a in params:
            f["SWAP"].attrs[a] = params[a]
    else:
        f = h5.File(file("BaseRAM.h5"), "w")
        f.create_dataset("RAM", data=used_ram)
        for a in params:
            f["RAM"].attrs[a] = params[a]
        f.create_dataset("SWAP", data=swapped_ram)
        for a in params:
            f["SWAP"].attrs[a] = params[a]
    f.close()
    del f

    sim.reset_meep()

    #%% FURTHER SIMULATION

    if surface_index != 1:

        #% FURTHER SIMULATION: SETUP

        measure_ram()

        params = {}
        for p in params_list:
            params[p] = eval(p)

        sim = mp.Simulation(resolution=resolution,
                            cell_size=cell_size,
                            boundary_layers=pml_layers,
                            sources=sources,
                            k_point=mp.Vector3(),
                            Courant=courant,
                            default_material=mp.Medium(index=surface_index),
                            output_single_precision=True,
                            split_chunks_evenly=split_chunks_evenly)

        measure_ram()

        near2far_box = sim.add_near2far(
            freq_center, freq_width, nfreq,
            mp.Near2FarRegion(center=mp.Vector3(x=-flux_box_size / 2),
                              size=mp.Vector3(0, flux_box_size, flux_box_size),
                              weight=-1),
            mp.Near2FarRegion(center=mp.Vector3(x=+flux_box_size / 2),
                              size=mp.Vector3(0, flux_box_size, flux_box_size),
                              weight=+1),
            mp.Near2FarRegion(center=mp.Vector3(y=-flux_box_size / 2),
                              size=mp.Vector3(flux_box_size, 0, flux_box_size),
                              weight=-1),
            mp.Near2FarRegion(center=mp.Vector3(y=+flux_box_size / 2),
                              size=mp.Vector3(flux_box_size, 0, flux_box_size),
                              weight=+1),
            mp.Near2FarRegion(center=mp.Vector3(z=-flux_box_size / 2),
                              size=mp.Vector3(flux_box_size, flux_box_size, 0),
                              weight=-1),
            mp.Near2FarRegion(center=mp.Vector3(z=+flux_box_size / 2),
                              size=mp.Vector3(flux_box_size, flux_box_size, 0),
                              weight=+1))
        measure_ram()
        # used_ram.append(used_ram[-1])

        #% FURTHER SIMULATION: INITIALIZE

        temp = time()
        sim.init_sim()
        enlapsed.append(time() - temp)
        measure_ram()

        #% FURTHER SIMULATION: SIMULATION :D

        step_ram_function = lambda sim: measure_ram()

        temp = time()
        sim.run(mp.at_beginning(step_ram_function),
                mp.at_time(int(second_time_factor * until_after_sources / 2),
                           step_ram_function),
                mp.at_end(step_ram_function),
                until_after_sources=second_time_factor * until_after_sources)
        #     mp.stop_when_fields_decayed(
        # np.mean(wlen_range), # dT = mean period of source
        # mp.Ez, # Component of field to check
        # mp.Vector3(0.5*cell_width - pml_width, 0, 0), # Where to check
        # 1e-3)) # Factor to decay
        enlapsed.append(time() - temp)
        del temp
        # Aprox 30 periods of lowest frequency, using T=λ/c=λ in Meep units

        #% FURTHER SIMULATION: ANGULAR PATTERN ANALYSIS

        poynting_x2 = []
        poynting_y2 = []
        poynting_z2 = []
        poynting_r2 = []

        for phi in azimuthal_angle:

            poynting_x2.append([])
            poynting_y2.append([])
            poynting_z2.append([])
            poynting_r2.append([])

            for theta in polar_angle:

                farfield_dict = sim.get_farfields(
                    near2far_box,
                    1,
                    where=mp.Volume(center=mp.Vector3(
                        radial_distance * np.cos(np.pi * phi) *
                        np.sin(np.pi * theta),
                        radial_distance * np.sin(np.pi * phi) *
                        np.sin(np.pi *
                               theta), radial_distance *
                        np.cos(np.pi * theta))))

                Px = farfield_dict["Ey"] * np.conjugate(farfield_dict["Hz"])
                Px -= farfield_dict["Ez"] * np.conjugate(farfield_dict["Hy"])
                Py = farfield_dict["Ez"] * np.conjugate(farfield_dict["Hx"])
                Py -= farfield_dict["Ex"] * np.conjugate(farfield_dict["Hz"])
                Pz = farfield_dict["Ex"] * np.conjugate(farfield_dict["Hy"])
                Pz -= farfield_dict["Ey"] * np.conjugate(farfield_dict["Hx"])

                Px = np.real(Px)
                Py = np.real(Py)
                Pz = np.real(Pz)

                poynting_x2[-1].append(Px)
                poynting_y2[-1].append(Py)
                poynting_z2[-1].append(Pz)
                poynting_r2[-1].append(
                    np.sqrt(np.square(Px) + np.square(Py) + np.square(Pz)))

        del phi, theta, farfield_dict, Px, Py, Pz

        poynting_x2 = np.array(poynting_x2)
        poynting_y2 = np.array(poynting_y2)
        poynting_z2 = np.array(poynting_z2)
        poynting_r2 = np.array(poynting_r2)

        #% FURTHER SIMULATION: SAVE DATA

        for p in params_list:
            params[p] = eval(p)

        os.chdir(path)
        sim.save_near2far("FurtherNear2Far", near2far_box)
        if vm.parallel_assign(0, np_process, parallel):
            f = h5.File("FurtherNear2Far.h5", "r+")
            for key, par in params.items():
                f[list(f.keys())[0]].attrs[key] = par
            f.close()
            del f
        os.chdir(syshome)

        if vm.parallel_assign(1, np_process, parallel):
            f = h5.File(file("FurtherResults.h5"), "w")
            f["Px"] = poynting_x2
            f["Py"] = poynting_y2
            f["Pz"] = poynting_z2
            f["Pr"] = poynting_r2
            for dset in f.values():
                for key, par in params.items():
                    dset.attrs[key] = par
            f.close()
            del f

        # if not split_chunks_evenly:
        #     vm.save_chunks(sim, params, path)

        if parallel:
            f = h5.File(file("FurtherRAM.h5"),
                        "w",
                        driver='mpio',
                        comm=MPI.COMM_WORLD)
            current_process = mp.my_rank()
            f.create_dataset("RAM", (len(used_ram), np_process), dtype="float")
            f["RAM"][:, current_process] = used_ram
            for a in params:
                f["RAM"].attrs[a] = params[a]
            f.create_dataset("SWAP", (len(used_ram), np_process), dtype="int")
            f["SWAP"][:, current_process] = swapped_ram
            for a in params:
                f["SWAP"].attrs[a] = params[a]
        else:
            f = h5.File(file("FurtherRAM.h5"), "w")
            f.create_dataset("RAM", data=used_ram)
            for a in params:
                f["RAM"].attrs[a] = params[a]
            f.create_dataset("SWAP", data=swapped_ram)
            for a in params:
                f["SWAP"].attrs[a] = params[a]
        f.close()
        del f

    #%% NORMALIZE AND REARANGE DATA

    if surface_index != 1:
        max_poynting_r = np.max(
            [np.max(np.abs(poynting_r)),
             np.max(np.abs(poynting_r2))])
    else:
        max_poynting_r = np.max(np.abs(poynting_r))

    poynting_x = np.array(poynting_x) / max_poynting_r
    poynting_y = np.array(poynting_y) / max_poynting_r
    poynting_z = np.array(poynting_z) / max_poynting_r
    poynting_r = np.array(poynting_r) / max_poynting_r

    if surface_index != 1:

        poynting_x0 = np.array(poynting_x)
        poynting_y0 = np.array(poynting_y)
        poynting_z0 = np.array(poynting_z)
        poynting_r0 = np.array(poynting_r)

        poynting_x2 = np.array(poynting_x2) / max_poynting_r
        poynting_y2 = np.array(poynting_y2) / max_poynting_r
        poynting_z2 = np.array(poynting_z2) / max_poynting_r
        poynting_r2 = np.array(poynting_r2) / max_poynting_r

    #%%
    """
    poynting_x = np.array(poynting_x0)
    poynting_y = np.array(poynting_y0)
    poynting_z = np.array(poynting_z0)
    poynting_r = np.array(poynting_r0)
    """

    if surface_index != 1:

        polar_limit = np.arcsin(displacement / radial_distance) + .5

        for i in range(len(polar_angle)):
            if polar_angle[i] > polar_limit:
                index_limit = i
                break

        poynting_x[:, index_limit:, :] = poynting_x2[:, index_limit:, :]
        poynting_y[:, index_limit:, :] = poynting_y2[:, index_limit:, :]
        poynting_z[:, index_limit:, :] = poynting_z2[:, index_limit:, :]
        poynting_r[:, index_limit:, :] = poynting_r2[:, index_limit:, :]

        poynting_x[:, index_limit - 1, :] = np.array([[
            np.mean([p2, p0]) for p2, p0 in zip(poy2, poy0)
        ] for poy2, poy0 in zip(poynting_x2[:, index_limit -
                                            1, :], poynting_x0[:, index_limit -
                                                               1, :])])
        poynting_y[:, index_limit - 1, :] = np.array([[
            np.mean([p2, p0]) for p2, p0 in zip(poy2, poy0)
        ] for poy2, poy0 in zip(poynting_y2[:, index_limit -
                                            1, :], poynting_y0[:, index_limit -
                                                               1, :])])
        poynting_z[:, index_limit - 1, :] = np.array([[
            np.mean([p2, p0]) for p2, p0 in zip(poy2, poy0)
        ] for poy2, poy0 in zip(poynting_z2[:, index_limit -
                                            1, :], poynting_z0[:, index_limit -
                                                               1, :])])
        poynting_r[:, index_limit - 1, :] = np.sqrt(
            np.squared(poynting_x[:, index_limit - 1, :]) +
            np.squared(poynting_y[:, index_limit - 1, :]) +
            np.squared(poynting_y[:, index_limit - 1, :]))

    #%% SAVE FINAL DATA

    if surface_index != 1 and vm.parallel_assign(0, np_process, parallel):

        os.remove(file("BaseRAM.h5"))
        os.rename(file("FurtherRAM.h5"), file("RAM.h5"))

    elif vm.parallel_assign(0, np_process, parallel):

        os.rename(file("BaseRAM.h5"), file("RAM.h5"))

    #%% PLOT ANGULAR PATTERN IN 3D

    if vm.parallel_assign(1, np_process, parallel):

        freq_index = np.argmin(np.abs(freqs - freq_center))

        fig = plt.figure()
        plt.suptitle(
            f'Angular Pattern of point dipole molecule at {from_um_factor * 1e3 * wlen_center:.0f} nm'
        )
        ax = fig.add_subplot(1, 1, 1, projection='3d')
        ax.plot_surface(poynting_x[:, :, freq_index],
                        poynting_y[:, :, freq_index],
                        poynting_z[:, :, freq_index],
                        cmap=plt.get_cmap('jet'),
                        linewidth=1,
                        antialiased=False,
                        alpha=0.5)
        ax.set_xlabel(r"$P_x$")
        ax.set_ylabel(r"$P_y$")
        ax.set_zlabel(r"$P_z$")

        plt.savefig(file("AngularPattern.png"))

    #%% PLOT ANGULAR PATTERN PROFILE FOR DIFFERENT POLAR ANGLES

    if vm.parallel_assign(0, np_process, parallel):

        freq_index = np.argmin(np.abs(freqs - freq_center))
        index = [
            list(polar_angle).index(alpha) for alpha in [0, .25, .5, .75, 1]
        ]

        plt.figure()
        plt.suptitle(
            f'Angular Pattern of point dipole molecule at {from_um_factor * 1e3 * wlen_center:.0f} nm'
        )
        ax_plain = plt.axes()
        for i in index:
            ax_plain.plot(poynting_x[:, i, freq_index],
                          poynting_y[:, i, freq_index],
                          ".-",
                          label=rf"$\theta$ = {polar_angle[i]:.2f} $\pi$")
        plt.legend()
        ax_plain.set_xlabel(r"$P_x$")
        ax_plain.set_ylabel(r"$P_y$")
        ax_plain.set_aspect("equal")

        plt.savefig(file("AngularPolar.png"))

    #%% PLOT ANGULAR PATTERN PROFILE FOR DIFFERENT AZIMUTHAL ANGLES

    if vm.parallel_assign(1, np_process, parallel):

        freq_index = np.argmin(np.abs(freqs - freq_center))
        index = [
            list(azimuthal_angle).index(alpha)
            for alpha in [0, .25, .5, .75, 1, 1.25, 1.5, 1.75, 2]
        ]

        plt.figure()
        plt.suptitle(
            f'Angular Pattern of point dipole molecule at {from_um_factor * 1e3 * wlen_center:.0f} nm'
        )
        ax_plain = plt.axes()
        for i in index:
            ax_plain.plot(poynting_x[i, :, freq_index],
                          poynting_z[i, :, freq_index],
                          ".-",
                          label=rf"$\phi$ = {azimuthal_angle[i]:.2f} $\pi$")
        plt.legend()
        ax_plain.set_xlabel(r"$P_x$")
        ax_plain.set_ylabel(r"$P_z$")

        plt.savefig(file("AngularAzimuthal.png"))

    if vm.parallel_assign(0, np_process, parallel):

        freq_index = np.argmin(np.abs(freqs - freq_center))
        index = [
            list(azimuthal_angle).index(alpha)
            for alpha in [0, .25, .5, .75, 1, 1.25, 1.5, 1.75, 2]
        ]

        plt.figure()
        plt.suptitle(
            f'Angular Pattern of point dipole molecule at {from_um_factor * 1e3 * wlen_center:.0f} nm'
        )
        ax_plain = plt.axes()
        for i in index:
            ax_plain.plot(np.sqrt(
                np.square(poynting_x[i, :, freq_index]) +
                np.square(poynting_y[i, :, freq_index])),
                          poynting_z[i, :, freq_index],
                          ".-",
                          label=rf"$\phi$ = {azimuthal_angle[i]:.2f} $\pi$")
        plt.legend()
        ax_plain.set_xlabel(r"$P_\rho$")
        ax_plain.set_ylabel(r"$P_z$")

        plt.savefig(file("AngularAzimuthalAbs.png"))
Пример #33
0
def main(args):
    print("\nstart time:", datetime.now())

    # --------------------------------------------------------------------------
    # physical parameters characterizing light source and interface characteris-
    # tics (must be adjusted - eihter here or via command line interface (CLI))
    # --------------------------------------------------------------------------
    interface = args.interface
    s_pol = args.s_pol
    ref_medium = args.ref_medium

    n1 = args.n1
    n2 = args.n2

    kw_0 = args.kw_0
    kr_w = args.kr_w
    kr_c = args.kr_c

    # angle of incidence
    chi_deg = args.chi_deg
    #chi_deg = 1.0*Critical(n1, n2)
    #chi_deg = 0.95*Brewster(n1, n2)

    test_output = args.test_output

    # --------------------------------------------------------------------------
    # specific Meep parameters (may need to be adjusted)
    # --------------------------------------------------------------------------
    sx = 5   # size of cell including PML in x-direction
    sy = 5   # size of cell including PML in y-direction
    pml_thickness = 0.25   # thickness of PML layer
    freq = 12      # vacuum frequency of source (5 to 12 is good)
    runtime = 10   # runs simulation for 10 times freq periods

    # number of pixels per wavelength in the denser medium (at least 10,
    # 20 to 30 is a good choice)
    pixel = 10

    # source position with respect to the center (point of impact) in Meep
    # units (-2.15 good); if equal -r_w, then source position coincides with
    # waist position
    source_shift = -2.15

    # --------------------------------------------------------------------------
    # derived (Meep) parameters (do not change)
    # --------------------------------------------------------------------------
    k_vac = 2 * math.pi * freq
    k1 = n1 * k_vac
    n_ref = (1  if ref_medium == 0 else
             n1 if ref_medium == 1 else
             n2 if ref_medium == 2 else math.nan)
    r_w = kr_w / (n_ref * k_vac)
    w_0 = kw_0 / (n_ref * k_vac)
    r_c = kr_c / (n_ref * k_vac)
    shift = source_shift + r_w
    chi_rad = math.radians(chi_deg)

    params = dict(W_y=w_0, k=k1)

    # --------------------------------------------------------------------------
    # placement of the dielectric interface within the computational cell
    # --------------------------------------------------------------------------
    # helper functions
    def alpha(chi_rad):
        """Angle of inclined plane with y-axis in radians."""
        return math.pi/2 - chi_rad

    def Delta_x(alpha):
        """Inclined plane offset to the center of the cell."""
        sin_alpha = math.sin(alpha)
        cos_alpha = math.cos(alpha)
        return (sx/2) * (((math.sqrt(2) - cos_alpha) - sin_alpha) / sin_alpha)

    cell = mp.Vector3(sx, sy, 0)  # geometry-lattice

    if interface == "planar":
        default_material = mp.Medium(index=n1)
        # located at lower right edge for 45 degree
        geometry = [mp.Block(size=mp.Vector3(mp.inf, sx*math.sqrt(2), mp.inf),
                             center=mp.Vector3(+sx/2 + Delta_x(alpha(chi_rad)),
                                               -sy/2),
                             e1=mp.Vector3(1/math.tan(alpha(chi_rad)), 1, 0),
                             e2=mp.Vector3(-1, 1/math.tan(alpha(chi_rad)), 0),
                             e3=mp.Vector3(0, 0, 1),
                             material=mp.Medium(index=n2))]
    elif interface == "concave":
        default_material = mp.Medium(index=n2)
        # move center to the right in order to ensure that the point of impact
        # is always centrally placed
        geometry = [mp.Cylinder(center=mp.Vector3(-r_c*math.cos(chi_rad),
                                                  +r_c*math.sin(chi_rad)),
                                height=mp.inf,
                                radius=r_c,
                                material=mp.Medium(index=n1))]
    elif interface == "convex":
        default_material = mp.Medium(index=n1)
        # move center to the right in order to ensure that the point of impact
        # is always centrally placed
        geometry = [mp.Cylinder(center=mp.Vector3(+r_c*math.cos(chi_rad),
                                                  -r_c*math.sin(chi_rad)),
                                height=mp.inf,
                                radius=r_c,
                                material=mp.Medium(index=n2))]

    # --------------------------------------------------------------------------
    # add absorbing boundary conditions and discretize structure
    # --------------------------------------------------------------------------
    pml_layers = [mp.PML(pml_thickness)]
    resolution = pixel * (n1 if n1 > n2 else n2) * freq
    # set Courant factor (mandatory if either n1 or n2 is smaller than 1)
    Courant = (n1 if n1 < n2 else n2) / 2

    # --------------------------------------------------------------------------
    # beam profile distribution (field amplitude) at the waist of the beam
    # --------------------------------------------------------------------------
    def Gauss(r, params):
        """Gauss profile."""
        W_y = params['W_y']

        return math.exp(-(r.y / W_y)**2)

    # --------------------------------------------------------------------------
    # spectrum amplitude distribution
    # --------------------------------------------------------------------------
    def f_Gauss(k_y, params):
        """Gaussian spectrum amplitude."""
        W_y = params['W_y']

        return math.exp(-(k_y*W_y/2)**2)

    if test_output:
        print("Gauss spectrum:", f_Gauss(0.2, params))

    # --------------------------------------------------------------------------
    # plane wave decomposition
    # (purpose: calculate field amplitude at light source position if not
    #           coinciding with beam waist)
    # --------------------------------------------------------------------------
    def psi(r, x, params):
        """Field amplitude function."""
        try:
            getattr(psi, "called")
        except AttributeError:
            psi.called = True
            print("Calculating inital field configuration. "
                  "This will take some time...")

        def phase(k_y, x, y):
            """Phase function."""
            return x*math.sqrt(k1**2 - k_y**2) + k_y*y

        try:
            (result,
             real_tol,
             imag_tol) = complex_quad(lambda k_y:
                                      f_Gauss(k_y, params) *
                                      cmath.exp(1j*phase(k_y, x, r.y)),
                                      -k1, k1)
        except Exception as e:
            print(type(e).__name__ + ":", e)
            sys.exit()

        return result

    # --------------------------------------------------------------------------
    # some test outputs (uncomment if needed)
    # --------------------------------------------------------------------------
    if test_output:
        x, y, z = -2.15, 0.3, 0.5
        r = mp.Vector3(0, y, z)

        print()
        print("psi :", psi(r, x, params))
        sys.exit()

    # --------------------------------------------------------------------------
    # display values of physical variables
    # --------------------------------------------------------------------------
    print()
    print("Specified variables and derived values:")
    print("n1:", n1)
    print("n2:", n2)
    print("chi:  ", chi_deg, " [degree]")
    print("incl.:", 90 - chi_deg, " [degree]")
    print("kw_0: ", kw_0)
    if interface != "planar":
        print("kr_c: ", kr_c)
    print("kr_w: ", kr_w)
    print("k_vac:", k_vac)
    print("polarisation:", "s" if s_pol else "p")
    print("interface:", interface)
    print()

    # --------------------------------------------------------------------------
    # specify current source, output functions and run simulation
    # --------------------------------------------------------------------------
    force_complex_fields = False          # default: False
    eps_averaging = True                  # default: True
    filename_prefix = None

    sources = [mp.Source(src=mp.ContinuousSource(frequency=freq, width=0.5),
                         component=mp.Ez if s_pol else mp.Ey,
                         size=mp.Vector3(0, 2, 0),
                         center=mp.Vector3(source_shift, 0, 0),
                         #amp_func=lambda r: Gauss(r, params)
                         amp_func=lambda r: psi(r, shift, params)
                         )
               ]

    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        default_material=default_material,
                        Courant=Courant,
                        geometry=geometry,
                        sources=sources,
                        resolution=resolution,
                        force_complex_fields=force_complex_fields,
                        eps_averaging=eps_averaging,
                        filename_prefix=filename_prefix
                        )

    sim.use_output_directory(interface)  # put output files in a separate folder

    def eSquared(r, ex, ey, ez):
        """Calculate |E|^2.

        With |.| denoting the complex modulus if 'force_complex_fields?'
        is set to true, otherwise |.| gives the Euclidean norm.
        """
        return mp.Vector3(ex, ey, ez).norm()**2

    def output_efield2(sim):
        """Output E-field intensity."""
        name = "e2_s" if s_pol else "e2_p"
        func = eSquared
        cs = [mp.Ex, mp.Ey, mp.Ez]
        return sim.output_field_function(name, cs, func, real_only=True)

    sim.run(mp.at_beginning(mp.output_epsilon),
            mp.at_end(mp.output_efield_z if s_pol else mp.output_efield_y),
            mp.at_end(output_efield2),
            until=runtime)

    print("\nend time:", datetime.now())
Пример #34
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()
Пример #35
0
pml_layers = [mp.PML(1.0)]

force_complex_fields = True  # so we can get time-average flux

resolution = 10

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

sim.run(
    mp.at_beginning(mp.output_epsilon),
    mp.at_end(mp.output_png(mp.Ez, "-a yarg -A $EPS -S3 -Zc dkbluered", rm_h5=False)),
    until=200
)

flux1 = sim.flux_in_box(mp.X, mp.Volume(center=mp.Vector3(-6.0), size=mp.Vector3(1.8, 6)))
flux2 = sim.flux_in_box(mp.X, mp.Volume(center=mp.Vector3(6.0), size=mp.Vector3(1.8, 6)))

# averaged over y region of width 1.8
print("left-going flux = {}".format(flux1 / -1.8))

# averaged over y region of width 1.8
print("right-going flux = {}".format(flux2 / 1.8))
Пример #36
0
 def test_extra_materials(self):
     sim = self.init_simple_simulation()
     sim.extra_materials = [mp.Medium(epsilon=5), mp.Medium(epsilon=10)]
     sim.run(mp.at_end(lambda sim: None), until=5)
Пример #37
0
pml_layers = [mp.PML(1.0)]

force_complex_fields = True  # so we can get time-average flux

resolution = 10

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

sim.run(mp.at_beginning(mp.output_epsilon),
        mp.at_end(
            mp.output_png(mp.Ez,
                          "-a yarg -A $EPS -S3 -Zc dkbluered",
                          rm_h5=False)),
        until=200)

flux1 = sim.flux_in_box(
    mp.X, mp.Volume(center=mp.Vector3(-6.0), size=mp.Vector3(1.8, 6)))
flux2 = sim.flux_in_box(
    mp.X, mp.Volume(center=mp.Vector3(6.0), size=mp.Vector3(1.8, 6)))

# averaged over y region of width 1.8
print("left-going flux = {}".format(flux1 / -1.8))

# averaged over y region of width 1.8
print("right-going flux = {}".format(flux2 / 1.8))
Пример #38
0
 def test_pw_source(self):
     self.sim.run(mp.at_end(mp.output_efield_z), until=400)
Пример #39
0
    return _pw_amp


fcen = 0.8  # pulse center frequency
df = 0.02  # turn-on bandwidth
kdir = mp.Vector3(1, 1)  # direction of k (length is irrelevant)
n = 1  # refractive index of material containing the source
k = kdir.unit().scale(2 * math.pi * fcen * n)  # k with correct length

sources = [
    mp.Source(mp.ContinuousSource(fcen, fwidth=df),
              component=mp.Ez,
              center=mp.Vector3(-0.5 * s, 0),
              size=mp.Vector3(0, s),
              amp_func=pw_amp(k, mp.Vector3(x=-0.5 * s))),
    mp.Source(mp.ContinuousSource(fcen, fwidth=df),
              component=mp.Ez,
              center=mp.Vector3(0, -0.5 * s),
              size=mp.Vector3(s, 0),
              amp_func=pw_amp(k, mp.Vector3(y=-0.5 * s)))
]

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

t = 400  # run time
sim.run(mp.at_end(mp.output_efield_z), until=t)
Пример #40
0
def main(args):
    print("\nstart time:", datetime.now())

    # --------------------------------------------------------------------------
    # physical parameters characterizing light source and interface characteris-
    # tics (must be adjusted - eihter here or via command line interface (CLI))
    # --------------------------------------------------------------------------
    s_pol = args.s_pol
    ref_medium = args.ref_medium

    n1 = args.n1
    n2 = args.n2

    kw_0 = args.kw_0
    kr_w = args.kr_w

    # Airy beam parameters
    M = args.M
    W = args.W

    # angle of incidence
    chi_deg = args.chi_deg
    #chi_deg = 1.0*op.critical(n1, n2)
    #chi_deg = 0.95*op.brewster(n1, n2)

    # --------------------------------------------------------------------------
    # specific Meep parameters (may need to be adjusted)
    # --------------------------------------------------------------------------
    sx = 10  # size of cell including PML in x-direction
    sy = 10  # size of cell including PML in y-direction
    pml_thickness = 0.25  # thickness of PML layer
    freq = 12  # vacuum frequency of source (4 to 12 is good)
    runtime = 90  # runs simulation for X times freq periods

    # number of pixels per wavelength in the denser medium (at least 10,
    # 20 to 30 is a good choice)
    pixel = 15

    # source position with respect to the center (point of impact) in Meep
    # units (-2.15 good); if equal -r_w, then source position coincides with
    # waist position
    #source_shift = 0
    source_shift = -0.4 * (sx - 2 * pml_thickness)

    # --------------------------------------------------------------------------
    # derived (Meep) parameters (do not change)
    # --------------------------------------------------------------------------
    k_vac = 2 * math.pi * freq
    k1 = n1 * k_vac
    n_ref = (1 if ref_medium == 0 else
             n1 if ref_medium == 1 else n2 if ref_medium == 2 else math.nan)
    r_w = kr_w / (n_ref * k_vac)
    w_0 = kw_0 / (n_ref * k_vac)
    shift = source_shift + r_w
    chi_rad = math.radians(chi_deg)

    params = dict(W_y=w_0, k=k1, M=M, W=W)

    # --------------------------------------------------------------------------
    # placement of the dielectric interface within the computational cell
    # --------------------------------------------------------------------------
    # helper functions
    def alpha(chi_rad):
        """Angle of inclined plane with y-axis in radians."""
        return math.pi / 2 - chi_rad

    def Delta_x(alpha):
        """Inclined plane offset to the center of the cell."""
        sin_alpha = math.sin(alpha)
        cos_alpha = math.cos(alpha)
        return (sx / 2) * ((
            (math.sqrt(2) - cos_alpha) - sin_alpha) / sin_alpha)

    cell = mp.Vector3(sx, sy, 0)  # geometry-lattice
    default_material = mp.Medium(index=n1)
    geometry = [
        mp.Block(mp.Vector3(mp.inf, sx * math.sqrt(2), mp.inf),
                 center=mp.Vector3(+sx / 2 + Delta_x(alpha(chi_rad)), -sy / 2),
                 e1=mp.Vector3(1 / math.tan(alpha(chi_rad)), 1, 0),
                 e2=mp.Vector3(-1, 1 / math.tan(alpha(chi_rad)), 0),
                 e3=mp.Vector3(0, 0, 1),
                 material=mp.Medium(index=n2))
    ]

    # --------------------------------------------------------------------------
    # add absorbing boundary conditions and discretize structure
    # --------------------------------------------------------------------------
    pml_layers = [mp.PML(pml_thickness)]
    resolution = pixel * (n1 if n1 > n2 else n2) * freq
    # set Courant factor (mandatory if either n1 or n2 is smaller than 1)
    Courant = (n1 if n1 < n2 else n2) / 2

    # --------------------------------------------------------------------------
    # display values of physical variables
    # --------------------------------------------------------------------------
    print()
    print("Specified variables and derived values:")
    print("n1:", n1)
    print("n2:", n2)
    print("chi:  ", chi_deg, " [degree]")
    print("incl.:", 90 - chi_deg, " [degree]")
    print("kw_0: ", kw_0)
    print("kr_w: ", kr_w)
    print("k_vac:", k_vac)
    print("polarisation:", "s" if s_pol else "p")
    print()

    # --------------------------------------------------------------------------
    # specify current source, output functions and run simulation
    # --------------------------------------------------------------------------
    force_complex_fields = False  # default: False
    eps_averaging = True  # default: True
    filename_prefix = None

    # specify optical beam
    beam = op.IncAiry2d(x=shift, params=params)

    sources = [
        mp.Source(src=mp.ContinuousSource(frequency=freq, width=0.5),
                  component=mp.Ez if s_pol else mp.Ey,
                  size=mp.Vector3(0, 9, 0),
                  center=mp.Vector3(source_shift, 0, 0),
                  amp_func=beam.profile)
    ]

    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        default_material=default_material,
                        Courant=Courant,
                        geometry=geometry,
                        sources=sources,
                        resolution=resolution,
                        force_complex_fields=force_complex_fields,
                        eps_averaging=eps_averaging,
                        filename_prefix=filename_prefix)

    sim.use_output_directory()  # put output files in a separate folder

    def eSquared(r, ex, ey, ez):
        """Calculate |E|^2.

        With |.| denoting the complex modulus if 'force_complex_fields?'
        is set to true, otherwise |.| gives the Euclidean norm.
        """
        return mp.Vector3(ex, ey, ez).norm()**2

    def output_efield2(sim):
        """Output E-field intensity."""
        name = "e2_s" if s_pol else "e2_p"
        func = eSquared
        cs = [mp.Ex, mp.Ey, mp.Ez]
        return sim.output_field_function(name, cs, func, real_only=True)

    sim.run(mp.at_beginning(mp.output_epsilon),
            mp.at_end(mp.output_efield_z if s_pol else mp.output_efield_y),
            mp.at_end(output_efield2),
            until=runtime)

    print("\nend time:", datetime.now())
Пример #41
0
 def test_extra_materials(self):
     sim = self.init_simple_simulation()
     sim.extra_materials = [mp.Medium(epsilon=5), mp.Medium(epsilon=10)]
     sim.run(mp.at_end(lambda sim: None), until=5)