Пример #1
0
    def test_resonant_modes(self):
        self.sim.sources = [mp.Source(mp.GaussianSource(self.fcen, fwidth=self.df),
                                      mp.Hz, mp.Vector3())]

        self.sim.symmetries = [mp.Mirror(mp.Y, phase=-1),
                               mp.Mirror(mp.X, phase=-1)]

        h = mp.Harminv(mp.Hz, mp.Vector3(), self.fcen, self.df)
        self.sim.run(mp.at_beginning(mp.output_epsilon),
                     mp.after_sources(h),
                     until_after_sources=400)

        expected = [
            0.23445415346009466,
            -3.147812367338531e-4,
            372.40808234438254,
            5.8121430334347135,
            -3.763107485715599,
            -4.429450156854109,
        ]

        m = h.modes[0]
        res = [m.freq, m.decay, m.Q, abs(m.amp), m.amp.real, m.amp.imag]

        np.testing.assert_allclose(expected, res)
Пример #2
0
    def test_resonant_modes(self):
        self.sim.sources = [
            mp.Source(mp.GaussianSource(self.fcen, fwidth=self.df), mp.Hz,
                      mp.Vector3())
        ]

        self.sim.symmetries = [
            mp.Mirror(mp.Y, phase=-1),
            mp.Mirror(mp.X, phase=-1)
        ]

        h = mp.Harminv(mp.Hz, mp.Vector3(), self.fcen, self.df)
        self.sim.run(mp.at_beginning(mp.output_epsilon),
                     mp.after_sources(h),
                     until_after_sources=400)

        expected = [
            0.23445415346009466,
            -3.147812367338531e-4,
            372.40808234438254,
            5.8121430334347135,
            -3.763107485715599,
            -4.429450156854109,
        ]

        m = h.modes[0]
        res = [m.freq, m.decay, m.Q, abs(m.amp), m.amp.real, m.amp.imag]

        np.testing.assert_allclose(expected, res)
Пример #3
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()))
Пример #4
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()))
Пример #5
0
def main(args):

    n = 3.4  # index of waveguide
    w = 1  # width of waveguide
    r = 1  # inner radius of ring
    pad = 4  # padding between waveguide and edge of PML
    dpml = 32  # thickness of PML

    sr = r + w + pad + dpml  # radial size (cell is from 0 to sr)
    dimensions = mp.CYLINDRICAL
    cell = mp.Vector3(sr, 0, 0)

    # in cylindrical coordinates, the phi (angular) dependence of the fields
    # is given by exp(i m phi), where m is given by:
    m = args.m

    geometry = [
        mp.Block(center=mp.Vector3(r + (w / 2)),
                 size=mp.Vector3(w, 1e20, 1e20),
                 material=mp.Medium(index=n))
    ]

    pml_layers = [mp.PML(dpml)]
    resolution = 20

    # If we don't want to excite a specific mode symmetry, we can just
    # put a single point source at some arbitrary place, pointing in some
    # arbitrary direction.  We will only look for TM modes (E out of the plane).

    fcen = args.fcen  # pulse center frequency
    df = args.df  # pulse frequency width
    sources = [
        mp.Source(src=mp.GaussianSource(fcen, fwidth=df),
                  component=mp.Ez,
                  center=mp.Vector3(r + 0.1))
    ]

    # note that the r -> -r mirror symmetry is exploited automatically

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

    sim.run(mp.after_sources(mp.Harminv(mp.Ez, mp.Vector3(r + 0.1), fcen, df)),
            until_after_sources=200)

    # Output fields for one period at the end.  (If we output
    # at a single time, we might accidentally catch the Ez field when it is
    # almost zero and get a distorted view.)  We'll append the fields
    # to a file to get an r-by-t picture.  We'll also output from -sr to -sr
    # instead of from 0 to sr.
    sim.run(mp.in_volume(
        mp.Volume(center=mp.Vector3(), size=mp.Vector3(2 * sr)),
        mp.at_beginning(mp.output_epsilon),
        mp.to_appended("ez", mp.at_every(1 / fcen / 20, mp.output_efield_z))),
            until=1 / fcen)
Пример #6
0
    def empty_run(self, sx, sy, animate=False):

        sources, refl_fr, trans_fr = self.set_source(sx, sy)

        sim = mp.Simulation(cell_size=mp.Vector3(sx, sy, self.sz),
                            geometry=[],
                            sources=sources,
                            boundary_layers=self.pml_layers,
                            k_point=self.k,
                            resolution=self.resolution)

        refl = sim.add_flux(self.fcen, self.df, self.nfreq, refl_fr)

        trans = sim.add_flux(self.fcen, self.df, self.nfreq, trans_fr)

        if animate:
            sim.run(mp.at_beginning(mp.output_epsilon),
                    mp.to_appended("ex", mp.at_every(0.6, mp.output_efield_z)),
                    until_after_sources=mp.stop_when_fields_decayed(25, mp.Ey, self.pt, 1e-3))
        else:
            sim.run(until_after_sources=mp.stop_when_fields_decayed(25, mp.Ey, self.pt, 1e-3))

        # for normalization run, save flux fields data for reflection plane
        self.store['straight_refl_data'] = sim.get_flux_data(refl)

        # save incident power for transmission plane
        self.store['flux_freqs'] = mp.get_flux_freqs(refl)
        self.store['straight_tran_flux'] = mp.get_fluxes(trans)
        self.store['straight_refl_flux'] = mp.get_fluxes(refl)
Пример #7
0
 def get_step_funcs(self):
     sf = {self._get_meep_output_comp(f) for f in self.static_fields}
     sf = (mp.at_beginning(f) for f in sf)
     df = {self._get_meep_output_comp(f) for f in self.dynamic_fields}
     df = (mp.at_every(self.dt, f) for f in df)
     volume = mp.in_volume(mp.Volume(center=self.size / 2, size=self.size))
     fields = mp.with_prefix(f'{results_dir}/', *sf, *df)
     return volume, fields
Пример #8
0
def main(args):

    n = 3.4     # index of waveguide
    w = 1       # width of waveguide
    r = 1       # inner radius of ring
    pad = 4     # padding between waveguide and edge of PML
    dpml = 32    # thickness of PML

    sr = r + w + pad + dpml  # radial size (cell is from 0 to sr)
    dimensions = mp.CYLINDRICAL
    cell = mp.Vector3(sr, 0, 0)

    # in cylindrical coordinates, the phi (angular) dependence of the fields
    # is given by exp(i m phi), where m is given by:
    m = args.m

    geometry = [mp.Block(center=mp.Vector3(r + (w / 2)),
                         size=mp.Vector3(w, mp.inf, mp.inf),
                         material=mp.Medium(index=n))]

    pml_layers = [mp.PML(dpml)]
    resolution = 20

    # If we don't want to excite a specific mode symmetry, we can just
    # put a single point source at some arbitrary place, pointing in some
    # arbitrary direction.  We will only look for Ez-polarized modes.

    fcen = args.fcen  # pulse center frequency
    df = args.df      # pulse frequency width
    sources = [mp.Source(src=mp.GaussianSource(fcen, fwidth=df),
                         component=mp.Ez,
                         center=mp.Vector3(r + 0.1))]

    # note that the r -> -r mirror symmetry is exploited automatically

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

    sim.run(mp.after_sources(mp.Harminv(mp.Ez, mp.Vector3(r + 0.1), fcen, df)),
            until_after_sources=200)

    # Output fields for one period at the end.  (If we output
    # at a single time, we might accidentally catch the Ez field when it is
    # almost zero and get a distorted view.)  We'll append the fields
    # to a file to get an r-by-t picture.  We'll also output from -sr to -sr
    # instead of from 0 to sr.
    sim.run(mp.in_volume(mp.Volume(center=mp.Vector3(), size=mp.Vector3(2 * sr)),
                         mp.at_beginning(mp.output_epsilon),
                         mp.to_appended("ez", mp.at_every(1 / fcen / 20, mp.output_efield_z))),
            until=1 / fcen)
Пример #9
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")
Пример #10
0
def main():
    # Some parameters to describe the geometry:
    eps = 13  # dielectric constant of waveguide
    w = 1.2  # width of waveguide
    r = 0.36  # radius of holes

    # The cell dimensions
    sy = 12  # size of cell in y direction (perpendicular to wvg.)
    dpml = 1  # PML thickness (y direction only!)

    cell = mp.Vector3(1, sy)

    b = mp.Block(size=mp.Vector3(mp.inf, w, mp.inf),
                 material=mp.Medium(epsilon=eps))
    c = mp.Cylinder(radius=r)

    fcen = 0.25  # pulse center frequency
    df = 1.5  # pulse freq. width: large df = short impulse

    s = mp.Source(src=mp.GaussianSource(fcen, fwidth=df),
                  component=mp.Hz,
                  center=mp.Vector3(0.1234))

    sym = mp.Mirror(direction=mp.Y, phase=-1)

    sim = mp.Simulation(cell_size=cell,
                        geometry=[b, c],
                        sources=[s],
                        symmetries=[sym],
                        boundary_layers=[mp.PML(dpml, direction=mp.Y)],
                        resolution=20)

    kx = False  # if true, do run at specified kx and get fields
    k_interp = 19  # # k-points to interpolate, otherwise

    if kx:
        sim.k_point = mp.Vector3(kx)

        sim.run(mp.at_beginning(mp.output_epsilon),
                mp.after_sources(
                    mp.Harminv(mp.Hz, mp.Vector3(0.1234), fcen, df)),
                until_after_sources=300)

        sim.run(mp.at_every(1 / fcen / 20, mp.output_hfield_z), until=1 / fcen)

    else:
        sim.run_k_points(
            300, mp.interpolate(k_interp,
                                [mp.Vector3(), mp.Vector3(0.5)]))
Пример #11
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")
Пример #12
0
    def test_harminv(self):
        self.init()

        self.sim.run(
            mp.at_beginning(mp.output_epsilon),
            mp.after_sources(self.h),
            until_after_sources=300
        )
        m1, m2, m3 = self.h.modes

        self.assertAlmostEqual(m1.freq, 0.118101315147, places=4)
        self.assertAlmostEqual(m1.decay, -0.000731513241623, places=4)
        self.assertAlmostEqual(abs(m1.amp), 0.00341267634436, places=4)
        self.assertAlmostEqual(m1.amp.real, -0.00304951667301, places=4)
        self.assertAlmostEqual(m1.amp.imag, -0.00153192946717, places=4)

        fp = self.sim.get_field_point(mp.Ez, mp.Vector3(1, 1))
        self.assertAlmostEqual(fp, -0.08185972142450348)
Пример #13
0
def do_simrun(base_refl_data=None, do_live=True, geo=None, **kwargs):
    sim = mp.Simulation(progress_interval=1e6 if do_live else 4,
                        **sim_kwargs(geo=geo, **kwargs))
    sim.reset_meep()

    # Now put in some flux monitors. Make sure the pulse source was selected
    refl, tran = add_monitors(sim)

    # for normal run, load negated fields to subtract incident from refl. fields
    if base_refl_data is not None:
        sim.load_minus_flux_data(refl, base_refl_data)

    run_args = (
        mp.at_beginning(livefield),
        mp.at_every(5, livefield),
    ) if do_live else tuple()
    t0 = time.time()
    sim.run(*run_args, **monitor_until(geo=geo, **kwargs))
    print('Realtime duration = {:.2f} seconds'.format(time.time() - t0))
    return sim, refl, tran
Пример #14
0
def main():
    n = 3.4  # index of waveguide
    w = 1  # width of waveguide
    r = 1  # inner radius of ring
    pad = 4  # padding between waveguide and edge of PML
    dpml = 2  # thickness of PML
    sxy = 2 * (r + w + pad + dpml)  # cell size

    # Create a ring waveguide by two overlapping cylinders - later objects
    # take precedence over earlier objects, so we put the outer cylinder first.
    # and the inner (air) cylinder second.

    c1 = mp.Cylinder(radius=r + w, material=mp.Medium(index=n))
    c2 = mp.Cylinder(radius=r)

    # If we don't want to excite a specific mode symmetry, we can just
    # put a single point source at some arbitrary place, pointing in some
    # arbitrary direction.  We will only look for Ez-polarized modes.

    fcen = 0.15  # pulse center frequency
    df = 0.1  # pulse width (in frequency)

    src = mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Ez, mp.Vector3(r + 0.1))

    sim = mp.Simulation(cell_size=mp.Vector3(sxy, sxy),
                        geometry=[c1, c2],
                        sources=[src],
                        resolution=10,
                        symmetries=[mp.Mirror(mp.Y)],
                        boundary_layers=[mp.PML(dpml)])

    sim.run(
        mp.at_beginning(mp.output_epsilon),
        mp.after_sources(mp.Harminv(mp.Ez, mp.Vector3(r + 0.1), fcen, df)),
        until_after_sources=300
    )

    # Output fields for one period at the end.  (If we output
    # at a single time, we might accidentally catch the Ez field when it is
    # almost zero and get a distorted view.)
    sim.run(mp.at_every((1 / fcen / 20), mp.output_efield_z), until=(1 / fcen))
Пример #15
0
    def test_harminv(self):
        self.init()

        self.sim.run(mp.at_beginning(mp.output_epsilon),
                     mp.after_sources(self.h),
                     until_after_sources=300)

        m1 = self.h.modes[0]

        self.assertAlmostEqual(m1.freq, 0.118101315147, places=4)
        self.assertAlmostEqual(m1.decay, -0.000731513241623, places=4)
        self.assertAlmostEqual(abs(m1.amp), 0.00341267634436, places=4)
        self.assertAlmostEqual(m1.amp.real, -0.00304951667301, places=4)
        self.assertAlmostEqual(m1.amp.imag, -0.00153192946717, places=3)

        v = mp.Vector3(1, 1)
        fp = self.sim.get_field_point(mp.Ez, v)
        ep = self.sim.get_epsilon_point(v)

        places = 5 if mp.is_single_precision() else 7
        self.assertAlmostEqual(ep, 11.559999999999999, places=places)
        self.assertAlmostEqual(fp, -0.08185972142450348, places=places)
Пример #16
0
def main():
    n = 3.4                 # index of waveguide
    w = 1                   # width of waveguide
    r = 1                   # inner radius of ring
    pad = 4                 # padding between waveguide and edge of PML
    dpml = 2                # thickness of PML
    sxy = 2*(r+w+pad+dpml)  # cell size

    # Create a ring waveguide by two overlapping cylinders - later objects
    # take precedence over earlier objects, so we put the outer cylinder first.
    # and the inner (air) cylinder second.

    c1 = mp.Cylinder(radius=r+w, material=mp.Medium(index=n))
    c2 = mp.Cylinder(radius=r)

    # If we don't want to excite a specific mode symmetry, we can just
    # put a single point source at some arbitrary place, pointing in some
    # arbitrary direction.  We will only look for Ez-polarized modes.

    fcen = 0.15             # pulse center frequency
    df = 0.1                # pulse width (in frequency)

    src = mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Ez, mp.Vector3(r+0.1))

    sim = mp.Simulation(cell_size=mp.Vector3(sxy, sxy),
                        geometry=[c1, c2],
                        sources=[src],
                        resolution=10,
                        symmetries=[mp.Mirror(mp.Y)],
                        boundary_layers=[mp.PML(dpml)])

    sim.run(mp.at_beginning(mp.output_epsilon),
            mp.after_sources(mp.Harminv(mp.Ez, mp.Vector3(r+0.1), fcen, df)),
            until_after_sources=300)

    # Output fields for one period at the end.  (If we output
    # at a single time, we might accidentally catch the Ez field when it is
    # almost zero and get a distorted view.)
    sim.run(mp.at_every(1/fcen/20, mp.output_efield_z), until=1/fcen)
Пример #17
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"))
Пример #18
0
def main(args):
    resolution = 20      # pixels/um
    eps = 13             # epsilon of waveguide
    w = 1.2              # width of the  waveguide
    dpml = 1             # PML thickness
    largC = 16           # largura da celula
    altC = 16            # altura da celula

    sx = largC + dpml
    sy = altC + dpml

    fcen = args.fcen     # pulse centger frequency
    df = args.df         # pulse frequency width


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


    def epsP(p):
       valorIm = -0.5 + math.pow(math.cos((p.y)*(2*math.pi/(altC/4))),2)
       return mp.Medium(epsilon=3, D_conductivity=2*math.pi*fcen*(valorIm)/3)
    epsP.do_averaging = True



    blk = mp.Block(size=mp.Vector3(mp.inf,mp.inf,mp.inf), material=mp.Medium(epsilon=eps))
    geometry = [blk]



#    AQUI ESTÁ A LINHA DE TESTE: USAMOS A FUNCAO PARA DEFINIR O EPSILON
#    geometry.append(mp.Block(size=mp.Vector3(mp.inf,w,mp.inf)))
    geometry.append(mp.Block(center=mp.Vector3(),size=mp.Vector3(mp.inf,altC,mp.inf),material=epsP))




    pml_layers = [mp.PML(1.0)]


    src = [mp.Source(mp.GaussianSource(fcen, fwidth=df),
                     component=mp.Ey,
                     center=mp.Vector3(-0.5*sx+dpml), # fonte na esquerda; para colocar na direita usar 0.5*sx - dpml
                     size=mp.Vector3(0,w))]


    sim = mp.Simulation(cell_size=cell,
                        geometry=geometry,
                        boundary_layers=pml_layers,
                        sources=src,                 #symmetries=sym,
                        resolution=resolution)


    sim.run(mp.at_beginning(mp.output_epsilon),
            mp.to_appended("hz",mp.at_every(0.4,mp.output_hfield_z)),
            until=300)



    epsilon0 = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Dielectric)
    plt.figure()
    plt.imshow(epsilon0.transpose(), interpolation='spline36', cmap='RdBu')
    plt.axis('off')
    plt.savefig('epsilon.png',format='png')
    plt.show()
Пример #19
0
results_plane = []
results_line = []

def get_slice_plane(sim):
    results_plane.append(sim.get_array(
        center=mp.Vector3(*plane_center), 
        size=mp.Vector3(*plane_size), 
        component=mp.Ez))

def get_slice_line(sim):
    results_line.append(sim.get_array(
        center=mp.Vector3(*line_center), 
        size=mp.Vector3(*line_size), 
        component=mp.Ez))

to_do_while_running = [mp.at_beginning(get_slice_line),
                       mp.at_beginning(get_slice_plane),
                       mp.at_every(period_line, get_slice_line),
                       mp.at_every(period_plane, get_slice_plane)]

#%% INITIALIZE

sim.reset_meep()

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

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

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

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

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

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

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

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

    return (get)
Пример #21
0
def main(args):
    resolution = 20 # pixels/um
    
    eps = 13      # dielectric constant of waveguide
    w = 1.2       # width of waveguide
    r = 0.36      # radius of holes
    d = 1.4       # defect spacing (ordinary spacing = 1)
    N = args.N    # number of holes on either side of defect

    sy = args.sy  # size of cell in y direction (perpendicular to wvg.)
    pad = 2       # padding between last hole and PML edge
    dpml = 1      # PML thickness

    sx = 2*(pad+dpml+N)+d-1  # size of cell in x direction

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

    blk = mp.Block(size=mp.Vector3(mp.inf,w,mp.inf),
                   material=mp.Medium(epsilon=eps))

    geometry = [blk]

    for i in range(N):
        geometry.append(mp.Cylinder(r, center=mp.Vector3(d/2+i)))
        geometry.append(mp.Cylinder(r, center=mp.Vector3(-(d/2+i))))

    fcen = args.fcen  # pulse center frequency
    df = args.df      # pulse frequency width
    nfreq = 500       # number of frequencies at which to compute flux

    sim = mp.Simulation(cell_size=cell,
                        geometry=geometry,
                        sources=[],
                        boundary_layers=[mp.PML(dpml)],
                        resolution=20)

    if args.resonant_modes:
        sim.sources.append(mp.Source(mp.GaussianSource(fcen, fwidth=df),
                                     component=mp.Hz,
                                     center=mp.Vector3()))

        sim.symmetries.append(mp.Mirror(mp.Y, phase=-1))
        sim.symmetries.append(mp.Mirror(mp.X, phase=-1))

        sim.run(mp.at_beginning(mp.output_epsilon),
                mp.after_sources(mp.Harminv(mp.Hz, mp.Vector3(), fcen, df)),
                until_after_sources=400)

        sim.run(mp.at_every(1/fcen/20, mp.output_hfield_z), until=1/fcen)
    else:
        sim.sources.append(mp.Source(mp.GaussianSource(fcen, fwidth=df),
                                     component=mp.Ey,
                                     center=mp.Vector3(-0.5*sx+dpml),
                                     size=mp.Vector3(0,w)))

        sim.symmetries.append(mp.Mirror(mp.Y, phase=-1))

        freg = mp.FluxRegion(center=mp.Vector3(0.5*sx-dpml-0.5),
                             size=mp.Vector3(0,2*w))

        # transmitted flux
        trans = sim.add_flux(fcen, df, nfreq, freg)

        vol = mp.Volume(mp.Vector3(), size=mp.Vector3(sx))

        sim.run(mp.at_beginning(mp.output_epsilon),
                mp.during_sources(mp.in_volume(vol, mp.to_appended("hz-slice", mp.at_every(0.4, mp.output_hfield_z)))),
                until_after_sources=mp.stop_when_fields_decayed(50, mp.Ey, mp.Vector3(0.5*sx-dpml-0.5), 1e-3))

        sim.display_fluxes(trans)  # print out the flux spectrum
Пример #22
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"))
Пример #23
0
def main(args):
    # Some parameters to describe the geometry:
    eps = 13  # dielectric constant of waveguide
    w = 1.2  # width of waveguide
    r = 0.36  # radius of holes
    d = 1.4  # defect spacing (ordinary spacing = 1)
    N = args.N  # number of holes on either side of defect

    # The cell dimensions
    sy = args.sy  # size of cell in y direction (perpendicular to wvg.)
    pad = 2  # padding between last hole and PML edge
    dpml = 1  # PML thickness

    sx = 2 * (pad + dpml + N) + d - 1  # size of cell in x direction

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

    blk = mp.Block(size=mp.Vector3(mp.inf, w, mp.inf),
                   material=mp.Medium(epsilon=eps))

    geometry = [blk]

    for i in range(N):
        geometry.append(mp.Cylinder(r, center=mp.Vector3(d / 2 + i)))
        geometry.append(mp.Cylinder(r, center=mp.Vector3(-(d / 2 + i))))

    fcen = args.fcen  # pulse center frequency
    df = args.df  # pulse frequency width

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

    sim = mp.Simulation(cell_size=cell,
                        geometry=geometry,
                        sources=[],
                        boundary_layers=[mp.PML(dpml)],
                        resolution=20)

    if args.resonant_modes:
        sim.sources.append(
            mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Hz, mp.Vector3()))

        sim.symmetries.append(mp.Mirror(mp.Y, phase=-1))
        sim.symmetries.append(mp.Mirror(mp.X, phase=-1))

        sim.run(  # mp.at_beginning(mp.output_epsilon),
            mp.after_sources(mp.Harminv(mp.Hz, mp.Vector3(), fcen, df)),
            until_after_sources=400)

        # sim.run(mp.at_every(1 / fcen / 20, mp.output_hfield_z), until=1 / fcen)

    else:
        sim.sources.append(
            mp.Source(mp.GaussianSource(fcen, fwidth=df),
                      mp.Ey,
                      mp.Vector3(dpml + (-0.5 * sx)),
                      size=mp.Vector3(0, w)))

        sim.symmetries.append(mp.Mirror(mp.Y, phase=-1))

        freg = mp.FluxRegion(center=mp.Vector3((0.5 * sx) - dpml - 0.5),
                             size=mp.Vector3(0, 2 * w))

        # transmitted flux
        trans = sim.add_flux(fcen, df, nfreq, freg)

        vol = mp.Volume(mp.Vector3(), size=mp.Vector3(sx))

        sim.run(mp.at_beginning(mp.output_epsilon),
                mp.during_sources(
                    mp.in_volume(
                        vol,
                        mp.to_appended("hz-slice",
                                       mp.at_every(0.4, mp.output_hfield_z)))),
                until_after_sources=mp.stop_when_fields_decayed(
                    50, mp.Ey, mp.Vector3((0.5 * sx) - dpml - 0.5, 0), 1e-3))

        sim.display_fluxes(trans)  # print out the flux spectrum
Пример #24
0
def generate_model(params, args):

    
    cell = mp.Vector3(params.cell_width, params.cell_height, 0)

    spheres = mplib.geo2D_spherical_pc(params.ps_n, params.si_n,
                                       params.ps_thickness, params.si_thickness, params.cell_height, params.num_layers,
                                       params.cell_width/2-200, params.sph_radius,
                                       params.sph_spacing, params.offset, params.xoffset)

    thin_film = mplib.geo2D_thin_film(params.ps_n, params.ps_thickness, params.cell_height,
                                      params.cell_width/2-100)

    pc_ideal = mplib.geo2D_photonic_crystal(params.ps_n, params.other_n,
                                            params.ps_thickness, params.cell_height,
                                            params.si_thickness, params.si_n,
                                            5, params.cell_width/2-200, 50)

    


    geometry = pc_ideal
    
    if args.background:
        geometry = []


    ## Gaussian source
    source_pos = -1*params.cell_width/2 + params.dpml+5
    sources = [mp.Source(mp.GaussianSource(frequency=params.freq, fwidth=params.df),
                         mp.Ez, center=mp.Vector3(source_pos,0,0),
                         size=mp.Vector3(0,params.cell_height,0))]
    
    
    pml_layers = [mp.PML(params.dpml, direction=mp.X)]


    sim = mp.Simulation(cell_size = cell,
                        boundary_layers = pml_layers,
                        geometry = geometry,
                        filename_prefix=args.filename,
                        sources = sources,
                        k_point = mp.Vector3(0,0,0),
                        resolution = params.resolution)

    freg_trans = mp.FluxRegion(center = mp.Vector3(0.5*params.cell_width - params.dpml - 1,0,0),
                         size = mp.Vector3(0, params.cell_height, 0))

    freg_ref    = mp.FluxRegion(center = mp.Vector3(source_pos + 10, 0, 0),
                                size = mp.Vector3(0, params.cell_height), weight=1.0)


    trans_flux = sim.add_flux(params.freq, params.df , 500, freg_trans)
    ref_flux    = sim.add_flux(params.freq, params.df, 500, freg_ref)
    vol = mp.Volume(mp.Vector3(0), size = mp.Vector3(params.cell_width,0,0))

    if not args.reflectflux:
        sim.load_minus_flux("pulse_bg_flux_{:d}".format(params.wavelength),ref_flux)

    if args.outdir:
        print("Output directory: {:s}".format(args.outdir))
        sim.use_output_directory(args.outdir)

    if args.geometry:
        sim.run(mp.at_beginning(mp.output_epsilon),
                until=1)
    else:   
        sim.run(mp.at_beginning(mp.output_epsilon),
                mp.to_appended("ez", mp.at_every(params.dt, mp.output_efield_z)),
                #mp.to_appended("ep", mp.at_every(params.dt, mp.output_dpwr)),
                mp.in_volume(vol, mp.to_appended("ez_slice", mp.at_every(params.dt, mp.output_efield_z))),
                until=params.time)

    if args.reflectflux:
        sim.save_flux("pulse_bg_flux_{:d}".format(params.wavelength),ref_flux)
    
    #sim.save_flux("bg_flux_other", trans_flux)
    sim.display_fluxes(trans_flux, ref_flux)
Пример #25
0
import meep as mp

cell_size = mp.Vector3(6, 6, 0)

geometry1 = [
    mp.Cylinder(center=mp.Vector3(), radius=1.0, material=mp.Medium(index=3.5))
]

sim1 = mp.Simulation(cell_size=cell_size, geometry=geometry1, resolution=20)

sim1.init_sim()

geometry2 = [
    mp.Cylinder(center=mp.Vector3(1, 1),
                radius=1.0,
                material=mp.Medium(index=3.5))
]

sim2 = mp.Simulation(cell_size=cell_size, geometry=geometry2, resolution=20)

sim2.init_sim()

sim1.fields.phase_in_material(sim2.structure, 10.0)

sim1.run(mp.at_beginning(mp.output_epsilon),
         mp.at_every(0.5, mp.output_epsilon),
         until=10)
Пример #26
0
    def simulate(self, config):
        start = time.time()
        dpml = config["dpml"]
        resolution = config["resolution"]
        use_fixed_time = config["use_fixed_time"]
        simulation_time = config["simulation_time"]
        padding = config["padding"]
        ff_pts = config["ff_pts"]
        ff_cover = config["ff_cover"]
        ff_calc = config["ff_calc"]
        use_symmetries = config["use_symmetries"]
        calculate_flux = config["calculate_flux"]
        calculate_source_flux = config["calculate_source_flux"]
        pixels = config["source_flux_pixel_size"]
        ff_calculations = config["ff_calculations"]
        ff_angle = math.pi / config["ff_angle"]
        FibonacciSampling = config["fibb_sampling"]
        simulation_ratio = eval(config["simulation_ratio"])
        substrate_ratio = eval(config["substrate_ratio"])
        output_ff = config["output_ff"]
        polarization_in_plane = config["polarization_in_plane"]
        geometry = config["geometry"]
        material_function = config["material_function"]

        substrate_height = self.pyramid_height * substrate_ratio  #height of the substrate, measured as fraction of pyramid height
        #"Cell size"
        sx = self.pyramid_width * simulation_ratio  #size of the cell in xy-plane is measured as a fraction of pyramid width
        sy = sx
        sz = self.pyramid_height * simulation_ratio  #z-"height" of sim. cell measured as a fraction of pyramid height.
        sh = substrate_height
        sh = 0
        padding = padding  ##distance from pml_layers to flux regions so PML don't overlap flux regions
        cell = mp.Vector3(sx + 2 * dpml, sy + 2 * dpml, sz +
                          2 * dpml)  #size of the simulation cell in meep units

        if self.CL_material == "Au":
            CL_material = Au
        elif self.CL_material == "Ag":
            CL_material = Ag
        elif self.CL_material == "Ag_visible":
            CL_material = Ag_visible
        else:
            CL_material = GaN
        print('CL MATERIAL:', CL_material, self.CL_material)

        #Symmetries for the simulation
        def create_symmetry(self):
            if self.source_direction == mp.Ex or self.source_direction == [
                    1, 0, 0
            ]:
                symmetry = [mp.Mirror(mp.Y), mp.Mirror(mp.X, phase=-1)]
            elif self.source_direction == mp.Ey or self.source_direction == [
                    0, 1, 0
            ]:
                symmetry = [mp.Mirror(mp.X), mp.Mirror(mp.Y, phase=-1)]
            elif self.source_direction == mp.Ez or self.source_direction == [
                    0, 0, 1
            ]:
                symmetry = [mp.Mirror(mp.X), mp.Mirror(mp.Y)]
            else:
                symmetry = []
            return symmetry

#Flux regions to calculate the total flux emitted from the simulation

        def define_flux_regions(sx, sy, sz, padding):
            fluxregion = []
            fluxregion.append(
                mp.FluxRegion(  #region x to calculate flux from
                    center=mp.Vector3(sx / 2 - padding, 0, 0),
                    size=mp.Vector3(0, sy - padding * 2, sz - padding * 2),
                    direction=mp.X))

            fluxregion.append(
                mp.FluxRegion(  # region -x to calculate flux from
                    center=mp.Vector3(-sx / 2 + padding, 0, 0),
                    size=mp.Vector3(0, sy - padding * 2, sz - padding * 2),
                    direction=mp.X,
                    weight=-1))

            fluxregion.append(
                mp.FluxRegion(  #region y to calculate flux from
                    center=mp.Vector3(0, sy / 2 - padding, 0),
                    size=mp.Vector3(sx - padding * 2, 0, sz - padding * 2),
                    direction=mp.Y))

            fluxregion.append(
                mp.FluxRegion(  #region -y to calculate flux from
                    center=mp.Vector3(0, -sy / 2 + padding, 0),
                    size=mp.Vector3(sx - padding * 2, 0, sz - padding * 2),
                    direction=mp.Y,
                    weight=-1))

            fluxregion.append(
                mp.FluxRegion(  #z-bottom region to calculate flux from
                    center=mp.Vector3(0, 0, sz / 2 - padding),
                    size=mp.Vector3(sx - padding * 2, sy - padding * 2, 0),
                    direction=mp.Z))

            fluxregion.append(
                mp.FluxRegion(  #z-top region to calculate flux from
                    center=mp.Vector3(0, 0, -sz / 2 + padding),
                    size=mp.Vector3(sx - padding * 2, sy - padding * 2, 0),
                    direction=mp.Z,
                    weight=-1))
            return fluxregion


#Flux regions to calculate the far field flux

        def define_nearfield_regions(sx, sy, sz, sh, padding, ff_cover):
            nearfieldregions = []
            nfrAbove = []
            nfrBelow = []
            #if ff_calc == True:
            #If we wish to calculate the far-field above and below the pyramid
            #	if ff_calc == "Both":
            nfrAbove.append(
                mp.Near2FarRegion(center=mp.Vector3(sx / 2 - padding, 0,
                                                    -sh / 2),
                                  size=mp.Vector3(0, sy - padding * 2,
                                                  sz - sh - padding * 2),
                                  direction=mp.X))

            nfrAbove.append(
                mp.Near2FarRegion(center=mp.Vector3(-sx / 2 + padding, 0,
                                                    -sh / 2),
                                  size=mp.Vector3(0, sy - padding * 2,
                                                  sz - sh - padding * 2),
                                  direction=mp.X,
                                  weight=-1))

            nfrAbove.append(
                mp.Near2FarRegion(center=mp.Vector3(0, sy / 2 - padding,
                                                    -sh / 2),
                                  size=mp.Vector3(sx - padding * 2, 0,
                                                  sz - sh - padding * 2),
                                  direction=mp.Y))

            nfrAbove.append(
                mp.Near2FarRegion(center=mp.Vector3(0, -sy / 2 + padding,
                                                    -sh / 2),
                                  size=mp.Vector3(sx - padding * 2, 0,
                                                  sz - sh - padding * 2),
                                  direction=mp.Y,
                                  weight=-1))

            nfrAbove.append(
                mp.Near2FarRegion(  #nearfield -z. above pyramid.		
                    center=mp.Vector3(0, 0, -sz / 2 + padding),
                    size=mp.Vector3(sx - padding * 2, sy - padding * 2, 0),
                    direction=mp.Z,
                    weight=-1))

            #Far-field to calculate below transmissions
            nfrBelow.append(
                mp.Near2FarRegion(center=mp.Vector3(sx / 2 - padding, 0,
                                                    sz / 2 - sh / 2),
                                  size=mp.Vector3(0, sy - padding * 2,
                                                  sh - padding * 2),
                                  direction=mp.X))

            nfrBelow.append(
                mp.Near2FarRegion(center=mp.Vector3(-sx / 2 + padding, 0,
                                                    sz / 2 - sh / 2),
                                  size=mp.Vector3(0, sy - padding * 2,
                                                  sh - padding * 2),
                                  direction=mp.X,
                                  weight=-1))

            nfrBelow.append(
                mp.Near2FarRegion(center=mp.Vector3(0, sy / 2 - padding,
                                                    sz / 2 - sh / 2),
                                  size=mp.Vector3(sx - padding * 2, 0,
                                                  sh - padding * 2),
                                  direction=mp.Y))

            nfrBelow.append(
                mp.Near2FarRegion(center=mp.Vector3(0, -sy / 2 + padding,
                                                    sz / 2 - sh / 2),
                                  size=mp.Vector3(sx - padding * 2, 0,
                                                  sh - padding * 2),
                                  direction=mp.Y,
                                  weight=-1))
            nfrBelow.append(
                mp.Near2FarRegion(center=mp.Vector3(0, 0, sz / 2 - padding),
                                  size=mp.Vector3(sx - padding * 2,
                                                  sy - padding * 2, 0),
                                  direction=mp.Z))
            if ff_cover == True:
                nfrAbove.append(
                    mp.Near2FarRegion(center=mp.Vector3(
                        0, 0, sz / 2 - padding),
                                      size=mp.Vector3(sx - padding * 2,
                                                      sy - padding * 2, 0),
                                      direction=mp.Z))

                nfrBelow.append(
                    mp.Near2FarRegion(center=mp.Vector3(
                        0, 0, -sz / 2 - padding),
                                      size=mp.Vector3(sx - padding * 2,
                                                      sy - padding * 2, 0),
                                      direction=mp.Z,
                                      weight=-1))
            nearfieldregions.append(nfrAbove)
            nearfieldregions.append(nfrBelow)
            return nearfieldregions

        ###GEOMETRY FOR THE SIMULATION#################################################

        #"Material parameters"
        air = mp.Medium(epsilon=1)  #air dielectric value
        SubstrateEps = GaN  #substrate epsilon

        #"Geometry to define the substrate and block of air to truncate the pyramid if self.truncation =/= 0"
        geometries = []
        #Substrate
        geometries.append(
            mp.Sphere(center=mp.Vector3(0, 0, self.distance / 2 + self.radius),
                      radius=self.radius,
                      material=CL_material))

        geometries.append(
            mp.Sphere(center=mp.Vector3(0, 0,
                                        -self.distance / 2 - self.radius),
                      radius=self.radius,
                      material=CL_material))

        if geometry == None:
            geometries = []

        if material_function == None:
            material_function = None

        ###SYMMETRIES#########################################################
        #"Symmetry logic."
        if use_symmetries:
            symmetry = create_symmetry(self)
            print('symmetry on:', symmetry)
        else:
            symmetry = []

        ###PML_LAYERS###################################################################

        pml_layer = [mp.PML(dpml)]

        ###SOURCE#######################################################################

        #"A gaussian with pulse source proportional to exp(-iwt-(t-t_0)^2/(2w^2))"

        abs_source_position_x = 0
        abs_source_position_y = 0
        abs_source_position_z = 0

        source = [
            mp.Source(
                mp.GaussianSource(
                    frequency=self.frequency_center,
                    fwidth=self.frequency_width,
                    cutoff=self.cutoff),  #gaussian current-source
                component=mp.Ez,
                amplitude=1,
                center=mp.Vector3(abs_source_position_x, abs_source_position_y,
                                  abs_source_position_z))
        ]

        #source.append(mp.Source(mp.GaussianSource(frequency=self.frequency_center,fwidth=self.frequency_width, cutoff=self.cutoff),	#gaussian current-source
        #		component=mp.Ey,
        #		amplitude=self.source_direction[1],
        #		center=mp.Vector3(abs_source_position_x,abs_source_position_y,abs_source_position_z)))

        #source.append(mp.Source(mp.GaussianSource(frequency=self.frequency_center,fwidth=self.frequency_width, cutoff=self.cutoff),	#gaussian current-source
        #		component=mp.Ez,
        #		amplitude=self.source_direction[2],
        #		center=mp.Vector3(abs_source_position_x,abs_source_position_y,abs_source_position_z)))
        #MEEP simulation constructor
        sim = mp.Simulation(
            cell_size=cell,
            geometry=geometries,
            symmetries=symmetry,
            sources=source,
            #eps_averaging=True,
            #subpixel_tol=1e-4,
            #subpixel_maxeval=1000,
            dimensions=3,
            #default_material=GaN,
            Courant=0.1,
            extra_materials=[CL_material],
            boundary_layers=pml_layer,
            split_chunks_evenly=False,
            resolution=resolution)

        ###SOURCE REGION###################################################
        print('pixels', pixels)

        def define_flux_source_regions(abs_source_position_x,
                                       abs_source_position_y,
                                       abs_source_position_z, resolution,
                                       pixels):
            distance = pixels * 1 / resolution
            source_region = []
            source_region.append(
                mp.FluxRegion(  #region x to calculate flux from
                    center=mp.Vector3(abs_source_position_x + distance,
                                      abs_source_position_y,
                                      abs_source_position_z),
                    size=mp.Vector3(0, 2 * pixels * 1 / resolution,
                                    2 * pixels * 1 / resolution),
                    direction=mp.X))

            source_region.append(
                mp.FluxRegion(  # region -x to calculate flux from
                    center=mp.Vector3(abs_source_position_x - distance,
                                      abs_source_position_y,
                                      abs_source_position_z),
                    size=mp.Vector3(0, 2 * pixels * 1 / resolution,
                                    2 * pixels * 1 / resolution),
                    direction=mp.X,
                    weight=-1))

            source_region.append(
                mp.FluxRegion(  #region y to calculate flux from
                    center=mp.Vector3(abs_source_position_x,
                                      abs_source_position_y + distance,
                                      abs_source_position_z),
                    size=mp.Vector3(2 * pixels * 1 / resolution, 0,
                                    2 * pixels * 1 / resolution),
                    direction=mp.Y))

            source_region.append(
                mp.FluxRegion(  #region -y to calculate flux from
                    center=mp.Vector3(abs_source_position_x,
                                      abs_source_position_y - distance,
                                      abs_source_position_z),
                    size=mp.Vector3(2 * pixels * 1 / resolution, 0,
                                    2 * pixels * 1 / resolution),
                    direction=mp.Y,
                    weight=-1))

            source_region.append(
                mp.FluxRegion(  #z-bottom region to calculate flux from
                    center=mp.Vector3(abs_source_position_x,
                                      abs_source_position_y,
                                      abs_source_position_z + distance),
                    size=mp.Vector3(2 * pixels * 1 / resolution,
                                    2 * pixels * 1 / resolution, 0),
                    direction=mp.Z))

            source_region.append(
                mp.FluxRegion(  #z-top region to calculate flux from
                    center=mp.Vector3(abs_source_position_x,
                                      abs_source_position_y,
                                      abs_source_position_z - distance),
                    size=mp.Vector3(2 * pixels * 1 / resolution,
                                    2 * pixels * 1 / resolution, 0),
                    direction=mp.Z,
                    weight=-1))
            return source_region

        ###REGIONS######################################################################

        #"These regions define the borders of the cell with distance 'padding' between the flux region and the dpml region to avoid calculation errors."
        if calculate_flux:
            flux_regions = define_flux_regions(sx, sy, sz, padding)
            fr1, fr2, fr3, fr4, fr5, fr6 = flux_regions
            flux_total = sim.add_flux(self.frequency_center,
                                      self.frequency_width,
                                      self.number_of_freqs, fr1, fr2, fr3, fr4,
                                      fr5,
                                      fr6)  #calculate flux for flux regions

        if calculate_source_flux:
            sr1, sr2, sr3, sr4, sr5, sr6 = define_flux_source_regions(
                abs_source_position_x, abs_source_position_y,
                abs_source_position_z, resolution, pixels)
            flux_source = sim.add_flux(self.frequency_center,
                                       self.frequency_width,
                                       self.number_of_freqs, sr1, sr2, sr3,
                                       sr4, sr5, sr6)

        ###FAR FIELD REGION#############################################################

        #"The simulation calculates the far field flux from the regions 1-5 below. It correspons to the air above and at the side of the pyramids. The edge of the simulation cell that touches the substrate is not added to this region. Far-field calculations can not handle different materials."
        if ff_calculations == True:
            nearfieldregions = define_nearfield_regions(
                sx, sy, sz, sh, padding, ff_cover)
            if ff_cover == True:
                nfrA1, nfrA2, nfrA3, nfrA4, nfrA5, nfrA6 = nearfieldregions[0]
                nfrB1, nfrB2, nfrB3, nfrB4, nfrB5, nfrB6 = nearfieldregions[1]
            else:
                nfrA1, nfrA2, nfrA3, nfrA4, nfrA6 = nearfieldregions[0]
                nfrB1, nfrB2, nfrB3, nfrB4, nfrB6 = nearfieldregions[1]
            if ff_calc == "Both" and ff_cover == True:
                nearfieldAbove = sim.add_near2far(self.frequency_center,
                                                  self.frequency_width,
                                                  self.number_of_freqs, nfrA1,
                                                  nfrA2, nfrA3, nfrA4, nfrA5,
                                                  nfrA6)
                nearfieldBelow = sim.add_near2far(self.frequency_center,
                                                  self.frequency_width,
                                                  self.number_of_freqs, nfrB1,
                                                  nfrB2, nfrB3, nfrB4, nfrB5,
                                                  nfrB6)
            elif ff_calc == "Above" and ff_cover == True:
                nearfieldAbove = sim.add_near2far(self.frequency_center,
                                                  self.frequency_width,
                                                  self.number_of_freqs, nfrA1,
                                                  nfrA2, nfrA3, nfrA4, nfrA5,
                                                  nfrA6)
            elif ff_calc == "Above" and ff_cover == False:
                nearfieldAbove = sim.add_near2far(self.frequency_center,
                                                  self.frequency_width,
                                                  self.number_of_freqs, nfrA1,
                                                  nfrA2, nfrA3, nfrA4, nfrA6)
            elif ff_calc == "Below" and ff_cover == True:
                nearfieldBelow = sim.add_near2far(self.frequency_center,
                                                  self.frequency_width,
                                                  self.number_of_freqs, nfrB1,
                                                  nfrB2, nfrB3, nfrB4, nfrB5,
                                                  nfrB6)
            elif ff_calc == "Below" and ff_cover == False:
                nearfieldBelow = sim.add_near2far(self.frequency_center,
                                                  self.frequency_width,
                                                  self.number_of_freqs, nfrB1,
                                                  nfrB2, nfrB3, nfrB4, nfrB6)
            #Assumed ff_calc == Both and ff_cover == False
            else:
                nearfieldAbove = sim.add_near2far(self.frequency_center,
                                                  self.frequency_width,
                                                  self.number_of_freqs, nfrA1,
                                                  nfrA2, nfrA3, nfrA4, nfrA6)
                nearfieldBelow = sim.add_near2far(self.frequency_center,
                                                  self.frequency_width,
                                                  self.number_of_freqs, nfrB1,
                                                  nfrB2, nfrB3, nfrB4, nfrB6)
        ###RUN##########################################################################
        #"Run the simulation"
        if True:
            sim.plot2D(output_plane=mp.Volume(
                center=mp.Vector3(0, 0 * abs_source_position_y, 0),
                size=mp.Vector3(0, sy + 2 * dpml, sz + 2 * dpml)))
            #plt.show()
            plt.savefig('foo.pdf')
            sim.plot2D(output_plane=mp.Volume(
                center=mp.Vector3(0 * abs_source_position_x, 0, 0),
                size=mp.Vector3(sx + 2 * dpml, 0, sz + 2 * dpml)))

            #plt.show()
            plt.savefig('foo2.pdf')
            sim.plot2D(output_plane=mp.Volume(
                center=mp.Vector3(0, 0, abs_source_position_z),
                size=mp.Vector3(sx + 2 * dpml, sy + 2 * dpml, 0)))
            #sim.plot2D(output_plane=mp.Volume(center=mp.Vector3(0,0,sz/2-sh-0.01),size=mp.Vector3(sx+2*dpml,sy+2*dpml,0)))
            plt.savefig('foo3.pdf')

        if use_fixed_time:
            sim.run(
                mp.dft_ldos(self.frequency_center, self.frequency_width,
                            self.number_of_freqs),
                #	mp.at_beginning(mp.output_epsilon),
                #until_after_sources=mp.stop_when_fields_decayed(2,mp.Ey,mp.Vector3(0,0,sbs_cource_position+0.2),1e-2))
                until=simulation_time)
        else:
            #Withdraw maximum dipole amplitude direction
            max_index = self.source_direction.index(max(self.source_direction))
            if max_index == 0:
                detector_pol = mp.Ex
            elif max_index == 1:
                detector_pol = mp.Ey
            else:
                detector_pol = mp.Ez
            #TODO: exchange self.source_direction to maxmimum dipole ampltitude
            sim.run(
                mp.dft_ldos(self.frequency_center, self.frequency_width,
                            self.number_of_freqs),
                #mp.to_appended("ex", mp.at_every(0.6, mp.output_efield_x)),
                mp.at_beginning(mp.output_epsilon),
                until_after_sources=mp.stop_when_fields_decayed(
                    2, detector_pol,
                    mp.Vector3(0, 0, abs_source_position_z + 0.2), 1e-3))

        ###OUTPUT CALCULATIONS##########################################################

        #"Calculate the poynting flux given the far field values of E, H."
        myIntegration = True
        nfreq = self.number_of_freqs
        r = 2 * math.pow(
            self.pyramid_height, 2
        ) * self.frequency_center * 2 * 10  # 10 times the Fraunhofer-distance
        if ff_calculations:
            fields = []
            P_tot_ff = np.zeros(self.number_of_freqs)
            npts = ff_pts  #number of far-field points
            Px = 0
            Py = 0
            Pz = 0
            theta = ff_angle
            phi = math.pi * 2
            #"How many points on the ff-sphere"
            #global xPts
            #xPts=[]

            #global yPts
            #yPts=[]

            #global zPts
            #zPts=[]

            Pr_Array = []

            if myIntegration == True:
                #how to pick ff-points, this uses fibbonaci-sphere distribution
                if FibonacciSampling == True:
                    if theta == math.pi / 3:
                        offset = 1.5 / npts
                    elif theta == math.pi / 4:
                        npts = npts * 2
                        offset = 1.15 / npts
                    elif theta == math.pi / 5:
                        npts = npts * 2.5
                        offset = 0.95 / npts
                    elif theta == math.pi / 6:
                        #npts=npts*3
                        offset = 0.8 / npts
                    elif theta == math.pi / 7:
                        npts = npts * 3
                        offset = 0.7 / npts
                    elif theta == math.pi / 8:
                        npts = npts * 3
                        offset = 0.6 / npts
                    elif theta == math.pi / 12:
                        npts = npts * 3
                        offset = 0.4 / npts
                    else:
                        offset = 0.2 / npts
                    xPts, yPts, zPts = fibspherepts(r, theta, npts, offset)
                    range_npts = int((theta / math.pi) * npts)
                else:
                    #check out Lebedev quadrature
                    #if not fibb sampling then spherical sampling
                    theta_pts = npts
                    phi_pts = npts * 2
                    xPts, yPts, zPts = sphericalpts(r, theta, phi, theta_pts,
                                                    phi_pts)
                    range_npts = int(theta_pts * phi_pts + 1)

                if ff_calc == "Both":
                    #Pr_ArrayA for above, B for below
                    Pr_ArrayA = []
                    Pr_ArrayB = []
                    P_tot_ffA = [0] * (self.number_of_freqs)
                    P_tot_ffB = [0] * (self.number_of_freqs)
                    for n in range(range_npts):
                        ffA = sim.get_farfield(
                            nearfieldAbove,
                            mp.Vector3(xPts[n], yPts[n], zPts[n]))
                        ffB = sim.get_farfield(
                            nearfieldBelow,
                            mp.Vector3(xPts[n], yPts[n], -1 * zPts[n]))
                        i = 0
                        for k in range(nfreq):
                            "Calculate the poynting vector in x,y,z direction"
                            PrA = myPoyntingFlux(ffA, i)
                            PrB = myPoyntingFlux(ffB, i)
                            Pr_ArrayA.append(PrA)
                            Pr_ArrayB.append(PrB)
                            "the spherical cap has area 2*pi*r^2*(1-cos(theta))"
                            "divided by npts and we get evenly sized area chunks"
                            surface_Element = 2 * math.pi * pow(
                                r, 2) * (1 - math.cos(theta)) / range_npts
                            P_tot_ffA[k] += surface_Element * (1) * (PrA)
                            P_tot_ffB[k] += surface_Element * (1) * (PrB)
                            i = i + 6  #to keep track of the correct entries in the ff array
                if ff_calc == "Below":
                    for n in range(range_npts):
                        ff = sim.get_farfield(
                            nearfieldBelow,
                            mp.Vector3(xPts[n], yPts[n], -1 * zPts[n]))
                        fields.append({
                            "pos": (xPts[n], yPts[n], zPts[n]),
                            "field": ff
                        })
                        i = 0
                        for k in range(nfreq):
                            "Calculate the poynting vector in x,y,z direction"
                            Pr = myPoyntingFlux(ff, i)
                            Pr_Array.append(Pr)
                            "the spherical cap has area 2*pi*r^2*(1-cos(theta))"
                            "divided by npts and we get evenly sized area chunks"
                            surface_Element = 2 * math.pi * pow(
                                r, 2) * (1 - math.cos(theta)) / range_npts
                            P_tot_ff[k] += surface_Element * (1) * (Pr)
                            i = i + 6  #to keep track of the correct entries in the ff array
                if ff_calc == "Above":
                    for n in range(range_npts):
                        ff = sim.get_farfield(
                            nearfieldAbove,
                            mp.Vector3(xPts[n], yPts[n], zPts[n]))
                        fields.append({
                            "pos": (xPts[n], yPts[n], zPts[n]),
                            "field": ff
                        })
                        #		print('ff,n,x,y,z',n,xPts[n],yPts[n],zPts[n],ff)
                        #		print('fields',fields[n])
                        #		print('------')
                        i = 0
                        for k in range(nfreq):
                            "Calculate the poynting vector in x,y,z direction"
                            Pr = myPoyntingFlux(ff, i)
                            Pr_Array.append(Pr)
                            "the spherical cap has area 2*pi*r^2*(1-cos(theta))"
                            "divided by npts and we get evenly sized area chunks"
                            surface_Element = 2 * math.pi * pow(
                                r, 2) * (1 - math.cos(theta)) / range_npts
                            P_tot_ff[k] += surface_Element * (1) * (Pr)
                            #print('S',surface_Element,'r',r,'theta',theta,'range npts',range_npts)
                            i = i + 6  #to keep track of the correct entries in the ff array
                #	print('P_tot_ff',P_tot_ff)
                #	print('fields',fields)
                #	print('Pr_Array',Pr_Array)

            ##CALCULATE FLUX OUT FROM BOX###########################################
        if calculate_flux:
            #"Initialize variables to be used, pf stands for 'per frequency'"
            flux_tot_value = np.zeros(
                self.number_of_freqs)  #total flux out from box
            flux_tot_ff_ratio = np.zeros(self.number_of_freqs)
            flux_tot_out = mp.get_fluxes(flux_total)  #save total flux data
            freqs_out = mp.get_flux_freqs(flux_total)
            print('freqs', freqs_out)
            if calculate_source_flux:
                source_flux_out = mp.get_fluxes(flux_source)

            elapsed_time = round((time.time() - start) / 60, 1)
            print('LDOS', sim.ldos_data)
            print('LDOS0', sim.ldos_data[0])

            for i in range(len(flux_tot_out)):
                print(flux_tot_out[i] * 100 / source_flux_out[i],
                      'LE percentage for lambda: ', 1 / freqs_out[i])

            if False:
                fig = plt.figure()
                ax = fig.gca(projection='3d')
                Pr_Max = max(Pr_Array)
                R = [n / Pr_Max for n in Pr_Array]
                print(R)
                #			R=1
                pts = len(Pr_Array)
                theta, phi = np.linspace(0, np.pi,
                                         pts), np.linspace(0, 2 * np.pi, pts)
                THETA, PHI = np.meshgrid(theta, phi)
                #print(xPts)
                # print(yPts)
                # print(zPts)
                X = np.zeros(pts**2)
                Y = np.zeros(pts**2)
                Z = np.zeros(pts**2)
                print('R pts', pts)
                print('sample pts', len(xPts))
                for n in range(pts):
                    xPts[n] = R[n] * xPts[n]
                    yPts[n] = R[n] * yPts[n]
                    zPts[n] = R[n] * zPts[n]
                # #print(X)
                # #print(Y)
                # #print(Z)
                #ax.set_xlim(-100,100)
                #ax.set_zlim(-100,100)
                #ax.set_ylim(-100,100)

                #ax.scatter(xPts,yPts,zPts)
                u = np.linspace(0, 2 * np.pi, 120)
                v = np.linspace(0, np.pi / 6, 120)
                r_ = np.asarray(R)
                x = np.outer(np.cos(u), np.sin(v))
                y = np.outer(np.sin(u), np.sin(v))
                z = R * np.outer(np.ones(np.size(u)), np.cos(v))
                print('lenx', len(x), 'leny', len(y), 'lenz', len(z))
                #r = np.sqrt(xPts**2+yPts**2+zPts**2)
                #plot(r)
                ax.plot_surface(x, y, z, cmap='plasma')
                #ax.quiver(0,0,0,0,0,1,length=1.2,color='brown',normalize='true')
                #ax.text(0,0,1.3, '$\mathcal{P}$',size=20, zdir=None)
                #ax.set_zlim(-1,1)
                #ax.axis('off')
                #ax.plot_trisurf(list(x),list(y),list(z),cmap='plasma')
                plt.show()
            for n in range(len(flux_tot_out)):
                flux_tot_out[n] = round(flux_tot_out[n], 11)
            #	P_tot_ff[n]=round(P_tot_ff[n],9)
            ##Some processing to calculate the flux ratios per frequency
            if ff_calculations:
                for n in range(len(flux_tot_out)):
                    #	flux_tot_out[n]=round(flux_tot_out[n],9)
                    P_tot_ff[n] = round(P_tot_ff[n], 11)
                for i in range(self.number_of_freqs):

                    flux_tot_ff_ratio[i] = round(P_tot_ff[i] / flux_tot_out[i],
                                                 11)
                if ff_calc == "Both":
                    P_tot_ff = []
                    P_tot_ff.append(P_tot_ffA)
                    P_tot_ff.append(P_tot_ffB)
                    flux_tot_ff_ratio = []
                    flux_tot_ff_ratioA = [0] * (self.number_of_freqs)
                    flux_tot_ff_ratioB = [0] * (self.number_of_freqs)
                    for i in range(self.number_of_freqs):
                        flux_tot_ff_ratioA[i] = round(
                            P_tot_ffA[i] / flux_tot_out[i], 11)
                        flux_tot_ff_ratioB[i] = round(
                            P_tot_ffB[i] / flux_tot_out[i], 11)
                    flux_tot_ff_ratio.append(flux_tot_ff_ratioA)
                    flux_tot_ff_ratio.append(flux_tot_ff_ratioB)

                return {
                    "total_flux": flux_tot_out,
                    "source_flux": source_flux_out,
                    "ff_at_angle": P_tot_ff,
                    "flux_ratio": flux_tot_ff_ratio,
                    "LDOS": sim.ldos_data,
                    "Elapsed time (min)": elapsed_time
                }

            else:
                return {
                    "total_flux": flux_tot_out,
                    "source_flux": source_flux_out,
                    "ff_at_angle": None,
                    "flux_ratio": None,
                    "LDOS": sim.ldos_data,
                    "Elapsed time (min)": elapsed_time
                }
Пример #27
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())
Пример #28
0
def main():
    # Prefix all output files with the command line argument
    file_prefix = sys.argv[1]
    # Number of pixels per micron
    resolution = 150
    # Simulation volume (um)
    cell_x = 2
    cell_y = 2
    cell_z = 2.5
    # Refractive indicies
    index_si = 3.6  # previously 3.4467
    index_sio2 = 1.444
    # Durations in units of micron/c
    duration = round(1.5 * cell_x + 2)
    num_timesteps = duration * resolution
    # Absorbing layer on boundary
    pml = 0.5
    # Geometry
    src_buffer = pml / 16
    nbn_buffer = src_buffer
    nbn_length = cell_x - 2 * pml - src_buffer - nbn_buffer
    nbn_center_x = (src_buffer + nbn_buffer) / 2
    wavelength = 1.55
    waveguide_width = 0.750  # 750 nm
    waveguide_height = 0.110  # 110 nm
    plane_shift_y = 0

    # nbn is 10/8 times thicker than in reality to have enough simulation pixels
    # so we reduce its absorption by a factor of 5/4 to compensate
    nbn_thickness_comp = 250 / resolution

    nbn_thickness = 0.008 * nbn_thickness_comp  # Actually 8 nm, but simulating this for 2 grid points
    nbn_width = 0.100  # 100 nm
    nbn_spacing = 0.120  # 120 nm

    # Also compensate the difference in index by the same amount
    nbn_base_index = 5.23  # Taken from Hu thesis p86
    nbn_index = (5.23 - index_si) / nbn_thickness_comp + index_si
    nbn_base_k = 5.82  # Taken from Hu thesis p86
    nbn_k = nbn_base_k / nbn_thickness_comp
    conductivity = 2 * math.pi * wavelength * nbn_k / nbn_index

    flux_length = cell_x - 2 * pml - 4 * src_buffer

    # Generate simulation obejcts
    cell = mp.Vector3(cell_x, cell_y, cell_z)
    freq = 1 / wavelength
    src_pt = mp.Vector3(-cell_x / 2 + pml + src_buffer, 0, 0)
    output_slice = mp.Volume(center=mp.Vector3(y=(3 * waveguide_height / 4) +
                                               plane_shift_y),
                             size=(cell_x, 0, cell_z))

    # Log important quantities
    print('ABSORBING RUN')
    print('File prefix: {}'.format(file_prefix))
    print('Duration: {}'.format(duration))
    print('Resolution: {}'.format(resolution))
    print('Dimensions: {} um, {} um, {} um'.format(cell_x, cell_y, cell_z))
    print('Wavelength: {} um'.format(wavelength))
    print('Si thickness: {} um'.format(waveguide_height))
    print('NbN thickness: {} um'.format(nbn_thickness))
    print('Si index: {}; SiO2 index: {}'.format(index_si, index_sio2))
    print('Absorber dimensions: {} um, {} um, {} um'.format(
        nbn_length, nbn_thickness, nbn_width))
    print('Absorber n (base value): {} ({}), k: {} ({})'.format(
        nbn_index, nbn_base_index, nbn_k, nbn_base_k))
    print('Absorber compensation for thickness: {}'.format(nbn_thickness_comp))
    print('Flux length: {} um'.format(flux_length))
    print('\n\n**********\n\n')

    default_material = mp.Medium(epsilon=1)

    # Physical geometry of the simulation
    geometry = [
        mp.Block(mp.Vector3(mp.inf, cell_y, mp.inf),
                 center=mp.Vector3(0, -cell_y / 2 + plane_shift_y, 0),
                 material=mp.Medium(epsilon=index_sio2)),
        mp.Block(mp.Vector3(mp.inf, waveguide_height, waveguide_width),
                 center=mp.Vector3(0, waveguide_height / 2 + plane_shift_y, 0),
                 material=mp.Medium(epsilon=index_si))
    ]

    # Absorber will only be appended to geometry for the second simulation
    absorber = [
        mp.Block(mp.Vector3(nbn_length, nbn_thickness, nbn_width),
                 center=mp.Vector3(
                     nbn_center_x, waveguide_height +
                     nbn_thickness / nbn_thickness_comp / 2 + plane_shift_y,
                     nbn_spacing / 2),
                 material=mp.Medium(epsilon=nbn_index,
                                    D_conductivity=conductivity)),
        mp.Block(mp.Vector3(nbn_length, nbn_thickness, nbn_width),
                 center=mp.Vector3(
                     nbn_center_x, waveguide_height +
                     nbn_thickness / nbn_thickness_comp / 2 + plane_shift_y,
                     -nbn_spacing / 2),
                 material=mp.Medium(epsilon=nbn_index,
                                    D_conductivity=conductivity)),
    ]

    # geometry += absorber

    # Calculate eigenmode source
    src_max_y = cell_y - 2 * pml
    src_max_z = cell_z - 2 * pml
    src_y = src_max_y
    src_z = src_max_z  # min(3 * waveguide_width, src_max_z)

    src_center_y = 0  # plane_shift_y

    sources = [
        mp.EigenModeSource(src=mp.ContinuousSource(frequency=freq),
                           center=mp.Vector3(-cell_x / 2 + pml + src_buffer,
                                             src_center_y, 0),
                           size=mp.Vector3(0, src_y, src_z),
                           eig_match_freq=True,
                           eig_parity=mp.ODD_Z,
                           eig_band=1)
    ]

    pml_layers = [mp.PML(pml)]

    # Pass all simulation parameters to meep
    sim = mp.Simulation(
        cell_size=cell,
        boundary_layers=pml_layers,
        geometry=geometry,
        sources=sources,
        resolution=resolution,
        # eps_averaging=False,
        default_material=default_material,
        symmetries=[mp.Mirror(mp.Z, phase=-1)])

    # Create flux monitors to calculate transmission and absorption
    fr_y = cell_y - 2 * pml
    fr_z = cell_z - 2 * pml

    # Reflected flux
    refl_fr = mp.FluxRegion(center=mp.Vector3(
        -0.5 * cell_x + pml + 2 * src_buffer, 0, 0),
                            size=mp.Vector3(0, fr_y, fr_z))
    refl = sim.add_flux(freq, 0, 1, refl_fr)

    # Transmitted flux
    tran_fr = mp.FluxRegion(center=mp.Vector3(
        0.5 * cell_x - pml - 2 * src_buffer, 0, 0),
                            size=mp.Vector3(0, fr_y, fr_z))
    tran = sim.add_flux(freq, 0, 1, tran_fr)

    # Run simulation, outputting the epsilon distribution and the fields in the
    # x-y plane every 0.25 microns/c
    sim.run(mp.at_beginning(mp.output_epsilon),
            mp.to_appended(
                "ez_z0",
                mp.in_volume(output_slice,
                             mp.at_every(2 / resolution, mp.output_efield_z))),
            until=duration)

    print('\n\n**********\n\n')

    sim.fields.synchronize_magnetic_fields()

    # For normalization run, save flux fields data for reflection plane
    no_absorber_refl_data = sim.get_flux_data(refl)
    # Save incident power for transmission plane
    no_absorber_tran_flux = mp.get_fluxes(tran)

    print("Flux: {}".format(no_absorber_tran_flux[0]))

    eps_data = sim.get_array(center=mp.Vector3(z=(nbn_spacing + nbn_width) /
                                               2),
                             size=mp.Vector3(cell_x, cell_y, 0),
                             component=mp.Dielectric)
    eps_cross_data = sim.get_array(center=mp.Vector3(x=cell_x / 4),
                                   size=mp.Vector3(0, cell_y, cell_z),
                                   component=mp.Dielectric)

    max_field = 1.5

    # Plot epsilon distribution
    if mp.am_master():
        plt.figure()
        plt.imshow(eps_data.transpose(),
                   interpolation='spline36',
                   cmap='binary')
        plt.axis('off')
        plt.savefig(file_prefix + '_Eps_A.png', dpi=300)
        print('Saved ' + file_prefix + '_Eps_A.png')

    # Plot field on x-y plane
    ez_data = sim.get_array(center=mp.Vector3(),
                            size=mp.Vector3(cell_x, cell_y, 0),
                            component=mp.Ez)
    if mp.am_master():
        plt.figure()
        plt.imshow(eps_data.transpose(),
                   interpolation='spline36',
                   cmap='binary')
        plt.imshow(ez_data.transpose(),
                   interpolation='spline36',
                   cmap='RdBu',
                   alpha=0.9)
        plt.axis('off')
        plt.savefig(file_prefix + '_Ez_A.png', dpi=300)
        print('Saved ' + file_prefix + '_Ez_A.png')

    energy_side_data = sim.get_array(center=mp.Vector3(),
                                     size=mp.Vector3(cell_x, cell_y, 0),
                                     component=mp.EnergyDensity)
    if mp.am_master():
        plt.figure()
        plt.imshow(eps_data.transpose(),
                   interpolation='spline36',
                   cmap='binary')
        plt.imshow(energy_side_data.transpose(),
                   interpolation='spline36',
                   cmap='hot',
                   alpha=0.9)
        plt.axis('off')
        plt.savefig(file_prefix + '_Pwr0_A.png', dpi=300)
        print('Saved ' + file_prefix + '_Pwr0_A.png')

    # Plot energy density on y-z plane
    energy_data = sim.get_array(center=mp.Vector3(),
                                size=mp.Vector3(0, cell_y, cell_z),
                                component=mp.EnergyDensity)
    if mp.am_master():
        plt.figure()
        plt.imshow(eps_cross_data, interpolation='spline36', cmap='binary')
        plt.imshow(energy_data,
                   interpolation='spline36',
                   cmap='hot',
                   alpha=0.9)
        plt.axis('off')
        plt.savefig(file_prefix + '_Pwr1_A.png', dpi=300)
        print('Saved ' + file_prefix + '_Pwr1_A.png')

    energy_data = sim.get_array(center=mp.Vector3(x=cell_x / 4),
                                size=mp.Vector3(0, cell_y, cell_z),
                                component=mp.EnergyDensity)
    if mp.am_master():
        plt.figure()
        plt.imshow(eps_cross_data, interpolation='spline36', cmap='binary')
        plt.imshow(energy_data,
                   interpolation='spline36',
                   cmap='hot',
                   alpha=0.9)
        plt.axis('off')
        plt.savefig(file_prefix + '_Pwr2_A.png', dpi=300)
        print('Saved ' + file_prefix + '_Pwr2_A.png')

    # Plot cross-sectional fields at several locations to ensure seeing nonzero fields
    num_x = 4
    num_y = 3
    fig, ax = plt.subplots(num_x, num_y)
    fig.suptitle('Cross Sectional Ez Fields')

    for i in range(num_x * num_y):
        monitor_x = i * (cell_x / 4) / (num_x * num_y)
        ez_cross_data = sim.get_array(center=mp.Vector3(x=monitor_x),
                                      size=mp.Vector3(0, cell_y, cell_z),
                                      component=mp.Ez)
        ax_num = i // num_y, i % num_y
        if mp.am_master():
            ax[ax_num].imshow(eps_cross_data,
                              interpolation='spline36',
                              cmap='binary')
            ax[ax_num].imshow(ez_cross_data,
                              interpolation='spline36',
                              cmap='RdBu',
                              alpha=0.9,
                              norm=ZeroNormalize(vmax=np.max(max_field)))
            ax[ax_num].axis('off')
            ax[ax_num].set_title('x = {}'.format(
                round(cell_x / 4 + i / resolution, 3)))
    if mp.am_master():
        plt.savefig(file_prefix + '_Ez_CS_A.png', dpi=300)
        print('Saved ' + file_prefix + '_Ez_CS_A.png')

    fig_e, ax_e = plt.subplots(num_x, num_y)
    fig_e.suptitle('Cross Sectional Energy Density')

    for i in range(num_x * num_y):
        monitor_x = i * (cell_x / 4) / (num_x * num_y)
        energy_cross_data = sim.get_array(center=mp.Vector3(x=monitor_x),
                                          size=mp.Vector3(0, cell_y, cell_z),
                                          component=mp.EnergyDensity)
        ax_num = i // num_y, i % num_y
        if mp.am_master():
            ax_e[ax_num].imshow(eps_cross_data,
                                interpolation='spline36',
                                cmap='binary')
            ax_e[ax_num].imshow(energy_cross_data,
                                interpolation='spline36',
                                cmap='hot',
                                alpha=0.9)
            ax_e[ax_num].axis('off')
            ax_e[ax_num].set_title('x = {}'.format(
                round(cell_x / 4 + i / resolution, 3)))
    if mp.am_master():
        plt.savefig(file_prefix + '_Pwr_CS_A.png', dpi=300)
        print('Saved ' + file_prefix + '_Pwr_CS_A.png')

    print('\n\n**********\n\n')

    # Reset simulation for absorption run
    """
    sim.reset_meep()

    geometry += absorber

    sim = mp.Simulation(cell_size=cell,
                        boundary_layers=pml_layers,
                        geometry=geometry,
                        sources=sources,
                        resolution=resolution,
                        eps_averaging=False,
                        default_material=default_material,
                        symmetries=[mp.Mirror(mp.Z, phase=-1)])

    refl = sim.add_flux(freq, 0, 1, refl_fr)
    tran = sim.add_flux(freq, 0, 1, tran_fr)

    sim.load_minus_flux_data(refl, no_absorber_refl_data)

    # Run simulation with absorber
    sim.run(mp.at_beginning(mp.output_epsilon),
            mp.to_appended("ez_z0",
                           mp.in_volume(output_slice,
                                        mp.at_every(0.25, mp.output_efield_z))),
            until=duration)

    print('\n\n**********\n\n')

    # Calculate transmission and absorption
    absorber_refl_flux = mp.get_fluxes(refl)
    absorber_tran_flux = mp.get_fluxes(tran)

    transmittance = absorber_tran_flux[0] / no_absorber_tran_flux[0]
    reflectance = absorber_refl_flux[0] / no_absorber_tran_flux[0]
    absorption = 1 - transmittance
    penetration_depth = - nbn_length / math.log(transmittance)

    print('Flux: {}'.format(absorber_tran_flux[0]))
    print("Transmittance: %f" % transmittance)
    print("Reflectance: %f" % reflectance)
    print("Absorption: {} over {} um".format(absorption, nbn_length))
    print("lambda = {} mm".format(penetration_depth / 1000))

    eps_data = sim.get_array(center=mp.Vector3(z=(nbn_spacing + nbn_width) / 2), size=mp.Vector3(cell_x, cell_y, 0), component=mp.Dielectric)

    max_field = 1

    # Plot epsilon distribution with absorber
    if mp.am_master():
        plt.figure()
        plt.imshow(eps_data.transpose(), interpolation='spline36', cmap='binary')
        plt.axis('off')
        plt.savefig(file_prefix + '_Eps_B.png', dpi=300)
        print('Saved ' + file_prefix + '_Eps_B.png')

    # Plot fields in x-y plane with absorber
    ez_data = sim.get_array(center=mp.Vector3(), size=mp.Vector3(cell_x, cell_y, 0), component=mp.Ez)
    if mp.am_master():
        plt.figure()
        plt.imshow(eps_data.transpose(), interpolation='spline36', cmap='binary')
        plt.imshow(ez_data.transpose(), interpolation='spline36', cmap='RdBu', alpha=0.9)
        plt.axis('off')
        plt.savefig(file_prefix + '_Ez_B.png', dpi=300)
        print('Saved ' + file_prefix + '_Ez_B.png')

    # Plot field cross sections with absorber
    eps_cross_data = sim.get_array(center=mp.Vector3(x=cell_x/4), size=mp.Vector3(0, cell_y, cell_z), component=mp.Dielectric)
    num_x = 4
    num_y = 3
    fig, ax = plt.subplots(num_x, num_y)
    fig.suptitle('Cross Sectional Ez Fields')
    for i in range(num_x * num_y):
        monitor_x = cell_x/4 + i / resolution
        ez_cross_data = sim.get_array(center=mp.Vector3(x=monitor_x), size=mp.Vector3(0, cell_y, cell_z), component=mp.Ez)
        ax_num = i // num_y, i % num_y
        if mp.am_master():
            ax[ax_num].imshow(eps_cross_data, interpolation='spline36', cmap='binary')
            ax[ax_num].imshow(ez_cross_data, interpolation='spline36', cmap='RdBu', alpha=0.9, norm=ZeroNormalize(vmax=np.max(max_field)))
            ax[ax_num].axis('off')
            ax[ax_num].set_title('x = {}'.format(round(cell_x/4 + i / resolution, 3)))
    if mp.am_master():
        plt.savefig(file_prefix + '_Ez_CS_B.png', dpi=300)
        print('Saved ' + file_prefix + '_Ez_CS_B.png')

    print('\n\n**********\n\n')
    """

    print('Program finished.')
Пример #29
0
def main(args):

    resolution = 30

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

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

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

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

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

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

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

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

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

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

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

    geometry = []

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

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

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

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

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

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

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

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

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

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

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

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

    sim.display_fluxes(refl, trans_grid, trans_sub_top, trans_sub_bot)
Пример #30
0
def main(args):
    sx = 8.0  #spatial extent along x including pmls (μm)
    sy = 4
    sz = 0
    dpml = 1.0
    cell = mp.Vector3(sx, sy, sz)
    pml_layers = [mp.PML(dpml)]
    resolution = args.res
    wvl = args.wvl  #source wavelength
    fcen = 1 / wvl  #center frequency
    df = 0  #frequency bandwidth
    nfreq = 1  #number of frequencies
    dw = args.dw  #  slab thickness increment(um)
    w_init = args.w_init  # initial slab thickness(μm)
    n = args.n
    w = w_init + n * dw  #next slab thicknessw
    slab_center_y = 0.5 * w  #slab center y coordinate
    sfor_y = w + 0.005  #sfor_y = y coordinate of the slit_flux_output_region
    s = 0.030  #slit width
    print("wavelength =", wvl, "um")
    print("slab size =", w, "um")
    print("center frequency =", fcen, "1/um")
    print("slit_flux_output_region y coordinate =", sfor_y, "um")
    print("slab center y coordinate =", slab_center_y, "um")

    geometry = [
        mp.Block(mp.Vector3(mp.inf, w, mp.inf),
                 center=mp.Vector3(0, slab_center_y),
                 material=Ag)
    ]
    source = [
        mp.Source(mp.GaussianSource(fcen, df, nfreq),
                  component=mp.Ex,
                  center=mp.Vector3(0, -0.5 * (sy - 2.1), 0),
                  size=mp.Vector3(sx - 2.0, 0, 0))
    ]
    symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Z)]
    sim = mp.Simulation(cell_size=cell,
                        geometry=geometry,
                        sources=source,
                        resolution=resolution,
                        boundary_layers=pml_layers,
                        filename_prefix='slab_noslit')
    sim.use_output_directory()

    pt = mp.Vector3(
        0, -0.5 * (sy - 2.1), 0
    )  #point where field intensity is measured (usually at source position)

    slab_flux_in_region = mp.FluxRegion(
        center=mp.Vector3(0, -0.005, 0),
        size=mp.Vector3(sx, 0, 0))  #incident flux monitor 5nm above slab.
    slab_flux_in = sim.add_flux(fcen, df, nfreq, slab_flux_in_region)
    slab_flux_in_data = sim.get_flux_data(
        slab_flux_in)  #data are the E and H fields used to calculate S=ExH
    slab_flux_out_region = mp.FluxRegion(
        center=mp.Vector3(0, sfor_y, 0),
        size=mp.Vector3(sx, 0, 0))  #trans flux monitor 5nm below slab.
    slab_flux_out = sim.add_flux(fcen, df, nfreq, slab_flux_out_region)
    slab_flux_out_data = sim.get_flux_data(slab_flux_out)

    sim.run(mp.dft_ldos(fcen, df, nfreq),
            mp.at_beginning(mp.output_epsilon),
            until_after_sources=mp.stop_when_fields_decayed(
                10, mp.Hz, pt, 1e-5))

    slab_flux_input = []
    slab_flux_output = []
    slab_flux_input = mp.get_fluxes(slab_flux_in)
    slab_flux_output = mp.get_fluxes(slab_flux_out)

    print('incident flux slab =', slab_flux_input, ' ',
          'transmitted flux slab =', slab_flux_output, ' ',
          'normed transmitted flux=',
          np.divide(slab_flux_output, slab_flux_input))

    eps_data_slab = sim.get_array(center=mp.Vector3(0, 0, 0),
                                  size=mp.Vector3(sx, sy, sz),
                                  component=mp.Dielectric)
    ex_data_slab = sim.get_array(center=mp.Vector3(0, 0, 0),
                                 size=mp.Vector3(sx, sy, sz),
                                 component=mp.Ex)
    hz_data_slab = sim.get_array(center=mp.Vector3(0, 0, 0),
                                 size=mp.Vector3(sx, sy, sz),
                                 component=mp.Hz)

    sim.reset_meep()

    geometry = [
        mp.Block(mp.Vector3(mp.inf, w, mp.inf),
                 center=mp.Vector3(0, 0.5 * (w)),
                 material=Ag),
        mp.Block(mp.Vector3(s, w, 0),
                 center=mp.Vector3(0, 0.5 * (w), 0),
                 material=mp.Medium(epsilon=1))
    ]

    sim = mp.Simulation(cell_size=cell,
                        geometry=geometry,
                        sources=source,
                        resolution=resolution,
                        boundary_layers=pml_layers,
                        filename_prefix="slab_slit")
    sim.use_output_directory()

    slit_flux_in_region = mp.FluxRegion(center=mp.Vector3(0, -0.005, 0),
                                        size=mp.Vector3(
                                            sx, 0,
                                            0))  #same as slab_flux_in_region
    slit_flux_in = sim.add_flux(fcen, df, nfreq, slit_flux_in_region)
    slit_flux_in_data = sim.get_flux_data(slit_flux_in)
    slit_flux_out_region = mp.FluxRegion(center=mp.Vector3(0, w + 0.005, 0),
                                         size=mp.Vector3(
                                             sx, 0,
                                             0))  #same as slab_flux_out_region
    slit_flux_out = sim.add_flux(fcen, df, nfreq, slit_flux_out_region)
    slit_flux_out_data = sim.get_flux_data(slit_flux_out)

    sim.load_minus_flux_data(slit_flux_out, slab_flux_out_data)
    #subract  transmitted slab flux data (slab_flux_out_data) from slit_flux_out.  This is a correction so that flux only
    #from the slit is registered in slit_flux_out.

    sim.run(mp.dft_ldos(fcen, 0, nfreq),
            mp.at_beginning(mp.output_epsilon),
            until_after_sources=mp.stop_when_fields_decayed(
                10, mp.Hz, pt, 1e-4))

    slit_flux_input = []
    slit_flux_output = []
    slit_flux_input = mp.get_fluxes(slit_flux_in)
    slit_flux_output = mp.get_fluxes(slit_flux_out)
    print('slit flux net =', slit_flux_output, '  ', 'slit_flux_normed =',
          np.divide(slit_flux_output, slab_flux_input))
    eps_data_slit = sim.get_array(center=mp.Vector3(0, 0, 0),
                                  size=mp.Vector3(sx, sy, sz),
                                  component=mp.Dielectric)
    ex_data_slit = sim.get_array(center=mp.Vector3(0, 0, 0),
                                 size=mp.Vector3(sx, sy, sz),
                                 component=mp.Ex)
    hz_data_slit = sim.get_array(center=mp.Vector3(0, 0, 0),
                                 size=mp.Vector3(sx, sy, sz),
                                 component=mp.Hz)

    slabFlux = []
    slabFlux = np.append(slabFlux, slab_flux_input)
    slitFlux = []
    slitFlux = np.append(slitFlux, slit_flux_output)
    fracFlux = np.divide(slitFlux, slabFlux)
    print('normalised slit flux,',
          end=" ")  #suppress the print newline function with end=" "
    np.savetxt(
        sys.stdout, fracFlux, fmt='%7.5f'
    )  #print to stdout transmitted slit flux normalised to input flux.
    print('slab thickness,', end=" ")
    print(w)

    #-------------------------------- Next three lines ok for data file in mp meep, but writes data np times (np no. processors) in pmp.
    #f=open('fracFL.dat','ab')
    #np.savetxt(f,fracFl,fmt='%6.5f')
    #f.close()
    #----------------------------------------------------

    eps_data_slit = sim.get_array(center=mp.Vector3(0, 0, 0),
                                  size=mp.Vector3(sx, sy, sz),
                                  component=mp.Dielectric)
    hz_data_slit = sim.get_array(center=mp.Vector3(0, 0, 0),
                                 size=mp.Vector3(sx, sy, sz),
                                 component=mp.Hz)
    hz_scat = hz_data_slit - hz_data_slab
Пример #31
0
 def get_step_funcs(self, dt):
     sf = (mp.at_beginning(self.get_meep_output_comp(f))
           for f in self.dynamic_fields)
     df = (mp.at_every(dt, self.get_meep_output_comp(f))
           for f in self.static_fields)
     return (*sf, *df)
Пример #32
0
def main(args):
    """
    Args:
       * **fields** (boolean): If true, outputs the fields at the relevant waveguide cross-sections (top-down and side-view)
       * **output_directory** (string): Name of the output directory (for storing the fields)
       * **eps_input_file** (string): Name of the hdf5 file that defines the geometry through prisms
       * **input_pol** (string): Either "TE", or "TM", corresponding to the desired input mode.  Defaults to "TE"
       * **res** (int): Resolution of the MEEP simulation
       * **nfreq** (int): The number of wavelength points to record in the transmission/reflection spectra
       * **input_direction** (1 or -1): Direction of propagation for the input eigenmode.  If +1, goes in +x, else if -1, goes in -x.  Defaults to +1.
       * **dpml** (float): Length (in microns) of the perfectly-matched layer (PML) at simulation boundaries.  Defaults to 0.5 um.
       * **wl_center** (float): Center wavelength (in microns)
       * **wl_span** (float): Wavelength span (determines the pulse width)
       * **port_vcenter** (float): Vertical center of the waveguide
       * **port_height** (float): Height of the port cross-section (flux plane)
       * **port_width** (float): Width of the port cross-section (flux plane)
       * **source_offset** (float): Offset (in x-direction) between reflection monitor and source.  Defaults to 0.1 um.
       * **center_x** (float): x-coordinate of the center of the simulation region
       * **center_y** (float): y-coordinate of the center of the simulation region
       * **center_z** (float): z-coordinate of the center of the simulation region
       * **sx** (float): Size of the simulation region in x-direction
       * **sx** (float): Size of the simulation region in y-direction
       * **sz** (float): Size of the simulation region in z-direction
       * **port_coords** (list): List of the port coordinates (variable length), in the format [x1, y1, x2, y2, x3, y3, ...] (*must* be even)
    """
    #Boolean inputs
    fields = args.fields

    #String inputs
    output_directory = args.output_directory
    eps_input_file = args.eps_input_file
    input_pol = args.input_pol

    #Int inputs
    res = args.res
    nfreq = args.nfreq
    input_direction = args.input_direction

    #Float inputs
    dpml = args.dpml
    wl_center = args.wl_center
    wl_span = args.wl_span
    port_vcenter = args.port_vcenter
    port_height = args.port_height
    port_width = args.port_width
    source_offset = args.source_offset
    center_x, center_y, center_z = args.center_x, args.center_y, args.center_z
    sx, sy, sz = args.sx, args.sy, args.sz

    #List of floats
    port_coords = [float(x) for x in args.port_coords[0].split(" ")]
    ports = [(port_coords[2 * i], port_coords[2 * i + 1])
             for i in range(int(len(port_coords) / 2))]

    if input_pol == "TE":
        parity = mp.ODD_Z
    elif input_pol == "TM":
        parity = mp.EVEN_Z
    else:
        raise ValueError(
            "Warning! Improper value of 'input_pol' was passed to mcts.py (input_pol given ="
            + str(input_pol) + ")")

    if len(port_coords) % 2 != 0:
        raise ValueError(
            "Warning! Improper port_coords was passed to `meep_compute_transmission_spectra`.  Must be even number of port_coords in [x1, y1, x2, y2, ..] format."
        )

    # Setup the simulation geometries

    prism_objects = get_prism_objects(eps_input_file)
    geometry = []
    for p in prism_objects:
        #        print('vertices='+str(p['vlist']))
        #        print('axis = '+str(mp.Vector3(0,1,0)))
        #        print('height = '+str(p['height']))
        print('material = ' + str(p['eps']))
        #        print('\n')
        geometry.append(
            mp.Prism(p['vlist'],
                     axis=mp.Vector3(0, 1, 0),
                     height=p['height'],
                     material=mp.Medium(epsilon=p['eps'])))

    # Setup the simulation sources
    fmax = 1.0 / (wl_center - 0.5 * wl_span)
    fmin = 1.0 / (wl_center + 0.5 * wl_span)
    fcen = (fmax + fmin) / 2.0
    df = fmax - fmin
    if abs(abs(input_direction) - 1) > 1E-6:
        print(input_direction)
        raise ValueError("Warning! input_direction is not +1 or -1.")

    # Use first port in 'ports' as the location of the eigenmode source
    sources = [
        mp.EigenModeSource(
            src=mp.GaussianSource(fcen, fwidth=df, cutoff=30),
            component=mp.ALL_COMPONENTS,
            size=mp.Vector3(0, 3 * float(port_height), 3 * float(port_width)),
            center=mp.Vector3(ports[0][0] + source_offset - center_x,
                              float(port_vcenter) - center_y,
                              ports[0][1] - center_z),
            eig_match_freq=True,
            eig_parity=parity,
            eig_kpoint=mp.Vector3(float(input_direction) * wl_center, 0, 0),
            eig_resolution=2 * res if res > 16 else 32,
        )
    ]

    # Setup the simulation
    sim = mp.Simulation(cell_size=mp.Vector3(sx, sy, sz),
                        boundary_layers=[mp.PML(dpml)],
                        geometry=geometry,
                        sources=sources,
                        dimensions=3,
                        resolution=res,
                        filename_prefix=False)
    """ Add power flux monitors """
    print("ADDING FLUX MONITORS")
    flux_plane_objects = []

    for port in ports:
        flux_region = mp.FluxRegion(size=mp.Vector3(0, float(port_height),
                                                    float(port_width)),
                                    center=mp.Vector3(
                                        float(port[0]) - center_x,
                                        float(port_vcenter) - center_y,
                                        float(port[1]) - center_z))
        fpo = sim.add_flux(fcen, df, nfreq, flux_region)
        flux_plane_objects.append(fpo)

    sim.use_output_directory(str(output_directory))
    """ Run the simulation """
    """ Monitor the amplitude in the center of the structure """
    decay_pt = mp.Vector3(0, port_vcenter, 0)

    sv = mp.Volume(size=mp.Vector3(sx, sy, 0), center=mp.Vector3(0, 0, 0))
    tv = mp.Volume(size=mp.Vector3(sx, 0, sz),
                   center=mp.Vector3(0, port_vcenter, 0))

    print("RUNNING SIMULATION")

    if fields:
        sim.run(mp.at_beginning(mp.output_epsilon),
                mp.at_beginning(
                    mp.with_prefix(str("sideview-"),
                                   mp.in_volume(sv, mp.output_epsilon))),
                mp.at_beginning(
                    mp.with_prefix(str("topview-"),
                                   mp.in_volume(tv, mp.output_epsilon))),
                mp.at_every(
                    1.0,
                    mp.to_appended(str("ez-sideview"),
                                   mp.in_volume(sv, mp.output_efield_z))),
                mp.at_every(
                    1.0,
                    mp.to_appended(str("ez-topview"),
                                   mp.in_volume(tv, mp.output_efield_z))),
                until_after_sources=mp.stop_when_fields_decayed(
                    20, mp.Ez, decay_pt, 1e-4))
    else:
        sim.run(until_after_sources=mp.stop_when_fields_decayed(
            20, mp.Ez, decay_pt, 1e-4))

    sim.display_fluxes(*flux_plane_objects)

    print("FINISHED SIMULATION")
Пример #33
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))
Пример #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
#
dft_objx = []
for i in range(len(flux_freqsX)):
    dft_objx = np.append(
        dft_objx,
        sim.add_dft_fields([polarisation],
                           flux_freqsX[i],
                           flux_freqsX[i],
                           1,
                           where=monitor))

dft_obj = sim.add_dft_fields([polarisation], fcen, fcen, 1, where=monitor)

sim.use_output_directory('flux-out_1')
sim.run(mp.in_volume(monitor, mp.at_beginning(mp.output_epsilon)),
        mp.in_volume(
            monitor,
            mp.to_appended("ez", mp.at_every(time_step, mp.output_efield_x))),
        until_after_sources=mp.stop_when_fields_decayed(
            add_time, polarisation, pt, decay))
'''
sim.run(until_after_sources=mp.stop_when_fields_decayed(add_time,polarisation,pt,decay))
'''

#save scattered reflected flux from the surfaces
scat_refl_data_t = mp.get_fluxes(refl_t)
scat_refl_data_b = mp.get_fluxes(refl_b)
scat_refl_data_l = mp.get_fluxes(refl_l)
scat_refl_data_r = mp.get_fluxes(refl_r)
Пример #36
0
sources = [
    mp.Source(mp.ContinuousSource(wavelength=2 * (11 * 0.5), width=20),
              component=mp.Ez,
              center=mp.Vector3(-7, -3.5),
              size=mp.Vector3(0, 1))
]

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_beginning(mp.output_mu),
        mp.to_appended("ez", mp.at_every(0.6, mp.output_efield_z)),
        until=200)
"""Post-processing"""
# plot the epsilon and mu values
eps_data = sim.get_array(center=mp.Vector3(),
                         size=cell,
                         component=mp.Dielectric)
mu_data = sim.get_array(center=mp.Vector3(),
                        size=cell,
                        component=mp.Permeability)

fig, axs = plt.subplots(2, 2)

axs[0, 0].imshow(eps_data.transpose(), cmap='binary')
Пример #37
0
    refl_fr = mp.FluxRegion(center=mp.Vector3((-0.5 * sx) + 1, 0),size=mp.Vector3(0, sy))

    # reflected flux
    refl = sim.add_flux(fcen, df, nfreq, refl_fr)

    # for normal run, load negated fields to subtract incident from refl. fields
    if not args.no_ARC:
        sim.load_minus_flux('refl-flux', refl)

    if args.no_ARC:
        pt = mp.Vector3((T_Si / 2) - (T_Si / 100), 0)
    else:
        pt = mp.Vector3((T_Si / 2) - (T_Si / 100), 0)

    sim.run(mp.at_beginning(mp.output_epsilon),until_after_sources=mp.stop_when_fields_decayed(50, mp.Ez, pt, 1e-3))

    	# for normalization run, save flux fields for refl. plane
    if args.no_ARC:
        sim.save_flux('refl-flux', refl)

    sim.display_fluxes(trans, refl)

def test(inputv):
    print(inputv)

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-n', '--no_ARC', action='store_true', default=False,
					help="Straight waveguide without bend.")
    parser.add_argument('-v')