def _a_poly_tapering(geom=None, n_segments=20, material_holes=mp.vacuum): if geom is None: geom = [] material_holes = index_to_material(material_holes) hx = 0.143 hy = 0.315 w = 0.65 a_cen = 0.313 a_mirror = 0.361 Lx = 20 _cavity = OneDLattice(Lx = Lx) _n_taper = 10 h = 0.25 _cavity.polynomial_elliptical_hole_taper(_n_taper, hx, hy, w, a_cen, a_mirror ) _cavity.apply_poly_spacing() print("--------------------------------------------------------------------------------------------------------") print(" Poly Tapering : hx = {}, hy = {}, w = {}, h= {}, a_cen = {}, a_mirror = {}, n_taper = {}, Lx = {}".format(hx, hy,w, h, a_cen,a_mirror,_n_taper,Lx)) print("--------------------------------------------------------------------------------------------------------") #print(_cavity.coordinates) # cavity holes for x, y, z, hx, hy in _cavity.coordinates: # holes are completely filled with tuning material: geom.append(mp.Ellipsoid(material=material_holes, center=mp.Vector3(x, y, z), size=mp.Vector3(hx, hy, mp.inf))) geom.append(mp.Ellipsoid(material=material_holes, center=mp.Vector3(-x, y, z), size=mp.Vector3(hx, hy, mp.inf))) length = 2 * max(_cavity.coordinates[:, 0]) return geom, length
def _a_tapering(geom=None, n_segments=20, material_holes=mp.vacuum): """ Returns the geometry objects for a the air holes of 1D phc cavity with tapered lattice constants. TODO; allow change of resonant frequency to be able to make sweeps. """ if geom is None: geom = [] material_holes = index_to_material(material_holes) print(os.getcwd()) _cavity = Lattice(Lx=n_segments) _n_taper = 10 _cavity.polynomial_elliptical_hole_taper(_n_taper, 0.25, 0.25, 0.65, 0.349, 0.4) _cavity.apply_poly_spacing() print(_cavity.coordinates) # cavity holes for x, y, z, hx, hy in _cavity.coordinates: # holes are completely filled with tuning material: geom.append( mp.Ellipsoid(material=material_holes, center=mp.Vector3(x, y, z), size=mp.Vector3(hx, hy, mp.inf))) geom.append( mp.Ellipsoid(material=material_holes, center=mp.Vector3(-x, y, z), size=mp.Vector3(hx, hy, mp.inf))) length = 2 * max(_cavity.coordinates[:, 0]) return geom, length
def main(): c = mp.Cylinder(radius=3, material=mp.Medium(index=3.5)) e = mp.Ellipsoid(size=mp.Vector3(1, 2, 1e20)) src_cmpt = mp.Hz sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.1), component=src_cmpt, center=mp.Vector3()) if src_cmpt == mp.Ez: symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)] if src_cmpt == mp.Hz: symmetries = [mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, -1)] sim = mp.Simulation(cell_size=mp.Vector3(10, 10), geometry=[c, e], boundary_layers=[mp.PML(1.0)], sources=[sources], symmetries=symmetries, resolution=100) def print_stuff(sim_obj): v = mp.Vector3(4.13, 3.75, 0) p = sim.get_field_point(src_cmpt, v) print("t, Ez: {} {}+{}i".format(sim.round_time(), p.real, p.imag)) sim.run(mp.at_beginning(mp.output_epsilon), mp.at_every(0.25, print_stuff), mp.at_end(print_stuff), mp.at_end(mp.output_efield_z), until=23) print("stopped at meep time = {}".format(sim.round_time()))
def change_geom(sim): t = sim.meep_time() fn = t * 0.02 geom = [mp.Cylinder(radius=3, material=mp.Medium(index=3.5), center=mp.Vector3(fn, fn)), mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf), center=mp.Vector3(fn, fn))] sim.set_materials(geometry=geom)
def init(self): c = mp.Cylinder(radius=3, material=mp.Medium(index=3.5)) e = mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf)) sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.1), component=self.src_cmpt, center=mp.Vector3()) if self.src_cmpt == mp.Ez: symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)] if self.src_cmpt == mp.Hz: symmetries = [mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, -1)] self.sim = mp.Simulation(cell_size=mp.Vector3(10, 10), geometry=[c, e], boundary_layers=[mp.PML(1.0)], sources=[sources], symmetries=symmetries, resolution=100) self.sim.use_output_directory(self.temp_dir) def print_stuff(sim_obj): v = mp.Vector3(4.13, 3.75, 0) p = self.sim.get_field_point(self.src_cmpt, v) print("t, Ez: {} {}+{}i".format(self.sim.round_time(), p.real, p.imag)) self.print_stuff = print_stuff
def test_set_materials(self): def change_geom(sim): t = sim.meep_time() fn = t * 0.02 geom = [mp.Cylinder(radius=3, material=mp.Medium(index=3.5), center=mp.Vector3(fn, fn)), mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf), center=mp.Vector3(fn, fn))] sim.set_materials(geometry=geom) c = mp.Cylinder(radius=3, material=mp.Medium(index=3.5)) e = mp.Ellipsoid(size=mp.Vector3(1, 2, mp.inf)) sources = mp.Source(src=mp.GaussianSource(1, fwidth=0.1), component=mp.Hz, center=mp.Vector3()) symmetries = [mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, -1)] sim = mp.Simulation(cell_size=mp.Vector3(10, 10), geometry=[c, e], boundary_layers=[mp.PML(1.0)], sources=[sources], symmetries=symmetries, resolution=16) eps = {'arr1': None, 'arr2': None} def get_arr1(sim): eps['arr1'] = sim.get_array(mp.Dielectric, mp.Volume(mp.Vector3(), mp.Vector3(10, 10))) def get_arr2(sim): eps['arr2'] = sim.get_array(mp.Dielectric, mp.Volume(mp.Vector3(), mp.Vector3(10, 10))) sim.run(mp.at_time(50, get_arr1), mp.at_time(100, change_geom), mp.at_end(get_arr2), until=200) self.assertFalse(np.array_equal(eps['arr1'], eps['arr2']))
def get_freqs_interpolate(hx=0.24, hy=0.24, a=0.33, wy=0.7, h=0.22): ''' Useless ''' import meep as mp from meep import mpb mode = "zEyO" resolution = 20 # pixels/a, taken from simpetus example a = round(a, 3) # units of um h = round(h, 3) # units of um w = round(wy, 3) # units of um hx = round(hx, 3) hy = round(hy, 3) h = h / a # units of "a" w = w / a # units of "a" hx = hx / a # units of "a" hy = hy / a # units of "a" nSi = 3.45 Si = mp.Medium(index=nSi) geometry_lattice = mp.Lattice(size=mp.Vector3( 1, 4, 4)) # dimensions of lattice taken from simpetus example geometry = [ mp.Block(center=mp.Vector3(), size=mp.Vector3(mp.inf, w, h), material=Si), mp.Ellipsoid(material=mp.air, center=mp.Vector3(), size=mp.Vector3(hx, hy, mp.inf)) ] num_k = 20 # from simpetus example, no. of k_points to evaluate the eigen frequency at k_points = mp.interpolate( num_k, [mp.Vector3(0, 0, 0), mp.Vector3(0.5, 0, 0)]) num_bands = 2 # from simpetus example ms = mpb.ModeSolver(geometry_lattice=geometry_lattice, geometry=geometry, k_points=k_points, resolution=resolution, num_bands=num_bands) if mode == "te": ms.run_te() # running for all modes and extracting parities if mode == "zEyO": ms.run_yodd_zeven() return ms.freqs
def get_freqs(hx=0.24, hy=0.24, a=0.33, w=0.7, h=0.22): ''' Returns tuple of dielectric and air band edge frequencies for input parameters ''' import meep as mp from meep import mpb res = 20 mode = "zEyO" resolution = res # pixels/a, taken from simpetus example a = round(a, 3) # units of um h = round(h, 3) # units of um w = round(w, 3) # units of um hx = round(hx, 3) hy = round(hy, 3) h = h / a # units of "a" w = w / a # units of "a" hx = hx / a # units of "a" hy = hy / a # units of "a" nSi = 3.45 Si = mp.Medium(index=nSi) geometry_lattice = mp.Lattice(size=mp.Vector3( 1, 4, 4)) # dimensions of lattice taken from simpetus example geometry = [ mp.Block(center=mp.Vector3(), size=mp.Vector3(mp.inf, w, h), material=Si), mp.Ellipsoid(material=mp.air, center=mp.Vector3(), size=mp.Vector3(hx, hy, mp.inf)) ] k_points = [mp.Vector3(0.5, 0, 0)] num_bands = 2 # from simpetus example ms = mpb.ModeSolver(geometry_lattice=geometry_lattice, geometry=geometry, k_points=k_points, resolution=resolution, num_bands=num_bands) if mode == "te": ms.run_te() # running for all modes and extracting parities if mode == "zEyO": ms.run_yodd_zeven() return ms.freqs
def _a_normal_tapering(geom=None, n_segments=20, material_holes=mp.vacuum): if geom is None: geom = [] material_holes = index_to_material(material_holes) _cavity = OneDLattice(Lx = n_segments) _cavity.normal_spacing(a = 0.303, hx = 0.143, hy = 0.315) for x, y, z, hx, hy in _cavity.coordinates: # holes are completely filled with tuning material: geom.append(mp.Ellipsoid(material=material_holes, center=mp.Vector3(x, y, z), size=mp.Vector3(hx, hy, mp.inf))) geom.append(mp.Ellipsoid(material=material_holes, center=mp.Vector3(-x, y, z), size=mp.Vector3(hx, hy, mp.inf))) length = 10 return geom, length
def get_freqs(hx, hy, a, w): wz = 0.22 res = 20 mode = "zEyO" resolution = res # pixels/a, taken from simpetus example # a = round(a,3) # units of um # h = round(wz, 3) # units of um # w = round(wy, 3) # units of um # hx = round(hx, 3) # hy = round(hy, 3) h = wz h = h / a # units of "a" w = w / a # units of "a" hx = hx / a # units of "a" hy = hy / a # units of "a" nSi = 3.45 Si = mp.Medium(index=nSi) geometry_lattice = mp.Lattice(size=mp.Vector3( 1, 4, 4)) # dimensions of lattice taken from simpetus example geometry = [ mp.Block(center=mp.Vector3(), size=mp.Vector3(mp.inf, w, h), material=Si), mp.Ellipsoid(material=mp.air, center=mp.Vector3(), size=mp.Vector3(hx, hy, mp.inf)) ] k_points = [mp.Vector3(0.5, 0, 0)] num_bands = 2 # from simpetus example ms = mpb.ModeSolver(geometry_lattice=geometry_lattice, geometry=geometry, k_points=k_points, resolution=resolution, num_bands=num_bands) if mode == "te": ms.run_te() # running for all modes and extracting parities if mode == "zEyO": ms.run_yodd_zeven() return ms.freqs
def quadratic_radius_1d_symmetric(n_segments=20, a=.33, hx=.21, hy=.21, h_rel=.7, z_center=0, d_tuning=0, material_holes=mp.vacuum): """ Returns the geometry objects for a the air holes of 1D phc cavity with quadraticly tapered radii. TODO: change between Ellipsoids and Cylinders if hx==hy. """ material_holes = index_to_material(material_holes) cavity = Lattice(n_segments) cavity.set_z(z_center) cavity.quadratic_hole_taper(h_rel) cavity_holes = [] # cavity holes for x, y, z, hx, hy in cavity.coordinates: # holes are completely filled with tuning material: cavity_holes.append( mp.Ellipsoid(material=material_holes, center=mp.Vector3(x, y, z), size=mp.Vector3(hx, hy, mp.inf))) cavity_holes.append( mp.Ellipsoid(material=material_holes, center=mp.Vector3(-x, y, z), size=mp.Vector3(hx, hy, mp.inf))) length = 2 * max(cavity.coordinates[:, 0]) return cavity_holes, length
def geo2D_ellipsoid_pc(n_matrix, n_substrate, film_xsize, substrate_xsize, film_ysize, n_layers, film_base_x, ellipsex, ellipsey, ellipse_spacing, layer_offset, ellipse_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 + ellipse_x_offset offset = layer_offset[n] num_spheres = int(film_ysize / ellipse_spacing) sphere_layer = [ mp.Ellipsoid(size=mp.Vector3(ellipsex, ellipsey, 1e20), 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
def _a_poly_tapering(geom=None, n_segments=20, material_holes=mp.vacuum): filename = "bandstructure_data/sweep_data.hdf5" hf = h5py.File(filename, 'r') gamma_data = np.array( hf.get("gamma")) freq_data = np.array( hf.get("freq")) hf.close() if geom is None: geom = [] material_holes = index_to_material(material_holes) #--------------- These are the parameters for DESIGNED geometry, which we want to perturb ------------ # hx = 0.225 hy = 0.4 a_mirror = 0.414 a_cen = 0.385 w = 0.65 h = 0.19 mode = "zEyO" substrate = True Lx = 20 _n_taper = 10 _cavity = OneDLattice(Lx = Lx) # ------------------------------ PERTURBATION HERE -------------------------------------------- # # Essentially how this works is that at the end of all the repetitive code, you get 4 values: # (1) lower_param : the value of the parameter that gives a resonant frequency slightly lower than the earlier one # (2) upper_param : the value of the parameter that gives a resonant frequency slightly higher than the earlier one # (3) a_mirror_new_lower : the new a_mirror that maximizes gamma for positive delta_freq and new hy/hx # (4) a_mirror_new_upper : the new a_mirror that maximizes gamma for negative delta_freq and new hy/x to_perturb = "hx" # one of hx, hy and a perturb_range = 0.04 # edges of the wavelength (in um) window will be (target_lambda +- perturb_range) tol_Thz = 1 # tolerance in Thz to select the perturbed segment parameters target_wvl = 1.54 # vaccum wavelength ( in um ) of the unperturbed cavity design target_f = 1/target_wvl target_f_Thz = convert_freq_to_Thz(target_f) f_perturb_lower = 1 / (target_wvl + perturb_range ) # target_f - perturbation f_perturb_upper = 1 / (target_wvl - perturb_range ) # target_f + perturbation f_perturb_lower_Thz = convert_freq_to_Thz(f_perturb_lower) f_perturb_upper_Thz = convert_freq_to_Thz(f_perturb_upper) lower_param, upper_param = get_perturb_param(to_perturb = to_perturb , w = w, a = a_cen, hy = hy, hx = hx , h =h, target_f_Thz= target_f_Thz, substrate = substrate, f_perturb_lower_Thz= f_perturb_lower_Thz, f_perturb_upper_Thz= f_perturb_upper_Thz, tol_Thz = tol_Thz, mode = mode) step_size = 0.004 # size of each of the n_steps n_step = 7 # number of steps to search for the optimal gamma for the mirror segment a_mirror_new_lower, a_mirror_new_upper = get_mirror_param(to_perturb = to_perturb, w = w, a_mirror = a_mirror, hy = hy, hx = hx , h = h, target_f_Thz = target_f_Thz, f_perturb_lower_Thz = f_perturb_lower_Thz, f_perturb_upper_Thz = f_perturb_upper_Thz, mode = mode, substrate = substrate, step_size = step_size, n_step = n_step, lower_param = lower_param, upper_param = upper_param) # Here upper_param and lower_param correspond to the perturbed parameters that result in resonant # frequencies of f_perturb_upper_Thz and f_perturb_lower_Thz respectively # a_mirror_new_lower,a_mirror_new_upper refer to the new values of a_mirror that maximise gamma_mirror for # the the two ends of the perturbation window #----------------------------------------------------------------------------------------------------# _cavity.polynomial_elliptical_hole_taper(_n_taper, hx, hy, w, a_cen, a_mirror ) _cavity.apply_poly_spacing() print("--------------------------------------------------------------------------------------------------------") print(" Poly Tapering : hx = {}, hy = {}, w = {}, h= {}, a_cen = {}, a_mirror = {}, n_taper = {}, Lx = {}".format(hx, hy,w, h, a_cen,a_mirror,_n_taper,Lx)) print("--------------------------------------------------------------------------------------------------------") # cavity holes for x, y, z, hx, hy in _cavity.coordinates: # holes are completely filled with tuning material: geom.append(mp.Ellipsoid(material=material_holes, center=mp.Vector3(x, y, z), size=mp.Vector3(hx, hy, mp.inf))) geom.append(mp.Ellipsoid(material=material_holes, center=mp.Vector3(-x, y, z), size=mp.Vector3(hx, hy, mp.inf))) length = 2 * max(_cavity.coordinates[:, 0]) return geom, length
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.Ellipsoid(material=mp.metal, size=mp.Vector3(2, 0.5, 0.5), e1=mp.Vector3(1, 1, 1), e2=mp.Vector3(-1, 1, -1), e3=mp.Vector3(-2, 1, 1)) ] 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()
### Parameters rx = 100 * nm ry = 125 * nm rz = 75 * nm material = meep_ext.material.Au() material = meep.Medium(index=3.5) geometry = [] # axis = meep.Vector3(np.sin(theta[i])*np.cos(phi[i]), np.sin(theta[i])*np.sin(phi[i]), np.cos(theta[i])) q = miepy.quaternion.from_spherical_coords(np.pi / 4, np.pi / 3) R = miepy.quaternion.as_rotation_matrix(q) geometry.append( meep.Ellipsoid(center=meep.Vector3(0, 0, 0), size=2 * meep.Vector3(rx, ry, rz), e1=meep.Vector3(*R[:, 0]), e2=meep.Vector3(*R[:, 1]), e3=meep.Vector3(*R[:, 2]), material=material)) box = [2 * ry, 2 * ry, 2 * ry] resolution = 1 / (8 * nm) medium = meep.Medium(index=1) fcen, df = meep_ext.freq_data(1 / (400 * nm), 1 / (1000 * nm)) nfreq = 40 polarization = 'x' src_time = meep.GaussianSource(frequency=1.3 / um, fwidth=4.0 / um) if polarization == 'x': source = lambda sim: meep_ext.x_polarized_plane_wave(sim, src_time) decay = meep.Ex
hy = hy_actual/a_actual h = w/2/np.tan(theta*np.pi/180) #################################################################### #sets size of lattice to be 3D; 1by1by1 geometry_lattice = mp.Lattice(size=mp.Vector3(a, w*3, h*3)) #https://meep.readthedocs.io/en/latest/Python_User_Interface/#prism beam = mp.Prism([mp.Vector3(0,-w/2, h/2), mp.Vector3(0,w/2, h/2), mp.Vector3(0,0, -h/2)], a, axis=mp.Vector3(1,0,0), center=None, material=mp.Medium(epsilon=n**2)) #Diamond: n = 2.4063; n^2 = ep_r hole = mp.Ellipsoid(size=[hx, hy, mp.inf], material=mp.Medium(epsilon=1)) geometry = [beam, hole] #Symmetry points k_points = [ mp.Vector3(0,0,0), # Gamma mp.Vector3(0.5,0,0), # X (normalized to a?) ] #how many points to solve for between each specified point above k_points = mp.interpolate(kpt_resolution, k_points) #geometry_center #ModeSolver documentation: https://mpb.readthedocs.io/en/latest/Python_User_Interface/ ms = mpb.ModeSolver( geometry=geometry,
def get_freqs(hx, hy, a, w, h=0.22, substrate=False, output_epsilon=False, mode="zEyO", num_bands=2): # h = 0.23 # for manually setting waveguide height res = 20 #mode = "zEyO" resolution = res # pixels/a, taken from simpetus example print(" h = " + str(h) + ", SUBSTRATE = " + str(substrate) + ", mode = " + str(mode)) a = round(a, 3) # units of um h = round(h, 3) # units of um w = round(w, 3) # units of um hx = round(hx, 3) hy = round(hy, 3) h = h / a # units of "a" w = w / a # units of "a" hx = hx / a # units of "a" hy = hy / a # units of "a" cell_x = 1 cell_y = 4 cell_z = 4 nSi = 3.45 Si = mp.Medium(index=nSi) geometry_lattice = mp.Lattice(size=mp.Vector3( cell_x, cell_y, cell_z)) # dimensions of lattice taken from simpetus example geometry = [ mp.Block(center=mp.Vector3(), size=mp.Vector3(mp.inf, w, h), material=Si), mp.Ellipsoid(material=mp.air, center=mp.Vector3(), size=mp.Vector3(hx, hy, mp.inf)) ] if substrate: geometry = add_substrate(geom=geometry, waveguide_height=h, substrate_height=cell_z / 2 - h / 2) # substrate height normalized with a k_points = [mp.Vector3(0.5, 0, 0)] num_bands = num_bands ms = mpb.ModeSolver(geometry_lattice=geometry_lattice, geometry=geometry, k_points=k_points, resolution=resolution, num_bands=num_bands) if mode == "te": ms.run_te() # running for all modes and extracting parities if mode == "zEyO": ms.run_yodd_zeven() if mode == "yO": ms.run_yodd() if mode == "yE": ms.run_yeven() # if output_epsilon: # visualise_geometry(ms = ms, x = None , y = None, z = (4 * res)/ 2, value = None) if output_epsilon: return ms.get_epsilon() # with h5py.File('epsilon.hdf5', 'w') as f: # arr = ms.get_epsilon # dset = f.create_dataset("epsilon", data = arr) return ms.freqs
def build_geom(sx, sy, dsub, gp, gh, lw, tr, br, sa, material): tw = gh / np.tan( sa * 2 * np.pi / 360) # part to subtract from top of grating width a = (gh - tr) / np.tan( sa * 2 * np.pi / 360) # intermediate for vertex calculation #vertices for trapezoids approximating grating cross-section vtx = [ mp.Vector3(-0.5 * lw - 0.5 * a + gp / 2, -1 * (-0.5 * gh), 0), mp.Vector3(0.5 * lw + 0.5 * a + gp / 2, -1 * (-0.5 * gh), 0), mp.Vector3(0.5 * lw - 0.5 * a + gp / 2, -1 * (0.5 * gh - tr), 0), mp.Vector3(-0.5 * lw + 0.5 * a + gp / 2, -1 * (0.5 * gh - tr), 0) ] vtx2 = [ mp.Vector3(-0.5 * lw - 0.5 * a - gp / 2, -1 * (-0.5 * gh), 0), mp.Vector3(0.5 * lw + 0.5 * a - gp / 2, -1 * (-0.5 * gh), 0), mp.Vector3(0.5 * lw - 0.5 * a - gp / 2, -1 * (0.5 * gh - tr), 0), mp.Vector3(-0.5 * lw + 0.5 * a - gp / 2, -1 * (0.5 * gh - tr), 0) ] #rounded corners for top of trapezoids c1 = mp.Cylinder(radius=tr, height=mp.inf, axis=mp.Vector3(0, 0, 1), center=mp.Vector3(-gp / 2 - lw / 2 + tw / 2 + tr, -1 * (-sy / 2 + dsub + gh - tr), 0), material=material) c2 = mp.Cylinder(radius=tr, height=mp.inf, axis=mp.Vector3(0, 0, 1), center=mp.Vector3(-gp / 2 + lw / 2 - tw / 2 - tr, -1 * (-sy / 2 + dsub + gh - tr), 0), material=material) c3 = mp.Cylinder(radius=tr, height=mp.inf, axis=mp.Vector3(0, 0, 1), center=mp.Vector3(gp / 2 - lw / 2 + tw / 2 + tr, -1 * (-sy / 2 + dsub + gh - tr), 0), material=material) c4 = mp.Cylinder(radius=tr, height=mp.inf, axis=mp.Vector3(0, 0, 1), center=mp.Vector3(gp / 2 + lw / 2 - tw / 2 - tr, -1 * (-sy / 2 + dsub + gh - tr), 0), material=material) #blocks for top of trapezoids inbetween rounded corners b1 = mp.Block(center=mp.Vector3(-gp / 2, -1 * (-sy / 2 + dsub + gh - tr / 2)), size=mp.Vector3(lw - tw - 2 * tr, tr, mp.inf), material=material) b2 = mp.Block(center=mp.Vector3(gp / 2, -1 * (-sy / 2 + dsub + gh - tr / 2)), size=mp.Vector3(lw - tw - 2 * tr, tr, mp.inf), material=material) #ellipsoid cutout to make bottom of grating round e1 = mp.Ellipsoid(center=mp.Vector3(0, -1 * (-sy / 2 + dsub), 0), size=mp.Vector3(gp - lw - a, br, mp.inf), material=mp.Medium(epsilon=1)) e2 = mp.Ellipsoid(center=mp.Vector3(-gp, -1 * (-sy / 2 + dsub), 0), size=mp.Vector3(gp - lw - a, br, mp.inf), material=mp.Medium(epsilon=1)) e3 = mp.Ellipsoid(center=mp.Vector3(gp, -1 * (-sy / 2 + dsub), 0), size=mp.Vector3(gp - lw - a, br, mp.inf), material=mp.Medium(epsilon=1)) geometry = [ mp.Block(material=material, size=mp.Vector3(sx, dsub, mp.inf), center=mp.Vector3(0, -1 * (-0.5 * sy + 0.5 * dsub), 0)), mp.Prism(vtx, height=mp.inf, center=mp.Vector3(0, -1 * (-0.5 * sy + dsub + 0.5 * gh), 0), material=material), mp.Prism(vtx2, height=mp.inf, center=mp.Vector3(0, -1 * (-0.5 * sy + dsub + 0.5 * gh), 0), material=material), c1, c2, c3, c4, b1, b2, e1, e2, e3 ] return geometry
def main(series, folder, resolution, from_um_factor, d, h, paper, wlen_range, nfreq): #%% PARAMETERS ### MEAN PARAMETERS # Units: 10 nm as length unit from_um_factor = 10e-3 # Conversion of 1 μm to my length unit (=10nm/1μm) # Au sphere medium = import_medium("Au", from_um_factor, paper=paper) # Medium of sphere: gold (Au) d = d / (from_um_factor * 1e3) # Diameter is now in Meep units h = h / (from_um_factor * 1e3) # Height is now in Meep units # Frequency and wavelength wlen_range = wlen_range / (from_um_factor * 1e3 ) # Wavelength range now in Meep units nfreq = 100 # Number of frequencies to discretize range cutoff = 3.2 # Computation time enlapsed = [] time_factor_cell = 1.2 until_after_sources = False second_time_factor = 10 # Saving directories home = vs.get_home() ### OTHER PARAMETERS # Units # uman = MeepUnitsManager(from_um_factor=from_um_factor) # Frequency and wavelength 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 = 0.38 * max(wlen_range) air_width = max(d / 2, h / 2) / 2 # 0.5 * max(wlen_range) #%% 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_z = 2 * (pml_width + air_width + h / 2 ) # Parallel to polarization. cell_width_z = cell_width_z - cell_width_z % (1 / resolution) cell_width_r = 2 * (pml_width + air_width + d / 2 ) # Parallel to incidence. cell_width_r = cell_width_r - cell_width_r % (1 / resolution) cell_size = mp.Vector3(cell_width_r, cell_width_r, cell_width_z) source_center = -0.5 * cell_width_r + pml_width # print("Resto Source Center: {}".format(source_center%(1/resolution))) 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_r, cell_width_z), 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 if time_factor_cell is not False: until_after_sources = time_factor_cell * cell_width_r else: if until_after_sources is False: raise ValueError( "Either time_factor_cell or until_after_sources must be specified" ) time_factor_cell = until_after_sources / cell_width_r # 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.Ellipsoid(size=mp.Vector3(d, d, h), material=medium, center=mp.Vector3()) ] # Au ellipsoid with frequency-dependant characteristics imported from Meep. path = os.path.join(home, folder, f"{series}") if not os.path.isdir(path) and mp.am_master(): vs.new_dir(path) file = lambda f: os.path.join(path, f) #%% FIRST RUN: SET UP sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=mp.Vector3()) #, # symmetries=symmetries) # >> k_point zero specifies boundary conditions needed # for the source to be infinitely extended # 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=-d / 2), size=mp.Vector3(0, d, h))) box_x2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(x=+d / 2), size=mp.Vector3(0, d, h))) box_y1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(y=-d / 2), size=mp.Vector3(d, 0, h))) box_y2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(y=+d / 2), size=mp.Vector3(d, 0, h))) box_z1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(z=-h / 2), size=mp.Vector3(d, d, 0))) box_z2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(z=+h / 2), size=mp.Vector3(d, d, 0))) # Funny you can encase the ellipsoid (diameter d and height h) so closely # (dxdxh-sided box) #%% FIRST RUN: INITIALIZE temp = time() sim.init_sim() enlapsed.append(time() - temp) """ 112x112x112 with resolution 4 (48 cells inside diameter) ==> 30 s to build 112x112x112 with resolution 2 (24 cells inside diameter) ==> 4.26 s to build 116x116x116 with resolution 2 (24 cells inside diameter) ==> 5.63 s 98 x 98 x 98 with resolution 3 (36 cells inside diameter) ==> 9.57 s 172x172x172 with resolution 2 (24 cells inside diameter) ==> 17.47 s 67 x 67 x 67 with resolution 4 (48 cells inside diameter) ==> 7.06 s 67,375 x 67,375 x 67,375 with resolution 8 (100 cells inside diameter) ==> 56.14 s """ #%% FIRST RUN: SIMULATION NEEDED TO NORMALIZE temp = time() sim.run(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) """ 112x112x112 with resolution 2 (24 cells inside diameter) ==> 135.95 s to complete 1st run 116x116x116 with resolution 2 (24 cells inside diameter) ==> 208 s to complete 1st run 67 x 67 x 67 with resolution 4 (48 cells inside diameter) ==> 2000 s = 33 min to complete 1st run """ freqs = np.asarray(mp.get_flux_freqs(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) 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)) # field = sim.get_array(center=mp.Vector3(), # size=(cell_width, cell_width, cell_width), # component=mp.Ez) sim.reset_meep() #%% SAVE MID DATA params = dict( from_um_factor=from_um_factor, resolution=resolution, d=d, h=h, paper=paper, wlen_range=wlen_range, nfreq=nfreq, cutoff=cutoff, pml_width=pml_width, air_width=air_width, source_center=source_center, enlapsed=enlapsed, series=series, folder=folder, pc=pc, until_after_sources=until_after_sources, time_factor_cell=time_factor_cell, second_time_factor=second_time_factor, ) # f = h5.File(file("MidField.h5"), "w") # f.create_dataset("Ez", data=field) # for a in params: f["Ez"].attrs[a] = params[a] # f.close() # del f 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 mp.am_master(): vs.savetxt(file("MidFlux.txt"), data_mid, header=header_mid, footer=params) #%% PLOT FLUX FOURIER MID DATA if mp.my_rank() == 1: 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, hm in zip(np.reshape(ax, 6), header_mid[1:]): a.set_ylabel(hm) for dm, a in zip(data_mid[:, 1:].T, np.reshape(ax, 6)): a.plot(1e3 * from_um_factor / freqs, dm) a.set_ylim(*ylims) ax[-1, 0].set_xlabel("Wavelength [nm]") ax[-1, 1].set_xlabel("Wavelength [nm]") plt.savefig(file("MidFlux.png")) #%% PLOT FLUX WALLS FIELD # if mp.am_master(): # index_to_space = lambda i : i/resolution - cell_width/2 # space_to_index = lambda x : round(resolution * (x + cell_width/2)) # field_walls = [field[space_to_index(-r),:,:], # field[space_to_index(r),:,:], # field[:,space_to_index(-r),:], # field[:,space_to_index(r),:], # field[:,:,space_to_index(-r)], # field[:,:,space_to_index(r)]] # zlims = (np.min([np.min(f) for f in field_walls]), # np.max([np.max(f) for f in field_walls])) # fig, ax = plt.subplots(3, 2) # fig.subplots_adjust(hspace=0.25) # for a, hm in zip(np.reshape(ax, 6), header_mid[1:]): # a.set_title(hm.split(" ")[1].split("0")[0]) # for f, a in zip(field_walls, np.reshape(ax, 6)): # a.imshow(f.T, interpolation='spline36', cmap='RdBu', # vmin=zlims[0], vmax=zlims[1]) # a.axis("off") # plt.savefig(file("MidField.png")) #%% SECOND RUN: SETUP sim = mp.Simulation( resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=mp.Vector3(), # symmetries=symmetries, geometry=geometry) box_x1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(x=-d / 2), size=mp.Vector3(0, d, h))) box_x2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(x=+d / 2), size=mp.Vector3(0, d, h))) box_y1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(y=-d / 2), size=mp.Vector3(d, 0, h))) box_y2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(y=+d / 2), size=mp.Vector3(d, 0, h))) box_z1 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(z=-h / 2), size=mp.Vector3(d, d, 0))) box_z2 = sim.add_flux( freq_center, freq_width, nfreq, mp.FluxRegion(center=mp.Vector3(z=+h / 2), size=mp.Vector3(d, d, 0))) #%% SECOND RUN: INITIALIZE temp = time() sim.init_sim() enlapsed.append(time() - temp) """ 112x112x112 with resolution 2 (24 cells in diameter) ==> 5.16 s to build with sphere 116x116x116 with resolution 2 (24 cells inside diameter) ==> 9.71 s to build with sphere 67 x 67 x 67 with resolution 4 (48 cells inside diameter) ==> 14.47 s to build with sphere """ 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) enlapsed.append(time() - temp) del box_x1_data, box_x2_data, box_y1_data, box_y2_data del box_z1_data, box_z2_data """ 112x112x112 with resolution 2 (24 cells in diameter) ==> 0.016 s to add flux 116x116x116 with resolution 2 (24 cells inside diameter) ==> 0.021 s to add flux 67 x 67 x 67 with resolution 4 (48 cells inside diameter) ==> 0.043 s to add flux """ #%% SECOND RUN: SIMULATION :D temp = time() sim.run(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)) #%% 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 / (d**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 * d**2) # Scattering efficiency = # = scattering cross section / cross sectional area of the sphere # WATCH IT! Is this the correct cross section? freqs = np.array(freqs) #%% SAVE FINAL DATA data = np.array([1e3 * from_um_factor / freqs, scatt_eff_meep]).T header = ["Longitud de onda [nm]", "Sección eficaz efectiva (Meep) [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 mp.am_master(): vs.savetxt(file("Results.txt"), data, header=header, footer=params) vs.savetxt(file("BaseResults.txt"), data_base, header=header_base, footer=params) #%% PLOT SCATTERING if mp.my_rank() == 1: 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(f'Scattering of Au Ellipsoid ({ 1e3*from_um_factor*d }x' + f'{ 1e3*from_um_factor*d }x{ 1e3*from_um_factor*h } nm)') plt.tight_layout() plt.savefig(file("ScattSpectra.png")) #%% PLOT ABSORPTION if mp.am_master(): plt.figure() plt.plot(1e3 * from_um_factor / freqs, 1 - scatt_eff_meep, 'bo-', label='Meep') plt.xlabel('Wavelength [nm]') plt.ylabel('Absorption efficiency [σ/πr$^{2}$]') plt.legend() plt.title(f'Absorption of Au Ellipsoid ({ 1e3*from_um_factor*d }x' + f'{ 1e3*from_um_factor*d }x{ 1e3*from_um_factor*h } nm)') plt.tight_layout() plt.savefig(file("AbsSpectra.png"))
rightwall = mp.Block(mp.Vector3(wallWidth, waveguideHeight + 2 * wallWidth, mp.inf), center=mp.Vector3(waveguideLength / 2 + wallWidth / 2, 0, 0), material=mp.metal) obstacle = mp.Cylinder(radius=2, height=1, axis=mp.Vector3(0, 0, 1), center=mp.Vector3(0, 0, 0), material=mp.metal) obstacle1 = mp.Ellipsoid(center=mp.Vector3(-5, 4, 0), size=mp.Vector3(8, 2, 2), e1=mp.Vector3(1, 1, 0), e2=mp.Vector3(0, 1, 0), e3=mp.Vector3(0, 0, 1), material=mp.metal) obstacle2 = mp.Ellipsoid(center=mp.Vector3(6, -6, 0), size=mp.Vector3(8, 2, 2), e1=mp.Vector3(1, .5, 0), e2=mp.Vector3(0, 1, 0), e3=mp.Vector3(0, 0, 1), material=mp.metal) port1 = mp.Block(portSize, center=p1Loc, material=mp.Medium(epsilon=dielectricConstant)) port2 = mp.Block(portSize,
# (its size parameter fills the entire cell in 2d) # >> The planewave source extends into the PML # ==> is_integrated=True must be specified if time_factor_cell is not False: until_after_sources = time_factor_cell * cell_width_r else: if until_after_sources is False: raise ValueError( "Either time_factor_cell or until_after_sources must be specified") time_factor_cell = until_after_sources / cell_width_r # 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.Ellipsoid(size=mp.Vector3(d, d, h), material=medium)] # Au ellipsoid with frequency-dependant characteristics imported from Meep. path = os.path.join(home, folder, f"{series}") if not os.path.isdir(path): vs.new_dir(path) file = lambda f: os.path.join(path, f) #%% FIRST RUN: SET UP sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, sources=sources, k_point=mp.Vector3()) #, # symmetries=symmetries) # >> k_point zero specifies boundary conditions needed