def test_2d_pml_and_absorber(self): blayers = [mp.PML(1, mp.Y, mp.High), mp.PML(2, mp.Y, mp.Low), mp.Absorber(1, mp.X, mp.High), mp.Absorber(3, mp.X, mp.Low)] fs = self.get_fragment_stats(mp.Vector3(), mp.Vector3(30, 30), 2, pml=blayers, geom=[]) self.assertEqual(fs.num_nonzero_conductivity_pixels, 12000) self.assertEqual(fs.num_1d_pml_pixels, 9000) self.assertEqual(fs.num_2d_pml_pixels, 0) self.assertEqual(fs.num_3d_pml_pixels, 0)
def main(args): resolution = 40 cell_size = mp.Vector3(z=10) boundary_layers = [ mp.PML(1, direction=mp.Z) if args.pml else mp.Absorber(1, direction=mp.Z) ] sources = [ mp.Source(src=mp.GaussianSource(1 / 0.803, fwidth=0.1), center=mp.Vector3(), component=mp.Ex) ] def print_stuff(sim): p = sim.get_field_point(mp.Ex, mp.Vector3()) print("ex:, {}, {}".format(sim.meep_time(), p.real)) sim = mp.Simulation(cell_size=cell_size, resolution=resolution, dimensions=1, default_material=Al, boundary_layers=boundary_layers, sources=sources) sim.run(mp.at_every(10, print_stuff), until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ex, mp.Vector3(), 1e-6))
def test_3d_with_absorbers(self): fs = self.get_fragment_stats(mp.Vector3(), mp.Vector3(30, 30, 30), 3, geom=[], pml=[mp.Absorber(1)]) self.assertEqual(fs.num_1d_pml_pixels, 0) self.assertEqual(fs.num_2d_pml_pixels, 0) self.assertEqual(fs.num_3d_pml_pixels, 0) self.assertEqual(fs.num_nonzero_conductivity_pixels, 5048000)
def main(args): resolution = 20 cell_size = mp.Vector3(z=10) dimensions = 1 # conversion factor fro eV to 1/um eV_um_scale = 1 / 1.23984193 # Al, from Rakic et al., Applied Optics, vol. 32, p. 5274 (1998) Al_eps_inf = 1 Al_plasma_frq = 14.98 * eV_um_scale Al_f0 = 0.523 Al_frq0 = 1e-10 Al_gam0 = 0.047 * eV_um_scale Al_sig0 = (Al_f0 * math.sqrt(Al_plasma_frq)) / (math.sqrt(Al_frq0)) Al_f1 = 0.050 Al_frq1 = 1.544 * eV_um_scale # 803 nm Al_gam1 = 0.312 * eV_um_scale Al_sig1 = (Al_f1 * math.sqrt(Al_plasma_frq)) / (math.sqrt(Al_frq1)) E_susceptibilities = [ mp.DrudeSusceptibility(frequency=Al_frq0, gamma=Al_gam0, sigma=Al_sig0), mp.LorentzianSusceptibility(frequency=Al_frq1, gamma=Al_gam1, sigma=Al_sig1) ] Al = mp.Medium(epsilon=Al_eps_inf, E_susceptibilities=E_susceptibilities) pml_layers = [ mp.PML(1, direction=mp.Z) if args.pml else mp.Absorber(1, direction=mp.Z) ] sources = [ mp.Source(src=mp.GaussianSource(1 / 0.803, fwidth=0.1), center=mp.Vector3(), component=mp.Ex) ] def print_stuff(sim): print("ex:, {}, {}".format(sim.meep_time(), sim.get_field_point(mp.Ex, mp.Vector3()))) sim = mp.Simulation(cell_size=cell_size, resolution=resolution, dimensions=dimensions, default_material=Al, boundary_layers=pml_layers, sources=sources) sim.run(mp.at_every(10, print_stuff), until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ex, mp.Vector3(), 1e-6))
def test_2d_pml_and_absorber(self): blayers = [mp.PML(1, mp.Y, mp.High), mp.PML(2, mp.Y, mp.Low), mp.Absorber(1, mp.X, mp.High), mp.Absorber(3, mp.X, mp.Low)] fragments = self.get_fragment_stats(mp.Vector3(), mp.Vector3(30, 30), 2, pml=blayers, geom=[]) num_nonzero_cond = 0 num_pml_1d = 0 num_pml_2d = 0 num_pml_3d = 0 for f in fragments: num_nonzero_cond += f.num_nonzero_conductivity_pixels num_pml_1d += f.num_1d_pml_pixels num_pml_2d += f.num_2d_pml_pixels num_pml_3d += f.num_3d_pml_pixels self.assertEqual(num_nonzero_cond, 12000) self.assertEqual(num_pml_1d, 9000) self.assertEqual(num_pml_2d, 0) self.assertEqual(num_pml_3d, 0)
def test_3d_with_absorbers(self): fs = self.get_fragment_stats(mp.Vector3(), mp.Vector3(30, 30, 30), 3, geom=[], pml=[mp.Absorber(1)]) total_nonzero_cond_pixels = 0 for i in range(len(fs)): self.assertEqual(fs[i].num_1d_pml_pixels, 0) self.assertEqual(fs[i].num_2d_pml_pixels, 0) self.assertEqual(fs[i].num_3d_pml_pixels, 0) total_nonzero_cond_pixels += fs[i].num_nonzero_conductivity_pixels self.assertEqual(total_nonzero_cond_pixels, 5048000)
def setUp(self): resolution = 20 cell_size = mp.Vector3(z=10) dimensions = 1 # conversion factor from eV to 1/um eV_um_scale = 1 / 1.23984193 # Al, from Rakic et al., Applied Optics, vol. 32, p. 5274 (1998) Al_eps_inf = 1 Al_plasma_frq = 14.98 * eV_um_scale Al_f0 = 0.523 Al_frq0 = 1e-10 Al_gam0 = 0.047 * eV_um_scale Al_sig0 = (Al_f0 * math.sqrt(Al_plasma_frq)) / (math.sqrt(Al_frq0)) Al_f1 = 0.050 Al_frq1 = 1.544 * eV_um_scale # 803 nm Al_gam1 = 0.312 * eV_um_scale Al_sig1 = (Al_f1 * math.sqrt(Al_plasma_frq)) / (math.sqrt(Al_frq1)) E_susceptibilities = [ mp.DrudeSusceptibility(frequency=Al_frq0, gamma=Al_gam0, sigma=Al_sig0), mp.LorentzianSusceptibility(frequency=Al_frq1, gamma=Al_gam1, sigma=Al_sig1) ] Al = mp.Medium(epsilon=Al_eps_inf, E_susceptibilities=E_susceptibilities) absorber_layers = [mp.Absorber(1, direction=mp.Z)] sources = [ mp.Source(src=mp.GaussianSource(1 / 0.803, fwidth=0.1), center=mp.Vector3(), component=mp.Ex) ] self.sim = mp.Simulation(cell_size=cell_size, resolution=resolution, dimensions=dimensions, default_material=Al, boundary_layers=absorber_layers, sources=sources)
def test_absorber_2d(self): source = mp.Source(src=mp.GaussianSource(frequency=0.1, fwidth=0.1), component=mp.Hz, center=mp.Vector3()) sim = mp.Simulation(cell_size=mp.Vector3(20, 20, 0), resolution=10, sources=[source], boundary_layers=[mp.Absorber(5)]) sim.run(until_after_sources=1000) v = mp.Vector3(4.13, 3.75, 0) p = sim.get_field_point(mp.Hz, v) self.assertAlmostEqual(-4.058476603571745e-11, p.real)
def setUp(self): resolution = 40 cell_size = mp.Vector3(z=10) absorber_layers = [mp.Absorber(1, direction=mp.Z)] sources = [mp.Source(src=mp.GaussianSource(1 / 0.803, fwidth=0.1), center=mp.Vector3(), component=mp.Ex)] self.sim = mp.Simulation(cell_size=cell_size, resolution=resolution, dimensions=1, default_material=Al, boundary_layers=absorber_layers, sources=sources)
def setUpClass(cls): cls.resolution = 30 # pixels/μm cls.dpml = 1.0 # PML thickness cls.dsub = 1.0 # substrate thickness cls.dpad = 1.0 # padding thickness between grating and PML cls.gp = 6.0 # grating period cls.gh = 0.5 # grating height cls.gdc = 0.5 # grating duty cycle cls.sx = cls.dpml + cls.dsub + cls.gh + cls.dpad + cls.dpml cls.sy = cls.gp cls.cell_size = mp.Vector3(cls.sx, cls.sy, 0) # replace anisotropic PML with isotropic Absorber to # attenuate parallel-directed fields of oblique source cls.abs_layers = [mp.Absorber(thickness=cls.dpml, direction=mp.X)] wvl = 0.5 # center wavelength cls.fcen = 1 / wvl # center frequency cls.df = 0.05 * cls.fcen # frequency width cls.ng = 1.5 cls.glass = mp.Medium(index=cls.ng) cls.geometry = [ mp.Block(material=cls.glass, size=mp.Vector3(cls.dpml + cls.dsub, mp.inf, mp.inf), center=mp.Vector3( -0.5 * cls.sx + 0.5 * (cls.dpml + cls.dsub), 0, 0)), mp.Block(material=cls.glass, size=mp.Vector3(cls.gh, cls.gdc * cls.gp, mp.inf), center=mp.Vector3( -0.5 * cls.sx + cls.dpml + cls.dsub + 0.5 * cls.gh, 0, 0)) ]
resolution = 50 # pixels/μm dpml = 2.0 # PML thickness dsub = 3.0 # substrate thickness dpad = 3.0 # length of padding between grating and pml gp = 10.0 # grating period gh = 0.5 # grating height gdc = 0.5 # grating duty cycle sx = dpml + dsub + gh + dpad + dpml sy = gp cell_size = mp.Vector3(sx, sy, 0) # replace anisotropic PML with isotropic Absorber to attenuate parallel-directed fields of oblique source abs_layers = [mp.Absorber(thickness=dpml, direction=mp.X)] wvl = 0.5 # center wavelength fcen = 1 / wvl # center frequency df = 0.05 * fcen # frequency width ng = 1.5 glass = mp.Medium(index=ng) # rotation angle of incident planewave; CCW about Y axis, 0 degrees along +X axis theta_in = math.radians(10.7) # k (in source medium) with correct length (plane of incidence: XY) k = mp.Vector3(math.cos(theta_in), math.sin(theta_in), 0).scale(fcen * ng) symmetries = []
pos_y = 0 pos_z = height + 0.005 pt = mp.Vector3(pos_x, pos_y, pos_z) resolution = 150 numx = int(width_cal * resolution) numy = int(height_cal * resolution) x_list = np.linspace(-width_cal / 2, width_cal / 2, numx) y_list = np.linspace(-height_cal / 2, height_cal / 2, numy) x_grid, y_grid = np.meshgrid(x_list, y_list) # %% cell_size = mp.Vector3(length_cal, width_cal, height_cal) pml_layers = [ mp.Absorber(thickness=t_pml, direction=mp.Y), mp.PML(thickness=t_pml, direction=mp.Z), mp.PML(thickness=t_pml, direction=mp.X) ] # Y dipole source = [ mp.Source(mp.ContinuousSource(frequency=omega), component=mp.Ey, center=pt) ] # We first calculate the normalized power sim0 = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, default_material=mp.Medium(index=index_SiN), sources=source,
#################### cfreq = 1.5 fwidth = 1.5 comp = mp.Hz sources = [ mp.Source(mp.GaussianSource(frequency=cfreq, fwidth=fwidth), size=mp.Vector3(0, fully, 0), component=comp, center=mp.Vector3(-sizex / 2, 0)) ] # Absorber on grating side because of field divergence at metal/pml interface pml_layers = [ mp.PML(pml_th, direction=mp.X), mp.Absorber(pml_th, direction=mp.Y) ] # empty cell for reference run geometry = [] sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, geometry=geometry, sources=sources, resolution=resolution, filename_prefix="data", split_chunks_evenly=False) # define monitors for further spectra calculation mon_height = sizey nfreq = 200
def run_binary_grating_oblique(self, theta): resolution = 30 # pixels/um dpml = 1.0 # PML thickness dsub = 1.0 # substrate thickness dpad = 1.0 # length of padding between grating and pml gp = 6.0 # grating period gh = 0.5 # grating height gdc = 0.5 # grating duty cycle sx = dpml+dsub+gh+dpad+dpml sy = gp cell_size = mp.Vector3(sx,sy,0) # replace anisotropic PML with isotropic Absorber to attenuate parallel-directed fields of oblique source abs_layers = [mp.Absorber(thickness=dpml,direction=mp.X)] wvl = 0.5 # center wavelength fcen = 1/wvl # center frequency df = 0.05*fcen # frequency width ng = 1.5 glass = mp.Medium(index=ng) # rotation angle of incident planewave; CCW about Y axis, 0 degrees along +X axis theta_in = math.radians(theta) # k (in source medium) with correct length (plane of incidence: XY) k = mp.Vector3(math.cos(theta_in),math.sin(theta_in),0).scale(fcen*ng) symmetries = [] eig_parity = mp.ODD_Z if theta_in == 0: k = mp.Vector3(0,0,0) symmetries = [mp.Mirror(mp.Y)] eig_parity += mp.EVEN_Y def pw_amp(k,x0): def _pw_amp(x): return cmath.exp(1j*2*math.pi*k.dot(x+x0)) return _pw_amp src_pt = mp.Vector3(-0.5*sx+dpml+0.3*dsub,0,0) sources = [mp.Source(mp.GaussianSource(fcen,fwidth=df), component=mp.Ez, center=src_pt, size=mp.Vector3(0,sy,0), amp_func=pw_amp(k,src_pt))] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=abs_layers, k_point=k, default_material=glass, sources=sources, symmetries=symmetries) refl_pt = mp.Vector3(-0.5*sx+dpml+0.5*dsub,0,0) refl_flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=refl_pt, size=mp.Vector3(0,sy,0))) sim.run(until_after_sources=100) input_flux = mp.get_fluxes(refl_flux) input_flux_data = sim.get_flux_data(refl_flux) sim.reset_meep() geometry = [mp.Block(material=glass, size=mp.Vector3(dpml+dsub,mp.inf,mp.inf), center=mp.Vector3(-0.5*sx+0.5*(dpml+dsub),0,0)), mp.Block(material=glass, size=mp.Vector3(gh,gdc*gp,mp.inf), center=mp.Vector3(-0.5*sx+dpml+dsub+0.5*gh,0,0))] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=abs_layers, geometry=geometry, k_point=k, sources=sources, symmetries=symmetries) refl_flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=refl_pt, size=mp.Vector3(0,sy,0))) sim.load_minus_flux_data(refl_flux,input_flux_data) tran_pt = mp.Vector3(0.5*sx-dpml-0.5*dpad,0,0) tran_flux = sim.add_flux(fcen, 0, 1, mp.FluxRegion(center=tran_pt, size=mp.Vector3(0,sy,0))) sim.run(until_after_sources=100) nm_r = np.floor((fcen*ng-k.y)*gp)-np.ceil((-fcen*ng-k.y)*gp) # number of reflected orders if theta_in == 0: nm_r = nm_r/2 # since eig_parity removes degeneracy in y-direction nm_r = int(nm_r) res = sim.get_eigenmode_coefficients(refl_flux, range(1,nm_r+1), eig_parity=eig_parity) r_coeffs = res.alpha Rsum = 0 for nm in range(nm_r): Rsum += abs(r_coeffs[nm,0,1])**2/input_flux[0] nm_t = np.floor((fcen-k.y)*gp)-np.ceil((-fcen-k.y)*gp) # number of transmitted orders if theta_in == 0: nm_t = nm_t/2 # since eig_parity removes degeneracy in y-direction nm_t = int(nm_t) res = sim.get_eigenmode_coefficients(tran_flux, range(1,nm_t+1), eig_parity=eig_parity) t_coeffs = res.alpha Tsum = 0 for nm in range(nm_t): Tsum += abs(t_coeffs[nm,0,0])**2/input_flux[0] r_flux = mp.get_fluxes(refl_flux) t_flux = mp.get_fluxes(tran_flux) Rflux = -r_flux[0]/input_flux[0] Tflux = t_flux[0]/input_flux[0] self.assertAlmostEqual(Rsum,Rflux,places=2) self.assertAlmostEqual(Tsum,Tflux,places=2)
def simulation_fun(): resolution = 50 geom = common.geom sig = common.sig # source parameters fcen = common.fcen df = common.df df2 = df * 1.4 # source frequency width nfreq = 31 # number of frequency bins k = False # ensure PEC boundary condition mat_env = mp.Medium(epsilon=1) mat_wg = mp.Medium(epsilon=14.44) mat_metal = mat.Al # mp.Medium(epsilon=20) nDBR = common.nDBR mat_high = mp.Medium(epsilon=14.44) mat_low = mp.Medium(epsilon=10.24) d_high = 0.25 d_low = 0.30 pol = common.pol src_cmpt = eval('mp.{}'.format(pol)) ############################################ # begin empty and actual simulation if geom == 'Empty': dpml = 1.0 sx = 1 sy = 1 sz = 1 sxx = sx + 2 * dpml syy = sy + 2 * dpml szz = sz + 2 * dpml cell_size = mp.Vector3(sxx, syy, szz) boundary_layers = [mp.PML(thickness=dpml)] # geometry geometry = [mp.Block(size=mp.Vector3(sxx, syy, szz), material=mat_wg)] # define point pt_src = mp.Vector3(0, 0, 0) pt_field = mp.Vector3(sx / 4, sy / 4, 0) pt_flux = mp.Vector3(0, 0, 0) l_flux = 0.1 frs_src = my.FluxRegions_Cube_Center(l_flux, pt_flux) # sources sources = [ mp.Source(mp.GaussianSource(fcen, fwidth=df2), component=src_cmpt, center=pt_src, size=mp.Vector3(0, 0, 0)) ] # symmetries = [mp.Mirror(mp.X), mp.Mirror(mp.Y)] if src_cmpt == mp.Ex: symmetries = [ mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, +1), mp.Mirror(mp.Z, +1) ] elif src_cmpt == mp.Ey: symmetries = [ mp.Mirror(mp.X, +1), mp.Mirror(mp.Y, -1), mp.Mirror(mp.Z, +1) ] elif src_cmpt == mp.Ez: symmetries = [ mp.Mirror(mp.X, +1), mp.Mirror(mp.Y, +1), mp.Mirror(mp.Z, -1) ] else: return None else: ### actually simulations # from bottom up t_front = 0.1 t_metal = 0.2 t_wg = common.t t_DBR = nDBR * (d_high + d_low) t_back = 0.2 a = common.a dx = common.dx dy = common.dy dz = common.dz dpmlxy = a # PML thickness dpmlz = 1 sx = 4 sy = 12 sz = t_front + t_metal + t_wg + t_DBR + t_back sxx = sx + 2 * dpmlxy syy = sy + 2 * dpmlxy szz = sz + dpmlz cell_size = mp.Vector3(sxx, syy, szz) # pml boundary_layers = [ mp.Absorber(thickness=dpmlxy, direction=mp.X), mp.Absorber(thickness=dpmlxy, direction=mp.Y), mp.PML(thickness=dpmlz, direction=mp.Z, side=mp.High) ] # geometry tts = [t_front, t_metal, t_wg] ccs = my.center_from_thickness(tts, -szz / 2) geometry = [ mp.Block(size=mp.Vector3(2 * sxx, 2 * syy, 2 * szz), center=mp.Vector3(0, 0, 0), material=mat_wg), mp.Block(size=mp.Vector3(sxx, syy, tts[1]), center=mp.Vector3(0, 0, ccs[1]), material=mat_metal), mp.Block(size=mp.Vector3(sxx, syy, tts[2]), center=mp.Vector3(0, 0, ccs[2]), material=mat_wg), ] z0 = -szz / 2 + t_front + t_metal + t_wg # waveguide/DBR interface for i in range(nDBR): # add low geometry.append( mp.Block(size=mp.Vector3(sxx, syy, d_low), center=mp.Vector3(0, 0, z0 + d_low / 2), material=mat_low)) z0 += d_low # add high geometry.append( mp.Block(size=mp.Vector3(sxx, syy, d_high), center=mp.Vector3(0, 0, z0 + d_high / 2), material=mat_high)) z0 += d_high # sources and flux box z0 = -szz / 2 + t_front + t_metal # metal surface z1 = z0 + t_wg + t_DBR # DBR surface pt_src = mp.Vector3(dx, dy, z0 + dz) pt_field = mp.Vector3(0.08 * sx / 2, 0.07 * sy / 2, z0 + 0.77 * t_wg) l_flux, pt_flux = my.FluxBox3D(size=0.1, src=pt_src, zmin=z0, zmax=z0 + t_wg) frs_src = my.FluxRegions_Cube_Center(l_flux, pt_flux) assert dz < t_wg, "The source is inside the waveguide." # big box, the box include the whole GaSb area frs_big = my.FluxRegions_Box_Corner(-sx / 2, sx / 2, -sy / 2, sy / 2, z0, z1) # near2far region near_sizes = np.arange(sy, sy - 6.05, -1.0) near_z = z1 + 0.1 # above DBR near_fluxes = [ mp.FluxRegion(center=mp.Vector3(0, 0, near_z), size=mp.Vector3(sx, nsize, 0)) for nsize in near_sizes ] near_regions = [ mp.Near2FarRegion(center=mp.Vector3(0, 0, near_z), size=mp.Vector3(sx, nsize, 0)) for nsize in near_sizes ] sources = [ mp.Source(mp.GaussianSource(fcen, fwidth=df2), component=src_cmpt, center=pt_src, size=mp.Vector3(0, 0, 0)) ] # symmetries if src_cmpt == mp.Ex: symmetries = [mp.Mirror(mp.X, -1), mp.Mirror(mp.Y, +1)] elif src_cmpt == mp.Ey: symmetries = [mp.Mirror(mp.X, +1), mp.Mirror(mp.Y, -1)] elif src_cmpt == mp.Ez: symmetries = [mp.Mirror(mp.X, +1), mp.Mirror(mp.Y, +1)] # end of big if between emtpy and geom #################################### print('Real simulation area ' + str(mp.Vector3(sx, sy, sz))) print('Total simulation area ' + str(mp.Vector3(sxx, syy, szz))) print('Source at ' + str(pt_src)) print('Field is monitored at ' + str(pt_field)) print('Flux center at ' + str(pt_flux)) print('Flux region size is ' + str(l_flux)) # set up simulation sim = mp.Simulation(resolution=resolution, cell_size=cell_size, geometry=geometry, boundary_layers=boundary_layers, dimensions=3, sources=sources, k_point=k, force_complex_fields=True, symmetries=symmetries, default_material=mat_wg, filename_prefix=sig) # calculate flux if geom == 'Empty': trans_src = [sim.add_flux(fcen, df, nfreq, fr) for fr in frs_src] else: trans_src = [sim.add_flux(fcen, df, nfreq, fr) for fr in frs_src] trans_big = [sim.add_flux(fcen, df, nfreq, fr) for fr in frs_big] near_trans = [sim.add_flux(fcen, df, nfreq, fr) for fr in near_fluxes] near_fields = [ sim.add_near2far(fcen, df, nfreq, rgn) for rgn in near_regions ] # nearfield=sim.add_near2far(fcen, df, nfreq, *frs) #### define two functions to organize output def get_flux_data_from_many(trans): # simulation data are saved in trans freqs = mp.get_flux_freqs(trans[0]) fluxes = [mp.get_fluxes(tran) for tran in trans] data = np.column_stack(( freqs, *fluxes, )) return data def get_flux_data_from_one(ntran, nsize): # simulation data are saved in trans freqs = mp.get_flux_freqs(ntran) fluxes = mp.get_fluxes(ntran) data = np.column_stack(( freqs, fluxes, )) data = np.insert(data, 1, nsize, axis=1) return data def get_far_data_from_one(nearfield, nsize): # simulation data are saved in nearfield freqs = mp.get_near2far_freqs(nearfield) r = 1000 * 3.8 # 1000 wavelengths out from the source thetas = np.concatenate( [np.arange(0.5, 20, 1), np.arange(22.5, 89, 3)]) # polar angle phis = [ 45, ] # azimuthal angle data = np.empty(shape=[0, 16]) for phi in phis: for theta in thetas: phi0 = np.radians(phi) theta0 = np.radians(theta) pt = r * mp.Vector3( math.sin(theta0) * math.cos(phi0), math.sin(theta0) * math.sin(phi0), math.cos(theta0)) fields = sim.get_farfield(nearfield, pt) mat = np.vstack((np.real(fields), np.imag(fields))) fields = mat.T.reshape((1, -1)).reshape((-1, 12)) infos = np.vstack( (freqs, nsize * np.ones(len(freqs)), theta * np.ones(len(freqs)), phi * np.ones(len(freqs)))) data = np.vstack((data, np.hstack((infos.T, fields)))) return data #### # define step function to display fluxes my_display_count = 0 step_time_flush = 10 step_time_print = 100 step_time_terminate = 20 def my_display_fluxes(sim): nonlocal my_display_count nonlocal step_time_print print('=' * 40) print('=' * 40) # power flow around the source data = get_flux_data_from_many(trans_src) my.matrix_output(None, data, "{:10.3e}", "flux_src") if geom != "Empty": print('<' * 40) data = get_flux_data_from_many(trans_big) my.matrix_output(None, data, "{:10.3e}", "flux_big") print('<' * 40) # power flow through near region for idx, ntran in enumerate(near_trans): nsize = near_sizes[idx] data = get_flux_data_from_one(ntran, nsize) my.matrix_output(None, data, "{:10.3e}", "flux{:0.2f}".format(nsize)) print('<' * 40) print('=' * 40) # far fields for idx, nfield in enumerate(near_fields): nsize = near_sizes[idx] data = get_far_data_from_one(nfield, nsize) my.matrix_output(None, data, "{:10.3e}", "farfield{:4.2f}".format(nsize)) print('>' * 40) my_display_count += 1 print('=' * 40) print('No. {} display at t={}'.format(my_display_count, step_time_print)) my.my_flush_step(sim) # run simulations sim.run( # mp.at_beginning(mp.output_epsilon), mp.at_every(step_time_flush, my.my_flush_step), mp.at_every(step_time_print, my_display_fluxes), until_after_sources=mp.stop_when_fields_decayed( step_time_terminate, src_cmpt, pt_field, 1e-9)) sys.stdout.flush() # power flow around the source data = get_flux_data_from_many(trans_src) fname = sig + "_T0.dat" my.matrix_output(fname, data, "{:10.6e}", "flux_src") if geom != "Empty": data = get_flux_data_from_many(trans_big) fname = sig + "_T1.dat" my.matrix_output(fname, data, "{:10.6e}", "flux_big") # power flow through near region for idx, ntran in enumerate(near_trans): nsize = near_sizes[idx] data = get_flux_data_from_one(ntran, nsize) fname = sig + "_S{:0.2f}_T.dat".format(nsize) my.matrix_output(fname, data, "{:10.6e}", "flux{:0.2f}".format(nsize)) # far field for idx, nfield in enumerate(near_fields): nsize = near_sizes[idx] data = get_far_data_from_one(nfield, nsize) fname = sig + "_S{:0.2f}_FF.dat".format(nsize) my.matrix_output(fname, data, "{:10.3e}", "farfield{:4.2f}".format(nsize))
while iscontinue: wvl_min = 0.350 wvl_max = 0.750 frq_min = 1 / wvl_max frq_max = 1 / wvl_min frq_cen = 0.5 * (frq_min + frq_max) dfrq = frq_max - frq_min nfrq = 100 Material = Au #here the resulation can be effect according to wavelength and simulation size resolution = 100 dpml = dpml + 0.02 #0.05 pml_layers = [ mp.PML(dpml, direction=mp.X, side=mp.High), mp.Absorber(dpml, direction=mp.X, side=mp.Low) ] symmetries = [mp.Mirror(mp.Y)] offsetx = 0.01 block_thicknessy = 0.5 block_thicknessx = 0.02 spacing_thickness = block_thicknessy * 2 # this varible is our main purpose of doing this experiment celly = (spacing_thickness + block_thicknessy) cellx = block_thicknessx + 2 * dpml + 2 * offsetx geometry = [] sources = [ mp.Source(mp.GaussianSource(frq_cen, fwidth=dfrq), center=mp.Vector3(-0.5 * cellx + dpml), size=mp.Vector3(0, celly),
Ls = -2 * x # Position of source Lr1 = -2 * x - 1.25 # Position of reflection monitor 1 Lr2 = -2 * x + 1.25 # Position of reflection monitor 2 Lt = -Lr2 # Position of transmission monitor scatter_monitor_size = 2 * Lt assert (Lr1 > -a / 2 + dpml ) # Make sure that nothing we care about is sitting inside the PML sources = [ mp.EigenModeSource(mp.ContinuousSource(frequency=fcen), size=mp.Vector3(0, H), center=mp.Vector3(Ls, 0)) ] pml_layers = [mp.Absorber(thickness=dpml)] sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, geometry=geometry, sources=sources, resolution=resolution) sim.reset_meep() nfreq = 1 refl_fr1 = mp.FluxRegion(center=mp.Vector3(Lr1, 0), size=mp.Vector3(0, monitorheight)) refl_fr2 = mp.FluxRegion(center=mp.Vector3(Lr2, 0), size=mp.Vector3(0, monitorheight))
def simulation(f_cen, df, fmin, fmax, sy, dpml, air, sx, resolution, nfreq, geometry, init_refl_data, init_tran_flux, n, THICKNESS): #----------------------Simulation------------------------------ cell = mp.Vector3(sx, sy) thick = np.sum(THICKNESS) #define Gaussian plane wave sources = [ mp.Source(mp.GaussianSource(f_cen, fwidth=df), component=mp.Ez, center=mp.Vector3(0, 0.5 * sy - dpml - 0.02 * air, 0), size=mp.Vector3(x=sx)) ] #define pml layers pml_layers = [ mp.PML(thickness=dpml, direction=mp.Y, side=mp.High), mp.Absorber(thickness=dpml, direction=mp.Y, side=mp.Low) ] tran_fr = mp.FluxRegion(center=mp.Vector3(0, -0.5 * sy + dpml + 0.05), size=mp.Vector3(x=sx)) refl_fr = mp.FluxRegion(center=mp.Vector3(0, 0.5 * sy - dpml - 0.1 * air), size=mp.Vector3(x=sx)) mp.quiet(quietval=True) if n == 0: #if os.path.exists('dft_Z_empty.h5'): #os.remove('dft_Z_empty.h5') sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, symmetries=[mp.Mirror(mp.X)], dimensions=2, resolution=resolution, k_point=mp.Vector3()) #----------------------Monitors------------------------------ refl = sim.add_flux(f_cen, df, nfreq, refl_fr) tran = sim.add_flux(f_cen, df, nfreq, tran_fr) dfts_Z = sim.add_dft_fields([mp.Ez], fmin, fmax, nfreq, where=mp.Volume(center=mp.Vector3( 0, -sy * 0.5 + dpml + THICKNESS * 0.5, 0), size=mp.Vector3( sx, THICKNESS))) #----------------------Run------------------------------ sim.run(until_after_sources=mp.stop_when_fields_decayed( 5, mp.Ez, mp.Vector3(), 1e-3)) #----------------------Genetic------------------------------ sim.output_dft(dfts_Z, "dft_Z_empty") init_refl_data = sim.get_flux_data(refl) init_tran_flux = mp.get_fluxes(tran) sim.reset_meep() get = init_refl_data, init_tran_flux elif n == 1: #if os.path.exists('dft_Z_fields.h5'): #os.remove('dft_Z_fields.h5') sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, geometry=geometry, symmetries=[mp.Mirror(mp.X)], dimensions=2, resolution=resolution, k_point=mp.Vector3()) refl = sim.add_flux(f_cen, df, nfreq, refl_fr) tran = sim.add_flux(f_cen, df, nfreq, tran_fr) sim.load_minus_flux_data(refl, init_refl_data) dfts_Z = sim.add_dft_fields([mp.Ez], fmin, fmax, nfreq, where=mp.Volume(center=mp.Vector3( 0, -sy * 0.5 + dpml + thick * 0.5, 0), size=mp.Vector3(sx, thick))) sim.run(until_after_sources=mp.stop_when_fields_decayed( 5, mp.Ez, mp.Vector3(), 1e-3)) #mp.at_beginning(mp.output_epsilon), sim.output_dft(dfts_Z, "dft_Z_fields") flux_freqs = mp.get_flux_freqs(refl) final_refl_flux = mp.get_fluxes(refl) wl = [] Rs = [] for i in range(nfreq): wl = np.append(wl, 1 / flux_freqs[i]) Rs = np.append(Rs, -final_refl_flux[i] / init_tran_flux[i]) sim.reset_meep() #get = np.min(Rs) en = enhance(Rs, 0) get = en, Rs, wl elif n == 2: #if os.path.exists('dft_Z_fields.h5'): #os.remove('dft_Z_fields.h5') sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, geometry=geometry, symmetries=[mp.Mirror(mp.X)], dimensions=2, resolution=resolution, k_point=mp.Vector3()) refl = sim.add_flux(f_cen, df, nfreq, refl_fr) tran = sim.add_flux(f_cen, df, nfreq, tran_fr) sim.load_minus_flux_data(refl, init_refl_data) dfts_Z = sim.add_dft_fields([mp.Ez], fmin, fmax, nfreq, where=mp.Volume(center=mp.Vector3( 0, -sy * 0.5 + dpml + thick * 0.5, 0), size=mp.Vector3(sx, thick))) sim.run(mp.at_beginning(mp.output_epsilon), until_after_sources=mp.stop_when_fields_decayed( 5, mp.Ez, mp.Vector3(), 1e-3)) #mp.at_beginning(mp.output_epsilon), sim.output_dft(dfts_Z, "dft_Z_fields") flux_freqs = mp.get_flux_freqs(refl) final_refl_flux = mp.get_fluxes(refl) final_tran_flux = mp.get_fluxes(tran) wl = [] Rs = [] Ts = [] for i in range(nfreq): wl = np.append(wl, 1 / flux_freqs[i]) Rs = np.append(Rs, -final_refl_flux[i] / init_tran_flux[i]) Ts = np.append(Ts, final_tran_flux[i] / init_tran_flux[i]) As = 1 - Rs - Ts plt.clf() plt.figure() plt.plot(wl, Rs, 'bo-', label='reflectance') plt.plot(wl, Ts, 'ro-', label='transmittance') plt.plot(wl, As, 'go-', label='absorption') plt.xlabel("wavelength (μm)") plt.legend(loc="upper right") plt.savefig('Extinction.png') #get = np.min(Rs) en = enhance(Rs, 1) get = en, Rs, wl #plt.figure() #plt.plot(wl,Rs,'bo-',label='reflectance') eps = h5py.File('_last-eps-000000000.h5', 'r') eps = eps.get('eps').value Enhance = np.rot90(eps) plt.clf() plt.figure() heat_map = sb.heatmap(Enhance, cmap='plasma', xticklabels=False, yticklabels=False) plt.xlabel("x-axis") plt.ylabel("y-axis") plt.savefig('Epsilon.png') return (get)
def run_binary_grating_diffraction(self, gp, gh, gdc, theta, bands, orders): resolution = 50 # pixels/um dpml = 1.0 # PML thickness dsub = 3.0 # substrate thickness dpad = 3.0 # length of padding between grating and PML sx = dpml + dsub + gh + dpad + dpml sy = gp cell_size = mp.Vector3(sx, sy, 0) absorber_layers = [mp.Absorber(thickness=dpml, direction=mp.X)] wvl = 0.5 # center wavelength fcen = 1 / wvl # center frequency df = 0.05 * fcen # frequency width ng = 1.5 glass = mp.Medium(index=ng) # rotation angle of incident planewave; counter clockwise (CCW) about Z axis, 0 degrees along +X axis theta_in = math.radians(theta) eig_parity = mp.ODD_Z # k (in source medium) with correct length (plane of incidence: XY) k = mp.Vector3(fcen * ng).rotate(mp.Vector3(z=1), theta_in) symmetries = [] if theta_in == 0: k = mp.Vector3() eig_parity += mp.EVEN_Y symmetries = [mp.Mirror(direction=mp.Y)] def pw_amp(k, x0): def _pw_amp(x): return cmath.exp(1j * 2 * math.pi * k.dot(x + x0)) return _pw_amp src_pt = mp.Vector3(-0.5 * sx + dpml, 0, 0) sources = [ mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ez, center=src_pt, size=mp.Vector3(0, sy, 0), amp_func=pw_amp(k, src_pt)) ] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=absorber_layers, k_point=k, default_material=glass, sources=sources, symmetries=symmetries) tran_pt = mp.Vector3(0.5 * sx - dpml, 0, 0) tran_flux = sim.add_flux( fcen, 0, 1, mp.FluxRegion(center=tran_pt, size=mp.Vector3(0, sy, 0))) sim.run(until_after_sources=50) input_flux = mp.get_fluxes(tran_flux) sim.reset_meep() geometry = [ mp.Block(material=glass, size=mp.Vector3(dpml + dsub, mp.inf, mp.inf), center=mp.Vector3(-0.5 * sx + 0.5 * (dpml + dsub), 0, 0)), mp.Block(material=glass, size=mp.Vector3(gh, gdc * gp, mp.inf), center=mp.Vector3(-0.5 * sx + dpml + dsub + 0.5 * gh, 0, 0)) ] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=absorber_layers, geometry=geometry, k_point=k, sources=sources, symmetries=symmetries) tran_flux = sim.add_mode_monitor( fcen, 0, 1, mp.FluxRegion(center=tran_pt, size=mp.Vector3(0, sy, 0))) sim.run(until_after_sources=100) for band, order in zip(bands, orders): res = sim.get_eigenmode_coefficients(tran_flux, [band], eig_parity=eig_parity) tran_ref = abs(res.alpha[0, 0, 0])**2 / input_flux[0] if (theta_in == 0): tran_ref = 0.5 * tran_ref vg_ref = res.vgrp[0] res = sim.get_eigenmode_coefficients( tran_flux, mp.DiffractedPlanewave((0, order, 0), mp.Vector3(0, 1, 0), 1, 0)) if res is not None: tran_dp = abs(res.alpha[0, 0, 0])**2 / input_flux[0] if ((theta_in == 0) and (order == 0)): tran_dp = 0.5 * tran_dp else: tran_dp = 0 vg_dp = res.vgrp[0] err = abs(tran_ref - tran_dp) / tran_ref print( "tran:, {} (band), {} (order), {:.8f} (eigensolver), {:.8f} (planewave), {:.8f} (error)" .format(band, order, tran_ref, tran_dp, err)) self.assertAlmostEqual(vg_ref, vg_dp, places=5) self.assertAlmostEqual(tran_ref, tran_dp, places=5)
def simulation(square, THICKNESS, cx, cy, cz): #----------------------------Variables------------------------------ period = square #um PADDING = 0.70 #um fmin = 1 / .800 #maximum wavelength fmax = 1 / .300 #minimum wavelength fcen = (fmax + fmin) / 2 #set centre of gaussian source df = fmax - fmin #set width of gaussian source nfreq = 50 #number of frequencies between min and max dpml = 0.4 #thickness of PML (top and bottom) um resolution = 100 #pixels/um BASE = PADDING - THICKNESS #metal thin film is set on a PDMS base sz = THICKNESS + 2 * PADDING + 2 * dpml #size of simulation sx = period #size of simulation sy = period #size of simulation box = 0.010 #optimised size of radiation monitoring box set around dipole cell = mp.Vector3(sx, sy, sz) runtime = 1600 #define geometry slab = mp.Block(size=mp.Vector3(1e20, 1e20, THICKNESS), center=mp.Vector3(0, 0, -THICKNESS / 2), material=Au) #Gold thin film hole = mp.Block(size=mp.Vector3(0.145, 0.145, THICKNESS), center=mp.Vector3(0, 0, 0)) #nanohole slab3 = mp.Block(mp.Vector3(1e20, 1e20, BASE), center=mp.Vector3(0, 0, -0.5 * sz + dpml + 0.5 * BASE), material=mp.Medium(index=1.53)) #pdms base geometry = [slab, hole, slab3] #--------------------------Simulation Parameters---------------------------------------- #define Gaussian plane wave Ez polarised sources = [ mp.Source(mp.GaussianSource(fcen, fwidth=df), component=mp.Ex, center=mp.Vector3(cx, cy, cz)) ] #define pml layers (Absorber is a type of PML that helps when there are Bloch Wave SPP modes. Placed in substrate) pml_layers = [ mp.Absorber(thickness=dpml, direction=mp.Z, side=mp.Low), mp.PML(thickness=dpml, direction=mp.Z, side=mp.High) ] #sets the simulation without the substrate so that it is a homogeneous environment sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, resolution=resolution, k_point=mp.Vector3(0, 0, 0)) #power monitors around the simulation #power monitor around the dipole dipole_box = sim.add_flux( fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(cx + 0.5 * box, cy, cz), size=mp.Vector3(0, box, box), direction=mp.X, weight=+1), mp.FluxRegion(center=mp.Vector3(cx - 0.5 * box, cy, cz), size=mp.Vector3(0, box, box), direction=mp.X, weight=-1), mp.FluxRegion(center=mp.Vector3(cx, cy, cz + 0.5 * box), size=mp.Vector3(box, box, 0), direction=mp.Z, weight=+1), mp.FluxRegion(center=mp.Vector3(cx, cy, cz - 0.5 * box), size=mp.Vector3(box, box, 0), direction=mp.Z, weight=-1), mp.FluxRegion(center=mp.Vector3(cx, cy + 0.5 * box, cz), size=mp.Vector3(box, 0, box), direction=mp.Y, weight=+1), mp.FluxRegion(center=mp.Vector3(cx, cy - 0.5 * box, cz), size=mp.Vector3(box, 0, box), direction=mp.Y, weight=-1)) #power monitor on the surface of the thin film rad_box = sim.add_flux( fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(0, 0, 0), size=mp.Vector3(sx, sy, 0), weight=-1)) #power monitors surrounding 'free space' top_box = sim.add_flux( fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(0, 0, 0.5 * sz - dpml), size=mp.Vector3(sx, sy, 0)), mp.FluxRegion(center=mp.Vector3(0, 0.5 * sy, 0.25 * sz), size=mp.Vector3(sx, 0, 0.5 * sz - dpml), weight=+1), mp.FluxRegion(center=mp.Vector3(0, -0.5 * sy, 0.25 * sz), size=mp.Vector3(sx, 0, 0.5 * sz - dpml), weight=-1), mp.FluxRegion(center=mp.Vector3(0.5 * sx, 0, 0.25 * sz), size=mp.Vector3(0, sy, 0.5 * sz - dpml), weight=+1), mp.FluxRegion(center=mp.Vector3(-0.5 * sx, 0, 0.25 * sz), size=mp.Vector3(0, sy, 0.5 * sz - dpml), weight=-1)) #run simulation until the source has decayed "fully" sim.run(until_after_sources=runtime) #collect radiation information init_rad = np.asarray(mp.get_fluxes(rad_box)) init_dipole = np.asarray(mp.get_fluxes(dipole_box)) init_top = np.asarray(mp.get_fluxes(top_box)) sim.reset_meep() #run simulation again with the substrate (inhomogeneous environment) sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, geometry=geometry, resolution=resolution, k_point=mp.Vector3(0, 0, 0)) #power monitors around the dipole dipole_box2 = sim.add_flux( fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(cx + 0.5 * box, cy, cz), size=mp.Vector3(0, box, box), direction=mp.X, weight=+1), mp.FluxRegion(center=mp.Vector3(cx - 0.5 * box, cy, cz), size=mp.Vector3(0, box, box), direction=mp.X, weight=-1), mp.FluxRegion(center=mp.Vector3(cx, cy, cz + 0.5 * box), size=mp.Vector3(box, box, 0), direction=mp.Z, weight=+1), mp.FluxRegion(center=mp.Vector3(cx, cy, cz - 0.5 * box), size=mp.Vector3(box, box, 0), direction=mp.Z, weight=-1), mp.FluxRegion(center=mp.Vector3(cx, cy + 0.5 * box, cz), size=mp.Vector3(box, 0, box), direction=mp.Y, weight=+1), mp.FluxRegion(center=mp.Vector3(cx, cy - 0.5 * box, cz), size=mp.Vector3(box, 0, box), direction=mp.Y, weight=-1)) rad_box2 = sim.add_flux( fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(0, 0, 0), size=mp.Vector3(sx, sy, 0), weight=-1)) top_box2 = sim.add_flux( fcen, df, nfreq, mp.FluxRegion(center=mp.Vector3(0, 0, 0.5 * sz - dpml), size=mp.Vector3(sx, sy, 0), weight=+1), mp.FluxRegion(center=mp.Vector3(0, 0.5 * sy, 0.25 * sz), size=mp.Vector3(sx, 0, 0.5 * sz - dpml), weight=+1), mp.FluxRegion(center=mp.Vector3(0, -0.5 * sy, 0.25 * sz), size=mp.Vector3(sx, 0, 0.5 * sz - dpml), weight=-1), mp.FluxRegion(center=mp.Vector3(0.5 * sx, 0, 0.25 * sz), size=mp.Vector3(0, sy, 0.5 * sz - dpml), weight=+1), mp.FluxRegion(center=mp.Vector3(-0.5 * sx, 0, 0.25 * sz), size=mp.Vector3(0, sy, 0.5 * sz - dpml), weight=-1)) sim.run(until_after_sources=runtime) rad = np.asarray(mp.get_fluxes(rad_box2)) dipole = np.asarray(mp.get_fluxes(dipole_box2)) top = np.asarray(mp.get_fluxes(top_box2)) #Output data data = np.zeros((6, len(rad))) data[0, :] = init_rad data[1, :] = rad data[2, :] = init_dipole data[3, :] = dipole data[4, :] = init_top data[5, :] = top np.savetxt('REPLACE.txt', data) return ()
def sim(queryrow, src_angle, nm_val, src_pol): global resolution result_df = pd.DataFrame(columns=result.columns) dpml = 1.0 # PML length dair = 4.0 # padding length between PML and grating dsub = 3.0 # substrate thickness d = queryrow["period"] # grating period h = queryrow["height"] # grating height g = queryrow["gap"] # grating gap theta_1 = math.radians(queryrow["theta_1"]) # grating sidewall angle #1 theta_2 = math.radians(queryrow["theta_2"]) # grating sidewall angle #2 transmittance = 0 sx = dpml + dair + h + dsub + dpml sy = d cell_size = mp.Vector3(sx, sy, 0) pml_layers = [mp.Absorber(thickness=dpml, direction=mp.X)] wvl = 0.5 # center wavelength fcen = 1 / wvl # center frequency df = 0.05 * fcen # frequency width ng = 1.716 # episulfide refractive index @ 0.532 um glass = mp.Medium(index=ng) if src_pol == 1: src_cmpt = mp.Ez eig_parity = mp.ODD_Z elif src_pol == 2: src_cmpt = mp.Hz eig_parity = mp.EVEN_Z else: sys.exit("error: src_pol={} is invalid".format(args.src_pol)) # rotation angle of incident planewave source; CCW about Z axis, 0 degrees along +X axis theta_src = math.radians(src_angle) # k (in source medium) with correct length (plane of incidence: XY) k = mp.Vector3(math.cos(theta_src), math.sin(theta_src), 0).scale(fcen) if theta_src == 0: k = mp.Vector3(0, 0, 0) def pw_amp(k, x0): def _pw_amp(x): return cmath.exp(1j * 2 * math.pi * k.dot(x + x0)) return _pw_amp src_pt = mp.Vector3(-0.5 * sx + dpml + 0.2 * dair, 0, 0) sources = [ mp.Source(mp.GaussianSource(fcen, fwidth=df), component=src_cmpt, center=src_pt, size=mp.Vector3(0, sy, 0), amp_func=pw_amp(k, src_pt)) ] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, k_point=k, sources=sources) refl_pt = mp.Vector3(-0.5 * sx + dpml + 0.7 * dair, 0, 0) refl_flux = sim.add_flux( fcen, 0, 1, mp.FluxRegion(center=refl_pt, size=mp.Vector3(0, sy, 0))) sim.run(until_after_sources=100) input_flux = mp.get_fluxes(refl_flux) input_flux_data = sim.get_flux_data(refl_flux) sim.reset_meep() geometry = [ mp.Block(material=glass, size=mp.Vector3(dpml + dsub, mp.inf, mp.inf), center=mp.Vector3(0.5 * sx - 0.5 * (dpml + dsub), 0, 0)), mp.Prism(material=glass, height=mp.inf, vertices=[ mp.Vector3(0.5 * sx - dpml - dsub, 0.5 * sy, 0), mp.Vector3(0.5 * sx - dpml - dsub - h, 0.5 * sy - h * math.tan(theta_2), 0), mp.Vector3(0.5 * sx - dpml - dsub - h, -0.5 * sy + g - h * math.tan(theta_1), 0), mp.Vector3(0.5 * sx - dpml - dsub, -0.5 * sy + g, 0) ]) ] sim = mp.Simulation(resolution=resolution, cell_size=cell_size, boundary_layers=pml_layers, k_point=k, sources=sources, geometry=geometry) refl_flux = sim.add_flux( fcen, 0, 1, mp.FluxRegion(center=refl_pt, size=mp.Vector3(0, sy, 0))) sim.load_minus_flux_data(refl_flux, input_flux_data) tran_pt = mp.Vector3(0.5 * sx - dpml - 0.5 * dsub, 0, 0) tran_flux = sim.add_flux( fcen, 0, 1, mp.FluxRegion(center=tran_pt, size=mp.Vector3(0, sy, 0))) sim.run(until_after_sources=500) kdom_tol = 1e-2 angle_tol = 1e-6 Rsum = 0 Tsum = 0 if theta_src == 0: nm_r = int(0.5 * (np.floor((fcen - k.y) * d) - np.ceil( (-fcen - k.y) * d))) # number of reflected orders res = sim.get_eigenmode_coefficients(refl_flux, range(1, nm_r + 1), eig_parity=eig_parity + mp.EVEN_Y) r_coeffs = res.alpha r_kdom = res.kdom for nm in range(nm_r): if nm != nm_val: continue if r_kdom[nm].x > kdom_tol: r_angle = np.sign(r_kdom[nm].y) * math.acos( r_kdom[nm].x / fcen) if ( r_kdom[nm].x % fcen > angle_tol) else 0 Rmode = abs(r_coeffs[nm, 0, 1])**2 / input_flux[0] print("refl: (even_y), {}, {:.2f}, {:.8f}".format( nm, math.degrees(r_angle), Rmode)) Rsum += Rmode res = sim.get_eigenmode_coefficients(refl_flux, range(1, nm_r + 1), eig_parity=eig_parity + mp.ODD_Y) r_coeffs = res.alpha r_kdom = res.kdom for nm in range(nm_r): if nm != nm_val: continue if r_kdom[nm].x > kdom_tol: r_angle = np.sign(r_kdom[nm].y) * math.acos( r_kdom[nm].x / fcen) if ( r_kdom[nm].x % fcen > angle_tol) else 0 Rmode = abs(r_coeffs[nm, 0, 1])**2 / input_flux[0] print("refl: (odd_y), {}, {:.2f}, {:.8f}".format( nm, math.degrees(r_angle), Rmode)) Rsum += Rmode nm_t = int(0.5 * (np.floor((fcen * ng - k.y) * d) - np.ceil( (-fcen * ng - k.y) * d))) # number of transmitted orders res = sim.get_eigenmode_coefficients(tran_flux, range(1, nm_t + 1), eig_parity=eig_parity + mp.EVEN_Y) t_coeffs = res.alpha t_kdom = res.kdom for nm in range(nm_t): if nm != nm_val: continue if t_kdom[nm].x > kdom_tol: t_angle = np.sign(t_kdom[nm].y) * math.acos( t_kdom[nm].x / (ng * fcen)) if ( t_kdom[nm].x % ng * fcen > angle_tol) else 0 Tmode = abs(t_coeffs[nm, 0, 0])**2 / input_flux[0] transmittance = transmittance + Tmode Tsum += Tmode res = sim.get_eigenmode_coefficients(tran_flux, range(1, nm_t + 1), eig_parity=eig_parity + mp.ODD_Y) t_coeffs = res.alpha t_kdom = res.kdom for nm in range(nm_t): if nm != nm_val: continue if t_kdom[nm].x > kdom_tol: t_angle = np.sign(t_kdom[nm].y) * math.acos( t_kdom[nm].x / (ng * fcen)) if ( t_kdom[nm].x % ng * fcen > angle_tol) else 0 Tmode = abs(t_coeffs[nm, 0, 0])**2 / input_flux[0] transmittance = transmittance + Tmode Tsum += Tmode else: nm_r = int(np.floor((fcen - k.y) * d) - np.ceil( (-fcen - k.y) * d)) # number of reflected orders res = sim.get_eigenmode_coefficients(refl_flux, range(1, nm_r + 1), eig_parity=eig_parity) r_coeffs = res.alpha r_kdom = res.kdom for nm in range(nm_r): if nm != nm_val: continue if r_kdom[nm].x > kdom_tol: r_angle = np.sign(r_kdom[nm].y) * math.acos( r_kdom[nm].x / fcen) if ( r_kdom[nm].x % fcen > angle_tol) else 0 Rmode = abs(r_coeffs[nm, 0, 1])**2 / input_flux[0] Rsum += Rmode nm_t = int( np.floor((fcen * ng - k.y) * d) - np.ceil( (-fcen * ng - k.y) * d)) # number of transmitted orders res = sim.get_eigenmode_coefficients(tran_flux, range(1, nm_t + 1), eig_parity=eig_parity) t_coeffs = res.alpha t_kdom = res.kdom for nm in range(nm_t): if nm != nm_val: continue if t_kdom[nm].x > kdom_tol: t_angle = np.sign(t_kdom[nm].y) * math.acos( t_kdom[nm].x / (ng * fcen)) if ( t_kdom[nm].x % ng * fcen > angle_tol) else 0 Tmode = abs(t_coeffs[nm, 0, 0])**2 / input_flux[0] transmittance = transmittance + Tmode return transmittance
import meep as mp import numpy as np results = [] for fi in range(1): for fj in range(10): fingersize = 0.05 * (fj + 1) cell = mp.Vector3(7, fingersize * 10, fingersize * 10) pml_layers = [mp.Absorber(1, mp.X, mp.Low), mp.PML(1, mp.X, mp.High)] CdSe = mp.Medium(index=2.52) ZnO = mp.Medium(index=2.21) resolution = 80 - fj * 4 sources = [ mp.Source(mp.ContinuousSource(wavelength=0.550, end_time=10), component=mp.Ez, center=mp.Vector3(-1, 0, 0)) ] firstfr = mp.FluxRegion(center=mp.Vector3(-2, 0, 0), size=mp.Vector3(0, cell.y, cell.z)) secfr = mp.FluxRegion(center=mp.Vector3(2.5, 0, 0), size=mp.Vector3(0, cell.y, cell.z)) sim = mp.Simulation(cell_size=cell, k_point=mp.Vector3(), default_material=CdSe, boundary_layers=pml_layers, eps_averaging=False,
def Simulation(period, grating_t, grating_w, sep, mthick, mat): #----------------------Variables------------------------------ sub = 1.4 #thickness of the substrate (where the grating is embedded) d1 = 1.52 #dielectric constant of medium dpml = 0.2 #um air = 1.5 #um matty = [Au, Ag] #-------------------------Clear------------------------------- #if os.path.exists("dft_X_empty.h5"): # os.remove("dft_X_empty.h5") #if os.path.exists("dft_X_fields.h5"): # os.remove("dft_X_fields.h5") #if os.path.exists("dft_Y_empty.h5"): # os.remove("dft_Y_empty.h5") #if os.path.exists("dft_Y_fields.h5"): # os.remove("dft_Y_fields.h5") #----------------------Simulation------------------------------ ideal = np.loadtxt('ideal_peak.txt') # maximum source waveWIDTH lambda_ideal = ideal nfreq = 1 f_cen = 1 / lambda_ideal # source frequency center df = 0.05 * f_cen # source frequency width sy = period sx = dpml + sub + sep + mthick + air + dpml resolution = 1000 #pixels/um diel1 = mp.Medium(index=d1) cell = mp.Vector3(sx, sy, 0) #define Gaussian plane wave sources = [ mp.Source(mp.GaussianSource(f_cen, fwidth=df), component=mp.Hz, center=mp.Vector3(-0.5 * sx + dpml + 0.1, 0, 0), size=mp.Vector3(0, sy, 0)) ] #define pml layers pml_layers = [mp.Absorber(thickness=dpml, direction=mp.X)] supers = mp.Block(mp.Vector3(sub + sep, mp.inf, mp.inf), center=mp.Vector3(-0.5 * sx + 0.5 * (sub + sep), 0, 0), material=diel1) geometry = [supers] #mp.quiet(quietval=True) sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, symmetries=[mp.Mirror(mp.Y, phase=-1)], dimensions=2, resolution=resolution, k_point=mp.Vector3(0, 0, 0)) #----------------------Monitors------------------------------ dfts_Y1 = sim.add_dft_fields([mp.Ey], f_cen, f_cen, 1, where=mp.Volume(center=mp.Vector3( 0.5 * sx - dpml - 0.5 * (mthick + air), 0), size=mp.Vector3( air + mthick, sy))) dfts_X1 = sim.add_dft_fields([mp.Ex], f_cen, f_cen, 1, where=mp.Volume(center=mp.Vector3( 0.5 * sx - dpml - 0.5 * (mthick + air), 0), size=mp.Vector3( air + mthick, sy))) #----------------------Run------------------------------ sim.run(until_after_sources=100) #----------------------Reset------------------------------ sim.output_dft(dfts_Y1, "dft_Y_empty") sim.output_dft(dfts_X1, "dft_X_empty") sim.reset_meep() grating = mp.Block(mp.Vector3(grating_t, grating_w, mp.inf), center=mp.Vector3(-0.5 * sx + sub - 0.5 * grating_t, 0, 0), material=matty[int(mat)]) metal = mp.Block(mp.Vector3(mthick, mp.inf, mp.inf), center=mp.Vector3(-0.5 * sx + sub + sep + 0.5 * mthick, 0, 0), material=matty[int(mat)]) geometry = [supers, grating, metal] sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, sources=sources, geometry=geometry, symmetries=[mp.Mirror(mp.Y, phase=-1)], dimensions=2, resolution=resolution, k_point=mp.Vector3(0, 0, 0)) dfts_Y2 = sim.add_dft_fields([mp.Ey], f_cen, f_cen, 1, where=mp.Volume(center=mp.Vector3( 0.5 * sx - dpml - 0.5 * (mthick + air), 0), size=mp.Vector3( air + mthick, sy))) dfts_X2 = sim.add_dft_fields([mp.Ex], f_cen, f_cen, 1, where=mp.Volume(center=mp.Vector3( 0.5 * sx - dpml - 0.5 * (mthick + air), 0), size=mp.Vector3( air + mthick, sy))) sim.run(until_after_sources=400) #mp.at_beginning(mp.output_epsilon), sim.output_dft(dfts_Y2, "dft_Y_fields") sim.output_dft(dfts_X2, "dft_X_fields") #----------------------------Graph the Outputs---------------------------- with h5py.File('dft_Y_fields.h5', 'r') as Esy: with h5py.File('dft_Y_empty.h5', 'r') as Eoy: with h5py.File('dft_X_fields.h5', 'r') as Esx: with h5py.File('dft_X_empty.h5', 'r') as Eox: eix2 = np.array(Esx[('ex_0.i')]) erx2 = np.array(Esx[('ex_0.r')]) eiy2 = np.array(Esy[('ey_0.i')]) ery2 = np.array(Esy[('ey_0.r')]) E2 = (eix2**2 + erx2**2) + (eiy2**2 + ery2**2) eix2 = np.array(Eox[('ex_0.i')]) erx2 = np.array(Eox[('ex_0.r')]) eiy2 = np.array(Eoy[('ey_0.i')]) ery2 = np.array(Eoy[('ey_0.r')]) E1 = (eix2**2 + erx2**2) + (eiy2**2 + ery2**2) Enhance = E2 / E1 Enhance = np.rot90(Enhance) heat_map = sb.heatmap(Enhance, cmap='plasma', xticklabels=False, yticklabels=False) plt.ylabel("y-axis") plt.xlabel("x-axis") plt.savefig('Enhance_Z.png') en = np.zeros(len(Enhance[0])) pos = np.linspace(0, 3.82, len(en)) for i in range(len(Enhance[0])): en[i] = np.max(Enhance[:, i]) plt.clf() plt.figure() plt.plot(pos, en) plt.xlabel('position along substrate (um)') plt.ylabel('enhancement') plt.savefig('Profile.png') return ()
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)
def notch(w): print("#----------------------------------------") print("NOTCH WIDTH: %s nanometers" % (w * 1000)) print("#----------------------------------------") # w is the width of the notch in the waveguide angrad = ang * pi / 180 bottomoffset = e * h / tan(angrad) vertices = [ mp.Vector3(w / 2 + bottomoffset, (.5 + e) * h), mp.Vector3(-w / 2 - bottomoffset, (.5 + e) * h), mp.Vector3(-w / 2 + bottomoffset, (.5 - e) * h), mp.Vector3(w / 2 - bottomoffset, (.5 - e) * h) ] if bottomoffset > w / 2: ratio = (w / 2) / bottomoffset vertices = [ mp.Vector3(w / 2, h / 2), mp.Vector3(-w / 2, h / 2), mp.Vector3(0, (.5 - e * ratio) * h) ] print(vertices) #Waveguide Geometry cell = mp.Vector3(a, H) geometry = [ mp.Block(cell, center=mp.Vector3(0, 0), material=default_material), mp.Block(mp.Vector3(a, hu + h / 2), center=mp.Vector3(0, (hu + h / 2) / 2), material=upper_material), mp.Block(mp.Vector3(a, hl + h / 2), center=mp.Vector3(0, -(hl + h / 2) / 2), material=lower_material), mp.Block(mp.Vector3(a, h), center=mp.Vector3(0, 0), material=core_material) ] if w > 0: geometry.append(mp.Prism(vertices, height=1, material=upper_material)) pml_layers = [mp.Absorber(thickness=dpml)] r00 = None r01 = None r10 = None r11 = None t00 = None t01 = None t10 = None t11 = None su0 = None sd0 = None su1 = None sd1 = None modes = [0, 1] if only_fund: modes = [0] # eig_parity_fund = mp.EVEN_Z+mp.EVEN_Y; # eig_parity_first = mp.EVEN_Z+mp.ODD_Y; eig_parity_fund = mp.EVEN_Y eig_parity_first = mp.ODD_Y # for mode in [0, 1]: for mode in modes: if mode == 0: eig_parity = eig_parity_fund # Fundamental print("-----------") print("MODE TYPE: FUNDAMENTAL") else: eig_parity = eig_parity_first # First Order print("-----------") print("MODE TYPE: FIRST ORDER") sources = [ mp.EigenModeSource(mp.ContinuousSource(frequency=fcen), size=mp.Vector3(0, H), center=mp.Vector3(Ls, 0), eig_parity=eig_parity) ] sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, geometry=geometry, sources=sources, resolution=resolution, force_complex_fields=True) ''' #-------------------------------------------------- #FOR DISPLAYING THE GEOMETRY sim.run(until = 200) eps_data = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Dielectric) plt.figure(dpi=100) plt.imshow(eps_data.transpose(), interpolation='spline36', cmap='binary') #plt.axis('off') plt.show() quit() #---------------------------------------------------- ''' ''' #------------------------------------------------------ #FOR GENERATING THE ELECTRIC FIELD GIF #Note: After running this program, write the following commands in Terminal: # $ source deactivate mp # $ cd notch-out/ # $ python ../NotchIP.py sim.use_output_directory() sim.run(mp.at_beginning(mp.output_epsilon), mp.to_appended("ez", mp.at_every(0.6, mp.output_efield_z)), until = 200) #sim.run(mp.at_every(0.6 , mp.output_png(mp.Ez, "-Zc dkbluered")), until=200) #--------------------------------------------------------- ''' #--------------------------------------------------------- # FOR GENERATING THE TRANSMITTANCE SPECTRUM nfreq = 1 # number of frequencies at which to compute flux refl_fr1 = mp.FluxRegion(center=mp.Vector3(Lr1, 0), size=mp.Vector3( 0, monitorheight)) # Reflected flux 1 refl_fr2 = mp.FluxRegion(center=mp.Vector3(Lr2, 0), size=mp.Vector3( 0, monitorheight)) # Reflected flux 2 tran_fr = mp.FluxRegion(center=mp.Vector3(Lt, 0), size=mp.Vector3( 0, monitorheight)) # Transmitted flux su_fr = mp.FluxRegion(center=mp.Vector3(0, monitorheight / 2), size=mp.Vector3( a, 0)) # Flux loss above the waveguide sd_fr = mp.FluxRegion(center=mp.Vector3(0, -monitorheight / 2), size=mp.Vector3( a, 0)) # Flux loss below the waveguide # refl1 = sim.add_flux(fcen, df, nfreq, refl_fr1) # refl2 = sim.add_flux(fcen, df, nfreq, refl_fr2) # tran = sim.add_flux(fcen, df, nfreq, tran_fr) # su = sim.add_flux(fcen, df, nfreq, su_fr) # sd = sim.add_flux(fcen, df, nfreq, sd_fr) # ------------------------ CODE FOR SEPARATING FUND AND FIRST ORDER MODE STARTS HERE ------------------------ refl_vals = [] tran_vals = [] def get_refl_slice(sim): # print(sim.get_array(center=mp.Vector3(Lr1,0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True)) # refl_val = sim.get_array(center=mp.Vector3(Lr1,0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True) refl_vals.append( sim.get_array(center=mp.Vector3(Lr1, 0), size=mp.Vector3(0, monitorheight - 2 / resolution), component=mp.Ez, cmplx=True)) def get_tran_slice(sim): # print(sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True)) # tran_val = sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True) tran_vals.append( sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0, monitorheight - 2 / resolution), component=mp.Ez, cmplx=True)) gif = True if gif: # and w == 0.1: sim.use_output_directory() sim.run(mp.at_beginning(mp.output_epsilon), mp.at_end(get_refl_slice), mp.at_end(get_tran_slice), until=100) refl1 = sim.add_flux(fcen, df, nfreq, refl_fr1) refl2 = sim.add_flux(fcen, df, nfreq, refl_fr2) tran = sim.add_flux(fcen, df, nfreq, tran_fr) su = sim.add_flux(fcen, df, nfreq, su_fr) sd = sim.add_flux(fcen, df, nfreq, sd_fr) # sim.run(mp.at_every(wavelength / 20, mp.output_efield_z), until=wavelength) # sim.run(mp.at_every(wavelength/20 , mp.output_png(mp.Ez, "-RZc bluered -A notch-out/notch-eps-000000000.h5 -a gray:.2")), until=19*wavelength/20) sim.run(mp.at_every( wavelength / 20, mp.output_png( mp.Ez, "-RZc bluered -A notch-out/notch-eps-000000.00.h5 -a gray:.2" )), until=19 * wavelength / 20) sim.run(until=50) else: sim.run(mp.at_end(get_refl_slice), mp.at_end(get_tran_slice), until=100) sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ez, mp.Vector3(), 1e-5)) os.system( "h5topng notch-out/notch-eps-000000.00.h5; mv notch-out/notch-eps-000000.00.png " + case + "-" + str(int(w * 1000)) + "-" + str(mode) + "-eps.png") os.system("cp notch-out/notch-ez-000100.00.png " + case + "-" + str(int(w * 1000)) + "-" + str(mode) + ".png") os.system("convert notch-out/notch-ez-*.png " + case + "-" + str(int(w * 1000)) + "-" + str(mode) + ".gif") # get_eigenmode(fcen, mp., refl_fr1, 1, kpoint) # v = mp.volume(mp.vec(Lr1, -monitorheight/2), mp.vec(Lr1, monitorheight/2)) # mode = get_eigenmode(fcen, mp.X, v, v, 1, mp.vec(0, 0, 0), True, 0, 0, 1e-7, True) # print(mode.amplitude) # coef_refl_fund = mp.get_eigenmode_coefficients_and_kpoints(refl_fr1, 1, eig_parity=eig_parity_fund, eig_resolution=resolution, eig_tolerance=1e-7) # coef_refl_first = mp.get_eigenmode_coefficients_and_kpoints(refl_fr1, 1, eig_parity=eig_parity_first, eig_resolution=resolution, eig_tolerance=1e-7) # # coef_tran_fund = mp.get_eigenmode_coefficients_and_kpoints(tran_fr, 1, eig_parity=eig_parity_fund, eig_resolution=resolution, eig_tolerance=1e-7) # coef_tran_first = mp.get_eigenmode_coefficients_and_kpoints(tran_fr, 1, eig_parity=eig_parity_first, eig_resolution=resolution, eig_tolerance=1e-7) ep = mp.ODD_Z #coef_refl_fund, vgrp, kpoints_fund = sim.get_eigenmode_coefficients(refl1, [1], eig_parity=ep, eig_resolution=resolution, eig_tolerance=1e-7) #coef_refl_first, vgrp, kpoints_first = sim.get_eigenmode_coefficients(refl1, [2], eig_parity=ep, eig_resolution=resolution, eig_tolerance=1e-7) #coef_tran_fund, vgrp, kpoints_fund = sim.get_eigenmode_coefficients(tran, [1], eig_parity=ep, eig_resolution=resolution, eig_tolerance=1e-7) #coef_tran_first, vgrp, kpoints_first = sim.get_eigenmode_coefficients(tran, [2], eig_parity=ep, eig_resolution=resolution, eig_tolerance=1e-7) # print(kpoints_fund) # print(kpoints_first) # print(kpoints_fund[0]) # print(type(kpoints_fund[0])) # print(dir(kpoints_fund[0])) # n_eff_fund = wavelength*kpoints_fund[0].x # n_eff_first = wavelength*kpoints_first[0].x n_eff_fund = neff n_eff_first = 1 print(n_eff_fund) print(n_eff_first) # print(coef_refl_fund) # print(type(coef_refl_fund)) # print(dir(coef_refl_fund)) # print(coef_refl_fund[0]) # print(coef_refl_fund[0][0,0,:]) # # fund_refl_amp = coef_refl_fund[0][0,0,1]; # first_order_refl_amp = coef_refl_first[0][0,0,1]; # fund_tran_amp = coef_tran_fund[0][0,0,0]; # first_order_tran_amp = coef_tran_first[0][0,0,0]; print("get_eigenmode_coefficients:\n") #print(coef_refl_fund) #print(coef_refl_first) #print(coef_tran_fund) #print(coef_tran_first) print("\n") # print(coef_refl_fund[0,0,:]) #fund_refl_amp = coef_refl_fund[0,0,1]; #first_order_refl_amp = coef_refl_first[0,0,1]; #fund_tran_amp = coef_tran_fund[0,0,0]; #first_order_tran_amp = coef_tran_first[0,0,0]; refl_val = refl_vals[0] tran_val = tran_vals[0] # n_eff must satisfy n_e <= n_eff <= n_c for the mode to be bound. def fund_func(n_eff): if n_eff >= n_c and n_eff <= n_e: return sqrt(n_eff**2 - n_c**2) - sqrt(n_e**2 - n_eff**2) * tan( pi * h / wavelength * sqrt(n_e**2 - n_eff**2)) def first_order_func(n_eff): if n_eff >= n_c and n_eff <= n_e: return sqrt(n_eff**2 - n_c**2) - sqrt(n_e**2 - n_eff**2) * tan( pi * h / wavelength * sqrt(n_e**2 - n_eff**2) - pi / 2) initial_guess = (n_c + n_e) / 2 # n_eff_fund = fsolve(fund_func, initial_guess) # n_eff_first = fsolve(first_order_func, n_c) print(n_eff_fund, n_eff_first) assert (n_eff_fund > n_eff_first) if len(n_eff_funds) == 0: n_eff_funds.append(n_eff_fund) if len(n_eff_firsts) == 0: n_eff_firsts.append(n_eff_first) ky0_fund = np.abs(2 * pi / wavelength * sqrt(n_e**2 - n_eff_fund**2)) ky0_first = np.abs(2 * pi / wavelength * sqrt(n_e**2 - n_eff_first**2)) ky1_fund = ky0_fund # np.abs(2 * pi / wavelength * sqrt(n_eff_fund **2 - n_c**2)) ky1_first = ky0_first # np.abs(2 * pi / wavelength * sqrt(n_eff_first**2 - n_c**2)) E_fund = lambda y: cos(ky0_fund * y) if np.abs(y) < h / 2 else cos( ky0_fund * h / 2) * np.exp(-ky1_fund * (np.abs(y) - h / 2)) E_first_order = lambda y: sin(ky0_first * y) if np.abs( y) < h / 2 else sin(ky0_first * h / 2) * np.exp(-ky1_first * ( np.abs(y) - h / 2)) * np.sign(y) # y_list = np.arange(-H/2+.5/resolution, H/2-.5/resolution, 1/resolution) #print("Y LIST: ", y_list) #print("SIZE OF Y LIST: ", y_list.size) E_fund_vec = np.zeros(y_list.size) E_first_order_vec = np.zeros(y_list.size) for index in range(y_list.size): y = y_list[index] E_fund_vec[index] = E_fund(y) E_first_order_vec[index] = E_first_order(y) # print(dir(sim)) # print(type(sim.get_eigenmode_coefficients)) # print(dir(sim.get_eigenmode_coefficients)) # print(type(sim.get_eigenmode)) # print(dir(sim.get_eigenmode)) # print(sim.get_eigenmode.__code__.co_varnames) # print(sim.get_eigenmode.__defaults__) # E1 = sim.get_eigenmode(fcen, mp.X, refl1.where, 1, None) # E2 = sim.get_eigenmode(fcen, mp.X, refl1.where, 2, None) # E3 = sim.get_eigenmode(fcen, mp.X, refl1.where, 3, None) # E4 = sim.get_eigenmode(fcen, mp.X, refl1.where, 4, None) # E1 = sim.get_eigenmode(fcen, mp.X, refl1.where, 1, mp.Vector3(0, 0, 0)) # E2 = sim.get_eigenmode(fcen, mp.X, refl1.where, 2, mp.Vector3(0, 0, 0)) # E3 = sim.get_eigenmode(fcen, mp.X, refl1.where, 3, mp.Vector3(0, 0, 0)) # E4 = sim.get_eigenmode(fcen, mp.X, refl1.where, 4, mp.Vector3(0, 0, 0)) # print(refl1.where) # numEA = 0 # E1 = sim.fields.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 1, mp.vec(0,0,0), True, 0, numEA, 1e-7, True) # print(type(E1)) # print(dir(E1)) # # print(refl1.where) # # print(E1, E2, E3, E4) # print(E1.amplitude, E1.band_num, E1.group_velocity, E1.k) # print(type(E1.amplitude)) # print(dir(E1.amplitude)) # print(doc(E1.amplitude)) # print(self(E1.amplitude)) # print(E1.amplitude(y_list)) # print(type(E1.amplitude(y_list))) # print(dir(E1.amplitude(y_list))) # print(E1.amplitude, E2.amplitude, E3.amplitude, E4.amplitude) # E1 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 1, mp.vec(0, 0, 0)) # E2 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 2, mp.vec(0, 0, 0)) # E3 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 3, mp.vec(0, 0, 0)) # E4 = sim.get_eigenmode(fcen, mp.X, refl1.where, refl1.where, 4, mp.vec(0, 0, 0)) # print(y_list) # # E1a = np.zeros(y_list.size, dtype='Complex128'); # E2a = np.zeros(y_list.size, dtype='Complex128'); # E3a = np.zeros(y_list.size, dtype='Complex128'); # E4a = np.zeros(y_list.size, dtype='Complex128'); # # # print(mp.eigenmode_amplitude.__code__.co_varnames) # # print(mp.eigenmode_amplitude.__defaults__) # # for i in range(y_list.size): # # print(E1) # # print(E1.swigobj) # # print(E1.amplitude) # # print(mp.vec(Lr1, y_list[i], 0)) # # print(mp.Vector3(Lr1, y_list[i], 0)) # # print(mp.Ez) # # E1a[i] = mp.eigenmode_amplitude(E1.swigobj, mp.vec(Lr1, y_list[i], 0), mp.Ez); # eval_point = mp.vec(Lr1, y_list[i], 0) # # print(eval_point) # E1a[i] = mp.eigenmode_amplitude(E1.swigobj, eval_point, mp.Ex) # E2a[i] = mp.eigenmode_amplitude(E2.swigobj, eval_point, mp.Ex) # E3a[i] = mp.eigenmode_amplitude(E3.swigobj, eval_point, mp.Ex) # E4a[i] = mp.eigenmode_amplitude(E4.swigobj, eval_point, mp.Ex) # # E1a[i] = mp.eigenmode_amplitude(E1.amplitude, mp.Vector3(Lr1, y_list[i], 0), mp.Ez); # # plt.plot(y_list, np.abs(E1a)**2, 'bo-', label='E1') # plt.plot(y_list, np.abs(E2a)**2, 'ro-', label='E2') # plt.plot(y_list, np.abs(E3a)**2, 'go-', label='E3') # plt.plot(y_list, np.abs(E4a)**2, 'co-', label='E4') # # plt.axis([40.0, 300.0, 0.0, 100.0]) # plt.xlabel("y (um)") # plt.ylabel("Field (a.u.)") # plt.legend(loc="center right") # plt.show() # print("r VECTOR: ", refl_val) # print("t VECTOR: ", tran_val) # print("E0 VECTOR: ", E_fund_vec) # print("E1 VECTOR: ", E_first_order_vec) # fund_refl_amp_2 = np.conj(np.dot(refl_val, E_fund_vec) / np.dot(E_fund_vec, E_fund_vec)) # Conjugate becasue MEEP uses physics exp(kz-wt) rather than engineering exp(wt-kz) # first_order_refl_amp_2 = np.conj(np.dot(refl_val, E_first_order_vec) / np.dot(E_first_order_vec, E_first_order_vec)) # fund_tran_amp_2 = np.conj(np.dot(tran_val, E_fund_vec) / np.dot(E_fund_vec, E_fund_vec)) # first_order_tran_amp_2 = np.conj(np.dot(tran_val, E_first_order_vec) / np.dot(E_first_order_vec, E_first_order_vec)) fund_refl_amp = np.conj( np.dot(refl_val, E0) / np.dot(E0, E0) ) # Conjugate becasue MEEP uses physics exp(kz-wt) rather than engineering exp(wt-kz) first_order_refl_amp = 0 # np.conj(np.dot(refl_val, E1[:,2]) / np.dot(E1[:,2], E1[:,2])) fund_tran_amp = np.conj(np.dot(tran_val, E0) / np.dot(E0, E0)) first_order_tran_amp = 0 # np.conj(np.dot(tran_val, E1[:,2]) / np.dot(E1[:,2], E1[:,2])) fund_refl = np.conj(fund_refl_amp) * E0 not_fund_refl = refl_val - fund_refl fund_tran = np.conj(fund_tran_amp) * E0 not_fund_tran = tran_val - fund_tran fund_refl_power = np.dot(np.conj(fund_refl), fund_refl) not_fund_refl_power = np.dot(np.conj(not_fund_refl), not_fund_refl) fund_tran_power = np.dot(np.conj(fund_tran), fund_tran) not_fund_tran_power = np.dot(np.conj(not_fund_tran), not_fund_tran) fund_refl_ratio = np.abs(fund_refl_power / (fund_refl_power + not_fund_refl_power)) first_order_refl_ratio = 0 fund_tran_ratio = np.abs(fund_tran_power / (fund_tran_power + not_fund_tran_power)) first_order_tran_ratio = 0 # plt.plot(y_list, np.abs(refl_val), 'bo-',label='reflectance') # plt.plot(y_list, np.abs(tran_val), 'ro-',label='transmittance') # plt.plot(y_list, E0, 'go-',label='E0') # plt.plot(y_list, fund_refl_amp*E0, 'co-',label='over') # # plt.axis([40.0, 300.0, 0.0, 100.0]) # plt.xlabel("y (um)") # plt.ylabel("Field") # plt.legend(loc="center right") # plt.show() # # print("\n") # # print(tran_val.size, refl_val.size) # # print("\n") # # print(tran_val, refl_val, E0) # # print("\n") # # print(np.conj(tran_val), tran_val, E1[:,2]) # # # # print(np.conj(refl_val), refl_val, E1[:,2]) # # refl_tot_power = np.abs(np.dot(np.conj(refl_val), refl_val)) # tran_tot_power = np.abs(np.dot(np.conj(tran_val), tran_val)) # # print(fund_refl_amp, refl_tot_power, fund_tran_amp, tran_tot_power) # print(fund_refl_amp , fund_refl_amp_2 ) # print(first_order_refl_amp , first_order_refl_amp_2) # print(fund_tran_amp , fund_tran_amp_2 ) # print(first_order_tran_amp , first_order_tran_amp_2) # # print(np.angle(fund_refl_amp), np.angle(fund_refl_amp_2)) # print(np.angle(first_order_refl_amp), np.angle(first_order_refl_amp_2)) # print(np.angle(fund_tran_amp), np.angle(fund_tran_amp_2)) # print(np.angle(first_order_tran_amp), np.angle(first_order_tran_amp_2)) # fund_refl_power = np.abs(fund_tran_amp) ** 2 # fund_refl_power = np.abs(fund_refl_amp) ** 2 # first_order_refl_power = np.abs(first_order_refl_amp) ** 2 # fund_tran_power = np.abs(fund_tran_amp) ** 2 # first_order_tran_power = np.abs(first_order_tran_amp) ** 2 # print(fund_refl_power, first_order_refl_power, fund_tran_power, first_order_tran_power) # fund_refl_ratio = fund_refl_power / (fund_refl_power + first_order_refl_power) # first_order_refl_ratio = first_order_refl_power / (fund_refl_power + first_order_refl_power) # fund_tran_ratio = fund_tran_power / (fund_tran_power + first_order_tran_power) # first_order_tran_ratio = first_order_tran_power / (fund_tran_power + first_order_tran_power) # fund_refl_power = np.abs(fund_refl_amp) ** 2 # first_order_refl_power = np.abs(first_order_refl_amp) ** 2 # fund_tran_power = np.abs(fund_tran_amp) ** 2 # first_order_tran_power = np.abs(first_order_tran_amp) ** 2 # # fund_refl_ratio = fund_refl_power / refl_tot_power # first_order_refl_ratio = first_order_refl_power / refl_tot_power # fund_tran_ratio = fund_tran_power / tran_tot_power # first_order_tran_ratio = first_order_tran_power / tran_tot_power # # fund_refl_ratio = 1 # first_order_refl_ratio = 0 # fund_tran_ratio = 1 # first_order_tran_ratio = 0 print("Percentage of reflected light in fundamental mode: ", fund_refl_ratio * 100) print("Percentage of reflected light in first order mode: ", first_order_refl_ratio * 100) print("Percentage of transmitted light in fundamental mode: ", fund_tran_ratio * 100) print("Percentage of transmitted light in first order mode: ", first_order_tran_ratio * 100) # ------------------------ CODE FOR SEPARATING FUND AND FIRST ORDER MODE ENDS HERE ------------------------ wl = [] #list of wavelengths refl1_flux = mp.get_fluxes(refl1) refl2_flux = mp.get_fluxes(refl2) tran_flux = mp.get_fluxes(tran) su_flux = mp.get_fluxes(su) sd_flux = mp.get_fluxes(sd) flux_freqs = mp.get_flux_freqs(refl1) for i in range(nfreq): wl = np.append(wl, 1 / flux_freqs[i]) print(1 / flux_freqs[i]) # for ind, elt in enumerate(wl): # #print(round(elt, 4)) # if round(elt, 3) == 0.637: # #print("ALERT: MATCH FOUND") # index = ind index = 0 rp = refl1_flux[index] tp = tran_flux[index] # print("rp/tp:\n") # print(rp) # print(tp) # print("\n") R = -refl1_flux[index] / (refl2_flux[index] - refl1_flux[index]) T = tran_flux[index] / (refl2_flux[index] - refl1_flux[index]) S = (refl2_flux[index] - tran_flux[index]) / (refl2_flux[index] - refl1_flux[index]) Su = su_flux[index] / (refl2_flux[index] - refl1_flux[index]) Sd = -sd_flux[index] / (refl2_flux[index] - refl1_flux[index]) S_correction = (1 - R - T) / (Su + Sd) # print(R, T, S, Su, Sd) r = sqrt(R) t = sqrt(T) # The amplitude ... times the phase ... accounting for the distance to the detector (Reverse exp(-kz) of phase). # r_fund = (r * fund_refl_ratio) * (fund_refl_amp / np.abs(fund_refl_amp)) * (np.exp( 2j*pi * (-Lr1 - w/2) * n_eff_fund / wavelength)) # Lr1 is negative because it is the (negative) position of the monitor, not the distace from the monitor to the center. # r_first = (r * first_order_refl_ratio) * (first_order_refl_amp / np.abs(first_order_refl_amp)) * (np.exp( 2j*pi * (-Lr1 - w/2) * n_eff_first / wavelength)) # t_fund = (t * fund_tran_ratio) * (fund_tran_amp / np.abs(fund_tran_amp)) * (np.exp( 2j*pi * ( Lt - w/2) * n_eff_fund / wavelength)) # t_first = (t * first_order_tran_ratio) * (first_order_tran_amp / np.abs(first_order_tran_amp)) * (np.exp( 2j*pi * ( Lt - w/2) * n_eff_first / wavelength)) r_fund = (r * fund_refl_ratio) * np.exp( 1j * np.angle(fund_refl_amp) + 2j * pi * (-Lr1 - w / 2) * n_eff_fund / wavelength ) # Lr1 is negative because it is the (negative) position of the monitor, not the distace from the monitor to the center. r_first = (r * first_order_refl_ratio ) * np.exp(1j * np.angle(first_order_refl_amp) + 2j * pi * (-Lr1 - w / 2) * n_eff_first / wavelength) t_fund = (t * fund_tran_ratio ) * np.exp(1j * np.angle(fund_tran_amp) + 2j * pi * (Lt - w / 2) * n_eff_fund / wavelength) t_first = (t * first_order_tran_ratio ) * np.exp(1j * np.angle(first_order_tran_amp) + 2j * pi * (Lt - w / 2) * n_eff_first / wavelength) if mode == 0: r00 = r_fund r01 = r_first t00 = t_fund t01 = t_first su0 = sqrt(np.abs(Su * S_correction)) sd0 = sqrt(np.abs(Sd * S_correction)) # su0 = sqrt(Su) # sd0 = sqrt(Sd) r00s.append(r00) r01s.append(r01) t00s.append(t00) t01s.append(t01) su0s.append(su0) sd0s.append(sd0) if only_fund: r10s.append(0) r11s.append(0) t10s.append(0) t11s.append(1) su1s.append(0) sd1s.append(0) else: r10 = r_fund r11 = r_first t10 = t_fund t11 = t_first su1 = sqrt(np.abs(Su * S_correction)) sd1 = sqrt(np.abs(Sd * S_correction)) # su1 = sqrt(Su) # sd1 = sqrt(Sd) r10s.append(r10) r11s.append(r11) t10s.append(t10) t11s.append(t11) su1s.append(su1) sd1s.append(sd1) norm_Su = S * Su / (Su + Sd) NET = round((R + T + S) * 100, 0) if NET > 100.0: NET = 100.0 NET_LOSS = round((Su + Sd) / S * 100, 0) if NET_LOSS > 100.0: NET_LOSS = 100.0 ''' np.append(ws, [w * 1000]) np.append(Rs, [R * 100]) np.append(Ts, [T * 100]) np.append(Ss, [S * 100]) np.append(NET_LIST, [NET]) np.append(Sus, [Su * 100]) np.append(Sds, [Sd * 100]) np.append(NET_LOSS_LIST, [NET_LOSS]) np.append(norm_Sus, [norm_Su * 100]) ''' if mode == 0: ws.append(w * 1000) Rs.append(R * 100) Ts.append(T * 100) Ss.append(S * 100) NET_LIST.append(NET) Sus.append(Su * 100) Sds.append(Sd * 100) NET_LOSS_LIST.append(NET_LOSS) norm_Sus.append(norm_Su * 100) if mode == 0: f1.write("--------------------------------------------------- \n") f1.write("Notch Width: %s nanometers \n" % (w * 1000)) f1.write("Reflection Percentage: %s\n" % (R * 100)) f1.write("Transmission Percentage: %s\n" % (T * 100)) f1.write("Total Loss Percentage: %s\n" % (S * 100)) f1.write("Percentage of Light Accounted For: %s\n" % (NET)) f1.write("Upper Loss Percentage: %s\n" % (Su * 100)) f1.write("Lower Loss Percentage: %s\n" % (Sd * 100)) f1.write("Percentage of Total Loss Accounted For: %s\n" % (NET_LOSS)) f1.write("Normalized Upper Loss Percentage: %s\n" % (norm_Su * 100)) f1.write("\n \n") f1.write("FUNDAMENTAL MODE \n") f1.write("n_eff: %s\n" % (n_eff_fund)) f1.write("Re(r00): %s\n" % (np.real(r00))) f1.write("Im(r00): %s\n" % (np.imag(r00))) f1.write("Re(r01): %s\n" % (np.real(r01))) f1.write("Im(r01): %s\n" % (np.imag(r01))) f1.write("Re(t00): %s\n" % (np.real(t00))) f1.write("Im(t00): %s\n" % (np.imag(t00))) f1.write("Re(t01): %s\n" % (np.real(t01))) f1.write("Im(t01): %s\n" % (np.imag(t01))) f1.write("Re(su0): %s\n" % (np.real(su0))) f1.write("Im(su0): %s\n" % (np.imag(su0))) f1.write("Re(sd0): %s\n" % (np.real(sd0))) f1.write("Im(sd0): %s\n" % (np.imag(sd0))) f1.write("\n") else: f1.write("FIRST ORDER MODE \n") f1.write("n_eff: %s\n" % (n_eff_first)) f1.write("Re(r10): %s\n" % (np.real(r10))) f1.write("Im(r10): %s\n" % (np.imag(r10))) f1.write("Re(r11): %s\n" % (np.real(r11))) f1.write("Im(r11): %s\n" % (np.imag(r11))) f1.write("Re(t10): %s\n" % (np.real(t10))) f1.write("Im(t10): %s\n" % (np.imag(t10))) f1.write("Re(t11): %s\n" % (np.real(t11))) f1.write("Im(t11): %s\n" % (np.imag(t11))) f1.write("Re(su1): %s\n" % (np.real(su1))) f1.write("Im(su1): %s\n" % (np.imag(su1))) f1.write("Re(sd1): %s\n" % (np.real(sd1))) f1.write("Im(sd1): %s\n" % (np.imag(sd1))) f1.write("--------------------------------------------------- \n") sim.reset_meep()
def _load_dump_structure_3d(self, chunk_file=False, chunk_sim=False, single_parallel_file=True): from meep.materials import aSi resolution = 15 cell = mp.Vector3(2.3, 2.1, 2.7) sources = mp.Source(src=mp.GaussianSource(2.5, fwidth=0.1), center=mp.Vector3(), component=mp.Hy) one_by_one_by_one = mp.Vector3(1, 1, 1) geometry = [ mp.Block(material=mp.Medium(index=2.3), center=mp.Vector3(), size=one_by_one_by_one), mp.Block(material=aSi, center=mp.Vector3(1), size=one_by_one_by_one) ] default_material = mp.Medium(index=1.4) boundary_layers = [mp.Absorber(0.2)] k_point = mp.Vector3(0.4, -1.3, 0.7) sim1 = mp.Simulation(resolution=resolution, cell_size=cell, k_point=k_point, geometry=geometry, boundary_layers=boundary_layers, default_material=default_material, sources=[sources]) sample_point = mp.Vector3(0.73, -0.33, 0.61) ref_field_points = [] def get_ref_field_point(sim): p = sim.get_field_point(mp.Hy, sample_point) ref_field_points.append(p.real) sim1.run(mp.at_every(5, get_ref_field_point), until=50) dump_dirname = os.path.join(self.temp_dir, 'test_load_dump_structure') sim1.dump(dump_dirname, dump_structure=True, dump_fields=False, single_parallel_file=single_parallel_file) dump_chunk_fname = None chunk_layout = None if chunk_file: dump_chunk_fname = os.path.join(dump_dirname, 'chunk_layout.h5') sim1.dump_chunk_layout(dump_chunk_fname) chunk_layout = dump_chunk_fname if chunk_sim: chunk_layout = sim1 sim = mp.Simulation(resolution=resolution, cell_size=cell, sources=[sources], k_point=k_point, boundary_layers=boundary_layers, chunk_layout=chunk_layout) sim.load(dump_dirname, load_structure=True, load_fields=False, single_parallel_file=single_parallel_file) field_points = [] def get_field_point(sim): p = sim.get_field_point(mp.Hy, sample_point) field_points.append(p.real) sim.run(mp.at_every(5, get_field_point), until=50) for ref_pt, pt in zip(ref_field_points, field_points): self.assertAlmostEqual(ref_pt, pt)
def notch(w): print("#----------------------------------------") print("NOTCH WIDTH: %s nanometers" % (w * 1000)) print("#----------------------------------------") # w is the width of the notch in the waveguide #Waveguide Math e = 0.4 # etch fraction [0 -> 1] h2 = h * (1 - e) #height of the etched region d = 1 #spacing of the waveguides posd = d / 2 #pos half d negd = -d / 2 #neg half d ang = 80 #angle of the sidewall angrad = ang * pi / 180 bottomoffset = h / tan(angrad) c = bottomoffset / 2 r = sqrt(bottomoffset**2 + h**2) fcen = 1 / wavelength df = 0.05 n_e = 2.2012 # refractive index inside waveguide (at wavelength 0.6372) n_c = 1.4569 # refractive index outside waveguide (at wavelength 0.6372) #Waveguide Geometry cell = mp.Vector3(a, H) default_material = mp.Medium(epsilon=n_c**2) core_material = mp.Medium(epsilon=n_e**2) geometry = [ mp.Block(cell, center=mp.Vector3(0, 0), material=default_material), mp.Block(mp.Vector3(a + 2 * h, h), center=mp.Vector3(0, 0), material=core_material), # mp.Block(mp.Vector3(w, e * h), mp.Block(mp.Vector3(w, e * h), center=mp.Vector3(0, h2 / 2), material=default_material) ] # pml_layers = [mp.PML(0.2)] pml_layers = [mp.Absorber(thickness=pmlthickness)] # resolution = 50 r00 = None r01 = None r10 = None r11 = None t00 = None t01 = None t10 = None t11 = None su0 = None sd0 = None su1 = None sd1 = None only_fund = True modes = [0, 1] if only_fund: modes = [0] # for mode in [0, 1]: for mode in modes: if mode == 0: eig_parity = mp.EVEN_Y # Fundamental print("-----------") print("MODE TYPE: FUNDAMENTAL") else: eig_parity = mp.ODD_Y # First Order print("-----------") print("MODE TYPE: FIRST ORDER") sources = [ mp.EigenModeSource(mp.GaussianSource(frequency=fcen, fwidth=df), size=mp.Vector3(0, H), center=mp.Vector3(Ls, 0), eig_parity=eig_parity) ] sim = mp.Simulation(cell_size=cell, boundary_layers=pml_layers, geometry=geometry, sources=sources, resolution=resolution, force_complex_fields=True) ''' #-------------------------------------------------- #FOR DISPLAYING THE GEOMETRY sim.run(until = 200) eps_data = sim.get_array(center=mp.Vector3(), size=cell, component=mp.Dielectric) plt.figure(dpi=100) plt.imshow(eps_data.transpose(), interpolation='spline36', cmap='binary') #plt.axis('off') plt.show() quit() #---------------------------------------------------- ''' ''' #------------------------------------------------------ #FOR GENERATING THE ELECTRIC FIELD GIF #Note: After running this program, write the following commands in Terminal: # $ source deactivate mp # $ cd notch-out/ # $ python ../NotchIP.py sim.use_output_directory() sim.run(mp.at_beginning(mp.output_epsilon), mp.to_appended("ez", mp.at_every(0.6, mp.output_efield_z)), until = 200) #sim.run(mp.at_every(0.6 , mp.output_png(mp.Ez, "-Zc dkbluered")), until=200) #--------------------------------------------------------- ''' #--------------------------------------------------------- # FOR GENERATING THE TRANSMITTANCE SPECTRUM nfreq = 20 # number of frequencies at which to compute flux refl_fr1 = mp.FluxRegion(center=mp.Vector3(Lr1, 0), size=mp.Vector3( 0, monitorheight)) # Reflected flux 1 refl_fr2 = mp.FluxRegion(center=mp.Vector3(Lr2, 0), size=mp.Vector3( 0, monitorheight)) # Reflected flux 2 tran_fr = mp.FluxRegion(center=mp.Vector3(Lt, 0), size=mp.Vector3( 0, monitorheight)) # Transmitted flux su_fr = mp.FluxRegion(center=mp.Vector3(0, monitorheight / 2), size=mp.Vector3( a, 0)) # Flux loss above the waveguide sd_fr = mp.FluxRegion(center=mp.Vector3(0, -monitorheight / 2), size=mp.Vector3( a, 0)) # Flux loss below the waveguide refl1 = sim.add_flux(fcen, df, nfreq, refl_fr1) refl2 = sim.add_flux(fcen, df, nfreq, refl_fr2) tran = sim.add_flux(fcen, df, nfreq, tran_fr) su = sim.add_flux(fcen, df, nfreq, su_fr) sd = sim.add_flux(fcen, df, nfreq, sd_fr) # ------------------------ CODE FOR SEPARATING FUND AND FIRST ORDER MODE STARTS HERE ------------------------ y_list = np.arange(-H / 2, H / 2, 1 / resolution) refl_vals = [] tran_vals = [] def get_refl_slice(sim): # print(sim.get_array(center=mp.Vector3(Lr1,0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True)) # refl_val = sim.get_array(center=mp.Vector3(Lr1,0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True) refl_vals.append( sim.get_array(center=mp.Vector3(Lr1, 0), size=mp.Vector3(0, H), component=mp.Ez, cmplx=True)) def get_tran_slice(sim): # print(sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True)) # tran_val = sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0,H), component=mp.Ez, cmplx=True) tran_vals.append( sim.get_array(center=mp.Vector3(Lt, 0), size=mp.Vector3(0, H), component=mp.Ez, cmplx=True)) pt = mp.Vector3(9.75, 0) # Hardcoded? gif = True if gif: # and w == 0.1: sim.use_output_directory() sim.run(mp.at_beginning(mp.output_epsilon), mp.at_end(get_refl_slice), mp.at_end(get_tran_slice), until=100) # sim.run(mp.at_every(wavelength / 20, mp.output_efield_z), until=wavelength) sim.run(mp.at_every( wavelength / 20, mp.output_png( mp.Ez, "-RZc bluered -A notch-out/notch-eps-000000.00.h5 -a gray:.2" )), until=19 * wavelength / 20) sim.run(until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ez, pt, 1e-3)) else: sim.run(mp.at_beginning(mp.output_epsilon), mp.at_time(100, get_refl_slice), mp.at_time(100, get_tran_slice), until_after_sources=mp.stop_when_fields_decayed( 50, mp.Ez, pt, 1e-3)) os.system("cp notch-out/notch-ez-000100.00.png " + str(int(w * 1000)) + "-" + str(mode) + ".png") os.system("convert notch-out/notch-ez-*.png " + str(int(w * 1000)) + "-" + str(mode) + ".gif") refl_val = refl_vals[0] tran_val = tran_vals[0] # n_eff must satisfy n_e <= n_eff <= n_c for the mode to be bound. def fund_func(n_eff): if n_eff >= n_c and n_eff <= n_e: return sqrt(n_eff**2 - n_c**2) - sqrt(n_e**2 - n_eff**2) * tan( pi * h / wavelength * sqrt(n_e**2 - n_eff**2)) def first_order_func(n_eff): if n_eff >= n_c and n_eff <= n_e: return sqrt(n_eff**2 - n_c**2) - sqrt(n_e**2 - n_eff**2) * tan( pi * h / wavelength * sqrt(n_e**2 - n_eff**2) - pi / 2) initial_guess = (n_c + n_e) / 2 n_eff_fund = fsolve(fund_func, initial_guess) n_eff_first = fsolve(first_order_func, n_c) print(n_eff_fund, n_eff_first) assert (n_eff_fund > n_eff_first) if len(n_eff_funds) == 0: n_eff_funds.append(n_eff_fund[0]) if len(n_eff_firsts) == 0: n_eff_firsts.append(n_eff_first[0]) ky0_fund = np.absolute(2 * pi / wavelength * sqrt(n_e**2 - n_eff_fund**2)) ky0_first = np.absolute(2 * pi / wavelength * sqrt(n_e**2 - n_eff_first**2)) ky1_fund = np.absolute(2 * pi / wavelength * sqrt(n_eff_fund**2 - n_c**2)) ky1_first = np.absolute(2 * pi / wavelength * sqrt(n_eff_first**2 - n_c**2)) E_fund = lambda y: cos(ky0_fund * y) if np.absolute( y) < h / 2 else cos(ky0_fund * h / 2) * np.exp(-ky1_fund * ( np.absolute(y) - h / 2)) E_first_order = lambda y: sin(ky0_first * y) if np.absolute( y) < h / 2 else sin(ky0_first * h / 2) * np.exp(-ky1_first * ( np.absolute(y) - h / 2)) * np.sign(y) # y_list = np.arange(-H/2+.5/resolution, H/2-.5/resolution, 1/resolution) #print("Y LIST: ", y_list) #print("SIZE OF Y LIST: ", y_list.size) E_fund_vec = np.zeros(y_list.size) E_first_order_vec = np.zeros(y_list.size) for index in range(y_list.size): y = y_list[index] E_fund_vec[index] = E_fund(y) E_first_order_vec[index] = E_first_order(y) # print("r VECTOR: ", refl_val) # print("t VECTOR: ", tran_val) # print("E0 VECTOR: ", E_fund_vec) # print("E1 VECTOR: ", E_first_order_vec) # plt.plot(y_list, refl_val*100,'bo-',label='reflectance') # plt.plot(y_list, tran_val*1,'ro-',label='transmittance') # plt.plot(y_list, E_fund_vec,'go-',label='E0') # plt.plot(y_list, E_first_order_vec, 'co-', label='E1') # # plt.axis([40.0, 300.0, 0.0, 100.0]) # plt.xlabel("y (um)") # plt.ylabel("Field") # plt.legend(loc="center right") # plt.show() fund_refl_amp = np.conj( np.dot(refl_val, E_fund_vec) / np.dot(E_fund_vec, E_fund_vec) ) # Conjugate becasue MEEP uses physics exp(kz-wt) rather than engineering exp(wt-kz) first_order_refl_amp = np.conj( np.dot(refl_val, E_first_order_vec) / np.dot(E_first_order_vec, E_first_order_vec)) fund_tran_amp = np.conj( np.dot(tran_val, E_fund_vec) / np.dot(E_fund_vec, E_fund_vec)) first_order_tran_amp = np.conj( np.dot(tran_val, E_first_order_vec) / np.dot(E_first_order_vec, E_first_order_vec)) # fund_refl_power = np.abs(fund_tran_amp) ** 2 fund_refl_power = np.abs(fund_refl_amp)**2 first_order_refl_power = np.abs(first_order_refl_amp)**2 fund_tran_power = np.abs(fund_tran_amp)**2 first_order_tran_power = np.abs(first_order_tran_amp)**2 print(fund_refl_power, first_order_refl_power, fund_tran_power, first_order_tran_power) fund_refl_ratio = fund_refl_power / (fund_refl_power + first_order_refl_power) first_order_refl_ratio = first_order_refl_power / ( fund_refl_power + first_order_refl_power) fund_tran_ratio = fund_tran_power / (fund_tran_power + first_order_tran_power) first_order_tran_ratio = first_order_tran_power / ( fund_tran_power + first_order_tran_power) print("Percentage of reflected light in fundamental mode: ", fund_refl_ratio * 100) print("Percentage of reflected light in first order mode: ", first_order_refl_ratio * 100) print("Percentage of transmitted light in fundamental mode: ", fund_tran_ratio * 100) print("Percentage of transmitted light in first order mode: ", first_order_tran_ratio * 100) # ------------------------ CODE FOR SEPARATING FUND AND FIRST ORDER MODE ENDS HERE ------------------------ wl = [] #list of wavelengths refl1_flux = mp.get_fluxes(refl1) refl2_flux = mp.get_fluxes(refl2) tran_flux = mp.get_fluxes(tran) su_flux = mp.get_fluxes(su) sd_flux = mp.get_fluxes(sd) flux_freqs = mp.get_flux_freqs(refl1) for i in range(nfreq): wl = np.append(wl, 1 / flux_freqs[i]) print(1 / flux_freqs[i]) for ind, elt in enumerate(wl): #print(round(elt, 4)) if round(elt, 3) == 0.637: #print("ALERT: MATCH FOUND") index = ind R = -refl1_flux[index] / (refl2_flux[index] - refl1_flux[index]) T = tran_flux[index] / (refl2_flux[index] - refl1_flux[index]) S = (refl2_flux[index] - tran_flux[index]) / (refl2_flux[index] - refl1_flux[index]) Su = su_flux[index] / (refl2_flux[index] - refl1_flux[index]) Sd = -sd_flux[index] / (refl2_flux[index] - refl1_flux[index]) S_correction = (1 - R - T) / (Su + Sd) print(R, T, S, Su, Sd) r = sqrt(R) t = sqrt(T) # The amplitude ... times the phase ... accounting for the distance to the detector (Reverse exp(-kz) of phase). r_fund = (r * fund_refl_ratio) * ( fund_refl_amp / np.abs(fund_refl_amp) ) * ( np.exp(2j * pi * (-Lr1 - w / 2) * n_eff_fund / wavelength) ) # Lr1 is negative because it is the (negative) position of the monitor, not the distace from the monitor to the center. r_first = (r * first_order_refl_ratio) * ( first_order_refl_amp / np.abs(first_order_refl_amp)) * (np.exp( 2j * pi * (-Lr1 - w / 2) * n_eff_first / wavelength)) t_fund = (t * fund_tran_ratio) * ( fund_tran_amp / np.abs(fund_tran_amp)) * (np.exp( 2j * pi * (Lt - w / 2) * n_eff_fund / wavelength)) t_first = (t * first_order_tran_ratio) * ( first_order_tran_amp / np.abs(first_order_tran_amp)) * (np.exp( 2j * pi * (Lt - w / 2) * n_eff_first / wavelength)) if mode == 0: r00 = r_fund r01 = r_first t00 = t_fund t01 = t_first su0 = sqrt(np.abs(Su * S_correction)) sd0 = sqrt(np.abs(Sd * S_correction)) r00s.append(r00[0]) r01s.append(r01[0]) t00s.append(t00[0]) t01s.append(t01[0]) su0s.append(su0) sd0s.append(sd0) if only_fund: r10s.append(0) r11s.append(0) t10s.append(0) t11s.append(1) su1s.append(0) sd1s.append(0) else: r10 = r_fund r11 = r_first t10 = t_fund t11 = t_first su1 = sqrt(np.abs(Su * S_correction)) sd1 = sqrt(np.abs(Sd * S_correction)) r10s.append(r10[0]) r11s.append(r11[0]) t10s.append(t10[0]) t11s.append(t11[0]) su1s.append(su1) sd1s.append(sd1) norm_Su = S * Su / (Su + Sd) NET = round((R + T + S) * 100, 0) if NET > 100.0: NET = 100.0 NET_LOSS = round((Su + Sd) / S * 100, 0) if NET_LOSS > 100.0: NET_LOSS = 100.0 ''' np.append(ws, [w * 1000]) np.append(Rs, [R * 100]) np.append(Ts, [T * 100]) np.append(Ss, [S * 100]) np.append(NET_LIST, [NET]) np.append(Sus, [Su * 100]) np.append(Sds, [Sd * 100]) np.append(NET_LOSS_LIST, [NET_LOSS]) np.append(norm_Sus, [norm_Su * 100]) ''' if mode == 0: ws.append(w * 1000) Rs.append(R * 100) Ts.append(T * 100) Ss.append(S * 100) NET_LIST.append(NET) Sus.append(Su * 100) Sds.append(Sd * 100) NET_LOSS_LIST.append(NET_LOSS) norm_Sus.append(norm_Su * 100) if mode == 0: f1.write("--------------------------------------------------- \n") f1.write("Notch Width: %s nanometers \n" % (w * 1000)) f1.write("Reflection Percentage: %s\n" % (R * 100)) f1.write("Transmission Percentage: %s\n" % (T * 100)) f1.write("Total Loss Percentage: %s\n" % (S * 100)) f1.write("Percentage of Light Accounted For: %s\n" % (NET)) f1.write("Upper Loss Percentage: %s\n" % (Su * 100)) f1.write("Lower Loss Percentage: %s\n" % (Sd * 100)) f1.write("Percentage of Total Loss Accounted For: %s\n" % (NET_LOSS)) f1.write("Normalized Upper Loss Percentage: %s\n" % (norm_Su * 100)) f1.write("\n \n") f1.write("FUNDAMENTAL MODE \n") f1.write("n_eff: %s\n" % (n_eff_fund[0])) f1.write("Re(r00): %s\n" % (np.real(r00))[0]) f1.write("Im(r00): %s\n" % (np.imag(r00))[0]) f1.write("Re(r01): %s\n" % (np.real(r01))[0]) f1.write("Im(r01): %s\n" % (np.imag(r01))[0]) f1.write("Re(t00): %s\n" % (np.real(t00))[0]) f1.write("Im(t00): %s\n" % (np.imag(t00))[0]) f1.write("Re(t01): %s\n" % (np.real(t01))[0]) f1.write("Im(t01): %s\n" % (np.imag(t01))[0]) f1.write("Re(su0): %s\n" % (np.real(su0))) f1.write("Im(su0): %s\n" % (np.imag(su0))) f1.write("Re(sd0): %s\n" % (np.real(sd0))) f1.write("Im(sd0): %s\n" % (np.imag(sd0))) f1.write("\n") else: f1.write("FIRST ORDER MODE \n") f1.write("n_eff: %s\n" % (n_eff_first[0])) f1.write("Re(r10): %s\n" % (np.real(r10))[0]) f1.write("Im(r10): %s\n" % (np.imag(r10))[0]) f1.write("Re(r11): %s\n" % (np.real(r11))[0]) f1.write("Im(r11): %s\n" % (np.imag(r11))[0]) f1.write("Re(t10): %s\n" % (np.real(t10))[0]) f1.write("Im(t10): %s\n" % (np.imag(t10))[0]) f1.write("Re(t11): %s\n" % (np.real(t11))[0]) f1.write("Im(t11): %s\n" % (np.imag(t11))[0]) f1.write("Re(su1): %s\n" % (np.real(su1))) f1.write("Im(su1): %s\n" % (np.imag(su1))) f1.write("Re(sd1): %s\n" % (np.real(sd1))) f1.write("Im(sd1): %s\n" % (np.imag(sd1))) f1.write("--------------------------------------------------- \n") sim.reset_meep()
def energy_flux(): """Source frequency interval""" f_inf = 0.20 f_sup = 0.35 f = 0.5 * (f_inf + f_sup) df = f_sup - f_inf wvl = 1 / f n_freq = 100 source_component = mp.Ex """Materials""" n_ej232 = 1.58 n_bgo = 2.15 n_lyso = 1.82 n_cdse = 2.61 eps1_cdse = n_cdse**2 eps2_cdse = 0 # eps2_cdse = 0.5 # fixme: here the sigma_d is different from MEEP's doc in function of freqeuency! cdse = mp.Medium(epsilon=eps1_cdse, D_conductivity=f * eps2_cdse / eps1_cdse) """Dimension""" a = 1. thickness = 1. * a radius = 0.1 * a dpml = 0.5 * wvl """Computational domain in Meep""" r1 = np.array([0.5, -np.sqrt(3) / 2]) * a r2 = np.array([0.5, np.sqrt(3) / 2]) * a vec1 = mp.Vector3(*r1) vec2 = mp.Vector3(*r2) height = thickness + 2 * (wvl + dpml) width = 2 * wvl + 2 * dpml cell_size = mp.Vector3(width, width, height) # resolution = np.ceil((1 / (wvl / 50))) resolution = 20 # geometry geom = [ mp.Block(center=mp.Vector3(z=0.25 * cell_size.z), size=mp.Vector3(mp.inf, mp.inf, 0.5 * cell_size.z), material=mp.Medium(index=n_ej232)), mp.Block(center=mp.Vector3(z=-0.25 * cell_size.z), size=mp.Vector3(mp.inf, mp.inf, 0.5 * cell_size.z), material=mp.Medium(index=n_lyso)) ] # periodic patterns diagonal = np.sqrt(cell_size.x**2 + cell_size.y**2) n1 = int(0.7 * diagonal / vec1.norm()) n2 = int(0.7 * diagonal / vec2.norm()) geom.append( mp.Block(center=mp.Vector3(), size=mp.Vector3(mp.inf, mp.inf, thickness), material=cdse)) for i in range(-n1, n1 + 1): for j in range(-n2, n2 + 1): hole_center = i * vec1 + j * vec2 if -0.5 * cell_size.x < hole_center.x < 0.5 * cell_size.x \ and -0.5 * cell_size.y < hole_center.y < 0.5 * cell_size.y: geom.append( mp.Cylinder(radius=radius, center=hole_center, height=thickness, material=mp.Medium(index=n_ej232))) source = mp.Source(src=mp.GaussianSource(f, fwidth=df), center=mp.Vector3(), component=mp.Ex) """Boundary conditions""" pml_layers = [ mp.Absorber(dpml, direction=mp.X), mp.Absorber(dpml, direction=mp.Y), mp.PML(dpml, direction=mp.Z) ] sim = mp.Simulation(sources=[source], boundary_layers=pml_layers, cell_size=cell_size, geometry=geom, resolution=resolution) """Energy flux region""" # source surrounding box srcbox_width = wvl / 4 srcbox_top = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(0, 0, 0.5 * srcbox_width), size=mp.Vector3(srcbox_width, srcbox_width, 0), direction=mp.Z, weight=1)) srcbox_bot = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(0, 0, -0.5 * srcbox_width), size=mp.Vector3(srcbox_width, srcbox_width, 0), direction=mp.Z, weight=-1)) srcbox_yf = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(0, 0.5 * srcbox_width, 0), size=mp.Vector3(srcbox_width, 0, srcbox_width), direction=mp.Y, weight=1)) srcbox_yb = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(0, -0.5 * srcbox_width, 0), size=mp.Vector3(srcbox_width, 0, srcbox_width), direction=mp.Y, weight=-1)) srcbox_xf = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(0.5 * srcbox_width, 0, 0), size=mp.Vector3(0, srcbox_width, srcbox_width), direction=mp.X, weight=1)) srcbox_xb = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(-0.5 * srcbox_width, 0, 0), size=mp.Vector3(0, srcbox_width, srcbox_width), direction=mp.X, weight=-1)) srcbox_flux = [ srcbox_top, srcbox_bot, srcbox_xf, srcbox_xb, srcbox_yf, srcbox_yb ] # axial energy flux upper_axial = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(0, 0, 0.5 * height - dpml), size=mp.Vector3(cell_size[0] - 2 * dpml, cell_size[1] - 2 * dpml, 0), direction=mp.Z, weight=1)) lower_axial = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(0, 0, -0.5 * height + dpml), size=mp.Vector3(cell_size[0] - 2 * dpml, cell_size[1] - 2 * dpml, 0), direction=mp.Z, weight=-1)) # lateral energy flux lat_xz1_flux = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(0, 0.5 * cell_size[1] - dpml, 0), size=mp.Vector3(cell_size[0] - 2 * dpml, 0, cell_size[2] - 2 * dpml), direction=mp.Y)) lat_xz2_flux = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(0, -0.5 * cell_size[1] + dpml, 0), size=mp.Vector3(cell_size[0] - 2 * dpml, 0, cell_size[2] - 2 * dpml), direction=mp.Y, weight=-1)) lat_yz1_flux = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(0.5 * cell_size[0] - dpml, 0, 0), size=mp.Vector3(0, cell_size[1] - 2 * dpml, cell_size[2] - 2 * dpml), direction=mp.X)) lat_yz2_flux = sim.add_flux( f, df, n_freq, mp.FluxRegion(center=mp.Vector3(-0.5 * cell_size[0] + dpml, 0, 0), size=mp.Vector3(0, cell_size[1] - 2 * dpml, cell_size[2] - 2 * dpml), direction=mp.X, weight=-1)) lateral_flux = [lat_xz1_flux, lat_xz2_flux, lat_yz1_flux, lat_yz2_flux] """Decay point for the stop criteria""" decay_point = mp.Vector3(0.5 * cell_size.x - 1.1 * dpml, 0.5 * cell_size.y - 1.1 * dpml, 0) # sim.run(until=2) sim.run(until_after_sources=mp.stop_when_fields_decayed( 1, source_component, decay_point, 1e-6)) """Visualization""" # eps_data = sim.get_array(center=mp.Vector3(), size=cell_size, component=mp.Dielectric) # plot_slice(np.sqrt(eps_data)) # plt.show() """Post-processing""" freq = np.array(mp.get_flux_freqs(lower_axial)) lateral_energy = np.zeros(freq.shape) for flux in lateral_flux: if np.min(mp.get_fluxes(flux)) < 0: raise ValueError("Energy flux negative for LATERAL") lateral_energy += np.array(mp.get_fluxes(flux)) # print(np.min(np.array(mp.get_fluxes(flux)))) source_energy = np.zeros(freq.shape) for flux in srcbox_flux: # if np.min(mp.get_fluxes(flux)) < 0: # raise ValueError("Energy flux negative for SOURCE") source_energy += np.array(mp.get_fluxes(flux)) lower_axial = np.array(mp.get_fluxes(lower_axial)) upper_axial = np.array(mp.get_fluxes(upper_axial)) """Post-processing""" eps_data = sim.get_array(center=mp.Vector3(), size=cell_size, component=mp.Dielectric) index_data = np.sqrt(eps_data) return index_data, freq, source_energy, lateral_energy, lower_axial, upper_axial