mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Hz, mp.Vector3())
]

# run until sources are finished (and no later)
sim._run_sources_until(0, [])

# get 1D and 2D array slices
xMin = -0.25 * sx
xMax = +0.25 * sx
yMin = -0.15 * sy
yMax = +0.15 * sy

# 1D slice of Hz data
size_1d = mp.Vector3(xMax - xMin)
center_1d = mp.Vector3((xMin + xMax) / 2)
slice1d = sim.get_array(vol=mp.Volume(center_1d, size=size_1d),
                        component=mp.Hz)

# 2D slice of Hz data
size_2d = mp.Vector3(xMax - xMin, yMax - yMin)
center_2d = mp.Vector3((xMin + xMax) / 2, (yMin + yMax) / 2)
slice2d = sim.get_array(vol=mp.Volume(center_2d, size=size_2d),
                        component=mp.Hz)

# plot 1D slice
plt.subplot(1, 2, 1)
x1d = np.linspace(xMin, xMax, len(slice1d))
plt.plot(x1d, slice1d)

# plot 2D slice
plt.subplot(1, 2, 2)
Beispiel #2
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"))
Beispiel #3
0
class TestFieldFunctions(unittest.TestCase):

    cs = [mp.Ex, mp.Hz, mp.Dielectric]
    vol = mp.Volume(size=mp.Vector3(1), center=mp.Vector3())

    def init(self):
        resolution = 20

        cell = mp.Vector3(10, 10, 0)

        pml_layers = mp.PML(1.0)

        fcen = 1.0
        df = 1.0

        sources = mp.Source(src=mp.GaussianSource(fcen, fwidth=df),
                            center=mp.Vector3(),
                            component=mp.Ez)

        symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)]

        return mp.Simulation(resolution=resolution,
                             cell_size=cell,
                             boundary_layers=[pml_layers],
                             sources=[sources],
                             symmetries=symmetries)

    def init2(self):
        n = 3.4
        w = 1
        r = 1
        pad = 4
        dpml = 2
        sxy = 2 * (r + w + pad + dpml)
        cell = mp.Vector3(sxy, sxy)

        geometry = [
            mp.Cylinder(radius=r + w,
                        height=mp.inf,
                        material=mp.Medium(index=n)),
            mp.Cylinder(radius=r, height=mp.inf, material=mp.air)
        ]

        pml_layers = [mp.PML(dpml)]
        resolution = 5
        fcen = 0.118
        df = 0.010

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

        symmetries = [mp.Mirror(mp.Y)]

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

    def test_integrate_field_function(self):
        sim = self.init()
        sim.use_output_directory(temp_dir)
        sim.run(until=200)

        res1 = sim.integrate_field_function(self.cs, f)
        res2 = sim.integrate_field_function(self.cs, f, self.vol)

        self.assertAlmostEqual(res1, complex(-6.938893903907228e-18, 0.0))
        self.assertAlmostEqual(res2, 0.0j)

        sim.output_field_function("weird-function", self.cs, f)

    def test_integrate2_field_function(self):
        sim = self.init2()
        sim.run(until_after_sources=10)
        fields2 = sim.fields
        sim.reset_meep()
        sim.run(until_after_sources=10)

        res1 = sim.integrate2_field_function(fields2, [mp.Ez], [mp.Ez], f2)
        self.assertAlmostEqual(res1, 0.17158099566244897)

    def test_max_abs_field_function(self):
        sim = self.init()
        sim.run(until=200)

        self.cs = [mp.Ex, mp.Hz, mp.Dielectric]
        res = sim.max_abs_field_function(self.cs, f, self.vol)
        self.assertAlmostEqual(res, 0.27593732304637586)
Beispiel #4
0
import meep as mp
import numpy as np
from numpy import linalg as LA
import matplotlib.pyplot as plt

n = 3.4
w = 1
r = 1
pad = 4
dpml = 2

sxy = 2 * (r + w + pad + dpml)
vol = mp.Volume(mp.Vector3(), size=mp.Vector3(sxy - 2 * dpml, sxy - 2 * dpml))

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

fcen = 0.118
df = 0.08
src = mp.Source(mp.ContinuousSource(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,
                    force_complex_fields=True,
                    symmetries=[mp.Mirror(mp.Y)],
                    boundary_layers=[mp.PML(dpml)])

num_tols = 5
Beispiel #5
0
    def test_animation_output(self):
        # ------------------------- #
        # Check over 2D domain
        # ------------------------- #

        sim = setup_sim()  # generate 2D simulation

        Animate = mp.Animate2D(sim,
                               fields=mp.Ez,
                               realtime=False,
                               normalize=False)  # Check without normalization
        Animate_norm = mp.Animate2D(sim, mp.Ez, realtime=False,
                                    normalize=True)  # Check with normalization

        # test both animation objects during same run
        sim.run(mp.at_every(1, Animate), mp.at_every(1, Animate_norm), until=5)

        # Test outputs
        Animate.to_mp4(5, os.path.join(temp_dir,
                                       'test_2D.mp4'))  # Check mp4 output
        Animate.to_gif(150, os.path.join(temp_dir,
                                         'test_2D.gif'))  # Check gif output
        Animate.to_jshtml(10)  # Check jshtml output
        Animate_norm.to_mp4(5, os.path.join(
            temp_dir, 'test_2D_norm.mp4'))  # Check mp4 output
        Animate_norm.to_gif(150, os.path.join(
            temp_dir, 'test_2D_norm.gif'))  # Check gif output
        Animate_norm.to_jshtml(10)  # Check jshtml output

        # ------------------------- #
        # Check over 3D domain
        # ------------------------- #
        sim = setup_sim(5)  # generate 2D simulation

        Animate_xy = mp.Animate2D(
            sim, fields=mp.Ey, realtime=False,
            normalize=True)  # Check without normalization
        Animate_xz = mp.Animate2D(sim, mp.Ey, realtime=False,
                                  normalize=True)  # Check with normalization

        # test both animation objects during same run
        sim.run(mp.at_every(
            1,
            mp.in_volume(
                mp.Volume(center=mp.Vector3(),
                          size=mp.Vector3(sim.cell_size.x, sim.cell_size.y)),
                Animate_xy)),
                mp.at_every(
                    1,
                    mp.in_volume(
                        mp.Volume(center=mp.Vector3(),
                                  size=mp.Vector3(sim.cell_size.x, 0,
                                                  sim.cell_size.z)),
                        Animate_xz)),
                until=5)

        # Test outputs
        Animate_xy.to_mp4(5,
                          os.path.join(temp_dir,
                                       'test_3D_xy.mp4'))  # Check mp4 output
        Animate_xy.to_gif(150,
                          os.path.join(temp_dir,
                                       'test_3D_xy.gif'))  # Check gif output
        Animate_xy.to_jshtml(10)  # Check jshtml output
        Animate_xz.to_mp4(5,
                          os.path.join(temp_dir,
                                       'test_3D_xz.mp4'))  # Check mp4 output
        Animate_xz.to_gif(150,
                          os.path.join(temp_dir,
                                       'test_3D_xz.gif'))  # Check gif output
        Animate_xz.to_jshtml(10)  # Check jshtml output
Beispiel #6
0
        eig_band=1,
        direction=mp.NO_DIRECTION,
        eig_kpoint=kpoint,
        size=source_size,
        eig_parity=mp.EVEN_Y,  # TE mode
        center=source_center)
]

#----------------------------------------------------------------------
#- geometric objects
#----------------------------------------------------------------------

Nx = 10
Ny = 10

design_region = mp.Volume(center=mp.Vector3(), size=mp.Vector3(1, 1, 0))
rho_vector = 11 * np.random.rand(Nx * Ny) + 1
basis = mpa.BilinearInterpolationBasis(volume=design_region,
                                       Nx=Nx,
                                       Ny=Ny,
                                       rho_vector=rho_vector)

geometry = [
    mp.Block(center=mp.Vector3(x=-Sx / 4),
             material=mp.Medium(index=3.45),
             size=mp.Vector3(Sx / 2, 0.5, 0)),  # horizontal waveguide
    mp.Block(center=mp.Vector3(),
             material=mp.Medium(index=3.45),
             size=mp.Vector3(0.5, mp.inf, 0)),  # vertical waveguide
    mp.Block(center=design_region.center,
             size=design_region.size,
source_time_profile = mp.GaussianSource(fcen, fwidth=df)
sources = [mp.Source(src=source_time_profile, component=mp.Ez, center=origin)]

symmetries = [mp.Mirror(mp.Y)] if use_symmetry else []

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

# mv_box is the region within which we compute modal volume
mv_box_size = mp.Vector3(L_inner, L_inner, mp.inf)
mv_box = mp.Volume(center=origin, size=mv_box_size)
dft_cell = sim.add_dft_fields([mp.Ex, mp.Ey, mp.Ez],
                              fcen - df,
                              fcen + df,
                              3,
                              where=mv_box)

# Timestep until the sources are finished, pausing at fixed intervals to
# compare the modal volume within mv_box as computed from time-domain fields
# (a) by the built-in mode-volume computation in libmeep,
# (b) by the python routine above based on array metadata
source_end_time = source_time_profile.swigobj.last_time_max()
measurement_interval = source_end_time / 10.0
next_measurement_time = sim.round_time(
) + 2 * measurement_interval  # skip first interval
td_values = 0
Beispiel #8
0
    def test_get_dft_array(self):
        sim = self.init()
        sim.init_sim()
        dft_fields = sim.add_dft_fields([mp.Ez], self.fcen, 0, 1)
        fr = mp.FluxRegion(mp.Vector3(),
                           size=mp.Vector3(self.sxy, self.sxy),
                           direction=mp.X)
        dft_flux = sim.add_flux(self.fcen, 0, 1, fr)

        # volumes with zero thickness in x and y directions to test collapsing
        # of empty dimensions in DFT array and HDF5 output routines
        thin_x_volume = mp.Volume(center=mp.Vector3(0.35 * self.sxy),
                                  size=mp.Vector3(y=0.8 * self.sxy))
        thin_x_flux = sim.add_dft_fields([mp.Ez],
                                         self.fcen,
                                         0,
                                         1,
                                         where=thin_x_volume)
        thin_y_volume = mp.Volume(center=mp.Vector3(y=0.25 * self.sxy),
                                  size=mp.Vector3(x=self.sxy))
        thin_y_flux = sim.add_flux(self.fcen, 0, 1,
                                   mp.FluxRegion(volume=thin_y_volume))

        sim.run(until_after_sources=100)

        # test proper collapsing of degenerate dimensions in HDF5 files and arrays
        thin_x_array = sim.get_dft_array(thin_x_flux, mp.Ez, 0)
        thin_y_array = sim.get_dft_array(thin_y_flux, mp.Ez, 0)
        np.testing.assert_equal(thin_x_array.ndim, 1)
        np.testing.assert_equal(thin_y_array.ndim, 1)

        sim.output_dft(thin_x_flux, os.path.join(self.temp_dir, 'thin-x-flux'))
        sim.output_dft(thin_y_flux, os.path.join(self.temp_dir, 'thin-y-flux'))

        with h5py.File(os.path.join(self.temp_dir, 'thin-x-flux.h5'),
                       'r') as thin_x:
            thin_x_h5 = mp.complexarray(thin_x['ez_0.r'][()],
                                        thin_x['ez_0.i'][()])

        with h5py.File(os.path.join(self.temp_dir, 'thin-y-flux.h5'),
                       'r') as thin_y:
            thin_y_h5 = mp.complexarray(thin_y['ez_0.r'][()],
                                        thin_y['ez_0.i'][()])

        tol = 1e-6
        self.assertClose(thin_x_array, thin_x_h5, epsilon=tol)
        self.assertClose(thin_y_array, thin_y_h5, epsilon=tol)

        # compare array data to HDF5 file content for fields and flux
        fields_arr = sim.get_dft_array(dft_fields, mp.Ez, 0)
        flux_arr = sim.get_dft_array(dft_flux, mp.Ez, 0)

        sim.output_dft(dft_fields, os.path.join(self.temp_dir, 'dft-fields'))
        sim.output_dft(dft_flux, os.path.join(self.temp_dir, 'dft-flux'))

        with h5py.File(os.path.join(self.temp_dir, 'dft-fields.h5'),
                       'r') as fields, h5py.File(
                           os.path.join(self.temp_dir, 'dft-flux.h5'),
                           'r') as flux:
            exp_fields = mp.complexarray(fields['ez_0.r'][()],
                                         fields['ez_0.i'][()])
            exp_flux = mp.complexarray(flux['ez_0.r'][()], flux['ez_0.i'][()])

        tol = 1e-6
        self.assertClose(exp_fields, fields_arr, epsilon=tol)
        self.assertClose(exp_flux, flux_arr, epsilon=tol)
    mp.Source(mp.GaussianSource(fcen, fwidth=df), mp.Hz, mp.Vector3())
]

# run until sources are finished (and no later)
sim._run_sources_until(0, [])

# get 1D and 2D array slices
xMin = -0.25 * sx
xMax = +0.25 * sx
yMin = -0.15 * sy
yMax = +0.15 * sy

# 1D slice of Hz data
size_1d = mp.Vector3(xMax - xMin)
center_1d = mp.Vector3((xMin + xMax) / 2)
slice1d = sim.get_array(mp.Volume(center_1d, size=size_1d), component=mp.Hz)

# 2D slice of Hz data
size_2d = mp.Vector3(xMax - xMin, yMax - yMin)
center_2d = mp.Vector3((xMin + xMax) / 2, (yMin + yMax) / 2)
slice2d = sim.get_array(mp.Volume(center_2d, size=size_2d), component=mp.Hz)

# plot 1D slice
plt.subplot(1, 2, 1)
x1d = np.linspace(xMin, xMax, len(slice1d))
plt.plot(x1d, slice1d)

# plot 2D slice
plt.subplot(1, 2, 2)
dy = (yMax - yMin) / slice2d.shape[1]
dx = (xMax - xMin) / slice2d.shape[0]
Beispiel #10
0
rot_angle = 0  # CCW rotation angle about z axis (0: +y axis)
beam_kdir = mp.Vector3(0, 1, 0).rotate(mp.Vector3(
    0, 0, 1), math.radians(rot_angle))  # beam propagation direction
beam_w0 = 0.8  # beam waist radius
beam_E0 = mp.Vector3(0, 0, 1)
fcen = 1
sources = [
    mp.GaussianBeamSource(src=mp.ContinuousSource(fcen),
                          center=mp.Vector3(0, -0.5 * s + dpml + 1.0),
                          size=mp.Vector3(s),
                          beam_x0=beam_x0,
                          beam_kdir=beam_kdir,
                          beam_w0=beam_w0,
                          beam_E0=beam_E0)
]

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

sim.run(until=20)

sim.plot2D(fields=mp.Ez,
           output_plane=mp.Volume(center=mp.Vector3(),
                                  size=mp.Vector3(s - 2 * dpml, s - 2 * dpml)))

plt.savefig('Ez_angle{}.png'.format(rot_angle),
            bbox_inches='tight',
            pad_inches=0)
Beispiel #11
0
def _get_waveguide_mode(sim: mp.Simulation,
                        src: WaveguideModeSource) -> MeepWaveguideMode:
    """Computes the waveguide mode in Meep (via MPB).

    Args:
        sim: Meep simulation object.
        src: Waveguide mode source properties.

    Returns:
        A tuple `(mode_fields, mode_comps, xyzw)`. `mode_fields`
        is the sampled transverse fields of the mode. `mode_fields` is an array
        with four elements, one for each transverse element as determined by
        `mode_comps`. `xyzw` is the Meep array metadata for the region: It is
        a 4-element tuple `(x, y, z, w)` where the `x`, `y`, and `z` are arrays
        indicating the cell coordinates where the fields are sampled and `w`
        is the volume weight factor used when calculating integrals involving
        the fields (see Meep documentation for details).
    """

    wlen = src.wavelength
    fcen = 1 / wlen
    normal_axis = gridlock.axisvec2axis(src.normal)

    # Extract the eigenmode from Meep.
    # `xyzw` is a tuple `(x_coords, y_coords, z_coords, weights)` where
    # `x_coords`, `y_coords`, and `z_coords` is a list of the coordinates of
    # the Yee cells within the source region.

    # TODO(logansu): Remove this hack when Meep fixes its bugs with
    # `get_array_metadata`. For now, we ensure that the slices are 3D, otherwise
    # the values returned for `w` can be wrong and undeterministic.
    dx = 1 / sim.resolution
    # Count number of dimensions are effectively "zero". This is used to
    # determine the dimensionality of the source (1D or 2D).
    overlap_dims = 3 - sum(val <= dx for val in src.extents)
    extents = [val if val >= dx else dx for val in src.extents]
    xyzw = sim.get_array_metadata(center=src.center, size=extents)

    # TODO(logansu): Understand how to guess a k-vector. Is it necessary?
    k_guess = [0, 0, 0]
    k_guess[normal_axis] = fcen
    k_guess = mp.Vector3(*k_guess)
    mode_dirs = [mp.X, mp.Y, mp.Z]
    mode_data = sim.get_eigenmode(
        fcen, mode_dirs[normal_axis],
        mp.Volume(center=src.center, size=src.extents), src.mode_num + 1,
        k_guess)

    # Determine which field components are relevant for TFSF source (i.e. the
    # field components tangential to the propagation direction.
    # For simplicity, we order them in circular permutation order (x->y->z) with
    # E fields followed by H fields.
    if normal_axis == 0:
        field_comps = [mp.Ey, mp.Ez, mp.Hy, mp.Hz]
    elif normal_axis == 1:
        field_comps = [mp.Ez, mp.Ex, mp.Hz, mp.Hx]
    else:
        field_comps = [mp.Ex, mp.Ey, mp.Hx, mp.Hy]

    # Extract the actual field values for the relevant field components.
    # Note that passing in `mode_data.amplitude` into `amp_func` parameter of
    # `mp.Source` seems to give a bad source.
    mode_fields = []
    for c in field_comps:
        field_slice = []
        for x, y, z in itertools.product(xyzw[0], xyzw[1], xyzw[2]):
            field_slice.append(mode_data.amplitude(mp.Vector3(x, y, z), c))
        field_slice = np.reshape(field_slice,
                                 (len(xyzw[0]), len(xyzw[1]), len(xyzw[2])))
        mode_fields.append(field_slice)

    # Sometimes Meep returns an extra layer of fields when one of the dimensions
    # of the overlap region is zero. In that case, only use the first slice.
    field_slicer = [slice(None), slice(None), slice(None)]
    field_slicer[normal_axis] = slice(0, 1)
    field_slicer = tuple(field_slicer)
    for i in range(4):
        mode_fields[i] = mode_fields[i][field_slicer]

    xyzw[3] = np.reshape(xyzw[3], (len(xyzw[0]), len(xyzw[1]), len(xyzw[2])))
    xyzw[3] = xyzw[3][field_slicer]
    # TODO(logansu): See above TODO about hacking `get_array_metadata`.
    # For now, just guess the correct value. The error introduced by this
    # occurs at the edges of the source/overlap where the fields are small
    # anyway.
    xyzw[3][:] = dx**overlap_dims

    # Fix the phase of the mode by normalizing the phase by the phase where
    # the electric field as largest magnitude.
    arr = np.hstack([mode_fields[0].flatten(), mode_fields[1].flatten()])
    phase_norm = np.angle(arr[np.argmax(np.abs(arr))])
    phase_norm = np.exp(1j * phase_norm)
    mode_fields = [f / phase_norm for f in mode_fields]

    return MeepWaveguideMode(wlen, field_comps, mode_fields, xyzw)
Beispiel #12
0
 def get_arr2(sim):
     eps['arr2'] = sim.get_array(mp.Volume(mp.Vector3(),
                                           mp.Vector3(10, 10)),
                                 component=mp.Dielectric)
 def volume(self):
     return mp.Volume(center=self.center, size=self.size)
Beispiel #14
0
d1 = 0.2

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

nearfield = sim.add_near2far(
    fcen, 0, 1,
    mp.Near2FarRegion(mp.Vector3(0, 0.5 * w + d1),
                      size=mp.Vector3(2 * dpml - sx)),
    mp.Near2FarRegion(mp.Vector3(-0.5 * sx + dpml, 0.5 * w + 0.5 * d1),
                      size=mp.Vector3(0, d1),
                      weight=-1.0),
    mp.Near2FarRegion(mp.Vector3(0.5 * sx - dpml, 0.5 * w + 0.5 * d1),
                      size=mp.Vector3(0, d1)))

sim.run(until_after_sources=mp.stop_when_fields_decayed(
    50, mp.Hz, mp.Vector3(0.12, -0.37), 1e-8))

d2 = 20
h = 4

sim.output_farfields(
    nearfield, "spectra-{}-{}-{}".format(d1, d2, h),
    mp.Volume(mp.Vector3(0, (0.5 * w) + d2 + (0.5 * h)),
              size=mp.Vector3(sx - 2 * dpml, h)), resolution)
Beispiel #15
0
    ]

sim = mp.Simulation(cell_size=cell_size,
                    resolution=resolution,
                    boundary_layers=pml_layers,
                    sources=sources,
                    geometry=geometry,
                    symmetries=[mp.Mirror(mp.Y)] if rot_angle == 0 else [])

if compute_flux:
    tran = sim.add_flux(
        fsrc, 0, 1, mp.FluxRegion(center=mp.Vector3(x=5),
                                  size=mp.Vector3(y=14)))
    sim.run(until_after_sources=50)
    print("flux:, {:.6f}".format(mp.get_fluxes(tran)[0]))
else:
    sim.run(until=100)
    nonpml_vol = mp.Volume(center=mp.Vector3(), size=mp.Vector3(10, 10, 0))
    eps_data = sim.get_array(vol=nonpml_vol, component=mp.Dielectric)
    ez_data = sim.get_array(vol=nonpml_vol, component=mp.Ez)
    plt.figure()
    plt.imshow(np.flipud(np.transpose(eps_data)),
               interpolation='spline36',
               cmap='binary')
    plt.imshow(np.flipud(np.transpose(ez_data)),
               interpolation='spline36',
               cmap='RdBu',
               alpha=0.9)
    plt.axis('off')
    plt.show()
def adjoint_solver(design_params, mon_type, frequencies=None, mat2=silicon):
    matgrid = mp.MaterialGrid(mp.Vector3(Nx, Ny),
                              mp.air,
                              mat2,
                              weights=np.ones((Nx, Ny)))

    matgrid_region = mpa.DesignRegion(
        matgrid,
        volume=mp.Volume(center=mp.Vector3(),
                         size=mp.Vector3(design_region_size.x,
                                         design_region_size.y, 0)))

    matgrid_geometry = [
        mp.Block(center=matgrid_region.center,
                 size=matgrid_region.size,
                 material=matgrid)
    ]

    geometry = waveguide_geometry + matgrid_geometry

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        boundary_layers=pml_xy,
                        sources=wvg_source,
                        geometry=geometry)

    if not frequencies:
        frequencies = [fcen]

    if mon_type.name == 'EIGENMODE':
        obj_list = [
            mpa.EigenmodeCoefficient(
                sim,
                mp.Volume(center=mp.Vector3(0.5 * sxy - dpml - 0.1),
                          size=mp.Vector3(0, sxy - 2 * dpml, 0)),
                1,
                eig_parity=eig_parity)
        ]

        def J(mode_mon):
            return npa.power(npa.abs(mode_mon), 2)
    elif mon_type.name == 'DFT':
        obj_list = [
            mpa.FourierFields(
                sim,
                mp.Volume(center=mp.Vector3(1.25), size=mp.Vector3(0.25, 1,
                                                                   0)), mp.Ez)
        ]

        def J(mode_mon):
            return npa.power(npa.abs(mode_mon[:, 4, 10]), 2)

    opt = mpa.OptimizationProblem(simulation=sim,
                                  objective_functions=J,
                                  objective_arguments=obj_list,
                                  design_regions=[matgrid_region],
                                  frequencies=frequencies)

    f, dJ_du = opt([design_params])

    sim.reset_meep()

    return f, dJ_du
Beispiel #17
0
symmetries = [mp.Mirror(mp.Y, phase=-1), mp.Mirror(mp.X, phase=-1)]

d1 = 0.2

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

nearfield = sim.add_near2far(
    fcen, 0, 1,
    mp.Near2FarRegion(mp.Vector3(0, 0.5 * w + d1),
                      size=mp.Vector3(2 * dpml - sx)),
    mp.Near2FarRegion(mp.Vector3(-0.5 * sx + dpml, 0.5 * w +
                                 0.5 * d1), size=mp.Vector3(0, d1), weight=-1.0),
    mp.Near2FarRegion(mp.Vector3(0.5 * sx - dpml, 0.5 *
                                 w + 0.5 * d1), size=mp.Vector3(0, d1))
)

sim.run(until_after_sources=mp.stop_when_fields_decayed(
    50, mp.Hz, mp.Vector3(0.12, -0.37), 1e-8))

d2 = 20
h = 4

sim.output_farfields(nearfield, "spectra-{}-{}-{}".format(d1, d2, h), resolution,
                     where=mp.Volume(mp.Vector3(0, (0.5 * w) + d2 + (0.5 * h)),
                                     size=mp.Vector3(sx - 2 * dpml, h)))
                  component=mp.Ez)
    ]

sim = mp.Simulation(cell_size=cell_size,
                    resolution=resolution,
                    boundary_layers=pml_layers,
                    sources=sources,
                    geometry=geometry,
                    symmetries=[mp.Mirror(mp.Y)] if rot_angle == 0 else [])

if compute_flux:
    tran = sim.add_flux(
        fsrc, 0, 1, mp.FluxRegion(center=mp.Vector3(x=5),
                                  size=mp.Vector3(y=14)))
    sim.run(until_after_sources=50)
    res = sim.get_eigenmode_coefficients(
        tran, [1],
        eig_parity=mp.EVEN_Y + mp.ODD_Z if rot_angle == 0 else mp.ODD_Z,
        direction=mp.NO_DIRECTION,
        kpoint_func=lambda f, n: kpoint)
    print("flux:, {:.6f}, {:.6f}".format(
        mp.get_fluxes(tran)[0],
        abs(res.alpha[0, 0, 0])**2))
else:
    sim.run(until=100)
    sim.plot2D(output_plane=mp.Volume(center=mp.Vector3(),
                                      size=mp.Vector3(10, 10)),
               fields=mp.Ez,
               field_parameters={'alpha': 0.9})
    plt.show()
    mp.FluxRegion(center=mp.Vector3(+0.5 * sxy, 0),
                  size=mp.Vector3(0, sxy),
                  weight=+1),
    mp.FluxRegion(center=mp.Vector3(-0.5 * sxy, 0),
                  size=mp.Vector3(0, sxy),
                  weight=-1))

sim.run(until_after_sources=mp.stop_when_fields_decayed(
    50, src_cmpt, mp.Vector3(), 1e-8))

near_flux = mp.get_fluxes(flux_box)[0]

r = 1000 / fcen  # half side length of far-field square box OR radius of far-field circle
res_ff = 1  # resolution of far fields (points/μm)
far_flux_box = (nearfield_box.flux(
    mp.Y, mp.Volume(center=mp.Vector3(y=r), size=mp.Vector3(2 * r)),
    res_ff)[0] - nearfield_box.flux(
        mp.Y, mp.Volume(center=mp.Vector3(y=-r), size=mp.Vector3(2 * r)),
        res_ff)[0] + nearfield_box.flux(
            mp.X, mp.Volume(center=mp.Vector3(r), size=mp.Vector3(y=2 * r)),
            res_ff)[0] - nearfield_box.flux(
                mp.X, mp.Volume(center=mp.Vector3(-r),
                                size=mp.Vector3(y=2 * r)), res_ff)[0])

npts = 100  # number of points in [0,2*pi) range of angles
angles = 2 * math.pi / npts * np.arange(npts)

E = np.zeros((npts, 3), dtype=np.complex128)
H = np.zeros((npts, 3), dtype=np.complex128)
for n in range(npts):
    ff = sim.get_farfield(
Beispiel #20
0
sx = 14 * rad  # Size of inner shell
sy = 14 * rad  # Size of inner shell
sx0 = sx + 2 * dpml  # size of cell in X direction
sy0 = sy + 2 * dpml  # size of cell in Y direction
mx = 8 * rad
fx = 4 * rad
sc = 6 * rad  # source center coordinate shift
sw = sx0  # source width, needs to be bigger than inner cell to generate only plane-waves
nfreq = 100  # number of frequencies at which to compute flux
courant = 0.5  # numerical stability, default is 0.5, should be lower in case refractive index n<1
time_step = 0.05  # time step to measure flux
add_time = 2  # additional time until field decays 1e-6
resolution = 2500  # resolution pixels/um (pixels/micrometers)
decay = 1e-12  # decay limit condition for the field measurement
cell = mp.Vector3(sx0, sy0, 0)
monitor = mp.Volume(center=mp.Vector3(0, 0, 0), size=mp.Vector3(mx, mx, 0))
'''

  +--------------------Cell-------------------+
  |                                           |
  |                    PML                    |
  |     +-------------------------------+     |
  |     |                               |     |
  |     |              .pt              |     |
  |     |                               |     |
  |     |     +---+monitor-area---+     |     |
  |     |     |                   |     |     |
  |     |     |   +---Flux----+   |     |     |
  |     |     |   |           |   |     |     |
  |     |     |   |    XXX    |   |     |     |
  |     |     |   |   XXXXX   |   |     |     |
def Simulation(period, grating_t, grating_w, sep, mthick, mat):

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

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

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

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

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

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

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

    return ()
Beispiel #22
0
def plot_xsection(sim, center=(0, 0, 0), size=(0, 2, 2)):
    """
    sim: simulation object
    """
    sim.plot2D(output_plane=mp.Volume(center=center, size=size))
Beispiel #23
0
    def init_problem(self, args):

        #----------------------------------------
        # size of computational cell
        #----------------------------------------
        lcen = 1.0 / args.fcen
        dpml = 0.5 * lcen if args.dpml == -1.0 else args.dpml
        dair = 0.5 * args.w_in if args.dair == -1.0 else args.dair
        sx = dpml + args.l_stub + args.l_design + args.l_stub + dpml
        sy = dpml + dair + args.h_design + dair + dpml
        cell_size = mp.Vector3(sx, sy, 0.0)

        #----------------------------------------
        #- design region
        #----------------------------------------
        design_center = origin
        design_size = mp.Vector3(args.l_design, args.h_design, 0.0)
        design_region = mp.Volume(center=design_center, size=design_size)

        #----------------------------------------
        #- objective regions
        #----------------------------------------
        x_in = -0.5 * (args.l_design + args.l_stub)
        x_out = +0.5 * (args.l_design + args.l_stub)
        y_out1 = +0.25 * args.h_design
        y_out2 = -0.25 * args.h_design

        flux_in = FluxLine(x_in, 0.0, 2.0 * args.w_in, mp.X, 'in')
        flux_out1 = FluxLine(x_out, y_out1, 2.0 * args.w_out1, mp.X, 'out1')
        flux_out2 = FluxLine(x_out, y_out2, 2.0 * args.w_out2, mp.X, 'out2')

        objective_regions = [flux_in, flux_out1, flux_out2]

        #----------------------------------------
        #- optional extra regions for visualization if the --full-dfts options is present.
        #----------------------------------------
        extra_regions = [mp.Volume(center=origin, size=cell_size)
                         ] if args.full_dfts else []

        #----------------------------------------
        # forward source region
        #----------------------------------------
        source_center = (x_in - 0.25 * args.l_stub) * xHat
        source_size = 2.0 * args.w_in * yHat

        #----------------------------------------
        # basis set
        #----------------------------------------
        basis = FiniteElementBasis(args.l_design, args.h_design, args.nfe)

        #----------------------------------------
        #- objective function
        #----------------------------------------
        fstr = ('Abs(P1_out1)**2' + '+0.0*(P1_out1 + M1_out1)' +
                '+0.0*(P1_out2 + M1_out2)' +
                '+0.0*(P1_in   + M1_in + S_out1 + S_out2 + S_in)')

        #----------------------------------------
        #- internal storage for variables needed later
        #----------------------------------------
        self.args = args
        self.dpml = dpml
        self.cell_size = cell_size
        self.basis = basis
        self.design_center = origin
        self.design_size = design_size
        self.source_center = source_center
        self.source_size = source_size

        return fstr, objective_regions, extra_regions, design_region, basis
    def test_farfield(self):
        resolution = 50
        sxy = 4
        dpml = 1
        cell = mp.Vector3(sxy + 2 * dpml, sxy + 2 * dpml)

        pml_layers = mp.PML(dpml)

        fcen = 1.0
        df = 0.4

        sources = mp.Source(src=mp.GaussianSource(fcen, fwidth=df),
                            center=mp.Vector3(),
                            component=mp.Ez)

        symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)]

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

        nearfield_box = sim.add_near2far(
            fcen, 0, 1,
            mp.Near2FarRegion(mp.Vector3(y=0.5 * sxy), size=mp.Vector3(sxy)),
            mp.Near2FarRegion(mp.Vector3(y=-0.5 * sxy),
                              size=mp.Vector3(sxy),
                              weight=-1),
            mp.Near2FarRegion(mp.Vector3(0.5 * sxy), size=mp.Vector3(y=sxy)),
            mp.Near2FarRegion(mp.Vector3(-0.5 * sxy),
                              size=mp.Vector3(y=sxy),
                              weight=-1))

        flux_box = sim.add_flux(
            fcen, 0, 1,
            mp.FluxRegion(mp.Vector3(y=0.5 * sxy), size=mp.Vector3(sxy)),
            mp.FluxRegion(mp.Vector3(y=-0.5 * sxy),
                          size=mp.Vector3(sxy),
                          weight=-1),
            mp.FluxRegion(mp.Vector3(0.5 * sxy), size=mp.Vector3(y=sxy)),
            mp.FluxRegion(mp.Vector3(-0.5 * sxy),
                          size=mp.Vector3(y=sxy),
                          weight=-1))

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

        near_flux = mp.get_fluxes(flux_box)[0]

        r = 1000 / fcen  # radius of far field circle
        npts = 100  # number of points in [0,2*pi) range of angles
        E = np.zeros((npts, 3), dtype=np.complex128)
        H = np.zeros((npts, 3), dtype=np.complex128)
        for n in range(npts):
            ff = sim.get_farfield(
                nearfield_box,
                mp.Vector3(r * math.cos(2 * math.pi * n / npts),
                           r * math.sin(2 * math.pi * n / npts)))
            E[n, :] = [np.conj(ff[j]) for j in range(3)]
            H[n, :] = [ff[j + 3] for j in range(3)]

        Px = np.real(E[:, 1] * H[:, 2] - E[:, 2] * H[:, 1])
        Py = np.real(E[:, 2] * H[:, 0] - E[:, 0] * H[:, 2])
        Pr = np.sqrt(np.square(Px) + np.square(Py))
        far_flux_circle = np.sum(Pr) * 2 * np.pi * r / len(Pr)

        rr = 20 / fcen  # length of far field square box
        far_flux_square = (
            nearfield_box.flux(
                mp.Y,
                mp.Volume(center=mp.Vector3(y=0.5 * rr), size=mp.Vector3(rr)),
                resolution)[0] - nearfield_box.flux(
                    mp.Y,
                    mp.Volume(center=mp.Vector3(y=-0.5 * rr),
                              size=mp.Vector3(rr)), resolution)[0] +
            nearfield_box.flux(
                mp.X,
                mp.Volume(center=mp.Vector3(0.5 * rr), size=mp.Vector3(y=rr)),
                resolution)[0] - nearfield_box.flux(
                    mp.X,
                    mp.Volume(center=mp.Vector3(-0.5 * rr),
                              size=mp.Vector3(y=rr)), resolution)[0])

        print("flux:, {:.6f}, {:.6f}, {:.6f}".format(near_flux,
                                                     far_flux_circle,
                                                     far_flux_square))

        self.assertAlmostEqual(near_flux, far_flux_circle, places=2)
        self.assertAlmostEqual(far_flux_circle, far_flux_square, places=2)
        self.assertAlmostEqual(far_flux_square, near_flux, places=2)
Beispiel #25
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
Beispiel #26
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))
Beispiel #27
0
sources = [
    mp.Source(src=mp.ContinuousSource(fcen,
                                      fwidth=0.2 * fcen,
                                      start_time=10,
                                      end_time=15),
              component=mp.Ez,
              center=src_center,
              size=mp.Vector3(cell_size.x, cell_size.y),
              amp_func=gaussian_beam(sigma, k, src_center))
]

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

sim.run(until=20)

x_plane = mp.Volume(center=mp.Vector3(0, 0, 0),
                    size=mp.Vector3(0, cell_size.y, cell_size.x))
ez_x = sim.get_array(vol=x_plane, component=mp.Ez)
print(sim.get_array(mp.Ez).max())

plt.figure()
plt.imshow(np.flipud(np.transpose(np.real(ez_x))),
           interpolation='spline36',
           cmap='RdBu')
plt.axis('off')
plt.show()
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"))
Beispiel #29
0
 def test_in_volume(self):
     sim = self.init_simple_simulation()
     sim.filename_prefix = 'test_in_volume'
     vol = mp.Volume(mp.Vector3(), size=mp.Vector3(x=2))
     sim.run(mp.at_end(mp.in_volume(vol, mp.output_efield_z)), until=200)
Beispiel #30
0
    def test_array_metadata(self):
        resolution = 25

        n = 3.4
        w = 1
        r = 1
        pad = 4
        dpml = 2

        sxy = 2*(r+w+pad+dpml)
        cell_size = mp.Vector3(sxy,sxy)

        nonpml_vol = mp.Volume(mp.Vector3(), size=mp.Vector3(sxy-2*dpml,sxy-2*dpml))

        geometry = [mp.Cylinder(radius=r+w, material=mp.Medium(index=n)),
                    mp.Cylinder(radius=r)]

        fcen = 0.118
        df = 0.08

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

        pml_layers = [mp.PML(dpml)]

        # CW source
        src = [mp.Source(mp.ContinuousSource(fcen,fwidth=df), mp.Ez, mp.Vector3(r+0.1)),
               mp.Source(mp.ContinuousSource(fcen,fwidth=df), mp.Ez, mp.Vector3(-(r+0.1)), amplitude=-1)]

        sim = mp.Simulation(cell_size=cell_size,
                            geometry=geometry,
                            sources=src,
                            resolution=resolution,
                            force_complex_fields=True,
                            symmetries=symmetries,
                            boundary_layers=pml_layers)

        sim.init_sim()
        sim.solve_cw(1e-6, 1000, 10)

        def electric_energy(r, ez, eps):
            return np.real(eps * np.conj(ez)*ez)

        def vec_func(r):
            return r.x**2 + 2*r.y**2

        electric_energy_total = sim.integrate_field_function([mp.Ez,mp.Dielectric],electric_energy,nonpml_vol)
        electric_energy_max = sim.max_abs_field_function([mp.Ez,mp.Dielectric],electric_energy,nonpml_vol)
        vec_func_total = sim.integrate_field_function([],vec_func,nonpml_vol)
        cw_modal_volume = (electric_energy_total / electric_energy_max) * vec_func_total

        sim.reset_meep()

        # pulsed source
        src = [mp.Source(mp.GaussianSource(fcen,fwidth=df), mp.Ez, mp.Vector3(r+0.1)),
               mp.Source(mp.GaussianSource(fcen,fwidth=df), mp.Ez, mp.Vector3(-(r+0.1)), amplitude=-1)]

        sim = mp.Simulation(cell_size=cell_size,
                            geometry=geometry,
                            k_point=mp.Vector3(),
                            sources=src,
                            resolution=resolution,
                            symmetries=symmetries,
                            boundary_layers=pml_layers)

        dft_obj = sim.add_dft_fields([mp.Ez], fcen, 0, 1, where=nonpml_vol)
        sim.run(until_after_sources=100)

        Ez = sim.get_dft_array(dft_obj, mp.Ez, 0)
        (X,Y,Z,W) = sim.get_array_metadata(dft_cell=dft_obj)
        Eps = sim.get_array(vol=nonpml_vol,component=mp.Dielectric)
        EpsE2 = np.real(Eps*np.conj(Ez)*Ez)
        xm, ym = np.meshgrid(X,Y)
        vec_func_sum = np.sum(W*(xm**2 + 2*ym**2))
        pulse_modal_volume = np.sum(W*EpsE2)/np.max(EpsE2) * vec_func_sum

        self.assertAlmostEqual(cw_modal_volume/pulse_modal_volume, 1.00, places=2)