Ejemplo n.º 1
0
def sim(separation):
    """perform scattering simulation"""
    L = separation + 2*radius + 2*pml_monitor_gap + 2*particle_monitor_gap + 2*pml.thickness
    cell = meep.Vector3(L,L,L)

    p1 = meep.Vector3(-separation/2, 0, 0)
    p2 = meep.Vector3(separation/2, 0, 0)
    geometry = [meep.Sphere(center=p1,
                         radius=radius, 
                         material=gold),
                meep.Sphere(center=p2,
                         radius=radius, 
                         material=gold)]

    scat = meep.Simulation(cell_size=cell,
                        boundary_layers=[pml],
                        geometry=geometry,
                        resolution=resolution)
    scat.init_fields()
    source(scat)

    L = 2*radius + 2*particle_monitor_gap
    Fx = meep_ext.add_force_box(scat, fcen, 0, 1, p2, [L,L,L], meep.X)
    Fy = meep_ext.add_force_box(scat, fcen, 0, 1, p2, [L,L,L], meep.Y)
    Fz = meep_ext.add_force_box(scat, fcen, 0, 1, p2, [L,L,L], meep.Z)

    # scat.run(until_after_sources=8*um)
    scat.run(until_after_sources=meep.stop_when_fields_decayed(.5*um, meep.Ex,
                pt=p2-meep.Vector3(0,0,L/2), decay_by=1e-5))

    return {'Fx': np.array(meep.get_forces(Fx))[0], 'Fy': np.array(meep.get_forces(Fy))[0], 'Fz': np.array(meep.get_forces(Fz))[0]}
Ejemplo n.º 2
0
def sim(separation, monitor_size, unique_id):
    """perform scattering simulation"""
    monitor_size = np.asarray(monitor_size)
    cell_size = monitor_size + 2*pml_monitor_gap + 2*pml.thickness
    cell = meep.Vector3(*cell_size)

    p1 = meep.Vector3(-separation/2, 0, 0)
    p2 = meep.Vector3(separation/2, 0, 0)
    geometry = [meep.Sphere(center=p1,
                         radius=radius, 
                         material=gold),
                meep.Sphere(center=p2,
                         radius=radius, 
                         material=gold)]

    scat = meep.Simulation(cell_size=cell,
                        boundary_layers=[pml],
                        geometry=geometry,
                        default_material=medium,
                        resolution=resolution)
    scat.init_fields()
    source(scat)

    flux_box_absorb = meep_ext.add_flux_box(scat, fcen, 0, 1, [0,0,0], monitor_size)
    flux_box_scat   = meep_ext.add_flux_box(scat, fcen, 0, 1, [0,0,0], monitor_size)
    scat.load_minus_flux(norm_file_ext.format(unique_id), flux_box_scat)

    # scat.run(until_after_sources=8*um)
    scat.run(until_after_sources=meep.stop_when_fields_decayed(.5*um, polarization,
                pt=p2 - meep.Vector3(0,0,monitor_size[2]/2), decay_by=1e-4))

    return {'scattering': np.array(meep.get_fluxes(flux_box_scat)), 'absorption': -np.array(meep.get_fluxes(flux_box_absorb))}
Ejemplo n.º 3
0
    def test_epsilon_warning(self):
        ## fields blow up using dispersive material
        ## when compiled using single precision

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            from meep.materials import Si
            self.assertEqual(len(w), 0)

        from meep.materials import Mo
        geom = [mp.Sphere(radius=0.2, material=Mo)]
        sim = self.init_simple_simulation(geometry=geom)
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            sim.run(until=5)
            self.assertGreater(len(w), 0)
            self.assertIn("Epsilon", str(w[0].message))

        from meep.materials import SiO2
        geom = [mp.Sphere(radius=0.2, material=SiO2)]
        sim = self.init_simple_simulation(geometry=geom)
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            sim.run(until=5)
            self.assertEqual(len(w), 1)
            self.assertNotIn("Epsilon", str(w[0].message))
Ejemplo n.º 4
0
    def test_check_material_frequencies(self):
        mat = mp.Medium(valid_freq_range=mp.FreqRange(min=10, max=20))
        invalid_sources = [
            [mp.Source(mp.GaussianSource(5, fwidth=1), mp.Ez, mp.Vector3())],
            [mp.Source(mp.ContinuousSource(10, fwidth=1), mp.Ez, mp.Vector3())],
            [mp.Source(mp.GaussianSource(10, width=1), mp.Ez, mp.Vector3())],
            [mp.Source(mp.GaussianSource(20, width=1), mp.Ez, mp.Vector3())],
        ]

        cell_size = mp.Vector3(5, 5)
        resolution = 5

        def check_warnings(sim, should_warn=True):
            with warnings.catch_warnings(record=True) as w:
                warnings.simplefilter("always")
                sim.run(until=5)

                if should_warn:
                    self.assertEqual(len(w), 1)
                    self.assertIn("material", str(w[-1].message))
                else:
                    self.assertEqual(len(w), 0)

        geom = [mp.Sphere(0.2, material=mat)]

        for s in invalid_sources:
            # Check for invalid extra_materials
            sim = mp.Simulation(cell_size=cell_size, resolution=resolution, sources=s, extra_materials=[mat])
            check_warnings(sim)

            # Check for invalid geometry materials
            sim = mp.Simulation(cell_size=cell_size, resolution=resolution, sources=s, geometry=geom)
            check_warnings(sim)

        valid_sources = [
            [mp.Source(mp.GaussianSource(15, fwidth=1), mp.Ez, mp.Vector3())],
            [mp.Source(mp.ContinuousSource(15, width=5), mp.Ez, mp.Vector3())]
        ]

        for s in valid_sources:
            sim = mp.Simulation(cell_size=cell_size, resolution=resolution, sources=s, extra_materials=[mat])
            check_warnings(sim, False)

        # Check DFT frequencies

        # Invalid extra_materials
        sim = mp.Simulation(cell_size=cell_size, resolution=resolution, sources=valid_sources[0],
                            extra_materials=[mat])
        fregion = mp.FluxRegion(center=mp.Vector3(0, 1), size=mp.Vector3(2, 2), direction=mp.X)
        sim.add_flux(18, 6, 2, fregion)
        check_warnings(sim)

        # Invalid geometry material
        sim = mp.Simulation(cell_size=cell_size, resolution=resolution, sources=valid_sources[0], geometry=geom)
        sim.add_flux(18, 6, 2, fregion)
        check_warnings(sim)
Ejemplo n.º 5
0
    def __init__(self, dir_name, wavelength, cyt_absorb):
        self.base_directory = base_directory + str(dir_name)

        self.wavelength = wavelength
        self.cyt_absorb = cyt_absorb
        self.frequency = 1 / wavelength
        # Calculate wavelengths dependent on RI
        self.wavelength_in_media = wavelength / ri_media
        self.wavelength_in_cytoplasm = wavelength / ri_cytoplasm
        max_freq = self.frequency - 0.01
        min_freq = self.frequency + 0.01
        self.pulse_width = abs(max_freq - min_freq)

        cell = mp.Vector3(sxx, sxy, 0)
        pml_layers = [mp.PML(dpml)]

        cytoplasm_material = mp.Medium(index=ri_cytoplasm,
                                       D_conductivity=2 * math.pi * self.frequency * (cyt_absorb / (ri_cytoplasm ** 2)))

        cytoplasm_region = mp.Sphere(radius=cell_radius,
                                     center=mp.Vector3(0, 0),
                                     material=cytoplasm_material)
        geometry = [cytoplasm_region]

        # Sources
        kdir = mp.Vector3(1, 0, 0)  # direction of k (length is irrelevant)
        n = ri_media  # refractive index of material containing the source
        k = kdir.unit().scale(2 * math.pi * self.frequency * n)  # k with correct length

        def pw_amp(k, x0):
            def _pw_amp(x):
                return cmath.exp(1j * k.dot(x + x0))
            return _pw_amp
        source = [
            mp.Source(
                mp.ContinuousSource(frequency=self.frequency, fwidth=self.pulse_width),  # along x axis
                component=mp.Ez,
                center=mp.Vector3(-0.5 * simulation_size, 0),  # x, ,y ,z
                size=mp.Vector3(0, sxy, 0),
                amp_func=pw_amp(k, mp.Vector3(x=-0.5 * simulation_size))
            )
            ]

        sim = mp.Simulation(
            cell_size=cell,
            sources=source,
            boundary_layers=pml_layers,
            resolution=resolution,
            geometry=geometry,
            default_material=mp.Medium(index=ri_media),
            force_complex_fields=complex_f,
            eps_averaging=eps_av,
        )

        sim.use_output_directory(self.base_directory)
        sim.run(mp.at_every(0.6, mp.output_png(mp.Ez, "-Zc/data/home/bt16268/simInput/customColour.txt")), until=t)
Ejemplo n.º 6
0
def sweep_dis(l, sources, dis_mat, tstop, span, pos, frq):
    if sources == "x":
        sources_use = sourcesx
    if sources == "z":
        sources_use = sourcesz

    geometryAu = [
        mp.Sphere(material=Au, center=mp.Vector3(x=r + dis_mat[l]), radius=r)
    ]
    frqs, p_flux = purcell_cal(sources_use, geometryAu, tstop, span, pos, frq)
    return p_flux
Ejemplo n.º 7
0
def main(args):
    sx = 4.0  #spatial extent along x including pmls (μm)
    sy = 4.0
    sz = 4.0
    dpml = 1.0

    cell = mp.Vector3(sx, sy, sz)
    pml_layers = [mp.PML(dpml)]
    geometry = [
        mp.Sphere(radius=0.7, center=mp.Vector3(0, 0, 0), material=Graph),
        mp.Sphere(radius=0.5,
                  center=mp.Vector3(0, 0, 0),
                  material=mp.Medium(epsilon=12.25))
    ]
    resolution = args.res
    wvl = args.wvl / 1000  #convert args.wvl from nm to μm
    fcen = 1 / wvl
    df = 0.1 * fcen
    nfreq = 1
    print("wavelength =", wvl, "μm")
    print("center frequency =", fcen, "1/μm")

    source = [
        mp.Source(mp.GaussianSource(fcen, df, nfreq),
                  component=mp.Ex,
                  center=mp.Vector3(0, 0.705, 0))
    ]

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

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

    pt = mp.Vector3(0, 0.75, 0)

    sim.run(mp.dft_ldos(fcen, df, nfreq),
            until_after_sources=mp.stop_when_fields_decayed(
                20, mp.Ex, pt, 1e-9))
Ejemplo n.º 8
0
    def __init__(self, dir_name, wavelength, cyt_absorb):
        self.base_directory = base_directory + str(dir_name)

        self.wavelength = wavelength
        self.cyt_absorb = cyt_absorb
        self.frequency = 1 / wavelength
        # Calculate wavelengths dependent on RI
        self.wavelength_in_media = wavelength / ri_media
        self.wavelength_in_cytoplasm = wavelength / ri_cytoplasm
        max_freq = self.frequency - 0.01
        min_freq = self.frequency + 0.01
        self.pulse_width = abs(max_freq - min_freq)

        cell = mp.Vector3(sxx, sxy, 0)
        pml_layers = [mp.PML(dpml)]

        cytoplasm_material = mp.Medium(index=ri_cytoplasm,
                                       D_conductivity=2 * math.pi *
                                       self.frequency * (cyt_absorb /
                                                         (ri_cytoplasm**2)))

        cytoplasm_region = mp.Sphere(radius=cell_radius,
                                     center=mp.Vector3(0, 0),
                                     material=cytoplasm_material)
        geometry = []

        source = [
            mp.Source(mp.ContinuousSource(frequency=self.frequency,
                                          fwidth=self.pulse_width),
                      compone=mp.Ez,
                      center=(mp.Vector3(-0.5 * simulation_size, 0)),
                      size=mp.Vector3(0, 10))
        ]

        sim = mp.Simulation(
            cell_size=cell,
            sources=source,
            boundary_layers=pml_layers,
            resolution=resolution,
            geometry=geometry,
            default_material=mp.Medium(index=ri_media),
            force_complex_fields=complex_f,
            eps_averaging=eps_av,
        )

        sim.use_output_directory(self.base_directory)
        sim.run(mp.at_every(
            0.6,
            mp.output_png(mp.Ez,
                          "-Zc/data/home/bt16268/simInput/customColour.txt")),
                until=t)
Ejemplo n.º 9
0
    def test_epsilon_warning(self):

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            from materials_library import Si
            self.assertEqual(len(w), 0)

        from materials_library import Mo
        geom = [mp.Sphere(radius=0.2, material=Mo)]
        sim = self.init_simple_simulation(geometry=geom)
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            sim.run(until=5)
            self.assertGreater(len(w), 0)
            self.assertIn("Epsilon", str(w[0].message))

        from materials_library import SiO2
        geom = [mp.Sphere(radius=0.2, material=SiO2)]
        sim = self.init_simple_simulation(geometry=geom)
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            sim.run(until=5)
            self.assertEqual(len(w), 1)
            self.assertNotIn("Epsilon", str(w[0].message))
Ejemplo n.º 10
0
Archivo: geom.py Proyecto: jlollis/meep
    def test_geometric_object_duplicates_xyz(self):
        rad = 1
        s = mp.Sphere(rad)
        res = mp.geometric_object_duplicates(mp.Vector3(1, 1, 1), 1, 5, s)

        expected = [
            mp.Sphere(rad, center=mp.Vector3(1, 1, 1)),
            mp.Sphere(rad, center=mp.Vector3(2, 2, 2)),
            mp.Sphere(rad, center=mp.Vector3(3, 3, 3)),
            mp.Sphere(rad, center=mp.Vector3(4, 4, 4)),
            mp.Sphere(rad, center=mp.Vector3(5, 5, 5))
        ]

        for r, e in zip(res, expected):
            self.assertEqual(r.center, e.center)
Ejemplo n.º 11
0
Archivo: geom.py Proyecto: jlollis/meep
    def test_geometric_object_duplicates_x(self):
        rad = 1
        s = mp.Sphere(rad)
        res = mp.geometric_object_duplicates(mp.Vector3(x=1), 1, 5, s)

        expected = [
            mp.Sphere(rad, center=mp.Vector3(x=1)),
            mp.Sphere(rad, center=mp.Vector3(x=2)),
            mp.Sphere(rad, center=mp.Vector3(x=3)),
            mp.Sphere(rad, center=mp.Vector3(x=4)),
            mp.Sphere(rad, center=mp.Vector3(x=5))
        ]

        for r, e in zip(res, expected):
            self.assertEqual(r.center, e.center)
Ejemplo n.º 12
0
def geo2D_spherical_pc(n_matrix,
                       n_substrate,
                       film_xsize,
                       substrate_xsize,
                       film_ysize,
                       n_layers,
                       film_base_x,
                       sph_radius,
                       sph_spacing,
                       layer_offset,
                       sph_x_offset=0):
    """
    Generate a layered structure with spheres. Within a layer the spheres are hexagonally packed
    """
    matrix_block = mp.Block(size=mp.Vector3(film_xsize, film_ysize, 1e20),
                            center=mp.Vector3(film_base_x - film_xsize / 2),
                            material=mp.Medium(epsilon=n_matrix**2))

    si_block = mp.Block(size=mp.Vector3(substrate_xsize, film_ysize, 1e20),
                        center=mp.Vector3(film_base_x + substrate_xsize / 2, 0,
                                          0),
                        material=mp.Medium(epsilon=n_substrate**2))

    print(n_substrate)

    spheres = [si_block, matrix_block]
    #spheres = []

    for n in range(n_layers):
        x = film_base_x - film_xsize * (n + 0.5) / n_layers + sph_x_offset
        offset = layer_offset[n]
        num_spheres = int(film_ysize / sph_spacing)
        sphere_layer = [
            mp.Sphere(radius=sph_radius,
                      center=mp.Vector3(x, y + offset - film_ysize / 2, 0),
                      material=mp.Medium(epsilon=1))
            for y in np.linspace(0, film_ysize, num_spheres)
        ]
        spheres = spheres + sphere_layer

    return spheres
Ejemplo n.º 13
0
import meep as mp
import numpy as np
import math

cell_size = mp.Vector3(2, 2, 2)

geometry = [  #mp.Block(center=mp.Vector3(0,0,0), size=cell_size, material=mp.air),
    mp.Sphere(center=mp.Vector3(0, 0, 0), radius=1, material=mp.metal)
]

sim = mp.Simulation(resolution=50, cell_size=cell_size, geometry=geometry)

sim.init_sim()

eps_data = sim.get_epsilon()
#eps_data = sim.get_array()

#sim.plot3D(eps_data)

#from mayavi import mlab
#s = mlab.contour3d()
#mlab.show()
#mlab.savefig(filename='test2.png')

from mayavi import mlab
s = mlab.contour3d(eps_data, colormap="hsv")
#mlab.show()
mlab.savefig('Sphere3D.pdf')
Ejemplo n.º 14
0
def compute_resonant_mode_3d(use_matgrid=True):
    resolution = 25

    wvl = 1.27
    fcen = 1 / wvl
    df = 0.02 * fcen

    nSi = 3.45
    Si = mp.Medium(index=nSi)
    nSiO2 = 1.45
    SiO2 = mp.Medium(index=nSiO2)

    s = 1.0
    cell_size = mp.Vector3(s, s, s)

    rad = 0.34  # radius of sphere

    if use_matgrid:
        matgrid_resolution = 2 * resolution
        N = int(s * matgrid_resolution)
        coord = np.linspace(-0.5 * s, 0.5 * s, N)
        xv, yv, zv = np.meshgrid(coord, coord, coord)

        weights = np.sqrt(np.square(xv) + np.square(yv) + np.square(zv)) < rad
        filtered_weights = gaussian_filter(weights,
                                           sigma=4 / resolution,
                                           output=np.double)

        matgrid = mp.MaterialGrid(mp.Vector3(N, N, N),
                                  SiO2,
                                  Si,
                                  weights=filtered_weights,
                                  do_averaging=True,
                                  beta=1000,
                                  eta=0.5)

        geometry = [
            mp.Block(center=mp.Vector3(), size=cell_size, material=matgrid)
        ]
    else:
        geometry = [mp.Sphere(center=mp.Vector3(), radius=rad, material=Si)]

    sources = [
        mp.Source(src=mp.GaussianSource(fcen, fwidth=df),
                  size=mp.Vector3(),
                  center=mp.Vector3(0.13, 0.25, 0.06),
                  component=mp.Ez)
    ]

    k_point = mp.Vector3(0.23, -0.17, 0.35)

    sim = mp.Simulation(resolution=resolution,
                        cell_size=cell_size,
                        sources=sources,
                        default_material=SiO2,
                        k_point=k_point,
                        geometry=geometry)

    h = mp.Harminv(mp.Ez, mp.Vector3(-0.2684, 0.1185, 0.0187), fcen, df)

    sim.run(mp.after_sources(h), until_after_sources=200)

    try:
        for m in h.modes:
            print("harminv:, {}, {}, {}".format(resolution, m.freq, m.Q))
        freq = h.modes[0].freq
    except:
        raise RuntimeError("No resonant modes found.")

    return freq
Ejemplo n.º 15
0
        center=mp.Vector3(0, 0, -(sizeZ / 2 + 6 * addFlux)),  #3D case
        # center=mp.Vector3(-sizeX/2, 0, 0),
        size=mp.Vector3(sizeX, sizeY, 0),
        amplitude=1)
]
#sources = create_sources(freq, df, 0.7, 5, resolution, 4, 0, 0, 0, 24, 0)
#sys.stderr.write(np.str(mp.Vector3(z=-0.5*sizeZ-addFlux/2)))
#sys.stderr.write(np.str(mp.Vector3(sizeX+addFlux/2, sizeY+addFlux/2, 0)))
geometry = []
while Z < sizeZ / 2 - 1:
    for i in range(N):
        coord[0, i] = np.random.rand() * sizeX - sizeX / 2
        coord[1, i] = np.random.rand() * sizeY - sizeY / 2
        coord[2, i] = Z
        bufferShape = mp.Sphere(center=mp.Vector3(coord[0, i], coord[1, i],
                                                  coord[2, i]),
                                radius=radius,
                                material=mp.Medium(epsilon=1.44))
        geometry.append(bufferShape)
    Z = Z + dZ

# for i in range(N):
#         coord[0, i] = np.random.rand()*sizeX-sizeX/2
#         coord[1, i] = np.random.rand()*sizeY-sizeY/2
#         coord[2, i] = Z
#         bufferShape = mp.Sphere(center=mp.Vector3(coord[0, i], coord[1, i], coord[2, i]),
#                               radius=radius,
#                               material=mp.Medium(epsilon=12))
#         geometry.append(bufferShape)
pml_layers = [mp.PML(thicknessPML)]
sim = mp.Simulation(
    cell_size=cell,
Ejemplo n.º 16
0
def main(from_um_factor, resolution, courant, r, material, paper, reference,
         submerged_index, displacement, surface_index, wlen_range, nfreq,
         air_r_factor, pml_wlen_factor, flux_r_factor, time_factor_cell,
         second_time_factor, series, folder, parallel, n_processes, n_cores,
         n_nodes, split_chunks_evenly, load_flux, load_chunks, near2far):

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

    #%% MORE INPUT PARAMETERS

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

    ### TREATED INPUT PARAMETERS

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

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

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

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

    #%% GENERAL GEOMETRY SETUP

    air_width = air_width - air_width % (1 / resolution)

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

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

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

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

    displacement = displacement - displacement % (1 / resolution)

    flux_box_size = flux_box_size - flux_box_size % (1 / resolution)

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

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

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

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

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

    # Computation
    enlapsed = []

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

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

    #%% FIRST RUN

    measure_ram()

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

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

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

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

    if chunks_needed:

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

        sim.init_sim()

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

        del sim

    if flux_needed:

        #% FIRST RUN: SET UP

        measure_ram()

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

        measure_ram()

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

        measure_ram()

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

        #% FIRST RUN: INITIALIZE

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

        step_ram_function = lambda sim: measure_ram()

        #% FIRST RUN: SIMULATION NEEDED TO NORMALIZE

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

        #% SAVE MID DATA

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

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

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

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

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

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

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

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

        #% PLOT FLUX FOURIER MID DATA

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

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

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

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

        sim.reset_meep()

    #%% SECOND RUN: SETUP

    measure_ram()

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

    measure_ram()

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

    measure_ram()

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

    #%% SECOND RUN: INITIALIZE

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

    #%% LOAD FLUX FROM FILE

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

    measure_ram()

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

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

    measure_ram()

    #%% SECOND RUN: SIMULATION :D

    step_ram_function = lambda sim: measure_ram()

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

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

    #%% SCATTERING ANALYSIS

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

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

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

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

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

    #%% ANGULAR PATTERN ANALYSIS

    if near2far:

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

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

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

        for phi in azimuthal_angle:

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

            for theta in polar_angle:

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

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

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

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

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

    #%% SAVE FINAL DATA

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

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

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

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

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

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

    if near2far:

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

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

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

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

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

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

    #%% PLOT ALL TOGETHER

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

    #%% PLOT SEPARATE

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

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

    #%% PLOT ONE ABOVE THE OTHER

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

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

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

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

    #%% PLOT FLUX FOURIER FINAL DATA

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

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

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

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

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

    #%% PLOT ANGULAR PATTERN IN 3D

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

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

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

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

    #%% PLOT ANGULAR PATTERN PROFILE FOR DIFFERENT POLAR ANGLES

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

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

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

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

    #%% PLOT ANGULAR PATTERN PROFILE FOR DIFFERENT AZIMUTHAL ANGLES

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

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

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

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

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

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

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

        plt.savefig(file("AngularAzimuthalAbs.png"))
Ejemplo n.º 17
0
                      weight=+1),
    mp.Near2FarRegion(center=mp.Vector3(z=+2 * r),
                      size=mp.Vector3(4 * r, 4 * r, 0),
                      weight=-1))

sim.run(until_after_sources=10)

input_flux = mp.get_fluxes(box_flux)[0]
nearfield_box_data = sim.get_near2far_data(nearfield_box)

sim.reset_meep()

n_sphere = 2.0
geometry = [
    mp.Sphere(material=mp.Medium(index=n_sphere),
              center=mp.Vector3(),
              radius=r)
]

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

nearfield_box = sim.add_near2far(
    frq_cen, 0, 1,
    mp.Near2FarRegion(center=mp.Vector3(x=-2 * r),
                      size=mp.Vector3(0, 4 * r, 4 * r),
                      weight=+1),
Ejemplo n.º 18
0
import meep as mp
import numpy as np
import matplotlib.pyplot as plt
import argparse
from meep.materials import Ag, BK7

sx = 4.0  #spatial extent along x including pmls (μm)
sy = 4.0
sz = 0.0
dpml = 1.0

cell = mp.Vector3(sx, sy, sz)
pml_layers = [mp.PML(dpml)]
geometry = [
    mp.Sphere(radius=0.7, center=mp.Vector3(0, 0, 0), material=Ag),
    mp.Sphere(radius=0.5,
              center=mp.Vector3(0, 0, 0),
              material=mp.Medium(epsilon=12.25))
]
resolution = 200
wvl = 825 / 1000  #convert args.wvl from nm to μm
fcen = 1 / wvl
df = 0
nfreq = 1
print("wavelength =", wvl, "μm")
print("center frequency =", fcen, "1/μm")

source = [
    mp.Source(mp.GaussianSource(fcen, df, nfreq),
              component=mp.Ey,
              center=mp.Vector3(0, -0.705, 0))
Ejemplo n.º 19
0
cell_size = mp.Vector3(cell_width, cell_width, cell_width)

source_center = -0.5 * cell_width + pml_width
print("Resto Source Center: {}".format(source_center % (1 / resolution)))
sources = [
    mp.Source(mp.ContinuousSource(wavelength=wlen, is_integrated=True),
              center=mp.Vector3(source_center),
              size=mp.Vector3(0, cell_width, cell_width),
              component=mp.Ez)
]
# Ez-polarized monochromatic planewave
# (its size parameter fills the entire cell in 2d)
# >> The planewave source extends into the PML
# ==> is_integrated=True must be specified

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

path = os.path.join(home, folder, series)
if not os.path.isdir(path): vs.new_dir(path)
file = lambda f: os.path.join(path, f)

#%% SAVE GET FUNCTIONS


def get_line(sim):
    return sim.get_array(center=mp.Vector3(),
                         size=mp.Vector3(cell_width),
                         component=mp.Ez)

Ejemplo n.º 20
0
    def simulate(self, config):
        start = time.time()
        dpml = config["dpml"]
        resolution = config["resolution"]
        use_fixed_time = config["use_fixed_time"]
        simulation_time = config["simulation_time"]
        padding = config["padding"]
        ff_pts = config["ff_pts"]
        ff_cover = config["ff_cover"]
        ff_calc = config["ff_calc"]
        use_symmetries = config["use_symmetries"]
        calculate_flux = config["calculate_flux"]
        calculate_source_flux = config["calculate_source_flux"]
        pixels = config["source_flux_pixel_size"]
        ff_calculations = config["ff_calculations"]
        ff_angle = math.pi / config["ff_angle"]
        FibonacciSampling = config["fibb_sampling"]
        simulation_ratio = eval(config["simulation_ratio"])
        substrate_ratio = eval(config["substrate_ratio"])
        output_ff = config["output_ff"]
        polarization_in_plane = config["polarization_in_plane"]
        geometry = config["geometry"]
        material_function = config["material_function"]

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

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

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

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

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

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

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

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

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

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


#Flux regions to calculate the far field flux

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        if geometry == None:
            geometries = []

        if material_function == None:
            material_function = None

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

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

        pml_layer = [mp.PML(dpml)]

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

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

        abs_source_position_x = 0
        abs_source_position_y = 0
        abs_source_position_z = 0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            #global yPts
            #yPts=[]

            #global zPts
            #zPts=[]

            Pr_Array = []

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

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

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

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

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

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

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

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

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

            else:
                return {
                    "total_flux": flux_tot_out,
                    "source_flux": source_flux_out,
                    "ff_at_angle": None,
                    "flux_ratio": None,
                    "LDOS": sim.ldos_data,
                    "Elapsed time (min)": elapsed_time
                }
Ejemplo n.º 21
0
    mp.Vector3(0, 0.5, 0.5),  # X
    mp.Vector3(0.25, 0.75, 0.5),  # W
    mp.Vector3(0.375, 0.75, 0.375)  # K
]

k_points = mp.interpolate(4, vlist)

# define a couple of parameters (which we can set from the command_line)
eps = 11.56  # the dielectric constant of the spheres
r = 0.25  # the radius of the spheres

diel = mp.Medium(epsilon=eps)

# A diamond lattice has two "atoms" per unit cell:
geometry = [
    mp.Sphere(r, center=mp.Vector3(0.125, 0.125, 0.125), material=diel),
    mp.Sphere(r, center=mp.Vector3(-0.125, -0.125, -0.125), material=diel)
]

# (A simple fcc lattice would have only one sphere/object at the origin.)

resolution = 16  # use a 16x16x16 grid
mesh_size = 5
num_bands = 5

ms = mpb.ModeSolver(geometry_lattice=geometry_lattice,
                    k_points=k_points,
                    geometry=geometry,
                    resolution=resolution,
                    num_bands=num_bands,
                    mesh_size=mesh_size)
Ejemplo n.º 22
0
def main(series, folder, resolution, from_um_factor, r, paper, wlen):
    #%% PARAMETERS

    # Au sphere
    r = r / (from_um_factor * 1e3)  # Radius of sphere now in Meep units
    medium = import_medium("Au", from_um_factor,
                           paper=paper)  # Medium of sphere: gold (Au)

    # Frequency and wavelength
    wlen = wlen / (from_um_factor * 1e3)  # Wavelength now in Meep units

    # Space configuration
    pml_width = 0.38 * wlen  # 0.5 * wlen
    air_width = r / 2  # 2 * r

    # Field Measurements
    period_line = 1
    period_plane = 1
    after_cell_run_time = 10 * wlen

    # Computation time
    enlapsed = []

    # Saving directories
    if series is None:
        series = f"AuSphereField{2*r*from_um_factor*1e3:.0f}WLen{wlen*from_um_factor*1e3:.0f}"
    if folder is None:
        folder = "AuMieSphere/AuSphereField"
    home = vs.get_home()

    #%% 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)]
    # Cause of symmetry, two mirror planes reduce cell size to 1/4

    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)

    source_center = -0.5 * cell_width + pml_width
    print("Resto Source Center: {}".format(source_center % (1 / resolution)))
    sources = [
        mp.Source(mp.ContinuousSource(wavelength=wlen, is_integrated=True),
                  center=mp.Vector3(source_center),
                  size=mp.Vector3(0, cell_width, cell_width),
                  component=mp.Ez)
    ]
    # Ez-polarized monochromatic planewave
    # (its size parameter fills the entire cell in 2d)
    # >> The planewave source extends into the PML
    # ==> is_integrated=True must be specified

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

    path = os.path.join(home, folder, series)
    if not os.path.isdir(path): vs.new_dir(path)
    file = lambda f: os.path.join(path, f)

    #%% SAVE GET FUNCTIONS

    def get_line(sim):
        return sim.get_array(center=mp.Vector3(),
                             size=mp.Vector3(cell_width),
                             component=mp.Ez)

    def get_plane(sim):
        return sim.get_array(center=mp.Vector3(),
                             size=mp.Vector3(0, cell_width, cell_width),
                             component=mp.Ez)

    #%% INITIALIZE

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

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

    #%% DEFINE SAVE STEP FUNCTIONS

    f, save_line = vs.save_slice_generator(sim, file("Lines.h5"), "Ez",
                                           get_line)
    g, save_plane = vs.save_slice_generator(sim, file("Planes.h5"), "Ez",
                                            get_plane)

    to_do_while_running = [
        mp.at_every(period_line, save_line),
        mp.at_every(period_plane, save_plane)
    ]

    #%% RUN!

    temp = time()
    sim.run(*to_do_while_running, until=cell_width + after_cell_run_time)
    del f, g
    enlapsed.append(time() - temp)

    #%% SAVE METADATA

    params = dict(from_um_factor=from_um_factor,
                  resolution=resolution,
                  r=r,
                  paper=paper,
                  pml_width=pml_width,
                  air_width=air_width,
                  cell_width=cell_width,
                  source_center=source_center,
                  wlen=wlen,
                  period_line=period_line,
                  period_plane=period_plane,
                  after_cell_run_time=after_cell_run_time,
                  series=series,
                  folder=folder,
                  home=home,
                  enlapsed=enlapsed)

    f = h5.File(file("Lines.h5"), "r+")
    for a in params:
        f["Ez"].attrs[a] = params[a]
    f.close()
    del f

    g = h5.File(file("Planes.h5"), "r+")
    for a in params:
        g["Ez"].attrs[a] = params[a]
    g.close()
    del g

    sim.reset_meep()
Ejemplo n.º 23
0
    def __init__(self, dir_name, wavelength, thy_absorb, cyt_absorb):
        self.base_directory = base_directory + str(dir_name)

        self.wavelength = wavelength
        self.thy_absorb = thy_absorb
        self.cyt_absorb = cyt_absorb
        self.frequency = 1 / wavelength
        # Calculate wavelengths dependent on RI
        self.wavelength_in_media = wavelength / ri_media
        self.wavelength_in_cytoplasm = wavelength / ri_cytoplasm
        self.wavelength_in_thylakoid = wavelength / ri_thylakoid
        max_freq = self.frequency - 0.01
        min_freq = self.frequency + 0.01
        self.pulse_width = abs(max_freq - min_freq)

        cell = mp.Vector3(sxx, sxy, sxz)
        pml_layers = [mp.PML(dpml)]

        thylakoid_material = mp.Medium(index=ri_thylakoid,
                                       D_conductivity=2 * math.pi *
                                       self.frequency * (thy_absorb /
                                                         (ri_thylakoid**2)))
        cytoplasm_material = mp.Medium(index=ri_cytoplasm,
                                       D_conductivity=2 * math.pi *
                                       self.frequency * (cyt_absorb /
                                                         (ri_cytoplasm**2)))

        thylakoid_region = mp.Sphere(radius=cell_radius,
                                     center=mp.Vector3(0, 0, 0),
                                     material=thylakoid_material)
        cytoplasm_region = mp.Sphere(radius=cell_radius - thylakoid_thickness,
                                     center=mp.Vector3(0, 0, 0),
                                     material=cytoplasm_material)
        geometry = [thylakoid_region, cytoplasm_region]

        # Sources
        kdir = mp.Vector3(1, 0, 0)  # direction of k (length is irrelevant)
        n = ri_media  # refractive index of material containing the source
        k = kdir.unit().scale(2 * math.pi * self.frequency *
                              n)  # k with correct length

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

            return _pw_amp

        source = [
            mp.Source(
                mp.ContinuousSource(frequency=self.frequency,
                                    fwidth=self.pulse_width),  # along x axis
                component=mp.Ez,
                center=mp.Vector3(-0.5 * simulation_size, 0, 0),  # x, ,y ,z
                size=mp.Vector3(0, sxy, sxz),
                amp_func=pw_amp(k, mp.Vector3(x=-0.5 * simulation_size)))
        ]

        sim = mp.Simulation(
            cell_size=cell,
            sources=source,
            boundary_layers=pml_layers,
            resolution=resolution,
            geometry=geometry,
            default_material=mp.Medium(index=ri_media),
            force_complex_fields=complex_f,
            eps_averaging=eps_av,
        )

        def output_fields(sim):
            ez_output = open(base_directory + "Ez Field 430 NoAbs" + ".npy",
                             'wb')
            ez_array = sim.get_array(component=mp.Ez, cmplx=complex_f)
            ez_field_output = np.asarray(ez_array)
            np.save(ez_output, ez_field_output)
            ez_output.close()

            # ey_output = open(base_directory + "Ey Field 300 Std" + ".npy", 'wb')
            # ey_array = sim.get_array(component=mp.Ey, cmplx=complex_f)
            # ey_field_output = np.asarray(ey_array)
            # np.save(ey_output, ey_field_output)
            # ey_output.close()
            #
            # ex_output = open(base_directory + "Ex Field 300 std abs" + ".npy", 'wb')
            # ex_array = sim.get_array(component=mp.Ex, cmplx=complex_f)
            # ex_field_output = np.asarray(ex_array)
            # np.save(ex_output, ex_field_output)
            # ex_output.close()

            # eps_output = open(base_directory + "Refractive Index" + ".npy", 'wb')
            # eps_array = sim.get_array(component=mp.Dielectric, cmplx=complex_f)
            # np.save(eps_output, eps_array)
            # eps_output.close()

        sim.use_output_directory(self.base_directory)
        sim.run(mp.at_every(1, output_fields), until=t)
Ejemplo n.º 24
0
def main(args):

    resolution = 30

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

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

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

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

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

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

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

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

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

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

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

    geometry = []

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

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

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

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

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

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

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

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

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

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

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

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

    sim.display_fluxes(refl, trans_grid, trans_sub_top, trans_sub_bot)
Ejemplo n.º 25
0
import pinboard

job = pinboard.pinboard()
nm = 1e-9
um = 1e-6

### geometry
radius = 75 * nm
gold = meep_ext.material.Au()
gold = meep.Medium(index=3.5)

sep = 400 * nm
p1 = meep.Vector3(-sep / 2, 0, 0)
p2 = meep.Vector3(sep / 2, 0, 0)
geometry = [
    meep.Sphere(center=p1, radius=radius, material=gold),
    meep.Sphere(center=p2, radius=radius, material=gold)
]

### source
fcen, df = meep_ext.freq_data(1 / (400 * nm), 1 / (1000 * nm))
nfreq = 40
src_time = meep.GaussianSource(frequency=1.3 / um, fwidth=4.0 / um)
polarization = meep.Ex  # used in convergence check 'decay_by'
source = lambda sim: meep_ext.x_polarized_plane_wave(sim, src_time)

### monitor info
particle_monitor_gap = 50 * nm
pml_monitor_gap = 50 * nm
norm_file_ext = 'norm'
monitor_size = [
def run_simulation(save_prefix,
                   tip_radius=0.007,
                   cone_height=0.364,
                   trunk_radius=0.275,
                   n_tip=3.694,
                   k_tip=0.0,
                   fcen=1.25,
                   waves=7.5,
                   theta_deg=10,
                   sample=20,
                   sx=0.8,
                   sy=1.5,
                   sz=1.0,
                   dpml=0.1,
                   res=1000,
                   res_factor=0.2,
                   X_1=-0.2,
                   X_2=0.2,
                   Y_1=-0.2,
                   Y_2=0.2,
                   Z_1=-0.2,
                   Z_2=0.2,
                   x_mon_rat=1.0,
                   y_mon_rat=1.0,
                   z_mon_rat=1.0):

    #Interpolate to next resolution step for high-res region
    dx = 1 / res
    X_1 = np.floor(X_1 / dx) * dx
    X_2 = np.ceil(X_2 / dx) * dx
    Y_1 = np.floor(Y_1 / dx) * dx
    Y_2 = np.ceil(Y_2 / dx) * dx
    Z_1 = np.floor(Z_1 / dx) * dx
    Z_2 = np.ceil(Z_2 / dx) * dx

    #Dump all the settings to a file:
    settings_file = h5py.File(
        Path(sys.argv[0]).stem + '-' + save_prefix + '_settings.h5', 'w')
    settings_file.create_dataset('tip_radius', data=tip_radius)
    settings_file.create_dataset('cone_height', data=cone_height)
    settings_file.create_dataset('trunk_radius', data=trunk_radius)
    settings_file.create_dataset('n_tip', data=n_tip)
    settings_file.create_dataset('k_tip', data=k_tip)
    settings_file.create_dataset('fcen', data=fcen)
    settings_file.create_dataset('waves', data=waves)
    settings_file.create_dataset('theta_deg', data=theta_deg)
    settings_file.create_dataset('sample', data=sample)
    settings_file.create_dataset('sx', data=sx)
    settings_file.create_dataset('sy', data=sy)
    settings_file.create_dataset('sz', data=sz)
    settings_file.create_dataset('dpml', data=dpml)
    settings_file.create_dataset('res', data=res)
    settings_file.create_dataset('res_factor', data=res_factor)
    settings_file.create_dataset('X_1', data=X_1)
    settings_file.create_dataset('X_2', data=X_2)
    settings_file.create_dataset('Y_1', data=Y_1)
    settings_file.create_dataset('Y_2', data=Y_2)
    settings_file.create_dataset('Z_1', data=Z_1)
    settings_file.create_dataset('Z_2', data=Z_2)
    settings_file.create_dataset('x_mon_rat', data=x_mon_rat)
    settings_file.create_dataset('y_mon_rat', data=y_mon_rat)
    settings_file.create_dataset('z_mon_rat', data=z_mon_rat)
    settings_file.close()

    #Convert theta to radians
    theta = theta_deg * np.pi / 180

    eps_tip = calc_eps_r(n_tip, k_tip)
    sig_d_tip = calc_sig_d(n_tip, k_tip, fcen)

    #Create the cell size
    sX = 2 * dpml + sx
    sY = 2 * dpml + sy
    sZ = 2 * dpml + sz

    #Monitor sizes
    x_mon = sx * x_mon_rat
    y_mon = sx * y_mon_rat
    z_mon = sx * z_mon_rat

    #Calculate values in prime-space:
    sx_prime = sx * res_factor + (X_2 - X_1) * (1 - res_factor)
    sy_prime = sy * res_factor + (Y_2 - Y_1) * (1 - res_factor)
    sz_prime = sz * res_factor + (Z_2 - Z_1) * (1 - res_factor)
    dpml_prime = dpml * res_factor

    sX_prime = 2 * dpml_prime + sx_prime
    sY_prime = 2 * dpml_prime + sy_prime
    sZ_prime = 2 * dpml_prime + sz_prime

    x_mon_prime = (x_mon/2.0 > X_2)*((x_mon/2.0 - X_2)*res_factor + X_2) +\
                  (x_mon/2.0)*(x_mon/2.0 <= X_2) -\
                  (-1*x_mon/2.0 < X_1)*((-1*x_mon/2.0 - X_1)*res_factor + X_1) -\
                  (-1*x_mon/2.0)*(-1*x_mon/2.0 >= X_1)

    y_mon_prime = (y_mon/2.0 > Y_2)*((y_mon/2.0 - Y_2)*res_factor + Y_2) +\
                  (y_mon/2.0)*(y_mon/2.0 <= Y_2) -\
                  (-1*y_mon/2.0 < Y_1)*((-1*y_mon/2.0 - Y_1)*res_factor + Y_1) -\
                  (-1*y_mon/2.0)*(-1*y_mon/2.0 >= Y_1)

    z_mon_prime = (z_mon/2.0 > Z_2)*((z_mon/2.0 - Z_2)*res_factor + Z_2) +\
                  (z_mon/2.0)*(z_mon/2.0 <= Z_2) -\
                  (-1*z_mon/2.0 < Z_1)*((-1*z_mon/2.0 - Z_1)*res_factor + Z_1) -\
                  (-1*z_mon/2.0)*(-1*z_mon/2.0 >= Z_1)

    cell = mp.Vector3(sX_prime, sY_prime, sZ_prime)

    tip = [
        mp.Cylinder(radius=trunk_radius,
                    center=mp.Vector3(
                        0.0, -1 * sY / 4.0 - cone_height / 2.0 - tip_radius,
                        0.0),
                    height=(sY / 2.0 - cone_height),
                    axis=mp.Vector3(0.0, 1.0, 0.0)),
        mp.Cone(center=mp.Vector3(0, -1 * cone_height / 2 - tip_radius, 0),
                height=cone_height,
                radius=trunk_radius,
                radius2=tip_radius,
                axis=mp.Vector3(0, 1, 0)),
        mp.Sphere(center=mp.Vector3(0, -1 * tip_radius, 0), radius=tip_radius)
    ]

    def mat_func(r_prime):

        r_x = r_prime.x
        r_y = r_prime.y
        r_z = r_prime.z

        x_fac = 1
        y_fac = 1
        z_fac = 1

        if (r_prime.x < X_1):
            x_fac = res_factor
            r_x = X_1 + (r_prime.x - X_1) / res_factor
        elif (r_prime.x > X_2):
            x_fac = res_factor
            r_x = X_2 + (r_prime.x - X_2) / res_factor

        if (r_prime.y < Y_1):
            y_fac = res_factor
            r_y = Y_1 + (r_prime.y - Y_1) / res_factor
        elif (r_prime.y > Y_2):
            y_fac = res_factor
            r_y = Y_2 + (r_prime.y - Y_2) / res_factor

        if (r_prime.z < Z_1):
            z_fac = res_factor
            r_z = Z_1 + (r_prime.z - Z_1) / res_factor
        elif (r_prime.z > Z_2):
            z_fac = res_factor
            r_z = Z_2 + (r_prime.z - Z_2) / res_factor

        r = mp.Vector3(r_x, r_y, r_z)

        J = np.matrix([[x_fac, 0, 0], [0, y_fac, 0], [0, 0, z_fac]])

        #Loop through all objects inside of tip and see if point is inside.
        #  if yes -- then set eps_point to tip eps
        #  if no -- then leave it as air
        eps_point = 1.0
        for kk in range(len(tip)):
            if (mp.is_point_in_object(r, tip[kk])):
                eps_point = eps_tip

        eps_transform = eps_point * J * J.transpose() / np.linalg.det(J)
        mu_transform = J * J.transpose() / np.linalg.det(J)

        eps_diag = eps_transform.diagonal()
        mu_diag = mu_transform.diagonal()

        mat = mp.Medium(epsilon_diag=mp.Vector3(eps_diag[0, 0], eps_diag[0, 1],
                                                eps_diag[0, 2]),
                        mu_diag=mp.Vector3(mu_diag[0, 0], mu_diag[0, 1],
                                           mu_diag[0, 2]),
                        D_conductivity=sig_d_tip)

        return mat

    #Create source amplitude function:
    ky = fcen * np.sin(theta)
    ky_prime = ky * sY / sY_prime

    def my_amp_func_y(r_prime):

        r_y = r_prime.y
        y_fac = 1 / res_factor

        if ((r_prime.x >= X_1) and (r_prime.x <= X_2)):
            x_fac = 1.0 / res_factor
        else:
            x_fac = 1.0

        if (r_prime.y < Y_1):
            y_fac = 1.0
            r_y = Y_1 + (r_prime.y - Y_1) / res_factor
        elif (r_prime.y > Y_2):
            y_fac = 1.0
            r_y = Y_2 + (r_prime.y - Y_2) / res_factor

        if ((r_prime.z >= Z_1) and (r_prime.z <= Z_2)):
            z_fac = 1.0 / res_factor
        else:
            z_fac = 1.0

        J = np.matrix([[x_fac, 0, 0], [0, y_fac, 0], [0, 0, z_fac]])

        transform = J / np.linalg.det(J)

        phase_factor = np.exp(-1 * 2 * 1j * np.pi * ky * r_y)
        amp_factor = transform.diagonal()[0, 1]

        return amp_factor * phase_factor

    def my_amp_func_z(r_prime):

        r_y = r_prime.y
        y_fac = 1.0 / res_factor

        if ((r_prime.x >= X_1) and (r_prime.x <= X_2)):
            x_fac = 1.0 / res_factor
        else:
            x_fac = 1.0

        if (r_prime.y < Y_1):
            y_fac = 1.0
            r_y = Y_1 + (r_prime.y - Y_1) / res_factor
        elif (r_prime.y > Y_2):
            y_fac = 1.0
            r_y = Y_2 + (r_prime.y - Y_2) / res_factor

        if ((r_prime.z >= Z_1) and (r_prime.z <= Z_2)):
            z_fac = 1.0 / res_factor
        else:
            z_fac = 1.0

        J = np.matrix([[x_fac, 0, 0], [0, y_fac, 0], [0, 0, z_fac]])

        transform = J / np.linalg.det(J)

        phase_factor = np.exp(-1 * 2 * 1j * np.pi * ky * r_y)
        amp_factor = transform.diagonal()[0, 2]

        return amp_factor * phase_factor

    #Create PMLs
    pml_layers = [
        mp.PML(thickness=dpml_prime, direction=mp.X),
        mp.PML(thickness=dpml_prime, direction=mp.Y),
        mp.PML(thickness=dpml_prime, direction=mp.Z)
    ]

    symmetry = [mp.Mirror(direction=mp.X)]

    #Sources
    Ey_source = mp.Source(mp.ContinuousSource(frequency=fcen),
                          component=mp.Ey,
                          center=mp.Vector3(0, 0, -1 * sz_prime * 0.5),
                          size=mp.Vector3(sX_prime, sY_prime, 0),
                          amp_func=my_amp_func_y,
                          amplitude=np.cos(theta))

    Ez_source = mp.Source(mp.ContinuousSource(frequency=fcen),
                          component=mp.Ez,
                          center=mp.Vector3(0, 0, -1 * sz_prime * 0.5),
                          size=mp.Vector3(sX_prime, sY_prime, 0),
                          amp_func=my_amp_func_z,
                          amplitude=np.sin(theta))

    sources = [Ey_source, Ez_source]

    monitor_xy = mp.Volume(center=mp.Vector3(0, 0, 0),
                           size=mp.Vector3(x_mon_prime, y_mon_prime, 0))
    monitor_yz = mp.Volume(center=mp.Vector3(0, 0, 0),
                           size=mp.Vector3(0, y_mon_prime, z_mon_prime))

    #Now make the simulation
    sim = mp.Simulation(
        cell_size=cell,
        boundary_layers=pml_layers,
        geometry=[],
        sources=sources,
        resolution=res,
        symmetries=symmetry,
        dimensions=3,
        k_point=mp.Vector3(0, -1 * ky_prime, 0),
        material_function=mat_func,
        extra_materials=[mp.Medium(epsilon=eps_tip, mu=4, D_conductivity=1)],
        verbose=True)

    sim.run(mp.in_volume(
        monitor_xy,
        mp.to_appended(save_prefix + "E_xy",
                       mp.at_every(1 / fcen / sample, mp.output_efield))),
            mp.in_volume(
                monitor_yz,
                mp.to_appended(
                    save_prefix + "E_yz",
                    mp.at_every(1 / fcen / sample, mp.output_efield))),
            until=waves / fcen)